@roxyon/deploy-core 0.1.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 +34 -0
- package/dist/index.cjs +521 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +168 -0
- package/dist/index.d.ts +168 -0
- package/dist/index.js +468 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 BEA Technology Company
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# @roxyon/deploy-core
|
|
2
|
+
|
|
3
|
+
The shared deploy pipeline behind [`@roxyon/cli`](https://www.npmjs.com/package/@roxyon/cli)
|
|
4
|
+
and [`@roxyon/mcp`](https://www.npmjs.com/package/@roxyon/mcp): project-type
|
|
5
|
+
detection, deterministic archiving, and the build → upload → poll orchestration.
|
|
6
|
+
You normally use the CLI or the MCP server, not this directly.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm i @roxyon/deploy-core
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import { Roxyon } from '@roxyon/api-client';
|
|
14
|
+
import { deployProject } from '@roxyon/deploy-core';
|
|
15
|
+
|
|
16
|
+
const outcome = await deployProject({
|
|
17
|
+
cwd: process.cwd(),
|
|
18
|
+
roxyon: new Roxyon({ sessionToken: process.env.ROXYON_TOKEN }),
|
|
19
|
+
reporter: { step: console.log, log: console.log },
|
|
20
|
+
});
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Exports
|
|
24
|
+
|
|
25
|
+
- `deployProject()` — reads `roxyon.json`, builds if configured, packs (minus
|
|
26
|
+
`.roxyonignore` / `.gitignore`), uploads, and for app runtimes polls until the
|
|
27
|
+
deploy is live or failed. The console creates the application on the first
|
|
28
|
+
deploy.
|
|
29
|
+
- `detectRuntime()` / `buildProjectConfig()` — for `roxyon init`
|
|
30
|
+
- `packDirectory()` / `buildIgnore()` / `listFiles()` — the archiver
|
|
31
|
+
- `loadProjectConfig()` / `saveProjectConfig()` — `roxyon.json`
|
|
32
|
+
- `loadCredentials()` / `saveCredentials()` — `~/.roxyon/config.json`
|
|
33
|
+
|
|
34
|
+
MIT · part of [roxyon-devtools](https://github.com/bea-technology/roxyon-devtools)
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
ALWAYS_IGNORE: () => ALWAYS_IGNORE,
|
|
34
|
+
DeployError: () => DeployError,
|
|
35
|
+
PROJECT_FILE: () => PROJECT_FILE,
|
|
36
|
+
buildIgnore: () => buildIgnore,
|
|
37
|
+
buildProjectConfig: () => buildProjectConfig,
|
|
38
|
+
clearCredentials: () => clearCredentials,
|
|
39
|
+
credentialsDir: () => credentialsDir,
|
|
40
|
+
credentialsPath: () => credentialsPath,
|
|
41
|
+
deployProject: () => deployProject,
|
|
42
|
+
detectRuntime: () => detectRuntime,
|
|
43
|
+
endpointsFromEnv: () => endpointsFromEnv,
|
|
44
|
+
listFiles: () => listFiles,
|
|
45
|
+
loadCredentials: () => loadCredentials,
|
|
46
|
+
loadProjectConfig: () => loadProjectConfig,
|
|
47
|
+
measure: () => measure,
|
|
48
|
+
packDirectory: () => packDirectory,
|
|
49
|
+
projectConfigPath: () => projectConfigPath,
|
|
50
|
+
runShellCommand: () => runShellCommand,
|
|
51
|
+
saveCredentials: () => saveCredentials,
|
|
52
|
+
saveProjectConfig: () => saveProjectConfig,
|
|
53
|
+
tokenFromEnv: () => tokenFromEnv
|
|
54
|
+
});
|
|
55
|
+
module.exports = __toCommonJS(index_exports);
|
|
56
|
+
|
|
57
|
+
// src/archive.ts
|
|
58
|
+
var import_promises = require("fs/promises");
|
|
59
|
+
var import_node_path = require("path");
|
|
60
|
+
var import_ignore = __toESM(require("ignore"), 1);
|
|
61
|
+
var import_tar = require("tar");
|
|
62
|
+
var ALWAYS_IGNORE = [
|
|
63
|
+
"node_modules",
|
|
64
|
+
".git",
|
|
65
|
+
".next",
|
|
66
|
+
".nuxt",
|
|
67
|
+
".venv",
|
|
68
|
+
"__pycache__",
|
|
69
|
+
".DS_Store",
|
|
70
|
+
".roxyon",
|
|
71
|
+
"dist/.cache"
|
|
72
|
+
];
|
|
73
|
+
async function readIgnoreFile(root, name) {
|
|
74
|
+
try {
|
|
75
|
+
return (await (0, import_promises.readFile)((0, import_node_path.join)(root, name), "utf8")).split(/\r?\n/);
|
|
76
|
+
} catch {
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async function buildIgnore(root) {
|
|
81
|
+
const ig = (0, import_ignore.default)().add(ALWAYS_IGNORE);
|
|
82
|
+
const roxyon = await readIgnoreFile(root, ".roxyonignore");
|
|
83
|
+
if (roxyon.length) ig.add(roxyon);
|
|
84
|
+
else ig.add(await readIgnoreFile(root, ".gitignore"));
|
|
85
|
+
return ig;
|
|
86
|
+
}
|
|
87
|
+
async function listFiles(root, ig) {
|
|
88
|
+
const files = [];
|
|
89
|
+
async function walk(dir) {
|
|
90
|
+
const entries = await (0, import_promises.readdir)(dir, { withFileTypes: true });
|
|
91
|
+
for (const entry of entries) {
|
|
92
|
+
const abs = (0, import_node_path.join)(dir, entry.name);
|
|
93
|
+
const rel = (0, import_node_path.relative)(root, abs).split(import_node_path.sep).join("/");
|
|
94
|
+
if (!rel || ig.ignores(rel) || ig.ignores(`${rel}/`)) continue;
|
|
95
|
+
if (entry.isDirectory()) {
|
|
96
|
+
await walk(abs);
|
|
97
|
+
} else if (entry.isFile() || entry.isSymbolicLink()) {
|
|
98
|
+
files.push(rel);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
await walk(root);
|
|
103
|
+
return files.sort();
|
|
104
|
+
}
|
|
105
|
+
async function packDirectory(root, opts = {}) {
|
|
106
|
+
const ig = await buildIgnore(root);
|
|
107
|
+
const files = await listFiles(root, ig);
|
|
108
|
+
if (files.length === 0) {
|
|
109
|
+
throw new Error(
|
|
110
|
+
`Nothing to deploy from ${root} \u2014 every file is ignored or the folder is empty.`
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
const stream = (0, import_tar.create)(
|
|
114
|
+
{
|
|
115
|
+
gzip: true,
|
|
116
|
+
cwd: root,
|
|
117
|
+
portable: true,
|
|
118
|
+
mtime: /* @__PURE__ */ new Date(0),
|
|
119
|
+
// stable -> byte-identical archive for an unchanged tree
|
|
120
|
+
prefix: opts.prefix,
|
|
121
|
+
follow: false
|
|
122
|
+
},
|
|
123
|
+
files
|
|
124
|
+
);
|
|
125
|
+
const chunks = [];
|
|
126
|
+
let bytes = 0;
|
|
127
|
+
const max = opts.maxBytes ?? 512 * 1024 * 1024;
|
|
128
|
+
for await (const chunk of stream) {
|
|
129
|
+
bytes += chunk.length;
|
|
130
|
+
if (bytes > max) {
|
|
131
|
+
throw new Error(
|
|
132
|
+
`Deploy archive exceeds ${max / 1024 / 1024 | 0} MB. Add large files to .roxyonignore.`
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
chunks.push(chunk);
|
|
136
|
+
}
|
|
137
|
+
return { buffer: Buffer.concat(chunks), files, bytes };
|
|
138
|
+
}
|
|
139
|
+
async function measure(root, files) {
|
|
140
|
+
let total = 0;
|
|
141
|
+
for (const f of files) {
|
|
142
|
+
try {
|
|
143
|
+
total += (await (0, import_promises.stat)((0, import_node_path.join)(root, f))).size;
|
|
144
|
+
} catch {
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return total;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// src/detect.ts
|
|
151
|
+
var import_promises2 = require("fs/promises");
|
|
152
|
+
var import_node_path2 = require("path");
|
|
153
|
+
async function exists(root, name) {
|
|
154
|
+
try {
|
|
155
|
+
await (0, import_promises2.readFile)((0, import_node_path2.join)(root, name));
|
|
156
|
+
return true;
|
|
157
|
+
} catch {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
async function readJson(root, name) {
|
|
162
|
+
try {
|
|
163
|
+
return JSON.parse(await (0, import_promises2.readFile)((0, import_node_path2.join)(root, name), "utf8"));
|
|
164
|
+
} catch {
|
|
165
|
+
return void 0;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
async function detectRuntime(root) {
|
|
169
|
+
const pkg = await readJson(root, "package.json");
|
|
170
|
+
const hasConfigJson = await exists(root, "config.json");
|
|
171
|
+
let hasViews = false;
|
|
172
|
+
try {
|
|
173
|
+
hasViews = (await (0, import_promises2.readdir)((0, import_node_path2.join)(root, "src", "views"))).length >= 0;
|
|
174
|
+
} catch {
|
|
175
|
+
hasViews = false;
|
|
176
|
+
}
|
|
177
|
+
if (hasConfigJson && hasViews) {
|
|
178
|
+
const deps = {
|
|
179
|
+
...pkg?.dependencies,
|
|
180
|
+
...pkg?.devDependencies
|
|
181
|
+
};
|
|
182
|
+
if (!("next" in deps) && !("nuxt" in deps) && !("express" in deps) && !("fastify" in deps)) {
|
|
183
|
+
return { runtime: "lumen", reason: "config.json + src/views/ and no server framework" };
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (pkg) {
|
|
187
|
+
const scripts = pkg.scripts ?? {};
|
|
188
|
+
const start = scripts.start ? "npm run start" : scripts.serve ? "npm run serve" : "node .";
|
|
189
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
190
|
+
if ("next" in deps)
|
|
191
|
+
return { runtime: "node", reason: "Next.js in package.json", start: "npm run start" };
|
|
192
|
+
if ("nuxt" in deps)
|
|
193
|
+
return { runtime: "node", reason: "Nuxt in package.json", start: "npm run start" };
|
|
194
|
+
return { runtime: "node", reason: "package.json present", start };
|
|
195
|
+
}
|
|
196
|
+
if (await exists(root, "requirements.txt") || await exists(root, "pyproject.toml")) {
|
|
197
|
+
return {
|
|
198
|
+
runtime: "python",
|
|
199
|
+
reason: "requirements.txt / pyproject.toml",
|
|
200
|
+
start: "gunicorn app:app"
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
if (await exists(root, "composer.json") || await exists(root, "server.php")) {
|
|
204
|
+
return { runtime: "php", reason: "composer.json / server.php", start: "php8.4 server.php" };
|
|
205
|
+
}
|
|
206
|
+
return { runtime: "lumen", reason: "no framework markers \u2014 treating as a static site" };
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// src/project.ts
|
|
210
|
+
var import_promises3 = require("fs/promises");
|
|
211
|
+
var import_node_path3 = require("path");
|
|
212
|
+
var import_api_client = require("@roxyon/api-client");
|
|
213
|
+
var PROJECT_FILE = "roxyon.json";
|
|
214
|
+
function projectConfigPath(cwd = process.cwd()) {
|
|
215
|
+
return (0, import_node_path3.resolve)(cwd, PROJECT_FILE);
|
|
216
|
+
}
|
|
217
|
+
async function loadProjectConfig(cwd = process.cwd()) {
|
|
218
|
+
try {
|
|
219
|
+
return JSON.parse(await (0, import_promises3.readFile)(projectConfigPath(cwd), "utf8"));
|
|
220
|
+
} catch {
|
|
221
|
+
return void 0;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
async function saveProjectConfig(config, cwd = process.cwd()) {
|
|
225
|
+
const path = projectConfigPath(cwd);
|
|
226
|
+
await (0, import_promises3.mkdir)((0, import_node_path3.dirname)(path), { recursive: true });
|
|
227
|
+
await (0, import_promises3.writeFile)(path, `${JSON.stringify(config, null, 2)}
|
|
228
|
+
`);
|
|
229
|
+
return path;
|
|
230
|
+
}
|
|
231
|
+
function buildProjectConfig(input) {
|
|
232
|
+
const folder = String(input.folder ?? "").replace(/^\/+|\/+$/g, "");
|
|
233
|
+
const config = {
|
|
234
|
+
name: input.name ?? (0, import_node_path3.basename)(input.cwd),
|
|
235
|
+
host: input.host,
|
|
236
|
+
folder,
|
|
237
|
+
runtime: input.runtime,
|
|
238
|
+
kind: input.runtime === "lumen" ? "static" : "app"
|
|
239
|
+
};
|
|
240
|
+
if (input.runtime === "lumen") {
|
|
241
|
+
config.build = import_api_client.LUMEN_BUILD.command;
|
|
242
|
+
config.outDir = import_api_client.LUMEN_BUILD.outDir;
|
|
243
|
+
} else {
|
|
244
|
+
const spec = import_api_client.RUNTIMES[input.runtime];
|
|
245
|
+
config.runtimeVersion = spec.defaultVersion;
|
|
246
|
+
config.preset = spec.presets[0]?.[0];
|
|
247
|
+
config.start = input.start ?? spec.command;
|
|
248
|
+
config.public = true;
|
|
249
|
+
config.build = "";
|
|
250
|
+
}
|
|
251
|
+
return config;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// src/deploy.ts
|
|
255
|
+
var import_promises4 = require("fs/promises");
|
|
256
|
+
var import_node_path4 = require("path");
|
|
257
|
+
var import_api_client2 = require("@roxyon/api-client");
|
|
258
|
+
|
|
259
|
+
// src/run-command.ts
|
|
260
|
+
var import_node_child_process = require("child_process");
|
|
261
|
+
function runShellCommand(command, cwd, reporter) {
|
|
262
|
+
return new Promise((resolvePromise) => {
|
|
263
|
+
const child = (0, import_node_child_process.spawn)(command, { cwd, shell: true, stdio: ["ignore", "pipe", "pipe"] });
|
|
264
|
+
const pipe = (buf) => {
|
|
265
|
+
for (const line of buf.toString("utf8").split("\n")) {
|
|
266
|
+
if (line.trim()) reporter?.log?.(line);
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
child.stdout?.on("data", pipe);
|
|
270
|
+
child.stderr?.on("data", pipe);
|
|
271
|
+
child.on("close", (code) => resolvePromise(code ?? 0));
|
|
272
|
+
child.on("error", () => resolvePromise(127));
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// src/deploy.ts
|
|
277
|
+
var DeployError = class extends Error {
|
|
278
|
+
code;
|
|
279
|
+
constructor(message, code) {
|
|
280
|
+
super(message);
|
|
281
|
+
this.name = "DeployError";
|
|
282
|
+
this.code = code;
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
286
|
+
async function deployProject(params) {
|
|
287
|
+
const { cwd, roxyon, reporter } = params;
|
|
288
|
+
const runCommand = params.runCommand ?? runShellCommand;
|
|
289
|
+
const config = await loadProjectConfig(cwd);
|
|
290
|
+
if (!config) {
|
|
291
|
+
throw new DeployError("No roxyon.json in this directory \u2014 run init first.", "no-config");
|
|
292
|
+
}
|
|
293
|
+
const ctx = await roxyon.account.context().catch((e) => {
|
|
294
|
+
if ((0, import_api_client2.isAuthError)(e)) throw new DeployError("Session expired \u2014 sign in again.", "auth");
|
|
295
|
+
throw e;
|
|
296
|
+
});
|
|
297
|
+
const domain = ctx.domains.find((d) => d.name === config.host);
|
|
298
|
+
if (!domain) {
|
|
299
|
+
throw new DeployError(
|
|
300
|
+
`Host "${config.host}" is not on this account (have: ${ctx.domains.map((d) => d.name).join(", ") || "none"}).`,
|
|
301
|
+
"bad-host"
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
if (config.build && params.build !== false) {
|
|
305
|
+
reporter?.step?.(`Build: ${config.build}`);
|
|
306
|
+
const code = await runCommand(config.build, cwd, reporter);
|
|
307
|
+
if (code !== 0) throw new DeployError(`Build command exited ${code}.`, "build-failed");
|
|
308
|
+
}
|
|
309
|
+
const artifactDir = config.kind === "static" && config.outDir ? (0, import_node_path4.resolve)(cwd, config.outDir) : cwd;
|
|
310
|
+
if (config.kind === "static" && config.outDir) {
|
|
311
|
+
await (0, import_promises4.access)(artifactDir).catch(() => {
|
|
312
|
+
throw new DeployError(
|
|
313
|
+
`Build output "${config.outDir}" not found \u2014 did the build run?`,
|
|
314
|
+
"no-build-output"
|
|
315
|
+
);
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
reporter?.step?.(`Packing ${artifactDir === cwd ? "." : config.outDir}`);
|
|
319
|
+
const pack = await packDirectory(artifactDir);
|
|
320
|
+
reporter?.log?.(`${pack.files.length} files \xB7 ${(pack.bytes / 1024).toFixed(0)} KB`);
|
|
321
|
+
if (config.kind === "static") {
|
|
322
|
+
reporter?.step?.(`Uploading to ${config.host}${config.folder ? `/${config.folder}` : ""}`);
|
|
323
|
+
let res;
|
|
324
|
+
try {
|
|
325
|
+
res = await roxyon.sites.deploy(config.host, config.folder, pack.buffer);
|
|
326
|
+
} catch (err) {
|
|
327
|
+
throw new DeployError(
|
|
328
|
+
err instanceof import_api_client2.RoxyonApiError ? err.message : String(err),
|
|
329
|
+
"upload-failed"
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
const url2 = `https://${res.host}${res.path && res.path !== "/" ? res.path : ""}`;
|
|
333
|
+
reporter?.step?.(`Live \u2014 ${url2}`);
|
|
334
|
+
return { kind: "static", ok: true, url: url2, files: res.files ?? pack.files.length, config };
|
|
335
|
+
}
|
|
336
|
+
const runtime = config.runtime === "lumen" ? "node" : config.runtime;
|
|
337
|
+
const spec = import_api_client2.RUNTIMES[runtime];
|
|
338
|
+
const target = config.application ?? {
|
|
339
|
+
host: config.host,
|
|
340
|
+
folder: config.folder,
|
|
341
|
+
runtime,
|
|
342
|
+
runtimeVersion: config.runtimeVersion ?? spec.defaultVersion,
|
|
343
|
+
preset: config.preset ?? spec.presets[0]?.[0] ?? runtime,
|
|
344
|
+
command: config.start ?? spec.command,
|
|
345
|
+
public: config.public ?? true
|
|
346
|
+
};
|
|
347
|
+
reporter?.step?.(
|
|
348
|
+
config.application ? "Uploading source" : "Creating the application & uploading"
|
|
349
|
+
);
|
|
350
|
+
let revision = 0;
|
|
351
|
+
let appId;
|
|
352
|
+
try {
|
|
353
|
+
const res = await roxyon.applications.uploadSource(target, pack.buffer);
|
|
354
|
+
revision = res.configRevision ?? 0;
|
|
355
|
+
appId = res.application;
|
|
356
|
+
if (res.created && appId && appId !== config.application) {
|
|
357
|
+
config.application = appId;
|
|
358
|
+
await saveProjectConfig(config, cwd);
|
|
359
|
+
reporter?.log?.(`application ${appId} created`);
|
|
360
|
+
}
|
|
361
|
+
} catch (err) {
|
|
362
|
+
throw new DeployError(
|
|
363
|
+
err instanceof import_api_client2.RoxyonApiError ? err.message : String(err),
|
|
364
|
+
config.application ? "upload-failed" : "create-failed"
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
const url = config.public ? `https://${config.host}${config.folder ? `/${config.folder}` : ""}` : void 0;
|
|
368
|
+
if (params.follow === false) {
|
|
369
|
+
reporter?.step?.(`Build queued (revision ${revision})`);
|
|
370
|
+
return {
|
|
371
|
+
kind: "app",
|
|
372
|
+
ok: true,
|
|
373
|
+
application: appId,
|
|
374
|
+
status: "building",
|
|
375
|
+
revision,
|
|
376
|
+
url,
|
|
377
|
+
config,
|
|
378
|
+
logs: []
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
return watch(roxyon, appId, {
|
|
382
|
+
reporter,
|
|
383
|
+
url,
|
|
384
|
+
config,
|
|
385
|
+
pollMs: params.pollMs ?? 3e3,
|
|
386
|
+
timeoutMs: params.timeoutMs ?? 10 * 60 * 1e3
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
async function watch(roxyon, appId, opts) {
|
|
390
|
+
const started = Date.now();
|
|
391
|
+
const seen = /* @__PURE__ */ new Set();
|
|
392
|
+
const collected = [];
|
|
393
|
+
let lastStatus = "";
|
|
394
|
+
opts.reporter?.step?.("Building");
|
|
395
|
+
while (true) {
|
|
396
|
+
await sleep(opts.pollMs);
|
|
397
|
+
let app;
|
|
398
|
+
try {
|
|
399
|
+
app = await roxyon.account.getApp(appId);
|
|
400
|
+
} catch {
|
|
401
|
+
}
|
|
402
|
+
if (!app) {
|
|
403
|
+
if (Date.now() - started > opts.timeoutMs) break;
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
const cfg = app.configRevision;
|
|
407
|
+
const applied = app.appliedRevision;
|
|
408
|
+
const status = app.status;
|
|
409
|
+
if (status !== lastStatus) {
|
|
410
|
+
opts.reporter?.step?.(`${status || "pending"} (${applied}/${cfg})`);
|
|
411
|
+
lastStatus = status;
|
|
412
|
+
}
|
|
413
|
+
try {
|
|
414
|
+
for (const line of await roxyon.applications.logs(appId, 40)) {
|
|
415
|
+
if (line && !seen.has(line)) {
|
|
416
|
+
seen.add(line);
|
|
417
|
+
collected.push(line);
|
|
418
|
+
opts.reporter?.log?.(line);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
} catch {
|
|
422
|
+
}
|
|
423
|
+
if (cfg <= applied && status === "running") {
|
|
424
|
+
opts.reporter?.step?.(`Live${opts.url ? ` \u2014 ${opts.url}` : ""}`);
|
|
425
|
+
return {
|
|
426
|
+
kind: "app",
|
|
427
|
+
ok: true,
|
|
428
|
+
application: appId,
|
|
429
|
+
status: "running",
|
|
430
|
+
revision: applied,
|
|
431
|
+
url: opts.url,
|
|
432
|
+
config: opts.config,
|
|
433
|
+
logs: collected
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
if (status === "failed") {
|
|
437
|
+
return {
|
|
438
|
+
kind: "app",
|
|
439
|
+
ok: false,
|
|
440
|
+
application: appId,
|
|
441
|
+
status: "failed",
|
|
442
|
+
error: (app.lastError || "Deploy failed.").trim(),
|
|
443
|
+
config: opts.config,
|
|
444
|
+
logs: collected
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
if (Date.now() - started > opts.timeoutMs) break;
|
|
448
|
+
}
|
|
449
|
+
return {
|
|
450
|
+
kind: "app",
|
|
451
|
+
ok: false,
|
|
452
|
+
application: appId,
|
|
453
|
+
status: "timeout",
|
|
454
|
+
error: "Still building after the timeout \u2014 check `roxyon logs`.",
|
|
455
|
+
config: opts.config,
|
|
456
|
+
logs: collected
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// src/credentials.ts
|
|
461
|
+
var import_promises5 = require("fs/promises");
|
|
462
|
+
var import_node_os = require("os");
|
|
463
|
+
var import_node_path5 = require("path");
|
|
464
|
+
function credentialsDir() {
|
|
465
|
+
return (0, import_node_path5.join)((0, import_node_os.homedir)(), ".roxyon");
|
|
466
|
+
}
|
|
467
|
+
function credentialsPath() {
|
|
468
|
+
return (0, import_node_path5.join)(credentialsDir(), "config.json");
|
|
469
|
+
}
|
|
470
|
+
function endpointsFromEnv() {
|
|
471
|
+
return {
|
|
472
|
+
apiUrl: process.env.ROXYON_API_URL,
|
|
473
|
+
consoleUrl: process.env.ROXYON_CONSOLE_URL
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
function tokenFromEnv() {
|
|
477
|
+
return process.env.ROXYON_TOKEN || void 0;
|
|
478
|
+
}
|
|
479
|
+
async function loadCredentials() {
|
|
480
|
+
try {
|
|
481
|
+
return JSON.parse(await (0, import_promises5.readFile)(credentialsPath(), "utf8"));
|
|
482
|
+
} catch {
|
|
483
|
+
return void 0;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
async function saveCredentials(creds) {
|
|
487
|
+
const path = credentialsPath();
|
|
488
|
+
await (0, import_promises5.mkdir)(credentialsDir(), { recursive: true, mode: 448 });
|
|
489
|
+
await (0, import_promises5.writeFile)(path, `${JSON.stringify(creds, null, 2)}
|
|
490
|
+
`, { mode: 384 });
|
|
491
|
+
await (0, import_promises5.chmod)(path, 384).catch(() => void 0);
|
|
492
|
+
return path;
|
|
493
|
+
}
|
|
494
|
+
async function clearCredentials() {
|
|
495
|
+
await (0, import_promises5.rm)(credentialsPath(), { force: true });
|
|
496
|
+
}
|
|
497
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
498
|
+
0 && (module.exports = {
|
|
499
|
+
ALWAYS_IGNORE,
|
|
500
|
+
DeployError,
|
|
501
|
+
PROJECT_FILE,
|
|
502
|
+
buildIgnore,
|
|
503
|
+
buildProjectConfig,
|
|
504
|
+
clearCredentials,
|
|
505
|
+
credentialsDir,
|
|
506
|
+
credentialsPath,
|
|
507
|
+
deployProject,
|
|
508
|
+
detectRuntime,
|
|
509
|
+
endpointsFromEnv,
|
|
510
|
+
listFiles,
|
|
511
|
+
loadCredentials,
|
|
512
|
+
loadProjectConfig,
|
|
513
|
+
measure,
|
|
514
|
+
packDirectory,
|
|
515
|
+
projectConfigPath,
|
|
516
|
+
runShellCommand,
|
|
517
|
+
saveCredentials,
|
|
518
|
+
saveProjectConfig,
|
|
519
|
+
tokenFromEnv
|
|
520
|
+
});
|
|
521
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/archive.ts","../src/detect.ts","../src/project.ts","../src/deploy.ts","../src/run-command.ts","../src/credentials.ts"],"sourcesContent":["export {\n ALWAYS_IGNORE,\n buildIgnore,\n listFiles,\n measure,\n packDirectory,\n type PackResult,\n} from './archive.js';\nexport { type Detection, detectRuntime } from './detect.js';\nexport {\n buildProjectConfig,\n type BuildConfigInput,\n type DeployKind,\n loadProjectConfig,\n PROJECT_FILE,\n type ProjectConfig,\n projectConfigPath,\n saveProjectConfig,\n} from './project.js';\nexport {\n deployProject,\n DeployError,\n type DeployOutcome,\n type DeployParams,\n type DeployReporter,\n} from './deploy.js';\nexport { runShellCommand } from './run-command.js';\nexport {\n type Credentials,\n credentialsDir,\n credentialsPath,\n clearCredentials,\n type Endpoints,\n endpointsFromEnv,\n loadCredentials,\n saveCredentials,\n tokenFromEnv,\n} from './credentials.js';\n","import { readFile, readdir, stat } from 'node:fs/promises';\nimport { join, relative, sep } from 'node:path';\nimport ignore, { type Ignore } from 'ignore';\nimport { create as tarCreate } from 'tar';\n\n/** Always excluded, regardless of ignore files — build artefacts and VCS/OS cruft. */\nexport const ALWAYS_IGNORE = [\n 'node_modules',\n '.git',\n '.next',\n '.nuxt',\n '.venv',\n '__pycache__',\n '.DS_Store',\n '.roxyon',\n 'dist/.cache',\n];\n\nasync function readIgnoreFile(root: string, name: string): Promise<string[]> {\n try {\n return (await readFile(join(root, name), 'utf8')).split(/\\r?\\n/);\n } catch {\n return [];\n }\n}\n\n/** Build the ignore matcher: `.roxyonignore` if present, else `.gitignore`, plus the always-list. */\nexport async function buildIgnore(root: string): Promise<Ignore> {\n const ig = ignore().add(ALWAYS_IGNORE);\n const roxyon = await readIgnoreFile(root, '.roxyonignore');\n if (roxyon.length) ig.add(roxyon);\n else ig.add(await readIgnoreFile(root, '.gitignore'));\n return ig;\n}\n\n/** Recursively list files under `root` that survive the ignore matcher (POSIX-relative paths). */\nexport async function listFiles(root: string, ig: Ignore): Promise<string[]> {\n const files: string[] = [];\n\n async function walk(dir: string): Promise<void> {\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n const abs = join(dir, entry.name);\n const rel = relative(root, abs).split(sep).join('/');\n if (!rel || ig.ignores(rel) || ig.ignores(`${rel}/`)) continue;\n if (entry.isDirectory()) {\n await walk(abs);\n } else if (entry.isFile() || entry.isSymbolicLink()) {\n files.push(rel);\n }\n }\n }\n\n await walk(root);\n return files.sort();\n}\n\nexport interface PackResult {\n buffer: Buffer;\n files: string[];\n bytes: number;\n}\n\n/**\n * Create a deterministic gzipped tarball of `root` (minus ignored paths).\n * `prefix`, when given, is prepended to every entry path inside the archive.\n */\nexport async function packDirectory(\n root: string,\n opts: { prefix?: string; maxBytes?: number } = {},\n): Promise<PackResult> {\n const ig = await buildIgnore(root);\n const files = await listFiles(root, ig);\n if (files.length === 0) {\n throw new Error(\n `Nothing to deploy from ${root} — every file is ignored or the folder is empty.`,\n );\n }\n\n const stream = tarCreate(\n {\n gzip: true,\n cwd: root,\n portable: true,\n mtime: new Date(0), // stable -> byte-identical archive for an unchanged tree\n prefix: opts.prefix,\n follow: false,\n },\n files,\n );\n\n const chunks: Buffer[] = [];\n let bytes = 0;\n const max = opts.maxBytes ?? 512 * 1024 * 1024;\n for await (const chunk of stream as AsyncIterable<Buffer>) {\n bytes += chunk.length;\n if (bytes > max) {\n throw new Error(\n `Deploy archive exceeds ${(max / 1024 / 1024) | 0} MB. Add large files to .roxyonignore.`,\n );\n }\n chunks.push(chunk);\n }\n\n return { buffer: Buffer.concat(chunks), files, bytes };\n}\n\n/** Total on-disk size of a set of files. */\nexport async function measure(root: string, files: string[]): Promise<number> {\n let total = 0;\n for (const f of files) {\n try {\n total += (await stat(join(root, f))).size;\n } catch {\n /* ignore */\n }\n }\n return total;\n}\n","import { readFile, readdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { RuntimeName } from '@roxyon/api-client';\n\nexport interface Detection {\n runtime: RuntimeName;\n /** why we think so — shown to the user, who can override */\n reason: string;\n /** best-guess start command for a server runtime */\n start?: string;\n}\n\nasync function exists(root: string, name: string): Promise<boolean> {\n try {\n await readFile(join(root, name));\n return true;\n } catch {\n return false;\n }\n}\n\nasync function readJson(root: string, name: string): Promise<Record<string, unknown> | undefined> {\n try {\n return JSON.parse(await readFile(join(root, name), 'utf8')) as Record<string, unknown>;\n } catch {\n return undefined;\n }\n}\n\n/** Best-effort project-type detection. Deterministic; the caller confirms. */\nexport async function detectRuntime(root: string): Promise<Detection> {\n const pkg = await readJson(root, 'package.json');\n const hasConfigJson = await exists(root, 'config.json');\n let hasViews = false;\n try {\n hasViews = (await readdir(join(root, 'src', 'views'))).length >= 0;\n } catch {\n hasViews = false;\n }\n\n if (hasConfigJson && hasViews) {\n const deps = {\n ...(pkg?.dependencies as object),\n ...(pkg?.devDependencies as object),\n } as Record<string, string>;\n if (!('next' in deps) && !('nuxt' in deps) && !('express' in deps) && !('fastify' in deps)) {\n return { runtime: 'lumen', reason: 'config.json + src/views/ and no server framework' };\n }\n }\n\n if (pkg) {\n const scripts = (pkg.scripts as Record<string, string>) ?? {};\n const start = scripts.start ? 'npm run start' : scripts.serve ? 'npm run serve' : 'node .';\n const deps = { ...(pkg.dependencies as object), ...(pkg.devDependencies as object) } as Record<\n string,\n string\n >;\n if ('next' in deps)\n return { runtime: 'node', reason: 'Next.js in package.json', start: 'npm run start' };\n if ('nuxt' in deps)\n return { runtime: 'node', reason: 'Nuxt in package.json', start: 'npm run start' };\n return { runtime: 'node', reason: 'package.json present', start };\n }\n\n if ((await exists(root, 'requirements.txt')) || (await exists(root, 'pyproject.toml'))) {\n return {\n runtime: 'python',\n reason: 'requirements.txt / pyproject.toml',\n start: 'gunicorn app:app',\n };\n }\n\n if ((await exists(root, 'composer.json')) || (await exists(root, 'server.php'))) {\n return { runtime: 'php', reason: 'composer.json / server.php', start: 'php8.4 server.php' };\n }\n\n return { runtime: 'lumen', reason: 'no framework markers — treating as a static site' };\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { basename, dirname, resolve } from 'node:path';\nimport { type DeployKind, LUMEN_BUILD, RUNTIMES, type RuntimeName } from '@roxyon/api-client';\n\nexport type { DeployKind };\n\nexport interface ProjectConfig {\n name: string;\n /** `Applications.objectId`, filled after the first `app`-kind deploy. */\n application?: string;\n /** Route host — `Domains.Name`. */\n host: string;\n /** Sub-path under the host's docroot / source tree. `\"\"` = root. */\n folder: string;\n runtime: RuntimeName;\n runtimeVersion?: string;\n preset?: string;\n kind: DeployKind;\n /** Local build command (LumenJS / static). Empty for server runtimes. */\n build?: string;\n /** Directory the build writes to (relative to project root). */\n outDir?: string;\n /** Web-process start command (app kind only). */\n start?: string;\n /** Serve the app on the host instead of the host's own files. */\n public?: boolean;\n}\n\nexport const PROJECT_FILE = 'roxyon.json';\n\nexport function projectConfigPath(cwd: string = process.cwd()): string {\n return resolve(cwd, PROJECT_FILE);\n}\n\nexport async function loadProjectConfig(\n cwd: string = process.cwd(),\n): Promise<ProjectConfig | undefined> {\n try {\n return JSON.parse(await readFile(projectConfigPath(cwd), 'utf8')) as ProjectConfig;\n } catch {\n return undefined;\n }\n}\n\nexport async function saveProjectConfig(\n config: ProjectConfig,\n cwd: string = process.cwd(),\n): Promise<string> {\n const path = projectConfigPath(cwd);\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, `${JSON.stringify(config, null, 2)}\\n`);\n return path;\n}\n\nexport interface BuildConfigInput {\n cwd: string;\n runtime: RuntimeName;\n host: string;\n folder?: string;\n name?: string;\n start?: string;\n}\n\n/**\n * Produce a `ProjectConfig` from a resolved runtime + host. Shared by the CLI's\n * `roxyon init` and the MCP `roxyon_init` tool so both write the same shape.\n */\nexport function buildProjectConfig(input: BuildConfigInput): ProjectConfig {\n const folder = String(input.folder ?? '').replace(/^\\/+|\\/+$/g, '');\n const config: ProjectConfig = {\n name: input.name ?? basename(input.cwd),\n host: input.host,\n folder,\n runtime: input.runtime,\n kind: input.runtime === 'lumen' ? 'static' : 'app',\n };\n\n if (input.runtime === 'lumen') {\n config.build = LUMEN_BUILD.command;\n config.outDir = LUMEN_BUILD.outDir;\n } else {\n const spec = RUNTIMES[input.runtime];\n config.runtimeVersion = spec.defaultVersion;\n config.preset = spec.presets[0]?.[0];\n config.start = input.start ?? spec.command;\n config.public = true;\n config.build = '';\n }\n return config;\n}\n","import { access } from 'node:fs/promises';\nimport { resolve } from 'node:path';\nimport {\n type AccountApp,\n RUNTIMES,\n type Roxyon,\n RoxyonApiError,\n isAuthError,\n} from '@roxyon/api-client';\nimport { packDirectory } from './archive.js';\nimport { type ProjectConfig, loadProjectConfig, saveProjectConfig } from './project.js';\nimport { runShellCommand } from './run-command.js';\n\nexport interface DeployReporter {\n /** A high-level phase change (\"Building\", \"Uploading\", \"Live\"). */\n step?: (msg: string) => void;\n /** A single build- or runtime-log line. */\n log?: (line: string) => void;\n}\n\nexport interface DeployParams {\n cwd: string;\n /** An authenticated client. */\n roxyon: Roxyon;\n /** Subscription objectId / Name to prefer when the account has several. */\n preferredSubscription?: string;\n /** Run the configured build command (default true). */\n build?: boolean;\n /** For app deploys: poll until running/failed (default true). */\n follow?: boolean;\n pollMs?: number;\n timeoutMs?: number;\n reporter?: DeployReporter;\n /** Override the build-command runner (default: spawn a shell). */\n runCommand?: (command: string, cwd: string, reporter?: DeployReporter) => Promise<number>;\n}\n\nexport type DeployOutcome =\n | { kind: 'static'; ok: true; url: string; files: number; config: ProjectConfig }\n | {\n kind: 'app';\n ok: true;\n application: string;\n status: string;\n revision: number;\n url?: string;\n config: ProjectConfig;\n logs: string[];\n }\n | {\n kind: 'app';\n ok: false;\n application: string;\n status: string;\n error: string;\n config: ProjectConfig;\n logs: string[];\n };\n\nexport class DeployError extends Error {\n readonly code:\n | 'no-config'\n | 'auth'\n | 'bad-host'\n | 'build-failed'\n | 'no-build-output'\n | 'upload-failed'\n | 'create-failed';\n constructor(message: string, code: DeployError['code']) {\n super(message);\n this.name = 'DeployError';\n this.code = code;\n }\n}\n\nconst sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));\n\n/**\n * Build (if configured), archive, upload, and — for app runtimes — poll until\n * the deploy settles. Self-contained: one `/account/context` call validates the\n * host (works with a session token or a `roxp_` PAT), and the console creates\n * the application on the first deploy — the new id is written back to\n * `roxyon.json`.\n */\nexport async function deployProject(params: DeployParams): Promise<DeployOutcome> {\n const { cwd, roxyon, reporter } = params;\n const runCommand = params.runCommand ?? runShellCommand;\n\n const config = await loadProjectConfig(cwd);\n if (!config) {\n throw new DeployError('No roxyon.json in this directory — run init first.', 'no-config');\n }\n\n // One call — works with a session token or a PAT.\n const ctx = await roxyon.account.context().catch((e) => {\n if (isAuthError(e)) throw new DeployError('Session expired — sign in again.', 'auth');\n throw e;\n });\n const domain = ctx.domains.find((d) => d.name === config.host);\n if (!domain) {\n throw new DeployError(\n `Host \"${config.host}\" is not on this account (have: ${\n ctx.domains.map((d) => d.name).join(', ') || 'none'\n }).`,\n 'bad-host',\n );\n }\n\n // ---- build ----\n if (config.build && params.build !== false) {\n reporter?.step?.(`Build: ${config.build}`);\n const code = await runCommand(config.build, cwd, reporter);\n if (code !== 0) throw new DeployError(`Build command exited ${code}.`, 'build-failed');\n }\n\n // ---- pack ----\n const artifactDir = config.kind === 'static' && config.outDir ? resolve(cwd, config.outDir) : cwd;\n if (config.kind === 'static' && config.outDir) {\n await access(artifactDir).catch(() => {\n throw new DeployError(\n `Build output \"${config.outDir}\" not found — did the build run?`,\n 'no-build-output',\n );\n });\n }\n reporter?.step?.(`Packing ${artifactDir === cwd ? '.' : config.outDir}`);\n const pack = await packDirectory(artifactDir);\n reporter?.log?.(`${pack.files.length} files · ${(pack.bytes / 1024).toFixed(0)} KB`);\n\n // ---- static ----\n if (config.kind === 'static') {\n reporter?.step?.(`Uploading to ${config.host}${config.folder ? `/${config.folder}` : ''}`);\n let res: Awaited<ReturnType<typeof roxyon.sites.deploy>>;\n try {\n res = await roxyon.sites.deploy(config.host, config.folder, pack.buffer);\n } catch (err) {\n throw new DeployError(\n err instanceof RoxyonApiError ? err.message : String(err),\n 'upload-failed',\n );\n }\n const url = `https://${res.host}${res.path && res.path !== '/' ? res.path : ''}`;\n reporter?.step?.(`Live — ${url}`);\n return { kind: 'static', ok: true, url, files: res.files ?? pack.files.length, config };\n }\n\n // ---- app ----\n // The console's /applications/deploy creates the app rows on the first deploy\n // (no `application` id yet) from the host + runtime params — one trusted call,\n // so a PAT-only CI job needs no BaaS write access.\n const runtime = config.runtime === 'lumen' ? 'node' : config.runtime;\n const spec = RUNTIMES[runtime];\n const target = config.application ?? {\n host: config.host,\n folder: config.folder,\n runtime,\n runtimeVersion: config.runtimeVersion ?? spec.defaultVersion,\n preset: config.preset ?? spec.presets[0]?.[0] ?? runtime,\n command: config.start ?? spec.command,\n public: config.public ?? true,\n };\n\n reporter?.step?.(\n config.application ? 'Uploading source' : 'Creating the application & uploading',\n );\n let revision = 0;\n let appId: string;\n try {\n const res = await roxyon.applications.uploadSource(target, pack.buffer);\n revision = res.configRevision ?? 0;\n appId = res.application;\n if (res.created && appId && appId !== config.application) {\n config.application = appId;\n await saveProjectConfig(config, cwd);\n reporter?.log?.(`application ${appId} created`);\n }\n } catch (err) {\n throw new DeployError(\n err instanceof RoxyonApiError ? err.message : String(err),\n config.application ? 'upload-failed' : 'create-failed',\n );\n }\n\n const url = config.public\n ? `https://${config.host}${config.folder ? `/${config.folder}` : ''}`\n : undefined;\n\n if (params.follow === false) {\n reporter?.step?.(`Build queued (revision ${revision})`);\n return {\n kind: 'app',\n ok: true,\n application: appId,\n status: 'building',\n revision,\n url,\n config,\n logs: [],\n };\n }\n\n return watch(roxyon, appId, {\n reporter,\n url,\n config,\n pollMs: params.pollMs ?? 3000,\n timeoutMs: params.timeoutMs ?? 10 * 60 * 1000,\n });\n}\n\nasync function watch(\n roxyon: Roxyon,\n appId: string,\n opts: {\n reporter?: DeployReporter;\n url?: string;\n config: ProjectConfig;\n pollMs: number;\n timeoutMs: number;\n },\n): Promise<DeployOutcome> {\n const started = Date.now();\n const seen = new Set<string>();\n const collected: string[] = [];\n let lastStatus = '';\n\n opts.reporter?.step?.('Building');\n while (true) {\n await sleep(opts.pollMs);\n\n let app: AccountApp | undefined;\n try {\n app = await roxyon.account.getApp(appId);\n } catch {\n /* transient */\n }\n if (!app) {\n if (Date.now() - started > opts.timeoutMs) break;\n continue;\n }\n\n const cfg = app.configRevision;\n const applied = app.appliedRevision;\n const status = app.status;\n if (status !== lastStatus) {\n opts.reporter?.step?.(`${status || 'pending'} (${applied}/${cfg})`);\n lastStatus = status;\n }\n\n try {\n for (const line of await roxyon.applications.logs(appId, 40)) {\n if (line && !seen.has(line)) {\n seen.add(line);\n collected.push(line);\n opts.reporter?.log?.(line);\n }\n }\n } catch {\n /* transient */\n }\n\n if (cfg <= applied && status === 'running') {\n opts.reporter?.step?.(`Live${opts.url ? ` — ${opts.url}` : ''}`);\n return {\n kind: 'app',\n ok: true,\n application: appId,\n status: 'running',\n revision: applied,\n url: opts.url,\n config: opts.config,\n logs: collected,\n };\n }\n if (status === 'failed') {\n return {\n kind: 'app',\n ok: false,\n application: appId,\n status: 'failed',\n error: (app.lastError || 'Deploy failed.').trim(),\n config: opts.config,\n logs: collected,\n };\n }\n if (Date.now() - started > opts.timeoutMs) break;\n }\n\n return {\n kind: 'app',\n ok: false,\n application: appId,\n status: 'timeout',\n error: 'Still building after the timeout — check `roxyon logs`.',\n config: opts.config,\n logs: collected,\n };\n}\n","import { spawn } from 'node:child_process';\nimport type { DeployReporter } from './deploy.js';\n\n/**\n * Default build-command runner: spawn a shell, stream output to the reporter.\n * Callers in a non-local context (a hosted server) can pass their own.\n */\nexport function runShellCommand(\n command: string,\n cwd: string,\n reporter?: DeployReporter,\n): Promise<number> {\n return new Promise((resolvePromise) => {\n const child = spawn(command, { cwd, shell: true, stdio: ['ignore', 'pipe', 'pipe'] });\n const pipe = (buf: Buffer) => {\n for (const line of buf.toString('utf8').split('\\n')) {\n if (line.trim()) reporter?.log?.(line);\n }\n };\n child.stdout?.on('data', pipe);\n child.stderr?.on('data', pipe);\n child.on('close', (code) => resolvePromise(code ?? 0));\n child.on('error', () => resolvePromise(127));\n });\n}\n","import { chmod, mkdir, readFile, rm, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n/**\n * Stored login for Roxyon tooling — `~/.roxyon/config.json`, mode 0600. Written\n * by `roxyon login`; read by the CLI and the MCP server alike.\n */\nexport interface Credentials {\n sessionToken: string;\n refreshToken?: string;\n userId: string;\n email?: string;\n /** Preferred subscription (objectId / Name) when the account has several. */\n subscription?: string;\n savedAt: string;\n}\n\nexport interface Endpoints {\n apiUrl?: string;\n consoleUrl?: string;\n}\n\nexport function credentialsDir(): string {\n return join(homedir(), '.roxyon');\n}\nexport function credentialsPath(): string {\n return join(credentialsDir(), 'config.json');\n}\n\n/** Endpoint overrides from the environment (`ROXYON_API_URL`, `ROXYON_CONSOLE_URL`). */\nexport function endpointsFromEnv(): Endpoints {\n return {\n apiUrl: process.env.ROXYON_API_URL,\n consoleUrl: process.env.ROXYON_CONSOLE_URL,\n };\n}\n\n/** A token supplied out-of-band (CI, or an MCP host env). Skips the stored login. */\nexport function tokenFromEnv(): string | undefined {\n return process.env.ROXYON_TOKEN || undefined;\n}\n\nexport async function loadCredentials(): Promise<Credentials | undefined> {\n try {\n return JSON.parse(await readFile(credentialsPath(), 'utf8')) as Credentials;\n } catch {\n return undefined;\n }\n}\n\nexport async function saveCredentials(creds: Credentials): Promise<string> {\n const path = credentialsPath();\n await mkdir(credentialsDir(), { recursive: true, mode: 0o700 });\n await writeFile(path, `${JSON.stringify(creds, null, 2)}\\n`, { mode: 0o600 });\n await chmod(path, 0o600).catch(() => undefined);\n return path;\n}\n\nexport async function clearCredentials(): Promise<void> {\n await rm(credentialsPath(), { force: true });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,sBAAwC;AACxC,uBAAoC;AACpC,oBAAoC;AACpC,iBAAoC;AAG7B,IAAM,gBAAgB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,eAAe,eAAe,MAAc,MAAiC;AAC3E,MAAI;AACF,YAAQ,UAAM,8BAAS,uBAAK,MAAM,IAAI,GAAG,MAAM,GAAG,MAAM,OAAO;AAAA,EACjE,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAGA,eAAsB,YAAY,MAA+B;AAC/D,QAAM,SAAK,cAAAA,SAAO,EAAE,IAAI,aAAa;AACrC,QAAM,SAAS,MAAM,eAAe,MAAM,eAAe;AACzD,MAAI,OAAO,OAAQ,IAAG,IAAI,MAAM;AAAA,MAC3B,IAAG,IAAI,MAAM,eAAe,MAAM,YAAY,CAAC;AACpD,SAAO;AACT;AAGA,eAAsB,UAAU,MAAc,IAA+B;AAC3E,QAAM,QAAkB,CAAC;AAEzB,iBAAe,KAAK,KAA4B;AAC9C,UAAM,UAAU,UAAM,yBAAQ,KAAK,EAAE,eAAe,KAAK,CAAC;AAC1D,eAAW,SAAS,SAAS;AAC3B,YAAM,UAAM,uBAAK,KAAK,MAAM,IAAI;AAChC,YAAM,UAAM,2BAAS,MAAM,GAAG,EAAE,MAAM,oBAAG,EAAE,KAAK,GAAG;AACnD,UAAI,CAAC,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,GAAG,GAAG,EAAG;AACtD,UAAI,MAAM,YAAY,GAAG;AACvB,cAAM,KAAK,GAAG;AAAA,MAChB,WAAW,MAAM,OAAO,KAAK,MAAM,eAAe,GAAG;AACnD,cAAM,KAAK,GAAG;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,KAAK,IAAI;AACf,SAAO,MAAM,KAAK;AACpB;AAYA,eAAsB,cACpB,MACA,OAA+C,CAAC,GAC3B;AACrB,QAAM,KAAK,MAAM,YAAY,IAAI;AACjC,QAAM,QAAQ,MAAM,UAAU,MAAM,EAAE;AACtC,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,IAAI;AAAA,MACR,0BAA0B,IAAI;AAAA,IAChC;AAAA,EACF;AAEA,QAAM,aAAS,WAAAC;AAAA,IACb;AAAA,MACE,MAAM;AAAA,MACN,KAAK;AAAA,MACL,UAAU;AAAA,MACV,OAAO,oBAAI,KAAK,CAAC;AAAA;AAAA,MACjB,QAAQ,KAAK;AAAA,MACb,QAAQ;AAAA,IACV;AAAA,IACA;AAAA,EACF;AAEA,QAAM,SAAmB,CAAC;AAC1B,MAAI,QAAQ;AACZ,QAAM,MAAM,KAAK,YAAY,MAAM,OAAO;AAC1C,mBAAiB,SAAS,QAAiC;AACzD,aAAS,MAAM;AACf,QAAI,QAAQ,KAAK;AACf,YAAM,IAAI;AAAA,QACR,0BAA2B,MAAM,OAAO,OAAQ,CAAC;AAAA,MACnD;AAAA,IACF;AACA,WAAO,KAAK,KAAK;AAAA,EACnB;AAEA,SAAO,EAAE,QAAQ,OAAO,OAAO,MAAM,GAAG,OAAO,MAAM;AACvD;AAGA,eAAsB,QAAQ,MAAc,OAAkC;AAC5E,MAAI,QAAQ;AACZ,aAAW,KAAK,OAAO;AACrB,QAAI;AACF,gBAAU,UAAM,0BAAK,uBAAK,MAAM,CAAC,CAAC,GAAG;AAAA,IACvC,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO;AACT;;;ACtHA,IAAAC,mBAAkC;AAClC,IAAAC,oBAAqB;AAWrB,eAAe,OAAO,MAAc,MAAgC;AAClE,MAAI;AACF,cAAM,+BAAS,wBAAK,MAAM,IAAI,CAAC;AAC/B,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,SAAS,MAAc,MAA4D;AAChG,MAAI;AACF,WAAO,KAAK,MAAM,UAAM,+BAAS,wBAAK,MAAM,IAAI,GAAG,MAAM,CAAC;AAAA,EAC5D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGA,eAAsB,cAAc,MAAkC;AACpE,QAAM,MAAM,MAAM,SAAS,MAAM,cAAc;AAC/C,QAAM,gBAAgB,MAAM,OAAO,MAAM,aAAa;AACtD,MAAI,WAAW;AACf,MAAI;AACF,gBAAY,UAAM,8BAAQ,wBAAK,MAAM,OAAO,OAAO,CAAC,GAAG,UAAU;AAAA,EACnE,QAAQ;AACN,eAAW;AAAA,EACb;AAEA,MAAI,iBAAiB,UAAU;AAC7B,UAAM,OAAO;AAAA,MACX,GAAI,KAAK;AAAA,MACT,GAAI,KAAK;AAAA,IACX;AACA,QAAI,EAAE,UAAU,SAAS,EAAE,UAAU,SAAS,EAAE,aAAa,SAAS,EAAE,aAAa,OAAO;AAC1F,aAAO,EAAE,SAAS,SAAS,QAAQ,mDAAmD;AAAA,IACxF;AAAA,EACF;AAEA,MAAI,KAAK;AACP,UAAM,UAAW,IAAI,WAAsC,CAAC;AAC5D,UAAM,QAAQ,QAAQ,QAAQ,kBAAkB,QAAQ,QAAQ,kBAAkB;AAClF,UAAM,OAAO,EAAE,GAAI,IAAI,cAAyB,GAAI,IAAI,gBAA2B;AAInF,QAAI,UAAU;AACZ,aAAO,EAAE,SAAS,QAAQ,QAAQ,2BAA2B,OAAO,gBAAgB;AACtF,QAAI,UAAU;AACZ,aAAO,EAAE,SAAS,QAAQ,QAAQ,wBAAwB,OAAO,gBAAgB;AACnF,WAAO,EAAE,SAAS,QAAQ,QAAQ,wBAAwB,MAAM;AAAA,EAClE;AAEA,MAAK,MAAM,OAAO,MAAM,kBAAkB,KAAO,MAAM,OAAO,MAAM,gBAAgB,GAAI;AACtF,WAAO;AAAA,MACL,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,OAAO;AAAA,IACT;AAAA,EACF;AAEA,MAAK,MAAM,OAAO,MAAM,eAAe,KAAO,MAAM,OAAO,MAAM,YAAY,GAAI;AAC/E,WAAO,EAAE,SAAS,OAAO,QAAQ,8BAA8B,OAAO,oBAAoB;AAAA,EAC5F;AAEA,SAAO,EAAE,SAAS,SAAS,QAAQ,wDAAmD;AACxF;;;AC7EA,IAAAC,mBAA2C;AAC3C,IAAAC,oBAA2C;AAC3C,wBAAyE;AA0BlE,IAAM,eAAe;AAErB,SAAS,kBAAkB,MAAc,QAAQ,IAAI,GAAW;AACrE,aAAO,2BAAQ,KAAK,YAAY;AAClC;AAEA,eAAsB,kBACpB,MAAc,QAAQ,IAAI,GACU;AACpC,MAAI;AACF,WAAO,KAAK,MAAM,UAAM,2BAAS,kBAAkB,GAAG,GAAG,MAAM,CAAC;AAAA,EAClE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,kBACpB,QACA,MAAc,QAAQ,IAAI,GACT;AACjB,QAAM,OAAO,kBAAkB,GAAG;AAClC,YAAM,4BAAM,2BAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9C,YAAM,4BAAU,MAAM,GAAG,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,CAAI;AAC5D,SAAO;AACT;AAeO,SAAS,mBAAmB,OAAwC;AACzE,QAAM,SAAS,OAAO,MAAM,UAAU,EAAE,EAAE,QAAQ,cAAc,EAAE;AAClE,QAAM,SAAwB;AAAA,IAC5B,MAAM,MAAM,YAAQ,4BAAS,MAAM,GAAG;AAAA,IACtC,MAAM,MAAM;AAAA,IACZ;AAAA,IACA,SAAS,MAAM;AAAA,IACf,MAAM,MAAM,YAAY,UAAU,WAAW;AAAA,EAC/C;AAEA,MAAI,MAAM,YAAY,SAAS;AAC7B,WAAO,QAAQ,8BAAY;AAC3B,WAAO,SAAS,8BAAY;AAAA,EAC9B,OAAO;AACL,UAAM,OAAO,2BAAS,MAAM,OAAO;AACnC,WAAO,iBAAiB,KAAK;AAC7B,WAAO,SAAS,KAAK,QAAQ,CAAC,IAAI,CAAC;AACnC,WAAO,QAAQ,MAAM,SAAS,KAAK;AACnC,WAAO,SAAS;AAChB,WAAO,QAAQ;AAAA,EACjB;AACA,SAAO;AACT;;;ACzFA,IAAAC,mBAAuB;AACvB,IAAAC,oBAAwB;AACxB,IAAAC,qBAMO;;;ACRP,gCAAsB;AAOf,SAAS,gBACd,SACA,KACA,UACiB;AACjB,SAAO,IAAI,QAAQ,CAAC,mBAAmB;AACrC,UAAM,YAAQ,iCAAM,SAAS,EAAE,KAAK,OAAO,MAAM,OAAO,CAAC,UAAU,QAAQ,MAAM,EAAE,CAAC;AACpF,UAAM,OAAO,CAAC,QAAgB;AAC5B,iBAAW,QAAQ,IAAI,SAAS,MAAM,EAAE,MAAM,IAAI,GAAG;AACnD,YAAI,KAAK,KAAK,EAAG,WAAU,MAAM,IAAI;AAAA,MACvC;AAAA,IACF;AACA,UAAM,QAAQ,GAAG,QAAQ,IAAI;AAC7B,UAAM,QAAQ,GAAG,QAAQ,IAAI;AAC7B,UAAM,GAAG,SAAS,CAAC,SAAS,eAAe,QAAQ,CAAC,CAAC;AACrD,UAAM,GAAG,SAAS,MAAM,eAAe,GAAG,CAAC;AAAA,EAC7C,CAAC;AACH;;;ADmCO,IAAM,cAAN,cAA0B,MAAM;AAAA,EAC5B;AAAA,EAQT,YAAY,SAAiB,MAA2B;AACtD,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AACF;AAEA,IAAM,QAAQ,CAAC,OAAe,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC;AASlE,eAAsB,cAAc,QAA8C;AAChF,QAAM,EAAE,KAAK,QAAQ,SAAS,IAAI;AAClC,QAAM,aAAa,OAAO,cAAc;AAExC,QAAM,SAAS,MAAM,kBAAkB,GAAG;AAC1C,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,YAAY,2DAAsD,WAAW;AAAA,EACzF;AAGA,QAAM,MAAM,MAAM,OAAO,QAAQ,QAAQ,EAAE,MAAM,CAAC,MAAM;AACtD,YAAI,gCAAY,CAAC,EAAG,OAAM,IAAI,YAAY,yCAAoC,MAAM;AACpF,UAAM;AAAA,EACR,CAAC;AACD,QAAM,SAAS,IAAI,QAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,OAAO,IAAI;AAC7D,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI;AAAA,MACR,SAAS,OAAO,IAAI,mCAClB,IAAI,QAAQ,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,IAAI,KAAK,MAC/C;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAGA,MAAI,OAAO,SAAS,OAAO,UAAU,OAAO;AAC1C,cAAU,OAAO,UAAU,OAAO,KAAK,EAAE;AACzC,UAAM,OAAO,MAAM,WAAW,OAAO,OAAO,KAAK,QAAQ;AACzD,QAAI,SAAS,EAAG,OAAM,IAAI,YAAY,wBAAwB,IAAI,KAAK,cAAc;AAAA,EACvF;AAGA,QAAM,cAAc,OAAO,SAAS,YAAY,OAAO,aAAS,2BAAQ,KAAK,OAAO,MAAM,IAAI;AAC9F,MAAI,OAAO,SAAS,YAAY,OAAO,QAAQ;AAC7C,cAAM,yBAAO,WAAW,EAAE,MAAM,MAAM;AACpC,YAAM,IAAI;AAAA,QACR,iBAAiB,OAAO,MAAM;AAAA,QAC9B;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AACA,YAAU,OAAO,WAAW,gBAAgB,MAAM,MAAM,OAAO,MAAM,EAAE;AACvE,QAAM,OAAO,MAAM,cAAc,WAAW;AAC5C,YAAU,MAAM,GAAG,KAAK,MAAM,MAAM,gBAAa,KAAK,QAAQ,MAAM,QAAQ,CAAC,CAAC,KAAK;AAGnF,MAAI,OAAO,SAAS,UAAU;AAC5B,cAAU,OAAO,gBAAgB,OAAO,IAAI,GAAG,OAAO,SAAS,IAAI,OAAO,MAAM,KAAK,EAAE,EAAE;AACzF,QAAI;AACJ,QAAI;AACF,YAAM,MAAM,OAAO,MAAM,OAAO,OAAO,MAAM,OAAO,QAAQ,KAAK,MAAM;AAAA,IACzE,SAAS,KAAK;AACZ,YAAM,IAAI;AAAA,QACR,eAAe,oCAAiB,IAAI,UAAU,OAAO,GAAG;AAAA,QACxD;AAAA,MACF;AAAA,IACF;AACA,UAAMC,OAAM,WAAW,IAAI,IAAI,GAAG,IAAI,QAAQ,IAAI,SAAS,MAAM,IAAI,OAAO,EAAE;AAC9E,cAAU,OAAO,eAAUA,IAAG,EAAE;AAChC,WAAO,EAAE,MAAM,UAAU,IAAI,MAAM,KAAAA,MAAK,OAAO,IAAI,SAAS,KAAK,MAAM,QAAQ,OAAO;AAAA,EACxF;AAMA,QAAM,UAAU,OAAO,YAAY,UAAU,SAAS,OAAO;AAC7D,QAAM,OAAO,4BAAS,OAAO;AAC7B,QAAM,SAAS,OAAO,eAAe;AAAA,IACnC,MAAM,OAAO;AAAA,IACb,QAAQ,OAAO;AAAA,IACf;AAAA,IACA,gBAAgB,OAAO,kBAAkB,KAAK;AAAA,IAC9C,QAAQ,OAAO,UAAU,KAAK,QAAQ,CAAC,IAAI,CAAC,KAAK;AAAA,IACjD,SAAS,OAAO,SAAS,KAAK;AAAA,IAC9B,QAAQ,OAAO,UAAU;AAAA,EAC3B;AAEA,YAAU;AAAA,IACR,OAAO,cAAc,qBAAqB;AAAA,EAC5C;AACA,MAAI,WAAW;AACf,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,MAAM,OAAO,aAAa,aAAa,QAAQ,KAAK,MAAM;AACtE,eAAW,IAAI,kBAAkB;AACjC,YAAQ,IAAI;AACZ,QAAI,IAAI,WAAW,SAAS,UAAU,OAAO,aAAa;AACxD,aAAO,cAAc;AACrB,YAAM,kBAAkB,QAAQ,GAAG;AACnC,gBAAU,MAAM,eAAe,KAAK,UAAU;AAAA,IAChD;AAAA,EACF,SAAS,KAAK;AACZ,UAAM,IAAI;AAAA,MACR,eAAe,oCAAiB,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD,OAAO,cAAc,kBAAkB;AAAA,IACzC;AAAA,EACF;AAEA,QAAM,MAAM,OAAO,SACf,WAAW,OAAO,IAAI,GAAG,OAAO,SAAS,IAAI,OAAO,MAAM,KAAK,EAAE,KACjE;AAEJ,MAAI,OAAO,WAAW,OAAO;AAC3B,cAAU,OAAO,0BAA0B,QAAQ,GAAG;AACtD,WAAO;AAAA,MACL,MAAM;AAAA,MACN,IAAI;AAAA,MACJ,aAAa;AAAA,MACb,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,CAAC;AAAA,IACT;AAAA,EACF;AAEA,SAAO,MAAM,QAAQ,OAAO;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ,OAAO,UAAU;AAAA,IACzB,WAAW,OAAO,aAAa,KAAK,KAAK;AAAA,EAC3C,CAAC;AACH;AAEA,eAAe,MACb,QACA,OACA,MAOwB;AACxB,QAAM,UAAU,KAAK,IAAI;AACzB,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,YAAsB,CAAC;AAC7B,MAAI,aAAa;AAEjB,OAAK,UAAU,OAAO,UAAU;AAChC,SAAO,MAAM;AACX,UAAM,MAAM,KAAK,MAAM;AAEvB,QAAI;AACJ,QAAI;AACF,YAAM,MAAM,OAAO,QAAQ,OAAO,KAAK;AAAA,IACzC,QAAQ;AAAA,IAER;AACA,QAAI,CAAC,KAAK;AACR,UAAI,KAAK,IAAI,IAAI,UAAU,KAAK,UAAW;AAC3C;AAAA,IACF;AAEA,UAAM,MAAM,IAAI;AAChB,UAAM,UAAU,IAAI;AACpB,UAAM,SAAS,IAAI;AACnB,QAAI,WAAW,YAAY;AACzB,WAAK,UAAU,OAAO,GAAG,UAAU,SAAS,KAAK,OAAO,IAAI,GAAG,GAAG;AAClE,mBAAa;AAAA,IACf;AAEA,QAAI;AACF,iBAAW,QAAQ,MAAM,OAAO,aAAa,KAAK,OAAO,EAAE,GAAG;AAC5D,YAAI,QAAQ,CAAC,KAAK,IAAI,IAAI,GAAG;AAC3B,eAAK,IAAI,IAAI;AACb,oBAAU,KAAK,IAAI;AACnB,eAAK,UAAU,MAAM,IAAI;AAAA,QAC3B;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAEA,QAAI,OAAO,WAAW,WAAW,WAAW;AAC1C,WAAK,UAAU,OAAO,OAAO,KAAK,MAAM,WAAM,KAAK,GAAG,KAAK,EAAE,EAAE;AAC/D,aAAO;AAAA,QACL,MAAM;AAAA,QACN,IAAI;AAAA,QACJ,aAAa;AAAA,QACb,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,KAAK,KAAK;AAAA,QACV,QAAQ,KAAK;AAAA,QACb,MAAM;AAAA,MACR;AAAA,IACF;AACA,QAAI,WAAW,UAAU;AACvB,aAAO;AAAA,QACL,MAAM;AAAA,QACN,IAAI;AAAA,QACJ,aAAa;AAAA,QACb,QAAQ;AAAA,QACR,QAAQ,IAAI,aAAa,kBAAkB,KAAK;AAAA,QAChD,QAAQ,KAAK;AAAA,QACb,MAAM;AAAA,MACR;AAAA,IACF;AACA,QAAI,KAAK,IAAI,IAAI,UAAU,KAAK,UAAW;AAAA,EAC7C;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,QAAQ,KAAK;AAAA,IACb,MAAM;AAAA,EACR;AACF;;;AEzSA,IAAAC,mBAAsD;AACtD,qBAAwB;AACxB,IAAAC,oBAAqB;AAqBd,SAAS,iBAAyB;AACvC,aAAO,4BAAK,wBAAQ,GAAG,SAAS;AAClC;AACO,SAAS,kBAA0B;AACxC,aAAO,wBAAK,eAAe,GAAG,aAAa;AAC7C;AAGO,SAAS,mBAA8B;AAC5C,SAAO;AAAA,IACL,QAAQ,QAAQ,IAAI;AAAA,IACpB,YAAY,QAAQ,IAAI;AAAA,EAC1B;AACF;AAGO,SAAS,eAAmC;AACjD,SAAO,QAAQ,IAAI,gBAAgB;AACrC;AAEA,eAAsB,kBAAoD;AACxE,MAAI;AACF,WAAO,KAAK,MAAM,UAAM,2BAAS,gBAAgB,GAAG,MAAM,CAAC;AAAA,EAC7D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,gBAAgB,OAAqC;AACzE,QAAM,OAAO,gBAAgB;AAC7B,YAAM,wBAAM,eAAe,GAAG,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AAC9D,YAAM,4BAAU,MAAM,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAAA,GAAM,EAAE,MAAM,IAAM,CAAC;AAC5E,YAAM,wBAAM,MAAM,GAAK,EAAE,MAAM,MAAM,MAAS;AAC9C,SAAO;AACT;AAEA,eAAsB,mBAAkC;AACtD,YAAM,qBAAG,gBAAgB,GAAG,EAAE,OAAO,KAAK,CAAC;AAC7C;","names":["ignore","tarCreate","import_promises","import_node_path","import_promises","import_node_path","import_promises","import_node_path","import_api_client","url","import_promises","import_node_path"]}
|