handoff-app 2.0.0-9 → 2.0.1
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/AGENTS.md +90 -1
- package/{Changelog.md → CHANGELOG.md} +105 -1
- package/CLAUDE.md +92 -1
- package/{License.md → LICENSE.md} +1 -1
- package/README.md +818 -406
- package/RECIPES.md +975 -0
- package/UPGRADE.md +57 -9
- package/components.json +20 -20
- package/config/docs/foundations/colors/guidelines.md +0 -1
- package/config/docs/foundations/colors.md +0 -1
- package/config/docs/foundations/effects/guidelines.md +0 -1
- package/config/docs/foundations/effects/resources.md +0 -1
- package/config/docs/foundations/effects.md +0 -1
- package/config/docs/foundations/fonts.md +0 -1
- package/config/docs/foundations/grid.md +0 -1
- package/config/docs/foundations/icon.md +0 -1
- package/config/docs/foundations/icons/guidelines.md +0 -1
- package/config/docs/foundations/icons.md +0 -1
- package/config/docs/foundations/images/guidelines.md +0 -1
- package/config/docs/foundations/images/resources.md +0 -1
- package/config/docs/foundations/images.md +0 -1
- package/config/docs/foundations/logo/resources.md +0 -1
- package/config/docs/foundations/logo.md +0 -1
- package/config/docs/foundations/typography/guidelines.md +0 -1
- package/config/docs/foundations/typography/resources.md +0 -1
- package/config/docs/foundations/typography.md +0 -1
- package/config/docs/foundations.md +0 -1
- package/config/docs/guidelines.md +0 -1
- package/config/docs/index.md +0 -1
- package/config/docs/system/tokens/foundations/colors.md +0 -4
- package/config/docs/system/tokens/foundations/effects.md +0 -4
- package/config/docs/system/tokens/foundations/typography.md +0 -2
- package/config/docs/system.md +0 -2
- package/config/templates/page.md +2 -1
- package/config/templates/page.mdx +2 -1
- package/dist/ai/connections.d.ts +66 -0
- package/dist/ai/connections.js +149 -0
- package/dist/ai/define.d.ts +10 -0
- package/dist/ai/define.js +13 -0
- package/dist/ai/types.d.ts +26 -0
- package/dist/ai/types.js +10 -0
- package/dist/app-builder/build.d.ts +14 -7
- package/dist/app-builder/build.js +195 -66
- package/dist/app-builder/client-config.js +3 -2
- package/dist/app-builder/paths.d.ts +0 -12
- package/dist/app-builder/paths.js +3 -20
- package/dist/app-builder/static-export.js +1 -1
- package/dist/app-builder/vercel-output.d.ts +1 -1
- package/dist/app-builder/vercel-output.js +5 -4
- package/dist/cache/build-cache.d.ts +27 -4
- package/dist/cache/build-cache.js +114 -47
- package/dist/cache/build-inputs.d.ts +13 -0
- package/dist/cache/build-inputs.js +19 -0
- package/dist/cache/index.d.ts +2 -1
- package/dist/cache/index.js +5 -1
- package/dist/cli/create.js +1 -2
- package/dist/cli.js +1 -1
- package/dist/commands/build/index.d.ts +1 -1
- package/dist/commands/build/index.js +1 -1
- package/dist/commands/utils.d.ts +3 -3
- package/dist/config/defaults.js +7 -4
- package/dist/config/from-env.d.ts +4 -0
- package/dist/config/from-env.js +38 -1
- package/dist/config/helpers.js +2 -2
- package/dist/config/index.d.ts +0 -1
- package/dist/config/index.js +1 -4
- package/dist/config/loader.js +26 -2
- package/dist/config/resolve-env.d.ts +2 -1
- package/dist/config/resolve-env.js +28 -12
- package/dist/config/runtime.js +1 -1
- package/dist/index.d.ts +12 -7
- package/dist/index.js +18 -22
- package/dist/nav/index.d.ts +2 -2
- package/dist/nav/registry.d.ts +3 -3
- package/dist/nav/registry.js +1 -1
- package/dist/nav/workspace.d.ts +3 -3
- package/dist/nav/workspace.js +1 -1
- package/dist/pipeline/figma.d.ts +13 -2
- package/dist/pipeline/figma.js +86 -46
- package/dist/pipeline/styles.js +1 -1
- package/dist/pipeline/validation.d.ts +1 -1
- package/dist/pipeline/validation.js +3 -3
- package/dist/providers.d.ts +10 -0
- package/dist/providers.js +13 -0
- package/dist/registry/asset-storage/define.d.ts +5 -5
- package/dist/registry/asset-storage/define.js +4 -4
- package/dist/registry/asset-storage/resolve.d.ts +9 -19
- package/dist/registry/asset-storage/resolve.js +33 -21
- package/dist/registry/asset-storage/types.d.ts +37 -17
- package/dist/registry/asset-storage/types.js +5 -5
- package/dist/registry/auth/ai-keys.d.ts +32 -0
- package/dist/registry/auth/ai-keys.js +69 -0
- package/dist/registry/auth/crypto.d.ts +17 -0
- package/dist/registry/auth/crypto.js +61 -1
- package/dist/registry/auth/index.d.ts +2 -1
- package/dist/registry/auth/index.js +11 -2
- package/dist/registry/checkout/index.d.ts +2 -1
- package/dist/registry/checkout/index.js +57 -127
- package/dist/registry/client.js +53 -17
- package/dist/registry/db/driver.js +3 -3
- package/dist/registry/db/schema.d.ts +261 -3
- package/dist/registry/db/schema.js +29 -4
- package/dist/registry/email/define.d.ts +10 -0
- package/dist/registry/email/define.js +13 -0
- package/dist/registry/email/providers/smtp.d.ts +10 -0
- package/dist/registry/email/providers/smtp.js +73 -0
- package/dist/registry/email/resolve.d.ts +28 -0
- package/dist/registry/email/resolve.js +74 -0
- package/dist/registry/email/types.d.ts +24 -0
- package/dist/registry/email/types.js +6 -0
- package/dist/registry/path.d.ts +2 -0
- package/dist/registry/path.js +11 -1
- package/dist/registry/publish/errors.js +4 -0
- package/dist/registry/publish/index.js +2 -0
- package/dist/registry/publish/package.d.ts +6 -0
- package/dist/registry/publish/package.js +29 -1
- package/dist/registry/transfer.d.ts +4 -0
- package/dist/store/registry.d.ts +3 -3
- package/dist/store/registry.js +4 -4
- package/dist/transformers/preview/component/builder.d.ts +1 -9
- package/dist/transformers/preview/component/builder.js +17 -17
- package/dist/transformers/preview/component/css.d.ts +2 -1
- package/dist/transformers/preview/component/css.js +8 -5
- package/dist/transformers/preview/component/html.d.ts +3 -1
- package/dist/transformers/preview/component/html.js +6 -2
- package/dist/transformers/preview/component/javascript.d.ts +2 -1
- package/dist/transformers/preview/component/javascript.js +10 -4
- package/dist/transformers/utils/build.d.ts +9 -0
- package/dist/transformers/utils/build.js +27 -5
- package/dist/types/config.d.ts +129 -18
- package/dist/utils/path.d.ts +1 -5
- package/dist/utils/path.js +6 -23
- package/docs/api.md +6 -4
- package/docs/cli.md +275 -54
- package/drizzle/0007_add_ai_keys.sql +11 -0
- package/drizzle/0008_add_source_dir.sql +2 -0
- package/drizzle/meta/0007_snapshot.json +2013 -0
- package/drizzle/meta/0008_snapshot.json +2025 -0
- package/drizzle/meta/_journal.json +14 -0
- package/package.json +19 -8
- package/src/ai/README.md +42 -0
- package/src/ai/connections.ts +189 -0
- package/src/ai/define.ts +15 -0
- package/src/ai/types.ts +30 -0
- package/src/app/components/AiAssistant/AiAssistantPanel.tsx +144 -0
- package/src/app/components/AiAssistant/AiAssistantProvider.tsx +215 -0
- package/src/app/components/AiAssistant/AiConversation.tsx +737 -0
- package/src/app/components/AiAssistant/AiToolResult.tsx +99 -0
- package/src/app/components/AiAssistant/dockState.ts +86 -0
- package/src/app/components/AiAssistant/toolLabel.ts +24 -0
- package/src/app/components/AiAssistant/useAiChat.ts +147 -0
- package/src/app/components/AiAssistant/useAiConnections.ts +86 -0
- package/src/app/components/AiAssistant/usePageContext.ts +63 -0
- package/src/app/components/Auth/AccountLayout.tsx +58 -19
- package/src/app/components/Auth/AuthShell.tsx +27 -33
- package/src/app/components/Auth/RegistryInstallGate.tsx +4 -8
- package/src/app/components/Auth/installStatus.ts +29 -0
- package/src/app/components/Component/Preview.tsx +5 -2
- package/src/app/components/Foundations/ColorGrid.tsx +13 -14
- package/src/app/components/Layout/Header.tsx +21 -15
- package/src/app/components/Layout/Main.tsx +2 -2
- package/src/app/components/Markdown/MarkdownComponents.tsx +30 -32
- package/src/app/components/McpIntegration/McpConfigDialog.tsx +12 -51
- package/src/app/components/Navigation/MobileNav.tsx +2 -2
- package/src/app/components/Navigation/SideNav.tsx +1 -15
- package/src/app/components/context/NavProvider.tsx +7 -3
- package/src/app/components/ui/attachment.tsx +50 -0
- package/src/app/components/ui/bubble.tsx +57 -0
- package/src/app/components/ui/button.tsx +3 -1
- package/src/app/components/ui/confirm-dialog.tsx +87 -0
- package/src/app/components/ui/dialog.tsx +7 -2
- package/src/app/components/ui/marker.tsx +56 -0
- package/src/app/components/ui/sidebar.tsx +3 -1
- package/src/app/components/util/index.ts +3 -12
- package/src/app/css/index.css +64 -0
- package/src/app/lib/ai/auth.ts +33 -0
- package/src/app/lib/ai/context.ts +99 -0
- package/src/app/lib/ai/model.ts +79 -0
- package/src/app/lib/ai/prompt.ts +36 -0
- package/src/app/lib/ai/resolve.ts +97 -0
- package/src/app/lib/ai/tools.ts +120 -0
- package/src/app/lib/api/methods.ts +13 -0
- package/src/app/lib/asset-storage.ts +35 -36
- package/src/app/lib/auth/api.ts +4 -12
- package/src/app/lib/auth/email.ts +96 -23
- package/src/app/lib/docs-api/page-rendering.ts +1 -1
- package/src/app/lib/docs-api/registry.ts +2 -3
- package/src/app/lib/docs-api/runtime-config.ts +47 -21
- package/src/app/lib/mcp/components.ts +523 -0
- package/src/app/lib/mcp/page-url.ts +24 -0
- package/src/app/lib/mcp/pages.ts +84 -0
- package/src/app/lib/mcp/result.ts +33 -0
- package/src/app/lib/mcp/server.ts +39 -318
- package/src/app/lib/mcp/tokens.ts +334 -0
- package/src/app/lib/mcp/tool.ts +19 -0
- package/src/app/lib/registry-api/asset-transfer.ts +119 -11
- package/src/app/lib/registry-api/errors.ts +2 -0
- package/src/app/lib/registry-api/handler.ts +7 -1
- package/src/app/lib/registry-api/transfer.ts +28 -6
- package/src/app/lib/server-module.ts +34 -0
- package/src/app/lib/utils.ts +20 -0
- package/src/app/next.config.mjs +26 -24
- package/src/app/pages/[...slug]/index.tsx +2 -1
- package/src/app/pages/_app.tsx +6 -2
- package/src/app/pages/_document.tsx +6 -0
- package/src/app/pages/account/ai.tsx +183 -0
- package/src/app/pages/account/index.tsx +68 -68
- package/src/app/pages/account/tokens.tsx +37 -7
- package/src/app/pages/account/users.tsx +75 -15
- package/src/app/pages/api/account/ai/keys/[connectionId].ts +60 -0
- package/src/app/pages/api/account/ai/keys/index.ts +20 -0
- package/src/app/pages/api/admin/users/[id]/[action].ts +80 -11
- package/src/app/pages/api/admin/users/index.ts +2 -2
- package/src/app/pages/api/ai/chat.ts +115 -0
- package/src/app/pages/api/ai/connections.ts +23 -0
- package/src/app/pages/api/auth/request-reset.ts +14 -16
- package/src/app/pages/api/docs/nav.json.ts +1 -1
- package/src/app/pages/api/install.ts +3 -3
- package/src/app/pages/api/mcp.ts +6 -0
- package/src/app/pages/api/registry/transfer/assets/blobs/[hash]/complete.ts +11 -0
- package/src/app/pages/api/registry/transfer/assets/blobs/[hash]/upload.ts +12 -0
- package/src/app/pages/api/registry/transfer/assets/blobs/[hash].ts +1 -1
- package/src/app/pages/cli/device.tsx +10 -5
- package/src/app/pages/foundations/colors.tsx +9 -8
- package/src/app/pages/foundations/index.tsx +3 -3
- package/src/app/pages/index.tsx +2 -2
- package/src/app/pages/install.tsx +7 -2
- package/src/app/pages/login.tsx +32 -27
- package/src/app/pages/reset-password.tsx +21 -20
- package/src/app/pages/system/component/[component]/index.tsx +2 -5
- package/src/app/pages/system/index.tsx +11 -11
- package/src/app/pages/system/pattern/[pattern]/index.tsx +2 -2
- package/src/app/pages/system/tokens/components/[component]/index.tsx +0 -4
- package/src/app-builder/README.md +2 -1
- package/src/app-builder/build.ts +218 -73
- package/src/app-builder/client-config.ts +3 -2
- package/src/app-builder/paths.ts +3 -22
- package/src/app-builder/static-export.ts +1 -1
- package/src/app-builder/vercel-output.ts +5 -4
- package/src/cache/README.md +4 -1
- package/src/cache/build-cache.ts +128 -43
- package/src/cache/build-inputs.ts +28 -0
- package/src/cache/index.ts +4 -0
- package/src/cli/create.ts +1 -2
- package/src/cli.ts +1 -1
- package/src/commands/build/index.ts +1 -1
- package/src/config/README.md +10 -9
- package/src/config/defaults.ts +7 -4
- package/src/config/from-env.ts +33 -0
- package/src/config/helpers.ts +1 -3
- package/src/config/index.ts +0 -3
- package/src/config/loader.ts +25 -3
- package/src/config/resolve-env.ts +28 -15
- package/src/config/runtime.ts +1 -1
- package/src/index.ts +33 -29
- package/src/nav/index.ts +2 -2
- package/src/nav/registry.ts +3 -3
- package/src/nav/workspace.ts +3 -3
- package/src/pipeline/README.md +1 -1
- package/src/pipeline/figma.ts +98 -49
- package/src/pipeline/styles.ts +1 -1
- package/src/pipeline/validation.ts +3 -3
- package/src/providers.ts +18 -0
- package/src/registry/asset-storage/define.ts +6 -6
- package/src/registry/asset-storage/resolve.ts +38 -37
- package/src/registry/asset-storage/types.ts +39 -17
- package/src/registry/auth/ai-keys.ts +62 -0
- package/src/registry/auth/crypto.ts +63 -1
- package/src/registry/auth/index.ts +11 -1
- package/src/registry/checkout/index.ts +60 -138
- package/src/registry/client.ts +60 -20
- package/src/registry/db/driver.ts +2 -2
- package/src/registry/db/schema.ts +49 -22
- package/src/registry/email/define.ts +15 -0
- package/src/registry/email/providers/smtp.ts +39 -0
- package/src/registry/email/resolve.ts +94 -0
- package/src/registry/email/types.ts +28 -0
- package/src/registry/path.ts +11 -0
- package/src/registry/publish/errors.ts +4 -0
- package/src/registry/publish/index.ts +3 -1
- package/src/registry/publish/package.ts +33 -0
- package/src/registry/transfer.ts +4 -0
- package/src/store/registry.ts +7 -7
- package/src/transformers/preview/component/builder.ts +19 -25
- package/src/transformers/preview/component/css.ts +9 -4
- package/src/transformers/preview/component/html.ts +6 -2
- package/src/transformers/preview/component/javascript.ts +14 -4
- package/src/transformers/utils/build.ts +22 -4
- package/src/types/config.ts +142 -20
- package/src/utils/README.md +1 -1
- package/src/utils/path.ts +6 -29
- package/templates/default/handoff.config.js.tpl +10 -2
- package/templates/default/handoff.config.ts.tpl +10 -2
- package/templates/default/handoff.config.with-examples.js.tpl +10 -2
- package/templates/default/handoff.config.with-examples.ts.tpl +10 -2
- package/templates/default/package.json.tpl +2 -2
- package/.editorconfig +0 -19
- package/.eslintrc.json +0 -4
- package/.prettierignore +0 -0
- package/.prettierrc.json +0 -8
- package/.vscode/settings.json +0 -17
- package/dist/config/validator.d.ts +0 -9
- package/dist/config/validator.js +0 -24
- package/dist/registry/asset-storage/adapters/vercel-blob.d.ts +0 -17
- package/dist/registry/asset-storage/adapters/vercel-blob.js +0 -87
- package/src/app/components/old/Header.tsx +0 -89
- package/src/app/lib/mcp/shape.ts +0 -596
- package/src/app/pages/assets/fonts.tsx +0 -129
- package/src/app/pages/assets/index.tsx +0 -91
- package/src/app/pages/assets/logos.tsx +0 -75
- package/src/config/validator.ts +0 -22
- package/src/registry/asset-storage/adapters/vercel-blob.ts +0 -51
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'fs-extra';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { InlineConfig, build as viteBuild } from 'vite';
|
|
4
|
+
import { BuildInputs, withBuildInputs } from '../../../cache/build-inputs';
|
|
4
5
|
import Handoff from '../../../index';
|
|
5
6
|
import { formatDurationMs } from '../../../utils/duration';
|
|
6
7
|
import { Logger } from '../../../utils/logger';
|
|
@@ -22,6 +23,7 @@ export const SHARED_COMPONENT_CSS_FILE = 'shared.css';
|
|
|
22
23
|
* @param options.outputFilename - The name of the output file
|
|
23
24
|
* @param options.loadPaths - Array of paths for SASS to look for imports
|
|
24
25
|
* @param options.handoff - The Handoff configuration object
|
|
26
|
+
* @param options.inputs - Collects the files that the build reads, for the build cache
|
|
25
27
|
*/
|
|
26
28
|
const buildCssBundle = async ({
|
|
27
29
|
entry,
|
|
@@ -29,12 +31,14 @@ const buildCssBundle = async ({
|
|
|
29
31
|
outputFilename,
|
|
30
32
|
loadPaths,
|
|
31
33
|
handoff,
|
|
34
|
+
inputs,
|
|
32
35
|
}: {
|
|
33
36
|
entry: string;
|
|
34
37
|
outputPath: string;
|
|
35
38
|
outputFilename: string;
|
|
36
39
|
loadPaths: string[];
|
|
37
40
|
handoff: Handoff;
|
|
41
|
+
inputs?: BuildInputs;
|
|
38
42
|
}): Promise<void> => {
|
|
39
43
|
// Store the current NODE_ENV value
|
|
40
44
|
const oldNodeEnv = process.env.NODE_ENV;
|
|
@@ -85,7 +89,7 @@ const buildCssBundle = async ({
|
|
|
85
89
|
viteConfig = handoff.config.hooks.cssBuildConfig(viteConfig);
|
|
86
90
|
}
|
|
87
91
|
|
|
88
|
-
await viteBuild(viteConfig);
|
|
92
|
+
await viteBuild(withBuildInputs(viteConfig, inputs));
|
|
89
93
|
} catch (e) {
|
|
90
94
|
Logger.error(`Failed to build CSS for "${entry}"`);
|
|
91
95
|
throw e;
|
|
@@ -141,7 +145,7 @@ const writeCombinedStyleEntry = async (sources: string[], outputPath: string, id
|
|
|
141
145
|
return entryPath;
|
|
142
146
|
};
|
|
143
147
|
|
|
144
|
-
const buildComponentCss = async (data: TransformComponentTokensResult, handoff: Handoff) => {
|
|
148
|
+
const buildComponentCss = async (data: TransformComponentTokensResult, handoff: Handoff, inputs?: BuildInputs) => {
|
|
145
149
|
const id = data.id;
|
|
146
150
|
Logger.debug(`buildComponentCss`, id);
|
|
147
151
|
const outputPath = getComponentOutputPath(handoff);
|
|
@@ -175,7 +179,7 @@ const buildComponentCss = async (data: TransformComponentTokensResult, handoff:
|
|
|
175
179
|
// Setup SASS load paths
|
|
176
180
|
const loadPaths = [
|
|
177
181
|
path.resolve(handoff.workingPath),
|
|
178
|
-
|
|
182
|
+
handoff.getOutputPath(),
|
|
179
183
|
path.resolve(handoff.workingPath, 'node_modules'),
|
|
180
184
|
];
|
|
181
185
|
|
|
@@ -189,6 +193,7 @@ const buildComponentCss = async (data: TransformComponentTokensResult, handoff:
|
|
|
189
193
|
outputFilename: `${id}.css`,
|
|
190
194
|
loadPaths,
|
|
191
195
|
handoff,
|
|
196
|
+
inputs,
|
|
192
197
|
});
|
|
193
198
|
|
|
194
199
|
// Read the built CSS
|
|
@@ -242,7 +247,7 @@ export const buildMainCss = async (handoff: Handoff): Promise<void> => {
|
|
|
242
247
|
const loadPaths = [
|
|
243
248
|
path.dirname(scssEntry),
|
|
244
249
|
path.resolve(handoff.workingPath),
|
|
245
|
-
|
|
250
|
+
handoff.getOutputPath(),
|
|
246
251
|
path.resolve(handoff.workingPath, 'node_modules'),
|
|
247
252
|
];
|
|
248
253
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import react from '@vitejs/plugin-react';
|
|
2
2
|
import { Types as CoreTypes } from 'handoff-core';
|
|
3
3
|
import { InlineConfig, PluginOption, build as viteBuild } from 'vite';
|
|
4
|
+
import { BuildInputs, withBuildInputs } from '../../../cache/build-inputs';
|
|
4
5
|
import type { RendererKind, SourceFormat } from '../../../catalog/renderers';
|
|
5
6
|
import Handoff from '../../../index';
|
|
6
7
|
import { Logger } from '../../../utils/logger';
|
|
@@ -35,6 +36,7 @@ const RENDERER_PLUGINS: Record<RendererKind, PreviewPlugins> = {
|
|
|
35
36
|
* @param data - The result of transforming component tokens.
|
|
36
37
|
* @param handoff - The Handoff configuration object.
|
|
37
38
|
* @param components - Optional file components object.
|
|
39
|
+
* @param inputs - Collects the files that the build reads, for the build cache.
|
|
38
40
|
* @returns A promise that resolves to the transformed component tokens result.
|
|
39
41
|
* @throws Will throw an error if the Vite build process fails.
|
|
40
42
|
*
|
|
@@ -46,7 +48,8 @@ const RENDERER_PLUGINS: Record<RendererKind, PreviewPlugins> = {
|
|
|
46
48
|
export const buildPreviews = async (
|
|
47
49
|
data: TransformComponentTokensResult,
|
|
48
50
|
handoff: Handoff,
|
|
49
|
-
components?: CoreTypes.IDocumentationObject['components']
|
|
51
|
+
components?: CoreTypes.IDocumentationObject['components'],
|
|
52
|
+
inputs?: BuildInputs
|
|
50
53
|
): Promise<TransformComponentTokensResult> => {
|
|
51
54
|
if (!data.entries?.template) return data;
|
|
52
55
|
|
|
@@ -87,8 +90,9 @@ export const buildPreviews = async (
|
|
|
87
90
|
viteConfig = handoff.config.hooks.htmlBuildConfig(viteConfig);
|
|
88
91
|
}
|
|
89
92
|
|
|
90
|
-
await viteBuild(viteConfig);
|
|
93
|
+
await viteBuild(withBuildInputs(viteConfig, inputs));
|
|
91
94
|
} catch (error) {
|
|
95
|
+
if (inputs) inputs.failed = true;
|
|
92
96
|
Logger.error(`Error building component previews: ${data.entries.template}`, error);
|
|
93
97
|
} finally {
|
|
94
98
|
// Restore the original NODE_ENV value after vite build completes
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'fs-extra';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { InlineConfig, build as viteBuild } from 'vite';
|
|
4
|
+
import { BuildInputs, withBuildInputs } from '../../../cache/build-inputs';
|
|
4
5
|
import Handoff from '../../../index';
|
|
5
6
|
import { formatDurationMs } from '../../../utils/duration';
|
|
6
7
|
import { Logger } from '../../../utils/logger';
|
|
@@ -17,6 +18,7 @@ export const MAIN_COMPONENT_JS_FILE = 'main.js';
|
|
|
17
18
|
* @param options.entry - The entry file path for the bundle
|
|
18
19
|
* @param options.outputPath - The directory where the bundle will be output
|
|
19
20
|
* @param options.outputFilename - The name of the output file
|
|
21
|
+
* @param inputs - Collects the files that the build reads, for the build cache
|
|
20
22
|
*/
|
|
21
23
|
const buildJsBundle = async (
|
|
22
24
|
{
|
|
@@ -25,7 +27,8 @@ const buildJsBundle = async (
|
|
|
25
27
|
outputFilename,
|
|
26
28
|
format = 'cjs',
|
|
27
29
|
}: { entry: string; outputPath: string; outputFilename: string; format?: 'cjs' | 'iife' },
|
|
28
|
-
handoff: Handoff
|
|
30
|
+
handoff: Handoff,
|
|
31
|
+
inputs?: BuildInputs
|
|
29
32
|
) => {
|
|
30
33
|
const absEntryPath = path.resolve(entry);
|
|
31
34
|
|
|
@@ -62,7 +65,7 @@ const buildJsBundle = async (
|
|
|
62
65
|
viteConfig = handoff.config.hooks.jsBuildConfig(viteConfig);
|
|
63
66
|
}
|
|
64
67
|
|
|
65
|
-
await viteBuild(viteConfig);
|
|
68
|
+
await viteBuild(withBuildInputs(viteConfig, inputs));
|
|
66
69
|
} finally {
|
|
67
70
|
// Restore the original NODE_ENV value after vite build completes
|
|
68
71
|
// This prevents interference with Next.js app building/running processes
|
|
@@ -84,7 +87,11 @@ const buildJsBundle = async (
|
|
|
84
87
|
* @param handoff - The Handoff configuration object
|
|
85
88
|
* @returns The updated component transformation result with JavaScript data
|
|
86
89
|
*/
|
|
87
|
-
export const buildComponentJs = async (
|
|
90
|
+
export const buildComponentJs = async (
|
|
91
|
+
data: TransformComponentTokensResult,
|
|
92
|
+
handoff: Handoff,
|
|
93
|
+
inputs?: BuildInputs
|
|
94
|
+
): Promise<TransformComponentTokensResult> => {
|
|
88
95
|
const id = data.id;
|
|
89
96
|
const outputPath = getComponentOutputPath(handoff);
|
|
90
97
|
const builtJsPath = path.resolve(outputPath, `${id}.js`);
|
|
@@ -111,9 +118,11 @@ export const buildComponentJs = async (data: TransformComponentTokensResult, han
|
|
|
111
118
|
outputPath,
|
|
112
119
|
outputFilename: `${id}.js`,
|
|
113
120
|
},
|
|
114
|
-
handoff
|
|
121
|
+
handoff,
|
|
122
|
+
inputs
|
|
115
123
|
);
|
|
116
124
|
} catch (e) {
|
|
125
|
+
if (inputs) inputs.failed = true;
|
|
117
126
|
Logger.error(`Failed to bundle JS for component "${id}" (${id}.js):`, e);
|
|
118
127
|
return data;
|
|
119
128
|
}
|
|
@@ -126,6 +135,7 @@ export const buildComponentJs = async (data: TransformComponentTokensResult, han
|
|
|
126
135
|
delete data['jsCompiled'];
|
|
127
136
|
}
|
|
128
137
|
} catch (e) {
|
|
138
|
+
if (inputs) inputs.failed = true;
|
|
129
139
|
Logger.error(`JS build failed for component "${id}":`, e);
|
|
130
140
|
}
|
|
131
141
|
|
|
@@ -31,6 +31,10 @@ export const DEFAULT_SSR_BUILD_CONFIG: esbuild.BuildOptions = {
|
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Default esbuild configuration for client builds
|
|
34
|
+
*
|
|
35
|
+
* Production React, minified: each client bundle carries its own React copy, and a publish uploads it
|
|
36
|
+
* with the component and with every pattern that uses it. A development build quickly pushes a pattern
|
|
37
|
+
* past serverless request body limits.
|
|
34
38
|
*/
|
|
35
39
|
export const DEFAULT_CLIENT_BUILD_CONFIG: esbuild.BuildOptions = {
|
|
36
40
|
bundle: true,
|
|
@@ -39,7 +43,8 @@ export const DEFAULT_CLIENT_BUILD_CONFIG: esbuild.BuildOptions = {
|
|
|
39
43
|
platform: 'browser',
|
|
40
44
|
jsx: 'automatic',
|
|
41
45
|
sourcemap: false,
|
|
42
|
-
minify:
|
|
46
|
+
minify: true,
|
|
47
|
+
define: { 'process.env.NODE_ENV': '"production"' },
|
|
43
48
|
loader: STYLE_IMPORT_LOADERS,
|
|
44
49
|
};
|
|
45
50
|
|
|
@@ -88,6 +93,20 @@ function orderStyleImports(metafile: esbuild.Metafile, entryPath: string): strin
|
|
|
88
93
|
* declared entry.
|
|
89
94
|
*/
|
|
90
95
|
export async function collectStyleImports(entryPath: string, handoff: any): Promise<string[]> {
|
|
96
|
+
const metafile = await buildModuleGraph(entryPath, handoff);
|
|
97
|
+
return metafile ? orderStyleImports(metafile, entryPath) : [];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Every file in the module graph of an entry, stylesheets included, or `null` when the graph does
|
|
102
|
+
* not build.
|
|
103
|
+
*/
|
|
104
|
+
export async function collectModuleInputs(entryPath: string, handoff: any): Promise<string[] | null> {
|
|
105
|
+
const metafile = await buildModuleGraph(entryPath, handoff);
|
|
106
|
+
return metafile ? Object.keys(metafile.inputs).map((input) => path.resolve(input)) : null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function buildModuleGraph(entryPath: string, handoff: any): Promise<esbuild.Metafile | null> {
|
|
91
110
|
const baseConfig: esbuild.BuildOptions = {
|
|
92
111
|
...DEFAULT_SSR_BUILD_CONFIG,
|
|
93
112
|
entryPoints: [entryPath],
|
|
@@ -99,10 +118,9 @@ export async function collectStyleImports(entryPath: string, handoff: any): Prom
|
|
|
99
118
|
// The `empty` loader keeps stylesheets out of the JavaScript, and the metafile still records
|
|
100
119
|
// them as inputs, so the graph carries the order.
|
|
101
120
|
const result = await esbuild.build({ ...withStyleLoaders(hookedConfig), metafile: true });
|
|
102
|
-
|
|
103
|
-
return result.metafile ? orderStyleImports(result.metafile, entryPath) : [];
|
|
121
|
+
return result.metafile ?? null;
|
|
104
122
|
} catch {
|
|
105
|
-
return
|
|
123
|
+
return null;
|
|
106
124
|
}
|
|
107
125
|
}
|
|
108
126
|
|
package/src/types/config.ts
CHANGED
|
@@ -115,6 +115,108 @@ export type RuntimeMode = 'workspace' | 'registry';
|
|
|
115
115
|
/** Format used when synthesizing local workspace declarations. */
|
|
116
116
|
export type DeclarationFormat = 'ts' | 'js' | 'cjs';
|
|
117
117
|
|
|
118
|
+
/** How a connection's credential is supplied. Declared, never inferred from a missing key. */
|
|
119
|
+
export type AiCredentialKind = 'service' | 'user' | 'none';
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* An email option: a literal, baked into the build, or an environment reference, read by the deployed
|
|
123
|
+
* app at request time.
|
|
124
|
+
*/
|
|
125
|
+
export type HandoffEmailOption<T> = T | RuntimeEnvReference<T>;
|
|
126
|
+
|
|
127
|
+
interface HandoffEmailBase {
|
|
128
|
+
/** Sender address, such as `Handoff <no-reply@example.com>`. Use a profile for per-environment values. */
|
|
129
|
+
from?: string;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Send through an SMTP server, such as Amazon SES, SendGrid, Postmark, Mailgun or Microsoft 365. */
|
|
133
|
+
export interface HandoffSmtpEmail extends HandoffEmailBase {
|
|
134
|
+
provider: 'smtp';
|
|
135
|
+
options: {
|
|
136
|
+
host: HandoffEmailOption<string>;
|
|
137
|
+
/** @default 465, or 587 when `secure` is false */
|
|
138
|
+
port?: HandoffEmailOption<number>;
|
|
139
|
+
/**
|
|
140
|
+
* Use TLS from the start of the connection. When false, the connection upgrades with STARTTLS if
|
|
141
|
+
* the server offers it. @default true, or false when `port` is set to a port other than 465
|
|
142
|
+
*/
|
|
143
|
+
secure?: HandoffEmailOption<boolean>;
|
|
144
|
+
user?: HandoffEmailOption<string>;
|
|
145
|
+
/** Environment reference to the SMTP password. */
|
|
146
|
+
password?: RuntimeEnvReference<string>;
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Send through a server-only module that default-exports a `defineEmailProvider()` result. */
|
|
151
|
+
export interface HandoffCustomEmail extends HandoffEmailBase {
|
|
152
|
+
provider: 'custom';
|
|
153
|
+
/** Server-only module path. It must be its own file so the build can trace it into the deployed registry. */
|
|
154
|
+
module: string;
|
|
155
|
+
/**
|
|
156
|
+
* Options passed to the provider factory. Literals are baked. Environment references are resolved
|
|
157
|
+
* at request time. `apiKey` and `password` must be environment references.
|
|
158
|
+
*/
|
|
159
|
+
options?: Record<string, unknown>;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** Registry email settings. `provider` selects the shape of `options`. */
|
|
163
|
+
export type HandoffEmailConfig = HandoffSmtpEmail | HandoffCustomEmail;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* One AI connection the deployment declares. Connections are the whole surface: a reader can add a
|
|
167
|
+
* key for a declared connection and nothing else, so the server never calls a URL a reader chose.
|
|
168
|
+
*
|
|
169
|
+
* Every connection speaks the OpenAI-compatible `/chat/completions` API. A provider that fits
|
|
170
|
+
* nothing else names a server-only `module` instead of a `baseUrl`.
|
|
171
|
+
*/
|
|
172
|
+
export interface HandoffAiConnection {
|
|
173
|
+
/** Stable id. A model is addressed as `<id>/<model>`. */
|
|
174
|
+
id: string;
|
|
175
|
+
/** Name shown to a reader in the model picker and on the account page. */
|
|
176
|
+
label: string;
|
|
177
|
+
/** OpenAI-compatible base URL, such as `https://api.openai.com/v1`. Omit only when `module` is set. */
|
|
178
|
+
baseUrl?: string;
|
|
179
|
+
/**
|
|
180
|
+
* Server-only module path default-exporting a `defineAiProvider()` result, for a provider that is
|
|
181
|
+
* not OpenAI-compatible. It must be its own file so the build can trace it into the deployed
|
|
182
|
+
* registry.
|
|
183
|
+
*/
|
|
184
|
+
module?: string;
|
|
185
|
+
/**
|
|
186
|
+
* Environment reference to the deployment's own key. Its presence makes the connection a service
|
|
187
|
+
* key: the deployment pays and every reader can use it. The name is baked; the value is read at
|
|
188
|
+
* request time and never leaves the server.
|
|
189
|
+
*/
|
|
190
|
+
apiKey?: RuntimeEnvReference<string>;
|
|
191
|
+
/**
|
|
192
|
+
* Set to `'user'` when each reader supplies their own key. Without it, a connection that needs a
|
|
193
|
+
* reader's key looks like one that needs none, and the reader gets a raw 401 instead of an
|
|
194
|
+
* instruction.
|
|
195
|
+
*/
|
|
196
|
+
credential?: 'user';
|
|
197
|
+
/** The models this connection offers. A reader cannot use a model that is not listed. */
|
|
198
|
+
models?: string[];
|
|
199
|
+
/**
|
|
200
|
+
* Options passed to a `module` provider factory. Literals are baked. Environment references are
|
|
201
|
+
* resolved at request time, so secrets must be environment references.
|
|
202
|
+
*/
|
|
203
|
+
options?: Record<string, unknown>;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* The AI assistant block. Presence of the block opts the build in, and `enabled: false` turns it
|
|
208
|
+
* off. Like `mcp`, `enabled` is config-only and baked at build time, so a build without it leaves
|
|
209
|
+
* out both the chat route and the header control rather than showing a control that fails.
|
|
210
|
+
*/
|
|
211
|
+
export interface HandoffAiConfig {
|
|
212
|
+
/** @default true when the `ai` block is present */
|
|
213
|
+
enabled?: boolean;
|
|
214
|
+
/** Declared connections. Merged by `id` with any supplied through `HANDOFF_AI_CONNECTIONS`. */
|
|
215
|
+
connections?: HandoffAiConnection[];
|
|
216
|
+
/** The `<connectionId>/<model>` used when a reader has not picked one. */
|
|
217
|
+
defaultModel?: string;
|
|
218
|
+
}
|
|
219
|
+
|
|
118
220
|
/**
|
|
119
221
|
* User-facing `runtime` configuration block. A single optional block that selects the runtime
|
|
120
222
|
* mode and carries mode-specific host/connection settings.
|
|
@@ -135,6 +237,8 @@ export interface HandoffRuntimeConfig {
|
|
|
135
237
|
* @default true
|
|
136
238
|
*/
|
|
137
239
|
mcp?: boolean;
|
|
240
|
+
/** The docs AI assistant. Omit the block to leave it out of the build. See {@link HandoffAiConfig}. */
|
|
241
|
+
ai?: HandoffAiConfig;
|
|
138
242
|
/** Workspace-mode settings. */
|
|
139
243
|
workspace?: {
|
|
140
244
|
entries?: ConfigEntries;
|
|
@@ -142,9 +246,9 @@ export interface HandoffRuntimeConfig {
|
|
|
142
246
|
};
|
|
143
247
|
/** Registry-mode host settings. Env-var values are stored as names, never as secrets. */
|
|
144
248
|
registry?: {
|
|
145
|
-
/** Environment reference to the database URL. @default fromEnv('DATABASE_URL') */
|
|
146
|
-
databaseUrl?: RuntimeEnvReference<string>;
|
|
147
249
|
database?: {
|
|
250
|
+
/** Environment reference to the database URL. @default fromEnv('DATABASE_URL') */
|
|
251
|
+
url?: RuntimeEnvReference<string>;
|
|
148
252
|
/**
|
|
149
253
|
* PostgreSQL is the supported database. `driver` selects the built-in connection driver — how
|
|
150
254
|
* to connect, not which engine — over the same package-owned Postgres schema and migrations.
|
|
@@ -159,20 +263,26 @@ export interface HandoffRuntimeConfig {
|
|
|
159
263
|
*/
|
|
160
264
|
assetStorage?: {
|
|
161
265
|
/**
|
|
162
|
-
* Active storage provider for new uploads. `database` keeps bytes inline in Postgres; use
|
|
163
|
-
*
|
|
266
|
+
* Active storage provider for new uploads. `database` keeps bytes inline in Postgres; use a
|
|
267
|
+
* `custom` module for object storage.
|
|
164
268
|
* @default "database"
|
|
165
269
|
*/
|
|
166
|
-
|
|
167
|
-
/** For `
|
|
270
|
+
provider?: 'database' | 'custom';
|
|
271
|
+
/** For `provider: "custom"` - server-only module path default-exporting a `defineStorageProvider()` result. */
|
|
168
272
|
module?: string;
|
|
169
|
-
/** For `adapter: "vercel-blob"` - environment reference to the Blob read/write token. @default fromEnv('BLOB_READ_WRITE_TOKEN') */
|
|
170
|
-
token?: RuntimeEnvReference<string>;
|
|
171
273
|
/** Max bytes kept inline in the database `bytea` column (larger uploads are rejected). @default 4194304 */
|
|
172
274
|
maxInlineBytes?: number;
|
|
173
|
-
/**
|
|
275
|
+
/**
|
|
276
|
+
* Options passed to the provider factory. Literals are baked. Environment references are resolved
|
|
277
|
+
* at request time, so secrets must be environment references.
|
|
278
|
+
*/
|
|
174
279
|
options?: Record<string, unknown>;
|
|
175
280
|
};
|
|
281
|
+
/**
|
|
282
|
+
* Invitation and password-reset email. Email stays off until `from` is set and the required
|
|
283
|
+
* options of the provider have values. Until then, invitation links are shown to an administrator.
|
|
284
|
+
*/
|
|
285
|
+
email?: HandoffEmailConfig;
|
|
176
286
|
};
|
|
177
287
|
/**
|
|
178
288
|
* Connected-workspace settings pointing at a remote registry. A connected workspace is
|
|
@@ -186,11 +296,19 @@ export interface HandoffRuntimeConfig {
|
|
|
186
296
|
};
|
|
187
297
|
}
|
|
188
298
|
|
|
299
|
+
/** Connections to external services. */
|
|
300
|
+
export interface ConfigIntegrations {
|
|
301
|
+
/** The Figma file that `fetch` reads foundations from. In a terminal, `fetch` asks for an empty value. */
|
|
302
|
+
figma?: {
|
|
303
|
+
/** The Figma file ID. @default fromEnv('HANDOFF_FIGMA_PROJECT_ID', { default: null }) */
|
|
304
|
+
projectId?: EnvValue<string | null>;
|
|
305
|
+
/** A Figma personal access token. Accepts only an environment reference. @default fromEnv('HANDOFF_DEV_ACCESS_TOKEN', { default: null }) */
|
|
306
|
+
accessToken?: EnvSecret<string | null>;
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
189
310
|
export interface Config {
|
|
190
|
-
|
|
191
|
-
devAccessToken?: EnvSecret<string | null>;
|
|
192
|
-
figma_project_id?: EnvValue<string | null>;
|
|
193
|
-
figmaProjectId?: EnvValue<string | null>;
|
|
311
|
+
integrations?: ConfigIntegrations;
|
|
194
312
|
exportsOutputDirectory?: EnvValue<string>;
|
|
195
313
|
sitesOutputDirectory?: EnvValue<string>;
|
|
196
314
|
useVariables?: EnvValue<boolean>;
|
|
@@ -402,13 +520,14 @@ export interface ClientRuntimeConfig {
|
|
|
402
520
|
/** Values available after config loading. Deferred references retain their names. */
|
|
403
521
|
export type ResolvedConfig = Omit<
|
|
404
522
|
Config,
|
|
405
|
-
|
|
406
|
-
|
|
523
|
+
| 'integrations'
|
|
524
|
+
| 'exportsOutputDirectory'
|
|
525
|
+
| 'sitesOutputDirectory'
|
|
526
|
+
| 'useVariables'
|
|
527
|
+
| 'app'
|
|
528
|
+
| 'runtime'
|
|
407
529
|
> & {
|
|
408
|
-
|
|
409
|
-
devAccessToken?: string | null;
|
|
410
|
-
figma_project_id?: string | null;
|
|
411
|
-
figmaProjectId?: string | null;
|
|
530
|
+
integrations?: { figma?: { projectId?: string | null; accessToken?: string | null } };
|
|
412
531
|
exportsOutputDirectory?: string;
|
|
413
532
|
sitesOutputDirectory?: string;
|
|
414
533
|
useVariables?: boolean;
|
|
@@ -418,7 +537,10 @@ export type ResolvedConfig = Omit<
|
|
|
418
537
|
};
|
|
419
538
|
};
|
|
420
539
|
|
|
421
|
-
export type ClientConfig = Pick<
|
|
540
|
+
export type ClientConfig = Pick<
|
|
541
|
+
ResolvedConfig,
|
|
542
|
+
'app' | 'exportsOutputDirectory' | 'sitesOutputDirectory' | 'assets_zip_links' | 'useVariables'
|
|
543
|
+
> & {
|
|
422
544
|
runtime: ClientRuntimeConfig;
|
|
423
545
|
};
|
|
424
546
|
|
package/src/utils/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Shared utility functions used across the codebase.
|
|
|
8
8
|
|------|---------|
|
|
9
9
|
| `logger.ts` | `Logger` class — timestamped, color-coded console logging |
|
|
10
10
|
| `filter.ts` | `evaluateFilter()`, `filterAndSort()` — generic object filtering with logical operators |
|
|
11
|
-
| `path.ts` | `generateFilesystemSafeId()` — creates safe directory names from paths |
|
|
11
|
+
| `path.ts` | `generateFilesystemSafeId()` — creates short, safe directory names (base name + path hash) from paths |
|
|
12
12
|
| `fs.ts` | `findFilesByExtension()` — recursive file search by extension |
|
|
13
13
|
| `markdown.ts` | `parseMarkdown()` — frontmatter parse without gray-matter's unbounded module cache |
|
|
14
14
|
| `index.ts` | `filterOutNull()` type guard |
|
package/src/utils/path.ts
CHANGED
|
@@ -1,35 +1,12 @@
|
|
|
1
|
+
import { createHash } from 'crypto';
|
|
1
2
|
import path from 'path';
|
|
2
3
|
|
|
3
|
-
/**
|
|
4
|
-
* Generates a filesystem-safe directory name from an absolute path
|
|
5
|
-
* @param workingPath - The absolute working path to transform
|
|
6
|
-
* @returns A filesystem-safe string suitable for use as a directory name
|
|
7
|
-
*/
|
|
4
|
+
/** `<base name>-<path hash>`; the hash keeps directories with the same base name apart. */
|
|
8
5
|
export function generateFilesystemSafeId(workingPath: string): string {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
safeId = safeId.replace(/\//g, '-');
|
|
14
|
-
|
|
15
|
-
// Remove or replace invalid filesystem characters
|
|
16
|
-
safeId = safeId.replace(/[<>:"|?*\x00]/g, '-');
|
|
17
|
-
|
|
18
|
-
// Remove leading/trailing dashes and spaces
|
|
19
|
-
safeId = safeId.replace(/^[\s-]+|[\s-]+$/g, '');
|
|
20
|
-
|
|
21
|
-
// Handle Windows reserved names (case-insensitive)
|
|
22
|
-
const reservedNames = /^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])(\.|$)/i;
|
|
23
|
-
if (reservedNames.test(safeId)) {
|
|
24
|
-
safeId = `project-${safeId}`;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Ensure we have at least one character
|
|
28
|
-
if (!safeId) {
|
|
29
|
-
safeId = 'default-project';
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return safeId;
|
|
6
|
+
const baseName = path.basename(path.resolve(workingPath));
|
|
7
|
+
const name = baseName.replace(/[^A-Za-z0-9._-]/g, '-').replace(/^[.-]+|[.-]+$/g, '') || 'project';
|
|
8
|
+
const hash = createHash('sha256').update(normalizePathForCompare(workingPath)).digest('hex').slice(0, 8);
|
|
9
|
+
return `${name}-${hash}`;
|
|
33
10
|
}
|
|
34
11
|
|
|
35
12
|
/**
|
|
@@ -46,6 +46,15 @@ const config = {
|
|
|
46
46
|
// subdirectories are each an item.
|
|
47
47
|
// catalog: { include: ["components", "patterns"] },
|
|
48
48
|
|
|
49
|
+
// Figma: `fetch` reads the file ID and token from these variables. Defaults shown. If a value is
|
|
50
|
+
// empty, `fetch` asks for it. The token accepts only an environment reference.
|
|
51
|
+
// integrations: {
|
|
52
|
+
// figma: {
|
|
53
|
+
// projectId: fromEnv("HANDOFF_FIGMA_PROJECT_ID", { default: null }),
|
|
54
|
+
// accessToken: fromEnv("HANDOFF_DEV_ACCESS_TOKEN", { default: null }),
|
|
55
|
+
// },
|
|
56
|
+
// },
|
|
57
|
+
|
|
49
58
|
// `mode` selects the runtime: "workspace" (no database) or "registry" (Postgres). The registry
|
|
50
59
|
// block is read only by `build --target registry` and `db:migrate`, and secrets are referenced by
|
|
51
60
|
// env var name. A named profile (`handoff.config.registry.*`, `--profile registry`) is a good home
|
|
@@ -54,8 +63,7 @@ const config = {
|
|
|
54
63
|
mode: "workspace",
|
|
55
64
|
// mcp: false,
|
|
56
65
|
// registry: {
|
|
57
|
-
//
|
|
58
|
-
// database: { driver: "pg" }, // 'pg' | 'neon'
|
|
66
|
+
// database: { url: fromEnv("DATABASE_URL"), driver: "pg" }, // driver: 'pg' | 'neon'
|
|
59
67
|
// },
|
|
60
68
|
},
|
|
61
69
|
|
|
@@ -44,6 +44,15 @@ export default defineConfig({
|
|
|
44
44
|
// subdirectories are each an item.
|
|
45
45
|
// catalog: { include: ["components", "patterns"] },
|
|
46
46
|
|
|
47
|
+
// Figma: `fetch` reads the file ID and token from these variables. Defaults shown. If a value is
|
|
48
|
+
// empty, `fetch` asks for it. The token accepts only an environment reference.
|
|
49
|
+
// integrations: {
|
|
50
|
+
// figma: {
|
|
51
|
+
// projectId: fromEnv("HANDOFF_FIGMA_PROJECT_ID", { default: null }),
|
|
52
|
+
// accessToken: fromEnv("HANDOFF_DEV_ACCESS_TOKEN", { default: null }),
|
|
53
|
+
// },
|
|
54
|
+
// },
|
|
55
|
+
|
|
47
56
|
// `mode` selects the runtime: "workspace" (no database) or "registry" (Postgres). The registry
|
|
48
57
|
// block is read only by `build --target registry` and `db:migrate`, and secrets are referenced by
|
|
49
58
|
// env var name. A named profile (`handoff.config.registry.*`, `--profile registry`) is a good home
|
|
@@ -52,8 +61,7 @@ export default defineConfig({
|
|
|
52
61
|
mode: "workspace",
|
|
53
62
|
// mcp: false,
|
|
54
63
|
// registry: {
|
|
55
|
-
//
|
|
56
|
-
// database: { driver: "pg" }, // 'pg' | 'neon'
|
|
64
|
+
// database: { url: fromEnv("DATABASE_URL"), driver: "pg" }, // driver: 'pg' | 'neon'
|
|
57
65
|
// },
|
|
58
66
|
},
|
|
59
67
|
|
|
@@ -48,6 +48,15 @@ const config = {
|
|
|
48
48
|
include: ["components/button"],
|
|
49
49
|
},
|
|
50
50
|
|
|
51
|
+
// Figma: `fetch` reads the file ID and token from these variables. Defaults shown. If a value is
|
|
52
|
+
// empty, `fetch` asks for it. The token accepts only an environment reference.
|
|
53
|
+
// integrations: {
|
|
54
|
+
// figma: {
|
|
55
|
+
// projectId: fromEnv("HANDOFF_FIGMA_PROJECT_ID", { default: null }),
|
|
56
|
+
// accessToken: fromEnv("HANDOFF_DEV_ACCESS_TOKEN", { default: null }),
|
|
57
|
+
// },
|
|
58
|
+
// },
|
|
59
|
+
|
|
51
60
|
// `mode` selects the runtime: "workspace" (no database) or "registry" (Postgres). The registry
|
|
52
61
|
// block is read only by `build --target registry` and `db:migrate`, and secrets are referenced by
|
|
53
62
|
// env var name. A named profile (`handoff.config.registry.*`, `--profile registry`) is a good home
|
|
@@ -56,8 +65,7 @@ const config = {
|
|
|
56
65
|
mode: "workspace",
|
|
57
66
|
// mcp: false,
|
|
58
67
|
// registry: {
|
|
59
|
-
//
|
|
60
|
-
// database: { driver: "pg" }, // 'pg' | 'neon'
|
|
68
|
+
// database: { url: fromEnv("DATABASE_URL"), driver: "pg" }, // driver: 'pg' | 'neon'
|
|
61
69
|
// },
|
|
62
70
|
},
|
|
63
71
|
|
|
@@ -46,6 +46,15 @@ export default defineConfig({
|
|
|
46
46
|
include: ["components/button"],
|
|
47
47
|
},
|
|
48
48
|
|
|
49
|
+
// Figma: `fetch` reads the file ID and token from these variables. Defaults shown. If a value is
|
|
50
|
+
// empty, `fetch` asks for it. The token accepts only an environment reference.
|
|
51
|
+
// integrations: {
|
|
52
|
+
// figma: {
|
|
53
|
+
// projectId: fromEnv("HANDOFF_FIGMA_PROJECT_ID", { default: null }),
|
|
54
|
+
// accessToken: fromEnv("HANDOFF_DEV_ACCESS_TOKEN", { default: null }),
|
|
55
|
+
// },
|
|
56
|
+
// },
|
|
57
|
+
|
|
49
58
|
// `mode` selects the runtime: "workspace" (no database) or "registry" (Postgres). The registry
|
|
50
59
|
// block is read only by `build --target registry` and `db:migrate`, and secrets are referenced by
|
|
51
60
|
// env var name. A named profile (`handoff.config.registry.*`, `--profile registry`) is a good home
|
|
@@ -54,8 +63,7 @@ export default defineConfig({
|
|
|
54
63
|
mode: "workspace",
|
|
55
64
|
// mcp: false,
|
|
56
65
|
// registry: {
|
|
57
|
-
//
|
|
58
|
-
// database: { driver: "pg" }, // 'pg' | 'neon'
|
|
66
|
+
// database: { url: fromEnv("DATABASE_URL"), driver: "pg" }, // driver: 'pg' | 'neon'
|
|
59
67
|
// },
|
|
60
68
|
},
|
|
61
69
|
|
package/.editorconfig
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# EditorConfig is awesome: https://EditorConfig.org
|
|
2
|
-
|
|
3
|
-
# top-most EditorConfig file
|
|
4
|
-
root = true
|
|
5
|
-
|
|
6
|
-
[*.{css,scss,sass}]
|
|
7
|
-
charset = utf-8
|
|
8
|
-
indent_style = tab
|
|
9
|
-
indent_size = unset
|
|
10
|
-
end_of_line = lf
|
|
11
|
-
trim_trailing_whitespace = true
|
|
12
|
-
insert_final_newline = true
|
|
13
|
-
|
|
14
|
-
[*.{js,ts,jsx,tsx}]
|
|
15
|
-
charset = utf-8
|
|
16
|
-
indent_style = space
|
|
17
|
-
end_of_line = lf
|
|
18
|
-
trim_trailing_whitespace = true
|
|
19
|
-
insert_final_newline = true
|
package/.eslintrc.json
DELETED
package/.prettierignore
DELETED
|
File without changes
|