@atlasauth/cli 0.2.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.
@@ -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":";;AAqBA,4BAgDC;AApED,kCAAqD;AAErD,sCAAqC;AACrC,sCAAyE;AACzE,wCAAqC;AACrC,wCAA2C;AAC3C,qCAAiE;AAEjE,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;;;GAGG;AACI,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,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,GAAG,GAAG,IAAA,UAAG,EAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YACpC,IAAI,CAAC,GAAG;gBAAE,MAAM,IAAI,iBAAQ,CAAC,6CAA6C,CAAC,CAAC;YAC5E,MAAM,MAAM,GAAG,IAAA,WAAI,EAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YAC3C,MAAM,IAAI,GAAG,IAAA,oBAAW,EAAC,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YAC3C,MAAM,QAAQ,GAAG,MAAM,IAAA,iBAAO,EAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAE1F,uBAAuB,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YAC1F,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,QAAQ,CAAC;YACrC,IAAI,UAA8B,CAAC;YACnC,IAAI,MAAM,EAAE,CAAC;gBACX,UAAU,GAAG,IAAA,uBAAa,EAAC;oBACzB,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE;oBAC7D,GAAG,EAAE,GAAG,CAAC,GAAG;oBACZ,OAAO,EAAE,IAAA,UAAG,EAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,IAAI,WAAW;oBACnD,QAAQ,EAAE,WAAW,QAAQ,CAAC,EAAE,MAAM;oBACtC,OAAO,EAAE,EAAE,oBAAoB,EAAE,MAAM,EAAE;oBACzC,KAAK,EAAE,oBAAoB;oBAC3B,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,KAAK,IAAI;oBACjD,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI;oBACjC,OAAO,EAAE,uCAAuC,QAAQ,CAAC,EAAE,KAAK,GAAG,IAAI;iBACxE,CAAC,CAAC,IAAI,CAAC;YACV,CAAC;YACD,IAAI,IAAI;gBAAE,IAAA,kBAAS,EAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,WAAW,EAAE,UAAU,IAAI,IAAI,EAAE,CAAC,CAAC;;gBACvH,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,4BAA4B,QAAQ,CAAC,EAAE,MAAM,QAAQ,CAAC,GAAG,GAAG,CAAC,CAAC;YAC9E,OAAO,CAAC,CAAC;QACX,CAAC;QAED;YACE,MAAM,IAAI,iBAAQ,CAChB,GAAG;gBACD,CAAC,CAAC,gCAAgC,GAAG,uBAAuB;gBAC5D,CAAC,CAAC,4CAA4C,CACjD,CAAC;IACN,CAAC;AACH,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 config export|import Config-as-code: round-trip the instance's config\n actions list|deploy|test|logs\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>;
package/dist/help.js CHANGED
@@ -17,10 +17,14 @@ Commands:
17
17
  users list|get|create|delete
18
18
  orgs list|get|members
19
19
  api-keys list|create|revoke
20
- webhooks list
20
+ webhooks list|create
21
21
  sessions revoke
22
22
  config export|import Config-as-code: round-trip the instance's config
23
23
  actions list|deploy|test|logs
24
+ init Create or complete an app's setup (idempotent); secrets to 0600 files
25
+ preflight Check an instance's setup; non-zero exit on errors (for CI)
26
+ env Print deploy variables: public values + secret file paths
27
+ client rotate Rotate an OAuth client secret straight into its file
24
28
 
25
29
  Global options:
26
30
  --profile <name> Use a named profile (default: active, else "default")
@@ -33,6 +37,10 @@ Global options:
33
37
  Environment overrides:
34
38
  ATLAS_SECRET_KEY Secret key to use instead of the stored one
35
39
  ATLAS_API_URL API URL to use instead of the stored one
40
+ ATLAS_PLATFORM_KEY Platform key (psk_) for atlas init
41
+
42
+ Secrets: a command that receives a secret writes it to a 0600 file under
43
+ ~/.config/<product>/ and prints only the path. --print-secret prints it instead.
36
44
 
37
45
  Run 'atlas <command> --help' for command-specific help.`;
38
46
  /** Per-command help, keyed by the resource word. */
@@ -67,12 +75,69 @@ Usage:
67
75
 
68
76
  Usage:
69
77
  atlas api-keys list [--subject-type <user|organization>] [--subject-id <id>] [--json]
70
- atlas api-keys create --subject-type <user|organization> --subject-id <id> [--name <n>] [--json]
78
+ atlas api-keys create --subject-type <user|organization> --subject-id <id> [--name <n>]
79
+ [--product <name>] [--force] [--print-secret] [--json]
71
80
  atlas api-keys revoke <api-key-id> [--json]`,
72
- webhooks: `atlas webhooks — inspect webhook endpoints
81
+ webhooks: `atlas webhooks — manage webhook endpoints
82
+
83
+ Usage:
84
+ atlas webhooks list [--json]
85
+ atlas webhooks create --url <https-url> [--events a,b] [--product <name>] [--print-secret] [--json]
86
+
87
+ create writes the signing secret to a 0600 file and prints only its path.`,
88
+ init: `atlas init — create or complete an app's setup, idempotently
73
89
 
74
90
  Usage:
75
- atlas webhooks list [--json]`,
91
+ atlas init --product <name> [--domain <domain>] [--auth-host <host>]
92
+ [--instance-env development|production] [--name <app-name>]
93
+ [--strategies password,email_code,...]
94
+ [--email managed|development|none] [--email-from <address>]
95
+ [--email-provider resend|brevo --email-key-file <path|->]
96
+ [--client-redirect <url>]... [--webhook-url <url>]
97
+ [--yes] [--force] [--rotate-secret] [--json]
98
+
99
+ Needs a platform key (ATLAS_PLATFORM_KEY, or a psk_ profile from atlas login).
100
+ Finds the app by name and environment, or creates it, then sets strategies, the
101
+ email sender, the custom domain (auth.<domain> unless --auth-host; prints the
102
+ CNAME), a first-party OAuth client and a webhook. Re-running only fills what is
103
+ missing.
104
+
105
+ Email always goes through YOUR provider account (Atlas lends none):
106
+ managed Atlas sets your domain up on your Resend or Brevo account and
107
+ prints the DNS records.
108
+ development development instances only: your provider without a verified
109
+ domain (Resend's onboarding@resend.dev by default), capped.
110
+ The key is read from --email-key-file (a file holding the key or KEY=value; '-'
111
+ reads stdin). It is never taken from argv and never printed.
112
+
113
+ Every secret goes to ~/.config/<product>/<env>*.env (dir 0700, files 0600) and
114
+ is never printed. An existing file is never overwritten without --force.
115
+ --rotate-secret mints a new secret key when the app exists but its file is gone.
116
+ Public values and file paths are kept in ~/.config/<product>/atlas.json.`,
117
+ preflight: `atlas preflight — check an instance's setup (a CI / deploy gate)
118
+
119
+ Usage: atlas preflight [--instance <id> | --product <name> [--instance-env <env>]]
120
+ [--fail-on error|warning] [--json]
121
+
122
+ Prints every finding (severity, code, message, fix). Exits 1 when there is an
123
+ error, or with --fail-on warning also on a warning.`,
124
+ env: `atlas env — print deploy variables without secrets
125
+
126
+ Usage: atlas env --product <name> [--instance-env <env>] [--format dotenv|coolify|vercel] [--json]
127
+
128
+ Public values (publishable key, Frontend API, issuer, discovery and JWKS URLs,
129
+ OAuth client id) are printed as-is. Secrets are printed as references to their
130
+ 0600 files: *_FILE=<path> (dotenv), KEY=@<path> (coolify), or a vercel env add
131
+ command that pipes the value from the file (vercel).`,
132
+ client: `atlas client — OAuth clients
133
+
134
+ Usage: atlas client rotate <client-id> [--now | --overlap <seconds>]
135
+ [--instance <id> | --product <name> [--instance-env <env>]]
136
+ [--print-secret]
137
+
138
+ Rotates the client secret and writes the new one straight to its 0600 file.
139
+ --now revokes the old secret immediately; --overlap keeps it working for that
140
+ many seconds. Prints when the old secret stops working.`,
76
141
  sessions: `atlas sessions — manage sessions
77
142
 
78
143
  Usage:
package/dist/help.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"help.js","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEU,QAAA,QAAQ,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;wDA4BgC,CAAC;AAEzD,oDAAoD;AACvC,QAAA,YAAY,GAA2B;IAClD,KAAK,EAAE;;;;;;mCAM0B;IAEjC,MAAM,EAAE;;uCAE6B;IAErC,MAAM,EAAE;;gDAEsC;IAE9C,KAAK,EAAE;;;;;;wCAM+B;IAEtC,IAAI,EAAE;;;;;uCAK+B;IAErC,UAAU,EAAE;;;;;8CAKgC;IAE5C,QAAQ,EAAE;;;+BAGmB;IAE7B,QAAQ,EAAE;;;8CAGkC;IAE5C,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;8EAoBoE;IAC5E,OAAO,EAAE;;;;;;;;;;;gFAWqE;CAC/E,CAAC"}
1
+ {"version":3,"file":"help.js","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEU,QAAA,QAAQ,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wDAoCgC,CAAC;AAEzD,oDAAoD;AACvC,QAAA,YAAY,GAA2B;IAClD,KAAK,EAAE;;;;;;mCAM0B;IAEjC,MAAM,EAAE;;uCAE6B;IAErC,MAAM,EAAE;;gDAEsC;IAE9C,KAAK,EAAE;;;;;;wCAM+B;IAEtC,IAAI,EAAE;;;;;uCAK+B;IAErC,UAAU,EAAE;;;;;;8CAMgC;IAE5C,QAAQ,EAAE;;;;;;0EAM8D;IAExE,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;yEA4BiE;IAEvE,SAAS,EAAE;;;;;;oDAMuC;IAElD,GAAG,EAAE;;;;;;;qDAO8C;IAEnD,MAAM,EAAE;;;;;;;;wDAQ8C;IAEtD,QAAQ,EAAE;;;8CAGkC;IAE5C,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;8EAoBoE;IAC5E,OAAO,EAAE;;;;;;;;;;;gFAWqE;CAC/E,CAAC"}
package/dist/index.d.ts CHANGED
@@ -20,3 +20,7 @@ export { webhooks } from './commands/webhooks';
20
20
  export { sessions } from './commands/sessions';
21
21
  export { config } from './commands/config';
22
22
  export { actions } from './commands/actions';
23
+ export { init } from './commands/init';
24
+ export { preflight, envCommand, client } from './commands/project-commands';
25
+ export { writeSecretFile, readEnvFile, parseDotenv, renderDotenv, productDir, deliverSecret, } from './secrets';
26
+ export { readManifest, writeManifest, manifestPath, type ProjectManifest, type ProjectInstance, type InstanceEnv, } from './project';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.actions = exports.config = exports.sessions = exports.webhooks = exports.apiKeys = exports.orgs = exports.users = exports.whoami = exports.logout = exports.login = exports.getVersion = exports.defaultPrompter = exports.defaultConfigPath = exports.MemoryConfigStore = exports.FileConfigStore = exports.captureIO = exports.defaultIO = exports.CliError = exports.isNotFound = exports.createConfigHttp = exports.defaultContext = exports.run = void 0;
3
+ exports.manifestPath = exports.writeManifest = exports.readManifest = exports.deliverSecret = exports.productDir = exports.renderDotenv = exports.parseDotenv = exports.readEnvFile = exports.writeSecretFile = exports.client = exports.envCommand = exports.preflight = exports.init = exports.actions = exports.config = exports.sessions = exports.webhooks = exports.apiKeys = exports.orgs = exports.users = exports.whoami = exports.logout = exports.login = exports.getVersion = exports.defaultPrompter = exports.defaultConfigPath = exports.MemoryConfigStore = exports.FileConfigStore = exports.captureIO = exports.defaultIO = exports.CliError = exports.isNotFound = exports.createConfigHttp = exports.defaultContext = exports.run = void 0;
4
4
  /**
5
5
  * Library surface of `@atlasauth/cli`. The package ships a bin (`atlas`), but
6
6
  * exporting the pieces lets the handlers be unit-tested with injected deps and
@@ -46,4 +46,21 @@ var config_2 = require("./commands/config");
46
46
  Object.defineProperty(exports, "config", { enumerable: true, get: function () { return config_2.config; } });
47
47
  var actions_1 = require("./commands/actions");
48
48
  Object.defineProperty(exports, "actions", { enumerable: true, get: function () { return actions_1.actions; } });
49
+ var init_1 = require("./commands/init");
50
+ Object.defineProperty(exports, "init", { enumerable: true, get: function () { return init_1.init; } });
51
+ var project_commands_1 = require("./commands/project-commands");
52
+ Object.defineProperty(exports, "preflight", { enumerable: true, get: function () { return project_commands_1.preflight; } });
53
+ Object.defineProperty(exports, "envCommand", { enumerable: true, get: function () { return project_commands_1.envCommand; } });
54
+ Object.defineProperty(exports, "client", { enumerable: true, get: function () { return project_commands_1.client; } });
55
+ var secrets_1 = require("./secrets");
56
+ Object.defineProperty(exports, "writeSecretFile", { enumerable: true, get: function () { return secrets_1.writeSecretFile; } });
57
+ Object.defineProperty(exports, "readEnvFile", { enumerable: true, get: function () { return secrets_1.readEnvFile; } });
58
+ Object.defineProperty(exports, "parseDotenv", { enumerable: true, get: function () { return secrets_1.parseDotenv; } });
59
+ Object.defineProperty(exports, "renderDotenv", { enumerable: true, get: function () { return secrets_1.renderDotenv; } });
60
+ Object.defineProperty(exports, "productDir", { enumerable: true, get: function () { return secrets_1.productDir; } });
61
+ Object.defineProperty(exports, "deliverSecret", { enumerable: true, get: function () { return secrets_1.deliverSecret; } });
62
+ var project_1 = require("./project");
63
+ Object.defineProperty(exports, "readManifest", { enumerable: true, get: function () { return project_1.readManifest; } });
64
+ Object.defineProperty(exports, "writeManifest", { enumerable: true, get: function () { return project_1.writeManifest; } });
65
+ Object.defineProperty(exports, "manifestPath", { enumerable: true, get: function () { return project_1.manifestPath; } });
49
66
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA;;;;;GAKG;AACH,6BAA0C;AAAjC,0FAAA,GAAG,OAAA;AACZ,qCAAmF;AAA1E,yGAAA,cAAc,OAAA;AACvB,6CAA8E;AAArE,+GAAA,gBAAgB,OAAA;AAAE,yGAAA,UAAU,OAAA;AACrC,mCAAoC;AAA3B,kGAAA,QAAQ,OAAA;AACjB,2BAAqE;AAA5D,+FAAA,SAAS,OAAA;AAAE,+FAAA,SAAS,OAAA;AAC7B,mCAOkB;AANhB,yGAAA,eAAe,OAAA;AACf,2GAAA,iBAAiB,OAAA;AACjB,2GAAA,iBAAiB,OAAA;AAKnB,mCAA0D;AAAjD,yGAAA,eAAe,OAAA;AACxB,qCAAuC;AAA9B,qGAAA,UAAU,OAAA;AAEnB,0EAA0E;AAC1E,wCAAwD;AAA/C,6FAAA,KAAK,OAAA;AAAE,8FAAA,MAAM,OAAA;AAAE,8FAAA,MAAM,OAAA;AAC9B,0CAAyC;AAAhC,8FAAA,KAAK,OAAA;AACd,wCAAuC;AAA9B,4FAAA,IAAI,OAAA;AACb,gDAA8C;AAArC,mGAAA,OAAO,OAAA;AAChB,gDAA+C;AAAtC,oGAAA,QAAQ,OAAA;AACjB,gDAA+C;AAAtC,oGAAA,QAAQ,OAAA;AACjB,4CAA2C;AAAlC,gGAAA,MAAM,OAAA;AACf,8CAA6C;AAApC,kGAAA,OAAO,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA;;;;;GAKG;AACH,6BAA0C;AAAjC,0FAAA,GAAG,OAAA;AACZ,qCAAmF;AAA1E,yGAAA,cAAc,OAAA;AACvB,6CAA8E;AAArE,+GAAA,gBAAgB,OAAA;AAAE,yGAAA,UAAU,OAAA;AACrC,mCAAoC;AAA3B,kGAAA,QAAQ,OAAA;AACjB,2BAAqE;AAA5D,+FAAA,SAAS,OAAA;AAAE,+FAAA,SAAS,OAAA;AAC7B,mCAOkB;AANhB,yGAAA,eAAe,OAAA;AACf,2GAAA,iBAAiB,OAAA;AACjB,2GAAA,iBAAiB,OAAA;AAKnB,mCAA0D;AAAjD,yGAAA,eAAe,OAAA;AACxB,qCAAuC;AAA9B,qGAAA,UAAU,OAAA;AAEnB,0EAA0E;AAC1E,wCAAwD;AAA/C,6FAAA,KAAK,OAAA;AAAE,8FAAA,MAAM,OAAA;AAAE,8FAAA,MAAM,OAAA;AAC9B,0CAAyC;AAAhC,8FAAA,KAAK,OAAA;AACd,wCAAuC;AAA9B,4FAAA,IAAI,OAAA;AACb,gDAA8C;AAArC,mGAAA,OAAO,OAAA;AAChB,gDAA+C;AAAtC,oGAAA,QAAQ,OAAA;AACjB,gDAA+C;AAAtC,oGAAA,QAAQ,OAAA;AACjB,4CAA2C;AAAlC,gGAAA,MAAM,OAAA;AACf,8CAA6C;AAApC,kGAAA,OAAO,OAAA;AAChB,wCAAuC;AAA9B,4FAAA,IAAI,OAAA;AACb,gEAA4E;AAAnE,6GAAA,SAAS,OAAA;AAAE,8GAAA,UAAU,OAAA;AAAE,0GAAA,MAAM,OAAA;AACtC,qCAOmB;AANjB,0GAAA,eAAe,OAAA;AACf,sGAAA,WAAW,OAAA;AACX,sGAAA,WAAW,OAAA;AACX,uGAAA,YAAY,OAAA;AACZ,qGAAA,UAAU,OAAA;AACV,wGAAA,aAAa,OAAA;AAEf,qCAOmB;AANjB,uGAAA,YAAY,OAAA;AACZ,wGAAA,aAAa,OAAA;AACb,uGAAA,YAAY,OAAA"}
@@ -0,0 +1,63 @@
1
+ import { type ConfigHttp } from './config-http';
2
+ import type { RunContext } from './context';
3
+ /**
4
+ * The project manifest `atlas init` keeps at `~/.config/<product>/atlas.json`:
5
+ * PUBLIC values only (ids, publishable key, hosts, redirect URIs) plus the path
6
+ * of each secret file. `atlas env`, `atlas preflight --instance` and
7
+ * `atlas client rotate` read it, so they know where a secret lives without
8
+ * ever holding it in the manifest.
9
+ */
10
+ export type InstanceEnv = 'development' | 'production';
11
+ export interface ProjectInstance {
12
+ instance_id: string;
13
+ environment: InstanceEnv;
14
+ publishable_key: string;
15
+ frontend_api_host: string | null;
16
+ issuer: string | null;
17
+ discovery_url: string | null;
18
+ jwks_uri: string | null;
19
+ /** The file holding ATLAS_SECRET_KEY. */
20
+ secret_file: string;
21
+ oauth_client?: {
22
+ id: string;
23
+ client_id: string;
24
+ redirect_uris: string[];
25
+ secret_file: string | null;
26
+ };
27
+ webhook?: {
28
+ id: string;
29
+ url: string;
30
+ secret_file: string | null;
31
+ };
32
+ custom_domain?: {
33
+ host: string;
34
+ cname_target: string | null;
35
+ status: string;
36
+ };
37
+ email?: {
38
+ mode: 'managed' | 'development' | 'none';
39
+ from_address?: string | null;
40
+ };
41
+ }
42
+ export interface ProjectManifest {
43
+ product: string;
44
+ api_url: string;
45
+ instances: Partial<Record<InstanceEnv, ProjectInstance>>;
46
+ }
47
+ export declare const MANIFEST_FILE = "atlas.json";
48
+ export declare function manifestPath(env: NodeJS.ProcessEnv, product: string): string;
49
+ export declare function readManifest(env: NodeJS.ProcessEnv, product: string): ProjectManifest | undefined;
50
+ export declare function writeManifest(env: NodeJS.ProcessEnv, manifest: ProjectManifest): string;
51
+ /** Find the project + instance an instance id belongs to, scanning every product directory. */
52
+ export declare function findInstance(env: NodeJS.ProcessEnv, instanceId: string, product?: string): {
53
+ manifest: ProjectManifest;
54
+ instance: ProjectInstance;
55
+ } | undefined;
56
+ export declare function parseInstanceEnv(raw: string | undefined, fallback: InstanceEnv): InstanceEnv;
57
+ /** The raw HTTP client for a credential (the context's, or the real one). */
58
+ export declare function httpFor(ctx: RunContext, opts: {
59
+ secretKey: string;
60
+ apiUrl: string;
61
+ }): ConfigHttp;
62
+ /** Read the instance secret key from the project's secret file. */
63
+ export declare function instanceSecretFromFile(instance: ProjectInstance): string;