@xanots/sdk 0.0.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/LICENSE +21 -0
- package/README.md +384 -0
- package/dist/agent-file-refresh-7XCACU34.js +95 -0
- package/dist/bin.d.ts +1 -0
- package/dist/bin.js +184 -0
- package/dist/capture-HUV5BNTC.js +32 -0
- package/dist/chunk-26CNBZE2.js +963 -0
- package/dist/chunk-33ND6LKO.js +78 -0
- package/dist/chunk-3DUAGYGP.js +1550 -0
- package/dist/chunk-3IGNIP6R.js +89 -0
- package/dist/chunk-47WDWMBJ.js +14 -0
- package/dist/chunk-4BXJGVZ3.js +318 -0
- package/dist/chunk-4HT3BNZ7.js +675 -0
- package/dist/chunk-4YMD2OOZ.js +23 -0
- package/dist/chunk-5WGEURVI.js +156 -0
- package/dist/chunk-5YTBTF25.js +29 -0
- package/dist/chunk-6DHBYBTO.js +166 -0
- package/dist/chunk-76QBEIGO.js +66 -0
- package/dist/chunk-7DKX2SPN.js +100 -0
- package/dist/chunk-7REDODS2.js +468 -0
- package/dist/chunk-C56BC2FY.js +254 -0
- package/dist/chunk-DGSF2Q5H.js +60 -0
- package/dist/chunk-EMCAWMHC.js +3982 -0
- package/dist/chunk-EZG76F7R.js +159 -0
- package/dist/chunk-FJ6ZS5KB.js +3607 -0
- package/dist/chunk-GNPVYOPB.js +17 -0
- package/dist/chunk-HJPTWBLH.js +38 -0
- package/dist/chunk-IZW6MK3U.js +248 -0
- package/dist/chunk-LH6Z6KFV.js +247 -0
- package/dist/chunk-MZUI3JNX.js +93 -0
- package/dist/chunk-NDZFBZHC.js +167 -0
- package/dist/chunk-NOO35BQ2.js +37 -0
- package/dist/chunk-NUQCEOKA.js +13 -0
- package/dist/chunk-QTNO2WD6.js +56 -0
- package/dist/chunk-RVB7ITKN.js +49 -0
- package/dist/chunk-TRU5OHQ5.js +6904 -0
- package/dist/chunk-VKFQJEMW.js +814 -0
- package/dist/chunk-VTIL47DT.js +125 -0
- package/dist/chunk-WHOJWOSV.js +112 -0
- package/dist/chunk-WKP4D5MO.js +1692 -0
- package/dist/chunk-X4DVXBFY.js +38 -0
- package/dist/chunk-XQ22GLYS.js +118 -0
- package/dist/chunk-YDZYMZBE.js +670 -0
- package/dist/chunk-YGPIY3WT.js +1146 -0
- package/dist/chunk-YYRDLFSJ.js +602 -0
- package/dist/chunk-ZUTSMMAG.js +46 -0
- package/dist/cli.d.ts +331 -0
- package/dist/cli.js +33 -0
- package/dist/codegen-command-OOKK6AZK.js +40 -0
- package/dist/codegen.d.ts +114 -0
- package/dist/codegen.js +71 -0
- package/dist/completion-TIPPZN7H.js +298 -0
- package/dist/config-NL33PN4D.js +84 -0
- package/dist/deploy-command-4EQ7XX5G.js +451 -0
- package/dist/env-target-IFJ5QDHC.js +16 -0
- package/dist/ephemeral-command-3X3I4ULC.js +242 -0
- package/dist/index.d.ts +4477 -0
- package/dist/index.js +300 -0
- package/dist/init-command-R6H7ZXW5.js +27 -0
- package/dist/internal.d.ts +74 -0
- package/dist/internal.js +2065 -0
- package/dist/io-AMIKRLPC.js +11 -0
- package/dist/live-diff-Y3AKETHE.js +196 -0
- package/dist/lock-3CVKALKT.js +37 -0
- package/dist/lock-commands-XTR2YKLY.js +232 -0
- package/dist/login-command-ACJF6KWQ.js +167 -0
- package/dist/logout-command-MX3MJS5U.js +68 -0
- package/dist/loop-OM3P2Z6O.js +93 -0
- package/dist/marketplace-command-RATXTKXN.js +379 -0
- package/dist/meta-client-OW5WKWW7.js +170 -0
- package/dist/node.d.ts +59 -0
- package/dist/node.js +442 -0
- package/dist/profile-command-SWJ3SPKR.js +77 -0
- package/dist/release-command-VV5UVZKL.js +427 -0
- package/dist/response-CVAE2kMj.d.ts +1915 -0
- package/dist/routes-manifest-SP3ZXLMR.js +244 -0
- package/dist/runtime-V4C3AC3A.js +13 -0
- package/dist/sandbox-details-command-HJE5SPVG.js +18 -0
- package/dist/sandbox-export-command-QCJY4GMV.js +24 -0
- package/dist/static-host-D6KS7X45.js +138 -0
- package/dist/store-BQ97nKIF.d.ts +7760 -0
- package/dist/test-command-TSPBQHBM.js +383 -0
- package/dist/validate-command-4ERHJSCO.js +122 -0
- package/dist/verify-rollout-FAVQ6EJY.js +40 -0
- package/dist/workspace-K72NP7SX.js +49 -0
- package/dist/workspace-command-OF23DPNI.js +156 -0
- package/dist/workspace-export-AJMGN3CQ.js +10 -0
- package/llms/fields.md +104 -0
- package/llms/filters.md +183 -0
- package/llms/kinds-agent-mcp.md +11 -0
- package/llms/kinds-core.md +68 -0
- package/llms/kinds-realtime.md +76 -0
- package/llms/lambda.md +111 -0
- package/llms/legacy.md +43 -0
- package/llms/object-kinds.md +31 -0
- package/llms/statements-calls.md +23 -0
- package/llms/statements-catalog.md +309 -0
- package/llms/statements-data.md +58 -0
- package/llms/statements-runtime.md +48 -0
- package/llms/tests.md +58 -0
- package/llms/triggers.md +22 -0
- package/llms/values.md +29 -0
- package/llms-full.txt +1672 -0
- package/llms.txt +483 -0
- package/manifest.json +9592 -0
- package/package.json +110 -0
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import {
|
|
2
|
+
confirm
|
|
3
|
+
} from "./chunk-5YTBTF25.js";
|
|
4
|
+
import {
|
|
5
|
+
assertBundleInput,
|
|
6
|
+
loadBundleText
|
|
7
|
+
} from "./chunk-NOO35BQ2.js";
|
|
8
|
+
import {
|
|
9
|
+
importWorkspaceArchive,
|
|
10
|
+
planWorkspaceImport
|
|
11
|
+
} from "./chunk-5WGEURVI.js";
|
|
12
|
+
import {
|
|
13
|
+
encodeWorkspaceArchive
|
|
14
|
+
} from "./chunk-ZUTSMMAG.js";
|
|
15
|
+
import "./chunk-X4DVXBFY.js";
|
|
16
|
+
import {
|
|
17
|
+
isMachineOutput,
|
|
18
|
+
writeJson
|
|
19
|
+
} from "./chunk-NUQCEOKA.js";
|
|
20
|
+
import "./chunk-3IGNIP6R.js";
|
|
21
|
+
import {
|
|
22
|
+
getAccessToken
|
|
23
|
+
} from "./chunk-C56BC2FY.js";
|
|
24
|
+
import "./chunk-7REDODS2.js";
|
|
25
|
+
import {
|
|
26
|
+
resolveLockPath
|
|
27
|
+
} from "./chunk-YGPIY3WT.js";
|
|
28
|
+
import {
|
|
29
|
+
UsageError,
|
|
30
|
+
assertWritableDest
|
|
31
|
+
} from "./chunk-IZW6MK3U.js";
|
|
32
|
+
import {
|
|
33
|
+
blank,
|
|
34
|
+
detail,
|
|
35
|
+
info,
|
|
36
|
+
link,
|
|
37
|
+
step,
|
|
38
|
+
success,
|
|
39
|
+
warn
|
|
40
|
+
} from "./chunk-EZG76F7R.js";
|
|
41
|
+
import "./chunk-3DUAGYGP.js";
|
|
42
|
+
import "./chunk-YYRDLFSJ.js";
|
|
43
|
+
import "./chunk-EMCAWMHC.js";
|
|
44
|
+
import "./chunk-WHOJWOSV.js";
|
|
45
|
+
import "./chunk-LH6Z6KFV.js";
|
|
46
|
+
import {
|
|
47
|
+
readLockFile
|
|
48
|
+
} from "./chunk-HJPTWBLH.js";
|
|
49
|
+
import "./chunk-GNPVYOPB.js";
|
|
50
|
+
import {
|
|
51
|
+
REFERENCEABLE_KIND_PAYLOAD_KEYS,
|
|
52
|
+
lockKey
|
|
53
|
+
} from "./chunk-4HT3BNZ7.js";
|
|
54
|
+
|
|
55
|
+
// src/emit/release-command.ts
|
|
56
|
+
import { existsSync } from "fs";
|
|
57
|
+
var DESTRUCTIVE_ACTIONS = /* @__PURE__ */ new Set(["delete", "truncate", "drop"]);
|
|
58
|
+
var IDENTITY_EXEMPT_TYPES = /* @__PURE__ */ new Set(["workspace"]);
|
|
59
|
+
function resolveRequest(args) {
|
|
60
|
+
if (args.replace) {
|
|
61
|
+
const conflicting = [
|
|
62
|
+
args.prune ? "--prune" : "",
|
|
63
|
+
args.resetData ? "--reset-data" : "",
|
|
64
|
+
args.seed ? "--seed" : ""
|
|
65
|
+
].filter(Boolean);
|
|
66
|
+
if (conflicting.length > 0) {
|
|
67
|
+
throw new UsageError(
|
|
68
|
+
`\`--replace\` cannot be combined with ${conflicting.join(" or ")}. A replace already clears every object and every table row, so there is nothing left for those flags to describe. Drop \`--replace\` to merge, or drop ${conflicting.join("/")}.`,
|
|
69
|
+
{ helpFor: { command: "release" } }
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
return { mode: "replace" };
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
mode: "merge",
|
|
76
|
+
prune: args.prune,
|
|
77
|
+
records: args.seed,
|
|
78
|
+
truncate: args.resetData
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function isDestructive(req) {
|
|
82
|
+
return req.mode === "replace" || req.prune === true || req.truncate === true || req.records === true;
|
|
83
|
+
}
|
|
84
|
+
function countByAction(plan) {
|
|
85
|
+
const counts = /* @__PURE__ */ new Map();
|
|
86
|
+
for (const op of plan.operations) {
|
|
87
|
+
counts.set(op.action, (counts.get(op.action) ?? 0) + 1);
|
|
88
|
+
}
|
|
89
|
+
return counts;
|
|
90
|
+
}
|
|
91
|
+
function correspondence(plan) {
|
|
92
|
+
let matched = 0;
|
|
93
|
+
let created = 0;
|
|
94
|
+
let orphaned = 0;
|
|
95
|
+
for (const op of plan.operations) {
|
|
96
|
+
if (IDENTITY_EXEMPT_TYPES.has(op.type)) continue;
|
|
97
|
+
if (op.action === "create") created++;
|
|
98
|
+
else if (op.action === "delete") orphaned++;
|
|
99
|
+
else matched++;
|
|
100
|
+
}
|
|
101
|
+
return { matched, created, orphaned };
|
|
102
|
+
}
|
|
103
|
+
function warnOnZeroCorrespondence(plan, req, targetIsEmpty2) {
|
|
104
|
+
if (req.mode !== "merge") return;
|
|
105
|
+
const { matched, created, orphaned } = correspondence(plan);
|
|
106
|
+
if (matched > 0 || created === 0) return;
|
|
107
|
+
if (targetIsEmpty2) return;
|
|
108
|
+
blank();
|
|
109
|
+
if (orphaned > 0) {
|
|
110
|
+
warn(
|
|
111
|
+
`NOTHING MATCHED. All ${created} objects would be created and ${orphaned} existing objects deleted \u2014 not one object already in this workspace shares an identity with this project.`
|
|
112
|
+
);
|
|
113
|
+
detail("This is not an update. It empties the workspace and rebuilds it from scratch.");
|
|
114
|
+
detail(
|
|
115
|
+
"That is what promoting into a workspace this project has never released to looks like \u2014 including one populated by `--replace`, which mints its own identities."
|
|
116
|
+
);
|
|
117
|
+
detail("To adopt what is already there, pin those objects' guids on your defs first. A prune here is not recoverable.");
|
|
118
|
+
} else {
|
|
119
|
+
warn(`Nothing matched: all ${created} objects would be created, none updated.`);
|
|
120
|
+
detail(
|
|
121
|
+
"If this workspace is already populated, its objects carry different identities and you will end up with two of everything. Only a workspace this project has already released to will match."
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function payloadKeyFor(type) {
|
|
126
|
+
return REFERENCEABLE_KIND_PAYLOAD_KEYS[type] ?? type;
|
|
127
|
+
}
|
|
128
|
+
function splitPruneDeletes(plan, tracked) {
|
|
129
|
+
const collateral = [];
|
|
130
|
+
const owned = [];
|
|
131
|
+
for (const op of plan.operations) {
|
|
132
|
+
if (op.action !== "delete") continue;
|
|
133
|
+
if (IDENTITY_EXEMPT_TYPES.has(op.type)) continue;
|
|
134
|
+
(tracked.has(lockKey(payloadKeyFor(op.type), op.name)) ? owned : collateral).push(op);
|
|
135
|
+
}
|
|
136
|
+
return { collateral, owned };
|
|
137
|
+
}
|
|
138
|
+
async function reconcileLockAfterReplace(args, auth, workspaceId) {
|
|
139
|
+
const lockPath = args.lockPath ?? (args.file !== void 0 ? resolveLockPath(args, args.file) : void 0);
|
|
140
|
+
if (lockPath === void 0 || !existsSync(lockPath)) {
|
|
141
|
+
blank();
|
|
142
|
+
warn("`--replace` rebuilt this workspace with new object identities.");
|
|
143
|
+
detail("Nothing pins them, so the next release will match nothing and create a duplicate of every object.");
|
|
144
|
+
detail("Run `xanots lock adopt` against this workspace, and commit the lock.");
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const live = await readLiveWorkspace(auth, workspaceId);
|
|
148
|
+
if (live === void 0) {
|
|
149
|
+
blank();
|
|
150
|
+
warn(`\`--replace\` minted new object identities and ${lockPath} still names the old ones.`);
|
|
151
|
+
detail("The target could not be re-read to update it, so the next release would match nothing.");
|
|
152
|
+
detail(`Run \`xanots lock adopt\` against this workspace before releasing again.`);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
try {
|
|
156
|
+
const { adoptFromBundle } = await import("./lock-3CVKALKT.js");
|
|
157
|
+
const { readLockFile: readLockFile2, writeLockFile } = await import("./io-AMIKRLPC.js");
|
|
158
|
+
const { lock, added, changed } = adoptFromBundle(readLockFile2(lockPath), live, lockPath);
|
|
159
|
+
writeLockFile(lockPath, lock);
|
|
160
|
+
const touched = added.length + changed.length;
|
|
161
|
+
if (touched > 0) {
|
|
162
|
+
detail(`Updated ${touched} lock entr${touched === 1 ? "y" : "ies"} to the identities \`--replace\` minted.`);
|
|
163
|
+
detail("Commit the lock \u2014 without it the next release matches nothing.");
|
|
164
|
+
}
|
|
165
|
+
} catch (err) {
|
|
166
|
+
blank();
|
|
167
|
+
warn(`Could not update ${lockPath} after the replace: ${err instanceof Error ? err.message : String(err)}`);
|
|
168
|
+
detail("It still names the identities the replace destroyed. Run `xanots lock adopt` before releasing again.");
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async function readLiveWorkspace(auth, workspaceId) {
|
|
172
|
+
try {
|
|
173
|
+
const { exportWorkspaceBundle } = await import("./workspace-export-AJMGN3CQ.js");
|
|
174
|
+
return await exportWorkspaceBundle(auth, {
|
|
175
|
+
base: auth.instance,
|
|
176
|
+
workspaceId,
|
|
177
|
+
label: "reading the target workspace"
|
|
178
|
+
});
|
|
179
|
+
} catch {
|
|
180
|
+
return void 0;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function targetIsEmpty(live) {
|
|
184
|
+
if (live === void 0) return false;
|
|
185
|
+
const payload = live.payload;
|
|
186
|
+
if (payload === null || typeof payload !== "object") return false;
|
|
187
|
+
return !Object.entries(payload).some(
|
|
188
|
+
// The workspace settings row is present in every workspace, empty or not.
|
|
189
|
+
([key, value]) => key !== "workspace" && Array.isArray(value) && value.length > 0
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
async function convergedWithLive(live, req, outgoingBundle) {
|
|
193
|
+
if (live === void 0 || req.mode !== "merge") return false;
|
|
194
|
+
if (req.records === true || req.truncate === true) return false;
|
|
195
|
+
const { compareToLive } = await import("./live-diff-Y3AKETHE.js");
|
|
196
|
+
let result;
|
|
197
|
+
try {
|
|
198
|
+
result = compareToLive(JSON.parse(outgoingBundle), live);
|
|
199
|
+
} catch {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
if (!result.converged) return false;
|
|
203
|
+
if (req.prune === true && result.liveOnly.length > 0) return false;
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
async function warnAboutLiveLosses(live, req, outgoingBundle) {
|
|
207
|
+
if (live === void 0) {
|
|
208
|
+
blank();
|
|
209
|
+
warn("Could not read the target workspace, so this plan does not account for dropped columns or env that will not update.");
|
|
210
|
+
return { droppedColumns: 0, unchangedEnv: [] };
|
|
211
|
+
}
|
|
212
|
+
const { diffAgainstLive } = await import("./live-diff-Y3AKETHE.js");
|
|
213
|
+
let diff;
|
|
214
|
+
try {
|
|
215
|
+
diff = diffAgainstLive(JSON.parse(outgoingBundle), live, { mode: req.mode });
|
|
216
|
+
} catch {
|
|
217
|
+
return { droppedColumns: 0, unchangedEnv: [] };
|
|
218
|
+
}
|
|
219
|
+
if (diff.droppedColumns.length > 0) {
|
|
220
|
+
blank();
|
|
221
|
+
warn(
|
|
222
|
+
`${diff.droppedColumns.length} column${diff.droppedColumns.length === 1 ? "" : "s"} will be DROPPED, destroying the data held in ${diff.droppedColumns.length === 1 ? "it" : "them"}:`
|
|
223
|
+
);
|
|
224
|
+
for (const { table, column } of diff.droppedColumns) {
|
|
225
|
+
detail(`drop column ${table}."${column}"`);
|
|
226
|
+
}
|
|
227
|
+
detail("The plan reports these as a routine in-place table update; they are not recoverable.");
|
|
228
|
+
}
|
|
229
|
+
if (diff.unchangedEnv.length > 0) {
|
|
230
|
+
blank();
|
|
231
|
+
warn(
|
|
232
|
+
`${diff.unchangedEnv.length} environment variable${diff.unchangedEnv.length === 1 ? "" : "s"} will NOT be updated: ${diff.unchangedEnv.map((e) => e.name).join(", ")}`
|
|
233
|
+
);
|
|
234
|
+
detail("A merge is add-only for env: it creates keys that do not exist and leaves existing ones as they are.");
|
|
235
|
+
detail("To change these values, set them in the workspace directly, or release with `--replace` (which rebuilds the workspace).");
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
droppedColumns: diff.droppedColumns.length,
|
|
239
|
+
unchangedEnv: diff.unchangedEnv.map((e) => e.name)
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
function assertPruneStaysInScope(args, plan) {
|
|
243
|
+
if (args.lockPath === void 0 && args.file === void 0) {
|
|
244
|
+
throw new UsageError(
|
|
245
|
+
"`--prune` needs a lock file to know which objects belong to this project, and `--bundle` carries none. Pass `--lock=<path>` to name the lock that was written when the bundle was compiled, release from the entry file instead, or drop `--prune`.",
|
|
246
|
+
{ helpFor: { command: "release" } }
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
const lockPath = resolveLockPath(args, args.file ?? ".");
|
|
250
|
+
if (!existsSync(lockPath)) {
|
|
251
|
+
throw new UsageError(
|
|
252
|
+
`\`--prune\` needs a lock file and none exists at ${lockPath}.
|
|
253
|
+
Without it there is no record of which objects this project created, so a prune cannot tell yours from ones that were already in the workspace \u2014 and it deletes both.
|
|
254
|
+
Create one with \`xanots export ${args.file} --lock\` and commit it, or drop \`--prune\`.`,
|
|
255
|
+
{ helpFor: { command: "release" } }
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
const tracked = new Set(Object.keys(readLockFile(lockPath).objects));
|
|
259
|
+
const { collateral, owned } = splitPruneDeletes(plan, tracked);
|
|
260
|
+
if (collateral.length === 0) return;
|
|
261
|
+
blank();
|
|
262
|
+
const lines = collateral.map((op) => ` ${op.type} "${op.name}"${op.reason !== void 0 ? ` \u2014 ${op.reason}` : ""}`);
|
|
263
|
+
throw new UsageError(
|
|
264
|
+
`\`--prune\` would delete ${collateral.length} object${collateral.length === 1 ? "" : "s"} this project has never released:
|
|
265
|
+
${lines.join("\n")}
|
|
266
|
+
|
|
267
|
+
\`--prune\` is documented as deleting objects your project no longer defines, but the endpoint deletes everything absent from the bundle \u2014 including objects that predate the project. Dropping a populated table is not recoverable.
|
|
268
|
+
` + (owned.length > 0 ? `The ${owned.length} deletion${owned.length === 1 ? "" : "s"} this project does own would have been correct.
|
|
269
|
+
` : "") + `To delete the objects above anyway, adopt them into the project first (\`xanots lock adopt\`) so they are yours to remove. To keep them, drop \`--prune\`.`,
|
|
270
|
+
{ helpFor: { command: "release" } }
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
function renderPlan(plan, req, workspaceId, targetIsEmpty2, converged = false) {
|
|
274
|
+
const counts = countByAction(plan);
|
|
275
|
+
const label = plan.workspaceName !== void 0 ? `${plan.workspaceName} (#${workspaceId})` : `#${workspaceId}`;
|
|
276
|
+
blank();
|
|
277
|
+
step(`Plan for workspace ${label}`);
|
|
278
|
+
if (converged) {
|
|
279
|
+
detail("no changes \u2014 every object this project defines already matches the workspace");
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const order = ["create", "update", "delete", "truncate", "drop"];
|
|
283
|
+
const seen = [...order.filter((a) => counts.has(a)), ...[...counts.keys()].filter((a) => !order.includes(a))];
|
|
284
|
+
if (seen.length === 0) {
|
|
285
|
+
detail("no changes");
|
|
286
|
+
} else {
|
|
287
|
+
for (const action of seen) {
|
|
288
|
+
detail(`${action}: ${counts.get(action)}`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
const destructive = plan.operations.filter((op) => DESTRUCTIVE_ACTIONS.has(op.action));
|
|
292
|
+
if (destructive.length > 0) {
|
|
293
|
+
blank();
|
|
294
|
+
warn(`${destructive.length} destructive operation${destructive.length === 1 ? "" : "s"}:`);
|
|
295
|
+
for (const op of destructive) {
|
|
296
|
+
const why = op.reason !== void 0 ? ` \u2014 ${op.reason}` : "";
|
|
297
|
+
detail(`${op.action} ${op.type} "${op.name}"${why}`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
if (plan.hasRecords) {
|
|
301
|
+
blank();
|
|
302
|
+
warn("Table rows from the bundle WILL be written.");
|
|
303
|
+
}
|
|
304
|
+
blank();
|
|
305
|
+
if (plan.hasEnv) {
|
|
306
|
+
warn("Environment variables from the bundle WILL be written.");
|
|
307
|
+
if (req.mode === "merge") {
|
|
308
|
+
detail("Merge is add-only: keys that do not exist are created; existing keys are NOT updated.");
|
|
309
|
+
}
|
|
310
|
+
} else {
|
|
311
|
+
detail("The archive carries no environment variables \u2014 existing env is left untouched.");
|
|
312
|
+
}
|
|
313
|
+
const notes = plan.summary.notes;
|
|
314
|
+
if (typeof notes === "string" && notes !== "") {
|
|
315
|
+
blank();
|
|
316
|
+
warn(notes);
|
|
317
|
+
} else if (Array.isArray(notes)) {
|
|
318
|
+
blank();
|
|
319
|
+
for (const note of notes) {
|
|
320
|
+
if (typeof note === "string" && note !== "") warn(note);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if (req.mode === "replace") {
|
|
324
|
+
blank();
|
|
325
|
+
warn("`--replace` wipes this workspace before importing \u2014 including table data and history.");
|
|
326
|
+
}
|
|
327
|
+
warnOnZeroCorrespondence(plan, req, targetIsEmpty2);
|
|
328
|
+
blank();
|
|
329
|
+
}
|
|
330
|
+
async function runReleaseCommand(args) {
|
|
331
|
+
assertWritableDest(args.dest, "release");
|
|
332
|
+
const req = resolveRequest(args);
|
|
333
|
+
assertBundleInput(args, { command: "release" });
|
|
334
|
+
const auth = await getAccessToken(args);
|
|
335
|
+
const { bundle, source, content, nonPublicSeedValues } = await loadBundleText(
|
|
336
|
+
args,
|
|
337
|
+
{ command: "release" },
|
|
338
|
+
{ withSeed: req.records === true }
|
|
339
|
+
);
|
|
340
|
+
if (args.static !== void 0) {
|
|
341
|
+
const { assertNoSeedLeaks } = await import("./deploy-command-4EQ7XX5G.js");
|
|
342
|
+
await assertNoSeedLeaks(args.static, nonPublicSeedValues, args.allowSeedInStatic);
|
|
343
|
+
}
|
|
344
|
+
const workspaceId = auth.workspaceId;
|
|
345
|
+
const archive = encodeWorkspaceArchive(bundle, content);
|
|
346
|
+
if (req.records === true && content.length === 0) {
|
|
347
|
+
warn("`--seed` was passed, but no table in this project declares seed rows \u2014 no rows will be written.");
|
|
348
|
+
}
|
|
349
|
+
const target = { baseUrl: auth.instance, archive, workspaceId, ...req };
|
|
350
|
+
step(
|
|
351
|
+
`Releasing ${source} \u2192 instance workspace #${workspaceId}` + (req.mode === "replace" ? " (full replace)" : " (merge)")
|
|
352
|
+
);
|
|
353
|
+
const plan = await planWorkspaceImport(auth, target);
|
|
354
|
+
const live = await readLiveWorkspace(auth, workspaceId);
|
|
355
|
+
const converged = await convergedWithLive(live, req, bundle);
|
|
356
|
+
renderPlan(plan, req, workspaceId, targetIsEmpty(live), converged);
|
|
357
|
+
const losses = await warnAboutLiveLosses(live, req, bundle);
|
|
358
|
+
if (req.prune === true) assertPruneStaysInScope(args, plan);
|
|
359
|
+
if (args.dryRun) {
|
|
360
|
+
info("Dry run \u2014 nothing was sent.");
|
|
361
|
+
if (isMachineOutput(args)) writeJson({ released: false, dryRun: true, workspaceId, plan });
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
const upToDate = plan.operations.length === 0 || converged;
|
|
365
|
+
if (upToDate) {
|
|
366
|
+
success(`Workspace #${workspaceId} is already up to date \u2014 no import sent.`);
|
|
367
|
+
} else {
|
|
368
|
+
if ((isDestructive(req) || losses.droppedColumns > 0) && !args.yes && !args.force) {
|
|
369
|
+
const ok = await confirm(`Apply this plan to workspace #${workspaceId}?`, {
|
|
370
|
+
flag: "--yes",
|
|
371
|
+
helpFor: { command: "release" }
|
|
372
|
+
});
|
|
373
|
+
if (!ok) {
|
|
374
|
+
info("Release cancelled.");
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
await importWorkspaceArchive(auth, target);
|
|
379
|
+
success(`Released to instance workspace #${workspaceId}`);
|
|
380
|
+
if (req.mode === "replace") await reconcileLockAfterReplace(args, auth, workspaceId);
|
|
381
|
+
}
|
|
382
|
+
link(auth.instance);
|
|
383
|
+
const summary = {
|
|
384
|
+
// `released: false` with `upToDate: true` is a SUCCESS, not a failure — the
|
|
385
|
+
// workspace already matches. A wrapper gating on `released` alone would read
|
|
386
|
+
// a converged release as a broken one, so both fields are always present.
|
|
387
|
+
released: !upToDate,
|
|
388
|
+
upToDate,
|
|
389
|
+
mode: req.mode,
|
|
390
|
+
prune: req.prune === true,
|
|
391
|
+
// What HAPPENED, not the flag that was asked for. This is the one field
|
|
392
|
+
// someone checks to confirm a seed landed, and echoing the input into it
|
|
393
|
+
// reported success over a write that never occurred (issue #167). Rows go
|
|
394
|
+
// out only when the flag was set AND the archive actually carried some AND
|
|
395
|
+
// the import ran.
|
|
396
|
+
records: req.records === true && content.length > 0 && !upToDate,
|
|
397
|
+
truncate: req.truncate === true,
|
|
398
|
+
workspaceId,
|
|
399
|
+
instance: auth.instance,
|
|
400
|
+
// What this release will DO, not what the plan enumerated: a converged
|
|
401
|
+
// release sends nothing, and reporting the server's matched-identity count
|
|
402
|
+
// beside `upToDate: true` would contradict it.
|
|
403
|
+
operations: upToDate ? 0 : plan.operations.length,
|
|
404
|
+
droppedColumns: losses.droppedColumns,
|
|
405
|
+
unchangedEnv: losses.unchangedEnv
|
|
406
|
+
};
|
|
407
|
+
if (args.static !== void 0) {
|
|
408
|
+
const { buildStaticEnv, deployStaticTo } = await import("./deploy-command-4EQ7XX5G.js");
|
|
409
|
+
const env = buildStaticEnv(auth.instance, args.staticEnv);
|
|
410
|
+
const explicit = Object.keys(args.staticEnv).length > 0;
|
|
411
|
+
summary.static = await deployStaticTo(
|
|
412
|
+
args.static,
|
|
413
|
+
auth,
|
|
414
|
+
{ baseUrl: auth.instance, workspaceId, label: void 0 },
|
|
415
|
+
env,
|
|
416
|
+
explicit,
|
|
417
|
+
args.staticHost,
|
|
418
|
+
args.noVerify,
|
|
419
|
+
args.staticRouting
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
if (isMachineOutput(args)) writeJson(summary);
|
|
423
|
+
}
|
|
424
|
+
export {
|
|
425
|
+
runReleaseCommand
|
|
426
|
+
};
|
|
427
|
+
//# sourceMappingURL=release-command-VV5UVZKL.js.map
|