@tokenoftrust/storefront-runner 2.2.108 → 2.2.109
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -50,6 +50,10 @@ export function readCatalogFiles(
|
|
|
50
50
|
export const CATALOG_LISTING_VERSION: number;
|
|
51
51
|
export const LISTING_DESCRIPTION_CHARS: number;
|
|
52
52
|
export function catalogListingProjection(entries: Iterable<{ path: string; raw: string | null }>): string | null;
|
|
53
|
+
export function createCatalogListingBuilder(): {
|
|
54
|
+
add(path: string, raw: string | null): void;
|
|
55
|
+
build(): string | null;
|
|
56
|
+
};
|
|
53
57
|
export function readCatalogListing(
|
|
54
58
|
raw: string,
|
|
55
59
|
store: CatalogStore,
|
|
@@ -287,6 +287,58 @@ function listingProduct(record) {
|
|
|
287
287
|
};
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
+
/** A record's file-stem handle, for the listing's deterministic sort (see {@link createCatalogListingBuilder}). */
|
|
291
|
+
function recordHandle(doc) {
|
|
292
|
+
return isObject(doc) && typeof doc.handle === "string" ? doc.handle : "";
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Incremental builder for the listing projection: `add` one catalog file at a time instead of
|
|
297
|
+
* handing the whole catalog's raw content to one call, so a caller streaming thousands of large
|
|
298
|
+
* files (a store's product catalog) never needs to hold them all in memory at once just to build
|
|
299
|
+
* this one derived document — see `prepareReconcile` in the platform's reconcile pipeline, which
|
|
300
|
+
* feeds this builder as each file streams through, and discards the file's content right after.
|
|
301
|
+
*
|
|
302
|
+
* `products`/`collections` are sorted by handle in `build()` (not insertion order), so the
|
|
303
|
+
* document is identical regardless of what order — concurrent or not — files were added in.
|
|
304
|
+
*/
|
|
305
|
+
export function createCatalogListingBuilder() {
|
|
306
|
+
const products = [];
|
|
307
|
+
const collections = [];
|
|
308
|
+
const failures = [];
|
|
309
|
+
let any = false;
|
|
310
|
+
return {
|
|
311
|
+
/** @param {string} path `content/`-relative path @param {string | null} raw the file's text */
|
|
312
|
+
add(path, raw) {
|
|
313
|
+
if (classifyCatalogPath(path) === null) return;
|
|
314
|
+
any = true;
|
|
315
|
+
if (raw === null) {
|
|
316
|
+
failures.push({ path, issues: ["listed in the catalog but unreadable"] });
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
const parsed = parse(path, raw, "", { available: true });
|
|
320
|
+
if (parsed.issues.length > 0) {
|
|
321
|
+
failures.push({ path, issues: parsed.issues });
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
const doc = JSON.parse(raw);
|
|
325
|
+
if (parsed.kind === "product") products.push(listingProduct(catalogFileRecord("product", doc)));
|
|
326
|
+
else collections.push(doc);
|
|
327
|
+
},
|
|
328
|
+
/** @returns {string | null} the document's text, or null when nothing was ever added. */
|
|
329
|
+
build() {
|
|
330
|
+
if (!any) return null;
|
|
331
|
+
if (failures.length > 0) {
|
|
332
|
+
failures.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
|
|
333
|
+
return JSON.stringify({ version: CATALOG_LISTING_VERSION, failures });
|
|
334
|
+
}
|
|
335
|
+
products.sort((a, b) => (recordHandle(a) < recordHandle(b) ? -1 : recordHandle(a) > recordHandle(b) ? 1 : 0));
|
|
336
|
+
collections.sort((a, b) => (recordHandle(a) < recordHandle(b) ? -1 : recordHandle(a) > recordHandle(b) ? 1 : 0));
|
|
337
|
+
return JSON.stringify({ version: CATALOG_LISTING_VERSION, products, collections });
|
|
338
|
+
},
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
290
342
|
/**
|
|
291
343
|
* Build the listing projection from a store's catalog files, validating each one exactly as the
|
|
292
344
|
* reader does. Records are kept as their files hold them (identity and availability are stamped
|
|
@@ -297,32 +349,9 @@ function listingProduct(record) {
|
|
|
297
349
|
* @returns {string | null}
|
|
298
350
|
*/
|
|
299
351
|
export function catalogListingProjection(entries) {
|
|
300
|
-
const
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
let any = false;
|
|
304
|
-
for (const { path, raw } of entries) {
|
|
305
|
-
if (classifyCatalogPath(path) === null) continue;
|
|
306
|
-
any = true;
|
|
307
|
-
if (raw === null) {
|
|
308
|
-
failures.push({ path, issues: ["listed in the catalog but unreadable"] });
|
|
309
|
-
continue;
|
|
310
|
-
}
|
|
311
|
-
const parsed = parse(path, raw, "", { available: true });
|
|
312
|
-
if (parsed.issues.length > 0) {
|
|
313
|
-
failures.push({ path, issues: parsed.issues });
|
|
314
|
-
continue;
|
|
315
|
-
}
|
|
316
|
-
const doc = JSON.parse(raw);
|
|
317
|
-
if (parsed.kind === "product") products.push(listingProduct(catalogFileRecord("product", doc)));
|
|
318
|
-
else collections.push(doc);
|
|
319
|
-
}
|
|
320
|
-
if (!any) return null;
|
|
321
|
-
return JSON.stringify(
|
|
322
|
-
failures.length > 0
|
|
323
|
-
? { version: CATALOG_LISTING_VERSION, failures }
|
|
324
|
-
: { version: CATALOG_LISTING_VERSION, products, collections },
|
|
325
|
-
);
|
|
352
|
+
const builder = createCatalogListingBuilder();
|
|
353
|
+
for (const { path, raw } of entries) builder.add(path, raw);
|
|
354
|
+
return builder.build();
|
|
326
355
|
}
|
|
327
356
|
|
|
328
357
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokenoftrust/storefront-runner",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.109",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"description": "World-shareable storefront runner: multi-tenant renderer on Astro/Cloudflare. No control plane.",
|
|
6
6
|
"packageManager": "pnpm@11.9.0",
|