@elytracms/next 0.0.94 → 0.0.95
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 +19 -4
- package/dist/index.js +36 -21
- 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)
|
|
@@ -307,10 +312,14 @@ interface StaticContentData {
|
|
|
307
312
|
documents?: readonly ContentDocumentSource[];
|
|
308
313
|
assets?: readonly AssetRecord[];
|
|
309
314
|
/**
|
|
310
|
-
* Resolve a serve URL for assets without a stored `url
|
|
311
|
-
*
|
|
315
|
+
* Resolve a serve URL for assets without a stored `url` (`undefined` when there is
|
|
316
|
+
* none). EC-633: no default — an asset with no URL is no resolved asset (the ONE
|
|
317
|
+
* constructor, `resolvedAsset`, decides it): it renders the canvas's empty state, its
|
|
318
|
+
* field resolves to `null` with an `asset-without-url` issue, and this source names it
|
|
319
|
+
* on `sourceIssues`. The placeholder this used to default to (`asset://unresolved/…`)
|
|
320
|
+
* rendered a broken image on the site.
|
|
312
321
|
*/
|
|
313
|
-
assetUrl?: (asset: AssetRecord) => string;
|
|
322
|
+
assetUrl?: (asset: AssetRecord) => string | undefined;
|
|
314
323
|
/**
|
|
315
324
|
* EC-585 — the stored rows the host could not read (`parseDeliveredDocuments`), handed
|
|
316
325
|
* to every client of this source as its `sourceIssues` (and in the results they
|
|
@@ -1991,6 +2000,12 @@ interface LiveContentOptions {
|
|
|
1991
2000
|
interface DeliverySnapshotPayload {
|
|
1992
2001
|
projectId: string;
|
|
1993
2002
|
redirects?: unknown[];
|
|
2003
|
+
/**
|
|
2004
|
+
* EC-628 — the stored redirects the deployment withheld because it could not read them
|
|
2005
|
+
* (`invalid-redirect` issues from the one live rule). Absent from a deployment older than
|
|
2006
|
+
* EC-628, which serves such rows in `redirects` instead (and this host names them there).
|
|
2007
|
+
*/
|
|
2008
|
+
redirectIssues?: unknown[];
|
|
1994
2009
|
documents: unknown[];
|
|
1995
2010
|
assets: unknown[];
|
|
1996
2011
|
}
|
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, 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 { 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,12 +136,16 @@ 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 sourceIssues = [
|
|
140
|
+
...data.sourceIssues ?? [],
|
|
141
|
+
...[...assets.values()].filter((record2) => !assetUrl(record2)).map((record2) => assetWithoutUrlIssue(record2.id))
|
|
142
|
+
];
|
|
139
143
|
const lookupFor = (_perspective) => ({
|
|
140
144
|
collection: (id) => collections.get(id),
|
|
141
145
|
document: (ref) => documents.get(documentKey(ref)),
|
|
142
146
|
documents: (collectionId) => byCollection.get(collectionId) ?? [],
|
|
143
147
|
asset: (id) => assets.get(id),
|
|
144
|
-
assetUrl
|
|
148
|
+
assetUrl
|
|
145
149
|
});
|
|
146
150
|
const client = (init) => createContentClient({
|
|
147
151
|
lookup: lookupFor(init.perspective),
|
|
@@ -152,7 +156,7 @@ function createStaticContentSource(data) {
|
|
|
152
156
|
}),
|
|
153
157
|
routes,
|
|
154
158
|
redirects,
|
|
155
|
-
...
|
|
159
|
+
...sourceIssues.length > 0 ? { sourceIssues } : {}
|
|
156
160
|
});
|
|
157
161
|
return {
|
|
158
162
|
projectId: data.projectId,
|
|
@@ -163,7 +167,14 @@ function createStaticContentSource(data) {
|
|
|
163
167
|
// `asset`-typed Image prop (an asset id) to a usable url + intrinsic
|
|
164
168
|
// dimensions. Baked into the (serializable) render outcome by the route
|
|
165
169
|
// helper, so a cached page keeps its images during a backend outage.
|
|
166
|
-
|
|
170
|
+
// EC-632: in the requested locale (the route helper passes the request's), so a
|
|
171
|
+
// localized alt is baked in the locale the page renders in.
|
|
172
|
+
// EC-633: a record with no URL is no resolved asset — not baked, so the page renders
|
|
173
|
+
// the empty state the canvas renders for it (and `sourceIssues` names it).
|
|
174
|
+
assets: (locale) => [...assets.values()].flatMap((record2) => {
|
|
175
|
+
const asset = resolvedAsset(record2, assetUrl(record2), assetReadLocale(locales, locale));
|
|
176
|
+
return asset ? [asset] : [];
|
|
177
|
+
}),
|
|
167
178
|
// EC-499: the schema the route helper reads a collection's declared
|
|
168
179
|
// `presentation` from (which field is the delivery body, which component
|
|
169
180
|
// wraps it). Already prefetched for the lookup above — exposing it costs
|
|
@@ -175,8 +186,16 @@ async function createContentSnapshot(adapter, projectId, options) {
|
|
|
175
186
|
const documentRecords = await adapter.cms.listDocuments(projectId);
|
|
176
187
|
const versionRecords = await adapter.cms.listAllDocumentVersions(projectId);
|
|
177
188
|
const assetRecords = await adapter.assets.listAssets(projectId);
|
|
189
|
+
const blobs = adapter.blobs;
|
|
190
|
+
const servedUrls = /* @__PURE__ */ new Map();
|
|
191
|
+
await Promise.all(
|
|
192
|
+
assetRecords.filter((record2) => !record2.url).map(async (record2) => {
|
|
193
|
+
const url = blobs.resolveUrl ? await blobs.resolveUrl(record2.storageKey).catch(() => void 0) : blobs.url(record2.storageKey);
|
|
194
|
+
servedUrls.set(record2.id, url || void 0);
|
|
195
|
+
})
|
|
196
|
+
);
|
|
178
197
|
const redirectRecords = await adapter.records(redirectRecordKind).list(projectId);
|
|
179
|
-
const redirects =
|
|
198
|
+
const { redirects, issues: redirectIssues } = readLiveRedirects(redirectRecords);
|
|
180
199
|
const versionsByKey = /* @__PURE__ */ new Map();
|
|
181
200
|
for (const record2 of versionRecords) {
|
|
182
201
|
const key = `${record2.collection}:${record2.docId}`;
|
|
@@ -194,13 +213,15 @@ async function createContentSnapshot(adapter, projectId, options) {
|
|
|
194
213
|
});
|
|
195
214
|
return createStaticContentSource({
|
|
196
215
|
projectId,
|
|
216
|
+
// EC-628: only for the stored redirects this source serves (an explicit override replaces them).
|
|
217
|
+
...options.redirects === void 0 && redirectIssues.length > 0 ? { sourceIssues: redirectIssues } : {},
|
|
197
218
|
locales: options.locales,
|
|
198
219
|
...options.routes ? { routes: options.routes } : {},
|
|
199
220
|
redirects: options.redirects ? [...options.redirects] : redirects,
|
|
200
221
|
collections: options.collections,
|
|
201
222
|
documents,
|
|
202
223
|
assets: assetRecords,
|
|
203
|
-
assetUrl: (asset) =>
|
|
224
|
+
assetUrl: (asset) => servedUrls.get(asset.id)
|
|
204
225
|
});
|
|
205
226
|
}
|
|
206
227
|
function seoContextOf(result, assets = []) {
|
|
@@ -410,7 +431,7 @@ async function resolveCanvasPage(source, url, perspective, options = {}) {
|
|
|
410
431
|
}
|
|
411
432
|
const presentation = presentationFor(source, result);
|
|
412
433
|
const body = pageBodyOf(result, presentation);
|
|
413
|
-
const allAssets = source.assets?.() ?? [];
|
|
434
|
+
const allAssets = source.assets?.(locale) ?? [];
|
|
414
435
|
const bakedAssets = options.registry ? scopeAssetsToPage(
|
|
415
436
|
allAssets,
|
|
416
437
|
options.registry,
|
|
@@ -1083,17 +1104,11 @@ async function runConvexQuery(fetchImpl, convexUrl, path, args) {
|
|
|
1083
1104
|
}
|
|
1084
1105
|
return body.value;
|
|
1085
1106
|
}
|
|
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
1107
|
function assembleLiveSource(payload, options, perspective) {
|
|
1095
1108
|
const locales = options.locales;
|
|
1096
|
-
const { documents, issues:
|
|
1109
|
+
const { documents, issues: documentIssues } = parseDeliveredDocuments(payload.documents);
|
|
1110
|
+
const delivered = parseDeliveredRedirects(payload.redirects ?? [], payload.redirectIssues ?? []);
|
|
1111
|
+
const sourceIssues = [...documentIssues, ...delivered.issues];
|
|
1097
1112
|
const routes = [...options.routes];
|
|
1098
1113
|
const documentSources = perspective === "published" ? documents.map((doc) => ({ draft: doc, published: doc, versions: [] })) : documents;
|
|
1099
1114
|
return createStaticContentSource({
|
|
@@ -1103,7 +1118,7 @@ function assembleLiveSource(payload, options, perspective) {
|
|
|
1103
1118
|
// Redirects are editorial DATA (EC-303): the ENABLED ones ship in the
|
|
1104
1119
|
// snapshot, so they change dynamically (no redeploy). Native next.config
|
|
1105
1120
|
// redirects run before this.
|
|
1106
|
-
redirects:
|
|
1121
|
+
redirects: delivered.redirects,
|
|
1107
1122
|
collections: [...options.collections],
|
|
1108
1123
|
documents: documentSources,
|
|
1109
1124
|
assets: payload.assets,
|
|
@@ -1159,7 +1174,7 @@ function resolveGlobals(source, options = {}) {
|
|
|
1159
1174
|
const navigationCollection = conventions.navigationCollection ?? "navigation";
|
|
1160
1175
|
const itemsFields = conventions.navigationItemsFields ?? DEFAULT_ITEMS_FIELDS;
|
|
1161
1176
|
const client = source.client({ perspective, ...options.locale ? { locale: options.locale } : {} });
|
|
1162
|
-
const assets = source.assets?.() ?? [];
|
|
1177
|
+
const assets = source.assets?.(options.locale) ?? [];
|
|
1163
1178
|
const assetById = new Map(assets.map((asset) => [asset.id, asset]));
|
|
1164
1179
|
const listDocs = (collection) => {
|
|
1165
1180
|
const result = client.listDocuments(collection);
|