handoff-app 2.0.0-7 → 2.0.0-8
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 +111 -11
- 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/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 +119 -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/validator.d.ts +2 -2
- package/dist/config/validator.js +2 -4
- 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/types/config.d.ts +48 -29
- package/docs/api.md +31 -0
- package/docs/cli.md +2 -2
- package/package.json +1 -1
- 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/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 +156 -50
- package/src/config/resolve-env.ts +94 -0
- package/src/config/runtime.ts +3 -3
- package/src/config/validator.ts +4 -6
- 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/types/config.ts +45 -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
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* {@link import('../db/driver')}: only provider selection, module location, non-secret options, and
|
|
7
7
|
* env-var *names* are ever persisted; secret *values* are read from `process.env` at request time.
|
|
8
8
|
*/
|
|
9
|
-
import type {
|
|
9
|
+
import type { ResolvedConfig } from '../../types/config';
|
|
10
10
|
import type { AssetStorageProvider } from '../db/schema';
|
|
11
11
|
/** Which adapter implementation is active. */
|
|
12
12
|
export type AssetStorageAdapterKind = 'database' | 'vercel-blob' | 'custom';
|
|
@@ -42,4 +42,4 @@ export interface ResolvedAssetStorage {
|
|
|
42
42
|
/** Resolve raw asset storage settings into a fully-defaulted shape. */
|
|
43
43
|
export declare const resolveAssetStorageSettings: (settings: AssetStorageSettings | null | undefined) => ResolvedAssetStorage;
|
|
44
44
|
/** Resolve the active asset storage settings from a loaded config (CLI/build side). */
|
|
45
|
-
export declare const resolveAssetStorageFromConfig: (config:
|
|
45
|
+
export declare const resolveAssetStorageFromConfig: (config: ResolvedConfig | null | undefined) => ResolvedAssetStorage;
|
|
@@ -32,5 +32,8 @@ const resolveAssetStorageSettings = (settings) => {
|
|
|
32
32
|
};
|
|
33
33
|
exports.resolveAssetStorageSettings = resolveAssetStorageSettings;
|
|
34
34
|
/** Resolve the active asset storage settings from a loaded config (CLI/build side). */
|
|
35
|
-
const resolveAssetStorageFromConfig = (config) => {
|
|
35
|
+
const resolveAssetStorageFromConfig = (config) => {
|
|
36
|
+
var _a, _b, _c, _d, _e, _f;
|
|
37
|
+
return (0, exports.resolveAssetStorageSettings)(Object.assign(Object.assign({}, (_b = (_a = config === null || config === void 0 ? void 0 : config.runtime) === null || _a === void 0 ? void 0 : _a.registry) === null || _b === void 0 ? void 0 : _b.assetStorage), { tokenEnv: (_f = (_e = (_d = (_c = config === null || config === void 0 ? void 0 : config.runtime) === null || _c === void 0 ? void 0 : _c.registry) === null || _d === void 0 ? void 0 : _d.assetStorage) === null || _e === void 0 ? void 0 : _e.token) === null || _f === void 0 ? void 0 : _f.$env }));
|
|
38
|
+
};
|
|
36
39
|
exports.resolveAssetStorageFromConfig = resolveAssetStorageFromConfig;
|
|
@@ -106,14 +106,14 @@ const resolveConnectionOrThrow = (handoff) => __awaiter(void 0, void 0, void 0,
|
|
|
106
106
|
throw new CheckoutError(`checkout is only available from a connected workspace (runtime.mode: "workspace"); this project is "${mode}". ` +
|
|
107
107
|
'A registry host stores and serves entities; it has no local workspace to check them out into.');
|
|
108
108
|
}
|
|
109
|
-
const connection = yield (0, connection_1.resolveAuthenticatedRegistryConnection)(handoff.config, handoff.workingPath);
|
|
109
|
+
const connection = yield (0, connection_1.resolveAuthenticatedRegistryConnection)(handoff.config, handoff.workingPath, handoff.getProfile());
|
|
110
110
|
if (!connection.url) {
|
|
111
|
-
throw new CheckoutError(`No registry is configured. Run
|
|
111
|
+
throw new CheckoutError(`No registry is configured. Run \`${(0, connection_1.loginCommandHint)(connection)}\`, set runtime.registryConnection.url, ` +
|
|
112
112
|
`or set the "${connection.urlEnv}" environment variable to the base URL of the registry to checkout from.`);
|
|
113
113
|
}
|
|
114
114
|
if (!connection.accessToken) {
|
|
115
|
-
throw new CheckoutError(`No registry access token is configured. Run
|
|
116
|
-
`"${connection.accessTokenEnv}" environment variable to a user-issued token for CI
|
|
115
|
+
throw new CheckoutError(`No registry access token is configured. Run \`${(0, connection_1.loginCommandHint)(connection)}\`, or set the ` +
|
|
116
|
+
`"${connection.accessTokenEnv}" environment variable to a user-issued token for CI.${(0, connection_1.unusedLoginNote)(connection)}`);
|
|
117
117
|
}
|
|
118
118
|
return connection;
|
|
119
119
|
});
|
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* A connected workspace is `runtime.mode: 'workspace'` plus a `runtime.registryConnection` block
|
|
5
|
-
* pointing at a remote registry — it is not a third runtime mode. The connection is resolved from
|
|
6
|
-
* config + environment: the registry URL may be given inline or via an env-var *name*, and the
|
|
7
|
-
* access token is always read from an env-var name (never persisted as a value). This is the single
|
|
8
|
-
* source the publish (and later checkout) client reads its target + credentials from.
|
|
9
|
-
*
|
|
10
|
-
* The older `HANDOFF_CLOUD_*` names still work as deprecated fallbacks; see
|
|
11
|
-
* {@link DEPRECATED_ENV_ALIASES}.
|
|
2
|
+
* Registry connection values resolve at config load. Saved device login credentials can fill
|
|
3
|
+
* missing values for CLI operations; neither source is persisted in the app's client config.
|
|
12
4
|
*/
|
|
13
|
-
import type {
|
|
5
|
+
import type { ResolvedConfig } from '../types/config';
|
|
14
6
|
/** Default env-var name holding the remote registry base URL. */
|
|
15
7
|
export declare const DEFAULT_REGISTRY_URL_ENV = "HANDOFF_REGISTRY_URL";
|
|
16
8
|
/** Default env-var name holding the connected-workspace access token. */
|
|
17
9
|
export declare const DEFAULT_REGISTRY_ACCESS_TOKEN_ENV = "HANDOFF_REGISTRY_ACCESS_TOKEN";
|
|
10
|
+
/** A saved login and the profile it is stored under, which is not always the selected profile. */
|
|
11
|
+
interface SavedLogin {
|
|
12
|
+
profile: string;
|
|
13
|
+
url: string;
|
|
14
|
+
}
|
|
18
15
|
/** Fully resolved connected-workspace registry connection. */
|
|
19
16
|
export interface ResolvedRegistryConnection {
|
|
20
17
|
/** Resolved registry base URL (inline config value wins, else the named env var), or `''`. */
|
|
@@ -25,25 +22,32 @@ export interface ResolvedRegistryConnection {
|
|
|
25
22
|
urlEnv: string;
|
|
26
23
|
/** Name of the env var the access token is read from. */
|
|
27
24
|
accessTokenEnv: string;
|
|
25
|
+
/** Profile the saved login was looked up under. */
|
|
26
|
+
loginProfile: string;
|
|
27
|
+
/** Set when a saved login was skipped because it was issued for another registry. */
|
|
28
|
+
unmatchedLogin?: SavedLogin;
|
|
28
29
|
}
|
|
29
|
-
/**
|
|
30
|
-
|
|
31
|
-
* Callers inspect the resolved URL and access token to surface specific configuration errors.
|
|
32
|
-
*
|
|
33
|
-
* `urlEnv` and `accessTokenEnv` always report the canonical name, even when an alias supplied the
|
|
34
|
-
* value, so errors built from them point at the variable to adopt.
|
|
35
|
-
*/
|
|
36
|
-
export declare const resolveRegistryConnection: (config: Config | null | undefined) => ResolvedRegistryConnection;
|
|
30
|
+
/** Read values resolved at config load, retaining variable names for CLI diagnostics. */
|
|
31
|
+
export declare const resolveRegistryConnection: (config: ResolvedConfig | null | undefined) => ResolvedRegistryConnection;
|
|
37
32
|
/**
|
|
38
33
|
* Resolve the same connection for an authenticated CLI operation, letting a saved device login fill
|
|
39
34
|
* in what the environment does not provide. A valid login supplies both the registry URL and the
|
|
40
|
-
* access token, so `handoff-app login` alone is enough to publish and checkout.
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
35
|
+
* access token, so `handoff-app login` alone is enough to publish and checkout. The login is the one
|
|
36
|
+
* saved under the selected profile, which is how one workspace addresses several registries.
|
|
37
|
+
* Environment values keep precedence for deterministic CI: `HANDOFF_REGISTRY_URL` (or inline config)
|
|
38
|
+
* wins over the saved URL, and `HANDOFF_REGISTRY_ACCESS_TOKEN` wins over the saved token. The saved
|
|
39
|
+
* token only applies to the URL it was issued for.
|
|
44
40
|
*
|
|
45
41
|
* A configured `HANDOFF_SYNC_SECRET` is the last resort. Being deployment-wide rather than personal,
|
|
46
42
|
* it fills in only where there is no explicit token and no login (CI, in practice), instead of quietly
|
|
47
43
|
* speaking for a developer who is signed in.
|
|
48
44
|
*/
|
|
49
|
-
export declare const resolveAuthenticatedRegistryConnection: (config:
|
|
45
|
+
export declare const resolveAuthenticatedRegistryConnection: (config: ResolvedConfig | null | undefined, workingPath?: string, profile?: string) => Promise<ResolvedRegistryConnection>;
|
|
46
|
+
/** The `handoff-app login` call that would authorize this connection, naming the selected profile. */
|
|
47
|
+
export declare const loginCommandHint: (connection: ResolvedRegistryConnection) => string;
|
|
48
|
+
/**
|
|
49
|
+
* Names a saved login that was skipped because it belongs to another registry. Without it, a run
|
|
50
|
+
* that resolves its URL from the environment reports a missing token while a login is in place.
|
|
51
|
+
*/
|
|
52
|
+
export declare const unusedLoginNote: (connection: ResolvedRegistryConnection) => string;
|
|
53
|
+
export {};
|
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* A connected workspace is `runtime.mode: 'workspace'` plus a `runtime.registryConnection` block
|
|
6
|
-
* pointing at a remote registry — it is not a third runtime mode. The connection is resolved from
|
|
7
|
-
* config + environment: the registry URL may be given inline or via an env-var *name*, and the
|
|
8
|
-
* access token is always read from an env-var name (never persisted as a value). This is the single
|
|
9
|
-
* source the publish (and later checkout) client reads its target + credentials from.
|
|
10
|
-
*
|
|
11
|
-
* The older `HANDOFF_CLOUD_*` names still work as deprecated fallbacks; see
|
|
12
|
-
* {@link DEPRECATED_ENV_ALIASES}.
|
|
3
|
+
* Registry connection values resolve at config load. Saved device login credentials can fill
|
|
4
|
+
* missing values for CLI operations; neither source is persisted in the app's client config.
|
|
13
5
|
*/
|
|
14
6
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
15
7
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
@@ -21,89 +13,83 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
21
13
|
});
|
|
22
14
|
};
|
|
23
15
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
-
exports.resolveAuthenticatedRegistryConnection = exports.resolveRegistryConnection = exports.DEFAULT_REGISTRY_ACCESS_TOKEN_ENV = exports.DEFAULT_REGISTRY_URL_ENV = void 0;
|
|
16
|
+
exports.unusedLoginNote = exports.loginCommandHint = exports.resolveAuthenticatedRegistryConnection = exports.resolveRegistryConnection = exports.DEFAULT_REGISTRY_ACCESS_TOKEN_ENV = exports.DEFAULT_REGISTRY_URL_ENV = void 0;
|
|
17
|
+
const resolve_env_1 = require("../config/resolve-env");
|
|
25
18
|
const store_1 = require("../cli/auth/store");
|
|
26
19
|
// Imported straight from the module, not the `auth` barrel, to keep the database schema off the CLI
|
|
27
20
|
// startup path; this file is resolved for every command.
|
|
28
21
|
const sync_secret_1 = require("./auth/sync-secret");
|
|
29
|
-
const logger_1 = require("../utils/logger");
|
|
30
22
|
/** Default env-var name holding the remote registry base URL. */
|
|
31
23
|
exports.DEFAULT_REGISTRY_URL_ENV = 'HANDOFF_REGISTRY_URL';
|
|
32
24
|
/** Default env-var name holding the connected-workspace access token. */
|
|
33
25
|
exports.DEFAULT_REGISTRY_ACCESS_TOKEN_ENV = 'HANDOFF_REGISTRY_ACCESS_TOKEN';
|
|
34
|
-
/**
|
|
35
|
-
* Old env-var names we still read, keyed by the name that replaced them. Keeps workspaces set up
|
|
36
|
-
* from the older docs working instead of silently reporting no registry.
|
|
37
|
-
*/
|
|
38
|
-
const DEPRECATED_ENV_ALIASES = {
|
|
39
|
-
[exports.DEFAULT_REGISTRY_URL_ENV]: 'HANDOFF_CLOUD_URL',
|
|
40
|
-
[exports.DEFAULT_REGISTRY_ACCESS_TOKEN_ENV]: 'HANDOFF_CLOUD_TOKEN',
|
|
41
|
-
};
|
|
42
|
-
/** Aliases we've already warned about, so each one warns once per run and not once per lookup. */
|
|
43
|
-
const warnedAliases = new Set();
|
|
44
|
-
/**
|
|
45
|
-
* Value of the named env var, falling back to its deprecated alias. Only the default names have
|
|
46
|
-
* aliases: a custom `urlEnv`/`accessTokenEnv` is a deliberate choice, so a stray `HANDOFF_CLOUD_*`
|
|
47
|
-
* must not stand in for it. The warning goes through {@link Logger.warn}, so
|
|
48
|
-
* `HANDOFF_LOG_LEVEL=error` silences it in CI.
|
|
49
|
-
*/
|
|
50
|
-
const readConnectionEnv = (name) => {
|
|
51
|
-
var _a, _b;
|
|
52
|
-
const configured = (_a = process.env[name]) === null || _a === void 0 ? void 0 : _a.trim();
|
|
53
|
-
if (configured)
|
|
54
|
-
return configured;
|
|
55
|
-
const alias = DEPRECATED_ENV_ALIASES[name];
|
|
56
|
-
const inherited = alias ? (_b = process.env[alias]) === null || _b === void 0 ? void 0 : _b.trim() : '';
|
|
57
|
-
if (!inherited)
|
|
58
|
-
return '';
|
|
59
|
-
if (!warnedAliases.has(alias)) {
|
|
60
|
-
warnedAliases.add(alias);
|
|
61
|
-
logger_1.Logger.warn(`${alias} is deprecated and will be removed in a future release; set ${name} instead.`);
|
|
62
|
-
}
|
|
63
|
-
return inherited;
|
|
64
|
-
};
|
|
65
|
-
/**
|
|
66
|
-
* Resolve the connected-workspace registry connection from config + environment. Never throws —
|
|
67
|
-
* Callers inspect the resolved URL and access token to surface specific configuration errors.
|
|
68
|
-
*
|
|
69
|
-
* `urlEnv` and `accessTokenEnv` always report the canonical name, even when an alias supplied the
|
|
70
|
-
* value, so errors built from them point at the variable to adopt.
|
|
71
|
-
*/
|
|
26
|
+
/** Read values resolved at config load, retaining variable names for CLI diagnostics. */
|
|
72
27
|
const resolveRegistryConnection = (config) => {
|
|
73
|
-
var _a, _b, _c
|
|
28
|
+
var _a, _b, _c;
|
|
74
29
|
const connection = (_a = config === null || config === void 0 ? void 0 : config.runtime) === null || _a === void 0 ? void 0 : _a.registryConnection;
|
|
75
|
-
const urlEnv = (
|
|
76
|
-
const accessTokenEnv = (
|
|
77
|
-
const
|
|
78
|
-
const
|
|
79
|
-
const accessToken = readConnectionEnv(accessTokenEnv);
|
|
30
|
+
const urlEnv = (0, resolve_env_1.configEnvName)(config, 'runtime.registryConnection.url') || exports.DEFAULT_REGISTRY_URL_ENV;
|
|
31
|
+
const accessTokenEnv = (0, resolve_env_1.configEnvName)(config, 'runtime.registryConnection.accessToken') || exports.DEFAULT_REGISTRY_ACCESS_TOKEN_ENV;
|
|
32
|
+
const url = ((_b = connection === null || connection === void 0 ? void 0 : connection.url) === null || _b === void 0 ? void 0 : _b.trim()) || '';
|
|
33
|
+
const accessToken = ((_c = connection === null || connection === void 0 ? void 0 : connection.accessToken) === null || _c === void 0 ? void 0 : _c.trim()) || '';
|
|
80
34
|
return {
|
|
81
35
|
url,
|
|
82
36
|
accessToken,
|
|
83
37
|
urlEnv,
|
|
84
38
|
accessTokenEnv,
|
|
39
|
+
loginProfile: store_1.DEFAULT_LOGIN_PROFILE,
|
|
85
40
|
};
|
|
86
41
|
};
|
|
87
42
|
exports.resolveRegistryConnection = resolveRegistryConnection;
|
|
43
|
+
/**
|
|
44
|
+
* The valid login to use for a profile. A profile without its own login falls back to the default
|
|
45
|
+
* login, so a workspace that names profiles for other reasons keeps working after one plain
|
|
46
|
+
* `handoff-app login`. The fallback is safe because a token is only ever used for the registry URL
|
|
47
|
+
* it was issued for.
|
|
48
|
+
*/
|
|
49
|
+
const readProfileLogin = (workingPath, profile) => __awaiter(void 0, void 0, void 0, function* () {
|
|
50
|
+
const own = yield (0, store_1.readCliAuth)(workingPath, profile);
|
|
51
|
+
if ((0, store_1.cliAuthTokenIsValid)(own))
|
|
52
|
+
return { auth: own, profile };
|
|
53
|
+
const fallback = profile === store_1.DEFAULT_LOGIN_PROFILE ? null : yield (0, store_1.readCliAuth)(workingPath);
|
|
54
|
+
return (0, store_1.cliAuthTokenIsValid)(fallback) ? { auth: fallback, profile: store_1.DEFAULT_LOGIN_PROFILE } : null;
|
|
55
|
+
});
|
|
88
56
|
/**
|
|
89
57
|
* Resolve the same connection for an authenticated CLI operation, letting a saved device login fill
|
|
90
58
|
* in what the environment does not provide. A valid login supplies both the registry URL and the
|
|
91
|
-
* access token, so `handoff-app login` alone is enough to publish and checkout.
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
59
|
+
* access token, so `handoff-app login` alone is enough to publish and checkout. The login is the one
|
|
60
|
+
* saved under the selected profile, which is how one workspace addresses several registries.
|
|
61
|
+
* Environment values keep precedence for deterministic CI: `HANDOFF_REGISTRY_URL` (or inline config)
|
|
62
|
+
* wins over the saved URL, and `HANDOFF_REGISTRY_ACCESS_TOKEN` wins over the saved token. The saved
|
|
63
|
+
* token only applies to the URL it was issued for.
|
|
95
64
|
*
|
|
96
65
|
* A configured `HANDOFF_SYNC_SECRET` is the last resort. Being deployment-wide rather than personal,
|
|
97
66
|
* it fills in only where there is no explicit token and no login (CI, in practice), instead of quietly
|
|
98
67
|
* speaking for a developer who is signed in.
|
|
99
68
|
*/
|
|
100
|
-
const resolveAuthenticatedRegistryConnection = (config_1, ...args_1) => __awaiter(void 0, [config_1, ...args_1], void 0, function* (config, workingPath = process.cwd()) {
|
|
69
|
+
const resolveAuthenticatedRegistryConnection = (config_1, ...args_1) => __awaiter(void 0, [config_1, ...args_1], void 0, function* (config, workingPath = process.cwd(), profile) {
|
|
101
70
|
const connection = (0, exports.resolveRegistryConnection)(config);
|
|
102
|
-
const
|
|
103
|
-
const login = (
|
|
104
|
-
const url = connection.url || (login === null || login === void 0 ? void 0 : login.remoteUrl) || '';
|
|
105
|
-
const
|
|
106
|
-
const accessToken = connection.accessToken ||
|
|
107
|
-
return Object.assign(Object.assign({}, connection), { url,
|
|
71
|
+
const loginProfile = (profile === null || profile === void 0 ? void 0 : profile.trim()) || store_1.DEFAULT_LOGIN_PROFILE;
|
|
72
|
+
const login = yield readProfileLogin(workingPath, loginProfile);
|
|
73
|
+
const url = connection.url || (login === null || login === void 0 ? void 0 : login.auth.remoteUrl) || '';
|
|
74
|
+
const matches = Boolean(login) && (0, store_1.cliAuthMatchesRegistry)(login.auth, url);
|
|
75
|
+
const accessToken = connection.accessToken || (matches ? login.auth.accessToken : '') || (0, sync_secret_1.resolveRegistrySyncSecret)();
|
|
76
|
+
return Object.assign(Object.assign({}, connection), { url,
|
|
77
|
+
accessToken,
|
|
78
|
+
loginProfile, unmatchedLogin: login && !matches ? { profile: login.profile, url: login.auth.remoteUrl } : undefined });
|
|
108
79
|
});
|
|
109
80
|
exports.resolveAuthenticatedRegistryConnection = resolveAuthenticatedRegistryConnection;
|
|
81
|
+
/** The `handoff-app login` call that would authorize this connection, naming the selected profile. */
|
|
82
|
+
const loginCommandHint = (connection) => [
|
|
83
|
+
'handoff-app login',
|
|
84
|
+
connection.loginProfile === store_1.DEFAULT_LOGIN_PROFILE ? '' : ` --profile ${connection.loginProfile}`,
|
|
85
|
+
` --url ${connection.url || '<registry-url>'}`,
|
|
86
|
+
].join('');
|
|
87
|
+
exports.loginCommandHint = loginCommandHint;
|
|
88
|
+
/**
|
|
89
|
+
* Names a saved login that was skipped because it belongs to another registry. Without it, a run
|
|
90
|
+
* that resolves its URL from the environment reports a missing token while a login is in place.
|
|
91
|
+
*/
|
|
92
|
+
const unusedLoginNote = (connection) => connection.unmatchedLogin
|
|
93
|
+
? ` The login saved for profile "${connection.unmatchedLogin.profile}" is for ${connection.unmatchedLogin.url}, not ${connection.url}.`
|
|
94
|
+
: '';
|
|
95
|
+
exports.unusedLoginNote = unusedLoginNote;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* credentials are referenced by environment-variable name only and resolved to a value at runtime;
|
|
10
10
|
* the value is never stored in config.
|
|
11
11
|
*/
|
|
12
|
-
import type {
|
|
12
|
+
import type { ResolvedConfig } from '../../types/config';
|
|
13
13
|
/** Built-in registry database connection driver. Both ship with the package and target Postgres. */
|
|
14
14
|
export type RegistryDatabaseDriver = 'pg' | 'neon';
|
|
15
15
|
/** Default env-var name holding the database connection string. */
|
|
@@ -28,19 +28,12 @@ export interface ResolvedRegistryDatabase {
|
|
|
28
28
|
connectionString: string;
|
|
29
29
|
}
|
|
30
30
|
/** Resolve the env-var name holding the database URL (defaults to `DATABASE_URL`). */
|
|
31
|
-
export declare const resolveDatabaseUrlEnv: (config:
|
|
32
|
-
/**
|
|
33
|
-
* Resolve the legacy fixed-token env-var name for configuration compatibility.
|
|
34
|
-
*
|
|
35
|
-
* @deprecated The returned env var is intentionally ignored by registry authorization. Use a
|
|
36
|
-
* user-issued access token or `handoff-app login`.
|
|
37
|
-
*/
|
|
38
|
-
export declare const resolveApiTokenEnv: (config: Config | null | undefined) => string;
|
|
31
|
+
export declare const resolveDatabaseUrlEnv: (config: ResolvedConfig | null | undefined) => string;
|
|
39
32
|
/** Resolve the configured registry database driver (defaults to `pg`). */
|
|
40
|
-
export declare const resolveRegistryDriver: (config:
|
|
33
|
+
export declare const resolveRegistryDriver: (config: ResolvedConfig | null | undefined) => RegistryDatabaseDriver;
|
|
41
34
|
/**
|
|
42
35
|
* Resolve the registry database connection from config + environment. Throws an actionable error
|
|
43
36
|
* when the configured env var is unset so the CLI can surface a clear "missing database URL"
|
|
44
37
|
* message instead of failing deep inside the driver.
|
|
45
38
|
*/
|
|
46
|
-
export declare const resolveRegistryDatabase: (config:
|
|
39
|
+
export declare const resolveRegistryDatabase: (config: ResolvedConfig | null | undefined) => ResolvedRegistryDatabase;
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* the value is never stored in config.
|
|
12
12
|
*/
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.resolveRegistryDatabase = exports.resolveRegistryDriver = exports.
|
|
14
|
+
exports.resolveRegistryDatabase = exports.resolveRegistryDriver = exports.resolveDatabaseUrlEnv = exports.DEFAULT_REGISTRY_DRIVER = exports.DEFAULT_REGISTRY_API_TOKEN_ENV = exports.DEFAULT_DATABASE_URL_ENV = void 0;
|
|
15
15
|
/** Default env-var name holding the database connection string. */
|
|
16
16
|
exports.DEFAULT_DATABASE_URL_ENV = 'DATABASE_URL';
|
|
17
17
|
/** @deprecated Fixed registry server secrets are no longer authorized. */
|
|
@@ -20,23 +20,11 @@ exports.DEFAULT_REGISTRY_API_TOKEN_ENV = 'HANDOFF_REGISTRY_API_TOKEN';
|
|
|
20
20
|
exports.DEFAULT_REGISTRY_DRIVER = 'pg';
|
|
21
21
|
/** Resolve the env-var name holding the database URL (defaults to `DATABASE_URL`). */
|
|
22
22
|
const resolveDatabaseUrlEnv = (config) => {
|
|
23
|
-
var _a, _b, _c;
|
|
24
|
-
const configured = (_c = (_b = (_a = config === null || config === void 0 ? void 0 : config.runtime) === null || _a === void 0 ? void 0 : _a.registry) === null || _b === void 0 ? void 0 : _b.
|
|
23
|
+
var _a, _b, _c, _d;
|
|
24
|
+
const configured = (_d = (_c = (_b = (_a = config === null || config === void 0 ? void 0 : config.runtime) === null || _a === void 0 ? void 0 : _a.registry) === null || _b === void 0 ? void 0 : _b.databaseUrl) === null || _c === void 0 ? void 0 : _c.$env) === null || _d === void 0 ? void 0 : _d.trim();
|
|
25
25
|
return configured || exports.DEFAULT_DATABASE_URL_ENV;
|
|
26
26
|
};
|
|
27
27
|
exports.resolveDatabaseUrlEnv = resolveDatabaseUrlEnv;
|
|
28
|
-
/**
|
|
29
|
-
* Resolve the legacy fixed-token env-var name for configuration compatibility.
|
|
30
|
-
*
|
|
31
|
-
* @deprecated The returned env var is intentionally ignored by registry authorization. Use a
|
|
32
|
-
* user-issued access token or `handoff-app login`.
|
|
33
|
-
*/
|
|
34
|
-
const resolveApiTokenEnv = (config) => {
|
|
35
|
-
var _a, _b, _c;
|
|
36
|
-
const configured = (_c = (_b = (_a = config === null || config === void 0 ? void 0 : config.runtime) === null || _a === void 0 ? void 0 : _a.registry) === null || _b === void 0 ? void 0 : _b.apiTokenEnv) === null || _c === void 0 ? void 0 : _c.trim();
|
|
37
|
-
return configured || exports.DEFAULT_REGISTRY_API_TOKEN_ENV;
|
|
38
|
-
};
|
|
39
|
-
exports.resolveApiTokenEnv = resolveApiTokenEnv;
|
|
40
28
|
/** Resolve the configured registry database driver (defaults to `pg`). */
|
|
41
29
|
const resolveRegistryDriver = (config) => {
|
|
42
30
|
var _a, _b, _c, _d;
|
|
@@ -55,7 +43,7 @@ const resolveRegistryDatabase = (config) => {
|
|
|
55
43
|
const connectionString = (_a = process.env[databaseUrlEnv]) === null || _a === void 0 ? void 0 : _a.trim();
|
|
56
44
|
if (!connectionString) {
|
|
57
45
|
throw new Error(`Registry database URL is not configured. Set the "${databaseUrlEnv}" environment variable to a ` +
|
|
58
|
-
`PostgreSQL connection string (or change "runtime.registry.
|
|
46
|
+
`PostgreSQL connection string (or change "runtime.registry.databaseUrl" to point at the env var you use).`);
|
|
59
47
|
}
|
|
60
48
|
return { driver, databaseUrlEnv, connectionString };
|
|
61
49
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { buildMetadata, componentFiles, components, docsArtifacts, patternFiles, patterns, registryAccessTokens, registryAuthActionTokens, registryAuthRateLimits, registryDeviceAuthorizations, registryInstallations, registrySchema, registryUsers, type BuildMetadataEntityKind, type DocsArtifactEntityKind, type RegistryAccessScope, type RegistryAuthActionPurpose, type RegistryDeviceAuthorizationStatus, type RegistryRateLimitBucket, type RegistryReviewMetadata, type RegistryUserRole, type RegistryUserStatus, } from './schema';
|
|
2
2
|
export type { ArtifactBuildStatus as RegistryBuildStatus } from '../../artifacts/types';
|
|
3
|
-
export { DEFAULT_DATABASE_URL_ENV, DEFAULT_REGISTRY_DRIVER, DEFAULT_REGISTRY_API_TOKEN_ENV,
|
|
3
|
+
export { DEFAULT_DATABASE_URL_ENV, DEFAULT_REGISTRY_DRIVER, DEFAULT_REGISTRY_API_TOKEN_ENV, resolveDatabaseUrlEnv, resolveRegistryDriver, resolveRegistryDatabase, type RegistryDatabaseDriver, type ResolvedRegistryDatabase, } from './driver';
|
|
4
4
|
export { createRegistryDbConnection, type CreateRegistryDbConnectionParams, type RegistryDatabase, type RegistryDbConnection, } from './client';
|
|
5
5
|
export { getMigrationsFolder, runRegistryMigrations } from './migrate';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.runRegistryMigrations = exports.getMigrationsFolder = exports.createRegistryDbConnection = exports.resolveRegistryDatabase = exports.resolveRegistryDriver = exports.resolveDatabaseUrlEnv = exports.
|
|
3
|
+
exports.runRegistryMigrations = exports.getMigrationsFolder = exports.createRegistryDbConnection = exports.resolveRegistryDatabase = exports.resolveRegistryDriver = exports.resolveDatabaseUrlEnv = exports.DEFAULT_REGISTRY_API_TOKEN_ENV = exports.DEFAULT_REGISTRY_DRIVER = exports.DEFAULT_DATABASE_URL_ENV = exports.registryUsers = exports.registrySchema = exports.registryInstallations = exports.registryDeviceAuthorizations = exports.registryAuthRateLimits = exports.registryAuthActionTokens = exports.registryAccessTokens = exports.patterns = exports.patternFiles = exports.docsArtifacts = exports.components = exports.componentFiles = exports.buildMetadata = void 0;
|
|
4
4
|
var schema_1 = require("./schema");
|
|
5
5
|
Object.defineProperty(exports, "buildMetadata", { enumerable: true, get: function () { return schema_1.buildMetadata; } });
|
|
6
6
|
Object.defineProperty(exports, "componentFiles", { enumerable: true, get: function () { return schema_1.componentFiles; } });
|
|
@@ -19,7 +19,6 @@ var driver_1 = require("./driver");
|
|
|
19
19
|
Object.defineProperty(exports, "DEFAULT_DATABASE_URL_ENV", { enumerable: true, get: function () { return driver_1.DEFAULT_DATABASE_URL_ENV; } });
|
|
20
20
|
Object.defineProperty(exports, "DEFAULT_REGISTRY_DRIVER", { enumerable: true, get: function () { return driver_1.DEFAULT_REGISTRY_DRIVER; } });
|
|
21
21
|
Object.defineProperty(exports, "DEFAULT_REGISTRY_API_TOKEN_ENV", { enumerable: true, get: function () { return driver_1.DEFAULT_REGISTRY_API_TOKEN_ENV; } });
|
|
22
|
-
Object.defineProperty(exports, "resolveApiTokenEnv", { enumerable: true, get: function () { return driver_1.resolveApiTokenEnv; } });
|
|
23
22
|
Object.defineProperty(exports, "resolveDatabaseUrlEnv", { enumerable: true, get: function () { return driver_1.resolveDatabaseUrlEnv; } });
|
|
24
23
|
Object.defineProperty(exports, "resolveRegistryDriver", { enumerable: true, get: function () { return driver_1.resolveRegistryDriver; } });
|
|
25
24
|
Object.defineProperty(exports, "resolveRegistryDatabase", { enumerable: true, get: function () { return driver_1.resolveRegistryDatabase; } });
|
|
@@ -79,14 +79,14 @@ const assertUniqueCatalogIds = (handoff) => {
|
|
|
79
79
|
*/
|
|
80
80
|
const resolveConnectionOrThrow = (handoff) => __awaiter(void 0, void 0, void 0, function* () {
|
|
81
81
|
(0, exports.assertPublishableWorkspace)(handoff);
|
|
82
|
-
const connection = yield (0, connection_1.resolveAuthenticatedRegistryConnection)(handoff.config, handoff.workingPath);
|
|
82
|
+
const connection = yield (0, connection_1.resolveAuthenticatedRegistryConnection)(handoff.config, handoff.workingPath, handoff.getProfile());
|
|
83
83
|
if (!connection.url) {
|
|
84
|
-
throw new PublishError(`No registry is configured. Run
|
|
84
|
+
throw new PublishError(`No registry is configured. Run \`${(0, connection_1.loginCommandHint)(connection)}\`, set runtime.registryConnection.url, ` +
|
|
85
85
|
`or set the "${connection.urlEnv}" environment variable to the base URL of the registry to publish to.`);
|
|
86
86
|
}
|
|
87
87
|
if (!connection.accessToken) {
|
|
88
|
-
throw new PublishError(`No registry access token is configured. Run
|
|
89
|
-
`"${connection.accessTokenEnv}" environment variable to a user-issued token for CI
|
|
88
|
+
throw new PublishError(`No registry access token is configured. Run \`${(0, connection_1.loginCommandHint)(connection)}\`, or set the ` +
|
|
89
|
+
`"${connection.accessTokenEnv}" environment variable to a user-issued token for CI.${(0, connection_1.unusedLoginNote)(connection)}`);
|
|
90
90
|
}
|
|
91
91
|
return connection;
|
|
92
92
|
});
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* without changing how anything is discovered or built.
|
|
10
10
|
*/
|
|
11
11
|
import type { ComponentListObject, PageListObject, PatternListObject } from '../transformers/preview/types';
|
|
12
|
-
import type {
|
|
12
|
+
import type { ResolvedConfig, RuntimeConfig } from '../types/config';
|
|
13
13
|
import type { ComponentStore, PageStore, PatternStore, SourceReference, TextFileResource, TokenArtifactResource, TokenSetRecord, TokenStore } from './types';
|
|
14
14
|
/**
|
|
15
15
|
* Minimal context needed to back the filesystem store. A `Handoff` instance satisfies this (it
|
|
@@ -18,7 +18,7 @@ import type { ComponentStore, PageStore, PatternStore, SourceReference, TextFile
|
|
|
18
18
|
*/
|
|
19
19
|
export interface FilesystemStoreContext {
|
|
20
20
|
runtimeConfig?: RuntimeConfig | null;
|
|
21
|
-
config?:
|
|
21
|
+
config?: ResolvedConfig | null;
|
|
22
22
|
/** Workspace root (`Handoff.workingPath`), holding `public/` and `fonts/`. */
|
|
23
23
|
workingPath?: string;
|
|
24
24
|
/** Absolute path to the generated `tokens.json` (`Handoff.getTokensFilePath()`). */
|
package/dist/types/config.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { EnvValue, EnvSecret, RuntimeEnvReference } from '../config/from-env';
|
|
1
2
|
import { BuildOptions } from 'esbuild';
|
|
2
3
|
import type Handlebars from 'handlebars';
|
|
3
4
|
import { Types as HandoffTypes } from 'handoff-core';
|
|
@@ -63,8 +64,8 @@ export type RegisterHandlebarsHelpersContext = {
|
|
|
63
64
|
};
|
|
64
65
|
export interface NextAppConfig {
|
|
65
66
|
theme?: string;
|
|
66
|
-
title
|
|
67
|
-
client
|
|
67
|
+
title?: string;
|
|
68
|
+
client?: string;
|
|
68
69
|
google_tag_manager?: string | null | undefined;
|
|
69
70
|
googleTagManager?: string | null | undefined;
|
|
70
71
|
type_copy?: string;
|
|
@@ -73,15 +74,17 @@ export interface NextAppConfig {
|
|
|
73
74
|
typeSort?: string[];
|
|
74
75
|
color_sort?: string[];
|
|
75
76
|
colorSort?: string[];
|
|
76
|
-
|
|
77
|
+
/** Omit to keep the defaults; a declared block merges onto them rather than replacing them. */
|
|
78
|
+
breakpoints?: Breakpoints;
|
|
77
79
|
component_sort?: string[];
|
|
78
80
|
componentSort?: string[];
|
|
79
81
|
base_path?: string;
|
|
80
82
|
basePath?: string;
|
|
81
|
-
|
|
83
|
+
/** @default true */
|
|
84
|
+
attribution?: boolean;
|
|
82
85
|
ports?: {
|
|
83
|
-
app: number
|
|
84
|
-
websocket: number
|
|
86
|
+
app: EnvValue<number>;
|
|
87
|
+
websocket: EnvValue<number>;
|
|
85
88
|
};
|
|
86
89
|
}
|
|
87
90
|
/**
|
|
@@ -139,13 +142,8 @@ export interface HandoffRuntimeConfig {
|
|
|
139
142
|
};
|
|
140
143
|
/** Registry-mode host settings. Env-var values are stored as names, never as secrets. */
|
|
141
144
|
registry?: {
|
|
142
|
-
/**
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* @deprecated Fixed registry secrets are no longer authorized. This option remains parseable
|
|
146
|
-
* only so existing configuration files do not break.
|
|
147
|
-
*/
|
|
148
|
-
apiTokenEnv?: string;
|
|
145
|
+
/** Environment reference to the database URL. @default fromEnv('DATABASE_URL') */
|
|
146
|
+
databaseUrl?: RuntimeEnvReference<string>;
|
|
149
147
|
database?: {
|
|
150
148
|
/**
|
|
151
149
|
* PostgreSQL is the supported database. `driver` selects the built-in connection driver — how
|
|
@@ -168,11 +166,11 @@ export interface HandoffRuntimeConfig {
|
|
|
168
166
|
adapter?: 'database' | 'vercel-blob' | 'custom';
|
|
169
167
|
/** For `adapter: "custom"` - server-only module path default-exporting a `defineAssetStorage` adapter. */
|
|
170
168
|
module?: string;
|
|
171
|
-
/** For `adapter: "vercel-blob"` -
|
|
172
|
-
|
|
169
|
+
/** For `adapter: "vercel-blob"` - environment reference to the Blob read/write token. @default fromEnv('BLOB_READ_WRITE_TOKEN') */
|
|
170
|
+
token?: RuntimeEnvReference<string>;
|
|
173
171
|
/** Max bytes kept inline in the database `bytea` column (larger uploads are rejected). @default 4194304 */
|
|
174
172
|
maxInlineBytes?: number;
|
|
175
|
-
/** Non-secret
|
|
173
|
+
/** Non-secret options, JSON-encoded into the bundle. Environment references are rejected. Pass variable names instead. */
|
|
176
174
|
options?: Record<string, unknown>;
|
|
177
175
|
};
|
|
178
176
|
};
|
|
@@ -181,21 +179,20 @@ export interface HandoffRuntimeConfig {
|
|
|
181
179
|
* `mode: 'workspace'` plus this block — it is not a third runtime mode.
|
|
182
180
|
*/
|
|
183
181
|
registryConnection?: {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
accessTokenEnv?: string;
|
|
182
|
+
/** @default fromEnv('HANDOFF_REGISTRY_URL', { default: '' }) */
|
|
183
|
+
url?: EnvValue<string>;
|
|
184
|
+
/** @default fromEnv('HANDOFF_REGISTRY_ACCESS_TOKEN', { default: '' }) */
|
|
185
|
+
accessToken?: EnvSecret<string>;
|
|
189
186
|
};
|
|
190
187
|
}
|
|
191
188
|
export interface Config {
|
|
192
|
-
dev_access_token?: string | null
|
|
193
|
-
devAccessToken?: string | null
|
|
194
|
-
figma_project_id?: string | null
|
|
195
|
-
figmaProjectId?: string | null
|
|
196
|
-
exportsOutputDirectory?: string
|
|
197
|
-
sitesOutputDirectory?: string
|
|
198
|
-
useVariables?: boolean
|
|
189
|
+
dev_access_token?: EnvSecret<string | null>;
|
|
190
|
+
devAccessToken?: EnvSecret<string | null>;
|
|
191
|
+
figma_project_id?: EnvValue<string | null>;
|
|
192
|
+
figmaProjectId?: EnvValue<string | null>;
|
|
193
|
+
exportsOutputDirectory?: EnvValue<string>;
|
|
194
|
+
sitesOutputDirectory?: EnvValue<string>;
|
|
195
|
+
useVariables?: EnvValue<boolean>;
|
|
199
196
|
/**
|
|
200
197
|
* Configuration for React component docs generation (handoff-docgen).
|
|
201
198
|
*/
|
|
@@ -387,7 +384,29 @@ export interface ClientRuntimeConfig {
|
|
|
387
384
|
*/
|
|
388
385
|
connected: boolean;
|
|
389
386
|
}
|
|
390
|
-
|
|
387
|
+
/** Values available after config loading. Deferred references retain their names. */
|
|
388
|
+
export type ResolvedConfig = Omit<Config, 'dev_access_token' | 'devAccessToken' | 'figma_project_id' | 'figmaProjectId' | 'exportsOutputDirectory' | 'sitesOutputDirectory' | 'useVariables' | 'app' | 'runtime'> & {
|
|
389
|
+
dev_access_token?: string | null;
|
|
390
|
+
devAccessToken?: string | null;
|
|
391
|
+
figma_project_id?: string | null;
|
|
392
|
+
figmaProjectId?: string | null;
|
|
393
|
+
exportsOutputDirectory?: string;
|
|
394
|
+
sitesOutputDirectory?: string;
|
|
395
|
+
useVariables?: boolean;
|
|
396
|
+
app?: Omit<NextAppConfig, 'ports'> & {
|
|
397
|
+
ports?: {
|
|
398
|
+
app: number;
|
|
399
|
+
websocket: number;
|
|
400
|
+
};
|
|
401
|
+
};
|
|
402
|
+
runtime?: Omit<HandoffRuntimeConfig, 'registryConnection'> & {
|
|
403
|
+
registryConnection?: {
|
|
404
|
+
url?: string;
|
|
405
|
+
accessToken?: string;
|
|
406
|
+
};
|
|
407
|
+
};
|
|
408
|
+
};
|
|
409
|
+
export type ClientConfig = Pick<ResolvedConfig, 'app' | 'exportsOutputDirectory' | 'sitesOutputDirectory' | 'assets_zip_links' | 'useVariables'> & {
|
|
391
410
|
runtime: ClientRuntimeConfig;
|
|
392
411
|
};
|
|
393
412
|
export interface RuntimeConfigComponentOptions {
|
package/docs/api.md
CHANGED
|
@@ -29,6 +29,37 @@ handoff.fetch();
|
|
|
29
29
|
3. Build your typescript `tsc`
|
|
30
30
|
4. Run your project `node handoff.js`
|
|
31
31
|
|
|
32
|
+
## Configuration profiles
|
|
33
|
+
|
|
34
|
+
A profile is a sidecar config file, `handoff.config.<profile>.*`, that merges
|
|
35
|
+
onto the base config. The CLI selects one with `--profile`, and the class takes
|
|
36
|
+
it as a constructor option. Handoff reads `HANDOFF_PROFILE` when neither is
|
|
37
|
+
given.
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
const handoff = new Handoff({ profile: 'registry' });
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
A profile also names the saved registry login that `publish` and `checkout`
|
|
44
|
+
use, so one workspace can address several registries. `profileWithoutConfig`
|
|
45
|
+
decides what a profile may resolve to when it has no config file:
|
|
46
|
+
`'saved-login'` accepts a name a saved login uses, and `'any'` accepts any
|
|
47
|
+
valid name, which is how `login` creates a new one.
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
const handoff = new Handoff({ profile: 'staging', profileWithoutConfig: 'saved-login' });
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`defineConfig` types a profile as well as a base config.
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { defineConfig } from 'handoff-app';
|
|
57
|
+
|
|
58
|
+
export default defineConfig({
|
|
59
|
+
runtime: { registry: { database: { driver: 'neon' } } },
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
32
63
|
## Methods
|
|
33
64
|
|
|
34
65
|
Methods of the handoff class can be called to run actions in the
|
package/docs/cli.md
CHANGED
|
@@ -58,9 +58,9 @@ Commands:
|
|
|
58
58
|
|
|
59
59
|
db:migrate [opts] - Runs registry database migrations (Drizzle / PostgreSQL). Reads the project config and database env vars, applies the package-owned migration set, and runs independently of `build`.
|
|
60
60
|
|
|
61
|
-
login --url <registry-url> - Authorizes this workspace in the browser and stores a revocable token in `.handoff/cli-auth.json
|
|
61
|
+
login [--profile <name>] --url <registry-url> - Authorizes this workspace in the browser and stores a revocable token in `.handoff/cli-auth.json`, under the selected profile.
|
|
62
62
|
|
|
63
|
-
logout [--url <registry-url>] - Revokes the saved token when possible, then removes the local credential
|
|
63
|
+
logout [--profile <name>] [--url <registry-url>] [--all] - Revokes the saved token when possible, then removes the local credential of the selected profile, or of every profile with `--all`.
|
|
64
64
|
|
|
65
65
|
make
|
|
66
66
|
make:component <name> [opts] - Creates a new catalog item with a declaration
|