@atlasauth/cli 0.1.0 → 0.3.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 (48) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +74 -1
  3. package/dist/args.d.ts +82 -1
  4. package/dist/args.js +40 -0
  5. package/dist/args.js.map +1 -1
  6. package/dist/commands/actions.d.ts +11 -0
  7. package/dist/commands/actions.js +120 -0
  8. package/dist/commands/actions.js.map +1 -0
  9. package/dist/commands/api-keys.js +18 -3
  10. package/dist/commands/api-keys.js.map +1 -1
  11. package/dist/commands/auth.js +7 -3
  12. package/dist/commands/auth.js.map +1 -1
  13. package/dist/commands/config.d.ts +4 -0
  14. package/dist/commands/config.js +721 -0
  15. package/dist/commands/config.js.map +1 -0
  16. package/dist/commands/init.d.ts +3 -0
  17. package/dist/commands/init.js +409 -0
  18. package/dist/commands/init.js.map +1 -0
  19. package/dist/commands/project-commands.d.ts +8 -0
  20. package/dist/commands/project-commands.js +236 -0
  21. package/dist/commands/project-commands.js.map +1 -0
  22. package/dist/commands/webhooks.d.ts +5 -2
  23. package/dist/commands/webhooks.js +37 -3
  24. package/dist/commands/webhooks.js.map +1 -1
  25. package/dist/config-http.d.ts +27 -0
  26. package/dist/config-http.js +63 -0
  27. package/dist/config-http.js.map +1 -0
  28. package/dist/context.d.ts +17 -1
  29. package/dist/context.js +4 -0
  30. package/dist/context.js.map +1 -1
  31. package/dist/help.d.ts +1 -1
  32. package/dist/help.js +104 -4
  33. package/dist/help.js.map +1 -1
  34. package/dist/index.d.ts +7 -0
  35. package/dist/index.js +25 -1
  36. package/dist/index.js.map +1 -1
  37. package/dist/project.d.ts +63 -0
  38. package/dist/project.js +86 -0
  39. package/dist/project.js.map +1 -0
  40. package/dist/run.js +10 -0
  41. package/dist/run.js.map +1 -1
  42. package/dist/secrets.d.ts +41 -0
  43. package/dist/secrets.js +142 -0
  44. package/dist/secrets.js.map +1 -0
  45. package/dist/serialize.d.ts +31 -0
  46. package/dist/serialize.js +248 -0
  47. package/dist/serialize.js.map +1 -0
  48. package/package.json +5 -3
@@ -0,0 +1,236 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.preflight = preflight;
4
+ exports.envCommand = envCommand;
5
+ exports.client = client;
6
+ const backend_1 = require("@atlasauth/backend");
7
+ const args_1 = require("../args");
8
+ const errors_1 = require("../errors");
9
+ const output_1 = require("../output");
10
+ const project_1 = require("../project");
11
+ const secrets_1 = require("../secrets");
12
+ const shared_1 = require("./shared");
13
+ /**
14
+ * The project commands that sit beside `atlas init`: `preflight` (a CI gate),
15
+ * `env` (deploy variables without secrets) and `client rotate` (a new OAuth
16
+ * client secret, written straight to its file).
17
+ */
18
+ /**
19
+ * The instance credential a project command runs with:
20
+ * - `--instance <id>`: the instance's secret file from a project manifest;
21
+ * - `--product <name>` [`--instance-env`]: that project's instance;
22
+ * - otherwise the profile / ATLAS_SECRET_KEY, as every other command.
23
+ */
24
+ function instanceCredential(ctx, args) {
25
+ const v = args.values;
26
+ const instanceId = (0, args_1.str)(v, 'instance');
27
+ const product = (0, args_1.str)(v, 'product');
28
+ if (instanceId) {
29
+ const found = (0, project_1.findInstance)(ctx.env, instanceId, product);
30
+ if (!found) {
31
+ throw new errors_1.CliError(`No project manifest knows instance ${instanceId}${product ? ` (product '${product}')` : ''}. Run 'atlas init' for it, or use ATLAS_SECRET_KEY.`);
32
+ }
33
+ return {
34
+ secretKey: (0, project_1.instanceSecretFromFile)(found.instance),
35
+ apiUrl: ctx.env.ATLAS_API_URL?.trim() || found.manifest.api_url,
36
+ manifest: found.manifest,
37
+ instance: found.instance,
38
+ };
39
+ }
40
+ if (product) {
41
+ const { manifest, instance } = projectInstance(ctx, args, product);
42
+ return {
43
+ secretKey: (0, project_1.instanceSecretFromFile)(instance),
44
+ apiUrl: ctx.env.ATLAS_API_URL?.trim() || manifest.api_url,
45
+ manifest,
46
+ instance,
47
+ };
48
+ }
49
+ const auth = (0, shared_1.resolveAuth)(ctx, v);
50
+ return { secretKey: auth.secretKey, apiUrl: auth.apiUrl };
51
+ }
52
+ /** The manifest instance for `--product` + `--instance-env` (default: production, else the only one). */
53
+ function projectInstance(ctx, args, product) {
54
+ const manifest = (0, project_1.readManifest)(ctx.env, product);
55
+ if (!manifest) {
56
+ throw new errors_1.CliError(`No project '${product}' at ${(0, secrets_1.productDir)(ctx.env, product)}. Run 'atlas init --product ${product}' first.`);
57
+ }
58
+ const requested = (0, args_1.str)(args.values, 'instance-env');
59
+ const envs = Object.keys(manifest.instances);
60
+ const env = requested
61
+ ? (0, project_1.parseInstanceEnv)(requested, 'production')
62
+ : manifest.instances.production
63
+ ? 'production'
64
+ : envs.length === 1
65
+ ? envs[0]
66
+ : 'production';
67
+ const instance = manifest.instances[env];
68
+ if (!instance)
69
+ throw new errors_1.CliError(`Project '${product}' has no ${env} instance. Run 'atlas init --product ${product} --instance-env ${env}'.`);
70
+ return { manifest, instance };
71
+ }
72
+ const FINDING_COLUMNS = [
73
+ { header: 'SEVERITY', get: (f) => f.severity },
74
+ { header: 'CODE', get: (f) => f.code },
75
+ { header: 'MESSAGE', get: (f) => f.message },
76
+ ];
77
+ /** `atlas preflight` — run the instance's setup checks; exit 1 on errors (or warnings with --fail-on warning). */
78
+ async function preflight(ctx, args) {
79
+ const failOn = (0, args_1.str)(args.values, 'fail-on') ?? 'error';
80
+ if (failOn !== 'error' && failOn !== 'warning') {
81
+ throw new errors_1.CliError(`--fail-on must be error or warning, got '${failOn}'.`);
82
+ }
83
+ const cred = instanceCredential(ctx, args);
84
+ const report = await (0, project_1.httpFor)(ctx, cred).get('/v1/instance/preflight');
85
+ const findings = report.findings ?? [];
86
+ const errors = findings.filter((f) => f.severity === 'error').length;
87
+ const warnings = findings.filter((f) => f.severity === 'warning').length;
88
+ const failed = errors > 0 || (failOn === 'warning' && warnings > 0);
89
+ if ((0, shared_1.wantsJson)(args.values)) {
90
+ (0, output_1.printJson)(ctx.io, report);
91
+ }
92
+ else if (findings.length === 0) {
93
+ ctx.io.out('Preflight passed: no findings.');
94
+ }
95
+ else {
96
+ ctx.io.out((0, output_1.renderTable)(FINDING_COLUMNS, findings));
97
+ ctx.io.out('');
98
+ for (const f of findings.filter((x) => x.severity !== 'info')) {
99
+ ctx.io.out(`${f.code}: ${f.fix}`);
100
+ }
101
+ ctx.io.out('');
102
+ ctx.io.out(`${errors} error(s), ${warnings} warning(s), ${findings.length - errors - warnings} info.`);
103
+ }
104
+ if (failed) {
105
+ ctx.io.err(`atlas: preflight failed (${errors} error(s)${failOn === 'warning' ? `, ${warnings} warning(s)` : ''}).`);
106
+ return 1;
107
+ }
108
+ return 0;
109
+ }
110
+ // ---- atlas env ----------------------------------------------------------------
111
+ const FORMATS = ['dotenv', 'coolify', 'vercel'];
112
+ /** Public values, then each secret as a reference to its file — never the value. */
113
+ async function envCommand(ctx, args) {
114
+ const format = ((0, args_1.str)(args.values, 'format') ?? 'dotenv');
115
+ if (!FORMATS.includes(format))
116
+ throw new errors_1.CliError(`--format must be one of: ${FORMATS.join(', ')} (got '${format}').`);
117
+ const product = (0, args_1.str)(args.values, 'product');
118
+ if (!product)
119
+ throw new errors_1.CliError('atlas env needs --product <name> (the name you passed to atlas init).');
120
+ const { manifest, instance } = projectInstance(ctx, args, product);
121
+ const pub = {
122
+ ATLAS_PUBLISHABLE_KEY: instance.publishable_key,
123
+ ATLAS_API_URL: manifest.api_url,
124
+ };
125
+ if (instance.frontend_api_host)
126
+ pub.ATLAS_FRONTEND_API = `https://${instance.frontend_api_host}`;
127
+ if (instance.issuer)
128
+ pub.ATLAS_ISSUER = instance.issuer;
129
+ if (instance.discovery_url)
130
+ pub.ATLAS_DISCOVERY_URL = instance.discovery_url;
131
+ if (instance.jwks_uri)
132
+ pub.ATLAS_JWKS_URI = instance.jwks_uri;
133
+ if (instance.oauth_client)
134
+ pub.ATLAS_CLIENT_ID = instance.oauth_client.client_id;
135
+ const secrets = [{ key: 'ATLAS_SECRET_KEY', file: instance.secret_file }];
136
+ if (instance.oauth_client?.secret_file)
137
+ secrets.push({ key: 'ATLAS_CLIENT_SECRET', file: instance.oauth_client.secret_file });
138
+ if (instance.webhook?.secret_file)
139
+ secrets.push({ key: 'ATLAS_WEBHOOK_SECRET', file: instance.webhook.secret_file });
140
+ if ((0, shared_1.wantsJson)(args.values)) {
141
+ (0, output_1.printJson)(ctx.io, { product, environment: instance.environment, public: pub, secret_files: Object.fromEntries(secrets.map((s) => [s.key, s.file])) });
142
+ return 0;
143
+ }
144
+ const out = (l) => ctx.io.out(l);
145
+ if (format === 'dotenv') {
146
+ out(`# ${product} (${instance.environment}): public values`);
147
+ for (const [k, v] of Object.entries(pub))
148
+ out(`${k}=${v}`);
149
+ out('# Secrets are not printed. Each *_FILE variable names the 0600 file that holds it.');
150
+ for (const s of secrets)
151
+ out(`${s.key}_FILE=${s.file}`);
152
+ }
153
+ else if (format === 'coolify') {
154
+ out(`# ${product} (${instance.environment}): paste into Coolify → Environment Variables (Developer view).`);
155
+ for (const [k, v] of Object.entries(pub))
156
+ out(`${k}=${v}`);
157
+ out('# Secrets: copy each value from its file (mark them as secret in Coolify):');
158
+ for (const s of secrets)
159
+ out(`${s.key}=@${s.file}`);
160
+ }
161
+ else {
162
+ out(`# ${product} (${instance.environment}): Vercel CLI commands. Secrets are piped from their files, never echoed.`);
163
+ const target = instance.environment === 'production' ? 'production' : 'preview';
164
+ for (const [k, v] of Object.entries(pub))
165
+ out(`printf '%s' '${v.replace(/'/g, "'\\''")}' | vercel env add ${k} ${target}`);
166
+ for (const s of secrets)
167
+ out(`sed -n 's/^${s.key}=//p' '${s.file}' | tr -d '\\n' | vercel env add ${s.key} ${target}`);
168
+ }
169
+ return 0;
170
+ }
171
+ // ---- atlas client rotate ----------------------------------------------------------
172
+ /** `atlas client rotate <id> [--now | --overlap <seconds>]` — the new secret goes straight to its file. */
173
+ async function client(ctx, args) {
174
+ const sub = args.positionals[1];
175
+ if (sub !== 'rotate') {
176
+ throw new errors_1.CliError(sub ? `Unknown subcommand 'client ${sub}'. Try: rotate.` : 'client needs a subcommand: rotate.');
177
+ }
178
+ const ref = (0, shared_1.requireArg)(args.positionals, 2, 'client-id');
179
+ const v = args.values;
180
+ const overlapRaw = (0, args_1.str)(v, 'overlap');
181
+ if (v.now === true && overlapRaw !== undefined)
182
+ throw new errors_1.CliError('Pass --now or --overlap, not both.');
183
+ let overlapSeconds;
184
+ if (v.now === true)
185
+ overlapSeconds = 0;
186
+ else if (overlapRaw !== undefined) {
187
+ const n = Number(overlapRaw);
188
+ if (!Number.isInteger(n) || n < 0)
189
+ throw new errors_1.CliError(`--overlap must be a whole number of seconds, got '${overlapRaw}'.`);
190
+ overlapSeconds = n;
191
+ }
192
+ const cred = instanceCredential(ctx, args);
193
+ const api = (0, project_1.httpFor)(ctx, cred);
194
+ // Accept the internal id or the public client_id.
195
+ let id = ref;
196
+ if (ref.startsWith('client_')) {
197
+ const rows = (await api.get('/v1/oauth_clients')).data ?? [];
198
+ const match = rows.find((c) => c.client_id === ref);
199
+ if (!match)
200
+ throw new errors_1.CliError(`No OAuth client with client_id ${ref} on this instance.`);
201
+ id = match.id;
202
+ }
203
+ let res;
204
+ try {
205
+ res = await api.post(`/v1/oauth_clients/${id}/rotate_secret`, overlapSeconds === undefined ? {} : { overlap_seconds: overlapSeconds });
206
+ }
207
+ catch (err) {
208
+ if (err instanceof backend_1.AtlasApiError && err.status === 404)
209
+ throw new errors_1.CliError(`No OAuth client ${ref} on this instance.`);
210
+ throw err;
211
+ }
212
+ const product = (0, args_1.str)(v, 'product') ?? cred.manifest?.product;
213
+ const env = cred.instance?.environment;
214
+ const fileName = product && env && cred.instance?.oauth_client?.id === res.id ? `${env}-oauth-client.env` : `oauth-client-${res.id}.env`;
215
+ const entries = { ATLAS_CLIENT_ID: res.client_id, ATLAS_CLIENT_SECRET: res.client_secret };
216
+ if (v['print-secret'] === true) {
217
+ (0, secrets_1.deliverSecret)({ io: ctx.io, env: ctx.env, product: product ?? 'atlasauth', fileName, entries, label: 'The new client secret', printSecret: true });
218
+ }
219
+ else {
220
+ // A rotation replaces the file by design: the old secret is the one being retired.
221
+ const { path } = (0, secrets_1.writeSecretFile)((0, secrets_1.productDir)(ctx.env, product ?? 'atlasauth'), fileName, entries, {
222
+ force: true,
223
+ comment: `OAuth client ${res.id}. Server-side only.`,
224
+ });
225
+ ctx.io.out(`New client secret for ${res.client_id} written to ${path} (mode 0600).`);
226
+ }
227
+ const expires = res.previous_secret_expires_at;
228
+ if (overlapSeconds === 0 || expires === null)
229
+ ctx.io.out('The previous secret stopped working immediately.');
230
+ else if (typeof expires === 'number')
231
+ ctx.io.out(`The previous secret keeps working until ${new Date(expires).toISOString()}.`);
232
+ else
233
+ ctx.io.out('The API did not say when the previous secret stops working; assume immediately and deploy the new one now.');
234
+ return 0;
235
+ }
236
+ //# sourceMappingURL=project-commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-commands.js","sourceRoot":"","sources":["../../src/commands/project-commands.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,7 @@
1
- import type { ParsedArgs } from '../args';
1
+ import { type ParsedArgs } from '../args';
2
2
  import type { RunContext } from '../context';
3
- /** `atlas webhooks list` — the one read `client.webhooks` exposes for endpoints. */
3
+ /**
4
+ * `atlas webhooks list | create`. `create` writes the endpoint's signing secret
5
+ * to a 0600 file (never printed unless --print-secret).
6
+ */
4
7
  export declare function webhooks(ctx: RunContext, args: ParsedArgs): Promise<number>;
@@ -1,8 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.webhooks = webhooks;
4
+ const args_1 = require("../args");
4
5
  const errors_1 = require("../errors");
5
6
  const output_1 = require("../output");
7
+ const project_1 = require("../project");
8
+ const secrets_1 = require("../secrets");
6
9
  const shared_1 = require("./shared");
7
10
  const COLUMNS = [
8
11
  { header: 'ID', get: (w) => w.id },
@@ -11,7 +14,10 @@ const COLUMNS = [
11
14
  { header: 'EVENTS', get: (w) => w.enabled_events },
12
15
  { header: 'CREATED', get: (w) => (0, output_1.fmtTime)(w.created_at) },
13
16
  ];
14
- /** `atlas webhooks list` — the one read `client.webhooks` exposes for endpoints. */
17
+ /**
18
+ * `atlas webhooks list | create`. `create` writes the endpoint's signing secret
19
+ * to a 0600 file (never printed unless --print-secret).
20
+ */
15
21
  async function webhooks(ctx, args) {
16
22
  const sub = args.positionals[1];
17
23
  const json = (0, shared_1.wantsJson)(args.values);
@@ -25,10 +31,38 @@ async function webhooks(ctx, args) {
25
31
  ctx.io.out((0, output_1.renderTable)(COLUMNS, page.data));
26
32
  return 0;
27
33
  }
34
+ case 'create': {
35
+ const url = (0, args_1.str)(args.values, 'url');
36
+ if (!url)
37
+ throw new errors_1.CliError('webhooks create requires --url <https-url>.');
38
+ const events = (0, args_1.list)(args.values, 'events');
39
+ const auth = (0, shared_1.resolveAuth)(ctx, args.values);
40
+ const endpoint = await (0, project_1.httpFor)(ctx, { secretKey: auth.secretKey, apiUrl: auth.apiUrl }).post('/v1/webhook_endpoints', { url, ...(events.length ? { enabled_events: events } : {}) });
41
+ const { secret, ...rest } = endpoint;
42
+ let secretFile;
43
+ if (secret) {
44
+ secretFile = (0, secrets_1.deliverSecret)({
45
+ io: json ? { out: () => undefined, err: ctx.io.err } : ctx.io,
46
+ env: ctx.env,
47
+ product: (0, args_1.str)(args.values, 'product') ?? 'atlasauth',
48
+ fileName: `webhook-${endpoint.id}.env`,
49
+ entries: { ATLAS_WEBHOOK_SECRET: secret },
50
+ label: 'The signing secret',
51
+ printSecret: args.values['print-secret'] === true,
52
+ force: args.values.force === true,
53
+ comment: `Signing secret for webhook endpoint ${endpoint.id} (${url}).`,
54
+ }).path;
55
+ }
56
+ if (json)
57
+ (0, output_1.printJson)(ctx.io, args.values['print-secret'] === true ? endpoint : { ...rest, secret_file: secretFile ?? null });
58
+ else
59
+ ctx.io.out(`Created webhook endpoint ${endpoint.id} → ${endpoint.url}.`);
60
+ return 0;
61
+ }
28
62
  default:
29
63
  throw new errors_1.CliError(sub
30
- ? `Unknown subcommand 'webhooks ${sub}'. Try: list.`
31
- : 'webhooks needs a subcommand: list.');
64
+ ? `Unknown subcommand 'webhooks ${sub}'. Try: list, create.`
65
+ : 'webhooks needs a subcommand: list, create.');
32
66
  }
33
67
  }
34
68
  //# sourceMappingURL=webhooks.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/commands/webhooks.ts"],"names":[],"mappings":";;AAgBA,4BAoBC;AAjCD,sCAAqC;AACrC,sCAAyE;AACzE,qCAAoD;AAEpD,MAAM,OAAO,GAA8B;IACzC,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;IAClC,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE;IACpC,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE;IAC1C,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,EAAE;IAClD,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,gBAAO,EAAC,CAAC,CAAC,UAAU,CAAC,EAAE;CACzD,CAAC;AAEF,oFAAoF;AAC7E,KAAK,UAAU,QAAQ,CAAC,GAAe,EAAE,IAAgB;IAC9D,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,IAAA,kBAAS,EAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAEpC,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,EAAE,MAAM,EAAE,GAAG,IAAA,sBAAa,EAAC,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YACnD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;YACpD,IAAI,IAAI;gBAAE,IAAA,kBAAS,EAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;;gBAC7B,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAA,oBAAW,EAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YACjD,OAAO,CAAC,CAAC;QACX,CAAC;QAED;YACE,MAAM,IAAI,iBAAQ,CAChB,GAAG;gBACD,CAAC,CAAC,gCAAgC,GAAG,eAAe;gBACpD,CAAC,CAAC,oCAAoC,CACzC,CAAC;IACN,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/commands/webhooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * A tiny, management-API HTTP seam used only by `atlas config`. The typed
3
+ * `@atlasauth/backend` client deliberately exposes a NARROW, hand-curated
4
+ * surface (and omits several config-only endpoints — redirect URLs, the org
5
+ * settings schema, notification templates, webhook PATCH, …). The deploy tool
6
+ * instead speaks to the raw `/v1/...` endpoints the Terraform provider already
7
+ * drives, so it needs a thin verb-per-method client over the same credential.
8
+ *
9
+ * It reuses the backend's {@link AtlasApiError} so a failure is formatted by the
10
+ * CLI's one error reporter exactly like any other API error, and it is a plain
11
+ * interface so tests inject an in-memory fake with no network.
12
+ */
13
+ export interface ConfigHttp {
14
+ get<T>(path: string): Promise<T>;
15
+ post<T>(path: string, body: unknown): Promise<T>;
16
+ put<T>(path: string, body: unknown): Promise<T>;
17
+ patch<T>(path: string, body: unknown): Promise<T>;
18
+ delete(path: string): Promise<void>;
19
+ }
20
+ /** The production {@link ConfigHttp}: Bearer-authed `fetch`, mirroring the backend client. */
21
+ export declare function createConfigHttp(opts: {
22
+ secretKey: string;
23
+ apiUrl: string;
24
+ fetch?: typeof fetch;
25
+ }): ConfigHttp;
26
+ /** True when an error is an Atlas 404 — a resource that does not (yet) exist. */
27
+ export declare function isNotFound(err: unknown): boolean;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createConfigHttp = createConfigHttp;
4
+ exports.isNotFound = isNotFound;
5
+ const backend_1 = require("@atlasauth/backend");
6
+ /** The production {@link ConfigHttp}: Bearer-authed `fetch`, mirroring the backend client. */
7
+ function createConfigHttp(opts) {
8
+ const base = opts.apiUrl.replace(/\/+$/, '');
9
+ const fetchImpl = opts.fetch ?? globalThis.fetch;
10
+ if (typeof fetchImpl !== 'function') {
11
+ throw new Error('No fetch implementation found for the Atlas config client.');
12
+ }
13
+ async function send(method, path, body) {
14
+ const headers = {
15
+ authorization: `Bearer ${opts.secretKey}`,
16
+ accept: 'application/json',
17
+ };
18
+ let payload;
19
+ if (body !== undefined) {
20
+ headers['content-type'] = 'application/json';
21
+ payload = JSON.stringify(body);
22
+ }
23
+ const res = await fetchImpl(`${base}${path}`, { method, headers, body: payload });
24
+ if (!res.ok)
25
+ throw await toApiError(res);
26
+ if (res.status === 204)
27
+ return undefined;
28
+ const text = await res.text();
29
+ return (text ? JSON.parse(text) : undefined);
30
+ }
31
+ return {
32
+ get: (path) => send('GET', path),
33
+ post: (path, body) => send('POST', path, body),
34
+ put: (path, body) => send('PUT', path, body),
35
+ patch: (path, body) => send('PATCH', path, body),
36
+ delete: async (path) => {
37
+ await send('DELETE', path);
38
+ },
39
+ };
40
+ }
41
+ async function toApiError(res) {
42
+ let errors = [];
43
+ const text = await res.text().catch(() => '');
44
+ if (text) {
45
+ try {
46
+ const parsed = JSON.parse(text);
47
+ if (Array.isArray(parsed.errors) && parsed.errors.length)
48
+ errors = parsed.errors;
49
+ }
50
+ catch {
51
+ /* non-JSON body */
52
+ }
53
+ }
54
+ if (!errors.length) {
55
+ errors = [{ code: 'UNKNOWN', message: `Atlas API request failed with status ${res.status}` }];
56
+ }
57
+ return new backend_1.AtlasApiError(res.status, errors);
58
+ }
59
+ /** True when an error is an Atlas 404 — a resource that does not (yet) exist. */
60
+ function isNotFound(err) {
61
+ return err instanceof backend_1.AtlasApiError && err.status === 404;
62
+ }
63
+ //# sourceMappingURL=config-http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-http.js","sourceRoot":"","sources":["../src/config-http.ts"],"names":[],"mappings":"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"}
package/dist/context.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { type AtlasClient } from '@atlasauth/backend';
2
2
  import { type ConfigStore } from './config';
3
+ import { type ConfigHttp } from './config-http';
3
4
  import { type IO } from './io';
4
5
  import { type Prompter } from './prompt';
5
6
  /**
@@ -8,7 +9,7 @@ import { type Prompter } from './prompt';
8
9
  * enforces — that the command set maps only onto namespaces that really exist,
9
10
  * and it keeps the fake a test injects small (five namespaces, not forty).
10
11
  */
11
- export type ManagementClient = Pick<AtlasClient, 'users' | 'organizations' | 'apiKeys' | 'webhooks' | 'sessions'>;
12
+ export type ManagementClient = Pick<AtlasClient, 'users' | 'organizations' | 'apiKeys' | 'webhooks' | 'sessions' | 'actions'>;
12
13
  /**
13
14
  * Everything a command touches the outside world through, in one injectable
14
15
  * bag. Production wires the real IO/config/prompt/client; every test builds
@@ -26,6 +27,21 @@ export interface RunContext {
26
27
  secretKey: string;
27
28
  apiUrl: string;
28
29
  }) => ManagementClient;
30
+ /**
31
+ * Builds the raw management-API HTTP client used by `atlas config` (the
32
+ * config-only `/v1` endpoints the typed client omits). Optional so existing
33
+ * contexts stay valid; the config command falls back to the real one.
34
+ */
35
+ makeHttp?: (opts: {
36
+ secretKey: string;
37
+ apiUrl: string;
38
+ }) => ConfigHttp;
39
+ /**
40
+ * Read a file's text, for commands that take a path (`atlas actions deploy`
41
+ * / `test`). Injectable so a test drives them with an in-memory file instead
42
+ * of touching the disk. Defaults to reading UTF-8 off the real filesystem.
43
+ */
44
+ readFile: (path: string) => string;
29
45
  }
30
46
  /**
31
47
  * The production context, with any piece overridable. Tests call this with a
package/dist/context.js CHANGED
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.defaultContext = defaultContext;
4
+ const node_fs_1 = require("node:fs");
4
5
  const backend_1 = require("@atlasauth/backend");
5
6
  const config_1 = require("./config");
7
+ const config_http_1 = require("./config-http");
6
8
  const io_1 = require("./io");
7
9
  const prompt_1 = require("./prompt");
8
10
  /**
@@ -17,6 +19,8 @@ function defaultContext(overrides = {}) {
17
19
  config: new config_1.FileConfigStore((0, config_1.defaultConfigPath)()),
18
20
  prompt: (0, prompt_1.defaultPrompter)(),
19
21
  makeClient: ({ secretKey, apiUrl }) => (0, backend_1.createAtlasClient)({ secretKey, apiUrl }),
22
+ makeHttp: ({ secretKey, apiUrl }) => (0, config_http_1.createConfigHttp)({ secretKey, apiUrl }),
23
+ readFile: (path) => (0, node_fs_1.readFileSync)(path, 'utf8'),
20
24
  ...overrides,
21
25
  };
22
26
  }
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":";;AAqCA,wCASC;AA9CD,gDAAyE;AACzE,qCAAgF;AAChF,6BAA0C;AAC1C,qCAA0D;AA6B1D;;;;GAIG;AACH,SAAgB,cAAc,CAAC,YAAiC,EAAE;IAChE,OAAO;QACL,EAAE,EAAE,IAAA,cAAS,GAAE;QACf,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,MAAM,EAAE,IAAI,wBAAe,CAAC,IAAA,0BAAiB,GAAE,CAAC;QAChD,MAAM,EAAE,IAAA,wBAAe,GAAE;QACzB,UAAU,EAAE,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,IAAA,2BAAiB,EAAC,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;QAC/E,GAAG,SAAS;KACb,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":";;AAmDA,wCAWC;AA9DD,qCAAuC;AACvC,gDAAyE;AACzE,qCAAgF;AAChF,+CAAkE;AAClE,6BAA0C;AAC1C,qCAA0D;AAyC1D;;;;GAIG;AACH,SAAgB,cAAc,CAAC,YAAiC,EAAE;IAChE,OAAO;QACL,EAAE,EAAE,IAAA,cAAS,GAAE;QACf,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,MAAM,EAAE,IAAI,wBAAe,CAAC,IAAA,0BAAiB,GAAE,CAAC;QAChD,MAAM,EAAE,IAAA,wBAAe,GAAE;QACzB,UAAU,EAAE,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,IAAA,2BAAiB,EAAC,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;QAC/E,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,IAAA,8BAAgB,EAAC,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;QAC5E,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAA,sBAAY,EAAC,IAAI,EAAE,MAAM,CAAC;QAC9C,GAAG,SAAS;KACb,CAAC;AACJ,CAAC"}
package/dist/help.d.ts CHANGED
@@ -3,6 +3,6 @@
3
3
  * out of the handlers so the dispatch code stays about control flow and the
4
4
  * copy can be read (and kept consistent) in one place.
5
5
  */
6
- export declare const TOP_HELP = "atlas \u2014 manage an Atlas instance from the terminal\n\nUsage: atlas <command> [subcommand] [arguments] [options]\n\nCommands:\n login Authenticate and store a profile credential\n logout Remove a stored profile credential\n whoami Show the active profile and instance\n users list|get|create|delete\n orgs list|get|members\n api-keys list|create|revoke\n webhooks list\n sessions revoke\n\nGlobal options:\n --profile <name> Use a named profile (default: active, else \"default\")\n --json Emit raw JSON instead of a human table\n --limit <n> Page size for list commands that paginate\n --starting-after <cursor> Pagination cursor (from a prior page's hint)\n -h, --help Show this help, or help for a command\n -v, --version Print the version\n\nEnvironment overrides:\n ATLAS_SECRET_KEY Secret key to use instead of the stored one\n ATLAS_API_URL API URL to use instead of the stored one\n\nRun 'atlas <command> --help' for command-specific help.";
6
+ export declare const TOP_HELP = "atlas \u2014 manage an Atlas instance from the terminal\n\nUsage: atlas <command> [subcommand] [arguments] [options]\n\nCommands:\n login Authenticate and store a profile credential\n logout Remove a stored profile credential\n whoami Show the active profile and instance\n users list|get|create|delete\n orgs list|get|members\n api-keys list|create|revoke\n webhooks list|create\n sessions revoke\n config export|import Config-as-code: round-trip the instance's config\n actions list|deploy|test|logs\n init Create or complete an app's setup (idempotent); secrets to 0600 files\n preflight Check an instance's setup; non-zero exit on errors (for CI)\n env Print deploy variables: public values + secret file paths\n client rotate Rotate an OAuth client secret straight into its file\n\nGlobal options:\n --profile <name> Use a named profile (default: active, else \"default\")\n --json Emit raw JSON instead of a human table\n --limit <n> Page size for list commands that paginate\n --starting-after <cursor> Pagination cursor (from a prior page's hint)\n -h, --help Show this help, or help for a command\n -v, --version Print the version\n\nEnvironment overrides:\n ATLAS_SECRET_KEY Secret key to use instead of the stored one\n ATLAS_API_URL API URL to use instead of the stored one\n ATLAS_PLATFORM_KEY Platform key (psk_) for atlas init\n\nSecrets: a command that receives a secret writes it to a 0600 file under\n~/.config/<product>/ and prints only the path. --print-secret prints it instead.\n\nRun 'atlas <command> --help' for command-specific help.";
7
7
  /** Per-command help, keyed by the resource word. */
8
8
  export declare const COMMAND_HELP: Record<string, string>;