···217217 }
218218 });
219219220220+ // Determine the rkey early since we need it for the path field
221221+ const rkey = existingDocUri ? new AtUri(existingDocUri).rkey : TID.nextStr();
222222+220223 // Create record based on the document type
221224 let record: PubLeafletDocument.Record | SiteStandardDocument.Record;
222225223226 if (documentType === "site.standard.document") {
224227 // site.standard.document format
225225- // For standalone docs, use a constructed site URI; for publication docs, use the publication URI
228228+ // For standalone docs, use HTTPS URL; for publication docs, use the publication AT-URI
226229 const siteUri = publication_uri || `https://leaflet.pub/p/${credentialSession.did}`;
227230228231 record = {
229232 $type: "site.standard.document",
230233 title: title || "Untitled",
231234 site: siteUri,
235235+ path: rkey,
232236 publishedAt: existingRecord.publishedAt || new Date().toISOString(),
233237 ...(description && { description }),
234238 ...(tags !== undefined && { tags }),
···257261 } satisfies PubLeafletDocument.Record;
258262 }
259263260260- // Keep the same rkey if updating an existing document
261261- let rkey = existingDocUri ? new AtUri(existingDocUri).rkey : TID.nextStr();
262264 let { data: result } = await agent.com.atproto.repo.putRecord({
263265 rkey,
264266 repo: credentialSession.did!,
···3333 if (!document) return null;
34343535 // Normalize the document record - this is the primary way consumers should access document data
3636- const normalizedDocument = normalizeDocumentRecord(document.data);
3636+ const normalizedDocument = normalizeDocumentRecord(document.data, document.uri);
3737 if (!normalizedDocument) return null;
38383939 // Normalize the publication record - this is the primary way consumers should access publication data
···8383 // Filter and sort documents by publishedAt
8484 const sortedDocs = allDocs
8585 .map((dip) => {
8686- const normalizedData = normalizeDocumentRecord(dip?.documents?.data);
8686+ const normalizedData = normalizeDocumentRecord(dip?.documents?.data, dip?.documents?.uri);
8787 return {
8888 uri: dip?.documents?.uri,
8989 title: normalizedData?.title,
+1-1
app/lish/[did]/[publication]/generateFeed.ts
···5454 await Promise.all(
5555 publication.documents_in_publications.map(async (doc) => {
5656 if (!doc.documents) return;
5757- const record = normalizeDocumentRecord(doc.documents?.data);
5757+ const record = normalizeDocumentRecord(doc.documents?.data, doc.documents?.uri);
5858 const uri = new AtUri(doc.documents?.uri);
5959 const rkey = uri.rkey;
6060 if (!record) return;
···2121import type * as SiteStandardThemeBasic from "../api/types/site/standard/theme/basic";
2222import type * as PubLeafletThemeColor from "../api/types/pub/leaflet/theme/color";
2323import type { $Typed } from "../api/util";
2424+import { AtUri } from "@atproto/syntax";
24252526// Normalized document type - uses the generated site.standard.document type
2627// with an additional optional theme field for backwards compatibility
···143144 * Normalizes a document record from either format to the standard format.
144145 *
145146 * @param record - The document record from the database (either pub.leaflet or site.standard)
147147+ * @param uri - Optional document URI, used to extract the rkey for the path field when normalizing pub.leaflet records
146148 * @returns A normalized document in site.standard format, or null if invalid/unrecognized
147149 */
148148-export function normalizeDocument(record: unknown): NormalizedDocument | null {
150150+export function normalizeDocument(record: unknown, uri?: string): NormalizedDocument | null {
149151 if (!record || typeof record !== "object") return null;
150152151153 // Pass through site.standard records directly (theme is already in correct format if present)
···168170 // This matches the pattern used in publishToPublication.ts for new standalone docs
169171 const site = record.publication || `https://leaflet.pub/p/${record.author}`;
170172173173+ // Extract path from URI if available
174174+ const path = uri ? new AtUri(uri).rkey : undefined;
175175+171176 // Wrap pages in pub.leaflet.content structure
172177 const content: $Typed<PubLeafletContent.Main> | undefined = record.pages
173178 ? {
···180185 $type: "site.standard.document",
181186 title: record.title,
182187 site,
188188+ path,
183189 publishedAt,
184190 description: record.description,
185191 tags: record.tags,
···1717 * Normalizes a document record from a database query result.
1818 * Returns the normalized document or null if the record is invalid/unrecognized.
1919 *
2020+ * @param data - The document record data from the database
2121+ * @param uri - Optional document URI, used to extract the rkey for the path field when normalizing pub.leaflet records
2222+ *
2023 * @example
2121- * const doc = normalizeDocumentRecord(dbResult.data);
2424+ * const doc = normalizeDocumentRecord(dbResult.data, dbResult.uri);
2225 * if (doc) {
2326 * // doc is NormalizedDocument with proper typing
2427 * console.log(doc.title, doc.site, doc.publishedAt);
2528 * }
2629 */
2730export function normalizeDocumentRecord(
2828- data: Json | unknown
3131+ data: Json | unknown,
3232+ uri?: string
2933): NormalizedDocument | null {
3030- return normalizeDocument(data);
3434+ return normalizeDocument(data, uri);
3135}
32363337/**
···69737074/**
7175 * Normalizes a document row in place, returning a properly typed row.
7676+ * If the row has a `uri` field, it will be used to extract the path.
7277 */
7373-export function normalizeDocumentRow<T extends { data: Json | unknown }>(
7878+export function normalizeDocumentRow<T extends { data: Json | unknown; uri?: string }>(
7479 row: T
7580): DocumentRowWithNormalizedData<T> {
7681 return {
7782 ...row,
7878- data: normalizeDocumentRecord(row.data),
8383+ data: normalizeDocumentRecord(row.data, row.uri),
7984 };
8085}
8186