@sylphx/cli 0.3.0 → 0.3.1
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/index.js +570 -717
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -24,13 +24,13 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/index.ts
|
|
27
|
-
var
|
|
28
|
-
var
|
|
27
|
+
var import_chalk25 = __toESM(require("chalk"));
|
|
28
|
+
var import_commander24 = require("commander");
|
|
29
29
|
|
|
30
30
|
// package.json
|
|
31
31
|
var package_default = {
|
|
32
32
|
name: "@sylphx/cli",
|
|
33
|
-
version: "0.3.
|
|
33
|
+
version: "0.3.1",
|
|
34
34
|
description: "Sylphx Platform CLI \u2014 deploy, manage logs, env vars, and more",
|
|
35
35
|
type: "commonjs",
|
|
36
36
|
bin: {
|
|
@@ -55,6 +55,7 @@ var package_default = {
|
|
|
55
55
|
registry: "https://registry.npmjs.org/"
|
|
56
56
|
},
|
|
57
57
|
dependencies: {
|
|
58
|
+
"@sylphx/management": "workspace:*",
|
|
58
59
|
chalk: "^5.3.0",
|
|
59
60
|
commander: "^12.1.0",
|
|
60
61
|
conf: "^13.0.0",
|
|
@@ -153,491 +154,213 @@ var config = {
|
|
|
153
154
|
};
|
|
154
155
|
|
|
155
156
|
// src/api.ts
|
|
157
|
+
var import_management = require("@sylphx/management");
|
|
156
158
|
var { version } = package_default;
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
var AUTH_BASE_URL = "https://sylphx.com";
|
|
160
|
-
var ApiError = class extends Error {
|
|
161
|
-
constructor(status, message, body) {
|
|
162
|
-
super(message);
|
|
163
|
-
this.status = status;
|
|
164
|
-
this.body = body;
|
|
165
|
-
this.name = "ApiError";
|
|
166
|
-
}
|
|
167
|
-
};
|
|
168
|
-
async function request(method, path5, options) {
|
|
169
|
-
const token = options?.token ?? config.getToken();
|
|
159
|
+
function getMgmt() {
|
|
160
|
+
const token = config.getToken();
|
|
170
161
|
if (!token) {
|
|
171
|
-
throw new ApiError(401, "Not authenticated. Run `sylphx login` first.");
|
|
172
|
-
}
|
|
173
|
-
let url = `${API_BASE}${path5}`;
|
|
174
|
-
if (options?.query) {
|
|
175
|
-
const params = new URLSearchParams(options.query);
|
|
176
|
-
url += `?${params.toString()}`;
|
|
162
|
+
throw new import_management.ApiError(401, "Not authenticated. Run `sylphx login` first.");
|
|
177
163
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
"User-Agent": `sylphx-cli/${version}`
|
|
182
|
-
};
|
|
183
|
-
const res = await fetch(url, {
|
|
184
|
-
method,
|
|
185
|
-
headers,
|
|
186
|
-
body: options?.body ? JSON.stringify(options.body) : void 0
|
|
164
|
+
return new import_management.SylphxManagement({
|
|
165
|
+
token,
|
|
166
|
+
userAgent: `sylphx-cli/${version}`
|
|
187
167
|
});
|
|
188
|
-
if (!res.ok) {
|
|
189
|
-
let body;
|
|
190
|
-
const text = await res.text();
|
|
191
|
-
try {
|
|
192
|
-
body = JSON.parse(text);
|
|
193
|
-
} catch {
|
|
194
|
-
body = text;
|
|
195
|
-
}
|
|
196
|
-
const message = typeof body === "object" && body !== null && "message" in body ? String(body.message) : `HTTP ${res.status}`;
|
|
197
|
-
throw new ApiError(res.status, message, body);
|
|
198
|
-
}
|
|
199
|
-
if (res.status === 204) {
|
|
200
|
-
return void 0;
|
|
201
|
-
}
|
|
202
|
-
return res.json();
|
|
203
168
|
}
|
|
204
169
|
var api = {
|
|
205
|
-
|
|
170
|
+
// Deployments
|
|
206
171
|
async getDeploymentStatus(projectId) {
|
|
207
|
-
return
|
|
172
|
+
return getMgmt().deployments.status(projectId);
|
|
208
173
|
},
|
|
209
|
-
/** Trigger a deploy for a project environment */
|
|
210
174
|
async triggerDeploy(projectId, envType) {
|
|
211
|
-
return
|
|
212
|
-
body: { envType }
|
|
213
|
-
});
|
|
175
|
+
return getMgmt().deployments.trigger(projectId, envType);
|
|
214
176
|
},
|
|
215
|
-
/** Get deployment history for a project environment */
|
|
216
177
|
async getDeploymentHistory(projectId, envType) {
|
|
217
|
-
return
|
|
218
|
-
query: { envType }
|
|
219
|
-
});
|
|
178
|
+
return getMgmt().deployments.history(projectId, envType);
|
|
220
179
|
},
|
|
221
|
-
/** Rollback to previous deployment.
|
|
222
|
-
* Accepts envId (rollback env to previous deploy), deploymentRecordId, or buildRecordId.
|
|
223
|
-
* One of these is required.
|
|
224
|
-
*/
|
|
225
180
|
async rollback(projectId, body) {
|
|
226
|
-
return
|
|
181
|
+
return getMgmt().deployments.rollback(projectId, body);
|
|
227
182
|
},
|
|
228
|
-
|
|
183
|
+
// Env Vars
|
|
229
184
|
async listEnvVars(projectId, envType) {
|
|
230
|
-
|
|
231
|
-
"GET",
|
|
232
|
-
`/projects/${projectId}/env-vars`,
|
|
233
|
-
{
|
|
234
|
-
query: { envType }
|
|
235
|
-
}
|
|
236
|
-
);
|
|
237
|
-
return Array.isArray(res) ? res : res.data ?? [];
|
|
185
|
+
return getMgmt().envVars.list(projectId, envType);
|
|
238
186
|
},
|
|
239
|
-
/** Set an env var (or batch of vars) for a project environment */
|
|
240
187
|
async setEnvVar(projectId, key, value, envType, secret) {
|
|
241
|
-
return
|
|
242
|
-
body: {
|
|
243
|
-
envType,
|
|
244
|
-
vars: [{ key, value, secret: secret ?? false }]
|
|
245
|
-
}
|
|
246
|
-
});
|
|
188
|
+
return getMgmt().envVars.set(projectId, key, value, envType, secret);
|
|
247
189
|
},
|
|
248
|
-
/** Delete an env var for a project environment */
|
|
249
190
|
async deleteEnvVar(projectId, key, envType) {
|
|
250
|
-
return
|
|
251
|
-
|
|
252
|
-
|
|
191
|
+
return getMgmt().envVars.delete(projectId, key, envType);
|
|
192
|
+
},
|
|
193
|
+
async setEnvVars(projectId, vars, envType) {
|
|
194
|
+
return getMgmt().envVars.setMany(projectId, vars, envType);
|
|
253
195
|
},
|
|
254
|
-
//
|
|
255
|
-
/** List all apex domains for a project environment */
|
|
196
|
+
// Domains
|
|
256
197
|
async listDomains(projectId, envType = "production") {
|
|
257
|
-
return
|
|
258
|
-
query: { envType }
|
|
259
|
-
});
|
|
198
|
+
return getMgmt().domains.list(projectId, envType);
|
|
260
199
|
},
|
|
261
|
-
/** Register an apex domain for a project (full domain object with DNS records) */
|
|
262
200
|
async createDomain(projectId, apexDomain, envType = "production") {
|
|
263
|
-
return
|
|
264
|
-
body: { apexDomain, envType }
|
|
265
|
-
});
|
|
201
|
+
return getMgmt().domains.create(projectId, apexDomain, envType);
|
|
266
202
|
},
|
|
267
|
-
/** Add a hostname binding to an existing domain */
|
|
268
203
|
async addHostname(projectId, domainId, hostname, opts) {
|
|
269
|
-
|
|
270
|
-
return request("POST", `/projects/${projectId}/domains/${domainId}/hostnames`, {
|
|
271
|
-
query: { envType },
|
|
272
|
-
body: { hostname, ...bodyOpts }
|
|
273
|
-
});
|
|
204
|
+
return getMgmt().domains.addHostname(projectId, domainId, hostname, opts);
|
|
274
205
|
},
|
|
275
|
-
/** Remove a hostname binding */
|
|
276
206
|
async removeHostname(projectId, domainId, hostnameId) {
|
|
277
|
-
return
|
|
278
|
-
"DELETE",
|
|
279
|
-
`/projects/${projectId}/domains/${domainId}/hostnames/${hostnameId}`
|
|
280
|
-
);
|
|
207
|
+
return getMgmt().domains.removeHostname(projectId, domainId, hostnameId);
|
|
281
208
|
},
|
|
282
|
-
/** Trigger DNS check for a hostname */
|
|
283
209
|
async checkHostname(projectId, domainId, hostnameId) {
|
|
284
|
-
return
|
|
285
|
-
"POST",
|
|
286
|
-
`/projects/${projectId}/domains/${domainId}/hostnames/${hostnameId}/check`
|
|
287
|
-
);
|
|
210
|
+
return getMgmt().domains.checkHostname(projectId, domainId, hostnameId);
|
|
288
211
|
},
|
|
289
|
-
/** Enable email sending for a domain (generates DKIM keypair) */
|
|
290
212
|
async enableEmail(projectId, domainId, opts) {
|
|
291
|
-
return
|
|
292
|
-
body: opts ?? {}
|
|
293
|
-
});
|
|
213
|
+
return getMgmt().domains.enableEmail(projectId, domainId, opts);
|
|
294
214
|
},
|
|
295
|
-
/** Check DKIM DNS propagation and load into Stalwart */
|
|
296
215
|
async checkEmail(projectId, domainId) {
|
|
297
|
-
return
|
|
298
|
-
"POST",
|
|
299
|
-
`/projects/${projectId}/domains/${domainId}/email/check`
|
|
300
|
-
);
|
|
216
|
+
return getMgmt().domains.checkEmail(projectId, domainId);
|
|
301
217
|
},
|
|
302
|
-
/** Disable email sending for a domain */
|
|
303
218
|
async disableEmail(projectId, domainId) {
|
|
304
|
-
return
|
|
219
|
+
return getMgmt().domains.disableEmail(projectId, domainId);
|
|
305
220
|
},
|
|
306
|
-
|
|
221
|
+
// User
|
|
307
222
|
async whoami() {
|
|
308
|
-
return
|
|
223
|
+
return getMgmt().user.whoami();
|
|
309
224
|
},
|
|
310
|
-
|
|
225
|
+
// Projects
|
|
311
226
|
async listProjects() {
|
|
312
|
-
|
|
313
|
-
return Array.isArray(res) ? res : res.data ?? [];
|
|
227
|
+
return getMgmt().projects.list();
|
|
314
228
|
},
|
|
315
|
-
/** Create a new project */
|
|
316
229
|
async createProject(data) {
|
|
317
|
-
return
|
|
230
|
+
return getMgmt().projects.create(data);
|
|
318
231
|
},
|
|
319
|
-
/** Delete a project */
|
|
320
232
|
async deleteProject(id) {
|
|
321
|
-
return
|
|
233
|
+
return getMgmt().projects.delete(id);
|
|
322
234
|
},
|
|
323
|
-
|
|
235
|
+
// Organization
|
|
236
|
+
async getCurrentOrg() {
|
|
237
|
+
return getMgmt().org.current();
|
|
238
|
+
},
|
|
239
|
+
async listOrgMembers(orgId) {
|
|
240
|
+
return getMgmt().org.listMembers(orgId);
|
|
241
|
+
},
|
|
242
|
+
async inviteOrgMember(orgId, email, role) {
|
|
243
|
+
return getMgmt().org.inviteMember(orgId, email, role);
|
|
244
|
+
},
|
|
245
|
+
async removeOrgMember(orgId, userId) {
|
|
246
|
+
return getMgmt().org.removeMember(orgId, userId);
|
|
247
|
+
},
|
|
248
|
+
/** @deprecated Use listProjects() */
|
|
324
249
|
async listApps(_orgId) {
|
|
325
250
|
return this.listProjects();
|
|
326
251
|
},
|
|
327
|
-
|
|
252
|
+
// Databases
|
|
328
253
|
async listDatabases() {
|
|
329
|
-
|
|
330
|
-
"GET",
|
|
331
|
-
"/resources",
|
|
332
|
-
{
|
|
333
|
-
query: { kind: "database" }
|
|
334
|
-
}
|
|
335
|
-
);
|
|
336
|
-
return Array.isArray(res) ? res : res.data ?? [];
|
|
254
|
+
return getMgmt().databases.list();
|
|
337
255
|
},
|
|
338
|
-
/** Provision a new database (via unified Resources API) */
|
|
339
256
|
async createDatabase(data) {
|
|
340
|
-
return
|
|
257
|
+
return getMgmt().databases.create(data);
|
|
341
258
|
},
|
|
342
|
-
/** Get database details (via unified Resources API) */
|
|
343
259
|
async getDatabase(id) {
|
|
344
|
-
return
|
|
260
|
+
return getMgmt().databases.get(id);
|
|
345
261
|
},
|
|
346
|
-
/** Delete a database (via unified Resources API) */
|
|
347
262
|
async deleteDatabase(id) {
|
|
348
|
-
return
|
|
263
|
+
return getMgmt().databases.delete(id);
|
|
349
264
|
},
|
|
350
|
-
/** Branch a database for staging/preview (via unified Resources API) */
|
|
351
265
|
async branchDatabase(id, data) {
|
|
352
|
-
return
|
|
353
|
-
},
|
|
354
|
-
/** Batch-set env vars for a project environment */
|
|
355
|
-
async setEnvVars(projectId, vars, envType) {
|
|
356
|
-
return request("POST", `/projects/${projectId}/env-vars`, {
|
|
357
|
-
body: { envType, vars }
|
|
358
|
-
});
|
|
266
|
+
return getMgmt().databases.branch(id, data);
|
|
359
267
|
},
|
|
360
|
-
|
|
361
|
-
async pollCliAuth(code) {
|
|
362
|
-
const res = await fetch(`${AUTH_BASE_URL}/api/auth/cli/poll?code=${encodeURIComponent(code)}`, {
|
|
363
|
-
headers: { "User-Agent": `sylphx-cli/${version}` }
|
|
364
|
-
});
|
|
365
|
-
if (!res.ok) {
|
|
366
|
-
throw new ApiError(res.status, "Failed to poll auth status");
|
|
367
|
-
}
|
|
368
|
-
return res.json();
|
|
369
|
-
},
|
|
370
|
-
// ── Services ─────────────────────────────────────────────────────────────
|
|
371
|
-
/** List services for a project */
|
|
268
|
+
// Services
|
|
372
269
|
async listServices(projectId) {
|
|
373
|
-
|
|
374
|
-
"GET",
|
|
375
|
-
`/projects/${encodeURIComponent(projectId)}/services`
|
|
376
|
-
);
|
|
377
|
-
return Array.isArray(res) ? res : res.data ?? [];
|
|
270
|
+
return getMgmt().services.list(projectId);
|
|
378
271
|
},
|
|
379
|
-
/** Get a service by name */
|
|
380
272
|
async getService(projectId, name) {
|
|
381
|
-
return
|
|
382
|
-
"GET",
|
|
383
|
-
`/projects/${encodeURIComponent(projectId)}/services/${encodeURIComponent(name)}`
|
|
384
|
-
);
|
|
273
|
+
return getMgmt().services.get(projectId, name);
|
|
385
274
|
},
|
|
386
|
-
/**
|
|
387
|
-
* Deploy a specific service.
|
|
388
|
-
* Backend expects { environmentId?, force?, image? } — NOT envType.
|
|
389
|
-
* Resolves envType → environmentId automatically.
|
|
390
|
-
*/
|
|
391
275
|
async deployService(projectId, name, envType) {
|
|
392
|
-
|
|
393
|
-
return request(
|
|
394
|
-
"POST",
|
|
395
|
-
`/projects/${encodeURIComponent(projectId)}/services/${encodeURIComponent(name)}/deploy`,
|
|
396
|
-
{ body: environmentId ? { environmentId } : {} }
|
|
397
|
-
);
|
|
276
|
+
return getMgmt().services.deploy(projectId, name, envType);
|
|
398
277
|
},
|
|
399
|
-
/** Delete a service */
|
|
400
278
|
async deleteService(projectId, name) {
|
|
401
|
-
return
|
|
402
|
-
"DELETE",
|
|
403
|
-
`/projects/${encodeURIComponent(projectId)}/services/${encodeURIComponent(name)}`
|
|
404
|
-
);
|
|
279
|
+
return getMgmt().services.delete(projectId, name);
|
|
405
280
|
},
|
|
406
|
-
//
|
|
407
|
-
/** List volumes for a project */
|
|
281
|
+
// Volumes
|
|
408
282
|
async listVolumes(projectId) {
|
|
409
|
-
|
|
410
|
-
"GET",
|
|
411
|
-
`/projects/${encodeURIComponent(projectId)}/volumes`
|
|
412
|
-
);
|
|
413
|
-
return Array.isArray(res) ? res : res.volumes ?? [];
|
|
283
|
+
return getMgmt().volumes.list(projectId);
|
|
414
284
|
},
|
|
415
|
-
/** Create a volume */
|
|
416
285
|
async createVolume(projectId, data) {
|
|
417
|
-
return
|
|
418
|
-
"POST",
|
|
419
|
-
`/projects/${encodeURIComponent(projectId)}/volumes`,
|
|
420
|
-
{ body: data }
|
|
421
|
-
);
|
|
286
|
+
return getMgmt().volumes.create(projectId, data);
|
|
422
287
|
},
|
|
423
|
-
/** Delete a volume */
|
|
424
288
|
async deleteVolume(projectId, volId) {
|
|
425
|
-
return
|
|
426
|
-
"DELETE",
|
|
427
|
-
`/projects/${encodeURIComponent(projectId)}/volumes/${encodeURIComponent(volId)}`
|
|
428
|
-
);
|
|
289
|
+
return getMgmt().volumes.delete(projectId, volId);
|
|
429
290
|
},
|
|
430
|
-
//
|
|
431
|
-
/** List storage resources for a project.
|
|
432
|
-
* Backend returns a plain array of binding objects (not wrapped in { data: [...] }).
|
|
433
|
-
* Optionally filter by envType client-side.
|
|
434
|
-
*/
|
|
291
|
+
// Storage
|
|
435
292
|
async listStorage(projectId, envType) {
|
|
436
|
-
|
|
437
|
-
"GET",
|
|
438
|
-
`/projects/${encodeURIComponent(projectId)}/storage`
|
|
439
|
-
);
|
|
440
|
-
const list = Array.isArray(res) ? res : [];
|
|
441
|
-
return envType ? list.filter((r) => !r.envType || r.envType === envType) : list;
|
|
293
|
+
return getMgmt().storage.list(projectId, envType);
|
|
442
294
|
},
|
|
443
|
-
/** Provision blob storage for a project environment */
|
|
444
295
|
async createStorage(projectId, data) {
|
|
445
|
-
return
|
|
446
|
-
body: data
|
|
447
|
-
});
|
|
296
|
+
return getMgmt().storage.create(projectId, data);
|
|
448
297
|
},
|
|
449
|
-
/** Delete a storage resource */
|
|
450
298
|
async deleteStorage(projectId, storageId) {
|
|
451
|
-
return
|
|
452
|
-
"DELETE",
|
|
453
|
-
`/projects/${encodeURIComponent(projectId)}/storage/${encodeURIComponent(storageId)}`
|
|
454
|
-
);
|
|
299
|
+
return getMgmt().storage.delete(projectId, storageId);
|
|
455
300
|
},
|
|
456
|
-
//
|
|
457
|
-
/**
|
|
458
|
-
* List all config keys for a project.
|
|
459
|
-
* Backend uses ?env=<envId> (not ?envType). Resolves envType → envId automatically.
|
|
460
|
-
*/
|
|
301
|
+
// Config
|
|
461
302
|
async listConfig(projectId, envType) {
|
|
462
|
-
|
|
463
|
-
if (envType) {
|
|
464
|
-
const envId = await this.resolveEnvId(projectId, envType);
|
|
465
|
-
if (envId) query.env = envId;
|
|
466
|
-
}
|
|
467
|
-
const res = await request(
|
|
468
|
-
"GET",
|
|
469
|
-
`/projects/${encodeURIComponent(projectId)}/config`,
|
|
470
|
-
{ query }
|
|
471
|
-
);
|
|
472
|
-
return Array.isArray(res) ? res : res.data ?? [];
|
|
303
|
+
return getMgmt().config.list(projectId, envType);
|
|
473
304
|
},
|
|
474
|
-
/**
|
|
475
|
-
* Get a single config key.
|
|
476
|
-
* Backend uses ?env=<envId> (not ?envType). Resolves envType → envId automatically.
|
|
477
|
-
*/
|
|
478
305
|
async getConfig(projectId, key, envType) {
|
|
479
|
-
|
|
480
|
-
if (envType) {
|
|
481
|
-
const envId = await this.resolveEnvId(projectId, envType);
|
|
482
|
-
if (envId) query.env = envId;
|
|
483
|
-
}
|
|
484
|
-
return request(
|
|
485
|
-
"GET",
|
|
486
|
-
`/projects/${encodeURIComponent(projectId)}/config/${encodeURIComponent(key)}`,
|
|
487
|
-
{ query }
|
|
488
|
-
);
|
|
306
|
+
return getMgmt().config.get(projectId, key, envType);
|
|
489
307
|
},
|
|
490
|
-
/**
|
|
491
|
-
* Set a config key.
|
|
492
|
-
* Backend expects { key, value, environmentId } (not envType).
|
|
493
|
-
* Resolves envType → environmentId automatically when envType is provided.
|
|
494
|
-
*/
|
|
495
308
|
async setConfig(projectId, key, value, envType) {
|
|
496
|
-
|
|
497
|
-
if (envType) {
|
|
498
|
-
environmentId = await this.resolveEnvId(projectId, envType);
|
|
499
|
-
}
|
|
500
|
-
return request("POST", `/projects/${encodeURIComponent(projectId)}/config`, {
|
|
501
|
-
body: { key, value, environmentId }
|
|
502
|
-
});
|
|
309
|
+
return getMgmt().config.set(projectId, key, value, envType);
|
|
503
310
|
},
|
|
504
|
-
/**
|
|
505
|
-
* Delete a config key.
|
|
506
|
-
* Backend uses ?env=<envId> (not ?envType). Resolves envType → envId automatically.
|
|
507
|
-
*/
|
|
508
311
|
async deleteConfig(projectId, key, envType) {
|
|
509
|
-
|
|
510
|
-
if (envType) {
|
|
511
|
-
const envId = await this.resolveEnvId(projectId, envType);
|
|
512
|
-
if (envId) query.env = envId;
|
|
513
|
-
}
|
|
514
|
-
return request(
|
|
515
|
-
"DELETE",
|
|
516
|
-
`/projects/${encodeURIComponent(projectId)}/config/${encodeURIComponent(key)}`,
|
|
517
|
-
{ query }
|
|
518
|
-
);
|
|
312
|
+
return getMgmt().config.delete(projectId, key, envType);
|
|
519
313
|
},
|
|
520
|
-
//
|
|
521
|
-
/** List environments for a project */
|
|
314
|
+
// Environments
|
|
522
315
|
async listEnvironments(projectId) {
|
|
523
|
-
|
|
524
|
-
"GET",
|
|
525
|
-
`/projects/${encodeURIComponent(projectId)}/environments`
|
|
526
|
-
);
|
|
527
|
-
return Array.isArray(res) ? res : res.data ?? [];
|
|
316
|
+
return getMgmt().environments.list(projectId);
|
|
528
317
|
},
|
|
529
|
-
/**
|
|
530
|
-
* Resolve an environment type string (e.g. "production") → its envId for the given project.
|
|
531
|
-
* Returns null if not found. Used internally by config commands.
|
|
532
|
-
*/
|
|
533
318
|
async resolveEnvId(projectId, envType) {
|
|
534
|
-
|
|
535
|
-
const match = envs.find((e) => (e.envType ?? "").toLowerCase() === envType.toLowerCase());
|
|
536
|
-
return match?.id ?? null;
|
|
319
|
+
return getMgmt().environments.resolveId(projectId, envType);
|
|
537
320
|
},
|
|
538
|
-
/** Promote an environment (e.g. staging → production).
|
|
539
|
-
* Backend returns { promoted: number, services: [...], sourceEnvironment, targetEnvironment }
|
|
540
|
-
*/
|
|
541
321
|
async promoteEnvironment(projectId, targetEnvId, sourceEnvId) {
|
|
542
|
-
return
|
|
543
|
-
"POST",
|
|
544
|
-
`/projects/${encodeURIComponent(projectId)}/environments/${encodeURIComponent(targetEnvId)}/promote`,
|
|
545
|
-
{ body: { sourceEnvId } }
|
|
546
|
-
);
|
|
322
|
+
return getMgmt().environments.promote(projectId, targetEnvId, sourceEnvId);
|
|
547
323
|
},
|
|
548
|
-
//
|
|
549
|
-
/** List bindings for a resource (which envs it's linked to).
|
|
550
|
-
* Backend returns { bindings: [...] }.
|
|
551
|
-
*/
|
|
324
|
+
// Resource Bindings
|
|
552
325
|
async listResourceBindings(resourceId) {
|
|
553
|
-
|
|
554
|
-
"GET",
|
|
555
|
-
`/resources/${encodeURIComponent(resourceId)}/bindings`
|
|
556
|
-
);
|
|
557
|
-
return res.bindings ?? [];
|
|
326
|
+
return getMgmt().resources.listBindings(resourceId);
|
|
558
327
|
},
|
|
559
|
-
/**
|
|
560
|
-
* Bind a resource to a project environment.
|
|
561
|
-
* Backend expects { appEnvironmentId, role? }.
|
|
562
|
-
* Accepts projectId + envType and resolves to appEnvironmentId automatically.
|
|
563
|
-
*/
|
|
564
328
|
async bindResource(resourceId, data) {
|
|
565
|
-
|
|
566
|
-
if (!appEnvironmentId) {
|
|
567
|
-
throw new Error(`Environment '${data.envType}' not found for project '${data.projectId}'`);
|
|
568
|
-
}
|
|
569
|
-
return request(
|
|
570
|
-
"POST",
|
|
571
|
-
`/resources/${encodeURIComponent(resourceId)}/bindings`,
|
|
572
|
-
{ body: { appEnvironmentId, role: data.role ?? "primary" } }
|
|
573
|
-
);
|
|
329
|
+
return getMgmt().resources.bind(resourceId, data);
|
|
574
330
|
},
|
|
575
|
-
/** Unbind a resource from a project environment */
|
|
576
331
|
async unbindResource(resourceId, bindingId) {
|
|
577
|
-
return
|
|
578
|
-
"DELETE",
|
|
579
|
-
`/resources/${encodeURIComponent(resourceId)}/bindings/${encodeURIComponent(bindingId)}`
|
|
580
|
-
);
|
|
332
|
+
return getMgmt().resources.unbind(resourceId, bindingId);
|
|
581
333
|
},
|
|
582
|
-
//
|
|
583
|
-
/**
|
|
584
|
-
* List task definitions for a project environment.
|
|
585
|
-
* Uses ?envId=<envId> (resolved from envType automatically).
|
|
586
|
-
*/
|
|
334
|
+
// Tasks
|
|
587
335
|
async listTasks(projectId, envType) {
|
|
588
|
-
|
|
589
|
-
if (envType) {
|
|
590
|
-
const envId = await this.resolveEnvId(projectId, envType);
|
|
591
|
-
if (envId) query.envId = envId;
|
|
592
|
-
}
|
|
593
|
-
const res = await request(
|
|
594
|
-
"GET",
|
|
595
|
-
`/projects/${encodeURIComponent(projectId)}/tasks`,
|
|
596
|
-
{ query }
|
|
597
|
-
);
|
|
598
|
-
return res.tasks ?? [];
|
|
336
|
+
return getMgmt().tasks.list(projectId, envType);
|
|
599
337
|
},
|
|
600
|
-
/**
|
|
601
|
-
* Create or update a task definition (upserts on taskName + environmentId).
|
|
602
|
-
* Backend requires envId — resolves from envType automatically.
|
|
603
|
-
*/
|
|
604
338
|
async createTask(projectId, data) {
|
|
605
|
-
|
|
606
|
-
if (!envId)
|
|
607
|
-
throw new Error(`Environment '${data.envType}' not found for project '${projectId}'`);
|
|
608
|
-
const { envType: _drop, ...rest } = data;
|
|
609
|
-
const res = await request(
|
|
610
|
-
"POST",
|
|
611
|
-
`/projects/${encodeURIComponent(projectId)}/tasks`,
|
|
612
|
-
{ body: { ...rest, envId } }
|
|
613
|
-
);
|
|
614
|
-
return res.task;
|
|
339
|
+
return getMgmt().tasks.create(projectId, data);
|
|
615
340
|
},
|
|
616
|
-
/** Get a single task definition */
|
|
617
341
|
async getTask(projectId, taskId) {
|
|
618
|
-
|
|
619
|
-
"GET",
|
|
620
|
-
`/projects/${encodeURIComponent(projectId)}/tasks/${encodeURIComponent(taskId)}`
|
|
621
|
-
);
|
|
622
|
-
return res.task;
|
|
342
|
+
return getMgmt().tasks.get(projectId, taskId);
|
|
623
343
|
},
|
|
624
|
-
/** Update a task definition */
|
|
625
344
|
async updateTask(projectId, taskId, data) {
|
|
626
|
-
|
|
627
|
-
"PATCH",
|
|
628
|
-
`/projects/${encodeURIComponent(projectId)}/tasks/${encodeURIComponent(taskId)}`,
|
|
629
|
-
{ body: data }
|
|
630
|
-
);
|
|
631
|
-
return res.task;
|
|
345
|
+
return getMgmt().tasks.update(projectId, taskId, data);
|
|
632
346
|
},
|
|
633
|
-
/** Delete a task definition */
|
|
634
347
|
async deleteTask(projectId, taskId) {
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
348
|
+
return getMgmt().tasks.delete(projectId, taskId);
|
|
349
|
+
},
|
|
350
|
+
// CLI-specific: auth poll (uses main sylphx.com domain, not api.sylphx.com)
|
|
351
|
+
async pollCliAuth(code) {
|
|
352
|
+
const AUTH_BASE_URL = "https://sylphx.com";
|
|
353
|
+
const res = await fetch(`${AUTH_BASE_URL}/api/auth/cli/poll?code=${encodeURIComponent(code)}`, {
|
|
354
|
+
headers: { "User-Agent": `sylphx-cli/${version}` }
|
|
355
|
+
});
|
|
356
|
+
if (!res.ok) {
|
|
357
|
+
throw new import_management.ApiError(res.status, "Failed to poll auth status");
|
|
358
|
+
}
|
|
359
|
+
return res.json();
|
|
639
360
|
}
|
|
640
361
|
};
|
|
362
|
+
var BASE_URL = process.env.SYLPHX_API_URL ?? "https://api.sylphx.com";
|
|
363
|
+
var API_BASE = `${BASE_URL}/v1`;
|
|
641
364
|
function createLogStream(projectId, envType) {
|
|
642
365
|
const params = new URLSearchParams({ envType, stream: "true", limit: "200" });
|
|
643
366
|
return {
|
|
@@ -1875,7 +1598,6 @@ var loginCommand = new import_commander8.Command("login").description("Authentic
|
|
|
1875
1598
|
try {
|
|
1876
1599
|
config.setToken(opts.token);
|
|
1877
1600
|
const me = await api.whoami();
|
|
1878
|
-
config.setToken(opts.token);
|
|
1879
1601
|
spinner2.succeed(import_chalk9.default.green(`Authenticated as ${import_chalk9.default.bold(me.user.email)}`));
|
|
1880
1602
|
} catch (err) {
|
|
1881
1603
|
config.clearToken();
|
|
@@ -2038,15 +1760,146 @@ var openCommand = new import_commander11.Command("open").description("Open the a
|
|
|
2038
1760
|
}
|
|
2039
1761
|
});
|
|
2040
1762
|
|
|
2041
|
-
// src/commands/
|
|
2042
|
-
var import_node_readline4 = __toESM(require("readline"));
|
|
1763
|
+
// src/commands/orgs.ts
|
|
2043
1764
|
var import_chalk13 = __toESM(require("chalk"));
|
|
2044
1765
|
var import_commander12 = require("commander");
|
|
2045
1766
|
var import_ora10 = __toESM(require("ora"));
|
|
2046
1767
|
function requireAuth2() {
|
|
2047
1768
|
const token = config.getToken();
|
|
2048
1769
|
if (!token) {
|
|
2049
|
-
console.
|
|
1770
|
+
console.error(import_chalk13.default.red("Not authenticated. Run `sylphx login` first."));
|
|
1771
|
+
process.exit(1);
|
|
1772
|
+
}
|
|
1773
|
+
return token;
|
|
1774
|
+
}
|
|
1775
|
+
function roleBadge(role) {
|
|
1776
|
+
switch (role.toLowerCase()) {
|
|
1777
|
+
case "owner":
|
|
1778
|
+
return import_chalk13.default.yellow("owner ");
|
|
1779
|
+
case "admin":
|
|
1780
|
+
return import_chalk13.default.cyan("admin ");
|
|
1781
|
+
default:
|
|
1782
|
+
return import_chalk13.default.dim("member");
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
async function showCurrentOrg() {
|
|
1786
|
+
requireAuth2();
|
|
1787
|
+
const spinner = (0, import_ora10.default)("Fetching org info...").start();
|
|
1788
|
+
try {
|
|
1789
|
+
const [org, whoami] = await Promise.all([api.getCurrentOrg(), api.whoami()]);
|
|
1790
|
+
spinner.stop();
|
|
1791
|
+
console.log("");
|
|
1792
|
+
console.log(import_chalk13.default.bold(" Organization"));
|
|
1793
|
+
console.log(import_chalk13.default.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
1794
|
+
console.log(` ${import_chalk13.default.bold("Name")} ${org.name}`);
|
|
1795
|
+
console.log(` ${import_chalk13.default.bold("Slug")} ${import_chalk13.default.cyan(org.slug)}`);
|
|
1796
|
+
console.log(` ${import_chalk13.default.bold("ID")} ${import_chalk13.default.dim(org.id)}`);
|
|
1797
|
+
if (org.email) console.log(` ${import_chalk13.default.bold("Email")} ${org.email}`);
|
|
1798
|
+
console.log("");
|
|
1799
|
+
const allOrgs = whoami.orgs;
|
|
1800
|
+
if (allOrgs.length > 1) {
|
|
1801
|
+
console.log(import_chalk13.default.dim(` You are a member of ${allOrgs.length} organizations:`));
|
|
1802
|
+
for (const o of allOrgs) {
|
|
1803
|
+
const isCurrent = o.id === org.id;
|
|
1804
|
+
console.log(
|
|
1805
|
+
` ${isCurrent ? import_chalk13.default.green("\u2192") : " "} ${import_chalk13.default.bold(o.name)} ${import_chalk13.default.dim(`(${o.slug})`)}`
|
|
1806
|
+
);
|
|
1807
|
+
}
|
|
1808
|
+
console.log("");
|
|
1809
|
+
}
|
|
1810
|
+
} catch (err) {
|
|
1811
|
+
spinner.fail("Failed to fetch org info");
|
|
1812
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1813
|
+
console.error(import_chalk13.default.red(message));
|
|
1814
|
+
process.exit(1);
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
var membersListCommand = new import_commander12.Command("list").alias("ls").description("List organization members").action(async () => {
|
|
1818
|
+
requireAuth2();
|
|
1819
|
+
const spinner = (0, import_ora10.default)("Fetching members...").start();
|
|
1820
|
+
try {
|
|
1821
|
+
const org = await api.getCurrentOrg();
|
|
1822
|
+
const members = await api.listOrgMembers(org.id);
|
|
1823
|
+
spinner.stop();
|
|
1824
|
+
if (members.length === 0) {
|
|
1825
|
+
console.log(import_chalk13.default.dim("\n No members found.\n"));
|
|
1826
|
+
return;
|
|
1827
|
+
}
|
|
1828
|
+
const colEmail = Math.max(5, ...members.map((m) => m.email.length));
|
|
1829
|
+
const colName = Math.max(4, ...members.map((m) => (m.name ?? "\u2014").length));
|
|
1830
|
+
console.log("");
|
|
1831
|
+
console.log(import_chalk13.default.bold(` Members of ${org.name}`));
|
|
1832
|
+
console.log(import_chalk13.default.dim(` ${"\u2500".repeat(colEmail + colName + 20)}`));
|
|
1833
|
+
console.log(
|
|
1834
|
+
import_chalk13.default.dim(` ${"ROLE ".padEnd(7)} ${"EMAIL".padEnd(colEmail)} ${"NAME".padEnd(colName)}`)
|
|
1835
|
+
);
|
|
1836
|
+
console.log(import_chalk13.default.dim(` ${"\u2500".repeat(colEmail + colName + 20)}`));
|
|
1837
|
+
for (const m of members) {
|
|
1838
|
+
const joined = m.joinedAt ? new Date(m.joinedAt).toLocaleDateString() : "";
|
|
1839
|
+
console.log(
|
|
1840
|
+
` ${roleBadge(m.role)} ${m.email.padEnd(colEmail)} ${(m.name ?? import_chalk13.default.dim("\u2014")).padEnd(colName)} ${import_chalk13.default.dim(joined)}`
|
|
1841
|
+
);
|
|
1842
|
+
}
|
|
1843
|
+
console.log("");
|
|
1844
|
+
console.log(import_chalk13.default.dim(` ${members.length} member${members.length !== 1 ? "s" : ""}`));
|
|
1845
|
+
console.log("");
|
|
1846
|
+
} catch (err) {
|
|
1847
|
+
spinner.fail("Failed to fetch members");
|
|
1848
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1849
|
+
console.error(import_chalk13.default.red(message));
|
|
1850
|
+
process.exit(1);
|
|
1851
|
+
}
|
|
1852
|
+
});
|
|
1853
|
+
var membersInviteCommand = new import_commander12.Command("invite").description("Invite a member to the organization by email").argument("<email>", "Email address to invite").option("--role <role>", "Role to assign (admin | member)", "member").action(async (email, options) => {
|
|
1854
|
+
requireAuth2();
|
|
1855
|
+
const role = options.role;
|
|
1856
|
+
if (role !== "admin" && role !== "member") {
|
|
1857
|
+
console.error(import_chalk13.default.red(`Invalid role "${role}". Must be "admin" or "member".`));
|
|
1858
|
+
process.exit(1);
|
|
1859
|
+
}
|
|
1860
|
+
const spinner = (0, import_ora10.default)(`Inviting ${email}...`).start();
|
|
1861
|
+
try {
|
|
1862
|
+
const org = await api.getCurrentOrg();
|
|
1863
|
+
await api.inviteOrgMember(org.id, email, role);
|
|
1864
|
+
spinner.succeed(
|
|
1865
|
+
`Invited ${import_chalk13.default.bold(email)} as ${import_chalk13.default.cyan(role)} to ${import_chalk13.default.bold(org.name)}`
|
|
1866
|
+
);
|
|
1867
|
+
console.log(import_chalk13.default.dim(" They will receive an invitation email shortly."));
|
|
1868
|
+
} catch (err) {
|
|
1869
|
+
spinner.fail("Failed to send invitation");
|
|
1870
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1871
|
+
console.error(import_chalk13.default.red(message));
|
|
1872
|
+
process.exit(1);
|
|
1873
|
+
}
|
|
1874
|
+
});
|
|
1875
|
+
var membersRemoveCommand = new import_commander12.Command("remove").description("Remove a member from the organization").argument("<userId>", "User ID to remove (use `sylphx orgs members` to list)").action(async (userId) => {
|
|
1876
|
+
requireAuth2();
|
|
1877
|
+
const spinner = (0, import_ora10.default)(`Removing member ${userId}...`).start();
|
|
1878
|
+
try {
|
|
1879
|
+
const org = await api.getCurrentOrg();
|
|
1880
|
+
await api.removeOrgMember(org.id, userId);
|
|
1881
|
+
spinner.succeed(`Removed member ${import_chalk13.default.bold(userId)} from ${import_chalk13.default.bold(org.name)}`);
|
|
1882
|
+
} catch (err) {
|
|
1883
|
+
spinner.fail("Failed to remove member");
|
|
1884
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1885
|
+
console.error(import_chalk13.default.red(message));
|
|
1886
|
+
process.exit(1);
|
|
1887
|
+
}
|
|
1888
|
+
});
|
|
1889
|
+
var membersCommand = new import_commander12.Command("members").description("Manage organization members").action(async () => {
|
|
1890
|
+
await membersListCommand.parseAsync([], { from: "user" });
|
|
1891
|
+
}).addCommand(membersListCommand).addCommand(membersInviteCommand).addCommand(membersRemoveCommand);
|
|
1892
|
+
var orgsCommand = new import_commander12.Command("orgs").description("Manage organizations").action(showCurrentOrg).addCommand(membersCommand);
|
|
1893
|
+
|
|
1894
|
+
// src/commands/projects.ts
|
|
1895
|
+
var import_node_readline4 = __toESM(require("readline"));
|
|
1896
|
+
var import_chalk14 = __toESM(require("chalk"));
|
|
1897
|
+
var import_commander13 = require("commander");
|
|
1898
|
+
var import_ora11 = __toESM(require("ora"));
|
|
1899
|
+
function requireAuth3() {
|
|
1900
|
+
const token = config.getToken();
|
|
1901
|
+
if (!token) {
|
|
1902
|
+
console.log(import_chalk14.default.red("Not authenticated. Run `sylphx login` first."));
|
|
2050
1903
|
process.exit(1);
|
|
2051
1904
|
}
|
|
2052
1905
|
return token;
|
|
@@ -2063,41 +1916,41 @@ function prompt4(question) {
|
|
|
2063
1916
|
});
|
|
2064
1917
|
});
|
|
2065
1918
|
}
|
|
2066
|
-
var projectsListCommand = new
|
|
2067
|
-
|
|
2068
|
-
const spinner = (0,
|
|
1919
|
+
var projectsListCommand = new import_commander13.Command("list").description("List all projects").action(async () => {
|
|
1920
|
+
requireAuth3();
|
|
1921
|
+
const spinner = (0, import_ora11.default)("Fetching projects...").start();
|
|
2069
1922
|
try {
|
|
2070
1923
|
const projects = await api.listProjects();
|
|
2071
1924
|
spinner.stop();
|
|
2072
1925
|
if (projects.length === 0) {
|
|
2073
|
-
console.log(
|
|
1926
|
+
console.log(import_chalk14.default.dim("\n No projects found.\n"));
|
|
2074
1927
|
return;
|
|
2075
1928
|
}
|
|
2076
1929
|
const colSlug = Math.max(4, ...projects.map((p) => p.slug.length));
|
|
2077
1930
|
const colName = Math.max(4, ...projects.map((p) => p.name.length));
|
|
2078
1931
|
console.log("");
|
|
2079
|
-
console.log(
|
|
2080
|
-
console.log(
|
|
1932
|
+
console.log(import_chalk14.default.bold(" Projects"));
|
|
1933
|
+
console.log(import_chalk14.default.dim(` ${"\u2500".repeat(colSlug + colName + 30)}`));
|
|
2081
1934
|
console.log(
|
|
2082
|
-
|
|
1935
|
+
import_chalk14.default.dim(` ${"SLUG".padEnd(colSlug)} ${"NAME".padEnd(colName)} ${"ENVIRONMENTS"}`)
|
|
2083
1936
|
);
|
|
2084
|
-
console.log(
|
|
1937
|
+
console.log(import_chalk14.default.dim(` ${"\u2500".repeat(colSlug + colName + 30)}`));
|
|
2085
1938
|
for (const p of projects) {
|
|
2086
|
-
const envNames = p.environments && p.environments.length > 0 ? p.environments.map((e) => e.name || e.envType || e.id).join(", ") :
|
|
1939
|
+
const envNames = p.environments && p.environments.length > 0 ? p.environments.map((e) => e.name || e.envType || e.id).join(", ") : import_chalk14.default.dim("\u2014");
|
|
2087
1940
|
console.log(
|
|
2088
|
-
` ${
|
|
1941
|
+
` ${import_chalk14.default.cyan(p.slug.padEnd(colSlug))} ${p.name.padEnd(colName)} ${envNames}`
|
|
2089
1942
|
);
|
|
2090
1943
|
}
|
|
2091
1944
|
console.log("");
|
|
2092
1945
|
} catch (err) {
|
|
2093
|
-
spinner.fail(
|
|
1946
|
+
spinner.fail(import_chalk14.default.red(`Failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
2094
1947
|
process.exit(1);
|
|
2095
1948
|
}
|
|
2096
1949
|
});
|
|
2097
|
-
var projectsCreateCommand = new
|
|
2098
|
-
|
|
1950
|
+
var projectsCreateCommand = new import_commander13.Command("create").description("Create a new project (without linking the current directory)").argument("<name>", "Project name").option("--git <repo>", "Git repository (e.g. owner/repo)").option("--port <port>", "Application port").action(async (name, opts) => {
|
|
1951
|
+
requireAuth3();
|
|
2099
1952
|
const slug = slugify2(name);
|
|
2100
|
-
const spinner = (0,
|
|
1953
|
+
const spinner = (0, import_ora11.default)(`Creating project ${import_chalk14.default.bold(name)}...`).start();
|
|
2101
1954
|
try {
|
|
2102
1955
|
const project = await api.createProject({
|
|
2103
1956
|
name,
|
|
@@ -2105,63 +1958,63 @@ var projectsCreateCommand = new import_commander12.Command("create").description
|
|
|
2105
1958
|
...opts.git ? { gitRepository: opts.git } : {},
|
|
2106
1959
|
...opts.port ? { port: Number.parseInt(opts.port, 10) } : {}
|
|
2107
1960
|
});
|
|
2108
|
-
spinner.succeed(
|
|
1961
|
+
spinner.succeed(import_chalk14.default.green(`\u2713 Created project ${import_chalk14.default.bold(project.name)}`));
|
|
2109
1962
|
console.log("");
|
|
2110
|
-
console.log(
|
|
2111
|
-
console.log(
|
|
1963
|
+
console.log(import_chalk14.default.dim(` ID : ${project.id}`));
|
|
1964
|
+
console.log(import_chalk14.default.dim(` Slug : ${project.slug}`));
|
|
2112
1965
|
console.log("");
|
|
2113
1966
|
console.log(
|
|
2114
|
-
|
|
1967
|
+
import_chalk14.default.dim(` Run ${import_chalk14.default.cyan("sylphx link")} to link this project to a directory.`)
|
|
2115
1968
|
);
|
|
2116
1969
|
console.log("");
|
|
2117
1970
|
} catch (err) {
|
|
2118
|
-
spinner.fail(
|
|
1971
|
+
spinner.fail(import_chalk14.default.red(`Failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
2119
1972
|
process.exit(1);
|
|
2120
1973
|
}
|
|
2121
1974
|
});
|
|
2122
|
-
var projectsDeleteCommand = new
|
|
2123
|
-
|
|
1975
|
+
var projectsDeleteCommand = new import_commander13.Command("delete").description("Delete a project").argument("<id>", "Project ID or slug").option("--force", "Skip confirmation prompt").action(async (id, opts) => {
|
|
1976
|
+
requireAuth3();
|
|
2124
1977
|
if (!opts.force) {
|
|
2125
1978
|
console.log("");
|
|
2126
1979
|
console.log(
|
|
2127
|
-
|
|
1980
|
+
import_chalk14.default.yellow(` \u26A0 You are about to permanently delete project ${import_chalk14.default.bold(id)}.`)
|
|
2128
1981
|
);
|
|
2129
|
-
console.log(
|
|
1982
|
+
console.log(import_chalk14.default.yellow(" This action cannot be undone."));
|
|
2130
1983
|
console.log("");
|
|
2131
1984
|
const answer = await prompt4(" Type the project ID/slug to confirm");
|
|
2132
1985
|
if (answer !== id) {
|
|
2133
|
-
console.log(
|
|
1986
|
+
console.log(import_chalk14.default.red("Confirmation did not match. Aborted."));
|
|
2134
1987
|
process.exit(1);
|
|
2135
1988
|
}
|
|
2136
1989
|
}
|
|
2137
|
-
const spinner = (0,
|
|
1990
|
+
const spinner = (0, import_ora11.default)(`Deleting project ${import_chalk14.default.bold(id)}...`).start();
|
|
2138
1991
|
try {
|
|
2139
1992
|
await api.deleteProject(id);
|
|
2140
|
-
spinner.succeed(
|
|
1993
|
+
spinner.succeed(import_chalk14.default.green(`\u2713 Deleted project ${import_chalk14.default.bold(id)}`));
|
|
2141
1994
|
} catch (err) {
|
|
2142
|
-
spinner.fail(
|
|
1995
|
+
spinner.fail(import_chalk14.default.red(`Failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
2143
1996
|
process.exit(1);
|
|
2144
1997
|
}
|
|
2145
1998
|
});
|
|
2146
|
-
var projectsCommand = new
|
|
1999
|
+
var projectsCommand = new import_commander13.Command("projects").description("Manage Sylphx projects").addCommand(projectsListCommand).addCommand(projectsCreateCommand).addCommand(projectsDeleteCommand);
|
|
2147
2000
|
|
|
2148
2001
|
// src/commands/promote.ts
|
|
2149
|
-
var
|
|
2150
|
-
var
|
|
2151
|
-
var
|
|
2152
|
-
var promoteCommand = new
|
|
2002
|
+
var import_chalk15 = __toESM(require("chalk"));
|
|
2003
|
+
var import_commander14 = require("commander");
|
|
2004
|
+
var import_ora12 = __toESM(require("ora"));
|
|
2005
|
+
var promoteCommand = new import_commander14.Command("promote").description("Promote an environment (e.g. staging \u2192 production)").option("--from <env>", "Source environment (default: staging)", "staging").option("--to <env>", "Target environment (default: production)", "production").option("--force", "Skip confirmation prompt").action(async (opts) => {
|
|
2153
2006
|
const token = config.getToken();
|
|
2154
2007
|
if (!token) {
|
|
2155
|
-
console.log(
|
|
2008
|
+
console.log(import_chalk15.default.red("Not authenticated. Run `sylphx login` first."));
|
|
2156
2009
|
process.exit(1);
|
|
2157
2010
|
}
|
|
2158
2011
|
const linked = config.getLinkedApp();
|
|
2159
2012
|
if (!linked) {
|
|
2160
|
-
console.log(
|
|
2013
|
+
console.log(import_chalk15.default.red("No app linked. Run `sylphx link` first."));
|
|
2161
2014
|
process.exit(1);
|
|
2162
2015
|
}
|
|
2163
2016
|
if (opts.from === opts.to) {
|
|
2164
|
-
console.log(
|
|
2017
|
+
console.log(import_chalk15.default.red("Source and target environments must be different."));
|
|
2165
2018
|
process.exit(1);
|
|
2166
2019
|
}
|
|
2167
2020
|
if (!opts.force) {
|
|
@@ -2169,13 +2022,13 @@ var promoteCommand = new import_commander13.Command("promote").description("Prom
|
|
|
2169
2022
|
const rl = readline9.createInterface({ input: process.stdin, output: process.stdout });
|
|
2170
2023
|
await new Promise((resolve) => {
|
|
2171
2024
|
rl.question(
|
|
2172
|
-
|
|
2173
|
-
` Promote ${
|
|
2025
|
+
import_chalk15.default.yellow(
|
|
2026
|
+
` Promote ${import_chalk15.default.bold(linked.appId)}: ${import_chalk15.default.cyan(opts.from)} \u2192 ${import_chalk15.default.green(opts.to)}? (y/N) `
|
|
2174
2027
|
),
|
|
2175
2028
|
(answer) => {
|
|
2176
2029
|
rl.close();
|
|
2177
2030
|
if (answer.toLowerCase() !== "y") {
|
|
2178
|
-
console.log(
|
|
2031
|
+
console.log(import_chalk15.default.dim(" Cancelled."));
|
|
2179
2032
|
process.exit(0);
|
|
2180
2033
|
}
|
|
2181
2034
|
resolve();
|
|
@@ -2183,7 +2036,7 @@ var promoteCommand = new import_commander13.Command("promote").description("Prom
|
|
|
2183
2036
|
);
|
|
2184
2037
|
});
|
|
2185
2038
|
}
|
|
2186
|
-
const spinner = (0,
|
|
2039
|
+
const spinner = (0, import_ora12.default)(`Resolving environments...`).start();
|
|
2187
2040
|
try {
|
|
2188
2041
|
const envs = await api.listEnvironments(linked.appId);
|
|
2189
2042
|
const sourceEnv = envs.find(
|
|
@@ -2193,48 +2046,48 @@ var promoteCommand = new import_commander13.Command("promote").description("Prom
|
|
|
2193
2046
|
(e) => (e.envType ?? e.name ?? "").toLowerCase() === opts.to.toLowerCase()
|
|
2194
2047
|
);
|
|
2195
2048
|
if (!sourceEnv) {
|
|
2196
|
-
spinner.fail(
|
|
2197
|
-
console.log(
|
|
2049
|
+
spinner.fail(import_chalk15.default.red(`Source environment '${opts.from}' not found.`));
|
|
2050
|
+
console.log(import_chalk15.default.dim(` Available: ${envs.map((e) => e.envType ?? e.name).join(", ")}`));
|
|
2198
2051
|
process.exit(1);
|
|
2199
2052
|
}
|
|
2200
2053
|
if (!targetEnv) {
|
|
2201
|
-
spinner.fail(
|
|
2202
|
-
console.log(
|
|
2054
|
+
spinner.fail(import_chalk15.default.red(`Target environment '${opts.to}' not found.`));
|
|
2055
|
+
console.log(import_chalk15.default.dim(` Available: ${envs.map((e) => e.envType ?? e.name).join(", ")}`));
|
|
2203
2056
|
process.exit(1);
|
|
2204
2057
|
}
|
|
2205
2058
|
spinner.text = `Promoting ${opts.from} \u2192 ${opts.to}...`;
|
|
2206
2059
|
const result = await api.promoteEnvironment(linked.appId, targetEnv.id, sourceEnv.id);
|
|
2207
2060
|
if (result.promoted === 0) {
|
|
2208
2061
|
spinner.warn(
|
|
2209
|
-
|
|
2210
|
-
`No services promoted from ${
|
|
2062
|
+
import_chalk15.default.yellow(
|
|
2063
|
+
`No services promoted from ${import_chalk15.default.bold(opts.from)} \u2014 nothing to push (source may have no deployed image yet)`
|
|
2211
2064
|
)
|
|
2212
2065
|
);
|
|
2213
2066
|
} else {
|
|
2214
2067
|
spinner.succeed(
|
|
2215
|
-
|
|
2216
|
-
`\u2713 Promoted ${
|
|
2068
|
+
import_chalk15.default.green(
|
|
2069
|
+
`\u2713 Promoted ${import_chalk15.default.bold(opts.from)} \u2192 ${import_chalk15.default.bold(opts.to)} (${result.promoted} service${result.promoted !== 1 ? "s" : ""})`
|
|
2217
2070
|
)
|
|
2218
2071
|
);
|
|
2219
2072
|
console.log(
|
|
2220
|
-
|
|
2221
|
-
Deployments queued. Run ${
|
|
2073
|
+
import_chalk15.default.dim(`
|
|
2074
|
+
Deployments queued. Run ${import_chalk15.default.cyan("sylphx status")} to monitor.`)
|
|
2222
2075
|
);
|
|
2223
2076
|
}
|
|
2224
2077
|
} catch (err) {
|
|
2225
|
-
spinner.fail(
|
|
2078
|
+
spinner.fail(import_chalk15.default.red(`Promote failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
2226
2079
|
process.exit(1);
|
|
2227
2080
|
}
|
|
2228
2081
|
});
|
|
2229
2082
|
|
|
2230
2083
|
// src/commands/resources.ts
|
|
2231
|
-
var
|
|
2232
|
-
var
|
|
2233
|
-
var
|
|
2084
|
+
var import_chalk16 = __toESM(require("chalk"));
|
|
2085
|
+
var import_commander15 = require("commander");
|
|
2086
|
+
var import_ora13 = __toESM(require("ora"));
|
|
2234
2087
|
function requireLinkedApp4() {
|
|
2235
2088
|
const linked = config.getLinkedApp();
|
|
2236
2089
|
if (!linked) {
|
|
2237
|
-
console.log(
|
|
2090
|
+
console.log(import_chalk16.default.red("No app linked. Run `sylphx link` first."));
|
|
2238
2091
|
process.exit(1);
|
|
2239
2092
|
}
|
|
2240
2093
|
return linked;
|
|
@@ -2242,145 +2095,145 @@ function requireLinkedApp4() {
|
|
|
2242
2095
|
function requireToken2() {
|
|
2243
2096
|
const token = config.getToken();
|
|
2244
2097
|
if (!token) {
|
|
2245
|
-
console.log(
|
|
2098
|
+
console.log(import_chalk16.default.red("Not authenticated. Run `sylphx login` first."));
|
|
2246
2099
|
process.exit(1);
|
|
2247
2100
|
}
|
|
2248
2101
|
return token;
|
|
2249
2102
|
}
|
|
2250
|
-
var listCmd2 = new
|
|
2103
|
+
var listCmd2 = new import_commander15.Command("list").description("List managed resources (databases, volumes, storage)").option("--kind <kind>", "Filter by kind: database, volume, storage").action(async (opts) => {
|
|
2251
2104
|
requireToken2();
|
|
2252
|
-
const spinner = (0,
|
|
2105
|
+
const spinner = (0, import_ora13.default)("Fetching resources...").start();
|
|
2253
2106
|
try {
|
|
2254
2107
|
const resources = await api.listDatabases();
|
|
2255
2108
|
spinner.stop();
|
|
2256
2109
|
if (resources.length === 0) {
|
|
2257
|
-
console.log(
|
|
2110
|
+
console.log(import_chalk16.default.dim(` No resources found.`));
|
|
2258
2111
|
return;
|
|
2259
2112
|
}
|
|
2260
2113
|
console.log();
|
|
2261
2114
|
console.log(
|
|
2262
|
-
` ${
|
|
2115
|
+
` ${import_chalk16.default.bold("NAME".padEnd(24))} ${"KIND".padEnd(12)} ${"STATUS".padEnd(14)} ID`
|
|
2263
2116
|
);
|
|
2264
2117
|
console.log(` ${"\u2500".repeat(72)}`);
|
|
2265
2118
|
for (const r of resources) {
|
|
2266
|
-
const statusColor2 = r.status === "ready" ?
|
|
2119
|
+
const statusColor2 = r.status === "ready" ? import_chalk16.default.green((r.status ?? "unknown").padEnd(14)) : import_chalk16.default.yellow((r.status ?? "unknown").padEnd(14));
|
|
2267
2120
|
console.log(
|
|
2268
|
-
` ${
|
|
2121
|
+
` ${import_chalk16.default.cyan(r.name.padEnd(24))} ${"database".padEnd(12)} ${statusColor2} ${import_chalk16.default.dim(r.id)}`
|
|
2269
2122
|
);
|
|
2270
2123
|
}
|
|
2271
2124
|
console.log();
|
|
2272
2125
|
} catch (err) {
|
|
2273
|
-
spinner.fail(
|
|
2126
|
+
spinner.fail(import_chalk16.default.red(err instanceof Error ? err.message : String(err)));
|
|
2274
2127
|
process.exit(1);
|
|
2275
2128
|
}
|
|
2276
2129
|
});
|
|
2277
|
-
var getCmd2 = new
|
|
2130
|
+
var getCmd2 = new import_commander15.Command("get").description("Get details of a resource").argument("<id>", "Resource ID").action(async (id) => {
|
|
2278
2131
|
requireToken2();
|
|
2279
|
-
const spinner = (0,
|
|
2132
|
+
const spinner = (0, import_ora13.default)(`Fetching resource ${id}...`).start();
|
|
2280
2133
|
try {
|
|
2281
2134
|
const r = await api.getDatabase(id);
|
|
2282
2135
|
spinner.stop();
|
|
2283
2136
|
console.log();
|
|
2284
|
-
console.log(` ${
|
|
2285
|
-
console.log(` ${
|
|
2137
|
+
console.log(` ${import_chalk16.default.bold("Name:")} ${import_chalk16.default.cyan(r.name)}`);
|
|
2138
|
+
console.log(` ${import_chalk16.default.bold("ID:")} ${r.id}`);
|
|
2286
2139
|
console.log(
|
|
2287
|
-
` ${
|
|
2140
|
+
` ${import_chalk16.default.bold("Status:")} ${r.status === "ready" ? import_chalk16.default.green(r.status) : import_chalk16.default.yellow(r.status ?? "unknown")}`
|
|
2288
2141
|
);
|
|
2289
|
-
if (r.tier) console.log(` ${
|
|
2290
|
-
if (r.host) console.log(` ${
|
|
2142
|
+
if (r.tier) console.log(` ${import_chalk16.default.bold("Tier:")} ${r.tier}`);
|
|
2143
|
+
if (r.host) console.log(` ${import_chalk16.default.bold("Host:")} ${r.host}${r.port ? `:${r.port}` : ""}`);
|
|
2291
2144
|
if (r.connectionString) {
|
|
2292
|
-
console.log(` ${
|
|
2145
|
+
console.log(` ${import_chalk16.default.bold("DSN:")} ${import_chalk16.default.dim(r.connectionString)}`);
|
|
2293
2146
|
}
|
|
2294
|
-
if (r.env) console.log(` ${
|
|
2147
|
+
if (r.env) console.log(` ${import_chalk16.default.bold("Env:")} ${r.env}`);
|
|
2295
2148
|
console.log();
|
|
2296
2149
|
} catch (err) {
|
|
2297
|
-
spinner.fail(
|
|
2150
|
+
spinner.fail(import_chalk16.default.red(err instanceof Error ? err.message : String(err)));
|
|
2298
2151
|
process.exit(1);
|
|
2299
2152
|
}
|
|
2300
2153
|
});
|
|
2301
|
-
var bindingsCmd = new
|
|
2154
|
+
var bindingsCmd = new import_commander15.Command("bindings").description("List project bindings for a resource").argument("<id>", "Resource ID").action(async (id) => {
|
|
2302
2155
|
requireToken2();
|
|
2303
|
-
const spinner = (0,
|
|
2156
|
+
const spinner = (0, import_ora13.default)(`Fetching bindings for ${id}...`).start();
|
|
2304
2157
|
try {
|
|
2305
2158
|
const bindings = await api.listResourceBindings(id);
|
|
2306
2159
|
spinner.stop();
|
|
2307
2160
|
if (bindings.length === 0) {
|
|
2308
|
-
console.log(
|
|
2161
|
+
console.log(import_chalk16.default.dim(" No bindings. Use `sylphx resources bind <id>` to link."));
|
|
2309
2162
|
return;
|
|
2310
2163
|
}
|
|
2311
2164
|
console.log();
|
|
2312
2165
|
console.log(
|
|
2313
|
-
` ${
|
|
2166
|
+
` ${import_chalk16.default.bold("BINDING ID".padEnd(26))} ${"PROJECT".padEnd(24)} ${"ENV".padEnd(12)} ROLE`
|
|
2314
2167
|
);
|
|
2315
2168
|
console.log(` ${"\u2500".repeat(80)}`);
|
|
2316
2169
|
for (const b of bindings) {
|
|
2317
2170
|
const project = b.projectName ?? b.projectSlug ?? "\u2014";
|
|
2318
2171
|
const env = b.envName ?? "\u2014";
|
|
2319
2172
|
console.log(
|
|
2320
|
-
` ${
|
|
2173
|
+
` ${import_chalk16.default.dim(b.id.padEnd(26))} ${project.padEnd(24)} ${env.padEnd(12)} ${b.role}`
|
|
2321
2174
|
);
|
|
2322
2175
|
}
|
|
2323
2176
|
console.log();
|
|
2324
2177
|
} catch (err) {
|
|
2325
|
-
spinner.fail(
|
|
2178
|
+
spinner.fail(import_chalk16.default.red(err instanceof Error ? err.message : String(err)));
|
|
2326
2179
|
process.exit(1);
|
|
2327
2180
|
}
|
|
2328
2181
|
});
|
|
2329
|
-
var bindCmd = new
|
|
2182
|
+
var bindCmd = new import_commander15.Command("bind").description("Bind a resource to this project environment").argument("<id>", "Resource ID (e.g. res_xxx)").option("--env <env>", "Environment (default: production)", "production").option(
|
|
2330
2183
|
"--role <role>",
|
|
2331
2184
|
"Binding role: primary, replica, analytics, backup (default: primary)",
|
|
2332
2185
|
"primary"
|
|
2333
2186
|
).action(async (id, opts) => {
|
|
2334
2187
|
requireToken2();
|
|
2335
2188
|
const linked = requireLinkedApp4();
|
|
2336
|
-
const spinner = (0,
|
|
2189
|
+
const spinner = (0, import_ora13.default)(`Binding resource ${id} to ${linked.appId} [${opts.env}]...`).start();
|
|
2337
2190
|
try {
|
|
2338
2191
|
const binding = await api.bindResource(id, {
|
|
2339
2192
|
projectId: linked.appId,
|
|
2340
2193
|
envType: opts.env,
|
|
2341
2194
|
role: opts.role
|
|
2342
2195
|
});
|
|
2343
|
-
spinner.succeed(
|
|
2196
|
+
spinner.succeed(import_chalk16.default.green(`\u2713 Resource bound (${binding.role})`));
|
|
2344
2197
|
console.log();
|
|
2345
|
-
console.log(` ${
|
|
2346
|
-
console.log(` ${
|
|
2198
|
+
console.log(` ${import_chalk16.default.dim("Binding ID:")} ${binding.id}`);
|
|
2199
|
+
console.log(` ${import_chalk16.default.dim("Env:")} ${binding.envName ?? opts.env}`);
|
|
2347
2200
|
console.log(
|
|
2348
|
-
|
|
2201
|
+
import_chalk16.default.dim(
|
|
2349
2202
|
`
|
|
2350
|
-
Run ${
|
|
2203
|
+
Run ${import_chalk16.default.cyan("sylphx deploy")} to apply the connection vars to your deployment.`
|
|
2351
2204
|
)
|
|
2352
2205
|
);
|
|
2353
2206
|
} catch (err) {
|
|
2354
|
-
spinner.fail(
|
|
2207
|
+
spinner.fail(import_chalk16.default.red(err instanceof Error ? err.message : String(err)));
|
|
2355
2208
|
process.exit(1);
|
|
2356
2209
|
}
|
|
2357
2210
|
});
|
|
2358
|
-
var unbindCmd = new
|
|
2211
|
+
var unbindCmd = new import_commander15.Command("unbind").description("Remove a resource binding").argument("<id>", "Resource ID").argument("<binding-id>", "Binding ID (from `sylphx resources bindings <id>`)").action(async (id, bindingId) => {
|
|
2359
2212
|
requireToken2();
|
|
2360
|
-
const spinner = (0,
|
|
2213
|
+
const spinner = (0, import_ora13.default)(`Removing binding ${bindingId}...`).start();
|
|
2361
2214
|
try {
|
|
2362
2215
|
await api.unbindResource(id, bindingId);
|
|
2363
|
-
spinner.succeed(
|
|
2216
|
+
spinner.succeed(import_chalk16.default.green(`\u2713 Binding removed`));
|
|
2364
2217
|
} catch (err) {
|
|
2365
|
-
spinner.fail(
|
|
2218
|
+
spinner.fail(import_chalk16.default.red(err instanceof Error ? err.message : String(err)));
|
|
2366
2219
|
process.exit(1);
|
|
2367
2220
|
}
|
|
2368
2221
|
});
|
|
2369
|
-
var resourcesCommand = new
|
|
2222
|
+
var resourcesCommand = new import_commander15.Command("resources").description("Manage resources and project bindings").addCommand(listCmd2).addCommand(getCmd2).addCommand(bindingsCmd).addCommand(bindCmd).addCommand(unbindCmd).action(() => resourcesCommand.help());
|
|
2370
2223
|
|
|
2371
2224
|
// src/commands/rollback.ts
|
|
2372
|
-
var
|
|
2373
|
-
var
|
|
2374
|
-
var
|
|
2375
|
-
var rollbackCommand = new
|
|
2225
|
+
var import_chalk17 = __toESM(require("chalk"));
|
|
2226
|
+
var import_commander16 = require("commander");
|
|
2227
|
+
var import_ora14 = __toESM(require("ora"));
|
|
2228
|
+
var rollbackCommand = new import_commander16.Command("rollback").description("Rollback to the previous deployment").option("--env <env>", "Environment to rollback (e.g. production, staging)").option("--deployment <id>", "Rollback to a specific deployment ID").option("--force", "Skip confirmation prompt").action(async (opts) => {
|
|
2376
2229
|
const token = config.getToken();
|
|
2377
2230
|
if (!token) {
|
|
2378
|
-
console.log(
|
|
2231
|
+
console.log(import_chalk17.default.red("Not authenticated. Run `sylphx login` first."));
|
|
2379
2232
|
process.exit(1);
|
|
2380
2233
|
}
|
|
2381
2234
|
const linked = config.getLinkedApp();
|
|
2382
2235
|
if (!linked) {
|
|
2383
|
-
console.log(
|
|
2236
|
+
console.log(import_chalk17.default.red("No app linked. Run `sylphx link` first."));
|
|
2384
2237
|
process.exit(1);
|
|
2385
2238
|
}
|
|
2386
2239
|
const envType = opts.env ?? linked.defaultEnv ?? "production";
|
|
@@ -2388,13 +2241,13 @@ var rollbackCommand = new import_commander15.Command("rollback").description("Ro
|
|
|
2388
2241
|
const readline9 = await import("readline");
|
|
2389
2242
|
const rl = readline9.createInterface({ input: process.stdin, output: process.stdout });
|
|
2390
2243
|
await new Promise((resolve) => {
|
|
2391
|
-
const label = opts.deployment ? `deployment ${
|
|
2244
|
+
const label = opts.deployment ? `deployment ${import_chalk17.default.bold(opts.deployment)}` : `previous deployment`;
|
|
2392
2245
|
rl.question(
|
|
2393
|
-
|
|
2246
|
+
import_chalk17.default.yellow(` Rollback ${import_chalk17.default.bold(linked.appId)} [${envType}] to ${label}? (y/N) `),
|
|
2394
2247
|
(answer) => {
|
|
2395
2248
|
rl.close();
|
|
2396
2249
|
if (answer.toLowerCase() !== "y") {
|
|
2397
|
-
console.log(
|
|
2250
|
+
console.log(import_chalk17.default.dim(" Cancelled."));
|
|
2398
2251
|
process.exit(0);
|
|
2399
2252
|
}
|
|
2400
2253
|
resolve();
|
|
@@ -2402,7 +2255,7 @@ var rollbackCommand = new import_commander15.Command("rollback").description("Ro
|
|
|
2402
2255
|
);
|
|
2403
2256
|
});
|
|
2404
2257
|
}
|
|
2405
|
-
const spinner = (0,
|
|
2258
|
+
const spinner = (0, import_ora14.default)(`Rolling back ${linked.appId} [${envType}]...`).start();
|
|
2406
2259
|
try {
|
|
2407
2260
|
let rollbackBody;
|
|
2408
2261
|
if (opts.deployment) {
|
|
@@ -2414,7 +2267,7 @@ var rollbackCommand = new import_commander15.Command("rollback").description("Ro
|
|
|
2414
2267
|
);
|
|
2415
2268
|
if (!envEntry?.envId) {
|
|
2416
2269
|
spinner.fail(
|
|
2417
|
-
|
|
2270
|
+
import_chalk17.default.red(
|
|
2418
2271
|
`Could not find environment '${envType}'. Run \`sylphx status\` to see available environments.`
|
|
2419
2272
|
)
|
|
2420
2273
|
);
|
|
@@ -2423,21 +2276,21 @@ var rollbackCommand = new import_commander15.Command("rollback").description("Ro
|
|
|
2423
2276
|
rollbackBody = { envId: envEntry.envId };
|
|
2424
2277
|
}
|
|
2425
2278
|
const result = await api.rollback(linked.appId, rollbackBody);
|
|
2426
|
-
spinner.succeed(
|
|
2279
|
+
spinner.succeed(import_chalk17.default.green(`\u2713 Rollback initiated`));
|
|
2427
2280
|
if (result.deploymentId) {
|
|
2428
|
-
console.log(
|
|
2281
|
+
console.log(import_chalk17.default.dim(` Deployment ID: ${result.deploymentId}`));
|
|
2429
2282
|
}
|
|
2430
2283
|
if (result.status) {
|
|
2431
|
-
console.log(
|
|
2284
|
+
console.log(import_chalk17.default.dim(` Status: ${result.status}`));
|
|
2432
2285
|
}
|
|
2433
2286
|
if (result.message) {
|
|
2434
|
-
console.log(
|
|
2287
|
+
console.log(import_chalk17.default.dim(` ${result.message}`));
|
|
2435
2288
|
}
|
|
2436
|
-
console.log(
|
|
2437
|
-
Run ${
|
|
2289
|
+
console.log(import_chalk17.default.dim(`
|
|
2290
|
+
Run ${import_chalk17.default.cyan("sylphx status")} to monitor progress.`));
|
|
2438
2291
|
} catch (err) {
|
|
2439
2292
|
spinner.fail(
|
|
2440
|
-
|
|
2293
|
+
import_chalk17.default.red(`Rollback failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
2441
2294
|
);
|
|
2442
2295
|
process.exit(1);
|
|
2443
2296
|
}
|
|
@@ -2445,13 +2298,13 @@ var rollbackCommand = new import_commander15.Command("rollback").description("Ro
|
|
|
2445
2298
|
|
|
2446
2299
|
// src/commands/services.ts
|
|
2447
2300
|
var import_node_readline5 = __toESM(require("readline"));
|
|
2448
|
-
var
|
|
2449
|
-
var
|
|
2450
|
-
var
|
|
2301
|
+
var import_chalk18 = __toESM(require("chalk"));
|
|
2302
|
+
var import_commander17 = require("commander");
|
|
2303
|
+
var import_ora15 = __toESM(require("ora"));
|
|
2451
2304
|
function requireLinkedApp5() {
|
|
2452
2305
|
const linked = config.getLinkedApp();
|
|
2453
2306
|
if (!linked) {
|
|
2454
|
-
console.log(
|
|
2307
|
+
console.log(import_chalk18.default.red("No app linked. Run `sylphx link` first."));
|
|
2455
2308
|
process.exit(1);
|
|
2456
2309
|
}
|
|
2457
2310
|
return linked;
|
|
@@ -2459,180 +2312,180 @@ function requireLinkedApp5() {
|
|
|
2459
2312
|
function requireToken3() {
|
|
2460
2313
|
const token = config.getToken();
|
|
2461
2314
|
if (!token) {
|
|
2462
|
-
console.log(
|
|
2315
|
+
console.log(import_chalk18.default.red("Not authenticated. Run `sylphx login` first."));
|
|
2463
2316
|
process.exit(1);
|
|
2464
2317
|
}
|
|
2465
2318
|
return token;
|
|
2466
2319
|
}
|
|
2467
|
-
var listCmd3 = new
|
|
2320
|
+
var listCmd3 = new import_commander17.Command("list").description("List all services in this project").action(async () => {
|
|
2468
2321
|
requireToken3();
|
|
2469
2322
|
const linked = requireLinkedApp5();
|
|
2470
|
-
const spinner = (0,
|
|
2323
|
+
const spinner = (0, import_ora15.default)("Fetching services...").start();
|
|
2471
2324
|
try {
|
|
2472
2325
|
const services = await api.listServices(linked.appId);
|
|
2473
2326
|
spinner.stop();
|
|
2474
2327
|
if (services.length === 0) {
|
|
2475
|
-
console.log(
|
|
2328
|
+
console.log(import_chalk18.default.dim(" No services defined."));
|
|
2476
2329
|
return;
|
|
2477
2330
|
}
|
|
2478
2331
|
console.log();
|
|
2479
|
-
console.log(` ${
|
|
2332
|
+
console.log(` ${import_chalk18.default.bold("NAME".padEnd(24))} ${"REPO".padEnd(36)} ENVS`);
|
|
2480
2333
|
console.log(` ${"\u2500".repeat(70)}`);
|
|
2481
2334
|
for (const svc of services) {
|
|
2482
|
-
const repo = svc.githubRepo ??
|
|
2335
|
+
const repo = svc.githubRepo ?? import_chalk18.default.dim("\u2014");
|
|
2483
2336
|
const envs = svc.environmentCount ?? 0;
|
|
2484
|
-
console.log(` ${
|
|
2337
|
+
console.log(` ${import_chalk18.default.cyan(svc.name.padEnd(24))} ${repo.padEnd(36)} ${envs}`);
|
|
2485
2338
|
}
|
|
2486
2339
|
console.log();
|
|
2487
2340
|
} catch (err) {
|
|
2488
|
-
spinner.fail(
|
|
2341
|
+
spinner.fail(import_chalk18.default.red(err instanceof Error ? err.message : String(err)));
|
|
2489
2342
|
process.exit(1);
|
|
2490
2343
|
}
|
|
2491
2344
|
});
|
|
2492
|
-
var getCmd3 = new
|
|
2345
|
+
var getCmd3 = new import_commander17.Command("get").description("Show details of a service").argument("<name>", "Service name").action(async (name) => {
|
|
2493
2346
|
requireToken3();
|
|
2494
2347
|
const linked = requireLinkedApp5();
|
|
2495
|
-
const spinner = (0,
|
|
2348
|
+
const spinner = (0, import_ora15.default)(`Fetching service '${name}'...`).start();
|
|
2496
2349
|
try {
|
|
2497
2350
|
const svc = await api.getService(linked.appId, name);
|
|
2498
2351
|
spinner.stop();
|
|
2499
2352
|
console.log();
|
|
2500
|
-
console.log(` ${
|
|
2501
|
-
console.log(` ${
|
|
2502
|
-
if (svc.githubRepo) console.log(` ${
|
|
2503
|
-
if (svc.githubBranch) console.log(` ${
|
|
2353
|
+
console.log(` ${import_chalk18.default.bold("Name:")} ${import_chalk18.default.cyan(svc.name)}`);
|
|
2354
|
+
console.log(` ${import_chalk18.default.bold("ID:")} ${svc.id}`);
|
|
2355
|
+
if (svc.githubRepo) console.log(` ${import_chalk18.default.bold("Repo:")} ${svc.githubRepo}`);
|
|
2356
|
+
if (svc.githubBranch) console.log(` ${import_chalk18.default.bold("Branch:")} ${svc.githubBranch}`);
|
|
2504
2357
|
if (svc.dockerfilePath)
|
|
2505
|
-
console.log(` ${
|
|
2506
|
-
if (svc.port) console.log(` ${
|
|
2358
|
+
console.log(` ${import_chalk18.default.bold("Dockerfile:")} ${svc.dockerfilePath}`);
|
|
2359
|
+
if (svc.port) console.log(` ${import_chalk18.default.bold("Port:")} ${svc.port}`);
|
|
2507
2360
|
if (svc.publicNetworking !== void 0 && svc.publicNetworking !== null)
|
|
2508
2361
|
console.log(
|
|
2509
|
-
` ${
|
|
2362
|
+
` ${import_chalk18.default.bold("Public:")} ${svc.publicNetworking ? import_chalk18.default.green("yes") : import_chalk18.default.dim("no")}`
|
|
2510
2363
|
);
|
|
2511
2364
|
console.log();
|
|
2512
2365
|
} catch (err) {
|
|
2513
|
-
spinner.fail(
|
|
2366
|
+
spinner.fail(import_chalk18.default.red(err instanceof Error ? err.message : String(err)));
|
|
2514
2367
|
process.exit(1);
|
|
2515
2368
|
}
|
|
2516
2369
|
});
|
|
2517
|
-
var deployCmd = new
|
|
2370
|
+
var deployCmd = new import_commander17.Command("deploy").description("Deploy a specific service").argument("<name>", "Service name").option("--env <env>", "Environment (default: production)", "production").action(async (name, opts) => {
|
|
2518
2371
|
requireToken3();
|
|
2519
2372
|
const linked = requireLinkedApp5();
|
|
2520
|
-
const spinner = (0,
|
|
2373
|
+
const spinner = (0, import_ora15.default)(`Deploying service '${name}' [${opts.env}]...`).start();
|
|
2521
2374
|
try {
|
|
2522
2375
|
const result = await api.deployService(linked.appId, name, opts.env);
|
|
2523
|
-
spinner.succeed(
|
|
2376
|
+
spinner.succeed(import_chalk18.default.green(`\u2713 Deploy triggered for service '${name}'`));
|
|
2524
2377
|
if (result.deploymentId) {
|
|
2525
|
-
console.log(
|
|
2378
|
+
console.log(import_chalk18.default.dim(` Deployment ID: ${result.deploymentId}`));
|
|
2526
2379
|
}
|
|
2527
|
-
console.log(
|
|
2528
|
-
Run ${
|
|
2380
|
+
console.log(import_chalk18.default.dim(`
|
|
2381
|
+
Run ${import_chalk18.default.cyan("sylphx status")} to monitor.`));
|
|
2529
2382
|
} catch (err) {
|
|
2530
|
-
spinner.fail(
|
|
2383
|
+
spinner.fail(import_chalk18.default.red(err instanceof Error ? err.message : String(err)));
|
|
2531
2384
|
process.exit(1);
|
|
2532
2385
|
}
|
|
2533
2386
|
});
|
|
2534
|
-
var rmCmd2 = new
|
|
2387
|
+
var rmCmd2 = new import_commander17.Command("rm").description("Delete a service").argument("<name>", "Service name").option("--force", "Skip confirmation prompt").action(async (name, opts) => {
|
|
2535
2388
|
requireToken3();
|
|
2536
2389
|
const linked = requireLinkedApp5();
|
|
2537
2390
|
if (!opts.force) {
|
|
2538
2391
|
const rl = import_node_readline5.default.createInterface({ input: process.stdin, output: process.stdout });
|
|
2539
2392
|
await new Promise((resolve) => {
|
|
2540
|
-
rl.question(
|
|
2393
|
+
rl.question(import_chalk18.default.yellow(` Delete service ${import_chalk18.default.bold(name)}? (y/N) `), (answer) => {
|
|
2541
2394
|
rl.close();
|
|
2542
2395
|
if (answer.toLowerCase() !== "y") {
|
|
2543
|
-
console.log(
|
|
2396
|
+
console.log(import_chalk18.default.dim(" Cancelled."));
|
|
2544
2397
|
process.exit(0);
|
|
2545
2398
|
}
|
|
2546
2399
|
resolve();
|
|
2547
2400
|
});
|
|
2548
2401
|
});
|
|
2549
2402
|
}
|
|
2550
|
-
const spinner = (0,
|
|
2403
|
+
const spinner = (0, import_ora15.default)(`Deleting service '${name}'...`).start();
|
|
2551
2404
|
try {
|
|
2552
2405
|
await api.deleteService(linked.appId, name);
|
|
2553
|
-
spinner.succeed(
|
|
2406
|
+
spinner.succeed(import_chalk18.default.green(`\u2713 Service '${name}' deleted`));
|
|
2554
2407
|
} catch (err) {
|
|
2555
|
-
spinner.fail(
|
|
2408
|
+
spinner.fail(import_chalk18.default.red(err instanceof Error ? err.message : String(err)));
|
|
2556
2409
|
process.exit(1);
|
|
2557
2410
|
}
|
|
2558
2411
|
});
|
|
2559
|
-
var servicesCommand = new
|
|
2412
|
+
var servicesCommand = new import_commander17.Command("services").description("Manage project services").addCommand(listCmd3).addCommand(getCmd3).addCommand(deployCmd).addCommand(rmCmd2).action(() => servicesCommand.help());
|
|
2560
2413
|
|
|
2561
2414
|
// src/commands/status.ts
|
|
2562
|
-
var
|
|
2563
|
-
var
|
|
2564
|
-
var
|
|
2415
|
+
var import_chalk19 = __toESM(require("chalk"));
|
|
2416
|
+
var import_commander18 = require("commander");
|
|
2417
|
+
var import_ora16 = __toESM(require("ora"));
|
|
2565
2418
|
function statusColor(status) {
|
|
2566
2419
|
const s = status.toLowerCase();
|
|
2567
2420
|
if (s === "running" || s === "active" || s === "healthy" || s === "success") {
|
|
2568
|
-
return
|
|
2421
|
+
return import_chalk19.default.green(status);
|
|
2569
2422
|
}
|
|
2570
2423
|
if (s === "deploying" || s === "building" || s === "pending") {
|
|
2571
|
-
return
|
|
2424
|
+
return import_chalk19.default.yellow(status);
|
|
2572
2425
|
}
|
|
2573
2426
|
if (s === "error" || s === "failed" || s === "stopped") {
|
|
2574
|
-
return
|
|
2427
|
+
return import_chalk19.default.red(status);
|
|
2575
2428
|
}
|
|
2576
|
-
return
|
|
2429
|
+
return import_chalk19.default.white(status);
|
|
2577
2430
|
}
|
|
2578
|
-
var statusCommand = new
|
|
2431
|
+
var statusCommand = new import_commander18.Command("status").description("Show deployment status").option("--env <env>", "Environment (e.g. production, staging)").action(async (opts) => {
|
|
2579
2432
|
const token = config.getToken();
|
|
2580
2433
|
if (!token) {
|
|
2581
|
-
console.log(
|
|
2434
|
+
console.log(import_chalk19.default.red("Not authenticated. Run `sylphx login` first."));
|
|
2582
2435
|
process.exit(1);
|
|
2583
2436
|
}
|
|
2584
2437
|
const linked = config.getLinkedApp();
|
|
2585
2438
|
if (!linked) {
|
|
2586
|
-
console.log(
|
|
2439
|
+
console.log(import_chalk19.default.red("No app linked. Run `sylphx link` first."));
|
|
2587
2440
|
process.exit(1);
|
|
2588
2441
|
}
|
|
2589
2442
|
const env = opts.env ?? linked.defaultEnv;
|
|
2590
|
-
const spinner = (0,
|
|
2443
|
+
const spinner = (0, import_ora16.default)(`Fetching status [${env}]...`).start();
|
|
2591
2444
|
try {
|
|
2592
2445
|
const status = await api.getDeploymentStatus(linked.appId);
|
|
2593
2446
|
spinner.stop();
|
|
2594
2447
|
console.log("");
|
|
2595
|
-
console.log(
|
|
2596
|
-
console.log(
|
|
2448
|
+
console.log(import_chalk19.default.bold(" Deployment Status"));
|
|
2449
|
+
console.log(import_chalk19.default.dim(` ${"\u2500".repeat(40)}`));
|
|
2597
2450
|
console.log("");
|
|
2598
|
-
console.log(` App: ${
|
|
2599
|
-
console.log(` Environment: ${
|
|
2451
|
+
console.log(` App: ${import_chalk19.default.cyan(linked.appId)}`);
|
|
2452
|
+
console.log(` Environment: ${import_chalk19.default.white(env)}`);
|
|
2600
2453
|
console.log(` Status: ${statusColor(status.status)}`);
|
|
2601
2454
|
if (status.deployedAt) {
|
|
2602
2455
|
const date = new Date(status.deployedAt);
|
|
2603
|
-
console.log(` Deployed: ${
|
|
2456
|
+
console.log(` Deployed: ${import_chalk19.default.white(date.toLocaleString())}`);
|
|
2604
2457
|
}
|
|
2605
2458
|
const envMatch = status.environments?.find((e) => e.envType === env) ?? status.environments?.find((e) => e.envType === "production") ?? status.environments?.[0];
|
|
2606
2459
|
const displayUrl = status.url ?? envMatch?.url ?? null;
|
|
2607
2460
|
if (displayUrl) {
|
|
2608
|
-
console.log(` URL: ${
|
|
2461
|
+
console.log(` URL: ${import_chalk19.default.cyan(displayUrl)}`);
|
|
2609
2462
|
}
|
|
2610
2463
|
if (envMatch?.lastDeployedAt) {
|
|
2611
2464
|
console.log(
|
|
2612
|
-
` Deployed: ${
|
|
2465
|
+
` Deployed: ${import_chalk19.default.white(new Date(envMatch.lastDeployedAt).toLocaleString())}`
|
|
2613
2466
|
);
|
|
2614
2467
|
}
|
|
2615
2468
|
if (status.replicas) {
|
|
2616
2469
|
const { ready, desired } = status.replicas;
|
|
2617
|
-
const replicaColor = ready === desired ?
|
|
2470
|
+
const replicaColor = ready === desired ? import_chalk19.default.green : import_chalk19.default.yellow;
|
|
2618
2471
|
console.log(` Replicas: ${replicaColor(`${ready}/${desired}`)}`);
|
|
2619
2472
|
}
|
|
2620
2473
|
console.log("");
|
|
2621
2474
|
} catch (err) {
|
|
2622
|
-
spinner.fail(
|
|
2475
|
+
spinner.fail(import_chalk19.default.red(`Failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
2623
2476
|
process.exit(1);
|
|
2624
2477
|
}
|
|
2625
2478
|
});
|
|
2626
2479
|
|
|
2627
2480
|
// src/commands/storage.ts
|
|
2628
2481
|
var import_node_readline6 = __toESM(require("readline"));
|
|
2629
|
-
var
|
|
2630
|
-
var
|
|
2631
|
-
var
|
|
2482
|
+
var import_chalk20 = __toESM(require("chalk"));
|
|
2483
|
+
var import_commander19 = require("commander");
|
|
2484
|
+
var import_ora17 = __toESM(require("ora"));
|
|
2632
2485
|
function requireLinkedApp6() {
|
|
2633
2486
|
const linked = config.getLinkedApp();
|
|
2634
2487
|
if (!linked) {
|
|
2635
|
-
console.log(
|
|
2488
|
+
console.log(import_chalk20.default.red("No app linked. Run `sylphx link` first."));
|
|
2636
2489
|
process.exit(1);
|
|
2637
2490
|
}
|
|
2638
2491
|
return linked;
|
|
@@ -2640,85 +2493,85 @@ function requireLinkedApp6() {
|
|
|
2640
2493
|
function requireToken4() {
|
|
2641
2494
|
const token = config.getToken();
|
|
2642
2495
|
if (!token) {
|
|
2643
|
-
console.log(
|
|
2496
|
+
console.log(import_chalk20.default.red("Not authenticated. Run `sylphx login` first."));
|
|
2644
2497
|
process.exit(1);
|
|
2645
2498
|
}
|
|
2646
2499
|
return token;
|
|
2647
2500
|
}
|
|
2648
|
-
var listCmd4 = new
|
|
2501
|
+
var listCmd4 = new import_commander19.Command("list").description("List storage resources for this project").option("--env <env>", "Environment (default: production)", "production").action(async (opts) => {
|
|
2649
2502
|
requireToken4();
|
|
2650
2503
|
const linked = requireLinkedApp6();
|
|
2651
|
-
const spinner = (0,
|
|
2504
|
+
const spinner = (0, import_ora17.default)("Fetching storage resources...").start();
|
|
2652
2505
|
try {
|
|
2653
2506
|
const resources = await api.listStorage(linked.appId, opts.env);
|
|
2654
2507
|
spinner.stop();
|
|
2655
2508
|
if (resources.length === 0) {
|
|
2656
|
-
console.log(
|
|
2509
|
+
console.log(import_chalk20.default.dim(" No storage resources provisioned."));
|
|
2657
2510
|
console.log(
|
|
2658
|
-
|
|
2659
|
-
Run ${
|
|
2511
|
+
import_chalk20.default.dim(`
|
|
2512
|
+
Run ${import_chalk20.default.cyan("sylphx storage create")} to provision storage.`)
|
|
2660
2513
|
);
|
|
2661
2514
|
return;
|
|
2662
2515
|
}
|
|
2663
2516
|
console.log();
|
|
2664
2517
|
for (const r of resources) {
|
|
2665
2518
|
const label = [r.role ?? "primary", r.envType].filter(Boolean).join(" \xB7 ");
|
|
2666
|
-
console.log(` ${
|
|
2519
|
+
console.log(` ${import_chalk20.default.cyan(label)} ${import_chalk20.default.dim(r.id)}`);
|
|
2667
2520
|
if (r.publicUrl) {
|
|
2668
|
-
console.log(` ${
|
|
2521
|
+
console.log(` ${import_chalk20.default.dim("URL:")} ${import_chalk20.default.cyan(r.publicUrl)}`);
|
|
2669
2522
|
}
|
|
2670
2523
|
if (r.bucket) {
|
|
2671
|
-
console.log(` ${
|
|
2524
|
+
console.log(` ${import_chalk20.default.dim("Bucket:")} ${r.bucket}`);
|
|
2672
2525
|
}
|
|
2673
2526
|
}
|
|
2674
2527
|
console.log();
|
|
2675
2528
|
} catch (err) {
|
|
2676
|
-
spinner.fail(
|
|
2529
|
+
spinner.fail(import_chalk20.default.red(err instanceof Error ? err.message : String(err)));
|
|
2677
2530
|
process.exit(1);
|
|
2678
2531
|
}
|
|
2679
2532
|
});
|
|
2680
|
-
var createCmd = new
|
|
2533
|
+
var createCmd = new import_commander19.Command("create").description("Provision blob storage for this project").argument("[name]", "Storage resource name (default: primary)", "primary").option("--env <env>", "Environment (default: production)", "production").action(async (name, opts) => {
|
|
2681
2534
|
requireToken4();
|
|
2682
2535
|
const linked = requireLinkedApp6();
|
|
2683
|
-
const spinner = (0,
|
|
2536
|
+
const spinner = (0, import_ora17.default)(`Provisioning storage '${name}' [${opts.env}]...`).start();
|
|
2684
2537
|
try {
|
|
2685
2538
|
const resource = await api.createStorage(linked.appId, { name, envType: opts.env });
|
|
2686
|
-
spinner.succeed(
|
|
2539
|
+
spinner.succeed(import_chalk20.default.green(`\u2713 Storage '${name}' provisioned`));
|
|
2687
2540
|
console.log();
|
|
2688
|
-
console.log(` ${
|
|
2541
|
+
console.log(` ${import_chalk20.default.dim("ID:")} ${resource.id}`);
|
|
2689
2542
|
if (resource.publicUrl) {
|
|
2690
|
-
console.log(` ${
|
|
2543
|
+
console.log(` ${import_chalk20.default.dim("Public URL:")} ${import_chalk20.default.cyan(resource.publicUrl)}`);
|
|
2691
2544
|
}
|
|
2692
2545
|
if (resource.envVars && Object.keys(resource.envVars).length > 0) {
|
|
2693
2546
|
console.log();
|
|
2694
|
-
console.log(
|
|
2547
|
+
console.log(import_chalk20.default.bold(" Env vars to add to your project:"));
|
|
2695
2548
|
for (const [k, v] of Object.entries(resource.envVars)) {
|
|
2696
|
-
console.log(` ${
|
|
2549
|
+
console.log(` ${import_chalk20.default.cyan(k)}=${v}`);
|
|
2697
2550
|
}
|
|
2698
2551
|
console.log();
|
|
2699
2552
|
console.log(
|
|
2700
|
-
|
|
2701
|
-
` Run ${
|
|
2553
|
+
import_chalk20.default.dim(
|
|
2554
|
+
` Run ${import_chalk20.default.cyan("sylphx env set KEY=VALUE")} to add these to your project.`
|
|
2702
2555
|
)
|
|
2703
2556
|
);
|
|
2704
2557
|
}
|
|
2705
2558
|
} catch (err) {
|
|
2706
|
-
spinner.fail(
|
|
2559
|
+
spinner.fail(import_chalk20.default.red(err instanceof Error ? err.message : String(err)));
|
|
2707
2560
|
process.exit(1);
|
|
2708
2561
|
}
|
|
2709
2562
|
});
|
|
2710
|
-
var rmCmd3 = new
|
|
2563
|
+
var rmCmd3 = new import_commander19.Command("rm").description("Delete a storage resource").argument("<id>", "Storage resource ID").option("--force", "Skip confirmation prompt").action(async (id, opts) => {
|
|
2711
2564
|
requireToken4();
|
|
2712
2565
|
const linked = requireLinkedApp6();
|
|
2713
2566
|
if (!opts.force) {
|
|
2714
2567
|
const rl = import_node_readline6.default.createInterface({ input: process.stdin, output: process.stdout });
|
|
2715
2568
|
await new Promise((resolve) => {
|
|
2716
2569
|
rl.question(
|
|
2717
|
-
|
|
2570
|
+
import_chalk20.default.yellow(` \u26A0\uFE0F Delete storage ${import_chalk20.default.bold(id)}? This is irreversible. (y/N) `),
|
|
2718
2571
|
(answer) => {
|
|
2719
2572
|
rl.close();
|
|
2720
2573
|
if (answer.toLowerCase() !== "y") {
|
|
2721
|
-
console.log(
|
|
2574
|
+
console.log(import_chalk20.default.dim(" Cancelled."));
|
|
2722
2575
|
process.exit(0);
|
|
2723
2576
|
}
|
|
2724
2577
|
resolve();
|
|
@@ -2726,26 +2579,26 @@ var rmCmd3 = new import_commander18.Command("rm").description("Delete a storage
|
|
|
2726
2579
|
);
|
|
2727
2580
|
});
|
|
2728
2581
|
}
|
|
2729
|
-
const spinner = (0,
|
|
2582
|
+
const spinner = (0, import_ora17.default)(`Deleting storage ${id}...`).start();
|
|
2730
2583
|
try {
|
|
2731
2584
|
await api.deleteStorage(linked.appId, id);
|
|
2732
|
-
spinner.succeed(
|
|
2585
|
+
spinner.succeed(import_chalk20.default.green(`\u2713 Storage ${id} deleted`));
|
|
2733
2586
|
} catch (err) {
|
|
2734
|
-
spinner.fail(
|
|
2587
|
+
spinner.fail(import_chalk20.default.red(err instanceof Error ? err.message : String(err)));
|
|
2735
2588
|
process.exit(1);
|
|
2736
2589
|
}
|
|
2737
2590
|
});
|
|
2738
|
-
var storageCommand = new
|
|
2591
|
+
var storageCommand = new import_commander19.Command("storage").description("Manage blob storage resources").addCommand(listCmd4).addCommand(createCmd).addCommand(rmCmd3).action(() => storageCommand.help());
|
|
2739
2592
|
|
|
2740
2593
|
// src/commands/tasks.ts
|
|
2741
2594
|
var import_node_readline7 = __toESM(require("readline"));
|
|
2742
|
-
var
|
|
2743
|
-
var
|
|
2744
|
-
var
|
|
2595
|
+
var import_chalk21 = __toESM(require("chalk"));
|
|
2596
|
+
var import_commander20 = require("commander");
|
|
2597
|
+
var import_ora18 = __toESM(require("ora"));
|
|
2745
2598
|
function requireLinkedApp7() {
|
|
2746
2599
|
const linked = config.getLinkedApp();
|
|
2747
2600
|
if (!linked) {
|
|
2748
|
-
console.log(
|
|
2601
|
+
console.log(import_chalk21.default.red("No app linked. Run `sylphx link` first."));
|
|
2749
2602
|
process.exit(1);
|
|
2750
2603
|
}
|
|
2751
2604
|
return linked;
|
|
@@ -2753,7 +2606,7 @@ function requireLinkedApp7() {
|
|
|
2753
2606
|
function requireToken5() {
|
|
2754
2607
|
const token = config.getToken();
|
|
2755
2608
|
if (!token) {
|
|
2756
|
-
console.log(
|
|
2609
|
+
console.log(import_chalk21.default.red("Not authenticated. Run `sylphx login` first."));
|
|
2757
2610
|
process.exit(1);
|
|
2758
2611
|
}
|
|
2759
2612
|
return token;
|
|
@@ -2761,74 +2614,74 @@ function requireToken5() {
|
|
|
2761
2614
|
function formatMode(mode) {
|
|
2762
2615
|
switch (mode) {
|
|
2763
2616
|
case "job":
|
|
2764
|
-
return
|
|
2617
|
+
return import_chalk21.default.blue("job");
|
|
2765
2618
|
case "cron":
|
|
2766
|
-
return
|
|
2619
|
+
return import_chalk21.default.magenta("cron");
|
|
2767
2620
|
case "service":
|
|
2768
|
-
return
|
|
2621
|
+
return import_chalk21.default.green("service");
|
|
2769
2622
|
default:
|
|
2770
|
-
return
|
|
2623
|
+
return import_chalk21.default.dim(mode);
|
|
2771
2624
|
}
|
|
2772
2625
|
}
|
|
2773
|
-
var listCmd5 = new
|
|
2626
|
+
var listCmd5 = new import_commander20.Command("list").description("List task definitions for this project").option("--env <env>", "Environment (default: production)", "production").action(async (opts) => {
|
|
2774
2627
|
requireToken5();
|
|
2775
2628
|
const linked = requireLinkedApp7();
|
|
2776
|
-
const spinner = (0,
|
|
2629
|
+
const spinner = (0, import_ora18.default)("Fetching tasks...").start();
|
|
2777
2630
|
try {
|
|
2778
2631
|
const tasks = await api.listTasks(linked.appId, opts.env);
|
|
2779
2632
|
spinner.stop();
|
|
2780
2633
|
if (tasks.length === 0) {
|
|
2781
|
-
console.log(
|
|
2634
|
+
console.log(import_chalk21.default.dim(` No task definitions for [${opts.env}].`));
|
|
2782
2635
|
console.log(
|
|
2783
|
-
|
|
2784
|
-
Run ${
|
|
2636
|
+
import_chalk21.default.dim(`
|
|
2637
|
+
Run ${import_chalk21.default.cyan("sylphx tasks create <name>")} to define a task.`)
|
|
2785
2638
|
);
|
|
2786
2639
|
return;
|
|
2787
2640
|
}
|
|
2788
2641
|
console.log();
|
|
2789
2642
|
console.log(
|
|
2790
|
-
` ${
|
|
2643
|
+
` ${import_chalk21.default.bold("NAME".padEnd(28))} ${"MODE".padEnd(10)} ${"IMAGE / HANDLER".padEnd(40)} ID`
|
|
2791
2644
|
);
|
|
2792
2645
|
console.log(` ${"\u2500".repeat(90)}`);
|
|
2793
2646
|
for (const t of tasks) {
|
|
2794
|
-
const label = t.imageRef ?? t.handlerPath ??
|
|
2647
|
+
const label = t.imageRef ?? t.handlerPath ?? import_chalk21.default.dim("\u2014");
|
|
2795
2648
|
console.log(
|
|
2796
|
-
` ${
|
|
2649
|
+
` ${import_chalk21.default.cyan(t.taskName.padEnd(28))} ${formatMode(t.executionMode ?? "job").padEnd(10)} ${String(label).padEnd(40)} ${import_chalk21.default.dim(t.id)}`
|
|
2797
2650
|
);
|
|
2798
2651
|
}
|
|
2799
2652
|
console.log();
|
|
2800
2653
|
} catch (err) {
|
|
2801
|
-
spinner.fail(
|
|
2654
|
+
spinner.fail(import_chalk21.default.red(err instanceof Error ? err.message : String(err)));
|
|
2802
2655
|
process.exit(1);
|
|
2803
2656
|
}
|
|
2804
2657
|
});
|
|
2805
|
-
var getCmd4 = new
|
|
2658
|
+
var getCmd4 = new import_commander20.Command("get").description("Show details of a task definition").argument("<task-id>", "Task ID (task_xxx)").action(async (taskId) => {
|
|
2806
2659
|
requireToken5();
|
|
2807
2660
|
const linked = requireLinkedApp7();
|
|
2808
|
-
const spinner = (0,
|
|
2661
|
+
const spinner = (0, import_ora18.default)(`Fetching task ${taskId}...`).start();
|
|
2809
2662
|
try {
|
|
2810
2663
|
const t = await api.getTask(linked.appId, taskId);
|
|
2811
2664
|
spinner.stop();
|
|
2812
2665
|
console.log();
|
|
2813
|
-
console.log(` ${
|
|
2814
|
-
console.log(` ${
|
|
2815
|
-
console.log(` ${
|
|
2816
|
-
if (t.imageRef) console.log(` ${
|
|
2817
|
-
if (t.handlerPath) console.log(` ${
|
|
2818
|
-
if (t.command?.length) console.log(` ${
|
|
2819
|
-
if (t.timeoutSeconds) console.log(` ${
|
|
2666
|
+
console.log(` ${import_chalk21.default.bold("Name:")} ${import_chalk21.default.cyan(t.taskName)}`);
|
|
2667
|
+
console.log(` ${import_chalk21.default.bold("ID:")} ${t.id}`);
|
|
2668
|
+
console.log(` ${import_chalk21.default.bold("Mode:")} ${formatMode(t.executionMode ?? "job")}`);
|
|
2669
|
+
if (t.imageRef) console.log(` ${import_chalk21.default.bold("Image:")} ${t.imageRef}`);
|
|
2670
|
+
if (t.handlerPath) console.log(` ${import_chalk21.default.bold("Handler:")} ${t.handlerPath}`);
|
|
2671
|
+
if (t.command?.length) console.log(` ${import_chalk21.default.bold("Command:")} ${t.command.join(" ")}`);
|
|
2672
|
+
if (t.timeoutSeconds) console.log(` ${import_chalk21.default.bold("Timeout:")} ${t.timeoutSeconds}s`);
|
|
2820
2673
|
if (t.machineConfig) {
|
|
2821
2674
|
const { cpu, memory, gpu } = t.machineConfig;
|
|
2822
2675
|
const parts = [cpu && `cpu=${cpu}`, memory && `mem=${memory}`, gpu && `gpu=${gpu}`].filter(Boolean).join(" ");
|
|
2823
|
-
if (parts) console.log(` ${
|
|
2676
|
+
if (parts) console.log(` ${import_chalk21.default.bold("Resources:")} ${parts}`);
|
|
2824
2677
|
}
|
|
2825
2678
|
if (t.retryConfig) {
|
|
2826
2679
|
console.log(
|
|
2827
|
-
` ${
|
|
2680
|
+
` ${import_chalk21.default.bold("Retry:")} max=${t.retryConfig.maxAttempts ?? 1}, backoff=${t.retryConfig.backoff ?? "fixed"}`
|
|
2828
2681
|
);
|
|
2829
2682
|
}
|
|
2830
2683
|
if (t.volumeMounts?.length) {
|
|
2831
|
-
console.log(` ${
|
|
2684
|
+
console.log(` ${import_chalk21.default.bold("Volumes:")}`);
|
|
2832
2685
|
for (const m of t.volumeMounts) {
|
|
2833
2686
|
const ro = m.readOnly ? " (ro)" : "";
|
|
2834
2687
|
console.log(` ${m.mountPath}${ro} \u2190 ${m.volumeId}`);
|
|
@@ -2836,19 +2689,19 @@ var getCmd4 = new import_commander19.Command("get").description("Show details of
|
|
|
2836
2689
|
}
|
|
2837
2690
|
console.log();
|
|
2838
2691
|
} catch (err) {
|
|
2839
|
-
spinner.fail(
|
|
2692
|
+
spinner.fail(import_chalk21.default.red(err instanceof Error ? err.message : String(err)));
|
|
2840
2693
|
process.exit(1);
|
|
2841
2694
|
}
|
|
2842
2695
|
});
|
|
2843
|
-
var createCmd2 = new
|
|
2696
|
+
var createCmd2 = new import_commander20.Command("create").description("Create (or upsert) a task definition").argument("<name>", "Task name (unique within the environment)").option("--env <env>", "Environment (default: production)", "production").option("--mode <mode>", "Execution mode: job | cron | service (default: job)", "job").option("--image <ref>", "Docker image reference").option("--handler <path>", "Handler function path (e.g. src/tasks/send-email.ts)").option("--cmd <cmd>", 'Command to run (comma-separated, e.g. "node,dist/worker.js")').option("--timeout <secs>", "Timeout in seconds").option("--cpu <cpu>", "CPU request (e.g. 0.5, 2)").option("--memory <mem>", "Memory request (e.g. 512Mi, 2Gi)").action(
|
|
2844
2697
|
async (name, opts) => {
|
|
2845
2698
|
requireToken5();
|
|
2846
2699
|
const linked = requireLinkedApp7();
|
|
2847
2700
|
if (!["job", "cron", "service"].includes(opts.mode)) {
|
|
2848
|
-
console.log(
|
|
2701
|
+
console.log(import_chalk21.default.red(` --mode must be one of: job, cron, service`));
|
|
2849
2702
|
process.exit(1);
|
|
2850
2703
|
}
|
|
2851
|
-
const spinner = (0,
|
|
2704
|
+
const spinner = (0, import_ora18.default)(`Creating task '${name}' [${opts.env}]...`).start();
|
|
2852
2705
|
try {
|
|
2853
2706
|
const task = await api.createTask(linked.appId, {
|
|
2854
2707
|
taskName: name,
|
|
@@ -2860,19 +2713,19 @@ var createCmd2 = new import_commander19.Command("create").description("Create (o
|
|
|
2860
2713
|
timeoutSeconds: opts.timeout ? Number.parseInt(opts.timeout, 10) : void 0,
|
|
2861
2714
|
machineConfig: opts.cpu || opts.memory ? { cpu: opts.cpu, memory: opts.memory } : void 0
|
|
2862
2715
|
});
|
|
2863
|
-
spinner.succeed(
|
|
2716
|
+
spinner.succeed(import_chalk21.default.green(`\u2713 Task '${task.taskName}' created`));
|
|
2864
2717
|
console.log();
|
|
2865
|
-
console.log(` ${
|
|
2866
|
-
console.log(` ${
|
|
2867
|
-
if (task.imageRef) console.log(` ${
|
|
2718
|
+
console.log(` ${import_chalk21.default.dim("ID:")} ${task.id}`);
|
|
2719
|
+
console.log(` ${import_chalk21.default.dim("Mode:")} ${task.executionMode}`);
|
|
2720
|
+
if (task.imageRef) console.log(` ${import_chalk21.default.dim("Image:")} ${task.imageRef}`);
|
|
2868
2721
|
console.log();
|
|
2869
2722
|
} catch (err) {
|
|
2870
|
-
spinner.fail(
|
|
2723
|
+
spinner.fail(import_chalk21.default.red(err instanceof Error ? err.message : String(err)));
|
|
2871
2724
|
process.exit(1);
|
|
2872
2725
|
}
|
|
2873
2726
|
}
|
|
2874
2727
|
);
|
|
2875
|
-
var updateCmd = new
|
|
2728
|
+
var updateCmd = new import_commander20.Command("update").description("Update a task definition").argument("<task-id>", "Task ID (task_xxx)").option("--mode <mode>", "Execution mode: job | cron | service").option("--image <ref>", "Docker image reference").option("--handler <path>", "Handler function path").option("--cmd <cmd>", "Command (comma-separated)").option("--timeout <secs>", "Timeout in seconds").option("--cpu <cpu>", "CPU request").option("--memory <mem>", "Memory request").action(
|
|
2876
2729
|
async (taskId, opts) => {
|
|
2877
2730
|
requireToken5();
|
|
2878
2731
|
const linked = requireLinkedApp7();
|
|
@@ -2884,72 +2737,72 @@ var updateCmd = new import_commander19.Command("update").description("Update a t
|
|
|
2884
2737
|
if (opts.timeout) patch.timeoutSeconds = Number.parseInt(opts.timeout, 10);
|
|
2885
2738
|
if (opts.cpu || opts.memory) patch.machineConfig = { cpu: opts.cpu, memory: opts.memory };
|
|
2886
2739
|
if (Object.keys(patch).length === 0) {
|
|
2887
|
-
console.log(
|
|
2740
|
+
console.log(import_chalk21.default.yellow(" Nothing to update. Pass at least one option."));
|
|
2888
2741
|
process.exit(1);
|
|
2889
2742
|
}
|
|
2890
|
-
const spinner = (0,
|
|
2743
|
+
const spinner = (0, import_ora18.default)(`Updating task ${taskId}...`).start();
|
|
2891
2744
|
try {
|
|
2892
2745
|
const task = await api.updateTask(linked.appId, taskId, patch);
|
|
2893
|
-
spinner.succeed(
|
|
2746
|
+
spinner.succeed(import_chalk21.default.green(`\u2713 Task '${task.taskName}' updated`));
|
|
2894
2747
|
} catch (err) {
|
|
2895
|
-
spinner.fail(
|
|
2748
|
+
spinner.fail(import_chalk21.default.red(err instanceof Error ? err.message : String(err)));
|
|
2896
2749
|
process.exit(1);
|
|
2897
2750
|
}
|
|
2898
2751
|
}
|
|
2899
2752
|
);
|
|
2900
|
-
var rmCmd4 = new
|
|
2753
|
+
var rmCmd4 = new import_commander20.Command("rm").description("Delete a task definition").argument("<task-id>", "Task ID (task_xxx)").option("--force", "Skip confirmation").action(async (taskId, opts) => {
|
|
2901
2754
|
requireToken5();
|
|
2902
2755
|
const linked = requireLinkedApp7();
|
|
2903
2756
|
if (!opts.force) {
|
|
2904
2757
|
const rl = import_node_readline7.default.createInterface({ input: process.stdin, output: process.stdout });
|
|
2905
2758
|
await new Promise((resolve) => {
|
|
2906
|
-
rl.question(
|
|
2759
|
+
rl.question(import_chalk21.default.yellow(` Delete task ${import_chalk21.default.bold(taskId)}? (y/N) `), (answer) => {
|
|
2907
2760
|
rl.close();
|
|
2908
2761
|
if (answer.toLowerCase() !== "y") {
|
|
2909
|
-
console.log(
|
|
2762
|
+
console.log(import_chalk21.default.dim(" Cancelled."));
|
|
2910
2763
|
process.exit(0);
|
|
2911
2764
|
}
|
|
2912
2765
|
resolve();
|
|
2913
2766
|
});
|
|
2914
2767
|
});
|
|
2915
2768
|
}
|
|
2916
|
-
const spinner = (0,
|
|
2769
|
+
const spinner = (0, import_ora18.default)(`Deleting task ${taskId}...`).start();
|
|
2917
2770
|
try {
|
|
2918
2771
|
await api.deleteTask(linked.appId, taskId);
|
|
2919
|
-
spinner.succeed(
|
|
2772
|
+
spinner.succeed(import_chalk21.default.green(`\u2713 Task ${taskId} deleted`));
|
|
2920
2773
|
} catch (err) {
|
|
2921
|
-
spinner.fail(
|
|
2774
|
+
spinner.fail(import_chalk21.default.red(err instanceof Error ? err.message : String(err)));
|
|
2922
2775
|
process.exit(1);
|
|
2923
2776
|
}
|
|
2924
2777
|
});
|
|
2925
|
-
var tasksCommand = new
|
|
2778
|
+
var tasksCommand = new import_commander20.Command("tasks").description("Manage task definitions (jobs, crons, services)").addCommand(listCmd5).addCommand(getCmd4).addCommand(createCmd2).addCommand(updateCmd).addCommand(rmCmd4).action(() => tasksCommand.help());
|
|
2926
2779
|
|
|
2927
2780
|
// src/commands/unlink.ts
|
|
2928
|
-
var
|
|
2929
|
-
var
|
|
2930
|
-
var unlinkCommand = new
|
|
2781
|
+
var import_chalk22 = __toESM(require("chalk"));
|
|
2782
|
+
var import_commander21 = require("commander");
|
|
2783
|
+
var unlinkCommand = new import_commander21.Command("unlink").description("Unlink current directory from its linked app").action(() => {
|
|
2931
2784
|
const linked = config.getLinkedApp();
|
|
2932
2785
|
if (!linked) {
|
|
2933
|
-
console.log(
|
|
2786
|
+
console.log(import_chalk22.default.yellow(" This directory is not linked to any app."));
|
|
2934
2787
|
process.exit(0);
|
|
2935
2788
|
}
|
|
2936
2789
|
const appId = linked.appId;
|
|
2937
2790
|
config.unlinkApp();
|
|
2938
2791
|
console.log("");
|
|
2939
|
-
console.log(
|
|
2940
|
-
console.log(
|
|
2792
|
+
console.log(import_chalk22.default.green(`\u2713 Unlinked from ${import_chalk22.default.bold(appId)}`));
|
|
2793
|
+
console.log(import_chalk22.default.dim(` Directory: ${process.cwd()}`));
|
|
2941
2794
|
console.log("");
|
|
2942
2795
|
});
|
|
2943
2796
|
|
|
2944
2797
|
// src/commands/volumes.ts
|
|
2945
2798
|
var import_node_readline8 = __toESM(require("readline"));
|
|
2946
|
-
var
|
|
2947
|
-
var
|
|
2948
|
-
var
|
|
2799
|
+
var import_chalk23 = __toESM(require("chalk"));
|
|
2800
|
+
var import_commander22 = require("commander");
|
|
2801
|
+
var import_ora19 = __toESM(require("ora"));
|
|
2949
2802
|
function requireLinkedApp8() {
|
|
2950
2803
|
const linked = config.getLinkedApp();
|
|
2951
2804
|
if (!linked) {
|
|
2952
|
-
console.log(
|
|
2805
|
+
console.log(import_chalk23.default.red("No app linked. Run `sylphx link` first."));
|
|
2953
2806
|
process.exit(1);
|
|
2954
2807
|
}
|
|
2955
2808
|
return linked;
|
|
@@ -2957,45 +2810,45 @@ function requireLinkedApp8() {
|
|
|
2957
2810
|
function requireToken6() {
|
|
2958
2811
|
const token = config.getToken();
|
|
2959
2812
|
if (!token) {
|
|
2960
|
-
console.log(
|
|
2813
|
+
console.log(import_chalk23.default.red("Not authenticated. Run `sylphx login` first."));
|
|
2961
2814
|
process.exit(1);
|
|
2962
2815
|
}
|
|
2963
2816
|
return token;
|
|
2964
2817
|
}
|
|
2965
|
-
var listCmd6 = new
|
|
2818
|
+
var listCmd6 = new import_commander22.Command("list").description("List persistent volumes for this project").action(async () => {
|
|
2966
2819
|
requireToken6();
|
|
2967
2820
|
const linked = requireLinkedApp8();
|
|
2968
|
-
const spinner = (0,
|
|
2821
|
+
const spinner = (0, import_ora19.default)("Fetching volumes...").start();
|
|
2969
2822
|
try {
|
|
2970
2823
|
const volumes = await api.listVolumes(linked.appId);
|
|
2971
2824
|
spinner.stop();
|
|
2972
2825
|
if (volumes.length === 0) {
|
|
2973
|
-
console.log(
|
|
2826
|
+
console.log(import_chalk23.default.dim(" No volumes provisioned."));
|
|
2974
2827
|
console.log(
|
|
2975
|
-
|
|
2976
|
-
Run ${
|
|
2828
|
+
import_chalk23.default.dim(`
|
|
2829
|
+
Run ${import_chalk23.default.cyan("sylphx volumes create <name>")} to provision.`)
|
|
2977
2830
|
);
|
|
2978
2831
|
return;
|
|
2979
2832
|
}
|
|
2980
2833
|
console.log();
|
|
2981
2834
|
console.log(
|
|
2982
|
-
` ${
|
|
2835
|
+
` ${import_chalk23.default.bold("NAME".padEnd(24))} ${"SIZE".padEnd(8)} ${"STATUS".padEnd(14)} ID`
|
|
2983
2836
|
);
|
|
2984
2837
|
console.log(` ${"\u2500".repeat(70)}`);
|
|
2985
2838
|
for (const v of volumes) {
|
|
2986
|
-
const statusColor2 = v.status === "ready" ?
|
|
2839
|
+
const statusColor2 = v.status === "ready" ? import_chalk23.default.green((v.status ?? "unknown").padEnd(14)) : import_chalk23.default.yellow((v.status ?? "unknown").padEnd(14));
|
|
2987
2840
|
const size = v.sizeGb ? `${v.sizeGb}Gi`.padEnd(8) : "\u2014".padEnd(8);
|
|
2988
2841
|
console.log(
|
|
2989
|
-
` ${
|
|
2842
|
+
` ${import_chalk23.default.cyan(v.name.padEnd(24))} ${size} ${statusColor2} ${import_chalk23.default.dim(v.id)}`
|
|
2990
2843
|
);
|
|
2991
2844
|
}
|
|
2992
2845
|
console.log();
|
|
2993
2846
|
} catch (err) {
|
|
2994
|
-
spinner.fail(
|
|
2847
|
+
spinner.fail(import_chalk23.default.red(err instanceof Error ? err.message : String(err)));
|
|
2995
2848
|
process.exit(1);
|
|
2996
2849
|
}
|
|
2997
2850
|
});
|
|
2998
|
-
var createCmd3 = new
|
|
2851
|
+
var createCmd3 = new import_commander22.Command("create").description("Provision a persistent volume").argument("<name>", "Volume name").option("--size <gb>", "Size in GiB (default: 10)", "10").option(
|
|
2999
2852
|
"--access-mode <mode>",
|
|
3000
2853
|
"ReadWriteOnce or ReadWriteMany (default: ReadWriteOnce)",
|
|
3001
2854
|
"ReadWriteOnce"
|
|
@@ -3004,14 +2857,14 @@ var createCmd3 = new import_commander21.Command("create").description("Provision
|
|
|
3004
2857
|
const linked = requireLinkedApp8();
|
|
3005
2858
|
const sizeGb = Number.parseInt(opts.size, 10);
|
|
3006
2859
|
if (Number.isNaN(sizeGb) || sizeGb < 1) {
|
|
3007
|
-
console.log(
|
|
2860
|
+
console.log(import_chalk23.default.red(" --size must be a number >= 1"));
|
|
3008
2861
|
process.exit(1);
|
|
3009
2862
|
}
|
|
3010
2863
|
if (!["ReadWriteOnce", "ReadWriteMany"].includes(opts.accessMode)) {
|
|
3011
|
-
console.log(
|
|
2864
|
+
console.log(import_chalk23.default.red(" --access-mode must be ReadWriteOnce or ReadWriteMany"));
|
|
3012
2865
|
process.exit(1);
|
|
3013
2866
|
}
|
|
3014
|
-
const spinner = (0,
|
|
2867
|
+
const spinner = (0, import_ora19.default)(`Provisioning volume '${name}' (${sizeGb}Gi)...`).start();
|
|
3015
2868
|
try {
|
|
3016
2869
|
const result = await api.createVolume(linked.appId, {
|
|
3017
2870
|
name,
|
|
@@ -3020,29 +2873,29 @@ var createCmd3 = new import_commander21.Command("create").description("Provision
|
|
|
3020
2873
|
mountPath: opts.mount
|
|
3021
2874
|
});
|
|
3022
2875
|
const vol = result.volume;
|
|
3023
|
-
spinner.succeed(
|
|
2876
|
+
spinner.succeed(import_chalk23.default.green(`\u2713 Volume '${vol.name}' provisioned`));
|
|
3024
2877
|
console.log();
|
|
3025
|
-
console.log(` ${
|
|
3026
|
-
console.log(` ${
|
|
3027
|
-
console.log(` ${
|
|
2878
|
+
console.log(` ${import_chalk23.default.dim("ID:")} ${vol.id}`);
|
|
2879
|
+
console.log(` ${import_chalk23.default.dim("Size:")} ${vol.sizeGb}Gi`);
|
|
2880
|
+
console.log(` ${import_chalk23.default.dim("Access:")} ${vol.accessMode ?? "ReadWriteOnce"}`);
|
|
3028
2881
|
console.log();
|
|
3029
2882
|
} catch (err) {
|
|
3030
|
-
spinner.fail(
|
|
2883
|
+
spinner.fail(import_chalk23.default.red(err instanceof Error ? err.message : String(err)));
|
|
3031
2884
|
process.exit(1);
|
|
3032
2885
|
}
|
|
3033
2886
|
});
|
|
3034
|
-
var rmCmd5 = new
|
|
2887
|
+
var rmCmd5 = new import_commander22.Command("rm").description("Delete a persistent volume").argument("<id>", "Volume ID").option("--force", "Skip confirmation prompt").action(async (id, opts) => {
|
|
3035
2888
|
requireToken6();
|
|
3036
2889
|
const linked = requireLinkedApp8();
|
|
3037
2890
|
if (!opts.force) {
|
|
3038
2891
|
const rl = import_node_readline8.default.createInterface({ input: process.stdin, output: process.stdout });
|
|
3039
2892
|
await new Promise((resolve) => {
|
|
3040
2893
|
rl.question(
|
|
3041
|
-
|
|
2894
|
+
import_chalk23.default.yellow(` \u26A0\uFE0F Delete volume ${import_chalk23.default.bold(id)}? This will destroy all data. (y/N) `),
|
|
3042
2895
|
(answer) => {
|
|
3043
2896
|
rl.close();
|
|
3044
2897
|
if (answer.toLowerCase() !== "y") {
|
|
3045
|
-
console.log(
|
|
2898
|
+
console.log(import_chalk23.default.dim(" Cancelled."));
|
|
3046
2899
|
process.exit(0);
|
|
3047
2900
|
}
|
|
3048
2901
|
resolve();
|
|
@@ -3050,62 +2903,62 @@ var rmCmd5 = new import_commander21.Command("rm").description("Delete a persiste
|
|
|
3050
2903
|
);
|
|
3051
2904
|
});
|
|
3052
2905
|
}
|
|
3053
|
-
const spinner = (0,
|
|
2906
|
+
const spinner = (0, import_ora19.default)(`Deleting volume ${id}...`).start();
|
|
3054
2907
|
try {
|
|
3055
2908
|
await api.deleteVolume(linked.appId, id);
|
|
3056
|
-
spinner.succeed(
|
|
2909
|
+
spinner.succeed(import_chalk23.default.green(`\u2713 Volume ${id} deleted`));
|
|
3057
2910
|
} catch (err) {
|
|
3058
|
-
spinner.fail(
|
|
2911
|
+
spinner.fail(import_chalk23.default.red(err instanceof Error ? err.message : String(err)));
|
|
3059
2912
|
process.exit(1);
|
|
3060
2913
|
}
|
|
3061
2914
|
});
|
|
3062
|
-
var volumesCommand = new
|
|
2915
|
+
var volumesCommand = new import_commander22.Command("volumes").description("Manage persistent volumes").addCommand(listCmd6).addCommand(createCmd3).addCommand(rmCmd5).action(() => volumesCommand.help());
|
|
3063
2916
|
|
|
3064
2917
|
// src/commands/whoami.ts
|
|
3065
|
-
var
|
|
3066
|
-
var
|
|
3067
|
-
var
|
|
3068
|
-
var whoamiCommand = new
|
|
2918
|
+
var import_chalk24 = __toESM(require("chalk"));
|
|
2919
|
+
var import_commander23 = require("commander");
|
|
2920
|
+
var import_ora20 = __toESM(require("ora"));
|
|
2921
|
+
var whoamiCommand = new import_commander23.Command("whoami").description("Show current user, org, and linked app").action(async () => {
|
|
3069
2922
|
const token = config.getToken();
|
|
3070
2923
|
if (!token) {
|
|
3071
|
-
console.log(
|
|
2924
|
+
console.log(import_chalk24.default.red("Not authenticated. Run `sylphx login` first."));
|
|
3072
2925
|
process.exit(1);
|
|
3073
2926
|
}
|
|
3074
|
-
const spinner = (0,
|
|
2927
|
+
const spinner = (0, import_ora20.default)("Fetching account info...").start();
|
|
3075
2928
|
try {
|
|
3076
2929
|
const me = await api.whoami();
|
|
3077
2930
|
spinner.stop();
|
|
3078
2931
|
console.log("");
|
|
3079
|
-
console.log(
|
|
3080
|
-
console.log(` User: ${
|
|
3081
|
-
console.log(` Name: ${
|
|
3082
|
-
console.log(` ID: ${
|
|
2932
|
+
console.log(import_chalk24.default.bold(" Account"));
|
|
2933
|
+
console.log(` User: ${import_chalk24.default.cyan(me.user.email)}`);
|
|
2934
|
+
console.log(` Name: ${import_chalk24.default.white(me.user.name)}`);
|
|
2935
|
+
console.log(` ID: ${import_chalk24.default.dim(me.user.id)}`);
|
|
3083
2936
|
if (me.orgs.length > 0) {
|
|
3084
2937
|
console.log("");
|
|
3085
|
-
console.log(
|
|
2938
|
+
console.log(import_chalk24.default.bold(" Organizations"));
|
|
3086
2939
|
for (const org of me.orgs) {
|
|
3087
2940
|
console.log(
|
|
3088
|
-
` ${
|
|
2941
|
+
` ${import_chalk24.default.cyan(org.slug)} ${import_chalk24.default.dim(`(${org.name})`)}`
|
|
3089
2942
|
);
|
|
3090
2943
|
}
|
|
3091
2944
|
}
|
|
3092
2945
|
const linkedApp = config.getLinkedApp();
|
|
3093
2946
|
if (linkedApp) {
|
|
3094
2947
|
console.log("");
|
|
3095
|
-
console.log(
|
|
3096
|
-
console.log(` App: ${
|
|
3097
|
-
console.log(` Org: ${
|
|
3098
|
-
console.log(` Env: ${
|
|
2948
|
+
console.log(import_chalk24.default.bold(" Linked App"));
|
|
2949
|
+
console.log(` App: ${import_chalk24.default.cyan(linkedApp.appId)}`);
|
|
2950
|
+
console.log(` Org: ${import_chalk24.default.white(linkedApp.orgId)}`);
|
|
2951
|
+
console.log(` Env: ${import_chalk24.default.white(linkedApp.defaultEnv)}`);
|
|
3099
2952
|
} else {
|
|
3100
2953
|
console.log("");
|
|
3101
2954
|
console.log(
|
|
3102
|
-
|
|
2955
|
+
import_chalk24.default.dim(" No app linked. Run `sylphx link` to link one.")
|
|
3103
2956
|
);
|
|
3104
2957
|
}
|
|
3105
2958
|
console.log("");
|
|
3106
2959
|
} catch (err) {
|
|
3107
2960
|
spinner.fail(
|
|
3108
|
-
|
|
2961
|
+
import_chalk24.default.red(
|
|
3109
2962
|
`Failed: ${err instanceof Error ? err.message : String(err)}`
|
|
3110
2963
|
)
|
|
3111
2964
|
);
|
|
@@ -3115,50 +2968,50 @@ var whoamiCommand = new import_commander22.Command("whoami").description("Show c
|
|
|
3115
2968
|
|
|
3116
2969
|
// src/index.ts
|
|
3117
2970
|
var { version: version4 } = package_default;
|
|
3118
|
-
var program = new
|
|
3119
|
-
program.name("sylphx").description(`${
|
|
2971
|
+
var program = new import_commander24.Command();
|
|
2972
|
+
program.name("sylphx").description(`${import_chalk25.default.bold("Sylphx Platform CLI")} \u2014 deploy and manage your applications`).version(version4, "-v, --version", "Print version").helpOption("-h, --help", "Show help").addHelpText(
|
|
3120
2973
|
"after",
|
|
3121
2974
|
`
|
|
3122
|
-
${
|
|
3123
|
-
${
|
|
3124
|
-
${
|
|
3125
|
-
${
|
|
3126
|
-
${
|
|
3127
|
-
${
|
|
3128
|
-
${
|
|
3129
|
-
${
|
|
3130
|
-
${
|
|
3131
|
-
${
|
|
3132
|
-
${
|
|
3133
|
-
${
|
|
3134
|
-
${
|
|
3135
|
-
${
|
|
3136
|
-
${
|
|
3137
|
-
${
|
|
3138
|
-
${
|
|
3139
|
-
${
|
|
3140
|
-
${
|
|
3141
|
-
${
|
|
3142
|
-
${
|
|
3143
|
-
${
|
|
3144
|
-
${
|
|
2975
|
+
${import_chalk25.default.bold("Examples:")}
|
|
2976
|
+
${import_chalk25.default.cyan("sylphx login")} Authenticate with Sylphx
|
|
2977
|
+
${import_chalk25.default.cyan("sylphx init my-app")} Create and link a new project
|
|
2978
|
+
${import_chalk25.default.cyan("sylphx link")} Link current directory to an app
|
|
2979
|
+
${import_chalk25.default.cyan("sylphx deploy")} Deploy to production
|
|
2980
|
+
${import_chalk25.default.cyan("sylphx deploy --env staging")} Deploy to staging
|
|
2981
|
+
${import_chalk25.default.cyan("sylphx promote --from staging")} Promote staging build \u2192 production
|
|
2982
|
+
${import_chalk25.default.cyan("sylphx rollback")} Rollback to previous deployment
|
|
2983
|
+
${import_chalk25.default.cyan("sylphx logs -f")} Stream live logs
|
|
2984
|
+
${import_chalk25.default.cyan("sylphx status")} Check deployment status
|
|
2985
|
+
${import_chalk25.default.cyan("sylphx env list")} List environment variables
|
|
2986
|
+
${import_chalk25.default.cyan("sylphx env set PORT=3000")} Set an env var
|
|
2987
|
+
${import_chalk25.default.cyan("sylphx config list")} List remote config keys
|
|
2988
|
+
${import_chalk25.default.cyan("sylphx config set KEY=value")} Set a remote config key
|
|
2989
|
+
${import_chalk25.default.cyan("sylphx db create my-db")} Provision a PostgreSQL database
|
|
2990
|
+
${import_chalk25.default.cyan("sylphx storage create")} Provision blob storage
|
|
2991
|
+
${import_chalk25.default.cyan("sylphx volumes create data --size 20")} Provision a persistent volume
|
|
2992
|
+
${import_chalk25.default.cyan("sylphx services list")} List project services
|
|
2993
|
+
${import_chalk25.default.cyan("sylphx services deploy web")} Deploy a specific service
|
|
2994
|
+
${import_chalk25.default.cyan("sylphx tasks list")} List task definitions
|
|
2995
|
+
${import_chalk25.default.cyan("sylphx tasks create <name> --image nginx")} Create a task
|
|
2996
|
+
${import_chalk25.default.cyan("sylphx resources bind <id>")} Bind a resource to this project
|
|
2997
|
+
${import_chalk25.default.cyan("sylphx projects list")} List all projects
|
|
3145
2998
|
|
|
3146
|
-
${
|
|
3147
|
-
${
|
|
2999
|
+
${import_chalk25.default.bold("Documentation:")}
|
|
3000
|
+
${import_chalk25.default.underline("https://docs.sylphx.com/cli")}
|
|
3148
3001
|
`
|
|
3149
3002
|
);
|
|
3150
|
-
program.addCommand(loginCommand).addCommand(logoutCommand).addCommand(whoamiCommand).addCommand(initCommand).addCommand(linkCommand).addCommand(unlinkCommand).addCommand(projectsCommand).addCommand(deployCommand).addCommand(promoteCommand).addCommand(rollbackCommand).addCommand(statusCommand).addCommand(logsCommand).addCommand(envCommand).addCommand(configCommand).addCommand(dbCommand).addCommand(storageCommand).addCommand(volumesCommand).addCommand(resourcesCommand).addCommand(tasksCommand).addCommand(servicesCommand).addCommand(domainsCommand).addCommand(openCommand);
|
|
3003
|
+
program.addCommand(loginCommand).addCommand(logoutCommand).addCommand(whoamiCommand).addCommand(initCommand).addCommand(linkCommand).addCommand(unlinkCommand).addCommand(projectsCommand).addCommand(orgsCommand).addCommand(deployCommand).addCommand(promoteCommand).addCommand(rollbackCommand).addCommand(statusCommand).addCommand(logsCommand).addCommand(envCommand).addCommand(configCommand).addCommand(dbCommand).addCommand(storageCommand).addCommand(volumesCommand).addCommand(resourcesCommand).addCommand(tasksCommand).addCommand(servicesCommand).addCommand(domainsCommand).addCommand(openCommand);
|
|
3151
3004
|
program.on("command:*", (operands) => {
|
|
3152
|
-
console.error(
|
|
3153
|
-
Unknown command: ${
|
|
3005
|
+
console.error(import_chalk25.default.red(`
|
|
3006
|
+
Unknown command: ${import_chalk25.default.bold(operands[0] ?? "")}
|
|
3154
3007
|
`));
|
|
3155
|
-
console.log(` Run ${
|
|
3008
|
+
console.log(` Run ${import_chalk25.default.cyan("sylphx --help")} for usage.
|
|
3156
3009
|
`);
|
|
3157
3010
|
process.exit(1);
|
|
3158
3011
|
});
|
|
3159
3012
|
program.parseAsync(process.argv).catch((err) => {
|
|
3160
3013
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3161
|
-
console.error(
|
|
3014
|
+
console.error(import_chalk25.default.red(`
|
|
3162
3015
|
Error: ${msg}
|
|
3163
3016
|
`));
|
|
3164
3017
|
process.exit(1);
|