@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/README.md +84 -0
- package/dist/api.d.ts +234 -0
- package/dist/api.js +220 -0
- package/dist/api.js.map +1 -0
- package/dist/auth.d.ts +103 -0
- package/dist/auth.js +225 -0
- package/dist/auth.js.map +1 -0
- package/dist/bin.d.ts +21 -0
- package/dist/bin.js +300 -0
- package/dist/bin.js.map +1 -0
- package/dist/bundler.d.ts +49 -0
- package/dist/bundler.js +123 -0
- package/dist/bundler.js.map +1 -0
- package/dist/commands/app.d.ts +223 -0
- package/dist/commands/app.js +539 -0
- package/dist/commands/app.js.map +1 -0
- package/dist/commands/builds.d.ts +22 -0
- package/dist/commands/builds.js +76 -0
- package/dist/commands/builds.js.map +1 -0
- package/dist/commands/deploy.d.ts +32 -0
- package/dist/commands/deploy.js +96 -0
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/login.d.ts +54 -0
- package/dist/commands/login.js +192 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/whoami.d.ts +10 -0
- package/dist/commands/whoami.js +54 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/config.d.ts +23 -0
- package/dist/config.js +65 -0
- package/dist/config.js.map +1 -0
- package/dist/manifest.d.ts +115 -0
- package/dist/manifest.js +262 -0
- package/dist/manifest.js.map +1 -0
- package/package.json +54 -0
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
|
package/dist/auth.js.map
ADDED
|
@@ -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
|
package/dist/bin.js.map
ADDED
|
@@ -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>;
|