primitive-admin 1.1.0-alpha.45 → 1.1.0-alpha.46

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.
Files changed (34) hide show
  1. package/dist/bin/primitive.js +2 -0
  2. package/dist/bin/primitive.js.map +1 -1
  3. package/dist/src/commands/collections.js +11 -0
  4. package/dist/src/commands/collections.js.map +1 -1
  5. package/dist/src/commands/databases.js +34 -49
  6. package/dist/src/commands/databases.js.map +1 -1
  7. package/dist/src/commands/sync.js +3 -0
  8. package/dist/src/commands/sync.js.map +1 -1
  9. package/dist/src/commands/vars.d.ts +8 -0
  10. package/dist/src/commands/vars.js +110 -0
  11. package/dist/src/commands/vars.js.map +1 -0
  12. package/dist/src/commands/workflows.js +23 -82
  13. package/dist/src/commands/workflows.js.map +1 -1
  14. package/dist/src/lib/api-client.d.ts +9 -0
  15. package/dist/src/lib/api-client.js +15 -0
  16. package/dist/src/lib/api-client.js.map +1 -1
  17. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.d.ts +68 -0
  18. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js +168 -0
  19. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js.map +1 -0
  20. package/dist/src/lib/generated-allowlist.js +2 -0
  21. package/dist/src/lib/generated-allowlist.js.map +1 -1
  22. package/dist/src/lib/toml-metadata-config.d.ts +10 -2
  23. package/dist/src/lib/toml-metadata-config.js +51 -15
  24. package/dist/src/lib/toml-metadata-config.js.map +1 -1
  25. package/dist/src/lib/workflow-codegen/generated-schema-descriptor.d.ts +33 -0
  26. package/dist/src/lib/workflow-codegen/generated-schema-descriptor.js +158 -1
  27. package/dist/src/lib/workflow-codegen/generated-schema-descriptor.js.map +1 -1
  28. package/dist/src/lib/workflow-codegen/generator.d.ts +6 -2
  29. package/dist/src/lib/workflow-codegen/generator.js +35 -6
  30. package/dist/src/lib/workflow-codegen/generator.js.map +1 -1
  31. package/dist/src/lib/workflow-codegen/schemaToTs.d.ts +13 -4
  32. package/dist/src/lib/workflow-codegen/schemaToTs.js +49 -4
  33. package/dist/src/lib/workflow-codegen/schemaToTs.js.map +1 -1
  34. package/package.json +1 -1
@@ -0,0 +1,8 @@
1
+ import { Command } from "commander";
2
+ /**
3
+ * `primitive vars` — non-secret per-app config scalars (issue #1364). The
4
+ * plaintext twin of `primitive secrets`: same key format and limits, but
5
+ * values are NOT secret — `list` shows them, and they appear unmasked in
6
+ * debug traces. Never store a credential in a var; use `primitive secrets`.
7
+ */
8
+ export declare function registerVarsCommands(program: Command): void;
@@ -0,0 +1,110 @@
1
+ import { ApiClient } from "../lib/api-client.js";
2
+ import { resolveAppId } from "../lib/config.js";
3
+ import { success, error, info, keyValue, formatTable, formatDate, json, } from "../lib/output.js";
4
+ /**
5
+ * `primitive vars` — non-secret per-app config scalars (issue #1364). The
6
+ * plaintext twin of `primitive secrets`: same key format and limits, but
7
+ * values are NOT secret — `list` shows them, and they appear unmasked in
8
+ * debug traces. Never store a credential in a var; use `primitive secrets`.
9
+ */
10
+ export function registerVarsCommands(program) {
11
+ const vars = program
12
+ .command("vars")
13
+ .description("Manage non-secret app config vars (values are visible; use secrets for credentials)")
14
+ .addHelpText("after", `
15
+ Examples:
16
+ $ primitive vars list
17
+ $ primitive vars set ADMIN_GROUP_ID --value grp_01ABC --summary "Admins group id"
18
+ $ primitive vars set ADMIN_GROUP_ID --value grp_01NEW (updates existing)
19
+ $ primitive vars delete ADMIN_GROUP_ID
20
+
21
+ Vars bind into CEL rules via the declared \`vars.*\` namespace — declare them
22
+ with \`vars = ["ADMIN_GROUP_ID"]\` in the config's access manifest.
23
+ `);
24
+ // List vars (values shown — non-secret)
25
+ vars
26
+ .command("list")
27
+ .description("List all config vars for an app (values are shown)")
28
+ .option("--app <app-id>", "App ID (uses current app if not specified)")
29
+ .option("--json", "Output as JSON")
30
+ .action(async (options) => {
31
+ const resolvedAppId = resolveAppId(undefined, options);
32
+ const client = new ApiClient();
33
+ try {
34
+ const varsList = await client.listAppConfigVars(resolvedAppId);
35
+ if (options.json) {
36
+ json(varsList);
37
+ return;
38
+ }
39
+ if (!varsList || varsList.length === 0) {
40
+ info("No vars found.");
41
+ return;
42
+ }
43
+ console.log(formatTable(varsList, [
44
+ { header: "KEY", key: "key" },
45
+ { header: "VALUE", key: "value" },
46
+ { header: "SUMMARY", key: "summary" },
47
+ { header: "CREATED", key: "createdAt", format: formatDate },
48
+ { header: "UPDATED", key: "updatedAt", format: formatDate },
49
+ ]));
50
+ }
51
+ catch (err) {
52
+ error(err.message);
53
+ process.exit(1);
54
+ }
55
+ });
56
+ // Set var (create or update — by-key upsert)
57
+ vars
58
+ .command("set")
59
+ .description("Create or update a config var")
60
+ .argument("<key>", "Var key (e.g., ADMIN_GROUP_ID)")
61
+ .option("--value <value>", "Var value (non-secret)")
62
+ .option("--summary <text>", "Description of the var")
63
+ .option("--app <app-id>", "App ID (uses current app if not specified)")
64
+ .option("--json", "Output as JSON")
65
+ .action(async (key, options) => {
66
+ const resolvedAppId = resolveAppId(undefined, options);
67
+ if (!options.value) {
68
+ error("--value is required");
69
+ process.exit(1);
70
+ }
71
+ const client = new ApiClient();
72
+ try {
73
+ const payload = { value: options.value };
74
+ if (options.summary !== undefined) {
75
+ payload.summary = options.summary;
76
+ }
77
+ const result = await client.upsertAppConfigVar(resolvedAppId, key, payload);
78
+ if (options.json) {
79
+ json(result);
80
+ return;
81
+ }
82
+ success(`Var '${key}' saved.`);
83
+ keyValue("Key", result?.key || key);
84
+ keyValue("Value", result?.value ?? options.value);
85
+ }
86
+ catch (err) {
87
+ error(err.message);
88
+ process.exit(1);
89
+ }
90
+ });
91
+ // Delete var (key-addressed — no id lookup needed)
92
+ vars
93
+ .command("delete")
94
+ .description("Delete a config var")
95
+ .argument("<key>", "Var key (e.g., ADMIN_GROUP_ID)")
96
+ .option("--app <app-id>", "App ID (uses current app if not specified)")
97
+ .action(async (key, options) => {
98
+ const resolvedAppId = resolveAppId(undefined, options);
99
+ const client = new ApiClient();
100
+ try {
101
+ await client.deleteAppConfigVar(resolvedAppId, key);
102
+ success(`Var '${key}' deleted.`);
103
+ }
104
+ catch (err) {
105
+ error(err.message);
106
+ process.exit(1);
107
+ }
108
+ });
109
+ }
110
+ //# sourceMappingURL=vars.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vars.js","sourceRoot":"","sources":["../../../src/commands/vars.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { readFileSync, writeFileSync, statSync, existsSync, readdirSync, } from "fs";
1
+ import { readFileSync, writeFileSync, statSync, readdirSync, } from "fs";
2
2
  import { basename } from "path";
3
3
  import * as path from "path";
4
4
  import { parseConfigToml, stringifyConfigToml } from "../lib/config-toml.js";
@@ -6,6 +6,7 @@ import { lookup as mimeLookup } from "mime-types";
6
6
  import { generateWorkflowTypes, } from "../lib/workflow-codegen/generator.js";
7
7
  import { ApiClient } from "../lib/api-client.js";
8
8
  import { resolveAppId } from "../lib/config.js";
9
+ import { resolveCodegenSourceDir } from "../lib/codegen-shared/resolveCodegenSourceDir.js";
9
10
  import { validateWorkflowToml, formatWorkflowTomlErrors, } from "../lib/workflow-toml-validator.js";
10
11
  import { expandWorkflow } from "../lib/workflow-fragments.js";
11
12
  import { buildWorkflowPayloadFromToml } from "../lib/workflow-payload.js";
@@ -2472,91 +2473,31 @@ Examples:
2472
2473
  .option("--json", "Output the result summary as JSON")
2473
2474
  .action(async (workflowKey, options) => {
2474
2475
  try {
2475
- // 1. Locate the workflows directory. Mirrors `databases codegen`'s
2476
- // sync-dir resolution: honor --sync-dir, else search any
2477
- // env/appId subtree under ./.primitive/sync that has a workflows/
2478
- // directory. When --app is given, restrict the scan to that app's
2479
- // subtree (the sync-tree layout is <env>/<appId>/), so a multi-app
2480
- // tree generates only the requested app's workflows instead of
2481
- // combining every app's and writing into the first one found.
2482
- const workflowDirs = [];
2483
- if (options.syncDir) {
2484
- const candidate = path.join(options.syncDir, "workflows");
2485
- if (existsSync(candidate)) {
2486
- workflowDirs.push(candidate);
2487
- }
2488
- }
2489
- else {
2490
- const root = path.join(process.cwd(), ".primitive", "sync");
2491
- if (existsSync(root)) {
2492
- for (const env of readdirSync(root)) {
2493
- const envDir = path.join(root, env);
2494
- try {
2495
- for (const app of readdirSync(envDir)) {
2496
- if (options.app && app !== options.app)
2497
- continue;
2498
- const candidate = path.join(envDir, app, "workflows");
2499
- if (existsSync(candidate)) {
2500
- workflowDirs.push(candidate);
2501
- }
2502
- }
2503
- }
2504
- catch {
2505
- // skip non-dirs
2506
- }
2507
- }
2508
- }
2509
- }
2510
- if (workflowDirs.length === 0) {
2511
- error(options.app
2512
- ? `No workflows/ directory found for app "${options.app}" under .primitive/sync/. Check the --app id, pass --sync-dir, or run \`primitive sync pull\` first.`
2513
- : "No workflows/ directory found. Pass --sync-dir or run `primitive sync pull` first.");
2514
- process.exit(1);
2515
- }
2516
- // Codegen writes one <key>.generated.ts per workflow into a single
2517
- // output dir derived from the first source dir below. Generating from
2518
- // more than one discovered workflows/ directory (multiple apps, or the
2519
- // same app across multiple synced envs) would combine unrelated apps'
2520
- // workflows into the first one's output dir and write nothing for the
2521
- // rest. Require the caller to disambiguate rather than combining.
2522
- if (workflowDirs.length > 1) {
2523
- const appsFound = [
2524
- ...new Set(workflowDirs.map((d) => path.basename(path.dirname(d)))),
2525
- ];
2526
- error(`Found workflows/ directories for more than one app/env:\n` +
2527
- workflowDirs
2528
- .map((d) => ` ${path.relative(process.cwd(), d)}`)
2529
- .join("\n") +
2530
- `\nCodegen writes into one output dir, so it must run against` +
2531
- ` one app. ` +
2532
- (options.app
2533
- ? `App "${options.app}" resolves to multiple synced envs — pass --sync-dir to pick one.`
2534
- : `Pass --app <app-id> (found: ${appsFound.join(", ")}) or` +
2535
- ` --sync-dir to select one.`));
2536
- process.exit(1);
2537
- }
2476
+ // 1. Resolve the single source workflows/ directory via the shared
2477
+ // active-environment resolver (issue #1510). Honors --sync-dir /
2478
+ // --app overrides, resolves the active env
2479
+ // (--env PRIMITIVE_ENV defaultEnvironment single-env), and
2480
+ // preserves the legacy per-app scan fallback in bare-dir mode.
2481
+ const workflowsSourceDir = resolveCodegenSourceDir({
2482
+ subdir: "workflows",
2483
+ options: { app: options.app, syncDir: options.syncDir },
2484
+ });
2538
2485
  // 2. Collect the source .toml files (one per workflow), filtered to a
2539
2486
  // single workflow when an argument is given. Match on the file stem;
2540
2487
  // the generator resolves the real key from `[workflow].key`.
2541
2488
  const inputs = [];
2542
- const seenStems = new Set();
2543
- for (const dir of workflowDirs) {
2544
- for (const fileName of readdirSync(dir)) {
2545
- if (!fileName.endsWith(".toml"))
2546
- continue;
2547
- const stem = fileName.slice(0, -".toml".length);
2548
- if (workflowKey && stem !== workflowKey)
2549
- continue;
2550
- if (seenStems.has(stem))
2551
- continue;
2552
- seenStems.add(stem);
2553
- const tomlPath = path.join(dir, fileName);
2554
- inputs.push({
2555
- fileStem: stem,
2556
- tomlPath,
2557
- tomlContent: readFileSync(tomlPath, "utf-8"),
2558
- });
2559
- }
2489
+ for (const fileName of readdirSync(workflowsSourceDir)) {
2490
+ if (!fileName.endsWith(".toml"))
2491
+ continue;
2492
+ const stem = fileName.slice(0, -".toml".length);
2493
+ if (workflowKey && stem !== workflowKey)
2494
+ continue;
2495
+ const tomlPath = path.join(workflowsSourceDir, fileName);
2496
+ inputs.push({
2497
+ fileStem: stem,
2498
+ tomlPath,
2499
+ tomlContent: readFileSync(tomlPath, "utf-8"),
2500
+ });
2560
2501
  }
2561
2502
  if (inputs.length === 0) {
2562
2503
  error(workflowKey