@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
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sprigr app publish` and `sprigr app validate`.
|
|
3
|
+
*
|
|
4
|
+
* Phase 2.1b of the ASCS platform implementation plan.
|
|
5
|
+
*
|
|
6
|
+
* sprigr app publish --dir <bundle-dir> [--manifest <path>]
|
|
7
|
+
* Reads the manifest, runs publish-time validation locally, bundles
|
|
8
|
+
* the directory the same way `sprigr deploy` does, and POSTs to
|
|
9
|
+
* /api/v1/data/marketplace/apps/publish. The server re-validates +
|
|
10
|
+
* stores the version + triggers the build-runner. We intentionally
|
|
11
|
+
* run validation client-side too — the publish API is slow (uploads
|
|
12
|
+
* a bundle to R2) so a clear local error beats a server round-trip.
|
|
13
|
+
*
|
|
14
|
+
* sprigr app validate --dir <bundle-dir> [--manifest <path>]
|
|
15
|
+
* Same validation as publish, no upload. Suitable for CI / local dev.
|
|
16
|
+
*
|
|
17
|
+
* Manifest format note (v1):
|
|
18
|
+
* The plan calls for sprigr-app.yaml. The CLI v1 ships with JSON
|
|
19
|
+
* support only (sprigr-app.json) so the npm-published bundle stays
|
|
20
|
+
* dependency-light. YAML support is a follow-up that adds the `yaml`
|
|
21
|
+
* package and detects sprigr-app.yaml in addition to sprigr-app.json.
|
|
22
|
+
* Server-side handling is unchanged either way — the wire payload is
|
|
23
|
+
* always JSON.
|
|
24
|
+
*
|
|
25
|
+
* Why the manifest is read separately from the bundle dir:
|
|
26
|
+
* The bundler walks the dir and uploads every file under it, so the
|
|
27
|
+
* manifest naturally lands in the bundle too — but we ALSO need the
|
|
28
|
+
* parsed manifest object to validate locally and to send as a separate
|
|
29
|
+
* field on the publish payload (the server reads it from there to
|
|
30
|
+
* route the build, not by parsing the bundle). Hence a separate read.
|
|
31
|
+
*/
|
|
32
|
+
import { promises as fs } from 'node:fs';
|
|
33
|
+
import path from 'node:path';
|
|
34
|
+
import { validateAppDependencies, validateCrossTenantTools, validateMigrations, validateRuntimeTier, validateSchedules, validateAgentSchedules, validateSecrets, validateWebhooks, } from '../manifest.js';
|
|
35
|
+
import { bundleDirectory } from '../bundler.js';
|
|
36
|
+
import { ApiClient, ApiError } from '../api.js';
|
|
37
|
+
/**
|
|
38
|
+
* Read + parse the manifest. Defaults to `<dir>/sprigr-app.json`. Returns
|
|
39
|
+
* a structured error object on failure so the caller can surface a clean
|
|
40
|
+
* message rather than a stack trace.
|
|
41
|
+
*/
|
|
42
|
+
export async function loadManifest(args) {
|
|
43
|
+
const resolvedPath = args.manifestPath
|
|
44
|
+
? path.resolve(args.manifestPath)
|
|
45
|
+
: path.resolve(args.dir, 'sprigr-app.json');
|
|
46
|
+
let raw;
|
|
47
|
+
try {
|
|
48
|
+
raw = await fs.readFile(resolvedPath, 'utf-8');
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
return {
|
|
52
|
+
error: `Could not read manifest at ${resolvedPath}: ${err instanceof Error ? err.message : String(err)}`,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
let parsed;
|
|
56
|
+
try {
|
|
57
|
+
parsed = JSON.parse(raw);
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
return {
|
|
61
|
+
error: `Manifest at ${resolvedPath} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
65
|
+
return { error: `Manifest at ${resolvedPath} must be a JSON object` };
|
|
66
|
+
}
|
|
67
|
+
return { manifest: parsed, resolvedPath };
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Run the publish-time validators against a parsed manifest. Mirrors
|
|
71
|
+
* the server's validateManifest in workers/provisioning so that local
|
|
72
|
+
* `app validate` produces the same verdict the publish API would. The
|
|
73
|
+
* legacy fields (sprigr_app, metadata, etc.) are checked here too —
|
|
74
|
+
* the shared package's per-field validators only cover the new
|
|
75
|
+
* marketplace-hosting fields.
|
|
76
|
+
*/
|
|
77
|
+
export function validateManifestLocally(manifest) {
|
|
78
|
+
if (!manifest.sprigr_app?.version)
|
|
79
|
+
return 'Missing sprigr_app.version';
|
|
80
|
+
if (!manifest.metadata?.name)
|
|
81
|
+
return 'Missing metadata.name';
|
|
82
|
+
if (!manifest.metadata?.slug)
|
|
83
|
+
return 'Missing metadata.slug';
|
|
84
|
+
if (!manifest.metadata?.version)
|
|
85
|
+
return 'Missing metadata.version';
|
|
86
|
+
if (!manifest.metadata?.description)
|
|
87
|
+
return 'Missing metadata.description';
|
|
88
|
+
if (!manifest.metadata?.author?.name)
|
|
89
|
+
return 'Missing metadata.author.name';
|
|
90
|
+
// Tier + framework are part of the new hosting schema; their absence is
|
|
91
|
+
// accepted (defaults applied later).
|
|
92
|
+
const tierErr = validateRuntimeTier(manifest.runtime?.tier);
|
|
93
|
+
if (tierErr)
|
|
94
|
+
return tierErr;
|
|
95
|
+
// Cross-tenant tools / app deps / migrations / secrets / schedules /
|
|
96
|
+
// webhooks share validators with the server.
|
|
97
|
+
const ctErr = validateCrossTenantTools(manifest.cross_tenant_tools);
|
|
98
|
+
if (ctErr)
|
|
99
|
+
return ctErr;
|
|
100
|
+
const depsErr = validateAppDependencies(manifest.app_dependencies);
|
|
101
|
+
if (depsErr)
|
|
102
|
+
return depsErr;
|
|
103
|
+
const migErr = validateMigrations(manifest.migrations);
|
|
104
|
+
if (migErr)
|
|
105
|
+
return migErr;
|
|
106
|
+
const secErr = validateSecrets(manifest.secrets);
|
|
107
|
+
if (secErr)
|
|
108
|
+
return secErr;
|
|
109
|
+
const declaredSecretKeys = new Set((manifest.secrets ?? []).map((s) => s.key));
|
|
110
|
+
const whErr = validateWebhooks(manifest.webhooks, declaredSecretKeys);
|
|
111
|
+
if (whErr)
|
|
112
|
+
return whErr;
|
|
113
|
+
const schErr = validateSchedules(manifest.schedules);
|
|
114
|
+
if (schErr)
|
|
115
|
+
return schErr;
|
|
116
|
+
const agentSchErr = validateAgentSchedules(manifest.agent_schedules);
|
|
117
|
+
if (agentSchErr)
|
|
118
|
+
return agentSchErr;
|
|
119
|
+
// Cross-validate that every declared migration file actually exists in
|
|
120
|
+
// the bundle is the publish flow's job (it has the file map). At
|
|
121
|
+
// validate time we don't have that, so we stop here.
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Per-framework filesystem checks (#1022). Runs after manifest validation
|
|
126
|
+
* and BEFORE bundle upload, so authors hear about missing required files
|
|
127
|
+
* locally instead of after the round-trip through publish → build → install
|
|
128
|
+
* → failure. Currently only Next.js has a checkable contract; other
|
|
129
|
+
* frameworks return null.
|
|
130
|
+
*
|
|
131
|
+
* Async because the check stats the customer's bundle dir for the
|
|
132
|
+
* required config files. Returns null on success or an error message
|
|
133
|
+
* suitable for stderr.
|
|
134
|
+
*/
|
|
135
|
+
export async function validateFrameworkFiles(manifest, dir) {
|
|
136
|
+
if (manifest.runtime?.framework !== 'next')
|
|
137
|
+
return null;
|
|
138
|
+
const exists = async (relPath) => {
|
|
139
|
+
try {
|
|
140
|
+
await fs.access(path.join(dir, relPath));
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
// open-next.config.ts is non-optional in @opennextjs/cloudflare: the
|
|
148
|
+
// build dies with `No \`open-next.config.ts\` file was found in the
|
|
149
|
+
// project root.` when it's missing. There is no .js/.mjs fallback.
|
|
150
|
+
if (!(await exists('open-next.config.ts'))) {
|
|
151
|
+
return 'missing open-next.config.ts — required by the OpenNext-Cloudflare build pipeline. Run `npx opennextjs-cloudflare migrate` in your app dir to generate one.';
|
|
152
|
+
}
|
|
153
|
+
// next.config can be .js / .mjs / .ts (Next.js accepts any of the three).
|
|
154
|
+
// Require at least one.
|
|
155
|
+
const nextConfigVariants = ['next.config.js', 'next.config.mjs', 'next.config.ts'];
|
|
156
|
+
const found = await Promise.all(nextConfigVariants.map(exists));
|
|
157
|
+
if (!found.some(Boolean)) {
|
|
158
|
+
return `missing next.config.{js,mjs,ts} — Next.js requires one at the project root. Got none of: ${nextConfigVariants.join(', ')}.`;
|
|
159
|
+
}
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
export async function runAppValidate(args) {
|
|
163
|
+
const loaded = await loadManifest({ dir: args.dir, manifestPath: args.manifestPath });
|
|
164
|
+
if ('error' in loaded) {
|
|
165
|
+
process.stderr.write(`${loaded.error}\n`);
|
|
166
|
+
return { exitCode: 2 };
|
|
167
|
+
}
|
|
168
|
+
const err = validateManifestLocally(loaded.manifest);
|
|
169
|
+
if (err) {
|
|
170
|
+
process.stderr.write(`Manifest validation failed: ${err}\n`);
|
|
171
|
+
return { exitCode: 1 };
|
|
172
|
+
}
|
|
173
|
+
const fsErr = await validateFrameworkFiles(loaded.manifest, args.dir);
|
|
174
|
+
if (fsErr) {
|
|
175
|
+
process.stderr.write(`Framework file check failed: ${fsErr}\n`);
|
|
176
|
+
return { exitCode: 1 };
|
|
177
|
+
}
|
|
178
|
+
process.stdout.write(`Manifest OK — ${loaded.manifest.metadata.slug}@${loaded.manifest.metadata.version}\n`);
|
|
179
|
+
return { exitCode: 0 };
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Cross-validate that every file referenced by manifest.migrations[]
|
|
183
|
+
* actually rides in the bundle. Mirrors what the server does at upload
|
|
184
|
+
* time so the CLI can surface a clear local error before the round trip.
|
|
185
|
+
*/
|
|
186
|
+
function validateMigrationFilesInBundle(manifest, bundle) {
|
|
187
|
+
if (!manifest.migrations || manifest.migrations.length === 0)
|
|
188
|
+
return null;
|
|
189
|
+
for (const m of manifest.migrations) {
|
|
190
|
+
if (!(m.file in bundle.files)) {
|
|
191
|
+
return `Manifest references migration file "${m.file}" but it is not in the bundle`;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
export async function runAppPublish(args) {
|
|
197
|
+
const loaded = await loadManifest({ dir: args.dir, manifestPath: args.manifestPath });
|
|
198
|
+
if ('error' in loaded) {
|
|
199
|
+
process.stderr.write(`${loaded.error}\n`);
|
|
200
|
+
return { exitCode: 2 };
|
|
201
|
+
}
|
|
202
|
+
const validationErr = validateManifestLocally(loaded.manifest);
|
|
203
|
+
if (validationErr) {
|
|
204
|
+
process.stderr.write(`Manifest validation failed: ${validationErr}\n`);
|
|
205
|
+
return { exitCode: 1 };
|
|
206
|
+
}
|
|
207
|
+
const fsErr = await validateFrameworkFiles(loaded.manifest, args.dir);
|
|
208
|
+
if (fsErr) {
|
|
209
|
+
process.stderr.write(`Framework file check failed: ${fsErr}\n`);
|
|
210
|
+
return { exitCode: 1 };
|
|
211
|
+
}
|
|
212
|
+
// The bundler treats the manifest like any other file (it gets
|
|
213
|
+
// uploaded), but we also send the parsed object as a top-level field
|
|
214
|
+
// on the publish payload so the server doesn't have to re-parse the
|
|
215
|
+
// bundle to route the build.
|
|
216
|
+
//
|
|
217
|
+
// Framework is resolved from manifest.runtime.framework: a Next.js / Astro
|
|
218
|
+
// / Remix bundle is the SOURCE (the build container produces index.html),
|
|
219
|
+
// so the bundler enforces `package.json` instead of `index.html`. Without
|
|
220
|
+
// this read the bundler always treated the bundle as static and rejected
|
|
221
|
+
// any SSR app for "Missing index.html" — caught during the hello-
|
|
222
|
+
// marketplace shakedown 2026-05-11.
|
|
223
|
+
const framework = loaded.manifest.runtime?.framework ?? 'static';
|
|
224
|
+
const bundle = await bundleDirectory(args.dir, framework);
|
|
225
|
+
if ('errors' in bundle) {
|
|
226
|
+
for (const e of bundle.errors)
|
|
227
|
+
process.stderr.write(`${e}\n`);
|
|
228
|
+
return { exitCode: 1 };
|
|
229
|
+
}
|
|
230
|
+
const migsErr = validateMigrationFilesInBundle(loaded.manifest, bundle);
|
|
231
|
+
if (migsErr) {
|
|
232
|
+
process.stderr.write(`${migsErr}\n`);
|
|
233
|
+
return { exitCode: 1 };
|
|
234
|
+
}
|
|
235
|
+
process.stdout.write(`Publishing ${loaded.manifest.metadata.slug}@${loaded.manifest.metadata.version} ` +
|
|
236
|
+
`(${bundle.fileCount} files, ${(bundle.totalBytes / 1024).toFixed(1)} KiB` +
|
|
237
|
+
`${bundle.binaryCount > 0 ? `, ${bundle.binaryCount} binary` : ''})…\n`);
|
|
238
|
+
const client = new ApiClient({
|
|
239
|
+
endpoint: args.endpoint,
|
|
240
|
+
apiKey: args.apiKey,
|
|
241
|
+
fetchImpl: args.fetchImpl,
|
|
242
|
+
});
|
|
243
|
+
try {
|
|
244
|
+
const result = await client.publishMarketplaceApp({
|
|
245
|
+
manifest: loaded.manifest,
|
|
246
|
+
files: bundle.files,
|
|
247
|
+
});
|
|
248
|
+
process.stdout.write(`Published version ${result.version} of ${result.slug}` +
|
|
249
|
+
(result.buildId ? ` (build ${result.buildId})` : '') +
|
|
250
|
+
'\n');
|
|
251
|
+
// Partial-fanout warning. Surfaced here because the publish 201 still
|
|
252
|
+
// succeeds even when some tracking installs failed to enqueue a build —
|
|
253
|
+
// those installs are now pinned to the new version but still serving the
|
|
254
|
+
// old WFP bundle. Recovery is `sprigr app upgrade <slug> --force` on the
|
|
255
|
+
// affected tenant (or for cross-publisher recovery, grep system_logs AE
|
|
256
|
+
// for `marketplace.upgrade.fanout_failed` / `*.fanout_threw` filtered by
|
|
257
|
+
// `app_slug`). We don't fail the exit code — the version itself
|
|
258
|
+
// published successfully, the publisher just needs to follow up.
|
|
259
|
+
if (result.fanout) {
|
|
260
|
+
if (result.fanout.threw) {
|
|
261
|
+
process.stderr.write(`Warning: auto-upgrade fan-out threw: ${result.fanout.threw}. ` +
|
|
262
|
+
`Check system_logs AE for marketplace.upgrade.fanout_threw, ` +
|
|
263
|
+
`then run \`sprigr app upgrade ${result.slug} --force\` ` +
|
|
264
|
+
`on affected tenants.\n`);
|
|
265
|
+
}
|
|
266
|
+
else if (result.fanout.failed > 0) {
|
|
267
|
+
process.stderr.write(`Warning: auto-upgrade fan-out partial — ` +
|
|
268
|
+
`${result.fanout.upgraded} upgraded, ${result.fanout.failed} failed. ` +
|
|
269
|
+
`Failed installs are pinned to ${result.version} but still serving the old bundle. ` +
|
|
270
|
+
`Recover with \`sprigr app upgrade ${result.slug} --force\` ` +
|
|
271
|
+
`or grep system_logs AE for marketplace.upgrade.fanout_failed.\n`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return { exitCode: 0 };
|
|
275
|
+
}
|
|
276
|
+
catch (err) {
|
|
277
|
+
if (err instanceof ApiError) {
|
|
278
|
+
process.stderr.write(`Publish failed: HTTP ${err.status} — ${err.message}\n`);
|
|
279
|
+
return { exitCode: 1 };
|
|
280
|
+
}
|
|
281
|
+
process.stderr.write(`Publish failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
282
|
+
return { exitCode: 1 };
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* `sprigr app upgrade <slug>` — manually bump this company's install of
|
|
287
|
+
* a marketplace app to the latest approved version. Hits
|
|
288
|
+
* POST /api/v1/data/apps/:slug/install/upgrade which:
|
|
289
|
+
* 1. Bumps `pinned_version_id` to current_version
|
|
290
|
+
* 2. Refreshes the integration row's snapshot manifest
|
|
291
|
+
* 3. Syncs the company's integration KV cache + reinits agent DOs
|
|
292
|
+
* 4. Enqueues a fresh build via `enqueueBuildForMarketplaceVersion`
|
|
293
|
+
*
|
|
294
|
+
* Returns the buildId for status polling. Idempotent — returns HTTP 400
|
|
295
|
+
* "Already on latest version" if the install is already pinned to the
|
|
296
|
+
* current version.
|
|
297
|
+
*
|
|
298
|
+
* Use this to recover from a silent publish-fanout enqueue failure (the
|
|
299
|
+
* symptom: a fresh version exists in `current_version` but no
|
|
300
|
+
* publish-fanout build appears in website_status after the publish).
|
|
301
|
+
*/
|
|
302
|
+
export async function runAppUpgrade(args) {
|
|
303
|
+
if (!args.slug) {
|
|
304
|
+
process.stderr.write('Missing app slug. Usage: sprigr app upgrade <slug>\n');
|
|
305
|
+
return { exitCode: 2 };
|
|
306
|
+
}
|
|
307
|
+
const client = new ApiClient({
|
|
308
|
+
endpoint: args.endpoint,
|
|
309
|
+
apiKey: args.apiKey,
|
|
310
|
+
fetchImpl: args.fetchImpl,
|
|
311
|
+
});
|
|
312
|
+
try {
|
|
313
|
+
const result = await client.upgradeMarketplaceInstall({ appSlug: args.slug, force: args.force });
|
|
314
|
+
process.stdout.write(`Upgrading ${args.slug} install to ${result.newVersion} (build ${result.buildId}). ` +
|
|
315
|
+
`Poll \`sprigr builds get <siteId> ${result.buildId}\` for completion.\n`);
|
|
316
|
+
return { exitCode: 0 };
|
|
317
|
+
}
|
|
318
|
+
catch (err) {
|
|
319
|
+
if (err instanceof ApiError) {
|
|
320
|
+
// 400 "Already on latest version" is a benign no-op; surface it
|
|
321
|
+
// explicitly but exit non-zero so scripts can detect it.
|
|
322
|
+
process.stderr.write(`Upgrade failed: HTTP ${err.status} — ${err.message}\n`);
|
|
323
|
+
return { exitCode: err.status === 400 ? 0 : 1 };
|
|
324
|
+
}
|
|
325
|
+
process.stderr.write(`Upgrade failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
326
|
+
return { exitCode: 1 };
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* `sprigr app delete <slug>` — hard-delete a marketplace app + all its
|
|
331
|
+
* versions + any leftover install rows owned by the publisher. Releases
|
|
332
|
+
* the slug for re-publication.
|
|
333
|
+
*
|
|
334
|
+
* Use this when migrating an app between publishers (personal staging
|
|
335
|
+
* → sprigr-hq, etc.). The runbook lives at
|
|
336
|
+
* sprigr-apps/docs/migrate-app-publisher.md — uninstall on every
|
|
337
|
+
* installer tenant first, THEN delete from the old publisher, THEN
|
|
338
|
+
* re-publish under the new publisher.
|
|
339
|
+
*
|
|
340
|
+
* The endpoint hard-deletes everything: all marketplace_app_versions
|
|
341
|
+
* rows, R2 bundle objects, any orphaned app_installations. Only the
|
|
342
|
+
* current publisher can call it (403 otherwise).
|
|
343
|
+
*
|
|
344
|
+
* Pass --yes to skip the confirmation prompt. CI / non-interactive
|
|
345
|
+
* callers must always pass --yes.
|
|
346
|
+
*/
|
|
347
|
+
export async function runAppDelete(args) {
|
|
348
|
+
if (!args.slug) {
|
|
349
|
+
process.stderr.write('Missing app slug. Usage: sprigr app delete <slug> [--yes]\n');
|
|
350
|
+
return { exitCode: 2 };
|
|
351
|
+
}
|
|
352
|
+
if (!args.yes) {
|
|
353
|
+
process.stderr.write(`Refusing to delete "${args.slug}" without --yes. This is a hard delete: every version, every R2 bundle, every install row this publisher owns is destroyed.\n`);
|
|
354
|
+
return { exitCode: 2 };
|
|
355
|
+
}
|
|
356
|
+
const client = new ApiClient({
|
|
357
|
+
endpoint: args.endpoint,
|
|
358
|
+
apiKey: args.apiKey,
|
|
359
|
+
fetchImpl: args.fetchImpl,
|
|
360
|
+
});
|
|
361
|
+
try {
|
|
362
|
+
await client.deleteMarketplaceApp({ appSlug: args.slug });
|
|
363
|
+
process.stdout.write(`Deleted ${args.slug}. Slug released; you can now republish under a different publisher.\n`);
|
|
364
|
+
return { exitCode: 0 };
|
|
365
|
+
}
|
|
366
|
+
catch (err) {
|
|
367
|
+
if (err instanceof ApiError) {
|
|
368
|
+
const hint = err.status === 403
|
|
369
|
+
? ' (caller is not the publisher; check `sprigr whoami --profile <name>`)'
|
|
370
|
+
: err.status === 404
|
|
371
|
+
? ' (slug already released)'
|
|
372
|
+
: '';
|
|
373
|
+
process.stderr.write(`Delete failed: HTTP ${err.status} — ${err.message}${hint}\n`);
|
|
374
|
+
return { exitCode: 1 };
|
|
375
|
+
}
|
|
376
|
+
process.stderr.write(`Delete failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
377
|
+
return { exitCode: 1 };
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* `sprigr app share <slug>` — generate a share token + auto-bump
|
|
382
|
+
* trust_tier from `private` to `shared`.
|
|
383
|
+
*
|
|
384
|
+
* Publisher-only. Lets other tenants in the same env install the app
|
|
385
|
+
* via their own CLI/MCP/portal without sharing the publisher's
|
|
386
|
+
* credentials. Calling again rotates the token but the trust tier
|
|
387
|
+
* stays at whatever it already is.
|
|
388
|
+
*
|
|
389
|
+
* The share URL prints to stdout (paste into a tenant browser to
|
|
390
|
+
* install via the share-link flow), but the more common path post-
|
|
391
|
+
* share is `sprigr app install <slug> --profile <other-tenant>` since
|
|
392
|
+
* trust_tier='shared' allows any tenant to install.
|
|
393
|
+
*/
|
|
394
|
+
export async function runAppShare(args) {
|
|
395
|
+
if (!args.slug) {
|
|
396
|
+
process.stderr.write('Missing app slug. Usage: sprigr app share <slug>\n');
|
|
397
|
+
return { exitCode: 2 };
|
|
398
|
+
}
|
|
399
|
+
const client = new ApiClient({
|
|
400
|
+
endpoint: args.endpoint,
|
|
401
|
+
apiKey: args.apiKey,
|
|
402
|
+
fetchImpl: args.fetchImpl,
|
|
403
|
+
});
|
|
404
|
+
try {
|
|
405
|
+
const result = await client.shareMarketplaceApp({ appSlug: args.slug });
|
|
406
|
+
process.stdout.write(`Shared ${args.slug}. trust_tier bumped to 'shared' (if previously 'private').\n` +
|
|
407
|
+
` share_token: ${result.share_token}\n` +
|
|
408
|
+
` share_url: ${result.share_url}\n`);
|
|
409
|
+
return { exitCode: 0 };
|
|
410
|
+
}
|
|
411
|
+
catch (err) {
|
|
412
|
+
if (err instanceof ApiError) {
|
|
413
|
+
const hint = err.status === 404
|
|
414
|
+
? ' (caller is not the publisher OR slug does not exist; run `sprigr whoami --profile <name>`)'
|
|
415
|
+
: '';
|
|
416
|
+
process.stderr.write(`Share failed: HTTP ${err.status} — ${err.message}${hint}\n`);
|
|
417
|
+
return { exitCode: 1 };
|
|
418
|
+
}
|
|
419
|
+
process.stderr.write(`Share failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
420
|
+
return { exitCode: 1 };
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* `sprigr app install <slug> --scopes ... [--secret KEY=VALUE ...]`
|
|
425
|
+
*
|
|
426
|
+
* Install a marketplace app on the calling tenant. Publisher-migration
|
|
427
|
+
* step 5 from sprigr-apps/docs/migrate-app-publisher.md.
|
|
428
|
+
*
|
|
429
|
+
* Body shape gotcha (documented at the runbook level too): the API is
|
|
430
|
+
* snake_case (granted_scopes, install_secrets). Sending camelCase
|
|
431
|
+
* silently parses + ignores the unknown keys → 400 "Missing required
|
|
432
|
+
* secrets". The CLI passes the right shape so callers don't have to
|
|
433
|
+
* remember.
|
|
434
|
+
*/
|
|
435
|
+
export async function runAppInstall(args) {
|
|
436
|
+
if (!args.slug) {
|
|
437
|
+
process.stderr.write('Missing app slug. Usage: sprigr app install <slug> --scopes <list> [--secret KEY=VALUE]\n');
|
|
438
|
+
return { exitCode: 2 };
|
|
439
|
+
}
|
|
440
|
+
if (!args.scopes) {
|
|
441
|
+
process.stderr.write(`Missing --scopes. Pass a comma-separated list, e.g. --scopes tools:register,knowledge:write\n`);
|
|
442
|
+
return { exitCode: 2 };
|
|
443
|
+
}
|
|
444
|
+
const grantedScopes = args.scopes.split(',').map((s) => s.trim()).filter(Boolean);
|
|
445
|
+
if (grantedScopes.length === 0) {
|
|
446
|
+
process.stderr.write('Empty --scopes list after splitting on commas.\n');
|
|
447
|
+
return { exitCode: 2 };
|
|
448
|
+
}
|
|
449
|
+
const client = new ApiClient({
|
|
450
|
+
endpoint: args.endpoint,
|
|
451
|
+
apiKey: args.apiKey,
|
|
452
|
+
fetchImpl: args.fetchImpl,
|
|
453
|
+
});
|
|
454
|
+
try {
|
|
455
|
+
const result = await client.installMarketplaceApp({
|
|
456
|
+
appSlug: args.slug,
|
|
457
|
+
grantedScopes,
|
|
458
|
+
installSecrets: args.secrets,
|
|
459
|
+
});
|
|
460
|
+
const ins = result.installation;
|
|
461
|
+
process.stdout.write(`Installed ${args.slug} → install ${ins.id}` +
|
|
462
|
+
(ins.website_slug ? ` (site ${ins.website_slug})` : '') +
|
|
463
|
+
(ins.build_id ? ` (build ${ins.build_id})` : '') +
|
|
464
|
+
'\n');
|
|
465
|
+
return { exitCode: 0 };
|
|
466
|
+
}
|
|
467
|
+
catch (err) {
|
|
468
|
+
if (err instanceof ApiError) {
|
|
469
|
+
const hint = err.status === 400 && /missing required secret/i.test(err.message)
|
|
470
|
+
? ' (the API wants snake_case secret KEYS that match manifest.secrets[].key — case-sensitive)'
|
|
471
|
+
: err.status === 403
|
|
472
|
+
? ' (caller tenant cannot install this app; private apps require publisher self-install or shared trust tier)'
|
|
473
|
+
: err.status === 404
|
|
474
|
+
? ' (app slug not found — check publisher with `sprigr whoami` then list apps via portal/MCP)'
|
|
475
|
+
: '';
|
|
476
|
+
process.stderr.write(`Install failed: HTTP ${err.status} — ${err.message}${hint}\n`);
|
|
477
|
+
return { exitCode: 1 };
|
|
478
|
+
}
|
|
479
|
+
process.stderr.write(`Install failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
480
|
+
return { exitCode: 1 };
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* `sprigr app set-publisher-secrets <slug> --secrets '<json>'`
|
|
485
|
+
*
|
|
486
|
+
* Seed or rotate the publisher-provided secret bag on the app row.
|
|
487
|
+
* The publisher's OAuth-app credentials (SHOPIFY_CLIENT_ID,
|
|
488
|
+
* SHOPIFY_CLIENT_SECRET, etc.) flow through this command — every
|
|
489
|
+
* install of the app picks them up automatically at install time.
|
|
490
|
+
*
|
|
491
|
+
* Auth: caller must be the app's publisher (the API checks
|
|
492
|
+
* publisher_company_id matches the calling tenant). Errors:
|
|
493
|
+
* - 404: caller doesn't own the app, OR slug doesn't exist
|
|
494
|
+
* - 400: a key isn't declared / isn't `publisher_provides: true` /
|
|
495
|
+
* value isn't a non-empty string
|
|
496
|
+
* - 500: WEBSITE_SECRETS_MASTER_KEY not bound on the platform
|
|
497
|
+
*
|
|
498
|
+
* No value is ever returned in plaintext from the API. Rotation =
|
|
499
|
+
* "set a new value"; there's no "show me the current value" path.
|
|
500
|
+
*/
|
|
501
|
+
export async function runAppSetPublisherSecrets(args) {
|
|
502
|
+
if (!args.slug) {
|
|
503
|
+
process.stderr.write('Missing app slug. Usage: sprigr app set-publisher-secrets <slug> --secrets \'<json>\'\n');
|
|
504
|
+
return { exitCode: 2 };
|
|
505
|
+
}
|
|
506
|
+
if (!args.secrets || Object.keys(args.secrets).length === 0) {
|
|
507
|
+
process.stderr.write('--secrets must contain at least one key (the no-op case is unsupported on the CLI to avoid silent misuse)\n');
|
|
508
|
+
return { exitCode: 2 };
|
|
509
|
+
}
|
|
510
|
+
const client = new ApiClient({
|
|
511
|
+
endpoint: args.endpoint,
|
|
512
|
+
apiKey: args.apiKey,
|
|
513
|
+
fetchImpl: args.fetchImpl,
|
|
514
|
+
});
|
|
515
|
+
try {
|
|
516
|
+
const result = await client.setMarketplaceAppPublisherSecrets({
|
|
517
|
+
appSlug: args.slug,
|
|
518
|
+
secrets: args.secrets,
|
|
519
|
+
});
|
|
520
|
+
process.stdout.write(`Set publisher secrets for ${args.slug}.\n` +
|
|
521
|
+
` updated keys: ${result.updated_keys.join(', ') || '(none)'}\n` +
|
|
522
|
+
` total stored: ${result.total_keys}\n`);
|
|
523
|
+
return { exitCode: 0 };
|
|
524
|
+
}
|
|
525
|
+
catch (err) {
|
|
526
|
+
if (err instanceof ApiError) {
|
|
527
|
+
const hint = err.status === 404
|
|
528
|
+
? ' (caller is not the publisher OR slug does not exist; run `sprigr whoami`)'
|
|
529
|
+
: err.status === 400 && /publisher_provides/i.test(err.message)
|
|
530
|
+
? ' (the manifest must declare each key with `publisher_provides: true` for this endpoint)'
|
|
531
|
+
: '';
|
|
532
|
+
process.stderr.write(`set-publisher-secrets failed: HTTP ${err.status} — ${err.message}${hint}\n`);
|
|
533
|
+
return { exitCode: 1 };
|
|
534
|
+
}
|
|
535
|
+
process.stderr.write(`set-publisher-secrets failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
536
|
+
return { exitCode: 1 };
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
//# sourceMappingURL=app.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/commands/app.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface BuildsListArgs {
|
|
2
|
+
siteId: string;
|
|
3
|
+
endpoint: string;
|
|
4
|
+
apiKey: string;
|
|
5
|
+
limit?: number;
|
|
6
|
+
log?: (line: string) => void;
|
|
7
|
+
fetchImpl?: typeof fetch;
|
|
8
|
+
}
|
|
9
|
+
export declare function runBuildsList(args: BuildsListArgs): Promise<number>;
|
|
10
|
+
export interface BuildsGetArgs {
|
|
11
|
+
siteId: string;
|
|
12
|
+
buildId: string;
|
|
13
|
+
endpoint: string;
|
|
14
|
+
apiKey: string;
|
|
15
|
+
/** When true, also fetch the captured stdout/stderr and append it after
|
|
16
|
+
* the build JSON. Default true — debugging is the dominant use case for
|
|
17
|
+
* `builds get`. Set false when scripting against the JSON shape. */
|
|
18
|
+
showLog?: boolean;
|
|
19
|
+
log?: (line: string) => void;
|
|
20
|
+
fetchImpl?: typeof fetch;
|
|
21
|
+
}
|
|
22
|
+
export declare function runBuildsGet(args: BuildsGetArgs): Promise<number>;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { ApiClient, ApiError } from '../api.js';
|
|
2
|
+
export async function runBuildsList(args) {
|
|
3
|
+
const log = args.log ?? ((line) => console.log(line));
|
|
4
|
+
const client = new ApiClient({ endpoint: args.endpoint, apiKey: args.apiKey, fetchImpl: args.fetchImpl });
|
|
5
|
+
try {
|
|
6
|
+
const { builds } = await client.listBuilds(args.siteId, args.limit ?? 20);
|
|
7
|
+
if (builds.length === 0) {
|
|
8
|
+
log('no builds found');
|
|
9
|
+
return 0;
|
|
10
|
+
}
|
|
11
|
+
log(formatBuildsTable(builds));
|
|
12
|
+
return 0;
|
|
13
|
+
}
|
|
14
|
+
catch (err) {
|
|
15
|
+
log(formatApiError(err));
|
|
16
|
+
return 1;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const TERMINAL_STATUSES = new Set([
|
|
20
|
+
'succeeded',
|
|
21
|
+
'failed',
|
|
22
|
+
'cancelled',
|
|
23
|
+
'timeout',
|
|
24
|
+
]);
|
|
25
|
+
export async function runBuildsGet(args) {
|
|
26
|
+
const log = args.log ?? ((line) => console.log(line));
|
|
27
|
+
const showLog = args.showLog ?? true;
|
|
28
|
+
const client = new ApiClient({ endpoint: args.endpoint, apiKey: args.apiKey, fetchImpl: args.fetchImpl });
|
|
29
|
+
try {
|
|
30
|
+
const { build } = await client.getBuild(args.siteId, args.buildId);
|
|
31
|
+
log(JSON.stringify(build, null, 2));
|
|
32
|
+
// Pull the build log too once the build has reached a terminal
|
|
33
|
+
// state and the runner produced one (logR2Key is set). Ignored for
|
|
34
|
+
// pending/running builds — they don't have a log yet.
|
|
35
|
+
if (showLog && TERMINAL_STATUSES.has(build.status) && build.logR2Key) {
|
|
36
|
+
try {
|
|
37
|
+
const text = await client.getBuildLog(args.siteId, args.buildId);
|
|
38
|
+
if (text !== null) {
|
|
39
|
+
log('');
|
|
40
|
+
log('--- build log ---');
|
|
41
|
+
log(text);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
log(`warn: failed to fetch build log: ${err instanceof Error ? err.message : String(err)}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return 0;
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
log(formatApiError(err));
|
|
52
|
+
return 1;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function formatBuildsTable(builds) {
|
|
56
|
+
const rows = builds.map((b) => [
|
|
57
|
+
b.id,
|
|
58
|
+
b.status.padEnd(9),
|
|
59
|
+
(b.framework ?? '-').padEnd(7),
|
|
60
|
+
formatSeconds(b.containerSeconds),
|
|
61
|
+
b.deploymentId ?? '-',
|
|
62
|
+
b.createdAt,
|
|
63
|
+
]);
|
|
64
|
+
return rows.map((r) => r.join(' ')).join('\n');
|
|
65
|
+
}
|
|
66
|
+
function formatSeconds(s) {
|
|
67
|
+
if (s === null)
|
|
68
|
+
return ' - ';
|
|
69
|
+
return `${s.toFixed(2)}s`.padStart(7);
|
|
70
|
+
}
|
|
71
|
+
function formatApiError(err) {
|
|
72
|
+
if (err instanceof ApiError)
|
|
73
|
+
return `error: ${err.status} ${err.message}`;
|
|
74
|
+
return `error: ${err instanceof Error ? err.message : String(err)}`;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=builds.js.map
|