@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,451 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertBundleInput,
|
|
3
|
+
loadBundleText
|
|
4
|
+
} from "./chunk-NOO35BQ2.js";
|
|
5
|
+
import {
|
|
6
|
+
importWorkspaceArchive
|
|
7
|
+
} from "./chunk-5WGEURVI.js";
|
|
8
|
+
import {
|
|
9
|
+
createEphemeral,
|
|
10
|
+
getEphemeral,
|
|
11
|
+
isEphemeralDisabled,
|
|
12
|
+
isExpired,
|
|
13
|
+
tenantBaseUrl,
|
|
14
|
+
waitUntilReady
|
|
15
|
+
} from "./chunk-6DHBYBTO.js";
|
|
16
|
+
import {
|
|
17
|
+
encodeWorkspaceArchive
|
|
18
|
+
} from "./chunk-ZUTSMMAG.js";
|
|
19
|
+
import {
|
|
20
|
+
getEnvironment,
|
|
21
|
+
readEphemeralState,
|
|
22
|
+
setEnvironment
|
|
23
|
+
} from "./chunk-DGSF2Q5H.js";
|
|
24
|
+
import {
|
|
25
|
+
openBrowser
|
|
26
|
+
} from "./chunk-VTIL47DT.js";
|
|
27
|
+
import "./chunk-X4DVXBFY.js";
|
|
28
|
+
import {
|
|
29
|
+
microserviceLine,
|
|
30
|
+
readyRatio,
|
|
31
|
+
waitForMicroservices
|
|
32
|
+
} from "./chunk-NDZFBZHC.js";
|
|
33
|
+
import {
|
|
34
|
+
isMachineOutput,
|
|
35
|
+
writeJson
|
|
36
|
+
} from "./chunk-NUQCEOKA.js";
|
|
37
|
+
import {
|
|
38
|
+
fetchOrExplain,
|
|
39
|
+
httpFailure
|
|
40
|
+
} from "./chunk-3IGNIP6R.js";
|
|
41
|
+
import {
|
|
42
|
+
getAccessToken
|
|
43
|
+
} from "./chunk-C56BC2FY.js";
|
|
44
|
+
import "./chunk-7REDODS2.js";
|
|
45
|
+
import "./chunk-YGPIY3WT.js";
|
|
46
|
+
import {
|
|
47
|
+
assertWritableDest
|
|
48
|
+
} from "./chunk-IZW6MK3U.js";
|
|
49
|
+
import {
|
|
50
|
+
blank,
|
|
51
|
+
detail,
|
|
52
|
+
elapsedSuffix,
|
|
53
|
+
formatExpiration,
|
|
54
|
+
hostLabel,
|
|
55
|
+
info,
|
|
56
|
+
link,
|
|
57
|
+
spinner,
|
|
58
|
+
step,
|
|
59
|
+
success,
|
|
60
|
+
warn,
|
|
61
|
+
withSpinner
|
|
62
|
+
} from "./chunk-EZG76F7R.js";
|
|
63
|
+
import "./chunk-3DUAGYGP.js";
|
|
64
|
+
import "./chunk-YYRDLFSJ.js";
|
|
65
|
+
import "./chunk-EMCAWMHC.js";
|
|
66
|
+
import "./chunk-WHOJWOSV.js";
|
|
67
|
+
import "./chunk-LH6Z6KFV.js";
|
|
68
|
+
import "./chunk-HJPTWBLH.js";
|
|
69
|
+
import "./chunk-GNPVYOPB.js";
|
|
70
|
+
import "./chunk-4HT3BNZ7.js";
|
|
71
|
+
|
|
72
|
+
// src/emit/deploy-command.ts
|
|
73
|
+
import { basename } from "path";
|
|
74
|
+
var EXIT_STATIC_FAILED = 3;
|
|
75
|
+
var EXIT_MICROSERVICE_NOT_READY = 4;
|
|
76
|
+
var EXIT_TESTS_UNREACHABLE = 6;
|
|
77
|
+
var SANDBOX_TIMEOUT_MS = 3e4;
|
|
78
|
+
function microserviceCheck(args) {
|
|
79
|
+
return { noVerify: args.noVerify, requireReady: args.requireMicroservices };
|
|
80
|
+
}
|
|
81
|
+
function buildStaticEnv(baseUrl, staticEnv) {
|
|
82
|
+
const env = {};
|
|
83
|
+
if (baseUrl) env.XANO_HOST = baseUrl;
|
|
84
|
+
Object.assign(env, staticEnv);
|
|
85
|
+
return env;
|
|
86
|
+
}
|
|
87
|
+
function deriveDisplay(bundleText, cwd) {
|
|
88
|
+
try {
|
|
89
|
+
const parsed = JSON.parse(bundleText);
|
|
90
|
+
const w = parsed.payload?.workspace;
|
|
91
|
+
const name = Array.isArray(w) ? w[0]?.name : w?.name;
|
|
92
|
+
if (typeof name === "string" && name.trim() !== "") return name;
|
|
93
|
+
} catch {
|
|
94
|
+
}
|
|
95
|
+
return basename(cwd) || "xanots-app";
|
|
96
|
+
}
|
|
97
|
+
async function resolveSandboxBaseUrl(auth) {
|
|
98
|
+
const url = new URL("/api:meta/sandbox/me", auth.instance);
|
|
99
|
+
const res = await fetchOrExplain(
|
|
100
|
+
url.href,
|
|
101
|
+
{
|
|
102
|
+
headers: { accept: "application/json", Authorization: `Bearer ${auth.access_token}` },
|
|
103
|
+
signal: AbortSignal.timeout(SANDBOX_TIMEOUT_MS)
|
|
104
|
+
},
|
|
105
|
+
"resolve sandbox",
|
|
106
|
+
SANDBOX_TIMEOUT_MS
|
|
107
|
+
);
|
|
108
|
+
const text = await res.text();
|
|
109
|
+
if (!res.ok) throw new Error(httpFailure("resolve sandbox", res, text));
|
|
110
|
+
let tenant = {};
|
|
111
|
+
try {
|
|
112
|
+
tenant = JSON.parse(text);
|
|
113
|
+
} catch {
|
|
114
|
+
throw new Error(`resolve sandbox: could not parse the ${url.pathname} response as JSON:
|
|
115
|
+
${text}`);
|
|
116
|
+
}
|
|
117
|
+
return tenantBaseUrl(tenant, auth.instance);
|
|
118
|
+
}
|
|
119
|
+
async function assertNoSeedLeaks(dir, values, allow) {
|
|
120
|
+
if (values.length === 0) return;
|
|
121
|
+
const unscannable = [
|
|
122
|
+
...new Set(values.filter((v) => v.scannable === false).map((v) => `${v.table}.${v.column}`))
|
|
123
|
+
];
|
|
124
|
+
if (unscannable.length > 0) {
|
|
125
|
+
warn(
|
|
126
|
+
`${unscannable.length} non-public seed column(s) hold values the static scan cannot search for \u2014 too short to match on, or not text at all \u2014 so they were NOT checked. Being unsearchable is not being safe: if any of these is a real credential, shorten the exposure rather than the value.`
|
|
127
|
+
);
|
|
128
|
+
for (const column of unscannable) detail(column);
|
|
129
|
+
}
|
|
130
|
+
const { findSeedLeaks } = await import("./static-host-D6KS7X45.js");
|
|
131
|
+
const leaks = findSeedLeaks(dir, values);
|
|
132
|
+
if (leaks.length === 0) return;
|
|
133
|
+
const lines = leaks.map((l) => ` ${l.file} \u2014 ${l.table}.${l.column}`);
|
|
134
|
+
if (allow) {
|
|
135
|
+
warn(`Publishing ${leaks.length} non-public seed value(s) in the static build (--allow-seed-in-static):`);
|
|
136
|
+
for (const line of lines) detail(line);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
throw new Error(
|
|
140
|
+
`Refusing to publish: the static build in "${dir}" contains seed values from columns your schema marks non-public. These would be served at a public URL.
|
|
141
|
+
${lines.join("\n")}
|
|
142
|
+
|
|
143
|
+
A bundler copied them in \u2014 most often from \`seed: () => import("./seed.json")\`, which does NOT keep seed values out of a frontend build. Use \`seedFile("./seed.json", import.meta.url)\` instead, then rebuild the frontend.
|
|
144
|
+
If the data is deliberately public demo content, pass --allow-seed-in-static.`
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
function deployTarget(auth) {
|
|
148
|
+
detail(`on ${hostLabel(auth.instance)} \xB7 workspace ${auth.workspaceId}`);
|
|
149
|
+
}
|
|
150
|
+
async function runDeployedTests(auth, dest, summary, args) {
|
|
151
|
+
try {
|
|
152
|
+
return await runTestsOrThrow(auth, dest, summary, args);
|
|
153
|
+
} catch (err) {
|
|
154
|
+
warn("The deploy stands, but its tests could not be run:");
|
|
155
|
+
detail(err instanceof Error ? err.message : String(err));
|
|
156
|
+
process.exitCode = EXIT_TESTS_UNREACHABLE;
|
|
157
|
+
return void 0;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async function runTestsOrThrow(auth, dest, summary, args) {
|
|
161
|
+
const { runSuite, EXIT_TESTS_FAILED } = await import("./test-command-TSPBQHBM.js");
|
|
162
|
+
let target;
|
|
163
|
+
if (dest === "ephemeral") {
|
|
164
|
+
if (summary.url === void 0) {
|
|
165
|
+
warn("Skipped --test: the ephemeral reported no base URL to run against.");
|
|
166
|
+
return void 0;
|
|
167
|
+
}
|
|
168
|
+
const name = summary.ephemeral?.name;
|
|
169
|
+
target = { base: summary.url, workspaceId: 1, label: name ? `ephemeral ${name}` : "the ephemeral", env: name };
|
|
170
|
+
} else {
|
|
171
|
+
const { resolveMetaTarget } = await import("./env-target-IFJ5QDHC.js");
|
|
172
|
+
target = await resolveMetaTarget(auth, { dest: "sandbox" });
|
|
173
|
+
}
|
|
174
|
+
const outcomes = await runSuite(auth, target, {
|
|
175
|
+
kind: args.kind,
|
|
176
|
+
concurrency: args.concurrency,
|
|
177
|
+
human: !isMachineOutput(args)
|
|
178
|
+
});
|
|
179
|
+
const passed = outcomes.filter((o) => o.status === "pass").length;
|
|
180
|
+
const failed = outcomes.length - passed;
|
|
181
|
+
if (!isMachineOutput(args)) {
|
|
182
|
+
blank();
|
|
183
|
+
if (outcomes.length === 0) detail("No tests found in the deployed environment.");
|
|
184
|
+
else if (failed > 0) warn(`${passed} passed, ${failed} failed`);
|
|
185
|
+
else success(`${passed} passed, 0 failed`);
|
|
186
|
+
}
|
|
187
|
+
if (failed > 0) process.exitCode = EXIT_TESTS_FAILED;
|
|
188
|
+
return {
|
|
189
|
+
total: outcomes.length,
|
|
190
|
+
passed,
|
|
191
|
+
failed,
|
|
192
|
+
results: outcomes.map((o) => ({
|
|
193
|
+
kind: o.kind,
|
|
194
|
+
name: o.name,
|
|
195
|
+
status: o.status,
|
|
196
|
+
message: o.message,
|
|
197
|
+
timing: o.timing
|
|
198
|
+
}))
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
async function runDeployCommand(args) {
|
|
202
|
+
assertWritableDest(args.dest, "deploy");
|
|
203
|
+
const dest = args.dest ?? "ephemeral";
|
|
204
|
+
const startedAt = Date.now();
|
|
205
|
+
if (args.reset) info("`--reset` is redundant \u2014 deploy is always a full replace.");
|
|
206
|
+
assertBundleInput(args, { command: "deploy" });
|
|
207
|
+
const auth = await getAccessToken(args);
|
|
208
|
+
const { bundle, source, content, nonPublicSeedValues } = await loadBundleText(
|
|
209
|
+
args,
|
|
210
|
+
{ command: "deploy" },
|
|
211
|
+
{ withSeed: true }
|
|
212
|
+
);
|
|
213
|
+
if (args.static !== void 0) {
|
|
214
|
+
await assertNoSeedLeaks(args.static, nonPublicSeedValues, args.allowSeedInStatic);
|
|
215
|
+
}
|
|
216
|
+
if (content.length > 0) {
|
|
217
|
+
const rows = content.length === 1 ? "1 seed content file" : `${content.length} seed content files`;
|
|
218
|
+
detail(`Bundling ${rows} (full replace re-seeds cleanly).`);
|
|
219
|
+
}
|
|
220
|
+
const archive = encodeWorkspaceArchive(bundle, content);
|
|
221
|
+
let staticSummary;
|
|
222
|
+
const staticDir = args.static;
|
|
223
|
+
const publishStatic = staticDir === void 0 ? void 0 : async (env) => {
|
|
224
|
+
const staticEnv = buildStaticEnv(env.baseUrl, args.staticEnv);
|
|
225
|
+
const explicit = Object.keys(args.staticEnv).length > 0;
|
|
226
|
+
try {
|
|
227
|
+
const target = dest === "ephemeral" ? { baseUrl: env.baseUrl, workspaceId: 1, label: env.label } : { baseUrl: auth.instance, workspaceId: auth.workspaceId, label: void 0 };
|
|
228
|
+
staticSummary = await deployStaticTo(staticDir, auth, target, staticEnv, explicit, args.staticHost, args.noVerify, args.staticRouting);
|
|
229
|
+
} catch (err) {
|
|
230
|
+
warn("The static-host upload failed \u2014 the backend deploy stands:");
|
|
231
|
+
detail(err instanceof Error ? err.message : String(err));
|
|
232
|
+
detail(
|
|
233
|
+
`Retry just the static step: xanots deploy --static ${staticDir}` + (args.staticHost ? ` --static-host ${args.staticHost}` : "")
|
|
234
|
+
);
|
|
235
|
+
process.exitCode = EXIT_STATIC_FAILED;
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
const summary = dest === "sandbox" ? await deploySandbox(auth, archive, source, microserviceCheck(args), startedAt, publishStatic) : await deployEphemeral(auth, { archive, bundle, source, args, startedAt, publishStatic });
|
|
239
|
+
if (staticSummary !== void 0) summary.static = staticSummary;
|
|
240
|
+
if (dest === "ephemeral" && summary.created === false && staticSummary?.url !== void 0) {
|
|
241
|
+
detail("This static URL is new \u2014 a re-deploy replaces the environment's hosting, so the previous one no longer serves.");
|
|
242
|
+
}
|
|
243
|
+
if (args.test) summary.tests = await runDeployedTests(auth, dest, summary, args);
|
|
244
|
+
if (args.open) openDeployed(summary);
|
|
245
|
+
if (isMachineOutput(args)) writeJson(summary);
|
|
246
|
+
}
|
|
247
|
+
function openDeployed(summary) {
|
|
248
|
+
const url = summary.static?.url ?? summary.url;
|
|
249
|
+
if (url === void 0) {
|
|
250
|
+
warn("--open had no URL to open \u2014 the deploy reported none.");
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
detail(`Opening ${url}`);
|
|
254
|
+
openBrowser(url);
|
|
255
|
+
}
|
|
256
|
+
async function deploySandbox(auth, archive, source, check, startedAt, publishStatic) {
|
|
257
|
+
step(`Deploying ${source} \u2192 sandbox (full replace)`);
|
|
258
|
+
deployTarget(auth);
|
|
259
|
+
const baseUrl = await resolveSandboxBaseUrl(auth);
|
|
260
|
+
await publishStatic?.({ baseUrl, label: void 0 });
|
|
261
|
+
await withSpinner(IMPORTING_LABEL, () => importWorkspaceArchive(auth, { baseUrl, archive }));
|
|
262
|
+
success(`Backend deployed to sandbox${elapsedSuffix(startedAt)}`);
|
|
263
|
+
link(baseUrl);
|
|
264
|
+
const microservices = await verifyMicroservices(auth, baseUrl, check);
|
|
265
|
+
return { dest: "sandbox", url: baseUrl, ...microservices ? { microservices } : {} };
|
|
266
|
+
}
|
|
267
|
+
var WAITING_LABEL = "Waiting for microservices\u2026";
|
|
268
|
+
var IMPORTING_LABEL = "Uploading and importing the workspace\u2026";
|
|
269
|
+
function waitingLabel(microservices) {
|
|
270
|
+
const { ready, startable } = readyRatio(microservices);
|
|
271
|
+
return startable === 0 ? WAITING_LABEL : `${WAITING_LABEL} (${ready}/${startable} ready)`;
|
|
272
|
+
}
|
|
273
|
+
async function verifyMicroservices(auth, baseUrl, opts, waitOpts = {}) {
|
|
274
|
+
if (opts.noVerify) return void 0;
|
|
275
|
+
const spin = spinner(WAITING_LABEL);
|
|
276
|
+
let result;
|
|
277
|
+
try {
|
|
278
|
+
result = await waitForMicroservices(auth, { baseUrl, workspaceId: 1 }, {
|
|
279
|
+
...waitOpts,
|
|
280
|
+
onPoll: (rows) => {
|
|
281
|
+
spin.update(waitingLabel(rows));
|
|
282
|
+
waitOpts.onPoll?.(rows);
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
} catch (err) {
|
|
286
|
+
warn("Could not read microservice status (the backend deployed fine):");
|
|
287
|
+
detail(err instanceof Error ? err.message : String(err));
|
|
288
|
+
return void 0;
|
|
289
|
+
} finally {
|
|
290
|
+
spin.stop();
|
|
291
|
+
}
|
|
292
|
+
const { microservices, timedOut, hadFailure } = result;
|
|
293
|
+
if (microservices.length === 0) return void 0;
|
|
294
|
+
const { ready, startable } = readyRatio(microservices);
|
|
295
|
+
if (hadFailure) {
|
|
296
|
+
warn("Some microservices failed to start:");
|
|
297
|
+
failDeploy();
|
|
298
|
+
} else if (timedOut) {
|
|
299
|
+
warn(`Microservices are still starting (${ready}/${startable} ready) \u2014 they should come up shortly:`);
|
|
300
|
+
if (opts.requireReady) failDeploy();
|
|
301
|
+
} else if (startable === 0) {
|
|
302
|
+
info("No microservices to start:");
|
|
303
|
+
} else {
|
|
304
|
+
success(`Microservices ready (${ready}/${startable})`);
|
|
305
|
+
}
|
|
306
|
+
for (const m of microservices) detail(microserviceLine(m));
|
|
307
|
+
if (timedOut && !hadFailure) {
|
|
308
|
+
detail("Re-check with `xanots ephemeral get <env>`, or skip this wait next time with --no-verify.");
|
|
309
|
+
if (!opts.requireReady) {
|
|
310
|
+
detail("Fail the deploy on this instead of warning: --require-microservices.");
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return microservices;
|
|
314
|
+
}
|
|
315
|
+
function failDeploy() {
|
|
316
|
+
if (!process.exitCode) process.exitCode = EXIT_MICROSERVICE_NOT_READY;
|
|
317
|
+
}
|
|
318
|
+
function ephemeralDisabledError(source) {
|
|
319
|
+
return new Error(
|
|
320
|
+
`Ephemeral environments are not enabled on this instance, so \`--dest ephemeral\` (the default) has nothing to create.
|
|
321
|
+
Deploy to the sandbox instead: \`xanots deploy --dest sandbox ${source}\`.
|
|
322
|
+
\u26A0 With \`--dest sandbox\`, \`--static\` publishes the frontend to your OWN (parent) workspace \u2014 the sandbox tenant does not serve static hosting \u2014 so it replaces whatever that workspace is hosting.`
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
async function deployEphemeral(auth, ctx) {
|
|
326
|
+
const { archive, bundle, source, args, startedAt, publishStatic } = ctx;
|
|
327
|
+
const parentWorkspaceId = auth.workspaceId;
|
|
328
|
+
const dir = process.cwd();
|
|
329
|
+
const stored = getEnvironment(readEphemeralState(dir), parentWorkspaceId);
|
|
330
|
+
let target = null;
|
|
331
|
+
if (stored) {
|
|
332
|
+
const existing = await getEphemeral(auth, { parentWorkspaceId, name: stored.name });
|
|
333
|
+
if (existing && !isExpired(existing.expiresAt)) target = existing;
|
|
334
|
+
}
|
|
335
|
+
const created = target === null;
|
|
336
|
+
if (target === null) {
|
|
337
|
+
const display = args.name ?? deriveDisplay(bundle, dir);
|
|
338
|
+
step(`Deploying ${source} \u2192 new ephemeral "${display}"`);
|
|
339
|
+
deployTarget(auth);
|
|
340
|
+
const fresh = await createEphemeral(auth, {
|
|
341
|
+
parentWorkspaceId,
|
|
342
|
+
display,
|
|
343
|
+
expiresHours: args.expiresHours
|
|
344
|
+
}).catch((err) => {
|
|
345
|
+
if (!isEphemeralDisabled(err)) throw err;
|
|
346
|
+
throw ephemeralDisabledError(source);
|
|
347
|
+
});
|
|
348
|
+
target = await withSpinner(
|
|
349
|
+
`Waiting for ${fresh.name} to become ready\u2026`,
|
|
350
|
+
() => waitUntilReady(auth, { parentWorkspaceId, name: fresh.name })
|
|
351
|
+
);
|
|
352
|
+
} else {
|
|
353
|
+
step(`Deploying ${source} \u2192 ephemeral ${target.name} (refresh, full replace)`);
|
|
354
|
+
deployTarget(auth);
|
|
355
|
+
}
|
|
356
|
+
const baseUrl = target.url;
|
|
357
|
+
if (baseUrl === void 0) {
|
|
358
|
+
throw new Error(`Ephemeral "${target.name}" has no base URL yet \u2014 try \`xanots deploy\` again.`);
|
|
359
|
+
}
|
|
360
|
+
setEnvironment(dir, parentWorkspaceId, {
|
|
361
|
+
name: target.name,
|
|
362
|
+
display: target.display ?? args.name ?? target.name,
|
|
363
|
+
url: baseUrl,
|
|
364
|
+
expires_at: target.expiresAt
|
|
365
|
+
});
|
|
366
|
+
let importFailure;
|
|
367
|
+
try {
|
|
368
|
+
await withSpinner(IMPORTING_LABEL, () => importWorkspaceArchive(auth, { baseUrl, archive }));
|
|
369
|
+
} catch (err) {
|
|
370
|
+
importFailure = err;
|
|
371
|
+
}
|
|
372
|
+
if (importFailure !== void 0) {
|
|
373
|
+
if (publishStatic !== void 0) {
|
|
374
|
+
warn("The import failed \u2014 republishing the frontend so the static host keeps serving.");
|
|
375
|
+
detail("It will run against this environment's PREVIOUS backend until a deploy imports cleanly.");
|
|
376
|
+
await publishStatic({ baseUrl, label: `ephemeral ${target.name}` });
|
|
377
|
+
}
|
|
378
|
+
throw importFailure;
|
|
379
|
+
}
|
|
380
|
+
const urlChanged = created || stored !== void 0 && stored.url !== baseUrl;
|
|
381
|
+
if (urlChanged) {
|
|
382
|
+
success(`Ephemeral ${target.name} deployed${elapsedSuffix(startedAt)}`);
|
|
383
|
+
warn("New ephemeral URL:");
|
|
384
|
+
link(baseUrl);
|
|
385
|
+
} else {
|
|
386
|
+
success(`Refreshed ${target.name} (URL unchanged)${elapsedSuffix(startedAt)}`);
|
|
387
|
+
link(baseUrl);
|
|
388
|
+
}
|
|
389
|
+
detail(`Expires ${formatExpiration(target.expiresAt)}`);
|
|
390
|
+
detail(`Manage with \`xanots ephemeral get ${target.name}\``);
|
|
391
|
+
detail(`Open the builder with \`xanots ephemeral impersonate ${target.name}\``);
|
|
392
|
+
await publishStatic?.({ baseUrl, label: `ephemeral ${target.name}` });
|
|
393
|
+
if (publishStatic !== void 0) {
|
|
394
|
+
detail(
|
|
395
|
+
"The frontend URL changes on every ephemeral deploy (the import clears static hosting) and the replace re-seeds the environment. For a stable URL while iterating, deploy with `--dest sandbox` \u2014 its frontend lands on your own workspace, which no import clears."
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
const microservices = await verifyMicroservices(auth, baseUrl, microserviceCheck(args));
|
|
399
|
+
return {
|
|
400
|
+
dest: "ephemeral",
|
|
401
|
+
url: baseUrl,
|
|
402
|
+
ephemeral: { name: target.name, display: target.display, expiresAt: target.expiresAt },
|
|
403
|
+
created,
|
|
404
|
+
...microservices ? { microservices } : {}
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
async function deployStaticTo(dir, auth, target, env, explicit, host, noVerify, routing) {
|
|
408
|
+
const { deployStaticHost } = await import("./static-host-D6KS7X45.js");
|
|
409
|
+
const where = target.label && target.label !== "" ? target.label : `workspace #${target.workspaceId}`;
|
|
410
|
+
step(`Deploying static frontend ${dir} \u2192 ${where}${host ? ` (host: ${host})` : ""}`);
|
|
411
|
+
const sh = await deployStaticHost({ host, dir, workspaceId: target.workspaceId, baseUrl: target.baseUrl, accessToken: auth.access_token, env, routing });
|
|
412
|
+
detail(
|
|
413
|
+
sh.routing === "multipage" ? "Routing: multipage \u2014 routes resolve to their own documents." : "Routing: spa \u2014 every path serves index.html."
|
|
414
|
+
);
|
|
415
|
+
const globals = Object.keys(env).map((k) => `window.${k}`);
|
|
416
|
+
if (globals.length > 0) {
|
|
417
|
+
const docs = sh.envDocuments === 1 ? "1 document" : `${sh.envDocuments} documents`;
|
|
418
|
+
if (sh.envInjected) success(`Config injected into ${docs}: ${globals.join(", ")}`);
|
|
419
|
+
else if (explicit) warn(`Config not injected \u2014 no HTML document with a <head> to anchor to. ${globals.join(", ")} unset.`);
|
|
420
|
+
else detail(`No HTML document to inject window.XANO_HOST into \u2014 skipped.`);
|
|
421
|
+
if (sh.envSkipped.length > 0) {
|
|
422
|
+
warn(`Config not injected into ${sh.envSkipped.join(", ")} \u2014 no <head> to anchor to; those routes run with ${globals.join(", ")} unset.`);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
success("Static host deployed");
|
|
426
|
+
if (sh.url) link(sh.url);
|
|
427
|
+
if (noVerify || sh.url === void 0 || sh.canonical === void 0) {
|
|
428
|
+
return { url: sh.url };
|
|
429
|
+
}
|
|
430
|
+
const { verifyRollout } = await import("./verify-rollout-FAVQ6EJY.js");
|
|
431
|
+
const { url, canonical } = sh;
|
|
432
|
+
const { live } = await withSpinner("Verifying the frontend is live\u2026", () => verifyRollout(url, canonical));
|
|
433
|
+
if (live) {
|
|
434
|
+
success("Frontend is live");
|
|
435
|
+
} else {
|
|
436
|
+
warn("Could not confirm the frontend is live within the wait window \u2014 the build uploaded and should come online shortly.");
|
|
437
|
+
detail(`Re-check by opening ${sh.url}, or skip this wait next time with --no-verify.`);
|
|
438
|
+
}
|
|
439
|
+
return { url: sh.url, verified: live };
|
|
440
|
+
}
|
|
441
|
+
export {
|
|
442
|
+
assertNoSeedLeaks,
|
|
443
|
+
buildStaticEnv,
|
|
444
|
+
deployStaticTo,
|
|
445
|
+
deriveDisplay,
|
|
446
|
+
ephemeralDisabledError,
|
|
447
|
+
runDeployCommand,
|
|
448
|
+
runDeployedTests,
|
|
449
|
+
verifyMicroservices
|
|
450
|
+
};
|
|
451
|
+
//# sourceMappingURL=deploy-command-4EQ7XX5G.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveMetaTarget
|
|
3
|
+
} from "./chunk-33ND6LKO.js";
|
|
4
|
+
import "./chunk-DGSF2Q5H.js";
|
|
5
|
+
import "./chunk-7DKX2SPN.js";
|
|
6
|
+
import "./chunk-NDZFBZHC.js";
|
|
7
|
+
import "./chunk-NUQCEOKA.js";
|
|
8
|
+
import "./chunk-3IGNIP6R.js";
|
|
9
|
+
import "./chunk-C56BC2FY.js";
|
|
10
|
+
import "./chunk-7REDODS2.js";
|
|
11
|
+
import "./chunk-EZG76F7R.js";
|
|
12
|
+
import "./chunk-GNPVYOPB.js";
|
|
13
|
+
export {
|
|
14
|
+
resolveMetaTarget
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=env-target-IFJ5QDHC.js.map
|