@elytracms/next 0.0.94 → 0.0.96
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.
- package/dist/index.d.ts +26 -4
- package/dist/index.js +42 -22
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -227,8 +227,13 @@ interface ContentSource {
|
|
|
227
227
|
* backend outage. Optional so existing custom sources stay valid; without it,
|
|
228
228
|
* asset-typed props fall back to their raw value (the renderer's visible
|
|
229
229
|
* degradation), never a crash.
|
|
230
|
+
*
|
|
231
|
+
* EC-632: resolved in `locale` (absent → the source's default locale) — a localized
|
|
232
|
+
* asset-collection field (alt, …) carries its value in that locale, with the default
|
|
233
|
+
* locale as its fallback. The route helper passes the request's locale, so a page bakes
|
|
234
|
+
* its assets in the locale it renders in.
|
|
230
235
|
*/
|
|
231
|
-
assets?(): readonly ResolvedAsset[];
|
|
236
|
+
assets?(locale?: Locale): readonly ResolvedAsset[];
|
|
232
237
|
}
|
|
233
238
|
/**
|
|
234
239
|
* Merge accessor cache tags into one deterministic set (sorted, deduplicated)
|
|
@@ -296,6 +301,13 @@ interface StaticContentData {
|
|
|
296
301
|
routes?: readonly RouteRecord[];
|
|
297
302
|
/** Redirect records served by `resolvePage` (EC-019/020). */
|
|
298
303
|
redirects?: readonly RedirectRecord[];
|
|
304
|
+
/**
|
|
305
|
+
* The project's collection definitions (every host path hands the resolved config's). They
|
|
306
|
+
* are also the asset metadata's lens (EC-659): the asset collection's `localized` fields
|
|
307
|
+
* are the only ones a stored per-locale value is read for. ABSENT means no schema — no
|
|
308
|
+
* field is localized, so every stored translation is drift: never applied (the shared
|
|
309
|
+
* value is served), each one named on `sourceIssues`.
|
|
310
|
+
*/
|
|
299
311
|
collections?: readonly CollectionDef[];
|
|
300
312
|
/**
|
|
301
313
|
* Stored document sources. Either a bare `CmsDocument` (gated by its own
|
|
@@ -307,10 +319,14 @@ interface StaticContentData {
|
|
|
307
319
|
documents?: readonly ContentDocumentSource[];
|
|
308
320
|
assets?: readonly AssetRecord[];
|
|
309
321
|
/**
|
|
310
|
-
* Resolve a serve URL for assets without a stored `url
|
|
311
|
-
*
|
|
322
|
+
* Resolve a serve URL for assets without a stored `url` (`undefined` when there is
|
|
323
|
+
* none). EC-633: no default — an asset with no URL is no resolved asset (the ONE
|
|
324
|
+
* constructor, `resolvedAsset`, decides it): it renders the canvas's empty state, its
|
|
325
|
+
* field resolves to `null` with an `asset-without-url` issue, and this source names it
|
|
326
|
+
* on `sourceIssues`. The placeholder this used to default to (`asset://unresolved/…`)
|
|
327
|
+
* rendered a broken image on the site.
|
|
312
328
|
*/
|
|
313
|
-
assetUrl?: (asset: AssetRecord) => string;
|
|
329
|
+
assetUrl?: (asset: AssetRecord) => string | undefined;
|
|
314
330
|
/**
|
|
315
331
|
* EC-585 — the stored rows the host could not read (`parseDeliveredDocuments`), handed
|
|
316
332
|
* to every client of this source as its `sourceIssues` (and in the results they
|
|
@@ -1991,6 +2007,12 @@ interface LiveContentOptions {
|
|
|
1991
2007
|
interface DeliverySnapshotPayload {
|
|
1992
2008
|
projectId: string;
|
|
1993
2009
|
redirects?: unknown[];
|
|
2010
|
+
/**
|
|
2011
|
+
* EC-628 — the stored redirects the deployment withheld because it could not read them
|
|
2012
|
+
* (`invalid-redirect` issues from the one live rule). Absent from a deployment older than
|
|
2013
|
+
* EC-628, which serves such rows in `redirects` instead (and this host names them there).
|
|
2014
|
+
*/
|
|
2015
|
+
redirectIssues?: unknown[];
|
|
1994
2016
|
documents: unknown[];
|
|
1995
2017
|
assets: unknown[];
|
|
1996
2018
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { registerComponents, createRenderContext, renderDocumentBodyItems, documentBodyItems, serializeListingQuery, documentBodyRichTextValues, documentBodyCompositionNodes, richTextEmbedsInValue, collectReferencedAssetIds, collectRichTextRefsInValue, collectReferencedRelations, collectReferencedListings, collectReferencedRichTextLinks, listingRequestOf } from '@elytracms/core/runtime-renderer';
|
|
2
2
|
import { isBlockSequenceValueShape } from '@elytracms/core/rich-text';
|
|
3
3
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
4
|
-
import { cacheTags, isDocumentHistory, resolvedAsset, parseDeliveredDocuments, createContentClient, createContentContext } from '@elytracms/core/content';
|
|
5
|
-
import { DEFAULT_SEO_FIELD, parseLocaleConfig, documentKey,
|
|
4
|
+
import { cacheTags, isDocumentHistory, assetWithoutUrlIssue, assetMetaDriftIssue, resolvedAsset, parseDeliveredDocuments, parseDeliveredRedirects, createContentClient, createContentContext } from '@elytracms/core/content';
|
|
5
|
+
import { DEFAULT_SEO_FIELD, parseLocaleConfig, documentKey, readLiveRedirects, SEO_SUBFIELDS, splitLocalePath, DRAFT_PERSPECTIVE, splitPath, localeUrlPath, variantOf, DRAFT_VARIANT, createRouter, presentationBodyFields } from '@elytracms/core/cms-core';
|
|
6
6
|
export { DRAFT_PERSPECTIVE, documentSchema, localeConfigSchema, localeUrlPath, parseLocaleConfig, redirectRecordSchema, resolveLocale, routeRecordSchema, splitLocalePath, textDirection, variantOf } from '@elytracms/core/cms-core';
|
|
7
|
-
import { redirectRecordKind } from '@elytracms/core/persistence';
|
|
7
|
+
import { assetMetaLens, assetMetaDrift, assetReadLocale, redirectRecordKind } from '@elytracms/core/persistence';
|
|
8
8
|
import { revalidateTag, cacheTag } from 'next/cache';
|
|
9
9
|
import { draftMode } from 'next/headers';
|
|
10
10
|
import { redirect, notFound, permanentRedirect } from 'next/navigation';
|
|
@@ -122,7 +122,7 @@ function createStaticContentSource(data) {
|
|
|
122
122
|
const locales = parseLocaleConfig(data.locales);
|
|
123
123
|
const routes = data.routes ?? [];
|
|
124
124
|
const redirects = data.redirects ?? [];
|
|
125
|
-
const assetUrl =
|
|
125
|
+
const assetUrl = (asset) => asset.url ?? data.assetUrl?.(asset);
|
|
126
126
|
const collections = /* @__PURE__ */ new Map();
|
|
127
127
|
for (const collection of data.collections ?? []) collections.set(collection.id, collection);
|
|
128
128
|
const documents = /* @__PURE__ */ new Map();
|
|
@@ -136,23 +136,32 @@ function createStaticContentSource(data) {
|
|
|
136
136
|
}
|
|
137
137
|
const assets = /* @__PURE__ */ new Map();
|
|
138
138
|
for (const record2 of data.assets ?? []) assets.set(record2.id, record2);
|
|
139
|
+
const metaLens = assetMetaLens(data.collections ?? []);
|
|
140
|
+
const sourceIssues = [
|
|
141
|
+
...data.sourceIssues ?? [],
|
|
142
|
+
...[...assets.values()].filter((record2) => !assetUrl(record2)).map((record2) => assetWithoutUrlIssue(record2.id)),
|
|
143
|
+
...[...assets.values()].flatMap(
|
|
144
|
+
(record2) => assetMetaDrift(record2, metaLens).map((drift) => assetMetaDriftIssue(record2.id, drift))
|
|
145
|
+
)
|
|
146
|
+
];
|
|
139
147
|
const lookupFor = (_perspective) => ({
|
|
140
148
|
collection: (id) => collections.get(id),
|
|
141
149
|
document: (ref) => documents.get(documentKey(ref)),
|
|
142
150
|
documents: (collectionId) => byCollection.get(collectionId) ?? [],
|
|
143
151
|
asset: (id) => assets.get(id),
|
|
144
|
-
assetUrl
|
|
152
|
+
assetUrl
|
|
145
153
|
});
|
|
146
154
|
const client = (init) => createContentClient({
|
|
147
155
|
lookup: lookupFor(init.perspective),
|
|
148
156
|
context: createContentContext({
|
|
149
157
|
locale: init.locale ?? locales.default,
|
|
150
158
|
perspective: init.perspective,
|
|
151
|
-
locales
|
|
159
|
+
locales,
|
|
160
|
+
assetMetaLens: metaLens
|
|
152
161
|
}),
|
|
153
162
|
routes,
|
|
154
163
|
redirects,
|
|
155
|
-
...
|
|
164
|
+
...sourceIssues.length > 0 ? { sourceIssues } : {}
|
|
156
165
|
});
|
|
157
166
|
return {
|
|
158
167
|
projectId: data.projectId,
|
|
@@ -163,7 +172,14 @@ function createStaticContentSource(data) {
|
|
|
163
172
|
// `asset`-typed Image prop (an asset id) to a usable url + intrinsic
|
|
164
173
|
// dimensions. Baked into the (serializable) render outcome by the route
|
|
165
174
|
// helper, so a cached page keeps its images during a backend outage.
|
|
166
|
-
|
|
175
|
+
// EC-632: in the requested locale (the route helper passes the request's), so a
|
|
176
|
+
// localized alt is baked in the locale the page renders in.
|
|
177
|
+
// EC-633: a record with no URL is no resolved asset — not baked, so the page renders
|
|
178
|
+
// the empty state the canvas renders for it (and `sourceIssues` names it).
|
|
179
|
+
assets: (locale) => [...assets.values()].flatMap((record2) => {
|
|
180
|
+
const asset = resolvedAsset(record2, assetUrl(record2), assetReadLocale(locales, metaLens, locale));
|
|
181
|
+
return asset ? [asset] : [];
|
|
182
|
+
}),
|
|
167
183
|
// EC-499: the schema the route helper reads a collection's declared
|
|
168
184
|
// `presentation` from (which field is the delivery body, which component
|
|
169
185
|
// wraps it). Already prefetched for the lookup above — exposing it costs
|
|
@@ -175,8 +191,16 @@ async function createContentSnapshot(adapter, projectId, options) {
|
|
|
175
191
|
const documentRecords = await adapter.cms.listDocuments(projectId);
|
|
176
192
|
const versionRecords = await adapter.cms.listAllDocumentVersions(projectId);
|
|
177
193
|
const assetRecords = await adapter.assets.listAssets(projectId);
|
|
194
|
+
const blobs = adapter.blobs;
|
|
195
|
+
const servedUrls = /* @__PURE__ */ new Map();
|
|
196
|
+
await Promise.all(
|
|
197
|
+
assetRecords.filter((record2) => !record2.url).map(async (record2) => {
|
|
198
|
+
const url = blobs.resolveUrl ? await blobs.resolveUrl(record2.storageKey).catch(() => void 0) : blobs.url(record2.storageKey);
|
|
199
|
+
servedUrls.set(record2.id, url || void 0);
|
|
200
|
+
})
|
|
201
|
+
);
|
|
178
202
|
const redirectRecords = await adapter.records(redirectRecordKind).list(projectId);
|
|
179
|
-
const redirects =
|
|
203
|
+
const { redirects, issues: redirectIssues } = readLiveRedirects(redirectRecords);
|
|
180
204
|
const versionsByKey = /* @__PURE__ */ new Map();
|
|
181
205
|
for (const record2 of versionRecords) {
|
|
182
206
|
const key = `${record2.collection}:${record2.docId}`;
|
|
@@ -194,13 +218,15 @@ async function createContentSnapshot(adapter, projectId, options) {
|
|
|
194
218
|
});
|
|
195
219
|
return createStaticContentSource({
|
|
196
220
|
projectId,
|
|
221
|
+
// EC-628: only for the stored redirects this source serves (an explicit override replaces them).
|
|
222
|
+
...options.redirects === void 0 && redirectIssues.length > 0 ? { sourceIssues: redirectIssues } : {},
|
|
197
223
|
locales: options.locales,
|
|
198
224
|
...options.routes ? { routes: options.routes } : {},
|
|
199
225
|
redirects: options.redirects ? [...options.redirects] : redirects,
|
|
200
226
|
collections: options.collections,
|
|
201
227
|
documents,
|
|
202
228
|
assets: assetRecords,
|
|
203
|
-
assetUrl: (asset) =>
|
|
229
|
+
assetUrl: (asset) => servedUrls.get(asset.id)
|
|
204
230
|
});
|
|
205
231
|
}
|
|
206
232
|
function seoContextOf(result, assets = []) {
|
|
@@ -410,7 +436,7 @@ async function resolveCanvasPage(source, url, perspective, options = {}) {
|
|
|
410
436
|
}
|
|
411
437
|
const presentation = presentationFor(source, result);
|
|
412
438
|
const body = pageBodyOf(result, presentation);
|
|
413
|
-
const allAssets = source.assets?.() ?? [];
|
|
439
|
+
const allAssets = source.assets?.(locale) ?? [];
|
|
414
440
|
const bakedAssets = options.registry ? scopeAssetsToPage(
|
|
415
441
|
allAssets,
|
|
416
442
|
options.registry,
|
|
@@ -1083,17 +1109,11 @@ async function runConvexQuery(fetchImpl, convexUrl, path, args) {
|
|
|
1083
1109
|
}
|
|
1084
1110
|
return body.value;
|
|
1085
1111
|
}
|
|
1086
|
-
function parseRedirects(rows) {
|
|
1087
|
-
const redirects = [];
|
|
1088
|
-
for (const row of rows) {
|
|
1089
|
-
const parsed = redirectRecordSchema.safeParse(row);
|
|
1090
|
-
if (parsed.success) redirects.push(parsed.data);
|
|
1091
|
-
}
|
|
1092
|
-
return redirects;
|
|
1093
|
-
}
|
|
1094
1112
|
function assembleLiveSource(payload, options, perspective) {
|
|
1095
1113
|
const locales = options.locales;
|
|
1096
|
-
const { documents, issues:
|
|
1114
|
+
const { documents, issues: documentIssues } = parseDeliveredDocuments(payload.documents);
|
|
1115
|
+
const delivered = parseDeliveredRedirects(payload.redirects ?? [], payload.redirectIssues ?? []);
|
|
1116
|
+
const sourceIssues = [...documentIssues, ...delivered.issues];
|
|
1097
1117
|
const routes = [...options.routes];
|
|
1098
1118
|
const documentSources = perspective === "published" ? documents.map((doc) => ({ draft: doc, published: doc, versions: [] })) : documents;
|
|
1099
1119
|
return createStaticContentSource({
|
|
@@ -1103,7 +1123,7 @@ function assembleLiveSource(payload, options, perspective) {
|
|
|
1103
1123
|
// Redirects are editorial DATA (EC-303): the ENABLED ones ship in the
|
|
1104
1124
|
// snapshot, so they change dynamically (no redeploy). Native next.config
|
|
1105
1125
|
// redirects run before this.
|
|
1106
|
-
redirects:
|
|
1126
|
+
redirects: delivered.redirects,
|
|
1107
1127
|
collections: [...options.collections],
|
|
1108
1128
|
documents: documentSources,
|
|
1109
1129
|
assets: payload.assets,
|
|
@@ -1159,7 +1179,7 @@ function resolveGlobals(source, options = {}) {
|
|
|
1159
1179
|
const navigationCollection = conventions.navigationCollection ?? "navigation";
|
|
1160
1180
|
const itemsFields = conventions.navigationItemsFields ?? DEFAULT_ITEMS_FIELDS;
|
|
1161
1181
|
const client = source.client({ perspective, ...options.locale ? { locale: options.locale } : {} });
|
|
1162
|
-
const assets = source.assets?.() ?? [];
|
|
1182
|
+
const assets = source.assets?.(options.locale) ?? [];
|
|
1163
1183
|
const assetById = new Map(assets.map((asset) => [asset.id, asset]));
|
|
1164
1184
|
const listDocs = (collection) => {
|
|
1165
1185
|
const result = client.listDocuments(collection);
|