fimo 2.1.0 → 2.2.0-staging.10
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/README.md +3 -2
- package/assets/agent-templates/_default/config.yaml +1 -0
- package/assets/agent-templates/broken-link-sweeper/config.yaml +1 -0
- package/assets/agent-templates/content-translator/config.yaml +1 -0
- package/assets/agent-templates/content-translator/scripts/translate-entries.ts +1 -1
- package/assets/agent-templates/post-deploy-check/config.yaml +1 -0
- package/assets/agent-templates/post-deploy-check/scripts/check-logs.ts +1 -1
- package/assets/agent-templates/seo-audit/config.yaml +1 -0
- package/assets/agent-templates/seo-audit/scripts/list-routes.ts +3 -3
- package/assets/skills/fimo-cli/SKILL.md +5 -5
- package/assets/skills/fimo-cli/references/agents.md +2 -1
- package/assets/skills/fimo-cli/references/assets.md +4 -1
- package/assets/skills/fimo-cli/references/branches.md +1 -1
- package/assets/skills/fimo-cli/references/content.md +3 -3
- package/assets/skills/fimo-cli/references/deploy.md +2 -2
- package/assets/skills/fimo-cli/references/forms.md +3 -1
- package/assets/skills/fimo-cli/references/history.md +1 -0
- package/assets/skills/fimo-cli/references/init.md +30 -39
- package/assets/skills/fimo-cli/references/preview.md +5 -3
- package/assets/skills/fimo-cli/references/schedules.md +4 -2
- package/assets/skills/fimo-cli/references/webhooks.md +2 -0
- package/assets/skills/fimo-code/references/frameworks/next.md +4 -1
- package/assets/skills/fimo-code/references/frameworks/react-router.md +4 -3
- package/assets/skills/fimo-migration/SKILL.md +3 -3
- package/assets/skills/fimo-studio/references/preview-and-responsive.md +4 -1
- package/assets/skills/fimo-studio/references/visual-editing.md +9 -1
- package/dist/build/astro/config.js +2 -1
- package/dist/build/vite/plugins/preview-health.d.ts +4 -0
- package/dist/build/vite/plugins/preview-health.js +40 -0
- package/dist/cli/bundle.json +1 -1
- package/dist/cli/index.js +136 -137
- package/dist/runtime/astro/server-runtime.js +7 -3
- package/dist/runtime/content/client/collection-core.js +3 -2
- package/dist/runtime/content/client/core-types.d.ts +4 -3
- package/dist/runtime/content/client/internal.d.ts +2 -0
- package/dist/runtime/content/client/internal.js +54 -25
- package/dist/runtime/content/client/singleton-core.js +2 -1
- package/dist/runtime/content/index.d.ts +1 -1
- package/dist/runtime/content/index.js +1 -1
- package/dist/runtime/paths/get-fimo-paths.js +7 -3
- package/dist/runtime/primitives/lib/index.d.ts +1 -1
- package/dist/runtime/primitives/lib/index.js +1 -1
- package/dist/runtime/primitives/lib/primitives.d.ts +24 -5
- package/dist/runtime/primitives/lib/primitives.js +69 -16
- package/dist/runtime/primitives/lib/template.js +2 -2
- package/dist/runtime/shared/branch-identity.d.ts +56 -0
- package/dist/runtime/shared/{env-identity.js → branch-identity.js} +40 -27
- package/dist/runtime/shared/local-runtime-env.d.ts +2 -2
- package/dist/runtime/shared/local-runtime-env.js +12 -10
- package/dist/runtime/templates.d.ts +8 -2
- package/dist/runtime/templates.js +34 -8
- package/package.json +13 -9
- package/release.json +2 -2
- package/templates/astro/package.json +2 -2
- package/templates/nextjs/AGENTS.md +1 -1
- package/templates/nextjs/package.json +4 -4
- package/templates/react-router/.fimo/config.json +1 -2
- package/templates/react-router/AGENTS.md +1 -1
- package/templates/react-router/package.json +4 -4
- package/templates/sveltekit/package.json +2 -2
- package/templates/vite/package.json +4 -4
- package/assets/starters/fimo-site/manifest.json +0 -64
- package/assets/starters/fimo-site/template/.fimo/agents/content-guide/GOAL.md +0 -8
- package/assets/starters/fimo-site/template/.fimo/agents/content-guide/capabilities.yaml +0 -1
- package/assets/starters/fimo-site/template/.fimo/agents/content-guide/config.yaml +0 -9
- package/assets/starters/fimo-site/template/.fimo/agents/site-review/GOAL.md +0 -14
- package/assets/starters/fimo-site/template/.fimo/agents/site-review/capabilities.yaml +0 -3
- package/assets/starters/fimo-site/template/.fimo/agents/site-review/config.yaml +0 -9
- package/assets/starters/fimo-site/template/src/forms/contact.json +0 -14
- package/assets/starters/fimo-site/template/src/forms/contact.ts +0 -46
- package/assets/starters/fimo-site/template/src/pages/Contact.tsx +0 -193
- package/assets/starters/fimo-site/template/src/pages/Index.tsx +0 -27
- package/assets/starters/fimo-site/template/src/pages/SiteContent.tsx +0 -191
- package/assets/starters/fimo-site/template/src/schemas/HomePage.json +0 -28
- package/assets/starters/fimo-site/template/src/schemas/HomePage.ts +0 -29
- package/assets/starters/fimo-site/template/src/schemas/HomePage.types.ts +0 -64
- package/dist/runtime/shared/env-identity.d.ts +0 -43
|
@@ -8,9 +8,13 @@ export const astroServerContentRuntime = {
|
|
|
8
8
|
},
|
|
9
9
|
headers(extra) {
|
|
10
10
|
const headers = { ...extra };
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
// `FIMO_ENV` is the variable name a customer's deployed build reads and
|
|
12
|
+
// keeps its spelling; only the header this build emits is canonical
|
|
13
|
+
// (branch-cutover ledger, F5). Builds already in production keep sending
|
|
14
|
+
// `X-Fimo-Env`, which the API still accepts.
|
|
15
|
+
const branch = import.meta.env.FIMO_ENV?.trim();
|
|
16
|
+
if (branch) {
|
|
17
|
+
headers['X-Fimo-Branch'] = branch;
|
|
14
18
|
}
|
|
15
19
|
return headers;
|
|
16
20
|
},
|
|
@@ -11,11 +11,12 @@ export function createCollectionContentCore(config, runtime) {
|
|
|
11
11
|
const meta = { uid: info.uid, pascal: info.pascal, localized: info.localized };
|
|
12
12
|
const self = { wrapWithSource, meta };
|
|
13
13
|
const resolve = (uid) => uid === info.uid ? self : resolveClientHandle(references[uid]);
|
|
14
|
-
function wrapWithSource(entry) {
|
|
14
|
+
function wrapWithSource(entry, context) {
|
|
15
15
|
return wrapEntry(info, entry, {
|
|
16
16
|
alwaysIncludeLocale: true,
|
|
17
17
|
defaultLocale: requestDefaultLocale ?? 'en',
|
|
18
18
|
resolve,
|
|
19
|
+
context,
|
|
19
20
|
});
|
|
20
21
|
}
|
|
21
22
|
function readPath(url, options) {
|
|
@@ -88,7 +89,7 @@ export function createCollectionContentCore(config, runtime) {
|
|
|
88
89
|
throw new Error(await response.text());
|
|
89
90
|
}
|
|
90
91
|
const body = parseCollectionResponse(await response.json());
|
|
91
|
-
const items = body.data.map(wrapWithSource);
|
|
92
|
+
const items = body.data.map((entry) => wrapWithSource(entry));
|
|
92
93
|
const pageInfo = {
|
|
93
94
|
limit: body.meta.limit,
|
|
94
95
|
offset: body.meta.offset,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { FimoSourceContext } from '../../primitives/lib/primitives.js';
|
|
1
2
|
import type { Fields, Populate, PopulatedResult, ProjectedWithPopulate, Query } from '../../primitives/lib/query.js';
|
|
2
3
|
export type ContentResult<T extends {
|
|
3
4
|
id: string;
|
|
@@ -43,7 +44,7 @@ export interface ContentModuleMeta {
|
|
|
43
44
|
readonly localized: boolean;
|
|
44
45
|
}
|
|
45
46
|
export interface ContentClientHandle {
|
|
46
|
-
wrapWithSource: (entry: Record<string, any
|
|
47
|
+
wrapWithSource: (entry: Record<string, any>, context?: FimoSourceContext) => unknown;
|
|
47
48
|
meta: ContentModuleMeta;
|
|
48
49
|
}
|
|
49
50
|
export type ContentModuleRef = ContentClientHandle | {
|
|
@@ -73,7 +74,7 @@ export interface CollectionContentCore<T extends {
|
|
|
73
74
|
id: string;
|
|
74
75
|
}, TInput extends object> {
|
|
75
76
|
readonly meta: ContentModuleMeta;
|
|
76
|
-
wrapWithSource(entry: Record<string, any
|
|
77
|
+
wrapWithSource(entry: Record<string, any>, context?: FimoSourceContext): T;
|
|
77
78
|
getById<TPopulate extends Populate<T> | undefined = undefined>(id: string, options?: ContentReadOptions<TPopulate>): Promise<ContentResult<T, undefined, TPopulate>>;
|
|
78
79
|
getBySlug<TPopulate extends Populate<T> | undefined = undefined>(slug: string, options?: ContentReadOptions<TPopulate>): Promise<ContentResult<T, undefined, TPopulate> | null>;
|
|
79
80
|
getByField<TPopulate extends Populate<T> | undefined = undefined>(fieldName: string, value: string, options?: ContentReadOptions<TPopulate>): Promise<ContentResult<T, undefined, TPopulate> | null>;
|
|
@@ -89,7 +90,7 @@ export interface SingletonContentCore<T extends {
|
|
|
89
90
|
id: string;
|
|
90
91
|
}, TInput extends object> {
|
|
91
92
|
readonly meta: ContentModuleMeta;
|
|
92
|
-
wrapWithSource(entry: Record<string, any
|
|
93
|
+
wrapWithSource(entry: Record<string, any>, context?: FimoSourceContext): T;
|
|
93
94
|
get<TPopulate extends Populate<T> | undefined = undefined>(options?: ContentReadOptions<TPopulate>): Promise<ContentResult<T, undefined, TPopulate>>;
|
|
94
95
|
update(payload: Partial<TInput>): Promise<T>;
|
|
95
96
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type FimoSourceContext } from '../../primitives/lib/primitives.js';
|
|
1
2
|
import type { ContentClientHandle, ContentModuleRef, ContentSchema, ContentSchemaField } from './core-types.js';
|
|
2
3
|
export interface InterpretedSchema {
|
|
3
4
|
uid: string;
|
|
@@ -37,6 +38,7 @@ export declare function wrapEntry(info: InterpretedSchema, entry: Record<string,
|
|
|
37
38
|
alwaysIncludeLocale: boolean;
|
|
38
39
|
defaultLocale: string;
|
|
39
40
|
resolve: ReferenceResolver;
|
|
41
|
+
context?: FimoSourceContext;
|
|
40
42
|
}): Record<string, unknown>;
|
|
41
43
|
export {};
|
|
42
44
|
//# sourceMappingURL=internal.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { pascalCase } from 'change-case';
|
|
2
|
-
import { FIMO_SOURCE, FimoBoolean, FimoMedia, FimoRichText, FimoString } from '../../primitives/lib/primitives.js';
|
|
2
|
+
import { FIMO_SOURCE, FIMO_SOURCE_CONTEXT, FimoBoolean, FimoMedia, FimoRichText, FimoString, } from '../../primitives/lib/primitives.js';
|
|
3
3
|
export function interpretSchema(schema) {
|
|
4
4
|
if (!schema || typeof schema.uid !== 'string' || schema.uid.length === 0) {
|
|
5
5
|
throw new Error('Content schema is missing a "uid".');
|
|
@@ -94,6 +94,19 @@ function isPopulatedEntry(value) {
|
|
|
94
94
|
typeof fimo === 'object' &&
|
|
95
95
|
typeof fimo.contentType === 'string');
|
|
96
96
|
}
|
|
97
|
+
function appendSourceContext(context, item) {
|
|
98
|
+
return [...(context ?? []), item];
|
|
99
|
+
}
|
|
100
|
+
function tagWithSourceContext(value, context) {
|
|
101
|
+
if (context && context.length > 0) {
|
|
102
|
+
Object.defineProperty(value, FIMO_SOURCE_CONTEXT, {
|
|
103
|
+
value: Object.freeze([...context]),
|
|
104
|
+
enumerable: false,
|
|
105
|
+
configurable: true,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
return value;
|
|
109
|
+
}
|
|
97
110
|
function asClientHandle(candidate) {
|
|
98
111
|
if (candidate == null || typeof candidate !== 'object') {
|
|
99
112
|
return undefined;
|
|
@@ -133,7 +146,7 @@ function unresolvableReference(uid) {
|
|
|
133
146
|
* union narrows in a switch. Raw (unpopulated) values and types outside the
|
|
134
147
|
* field's declared targets pass through untouched.
|
|
135
148
|
*/
|
|
136
|
-
function wrapPolymorphic(value, targetUids, resolve) {
|
|
149
|
+
function wrapPolymorphic(value, targetUids, source, resolve, context) {
|
|
137
150
|
if (!isPopulatedEntry(value)) {
|
|
138
151
|
return value;
|
|
139
152
|
}
|
|
@@ -145,11 +158,11 @@ function wrapPolymorphic(value, targetUids, resolve) {
|
|
|
145
158
|
if (!target) {
|
|
146
159
|
throw unresolvableReference(contentType);
|
|
147
160
|
}
|
|
148
|
-
const wrapped = target.wrapWithSource(value);
|
|
161
|
+
const wrapped = target.wrapWithSource(value, appendSourceContext(context, { kind: 'relation', source }));
|
|
149
162
|
wrapped.$type = contentType;
|
|
150
|
-
return wrapped;
|
|
163
|
+
return tagWithSource(wrapped, source, context);
|
|
151
164
|
}
|
|
152
|
-
function wrapReference(value, uid, resolve) {
|
|
165
|
+
function wrapReference(value, uid, source, resolve, context) {
|
|
153
166
|
if (!isPopulatedEntry(value)) {
|
|
154
167
|
return value;
|
|
155
168
|
}
|
|
@@ -157,7 +170,7 @@ function wrapReference(value, uid, resolve) {
|
|
|
157
170
|
if (!target) {
|
|
158
171
|
throw unresolvableReference(uid);
|
|
159
172
|
}
|
|
160
|
-
return target.wrapWithSource(value);
|
|
173
|
+
return tagWithSource(target.wrapWithSource(value, appendSourceContext(context, { kind: 'relation', source })), source, context);
|
|
161
174
|
}
|
|
162
175
|
/**
|
|
163
176
|
* Blocks values have no wrapper class of their own — the array structure stays
|
|
@@ -174,7 +187,7 @@ function blockItemFields(field, item) {
|
|
|
174
187
|
}
|
|
175
188
|
return schema.fields;
|
|
176
189
|
}
|
|
177
|
-
function wrapBlockItem(field, item,
|
|
190
|
+
function wrapBlockItem(field, item, listSource, itemSource, resolve, context) {
|
|
178
191
|
if (item == null || typeof item !== 'object' || Array.isArray(item)) {
|
|
179
192
|
return item;
|
|
180
193
|
}
|
|
@@ -183,61 +196,77 @@ function wrapBlockItem(field, item, source, resolve) {
|
|
|
183
196
|
if (!fields) {
|
|
184
197
|
return item;
|
|
185
198
|
}
|
|
199
|
+
const itemContext = typeof record._key === 'string' && record._key.length > 0
|
|
200
|
+
? appendSourceContext(context, {
|
|
201
|
+
kind: 'component',
|
|
202
|
+
source: listSource,
|
|
203
|
+
_key: record._key,
|
|
204
|
+
...(typeof record._type === 'string' && record._type.length > 0 ? { _type: record._type } : {}),
|
|
205
|
+
})
|
|
206
|
+
: context;
|
|
186
207
|
const wrapped = { ...record };
|
|
187
208
|
for (const [key, childField] of Object.entries(fields)) {
|
|
188
|
-
wrapped[key] = wrapField(childField, record[key], `${
|
|
209
|
+
wrapped[key] = wrapField(childField, record[key], `${itemSource}.${key}`, resolve, itemContext);
|
|
189
210
|
}
|
|
190
211
|
return wrapped;
|
|
191
212
|
}
|
|
192
213
|
/**
|
|
193
214
|
* A JSON field's declared shape is a plain object/array — tagging it in place
|
|
194
215
|
* (rather than boxing it, like the scalar wrappers below) keeps that shape
|
|
195
|
-
* intact so consumers that read it as ordinary JSON see no difference.
|
|
216
|
+
* intact so consumers that read it as ordinary JSON see no difference. A
|
|
217
|
+
* populated reference is tagged the same way, with the source of the field
|
|
218
|
+
* that HOLDS it (`Post.id:p1:en.author`), so the toolbar can select and
|
|
219
|
+
* repoint the reference itself; the target's own fields keep the sources the
|
|
220
|
+
* target client gave them.
|
|
196
221
|
*/
|
|
197
|
-
function tagWithSource(value, source) {
|
|
222
|
+
function tagWithSource(value, source, context) {
|
|
198
223
|
Object.defineProperty(value, FIMO_SOURCE, { value: source, enumerable: false, configurable: true });
|
|
199
|
-
return value;
|
|
224
|
+
return tagWithSourceContext(value, context);
|
|
200
225
|
}
|
|
201
|
-
function wrapField(field, value, source, resolve) {
|
|
226
|
+
function wrapField(field, value, source, resolve, context) {
|
|
202
227
|
switch (field.type) {
|
|
203
228
|
case 'string':
|
|
204
229
|
case 'text':
|
|
205
230
|
case 'date':
|
|
206
231
|
case 'datetime':
|
|
207
|
-
return value != null ? new FimoString(String(value), source) : value;
|
|
232
|
+
return value != null ? new FimoString(String(value), source, context) : value;
|
|
208
233
|
case 'richtext':
|
|
209
|
-
return value != null ? new FimoRichText(value, source) : value;
|
|
234
|
+
return value != null ? new FimoRichText(value, source, context) : value;
|
|
210
235
|
case 'boolean':
|
|
211
|
-
return value != null ? new FimoBoolean(value, source) : value;
|
|
236
|
+
return value != null ? new FimoBoolean(value, source, context) : value;
|
|
212
237
|
case 'json':
|
|
213
238
|
return value != null && typeof value === 'object'
|
|
214
|
-
? tagWithSource(Array.isArray(value) ? [...value] : { ...value }, source)
|
|
239
|
+
? tagWithSource(Array.isArray(value) ? [...value] : { ...value }, source, context)
|
|
215
240
|
: value;
|
|
216
241
|
case 'media':
|
|
217
242
|
if (field.multiple) {
|
|
218
|
-
return (value?.map((m, i) => new FimoMedia(m, `${source}[${i}]
|
|
243
|
+
return (value?.map((m, i) => new FimoMedia(m, `${source}[${i}]`, context)) ?? value);
|
|
219
244
|
}
|
|
220
|
-
return value != null ? new FimoMedia(value, source) : value;
|
|
245
|
+
return value != null ? new FimoMedia(value, source, context) : value;
|
|
221
246
|
case 'reference': {
|
|
222
247
|
const polymorphic = polymorphicTargetUids(field);
|
|
223
248
|
if (polymorphic) {
|
|
224
249
|
if (field.many) {
|
|
225
|
-
return Array.isArray(value)
|
|
250
|
+
return Array.isArray(value)
|
|
251
|
+
? value.map((item, i) => wrapPolymorphic(item, polymorphic, `${source}[${i}]`, resolve, context))
|
|
252
|
+
: value;
|
|
226
253
|
}
|
|
227
|
-
return wrapPolymorphic(value, polymorphic, resolve);
|
|
254
|
+
return wrapPolymorphic(value, polymorphic, source, resolve, context);
|
|
228
255
|
}
|
|
229
256
|
const uid = field.target;
|
|
230
257
|
if (!uid) {
|
|
231
258
|
return value;
|
|
232
259
|
}
|
|
233
260
|
if (field.many) {
|
|
234
|
-
return Array.isArray(value)
|
|
261
|
+
return Array.isArray(value)
|
|
262
|
+
? value.map((item, i) => wrapReference(item, uid, `${source}[${i}]`, resolve, context))
|
|
263
|
+
: value;
|
|
235
264
|
}
|
|
236
|
-
return wrapReference(value, uid, resolve);
|
|
265
|
+
return wrapReference(value, uid, source, resolve, context);
|
|
237
266
|
}
|
|
238
267
|
case 'blocks':
|
|
239
268
|
return Array.isArray(value)
|
|
240
|
-
? value.map((item, i) => wrapBlockItem(field, item, `${source}[${i}]`, resolve))
|
|
269
|
+
? value.map((item, i) => wrapBlockItem(field, item, source, `${source}[${i}]`, resolve, context))
|
|
241
270
|
: value;
|
|
242
271
|
// 'number' deliberately falls through here — this is a decision, not a
|
|
243
272
|
// gap. React renders a boxed String directly (`<span>{new FimoString(...)}
|
|
@@ -267,7 +296,7 @@ export function wrapEntry(info, entry, options) {
|
|
|
267
296
|
id,
|
|
268
297
|
entryId,
|
|
269
298
|
documentId,
|
|
270
|
-
slug: entry.slug != null ? new FimoString(entry.slug, `${sourcePrefix}.slug
|
|
299
|
+
slug: entry.slug != null ? new FimoString(entry.slug, `${sourcePrefix}.slug`, options.context) : entry.slug,
|
|
271
300
|
...(options.alwaysIncludeLocale || entry.locale ? { locale } : {}),
|
|
272
301
|
createdAt: entry.createdAt,
|
|
273
302
|
updatedAt: entry.updatedAt,
|
|
@@ -276,7 +305,7 @@ export function wrapEntry(info, entry, options) {
|
|
|
276
305
|
},
|
|
277
306
|
};
|
|
278
307
|
for (const [key, field] of info.fields) {
|
|
279
|
-
wrapped[key] = wrapField(field, entry[key], `${sourcePrefix}.${key}`, options.resolve);
|
|
308
|
+
wrapped[key] = wrapField(field, entry[key], `${sourcePrefix}.${key}`, options.resolve, options.context);
|
|
280
309
|
}
|
|
281
310
|
return wrapped;
|
|
282
311
|
}
|
|
@@ -28,11 +28,12 @@ export function createSingletonContentCore(config, runtime) {
|
|
|
28
28
|
localizedReferenceFields = fields;
|
|
29
29
|
return fields;
|
|
30
30
|
}
|
|
31
|
-
function wrapWithSource(entry) {
|
|
31
|
+
function wrapWithSource(entry, context) {
|
|
32
32
|
return wrapEntry(info, entry, {
|
|
33
33
|
alwaysIncludeLocale: info.localized,
|
|
34
34
|
defaultLocale: requestDefaultLocale ?? 'en',
|
|
35
35
|
resolve,
|
|
36
|
+
context,
|
|
36
37
|
});
|
|
37
38
|
}
|
|
38
39
|
function localize(options, fallbackLocale = requestDefaultLocale) {
|
|
@@ -16,6 +16,6 @@ export type { SingletonContentCore } from './client/singleton-core.js';
|
|
|
16
16
|
export { serializeContent, type SerializedContent, type SerializedMedia } from './serialization.js';
|
|
17
17
|
export { parseCollectionResponse, type CollectionResponse } from './parseCollectionResponse.js';
|
|
18
18
|
export type { CollectionPage, CollectionPageInfo, ContentClientConfig, ContentClientHandle, ContentModuleMeta, ContentModuleRef, ContentReadOptions, ContentResult, ContentSchema, ContentSchemaField, } from './client/core-types.js';
|
|
19
|
-
export { FIMO_PARTS, FIMO_SOURCE, FimoBoolean, FimoDate, FimoMedia, FimoRichText, FimoString, getFimoParts, getFimoSource, hasFimoSource, isFimoDate, isFimoString, type FimoPart, type FimoPolymorphicReference, type FimoReference, type FimoRichTextContent, type FimoSource, } from '../primitives/lib/primitives.js';
|
|
19
|
+
export { FIMO_PARTS, FIMO_SOURCE, FIMO_SOURCE_CONTEXT, FimoBoolean, FimoDate, FimoMedia, FimoRichText, FimoString, getFimoParts, getFimoSource, getFimoSourceContext, hasFimoSource, isFimoDate, isFimoString, type FimoPart, type FimoPolymorphicReference, type FimoReference, type FimoRichTextContent, type FimoSourceContext, type FimoSourceContextItem, type FimoSource, } from '../primitives/lib/primitives.js';
|
|
20
20
|
export type { BoolOps, DateOps, Field, Fields, FilterFor, NullOnlyOps, NumberOps, Populate, Populated, PopulatedResult, Projected, ProjectedWithPopulate, Query, ReferenceField, ReferenceMap, ScalarOps, Sort, SortField, StringOps, Where, WithReferences, } from '../primitives/lib/query.js';
|
|
21
21
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -13,4 +13,4 @@ export { readCollectionLocale, splitWritePayload, withMutationLocale } from './c
|
|
|
13
13
|
export { requireContentApiUrl } from './client/runtime.js';
|
|
14
14
|
export { serializeContent } from './serialization.js';
|
|
15
15
|
export { parseCollectionResponse } from './parseCollectionResponse.js';
|
|
16
|
-
export { FIMO_PARTS, FIMO_SOURCE, FimoBoolean, FimoDate, FimoMedia, FimoRichText, FimoString, getFimoParts, getFimoSource, hasFimoSource, isFimoDate, isFimoString, } from '../primitives/lib/primitives.js';
|
|
16
|
+
export { FIMO_PARTS, FIMO_SOURCE, FIMO_SOURCE_CONTEXT, FimoBoolean, FimoDate, FimoMedia, FimoRichText, FimoString, getFimoParts, getFimoSource, getFimoSourceContext, hasFimoSource, isFimoDate, isFimoString, } from '../primitives/lib/primitives.js';
|
|
@@ -46,9 +46,13 @@ async function fetchEntries(baseUrl, schema, rootDir, locale) {
|
|
|
46
46
|
url.searchParams.set('limit', '1');
|
|
47
47
|
}
|
|
48
48
|
const headers = {};
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
// `FIMO_ENV` is a customer-facing variable name and keeps its spelling; the
|
|
50
|
+
// header this build emits is canonical (branch-cutover ledger, F5). A
|
|
51
|
+
// deployed site always talks to the current API, and builds produced by an
|
|
52
|
+
// older `fimo` keep sending `X-Fimo-Env`, which the API still accepts.
|
|
53
|
+
const branch = readEnvValue(rootDir, 'FIMO_ENV') ?? resolveLocalRuntimeEnv({ cwd: rootDir })?.env;
|
|
54
|
+
if (branch) {
|
|
55
|
+
headers['X-Fimo-Branch'] = branch;
|
|
52
56
|
}
|
|
53
57
|
for (let attempt = 1; attempt <= MAX_FETCH_ATTEMPTS; attempt += 1) {
|
|
54
58
|
const res = await fetch(url, { headers });
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { FimoString, FimoDate, FimoMedia, FimoBoolean, FimoRichText, type FimoPolymorphicReference, type FimoReference, type FimoSource, type FimoPart, type FimoRichTextContent, FIMO_SOURCE, FIMO_PARTS, isFimoString, isFimoDate, hasFimoSource, getFimoSource, getFimoParts, } from './primitives.js';
|
|
1
|
+
export { FimoString, FimoDate, FimoMedia, FimoBoolean, FimoRichText, type FimoPolymorphicReference, type FimoReference, type FimoSource, type FimoPart, type FimoRichTextContent, type FimoSourceContext, type FimoSourceContextItem, FIMO_SOURCE, FIMO_SOURCE_CONTEXT, FIMO_PARTS, isFimoString, isFimoDate, hasFimoSource, getFimoSource, getFimoSourceContext, getFimoParts, } from './primitives.js';
|
|
2
2
|
export { fimo } from './template.js';
|
|
3
3
|
export { renderRichTextHtml, renderRichTextHtml as renderRichText } from './render-rich-text.js';
|
|
4
4
|
export { parseImageHostSuffixes, resolveImagePresentation, type ImageFit, type ImageObjectFit, type ImagePresentation, type ImagePresentationOptions, } from './image-optimization.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Fimo - Source tracking for inline editing
|
|
2
|
-
export { FimoString, FimoDate, FimoMedia, FimoBoolean, FimoRichText, FIMO_SOURCE, FIMO_PARTS, isFimoString, isFimoDate, hasFimoSource, getFimoSource, getFimoParts, } from './primitives.js';
|
|
2
|
+
export { FimoString, FimoDate, FimoMedia, FimoBoolean, FimoRichText, FIMO_SOURCE, FIMO_SOURCE_CONTEXT, FIMO_PARTS, isFimoString, isFimoDate, hasFimoSource, getFimoSource, getFimoSourceContext, getFimoParts, } from './primitives.js';
|
|
3
3
|
export { fimo } from './template.js';
|
|
4
4
|
export { renderRichTextHtml, renderRichTextHtml as renderRichText } from './render-rich-text.js';
|
|
5
5
|
export { parseImageHostSuffixes, resolveImagePresentation, } from './image-optimization.js';
|
|
@@ -16,13 +16,25 @@ export interface FimoPolymorphicReference {
|
|
|
16
16
|
id: string;
|
|
17
17
|
}
|
|
18
18
|
export declare const FIMO_SOURCE: unique symbol;
|
|
19
|
+
export declare const FIMO_SOURCE_CONTEXT: unique symbol;
|
|
19
20
|
export declare const FIMO_PARTS: unique symbol;
|
|
21
|
+
export type FimoSourceContextItem = {
|
|
22
|
+
kind: 'relation';
|
|
23
|
+
source: string;
|
|
24
|
+
} | {
|
|
25
|
+
kind: 'component';
|
|
26
|
+
source: string;
|
|
27
|
+
_key: string;
|
|
28
|
+
_type?: string;
|
|
29
|
+
};
|
|
30
|
+
export type FimoSourceContext = readonly FimoSourceContextItem[];
|
|
20
31
|
/**
|
|
21
32
|
* A piece of a composed FimoString — maps text to its source
|
|
22
33
|
*/
|
|
23
34
|
export type FimoPart = {
|
|
24
35
|
text: string;
|
|
25
36
|
source?: string;
|
|
37
|
+
context?: FimoSourceContext;
|
|
26
38
|
};
|
|
27
39
|
/**
|
|
28
40
|
* FimoString - A string with source tracking
|
|
@@ -32,8 +44,9 @@ export type FimoPart = {
|
|
|
32
44
|
*/
|
|
33
45
|
export declare class FimoString extends String {
|
|
34
46
|
readonly [FIMO_SOURCE]: string | null;
|
|
47
|
+
readonly [FIMO_SOURCE_CONTEXT]?: FimoSourceContext;
|
|
35
48
|
readonly [FIMO_PARTS]?: FimoPart[];
|
|
36
|
-
constructor(value: string, source: string | null);
|
|
49
|
+
constructor(value: string, source: string | null, context?: FimoSourceContext);
|
|
37
50
|
/**
|
|
38
51
|
* Compose multiple tracked values into one FimoString.
|
|
39
52
|
* Parts carry individual sources; the main FIMO_SOURCE is null.
|
|
@@ -50,7 +63,8 @@ export declare class FimoString extends String {
|
|
|
50
63
|
*/
|
|
51
64
|
export declare class FimoDate extends Date {
|
|
52
65
|
readonly [FIMO_SOURCE]: string;
|
|
53
|
-
|
|
66
|
+
readonly [FIMO_SOURCE_CONTEXT]?: FimoSourceContext;
|
|
67
|
+
constructor(value: Date | string | number, source: string, context?: FimoSourceContext);
|
|
54
68
|
get __fimo(): FimoSource;
|
|
55
69
|
}
|
|
56
70
|
/**
|
|
@@ -64,6 +78,7 @@ export declare class FimoMedia {
|
|
|
64
78
|
readonly width?: number;
|
|
65
79
|
readonly height?: number;
|
|
66
80
|
readonly [FIMO_SOURCE]: string;
|
|
81
|
+
readonly [FIMO_SOURCE_CONTEXT]?: FimoSourceContext;
|
|
67
82
|
constructor(data: {
|
|
68
83
|
url: string;
|
|
69
84
|
alt: string;
|
|
@@ -71,7 +86,7 @@ export declare class FimoMedia {
|
|
|
71
86
|
mime: string;
|
|
72
87
|
width?: number;
|
|
73
88
|
height?: number;
|
|
74
|
-
}, source: string);
|
|
89
|
+
}, source: string, context?: FimoSourceContext);
|
|
75
90
|
get __fimo(): FimoSource;
|
|
76
91
|
}
|
|
77
92
|
/**
|
|
@@ -80,7 +95,8 @@ export declare class FimoMedia {
|
|
|
80
95
|
export declare class FimoBoolean {
|
|
81
96
|
readonly value: boolean;
|
|
82
97
|
readonly [FIMO_SOURCE]: string;
|
|
83
|
-
|
|
98
|
+
readonly [FIMO_SOURCE_CONTEXT]?: FimoSourceContext;
|
|
99
|
+
constructor(value: boolean, source: string, context?: FimoSourceContext);
|
|
84
100
|
get __fimo(): FimoSource;
|
|
85
101
|
valueOf(): boolean;
|
|
86
102
|
}
|
|
@@ -105,7 +121,8 @@ export interface FimoRichTextContent {
|
|
|
105
121
|
export declare class FimoRichText {
|
|
106
122
|
readonly content: FimoRichTextContent;
|
|
107
123
|
readonly [FIMO_SOURCE]: string;
|
|
108
|
-
|
|
124
|
+
readonly [FIMO_SOURCE_CONTEXT]?: FimoSourceContext;
|
|
125
|
+
constructor(content: FimoRichTextContent, source: string, context?: FimoSourceContext);
|
|
109
126
|
get __fimo(): FimoSource;
|
|
110
127
|
}
|
|
111
128
|
/**
|
|
@@ -126,6 +143,8 @@ export declare function hasFimoSource(value: unknown): value is {
|
|
|
126
143
|
* Get the source from a fimo value, or undefined if not tracked
|
|
127
144
|
*/
|
|
128
145
|
export declare function getFimoSource(value: unknown): string | undefined;
|
|
146
|
+
/** Get the hidden relation/component ancestry from a wrapped value. */
|
|
147
|
+
export declare function getFimoSourceContext(value: unknown): FimoSourceContext | undefined;
|
|
129
148
|
/**
|
|
130
149
|
* Get the decomposed parts from a composed FimoString, or undefined
|
|
131
150
|
*/
|
|
@@ -4,10 +4,21 @@
|
|
|
4
4
|
* All Fimo types carry hidden metadata that enables the preview editor
|
|
5
5
|
* to know where content comes from (schema field, translation key, etc.)
|
|
6
6
|
*/
|
|
7
|
-
var _a, _b, _c, _d, _e, _f;
|
|
7
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
8
8
|
// Symbol for accessing fimo metadata (hidden from JSON.stringify)
|
|
9
9
|
export const FIMO_SOURCE = Symbol.for('fimo.source');
|
|
10
|
+
export const FIMO_SOURCE_CONTEXT = Symbol.for('fimo.sourceContext');
|
|
10
11
|
export const FIMO_PARTS = Symbol.for('fimo.parts');
|
|
12
|
+
function defineSourceContext(value, context) {
|
|
13
|
+
if (context && context.length > 0) {
|
|
14
|
+
Object.defineProperty(value, FIMO_SOURCE_CONTEXT, {
|
|
15
|
+
value: Object.freeze([...context]),
|
|
16
|
+
enumerable: false,
|
|
17
|
+
configurable: true,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
11
22
|
/**
|
|
12
23
|
* FimoString - A string with source tracking
|
|
13
24
|
*
|
|
@@ -15,7 +26,7 @@ export const FIMO_PARTS = Symbol.for('fimo.parts');
|
|
|
15
26
|
* but carries hidden metadata for inline editing.
|
|
16
27
|
*/
|
|
17
28
|
export class FimoString extends String {
|
|
18
|
-
constructor(value, source) {
|
|
29
|
+
constructor(value, source, context) {
|
|
19
30
|
super(value);
|
|
20
31
|
Object.defineProperty(this, _a, {
|
|
21
32
|
enumerable: true,
|
|
@@ -29,7 +40,14 @@ export class FimoString extends String {
|
|
|
29
40
|
writable: true,
|
|
30
41
|
value: void 0
|
|
31
42
|
});
|
|
43
|
+
Object.defineProperty(this, _c, {
|
|
44
|
+
enumerable: true,
|
|
45
|
+
configurable: true,
|
|
46
|
+
writable: true,
|
|
47
|
+
value: void 0
|
|
48
|
+
});
|
|
32
49
|
this[FIMO_SOURCE] = source;
|
|
50
|
+
defineSourceContext(this, context);
|
|
33
51
|
}
|
|
34
52
|
/**
|
|
35
53
|
* Compose multiple tracked values into one FimoString.
|
|
@@ -41,7 +59,7 @@ export class FimoString extends String {
|
|
|
41
59
|
const trackedParts = parts.filter((p) => p.source);
|
|
42
60
|
// Single tracked part with no static text — just return a normal FimoString
|
|
43
61
|
if (trackedParts.length === 1 && parts.length === 1) {
|
|
44
|
-
return new FimoString(text, trackedParts[0].source);
|
|
62
|
+
return new FimoString(text, trackedParts[0].source, trackedParts[0].context);
|
|
45
63
|
}
|
|
46
64
|
const instance = new FimoString(text, null);
|
|
47
65
|
instance[FIMO_PARTS] = parts;
|
|
@@ -54,31 +72,38 @@ export class FimoString extends String {
|
|
|
54
72
|
return { source: this[FIMO_SOURCE] ?? '' };
|
|
55
73
|
}
|
|
56
74
|
}
|
|
57
|
-
_a = FIMO_SOURCE, _b = FIMO_PARTS;
|
|
75
|
+
_a = FIMO_SOURCE, _b = FIMO_SOURCE_CONTEXT, _c = FIMO_PARTS;
|
|
58
76
|
/**
|
|
59
77
|
* FimoDate - A date with source tracking
|
|
60
78
|
*/
|
|
61
79
|
export class FimoDate extends Date {
|
|
62
|
-
constructor(value, source) {
|
|
80
|
+
constructor(value, source, context) {
|
|
63
81
|
super(value);
|
|
64
|
-
Object.defineProperty(this,
|
|
82
|
+
Object.defineProperty(this, _d, {
|
|
83
|
+
enumerable: true,
|
|
84
|
+
configurable: true,
|
|
85
|
+
writable: true,
|
|
86
|
+
value: void 0
|
|
87
|
+
});
|
|
88
|
+
Object.defineProperty(this, _e, {
|
|
65
89
|
enumerable: true,
|
|
66
90
|
configurable: true,
|
|
67
91
|
writable: true,
|
|
68
92
|
value: void 0
|
|
69
93
|
});
|
|
70
94
|
this[FIMO_SOURCE] = source;
|
|
95
|
+
defineSourceContext(this, context);
|
|
71
96
|
}
|
|
72
97
|
get __fimo() {
|
|
73
98
|
return { source: this[FIMO_SOURCE] };
|
|
74
99
|
}
|
|
75
100
|
}
|
|
76
|
-
|
|
101
|
+
_d = FIMO_SOURCE, _e = FIMO_SOURCE_CONTEXT;
|
|
77
102
|
/**
|
|
78
103
|
* FimoMedia - Media object with source tracking
|
|
79
104
|
*/
|
|
80
105
|
export class FimoMedia {
|
|
81
|
-
constructor(data, source) {
|
|
106
|
+
constructor(data, source, context) {
|
|
82
107
|
Object.defineProperty(this, "url", {
|
|
83
108
|
enumerable: true,
|
|
84
109
|
configurable: true,
|
|
@@ -115,7 +140,13 @@ export class FimoMedia {
|
|
|
115
140
|
writable: true,
|
|
116
141
|
value: void 0
|
|
117
142
|
});
|
|
118
|
-
Object.defineProperty(this,
|
|
143
|
+
Object.defineProperty(this, _f, {
|
|
144
|
+
enumerable: true,
|
|
145
|
+
configurable: true,
|
|
146
|
+
writable: true,
|
|
147
|
+
value: void 0
|
|
148
|
+
});
|
|
149
|
+
Object.defineProperty(this, _g, {
|
|
119
150
|
enumerable: true,
|
|
120
151
|
configurable: true,
|
|
121
152
|
writable: true,
|
|
@@ -128,24 +159,31 @@ export class FimoMedia {
|
|
|
128
159
|
this.width = data.width;
|
|
129
160
|
this.height = data.height;
|
|
130
161
|
this[FIMO_SOURCE] = source;
|
|
162
|
+
defineSourceContext(this, context);
|
|
131
163
|
}
|
|
132
164
|
get __fimo() {
|
|
133
165
|
return { source: this[FIMO_SOURCE] };
|
|
134
166
|
}
|
|
135
167
|
}
|
|
136
|
-
|
|
168
|
+
_f = FIMO_SOURCE, _g = FIMO_SOURCE_CONTEXT;
|
|
137
169
|
/**
|
|
138
170
|
* FimoBoolean - Boolean with source tracking (for display purposes)
|
|
139
171
|
*/
|
|
140
172
|
export class FimoBoolean {
|
|
141
|
-
constructor(value, source) {
|
|
173
|
+
constructor(value, source, context) {
|
|
142
174
|
Object.defineProperty(this, "value", {
|
|
143
175
|
enumerable: true,
|
|
144
176
|
configurable: true,
|
|
145
177
|
writable: true,
|
|
146
178
|
value: void 0
|
|
147
179
|
});
|
|
148
|
-
Object.defineProperty(this,
|
|
180
|
+
Object.defineProperty(this, _h, {
|
|
181
|
+
enumerable: true,
|
|
182
|
+
configurable: true,
|
|
183
|
+
writable: true,
|
|
184
|
+
value: void 0
|
|
185
|
+
});
|
|
186
|
+
Object.defineProperty(this, _j, {
|
|
149
187
|
enumerable: true,
|
|
150
188
|
configurable: true,
|
|
151
189
|
writable: true,
|
|
@@ -153,6 +191,7 @@ export class FimoBoolean {
|
|
|
153
191
|
});
|
|
154
192
|
this.value = value;
|
|
155
193
|
this[FIMO_SOURCE] = source;
|
|
194
|
+
defineSourceContext(this, context);
|
|
156
195
|
}
|
|
157
196
|
get __fimo() {
|
|
158
197
|
return { source: this[FIMO_SOURCE] };
|
|
@@ -161,21 +200,27 @@ export class FimoBoolean {
|
|
|
161
200
|
return this.value;
|
|
162
201
|
}
|
|
163
202
|
}
|
|
164
|
-
|
|
203
|
+
_h = FIMO_SOURCE, _j = FIMO_SOURCE_CONTEXT;
|
|
165
204
|
/**
|
|
166
205
|
* FimoRichText - Rich text content with source tracking
|
|
167
206
|
*
|
|
168
207
|
* Wraps Tiptap JSONContent for rich text fields with inline editing support.
|
|
169
208
|
*/
|
|
170
209
|
export class FimoRichText {
|
|
171
|
-
constructor(content, source) {
|
|
210
|
+
constructor(content, source, context) {
|
|
172
211
|
Object.defineProperty(this, "content", {
|
|
173
212
|
enumerable: true,
|
|
174
213
|
configurable: true,
|
|
175
214
|
writable: true,
|
|
176
215
|
value: void 0
|
|
177
216
|
});
|
|
178
|
-
Object.defineProperty(this,
|
|
217
|
+
Object.defineProperty(this, _k, {
|
|
218
|
+
enumerable: true,
|
|
219
|
+
configurable: true,
|
|
220
|
+
writable: true,
|
|
221
|
+
value: void 0
|
|
222
|
+
});
|
|
223
|
+
Object.defineProperty(this, _l, {
|
|
179
224
|
enumerable: true,
|
|
180
225
|
configurable: true,
|
|
181
226
|
writable: true,
|
|
@@ -183,12 +228,13 @@ export class FimoRichText {
|
|
|
183
228
|
});
|
|
184
229
|
this.content = content;
|
|
185
230
|
this[FIMO_SOURCE] = source;
|
|
231
|
+
defineSourceContext(this, context);
|
|
186
232
|
}
|
|
187
233
|
get __fimo() {
|
|
188
234
|
return { source: this[FIMO_SOURCE] };
|
|
189
235
|
}
|
|
190
236
|
}
|
|
191
|
-
|
|
237
|
+
_k = FIMO_SOURCE, _l = FIMO_SOURCE_CONTEXT;
|
|
192
238
|
/**
|
|
193
239
|
* Type guard to check if a value is a FimoString
|
|
194
240
|
*/
|
|
@@ -219,6 +265,13 @@ export function getFimoSource(value) {
|
|
|
219
265
|
}
|
|
220
266
|
return undefined;
|
|
221
267
|
}
|
|
268
|
+
/** Get the hidden relation/component ancestry from a wrapped value. */
|
|
269
|
+
export function getFimoSourceContext(value) {
|
|
270
|
+
if (value != null && typeof value === 'object' && FIMO_SOURCE_CONTEXT in value) {
|
|
271
|
+
return value[FIMO_SOURCE_CONTEXT];
|
|
272
|
+
}
|
|
273
|
+
return undefined;
|
|
274
|
+
}
|
|
222
275
|
/**
|
|
223
276
|
* Get the decomposed parts from a composed FimoString, or undefined
|
|
224
277
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FIMO_SOURCE, FimoString, hasFimoSource } from './primitives.js';
|
|
1
|
+
import { FIMO_SOURCE, getFimoSourceContext, FimoString, hasFimoSource } from './primitives.js';
|
|
2
2
|
/**
|
|
3
3
|
* Template literal helper for composing multiple Fimo values
|
|
4
4
|
*
|
|
@@ -19,7 +19,7 @@ export function fimo(strings, ...values) {
|
|
|
19
19
|
const value = values[i];
|
|
20
20
|
const text = String(value);
|
|
21
21
|
const source = hasFimoSource(value) ? value[FIMO_SOURCE] : undefined;
|
|
22
|
-
parts.push({ text, source: source ?? undefined });
|
|
22
|
+
parts.push({ text, source: source ?? undefined, context: getFimoSourceContext(value) });
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
return FimoString.compose(parts);
|