primitive-admin 1.0.48 → 1.0.50
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 +102 -2
- package/assets/skill/skills/primitive-platform/SKILL.md +85 -30
- package/dist/bin/primitive.d.ts +2 -0
- package/dist/bin/primitive.js +66 -1
- package/dist/bin/primitive.js.map +1 -1
- package/dist/src/commands/admins.d.ts +2 -0
- package/dist/src/commands/analytics.d.ts +2 -0
- package/dist/src/commands/apps.d.ts +2 -0
- package/dist/src/commands/apps.js +20 -0
- package/dist/src/commands/apps.js.map +1 -1
- package/dist/src/commands/auth.d.ts +2 -0
- package/dist/src/commands/blob-buckets.d.ts +2 -0
- package/dist/src/commands/catalog.d.ts +2 -0
- package/dist/src/commands/collection-type-configs.d.ts +2 -0
- package/dist/src/commands/collections.d.ts +2 -0
- package/dist/src/commands/comparisons.d.ts +2 -0
- package/dist/src/commands/cron-triggers.d.ts +2 -0
- package/dist/src/commands/cron-triggers.js +8 -15
- package/dist/src/commands/cron-triggers.js.map +1 -1
- package/dist/src/commands/database-types.d.ts +2 -0
- package/dist/src/commands/databases.d.ts +2 -0
- package/dist/src/commands/databases.js +31 -0
- package/dist/src/commands/databases.js.map +1 -1
- package/dist/src/commands/documents.d.ts +2 -0
- package/dist/src/commands/email-templates.d.ts +2 -0
- package/dist/src/commands/env.d.ts +12 -0
- package/dist/src/commands/group-type-configs.d.ts +2 -0
- package/dist/src/commands/groups.d.ts +2 -0
- package/dist/src/commands/guides.d.ts +84 -0
- package/dist/src/commands/guides.js +201 -24
- package/dist/src/commands/guides.js.map +1 -1
- package/dist/src/commands/init.d.ts +17 -0
- package/dist/src/commands/init.js +63 -25
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/integrations.d.ts +2 -0
- package/dist/src/commands/integrations.js +22 -5
- package/dist/src/commands/integrations.js.map +1 -1
- package/dist/src/commands/llm.d.ts +2 -0
- package/dist/src/commands/prompts.d.ts +2 -0
- package/dist/src/commands/rule-sets.d.ts +2 -0
- package/dist/src/commands/secrets.d.ts +2 -0
- package/dist/src/commands/skill.d.ts +2 -0
- package/dist/src/commands/sync.d.ts +113 -0
- package/dist/src/commands/sync.js +366 -12
- package/dist/src/commands/sync.js.map +1 -1
- package/dist/src/commands/tokens.d.ts +2 -0
- package/dist/src/commands/tokens.js +104 -1
- package/dist/src/commands/tokens.js.map +1 -1
- package/dist/src/commands/users.d.ts +2 -0
- package/dist/src/commands/waitlist.d.ts +2 -0
- package/dist/src/commands/waitlist.js +1 -1
- package/dist/src/commands/waitlist.js.map +1 -1
- package/dist/src/commands/webhooks.d.ts +2 -0
- package/dist/src/commands/workflows.d.ts +49 -0
- package/dist/src/commands/workflows.js +74 -21
- package/dist/src/commands/workflows.js.map +1 -1
- package/dist/src/lib/api-client.d.ts +1244 -0
- package/dist/src/lib/api-client.js +30 -0
- package/dist/src/lib/api-client.js.map +1 -1
- package/dist/src/lib/auth-flow.d.ts +8 -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 +37 -0
- package/dist/src/lib/confirm-prompt.d.ts +66 -0
- package/dist/src/lib/confirm-prompt.js +85 -0
- package/dist/src/lib/confirm-prompt.js.map +1 -0
- package/dist/src/lib/constants.d.ts +2 -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/csv.d.ts +48 -0
- package/dist/src/lib/db-codegen/dbFingerprint.d.ts +10 -0
- package/dist/src/lib/db-codegen/dbGenerator.d.ts +111 -0
- package/dist/src/lib/db-codegen/dbNaming.d.ts +45 -0
- package/dist/src/lib/db-codegen/dbTemplates.d.ts +97 -0
- package/dist/src/lib/db-codegen/dbTemplates.js +31 -10
- package/dist/src/lib/db-codegen/dbTemplates.js.map +1 -1
- package/dist/src/lib/db-codegen/dbTsTypes.d.ts +78 -0
- package/dist/src/lib/db-codegen/dbTsTypes.js +2 -2
- package/dist/src/lib/db-codegen/dbTsTypes.js.map +1 -1
- package/dist/src/lib/env-resolver.d.ts +62 -0
- package/dist/src/lib/fetch.d.ts +5 -0
- package/dist/src/lib/init-config.d.ts +46 -0
- package/dist/src/lib/init-config.js +7 -0
- package/dist/src/lib/init-config.js.map +1 -1
- package/dist/src/lib/migration-nag.d.ts +49 -0
- package/dist/src/lib/output.d.ts +49 -0
- package/dist/src/lib/output.js +25 -1
- package/dist/src/lib/output.js.map +1 -1
- package/dist/src/lib/paginate.d.ts +33 -0
- package/dist/src/lib/project-config.d.ts +97 -0
- package/dist/src/lib/refresh-admin-credentials.d.ts +65 -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/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 +29 -1
- package/dist/src/lib/sync-paths.js.map +1 -1
- package/dist/src/lib/template.d.ts +93 -0
- 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 +132 -0
- package/dist/src/lib/toml-params-validator.d.ts +95 -0
- package/dist/src/lib/version-check.d.ts +10 -0
- package/dist/src/lib/workflow-fragments.d.ts +41 -0
- package/dist/src/lib/workflow-toml-validator.d.ts +86 -0
- package/dist/src/lib/workflow-toml-validator.js +31 -1
- package/dist/src/lib/workflow-toml-validator.js.map +1 -1
- package/dist/src/types/index.d.ts +513 -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 +8 -2
|
@@ -0,0 +1,85 @@
|
|
|
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
|
+
* `confirmPrompt()` fixes the cause:
|
|
16
|
+
* 1. Non-TTY guard — if stdin is not a TTY, it never touches inquirer.
|
|
17
|
+
* Instead it throws a catchable `ConfirmPromptError` with an actionable
|
|
18
|
+
* message ("re-run with --yes ..."). Per the maintainer decision on #972
|
|
19
|
+
* this is a hard error, never a silent mutate or silent abort.
|
|
20
|
+
* 2. Local try/catch — in a real TTY the prompt is awaited inside a try/catch
|
|
21
|
+
* so an abort/EOF surfaces as a clean `ConfirmPromptError`, not a crash.
|
|
22
|
+
*
|
|
23
|
+
* Commands should call this instead of inquirer directly, e.g.:
|
|
24
|
+
*
|
|
25
|
+
* if (!options.yes) {
|
|
26
|
+
* try {
|
|
27
|
+
* const ok = await confirmPrompt(`Delete cron trigger ${id}?`);
|
|
28
|
+
* if (!ok) { info("Cancelled."); return; }
|
|
29
|
+
* } catch (err) {
|
|
30
|
+
* error(err.message);
|
|
31
|
+
* process.exit(1);
|
|
32
|
+
* }
|
|
33
|
+
* }
|
|
34
|
+
*/
|
|
35
|
+
/** Error thrown when a confirmation can't be obtained interactively. */
|
|
36
|
+
export class ConfirmPromptError extends Error {
|
|
37
|
+
constructor(message) {
|
|
38
|
+
super(message);
|
|
39
|
+
this.name = "ConfirmPromptError";
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function defaultPromptFn(questions) {
|
|
43
|
+
const inquirer = await import("inquirer");
|
|
44
|
+
return inquirer.default.prompt(questions);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Ask the user a yes/no confirmation question.
|
|
48
|
+
*
|
|
49
|
+
* @returns `true` if the user confirms, `false` if they decline.
|
|
50
|
+
* @throws {ConfirmPromptError} when stdin is not an interactive TTY (so the
|
|
51
|
+
* prompt can't be shown), or when the underlying prompt aborts/crashes.
|
|
52
|
+
*/
|
|
53
|
+
export async function confirmPrompt(message, options = {}) {
|
|
54
|
+
const isTTY = options.isTTY ?? Boolean(process.stdin.isTTY);
|
|
55
|
+
if (!isTTY) {
|
|
56
|
+
throw new ConfirmPromptError("No interactive terminal available to confirm this action. " +
|
|
57
|
+
"Re-run with --yes (-y) to skip the confirmation prompt in " +
|
|
58
|
+
"non-interactive contexts (CI, pipes, agents).");
|
|
59
|
+
}
|
|
60
|
+
const promptFn = options.promptFn ?? defaultPromptFn;
|
|
61
|
+
try {
|
|
62
|
+
const answers = await promptFn([
|
|
63
|
+
{
|
|
64
|
+
type: "confirm",
|
|
65
|
+
name: "confirm",
|
|
66
|
+
message,
|
|
67
|
+
default: options.defaultValue ?? false,
|
|
68
|
+
},
|
|
69
|
+
]);
|
|
70
|
+
return Boolean(answers.confirm);
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
// An abort/EOF/Ctrl-D inside inquirer (ERR_USE_AFTER_CLOSE) or any other
|
|
74
|
+
// prompt failure: surface it as a clean, catchable error rather than
|
|
75
|
+
// letting it escape as an uncaught crash.
|
|
76
|
+
if (err?.code === "ERR_USE_AFTER_CLOSE") {
|
|
77
|
+
throw new ConfirmPromptError("Confirmation prompt was interrupted (no interactive input). " +
|
|
78
|
+
"Re-run with --yes (-y) to skip confirmation.");
|
|
79
|
+
}
|
|
80
|
+
throw new ConfirmPromptError(err?.message
|
|
81
|
+
? `Confirmation prompt failed: ${err.message}`
|
|
82
|
+
: "Confirmation prompt failed.");
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# 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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;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;AA0BD,KAAK,UAAU,eAAe,CAC5B,SAAkC;IAElC,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;IAC1C,OAAO,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,SAAgB,CAAC,CAAC;AACnD,CAAC;AAED;;;;;;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,OAAO,GAAG,MAAM,QAAQ,CAAC;YAC7B;gBACE,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,SAAS;gBACf,OAAO;gBACP,OAAO,EAAE,OAAO,CAAC,YAAY,IAAI,KAAK;aACvC;SACF,CAAC,CAAC;QACH,OAAO,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,yEAAyE;QACzE,qEAAqE;QACrE,0CAA0C;QAC1C,IAAI,GAAG,EAAE,IAAI,KAAK,qBAAqB,EAAE,CAAC;YACxC,MAAM,IAAI,kBAAkB,CAC1B,8DAA8D;gBAC5D,8CAA8C,CACjD,CAAC;QACJ,CAAC;QACD,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,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;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a CSV string into an array of row objects keyed by header.
|
|
3
|
+
*
|
|
4
|
+
* Quote-aware: respects double-quoted fields that may contain the delimiter,
|
|
5
|
+
* embedded newlines, and escaped double-quotes (`""`). Empty-string cells are
|
|
6
|
+
* omitted from the row object (matching the client). Headers-only / empty
|
|
7
|
+
* input yields `[]`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseCsv(csv: string, delimiter?: string): Record<string, string>[];
|
|
10
|
+
/**
|
|
11
|
+
* Coerce a string cell to a target type. Mirrors the client's `coerceValue`:
|
|
12
|
+
* a failed number coercion returns the original string (so the server's
|
|
13
|
+
* schema validation surfaces a precise error rather than a silent bad write).
|
|
14
|
+
*/
|
|
15
|
+
export declare function coerceValue(value: string, type: string): any;
|
|
16
|
+
/**
|
|
17
|
+
* Rename row keys per a `{ "CSV Header": "fieldName" }` map. Keys not present
|
|
18
|
+
* in the map are preserved. No-op when `map` is undefined.
|
|
19
|
+
*/
|
|
20
|
+
export declare function applyColumnMap(rows: Record<string, any>[], map: Record<string, string> | undefined): Record<string, any>[];
|
|
21
|
+
export interface BuildRowsOptions {
|
|
22
|
+
/** Model name passed in each batch item's params. */
|
|
23
|
+
modelName: string;
|
|
24
|
+
/** Type coercion overrides keyed by (post-column-map) field name. */
|
|
25
|
+
types?: Record<string, string>;
|
|
26
|
+
/** CSV column whose value to use as the record id (else a ULID is generated). */
|
|
27
|
+
idColumn?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface BatchItem {
|
|
30
|
+
params: {
|
|
31
|
+
modelName: string;
|
|
32
|
+
id: string;
|
|
33
|
+
data: Record<string, any>;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export interface BuildRowsResult {
|
|
37
|
+
batch: BatchItem[];
|
|
38
|
+
rowCount: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Apply type coercion, assign each row an id (from `idColumn` or a generated
|
|
42
|
+
* ULID), and shape rows into `executeBatch` items
|
|
43
|
+
* (`{ params: { modelName, id, data } }`). Mirrors steps 5–7 of the client's
|
|
44
|
+
* `importCsv`.
|
|
45
|
+
*/
|
|
46
|
+
export declare function buildRows(rows: Record<string, any>[], options: BuildRowsOptions): BuildRowsResult;
|
|
47
|
+
/** Split an array into fixed-size chunks. */
|
|
48
|
+
export declare function chunk<T>(items: T[], size: number): T[][];
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Short fingerprint for a database-type TOML string (issue #814).
|
|
3
|
+
*
|
|
4
|
+
* Stamped in the header of every generated file so a human (or the
|
|
5
|
+
* `--check` CI guard) can tell at a glance whether the source TOML and the
|
|
6
|
+
* generated output are in sync. Mirrors codegen-v2's `fingerprintToml`
|
|
7
|
+
* (`packages/js-bao/src/cli/v2/fingerprint.ts`): 16 hex chars of SHA-256 —
|
|
8
|
+
* enough for a sanity check, short enough to fit on one comment line.
|
|
9
|
+
*/
|
|
10
|
+
export declare function fingerprintToml(tomlContent: string): string;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `databases codegen` orchestrator (issue #814).
|
|
3
|
+
*
|
|
4
|
+
* Pure-ish core: given a set of database-type TOML strings + a target
|
|
5
|
+
* output dir, decides what `*.generated.ts` files to write (in memory),
|
|
6
|
+
* then either (a) writes them, or (b) compares them against on-disk for
|
|
7
|
+
* `--check`. No commander dependency, no `process.exit`.
|
|
8
|
+
*
|
|
9
|
+
* Reuses the codegen-v2 machinery:
|
|
10
|
+
* - `loadSchemaFromTomlString` (the shared `[models.*]` parser) for record
|
|
11
|
+
* interfaces — the database-type `[models.*]` blocks round-trip through
|
|
12
|
+
* the same loader and the same `FieldType` vocabulary.
|
|
13
|
+
* - The banner + fingerprint header pattern and stale-output cleanup.
|
|
14
|
+
*
|
|
15
|
+
* Adds the OPERATIONS half (op-params interfaces + per-op result aliases)
|
|
16
|
+
* that codegen-v2 has no analog for. Op return contracts are NOT stored in
|
|
17
|
+
* the TOML, so result aliases are generic shapes keyed off `op.type`.
|
|
18
|
+
*/
|
|
19
|
+
export interface DbCodegenInput {
|
|
20
|
+
/** Database type name (drives the output filename). */
|
|
21
|
+
databaseType: string;
|
|
22
|
+
/** Path to the source `database-types/<type>.toml` file. */
|
|
23
|
+
tomlPath: string;
|
|
24
|
+
/** Raw TOML content (already read from disk). */
|
|
25
|
+
tomlContent: string;
|
|
26
|
+
}
|
|
27
|
+
export interface GenerateDbTypesOptions {
|
|
28
|
+
/** One entry per database-type TOML file to generate from. */
|
|
29
|
+
inputs: DbCodegenInput[];
|
|
30
|
+
/** Directory where `<type>.generated.ts` files are written. */
|
|
31
|
+
outputDir: string;
|
|
32
|
+
/**
|
|
33
|
+
* If true, do not write to disk. Compare the would-be output to what's on
|
|
34
|
+
* disk and return a non-empty `mismatches` list if any file would change.
|
|
35
|
+
*/
|
|
36
|
+
check?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Set when the run was filtered to a single database type (the
|
|
39
|
+
* `primitive databases codegen <type>` argument). The `inputs` set is then
|
|
40
|
+
* PARTIAL — it does not represent the full set of owned generated files — so
|
|
41
|
+
* stale-output cleanup (and `--check` stale detection) must be scoped to the
|
|
42
|
+
* filtered type's own file and must NOT touch / flag sibling types'
|
|
43
|
+
* `*.generated.ts` files. The unfiltered "generate all" run leaves this unset
|
|
44
|
+
* and keeps full orphan cleanup.
|
|
45
|
+
*/
|
|
46
|
+
singleType?: boolean;
|
|
47
|
+
}
|
|
48
|
+
export interface DbCodegenResult {
|
|
49
|
+
/** Files written (or that would be written under `--check`). */
|
|
50
|
+
writtenFiles: string[];
|
|
51
|
+
/** Stale `*.generated.ts` files deleted (or flagged stale under `--check`). */
|
|
52
|
+
deletedFiles: string[];
|
|
53
|
+
/** Only populated under `--check`: files whose on-disk content is out of date. */
|
|
54
|
+
mismatches: DbCheckMismatch[];
|
|
55
|
+
}
|
|
56
|
+
export interface DbCheckMismatch {
|
|
57
|
+
filePath: string;
|
|
58
|
+
reason: "missing" | "differs" | "stale";
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Render the in-memory `.generated.ts` content for a single database-type
|
|
62
|
+
* TOML. Exported so tests can assert on the rendered string directly.
|
|
63
|
+
*/
|
|
64
|
+
export declare function renderDbTypeFile(input: DbCodegenInput): string;
|
|
65
|
+
/**
|
|
66
|
+
* Per-model result of {@link inferRequiredRecordFields}. Shaped as an object
|
|
67
|
+
* (rather than a bare `Set`) so it can grow additional inferred metadata later
|
|
68
|
+
* without changing the call-site contract — e.g. future alignment with #845's
|
|
69
|
+
* server-side op-params analysis. For now it carries only the set of record
|
|
70
|
+
* fields the operation params prove are always supplied at create time.
|
|
71
|
+
*/
|
|
72
|
+
export interface InferredRecordModelInfo {
|
|
73
|
+
/** Record field names promoted to non-optional by op-params inference. */
|
|
74
|
+
fields: Set<string>;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Infer which record fields are always supplied at create time, by reading the
|
|
78
|
+
* `save` operation params (issue #842).
|
|
79
|
+
*
|
|
80
|
+
* A field is promoted to required for a model only if:
|
|
81
|
+
* - at least one `save` (create) op writes it from a bare `$params.X`
|
|
82
|
+
* binding, AND
|
|
83
|
+
* - EVERY `save` op that writes the field binds it to a param declared
|
|
84
|
+
* `required: true` (the "ALL writers agree" rule).
|
|
85
|
+
*
|
|
86
|
+
* Deliberately conservative:
|
|
87
|
+
* - `patch` (and every non-`save` inner op) is excluded — partial updates
|
|
88
|
+
* don't guarantee creation-time presence.
|
|
89
|
+
* - whole-object saves (`data = "$params.X"`, a string rather than a
|
|
90
|
+
* per-field map) carry no field-level mapping, so no field can be promoted
|
|
91
|
+
* from them (Q4 skip).
|
|
92
|
+
* - only an EXACT top-level bare `$params.X` value counts (the whole binding
|
|
93
|
+
* value must match `^\$params\.X$`, and `X` must be a declared top-level
|
|
94
|
+
* param). A literal, computed, partially-interpolated value, or a nested
|
|
95
|
+
* path (`$params.obj.sub`) never promotes a field — a nested sub-property
|
|
96
|
+
* may be absent even when the top-level object param is required. This is
|
|
97
|
+
* deliberately stricter than the CLI's lenient `collectParamRefs`
|
|
98
|
+
* first-segment rule, which is fine for its validation use but would
|
|
99
|
+
* wrongly promote nested bindings here.
|
|
100
|
+
* - inner ops are matched to the record model by the inner op's own
|
|
101
|
+
* `modelName` when present, falling back to the enclosing operation's
|
|
102
|
+
* `modelName`.
|
|
103
|
+
*
|
|
104
|
+
* Pure: no I/O, no mutation of the input. The caller OR's the result with the
|
|
105
|
+
* schema-level `required` flag, so inference only ever ADDS requiredness.
|
|
106
|
+
*/
|
|
107
|
+
export declare function inferRequiredRecordFields(operations: any[]): Map<string, InferredRecordModelInfo>;
|
|
108
|
+
/**
|
|
109
|
+
* Run codegen end-to-end across one or more database-type TOML inputs.
|
|
110
|
+
*/
|
|
111
|
+
export declare function generateDbTypes(options: GenerateDbTypesOptions): Promise<DbCodegenResult>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identifier-naming helpers for the `databases codegen` generator (issue #814).
|
|
3
|
+
*
|
|
4
|
+
* Record interfaces mirror codegen-v2's class-name resolution
|
|
5
|
+
* (`packages/js-bao/src/cli/v2/pluralization.ts`): honor a `class_name`
|
|
6
|
+
* override, else singularize a snake_case plural to PascalCase. The
|
|
7
|
+
* singularization algorithm below is a faithful copy of codegen-v2's
|
|
8
|
+
* `singularizeToPascalCase`; it is inlined rather than imported because the
|
|
9
|
+
* CLI builds standalone (`tsc -p cli/tsconfig.json`, `rootDir: "."`) and
|
|
10
|
+
* cannot reach into the vendored `packages/js-bao/src` tree.
|
|
11
|
+
*
|
|
12
|
+
* It DIVERGES in the fallback: codegen-v2 THROWS when a model name doesn't
|
|
13
|
+
* look like a recognizable plural (ORM models are expected to be plural).
|
|
14
|
+
* Database-type model names are author-curated and frequently already
|
|
15
|
+
* singular / PascalCase (e.g. `[models.User]`), so we PascalCase the name
|
|
16
|
+
* verbatim rather than failing the whole run.
|
|
17
|
+
*
|
|
18
|
+
* Op interfaces/aliases derive from the operation name (PascalCase) +
|
|
19
|
+
* `Params` / `Result` suffix (e.g. `saveAccount` → `SaveAccountParams`,
|
|
20
|
+
* `SaveAccountResult`).
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Resolve the record-interface name for a model. Honors a `class_name`
|
|
24
|
+
* override, then tries plural→singular Pascal, then falls back to a verbatim
|
|
25
|
+
* PascalCase of the model name (no throw).
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveRecordInterfaceName(modelName: string, classNameOverride: string | undefined): string;
|
|
28
|
+
/** `saveAccount` → `SaveAccountParams`. */
|
|
29
|
+
export declare function opParamsInterfaceName(opName: string): string;
|
|
30
|
+
/** `saveAccount` → `SaveAccountResult`. */
|
|
31
|
+
export declare function opResultAliasName(opName: string): string;
|
|
32
|
+
/**
|
|
33
|
+
* Convert a snake_case plural model name (`user_prefs`, `categories`) into a
|
|
34
|
+
* PascalCase singular interface name (`UserPref`, `Category`). Returns null
|
|
35
|
+
* if no suffix rule matches the input. Faithful copy of codegen-v2's
|
|
36
|
+
* `singularizeToPascalCase`.
|
|
37
|
+
*/
|
|
38
|
+
export declare function singularizeToPascalCase(snakePlural: string): string | null;
|
|
39
|
+
/**
|
|
40
|
+
* PascalCase an identifier: splits on non-alphanumeric separators
|
|
41
|
+
* (`_`, `-`, spaces) and capitalizes each segment, preserving any existing
|
|
42
|
+
* internal casing (`saveAccount` → `SaveAccount`, `save_account` →
|
|
43
|
+
* `SaveAccount`).
|
|
44
|
+
*/
|
|
45
|
+
export declare function pascalCase(name: string): string;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure string templates for the `databases codegen` generator (issue #814).
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the codegen-v2 template style
|
|
5
|
+
* (`packages/js-bao/src/cli/v2/templates.ts`): total functions (no I/O, no
|
|
6
|
+
* hidden state), an auto-generated banner + fingerprint header, and
|
|
7
|
+
* deterministic ordering so `--check` can compare byte-for-byte.
|
|
8
|
+
*
|
|
9
|
+
* Diverges from codegen-v2 in two ways:
|
|
10
|
+
* 1. Database-DO records are schemaless documents, NOT `BaseModel` ORM
|
|
11
|
+
* classes — so we emit plain `export interface` types with no class
|
|
12
|
+
* shell, no barrel registration, and `import type` only.
|
|
13
|
+
* 2. We add an OPERATIONS half codegen-v2 has no analog for: per-op
|
|
14
|
+
* input-params interfaces + per-op result aliases keyed off `op.type`.
|
|
15
|
+
*/
|
|
16
|
+
/** A field on a record interface (read shape). */
|
|
17
|
+
export interface RecordField {
|
|
18
|
+
name: string;
|
|
19
|
+
/** TOML field type (`string|number|boolean|date|id|stringset`). */
|
|
20
|
+
type: string;
|
|
21
|
+
/** Required props render as `name: T`; otherwise `name?: T`. */
|
|
22
|
+
required: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Allowed-value set for a `string` field (#843). When non-empty, the field
|
|
25
|
+
* renders a TS string-literal union (`"a" | "b"`) instead of bare `string`.
|
|
26
|
+
*/
|
|
27
|
+
enum?: string[];
|
|
28
|
+
}
|
|
29
|
+
export interface RenderRecordInterfaceInput {
|
|
30
|
+
/** PascalCase interface name (e.g. `Account`). */
|
|
31
|
+
interfaceName: string;
|
|
32
|
+
/** TOML model name (e.g. `accounts`). */
|
|
33
|
+
modelName: string;
|
|
34
|
+
fields: RecordField[];
|
|
35
|
+
/**
|
|
36
|
+
* Server-stamped field names (timestamps + auto-populated fields) that
|
|
37
|
+
* appear on the READ record interface as OPTIONAL props, and only if not
|
|
38
|
+
* already declared in `fields`.
|
|
39
|
+
*/
|
|
40
|
+
stampedFields: string[];
|
|
41
|
+
}
|
|
42
|
+
/** One declared param on an op-input interface (write shape). */
|
|
43
|
+
export interface ParamField {
|
|
44
|
+
name: string;
|
|
45
|
+
/** TOML param type (`string|number|boolean|object`). */
|
|
46
|
+
type: string;
|
|
47
|
+
required: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Allowed-value set for a `string` param → string-literal union (#861).
|
|
50
|
+
* Validated server-side (`validateParams`) at config-push time; the emitter
|
|
51
|
+
* renders the union when present and falls back to the base type otherwise.
|
|
52
|
+
*/
|
|
53
|
+
enum?: string[];
|
|
54
|
+
}
|
|
55
|
+
export interface RenderOpParamsInterfaceInput {
|
|
56
|
+
/** PascalCase params interface name (e.g. `SaveAccountParams`). */
|
|
57
|
+
interfaceName: string;
|
|
58
|
+
/** Operation name (e.g. `saveAccount`). */
|
|
59
|
+
opName: string;
|
|
60
|
+
params: ParamField[];
|
|
61
|
+
}
|
|
62
|
+
export interface RenderOpResultAliasInput {
|
|
63
|
+
/** Per-op result alias name (e.g. `SaveAccountResult`). */
|
|
64
|
+
aliasName: string;
|
|
65
|
+
/** Operation name (e.g. `saveAccount`). */
|
|
66
|
+
opName: string;
|
|
67
|
+
/** Operation type (`query|mutation|count|aggregate|pipeline|applyToQuery`). */
|
|
68
|
+
opType: string;
|
|
69
|
+
/**
|
|
70
|
+
* For `query` ops, the record interface name the result is generic over
|
|
71
|
+
* (`QueryResult<Account>`). Null when the op's model has no record
|
|
72
|
+
* interface (e.g. pipeline) — falls back to `QueryResult<Record<string, unknown>>`.
|
|
73
|
+
*/
|
|
74
|
+
recordInterfaceName: string | null;
|
|
75
|
+
}
|
|
76
|
+
/** The shared generic result aliases, keyed off `op.type`. */
|
|
77
|
+
export declare const RESULT_ALIASES_BLOCK = "// Generic per-op result shapes, keyed off the operation type. The op\n// return contract is NOT stored in the TOML \u2014 these mirror the runtime\n// result shapes produced by the database-operations controller.\n\n/** `query` ops return a page of records. */\nexport interface QueryResult<T = Record<string, unknown>> {\n data: T[];\n hasMore?: boolean;\n nextCursor?: string;\n}\n\n/** `mutation` ops return per-step results. */\nexport interface MutationResult {\n results: unknown[];\n}\n\n/** `count` ops return a single count. */\nexport interface CountResult {\n count: number;\n}\n\n/** `aggregate` ops return a single result object. */\nexport interface AggregateResult {\n result: Record<string, unknown>;\n}\n\n/** `applyToQuery` ops return match/affect/fail counts. */\nexport interface ApplyToQueryResult {\n matched: number;\n affected: number;\n failed: number;\n sample?: unknown[];\n}\n\n/** `pipeline` ops return per-step results keyed by step name. */\nexport interface PipelineResult {\n steps: Record<string, unknown>;\n}\n";
|
|
78
|
+
/**
|
|
79
|
+
* Render the header (banner + regen hint + fingerprint).
|
|
80
|
+
*/
|
|
81
|
+
export declare function renderHeader(fingerprint: string): string;
|
|
82
|
+
/**
|
|
83
|
+
* Render a single record interface (read shape). Stamped fields
|
|
84
|
+
* (`createdAt`, `modifiedAt`, `ownerId`, …) are appended as OPTIONAL props
|
|
85
|
+
* if not already present in `fields`.
|
|
86
|
+
*/
|
|
87
|
+
export declare function renderRecordInterface(input: RenderRecordInterfaceInput): string;
|
|
88
|
+
/**
|
|
89
|
+
* Render a single op-input-params interface (write shape). `required: true`
|
|
90
|
+
* params are non-optional; others are optional. `object` params render as
|
|
91
|
+
* `Record<string, any>`.
|
|
92
|
+
*/
|
|
93
|
+
export declare function renderOpParamsInterface(input: RenderOpParamsInterfaceInput): string;
|
|
94
|
+
/**
|
|
95
|
+
* Render a per-op result alias keyed off `op.type`.
|
|
96
|
+
*/
|
|
97
|
+
export declare function renderOpResultAlias(input: RenderOpResultAliasInput): string;
|