@elytracms/studio 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/convex/asset-alt-migration.test.ts +2 -2
- package/convex/asset-meta-patch.test.ts +218 -0
- package/convex/asset-replace-delete-race.test.ts +127 -0
- package/convex/assets.ts +27 -2
- package/convex/delivery-redirects.test.ts +167 -0
- package/convex/delivery.ts +15 -5
- package/convex/rail-write-parity.test.ts +6 -6
- package/convex/redirects.ts +1 -1
- package/convex/schema.ts +6 -0
- package/dist/addon.d.ts +1 -1
- package/dist/addon.js.map +1 -1
- package/dist/components/assets/asset-detail.js +26 -11
- package/dist/components/assets/asset-detail.js.map +1 -1
- package/dist/components/assets/asset-locale.d.ts +9 -0
- package/dist/components/assets/asset-locale.js +16 -0
- package/dist/components/assets/asset-locale.js.map +1 -0
- package/dist/components/assets/asset-meta-label.d.ts +12 -0
- package/dist/components/assets/asset-meta-label.js +15 -0
- package/dist/components/assets/asset-meta-label.js.map +1 -0
- package/dist/components/assets/asset-metadata.d.ts +69 -15
- package/dist/components/assets/asset-metadata.js +99 -11
- package/dist/components/assets/asset-metadata.js.map +1 -1
- package/dist/components/assets/asset-search.js +8 -2
- package/dist/components/assets/asset-search.js.map +1 -1
- package/dist/components/assets/asset-thumb.js +6 -2
- package/dist/components/assets/asset-thumb.js.map +1 -1
- package/dist/components/assets/assets-collection-view-source.d.ts +23 -9
- package/dist/components/assets/assets-collection-view-source.js +78 -26
- package/dist/components/assets/assets-collection-view-source.js.map +1 -1
- package/dist/components/assets/assets-store.js +17 -4
- package/dist/components/assets/assets-store.js.map +1 -1
- package/dist/components/builder/builder-store.d.ts +21 -0
- package/dist/components/builder/builder-store.js +22 -0
- package/dist/components/builder/builder-store.js.map +1 -1
- package/dist/components/builder/canvas-commit-boundary.d.ts +22 -0
- package/dist/components/builder/canvas-commit-boundary.js +27 -0
- package/dist/components/builder/canvas-commit-boundary.js.map +1 -0
- package/dist/components/builder/canvas-rebase.d.ts +77 -0
- package/dist/components/builder/canvas-rebase.js +169 -0
- package/dist/components/builder/canvas-rebase.js.map +1 -0
- package/dist/components/builder/canvas-render-context.d.ts +6 -3
- package/dist/components/builder/canvas-render-context.js +17 -9
- package/dist/components/builder/canvas-render-context.js.map +1 -1
- package/dist/components/builder/composition-field-editor.d.ts +20 -2
- package/dist/components/builder/composition-field-editor.js +45 -27
- package/dist/components/builder/composition-field-editor.js.map +1 -1
- package/dist/components/builder/node-factory.js +15 -3
- package/dist/components/builder/node-factory.js.map +1 -1
- package/dist/components/builder/property-inspector.js +3 -1
- package/dist/components/builder/property-inspector.js.map +1 -1
- package/dist/components/builder/run-inspector.js +10 -6
- package/dist/components/builder/run-inspector.js.map +1 -1
- package/dist/components/cms/asset-field.d.ts +5 -2
- package/dist/components/cms/asset-field.js +34 -17
- package/dist/components/cms/asset-field.js.map +1 -1
- package/dist/components/cms/asset-picker.js +3 -1
- package/dist/components/cms/asset-picker.js.map +1 -1
- package/dist/components/cms/canvas-commit.d.ts +56 -0
- package/dist/components/cms/canvas-commit.js +35 -0
- package/dist/components/cms/canvas-commit.js.map +1 -0
- package/dist/components/cms/collection-table.js +23 -7
- package/dist/components/cms/collection-table.js.map +1 -1
- package/dist/components/cms/commit-policy.d.ts +6 -2
- package/dist/components/cms/commit-policy.js +1 -1
- package/dist/components/cms/commit-policy.js.map +1 -1
- package/dist/components/cms/detail-editor.js +11 -1
- package/dist/components/cms/detail-editor.js.map +1 -1
- package/dist/components/cms/use-document-draft.d.ts +62 -4
- package/dist/components/cms/use-document-draft.js +102 -32
- package/dist/components/cms/use-document-draft.js.map +1 -1
- package/dist/components/cms/use-live-url.d.ts +6 -1
- package/dist/components/cms/use-live-url.js +12 -9
- package/dist/components/cms/use-live-url.js.map +1 -1
- package/dist/components/collection-view/cms-collection-view-source.js +9 -5
- package/dist/components/collection-view/cms-collection-view-source.js.map +1 -1
- package/dist/components/deployment-setup-gate.js +10 -1
- package/dist/components/deployment-setup-gate.js.map +1 -1
- package/dist/components/records/record-lens.js +3 -8
- package/dist/components/records/record-lens.js.map +1 -1
- package/dist/lib/assets/upload.d.ts +25 -7
- package/dist/lib/assets/upload.js +30 -21
- package/dist/lib/assets/upload.js.map +1 -1
- package/dist/lib/cms/published-documents.d.ts +24 -6
- package/dist/lib/cms/published-documents.js +39 -6
- package/dist/lib/cms/published-documents.js.map +1 -1
- package/dist/lib/cms-views/view-model.d.ts +14 -101
- package/dist/lib/cms-views/view-model.js +20 -101
- package/dist/lib/cms-views/view-model.js.map +1 -1
- package/dist/lib/collection-view/collection-view-source.d.ts +6 -1
- package/dist/lib/collection-view/collection-view-source.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 +7 -3
- package/dist/lib/i18n/messages.de.js.map +1 -1
- package/dist/lib/i18n/messages.en.d.ts +5 -1
- package/dist/lib/i18n/messages.en.js +8 -4
- package/dist/lib/i18n/messages.en.js.map +1 -1
- package/dist/lib/operations/config-manifest-lookup.d.ts +1 -1
- package/dist/lib/operations/config-manifest-lookup.js +3 -3
- package/dist/lib/operations/config-manifest-lookup.js.map +1 -1
- package/dist/lib/persistence/deployment-readiness.js +14 -11
- package/dist/lib/persistence/deployment-readiness.js.map +1 -1
- package/dist/lib/persona/labels.js +1 -0
- package/dist/lib/persona/labels.js.map +1 -1
- package/dist/lib/query/index.d.ts +2 -2
- package/dist/lib/query/index.js +1 -1
- package/dist/lib/query/index.js.map +1 -1
- package/dist/lib/query/operations-query.d.ts +26 -0
- package/dist/lib/query/operations-query.js +12 -0
- package/dist/lib/query/operations-query.js.map +1 -1
- package/dist/lib/registry/index.js +2 -2
- package/dist/lib/registry/index.js.map +1 -1
- package/dist/lib/registry/preview.d.ts +10 -0
- package/dist/lib/registry/preview.js +13 -4
- package/dist/lib/registry/preview.js.map +1 -1
- package/dist/lib/routes/route-issues.js +6 -3
- package/dist/lib/routes/route-issues.js.map +1 -1
- package/dist/lib/workspace/workspace-source.js +6 -7
- package/dist/lib/workspace/workspace-source.js.map +1 -1
- package/dist/previews/entry-node.d.ts +14 -0
- package/dist/previews/entry-node.js +22 -0
- package/dist/previews/entry-node.js.map +1 -0
- package/dist/previews/harness.js +2 -16
- package/dist/previews/harness.js.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-source.js","sourceRoot":"","sources":["../../../src/lib/workspace/workspace-source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAC9D,OAAO,EAAE,4BAA4B,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AAsClG
|
|
1
|
+
{"version":3,"file":"workspace-source.js","sourceRoot":"","sources":["../../../src/lib/workspace/workspace-source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAC9D,OAAO,EAAE,4BAA4B,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AAsClG;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,SAAS,SAAS,CAAC,KAAc,EAAE,MAAc;IAC/C,MAAM,MAAM,GAAG,sBAAsB,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;IAC9D,OAAO,MAAM,CAAC,EAAE;QACd,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE;QACvD,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAA;AACxD,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,qBAAqB,CAAC,OAAyB;IAC7D,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,IAAI,qBAAqB,CAAA;QACtD,MAAM,SAAS,GAAG,4BAA4B,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;QACxE,IAAI,OAAO,IAAI,SAAS;YAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAA;QAC7F,OAAO,SAAS,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;IACzC,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;AACzB,CAAC","sourcesContent":["import { WORKSPACE_CONFIG_FILE } from '@elytracms/core/config'\nimport { extractWorkspaceConfigExport, resolveWorkspaceConfig } from '@elytracms/core/studio-core'\nimport type { ResolvedProject, WorkspaceConfigIssue } from '@elytracms/core/studio-core'\n\n/**\n * Workspace-config resolution for the studio (EC-154, vision AD-8).\n *\n * The studio receives its code-first workspace config as the default export of\n * the consumer's `elytra.config.ts`, handed in at the mount point\n * (`createStudio(config)` in `./index.ts`) and resolved here as pure, testable\n * logic. A bundled `elytra.config.ts` at the builder app root — picked up by\n * Vite (`import.meta.glob`) — is the same channel for studio development and for\n * a self-hosted builder whose repo *is* the workspace.\n *\n * No channel → `none`: the single-project golden path, identical to today's\n * adapter-listed behavior. An invalid config is a deterministic boot-error state\n * (see `DeploymentSetupGate`) — never a silent fallback to unconfigured behavior.\n *\n * NOTE (EC-376): an earlier env-injected-JSON channel (`VITE_ELYTRA_WORKSPACE`)\n * for a hosted builder serving a *separate* host repo was plumbed here but never\n * wired end-to-end — no caller ever set it (EC-357 inventory). It was removed as\n * dead code. If hosted workspace-selection ever returns, wire it deliberately\n * through the EC-357 mount-env seam (`createStudio(config, studioConfig, { env })`\n * → `provideStudioEnv`/`studioEnv()` in `lib/persistence/backend-mode.ts`) rather\n * than resurrecting latent plumbing.\n */\n\nexport type WorkspaceState =\n | { kind: 'none' }\n | { kind: 'config'; source: string; projects: ResolvedProject[] }\n | { kind: 'invalid'; source: string; issues: WorkspaceConfigIssue[] }\n\nexport interface WorkspaceSources {\n /** Module namespace of the bundled `elytra.config.ts`, when one was bundled. */\n fileModule?: unknown\n /** Source label for file-channel issues (defaults to the conventional name). */\n fileName?: string\n}\n\n/**\n * `result.issues` is carried on the `invalid` path and **deliberately dropped on the\n * ok path** (EC-506, decided 2026-08-01) — not overlooked.\n *\n * `ok` means \"no error-severity issue\", so what would be dropped is warnings — and\n * the resolver has **no warning-severity producer** (measured 2026-08-01: every\n * `severity:` literal in `studio-core/workspace-config.ts` is `'error'`, and its one\n * pass-through of a foreign severity cannot carry `validateProjectSettings`'s only\n * warning; both gates are pinned by `workspace-config.test.ts`). Adding an `issues`\n * field here today would be a channel with a writer, no producer and no reader —\n * exactly the latent plumbing EC-376 deleted from this file (see the NOTE above).\n *\n * The consequence is a KNOWN, deliberate divergence from `elytra doctor`, which does\n * carry the issues on a valid config too (`cli/src/doctor.js` `configFactsFromOutcome`\n * sets `issues` whenever there are any, and `deployment-ready.ts`'s `config-valid` check\n * has a `warn` branch for a valid-config-with-issues that the studio can therefore never\n * reach). It is **latent, not live**: with zero producers a valid config carries no\n * issues, so both tools render the same `ok` today. (Read at both sites and inferred\n * from them; not exercised end-to-end through the studio gate.)\n *\n * **Resurface trigger.** The first warning-severity `WorkspaceConfigIssue` makes the\n * divergence live and this decision expires. At that point EC-506's audience question\n * (\"does an EDITOR need to know?\") returns as a real design call, and the shape is in\n * the EC-506 task file: `issues` here, a mapper in `config-issues.ts`, a rail-foot\n * reader, and a localized catalog key. Do not add the field ahead of the producer.\n */\nfunction fromValue(value: unknown, source: string): WorkspaceState {\n const result = resolveWorkspaceConfig(value, { file: source })\n return result.ok\n ? { kind: 'config', source, projects: result.projects }\n : { kind: 'invalid', source, issues: result.issues }\n}\n\n/** Resolve the workspace state from the bundled config module. Pure and deterministic. */\nexport function resolveWorkspaceState(sources: WorkspaceSources): WorkspaceState {\n if (sources.fileModule !== undefined) {\n const file = sources.fileName ?? WORKSPACE_CONFIG_FILE\n const extracted = extractWorkspaceConfigExport(sources.fileModule, file)\n if ('issue' in extracted) return { kind: 'invalid', source: file, issues: [extracted.issue] }\n return fromValue(extracted.value, file)\n }\n\n return { kind: 'none' }\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ComponentNode } from '@elytracms/core/project-graph';
|
|
2
|
+
import type { StudioRegistry } from '../lib/registry/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* The node one `elytra previews` entry renders — the exact subtree the blocks panel
|
|
5
|
+
* inserts (`fixtureSubtree` for a declared fixture, else the seeded manifest default,
|
|
6
|
+
* EC-439) — the fixture-less `Default` exactly as the Components view previews it
|
|
7
|
+
* ({@link defaultPreviewNode}: distinct ids, EC-624). Pure (no DOM), so the harness's
|
|
8
|
+
* node is testable node-side.
|
|
9
|
+
*/
|
|
10
|
+
export declare function previewEntryNode(studio: StudioRegistry, componentId: string, fixture: string): {
|
|
11
|
+
node: ComponentNode;
|
|
12
|
+
} | {
|
|
13
|
+
error: string;
|
|
14
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { DEFAULT_VARIANT, fixtureSubtree } from '../components/builder/blocks-model.js';
|
|
2
|
+
import { defaultPreviewNode } from '../lib/registry/preview.js';
|
|
3
|
+
/**
|
|
4
|
+
* The node one `elytra previews` entry renders — the exact subtree the blocks panel
|
|
5
|
+
* inserts (`fixtureSubtree` for a declared fixture, else the seeded manifest default,
|
|
6
|
+
* EC-439) — the fixture-less `Default` exactly as the Components view previews it
|
|
7
|
+
* ({@link defaultPreviewNode}: distinct ids, EC-624). Pure (no DOM), so the harness's
|
|
8
|
+
* node is testable node-side.
|
|
9
|
+
*/
|
|
10
|
+
export function previewEntryNode(studio, componentId, fixture) {
|
|
11
|
+
const manifest = studio.registry.getManifest(componentId);
|
|
12
|
+
if (!manifest)
|
|
13
|
+
return { error: `Unknown component "${componentId}".` };
|
|
14
|
+
const declared = manifest.fixtures?.find((f) => f.name === fixture);
|
|
15
|
+
if (declared)
|
|
16
|
+
return { node: fixtureSubtree(studio, manifest, declared, `preview-${componentId}`).node };
|
|
17
|
+
if (fixture === DEFAULT_VARIANT && (manifest.fixtures ?? []).length === 0) {
|
|
18
|
+
return { node: defaultPreviewNode(manifest, studio.registry) };
|
|
19
|
+
}
|
|
20
|
+
return { error: `Unknown fixture "${fixture}" for component "${componentId}".` };
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=entry-node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry-node.js","sourceRoot":"","sources":["../../src/previews/entry-node.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAA;AAEpF,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAE5D;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAC9B,MAAsB,EACtB,WAAmB,EACnB,OAAe;IAEf,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,WAAW,CAAC,CAAA;IACzD,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,KAAK,EAAE,sBAAsB,WAAW,IAAI,EAAE,CAAA;IACtE,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAA;IACnE,IAAI,QAAQ;QAAE,OAAO,EAAE,IAAI,EAAE,cAAc,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,WAAW,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IACxG,IAAI,OAAO,KAAK,eAAe,IAAI,CAAC,QAAQ,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1E,OAAO,EAAE,IAAI,EAAE,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAA;IAChE,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,oBAAoB,OAAO,oBAAoB,WAAW,IAAI,EAAE,CAAA;AAClF,CAAC","sourcesContent":["import type { ComponentNode } from '@elytracms/core/project-graph'\nimport { DEFAULT_VARIANT, fixtureSubtree } from '../components/builder/blocks-model'\nimport type { StudioRegistry } from '../lib/registry'\nimport { defaultPreviewNode } from '../lib/registry/preview'\n\n/**\n * The node one `elytra previews` entry renders — the exact subtree the blocks panel\n * inserts (`fixtureSubtree` for a declared fixture, else the seeded manifest default,\n * EC-439) — the fixture-less `Default` exactly as the Components view previews it\n * ({@link defaultPreviewNode}: distinct ids, EC-624). Pure (no DOM), so the harness's\n * node is testable node-side.\n */\nexport function previewEntryNode(\n studio: StudioRegistry,\n componentId: string,\n fixture: string,\n): { node: ComponentNode } | { error: string } {\n const manifest = studio.registry.getManifest(componentId)\n if (!manifest) return { error: `Unknown component \"${componentId}\".` }\n const declared = manifest.fixtures?.find((f) => f.name === fixture)\n if (declared) return { node: fixtureSubtree(studio, manifest, declared, `preview-${componentId}`).node }\n if (fixture === DEFAULT_VARIANT && (manifest.fixtures ?? []).length === 0) {\n return { node: defaultPreviewNode(manifest, studio.registry) }\n }\n return { error: `Unknown fixture \"${fixture}\" for component \"${componentId}\".` }\n}\n"]}
|
package/dist/previews/harness.js
CHANGED
|
@@ -3,10 +3,9 @@ import { Component } from 'react';
|
|
|
3
3
|
import { createRoot } from 'react-dom/client';
|
|
4
4
|
import { flushSync } from 'react-dom';
|
|
5
5
|
import { renderNode } from '@elytracms/core/runtime-renderer';
|
|
6
|
-
import { DEFAULT_VARIANT, fixtureSubtree } from '../components/builder/blocks-model.js';
|
|
7
|
-
import { seededNodeFromManifest } from '../components/builder/node-factory.js';
|
|
8
6
|
import { previewContext } from '../lib/registry/index.js';
|
|
9
7
|
import { previewEntriesForConfig, previewRegistryFromConfig } from './enumerate.js';
|
|
8
|
+
import { previewEntryNode } from './entry-node.js';
|
|
10
9
|
/**
|
|
11
10
|
* EC-440 — the browser half of the `elytra previews` render harness. The CLI
|
|
12
11
|
* boots the consumer studio app's OWN Vite (programmatically, with a minimal
|
|
@@ -62,19 +61,6 @@ async function settled(doc) {
|
|
|
62
61
|
})));
|
|
63
62
|
await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(() => resolve())));
|
|
64
63
|
}
|
|
65
|
-
/** Build the node a fixture renders — the exact subtree the blocks panel inserts. */
|
|
66
|
-
function nodeForEntry(studio, componentId, fixture) {
|
|
67
|
-
const manifest = studio.registry.getManifest(componentId);
|
|
68
|
-
if (!manifest)
|
|
69
|
-
return { error: `Unknown component "${componentId}".` };
|
|
70
|
-
const declared = manifest.fixtures?.find((f) => f.name === fixture);
|
|
71
|
-
if (declared)
|
|
72
|
-
return { node: fixtureSubtree(studio, manifest, declared, `preview-${componentId}`).node };
|
|
73
|
-
if (fixture === DEFAULT_VARIANT && (manifest.fixtures ?? []).length === 0) {
|
|
74
|
-
return { node: seededNodeFromManifest(manifest, studio.registry) };
|
|
75
|
-
}
|
|
76
|
-
return { error: `Unknown fixture "${fixture}" for component "${componentId}".` };
|
|
77
|
-
}
|
|
78
64
|
/**
|
|
79
65
|
* Mount the harness: build the registry from the consumer config, expose the
|
|
80
66
|
* driver API on `window.__ELYTRA_PREVIEWS__`. Idempotent per document.
|
|
@@ -94,7 +80,7 @@ export function mountPreviewHarness(config) {
|
|
|
94
80
|
}
|
|
95
81
|
let root = null;
|
|
96
82
|
const render = async (componentId, fixture) => {
|
|
97
|
-
const built =
|
|
83
|
+
const built = previewEntryNode(studio, componentId, fixture);
|
|
98
84
|
if ('error' in built)
|
|
99
85
|
return { ok: false, error: built.error };
|
|
100
86
|
// A fresh root per fixture: no state carryover between shots.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"harness.js","sourceRoot":"","sources":["../../src/previews/harness.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Component } from 'react'\nimport type { ReactNode } from 'react'\nimport { createRoot, type Root } from 'react-dom/client'\nimport { flushSync } from 'react-dom'\nimport { renderNode } from '@elytracms/core/runtime-renderer'\nimport type { RenderContext } from '@elytracms/core/runtime-renderer'\nimport type { ComponentNode } from '@elytracms/core/project-graph'\nimport { DEFAULT_VARIANT, fixtureSubtree } from '../components/builder/blocks-model'\nimport { seededNodeFromManifest } from '../components/builder/node-factory'\nimport { previewContext } from '../lib/registry'\nimport type { StudioRegistry } from '../lib/registry'\nimport { previewEntriesForConfig, previewRegistryFromConfig } from './enumerate'\n\n/**\n * EC-440 — the browser half of the `elytra previews` render harness. The CLI\n * boots the consumer studio app's OWN Vite (programmatically, with a minimal\n * inline config) and serves a page whose entry module does exactly three\n * things: import the consumer's `elytra.config.ts` (the component registry —\n * code), import the consumer THEME (the same standalone Tailwind entry the\n * canvas iframe and delivery load, EC-414 — so preview == canvas == delivery\n * by construction), and call {@link mountPreviewHarness}.\n *\n * DATA-FREE, deliberately (no new trust boundary): no persistence adapter, no\n * auth, no content data, no env secrets — `createStudio` is never called. The\n * registry is built directly from the config's `components` entries plus the\n * base primitives ({@link previewRegistryFromConfig}), and bindings resolve to\n * `undefined` (`previewContext`), so data-dependent components render their\n * honest empty states.\n *\n * The driving CLI talks to the page through `window.__ELYTRA_PREVIEWS__`:\n * `entries` (the same enumeration the CLI derives node-side — a handshake\n * guard) and `render(componentId, fixture)`, which mounts ONE fixture subtree\n * — the exact subtree the blocks panel inserts (`fixtureSubtree`, else the\n * seeded manifest default, EC-439) — into the stage and resolves once the\n * document has settled (fonts loaded, images complete, two animation frames).\n * The CLI then screenshots the viewport.\n */\n\n/** The id of the stage element fixtures render into (created when absent). */\nexport const PREVIEW_STAGE_ID = 'elytra-preview-stage'\n\nexport type PreviewRenderResult = { ok: true } | { ok: false; error: string }\n\nexport interface PreviewHarnessApi {\n ready: true\n entries: Array<{ componentId: string; fixture: string }>\n render: (componentId: string, fixture: string) => Promise<PreviewRenderResult>\n}\n\ndeclare global {\n interface Window {\n __ELYTRA_PREVIEWS__?: PreviewHarnessApi\n }\n}\n\n/** Catches a fixture whose render throws — the entry fails visibly, the page survives. */\nclass HarnessErrorBoundary extends Component<\n { children: ReactNode; onError: (error: Error) => void },\n { failed: boolean }\n> {\n override state = { failed: false }\n\n static getDerivedStateFromError(): { failed: boolean } {\n return { failed: true }\n }\n\n override componentDidCatch(error: Error): void {\n this.props.onError(error)\n }\n\n override render(): ReactNode {\n return this.state.failed ? null : this.props.children\n }\n}\n\n/** Resolve once the document is visually settled: fonts, images, two frames. */\nasync function settled(doc: Document): Promise<void> {\n try {\n await doc.fonts?.ready\n } catch {\n // Font-loading failures must not wedge the run — the render is still shot.\n }\n await Promise.all(\n Array.from(doc.images).map((img) =>\n img.complete\n ? Promise.resolve()\n : new Promise<void>((resolve) => {\n img.addEventListener('load', () => resolve(), { once: true })\n img.addEventListener('error', () => resolve(), { once: true })\n }),\n ),\n )\n await new Promise<void>((resolve) =>\n requestAnimationFrame(() => requestAnimationFrame(() => resolve())),\n )\n}\n\n/** Build the node a fixture renders — the exact subtree the blocks panel inserts. */\nfunction nodeForEntry(\n studio: StudioRegistry,\n componentId: string,\n fixture: string,\n): { node: ComponentNode } | { error: string } {\n const manifest = studio.registry.getManifest(componentId)\n if (!manifest) return { error: `Unknown component \"${componentId}\".` }\n const declared = manifest.fixtures?.find((f) => f.name === fixture)\n if (declared) return { node: fixtureSubtree(studio, manifest, declared, `preview-${componentId}`).node }\n if (fixture === DEFAULT_VARIANT && (manifest.fixtures ?? []).length === 0) {\n return { node: seededNodeFromManifest(manifest, studio.registry) }\n }\n return { error: `Unknown fixture \"${fixture}\" for component \"${componentId}\".` }\n}\n\n/**\n * Mount the harness: build the registry from the consumer config, expose the\n * driver API on `window.__ELYTRA_PREVIEWS__`. Idempotent per document.\n */\nexport function mountPreviewHarness(config: unknown): PreviewHarnessApi {\n const studio = previewRegistryFromConfig(config)\n const ctx: RenderContext = previewContext(studio)\n const entries = previewEntriesForConfig(config).map(({ componentId, fixture }) => ({\n componentId,\n fixture,\n }))\n\n let stage = document.getElementById(PREVIEW_STAGE_ID)\n if (!stage) {\n stage = document.createElement('div')\n stage.id = PREVIEW_STAGE_ID\n document.body.appendChild(stage)\n }\n\n let root: Root | null = null\n\n const render = async (componentId: string, fixture: string): Promise<PreviewRenderResult> => {\n const built = nodeForEntry(studio, componentId, fixture)\n if ('error' in built) return { ok: false, error: built.error }\n\n // A fresh root per fixture: no state carryover between shots.\n root?.unmount()\n root = createRoot(stage!)\n let renderError: Error | null = null\n try {\n flushSync(() => {\n root!.render(\n <HarnessErrorBoundary\n onError={(error) => {\n renderError = error\n }}\n >\n {renderNode(built.node, ctx)}\n </HarnessErrorBoundary>,\n )\n })\n } catch (error) {\n renderError = error instanceof Error ? error : new Error(String(error))\n }\n if (renderError !== null) return { ok: false, error: (renderError as Error).message }\n await settled(document)\n return { ok: true }\n }\n\n const api: PreviewHarnessApi = { ready: true, entries, render }\n window.__ELYTRA_PREVIEWS__ = api\n return api\n}\n"]}
|
|
1
|
+
{"version":3,"file":"harness.js","sourceRoot":"","sources":["../../src/previews/harness.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Component } from 'react'\nimport type { ReactNode } from 'react'\nimport { createRoot, type Root } from 'react-dom/client'\nimport { flushSync } from 'react-dom'\nimport { renderNode } from '@elytracms/core/runtime-renderer'\nimport type { RenderContext } from '@elytracms/core/runtime-renderer'\nimport { previewContext } from '../lib/registry'\nimport { previewEntriesForConfig, previewRegistryFromConfig } from './enumerate'\nimport { previewEntryNode } from './entry-node'\n\n/**\n * EC-440 — the browser half of the `elytra previews` render harness. The CLI\n * boots the consumer studio app's OWN Vite (programmatically, with a minimal\n * inline config) and serves a page whose entry module does exactly three\n * things: import the consumer's `elytra.config.ts` (the component registry —\n * code), import the consumer THEME (the same standalone Tailwind entry the\n * canvas iframe and delivery load, EC-414 — so preview == canvas == delivery\n * by construction), and call {@link mountPreviewHarness}.\n *\n * DATA-FREE, deliberately (no new trust boundary): no persistence adapter, no\n * auth, no content data, no env secrets — `createStudio` is never called. The\n * registry is built directly from the config's `components` entries plus the\n * base primitives ({@link previewRegistryFromConfig}), and bindings resolve to\n * `undefined` (`previewContext`), so data-dependent components render their\n * honest empty states.\n *\n * The driving CLI talks to the page through `window.__ELYTRA_PREVIEWS__`:\n * `entries` (the same enumeration the CLI derives node-side — a handshake\n * guard) and `render(componentId, fixture)`, which mounts ONE fixture subtree\n * — the exact subtree the blocks panel inserts (`fixtureSubtree`, else the\n * seeded manifest default, EC-439) — into the stage and resolves once the\n * document has settled (fonts loaded, images complete, two animation frames).\n * The CLI then screenshots the viewport.\n */\n\n/** The id of the stage element fixtures render into (created when absent). */\nexport const PREVIEW_STAGE_ID = 'elytra-preview-stage'\n\nexport type PreviewRenderResult = { ok: true } | { ok: false; error: string }\n\nexport interface PreviewHarnessApi {\n ready: true\n entries: Array<{ componentId: string; fixture: string }>\n render: (componentId: string, fixture: string) => Promise<PreviewRenderResult>\n}\n\ndeclare global {\n interface Window {\n __ELYTRA_PREVIEWS__?: PreviewHarnessApi\n }\n}\n\n/** Catches a fixture whose render throws — the entry fails visibly, the page survives. */\nclass HarnessErrorBoundary extends Component<\n { children: ReactNode; onError: (error: Error) => void },\n { failed: boolean }\n> {\n override state = { failed: false }\n\n static getDerivedStateFromError(): { failed: boolean } {\n return { failed: true }\n }\n\n override componentDidCatch(error: Error): void {\n this.props.onError(error)\n }\n\n override render(): ReactNode {\n return this.state.failed ? null : this.props.children\n }\n}\n\n/** Resolve once the document is visually settled: fonts, images, two frames. */\nasync function settled(doc: Document): Promise<void> {\n try {\n await doc.fonts?.ready\n } catch {\n // Font-loading failures must not wedge the run — the render is still shot.\n }\n await Promise.all(\n Array.from(doc.images).map((img) =>\n img.complete\n ? Promise.resolve()\n : new Promise<void>((resolve) => {\n img.addEventListener('load', () => resolve(), { once: true })\n img.addEventListener('error', () => resolve(), { once: true })\n }),\n ),\n )\n await new Promise<void>((resolve) =>\n requestAnimationFrame(() => requestAnimationFrame(() => resolve())),\n )\n}\n\n/**\n * Mount the harness: build the registry from the consumer config, expose the\n * driver API on `window.__ELYTRA_PREVIEWS__`. Idempotent per document.\n */\nexport function mountPreviewHarness(config: unknown): PreviewHarnessApi {\n const studio = previewRegistryFromConfig(config)\n const ctx: RenderContext = previewContext(studio)\n const entries = previewEntriesForConfig(config).map(({ componentId, fixture }) => ({\n componentId,\n fixture,\n }))\n\n let stage = document.getElementById(PREVIEW_STAGE_ID)\n if (!stage) {\n stage = document.createElement('div')\n stage.id = PREVIEW_STAGE_ID\n document.body.appendChild(stage)\n }\n\n let root: Root | null = null\n\n const render = async (componentId: string, fixture: string): Promise<PreviewRenderResult> => {\n const built = previewEntryNode(studio, componentId, fixture)\n if ('error' in built) return { ok: false, error: built.error }\n\n // A fresh root per fixture: no state carryover between shots.\n root?.unmount()\n root = createRoot(stage!)\n let renderError: Error | null = null\n try {\n flushSync(() => {\n root!.render(\n <HarnessErrorBoundary\n onError={(error) => {\n renderError = error\n }}\n >\n {renderNode(built.node, ctx)}\n </HarnessErrorBoundary>,\n )\n })\n } catch (error) {\n renderError = error instanceof Error ? error : new Error(String(error))\n }\n if (renderError !== null) return { ok: false, error: (renderError as Error).message }\n await settled(document)\n return { ok: true }\n }\n\n const api: PreviewHarnessApi = { ready: true, entries, render }\n window.__ELYTRA_PREVIEWS__ = api\n return api\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elytracms/studio",
|
|
3
3
|
"author": "finaldream <hi@finaldream.de>",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.95",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22.18.0"
|
|
7
7
|
},
|
|
@@ -153,7 +153,7 @@
|
|
|
153
153
|
"lucide-react": "^1.23.0",
|
|
154
154
|
"tailwind-merge": "^3.6.0",
|
|
155
155
|
"zod": "^4.4.3",
|
|
156
|
-
"@elytracms/core": "^0.0.
|
|
156
|
+
"@elytracms/core": "^0.0.95"
|
|
157
157
|
},
|
|
158
158
|
"peerDependencies": {
|
|
159
159
|
"@tanstack/react-router": "^1.170.0",
|
|
@@ -177,7 +177,7 @@
|
|
|
177
177
|
"react-dom": "^19.2.7",
|
|
178
178
|
"typescript": "^6.0.3",
|
|
179
179
|
"vite": "^8.1.3",
|
|
180
|
-
"@elytracms/components": "^0.0.
|
|
180
|
+
"@elytracms/components": "^0.0.95"
|
|
181
181
|
},
|
|
182
182
|
"scripts": {
|
|
183
183
|
"build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.build.json && node ../../scripts/fix-esm-extensions.mjs dist && node ../../scripts/check-esm-extensions.mjs dist",
|