@cimplify/cli 0.15.3 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +2 -2
- package/dist/add-SXC6RUPQ.mjs +140 -0
- package/dist/{add-KRIIKAS4.mjs → add-XQVQLD3F.mjs} +4 -4
- package/dist/ai-NQH5L4I6.mjs +17 -0
- package/dist/{assets-CWB72PZG.mjs → assets-FZGVOQXH.mjs} +12 -7
- package/dist/{auth-step-up-Z6KOTTV7.mjs → auth-step-up-67LCPDNL.mjs} +5 -5
- package/dist/build-J4ZUIOPX.mjs +625 -0
- package/dist/{cancel-ZHVVILOU.mjs → cancel-VGJHZJ4J.mjs} +4 -4
- package/dist/capture-RAJ2B3BH.mjs +69 -0
- package/dist/chunk-25ZPFHLF.mjs +51 -0
- package/dist/chunk-47ZXSY47.mjs +52 -0
- package/dist/{chunk-O2TO2J4I.mjs → chunk-54J3XR4T.mjs} +2 -2
- package/dist/chunk-5HP2INMY.mjs +10631 -0
- package/dist/chunk-7JR6JCFF.mjs +32 -0
- package/dist/chunk-7PQL7E7K.mjs +68 -0
- package/dist/chunk-AKACUJ3W.mjs +81 -0
- package/dist/chunk-BYNE553A.mjs +2945 -0
- package/dist/{chunk-NYXA6X56.mjs → chunk-CLQYPTJ2.mjs} +31 -11
- package/dist/chunk-CNZAOVSK.mjs +104 -0
- package/dist/chunk-CPBESPWK.mjs +5576 -0
- package/dist/{chunk-3RPR33MO.mjs → chunk-DYWUPHV3.mjs} +11 -7
- package/dist/chunk-EAV2P4N3.mjs +1941 -0
- package/dist/{chunk-UTD34C2H.mjs → chunk-EDZSOL5O.mjs} +2 -4
- package/dist/chunk-EGQIPYUN.mjs +696 -0
- package/dist/{chunk-DMLQBAGC.mjs → chunk-EOO4UOQD.mjs} +1 -1
- package/dist/chunk-EYEMPIMP.mjs +74 -0
- package/dist/chunk-G2ZEFSQJ.mjs +46 -0
- package/dist/{chunk-TH4XENKH.mjs → chunk-I4HNHPEM.mjs} +1 -1
- package/dist/chunk-JEVSFNPT.mjs +363 -0
- package/dist/chunk-JKECUAAV.mjs +2169 -0
- package/dist/chunk-KMHORI4Y.mjs +638 -0
- package/dist/chunk-KNPYBZ6B.mjs +502 -0
- package/dist/{chunk-3QUK5BPY.mjs → chunk-KOD4GBQ5.mjs} +8 -1
- package/dist/chunk-KQNZKV6E.mjs +535 -0
- package/dist/{chunk-2MKZKUVH.mjs → chunk-LLRUOIMU.mjs} +1 -2
- package/dist/{chunk-OLZKNUMK.mjs → chunk-LNMITJ4Z.mjs} +6 -6
- package/dist/chunk-MEM3MDV4.mjs +6463 -0
- package/dist/chunk-NY4YT7O6.mjs +84 -0
- package/dist/{chunk-LZEG3FEY.mjs → chunk-Q6CF4C3E.mjs} +7 -7
- package/dist/chunk-RP66A52P.mjs +86 -0
- package/dist/{chunk-I2UP7YTG.mjs → chunk-SAXGWS2K.mjs} +1 -1
- package/dist/chunk-SCKQ4XSD.mjs +41 -0
- package/dist/chunk-SF44L2OD.mjs +1152 -0
- package/dist/chunk-SGT5IJVW.mjs +28 -0
- package/dist/{chunk-LJEKKFC7.mjs → chunk-SS4JTMIV.mjs} +8 -8
- package/dist/chunk-T4MW3PD4.mjs +1456 -0
- package/dist/chunk-THATLMEX.mjs +1227 -0
- package/dist/{chunk-MLE4MVYC.mjs → chunk-TT4YI33G.mjs} +2 -2
- package/dist/chunk-TYV2SVFN.mjs +101 -0
- package/dist/chunk-VHK7WBO3.mjs +189 -0
- package/dist/chunk-VSA44UKR.mjs +391 -0
- package/dist/chunk-XL54SQJ3.mjs +42 -0
- package/dist/{chunk-5KYR6WJB.mjs → chunk-XQAHREKO.mjs} +17 -1
- package/dist/chunk-ZUCDXRFI.mjs +2011 -0
- package/dist/create-4S2EAUR3.mjs +10 -0
- package/dist/credits-NJOAOPPW.mjs +33 -0
- package/dist/{deploy-STWZ3OSM.mjs → deploy-26Y4UGZZ.mjs} +11 -11
- package/dist/dev-MOYURRWQ.mjs +401 -0
- package/dist/dev-WL43Q7VD.mjs +8 -0
- package/dist/dispatcher.mjs +131 -30
- package/dist/{doctor-3RW3OGZJ.mjs → doctor-E6ETD2GJ.mjs} +12 -20
- package/dist/{domains-FTNK4IKY.mjs → domains-LOTQMVOR.mjs} +6 -6
- package/dist/engine-runtime-fetch-CIE7S7PB.mjs +10 -0
- package/dist/{env-TNCYUAMT.mjs → env-3PDFC5XF.mjs} +7 -7
- package/dist/env-MOTYOPM5.mjs +19 -0
- package/dist/explain-K5QEVWCD.mjs +251 -0
- package/dist/{inspect-X3M7WSTL.mjs → inspect-Q3E2DHYY.mjs} +3 -3
- package/dist/inspect-SJ4WBAXO.mjs +86 -0
- package/dist/introspect-7F34YN5V.mjs +9 -0
- package/dist/kernel-DEGWMHFL.mjs +662 -0
- package/dist/kernel-plugin.js +6862 -0
- package/dist/keys-W5SN3DPK.mjs +71 -0
- package/dist/lines-XGJYTQ7P.mjs +56 -0
- package/dist/{link-76Z6V6CJ.mjs → link-NKUAVNM2.mjs} +6 -6
- package/dist/{lint-DDZ7HUQN.mjs → lint-G4YPQSSO.mjs} +2 -2
- package/dist/{list-2MFOQKKQ.mjs → list-TDR7K2JB.mjs} +3 -3
- package/dist/lock-EJPW2LM3.mjs +57 -0
- package/dist/{login-RLMDEWAL.mjs → login-AYLU7JU7.mjs} +10 -8
- package/dist/{logout-Z57X6HPE.mjs → logout-3M6VMHLH.mjs} +2 -2
- package/dist/{logs-TNDM4RFE.mjs → logs-4EL5SOXN.mjs} +5 -5
- package/dist/logs-4QQGG2XY.mjs +44 -0
- package/dist/mcp-4R2R6E5M.mjs +1077 -0
- package/dist/{mock-EVER34IX.mjs → mock-AK24GSP2.mjs} +2 -2
- package/dist/outdated-JEKCVLTG.mjs +58 -0
- package/dist/port-SBZ7X3EH.mjs +2408 -0
- package/dist/{projects-YL4T24VV.mjs → projects-7JKTC5WJ.mjs} +6 -6
- package/dist/publish-QQCX47HK.mjs +20 -0
- package/dist/remix-NLLYD3BI.mjs +125 -0
- package/dist/repo-Z4G4EW3N.mjs +9 -0
- package/dist/report-M7F4ZYP7.mjs +2 -0
- package/dist/rollback-2WQ2CW7T.mjs +43 -0
- package/dist/{rollback-47VQ4HJK.mjs → rollback-ZGU32HGT.mjs} +6 -6
- package/dist/scene-HXARHUM7.mjs +324 -0
- package/dist/{status-TWPOMWNA.mjs → status-C3ZSLZ7Q.mjs} +5 -5
- package/dist/status-WEQOC25K.mjs +18 -0
- package/dist/test-ZPBWV4VX.mjs +233 -0
- package/dist/testers-A3LMXOJJ.mjs +49 -0
- package/dist/{unlink-H3BO3DOQ.mjs → unlink-4G4FE4RJ.mjs} +2 -2
- package/dist/{update-FLY46XI3.mjs → update-GHKKM5FS.mjs} +4 -4
- package/dist/{whoami-CQPPARRS.mjs → whoami-3QQN6G2A.mjs} +3 -3
- package/dist/workshop-CD74D2LK.mjs +1703 -0
- package/package.json +11 -7
- package/templates/storefront-auto/app/products/[slug]/page.tsx +1 -1
- package/templates/storefront-auto/package.json +1 -1
- package/templates/storefront-bakery/package.json +1 -1
- package/templates/storefront-fashion/app/products/[slug]/page.tsx +1 -1
- package/templates/storefront-fashion/package.json +1 -1
- package/templates/storefront-grocery/package.json +1 -1
- package/templates/storefront-pharmacy/app/products/[slug]/page.tsx +1 -1
- package/templates/storefront-pharmacy/package.json +1 -1
- package/templates/storefront-restaurant/package.json +1 -1
- package/templates/storefront-retail/app/products/[slug]/page.tsx +1 -1
- package/templates/storefront-retail/package.json +1 -1
- package/templates/storefront-services/package.json +1 -1
- package/dist/chunk-ARIDYKLO.mjs +0 -6463
- package/dist/dev-7O65HY6C.mjs +0 -8
- package/dist/explain-DLRUUCNS.mjs +0 -251
- package/dist/introspect-RC265ACF.mjs +0 -9
- package/dist/repo-UUT3AZ3L.mjs +0 -9
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { CliError, CLI_ERROR_CODE } from './chunk-
|
|
2
|
+
import { CliError, CLI_ERROR_CODE } from './chunk-KOD4GBQ5.mjs';
|
|
3
3
|
import { randomBytes, createHash } from 'crypto';
|
|
4
4
|
import { createServer } from 'http';
|
|
5
5
|
import { spawn } from 'child_process';
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { hasher, sha256, finish } from './chunk-25ZPFHLF.mjs';
|
|
3
|
+
|
|
4
|
+
// src/interactives/build/chunk.ts
|
|
5
|
+
var CHUNK_MAGIC = 1262701891;
|
|
6
|
+
var CHUNK_FORMAT_VERSION = 1;
|
|
7
|
+
var CHUNK_HEADER_BYTES = 64;
|
|
8
|
+
var CHUNK_ALIGNMENT = 64;
|
|
9
|
+
var CHUNK_KIND = {
|
|
10
|
+
code: 0,
|
|
11
|
+
texture: 1,
|
|
12
|
+
mesh: 2,
|
|
13
|
+
audio: 3,
|
|
14
|
+
font: 4,
|
|
15
|
+
data: 5,
|
|
16
|
+
wasm: 6,
|
|
17
|
+
index: 7,
|
|
18
|
+
bytecode: 8
|
|
19
|
+
};
|
|
20
|
+
var KIND_BY_CODE = ["code", "texture", "mesh", "audio", "font", "data", "wasm", "index", "bytecode"];
|
|
21
|
+
var OFFSET_MAGIC = 0;
|
|
22
|
+
var OFFSET_VERSION = 4;
|
|
23
|
+
var OFFSET_KIND = 6;
|
|
24
|
+
var OFFSET_FLAGS = 7;
|
|
25
|
+
var OFFSET_LENGTH = 8;
|
|
26
|
+
var OFFSET_PAYLOAD = 16;
|
|
27
|
+
var OFFSET_ALIGNMENT = 20;
|
|
28
|
+
var ZERO_PADDING = Buffer.alloc(CHUNK_ALIGNMENT);
|
|
29
|
+
var CHUNK_PAYLOAD_PART = 1;
|
|
30
|
+
function paddingFor(length) {
|
|
31
|
+
const rem = length % CHUNK_ALIGNMENT;
|
|
32
|
+
return rem === 0 ? 0 : CHUNK_ALIGNMENT - rem;
|
|
33
|
+
}
|
|
34
|
+
function encodeChunk(kind, payload) {
|
|
35
|
+
const header = Buffer.alloc(CHUNK_HEADER_BYTES);
|
|
36
|
+
header.writeUInt32LE(CHUNK_MAGIC, OFFSET_MAGIC);
|
|
37
|
+
header.writeUInt16LE(CHUNK_FORMAT_VERSION, OFFSET_VERSION);
|
|
38
|
+
header.writeUInt8(CHUNK_KIND[kind], OFFSET_KIND);
|
|
39
|
+
header.writeUInt8(0, OFFSET_FLAGS);
|
|
40
|
+
header.writeBigUInt64LE(BigInt(payload.length), OFFSET_LENGTH);
|
|
41
|
+
header.writeUInt32LE(CHUNK_HEADER_BYTES, OFFSET_PAYLOAD);
|
|
42
|
+
header.writeUInt32LE(CHUNK_ALIGNMENT, OFFSET_ALIGNMENT);
|
|
43
|
+
const pad = paddingFor(payload.length);
|
|
44
|
+
const padding = ZERO_PADDING.subarray(0, pad);
|
|
45
|
+
const hash = hasher();
|
|
46
|
+
hash.update(header);
|
|
47
|
+
hash.update(payload);
|
|
48
|
+
if (pad > 0) hash.update(padding);
|
|
49
|
+
return {
|
|
50
|
+
digest: finish(hash),
|
|
51
|
+
payloadDigest: kind === "wasm" ? sha256(payload) : null,
|
|
52
|
+
kind,
|
|
53
|
+
payloadBytes: payload.length,
|
|
54
|
+
totalBytes: CHUNK_HEADER_BYTES + payload.length + pad,
|
|
55
|
+
parts: pad > 0 ? [header, payload, padding] : [header, payload]
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function decodeChunk(bytes) {
|
|
59
|
+
if (bytes.length < CHUNK_HEADER_BYTES) {
|
|
60
|
+
throw new Error("chunk is shorter than its header");
|
|
61
|
+
}
|
|
62
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, CHUNK_HEADER_BYTES);
|
|
63
|
+
if (view.getUint32(OFFSET_MAGIC, true) !== CHUNK_MAGIC) throw new Error("not a Cimplify chunk");
|
|
64
|
+
if (view.getUint16(OFFSET_VERSION, true) !== CHUNK_FORMAT_VERSION) throw new Error("unsupported chunk format version");
|
|
65
|
+
const code = view.getUint8(OFFSET_KIND);
|
|
66
|
+
const kind = KIND_BY_CODE[code];
|
|
67
|
+
if (kind === void 0) throw new Error(`unknown chunk kind ${code}`);
|
|
68
|
+
const length = view.getBigUint64(OFFSET_LENGTH, true);
|
|
69
|
+
const offset = view.getUint32(OFFSET_PAYLOAD, true);
|
|
70
|
+
if (length > BigInt(bytes.length - offset)) throw new Error("chunk payload is truncated");
|
|
71
|
+
return { kind, payload: bytes.subarray(offset, offset + Number(length)) };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export { CHUNK_ALIGNMENT, CHUNK_FORMAT_VERSION, CHUNK_HEADER_BYTES, CHUNK_KIND, CHUNK_PAYLOAD_PART, decodeChunk, encodeChunk };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { locateToolchain, localEngineRuntimeDir, validManifest, engineCacheRoot, cachedVersion, storeRuntime, cachedEngineRuntimeDir } from './chunk-ZUCDXRFI.mjs';
|
|
3
|
+
import { ApiClient } from './chunk-CLQYPTJ2.mjs';
|
|
4
|
+
import { readAuthOrNull } from './chunk-TT4YI33G.mjs';
|
|
5
|
+
import { isCliError, CLI_ERROR_CODE, info, dim, warn } from './chunk-KOD4GBQ5.mjs';
|
|
6
|
+
|
|
7
|
+
// src/interactives/build/engine-runtime-fetch.ts
|
|
8
|
+
var ENGINE_RUNTIME_ROUTE = "/v1/interactives/engine/runtime";
|
|
9
|
+
var ENGINE_RUNTIME_FILES_ROUTE = `${ENGINE_RUNTIME_ROUTE}/files`;
|
|
10
|
+
var DOWNLOAD_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
11
|
+
async function signedInClient() {
|
|
12
|
+
const auth = await readAuthOrNull();
|
|
13
|
+
return auth === null ? null : ApiClient.fromAuth(auth);
|
|
14
|
+
}
|
|
15
|
+
async function ensureEngineRuntime(options) {
|
|
16
|
+
const sdkDir = locateToolchain(options.projectRoot)?.sdkDir ?? null;
|
|
17
|
+
const local = sdkDir === null ? null : localEngineRuntimeDir(sdkDir);
|
|
18
|
+
if (local !== null) return { source: "local", dir: local, version: null };
|
|
19
|
+
const client = options.client === void 0 ? await signedInClient() : options.client;
|
|
20
|
+
if (client === null) return { source: "signed_out", dir: null, version: null };
|
|
21
|
+
let manifest;
|
|
22
|
+
try {
|
|
23
|
+
manifest = await client.get(ENGINE_RUNTIME_ROUTE);
|
|
24
|
+
} catch (error) {
|
|
25
|
+
if (isCliError(error) && error.code === CLI_ERROR_CODE.NOT_FOUND) return { source: "unpublished", dir: null, version: null };
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
if (!validManifest(manifest)) throw new Error("the registry returned an engine runtime manifest this CLI cannot use");
|
|
29
|
+
const root = options.root ?? engineCacheRoot();
|
|
30
|
+
const cached = cachedVersion(root, manifest.version);
|
|
31
|
+
if (cached !== null) return { source: "cached", dir: cached, version: manifest.version };
|
|
32
|
+
const download = (file) => client.getBytes(`${ENGINE_RUNTIME_FILES_ROUTE}/${file.sha256}`, { timeoutMs: DOWNLOAD_TIMEOUT_MS });
|
|
33
|
+
const dir = await storeRuntime(root, manifest, download);
|
|
34
|
+
return { source: "fetched", dir, version: manifest.version };
|
|
35
|
+
}
|
|
36
|
+
async function refreshEngineRuntime(projectRoot) {
|
|
37
|
+
try {
|
|
38
|
+
const fetched = await ensureEngineRuntime({ projectRoot });
|
|
39
|
+
if (fetched.source === "fetched") info(dim(`Downloaded the Cimplify Engine runtime ${fetched.version ?? ""}`));
|
|
40
|
+
} catch (error) {
|
|
41
|
+
if (cachedEngineRuntimeDir() !== null) return;
|
|
42
|
+
warn(`Could not update the Cimplify Engine runtime: ${error instanceof Error ? error.message : String(error)}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export { ENGINE_RUNTIME_FILES_ROUTE, ENGINE_RUNTIME_ROUTE, ensureEngineRuntime, refreshEngineRuntime };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { isAutoYes, isInteractive, CliError, CLI_ERROR_CODE } from './chunk-
|
|
2
|
+
import { isAutoYes, isInteractive, CliError, CLI_ERROR_CODE } from './chunk-KOD4GBQ5.mjs';
|
|
3
3
|
import readline from 'readline';
|
|
4
4
|
|
|
5
5
|
async function promptLine(question) {
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { LOCAL_ENVIRONMENT, resetLocalData, localEnvironments, localDataDir } from './chunk-SF44L2OD.mjs';
|
|
3
|
+
import { readInteractiveId, remoteCall, CHANNELS } from './chunk-SCKQ4XSD.mjs';
|
|
4
|
+
import { requireInteractiveProject } from './chunk-CPBESPWK.mjs';
|
|
5
|
+
import { flagBool, flagString, parseArgs } from './chunk-XQAHREKO.mjs';
|
|
6
|
+
import { ApiClient } from './chunk-CLQYPTJ2.mjs';
|
|
7
|
+
import { readAuthOrNull } from './chunk-TT4YI33G.mjs';
|
|
8
|
+
import { bold, dim, info, success, warn, result, CliError, CLI_ERROR_CODE } from './chunk-KOD4GBQ5.mjs';
|
|
9
|
+
|
|
10
|
+
// src/interactives/remote/environments.ts
|
|
11
|
+
var BASE = "/v1/interactives";
|
|
12
|
+
function segment(value) {
|
|
13
|
+
return encodeURIComponent(value);
|
|
14
|
+
}
|
|
15
|
+
function seedBody(seed) {
|
|
16
|
+
return { from: seed.from, at: seed.at, tables: [...seed.tables], kv_namespaces: [...seed.kvNamespaces] };
|
|
17
|
+
}
|
|
18
|
+
function change(body) {
|
|
19
|
+
return { change: body.change, table: body.table, column: body.column ?? null, index: body.index ?? null };
|
|
20
|
+
}
|
|
21
|
+
function environment(body) {
|
|
22
|
+
return {
|
|
23
|
+
name: body.name,
|
|
24
|
+
kind: body.kind,
|
|
25
|
+
status: body.status,
|
|
26
|
+
revision: body.revision_id,
|
|
27
|
+
previewToken: body.preview_token,
|
|
28
|
+
seed: body.seed === null ? null : { from: body.seed.from, at: body.seed.at, tables: body.seed.tables, kvNamespaces: body.seed.kv_namespaces },
|
|
29
|
+
schema: body.schema === null ? null : {
|
|
30
|
+
appliedVersion: body.schema.applied_version,
|
|
31
|
+
declaredVersion: body.schema.declared_version,
|
|
32
|
+
pending: body.schema.pending,
|
|
33
|
+
destructive: body.schema.destructive,
|
|
34
|
+
blocked: body.schema.blocked
|
|
35
|
+
},
|
|
36
|
+
createdAt: body.created_at,
|
|
37
|
+
lastActiveAt: body.last_active_at,
|
|
38
|
+
expiresAt: body.expires_at,
|
|
39
|
+
dataRollback: body.data_rollback
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function diff(body) {
|
|
43
|
+
return {
|
|
44
|
+
environment: body.environment,
|
|
45
|
+
revision: body.revision_id,
|
|
46
|
+
fromVersion: body.from_version,
|
|
47
|
+
toVersion: body.to_version,
|
|
48
|
+
changes: body.changes.map(change),
|
|
49
|
+
destructive: body.destructive,
|
|
50
|
+
blocked: body.blocked,
|
|
51
|
+
reversible: body.reversible,
|
|
52
|
+
statements: body.statements
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function migration(body) {
|
|
56
|
+
return {
|
|
57
|
+
id: body.id,
|
|
58
|
+
environment: body.environment,
|
|
59
|
+
revision: body.revision_id,
|
|
60
|
+
fromVersion: body.from_version,
|
|
61
|
+
toVersion: body.to_version,
|
|
62
|
+
changes: body.changes.map(change),
|
|
63
|
+
statements: body.statements,
|
|
64
|
+
reversible: body.reversible,
|
|
65
|
+
status: body.status,
|
|
66
|
+
appliedBy: body.applied_by,
|
|
67
|
+
appliedAt: body.applied_at,
|
|
68
|
+
rolledBackAt: body.rolled_back_at
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
var HttpEnvironments = class {
|
|
72
|
+
constructor(client) {
|
|
73
|
+
this.client = client;
|
|
74
|
+
}
|
|
75
|
+
client;
|
|
76
|
+
path(interactiveId, rest = "") {
|
|
77
|
+
return `${BASE}/${segment(interactiveId)}/environments${rest}`;
|
|
78
|
+
}
|
|
79
|
+
async list(interactiveId) {
|
|
80
|
+
return (await this.client.get(this.path(interactiveId))).environments.map(environment);
|
|
81
|
+
}
|
|
82
|
+
async get(interactiveId, name) {
|
|
83
|
+
return environment(await this.client.get(this.path(interactiveId, `/${segment(name)}`)));
|
|
84
|
+
}
|
|
85
|
+
async create(interactiveId, request) {
|
|
86
|
+
return environment(
|
|
87
|
+
await this.client.post(this.path(interactiveId), {
|
|
88
|
+
name: request.name,
|
|
89
|
+
revision_id: request.revision,
|
|
90
|
+
seed: request.seed === null ? null : seedBody(request.seed)
|
|
91
|
+
})
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
async remove(interactiveId, name) {
|
|
95
|
+
await this.client.delete(this.path(interactiveId, `/${segment(name)}`));
|
|
96
|
+
}
|
|
97
|
+
async deploy(interactiveId, name, revision) {
|
|
98
|
+
return environment(await this.client.put(this.path(interactiveId, `/${segment(name)}/revision`), { revision_id: revision }));
|
|
99
|
+
}
|
|
100
|
+
async diff(interactiveId, name, to) {
|
|
101
|
+
const query = to === null ? "" : `?to=${to}`;
|
|
102
|
+
return diff(await this.client.get(this.path(interactiveId, `/${segment(name)}/diff${query}`)));
|
|
103
|
+
}
|
|
104
|
+
async migrate(interactiveId, name, confirmDestructive) {
|
|
105
|
+
const body = await this.client.post(this.path(interactiveId, `/${segment(name)}/migrate`), { confirm_destructive: confirmDestructive });
|
|
106
|
+
return body === null ? null : migration(body);
|
|
107
|
+
}
|
|
108
|
+
async promote(interactiveId, name, to, confirmDestructive) {
|
|
109
|
+
const body = await this.client.post(this.path(interactiveId, `/${segment(name)}/promote`), {
|
|
110
|
+
to,
|
|
111
|
+
confirm_destructive: confirmDestructive
|
|
112
|
+
});
|
|
113
|
+
return { revision: body.revision_id, to: body.to, migrations: body.migrations.map(migration) };
|
|
114
|
+
}
|
|
115
|
+
async seed(interactiveId, seed) {
|
|
116
|
+
return environment(await this.client.post(this.path(interactiveId, "/test/seed"), seedBody(seed)));
|
|
117
|
+
}
|
|
118
|
+
async rollback(interactiveId, name, to) {
|
|
119
|
+
const body = await this.client.post(
|
|
120
|
+
this.path(interactiveId, `/${segment(name)}/rollback`),
|
|
121
|
+
{ to }
|
|
122
|
+
);
|
|
123
|
+
return { environment: body.environment, to: body.to, revision: body.revision_id, migrationsRolledBack: body.migrations_rolled_back };
|
|
124
|
+
}
|
|
125
|
+
async migrations(interactiveId, limit) {
|
|
126
|
+
return (await this.client.get(`${BASE}/${segment(interactiveId)}/migrations?limit=${limit}`)).map(migration);
|
|
127
|
+
}
|
|
128
|
+
async rollbackMigration(interactiveId, migrationId, confirm) {
|
|
129
|
+
return migration(await this.client.post(`${BASE}/${segment(interactiveId)}/migrations/${segment(migrationId)}/rollback`, { confirm }));
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
async function environmentsFromEnv() {
|
|
133
|
+
const auth = await readAuthOrNull();
|
|
134
|
+
if (auth === null) {
|
|
135
|
+
throw new CliError(CLI_ERROR_CODE.NOT_LOGGED_IN, "environments live on the Cimplify registry and need a signed-in account", {
|
|
136
|
+
remediation: "Run `cimplify login`. Local data for `cimplify dev` needs no account: `cimplify env list --local`."
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return new HttpEnvironments(ApiClient.fromAuth(auth));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// src/interactives/commands/env.ts
|
|
143
|
+
var USAGE = `usage:
|
|
144
|
+
cimplify env list [--local]
|
|
145
|
+
cimplify env create <name> [--revision <r>] [--seed-from live|test --seed-tables a,b --seed-kv a,b --seed-at <time>]
|
|
146
|
+
cimplify env delete <name>
|
|
147
|
+
cimplify env deploy <name> <revision>
|
|
148
|
+
cimplify env diff <name> [--to test|live]
|
|
149
|
+
cimplify env migrate <name> [--confirm]
|
|
150
|
+
cimplify env promote <name> --to test|live [--confirm]
|
|
151
|
+
cimplify env seed test --from live --tables a,b [--kv a,b] [--at <time>]
|
|
152
|
+
cimplify env rollback <name> --to <time>
|
|
153
|
+
cimplify env rollback --migration <id> [--confirm]
|
|
154
|
+
cimplify env migrations [--limit <n>]
|
|
155
|
+
cimplify env reset [<name>]`;
|
|
156
|
+
var NAME_PATTERN = /^[a-z](?:[a-z0-9-]{0,38}[a-z0-9])?$/;
|
|
157
|
+
var RESERVED = /* @__PURE__ */ new Set(["live", "test"]);
|
|
158
|
+
var DEFAULT_MIGRATIONS = 20;
|
|
159
|
+
function usage(detail) {
|
|
160
|
+
throw new CliError(CLI_ERROR_CODE.INVALID_INPUT, detail === void 0 ? USAGE : `${detail}
|
|
161
|
+
${USAGE}`);
|
|
162
|
+
}
|
|
163
|
+
function localEnvironmentName(raw) {
|
|
164
|
+
if (raw === void 0) return LOCAL_ENVIRONMENT;
|
|
165
|
+
if (raw !== LOCAL_ENVIRONMENT && !NAME_PATTERN.test(raw)) usage(`'${raw}' is not an environment name: lowercase letters, digits and dashes, starting with a letter`);
|
|
166
|
+
return raw;
|
|
167
|
+
}
|
|
168
|
+
function environmentName(raw, allowChannels) {
|
|
169
|
+
if (raw === void 0) usage();
|
|
170
|
+
if (RESERVED.has(raw)) {
|
|
171
|
+
if (allowChannels) return raw;
|
|
172
|
+
usage(`'${raw}' is a channel; branch environments take another name`);
|
|
173
|
+
}
|
|
174
|
+
if (!NAME_PATTERN.test(raw) || raw === LOCAL_ENVIRONMENT) usage(`'${raw}' is not an environment name: lowercase letters, digits and dashes, starting with a letter`);
|
|
175
|
+
return raw;
|
|
176
|
+
}
|
|
177
|
+
function channel(raw, flag) {
|
|
178
|
+
if (raw === void 0 || !CHANNELS.includes(raw)) usage(`--${flag} must be live or test`);
|
|
179
|
+
return raw;
|
|
180
|
+
}
|
|
181
|
+
function list(raw) {
|
|
182
|
+
if (raw === void 0) return [];
|
|
183
|
+
return raw.split(",").map((part) => part.trim()).filter((part) => part.length > 0);
|
|
184
|
+
}
|
|
185
|
+
function time(raw, flag) {
|
|
186
|
+
if (raw === void 0) usage(`--${flag} needs a time, for example 2026-10-14T09:30:00Z`);
|
|
187
|
+
const parsed = new Date(raw);
|
|
188
|
+
if (Number.isNaN(parsed.getTime())) usage(`--${flag} is not a time: '${raw}'`);
|
|
189
|
+
return parsed.toISOString();
|
|
190
|
+
}
|
|
191
|
+
function seedFrom(args, prefix) {
|
|
192
|
+
const from = flagString(args, `${prefix}from`);
|
|
193
|
+
if (from === void 0) return null;
|
|
194
|
+
const at = flagString(args, `${prefix}at`);
|
|
195
|
+
return {
|
|
196
|
+
from: channel(from, `${prefix}from`),
|
|
197
|
+
at: at === void 0 ? null : time(at, `${prefix}at`),
|
|
198
|
+
tables: list(flagString(args, `${prefix}tables`)),
|
|
199
|
+
kvNamespaces: list(flagString(args, `${prefix}kv`))
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
function parseEnvCommand(args) {
|
|
203
|
+
const [action, first, second] = args.positional;
|
|
204
|
+
const confirm = flagBool(args, "confirm") || flagBool(args, "yes");
|
|
205
|
+
switch (action) {
|
|
206
|
+
case "list":
|
|
207
|
+
case "ls":
|
|
208
|
+
return { action: "list", local: flagBool(args, "local") };
|
|
209
|
+
case "create":
|
|
210
|
+
return { action: "create", name: environmentName(first, false), revision: flagString(args, "revision") ?? null, seed: seedFrom(args, "seed-") };
|
|
211
|
+
case "delete":
|
|
212
|
+
case "rm":
|
|
213
|
+
return { action: "delete", name: environmentName(first, false) };
|
|
214
|
+
case "deploy":
|
|
215
|
+
if (second === void 0) usage();
|
|
216
|
+
return { action: "deploy", name: environmentName(first, false), revision: second };
|
|
217
|
+
case "diff": {
|
|
218
|
+
const to = flagString(args, "to");
|
|
219
|
+
return { action: "diff", name: environmentName(first, true), to: to === void 0 ? null : channel(to, "to") };
|
|
220
|
+
}
|
|
221
|
+
case "migrate":
|
|
222
|
+
return { action: "migrate", name: environmentName(first, true), confirm };
|
|
223
|
+
case "promote":
|
|
224
|
+
return { action: "promote", name: environmentName(first, true), to: channel(flagString(args, "to"), "to"), confirm };
|
|
225
|
+
case "seed": {
|
|
226
|
+
if (first !== "test") usage("only test is seeded; a branch takes --seed-from when it is created");
|
|
227
|
+
const seed = seedFrom(args, "");
|
|
228
|
+
if (seed === null) usage("seed needs --from live");
|
|
229
|
+
return { action: "seed", seed };
|
|
230
|
+
}
|
|
231
|
+
case "rollback": {
|
|
232
|
+
const migration2 = flagString(args, "migration");
|
|
233
|
+
if (migration2 !== void 0) return { action: "undo", migration: migration2, confirm };
|
|
234
|
+
return { action: "rollback", name: environmentName(first, true), to: time(flagString(args, "to"), "to") };
|
|
235
|
+
}
|
|
236
|
+
case "migrations": {
|
|
237
|
+
const limit = Number(flagString(args, "limit") ?? DEFAULT_MIGRATIONS);
|
|
238
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 100) usage("--limit is 1 to 100");
|
|
239
|
+
return { action: "migrations", limit };
|
|
240
|
+
}
|
|
241
|
+
case "reset":
|
|
242
|
+
return { action: "reset", name: first === void 0 ? null : localEnvironmentName(first) };
|
|
243
|
+
default:
|
|
244
|
+
return usage();
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
async function runEnvCommand(root, remote, command) {
|
|
248
|
+
if (command.action === "reset") return { kind: "reset", removed: await resetLocalData(root, command.name) };
|
|
249
|
+
if (command.action === "list" && command.local) {
|
|
250
|
+
return { kind: "local", environments: localEnvironments(root).map((name) => ({ name, dir: localDataDir(root, name) })) };
|
|
251
|
+
}
|
|
252
|
+
const id = await readInteractiveId(root);
|
|
253
|
+
const environments = await remote();
|
|
254
|
+
switch (command.action) {
|
|
255
|
+
case "list":
|
|
256
|
+
return { kind: "environments", environments: await remoteCall(() => environments.list(id)) };
|
|
257
|
+
case "create":
|
|
258
|
+
return { kind: "environment", environment: await remoteCall(() => environments.create(id, command)) };
|
|
259
|
+
case "delete":
|
|
260
|
+
await remoteCall(() => environments.remove(id, command.name));
|
|
261
|
+
return { kind: "deleted", name: command.name };
|
|
262
|
+
case "deploy":
|
|
263
|
+
return { kind: "environment", environment: await remoteCall(() => environments.deploy(id, command.name, command.revision)) };
|
|
264
|
+
case "diff":
|
|
265
|
+
return { kind: "diff", diff: await remoteCall(() => environments.diff(id, command.name, command.to)) };
|
|
266
|
+
case "migrate": {
|
|
267
|
+
const planned = await remoteCall(() => environments.diff(id, command.name, null));
|
|
268
|
+
if (planned.destructive && !command.confirm) return { kind: "diff", diff: planned };
|
|
269
|
+
return { kind: "migration", migration: await remoteCall(() => environments.migrate(id, command.name, command.confirm)) };
|
|
270
|
+
}
|
|
271
|
+
case "promote": {
|
|
272
|
+
const planned = await remoteCall(() => environments.diff(id, command.name, command.to));
|
|
273
|
+
if (planned.destructive && !command.confirm) return { kind: "diff", diff: planned };
|
|
274
|
+
const promoted = await remoteCall(() => environments.promote(id, command.name, command.to, command.confirm));
|
|
275
|
+
return { kind: "promoted", revision: promoted.revision, to: promoted.to, migrations: promoted.migrations };
|
|
276
|
+
}
|
|
277
|
+
case "seed":
|
|
278
|
+
return { kind: "environment", environment: await remoteCall(() => environments.seed(id, command.seed)) };
|
|
279
|
+
case "rollback": {
|
|
280
|
+
const rolled = await remoteCall(() => environments.rollback(id, command.name, command.to));
|
|
281
|
+
return { kind: "rolled_back", environment: rolled.environment, to: rolled.to, revision: rolled.revision, migrations: rolled.migrationsRolledBack };
|
|
282
|
+
}
|
|
283
|
+
case "undo":
|
|
284
|
+
return { kind: "migration", migration: await remoteCall(() => environments.rollbackMigration(id, command.migration, command.confirm)) };
|
|
285
|
+
case "migrations":
|
|
286
|
+
return { kind: "migrations", migrations: await remoteCall(() => environments.migrations(id, command.limit)) };
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
function renderDiff(diff2) {
|
|
290
|
+
const lines = [`${bold(diff2.environment)} schema v${diff2.fromVersion} -> v${diff2.toVersion}${diff2.revision === null ? "" : dim(` (${diff2.revision})`)}`];
|
|
291
|
+
if (diff2.changes.length === 0) lines.push(dim(" no schema changes"));
|
|
292
|
+
for (const c of diff2.changes) {
|
|
293
|
+
const target = [c.table, c.column ?? c.index].filter((part) => part !== null).join(".");
|
|
294
|
+
const mark = c.change.startsWith("drop") || c.change === "retype_column" ? "-" : c.change === "rekey_table" || c.change === "add_required_column" ? "!" : "+";
|
|
295
|
+
lines.push(` ${mark} ${c.change.replaceAll("_", " ")} ${target}`);
|
|
296
|
+
}
|
|
297
|
+
for (const s of diff2.statements) lines.push(dim(` ${s}`));
|
|
298
|
+
if (diff2.blocked) lines.push(" blocked: a table changes its key or gains a required column; declare a new table or a nullable column");
|
|
299
|
+
else if (diff2.destructive) lines.push(" destructive: drops data; rerun with --confirm to apply");
|
|
300
|
+
else if (diff2.changes.length > 0) lines.push(dim(diff2.reversible ? " additive: can be rolled back with env rollback --migration" : " cannot be rolled back"));
|
|
301
|
+
return lines;
|
|
302
|
+
}
|
|
303
|
+
function renderEnvironment(e) {
|
|
304
|
+
const schema = e.schema === null ? dim("schema unknown") : `schema v${e.schema.appliedVersion}${e.schema.pending ? ` (v${e.schema.declaredVersion} pending${e.schema.destructive ? ", destructive" : ""})` : ""}`;
|
|
305
|
+
const preview = e.previewToken === null ? "" : ` preview ${e.previewToken}`;
|
|
306
|
+
const seed = e.seed === null ? "" : dim(` seeded from ${e.seed.from} at ${e.seed.at}`);
|
|
307
|
+
const expiry = e.expiresAt === null ? "" : dim(` idle expiry ${e.expiresAt}`);
|
|
308
|
+
return `${bold(e.name.padEnd(16))} ${e.kind.padEnd(6)} ${e.revision ?? dim("no revision")} ${schema}${preview}${seed}${expiry}`;
|
|
309
|
+
}
|
|
310
|
+
function renderMigration(m) {
|
|
311
|
+
return `${m.id} ${m.environment} v${m.fromVersion} -> v${m.toVersion} ${m.status}${m.reversible ? "" : dim(" (not reversible)")} ${dim(m.appliedAt)}`;
|
|
312
|
+
}
|
|
313
|
+
function renderEnvOutcome(outcome) {
|
|
314
|
+
switch (outcome.kind) {
|
|
315
|
+
case "environments":
|
|
316
|
+
for (const e of outcome.environments) info(renderEnvironment(e));
|
|
317
|
+
return;
|
|
318
|
+
case "local":
|
|
319
|
+
if (outcome.environments.length === 0) info(dim("no local data yet; cimplify dev creates it on first use"));
|
|
320
|
+
for (const e of outcome.environments) info(`${bold(e.name.padEnd(16))} ${dim(e.dir)}`);
|
|
321
|
+
return;
|
|
322
|
+
case "environment":
|
|
323
|
+
success(renderEnvironment(outcome.environment));
|
|
324
|
+
return;
|
|
325
|
+
case "deleted":
|
|
326
|
+
success(`${outcome.name} deleted with its data and preview link`);
|
|
327
|
+
return;
|
|
328
|
+
case "diff":
|
|
329
|
+
for (const line of renderDiff(outcome.diff)) info(line);
|
|
330
|
+
if (outcome.diff.destructive && !outcome.diff.blocked) warn("nothing was applied");
|
|
331
|
+
return;
|
|
332
|
+
case "migration":
|
|
333
|
+
if (outcome.migration === null) success("data already holds the declared schema");
|
|
334
|
+
else success(renderMigration(outcome.migration));
|
|
335
|
+
return;
|
|
336
|
+
case "migrations":
|
|
337
|
+
if (outcome.migrations.length === 0) info(dim("no migrations recorded"));
|
|
338
|
+
for (const m of outcome.migrations) info(renderMigration(m));
|
|
339
|
+
return;
|
|
340
|
+
case "promoted":
|
|
341
|
+
success(`${outcome.revision} is on ${outcome.to}`);
|
|
342
|
+
for (const m of outcome.migrations) info(` ${renderMigration(m)}`);
|
|
343
|
+
return;
|
|
344
|
+
case "rolled_back":
|
|
345
|
+
success(`${outcome.environment} code and data are back at ${outcome.to}${outcome.revision === null ? "" : ` on ${outcome.revision}`}`);
|
|
346
|
+
if (outcome.migrations.length > 0) info(dim(` migrations rolled back: ${outcome.migrations.join(", ")}`));
|
|
347
|
+
return;
|
|
348
|
+
case "reset":
|
|
349
|
+
if (outcome.removed.length === 0) info(dim("no local data to reset"));
|
|
350
|
+
for (const name of outcome.removed) success(`local ${name} data reset`);
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
async function run(argv) {
|
|
355
|
+
const command = parseEnvCommand(parseArgs(argv));
|
|
356
|
+
const root = process.cwd();
|
|
357
|
+
requireInteractiveProject(root, "env");
|
|
358
|
+
const outcome = await runEnvCommand(root, environmentsFromEnv, command);
|
|
359
|
+
renderEnvOutcome(outcome);
|
|
360
|
+
result(outcome);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export { localEnvironmentName, parseEnvCommand, renderDiff, renderEnvOutcome, run, runEnvCommand };
|