handoff-app 1.2.2-7 → 2.0.0-0
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/Changelog.md +37 -15
- package/README.md +372 -118
- package/dist/app-builder/build.d.ts +41 -2
- package/dist/app-builder/build.js +455 -18
- package/dist/app-builder/client-config.d.ts +15 -2
- package/dist/app-builder/client-config.js +43 -4
- package/dist/app-builder/config-diff/snapshot.d.ts +1 -6
- package/dist/app-builder/config-diff/snapshot.js +2 -9
- package/dist/app-builder/index.d.ts +1 -1
- package/dist/app-builder/index.js +3 -1
- package/dist/app-builder/nav-shell.d.ts +23 -0
- package/dist/app-builder/nav-shell.js +80 -0
- package/dist/app-builder/static-export.d.ts +17 -0
- package/dist/app-builder/static-export.js +181 -0
- package/dist/app-builder/vercel-output.d.ts +39 -0
- package/dist/app-builder/vercel-output.js +259 -0
- package/dist/app-builder/watchers/utils.d.ts +2 -0
- package/dist/app-builder/watchers.d.ts +14 -4
- package/dist/app-builder/watchers.js +123 -28
- package/dist/app-builder/websocket.js +1 -1
- package/dist/artifacts/index.d.ts +2 -0
- package/dist/artifacts/index.js +13 -0
- package/dist/artifacts/types.d.ts +136 -0
- package/dist/artifacts/types.js +24 -0
- package/dist/artifacts/url.d.ts +49 -0
- package/dist/artifacts/url.js +86 -0
- package/dist/cache/build-cache.js +48 -4
- package/dist/cli.js +0 -0
- package/dist/commands/build/app.js +1 -2
- package/dist/commands/build/index.d.ts +17 -0
- package/dist/commands/build/index.js +66 -0
- package/dist/commands/checkout/index.d.ts +24 -0
- package/dist/commands/checkout/index.js +71 -0
- package/dist/commands/db/migrate.d.ts +11 -0
- package/dist/commands/db/migrate.js +33 -0
- package/dist/commands/index.js +8 -0
- package/dist/commands/publish/index.d.ts +21 -0
- package/dist/commands/publish/index.js +68 -0
- package/dist/config/defaults.js +15 -1
- package/dist/config/loader.js +6 -1
- package/dist/config/normalizers/declaration.js +4 -1
- package/dist/config/normalizers/page.d.ts +18 -0
- package/dist/config/normalizers/page.js +34 -0
- package/dist/config/normalizers/pattern.js +7 -1
- package/dist/config/runtime.d.ts +4 -0
- package/dist/config/runtime.js +53 -5
- package/dist/index.d.ts +65 -1
- package/dist/index.js +123 -3
- package/dist/nav/index.d.ts +83 -0
- package/dist/nav/index.js +9 -0
- package/dist/nav/registry.d.ts +15 -0
- package/dist/nav/registry.js +42 -0
- package/dist/nav/resolver.d.ts +8 -0
- package/dist/nav/resolver.js +192 -0
- package/dist/nav/workspace.d.ts +18 -0
- package/dist/nav/workspace.js +103 -0
- package/dist/pipeline/styles.js +7 -35
- package/dist/pipeline/token-transformers.d.ts +45 -0
- package/dist/pipeline/token-transformers.js +71 -0
- package/dist/registry/asset-storage/adapters/vercel-blob.d.ts +17 -0
- package/dist/registry/asset-storage/adapters/vercel-blob.js +87 -0
- package/dist/registry/asset-storage/define.d.ts +10 -0
- package/dist/registry/asset-storage/define.js +13 -0
- package/dist/registry/asset-storage/resolve.d.ts +45 -0
- package/dist/registry/asset-storage/resolve.js +36 -0
- package/dist/registry/asset-storage/types.d.ts +51 -0
- package/dist/registry/asset-storage/types.js +9 -0
- package/dist/registry/assets/layout.d.ts +22 -0
- package/dist/registry/assets/layout.js +30 -0
- package/dist/registry/assets/sets.d.ts +18 -0
- package/dist/registry/assets/sets.js +44 -0
- package/dist/registry/assets/transfer.d.ts +45 -0
- package/dist/registry/assets/transfer.js +11 -0
- package/dist/registry/checkout/assets.d.ts +16 -0
- package/dist/registry/checkout/assets.js +150 -0
- package/dist/registry/checkout/index.d.ts +33 -0
- package/dist/registry/checkout/index.js +610 -0
- package/dist/registry/checkout/tokens.d.ts +15 -0
- package/dist/registry/checkout/tokens.js +171 -0
- package/dist/registry/client.d.ts +61 -0
- package/dist/registry/client.js +211 -0
- package/dist/registry/connection.d.ts +30 -0
- package/dist/registry/connection.js +36 -0
- package/dist/registry/db/adapter.d.ts +43 -0
- package/dist/registry/db/adapter.js +59 -0
- package/dist/registry/db/client.d.ts +35 -0
- package/dist/registry/db/client.js +94 -0
- package/dist/registry/db/index.d.ts +5 -0
- package/dist/registry/db/index.js +24 -0
- package/dist/registry/db/migrate.d.ts +23 -0
- package/dist/registry/db/migrate.js +64 -0
- package/dist/registry/db/schema.d.ts +4869 -0
- package/dist/registry/db/schema.js +347 -0
- package/dist/registry/path.d.ts +4 -0
- package/dist/registry/path.js +31 -0
- package/dist/registry/publish/artifacts.d.ts +16 -0
- package/dist/registry/publish/artifacts.js +132 -0
- package/dist/registry/publish/assets.d.ts +16 -0
- package/dist/registry/publish/assets.js +129 -0
- package/dist/registry/publish/errors.d.ts +5 -0
- package/dist/registry/publish/errors.js +26 -0
- package/dist/registry/publish/index.d.ts +27 -0
- package/dist/registry/publish/index.js +126 -0
- package/dist/registry/publish/package.d.ts +27 -0
- package/dist/registry/publish/package.js +257 -0
- package/dist/registry/publish/publish-build.d.ts +12 -0
- package/dist/registry/publish/publish-build.js +43 -0
- package/dist/registry/publish/tokens.d.ts +18 -0
- package/dist/registry/publish/tokens.js +112 -0
- package/dist/registry/tokens/sets.d.ts +59 -0
- package/dist/registry/tokens/sets.js +109 -0
- package/dist/registry/tokens/transfer.d.ts +48 -0
- package/dist/registry/tokens/transfer.js +10 -0
- package/dist/registry/transfer.d.ts +75 -0
- package/dist/registry/transfer.js +11 -0
- package/dist/store/filesystem-assets.d.ts +17 -0
- package/dist/store/filesystem-assets.js +147 -0
- package/dist/store/filesystem.d.ts +76 -0
- package/dist/store/filesystem.js +208 -0
- package/dist/store/index.d.ts +20 -0
- package/dist/store/index.js +38 -0
- package/dist/store/registry.d.ts +77 -0
- package/dist/store/registry.js +350 -0
- package/dist/store/source-files.d.ts +24 -0
- package/dist/store/source-files.js +147 -0
- package/dist/store/types.d.ts +185 -0
- package/dist/store/types.js +12 -0
- package/dist/transformers/plugins/csf-render.js +17 -8
- package/dist/transformers/plugins/handlebars-previews.js +10 -3
- package/dist/transformers/plugins/ssr-render.js +116 -49
- package/dist/transformers/preview/component/api.js +3 -1
- package/dist/transformers/preview/component/artifacts.js +8 -1
- package/dist/transformers/preview/component/builder.js +13 -5
- package/dist/transformers/preview/component/css.js +9 -1
- package/dist/transformers/preview/component/javascript.d.ts +9 -3
- package/dist/transformers/preview/component/javascript.js +45 -17
- package/dist/transformers/preview/component/shared-artifacts.d.ts +83 -0
- package/dist/transformers/preview/component/shared-artifacts.js +92 -0
- package/dist/transformers/preview/component.js +5 -2
- package/dist/transformers/preview/pattern/builder.js +28 -9
- package/dist/transformers/preview/pattern/html.d.ts +13 -10
- package/dist/transformers/preview/pattern/html.js +62 -27
- package/dist/transformers/preview/types.d.ts +38 -0
- package/dist/transformers/utils/handlebars.d.ts +3 -0
- package/dist/transformers/utils/handlebars.js +19 -5
- package/dist/types/config.d.ts +118 -25
- package/dist/utils/menu-shell.d.ts +60 -0
- package/dist/utils/menu-shell.js +221 -0
- package/dist/utils/stable-stringify.d.ts +2 -0
- package/dist/utils/stable-stringify.js +8 -0
- package/docs/cli.md +4 -2
- package/drizzle/0000_init_registry_storage.sql +95 -0
- package/drizzle/0001_add_review_metadata.sql +2 -0
- package/drizzle/0002_add_pages.sql +28 -0
- package/drizzle/0003_add_tokens.sql +29 -0
- package/drizzle/0004_add_assets.sql +37 -0
- package/drizzle/meta/0000_snapshot.json +642 -0
- package/drizzle/meta/0001_snapshot.json +654 -0
- package/drizzle/meta/0002_snapshot.json +835 -0
- package/drizzle/meta/0003_snapshot.json +1023 -0
- package/drizzle/meta/0004_snapshot.json +1252 -0
- package/drizzle/meta/_journal.json +41 -0
- package/drizzle.config.ts +16 -0
- package/package.json +10 -1
- package/src/app/components/Component/Preview.tsx +3 -2
- package/src/app/components/Component/RegistryActions.tsx +150 -0
- package/src/app/components/Foundations/DisplayLogo.tsx +5 -3
- package/src/app/components/Layout/Header.tsx +21 -3
- package/src/app/components/Layout/Main.tsx +11 -3
- package/src/app/components/Navigation/MainNav.tsx +4 -2
- package/src/app/components/Navigation/MobileNav.tsx +4 -2
- package/src/app/components/Navigation/SideNav.tsx +46 -11
- package/src/app/components/NotFound.tsx +24 -0
- package/src/app/components/context/NavProvider.tsx +71 -0
- package/src/app/components/old/Header.tsx +3 -3
- package/src/app/components/util/index.ts +203 -380
- package/src/app/components/util/useCollectionAssets.ts +125 -0
- package/src/app/components/util/useFoundationTokens.ts +67 -0
- package/src/app/generated/default-pages.json +1 -0
- package/src/app/generated/nav-shell.json +1 -0
- package/src/app/lib/api/query.ts +6 -0
- package/src/app/lib/api/redact.ts +46 -0
- package/src/app/lib/asset-storage.ts +81 -0
- package/src/app/lib/docs-api/artifacts.ts +116 -0
- package/src/app/lib/docs-api/backend.ts +151 -0
- package/src/app/lib/docs-api/errors.ts +52 -0
- package/src/app/lib/docs-api/handler.ts +34 -0
- package/src/app/lib/docs-api/index.ts +7 -0
- package/src/app/lib/docs-api/records.ts +189 -0
- package/src/app/lib/docs-api/registry.ts +130 -0
- package/src/app/lib/docs-api/runtime-config.ts +173 -0
- package/src/app/lib/docs-api/serve.ts +37 -0
- package/src/app/lib/docs-api/token-detail.ts +19 -0
- package/src/app/lib/registry-api/allowlist.ts +163 -0
- package/src/app/lib/registry-api/asset-transfer.ts +363 -0
- package/src/app/lib/registry-api/auth.ts +68 -0
- package/src/app/lib/registry-api/entity-routes.ts +197 -0
- package/src/app/lib/registry-api/errors.ts +51 -0
- package/src/app/lib/registry-api/files.ts +135 -0
- package/src/app/lib/registry-api/handler.ts +96 -0
- package/src/app/lib/registry-api/index.ts +4 -0
- package/src/app/lib/registry-api/meta.ts +87 -0
- package/src/app/lib/registry-api/revalidate.ts +36 -0
- package/src/app/lib/registry-api/store.ts +348 -0
- package/src/app/lib/registry-api/token-transfer.ts +231 -0
- package/src/app/lib/registry-api/transfer.ts +513 -0
- package/src/app/lib/registry-api/validation.ts +74 -0
- package/src/app/lib/registry-connection.ts +58 -0
- package/src/app/lib/utils.ts +14 -0
- package/src/app/next.config.mjs +72 -13
- package/src/app/pages/[...slug]/index.tsx +74 -20
- package/src/app/pages/_app.tsx +5 -2
- package/src/app/pages/api/docs/artifacts/[...artifactPath].ts +16 -0
- package/src/app/pages/api/docs/assets/[collection]/[...path].ts +50 -0
- package/src/app/pages/api/docs/assets/[collection]/index.ts +22 -0
- package/src/app/pages/api/docs/components/[id]/assets/[asset].ts +33 -0
- package/src/app/pages/api/docs/components/[id]/inspect/[previewId].ts +20 -0
- package/src/app/pages/api/docs/components/[id]/previews/[previewId].ts +21 -0
- package/src/app/pages/api/docs/components/[id].ts +24 -0
- package/src/app/pages/api/docs/components.json.ts +12 -0
- package/src/app/pages/api/docs/nav.json.ts +48 -0
- package/src/app/pages/api/docs/patterns/[id]/preview.ts +19 -0
- package/src/app/pages/api/docs/patterns/[id].ts +24 -0
- package/src/app/pages/api/docs/patterns.json.ts +12 -0
- package/src/app/pages/api/docs/tokens/components/[id].ts +30 -0
- package/src/app/pages/api/docs/tokens/foundations/[type].ts +32 -0
- package/src/app/pages/api/registry/components/[id]/files/[...filePath].ts +19 -0
- package/src/app/pages/api/registry/components/[id]/files/index.ts +19 -0
- package/src/app/pages/api/registry/components/[id].ts +20 -0
- package/src/app/pages/api/registry/components/index.ts +19 -0
- package/src/app/pages/api/registry/health.ts +20 -0
- package/src/app/pages/api/registry/patterns/[id]/files/[...filePath].ts +19 -0
- package/src/app/pages/api/registry/patterns/[id]/files/index.ts +19 -0
- package/src/app/pages/api/registry/patterns/[id].ts +20 -0
- package/src/app/pages/api/registry/patterns/index.ts +19 -0
- package/src/app/pages/api/registry/transfer/[kind]/[id].ts +39 -0
- package/src/app/pages/api/registry/transfer/assets/[collection].ts +24 -0
- package/src/app/pages/api/registry/transfer/assets/blobs/[hash].ts +23 -0
- package/src/app/pages/api/registry/transfer/assets/blobs/have.ts +11 -0
- package/src/app/pages/api/registry/transfer/assets/index.ts +10 -0
- package/src/app/pages/api/registry/transfer/tokens/[...setId].ts +26 -0
- package/src/app/pages/api/registry/transfer/tokens/index.ts +11 -0
- package/src/app/pages/assets/fonts.tsx +41 -17
- package/src/app/pages/assets/index.tsx +2 -2
- package/src/app/pages/assets/logos.tsx +2 -2
- package/src/app/pages/foundations/colors.tsx +18 -8
- package/src/app/pages/foundations/effects.tsx +18 -8
- package/src/app/pages/foundations/icons/[name]/index.tsx +26 -14
- package/src/app/pages/foundations/icons/index.tsx +13 -9
- package/src/app/pages/foundations/index.tsx +1 -1
- package/src/app/pages/foundations/logo.tsx +7 -4
- package/src/app/pages/foundations/typography.tsx +19 -9
- package/src/app/pages/index.tsx +1 -1
- package/src/app/pages/system/component/[component]/index.tsx +87 -17
- package/src/app/pages/system/index.tsx +13 -4
- package/src/app/pages/system/pattern/[pattern]/index.tsx +70 -14
- package/src/app/pages/system/tokens/components/[component]/index.tsx +42 -14
- package/src/app/pages/system/tokens/foundations/colors.tsx +7 -5
- package/src/app/pages/system/tokens/foundations/effects.tsx +7 -5
- package/src/app/pages/system/tokens/foundations/typography.tsx +8 -4
- package/src/app/tsconfig.json +2 -3
- package/src/app-builder/build.ts +555 -11
- package/src/app-builder/client-config.ts +61 -4
- package/src/app-builder/config-diff/snapshot.ts +1 -11
- package/src/app-builder/index.ts +1 -1
- package/src/app-builder/nav-shell.ts +74 -0
- package/src/app-builder/static-export.ts +215 -0
- package/src/app-builder/vercel-output.ts +297 -0
- package/src/app-builder/watchers/utils.ts +2 -0
- package/src/app-builder/watchers.ts +149 -25
- package/src/app-builder/websocket.ts +2 -2
- package/src/artifacts/README.md +14 -0
- package/src/artifacts/index.ts +17 -0
- package/src/artifacts/types.ts +146 -0
- package/src/artifacts/url.ts +90 -0
- package/src/cache/build-cache.ts +47 -2
- package/src/commands/build/app.ts +1 -2
- package/src/commands/build/index.ts +61 -0
- package/src/commands/checkout/index.ts +66 -0
- package/src/commands/db/migrate.ts +25 -0
- package/src/commands/index.ts +8 -0
- package/src/commands/publish/index.ts +63 -0
- package/src/config/defaults.ts +15 -0
- package/src/config/loader.ts +10 -1
- package/src/config/normalizers/declaration.ts +3 -0
- package/src/config/normalizers/page.ts +45 -0
- package/src/config/normalizers/pattern.ts +4 -1
- package/src/config/runtime.ts +48 -2
- package/src/index.ts +126 -3
- package/src/nav/index.ts +94 -0
- package/src/nav/registry.ts +54 -0
- package/src/nav/resolver.ts +217 -0
- package/src/nav/workspace.ts +87 -0
- package/src/pipeline/styles.ts +4 -35
- package/src/pipeline/token-transformers.ts +97 -0
- package/src/registry/asset-storage/adapters/vercel-blob.ts +51 -0
- package/src/registry/asset-storage/define.ts +15 -0
- package/src/registry/asset-storage/resolve.ts +72 -0
- package/src/registry/asset-storage/types.ts +46 -0
- package/src/registry/assets/layout.ts +38 -0
- package/src/registry/assets/sets.ts +48 -0
- package/src/registry/assets/transfer.ts +50 -0
- package/src/registry/checkout/assets.ts +126 -0
- package/src/registry/checkout/index.ts +596 -0
- package/src/registry/checkout/tokens.ts +152 -0
- package/src/registry/client.ts +234 -0
- package/src/registry/connection.ts +50 -0
- package/src/registry/db/adapter.ts +74 -0
- package/src/registry/db/client.ts +88 -0
- package/src/registry/db/index.ts +35 -0
- package/src/registry/db/migrate.ts +56 -0
- package/src/registry/db/schema.ts +444 -0
- package/src/registry/path.ts +26 -0
- package/src/registry/publish/artifacts.ts +147 -0
- package/src/registry/publish/assets.ts +129 -0
- package/src/registry/publish/errors.ts +34 -0
- package/src/registry/publish/index.ts +128 -0
- package/src/registry/publish/package.ts +272 -0
- package/src/registry/publish/publish-build.ts +51 -0
- package/src/registry/publish/tokens.ts +119 -0
- package/src/registry/tokens/sets.ts +132 -0
- package/src/registry/tokens/transfer.ts +53 -0
- package/src/registry/transfer.ts +82 -0
- package/src/store/filesystem-assets.ts +152 -0
- package/src/store/filesystem.ts +237 -0
- package/src/store/index.ts +62 -0
- package/src/store/registry.ts +334 -0
- package/src/store/source-files.ts +155 -0
- package/src/store/types.ts +210 -0
- package/src/transformers/plugins/csf-render.ts +31 -7
- package/src/transformers/plugins/handlebars-previews.ts +22 -3
- package/src/transformers/plugins/ssr-render.ts +145 -57
- package/src/transformers/preview/component/api.ts +2 -1
- package/src/transformers/preview/component/artifacts.ts +10 -1
- package/src/transformers/preview/component/builder.ts +9 -2
- package/src/transformers/preview/component/css.ts +10 -1
- package/src/transformers/preview/component/javascript.ts +55 -20
- package/src/transformers/preview/component/shared-artifacts.ts +146 -0
- package/src/transformers/preview/component.ts +5 -2
- package/src/transformers/preview/pattern/builder.ts +33 -7
- package/src/transformers/preview/pattern/html.ts +71 -27
- package/src/transformers/preview/types.ts +42 -0
- package/src/transformers/utils/handlebars.ts +31 -5
- package/src/types/config.ts +123 -25
- package/src/utils/menu-shell.ts +241 -0
- package/src/utils/stable-stringify.ts +7 -0
- package/templates/default/package.json.tpl +1 -1
- package/handoff.config.js +0 -90
- package/src/app/components/ComponentSearch.tsx +0 -93
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import fs from 'fs-extra';
|
|
2
2
|
import path from 'path';
|
|
3
|
+
import { buildPatternDetailUrl } from '../../../artifacts/url';
|
|
3
4
|
import Handoff from '../../../index';
|
|
4
5
|
import { Logger } from '../../../utils/logger';
|
|
6
|
+
import {
|
|
7
|
+
resolveComponentArtifactPresence,
|
|
8
|
+
resolveSharedArtifactPresence,
|
|
9
|
+
type ComponentArtifactPresence,
|
|
10
|
+
type SharedArtifactPresence,
|
|
11
|
+
} from '../component/shared-artifacts';
|
|
5
12
|
import { PatternListObject, PatternObject } from '../types';
|
|
6
13
|
import { readPatternSummaryApi, syncPatternArtifacts, writePatternApi, writePatternHtml, writePatternSummaryApi } from './api';
|
|
7
14
|
import { composePatternHtml } from './html';
|
|
@@ -37,7 +44,8 @@ async function buildPattern(
|
|
|
37
44
|
patternId: string,
|
|
38
45
|
pattern: PatternObject,
|
|
39
46
|
componentOutputDir: string,
|
|
40
|
-
basePath: string
|
|
47
|
+
basePath: string,
|
|
48
|
+
sharedArtifacts: SharedArtifactPresence
|
|
41
49
|
): Promise<PatternListObject | null> {
|
|
42
50
|
const fragments: { componentId: string; html: string }[] = [];
|
|
43
51
|
let hasErrors = false;
|
|
@@ -77,6 +85,15 @@ async function buildPattern(
|
|
|
77
85
|
fragments.push({ componentId: ref.id, html });
|
|
78
86
|
}
|
|
79
87
|
|
|
88
|
+
// Resolve component-owned artifact presence for each composed component so the pattern references
|
|
89
|
+
// only the stylesheets that actually exist (no dangling references for style-less components).
|
|
90
|
+
const componentArtifacts = new Map<string, ComponentArtifactPresence>();
|
|
91
|
+
for (const fragment of fragments) {
|
|
92
|
+
if (!componentArtifacts.has(fragment.componentId)) {
|
|
93
|
+
componentArtifacts.set(fragment.componentId, resolveComponentArtifactPresence(handoff, fragment.componentId));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
80
97
|
if (fragments.length === 0) {
|
|
81
98
|
Logger.warn(`Pattern "${patternId}" produced no fragments. Skipping.`);
|
|
82
99
|
return null;
|
|
@@ -86,14 +103,14 @@ async function buildPattern(
|
|
|
86
103
|
Logger.warn(`Pattern "${patternId}" has missing components but will be composed from available fragments.`);
|
|
87
104
|
}
|
|
88
105
|
|
|
89
|
-
const composedHtml = composePatternHtml(patternId, pattern.title, fragments, basePath);
|
|
106
|
+
const composedHtml = composePatternHtml(patternId, pattern.title, fragments, basePath, sharedArtifacts, componentArtifacts);
|
|
90
107
|
const patternUrl = `${patternId}.html`;
|
|
91
108
|
|
|
92
109
|
const patternData: PatternListObject = {
|
|
93
110
|
...pattern,
|
|
94
111
|
id: patternId,
|
|
95
112
|
url: patternUrl,
|
|
96
|
-
path:
|
|
113
|
+
path: buildPatternDetailUrl(patternId, basePath),
|
|
97
114
|
};
|
|
98
115
|
|
|
99
116
|
await writePatternHtml(patternId, composedHtml, handoff);
|
|
@@ -109,7 +126,13 @@ async function buildPattern(
|
|
|
109
126
|
* so that all component preview HTML files already exist on disk.
|
|
110
127
|
*/
|
|
111
128
|
export async function processPatterns(handoff: Handoff, options?: ProcessPatternsOptions): Promise<PatternListObject[]> {
|
|
112
|
-
|
|
129
|
+
// Resolve the pattern set through the storage-agnostic store (v2). The filesystem store is a read
|
|
130
|
+
// view over `runtimeConfig.entries.patterns`, so these are the same records the build has always
|
|
131
|
+
// used — rebuilt into the id-keyed map the build logic below expects.
|
|
132
|
+
const runtimePatterns: Record<string, PatternListObject> = {};
|
|
133
|
+
for (const pattern of await handoff.store.patterns.list()) {
|
|
134
|
+
runtimePatterns[pattern.id] = pattern;
|
|
135
|
+
}
|
|
113
136
|
const patternIds = Object.keys(runtimePatterns);
|
|
114
137
|
const onlyPatternIds = options?.onlyPatternIds;
|
|
115
138
|
const isPartial = onlyPatternIds !== undefined;
|
|
@@ -122,6 +145,9 @@ export async function processPatterns(handoff: Handoff, options?: ProcessPattern
|
|
|
122
145
|
|
|
123
146
|
const componentOutputDir = path.resolve(handoff.workingPath, 'public/api/component');
|
|
124
147
|
const basePath = process.env.HANDOFF_APP_BASE_PATH ?? '';
|
|
148
|
+
// Resolve the shared/global artifacts once so composed patterns reference `component/main.css` and
|
|
149
|
+
// `component/main.js` only when present (deduplicated to a single global script per page).
|
|
150
|
+
const sharedArtifacts = resolveSharedArtifactPresence(handoff);
|
|
125
151
|
|
|
126
152
|
if (!isPartial) {
|
|
127
153
|
Logger.info(`Building ${patternIds.length} pattern(s)...`);
|
|
@@ -129,7 +155,7 @@ export async function processPatterns(handoff: Handoff, options?: ProcessPattern
|
|
|
129
155
|
|
|
130
156
|
for (const patternId of patternIds) {
|
|
131
157
|
const pattern = runtimePatterns[patternId];
|
|
132
|
-
const built = await buildPattern(handoff, patternId, pattern, componentOutputDir, basePath);
|
|
158
|
+
const built = await buildPattern(handoff, patternId, pattern, componentOutputDir, basePath, sharedArtifacts);
|
|
133
159
|
if (built) {
|
|
134
160
|
result.push(built);
|
|
135
161
|
}
|
|
@@ -159,7 +185,7 @@ export async function processPatterns(handoff: Handoff, options?: ProcessPattern
|
|
|
159
185
|
for (const patternId of patternIds) {
|
|
160
186
|
if (onlyPatternIds.has(patternId)) {
|
|
161
187
|
const pattern = runtimePatterns[patternId];
|
|
162
|
-
const built = await buildPattern(handoff, patternId, pattern, componentOutputDir, basePath);
|
|
188
|
+
const built = await buildPattern(handoff, patternId, pattern, componentOutputDir, basePath, sharedArtifacts);
|
|
163
189
|
if (built) {
|
|
164
190
|
existingById.set(patternId, built);
|
|
165
191
|
} else {
|
|
@@ -167,7 +193,7 @@ export async function processPatterns(handoff: Handoff, options?: ProcessPattern
|
|
|
167
193
|
}
|
|
168
194
|
} else if (!existingById.has(patternId)) {
|
|
169
195
|
const pattern = runtimePatterns[patternId];
|
|
170
|
-
const built = await buildPattern(handoff, patternId, pattern, componentOutputDir, basePath);
|
|
196
|
+
const built = await buildPattern(handoff, patternId, pattern, componentOutputDir, basePath, sharedArtifacts);
|
|
171
197
|
if (built) {
|
|
172
198
|
existingById.set(patternId, built);
|
|
173
199
|
}
|
|
@@ -1,34 +1,47 @@
|
|
|
1
1
|
import escape from 'lodash/escape';
|
|
2
2
|
import { parse } from 'node-html-parser';
|
|
3
|
+
import { SHARED_MAIN_CSS_ARTIFACT_PATH, SHARED_MAIN_JS_ARTIFACT_PATH } from '../../../artifacts';
|
|
4
|
+
import { buildArtifactUrl } from '../../../artifacts/url';
|
|
5
|
+
import type { ComponentArtifactPresence, SharedArtifactPresence } from '../component/shared-artifacts';
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* Composes multiple component preview HTML documents into a single-page HTML.
|
|
6
9
|
*
|
|
7
|
-
* Each component preview may be a React SSR document (
|
|
8
|
-
*
|
|
10
|
+
* Each component preview may be a React SSR document (server-rendered markup plus a `#root` /
|
|
11
|
+
* `#__APP_PROPS__` pair) or a static Handlebars document.
|
|
9
12
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
13
|
+
* React client/hydration bundles are component-owned artifacts (`component/<id>.client.js`). This
|
|
14
|
+
* composer copies no per-fragment bundle: it namespaces each fragment's root/props so multiple
|
|
15
|
+
* instances coexist, marks each root with the `data-handoff-component`/`data-handoff-props`
|
|
16
|
+
* attributes the component bundle hydrates by, and references each unique component's client artifact
|
|
17
|
+
* exactly once.
|
|
12
18
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* to overwrite earlier React instances before hydration completes.
|
|
19
|
+
* Shared/global artifacts follow the shared-artifact model: `component/main.css` and
|
|
20
|
+
* `component/main.js` are referenced only when present, and the global script is emitted exactly once
|
|
21
|
+
* (deduplicated across fragments) so its top-level side effects run a single time, ahead of the
|
|
22
|
+
* per-component client bundles.
|
|
18
23
|
*/
|
|
19
24
|
export const composePatternHtml = (
|
|
20
25
|
_patternId: string,
|
|
21
26
|
patternTitle: string,
|
|
22
27
|
fragments: { componentId: string; html: string }[],
|
|
23
|
-
basePath: string
|
|
28
|
+
basePath: string,
|
|
29
|
+
sharedArtifacts: SharedArtifactPresence,
|
|
30
|
+
componentArtifacts: Map<string, ComponentArtifactPresence>
|
|
24
31
|
): string => {
|
|
25
32
|
const cssHrefs = new Set<string>();
|
|
26
33
|
const bodyParts: string[] = [];
|
|
27
|
-
const
|
|
34
|
+
const clientArtifactHrefs = new Set<string>();
|
|
28
35
|
|
|
29
|
-
|
|
36
|
+
if (sharedArtifacts.mainCss) {
|
|
37
|
+
cssHrefs.add(buildArtifactUrl(SHARED_MAIN_CSS_ARTIFACT_PATH, basePath));
|
|
38
|
+
}
|
|
30
39
|
cssHrefs.add(`${basePath}/assets/css/preview.css`);
|
|
31
40
|
|
|
41
|
+
// Canonical URL of the shared global script; used to strip any per-fragment reference so the
|
|
42
|
+
// global script is emitted (and executed) exactly once for the whole composed page.
|
|
43
|
+
const globalScriptUrl = buildArtifactUrl(SHARED_MAIN_JS_ARTIFACT_PATH, basePath);
|
|
44
|
+
|
|
32
45
|
const seenComponents = new Set<string>();
|
|
33
46
|
|
|
34
47
|
for (let i = 0; i < fragments.length; i++) {
|
|
@@ -36,7 +49,11 @@ export const composePatternHtml = (
|
|
|
36
49
|
|
|
37
50
|
if (!seenComponents.has(componentId)) {
|
|
38
51
|
seenComponents.add(componentId);
|
|
39
|
-
|
|
52
|
+
// Reference a component's stylesheet only when it actually exists, so a pattern never requests
|
|
53
|
+
// an absent optional artifact for a component that declares no styles.
|
|
54
|
+
if (componentArtifacts.get(componentId)?.css) {
|
|
55
|
+
cssHrefs.add(buildArtifactUrl(`component/${componentId}.css`, basePath));
|
|
56
|
+
}
|
|
40
57
|
}
|
|
41
58
|
|
|
42
59
|
const doc = parse(html);
|
|
@@ -46,30 +63,40 @@ export const composePatternHtml = (
|
|
|
46
63
|
|
|
47
64
|
// -- Extract props JSON (React SSR) ------------------------------------
|
|
48
65
|
const propsScript = doc.querySelector('#__APP_PROPS__');
|
|
49
|
-
let propsContent =
|
|
66
|
+
let propsContent: string | null = null;
|
|
50
67
|
if (propsScript) {
|
|
51
68
|
propsContent = propsScript.textContent || '{}';
|
|
52
69
|
propsScript.remove();
|
|
53
70
|
}
|
|
54
71
|
|
|
55
|
-
// --
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
for (const script of
|
|
59
|
-
let code = script.textContent || '';
|
|
60
|
-
if (code.trim()) {
|
|
61
|
-
code = code
|
|
62
|
-
.replace(/__APP_PROPS__/g, namespacedPropsId)
|
|
63
|
-
.replace(/getElementById\(\s*["']root["']\s*\)/g, `getElementById("${namespacedRootId}")`);
|
|
64
|
-
scriptTags.push(` <script type="module">\n${code}\n </script>`);
|
|
65
|
-
}
|
|
72
|
+
// -- Drop the fragment's own client-artifact reference -----------------
|
|
73
|
+
// The bundle is referenced once per component for the whole page (below); a fragment must not
|
|
74
|
+
// carry its standalone-preview script tag into the composed document.
|
|
75
|
+
for (const script of doc.querySelectorAll('script[type="module"]')) {
|
|
66
76
|
script.remove();
|
|
67
77
|
}
|
|
68
78
|
|
|
79
|
+
// -- Drop the fragment's own global-script reference -------------------
|
|
80
|
+
// Static (Handlebars) fragments render the global `component/main.js` tag inside their body; left
|
|
81
|
+
// in place it would be inlined per fragment and run the global side effects multiple times. The
|
|
82
|
+
// page references the global script exactly once (below).
|
|
83
|
+
for (const script of doc.querySelectorAll('script')) {
|
|
84
|
+
if (script.getAttribute('src') === globalScriptUrl) {
|
|
85
|
+
script.remove();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
69
89
|
// -- Namespace the root element (React SSR) ----------------------------
|
|
90
|
+
// A React fragment exposes its mount point to the component bundle via stable data attributes.
|
|
70
91
|
const rootEl = doc.querySelector('#root');
|
|
92
|
+
const isReactFragment = !!rootEl && propsContent !== null;
|
|
71
93
|
if (rootEl) {
|
|
72
94
|
rootEl.setAttribute('id', namespacedRootId);
|
|
95
|
+
if (isReactFragment) {
|
|
96
|
+
rootEl.setAttribute('data-handoff-component', componentId);
|
|
97
|
+
rootEl.setAttribute('data-handoff-props', namespacedPropsId);
|
|
98
|
+
clientArtifactHrefs.add(buildArtifactUrl(`component/${componentId}.client.js`, basePath));
|
|
99
|
+
}
|
|
73
100
|
}
|
|
74
101
|
|
|
75
102
|
// -- Extract body content ----------------------------------------------
|
|
@@ -80,9 +107,14 @@ export const composePatternHtml = (
|
|
|
80
107
|
? rootEl.outerHTML
|
|
81
108
|
: doc.innerHTML || '';
|
|
82
109
|
|
|
110
|
+
const propsScriptTag =
|
|
111
|
+
propsContent !== null
|
|
112
|
+
? ` <script id="${namespacedPropsId}" type="application/json">${propsContent}</script>\n`
|
|
113
|
+
: '';
|
|
114
|
+
|
|
83
115
|
bodyParts.push(
|
|
84
116
|
` <div class="handoff-pattern-block" data-component="${componentId}" data-fragment="${i}">\n` +
|
|
85
|
-
|
|
117
|
+
propsScriptTag +
|
|
86
118
|
` ${bodyContent}\n` +
|
|
87
119
|
` </div>`
|
|
88
120
|
);
|
|
@@ -92,6 +124,18 @@ export const composePatternHtml = (
|
|
|
92
124
|
.map((href) => ` <link rel="stylesheet" href="${href}" />`)
|
|
93
125
|
.join('\n');
|
|
94
126
|
|
|
127
|
+
// The global script is referenced once for the whole page (deduplicated across fragments) and
|
|
128
|
+
// placed before the per-component client bundles so its side effects run first and exactly once.
|
|
129
|
+
const globalScriptTag = sharedArtifacts.mainJs
|
|
130
|
+
? ` <script src="${buildArtifactUrl(SHARED_MAIN_JS_ARTIFACT_PATH, basePath)}"></script>`
|
|
131
|
+
: '';
|
|
132
|
+
|
|
133
|
+
const clientScriptTags = Array.from(clientArtifactHrefs)
|
|
134
|
+
.map((href) => ` <script type="module" src="${href}"></script>`)
|
|
135
|
+
.join('\n');
|
|
136
|
+
|
|
137
|
+
const scriptTags = [globalScriptTag, clientScriptTags].filter(Boolean).join('\n');
|
|
138
|
+
|
|
95
139
|
return `<!DOCTYPE html>
|
|
96
140
|
<html lang="en">
|
|
97
141
|
<head>
|
|
@@ -101,7 +145,7 @@ ${linkTags}
|
|
|
101
145
|
</head>
|
|
102
146
|
<body>
|
|
103
147
|
${bodyParts.join('\n')}
|
|
104
|
-
${scriptTags
|
|
148
|
+
${scriptTags}
|
|
105
149
|
</body>
|
|
106
150
|
</html>`;
|
|
107
151
|
};
|
|
@@ -238,3 +238,45 @@ export type PatternListObject = {
|
|
|
238
238
|
id: string;
|
|
239
239
|
path: string;
|
|
240
240
|
} & PatternObject;
|
|
241
|
+
|
|
242
|
+
// ---------------------------------------------------------------------------
|
|
243
|
+
// Page types
|
|
244
|
+
// ---------------------------------------------------------------------------
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* A documentation page authored as markdown. The frontmatter is parsed into these fields and the
|
|
248
|
+
* markdown body is the rendered content. Pages are workspace-authored under `<workingPath>/pages/`
|
|
249
|
+
* and are first-class registry entities (publish/checkout) alongside components and patterns. Unlike
|
|
250
|
+
* components/patterns there is no rendered-artifact pipeline: the raw markdown is stored and rendered
|
|
251
|
+
* at runtime.
|
|
252
|
+
*/
|
|
253
|
+
export type PageObject = {
|
|
254
|
+
title: string;
|
|
255
|
+
description?: string;
|
|
256
|
+
group?: string;
|
|
257
|
+
/** Sort weight within the nav section (lower first). */
|
|
258
|
+
weight?: number;
|
|
259
|
+
/** Alternative title used in navigation. */
|
|
260
|
+
menuTitle?: string;
|
|
261
|
+
/** SEO overrides. */
|
|
262
|
+
metaTitle?: string;
|
|
263
|
+
metaDescription?: string;
|
|
264
|
+
/** When `false`, the page is hidden from navigation. */
|
|
265
|
+
enabled?: boolean;
|
|
266
|
+
/** External link target — a URL/path string, or `true` to flag the section as external. */
|
|
267
|
+
external?: string | boolean;
|
|
268
|
+
/** Optional declarative submenu structure (mirrors the markdown frontmatter `menu`). */
|
|
269
|
+
menu?: { [key: string]: any };
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
export type PageListObject = {
|
|
273
|
+
/** Stable page id — its slug path (e.g. `guides/setup`), derived from the file location (id ≡ route). */
|
|
274
|
+
id: string;
|
|
275
|
+
/** Logical route the page is served at (e.g. `/guides/setup`). */
|
|
276
|
+
path: string;
|
|
277
|
+
/**
|
|
278
|
+
* Absolute filesystem path of the source `.md` (workspace store only). Workspace-only and stripped
|
|
279
|
+
* from the published transfer item — never persisted to or served from the registry.
|
|
280
|
+
*/
|
|
281
|
+
sourcePath?: string;
|
|
282
|
+
} & PageObject;
|
|
@@ -2,6 +2,14 @@ import Handlebars from 'handlebars';
|
|
|
2
2
|
import { RegisterHandlebarsHelpersContext } from '../../types/config';
|
|
3
3
|
import { Logger } from '../../utils/logger';
|
|
4
4
|
import { SlotMetadata } from '../preview/component';
|
|
5
|
+
import {
|
|
6
|
+
renderComponentScriptTag,
|
|
7
|
+
renderComponentStyleLink,
|
|
8
|
+
renderGlobalScriptTag,
|
|
9
|
+
renderSharedStyleLinks,
|
|
10
|
+
type ComponentArtifactPresence,
|
|
11
|
+
type SharedArtifactPresence,
|
|
12
|
+
} from '../preview/component/shared-artifacts';
|
|
5
13
|
import { HandlebarsContext } from '../types';
|
|
6
14
|
|
|
7
15
|
/**
|
|
@@ -74,17 +82,35 @@ export const registerHandlebarsHelpers = (
|
|
|
74
82
|
export const createHandlebarsContext = (
|
|
75
83
|
data: { id: string; properties: { [key: string]: SlotMetadata }; title: string },
|
|
76
84
|
previewData: { values?: any },
|
|
77
|
-
options?: {
|
|
85
|
+
options?: {
|
|
86
|
+
includeSharedStyles?: boolean;
|
|
87
|
+
sharedArtifacts?: SharedArtifactPresence;
|
|
88
|
+
componentArtifacts?: ComponentArtifactPresence;
|
|
89
|
+
}
|
|
78
90
|
): HandlebarsContext => {
|
|
79
91
|
const basePath = process.env.HANDOFF_APP_BASE_PATH ?? '';
|
|
80
|
-
|
|
92
|
+
// Shared/global artifacts (`component/shared.css`, `component/main.css`, `component/main.js`) and
|
|
93
|
+
// the component's own css/js are referenced only when present, so a failed/absent build never
|
|
94
|
+
// produces a dangling reference. Absent presence info conservatively omits the artifacts.
|
|
95
|
+
const presence: SharedArtifactPresence = options?.sharedArtifacts ?? { mainJs: false, mainCss: false, sharedCss: false };
|
|
96
|
+
const componentPresence: ComponentArtifactPresence = options?.componentArtifacts ?? { css: false, js: false };
|
|
97
|
+
const sharedStyleLinks = renderSharedStyleLinks(presence, basePath, {
|
|
98
|
+
includeSharedStyles: options?.includeSharedStyles,
|
|
99
|
+
});
|
|
100
|
+
const componentStyleLink = renderComponentStyleLink(componentPresence, data.id, basePath);
|
|
101
|
+
// The global script loads before the component-specific script so global side effects run first.
|
|
102
|
+
const globalScriptTag = renderGlobalScriptTag(presence, basePath);
|
|
103
|
+
const componentScriptTag = renderComponentScriptTag(componentPresence, data.id, basePath);
|
|
81
104
|
|
|
82
105
|
return {
|
|
83
106
|
style:
|
|
84
|
-
`${
|
|
85
|
-
|
|
107
|
+
`${sharedStyleLinks ? `${sharedStyleLinks}\n` : ''}` +
|
|
108
|
+
`${componentStyleLink ? `${componentStyleLink}\n` : ''}` +
|
|
86
109
|
`<link rel="stylesheet" href="${basePath}/assets/css/preview.css">`,
|
|
87
|
-
script:
|
|
110
|
+
script:
|
|
111
|
+
`${globalScriptTag ? `${globalScriptTag}\n` : ''}` +
|
|
112
|
+
`${componentScriptTag ? `${componentScriptTag}\n` : ''}` +
|
|
113
|
+
`<script src="${basePath}/assets/js/preview.js"></script><script>var fields = ${JSON.stringify(data.properties)};</script>`,
|
|
88
114
|
properties: previewData.values || {},
|
|
89
115
|
fields: data.properties,
|
|
90
116
|
title: data.title,
|
package/src/types/config.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type Handlebars from 'handlebars';
|
|
|
3
3
|
import { Types as HandoffTypes } from 'handoff-core';
|
|
4
4
|
import { InlineConfig } from 'vite';
|
|
5
5
|
import { SlotMetadata } from '../transformers/preview/component';
|
|
6
|
-
import { ComponentListObject, PatternListObject, TransformComponentTokensResult } from '../transformers/preview/types';
|
|
6
|
+
import { ComponentListObject, PageListObject, PatternListObject, TransformComponentTokensResult } from '../transformers/preview/types';
|
|
7
7
|
import { ValidationResult } from './preview';
|
|
8
8
|
|
|
9
9
|
export interface ImageStyle {
|
|
@@ -80,6 +80,102 @@ export interface NextAppConfig {
|
|
|
80
80
|
};
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Configuration for entry points to assets and components that will be built.
|
|
85
|
+
*/
|
|
86
|
+
export interface ConfigEntries {
|
|
87
|
+
/**
|
|
88
|
+
* Path to the main SCSS entry file
|
|
89
|
+
* @example "styles/main.scss"
|
|
90
|
+
*/
|
|
91
|
+
scss?: string;
|
|
92
|
+
/**
|
|
93
|
+
* Path to the main JavaScript entry file
|
|
94
|
+
* @example "scripts/main.js"
|
|
95
|
+
*/
|
|
96
|
+
js?: string;
|
|
97
|
+
/**
|
|
98
|
+
* Array of component paths to be included in the build
|
|
99
|
+
* @example ["components/button", "components/input"]
|
|
100
|
+
*/
|
|
101
|
+
components?: string[];
|
|
102
|
+
/**
|
|
103
|
+
* Array of pattern paths to be included in the build.
|
|
104
|
+
* Patterns compose multiple component previews into single-page views.
|
|
105
|
+
* @example ["patterns/hero-section", "patterns"]
|
|
106
|
+
*/
|
|
107
|
+
patterns?: string[];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Runtime mode. Resolved solely from `runtime.mode`; never inferred from env vars or connection settings. */
|
|
111
|
+
export type RuntimeMode = 'workspace' | 'registry';
|
|
112
|
+
|
|
113
|
+
/** Format used when synthesizing local workspace declarations. */
|
|
114
|
+
export type DeclarationFormat = 'ts' | 'js' | 'cjs' | 'json';
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* User-facing `runtime` configuration block. A single optional block that selects the runtime
|
|
118
|
+
* mode and carries mode-specific host/connection settings.
|
|
119
|
+
*
|
|
120
|
+
* Note: this is the authored shape. {@link RuntimeConfig} is the separate, resolved post-discovery
|
|
121
|
+
* shape used internally by the build/runtime.
|
|
122
|
+
*/
|
|
123
|
+
export interface HandoffRuntimeConfig {
|
|
124
|
+
/**
|
|
125
|
+
* The sole determinant of runtime mode. Defaults to `'workspace'` when omitted.
|
|
126
|
+
* Mode is never inferred from environment variables, database settings, or token presence.
|
|
127
|
+
*/
|
|
128
|
+
mode?: RuntimeMode;
|
|
129
|
+
/** Workspace-mode settings. */
|
|
130
|
+
workspace?: {
|
|
131
|
+
entries?: ConfigEntries;
|
|
132
|
+
declarationFormat?: DeclarationFormat;
|
|
133
|
+
};
|
|
134
|
+
/** Registry-mode host settings. Env-var values are stored as names, never as secrets. */
|
|
135
|
+
registry?: {
|
|
136
|
+
/** Name of the env var holding the database URL. @default "DATABASE_URL" */
|
|
137
|
+
databaseUrlEnv?: string;
|
|
138
|
+
/** Name of the env var holding the registry API token. @default "HANDOFF_REGISTRY_API_TOKEN" */
|
|
139
|
+
apiTokenEnv?: string;
|
|
140
|
+
database?: {
|
|
141
|
+
/** @default "pg" */
|
|
142
|
+
adapter?: 'pg' | 'neon';
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Where published asset blobs (icons/logos/fonts/sprites/archives) are stored. Defaults to the
|
|
146
|
+
* built-in PostgreSQL `bytea` store when omitted. Secrets are never persisted here - only the
|
|
147
|
+
* *names* of the env vars their values are read from at request time.
|
|
148
|
+
*/
|
|
149
|
+
assetStorage?: {
|
|
150
|
+
/**
|
|
151
|
+
* Active storage provider for new uploads. `database` keeps bytes inline in Postgres; use the
|
|
152
|
+
* pre-packaged `vercel-blob` adapter or a `custom` module for object storage.
|
|
153
|
+
* @default "database"
|
|
154
|
+
*/
|
|
155
|
+
adapter?: 'database' | 'vercel-blob' | 'custom';
|
|
156
|
+
/** For `adapter: "custom"` - server-only module path default-exporting a `defineAssetStorage` adapter. */
|
|
157
|
+
module?: string;
|
|
158
|
+
/** For `adapter: "vercel-blob"` - env var name holding the Blob read/write token. @default "BLOB_READ_WRITE_TOKEN" */
|
|
159
|
+
tokenEnv?: string;
|
|
160
|
+
/** Max bytes kept inline in the database `bytea` column (larger uploads are rejected). @default 4194304 */
|
|
161
|
+
maxInlineBytes?: number;
|
|
162
|
+
/** Non-secret adapter options (bucket env-var names, region, a custom `providerId`, …). */
|
|
163
|
+
options?: Record<string, unknown>;
|
|
164
|
+
};
|
|
165
|
+
};
|
|
166
|
+
/**
|
|
167
|
+
* Connected-workspace settings pointing at a remote registry. A connected workspace is
|
|
168
|
+
* `mode: 'workspace'` plus this block — it is not a third runtime mode.
|
|
169
|
+
*/
|
|
170
|
+
registryConnection?: {
|
|
171
|
+
url?: string;
|
|
172
|
+
/** @default "HANDOFF_REGISTRY_URL" */
|
|
173
|
+
urlEnv?: string;
|
|
174
|
+
/** @default "HANDOFF_REGISTRY_ACCESS_TOKEN" */
|
|
175
|
+
accessTokenEnv?: string;
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
83
179
|
export interface Config {
|
|
84
180
|
dev_access_token?: string | null | undefined;
|
|
85
181
|
devAccessToken?: string | null | undefined;
|
|
@@ -108,32 +204,15 @@ export interface Config {
|
|
|
108
204
|
* Configuration for the build pipeline
|
|
109
205
|
*/
|
|
110
206
|
pipeline?: PipelineConfig;
|
|
207
|
+
/**
|
|
208
|
+
* Runtime configuration. `runtime.mode` is the sole determinant of runtime mode
|
|
209
|
+
* (`workspace` | `registry`), defaulting to `workspace` when omitted.
|
|
210
|
+
*/
|
|
211
|
+
runtime?: HandoffRuntimeConfig;
|
|
111
212
|
/**
|
|
112
213
|
* Configuration for entry points to assets and components that will be built
|
|
113
214
|
*/
|
|
114
|
-
entries?:
|
|
115
|
-
/**
|
|
116
|
-
* Path to the main SCSS entry file
|
|
117
|
-
* @example "styles/main.scss"
|
|
118
|
-
*/
|
|
119
|
-
scss?: string;
|
|
120
|
-
/**
|
|
121
|
-
* Path to the main JavaScript entry file
|
|
122
|
-
* @example "scripts/main.js"
|
|
123
|
-
*/
|
|
124
|
-
js?: string;
|
|
125
|
-
/**
|
|
126
|
-
* Array of component paths to be included in the build
|
|
127
|
-
* @example ["components/button", "components/input"]
|
|
128
|
-
*/
|
|
129
|
-
components?: string[];
|
|
130
|
-
/**
|
|
131
|
-
* Array of pattern paths to be included in the build.
|
|
132
|
-
* Patterns compose multiple component previews into single-page views.
|
|
133
|
-
* @example ["patterns/hero-section", "patterns"]
|
|
134
|
-
*/
|
|
135
|
-
patterns?: string[];
|
|
136
|
-
};
|
|
215
|
+
entries?: ConfigEntries;
|
|
137
216
|
/**
|
|
138
217
|
* Configuration for asset zip file download links
|
|
139
218
|
* @default { icons: "/icons.zip", logos: "/logos.zip" }
|
|
@@ -286,7 +365,23 @@ export interface Config {
|
|
|
286
365
|
};
|
|
287
366
|
}
|
|
288
367
|
|
|
289
|
-
|
|
368
|
+
/**
|
|
369
|
+
* Non-secret runtime values projected to the browser. Only the resolved {@link RuntimeMode}
|
|
370
|
+
* crosses to the client; secrets and connection values never do.
|
|
371
|
+
*/
|
|
372
|
+
export interface ClientRuntimeConfig {
|
|
373
|
+
mode: RuntimeMode;
|
|
374
|
+
/**
|
|
375
|
+
* True when the runtime is a connected workspace (`mode: 'workspace'` plus a resolvable
|
|
376
|
+
* `registryConnection` URL). Non-secret: it never carries the URL or token value, only whether a
|
|
377
|
+
* connection is configured. Drives the workspace-only publish affordance in the docs UI.
|
|
378
|
+
*/
|
|
379
|
+
connected: boolean;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
export type ClientConfig = Pick<Config, 'app' | 'exportsOutputDirectory' | 'sitesOutputDirectory' | 'assets_zip_links' | 'useVariables'> & {
|
|
383
|
+
runtime: ClientRuntimeConfig;
|
|
384
|
+
};
|
|
290
385
|
|
|
291
386
|
export interface RuntimeConfigComponentOptions {
|
|
292
387
|
cssRootClass?: string;
|
|
@@ -313,6 +408,9 @@ export interface RuntimeConfig {
|
|
|
313
408
|
patterns: {
|
|
314
409
|
[id: string]: PatternListObject;
|
|
315
410
|
};
|
|
411
|
+
pages: {
|
|
412
|
+
[id: string]: PageListObject;
|
|
413
|
+
};
|
|
316
414
|
};
|
|
317
415
|
options: {
|
|
318
416
|
[key: string]: RuntimeConfigComponentOptions;
|