handoff-app 2.0.0-7 → 2.0.0-9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +130 -14
- package/UPGRADE.md +20 -0
- package/dist/app-builder/build.js +10 -2
- package/dist/app-builder/client-config.js +3 -1
- package/dist/app-builder/watchers.js +17 -7
- package/dist/cache/build-cache.js +5 -1
- package/dist/catalog/normalize.js +3 -0
- package/dist/catalog/previews.js +5 -4
- package/dist/catalog/types.d.ts +8 -0
- package/dist/cli/auth/device.d.ts +6 -1
- package/dist/cli/auth/device.js +5 -2
- package/dist/cli/auth/store.d.ts +15 -6
- package/dist/cli/auth/store.js +72 -19
- package/dist/commands/login/index.d.ts +5 -0
- package/dist/commands/login/index.js +18 -6
- package/dist/commands/logout/index.d.ts +5 -0
- package/dist/commands/logout/index.js +54 -15
- package/dist/commands/types.d.ts +2 -0
- package/dist/commands/utils.d.ts +21 -7
- package/dist/commands/utils.js +11 -10
- package/dist/config/catalog-include.d.ts +2 -2
- package/dist/config/defaults.d.ts +3 -3
- package/dist/config/defaults.js +54 -48
- package/dist/config/env.d.ts +9 -0
- package/dist/config/env.js +43 -0
- package/dist/config/errors.d.ts +4 -0
- package/dist/config/errors.js +11 -0
- package/dist/config/from-env.d.ts +24 -0
- package/dist/config/from-env.js +7 -0
- package/dist/config/helpers.d.ts +2 -0
- package/dist/config/helpers.js +3 -1
- package/dist/config/index.d.ts +2 -1
- package/dist/config/index.js +6 -1
- package/dist/config/loader.d.ts +29 -11
- package/dist/config/loader.js +121 -46
- package/dist/config/resolve-env.d.ts +5 -0
- package/dist/config/resolve-env.js +102 -0
- package/dist/config/runtime.d.ts +3 -3
- package/dist/config/runtime.js +8 -10
- package/dist/config/validator.d.ts +2 -2
- package/dist/config/validator.js +2 -4
- package/dist/handlebars.d.ts +10 -2
- package/dist/index.d.ts +33 -4
- package/dist/index.js +60 -16
- package/dist/pipeline/index.d.ts +1 -1
- package/dist/pipeline/index.js +1 -1
- package/dist/registry/asset-storage/adapters/vercel-blob.js +1 -1
- package/dist/registry/asset-storage/resolve.d.ts +2 -2
- package/dist/registry/asset-storage/resolve.js +4 -1
- package/dist/registry/checkout/index.js +4 -4
- package/dist/registry/connection.d.ts +28 -24
- package/dist/registry/connection.js +53 -67
- package/dist/registry/db/driver.d.ts +4 -11
- package/dist/registry/db/driver.js +4 -16
- package/dist/registry/db/index.d.ts +1 -1
- package/dist/registry/db/index.js +1 -2
- package/dist/registry/publish/index.js +4 -4
- package/dist/store/filesystem.d.ts +2 -2
- package/dist/transformers/plugins/ssr-render.js +40 -15
- package/dist/transformers/preview/component/css.d.ts +1 -0
- package/dist/transformers/preview/component/css.js +85 -47
- package/dist/transformers/preview/pattern/html.js +3 -1
- package/dist/transformers/preview/types.d.ts +13 -0
- package/dist/transformers/utils/build.d.ts +19 -0
- package/dist/transformers/utils/build.js +83 -1
- package/dist/transformers/utils/module.js +2 -1
- package/dist/types/config.d.ts +54 -29
- package/docs/api.md +31 -0
- package/docs/cli.md +2 -2
- package/package.json +1 -1
- package/src/app/components/Component/PageSliceResolver.tsx +1 -0
- package/src/app/components/Component/Preview.tsx +380 -189
- package/src/app/components/Component/slices/ComponentDisplaySlice.tsx +4 -0
- package/src/app/pages/account/tokens.tsx +3 -1
- package/src/app-builder/build.ts +10 -2
- package/src/app-builder/client-config.ts +5 -3
- package/src/app-builder/watchers.ts +18 -8
- package/src/cache/build-cache.ts +5 -1
- package/src/catalog/README.md +3 -0
- package/src/catalog/normalize.ts +2 -0
- package/src/catalog/previews.ts +6 -3
- package/src/catalog/types.ts +8 -0
- package/src/cli/auth/device.ts +8 -3
- package/src/cli/auth/store.ts +75 -18
- package/src/commands/login/index.ts +20 -6
- package/src/commands/logout/index.ts +74 -20
- package/src/commands/types.ts +2 -0
- package/src/commands/utils.ts +14 -5
- package/src/config/README.md +61 -1
- package/src/config/catalog-include.ts +2 -2
- package/src/config/defaults.ts +24 -14
- package/src/config/env.ts +41 -0
- package/src/config/errors.ts +7 -0
- package/src/config/from-env.ts +26 -0
- package/src/config/helpers.ts +4 -2
- package/src/config/index.ts +4 -1
- package/src/config/loader.ts +158 -50
- package/src/config/resolve-env.ts +94 -0
- package/src/config/runtime.ts +12 -7
- package/src/config/validator.ts +4 -6
- package/src/handlebars.ts +8 -2
- package/src/index.d.ts +2 -2
- package/src/index.ts +85 -8
- package/src/pipeline/index.ts +1 -1
- package/src/registry/asset-storage/adapters/vercel-blob.ts +1 -1
- package/src/registry/asset-storage/resolve.ts +6 -3
- package/src/registry/checkout/index.ts +5 -5
- package/src/registry/connection.ts +72 -71
- package/src/registry/db/driver.ts +6 -17
- package/src/registry/db/index.ts +0 -1
- package/src/registry/publish/index.ts +5 -5
- package/src/store/filesystem.ts +2 -2
- package/src/transformers/plugins/ssr-render.ts +53 -16
- package/src/transformers/preview/component/css.ts +93 -50
- package/src/transformers/preview/pattern/html.ts +3 -1
- package/src/transformers/preview/types.ts +14 -0
- package/src/transformers/utils/build.ts +80 -0
- package/src/transformers/utils/module.ts +4 -2
- package/src/types/config.ts +51 -29
- package/templates/default/env.tpl +10 -0
- package/templates/default/gitignore.tpl +7 -0
- package/templates/default/handoff.config.js.tpl +21 -172
- package/templates/default/handoff.config.ts.tpl +21 -156
- package/templates/default/handoff.config.with-examples.js.tpl +20 -171
- package/templates/default/handoff.config.with-examples.ts.tpl +20 -155
|
@@ -14,6 +14,11 @@ const store_1 = require("../../cli/auth/store");
|
|
|
14
14
|
const connection_1 = require("../../registry/connection");
|
|
15
15
|
const logger_1 = require("../../utils/logger");
|
|
16
16
|
const utils_1 = require("../utils");
|
|
17
|
+
/**
|
|
18
|
+
* Saves one registry credential per profile, so a workspace can hold a login for every registry it
|
|
19
|
+
* publishes to. The name is independent of the config profiles, and `login` is the one command that
|
|
20
|
+
* accepts a profile nothing else knows yet.
|
|
21
|
+
*/
|
|
17
22
|
const command = {
|
|
18
23
|
command: 'login',
|
|
19
24
|
describe: 'Sign in to a registry using browser device authorization',
|
|
@@ -28,17 +33,24 @@ const command = {
|
|
|
28
33
|
describe: 'Open the approval URL in the default browser (disable with --no-browser)',
|
|
29
34
|
}),
|
|
30
35
|
handler: (args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
31
|
-
var _a;
|
|
32
|
-
const handoff = (0, utils_1.createHandoff)(args);
|
|
36
|
+
var _a, _b;
|
|
37
|
+
const handoff = (0, utils_1.createHandoff)(args, { profileWithoutConfig: 'any' });
|
|
38
|
+
const profile = (_a = handoff.getProfile()) !== null && _a !== void 0 ? _a : store_1.DEFAULT_LOGIN_PROFILE;
|
|
33
39
|
try {
|
|
34
40
|
const configured = (0, connection_1.resolveRegistryConnection)(handoff.config);
|
|
35
|
-
|
|
41
|
+
// Resolved in the order publish and checkout use, so a login always targets the registry those
|
|
42
|
+
// commands would reach.
|
|
43
|
+
const saved = yield (0, store_1.readCliAuth)(handoff.workingPath, profile);
|
|
44
|
+
const remoteUrl = ((_b = args.url) === null || _b === void 0 ? void 0 : _b.trim()) || configured.url || (saved === null || saved === void 0 ? void 0 : saved.remoteUrl);
|
|
36
45
|
if (!remoteUrl) {
|
|
37
46
|
throw new Error(`Pass --url <registry-url>, configure runtime.registryConnection.url, or set "${configured.urlEnv}".`);
|
|
38
47
|
}
|
|
39
|
-
yield (0, device_1.loginWithDevice)(handoff.workingPath, remoteUrl, { openBrowser: args.browser !== false });
|
|
40
|
-
|
|
41
|
-
logger_1.Logger.
|
|
48
|
+
yield (0, device_1.loginWithDevice)(handoff.workingPath, remoteUrl, { openBrowser: args.browser !== false, profile });
|
|
49
|
+
const named = profile === store_1.DEFAULT_LOGIN_PROFILE ? '' : ` under profile "${profile}"`;
|
|
50
|
+
logger_1.Logger.success(`Logged in. Credentials saved to ${(0, store_1.cliAuthFilePath)(handoff.workingPath)}${named}.`);
|
|
51
|
+
logger_1.Logger.info(profile === store_1.DEFAULT_LOGIN_PROFILE
|
|
52
|
+
? 'Publish and checkout commands will use this login for the matching registry URL.'
|
|
53
|
+
: `Publish and checkout commands will use this login when they run with --profile ${profile}.`);
|
|
42
54
|
}
|
|
43
55
|
catch (error) {
|
|
44
56
|
logger_1.Logger.error(error instanceof Error ? error.message : String(error));
|
|
@@ -2,6 +2,11 @@ import { CommandModule } from 'yargs';
|
|
|
2
2
|
import { SharedArgs } from '../types';
|
|
3
3
|
export interface LogoutArgs extends SharedArgs {
|
|
4
4
|
url?: string;
|
|
5
|
+
all?: boolean;
|
|
5
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* `handoff-app logout` removes the login of the selected profile, leaving every other profile signed
|
|
9
|
+
* in. `--all` removes them all.
|
|
10
|
+
*/
|
|
6
11
|
declare const command: CommandModule<{}, LogoutArgs>;
|
|
7
12
|
export default command;
|
|
@@ -13,33 +13,72 @@ const device_1 = require("../../cli/auth/device");
|
|
|
13
13
|
const store_1 = require("../../cli/auth/store");
|
|
14
14
|
const logger_1 = require("../../utils/logger");
|
|
15
15
|
const utils_1 = require("../utils");
|
|
16
|
+
/** Remote revocation is best effort: the local credential goes either way. */
|
|
17
|
+
const revoke = (auth) => __awaiter(void 0, void 0, void 0, function* () {
|
|
18
|
+
try {
|
|
19
|
+
yield (0, device_1.revokeAccessToken)(auth);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
logger_1.Logger.warn(`Could not revoke the registry token for ${auth.remoteUrl} (${error instanceof Error ? error.message : String(error)}). ` +
|
|
23
|
+
'It will still be removed from this workspace.');
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* `handoff-app logout` removes the login of the selected profile, leaving every other profile signed
|
|
28
|
+
* in. `--all` removes them all.
|
|
29
|
+
*/
|
|
16
30
|
const command = {
|
|
17
31
|
command: 'logout',
|
|
18
32
|
describe: 'Revoke and remove saved registry credentials',
|
|
19
|
-
builder: (yargs) => (0, utils_1.getSharedOptions)(yargs)
|
|
33
|
+
builder: (yargs) => (0, utils_1.getSharedOptions)(yargs)
|
|
34
|
+
.option('url', {
|
|
20
35
|
type: 'string',
|
|
21
36
|
describe: 'Revoke credentials only when they belong to this exact registry URL',
|
|
22
|
-
})
|
|
37
|
+
})
|
|
38
|
+
.option('all', {
|
|
39
|
+
type: 'boolean',
|
|
40
|
+
describe: 'Revoke and remove the saved credentials for every profile',
|
|
41
|
+
})
|
|
42
|
+
.conflicts('all', 'url'),
|
|
23
43
|
handler: (args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
44
|
+
var _a;
|
|
45
|
+
const handoff = (0, utils_1.createHandoff)(args, { profileWithoutConfig: 'saved-login' });
|
|
46
|
+
const profile = (_a = handoff.getProfile()) !== null && _a !== void 0 ? _a : store_1.DEFAULT_LOGIN_PROFILE;
|
|
47
|
+
const named = profile === store_1.DEFAULT_LOGIN_PROFILE ? '' : ` for profile "${profile}"`;
|
|
48
|
+
if (args.all) {
|
|
49
|
+
const logins = yield (0, store_1.readCliLogins)(handoff.workingPath);
|
|
50
|
+
const names = Object.keys(logins);
|
|
51
|
+
if (!names.length) {
|
|
52
|
+
logger_1.Logger.info('No saved logins.');
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
for (const name of names) {
|
|
56
|
+
yield revoke(logins[name]);
|
|
57
|
+
}
|
|
32
58
|
try {
|
|
33
|
-
yield (0,
|
|
59
|
+
yield (0, store_1.clearAllCliAuth)(handoff.workingPath);
|
|
60
|
+
logger_1.Logger.success(`Logged out of every saved profile: ${names.join(', ')}. Removed ${(0, store_1.cliAuthFilePath)(handoff.workingPath)}.`);
|
|
34
61
|
}
|
|
35
62
|
catch (error) {
|
|
36
|
-
logger_1.Logger.
|
|
37
|
-
|
|
63
|
+
logger_1.Logger.error(`Could not remove saved credentials: ${error instanceof Error ? error.message : String(error)}`);
|
|
64
|
+
process.exitCode = 1;
|
|
38
65
|
}
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const auth = yield (0, store_1.readCliAuth)(handoff.workingPath, profile);
|
|
69
|
+
if (!auth) {
|
|
70
|
+
logger_1.Logger.info(`No saved login${named}.`);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (args.url && !(0, store_1.cliAuthMatchesRegistry)(auth, args.url)) {
|
|
74
|
+
logger_1.Logger.error(`The saved login${named} belongs to ${auth.remoteUrl}, not ${(0, store_1.normalizeRegistryUrl)(args.url)}. No credentials were changed.`);
|
|
75
|
+
process.exitCode = 1;
|
|
76
|
+
return;
|
|
39
77
|
}
|
|
78
|
+
yield revoke(auth);
|
|
40
79
|
try {
|
|
41
|
-
yield (0, store_1.clearCliAuth)(handoff.workingPath);
|
|
42
|
-
logger_1.Logger.success(`Logged out
|
|
80
|
+
yield (0, store_1.clearCliAuth)(handoff.workingPath, profile);
|
|
81
|
+
logger_1.Logger.success(`Logged out of ${auth.remoteUrl}${named}. Removed the saved credentials.`);
|
|
43
82
|
}
|
|
44
83
|
catch (error) {
|
|
45
84
|
logger_1.Logger.error(`Could not remove saved credentials: ${error instanceof Error ? error.message : String(error)}`);
|
package/dist/commands/types.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { Arguments } from 'yargs';
|
|
|
2
2
|
export interface SharedArgs extends Arguments {
|
|
3
3
|
/** Explicit config file, replacing the usual `handoff.config.*` lookup. */
|
|
4
4
|
config?: string;
|
|
5
|
+
/** Config profile merged onto the base config; overrides `HANDOFF_PROFILE`. */
|
|
6
|
+
profile?: string;
|
|
5
7
|
force?: boolean;
|
|
6
8
|
debug?: boolean;
|
|
7
9
|
/**
|
package/dist/commands/utils.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Argv } from 'yargs';
|
|
2
|
-
import Handoff from '../';
|
|
2
|
+
import Handoff, { HandoffOptions } from '../';
|
|
3
3
|
import { SharedArgs } from './types';
|
|
4
4
|
/**
|
|
5
5
|
* The `type` argument accepted by publish and checkout, or `all` for every kind. `catalog` covers
|
|
@@ -15,13 +15,15 @@ export type RegistryTargetKind = (typeof REGISTRY_TARGET_KINDS)[number];
|
|
|
15
15
|
*/
|
|
16
16
|
export declare const COMPAT_TARGET_KINDS: readonly ["components", "patterns", "pages", "tokens", "assets", "all"];
|
|
17
17
|
export type CompatTargetKind = (typeof COMPAT_TARGET_KINDS)[number];
|
|
18
|
-
export declare const createHandoff: (args: SharedArgs) => Handoff;
|
|
18
|
+
export declare const createHandoff: (args: SharedArgs, options?: Pick<HandoffOptions, "profileWithoutConfig">) => Handoff;
|
|
19
19
|
/**
|
|
20
|
-
* Run a registry command against a fresh Handoff.
|
|
21
|
-
*
|
|
20
|
+
* Run a registry command against a fresh Handoff. A selected profile may name a saved login instead
|
|
21
|
+
* of a config file, because here the profile selects the registry. Registry failures are the
|
|
22
|
+
* user's to act on, so they surface as one actionable line and a non-zero exit rather than a stack
|
|
23
|
+
* trace.
|
|
22
24
|
*/
|
|
23
25
|
export declare const runRegistryCommand: (args: SharedArgs, run: (handoff: Handoff) => Promise<unknown>) => Promise<void>;
|
|
24
|
-
export declare const getSharedOptions: (yargs: Argv) => Argv<import("yargs").Omit<{}, "debug" | "config" | "force"> & import("yargs").InferredOptionTypes<{
|
|
26
|
+
export declare const getSharedOptions: (yargs: Argv) => Argv<import("yargs").Omit<{}, "debug" | "config" | "profile" | "force"> & import("yargs").InferredOptionTypes<{
|
|
25
27
|
config: {
|
|
26
28
|
alias: string;
|
|
27
29
|
type: "string";
|
|
@@ -37,9 +39,13 @@ export declare const getSharedOptions: (yargs: Argv) => Argv<import("yargs").Omi
|
|
|
37
39
|
type: "boolean";
|
|
38
40
|
description: string;
|
|
39
41
|
};
|
|
42
|
+
profile: {
|
|
43
|
+
type: "string";
|
|
44
|
+
description: string;
|
|
45
|
+
};
|
|
40
46
|
}>>;
|
|
41
47
|
/** Shared options plus the transfer options: publish and its compatibility aliases use these. */
|
|
42
|
-
export declare const getPublishOptions: (yargs: Argv) => Argv<import("yargs").Omit<import("yargs").Omit<{}, "debug" | "config" | "force"> & import("yargs").InferredOptionTypes<{
|
|
48
|
+
export declare const getPublishOptions: (yargs: Argv) => Argv<import("yargs").Omit<import("yargs").Omit<{}, "debug" | "config" | "profile" | "force"> & import("yargs").InferredOptionTypes<{
|
|
43
49
|
config: {
|
|
44
50
|
alias: string;
|
|
45
51
|
type: "string";
|
|
@@ -55,6 +61,10 @@ export declare const getPublishOptions: (yargs: Argv) => Argv<import("yargs").Om
|
|
|
55
61
|
type: "boolean";
|
|
56
62
|
description: string;
|
|
57
63
|
};
|
|
64
|
+
profile: {
|
|
65
|
+
type: "string";
|
|
66
|
+
description: string;
|
|
67
|
+
};
|
|
58
68
|
}>, "build" | "dry-run"> & import("yargs").InferredOptionTypes<{
|
|
59
69
|
'dry-run': {
|
|
60
70
|
type: "boolean";
|
|
@@ -67,7 +77,7 @@ export declare const getPublishOptions: (yargs: Argv) => Argv<import("yargs").Om
|
|
|
67
77
|
};
|
|
68
78
|
}>>;
|
|
69
79
|
/** Shared options plus `--dry-run`: checkout and its compatibility aliases use these. */
|
|
70
|
-
export declare const getCheckoutOptions: (yargs: Argv) => Argv<import("yargs").Omit<import("yargs").Omit<{}, "debug" | "config" | "force"> & import("yargs").InferredOptionTypes<{
|
|
80
|
+
export declare const getCheckoutOptions: (yargs: Argv) => Argv<import("yargs").Omit<import("yargs").Omit<{}, "debug" | "config" | "profile" | "force"> & import("yargs").InferredOptionTypes<{
|
|
71
81
|
config: {
|
|
72
82
|
alias: string;
|
|
73
83
|
type: "string";
|
|
@@ -83,6 +93,10 @@ export declare const getCheckoutOptions: (yargs: Argv) => Argv<import("yargs").O
|
|
|
83
93
|
type: "boolean";
|
|
84
94
|
description: string;
|
|
85
95
|
};
|
|
96
|
+
profile: {
|
|
97
|
+
type: "string";
|
|
98
|
+
description: string;
|
|
99
|
+
};
|
|
86
100
|
}>, "dry-run"> & import("yargs").InferredOptionTypes<{
|
|
87
101
|
'dry-run': {
|
|
88
102
|
type: "boolean";
|
package/dist/commands/utils.js
CHANGED
|
@@ -28,21 +28,18 @@ exports.REGISTRY_TARGET_KINDS = ['catalog', 'pages', 'tokens', 'assets', 'all'];
|
|
|
28
28
|
* not take, and omits `catalog`, which the docs do not describe.
|
|
29
29
|
*/
|
|
30
30
|
exports.COMPAT_TARGET_KINDS = [...content_kinds_1.REGISTRY_ENTITY_KINDS, 'all'];
|
|
31
|
-
const createHandoff = (args) => new __1.default({
|
|
32
|
-
debug: args.debug,
|
|
33
|
-
force: args.force,
|
|
34
|
-
configPath: args.config,
|
|
35
|
-
dryRun: args.dryRun,
|
|
31
|
+
const createHandoff = (args, options = {}) => new __1.default(Object.assign({ debug: args.debug, force: args.force, configPath: args.config, profile: args.profile, dryRun: args.dryRun,
|
|
36
32
|
// yargs gives `--no-build` as `build: false`; anything else leaves the build in place.
|
|
37
|
-
skipBuild: args.build === false,
|
|
38
|
-
});
|
|
33
|
+
skipBuild: args.build === false }, options));
|
|
39
34
|
exports.createHandoff = createHandoff;
|
|
40
35
|
/**
|
|
41
|
-
* Run a registry command against a fresh Handoff.
|
|
42
|
-
*
|
|
36
|
+
* Run a registry command against a fresh Handoff. A selected profile may name a saved login instead
|
|
37
|
+
* of a config file, because here the profile selects the registry. Registry failures are the
|
|
38
|
+
* user's to act on, so they surface as one actionable line and a non-zero exit rather than a stack
|
|
39
|
+
* trace.
|
|
43
40
|
*/
|
|
44
41
|
const runRegistryCommand = (args, run) => __awaiter(void 0, void 0, void 0, function* () {
|
|
45
|
-
const handoff = (0, exports.createHandoff)(args);
|
|
42
|
+
const handoff = (0, exports.createHandoff)(args, { profileWithoutConfig: 'saved-login' });
|
|
46
43
|
try {
|
|
47
44
|
yield run(handoff);
|
|
48
45
|
}
|
|
@@ -69,6 +66,10 @@ const getSharedOptions = (yargs) => {
|
|
|
69
66
|
type: 'boolean',
|
|
70
67
|
description: 'Enable debug mode',
|
|
71
68
|
},
|
|
69
|
+
profile: {
|
|
70
|
+
type: 'string',
|
|
71
|
+
description: 'Config profile merged onto the base config (handoff.config.<profile>.*), and the saved login that registry commands use; overrides HANDOFF_PROFILE',
|
|
72
|
+
},
|
|
72
73
|
});
|
|
73
74
|
};
|
|
74
75
|
exports.getSharedOptions = getSharedOptions;
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
* A workspace registers items under `catalog.include`. Discovery expands collection directories;
|
|
12
12
|
* the writer appends unlisted paths in JSON, TypeScript, JavaScript, and CommonJS project configs.
|
|
13
13
|
*/
|
|
14
|
-
import {
|
|
14
|
+
import { ResolvedConfig } from '../types/config';
|
|
15
15
|
/** Minimal handoff shape needed here; avoids importing the full Handoff class (circular dep). */
|
|
16
16
|
interface ConfigContext {
|
|
17
|
-
config?:
|
|
17
|
+
config?: ResolvedConfig;
|
|
18
18
|
workingPath: string;
|
|
19
19
|
}
|
|
20
20
|
/** Outcome of {@link addToCatalog}: `added` on success, `unsupported` when the config couldn't be edited. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ClientConfig, Config } from '../types/config';
|
|
1
|
+
import { ClientConfig, Config, ResolvedConfig } from '../types/config';
|
|
2
2
|
export interface ImageStyle {
|
|
3
3
|
name: string;
|
|
4
4
|
style: string;
|
|
@@ -7,7 +7,7 @@ export interface ImageStyle {
|
|
|
7
7
|
description: string;
|
|
8
8
|
}
|
|
9
9
|
/** Whether the MCP endpoint is served. On unless `runtime.mcp` is explicitly `false`. */
|
|
10
|
-
export declare const isMcpEnabled: (config: Config | null | undefined) => boolean;
|
|
10
|
+
export declare const isMcpEnabled: (config: Pick<Config, "runtime"> | Pick<ResolvedConfig, "runtime"> | null | undefined) => boolean;
|
|
11
11
|
export declare const defaultConfig: () => Config;
|
|
12
12
|
/**
|
|
13
13
|
* Retrieves the client configuration from the provided handoff configuration.
|
|
@@ -15,4 +15,4 @@ export declare const defaultConfig: () => Config;
|
|
|
15
15
|
* @param config - The full handoff Config object.
|
|
16
16
|
* @returns The client configuration object.
|
|
17
17
|
*/
|
|
18
|
-
export declare const getClientConfig: (config:
|
|
18
|
+
export declare const getClientConfig: (config: ResolvedConfig) => ClientConfig;
|
package/dist/config/defaults.js
CHANGED
|
@@ -1,60 +1,66 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getClientConfig = exports.defaultConfig = exports.isMcpEnabled = void 0;
|
|
4
|
+
const from_env_1 = require("./from-env");
|
|
4
5
|
const connection_1 = require("../registry/connection");
|
|
5
6
|
/** Whether the MCP endpoint is served. On unless `runtime.mcp` is explicitly `false`. */
|
|
6
7
|
const isMcpEnabled = (config) => { var _a; return ((_a = config === null || config === void 0 ? void 0 : config.runtime) === null || _a === void 0 ? void 0 : _a.mcp) !== false; };
|
|
7
8
|
exports.isMcpEnabled = isMcpEnabled;
|
|
8
|
-
const defaultConfig = () => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
const defaultConfig = () => ({
|
|
10
|
+
dev_access_token: (0, from_env_1.fromEnv)('HANDOFF_DEV_ACCESS_TOKEN', { default: null }),
|
|
11
|
+
figma_project_id: (0, from_env_1.fromEnv)('HANDOFF_FIGMA_PROJECT_ID', { default: null }),
|
|
12
|
+
runtime: {
|
|
13
|
+
mode: 'workspace',
|
|
14
|
+
registryConnection: {
|
|
15
|
+
url: (0, from_env_1.fromEnv)('HANDOFF_REGISTRY_URL', { default: '' }),
|
|
16
|
+
accessToken: (0, from_env_1.fromEnv)('HANDOFF_REGISTRY_ACCESS_TOKEN', { default: '' }),
|
|
15
17
|
},
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
reactDocgen: {
|
|
20
|
-
maxDepth: 7,
|
|
21
|
-
excludeDirectories: ['dist', 'build', '.next'],
|
|
18
|
+
registry: {
|
|
19
|
+
databaseUrl: (0, from_env_1.fromEnv)('DATABASE_URL'),
|
|
20
|
+
assetStorage: { token: (0, from_env_1.fromEnv)('BLOB_READ_WRITE_TOKEN') },
|
|
22
21
|
},
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
22
|
+
},
|
|
23
|
+
exportsOutputDirectory: (0, from_env_1.fromEnv)('HANDOFF_OUTPUT_DIR', { default: 'exported' }),
|
|
24
|
+
sitesOutputDirectory: (0, from_env_1.fromEnv)('HANDOFF_SITES_DIR', { default: 'out' }),
|
|
25
|
+
useVariables: (0, from_env_1.fromEnv)('HANDOFF_USE_VARIABLES', { default: false }),
|
|
26
|
+
reactDocgen: {
|
|
27
|
+
maxDepth: 7,
|
|
28
|
+
excludeDirectories: ['dist', 'build', '.next'],
|
|
29
|
+
},
|
|
30
|
+
app: {
|
|
31
|
+
theme: 'default',
|
|
32
|
+
title: 'Handoff Design System',
|
|
33
|
+
client: 'Handoff',
|
|
34
|
+
google_tag_manager: null,
|
|
35
|
+
attribution: true,
|
|
36
|
+
type_copy: 'Almost before we knew it, we had left the ground.',
|
|
37
|
+
type_sort: [
|
|
38
|
+
'Heading 1',
|
|
39
|
+
'Heading 2',
|
|
40
|
+
'Heading 3',
|
|
41
|
+
'Heading 4',
|
|
42
|
+
'Heading 5',
|
|
43
|
+
'Heading 6',
|
|
44
|
+
'Paragraph',
|
|
45
|
+
'Subheading',
|
|
46
|
+
'Blockquote',
|
|
47
|
+
'Input Labels',
|
|
48
|
+
'Link',
|
|
49
|
+
],
|
|
50
|
+
color_sort: ['primary', 'secondary', 'extra', 'system'],
|
|
51
|
+
component_sort: ['primary', 'secondary', 'transparent'],
|
|
52
|
+
base_path: '',
|
|
53
|
+
breakpoints: {
|
|
54
|
+
mobile: { size: 400, name: 'Mobile' },
|
|
55
|
+
tablet: { size: 800, name: 'Medium' },
|
|
56
|
+
desktop: { size: 1100, name: 'Large' },
|
|
55
57
|
},
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
+
ports: {
|
|
59
|
+
app: (0, from_env_1.fromEnv)('HANDOFF_APP_PORT', { default: 3000 }),
|
|
60
|
+
websocket: (0, from_env_1.fromEnv)('HANDOFF_WEBSOCKET_PORT', { default: 3001 }),
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
});
|
|
58
64
|
exports.defaultConfig = defaultConfig;
|
|
59
65
|
/**
|
|
60
66
|
* Retrieves the client configuration from the provided handoff configuration.
|
|
@@ -64,7 +70,7 @@ exports.defaultConfig = defaultConfig;
|
|
|
64
70
|
*/
|
|
65
71
|
const getClientConfig = (config) => {
|
|
66
72
|
var _a;
|
|
67
|
-
const { app, exportsOutputDirectory, sitesOutputDirectory, assets_zip_links = { icons: null, logos: null }, useVariables, runtime, } =
|
|
73
|
+
const { app, exportsOutputDirectory, sitesOutputDirectory, assets_zip_links = { icons: null, logos: null }, useVariables, runtime, } = config;
|
|
68
74
|
const mode = (_a = runtime === null || runtime === void 0 ? void 0 : runtime.mode) !== null && _a !== void 0 ? _a : 'workspace';
|
|
69
75
|
// Connected-workspace affordance: only a workspace with a resolvable registry URL is "connected".
|
|
70
76
|
// URL-only threshold (no token required) so the publish hint surfaces before the access token is
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apply `.env.<profile>` on top of the base `.env` for the selected profile. The file is optional:
|
|
3
|
+
* a profile needs a config file, not an env file.
|
|
4
|
+
*
|
|
5
|
+
* Precedence is the process environment, then the profile env file, then `.env`. Dotenv's own
|
|
6
|
+
* `override` option cannot express that - it would replace the values the shell supplied too - so
|
|
7
|
+
* the keys already present at startup are skipped here.
|
|
8
|
+
*/
|
|
9
|
+
export declare const loadProfileEnv: (profile?: string, directory?: string) => void;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.loadProfileEnv = void 0;
|
|
7
|
+
const dotenv_1 = __importDefault(require("dotenv"));
|
|
8
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
/**
|
|
11
|
+
* Environment variables that were already set when the process started. They outrank every `.env`
|
|
12
|
+
* file, so an inline `DATABASE_URL=… handoff-app db:migrate` wins over what a file says. Recorded
|
|
13
|
+
* before the base `.env` is read, which is why this module is imported first.
|
|
14
|
+
*/
|
|
15
|
+
const processEnvKeys = new Set(Object.keys(process.env));
|
|
16
|
+
// The base `.env`, read from the directory the command runs in, at module load so `process.env` is
|
|
17
|
+
// populated before the first Handoff is constructed.
|
|
18
|
+
dotenv_1.default.config();
|
|
19
|
+
/**
|
|
20
|
+
* Apply `.env.<profile>` on top of the base `.env` for the selected profile. The file is optional:
|
|
21
|
+
* a profile needs a config file, not an env file.
|
|
22
|
+
*
|
|
23
|
+
* Precedence is the process environment, then the profile env file, then `.env`. Dotenv's own
|
|
24
|
+
* `override` option cannot express that - it would replace the values the shell supplied too - so
|
|
25
|
+
* the keys already present at startup are skipped here.
|
|
26
|
+
*/
|
|
27
|
+
const loadProfileEnv = (profile, directory = process.cwd()) => {
|
|
28
|
+
if (!profile) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const envPath = path_1.default.resolve(directory, `.env.${profile}`);
|
|
32
|
+
if (!fs_extra_1.default.existsSync(envPath)) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const parsed = dotenv_1.default.parse(fs_extra_1.default.readFileSync(envPath));
|
|
36
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
37
|
+
if (processEnvKeys.has(key)) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
process.env[key] = value;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
exports.loadProfileEnv = loadProfileEnv;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HandoffConfigError = void 0;
|
|
4
|
+
/** Raised when configuration cannot be loaded or resolved. */
|
|
5
|
+
class HandoffConfigError extends Error {
|
|
6
|
+
constructor(message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = 'HandoffConfigError';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
exports.HandoffConfigError = HandoffConfigError;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** A JSON-compatible environment reference. Creating one never reads the environment. */
|
|
2
|
+
export type EnvReference<T> = {
|
|
3
|
+
$env: string;
|
|
4
|
+
default?: T;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Use for values that can be literals or environment references, such as output directories.
|
|
8
|
+
* References resolve at config load; ResolvedConfig holds the value.
|
|
9
|
+
*/
|
|
10
|
+
export type EnvValue<T> = T | EnvReference<T>;
|
|
11
|
+
/**
|
|
12
|
+
* Use for credentials the CLI needs, such as the Figma token. Only references are allowed.
|
|
13
|
+
* References resolve at config load; ResolvedConfig holds the secret value.
|
|
14
|
+
*/
|
|
15
|
+
export type EnvSecret<T> = EnvReference<T>;
|
|
16
|
+
/**
|
|
17
|
+
* Use for values the deployed app reads, such as its database URL. Only references are allowed.
|
|
18
|
+
* ResolvedConfig keeps the reference; the build stores its name, and the deployed app reads the value at runtime.
|
|
19
|
+
*/
|
|
20
|
+
export type RuntimeEnvReference<T> = EnvReference<T>;
|
|
21
|
+
export declare const fromEnv: <T = string>(name: string, options?: {
|
|
22
|
+
default: T;
|
|
23
|
+
}) => EnvReference<T>;
|
|
24
|
+
export declare const isEnvReference: (value: unknown) => value is EnvReference<unknown>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isEnvReference = exports.fromEnv = void 0;
|
|
4
|
+
const fromEnv = (name, options) => options === undefined ? { $env: name } : { $env: name, default: options.default };
|
|
5
|
+
exports.fromEnv = fromEnv;
|
|
6
|
+
const isEnvReference = (value) => value !== null && typeof value === 'object' && Object.prototype.hasOwnProperty.call(value, '$env');
|
|
7
|
+
exports.isEnvReference = isEnvReference;
|
package/dist/config/helpers.d.ts
CHANGED
|
@@ -3,5 +3,7 @@ export declare const normalizeConfig: (config: Config) => Config;
|
|
|
3
3
|
/**
|
|
4
4
|
* Optional helper for strongly-typed config authoring.
|
|
5
5
|
* It normalizes modern camelCase keys to legacy runtime keys.
|
|
6
|
+
*
|
|
7
|
+
* Every part of `Config` is optional, so this types a profile as well as a base config.
|
|
6
8
|
*/
|
|
7
9
|
export declare const defineConfig: (config: Config) => Config;
|
package/dist/config/helpers.js
CHANGED
|
@@ -20,12 +20,14 @@ const normalizeAppConfig = (app) => {
|
|
|
20
20
|
};
|
|
21
21
|
const normalizeConfig = (config) => {
|
|
22
22
|
const { devAccessToken, figmaProjectId, assetsZipLinks, app } = config, rest = __rest(config, ["devAccessToken", "figmaProjectId", "assetsZipLinks", "app"]);
|
|
23
|
-
return Object.assign(Object.assign({}, rest), { dev_access_token: devAccessToken !==
|
|
23
|
+
return Object.assign(Object.assign({}, rest), { dev_access_token: devAccessToken !== undefined ? devAccessToken : config.dev_access_token, figma_project_id: figmaProjectId !== undefined ? figmaProjectId : config.figma_project_id, assets_zip_links: assetsZipLinks !== null && assetsZipLinks !== void 0 ? assetsZipLinks : config.assets_zip_links, app: normalizeAppConfig(app) });
|
|
24
24
|
};
|
|
25
25
|
exports.normalizeConfig = normalizeConfig;
|
|
26
26
|
/**
|
|
27
27
|
* Optional helper for strongly-typed config authoring.
|
|
28
28
|
* It normalizes modern camelCase keys to legacy runtime keys.
|
|
29
|
+
*
|
|
30
|
+
* Every part of `Config` is optional, so this types a profile as well as a base config.
|
|
29
31
|
*/
|
|
30
32
|
const defineConfig = (config) => (0, exports.normalizeConfig)(config);
|
|
31
33
|
exports.defineConfig = defineConfig;
|
package/dist/config/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { defaultConfig, getClientConfig, isMcpEnabled } from './defaults';
|
|
2
2
|
export type { ImageStyle } from './defaults';
|
|
3
|
-
export {
|
|
3
|
+
export { loadProfileEnv } from './env';
|
|
4
|
+
export { CONFIG_FILE_PREFERENCE, HandoffConfigError, initConfig, initConfigWithMetadata, resolveProfileSelection } from './loader';
|
|
4
5
|
export type { ConfigLoadContext } from './loader';
|
|
5
6
|
export { defineConfig } from './helpers';
|
|
6
7
|
export { initRuntimeConfig } from './runtime';
|
package/dist/config/index.js
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isIncluded = exports.addToCatalog = exports.validateConfig = exports.initRuntimeConfig = exports.defineConfig = exports.initConfigWithMetadata = exports.initConfig = exports.HandoffConfigError = exports.isMcpEnabled = exports.getClientConfig = exports.defaultConfig = void 0;
|
|
3
|
+
exports.isIncluded = exports.addToCatalog = exports.validateConfig = exports.initRuntimeConfig = exports.defineConfig = exports.resolveProfileSelection = exports.initConfigWithMetadata = exports.initConfig = exports.HandoffConfigError = exports.CONFIG_FILE_PREFERENCE = exports.loadProfileEnv = exports.isMcpEnabled = exports.getClientConfig = exports.defaultConfig = void 0;
|
|
4
4
|
// Config defaults and client config
|
|
5
5
|
var defaults_1 = require("./defaults");
|
|
6
6
|
Object.defineProperty(exports, "defaultConfig", { enumerable: true, get: function () { return defaults_1.defaultConfig; } });
|
|
7
7
|
Object.defineProperty(exports, "getClientConfig", { enumerable: true, get: function () { return defaults_1.getClientConfig; } });
|
|
8
8
|
Object.defineProperty(exports, "isMcpEnabled", { enumerable: true, get: function () { return defaults_1.isMcpEnabled; } });
|
|
9
|
+
// Environment files
|
|
10
|
+
var env_1 = require("./env");
|
|
11
|
+
Object.defineProperty(exports, "loadProfileEnv", { enumerable: true, get: function () { return env_1.loadProfileEnv; } });
|
|
9
12
|
// Config file loading
|
|
10
13
|
var loader_1 = require("./loader");
|
|
14
|
+
Object.defineProperty(exports, "CONFIG_FILE_PREFERENCE", { enumerable: true, get: function () { return loader_1.CONFIG_FILE_PREFERENCE; } });
|
|
11
15
|
Object.defineProperty(exports, "HandoffConfigError", { enumerable: true, get: function () { return loader_1.HandoffConfigError; } });
|
|
12
16
|
Object.defineProperty(exports, "initConfig", { enumerable: true, get: function () { return loader_1.initConfig; } });
|
|
13
17
|
Object.defineProperty(exports, "initConfigWithMetadata", { enumerable: true, get: function () { return loader_1.initConfigWithMetadata; } });
|
|
18
|
+
Object.defineProperty(exports, "resolveProfileSelection", { enumerable: true, get: function () { return loader_1.resolveProfileSelection; } });
|
|
14
19
|
// Config helpers
|
|
15
20
|
var helpers_1 = require("./helpers");
|
|
16
21
|
Object.defineProperty(exports, "defineConfig", { enumerable: true, get: function () { return helpers_1.defineConfig; } });
|