@elytracms/studio 0.0.101 → 0.0.102
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/convex/asset-meta-patch.test.ts +7 -27
- package/convex/assets.ts +6 -41
- package/convex/cms.ts +2 -29
- package/convex/delivery.ts +2 -2
- package/convex/record-functions.ts +15 -82
- package/convex/redirects.ts +11 -116
- package/convex/schema.ts +4 -23
- package/convex/triggers.ts +7 -14
- package/dist/components/ai/ai-chat-panel.js +8 -5
- package/dist/components/ai/ai-chat-panel.js.map +1 -1
- package/dist/components/ai/translate-skipped.js +1 -0
- package/dist/components/ai/translate-skipped.js.map +1 -1
- package/dist/components/assets/asset-detail.js +1 -2
- package/dist/components/assets/asset-detail.js.map +1 -1
- package/dist/components/assets/asset-metadata.d.ts +2 -9
- package/dist/components/assets/asset-metadata.js +3 -10
- package/dist/components/assets/asset-metadata.js.map +1 -1
- package/dist/components/assets/asset-search.js +1 -1
- package/dist/components/assets/asset-search.js.map +1 -1
- package/dist/components/assets/asset-selection.js +2 -2
- package/dist/components/assets/asset-selection.js.map +1 -1
- package/dist/components/assets/assets-collection-view-source.d.ts +2 -3
- package/dist/components/assets/assets-collection-view-source.js +2 -3
- package/dist/components/assets/assets-collection-view-source.js.map +1 -1
- package/dist/components/builder/__fixtures__/reuse-race.d.ts +30 -0
- package/dist/components/builder/__fixtures__/reuse-race.js +77 -0
- package/dist/components/builder/__fixtures__/reuse-race.js.map +1 -0
- package/dist/components/builder/composition-field-editor.js +3 -3
- package/dist/components/builder/composition-field-editor.js.map +1 -1
- package/dist/components/builder/reuse-context.d.ts +2 -1
- package/dist/components/builder/reuse-context.js +5 -20
- package/dist/components/builder/reuse-context.js.map +1 -1
- package/dist/components/builder/reuse.d.ts +18 -11
- package/dist/components/builder/reuse.js +12 -14
- package/dist/components/builder/reuse.js.map +1 -1
- package/dist/components/cms/asset-field.js +1 -3
- package/dist/components/cms/asset-field.js.map +1 -1
- package/dist/components/cms/cell.d.ts +2 -2
- package/dist/components/cms/cell.js +8 -18
- package/dist/components/cms/cell.js.map +1 -1
- package/dist/components/cms/detail-editor.js +2 -1
- package/dist/components/cms/detail-editor.js.map +1 -1
- package/dist/components/cms/field-control.js +13 -1
- package/dist/components/cms/field-control.js.map +1 -1
- package/dist/lib/ai/chat-context.d.ts +6 -2
- package/dist/lib/ai/chat-context.js +11 -5
- package/dist/lib/ai/chat-context.js.map +1 -1
- package/dist/lib/ai/knowledge.d.ts +9 -9
- package/dist/lib/ai/knowledge.js +22 -0
- package/dist/lib/ai/knowledge.js.map +1 -1
- package/dist/lib/ai/tools.d.ts +8 -1
- package/dist/lib/ai/tools.js +33 -15
- package/dist/lib/ai/tools.js.map +1 -1
- package/dist/lib/ai/translate-document.d.ts +8 -1
- package/dist/lib/ai/translate-document.js +20 -5
- package/dist/lib/ai/translate-document.js.map +1 -1
- package/dist/lib/ai/update-fields.js +5 -12
- package/dist/lib/ai/update-fields.js.map +1 -1
- package/dist/lib/ai/writer-form.d.ts +61 -0
- package/dist/lib/ai/writer-form.js +218 -27
- package/dist/lib/ai/writer-form.js.map +1 -1
- package/dist/lib/assets/upload.d.ts +1 -2
- package/dist/lib/assets/upload.js +1 -2
- package/dist/lib/assets/upload.js.map +1 -1
- package/dist/lib/engine-version.d.ts +1 -1
- package/dist/lib/engine-version.js +1 -1
- package/dist/lib/engine-version.js.map +1 -1
- package/dist/lib/i18n/messages.de.js +9 -1
- package/dist/lib/i18n/messages.de.js.map +1 -1
- package/dist/lib/i18n/messages.en.d.ts +7 -0
- package/dist/lib/i18n/messages.en.js +11 -1
- package/dist/lib/i18n/messages.en.js.map +1 -1
- package/dist/lib/operations/cms-persistence.d.ts +20 -10
- package/dist/lib/operations/cms-persistence.js +11 -3
- package/dist/lib/operations/cms-persistence.js.map +1 -1
- package/dist/lib/persistence/convex-adapter.js +7 -2
- package/dist/lib/persistence/convex-adapter.js.map +1 -1
- package/package.json +3 -3
- package/convex/asset-alt-migration.test.ts +0 -127
- package/convex/redirect-migration.test.ts +0 -205
- package/convex/version-kind-stamping.test.ts +0 -118
|
@@ -194,8 +194,7 @@ async function embeddedMetaOf(file, fields, locales) {
|
|
|
194
194
|
* - each `meta` key the new file brings is a per-key `metaPatch` (EC-634), applied to the
|
|
195
195
|
* bag as STORED inside the write — never a copy read before the upload, so an editor's
|
|
196
196
|
* metadata save that lands while the bytes travel is kept. Sent only when the file
|
|
197
|
-
* brings something;
|
|
198
|
-
* clears it (EC-587), as for every patch;
|
|
197
|
+
* brings something;
|
|
199
198
|
* - the id, the focal point, the title and every other column are absent → kept;
|
|
200
199
|
* - `mustExist`: the write only updates the stored asset — gone (deleted meanwhile), it is
|
|
201
200
|
* refused inside the write and nothing is created.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload.js","sourceRoot":"","sources":["../../../src/lib/assets/upload.ts"],"names":[],"mappings":"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","sourcesContent":["import { embeddedAssetMeta, readEmbeddedMetadata } from '@elytracms/core/cms-core'\nimport type { FieldDef, Locale } from '@elytracms/core/cms-core'\nimport type {\n AssetRecord,\n AssetRepository,\n AssetWriteInput,\n BlobStorageAdapter,\n} from '@elytracms/core/persistence'\nimport { detectImageDimensions } from './image-dimensions'\nimport type { ImageDimensions } from './image-dimensions'\nimport { generateVariants } from './thumbnail'\nimport type { GeneratedVariants } from './thumbnail'\nimport { initialUploadState, uploadReducer } from './upload-state'\nimport type { UploadEvent, UploadFailure, UploadState } from './upload-state'\n\n/**\n * Upload orchestration (EC-151): request upload URL → transfer bytes →\n * confirm by writing the EC-044 metadata record (dimensions, mime, serve URL).\n * Storage is reached *only* through the {@link BlobStorageAdapter}; every\n * effect is injectable so the whole flow unit-tests without a browser or a\n * live Convex deployment.\n */\n\n/** The structural slice of a browser `File` the upload flow needs. */\nexport interface UploadableFile {\n name: string\n type: string\n size: number\n arrayBuffer(): Promise<ArrayBuffer>\n}\n\n/** Sends bytes to an upload URL, reporting progress; returns the assigned storage key. */\nexport type UploadTransport = (\n uploadUrl: string,\n file: UploadableFile,\n onProgress: (loaded: number, total: number) => void,\n) => Promise<{ storageKey: string }>\n\n/**\n * Default browser transport: XMLHttpRequest POST for real byte progress\n * (fetch has no upload progress without streams support everywhere).\n */\nexport const xhrUploadTransport: UploadTransport = (uploadUrl, file, onProgress) =>\n new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest()\n xhr.open('POST', uploadUrl)\n if (file.type) xhr.setRequestHeader('Content-Type', file.type)\n xhr.upload.onprogress = (event) => {\n if (event.lengthComputable) onProgress(event.loaded, event.total)\n }\n xhr.onerror = () => reject(new Error('Network error while uploading bytes.'))\n xhr.onabort = () => reject(new Error('Upload was aborted.'))\n xhr.onload = () => {\n if (xhr.status < 200 || xhr.status >= 300) {\n reject(new Error(`Upload failed with HTTP ${xhr.status}.`))\n return\n }\n try {\n const payload = JSON.parse(xhr.responseText) as { storageId?: unknown }\n if (typeof payload.storageId === 'string' && payload.storageId.length > 0) {\n resolve({ storageKey: payload.storageId })\n } else {\n reject(new Error('Upload response did not include a storageId.'))\n }\n } catch {\n reject(new Error('Upload response was not valid JSON.'))\n }\n }\n void file.arrayBuffer().then(\n (bytes) => xhr.send(bytes),\n () => reject(new Error('Could not read file bytes.')),\n )\n })\n\nexport interface UploadDeps {\n blobs: BlobStorageAdapter\n assets: AssetRepository\n /**\n * The project's asset collection fields (EC-568): the `source` declarations that map\n * the file's embedded IPTC facts onto `meta` keys. Absent → no embedded metadata is\n * written (a field without `source` is never filled).\n */\n assetFields?: readonly FieldDef[]\n /**\n * The project's locales (EC-632): a `localized: true` asset field's embedded value goes\n * to the locale buckets — each locale its `xml:lang` alternative, the default the\n * `x-default` reading. Absent → every field is written to the shared `meta`.\n */\n locales?: { readonly default: Locale; readonly locales: readonly Locale[] }\n /** Client-direct transport; only used when `blobs.createUploadUrl` exists. */\n transport?: UploadTransport\n /** Injectable dimension detection; defaults to `createImageBitmap`-based. */\n detectDimensions?: (file: UploadableFile) => Promise<ImageDimensions | undefined>\n /**\n * Injectable preview generation (EC-400 thumb + EC-420 lqip). Defaults to a\n * single `createImageBitmap` + canvas decode that stores the thumb via a second\n * `blobs.store()` and inlines the lqip data URI. Returns `{}` (or a partial) for\n * skipped/failed variants — a preview NEVER fails the upload (AD-2). Tests inject\n * a deterministic implementation.\n */\n generateVariants?: (\n file: UploadableFile,\n dimensions: ImageDimensions | undefined,\n ) => Promise<GeneratedVariants>\n}\n\nexport interface UploadRequest {\n projectId: string\n file: UploadableFile\n /**\n * EC-568 — REPLACE the file inside this existing asset instead of creating one: the\n * same id, the new bytes and everything derived from them (storage key, url,\n * dimensions, type, size, thumb, lqip) through this one upload path; `meta` overridden\n * per key where the new file carries a value (else kept); the focal point, the title\n * and every other key kept. The previous blobs are kept (see EC-568 § Done).\n */\n replace?: { assetId: string }\n /** Observe every state transition (drives progress UI). */\n onState?: (state: UploadState) => void\n}\n\nexport type UploadResult =\n | { ok: true; asset: AssetRecord; state: UploadState }\n | { ok: false; failure: UploadFailure; state: UploadState }\n\nasync function defaultDetectDimensions(file: UploadableFile): Promise<ImageDimensions | undefined> {\n if (typeof Blob === 'undefined' || !(file instanceof Blob)) return undefined\n return detectImageDimensions(file as Blob & { type: string })\n}\n\n/**\n * Default preview step (EC-400 thumb + EC-420 lqip): decode the real `File` (which\n * IS a `Blob` in the browser) ONCE and produce both variants — store the thumb on\n * `blobs`, inline the lqip data URI. Guards the `Blob` narrowing so a non-browser\n * `UploadableFile` (or a backend without `store()`) simply yields no thumb — never\n * an error that could fail the upload.\n */\nfunction defaultGenerateVariants(blobs: BlobStorageAdapter) {\n return async (\n file: UploadableFile,\n dimensions: ImageDimensions | undefined,\n ): Promise<GeneratedVariants> => {\n if (typeof Blob === 'undefined' || !(file instanceof Blob)) return {}\n return generateVariants({ blobs }, file, {\n contentType: file.type,\n ...(dimensions ? { width: dimensions.width, height: dimensions.height } : {}),\n })\n }\n}\n\nfunction failureOf(stage: UploadFailure['stage'], error: unknown): UploadFailure {\n return {\n stage,\n message: error instanceof Error ? error.message : String(error),\n retryable: true,\n }\n}\n\n/**\n * Run one upload attempt. Resolves with a discriminated result — it never\n * throws, and a failed transfer leaves no metadata record behind. Pass the\n * previous `state` to retry (the attempt counter carries over).\n */\nexport async function runUpload(\n deps: UploadDeps,\n request: UploadRequest,\n previous?: UploadState,\n): Promise<UploadResult> {\n let state = previous ?? initialUploadState\n const dispatch = (event: UploadEvent): void => {\n state = uploadReducer(state, event)\n request.onState?.(state)\n }\n dispatch(state.phase === 'failed' ? { type: 'retry' } : { type: 'start' })\n\n const { blobs, assets } = deps\n const { projectId, file } = request\n\n // --- prepare + transfer ---------------------------------------------------\n let storageKey: string\n try {\n if (blobs.createUploadUrl && deps.transport) {\n const uploadUrl = await blobs.createUploadUrl()\n dispatch({ type: 'url-ready' })\n try {\n const sent = await deps.transport(uploadUrl, file, (loaded, total) =>\n dispatch({ type: 'progress', loaded, total }),\n )\n storageKey = sent.storageKey\n } catch (error) {\n dispatch({ type: 'failed', ...failureOf('transfer', error) })\n return { ok: false, failure: failureOf('transfer', error), state }\n }\n } else {\n // Backend without client-direct uploads: push bytes through the adapter.\n dispatch({ type: 'url-ready' })\n const bytes = new Uint8Array(await file.arrayBuffer())\n try {\n if (blobs.store) {\n storageKey = await blobs.store(bytes, file.type)\n } else {\n storageKey = `${projectId}/${file.name}`\n await blobs.put(storageKey, bytes, file.type)\n }\n } catch (error) {\n dispatch({ type: 'failed', ...failureOf('transfer', error) })\n return { ok: false, failure: failureOf('transfer', error), state }\n }\n }\n } catch (error) {\n dispatch({ type: 'failed', ...failureOf('prepare', error) })\n return { ok: false, failure: failureOf('prepare', error), state }\n }\n dispatch({ type: 'transferred' })\n\n // --- confirm: metadata record linked to the stored blob --------------------\n try {\n // EC-568: the ONE embedded-metadata reader, for a first upload and a replace alike.\n const embedded = await embeddedMetaOf(file, deps.assetFields, deps.locales)\n const detect = deps.detectDimensions ?? defaultDetectDimensions\n const dimensions = await detect(file)\n // EC-400 + EC-420: produce the thumb + lqip previews from the bytes already in\n // hand (one decode). A preview failure is swallowed — the asset simply ships\n // without them (AD-2, scope §4); absence = today's behaviour, never an error.\n const generate = deps.generateVariants ?? defaultGenerateVariants(blobs)\n let variants: GeneratedVariants\n try {\n variants = await generate(file, dimensions)\n } catch {\n variants = {}\n }\n const url = (await blobs.resolveUrl?.(storageKey)) ?? blobs.url(storageKey)\n const derived = {\n filename: file.name,\n contentType: file.type || 'application/octet-stream',\n byteSize: file.size,\n storageKey,\n url,\n }\n let write: AssetWriteInput\n if (request.replace) {\n // A replace edits an asset, never creates one — decided by the write itself\n // (`mustExist`), against the row as it is when the write lands: a delete by another\n // session in the meantime makes the write fail here, visibly, and creates nothing.\n write = replaceWrite(request.replace.assetId, derived, dimensions, variants, embedded)\n } else {\n write = {\n ...derived,\n ...(dimensions ? { width: dimensions.width, height: dimensions.height } : {}),\n ...(variants.thumb ? { thumb: variants.thumb } : {}),\n ...(variants.lqip ? { lqip: variants.lqip } : {}),\n ...(Object.keys(embedded.meta).length > 0 ? { meta: embedded.meta } : {}),\n ...(Object.keys(embedded.localizedMeta).length > 0 ? { localizedMeta: embedded.localizedMeta } : {}),\n }\n }\n const asset = await assets.upsertAsset(projectId, write)\n dispatch({ type: 'confirmed', assetId: asset.id })\n return { ok: true, asset, state }\n } catch (error) {\n dispatch({ type: 'failed', ...failureOf('confirm', error) })\n return { ok: false, failure: failureOf('confirm', error), state }\n }\n}\n\n/**\n * The file's embedded facts as `meta` values (EC-568): `readEmbeddedMetadata` over the\n * bytes, mapped through the asset collection's `source` declarations. A file that cannot\n * be read yields `{}` — metadata never fails an upload.\n */\nasync function embeddedMetaOf(\n file: UploadableFile,\n fields: readonly FieldDef[] | undefined,\n locales: UploadDeps['locales'],\n): Promise<EmbeddedAssetWrite> {\n const none: EmbeddedAssetWrite = { meta: {}, localizedMeta: {} }\n if (!fields || !fields.some((field) => field.source !== undefined)) return none\n try {\n return embeddedAssetMeta(fields, readEmbeddedMetadata(new Uint8Array(await file.arrayBuffer())), locales)\n } catch {\n return none\n }\n}\n\n/** What a file's embedded facts write (EC-568 → EC-632): shared `meta` keys, and per-locale buckets of the localized fields. */\nexport interface EmbeddedAssetWrite {\n meta: Record<string, unknown>\n localizedMeta: Record<string, Record<string, unknown>>\n}\n\n/**\n * The write of a file REPLACE (EC-568, the owner's ruling: \"override the values with\n * available metadata, or keep the existing if no metadata is available\"):\n * - the bytes' columns are SET — and a derived column the new file does not have is\n * CLEARED (`null`), so an old thumb, lqip or dimension never outlives its file;\n * - each `meta` key the new file brings is a per-key `metaPatch` (EC-634), applied to the\n * bag as STORED inside the write — never a copy read before the upload, so an editor's\n * metadata save that lands while the bytes travel is kept. Sent only when the file\n * brings something; the write rule then lifts a legacy `alt` column into the bag and\n * clears it (EC-587), as for every patch;\n * - the id, the focal point, the title and every other column are absent → kept;\n * - `mustExist`: the write only updates the stored asset — gone (deleted meanwhile), it is\n * refused inside the write and nothing is created.\n */\nexport function replaceWrite(\n assetId: string,\n derived: Pick<AssetRecord, 'filename' | 'contentType' | 'byteSize' | 'storageKey'> & { url: string },\n dimensions: ImageDimensions | undefined,\n variants: GeneratedVariants,\n embedded: EmbeddedAssetWrite,\n): AssetWriteInput {\n const brings = Object.keys(embedded.meta).length > 0\n const bringsLocales = Object.keys(embedded.localizedMeta).length > 0\n return {\n id: assetId,\n // EC-634 follow-on: an update of a stored asset, never a create (a concurrent delete wins).\n mustExist: true,\n ...derived,\n width: dimensions?.width ?? null,\n height: dimensions?.height ?? null,\n thumb: variants.thumb ?? null,\n lqip: variants.lqip ?? null,\n ...(brings ? { metaPatch: embedded.meta } : {}),\n // EC-632: a localized field's embedded values patch their locale buckets per key.\n ...(bringsLocales ? { localizedMetaPatch: embedded.localizedMeta } : {}),\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"upload.js","sourceRoot":"","sources":["../../../src/lib/assets/upload.ts"],"names":[],"mappings":"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","sourcesContent":["import { embeddedAssetMeta, readEmbeddedMetadata } from '@elytracms/core/cms-core'\nimport type { FieldDef, Locale } from '@elytracms/core/cms-core'\nimport type {\n AssetRecord,\n AssetRepository,\n AssetWriteInput,\n BlobStorageAdapter,\n} from '@elytracms/core/persistence'\nimport { detectImageDimensions } from './image-dimensions'\nimport type { ImageDimensions } from './image-dimensions'\nimport { generateVariants } from './thumbnail'\nimport type { GeneratedVariants } from './thumbnail'\nimport { initialUploadState, uploadReducer } from './upload-state'\nimport type { UploadEvent, UploadFailure, UploadState } from './upload-state'\n\n/**\n * Upload orchestration (EC-151): request upload URL → transfer bytes →\n * confirm by writing the EC-044 metadata record (dimensions, mime, serve URL).\n * Storage is reached *only* through the {@link BlobStorageAdapter}; every\n * effect is injectable so the whole flow unit-tests without a browser or a\n * live Convex deployment.\n */\n\n/** The structural slice of a browser `File` the upload flow needs. */\nexport interface UploadableFile {\n name: string\n type: string\n size: number\n arrayBuffer(): Promise<ArrayBuffer>\n}\n\n/** Sends bytes to an upload URL, reporting progress; returns the assigned storage key. */\nexport type UploadTransport = (\n uploadUrl: string,\n file: UploadableFile,\n onProgress: (loaded: number, total: number) => void,\n) => Promise<{ storageKey: string }>\n\n/**\n * Default browser transport: XMLHttpRequest POST for real byte progress\n * (fetch has no upload progress without streams support everywhere).\n */\nexport const xhrUploadTransport: UploadTransport = (uploadUrl, file, onProgress) =>\n new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest()\n xhr.open('POST', uploadUrl)\n if (file.type) xhr.setRequestHeader('Content-Type', file.type)\n xhr.upload.onprogress = (event) => {\n if (event.lengthComputable) onProgress(event.loaded, event.total)\n }\n xhr.onerror = () => reject(new Error('Network error while uploading bytes.'))\n xhr.onabort = () => reject(new Error('Upload was aborted.'))\n xhr.onload = () => {\n if (xhr.status < 200 || xhr.status >= 300) {\n reject(new Error(`Upload failed with HTTP ${xhr.status}.`))\n return\n }\n try {\n const payload = JSON.parse(xhr.responseText) as { storageId?: unknown }\n if (typeof payload.storageId === 'string' && payload.storageId.length > 0) {\n resolve({ storageKey: payload.storageId })\n } else {\n reject(new Error('Upload response did not include a storageId.'))\n }\n } catch {\n reject(new Error('Upload response was not valid JSON.'))\n }\n }\n void file.arrayBuffer().then(\n (bytes) => xhr.send(bytes),\n () => reject(new Error('Could not read file bytes.')),\n )\n })\n\nexport interface UploadDeps {\n blobs: BlobStorageAdapter\n assets: AssetRepository\n /**\n * The project's asset collection fields (EC-568): the `source` declarations that map\n * the file's embedded IPTC facts onto `meta` keys. Absent → no embedded metadata is\n * written (a field without `source` is never filled).\n */\n assetFields?: readonly FieldDef[]\n /**\n * The project's locales (EC-632): a `localized: true` asset field's embedded value goes\n * to the locale buckets — each locale its `xml:lang` alternative, the default the\n * `x-default` reading. Absent → every field is written to the shared `meta`.\n */\n locales?: { readonly default: Locale; readonly locales: readonly Locale[] }\n /** Client-direct transport; only used when `blobs.createUploadUrl` exists. */\n transport?: UploadTransport\n /** Injectable dimension detection; defaults to `createImageBitmap`-based. */\n detectDimensions?: (file: UploadableFile) => Promise<ImageDimensions | undefined>\n /**\n * Injectable preview generation (EC-400 thumb + EC-420 lqip). Defaults to a\n * single `createImageBitmap` + canvas decode that stores the thumb via a second\n * `blobs.store()` and inlines the lqip data URI. Returns `{}` (or a partial) for\n * skipped/failed variants — a preview NEVER fails the upload (AD-2). Tests inject\n * a deterministic implementation.\n */\n generateVariants?: (\n file: UploadableFile,\n dimensions: ImageDimensions | undefined,\n ) => Promise<GeneratedVariants>\n}\n\nexport interface UploadRequest {\n projectId: string\n file: UploadableFile\n /**\n * EC-568 — REPLACE the file inside this existing asset instead of creating one: the\n * same id, the new bytes and everything derived from them (storage key, url,\n * dimensions, type, size, thumb, lqip) through this one upload path; `meta` overridden\n * per key where the new file carries a value (else kept); the focal point, the title\n * and every other key kept. The previous blobs are kept (see EC-568 § Done).\n */\n replace?: { assetId: string }\n /** Observe every state transition (drives progress UI). */\n onState?: (state: UploadState) => void\n}\n\nexport type UploadResult =\n | { ok: true; asset: AssetRecord; state: UploadState }\n | { ok: false; failure: UploadFailure; state: UploadState }\n\nasync function defaultDetectDimensions(file: UploadableFile): Promise<ImageDimensions | undefined> {\n if (typeof Blob === 'undefined' || !(file instanceof Blob)) return undefined\n return detectImageDimensions(file as Blob & { type: string })\n}\n\n/**\n * Default preview step (EC-400 thumb + EC-420 lqip): decode the real `File` (which\n * IS a `Blob` in the browser) ONCE and produce both variants — store the thumb on\n * `blobs`, inline the lqip data URI. Guards the `Blob` narrowing so a non-browser\n * `UploadableFile` (or a backend without `store()`) simply yields no thumb — never\n * an error that could fail the upload.\n */\nfunction defaultGenerateVariants(blobs: BlobStorageAdapter) {\n return async (\n file: UploadableFile,\n dimensions: ImageDimensions | undefined,\n ): Promise<GeneratedVariants> => {\n if (typeof Blob === 'undefined' || !(file instanceof Blob)) return {}\n return generateVariants({ blobs }, file, {\n contentType: file.type,\n ...(dimensions ? { width: dimensions.width, height: dimensions.height } : {}),\n })\n }\n}\n\nfunction failureOf(stage: UploadFailure['stage'], error: unknown): UploadFailure {\n return {\n stage,\n message: error instanceof Error ? error.message : String(error),\n retryable: true,\n }\n}\n\n/**\n * Run one upload attempt. Resolves with a discriminated result — it never\n * throws, and a failed transfer leaves no metadata record behind. Pass the\n * previous `state` to retry (the attempt counter carries over).\n */\nexport async function runUpload(\n deps: UploadDeps,\n request: UploadRequest,\n previous?: UploadState,\n): Promise<UploadResult> {\n let state = previous ?? initialUploadState\n const dispatch = (event: UploadEvent): void => {\n state = uploadReducer(state, event)\n request.onState?.(state)\n }\n dispatch(state.phase === 'failed' ? { type: 'retry' } : { type: 'start' })\n\n const { blobs, assets } = deps\n const { projectId, file } = request\n\n // --- prepare + transfer ---------------------------------------------------\n let storageKey: string\n try {\n if (blobs.createUploadUrl && deps.transport) {\n const uploadUrl = await blobs.createUploadUrl()\n dispatch({ type: 'url-ready' })\n try {\n const sent = await deps.transport(uploadUrl, file, (loaded, total) =>\n dispatch({ type: 'progress', loaded, total }),\n )\n storageKey = sent.storageKey\n } catch (error) {\n dispatch({ type: 'failed', ...failureOf('transfer', error) })\n return { ok: false, failure: failureOf('transfer', error), state }\n }\n } else {\n // Backend without client-direct uploads: push bytes through the adapter.\n dispatch({ type: 'url-ready' })\n const bytes = new Uint8Array(await file.arrayBuffer())\n try {\n if (blobs.store) {\n storageKey = await blobs.store(bytes, file.type)\n } else {\n storageKey = `${projectId}/${file.name}`\n await blobs.put(storageKey, bytes, file.type)\n }\n } catch (error) {\n dispatch({ type: 'failed', ...failureOf('transfer', error) })\n return { ok: false, failure: failureOf('transfer', error), state }\n }\n }\n } catch (error) {\n dispatch({ type: 'failed', ...failureOf('prepare', error) })\n return { ok: false, failure: failureOf('prepare', error), state }\n }\n dispatch({ type: 'transferred' })\n\n // --- confirm: metadata record linked to the stored blob --------------------\n try {\n // EC-568: the ONE embedded-metadata reader, for a first upload and a replace alike.\n const embedded = await embeddedMetaOf(file, deps.assetFields, deps.locales)\n const detect = deps.detectDimensions ?? defaultDetectDimensions\n const dimensions = await detect(file)\n // EC-400 + EC-420: produce the thumb + lqip previews from the bytes already in\n // hand (one decode). A preview failure is swallowed — the asset simply ships\n // without them (AD-2, scope §4); absence = today's behaviour, never an error.\n const generate = deps.generateVariants ?? defaultGenerateVariants(blobs)\n let variants: GeneratedVariants\n try {\n variants = await generate(file, dimensions)\n } catch {\n variants = {}\n }\n const url = (await blobs.resolveUrl?.(storageKey)) ?? blobs.url(storageKey)\n const derived = {\n filename: file.name,\n contentType: file.type || 'application/octet-stream',\n byteSize: file.size,\n storageKey,\n url,\n }\n let write: AssetWriteInput\n if (request.replace) {\n // A replace edits an asset, never creates one — decided by the write itself\n // (`mustExist`), against the row as it is when the write lands: a delete by another\n // session in the meantime makes the write fail here, visibly, and creates nothing.\n write = replaceWrite(request.replace.assetId, derived, dimensions, variants, embedded)\n } else {\n write = {\n ...derived,\n ...(dimensions ? { width: dimensions.width, height: dimensions.height } : {}),\n ...(variants.thumb ? { thumb: variants.thumb } : {}),\n ...(variants.lqip ? { lqip: variants.lqip } : {}),\n ...(Object.keys(embedded.meta).length > 0 ? { meta: embedded.meta } : {}),\n ...(Object.keys(embedded.localizedMeta).length > 0 ? { localizedMeta: embedded.localizedMeta } : {}),\n }\n }\n const asset = await assets.upsertAsset(projectId, write)\n dispatch({ type: 'confirmed', assetId: asset.id })\n return { ok: true, asset, state }\n } catch (error) {\n dispatch({ type: 'failed', ...failureOf('confirm', error) })\n return { ok: false, failure: failureOf('confirm', error), state }\n }\n}\n\n/**\n * The file's embedded facts as `meta` values (EC-568): `readEmbeddedMetadata` over the\n * bytes, mapped through the asset collection's `source` declarations. A file that cannot\n * be read yields `{}` — metadata never fails an upload.\n */\nasync function embeddedMetaOf(\n file: UploadableFile,\n fields: readonly FieldDef[] | undefined,\n locales: UploadDeps['locales'],\n): Promise<EmbeddedAssetWrite> {\n const none: EmbeddedAssetWrite = { meta: {}, localizedMeta: {} }\n if (!fields || !fields.some((field) => field.source !== undefined)) return none\n try {\n return embeddedAssetMeta(fields, readEmbeddedMetadata(new Uint8Array(await file.arrayBuffer())), locales)\n } catch {\n return none\n }\n}\n\n/** What a file's embedded facts write (EC-568 → EC-632): shared `meta` keys, and per-locale buckets of the localized fields. */\nexport interface EmbeddedAssetWrite {\n meta: Record<string, unknown>\n localizedMeta: Record<string, Record<string, unknown>>\n}\n\n/**\n * The write of a file REPLACE (EC-568, the owner's ruling: \"override the values with\n * available metadata, or keep the existing if no metadata is available\"):\n * - the bytes' columns are SET — and a derived column the new file does not have is\n * CLEARED (`null`), so an old thumb, lqip or dimension never outlives its file;\n * - each `meta` key the new file brings is a per-key `metaPatch` (EC-634), applied to the\n * bag as STORED inside the write — never a copy read before the upload, so an editor's\n * metadata save that lands while the bytes travel is kept. Sent only when the file\n * brings something;\n * - the id, the focal point, the title and every other column are absent → kept;\n * - `mustExist`: the write only updates the stored asset — gone (deleted meanwhile), it is\n * refused inside the write and nothing is created.\n */\nexport function replaceWrite(\n assetId: string,\n derived: Pick<AssetRecord, 'filename' | 'contentType' | 'byteSize' | 'storageKey'> & { url: string },\n dimensions: ImageDimensions | undefined,\n variants: GeneratedVariants,\n embedded: EmbeddedAssetWrite,\n): AssetWriteInput {\n const brings = Object.keys(embedded.meta).length > 0\n const bringsLocales = Object.keys(embedded.localizedMeta).length > 0\n return {\n id: assetId,\n // EC-634 follow-on: an update of a stored asset, never a create (a concurrent delete wins).\n mustExist: true,\n ...derived,\n width: dimensions?.width ?? null,\n height: dimensions?.height ?? null,\n thumb: variants.thumb ?? null,\n lqip: variants.lqip ?? null,\n ...(brings ? { metaPatch: embedded.meta } : {}),\n // EC-632: a localized field's embedded values patch their locale buckets per key.\n ...(bringsLocales ? { localizedMetaPatch: embedded.localizedMeta } : {}),\n }\n}\n"]}
|
|
@@ -13,4 +13,4 @@
|
|
|
13
13
|
* (The convex-side stamp does NOT read this mirror — `convex/delivery.ts` imports the
|
|
14
14
|
* package.json declaration directly; its bundler allows what tsc's rootDir forbids.)
|
|
15
15
|
*/
|
|
16
|
-
export declare const ENGINE_VERSION = "0.0.
|
|
16
|
+
export declare const ENGINE_VERSION = "0.0.102";
|
|
@@ -13,5 +13,5 @@
|
|
|
13
13
|
* (The convex-side stamp does NOT read this mirror — `convex/delivery.ts` imports the
|
|
14
14
|
* package.json declaration directly; its bundler allows what tsc's rootDir forbids.)
|
|
15
15
|
*/
|
|
16
|
-
export const ENGINE_VERSION = '0.0.
|
|
16
|
+
export const ENGINE_VERSION = '0.0.102';
|
|
17
17
|
//# sourceMappingURL=engine-version.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine-version.js","sourceRoot":"","sources":["../../src/lib/engine-version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,CAAA","sourcesContent":["/**\n * The engine version this studio build was compiled from (EC-552) — the client-side\n * half of the deployed-functions version handshake: the boot gate compares it against\n * what `delivery:engineVersion` answers from the deployment.\n *\n * A MIRROR of `package.json`'s `version`, not the declaration itself: client source\n * cannot import `../../package.json` (outside the tsc build's `rootDir`; moving the\n * root would reshape `dist` and every export path). The parity test beside this file\n * fs-reads the real declaration and fails `pnpm verify` the moment the two diverge,\n * so a release cannot ship with a stale mirror. `pnpm release:bump` writes this\n * alongside the five `package.json` versions (EC-608).\n *\n * (The convex-side stamp does NOT read this mirror — `convex/delivery.ts` imports the\n * package.json declaration directly; its bundler allows what tsc's rootDir forbids.)\n */\nexport const ENGINE_VERSION = '0.0.
|
|
1
|
+
{"version":3,"file":"engine-version.js","sourceRoot":"","sources":["../../src/lib/engine-version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,CAAA","sourcesContent":["/**\n * The engine version this studio build was compiled from (EC-552) — the client-side\n * half of the deployed-functions version handshake: the boot gate compares it against\n * what `delivery:engineVersion` answers from the deployment.\n *\n * A MIRROR of `package.json`'s `version`, not the declaration itself: client source\n * cannot import `../../package.json` (outside the tsc build's `rootDir`; moving the\n * root would reshape `dist` and every export path). The parity test beside this file\n * fs-reads the real declaration and fails `pnpm verify` the moment the two diverge,\n * so a release cannot ship with a stale mirror. `pnpm release:bump` writes this\n * alongside the five `package.json` versions (EC-608).\n *\n * (The convex-side stamp does NOT read this mirror — `convex/delivery.ts` imports the\n * package.json declaration directly; its bundler allows what tsc's rootDir forbids.)\n */\nexport const ENGINE_VERSION = '0.0.102'\n"]}
|
|
@@ -265,6 +265,8 @@ export const deMessages = {
|
|
|
265
265
|
'operations.error.documentSchemaViolation': 'Das Dokument „{collection}:{id}“ verletzt das Schema seiner Sammlung.',
|
|
266
266
|
'operations.error.strictReferencesBlockDelete': '„{target}“ kann nicht gelöscht werden: {count} Dokumente verweisen über strikte Beziehungsfelder darauf — {named}{more}. Entfernen Sie zuerst diese Verweise.',
|
|
267
267
|
'operations.error.strictReferencesBlockDeleteOne': '„{target}“ kann nicht gelöscht werden: {count} Dokument verweist über strikte Beziehungsfelder darauf — {named}. Entfernen Sie zuerst diese Verweise.',
|
|
268
|
+
'operations.error.referencesBlockDelete': '„{target}“ kann nicht gelöscht werden: {count} Dokumente verweisen darauf — {named}{more}. Dieses Löschen erfolgt nur, solange nichts darauf verweist.',
|
|
269
|
+
'operations.error.referencesBlockDeleteOne': '„{target}“ kann nicht gelöscht werden: {count} Dokument verweist darauf — {named}. Dieses Löschen erfolgt nur, solange nichts darauf verweist.',
|
|
268
270
|
'operations.error.strictReferencesBlockUnpublish': 'Die Veröffentlichung von „{target}“ kann nicht zurückgenommen werden: {count} Dokumente verweisen über strikte Beziehungsfelder darauf — {named}{more}. Entfernen Sie zuerst diese Verweise.',
|
|
269
271
|
'operations.error.strictReferencesBlockUnpublishOne': 'Die Veröffentlichung von „{target}“ kann nicht zurückgenommen werden: {count} Dokument verweist über strikte Beziehungsfelder darauf — {named}. Entfernen Sie zuerst diese Verweise.',
|
|
270
272
|
// EC-589 — die Gegenrichtung von `strict: true`: Veröffentlichen verweigert, solange ein striktes Ziel fehlt oder unveröffentlicht ist.
|
|
@@ -579,6 +581,7 @@ export const deMessages = {
|
|
|
579
581
|
'cms.issueMessage.preConvergenceV1': 'Das Feld „{field}“ enthält eine Inhaltsform von vor der Konvergenz (die v1-Hülle „{ version, doc }“) — die Engine liest nur noch die konvergierte Sequenz „{ version: 2, content }“. Dieser Inhalt muss neu eingespielt werden (Re-Seed).',
|
|
580
582
|
'cms.issueMessage.preConvergenceBareBlocks': 'Das Feld „{field}“ enthält eine Inhaltsform von vor der Konvergenz (eine blanke Komponentenliste) — die Engine liest nur noch die konvergierte Sequenz „{ version: 2, content }“. Dieser Inhalt muss neu eingespielt werden (Re-Seed).',
|
|
581
583
|
'cms.issueMessage.preConvergencePlaintext': 'Das Feld „{field}“ enthält eine Inhaltsform von vor der Konvergenz (unstrukturierter Alttext) — die Engine liest nur noch die konvergierte Sequenz „{ version: 2, content }“. Dieser Inhalt muss neu eingespielt werden (Re-Seed).',
|
|
584
|
+
'cms.issueMessage.untaggedSequenceComponent': 'Das Feld „{field}“ enthält die Komponente „{component}“ (Knoten „{node}“) ohne ihre Kennung „elytra/component“ in einer Inhaltsliste — die Engine liest dort nur gekennzeichnete Komponenten, daher zeigt der ganze Wert seinen Platzhalter für ungültigen Inhalt. Er wurde am Schreibweg vorbei geschrieben; speichern Sie das Feld erneut im Editor oder spielen Sie ihn neu ein (Re-Seed).',
|
|
582
585
|
'cms.issueMessage.gateUnknownCollection': 'Das Projekt deklariert keine Collection „{collection}“ — es gibt keine Regeln, nach denen sie veröffentlicht werden könnte.',
|
|
583
586
|
'cms.issueMessage.gateAssetLibraryUnready': 'Die Medienbibliothek konnte nicht gelesen werden — die Veröffentlichung ungeprüfter Medienverweise wird verweigert. Bitte erneut versuchen.',
|
|
584
587
|
'cms.issueMessage.gateNoLocales': 'Das Projekt deklariert keine Sprachen — die Veröffentlichung ohne sie wird verweigert.',
|
|
@@ -787,6 +790,8 @@ export const deMessages = {
|
|
|
787
790
|
// ─────────────────────────────────────────────────────────────────────────
|
|
788
791
|
'cms.field.rendererCrashed': 'Benutzerdefinierter Renderer abgestürzt — Standardsteuerung wird angezeigt.',
|
|
789
792
|
'cms.field.noRenderer': 'Kein Feld-Renderer für Steuerung „{control}“ registriert.',
|
|
793
|
+
'cms.field.blocksInFieldRow': 'Ein Blocks-Feld wird als Seiten-Canvas auf einem eigenen Formular-Tab bearbeitet — hier hat es keine Feldzeile.',
|
|
794
|
+
'cms.field.noControlForType': 'Keine eingebaute Steuerung für den Feldtyp „{type}“.',
|
|
790
795
|
'cms.field.itemActions': 'Elementaktionen',
|
|
791
796
|
'cms.field.moveUp': 'Nach oben',
|
|
792
797
|
'cms.field.moveDown': 'Nach unten',
|
|
@@ -1347,6 +1352,8 @@ export const deMessages = {
|
|
|
1347
1352
|
'ai.translate.skipped.unreadable': 'der gespeicherte Wert konnte nicht gelesen werden',
|
|
1348
1353
|
'ai.translate.skipped.notReturned': 'der Assistent hat dafür keinen Text geliefert',
|
|
1349
1354
|
'ai.translate.skipped.structureChanged': 'die Übersetzung hat Formatierungen, Links oder eingebettete Elemente verloren — das Original wurde beibehalten',
|
|
1355
|
+
// EC-738 — ein Bereich, dessen schreibgeschützter (oder für die KI ausgeschlossener) Inhalt anders aufgebaut ist als die Quelle.
|
|
1356
|
+
'ai.translate.skipped.locked': 'enthält Inhalte, die hier nicht geändert werden können, anders angeordnet als in der Quelle — unverändert gelassen',
|
|
1350
1357
|
// EC-378 — the update (edit-existing) proposal
|
|
1351
1358
|
'ai.update.proposalTitle': 'Änderungen an {collection}',
|
|
1352
1359
|
'ai.update.diffBefore': 'Aktuell',
|
|
@@ -1362,9 +1369,10 @@ export const deMessages = {
|
|
|
1362
1369
|
'builder.inspector.unset': 'Nicht gesetzt',
|
|
1363
1370
|
'builder.inspector.unsetWithHint': 'Nicht gesetzt (Standard: {hint})',
|
|
1364
1371
|
// EC-586 / EC-581 (wave-0092, zone A) — canonical values and the per-FieldType definition
|
|
1365
|
-
'cms.issueMessage.nonCanonicalValue': 'Das Feld „{field}“ ist in einer nicht kanonischen Form für ein Feld vom Typ „{type}“ gespeichert — es wurde am Schreibweg vorbei geschrieben, der je Feldtyp genau eine Form speichert.
|
|
1372
|
+
'cms.issueMessage.nonCanonicalValue': 'Das Feld „{field}“ ist in einer nicht kanonischen Form für ein Feld vom Typ „{type}“ gespeichert — es wurde am Schreibweg vorbei geschrieben, der je Feldtyp genau eine Form speichert. Speichern Sie das Feld erneut im Editor oder über eine Operation, um die kanonische Form abzulegen.',
|
|
1366
1373
|
'cms.issueMessage.propsNotJudged': 'Die Komponenten-Eigenschaften im Feld „{field}“ wurden nicht geprüft: Die Seite wurde ohne Komponenten-Registry aufgelöst, daher werden sie wie gespeichert ausgeliefert und ihre Probleme nicht gemeldet.',
|
|
1367
1374
|
'cms.issueMessage.assetHoldsUrl': 'Das Asset-Feld „{field}“ enthält eine URL — ein Asset-Wert ist ein Asset aus der Mediathek, nie eine URL. Laden Sie das Bild in die Mediathek hoch und wählen Sie es aus, oder tragen Sie die Adresse eines externen Bildes in das URL-Feld der Komponente ein (beim Bild: „Image URL“).',
|
|
1375
|
+
'cms.issueMessage.slugNotSegment': 'Das Slug-Feld „{field}“ enthält „{value}“, was kein URL-Segment ist — die Slug-Regel schreibt dafür „{slug}“. Die Live-URL wird aus dem gespeicherten Slug so gebildet, wie er steht; speichern Sie den Slug, den die Regel schreibt.',
|
|
1368
1376
|
// EC-584 — die AllowList-Prüfung (Konfiguration / Registrierung).
|
|
1369
1377
|
'cms.issueMessage.emptyAllow': 'Das Feld „{field}“ deklariert ein leeres „allow“ — eine Liste erlaubt genau die genannten IDs, eine leere also nichts. Lassen Sie „allow“ weg für die Standard-Auswahl des Feldtyps, oder nennen Sie die Komponenten-IDs.',
|
|
1370
1378
|
'cms.issueMessage.unknownAllowComponent': 'Das Feld „{field}“ erlaubt „{component}“, das keine Komponente dieses Projekts ist — prüfen Sie die ID oder entfernen Sie sie aus „allow“.',
|