@axtrabase/cli 0.1.0

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 (154) hide show
  1. package/README.md +130 -0
  2. package/dist/active-project.d.ts +12 -0
  3. package/dist/active-project.d.ts.map +1 -0
  4. package/dist/active-project.js +27 -0
  5. package/dist/active-project.js.map +1 -0
  6. package/dist/api-types.d.ts +187 -0
  7. package/dist/api-types.d.ts.map +1 -0
  8. package/dist/api-types.js +9 -0
  9. package/dist/api-types.js.map +1 -0
  10. package/dist/commands/config.d.ts +3 -0
  11. package/dist/commands/config.d.ts.map +1 -0
  12. package/dist/commands/config.js +98 -0
  13. package/dist/commands/config.js.map +1 -0
  14. package/dist/commands/connection.d.ts +3 -0
  15. package/dist/commands/connection.d.ts.map +1 -0
  16. package/dist/commands/connection.js +58 -0
  17. package/dist/commands/connection.js.map +1 -0
  18. package/dist/commands/context.d.ts +3 -0
  19. package/dist/commands/context.d.ts.map +1 -0
  20. package/dist/commands/context.js +128 -0
  21. package/dist/commands/context.js.map +1 -0
  22. package/dist/commands/docs.d.ts +11 -0
  23. package/dist/commands/docs.d.ts.map +1 -0
  24. package/dist/commands/docs.js +39 -0
  25. package/dist/commands/docs.js.map +1 -0
  26. package/dist/commands/keys.d.ts +3 -0
  27. package/dist/commands/keys.d.ts.map +1 -0
  28. package/dist/commands/keys.js +92 -0
  29. package/dist/commands/keys.js.map +1 -0
  30. package/dist/commands/login.d.ts +3 -0
  31. package/dist/commands/login.d.ts.map +1 -0
  32. package/dist/commands/login.js +68 -0
  33. package/dist/commands/login.js.map +1 -0
  34. package/dist/commands/logout.d.ts +12 -0
  35. package/dist/commands/logout.d.ts.map +1 -0
  36. package/dist/commands/logout.js +77 -0
  37. package/dist/commands/logout.js.map +1 -0
  38. package/dist/commands/openapi.d.ts +4 -0
  39. package/dist/commands/openapi.d.ts.map +1 -0
  40. package/dist/commands/openapi.js +40 -0
  41. package/dist/commands/openapi.js.map +1 -0
  42. package/dist/commands/organisations.d.ts +3 -0
  43. package/dist/commands/organisations.d.ts.map +1 -0
  44. package/dist/commands/organisations.js +64 -0
  45. package/dist/commands/organisations.js.map +1 -0
  46. package/dist/commands/permissions.d.ts +9 -0
  47. package/dist/commands/permissions.d.ts.map +1 -0
  48. package/dist/commands/permissions.js +61 -0
  49. package/dist/commands/permissions.js.map +1 -0
  50. package/dist/commands/projects.d.ts +3 -0
  51. package/dist/commands/projects.d.ts.map +1 -0
  52. package/dist/commands/projects.js +99 -0
  53. package/dist/commands/projects.js.map +1 -0
  54. package/dist/commands/requests.d.ts +3 -0
  55. package/dist/commands/requests.d.ts.map +1 -0
  56. package/dist/commands/requests.js +91 -0
  57. package/dist/commands/requests.js.map +1 -0
  58. package/dist/commands/schema.d.ts +3 -0
  59. package/dist/commands/schema.d.ts.map +1 -0
  60. package/dist/commands/schema.js +80 -0
  61. package/dist/commands/schema.js.map +1 -0
  62. package/dist/commands/status.d.ts +10 -0
  63. package/dist/commands/status.d.ts.map +1 -0
  64. package/dist/commands/status.js +46 -0
  65. package/dist/commands/status.js.map +1 -0
  66. package/dist/commands/tables.d.ts +3 -0
  67. package/dist/commands/tables.d.ts.map +1 -0
  68. package/dist/commands/tables.js +129 -0
  69. package/dist/commands/tables.js.map +1 -0
  70. package/dist/commands/whoami.d.ts +3 -0
  71. package/dist/commands/whoami.d.ts.map +1 -0
  72. package/dist/commands/whoami.js +41 -0
  73. package/dist/commands/whoami.js.map +1 -0
  74. package/dist/concurrency.d.ts +18 -0
  75. package/dist/concurrency.d.ts.map +1 -0
  76. package/dist/concurrency.js +32 -0
  77. package/dist/concurrency.js.map +1 -0
  78. package/dist/config/credentials.d.ts +17 -0
  79. package/dist/config/credentials.d.ts.map +1 -0
  80. package/dist/config/credentials.js +77 -0
  81. package/dist/config/credentials.js.map +1 -0
  82. package/dist/config/paths.d.ts +12 -0
  83. package/dist/config/paths.d.ts.map +1 -0
  84. package/dist/config/paths.js +20 -0
  85. package/dist/config/paths.js.map +1 -0
  86. package/dist/config/resolve.d.ts +22 -0
  87. package/dist/config/resolve.d.ts.map +1 -0
  88. package/dist/config/resolve.js +41 -0
  89. package/dist/config/resolve.js.map +1 -0
  90. package/dist/config/store.d.ts +24 -0
  91. package/dist/config/store.d.ts.map +1 -0
  92. package/dist/config/store.js +72 -0
  93. package/dist/config/store.js.map +1 -0
  94. package/dist/exit-codes.d.ts +18 -0
  95. package/dist/exit-codes.d.ts.map +1 -0
  96. package/dist/exit-codes.js +40 -0
  97. package/dist/exit-codes.js.map +1 -0
  98. package/dist/generators/typescript.d.ts +5 -0
  99. package/dist/generators/typescript.d.ts.map +1 -0
  100. package/dist/generators/typescript.js +70 -0
  101. package/dist/generators/typescript.js.map +1 -0
  102. package/dist/http/authenticated-client.d.ts +10 -0
  103. package/dist/http/authenticated-client.d.ts.map +1 -0
  104. package/dist/http/authenticated-client.js +24 -0
  105. package/dist/http/authenticated-client.js.map +1 -0
  106. package/dist/http/client.d.ts +42 -0
  107. package/dist/http/client.d.ts.map +1 -0
  108. package/dist/http/client.js +86 -0
  109. package/dist/http/client.js.map +1 -0
  110. package/dist/http/errors.d.ts +29 -0
  111. package/dist/http/errors.d.ts.map +1 -0
  112. package/dist/http/errors.js +21 -0
  113. package/dist/http/errors.js.map +1 -0
  114. package/dist/index.d.ts +3 -0
  115. package/dist/index.d.ts.map +1 -0
  116. package/dist/index.js +62 -0
  117. package/dist/index.js.map +1 -0
  118. package/dist/open-browser.d.ts +9 -0
  119. package/dist/open-browser.d.ts.map +1 -0
  120. package/dist/open-browser.js +32 -0
  121. package/dist/open-browser.js.map +1 -0
  122. package/dist/output/file-writer.d.ts +8 -0
  123. package/dist/output/file-writer.d.ts.map +1 -0
  124. package/dist/output/file-writer.js +28 -0
  125. package/dist/output/file-writer.js.map +1 -0
  126. package/dist/output/print.d.ts +15 -0
  127. package/dist/output/print.d.ts.map +1 -0
  128. package/dist/output/print.js +27 -0
  129. package/dist/output/print.js.map +1 -0
  130. package/dist/output/sanitize.d.ts +30 -0
  131. package/dist/output/sanitize.d.ts.map +1 -0
  132. package/dist/output/sanitize.js +40 -0
  133. package/dist/output/sanitize.js.map +1 -0
  134. package/dist/output/table.d.ts +9 -0
  135. package/dist/output/table.d.ts.map +1 -0
  136. package/dist/output/table.js +19 -0
  137. package/dist/output/table.js.map +1 -0
  138. package/dist/prompt-masked.d.ts +15 -0
  139. package/dist/prompt-masked.d.ts.map +1 -0
  140. package/dist/prompt-masked.js +75 -0
  141. package/dist/prompt-masked.js.map +1 -0
  142. package/dist/report-error.d.ts +18 -0
  143. package/dist/report-error.d.ts.map +1 -0
  144. package/dist/report-error.js +63 -0
  145. package/dist/report-error.js.map +1 -0
  146. package/dist/resolve-entity.d.ts +13 -0
  147. package/dist/resolve-entity.d.ts.map +1 -0
  148. package/dist/resolve-entity.js +18 -0
  149. package/dist/resolve-entity.js.map +1 -0
  150. package/dist/version.d.ts +4 -0
  151. package/dist/version.d.ts.map +1 -0
  152. package/dist/version.js +4 -0
  153. package/dist/version.js.map +1 -0
  154. package/package.json +51 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.d.ts","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAazC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAQ5D"}
@@ -0,0 +1,41 @@
1
+ import { requireControlPlaneClient } from "../http/authenticated-client.js";
2
+ import { resolveApiUrl } from "../config/resolve.js";
3
+ import { printJson, printKeyValueBlock, printLine } from "../output/print.js";
4
+ import { runWithErrorHandling } from "../report-error.js";
5
+ export function registerWhoamiCommand(program) {
6
+ program
7
+ .command("whoami")
8
+ .description("Show the signed-in user, organisation, and active API")
9
+ .action(async function () {
10
+ const options = this.optsWithGlobals();
11
+ await runWithErrorHandling(() => runWhoami(options), options);
12
+ });
13
+ }
14
+ async function runWhoami(options) {
15
+ const client = requireControlPlaneClient({ apiUrl: options.apiUrl });
16
+ const { data } = await client.get("/api/v1/me");
17
+ const apiUrl = resolveApiUrl(options.apiUrl);
18
+ if (options.json) {
19
+ printJson({
20
+ user: data.user,
21
+ organisation: data.organisation,
22
+ platformRole: data.platformRole,
23
+ api: { baseUrl: apiUrl }
24
+ });
25
+ return;
26
+ }
27
+ printLine("Signed in as:");
28
+ printLine(data.user.name);
29
+ printLine(data.user.email);
30
+ printLine();
31
+ printLine("Organisation:");
32
+ printLine(data.organisation.name);
33
+ printLine();
34
+ printLine("API:");
35
+ printLine(apiUrl);
36
+ if (data.platformRole) {
37
+ printLine();
38
+ printKeyValueBlock([["Platform role", data.platformRole]]);
39
+ }
40
+ }
41
+ //# sourceMappingURL=whoami.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAQ1D,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,uDAAuD,CAAC;SACpE,MAAM,CAAC,KAAK;QACX,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAiB,CAAC;QACtD,MAAM,oBAAoB,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;AACP,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,OAAsB;IAC7C,MAAM,MAAM,GAAG,yBAAyB,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACrE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,GAAG,CAAa,YAAY,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAE7C,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,SAAS,CAAC;YACR,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,GAAG,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE;SACzB,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,SAAS,CAAC,eAAe,CAAC,CAAC;IAC3B,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3B,SAAS,EAAE,CAAC;IACZ,SAAS,CAAC,eAAe,CAAC,CAAC;IAC3B,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IAClC,SAAS,EAAE,CAAC;IACZ,SAAS,CAAC,MAAM,CAAC,CAAC;IAClB,SAAS,CAAC,MAAM,CAAC,CAAC;IAClB,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;QACtB,SAAS,EAAE,CAAC;QACZ,kBAAkB,CAAC,CAAC,CAAC,eAAe,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC7D,CAAC;AACH,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * A small worker-pool mapper — no new dependency for something this simple
3
+ * (build brief §2/§37: "zero unnecessary framework weight"). At most
4
+ * `limit` calls to `fn` are ever in flight at once, regardless of `items`'
5
+ * length, so a schema export over hundreds of tables can't fire hundreds of
6
+ * simultaneous Dataverse/control-plane calls. Preserves the caller's input
7
+ * order in the returned array — results are written to fixed index slots,
8
+ * never pushed in completion order — so output stays deterministic even
9
+ * though completion timing isn't.
10
+ *
11
+ * Failure semantics are unchanged from a plain `Promise.all`: the first
12
+ * rejection propagates and stops the whole operation. That's a deliberate
13
+ * decision, not an oversight — a partial schema export silently missing
14
+ * some tables would be a worse failure mode than a clear, whole-command
15
+ * error.
16
+ */
17
+ export declare function mapWithConcurrencyLimit<T, R>(items: readonly T[], limit: number, fn: (item: T, index: number) => Promise<R>): Promise<R[]>;
18
+ //# sourceMappingURL=concurrency.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"concurrency.d.ts","sourceRoot":"","sources":["../src/concurrency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,uBAAuB,CAAC,CAAC,EAAE,CAAC,EAChD,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GACzC,OAAO,CAAC,CAAC,EAAE,CAAC,CAgBd"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * A small worker-pool mapper — no new dependency for something this simple
3
+ * (build brief §2/§37: "zero unnecessary framework weight"). At most
4
+ * `limit` calls to `fn` are ever in flight at once, regardless of `items`'
5
+ * length, so a schema export over hundreds of tables can't fire hundreds of
6
+ * simultaneous Dataverse/control-plane calls. Preserves the caller's input
7
+ * order in the returned array — results are written to fixed index slots,
8
+ * never pushed in completion order — so output stays deterministic even
9
+ * though completion timing isn't.
10
+ *
11
+ * Failure semantics are unchanged from a plain `Promise.all`: the first
12
+ * rejection propagates and stops the whole operation. That's a deliberate
13
+ * decision, not an oversight — a partial schema export silently missing
14
+ * some tables would be a worse failure mode than a clear, whole-command
15
+ * error.
16
+ */
17
+ export async function mapWithConcurrencyLimit(items, limit, fn) {
18
+ const results = new Array(items.length);
19
+ let nextIndex = 0;
20
+ async function worker() {
21
+ for (;;) {
22
+ const currentIndex = nextIndex++;
23
+ if (currentIndex >= items.length)
24
+ return;
25
+ results[currentIndex] = await fn(items[currentIndex], currentIndex);
26
+ }
27
+ }
28
+ const workerCount = Math.max(1, Math.min(limit, items.length));
29
+ await Promise.all(Array.from({ length: workerCount }, () => worker()));
30
+ return results;
31
+ }
32
+ //# sourceMappingURL=concurrency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"concurrency.js","sourceRoot":"","sources":["../src/concurrency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,KAAmB,EACnB,KAAa,EACb,EAA0C;IAE1C,MAAM,OAAO,GAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC7C,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,KAAK,UAAU,MAAM;QACnB,SAAS,CAAC;YACR,MAAM,YAAY,GAAG,SAAS,EAAE,CAAC;YACjC,IAAI,YAAY,IAAI,KAAK,CAAC,MAAM;gBAAE,OAAO;YACzC,OAAO,CAAC,YAAY,CAAC,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,YAAY,CAAM,EAAE,YAAY,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAC/D,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAEvE,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,17 @@
1
+ export interface StoredCredentials {
2
+ token: string;
3
+ }
4
+ /**
5
+ * Local storage for the CLI token — a plain file with 0600 permissions, not
6
+ * an OS keychain. This is a deliberate v1 tradeoff (see docs/cli.md's
7
+ * security section): native keychain bindings need per-platform builds,
8
+ * which conflicts with this monorepo's plain-`tsc`/zero-native-deps
9
+ * convention and would break headless CI. Never stores a Microsoft or
10
+ * Dataverse credential — only ever an `axcli_...` control-plane token.
11
+ */
12
+ export declare class CredentialStore {
13
+ read(): StoredCredentials | undefined;
14
+ write(credentials: StoredCredentials): void;
15
+ clear(): void;
16
+ }
17
+ //# sourceMappingURL=credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/config/credentials.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;GAOG;AACH,qBAAa,eAAe;IAC1B,IAAI,IAAI,iBAAiB,GAAG,SAAS;IAsBrC,KAAK,CAAC,WAAW,EAAE,iBAAiB,GAAG,IAAI;IAc3C,KAAK,IAAI,IAAI;CAQd"}
@@ -0,0 +1,77 @@
1
+ import { chmodSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
2
+ import { dirname } from "node:path";
3
+ import { credentialsFilePath } from "./paths.js";
4
+ const SECRET_FILE_MODE = 0o600;
5
+ /**
6
+ * Local storage for the CLI token — a plain file with 0600 permissions, not
7
+ * an OS keychain. This is a deliberate v1 tradeoff (see docs/cli.md's
8
+ * security section): native keychain bindings need per-platform builds,
9
+ * which conflicts with this monorepo's plain-`tsc`/zero-native-deps
10
+ * convention and would break headless CI. Never stores a Microsoft or
11
+ * Dataverse credential — only ever an `axcli_...` control-plane token.
12
+ */
13
+ export class CredentialStore {
14
+ read() {
15
+ let raw;
16
+ try {
17
+ raw = readFileSync(credentialsFilePath(), "utf8");
18
+ }
19
+ catch (error) {
20
+ if (isErrnoException(error) && error.code === "ENOENT")
21
+ return undefined;
22
+ throw error;
23
+ }
24
+ warnIfPermissionsAreLoose();
25
+ try {
26
+ const parsed = JSON.parse(raw);
27
+ if (isRecord(parsed) && typeof parsed.token === "string" && parsed.token.length > 0) {
28
+ return { token: parsed.token };
29
+ }
30
+ return undefined;
31
+ }
32
+ catch {
33
+ return undefined;
34
+ }
35
+ }
36
+ write(credentials) {
37
+ const path = credentialsFilePath();
38
+ mkdirSync(dirname(path), { recursive: true });
39
+ writeFileSync(path, `${JSON.stringify(credentials, null, 2)}\n`, {
40
+ encoding: "utf8",
41
+ mode: SECRET_FILE_MODE
42
+ });
43
+ // writeFileSync's `mode` option only applies when creating the file — an
44
+ // existing file (e.g. from a prior login) keeps its old mode, which may
45
+ // have been widened by umask or a prior version. Setting it explicitly
46
+ // every write is what actually guarantees 0600, not just on first login.
47
+ chmodSync(path, SECRET_FILE_MODE);
48
+ }
49
+ clear() {
50
+ try {
51
+ rmSync(credentialsFilePath());
52
+ }
53
+ catch (error) {
54
+ if (isErrnoException(error) && error.code === "ENOENT")
55
+ return;
56
+ throw error;
57
+ }
58
+ }
59
+ }
60
+ function warnIfPermissionsAreLoose() {
61
+ try {
62
+ const mode = statSync(credentialsFilePath()).mode & 0o777;
63
+ if (mode !== SECRET_FILE_MODE) {
64
+ process.stderr.write(`Warning: ${credentialsFilePath()} has permissions ${mode.toString(8)}, not 0600. Your CLI token may be readable by other local users. Run: chmod 600 ${credentialsFilePath()}\n`);
65
+ }
66
+ }
67
+ catch {
68
+ // Best-effort — never block a read over a stat failure.
69
+ }
70
+ }
71
+ function isRecord(value) {
72
+ return typeof value === "object" && value !== null && !Array.isArray(value);
73
+ }
74
+ function isErrnoException(error) {
75
+ return error instanceof Error && "code" in error;
76
+ }
77
+ //# sourceMappingURL=credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/config/credentials.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * `~/.config/axtrabase/` on every platform — the build brief explicitly
3
+ * allows "or platform-standard equivalent" and a single well-documented
4
+ * path is simpler to reason about and test than per-OS branching (no
5
+ * `%APPDATA%`/XDG special-casing). Overridable via AXTRABASE_CONFIG_DIR for
6
+ * tests and for anyone who wants config isolated from their real home dir.
7
+ */
8
+ export declare function configDir(): string;
9
+ export declare function configFilePath(): string;
10
+ /** Kept in a separate file from config.json so file permissions (0600) apply only to the credential, not to non-secret settings a user might reasonably want to inspect/edit more casually. */
11
+ export declare function credentialsFilePath(): string;
12
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/config/paths.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,+LAA+L;AAC/L,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C"}
@@ -0,0 +1,20 @@
1
+ import { homedir } from "node:os";
2
+ import { join } from "node:path";
3
+ /**
4
+ * `~/.config/axtrabase/` on every platform — the build brief explicitly
5
+ * allows "or platform-standard equivalent" and a single well-documented
6
+ * path is simpler to reason about and test than per-OS branching (no
7
+ * `%APPDATA%`/XDG special-casing). Overridable via AXTRABASE_CONFIG_DIR for
8
+ * tests and for anyone who wants config isolated from their real home dir.
9
+ */
10
+ export function configDir() {
11
+ return process.env.AXTRABASE_CONFIG_DIR ?? join(homedir(), ".config", "axtrabase");
12
+ }
13
+ export function configFilePath() {
14
+ return join(configDir(), "config.json");
15
+ }
16
+ /** Kept in a separate file from config.json so file permissions (0600) apply only to the credential, not to non-secret settings a user might reasonably want to inspect/edit more casually. */
17
+ export function credentialsFilePath() {
18
+ return join(configDir(), "credentials.json");
19
+ }
20
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/config/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;;;;;GAMG;AACH,MAAM,UAAU,SAAS;IACvB,OAAO,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;AACrF,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,IAAI,CAAC,SAAS,EAAE,EAAE,aAAa,CAAC,CAAC;AAC1C,CAAC;AAED,+LAA+L;AAC/L,MAAM,UAAU,mBAAmB;IACjC,OAAO,IAAI,CAAC,SAAS,EAAE,EAAE,kBAAkB,CAAC,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,22 @@
1
+ export declare const DEFAULT_API_URL = "https://api.axtrabase.com";
2
+ export declare const DEFAULT_DASHBOARD_URL = "https://app.axtrabase.com";
3
+ /** explicit flag > environment variable > saved config > production default (build brief §6). */
4
+ export declare function resolveApiUrl(flagValue?: string): string;
5
+ /** Same precedence as resolveApiUrl — the dashboard is a separate origin from the API, so it gets its own override (see docs/cli.md). */
6
+ export declare function resolveDashboardUrl(flagValue?: string): string;
7
+ /** explicit flag > AXTRABASE_PROJECT environment variable > saved config (build brief §9, §26). */
8
+ export declare function resolveProjectId(flagValue?: string): string | undefined;
9
+ export declare function resolveOrganisationId(flagValue?: string): string | undefined;
10
+ export interface ResolvedToken {
11
+ token: string;
12
+ /** "env" tokens (AXTRABASE_CLI_TOKEN) are never persisted or logged — see build brief §26. */
13
+ source: "env" | "file";
14
+ }
15
+ /**
16
+ * AXTRABASE_CLI_TOKEN environment variable > the locally persisted
17
+ * credential (see credentials.ts). The env var exists specifically for CI
18
+ * and ephemeral agent environments — it is read fresh on every call and
19
+ * never written to disk.
20
+ */
21
+ export declare function resolveToken(): ResolvedToken | undefined;
22
+ //# sourceMappingURL=resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/config/resolve.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,eAAe,8BAA8B,CAAC;AAC3D,eAAO,MAAM,qBAAqB,8BAA8B,CAAC;AAEjE,iGAAiG;AACjG,wBAAgB,aAAa,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAOxD;AAED,yIAAyI;AACzI,wBAAgB,mBAAmB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAO9D;AAED,mGAAmG;AACnG,wBAAgB,gBAAgB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEvE;AAED,wBAAgB,qBAAqB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE5E;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,8FAA8F;IAC9F,MAAM,EAAE,KAAK,GAAG,MAAM,CAAC;CACxB;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,aAAa,GAAG,SAAS,CAMxD"}
@@ -0,0 +1,41 @@
1
+ import { CredentialStore } from "./credentials.js";
2
+ import { ConfigStore } from "./store.js";
3
+ export const DEFAULT_API_URL = "https://api.axtrabase.com";
4
+ export const DEFAULT_DASHBOARD_URL = "https://app.axtrabase.com";
5
+ /** explicit flag > environment variable > saved config > production default (build brief §6). */
6
+ export function resolveApiUrl(flagValue) {
7
+ const value = flagValue ??
8
+ process.env.AXTRABASE_API_URL ??
9
+ new ConfigStore().read().apiUrl ??
10
+ DEFAULT_API_URL;
11
+ return value.replace(/\/$/, "");
12
+ }
13
+ /** Same precedence as resolveApiUrl — the dashboard is a separate origin from the API, so it gets its own override (see docs/cli.md). */
14
+ export function resolveDashboardUrl(flagValue) {
15
+ const value = flagValue ??
16
+ process.env.AXTRABASE_DASHBOARD_URL ??
17
+ new ConfigStore().read().dashboardUrl ??
18
+ DEFAULT_DASHBOARD_URL;
19
+ return value.replace(/\/$/, "");
20
+ }
21
+ /** explicit flag > AXTRABASE_PROJECT environment variable > saved config (build brief §9, §26). */
22
+ export function resolveProjectId(flagValue) {
23
+ return flagValue ?? process.env.AXTRABASE_PROJECT ?? new ConfigStore().read().projectId;
24
+ }
25
+ export function resolveOrganisationId(flagValue) {
26
+ return flagValue ?? new ConfigStore().read().organisationId;
27
+ }
28
+ /**
29
+ * AXTRABASE_CLI_TOKEN environment variable > the locally persisted
30
+ * credential (see credentials.ts). The env var exists specifically for CI
31
+ * and ephemeral agent environments — it is read fresh on every call and
32
+ * never written to disk.
33
+ */
34
+ export function resolveToken() {
35
+ const envToken = process.env.AXTRABASE_CLI_TOKEN;
36
+ if (envToken && envToken.length > 0)
37
+ return { token: envToken, source: "env" };
38
+ const stored = new CredentialStore().read();
39
+ return stored ? { token: stored.token, source: "file" } : undefined;
40
+ }
41
+ //# sourceMappingURL=resolve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/config/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,CAAC,MAAM,eAAe,GAAG,2BAA2B,CAAC;AAC3D,MAAM,CAAC,MAAM,qBAAqB,GAAG,2BAA2B,CAAC;AAEjE,iGAAiG;AACjG,MAAM,UAAU,aAAa,CAAC,SAAkB;IAC9C,MAAM,KAAK,GACT,SAAS;QACT,OAAO,CAAC,GAAG,CAAC,iBAAiB;QAC7B,IAAI,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM;QAC/B,eAAe,CAAC;IAClB,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAClC,CAAC;AAED,yIAAyI;AACzI,MAAM,UAAU,mBAAmB,CAAC,SAAkB;IACpD,MAAM,KAAK,GACT,SAAS;QACT,OAAO,CAAC,GAAG,CAAC,uBAAuB;QACnC,IAAI,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,YAAY;QACrC,qBAAqB,CAAC;IACxB,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAClC,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,gBAAgB,CAAC,SAAkB;IACjD,OAAO,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,IAAI,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;AAC1F,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,SAAkB;IACtD,OAAO,SAAS,IAAI,IAAI,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,cAAc,CAAC;AAC9D,CAAC;AAQD;;;;;GAKG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;IACjD,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAE/E,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC,IAAI,EAAE,CAAC;IAC5C,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AACtE,CAAC"}
@@ -0,0 +1,24 @@
1
+ export interface CliConfig {
2
+ /** Overrides the default AxtraBase API origin — see http/base-url.ts for the full precedence order. */
3
+ apiUrl?: string;
4
+ /** Where `axtrabase login` sends a user to generate a CLI token. Independent of apiUrl — the dashboard and API are separate origins (see docs/cli.md). */
5
+ dashboardUrl?: string;
6
+ organisationId?: string;
7
+ organisationSlug?: string;
8
+ projectId?: string;
9
+ projectSlug?: string;
10
+ }
11
+ /**
12
+ * Non-secret local CLI state — base URL override and the active
13
+ * organisation/project selected by `orgs use`/`projects use`. Deliberately
14
+ * a separate file from credentials.json (see paths.ts) so nothing here
15
+ * needs restrictive permissions.
16
+ */
17
+ export declare class ConfigStore {
18
+ read(): CliConfig;
19
+ write(config: CliConfig): void;
20
+ update(patch: Partial<CliConfig>): CliConfig;
21
+ /** Sets a single key to undefined (removes it) — used by `config unset`/clearing a stale project selection. */
22
+ unset(key: keyof CliConfig): CliConfig;
23
+ }
24
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/config/store.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,SAAS;IACxB,uGAAuG;IACvG,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0JAA0J;IAC1J,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAeD;;;;;GAKG;AACH,qBAAa,WAAW;IACtB,IAAI,IAAI,SAAS;IAiBjB,KAAK,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;IAK9B,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,SAAS;IAM5C,+GAA+G;IAC/G,KAAK,CAAC,GAAG,EAAE,MAAM,SAAS,GAAG,SAAS;CAMvC"}
@@ -0,0 +1,72 @@
1
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { dirname } from "node:path";
3
+ import { configFilePath } from "./paths.js";
4
+ const CONFIG_KEYS = [
5
+ "apiUrl",
6
+ "dashboardUrl",
7
+ "organisationId",
8
+ "organisationSlug",
9
+ "projectId",
10
+ "projectSlug"
11
+ ];
12
+ function isConfigKey(key) {
13
+ return CONFIG_KEYS.includes(key);
14
+ }
15
+ /**
16
+ * Non-secret local CLI state — base URL override and the active
17
+ * organisation/project selected by `orgs use`/`projects use`. Deliberately
18
+ * a separate file from credentials.json (see paths.ts) so nothing here
19
+ * needs restrictive permissions.
20
+ */
21
+ export class ConfigStore {
22
+ read() {
23
+ let raw;
24
+ try {
25
+ raw = readFileSync(configFilePath(), "utf8");
26
+ }
27
+ catch (error) {
28
+ if (isErrnoException(error) && error.code === "ENOENT")
29
+ return {};
30
+ throw error;
31
+ }
32
+ try {
33
+ const parsed = JSON.parse(raw);
34
+ return isRecord(parsed) ? sanitize(parsed) : {};
35
+ }
36
+ catch {
37
+ // A corrupt config file shouldn't crash every CLI invocation — treat it as empty and let the next `config set`/`login` overwrite it.
38
+ return {};
39
+ }
40
+ }
41
+ write(config) {
42
+ mkdirSync(dirname(configFilePath()), { recursive: true });
43
+ writeFileSync(configFilePath(), `${JSON.stringify(config, null, 2)}\n`, "utf8");
44
+ }
45
+ update(patch) {
46
+ const next = { ...this.read(), ...patch };
47
+ this.write(next);
48
+ return next;
49
+ }
50
+ /** Sets a single key to undefined (removes it) — used by `config unset`/clearing a stale project selection. */
51
+ unset(key) {
52
+ const next = this.read();
53
+ delete next[key];
54
+ this.write(next);
55
+ return next;
56
+ }
57
+ }
58
+ function sanitize(record) {
59
+ const config = {};
60
+ for (const [key, value] of Object.entries(record)) {
61
+ if (isConfigKey(key) && typeof value === "string")
62
+ config[key] = value;
63
+ }
64
+ return config;
65
+ }
66
+ function isRecord(value) {
67
+ return typeof value === "object" && value !== null && !Array.isArray(value);
68
+ }
69
+ function isErrnoException(error) {
70
+ return error instanceof Error && "code" in error;
71
+ }
72
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/config/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAa5C,MAAM,WAAW,GAAG;IAClB,QAAQ;IACR,cAAc;IACd,gBAAgB;IAChB,kBAAkB;IAClB,WAAW;IACX,aAAa;CACkC,CAAC;AAElD,SAAS,WAAW,CAAC,GAAW;IAC9B,OAAQ,WAAiC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AAC1D,CAAC;AAED;;;;;GAKG;AACH,MAAM,OAAO,WAAW;IACtB,IAAI;QACF,IAAI,GAAW,CAAC;QAChB,IAAI,CAAC;YACH,GAAG,GAAG,YAAY,CAAC,cAAc,EAAE,EAAE,MAAM,CAAC,CAAC;QAC/C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,gBAAgB,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;gBAAE,OAAO,EAAE,CAAC;YAClE,MAAM,KAAK,CAAC;QACd,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACxC,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAClD,CAAC;QAAC,MAAM,CAAC;YACP,qIAAqI;YACrI,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAiB;QACrB,SAAS,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1D,aAAa,CAAC,cAAc,EAAE,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAClF,CAAC;IAED,MAAM,CAAC,KAAyB;QAC9B,MAAM,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,EAAE,GAAG,KAAK,EAAE,CAAC;QAC1C,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,+GAA+G;IAC/G,KAAK,CAAC,GAAoB;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACjB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAED,SAAS,QAAQ,CAAC,MAA+B;IAC/C,MAAM,MAAM,GAAc,EAAE,CAAC;IAC7B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,IAAI,WAAW,CAAC,GAAG,CAAC,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACzE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,OAAO,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,CAAC;AACnD,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Stable exit-code contract for scripts/CI/coding agents — see docs/cli.md.
3
+ * Deliberately a small, closed set (build brief §23: "do not over-engineer
4
+ * dozens of exit codes").
5
+ */
6
+ export declare const EXIT_CODES: {
7
+ readonly SUCCESS: 0;
8
+ readonly GENERIC_FAILURE: 1;
9
+ readonly AUTHENTICATION_REQUIRED: 2;
10
+ readonly AUTHORIZATION_DENIED: 3;
11
+ readonly NOT_FOUND: 4;
12
+ readonly CONNECTION_NOT_READY: 5;
13
+ readonly INVALID_ARGUMENTS: 6;
14
+ };
15
+ export type ExitCode = (typeof EXIT_CODES)[keyof typeof EXIT_CODES];
16
+ /** Maps a control-plane AxtraErrorCode (see @axtrabase/shared, mirrored here without a workspace dependency — see http/errors.ts's doc comment) to this CLI's exit-code contract. */
17
+ export declare function exitCodeForErrorCode(code: string): ExitCode;
18
+ //# sourceMappingURL=exit-codes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit-codes.d.ts","sourceRoot":"","sources":["../src/exit-codes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,UAAU;;;;;;;;CAQb,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC;AAEpE,qLAAqL;AACrL,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAuB3D"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Stable exit-code contract for scripts/CI/coding agents — see docs/cli.md.
3
+ * Deliberately a small, closed set (build brief §23: "do not over-engineer
4
+ * dozens of exit codes").
5
+ */
6
+ export const EXIT_CODES = {
7
+ SUCCESS: 0,
8
+ GENERIC_FAILURE: 1,
9
+ AUTHENTICATION_REQUIRED: 2,
10
+ AUTHORIZATION_DENIED: 3,
11
+ NOT_FOUND: 4,
12
+ CONNECTION_NOT_READY: 5,
13
+ INVALID_ARGUMENTS: 6
14
+ };
15
+ /** Maps a control-plane AxtraErrorCode (see @axtrabase/shared, mirrored here without a workspace dependency — see http/errors.ts's doc comment) to this CLI's exit-code contract. */
16
+ export function exitCodeForErrorCode(code) {
17
+ switch (code) {
18
+ case "AXTRA_AUTHENTICATION_ERROR":
19
+ case "AXTRA_CLI_TOKEN_REVOKED":
20
+ case "AXTRA_CLI_TOKEN_EXPIRED":
21
+ case "AXTRA_API_KEY_REVOKED":
22
+ case "AXTRA_CLI_NOT_LOGGED_IN":
23
+ return EXIT_CODES.AUTHENTICATION_REQUIRED;
24
+ case "AXTRA_AUTHORISATION_ERROR":
25
+ case "AXTRA_TABLE_PERMISSION_DENIED":
26
+ return EXIT_CODES.AUTHORIZATION_DENIED;
27
+ case "AXTRA_RECORD_NOT_FOUND":
28
+ case "AXTRA_TABLE_NOT_FOUND":
29
+ return EXIT_CODES.NOT_FOUND;
30
+ case "AXTRA_CONNECTION_NOT_READY":
31
+ return EXIT_CODES.CONNECTION_NOT_READY;
32
+ case "AXTRA_VALIDATION_ERROR":
33
+ case "AXTRA_CLI_VALIDATION_ERROR":
34
+ case "AXTRA_CLI_NO_ACTIVE_PROJECT":
35
+ return EXIT_CODES.INVALID_ARGUMENTS;
36
+ default:
37
+ return EXIT_CODES.GENERIC_FAILURE;
38
+ }
39
+ }
40
+ //# sourceMappingURL=exit-codes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit-codes.js","sourceRoot":"","sources":["../src/exit-codes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,OAAO,EAAE,CAAC;IACV,eAAe,EAAE,CAAC;IAClB,uBAAuB,EAAE,CAAC;IAC1B,oBAAoB,EAAE,CAAC;IACvB,SAAS,EAAE,CAAC;IACZ,oBAAoB,EAAE,CAAC;IACvB,iBAAiB,EAAE,CAAC;CACZ,CAAC;AAIX,qLAAqL;AACrL,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,4BAA4B,CAAC;QAClC,KAAK,yBAAyB,CAAC;QAC/B,KAAK,yBAAyB,CAAC;QAC/B,KAAK,uBAAuB,CAAC;QAC7B,KAAK,yBAAyB;YAC5B,OAAO,UAAU,CAAC,uBAAuB,CAAC;QAC5C,KAAK,2BAA2B,CAAC;QACjC,KAAK,+BAA+B;YAClC,OAAO,UAAU,CAAC,oBAAoB,CAAC;QACzC,KAAK,wBAAwB,CAAC;QAC9B,KAAK,uBAAuB;YAC1B,OAAO,UAAU,CAAC,SAAS,CAAC;QAC9B,KAAK,4BAA4B;YAC/B,OAAO,UAAU,CAAC,oBAAoB,CAAC;QACzC,KAAK,wBAAwB,CAAC;QAC9B,KAAK,4BAA4B,CAAC;QAClC,KAAK,6BAA6B;YAChC,OAAO,UAAU,CAAC,iBAAiB,CAAC;QACtC;YACE,OAAO,UAAU,CAAC,eAAe,CAAC;IACtC,CAAC;AACH,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { TableMetadataResponse } from "../api-types.js";
2
+ /** Generates a single `export interface` for one table's columns, over metadata fetched via HTTP (never Dataverse directly). */
3
+ export declare function generateInterface(table: TableMetadataResponse): string;
4
+ export declare function generateTypeScriptModule(tables: TableMetadataResponse[]): string;
5
+ //# sourceMappingURL=typescript.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typescript.d.ts","sourceRoot":"","sources":["../../src/generators/typescript.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AA6C1E,gIAAgI;AAChI,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,qBAAqB,GAAG,MAAM,CAItE;AAsBD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,qBAAqB,EAAE,GAAG,MAAM,CAGhF"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Deliberately duplicated from (not imported from) `@axtrabase/dataverse`'s
3
+ * `generateInterface` (packages/dataverse/src/metadata/typescript-generator.ts),
4
+ * kept in sync by hand. This CLI is meant to be installable standalone
5
+ * (`npm install -g @axtrabase/cli`), same as @axtrabase/sdk — and like the
6
+ * SDK's errors.ts explains for its own error type, a package meant to ship
7
+ * to npm on its own must not take a runtime dependency on an internal,
8
+ * never-published workspace package just to reuse ~15 lines of pure logic.
9
+ * `@axtrabase/dataverse` itself carries Dataverse auth/client machinery this
10
+ * CLI has no business depending on at all — the whole point of the sprint
11
+ * is that this CLI never touches Dataverse directly.
12
+ */
13
+ const TS_TYPE_BY_COLUMN_TYPE = {
14
+ string: "string",
15
+ number: "number",
16
+ boolean: "boolean",
17
+ datetime: "string",
18
+ guid: "string",
19
+ money: "number",
20
+ decimal: "number",
21
+ choice: "number",
22
+ lookup: "string",
23
+ owner: "string",
24
+ state: "number",
25
+ status: "number",
26
+ unknown: "unknown"
27
+ };
28
+ function toPascalCase(logicalName) {
29
+ return logicalName
30
+ .split(/[_-]+/)
31
+ .filter(Boolean)
32
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
33
+ .join("");
34
+ }
35
+ function fieldLine(column) {
36
+ const tsType = TS_TYPE_BY_COLUMN_TYPE[column.type] ?? "unknown";
37
+ const optional = column.isPrimaryId ? "" : "?";
38
+ const nullable = column.isPrimaryId ? "" : " | null";
39
+ return ` ${column.logicalName}${optional}: ${tsType}${nullable};`;
40
+ }
41
+ /** Generates a single `export interface` for one table's columns, over metadata fetched via HTTP (never Dataverse directly). */
42
+ export function generateInterface(table) {
43
+ const name = toPascalCase(table.logicalName);
44
+ const lines = table.columns.map(fieldLine);
45
+ return [`export interface ${name} {`, ...lines, `}`].join("\n");
46
+ }
47
+ /**
48
+ * The generated-file header states the known metadata gap explicitly
49
+ * (build brief's anti-fabrication rule) rather than silently omitting
50
+ * relationships/choice values with no explanation.
51
+ */
52
+ function generatedHeader(tableNames) {
53
+ return [
54
+ "/**",
55
+ " * Generated by `axtrabase schema export --format typescript` — do not edit by hand.",
56
+ ` * Tables: ${tableNames.join(", ")}`,
57
+ " *",
58
+ " * Known gaps (see `axtrabase context --json`'s metadataCapabilities):",
59
+ " * - Incoming (one-to-many) relationships are not represented.",
60
+ " * - Choice/option-set values are not represented — choice columns are typed",
61
+ " * `number` (the underlying option value), not a literal union of known options.",
62
+ " */",
63
+ ""
64
+ ].join("\n");
65
+ }
66
+ export function generateTypeScriptModule(tables) {
67
+ const interfaces = tables.map((table) => generateInterface(table));
68
+ return `${generatedHeader(tables.map((t) => t.logicalName))}\n${interfaces.join("\n\n")}\n`;
69
+ }
70
+ //# sourceMappingURL=typescript.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typescript.js","sourceRoot":"","sources":["../../src/generators/typescript.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,MAAM,sBAAsB,GAA2B;IACrD,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,SAAS;IAClB,QAAQ,EAAE,QAAQ;IAClB,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,QAAQ;IACf,OAAO,EAAE,QAAQ;IACjB,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;IAChB,KAAK,EAAE,QAAQ;IACf,KAAK,EAAE,QAAQ;IACf,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,SAAS;CACnB,CAAC;AAEF,SAAS,YAAY,CAAC,WAAmB;IACvC,OAAO,WAAW;SACf,KAAK,CAAC,OAAO,CAAC;SACd,MAAM,CAAC,OAAO,CAAC;SACf,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SAC3D,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAED,SAAS,SAAS,CAAC,MAAmB;IACpC,MAAM,MAAM,GAAG,sBAAsB,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC;IAChE,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;IAC/C,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IACrD,OAAO,KAAK,MAAM,CAAC,WAAW,GAAG,QAAQ,KAAK,MAAM,GAAG,QAAQ,GAAG,CAAC;AACrE,CAAC;AAED,gIAAgI;AAChI,MAAM,UAAU,iBAAiB,CAAC,KAA4B;IAC5D,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC3C,OAAO,CAAC,oBAAoB,IAAI,IAAI,EAAE,GAAG,KAAK,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAClE,CAAC;AAED;;;;GAIG;AACH,SAAS,eAAe,CAAC,UAAoB;IAC3C,OAAO;QACL,KAAK;QACL,sFAAsF;QACtF,cAAc,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QACrC,IAAI;QACJ,wEAAwE;QACxE,gEAAgE;QAChE,8EAA8E;QAC9E,oFAAoF;QACpF,KAAK;QACL,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,MAA+B;IACtE,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC;IACnE,OAAO,GAAG,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,KAAK,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;AAC9F,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { ControlPlaneClient } from "./client.js";
2
+ export interface ClientOverrides {
3
+ apiUrl?: string;
4
+ organisationId?: string;
5
+ }
6
+ /** For the rare command that works whether or not the caller is logged in (none in v1, but keeps the option open) — never throws for a missing token. */
7
+ export declare function createControlPlaneClient(overrides?: ClientOverrides): ControlPlaneClient;
8
+ /** Every command that needs to act as a signed-in user calls this — throws a clear, exit-code-2 error rather than letting an unauthenticated request 401 confusingly deep inside a command. */
9
+ export declare function requireControlPlaneClient(overrides?: ClientOverrides): ControlPlaneClient;
10
+ //# sourceMappingURL=authenticated-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authenticated-client.d.ts","sourceRoot":"","sources":["../../src/http/authenticated-client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGjD,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,yJAAyJ;AACzJ,wBAAgB,wBAAwB,CAAC,SAAS,GAAE,eAAoB,GAAG,kBAAkB,CAM5F;AAED,+LAA+L;AAC/L,wBAAgB,yBAAyB,CAAC,SAAS,GAAE,eAAoB,GAAG,kBAAkB,CAc7F"}