primitive-admin 1.1.0-alpha.4 → 1.1.0-alpha.41
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 +325 -31
- package/assets/skill/skills/primitive-platform/SKILL.md +281 -0
- package/dist/bin/primitive.d.ts +2 -0
- package/dist/bin/primitive.js +268 -16
- package/dist/bin/primitive.js.map +1 -1
- package/dist/src/commands/admins.d.ts +2 -0
- package/dist/src/commands/admins.js +123 -18
- package/dist/src/commands/admins.js.map +1 -1
- package/dist/src/commands/analytics.d.ts +2 -0
- package/dist/src/commands/analytics.js +464 -55
- package/dist/src/commands/analytics.js.map +1 -1
- package/dist/src/commands/apps.d.ts +2 -0
- package/dist/src/commands/apps.js +55 -13
- package/dist/src/commands/apps.js.map +1 -1
- package/dist/src/commands/auth.d.ts +2 -0
- package/dist/src/commands/auth.js +177 -7
- package/dist/src/commands/auth.js.map +1 -1
- package/dist/src/commands/blob-buckets.d.ts +2 -0
- package/dist/src/commands/blob-buckets.js +422 -0
- package/dist/src/commands/blob-buckets.js.map +1 -0
- package/dist/src/commands/catalog.d.ts +2 -0
- package/dist/src/commands/catalog.js +34 -35
- package/dist/src/commands/catalog.js.map +1 -1
- package/dist/src/commands/collection-type-configs.d.ts +2 -0
- package/dist/src/commands/collection-type-configs.js +178 -0
- package/dist/src/commands/collection-type-configs.js.map +1 -0
- package/dist/src/commands/collections.d.ts +2 -0
- package/dist/src/commands/collections.js +515 -0
- package/dist/src/commands/collections.js.map +1 -0
- package/dist/src/commands/comparisons.d.ts +2 -0
- package/dist/src/commands/comparisons.js +6 -6
- package/dist/src/commands/comparisons.js.map +1 -1
- package/dist/src/commands/cron-triggers.d.ts +2 -0
- package/dist/src/commands/cron-triggers.js +357 -0
- package/dist/src/commands/cron-triggers.js.map +1 -0
- package/dist/src/commands/database-types.d.ts +2 -0
- package/dist/src/commands/database-types.js +471 -0
- package/dist/src/commands/database-types.js.map +1 -0
- package/dist/src/commands/databases.d.ts +2 -0
- package/dist/src/commands/databases.js +1462 -83
- package/dist/src/commands/databases.js.map +1 -1
- package/dist/src/commands/documents.d.ts +2 -0
- package/dist/src/commands/documents.js +518 -11
- package/dist/src/commands/documents.js.map +1 -1
- package/dist/src/commands/email-templates.d.ts +2 -0
- package/dist/src/commands/email-templates.js +281 -0
- package/dist/src/commands/email-templates.js.map +1 -0
- package/dist/src/commands/env.d.ts +12 -0
- package/dist/src/commands/env.js +260 -0
- package/dist/src/commands/env.js.map +1 -0
- package/dist/src/commands/group-type-configs.d.ts +2 -0
- package/dist/src/commands/group-type-configs.js +181 -0
- package/dist/src/commands/group-type-configs.js.map +1 -0
- package/dist/src/commands/groups.d.ts +2 -0
- package/dist/src/commands/groups.js +48 -45
- package/dist/src/commands/groups.js.map +1 -1
- package/dist/src/commands/guides.d.ts +159 -0
- package/dist/src/commands/guides.js +449 -35
- package/dist/src/commands/guides.js.map +1 -1
- package/dist/src/commands/init.d.ts +17 -0
- package/dist/src/commands/init.js +811 -201
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/integrations.d.ts +2 -0
- package/dist/src/commands/integrations.js +533 -46
- package/dist/src/commands/integrations.js.map +1 -1
- package/dist/src/commands/llm.d.ts +2 -0
- package/dist/src/commands/llm.js +4 -2
- package/dist/src/commands/llm.js.map +1 -1
- package/dist/src/commands/metadata.d.ts +2 -0
- package/dist/src/commands/metadata.js +194 -0
- package/dist/src/commands/metadata.js.map +1 -0
- package/dist/src/commands/prompts.d.ts +2 -0
- package/dist/src/commands/prompts.js +50 -52
- package/dist/src/commands/prompts.js.map +1 -1
- package/dist/src/commands/rule-sets.d.ts +3 -0
- package/dist/src/commands/rule-sets.js +388 -0
- package/dist/src/commands/rule-sets.js.map +1 -0
- package/dist/src/commands/scripts.d.ts +2 -0
- package/dist/src/commands/scripts.js +667 -0
- package/dist/src/commands/scripts.js.map +1 -0
- package/dist/src/commands/secrets.d.ts +2 -0
- package/dist/src/commands/secrets.js +108 -0
- package/dist/src/commands/secrets.js.map +1 -0
- package/dist/src/commands/skill.d.ts +2 -0
- package/dist/src/commands/skill.js +29 -0
- package/dist/src/commands/skill.js.map +1 -0
- package/dist/src/commands/sync.d.ts +175 -0
- package/dist/src/commands/sync.js +4412 -233
- package/dist/src/commands/sync.js.map +1 -1
- package/dist/src/commands/tokens.d.ts +2 -0
- package/dist/src/commands/tokens.js +122 -19
- package/dist/src/commands/tokens.js.map +1 -1
- package/dist/src/commands/users.d.ts +2 -0
- package/dist/src/commands/users.js +440 -22
- package/dist/src/commands/users.js.map +1 -1
- package/dist/src/commands/waitlist.d.ts +2 -0
- package/dist/src/commands/waitlist.js +10 -10
- package/dist/src/commands/waitlist.js.map +1 -1
- package/dist/src/commands/webhooks.d.ts +2 -0
- package/dist/src/commands/webhooks.js +391 -0
- package/dist/src/commands/webhooks.js.map +1 -0
- package/dist/src/commands/workflows.d.ts +49 -0
- package/dist/src/commands/workflows.js +1009 -123
- package/dist/src/commands/workflows.js.map +1 -1
- package/dist/src/lib/api-client.d.ts +1283 -0
- package/dist/src/lib/api-client.js +1129 -83
- package/dist/src/lib/api-client.js.map +1 -1
- package/dist/src/lib/auth-flow.d.ts +8 -0
- package/dist/src/lib/block-layout.d.ts +160 -0
- package/dist/src/lib/block-layout.js +451 -0
- package/dist/src/lib/block-layout.js.map +1 -0
- package/dist/src/lib/cli-manifest.d.ts +60 -0
- package/dist/src/lib/cli-manifest.js +70 -0
- package/dist/src/lib/cli-manifest.js.map +1 -0
- package/dist/src/lib/config.d.ts +53 -0
- package/dist/src/lib/config.js +92 -53
- package/dist/src/lib/config.js.map +1 -1
- package/dist/src/lib/confirm-prompt.d.ts +83 -0
- package/dist/src/lib/confirm-prompt.js +110 -0
- package/dist/src/lib/confirm-prompt.js.map +1 -0
- package/dist/src/lib/constants.d.ts +2 -0
- package/dist/src/lib/constants.js +3 -0
- package/dist/src/lib/constants.js.map +1 -0
- package/dist/src/lib/crash-handlers.d.ts +20 -0
- package/dist/src/lib/crash-handlers.js +49 -0
- package/dist/src/lib/crash-handlers.js.map +1 -0
- package/dist/src/lib/credentials-store.d.ts +79 -0
- package/dist/src/lib/credentials-store.js +307 -0
- package/dist/src/lib/credentials-store.js.map +1 -0
- package/dist/src/lib/csv.d.ts +48 -0
- package/dist/src/lib/csv.js +177 -0
- package/dist/src/lib/csv.js.map +1 -0
- package/dist/src/lib/db-codegen/dbFingerprint.d.ts +10 -0
- package/dist/src/lib/db-codegen/dbFingerprint.js +17 -0
- package/dist/src/lib/db-codegen/dbFingerprint.js.map +1 -0
- package/dist/src/lib/db-codegen/dbGenerator.d.ts +111 -0
- package/dist/src/lib/db-codegen/dbGenerator.js +371 -0
- package/dist/src/lib/db-codegen/dbGenerator.js.map +1 -0
- package/dist/src/lib/db-codegen/dbNaming.d.ts +45 -0
- package/dist/src/lib/db-codegen/dbNaming.js +104 -0
- package/dist/src/lib/db-codegen/dbNaming.js.map +1 -0
- package/dist/src/lib/db-codegen/dbTemplates.d.ts +97 -0
- package/dist/src/lib/db-codegen/dbTemplates.js +159 -0
- package/dist/src/lib/db-codegen/dbTemplates.js.map +1 -0
- package/dist/src/lib/db-codegen/dbTsTypes.d.ts +78 -0
- package/dist/src/lib/db-codegen/dbTsTypes.js +112 -0
- package/dist/src/lib/db-codegen/dbTsTypes.js.map +1 -0
- package/dist/src/lib/env-resolver.d.ts +62 -0
- package/dist/src/lib/env-resolver.js +121 -0
- package/dist/src/lib/env-resolver.js.map +1 -0
- package/dist/src/lib/fetch.d.ts +5 -0
- package/dist/src/lib/generated-allowlist.d.ts +28 -0
- package/dist/src/lib/generated-allowlist.js +220 -0
- package/dist/src/lib/generated-allowlist.js.map +1 -0
- package/dist/src/lib/init-config.d.ts +59 -0
- package/dist/src/lib/init-config.js +113 -0
- package/dist/src/lib/init-config.js.map +1 -0
- package/dist/src/lib/migration-nag.d.ts +49 -0
- package/dist/src/lib/migration-nag.js +163 -0
- package/dist/src/lib/migration-nag.js.map +1 -0
- package/dist/src/lib/output.d.ts +86 -0
- package/dist/src/lib/output.js +150 -8
- package/dist/src/lib/output.js.map +1 -1
- package/dist/src/lib/paginate.d.ts +33 -0
- package/dist/src/lib/paginate.js +42 -0
- package/dist/src/lib/paginate.js.map +1 -0
- package/dist/src/lib/project-config.d.ts +97 -0
- package/dist/src/lib/project-config.js +209 -0
- package/dist/src/lib/project-config.js.map +1 -0
- package/dist/src/lib/query-operators.d.ts +43 -0
- package/dist/src/lib/query-operators.js +80 -0
- package/dist/src/lib/query-operators.js.map +1 -0
- package/dist/src/lib/refresh-admin-credentials.d.ts +65 -0
- package/dist/src/lib/refresh-admin-credentials.js +103 -0
- package/dist/src/lib/refresh-admin-credentials.js.map +1 -0
- package/dist/src/lib/resolve-platform.d.ts +45 -0
- package/dist/src/lib/resolve-platform.js +43 -0
- package/dist/src/lib/resolve-platform.js.map +1 -0
- package/dist/src/lib/skill-installer.d.ts +23 -0
- package/dist/src/lib/skill-installer.js +135 -0
- package/dist/src/lib/skill-installer.js.map +1 -0
- package/dist/src/lib/snapshots.d.ts +99 -0
- package/dist/src/lib/snapshots.js +357 -0
- package/dist/src/lib/snapshots.js.map +1 -0
- package/dist/src/lib/sync-paths.d.ts +72 -0
- package/dist/src/lib/sync-paths.js +130 -0
- package/dist/src/lib/sync-paths.js.map +1 -0
- package/dist/src/lib/template.d.ts +97 -0
- package/dist/src/lib/template.js +336 -62
- package/dist/src/lib/template.js.map +1 -1
- package/dist/src/lib/token-inject.d.ts +56 -0
- package/dist/src/lib/token-inject.js +204 -0
- package/dist/src/lib/token-inject.js.map +1 -0
- package/dist/src/lib/toml-database-config.d.ts +152 -0
- package/dist/src/lib/toml-database-config.js +600 -0
- package/dist/src/lib/toml-database-config.js.map +1 -0
- package/dist/src/lib/toml-metadata-config.d.ts +139 -0
- package/dist/src/lib/toml-metadata-config.js +427 -0
- package/dist/src/lib/toml-metadata-config.js.map +1 -0
- package/dist/src/lib/toml-params-validator.d.ts +129 -0
- package/dist/src/lib/toml-params-validator.js +298 -0
- package/dist/src/lib/toml-params-validator.js.map +1 -0
- package/dist/src/lib/version-check.d.ts +10 -0
- package/dist/src/lib/version-check.js +172 -0
- package/dist/src/lib/version-check.js.map +1 -0
- package/dist/src/lib/workflow-apply.d.ts +66 -0
- package/dist/src/lib/workflow-apply.js +117 -0
- package/dist/src/lib/workflow-apply.js.map +1 -0
- package/dist/src/lib/workflow-fragments.d.ts +41 -0
- package/dist/src/lib/workflow-fragments.js +121 -0
- package/dist/src/lib/workflow-fragments.js.map +1 -0
- package/dist/src/lib/workflow-toml-validator.d.ts +95 -0
- package/dist/src/lib/workflow-toml-validator.js +323 -0
- package/dist/src/lib/workflow-toml-validator.js.map +1 -0
- package/dist/src/types/index.d.ts +520 -0
- package/dist/src/validators.d.ts +64 -0
- package/dist/src/validators.js +63 -0
- package/dist/src/validators.js.map +1 -0
- package/package.json +18 -4
package/dist/src/lib/config.js
CHANGED
|
@@ -1,46 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Thin compatibility shim over the new project-scoped config system.
|
|
3
|
+
*
|
|
4
|
+
* Historically the CLI had one global credentials file at
|
|
5
|
+
* ~/.primitive/credentials.json and a handful of helpers here. After the
|
|
6
|
+
* project-config overhaul (issue #373) credentials live per-environment
|
|
7
|
+
* inside `<projectRoot>/.primitive/credentials.json` when a
|
|
8
|
+
* .primitive/config.json is in scope, and fall back to the legacy global
|
|
9
|
+
* file otherwise.
|
|
10
|
+
*
|
|
11
|
+
* The rest of the CLI continues to import from this module, so we keep
|
|
12
|
+
* the original public API (loadCredentials, saveCredentials, etc.) and
|
|
13
|
+
* just delegate to the new stores.
|
|
14
|
+
*/
|
|
15
|
+
import { clearCredentialsStore, clearCurrentAppStore, loadCredentialsStore, peekLegacyCredentials, saveCredentialsStore, setCurrentAppStore, } from "./credentials-store.js";
|
|
16
|
+
import { getCurrentEnvironment, getCurrentEnvNameSafe, } from "./env-resolver.js";
|
|
17
|
+
import { PROJECT_CONFIG_DISPLAY_NAME } from "./project-config.js";
|
|
18
|
+
import { DEFAULT_SERVER_URL } from "./constants.js";
|
|
12
19
|
export function loadCredentials() {
|
|
13
|
-
|
|
14
|
-
if (!existsSync(CREDENTIALS_FILE)) {
|
|
15
|
-
return null;
|
|
16
|
-
}
|
|
17
|
-
const data = readFileSync(CREDENTIALS_FILE, "utf-8");
|
|
18
|
-
return JSON.parse(data);
|
|
19
|
-
}
|
|
20
|
-
catch {
|
|
21
|
-
return null;
|
|
22
|
-
}
|
|
20
|
+
return loadCredentialsStore();
|
|
23
21
|
}
|
|
24
22
|
export function saveCredentials(credentials) {
|
|
25
|
-
|
|
26
|
-
writeFileSync(CREDENTIALS_FILE, JSON.stringify(credentials, null, 2), {
|
|
27
|
-
mode: 0o600,
|
|
28
|
-
});
|
|
29
|
-
// Ensure file permissions are secure
|
|
30
|
-
chmodSync(CREDENTIALS_FILE, 0o600);
|
|
23
|
+
saveCredentialsStore(credentials);
|
|
31
24
|
}
|
|
32
25
|
export function clearCredentials() {
|
|
33
|
-
|
|
34
|
-
if (existsSync(CREDENTIALS_FILE)) {
|
|
35
|
-
writeFileSync(CREDENTIALS_FILE, "", { mode: 0o600 });
|
|
36
|
-
// Actually remove the file
|
|
37
|
-
const { unlinkSync } = require("fs");
|
|
38
|
-
unlinkSync(CREDENTIALS_FILE);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
catch {
|
|
42
|
-
// Ignore errors
|
|
43
|
-
}
|
|
26
|
+
clearCredentialsStore();
|
|
44
27
|
}
|
|
45
28
|
export function isTokenExpired(credentials) {
|
|
46
29
|
if (!credentials.expiresAt)
|
|
@@ -59,40 +42,96 @@ export function isTokenExpiringSoon(credentials) {
|
|
|
59
42
|
return expiresAt - now < 5 * 60 * 1000;
|
|
60
43
|
}
|
|
61
44
|
export function setCurrentApp(appId, appName) {
|
|
62
|
-
|
|
63
|
-
if (!credentials) {
|
|
64
|
-
throw new Error("Not logged in. Run 'primitive login' first.");
|
|
65
|
-
}
|
|
66
|
-
credentials.currentAppId = appId;
|
|
67
|
-
credentials.currentAppName = appName;
|
|
68
|
-
saveCredentials(credentials);
|
|
45
|
+
setCurrentAppStore(appId, appName);
|
|
69
46
|
}
|
|
70
47
|
export function clearCurrentApp() {
|
|
71
|
-
|
|
72
|
-
if (!credentials) {
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
delete credentials.currentAppId;
|
|
76
|
-
delete credentials.currentAppName;
|
|
77
|
-
saveCredentials(credentials);
|
|
48
|
+
clearCurrentAppStore();
|
|
78
49
|
}
|
|
79
50
|
export function getCurrentAppId() {
|
|
51
|
+
// In project mode, the appId may come from .primitive/config.json (via
|
|
52
|
+
// loadCredentialsStore), which is what we want. In legacy mode it comes
|
|
53
|
+
// from the global credentials file.
|
|
80
54
|
const credentials = loadCredentials();
|
|
81
55
|
return credentials?.currentAppId;
|
|
82
56
|
}
|
|
83
57
|
export function resolveAppId(appId, options) {
|
|
84
58
|
const resolved = appId || options.app || getCurrentAppId();
|
|
85
59
|
if (!resolved) {
|
|
86
|
-
|
|
60
|
+
// When the active env declares an `appId` in .primitive/config.json but
|
|
61
|
+
// has no credentials slot, loadCredentialsStore() returns null (its
|
|
62
|
+
// null == unauthenticated contract), so getCurrentAppId() yields nothing
|
|
63
|
+
// even though an appId IS configured. In that case the accurate problem
|
|
64
|
+
// is that the user isn't authenticated for this env — not that no app was
|
|
65
|
+
// specified. (A creds slot would have blended in env.config.appId and made
|
|
66
|
+
// `resolved` truthy, so reaching here with a configured appId can only mean
|
|
67
|
+
// missing credentials.)
|
|
68
|
+
let env = null;
|
|
69
|
+
try {
|
|
70
|
+
env = getCurrentEnvironment();
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// Env resolution failed (ambiguous/unknown env) — fall back to the
|
|
74
|
+
// original "No app specified." message below.
|
|
75
|
+
}
|
|
76
|
+
if (env && env.config.appId) {
|
|
77
|
+
console.error(`Not logged in to environment "${env.name}". An appId is configured in ${PROJECT_CONFIG_DISPLAY_NAME} but you're not authenticated. Run 'primitive -e ${env.name} login'.`);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
const envName = getCurrentEnvNameSafe();
|
|
81
|
+
const hint = envName
|
|
82
|
+
? `(current environment: ${envName}). Set 'appId' in .primitive/config.json, pass --app, or run 'primitive use <app-id>'.`
|
|
83
|
+
: `Use <app-id>, --app, or 'primitive use <app-id>' to set context.`;
|
|
84
|
+
console.error(`No app specified. ${hint}`);
|
|
87
85
|
process.exit(1);
|
|
88
86
|
}
|
|
89
87
|
return resolved;
|
|
90
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Returns the API base URL for the active environment (project mode) or
|
|
91
|
+
* the serverUrl saved in the legacy credentials file.
|
|
92
|
+
*/
|
|
91
93
|
export function getServerUrl() {
|
|
94
|
+
// Project mode takes priority — the project config is the source of
|
|
95
|
+
// truth for the API URL, even if we haven't logged in yet.
|
|
96
|
+
try {
|
|
97
|
+
const env = getCurrentEnvironment();
|
|
98
|
+
if (env)
|
|
99
|
+
return env.config.apiUrl;
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
// Env resolution failed — fall through to credentials-based lookup.
|
|
103
|
+
}
|
|
92
104
|
const credentials = loadCredentials();
|
|
93
105
|
if (!credentials?.serverUrl) {
|
|
94
106
|
throw new Error("Not logged in. Run 'primitive login' first.");
|
|
95
107
|
}
|
|
96
108
|
return credentials.serverUrl;
|
|
97
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Resolves the API base URL to authenticate against, used by `primitive login`
|
|
112
|
+
* (issue #1343).
|
|
113
|
+
*
|
|
114
|
+
* Unlike getServerUrl(), this must work *before* any credentials exist (first
|
|
115
|
+
* login), so it never falls back to the stored credentials' serverUrl:
|
|
116
|
+
*
|
|
117
|
+
* - Project mode → the active environment's `apiUrl` (canonical). Lets
|
|
118
|
+
* getCurrentEnvironment() throw on an unresolvable env (ambiguous/unknown
|
|
119
|
+
* --env) so the caller can fail loudly instead of silently targeting prod.
|
|
120
|
+
* - Legacy mode (no .primitive/config.json) → DEFAULT_SERVER_URL, which
|
|
121
|
+
* honors the PRIMITIVE_SERVER_URL escape hatch (constants.ts).
|
|
122
|
+
*
|
|
123
|
+
* The trailing slash is stripped so callers can build `${url}/admin/api/...`.
|
|
124
|
+
*/
|
|
125
|
+
export function getConfiguredServerUrl() {
|
|
126
|
+
const env = getCurrentEnvironment(); // may throw on an unresolvable env
|
|
127
|
+
return (env ? env.config.apiUrl : DEFAULT_SERVER_URL).replace(/\/$/, "");
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Exposed so commands can check whether there's a pre-project-config
|
|
131
|
+
* credentials file at ~/.primitive/credentials.json (used by migration
|
|
132
|
+
* prompts).
|
|
133
|
+
*/
|
|
134
|
+
export function legacyCredentialsExist() {
|
|
135
|
+
return peekLegacyCredentials() !== null;
|
|
136
|
+
}
|
|
98
137
|
//# sourceMappingURL=config.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/lib/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared interactive-confirmation helper for destructive CLI commands.
|
|
3
|
+
*
|
|
4
|
+
* Background (issue #972): every destructive command used the legacy
|
|
5
|
+
* `inquirer.default.prompt([{ type: "confirm", ... }])` pattern directly. When
|
|
6
|
+
* stdin is not a usable TTY (closed/piped/EOF/Ctrl-D), inquirer v9.3.8 throws
|
|
7
|
+
* `ERR_USE_AFTER_CLOSE: readline was closed` from inside a Node event-emitter
|
|
8
|
+
* callback (`PromptUI.onForceClose` -> `process.emit`). Because that throw
|
|
9
|
+
* originates in event-dispatch, it escapes both the command's own `try/catch`
|
|
10
|
+
* AND the top-level `.catch` in `cli/bin/primitive.ts` — and with no
|
|
11
|
+
* `uncaughtException` handler, Node printed only the bare `Node.js vX` banner
|
|
12
|
+
* and died before the API call. `cron-triggers delete` / `workflows delete`
|
|
13
|
+
* crashed without deleting anything.
|
|
14
|
+
*
|
|
15
|
+
* Migration (issue #999): the helper's internals are now built on the modern
|
|
16
|
+
* `@inquirer/prompts` `confirm()` API instead of legacy `inquirer.default.prompt`.
|
|
17
|
+
* The modern API rejects its promise with a *catchable* `ExitPromptError`
|
|
18
|
+
* (Ctrl-C / SIGINT / force-close) / `AbortPromptError` / `CancelPromptError`
|
|
19
|
+
* rather than crashing via `process.emit`, so the root-cause crash class is
|
|
20
|
+
* removed. Crucially, `@inquirer/prompts` `confirm()` has **no built-in non-TTY
|
|
21
|
+
* guard** — so the #972 guard below MUST stay, or the crash class regresses into
|
|
22
|
+
* a hang/opaque-reject on piped/closed stdin. The migration changes only the
|
|
23
|
+
* default prompt fn's internals; the guard, the `ConfirmPromptError` contract,
|
|
24
|
+
* and the public `confirmPrompt()` signature are preserved.
|
|
25
|
+
*
|
|
26
|
+
* `confirmPrompt()` fixes the cause:
|
|
27
|
+
* 1. Non-TTY guard — if stdin is not a TTY, it never touches the prompt.
|
|
28
|
+
* Instead it throws a catchable `ConfirmPromptError` with an actionable
|
|
29
|
+
* message ("re-run with --yes ..."). Per the maintainer decision on #972
|
|
30
|
+
* this is a hard error, never a silent mutate or silent abort.
|
|
31
|
+
* 2. Local try/catch — in a real TTY the prompt is awaited inside a try/catch
|
|
32
|
+
* so an abort/EOF (`ExitPromptError` / `AbortPromptError` /
|
|
33
|
+
* `CancelPromptError`, or legacy `ERR_USE_AFTER_CLOSE`) surfaces as a clean
|
|
34
|
+
* `ConfirmPromptError`, not a stack trace or crash.
|
|
35
|
+
*
|
|
36
|
+
* Commands should call this instead of inquirer directly, e.g.:
|
|
37
|
+
*
|
|
38
|
+
* if (!options.yes) {
|
|
39
|
+
* try {
|
|
40
|
+
* const ok = await confirmPrompt(`Delete cron trigger ${id}?`);
|
|
41
|
+
* if (!ok) { info("Cancelled."); return; }
|
|
42
|
+
* } catch (err) {
|
|
43
|
+
* error(err.message);
|
|
44
|
+
* process.exit(1);
|
|
45
|
+
* }
|
|
46
|
+
* }
|
|
47
|
+
*/
|
|
48
|
+
/** Error thrown when a confirmation can't be obtained interactively. */
|
|
49
|
+
export declare class ConfirmPromptError extends Error {
|
|
50
|
+
constructor(message: string);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Shape of the `@inquirer/prompts` `confirm()` function. Injectable for testing.
|
|
54
|
+
*
|
|
55
|
+
* Note (#999): this shifted from the legacy inquirer questions-array →
|
|
56
|
+
* `{ confirm: boolean }` shape to the modern bare `{ message, default }` →
|
|
57
|
+
* `Promise<boolean>` shape.
|
|
58
|
+
*/
|
|
59
|
+
export type PromptFn = (config: {
|
|
60
|
+
message: string;
|
|
61
|
+
default?: boolean;
|
|
62
|
+
}) => Promise<boolean>;
|
|
63
|
+
export interface ConfirmPromptOptions {
|
|
64
|
+
/** Default answer when the user just presses enter. Defaults to false. */
|
|
65
|
+
defaultValue?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Override the underlying prompt function (for tests). Defaults to lazily
|
|
68
|
+
* importing `@inquirer/prompts` `confirm`.
|
|
69
|
+
*/
|
|
70
|
+
promptFn?: PromptFn;
|
|
71
|
+
/**
|
|
72
|
+
* Override TTY detection (for tests). Defaults to `process.stdin.isTTY`.
|
|
73
|
+
*/
|
|
74
|
+
isTTY?: boolean;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Ask the user a yes/no confirmation question.
|
|
78
|
+
*
|
|
79
|
+
* @returns `true` if the user confirms, `false` if they decline.
|
|
80
|
+
* @throws {ConfirmPromptError} when stdin is not an interactive TTY (so the
|
|
81
|
+
* prompt can't be shown), or when the underlying prompt aborts/crashes.
|
|
82
|
+
*/
|
|
83
|
+
export declare function confirmPrompt(message: string, options?: ConfirmPromptOptions): Promise<boolean>;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared interactive-confirmation helper for destructive CLI commands.
|
|
3
|
+
*
|
|
4
|
+
* Background (issue #972): every destructive command used the legacy
|
|
5
|
+
* `inquirer.default.prompt([{ type: "confirm", ... }])` pattern directly. When
|
|
6
|
+
* stdin is not a usable TTY (closed/piped/EOF/Ctrl-D), inquirer v9.3.8 throws
|
|
7
|
+
* `ERR_USE_AFTER_CLOSE: readline was closed` from inside a Node event-emitter
|
|
8
|
+
* callback (`PromptUI.onForceClose` -> `process.emit`). Because that throw
|
|
9
|
+
* originates in event-dispatch, it escapes both the command's own `try/catch`
|
|
10
|
+
* AND the top-level `.catch` in `cli/bin/primitive.ts` — and with no
|
|
11
|
+
* `uncaughtException` handler, Node printed only the bare `Node.js vX` banner
|
|
12
|
+
* and died before the API call. `cron-triggers delete` / `workflows delete`
|
|
13
|
+
* crashed without deleting anything.
|
|
14
|
+
*
|
|
15
|
+
* Migration (issue #999): the helper's internals are now built on the modern
|
|
16
|
+
* `@inquirer/prompts` `confirm()` API instead of legacy `inquirer.default.prompt`.
|
|
17
|
+
* The modern API rejects its promise with a *catchable* `ExitPromptError`
|
|
18
|
+
* (Ctrl-C / SIGINT / force-close) / `AbortPromptError` / `CancelPromptError`
|
|
19
|
+
* rather than crashing via `process.emit`, so the root-cause crash class is
|
|
20
|
+
* removed. Crucially, `@inquirer/prompts` `confirm()` has **no built-in non-TTY
|
|
21
|
+
* guard** — so the #972 guard below MUST stay, or the crash class regresses into
|
|
22
|
+
* a hang/opaque-reject on piped/closed stdin. The migration changes only the
|
|
23
|
+
* default prompt fn's internals; the guard, the `ConfirmPromptError` contract,
|
|
24
|
+
* and the public `confirmPrompt()` signature are preserved.
|
|
25
|
+
*
|
|
26
|
+
* `confirmPrompt()` fixes the cause:
|
|
27
|
+
* 1. Non-TTY guard — if stdin is not a TTY, it never touches the prompt.
|
|
28
|
+
* Instead it throws a catchable `ConfirmPromptError` with an actionable
|
|
29
|
+
* message ("re-run with --yes ..."). Per the maintainer decision on #972
|
|
30
|
+
* this is a hard error, never a silent mutate or silent abort.
|
|
31
|
+
* 2. Local try/catch — in a real TTY the prompt is awaited inside a try/catch
|
|
32
|
+
* so an abort/EOF (`ExitPromptError` / `AbortPromptError` /
|
|
33
|
+
* `CancelPromptError`, or legacy `ERR_USE_AFTER_CLOSE`) surfaces as a clean
|
|
34
|
+
* `ConfirmPromptError`, not a stack trace or crash.
|
|
35
|
+
*
|
|
36
|
+
* Commands should call this instead of inquirer directly, e.g.:
|
|
37
|
+
*
|
|
38
|
+
* if (!options.yes) {
|
|
39
|
+
* try {
|
|
40
|
+
* const ok = await confirmPrompt(`Delete cron trigger ${id}?`);
|
|
41
|
+
* if (!ok) { info("Cancelled."); return; }
|
|
42
|
+
* } catch (err) {
|
|
43
|
+
* error(err.message);
|
|
44
|
+
* process.exit(1);
|
|
45
|
+
* }
|
|
46
|
+
* }
|
|
47
|
+
*/
|
|
48
|
+
/** Error thrown when a confirmation can't be obtained interactively. */
|
|
49
|
+
export class ConfirmPromptError extends Error {
|
|
50
|
+
constructor(message) {
|
|
51
|
+
super(message);
|
|
52
|
+
this.name = "ConfirmPromptError";
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async function defaultPromptFn(config) {
|
|
56
|
+
const { confirm } = await import("@inquirer/prompts");
|
|
57
|
+
return confirm(config);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Names of the catchable abort errors thrown by `@inquirer/prompts` when the
|
|
61
|
+
* user interrupts a prompt (Ctrl-C / SIGINT / force-close / abort signal /
|
|
62
|
+
* cancel). We match on `name` (not just `instanceof`) so detection is robust to
|
|
63
|
+
* the error class being duplicated across module realms.
|
|
64
|
+
*/
|
|
65
|
+
const ABORT_ERROR_NAMES = new Set([
|
|
66
|
+
"ExitPromptError",
|
|
67
|
+
"AbortPromptError",
|
|
68
|
+
"CancelPromptError",
|
|
69
|
+
]);
|
|
70
|
+
/**
|
|
71
|
+
* Ask the user a yes/no confirmation question.
|
|
72
|
+
*
|
|
73
|
+
* @returns `true` if the user confirms, `false` if they decline.
|
|
74
|
+
* @throws {ConfirmPromptError} when stdin is not an interactive TTY (so the
|
|
75
|
+
* prompt can't be shown), or when the underlying prompt aborts/crashes.
|
|
76
|
+
*/
|
|
77
|
+
export async function confirmPrompt(message, options = {}) {
|
|
78
|
+
const isTTY = options.isTTY ?? Boolean(process.stdin.isTTY);
|
|
79
|
+
if (!isTTY) {
|
|
80
|
+
throw new ConfirmPromptError("No interactive terminal available to confirm this action. " +
|
|
81
|
+
"Re-run with --yes (-y) to skip the confirmation prompt in " +
|
|
82
|
+
"non-interactive contexts (CI, pipes, agents).");
|
|
83
|
+
}
|
|
84
|
+
const promptFn = options.promptFn ?? defaultPromptFn;
|
|
85
|
+
try {
|
|
86
|
+
const confirmed = await promptFn({
|
|
87
|
+
message,
|
|
88
|
+
default: options.defaultValue ?? false,
|
|
89
|
+
});
|
|
90
|
+
return Boolean(confirmed);
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
// A deliberate abort/EOF/Ctrl-C/Ctrl-D — either the modern
|
|
94
|
+
// `@inquirer/prompts` `ExitPromptError`/`AbortPromptError`/`CancelPromptError`
|
|
95
|
+
// (matched by name to survive cross-realm `instanceof` mismatches), or the
|
|
96
|
+
// legacy inquirer `ERR_USE_AFTER_CLOSE`. Surface as a clean, actionable
|
|
97
|
+
// error so the caller exits 1 with no stack trace / bare `Node.js vX` banner.
|
|
98
|
+
if (ABORT_ERROR_NAMES.has(err?.name) ||
|
|
99
|
+
err?.code === "ERR_USE_AFTER_CLOSE") {
|
|
100
|
+
throw new ConfirmPromptError("Confirmation cancelled (no interactive input). " +
|
|
101
|
+
"Re-run with --yes (-y) to skip confirmation.");
|
|
102
|
+
}
|
|
103
|
+
// Any other prompt failure: still surface it as a clean, catchable error
|
|
104
|
+
// rather than letting it escape as an uncaught crash.
|
|
105
|
+
throw new ConfirmPromptError(err?.message
|
|
106
|
+
? `Confirmation prompt failed: ${err.message}`
|
|
107
|
+
: "Confirmation prompt failed.");
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=confirm-prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirm-prompt.js","sourceRoot":"","sources":["../../../src/lib/confirm-prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAEH,wEAAwE;AACxE,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAC3C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AA4BD,KAAK,UAAU,eAAe,CAAC,MAG9B;IACC,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;IACtD,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC;AACzB,CAAC;AAED;;;;;GAKG;AACH,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC;IAChC,iBAAiB;IACjB,kBAAkB;IAClB,mBAAmB;CACpB,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,OAAe,EACf,UAAgC,EAAE;IAElC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAE5D,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,kBAAkB,CAC1B,4DAA4D;YAC1D,4DAA4D;YAC5D,+CAA+C,CAClD,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,eAAe,CAAC;IAErD,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC;YAC/B,OAAO;YACP,OAAO,EAAE,OAAO,CAAC,YAAY,IAAI,KAAK;SACvC,CAAC,CAAC;QACH,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC;IAC5B,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,2DAA2D;QAC3D,+EAA+E;QAC/E,2EAA2E;QAC3E,wEAAwE;QACxE,8EAA8E;QAC9E,IACE,iBAAiB,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC;YAChC,GAAG,EAAE,IAAI,KAAK,qBAAqB,EACnC,CAAC;YACD,MAAM,IAAI,kBAAkB,CAC1B,iDAAiD;gBAC/C,8CAA8C,CACjD,CAAC;QACJ,CAAC;QACD,yEAAyE;QACzE,sDAAsD;QACtD,MAAM,IAAI,kBAAkB,CAC1B,GAAG,EAAE,OAAO;YACV,CAAC,CAAC,+BAA+B,GAAG,CAAC,OAAO,EAAE;YAC9C,CAAC,CAAC,6BAA6B,CAClC,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/lib/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,qBAAqB,GAAG,0BAA0B,CAAC;AAEhE,MAAM,CAAC,MAAM,kBAAkB,GAC7B,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global crash handlers for the CLI entrypoint (issue #972, Option A).
|
|
3
|
+
*
|
|
4
|
+
* The CLI previously registered no `uncaughtException` / `unhandledRejection`
|
|
5
|
+
* handlers. When an error escaped the top-level `.catch` in
|
|
6
|
+
* `cli/bin/primitive.ts` — e.g. the `ERR_USE_AFTER_CLOSE` thrown from inside an
|
|
7
|
+
* inquirer event-emitter callback when stdin isn't a usable TTY — Node printed
|
|
8
|
+
* only its bare `Node.js vX` version banner and died. That was the exact
|
|
9
|
+
* symptom in #972: a delete command crashed with no error message.
|
|
10
|
+
*
|
|
11
|
+
* These handlers are a narrow safety net: print a clean `✗ <message>` to stderr
|
|
12
|
+
* (matching `error()` in output.ts) and exit non-zero, so NO command can ever
|
|
13
|
+
* bare-crash again. They intentionally do not try to recover — they only make
|
|
14
|
+
* an already-fatal error legible.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Register process-level handlers that convert otherwise-fatal escaped errors
|
|
18
|
+
* into a clean stderr message + non-zero exit. Idempotent.
|
|
19
|
+
*/
|
|
20
|
+
export declare function installGlobalCrashHandlers(): void;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global crash handlers for the CLI entrypoint (issue #972, Option A).
|
|
3
|
+
*
|
|
4
|
+
* The CLI previously registered no `uncaughtException` / `unhandledRejection`
|
|
5
|
+
* handlers. When an error escaped the top-level `.catch` in
|
|
6
|
+
* `cli/bin/primitive.ts` — e.g. the `ERR_USE_AFTER_CLOSE` thrown from inside an
|
|
7
|
+
* inquirer event-emitter callback when stdin isn't a usable TTY — Node printed
|
|
8
|
+
* only its bare `Node.js vX` version banner and died. That was the exact
|
|
9
|
+
* symptom in #972: a delete command crashed with no error message.
|
|
10
|
+
*
|
|
11
|
+
* These handlers are a narrow safety net: print a clean `✗ <message>` to stderr
|
|
12
|
+
* (matching `error()` in output.ts) and exit non-zero, so NO command can ever
|
|
13
|
+
* bare-crash again. They intentionally do not try to recover — they only make
|
|
14
|
+
* an already-fatal error legible.
|
|
15
|
+
*/
|
|
16
|
+
import { error } from "./output.js";
|
|
17
|
+
function describe(err) {
|
|
18
|
+
if (err && typeof err === "object") {
|
|
19
|
+
const e = err;
|
|
20
|
+
// The signature crash from a non-TTY confirm prompt — give actionable help.
|
|
21
|
+
if (e.code === "ERR_USE_AFTER_CLOSE") {
|
|
22
|
+
return ("No interactive terminal available to confirm this action. " +
|
|
23
|
+
"Re-run with --yes (-y) to skip the confirmation prompt in " +
|
|
24
|
+
"non-interactive contexts (CI, pipes, agents).");
|
|
25
|
+
}
|
|
26
|
+
if (e.message)
|
|
27
|
+
return e.message;
|
|
28
|
+
}
|
|
29
|
+
return "An unexpected error occurred.";
|
|
30
|
+
}
|
|
31
|
+
let installed = false;
|
|
32
|
+
/**
|
|
33
|
+
* Register process-level handlers that convert otherwise-fatal escaped errors
|
|
34
|
+
* into a clean stderr message + non-zero exit. Idempotent.
|
|
35
|
+
*/
|
|
36
|
+
export function installGlobalCrashHandlers() {
|
|
37
|
+
if (installed)
|
|
38
|
+
return;
|
|
39
|
+
installed = true;
|
|
40
|
+
process.on("uncaughtException", (err) => {
|
|
41
|
+
error(describe(err));
|
|
42
|
+
process.exit(1);
|
|
43
|
+
});
|
|
44
|
+
process.on("unhandledRejection", (reason) => {
|
|
45
|
+
error(describe(reason));
|
|
46
|
+
process.exit(1);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=crash-handlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crash-handlers.js","sourceRoot":"","sources":["../../../src/lib/crash-handlers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC,SAAS,QAAQ,CAAC,GAAY;IAC5B,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QACnC,MAAM,CAAC,GAAG,GAA0C,CAAC;QACrD,4EAA4E;QAC5E,IAAI,CAAC,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;YACrC,OAAO,CACL,4DAA4D;gBAC5D,4DAA4D;gBAC5D,+CAA+C,CAChD,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,CAAC,OAAO;YAAE,OAAO,CAAC,CAAC,OAAO,CAAC;IAClC,CAAC;IACD,OAAO,+BAA+B,CAAC;AACzC,CAAC;AAED,IAAI,SAAS,GAAG,KAAK,CAAC;AAEtB;;;GAGG;AACH,MAAM,UAAU,0BAA0B;IACxC,IAAI,SAAS;QAAE,OAAO;IACtB,SAAS,GAAG,IAAI,CAAC;IAEjB,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,GAAG,EAAE,EAAE;QACtC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,MAAM,EAAE,EAAE;QAC1C,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credentials storage with dual-mode support.
|
|
3
|
+
*
|
|
4
|
+
* Mode A (project mode): credentials live at
|
|
5
|
+
* <projectRoot>/.primitive/credentials.json
|
|
6
|
+
* with per-environment slots:
|
|
7
|
+
* {
|
|
8
|
+
* "environments": {
|
|
9
|
+
* "dev": { "accessToken": "...", "refreshToken": "...", ... },
|
|
10
|
+
* "prod": { ... }
|
|
11
|
+
* }
|
|
12
|
+
* }
|
|
13
|
+
*
|
|
14
|
+
* Mode B (legacy mode): no .primitive/config.json in scope, so we fall back to
|
|
15
|
+
* ~/.primitive/credentials.json
|
|
16
|
+
* with the flat Credentials shape the CLI has always used.
|
|
17
|
+
*
|
|
18
|
+
* The legacy mode is still the "global default" for users who haven't
|
|
19
|
+
* run `primitive init` yet.
|
|
20
|
+
*/
|
|
21
|
+
import type { Credentials } from "../types/index.js";
|
|
22
|
+
export declare const PROJECT_LOCAL_DIR = ".primitive";
|
|
23
|
+
export declare const PROJECT_CREDENTIALS_FILENAME = "credentials.json";
|
|
24
|
+
/** Returns true when a .primitive/config.json is in scope (project mode active). */
|
|
25
|
+
export declare function isProjectMode(): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Returns the path to the credentials file that will be used, based on
|
|
28
|
+
* whether we're in project mode or legacy mode.
|
|
29
|
+
*/
|
|
30
|
+
export declare function getCredentialsFilePath(): string;
|
|
31
|
+
/**
|
|
32
|
+
* Reads credentials for the current environment (project mode) or the
|
|
33
|
+
* legacy global file. Returns the standard Credentials shape so existing
|
|
34
|
+
* callers don't need to change.
|
|
35
|
+
*
|
|
36
|
+
* In project mode, we blend the per-env stored creds with the serverUrl
|
|
37
|
+
* and appId from .primitive/config.json to produce the Credentials the rest of
|
|
38
|
+
* the CLI expects.
|
|
39
|
+
*/
|
|
40
|
+
export declare function loadCredentialsStore(): Credentials | null;
|
|
41
|
+
/**
|
|
42
|
+
* Saves credentials. In project mode, writes to the per-env slot in the
|
|
43
|
+
* project credentials file. In legacy mode, writes the global file.
|
|
44
|
+
*
|
|
45
|
+
* The serverUrl on the incoming Credentials is used as-is for legacy
|
|
46
|
+
* mode, and ignored in project mode (the env's apiUrl is canonical).
|
|
47
|
+
*/
|
|
48
|
+
export declare function saveCredentialsStore(credentials: Credentials): void;
|
|
49
|
+
/**
|
|
50
|
+
* Clears credentials for the current environment (project mode) or
|
|
51
|
+
* deletes the legacy file (legacy mode).
|
|
52
|
+
*/
|
|
53
|
+
export declare function clearCredentialsStore(): void;
|
|
54
|
+
/**
|
|
55
|
+
* Removes the credentials slot for the named environment in a specific
|
|
56
|
+
* project's credentials file. Used by `env remove` so stale tokens from a
|
|
57
|
+
* previously-removed environment can never be silently re-used if the same
|
|
58
|
+
* name is later added back. Never throws.
|
|
59
|
+
*/
|
|
60
|
+
export declare function clearCredentialsForEnvInProject(projectRoot: string, envName: string): void;
|
|
61
|
+
/**
|
|
62
|
+
* Lists all environments that have stored credentials in project mode.
|
|
63
|
+
* Returns an empty array in legacy mode.
|
|
64
|
+
*/
|
|
65
|
+
export declare function listAuthenticatedEnvironments(): string[];
|
|
66
|
+
/**
|
|
67
|
+
* Updates the "current app" in credential storage. In project mode with a
|
|
68
|
+
* project-level appId this is a no-op (the project config is canonical).
|
|
69
|
+
*/
|
|
70
|
+
export declare function setCurrentAppStore(appId: string, appName?: string): void;
|
|
71
|
+
/**
|
|
72
|
+
* Clears the "current app" for the current environment.
|
|
73
|
+
*/
|
|
74
|
+
export declare function clearCurrentAppStore(): void;
|
|
75
|
+
/**
|
|
76
|
+
* Returns the legacy credentials file, if one exists. Used by migration
|
|
77
|
+
* prompts that want to detect a pre-project-config install.
|
|
78
|
+
*/
|
|
79
|
+
export declare function peekLegacyCredentials(): Credentials | null;
|