@sprigr/cli 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/auth.js ADDED
@@ -0,0 +1,225 @@
1
+ import { promises as fs, readFileSync, readdirSync } from 'node:fs';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ /**
5
+ * Resolve the Sprigr API key.
6
+ *
7
+ * Resolution order:
8
+ * 1. `--api-key <key>` flag
9
+ * 2. `SPRIGR_API_KEY` env var
10
+ * 3. Credential file
11
+ * - When `profile` is set: `~/.config/sprigr/credentials/<profile>.json`
12
+ * - Otherwise (legacy default): `~/.config/sprigr/credentials.json`
13
+ *
14
+ * If none are set, returns null. Callers must surface a clear "run
15
+ * `sprigr login` or set SPRIGR_API_KEY" message rather than failing
16
+ * silently.
17
+ */
18
+ export function resolveApiKey(opts) {
19
+ const fromFlag = opts.flag?.trim();
20
+ if (fromFlag)
21
+ return fromFlag;
22
+ const fromEnv = process.env.SPRIGR_API_KEY?.trim();
23
+ if (fromEnv)
24
+ return fromEnv;
25
+ const fromFile = readApiKeyFromFileSync(opts.profile);
26
+ if (fromFile)
27
+ return fromFile;
28
+ return null;
29
+ }
30
+ /**
31
+ * Compute the credentials file path. Honors $XDG_CONFIG_HOME so users
32
+ * who customize their config layout still land in the right place;
33
+ * falls back to ~/.config/sprigr otherwise (Linux + macOS convention).
34
+ *
35
+ * When `profile` is given (e.g. `--profile staging` or `SPRIGR_PROFILE=...`),
36
+ * the file lives under `<config>/sprigr/credentials/<profile>.json` so
37
+ * multiple tenants can be logged in side-by-side without overwriting each
38
+ * other. When omitted, returns the legacy single-file path so existing
39
+ * setups keep working unchanged.
40
+ */
41
+ export function credentialsFilePath(profile) {
42
+ const base = process.env.XDG_CONFIG_HOME?.trim() ||
43
+ path.join(os.homedir(), '.config');
44
+ if (profile && profile.length > 0) {
45
+ assertValidProfileName(profile);
46
+ return path.join(base, 'sprigr', 'credentials', `${profile}.json`);
47
+ }
48
+ return path.join(base, 'sprigr', 'credentials.json');
49
+ }
50
+ const PROFILE_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;
51
+ /**
52
+ * Profile names map to filenames on disk; reject anything that could
53
+ * escape the credentials directory or look like a path traversal. The
54
+ * regex below also doubles as a sanity check on length (max 64 chars).
55
+ */
56
+ export function assertValidProfileName(name) {
57
+ if (!PROFILE_NAME_RE.test(name)) {
58
+ throw new Error(`Invalid profile name "${name}". Use alphanumerics, dash, underscore; ` +
59
+ `1-64 chars, must start with an alphanumeric.`);
60
+ }
61
+ }
62
+ /**
63
+ * Sync read so it can sit in the same call-stack as `resolveApiKey`
64
+ * without making the function async. The file is small (a few hundred
65
+ * bytes) and lives on a local FS — sync I/O is a non-issue.
66
+ *
67
+ * `readFileSync` is imported at the top of the module rather than
68
+ * required dynamically — `@sprigr/cli` ships as ESM (`"type": "module"`
69
+ * in package.json), and `require` is not defined in ESM at runtime.
70
+ * The previous `require('node:fs')` form silently threw inside the
71
+ * try/catch and the function returned null, leaving every subsequent
72
+ * `sprigr <command>` reading "No API key found" even when a valid
73
+ * credentials.json existed on disk. Caught during the staging
74
+ * shakedown of #458.
75
+ */
76
+ function readApiKeyFromFileSync(profile) {
77
+ try {
78
+ const raw = readFileSync(credentialsFilePath(profile), 'utf8');
79
+ const parsed = JSON.parse(raw);
80
+ if (typeof parsed.apiKey === 'string' && parsed.apiKey.length > 0) {
81
+ return parsed.apiKey;
82
+ }
83
+ return null;
84
+ }
85
+ catch {
86
+ // ENOENT / parse error / etc. — treat as "no credentials".
87
+ return null;
88
+ }
89
+ }
90
+ /**
91
+ * Read the `endpoint` field from the credentials file written by
92
+ * `sprigr login`. Used by `resolveEndpoint` so a `--endpoint` passed
93
+ * to `login` sticks for subsequent commands in the same session
94
+ * without the user having to re-pass it (or export SPRIGR_ENDPOINT).
95
+ *
96
+ * Without this, `sprigr login --endpoint https://staging-api-team.sprigr.com`
97
+ * mints a key against staging, but the next `sprigr app publish` (no
98
+ * flag) sends that staging key to the prod gateway — which rejects it
99
+ * 401 because the key row only exists in the staging registry DB.
100
+ * The CLI then surfaces "HTTP 401 — Unauthorized" with no hint that
101
+ * the user is talking to the wrong env.
102
+ */
103
+ export function readEndpointFromFileSync(profile) {
104
+ try {
105
+ const raw = readFileSync(credentialsFilePath(profile), 'utf8');
106
+ const parsed = JSON.parse(raw);
107
+ if (typeof parsed.endpoint === 'string' && parsed.endpoint.length > 0) {
108
+ return parsed.endpoint;
109
+ }
110
+ return null;
111
+ }
112
+ catch {
113
+ return null;
114
+ }
115
+ }
116
+ /** Read the full credentials record (used by `whoami`). Returns null on miss. */
117
+ export function readCredentialsSync(profile) {
118
+ try {
119
+ const raw = readFileSync(credentialsFilePath(profile), 'utf8');
120
+ const parsed = JSON.parse(raw);
121
+ if (typeof parsed.apiKey === 'string' && parsed.apiKey.length > 0 &&
122
+ typeof parsed.loggedInAt === 'string') {
123
+ return parsed;
124
+ }
125
+ return null;
126
+ }
127
+ catch {
128
+ return null;
129
+ }
130
+ }
131
+ /**
132
+ * List every profile we have credentials for. Returns the literal names
133
+ * (sans .json suffix); when only the legacy single-file credentials exist
134
+ * the special name `'(default)'` is included so `sprigr whoami --all` can
135
+ * show it. Returns an empty array if nothing is logged in.
136
+ */
137
+ export function listProfilesSync() {
138
+ const out = [];
139
+ // Profile dir
140
+ try {
141
+ const dir = path.dirname(credentialsFilePath('placeholder')); // <config>/sprigr/credentials
142
+ const entries = readdirSync(dir, { withFileTypes: true });
143
+ for (const e of entries) {
144
+ if (!e.isFile() || !e.name.endsWith('.json'))
145
+ continue;
146
+ out.push({ name: e.name.replace(/\.json$/, ''), isLegacy: false });
147
+ }
148
+ }
149
+ catch { /* dir not present yet */ }
150
+ // Legacy single-file
151
+ try {
152
+ readFileSync(credentialsFilePath(), 'utf8');
153
+ out.push({ name: '(default)', isLegacy: true });
154
+ }
155
+ catch { /* */ }
156
+ return out.sort((a, b) => a.name.localeCompare(b.name));
157
+ }
158
+ /**
159
+ * Write credentials to disk with mode 0600 (owner read/write only).
160
+ * The directory is created with mode 0700 if it doesn't yet exist —
161
+ * sibling tools like `vercel`, `gh`, `wrangler` follow the same
162
+ * convention. Overwrites any existing credentials.
163
+ *
164
+ * When `profile` is set the file lives at `<config>/sprigr/credentials/<profile>.json`
165
+ * (and the parent `credentials/` dir is created at 0700 too). Without a
166
+ * profile we write the legacy `<config>/sprigr/credentials.json` so
167
+ * existing setups stay byte-identical.
168
+ */
169
+ export async function writeCredentials(creds, profile) {
170
+ const target = credentialsFilePath(profile);
171
+ const dir = path.dirname(target);
172
+ await fs.mkdir(dir, { recursive: true, mode: 0o700 });
173
+ // Stamp the profile on the record so `whoami` can echo it back.
174
+ const toWrite = profile
175
+ ? { ...creds, profile }
176
+ : creds;
177
+ // Write to a temp file then rename — atomic on POSIX so a crash mid-
178
+ // write can't leave a half-written credentials file.
179
+ const tmp = `${target}.${process.pid}.${Date.now()}.tmp`;
180
+ await fs.writeFile(tmp, JSON.stringify(toWrite, null, 2), { mode: 0o600 });
181
+ await fs.rename(tmp, target);
182
+ // chmod the target separately in case the filesystem dropped the mode
183
+ // on rename (uncommon but cheap).
184
+ try {
185
+ await fs.chmod(target, 0o600);
186
+ }
187
+ catch { /* best-effort */ }
188
+ return target;
189
+ }
190
+ /**
191
+ * Delete the credential file. Returns true if a file was removed,
192
+ * false if no file was there to begin with. Other errors (permission,
193
+ * etc.) propagate so the caller can surface a useful message.
194
+ */
195
+ export async function deleteCredentials(profile) {
196
+ const target = credentialsFilePath(profile);
197
+ try {
198
+ await fs.unlink(target);
199
+ return true;
200
+ }
201
+ catch (err) {
202
+ if (err.code === 'ENOENT')
203
+ return false;
204
+ throw err;
205
+ }
206
+ }
207
+ /** Friendly message shown when no API key is configured. */
208
+ export const MISSING_API_KEY_MESSAGE = `No API key found.
209
+
210
+ Run \`sprigr login\` to authenticate via the portal, or set
211
+ SPRIGR_API_KEY in your shell:
212
+
213
+ export SPRIGR_API_KEY=sk_mcp_xxxxx
214
+
215
+ You can also pass --api-key on the command line. Manage keys at
216
+ team.sprigr.com under Settings → API keys.
217
+
218
+ To log in to a specific tenant without overwriting another, use a profile:
219
+
220
+ sprigr login --profile staging --endpoint staging
221
+ sprigr login --profile prod --endpoint prod
222
+ sprigr --profile staging app publish --dir <dir>
223
+ SPRIGR_PROFILE=prod sprigr app publish --dir <dir>
224
+ `;
225
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
package/dist/bin.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * sprigr — Sprigr Team CLI.
4
+ *
5
+ * Subcommands:
6
+ * sprigr deploy <siteId> --dir <dir> [--framework static|next|astro|remix] [--endpoint <url>] [--api-key <key>]
7
+ * sprigr builds list <siteId> [--limit N] [--endpoint <url>] [--api-key <key>]
8
+ * sprigr builds get <siteId> <buildId> [--endpoint <url>] [--api-key <key>]
9
+ *
10
+ * Auth: SPRIGR_API_KEY env var (or --api-key). Create a key in the portal
11
+ * under Settings → API keys. PKCE login is on the roadmap.
12
+ *
13
+ * Endpoint: defaults to api.team.sprigr.com. Override with --endpoint or
14
+ * SPRIGR_ENDPOINT (also accepts the literals `staging` / `prod`).
15
+ *
16
+ * Multi-tenant: pass `--profile <name>` (or set `SPRIGR_PROFILE=<name>`) to
17
+ * use a profile-scoped credentials file. Each profile stores its own
18
+ * endpoint + key, so staging and prod (or two different tenants) can be
19
+ * logged in at the same time without overwriting each other.
20
+ */
21
+ export {};
package/dist/bin.js ADDED
@@ -0,0 +1,300 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * sprigr — Sprigr Team CLI.
4
+ *
5
+ * Subcommands:
6
+ * sprigr deploy <siteId> --dir <dir> [--framework static|next|astro|remix] [--endpoint <url>] [--api-key <key>]
7
+ * sprigr builds list <siteId> [--limit N] [--endpoint <url>] [--api-key <key>]
8
+ * sprigr builds get <siteId> <buildId> [--endpoint <url>] [--api-key <key>]
9
+ *
10
+ * Auth: SPRIGR_API_KEY env var (or --api-key). Create a key in the portal
11
+ * under Settings → API keys. PKCE login is on the roadmap.
12
+ *
13
+ * Endpoint: defaults to api.team.sprigr.com. Override with --endpoint or
14
+ * SPRIGR_ENDPOINT (also accepts the literals `staging` / `prod`).
15
+ *
16
+ * Multi-tenant: pass `--profile <name>` (or set `SPRIGR_PROFILE=<name>`) to
17
+ * use a profile-scoped credentials file. Each profile stores its own
18
+ * endpoint + key, so staging and prod (or two different tenants) can be
19
+ * logged in at the same time without overwriting each other.
20
+ */
21
+ import { resolveEndpoint, resolveProfile } from './config.js';
22
+ import { resolveApiKey, MISSING_API_KEY_MESSAGE } from './auth.js';
23
+ import { runDeploy } from './commands/deploy.js';
24
+ import { runBuildsList, runBuildsGet } from './commands/builds.js';
25
+ import { runLogin, runLogout } from './commands/login.js';
26
+ import { runAppDelete, runAppInstall, runAppPublish, runAppSetPublisherSecrets, runAppShare, runAppUpgrade, runAppValidate } from './commands/app.js';
27
+ import { runWhoami } from './commands/whoami.js';
28
+ function parseArgs(argv) {
29
+ const positional = [];
30
+ const flags = {};
31
+ for (let i = 0; i < argv.length; i++) {
32
+ const arg = argv[i];
33
+ if (arg === undefined)
34
+ continue;
35
+ if (arg.startsWith('--')) {
36
+ const eq = arg.indexOf('=');
37
+ if (eq >= 0) {
38
+ flags[arg.slice(2, eq)] = arg.slice(eq + 1);
39
+ }
40
+ else {
41
+ const next = argv[i + 1];
42
+ if (next !== undefined && !next.startsWith('-')) {
43
+ flags[arg.slice(2)] = next;
44
+ i++;
45
+ }
46
+ else {
47
+ flags[arg.slice(2)] = '';
48
+ }
49
+ }
50
+ continue;
51
+ }
52
+ positional.push(arg);
53
+ }
54
+ return { positional, flags };
55
+ }
56
+ function usage() {
57
+ return `sprigr — Sprigr Team CLI
58
+
59
+ Commands:
60
+ sprigr login [--profile <name>] [--no-browser]
61
+ sprigr logout [--profile <name>]
62
+ sprigr whoami [--profile <name>] [--all]
63
+ sprigr deploy <siteId> --dir <dir> [--framework static]
64
+ sprigr builds list <siteId> [--limit N]
65
+ sprigr builds get <siteId> <buildId> [--no-log]
66
+ sprigr app validate --dir <dir> [--manifest <path>]
67
+ sprigr app publish --dir <dir> [--manifest <path>]
68
+ sprigr app upgrade <slug>
69
+ sprigr app delete <slug> --yes
70
+ sprigr app install <slug> --scopes <list> [--secrets '<json>']
71
+ sprigr app share <slug>
72
+ sprigr app set-publisher-secrets <slug> --secrets '<json>'
73
+
74
+ Common flags:
75
+ --profile <name> Use a profile-scoped credentials file (or SPRIGR_PROFILE)
76
+ --endpoint <url> Override API endpoint (or SPRIGR_ENDPOINT, or 'staging'/'prod')
77
+ --api-key <key> Sprigr API key (or SPRIGR_API_KEY env var)
78
+ --help Show this help
79
+
80
+ Multi-tenant example — staging and prod side-by-side, neither overwrites:
81
+
82
+ sprigr login --profile staging --endpoint staging
83
+ sprigr login --profile prod --endpoint prod
84
+ sprigr --profile staging app publish --dir apps/foo
85
+ SPRIGR_PROFILE=prod sprigr app publish --dir apps/foo
86
+ `;
87
+ }
88
+ async function main() {
89
+ const argv = process.argv.slice(2);
90
+ const { positional, flags } = parseArgs(argv);
91
+ if ('help' in flags || positional.length === 0) {
92
+ process.stdout.write(usage());
93
+ return positional.length === 0 ? 1 : 0;
94
+ }
95
+ let profile;
96
+ try {
97
+ profile = resolveProfile({ flag: flags.profile });
98
+ }
99
+ catch (err) {
100
+ process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`);
101
+ return 2;
102
+ }
103
+ const endpoint = resolveEndpoint({ flag: flags.endpoint, profile });
104
+ const cmd = positional[0];
105
+ // login + logout are the only commands that don't require an existing
106
+ // API key — login produces one, logout removes one. Run before the
107
+ // resolveApiKey gate.
108
+ if (cmd === 'login') {
109
+ const r = await runLogin({
110
+ endpoint,
111
+ profile,
112
+ noBrowser: 'no-browser' in flags,
113
+ });
114
+ return r.exitCode;
115
+ }
116
+ if (cmd === 'logout') {
117
+ const r = await runLogout({ profile });
118
+ return r.exitCode;
119
+ }
120
+ if (cmd === 'whoami') {
121
+ const r = await runWhoami({ profile, all: 'all' in flags });
122
+ return r.exitCode;
123
+ }
124
+ // `app validate` doesn't need an API key — it's a pure local check.
125
+ if (cmd === 'app' && positional[1] === 'validate') {
126
+ const dir = flags.dir;
127
+ if (!dir) {
128
+ process.stderr.write(`usage: sprigr app validate --dir <dir> [--manifest <path>]\n`);
129
+ return 2;
130
+ }
131
+ const r = await runAppValidate({ dir, manifestPath: flags.manifest });
132
+ return r.exitCode;
133
+ }
134
+ const apiKey = resolveApiKey({ flag: flags['api-key'], profile });
135
+ if (!apiKey) {
136
+ process.stderr.write(MISSING_API_KEY_MESSAGE);
137
+ return 2;
138
+ }
139
+ if (cmd === 'deploy') {
140
+ const siteId = positional[1];
141
+ const dir = flags.dir;
142
+ if (!siteId || !dir) {
143
+ process.stderr.write(`usage: sprigr deploy <siteId> --dir <dir>\n`);
144
+ return 2;
145
+ }
146
+ const framework = (flags.framework ?? 'static');
147
+ const result = await runDeploy({ siteId, dir, framework, endpoint, apiKey });
148
+ return result.exitCode;
149
+ }
150
+ if (cmd === 'app') {
151
+ const sub = positional[1];
152
+ if (sub === 'publish') {
153
+ const dir = flags.dir;
154
+ if (!dir) {
155
+ process.stderr.write(`usage: sprigr app publish --dir <dir> [--manifest <path>]\n`);
156
+ return 2;
157
+ }
158
+ const r = await runAppPublish({
159
+ dir,
160
+ manifestPath: flags.manifest,
161
+ endpoint,
162
+ apiKey,
163
+ });
164
+ return r.exitCode;
165
+ }
166
+ if (sub === 'upgrade') {
167
+ const slug = positional[2];
168
+ if (!slug) {
169
+ process.stderr.write(`usage: sprigr app upgrade <slug> [--force]\n`);
170
+ return 2;
171
+ }
172
+ const force = 'force' in flags;
173
+ const r = await runAppUpgrade({ slug, endpoint, apiKey, force });
174
+ return r.exitCode;
175
+ }
176
+ if (sub === 'delete') {
177
+ const slug = positional[2];
178
+ if (!slug) {
179
+ process.stderr.write(`usage: sprigr app delete <slug> --yes\n`);
180
+ return 2;
181
+ }
182
+ const yes = 'yes' in flags;
183
+ const r = await runAppDelete({ slug, endpoint, apiKey, yes });
184
+ return r.exitCode;
185
+ }
186
+ if (sub === 'install') {
187
+ const slug = positional[2];
188
+ if (!slug) {
189
+ process.stderr.write(`usage: sprigr app install <slug> --scopes <list> [--secrets '<json>']\n`);
190
+ return 2;
191
+ }
192
+ const scopes = flags['scopes'];
193
+ // --secrets '<json>' accepts a JSON-encoded object of key->value
194
+ // pairs. JSON sidesteps the "commas in values" footgun a repeated
195
+ // --secret KEY=VALUE would have, at the cost of needing the caller
196
+ // to quote the JSON in their shell.
197
+ let secrets;
198
+ const rawSecrets = flags['secrets'];
199
+ if (rawSecrets) {
200
+ try {
201
+ const parsed = JSON.parse(rawSecrets);
202
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
203
+ process.stderr.write(`--secrets must be a JSON object like {"KEY":"value"}\n`);
204
+ return 2;
205
+ }
206
+ secrets = {};
207
+ for (const [k, v] of Object.entries(parsed)) {
208
+ if (typeof v !== 'string') {
209
+ process.stderr.write(`--secrets value for "${k}" must be a string (got ${typeof v})\n`);
210
+ return 2;
211
+ }
212
+ secrets[k] = v;
213
+ }
214
+ }
215
+ catch (err) {
216
+ process.stderr.write(`--secrets must be valid JSON: ${err.message}\n`);
217
+ return 2;
218
+ }
219
+ }
220
+ const r = await runAppInstall({ slug, endpoint, apiKey, scopes, secrets });
221
+ return r.exitCode;
222
+ }
223
+ if (sub === 'share') {
224
+ const slug = positional[2];
225
+ if (!slug) {
226
+ process.stderr.write(`usage: sprigr app share <slug>\n`);
227
+ return 2;
228
+ }
229
+ const r = await runAppShare({ slug, endpoint, apiKey });
230
+ return r.exitCode;
231
+ }
232
+ if (sub === 'set-publisher-secrets') {
233
+ const slug = positional[2];
234
+ if (!slug) {
235
+ process.stderr.write(`usage: sprigr app set-publisher-secrets <slug> --secrets '<json>'\n`);
236
+ return 2;
237
+ }
238
+ const rawSecrets = flags['secrets'];
239
+ if (!rawSecrets) {
240
+ process.stderr.write(`--secrets is required. Pass a JSON object like {"SHOPIFY_CLIENT_ID":"...","SHOPIFY_CLIENT_SECRET":"..."}\n`);
241
+ return 2;
242
+ }
243
+ let secrets;
244
+ try {
245
+ const parsed = JSON.parse(rawSecrets);
246
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
247
+ process.stderr.write(`--secrets must be a JSON object like {"KEY":"value"}\n`);
248
+ return 2;
249
+ }
250
+ secrets = {};
251
+ for (const [k, v] of Object.entries(parsed)) {
252
+ if (typeof v !== 'string' || v.length === 0) {
253
+ process.stderr.write(`--secrets value for "${k}" must be a non-empty string\n`);
254
+ return 2;
255
+ }
256
+ secrets[k] = v;
257
+ }
258
+ }
259
+ catch (err) {
260
+ process.stderr.write(`--secrets must be valid JSON: ${err.message}\n`);
261
+ return 2;
262
+ }
263
+ const r = await runAppSetPublisherSecrets({ slug, endpoint, apiKey, secrets });
264
+ return r.exitCode;
265
+ }
266
+ process.stderr.write(`unknown subcommand: app ${sub}\n`);
267
+ return 2;
268
+ }
269
+ if (cmd === 'builds') {
270
+ const sub = positional[1];
271
+ if (sub === 'list') {
272
+ const siteId = positional[2];
273
+ if (!siteId) {
274
+ process.stderr.write(`usage: sprigr builds list <siteId> [--limit N]\n`);
275
+ return 2;
276
+ }
277
+ const limit = flags.limit ? Number.parseInt(flags.limit, 10) : 20;
278
+ return runBuildsList({ siteId, endpoint, apiKey, limit });
279
+ }
280
+ if (sub === 'get') {
281
+ const siteId = positional[2];
282
+ const buildId = positional[3];
283
+ if (!siteId || !buildId) {
284
+ process.stderr.write(`usage: sprigr builds get <siteId> <buildId>\n`);
285
+ return 2;
286
+ }
287
+ const showLog = !('no-log' in flags);
288
+ return runBuildsGet({ siteId, buildId, endpoint, apiKey, showLog });
289
+ }
290
+ process.stderr.write(`unknown subcommand: builds ${sub}\n`);
291
+ return 2;
292
+ }
293
+ process.stderr.write(`unknown command: ${cmd}\n${usage()}`);
294
+ return 2;
295
+ }
296
+ main().then((code) => process.exit(code), (err) => {
297
+ process.stderr.write(`fatal: ${err instanceof Error ? err.stack ?? err.message : String(err)}\n`);
298
+ process.exit(1);
299
+ });
300
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Walk a directory and produce a `{ path: SourceFile }` map suitable for
3
+ * the start-build API body.
4
+ *
5
+ * The wire shape is a tagged union per file so that text and binary assets
6
+ * can ride the same JSON envelope:
7
+ * - UTF-8 text → bare string (back-compat with the original shape)
8
+ * - Binary → `{ encoding: 'base64', content: '<base64>' }`
9
+ *
10
+ * Rationale: the build container's BuildArtifact output already supports
11
+ * base64 (png/woff2/etc. are emitted that way for the post-build R2
12
+ * upload). Extending the *input* side closes the loop so a customer with
13
+ * `public/logo.png` doesn't get a "non-UTF-8 bytes" rejection at bundle
14
+ * time. The decoded byte length still counts against the 5 MiB-per-file
15
+ * and 500-files-per-build caps — the inflated base64 string isn't what
16
+ * the server enforces against.
17
+ *
18
+ * Constraints (mirror the server side at workers/provisioning/src/build-routes.ts):
19
+ * - Caller-passed `dir` must contain index.html.
20
+ * - Maximum 500 files per build.
21
+ * - Each file capped at 5 MiB of *decoded* bytes (5 * 1024 * 1024).
22
+ *
23
+ * Default ignores: `node_modules/`, `.git/`, `.DS_Store`, anything starting
24
+ * with `.` at the top level (dotfiles often hold secrets), plus what's in a
25
+ * `.sprigrignore` if present (one glob/literal per line; `#` comments).
26
+ *
27
+ * Returns an object instead of throwing so callers can present a single
28
+ * grouped error message rather than a stack trace.
29
+ */
30
+ export type SourceFile = string | {
31
+ encoding: 'base64';
32
+ content: string;
33
+ };
34
+ export interface BundleResult {
35
+ files: Record<string, SourceFile>;
36
+ /** Sum of decoded bytes (i.e. raw on-disk file size, not the base64
37
+ * inflation). What the server's cap is enforced against. */
38
+ totalBytes: number;
39
+ fileCount: number;
40
+ /** How many entries in `files` ride as base64. Useful for the deploy
41
+ * command's progress line — telegraphs the binary footprint without
42
+ * forcing the caller to re-walk the map. */
43
+ binaryCount: number;
44
+ }
45
+ export interface BundleError {
46
+ errors: string[];
47
+ }
48
+ export type BundleFramework = 'static' | 'next' | 'astro' | 'remix';
49
+ export declare function bundleDirectory(rootDir: string, framework?: BundleFramework): Promise<BundleResult | BundleError>;