@akanjs/cli 3.0.2-rc.0 → 3.1.0-rc.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/.build-stamp +1 -1
- package/{CodeAgent-szbjv4gv.js → CodeAgent-q7a4srt6.js} +2 -2
- package/{CodeTui-5nw86ab6.js → CodeTui-ak23dxc9.js} +1 -1
- package/{TunnelShare-cwh9ezsm.js → TunnelShare-21mm6dr5.js} +2 -2
- package/{agent.command-np1dffkb.js → agent.command-f3gsc1gd.js} +5 -5
- package/akanCode.js +2 -2
- package/{application.command-fyjy9ryc.js → application.command-3v2d53gd.js} +38 -16
- package/{applicationBuildRunner-etrzfwjj.js → applicationBuildRunner-1yaqsrdq.js} +115 -103
- package/buildBatch.proc.js +17 -6
- package/cloud.command-kk2rwkvw.js +187 -0
- package/cloud.script-r7eyfey4.js +20 -0
- package/{code.command-hmtx14b2.js → code.command-30sca09d.js} +6 -6
- package/commandManifest.json +1 -1
- package/{context.command-6aqvdx43.js → context.command-k7eqacq6.js} +13 -13
- package/context.runner-hqd1ppqe.js +21 -0
- package/{guideline.command-axvf68gc.js → guideline.command-dtczrqpf.js} +2 -2
- package/guidelines/agentRule/agentRule.instruction.md +10 -2
- package/guidelines/conventions/conventions.instruction.md +68 -25
- package/guidelines/cssRule/cssRule.instruction.md +19 -0
- package/guidelines/mcpRule/mcpRule.instruction.md +67 -12
- package/guidelines/queryRule/queryRule.instruction.md +11 -1
- package/guidelines/runtimeRule/runtimeRule.instruction.md +97 -16
- package/guidelines/ssrRule/ssrRule.instruction.md +10 -7
- package/guidelines/transportRule/transportRule.instruction.md +19 -0
- package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +6 -6
- package/incrementalBuilder.proc.js +25 -4
- package/{index-h9ht6s60.js → index-05g3jayg.js} +1 -1
- package/{index-j38qkvkk.js → index-0bm04n5g.js} +12 -10
- package/{index-g38nhv87.js → index-2etcv0sc.js} +1 -1
- package/{index-zyw622y1.js → index-2mx692qq.js} +3 -3
- package/{index-jb0hmt3k.js → index-2t4tqd1c.js} +3 -3
- package/{index-50wb2a26.js → index-55mynnqs.js} +354 -129
- package/{index-q6ft9fkc.js → index-6jjtnhkw.js} +8 -3
- package/index-6w0rbr9d.js +68 -0
- package/{index-2wc41k5w.js → index-7bymavqk.js} +2 -2
- package/{index-krjcg4y6.js → index-aprt7pkz.js} +7 -10
- package/{index-1bjkfvm9.js → index-c1x0be5j.js} +2 -2
- package/{index-d95tfg3n.js → index-c2yrsxdh.js} +14 -8
- package/{index-cb6yc5mb.js → index-c76k723e.js} +2 -2
- package/{index-6keyf4sg.js → index-ctanya41.js} +4 -4
- package/{index-f4e08ptp.js → index-e0cvze1s.js} +4 -4
- package/{index-hp3stk1m.js → index-fm46xrf1.js} +3 -3
- package/{index-3xmzr1p1.js → index-gnyf1fqy.js} +2 -2
- package/{index-zwd84m0w.js → index-jyv387qw.js} +4 -4
- package/{index-senscydg.js → index-k9rrten6.js} +6 -1
- package/{index-jk9xnck6.js → index-kjvrq3nc.js} +231 -133
- package/{index-xwprn9nr.js → index-nz15k0b6.js} +1 -1
- package/{index-61mmsdjg.js → index-p9ystjrp.js} +174 -72
- package/index-q958tqqg.js +77 -0
- package/{index-50jjwg8y.js → index-qt22xstj.js} +1 -1
- package/{index-94s080qm.js → index-r2tpeb3n.js} +127 -1
- package/{index-bsv901fd.js → index-rwq3ekqc.js} +7 -7
- package/{index-gvpvxdm1.js → index-tn4rpqp1.js} +96 -12
- package/{index-1gs9g12n.js → index-v29746vb.js} +4 -4
- package/index-ww9bhp67.js +62 -0
- package/{index-hxnnfy57.js → index-y8q31011.js} +180 -8
- package/index.js +22 -21
- package/{library.command-9m2rdwwz.js → library.command-gaga5bmq.js} +3 -3
- package/{localRegistry.command-vacc2njh.js → localRegistry.command-9e84e32q.js} +10 -10
- package/{module.command-q63dffya.js → module.command-7vpf6db4.js} +5 -5
- package/{package.command-y2jh0m99.js → package.command-twmvvf69.js} +3 -3
- package/package.json +2 -2
- package/{page.command-f3e4cwhh.js → page.command-5asq7fdf.js} +3 -3
- package/pipeline.command-d0v38572.js +1334 -0
- package/{primitive.command-r4kq75qj.js → primitive.command-dyrs2fm8.js} +6 -6
- package/projectTypecheck-cvtkrzp2.js +7 -0
- package/{quality.command-f7gzh26z.js → quality.command-6emsqpbg.js} +5 -4
- package/{repair.command-0qmyr6qa.js → repair.command-8t6aegv5.js} +5 -5
- package/{scalar.command-kddn7av4.js → scalar.command-bnggy1x7.js} +4 -4
- package/{subspace.command-j7ayp382.js → subspace.command-f02j5tge.js} +158 -91
- package/templates/app/tsconfig.json.template +1 -6
- package/templates/appSample/page/task/[taskId]/_index.tsx +2 -2
- package/templates/appSample/page/task/[taskId]/edit.tsx +2 -2
- package/templates/appSample/page/task/_index.tsx +2 -2
- package/templates/crudPages/[__model__Id]/edit/page.tsx +2 -2
- package/templates/crudPages/[__model__Id]/page.tsx +3 -3
- package/templates/crudPages/page.tsx +2 -2
- package/templates/crudSinglePage/page.tsx +3 -3
- package/templates/lib/cnst.ts +2 -2
- package/templates/lib/sig.ts +3 -3
- package/{tunnel.command-b3ymdk4f.js → tunnel.command-9x8nfn75.js} +16 -13
- package/{workflow.command-z1srcdfw.js → workflow.command-jx0wag5r.js} +10 -10
- package/{workspace.command-17c46dbp.js → workspace.command-cmj6mqyk.js} +58 -28
- package/cloud.command-c0rnwy65.js +0 -95
- package/cloud.script-6ba8e9v8.js +0 -20
- package/context.runner-hnkvv3z3.js +0 -21
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
ApplicationBuildReporter,
|
|
4
|
+
UNAVAILABLE_REDIS_HOST,
|
|
5
|
+
redisTunnelPolicy,
|
|
4
6
|
BUILDER_MIN_RSS_RECYCLE_INTERVAL_MS,
|
|
5
7
|
SOURCE_EXTS,
|
|
6
8
|
shouldRestartBackendByDevPlan,
|
|
@@ -33,33 +35,36 @@ import {
|
|
|
33
35
|
filesChangedSince,
|
|
34
36
|
HmrWatcher,
|
|
35
37
|
WatchRootResolver
|
|
36
|
-
} from "./index-
|
|
38
|
+
} from "./index-k9rrten6.js";
|
|
37
39
|
import {
|
|
38
40
|
runner,
|
|
39
41
|
script
|
|
40
|
-
} from "./index-
|
|
42
|
+
} from "./index-6jjtnhkw.js";
|
|
41
43
|
import {
|
|
42
44
|
WorkspaceExecutor,
|
|
43
45
|
AppExecutor,
|
|
44
46
|
LibExecutor,
|
|
45
47
|
PkgExecutor
|
|
46
|
-
} from "./index-
|
|
48
|
+
} from "./index-55mynnqs.js";
|
|
47
49
|
import {
|
|
48
50
|
DesktopServerStage,
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
} from "./index-jk9xnck6.js";
|
|
51
|
+
NativeApp,
|
|
52
|
+
UpdateUploader
|
|
53
|
+
} from "./index-kjvrq3nc.js";
|
|
53
54
|
import {
|
|
54
55
|
LibraryScript
|
|
55
|
-
} from "./index-
|
|
56
|
+
} from "./index-c1x0be5j.js";
|
|
56
57
|
import {
|
|
57
58
|
stripAnsi
|
|
58
59
|
} from "./index-7md2g9vw.js";
|
|
59
60
|
import {
|
|
60
61
|
SlicePlanner,
|
|
61
62
|
formatSlicePlan
|
|
62
|
-
} from "./index-
|
|
63
|
+
} from "./index-qt22xstj.js";
|
|
64
|
+
import {
|
|
65
|
+
resolveMobileTargets,
|
|
66
|
+
resolveAppId
|
|
67
|
+
} from "./index-q958tqqg.js";
|
|
63
68
|
import {
|
|
64
69
|
openBrowser
|
|
65
70
|
} from "./index-9dp031by.js";
|
|
@@ -187,20 +192,29 @@ var closeBunSocket = (socket, error) => {
|
|
|
187
192
|
// pkgs/@akanjs/devkit/createTunnel.ts
|
|
188
193
|
var createTunnel = async (service, { app, environment, port = service === "postgres" ? 5432 : 6379 }) => {
|
|
189
194
|
const { serveDomain, repoName } = WorkspaceExecutor.getBaseDevEnv();
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
195
|
+
const host = `${app.name}-${environment}.${serveDomain}`;
|
|
196
|
+
const sshPort = process.env.SSH_TUNNEL_PORT ? parseInt(process.env.SSH_TUNNEL_PORT) : 32767;
|
|
197
|
+
const dstHost = `${service}-0.${service}-svc.${app.name}-${environment}.svc.cluster.local`;
|
|
198
|
+
const dstPort = service === "postgres" ? 5432 : 6379;
|
|
199
|
+
try {
|
|
200
|
+
await createSshTunnel({
|
|
201
|
+
localHost: "0.0.0.0",
|
|
202
|
+
localPort: port,
|
|
203
|
+
srcHost: "0.0.0.0",
|
|
204
|
+
srcPort: port,
|
|
205
|
+
dstHost,
|
|
206
|
+
dstPort,
|
|
207
|
+
sshOptions: {
|
|
208
|
+
host: host.endsWith(".localhost") ? "localhost" : host,
|
|
209
|
+
port: sshPort,
|
|
210
|
+
username: process.env.SSH_TUNNEL_USERNAME ?? "root",
|
|
211
|
+
password: process.env.SSH_TUNNEL_PASSWORD ?? repoName
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
} catch (error) {
|
|
215
|
+
const reasons = error instanceof AggregateError ? error.errors.map((reason) => reason instanceof Error ? reason.message : String(reason)).join("; ") : error instanceof Error ? error.message : String(error);
|
|
216
|
+
throw new Error(`Could not open the ${service} tunnel for ${app.name}-${environment}: SSH ${host}:${sshPort} -> ${dstHost}:${dstPort} failed (${reasons})`, { cause: error });
|
|
217
|
+
}
|
|
204
218
|
return `localhost:${port}`;
|
|
205
219
|
};
|
|
206
220
|
// pkgs/@akanjs/devkit/incrementalBuilder/incrementalBuilder.host.ts
|
|
@@ -818,9 +832,17 @@ class AkanAppHost {
|
|
|
818
832
|
}
|
|
819
833
|
async#prepareDatabase(type) {
|
|
820
834
|
const environment = WorkspaceExecutor.getBaseDevEnv().env;
|
|
821
|
-
|
|
835
|
+
const policy = redisTunnelPolicy({ environment, databaseMode: this.env.AKAN_DATABASE_MODE });
|
|
836
|
+
if (policy === "none")
|
|
822
837
|
return "localhost";
|
|
823
|
-
|
|
838
|
+
if (policy === "required")
|
|
839
|
+
return await createTunnel(type, { app: this.app, environment });
|
|
840
|
+
try {
|
|
841
|
+
return await createTunnel(type, { app: this.app, environment });
|
|
842
|
+
} catch (error) {
|
|
843
|
+
this.logger.warn(`${error instanceof Error ? error.message : String(error)} - continuing without Redis: the single database mode does not use it unless an app adaptor does`);
|
|
844
|
+
return UNAVAILABLE_REDIS_HOST;
|
|
845
|
+
}
|
|
824
846
|
}
|
|
825
847
|
#startBackend(startStatus = null) {
|
|
826
848
|
if (this.#stopping)
|
|
@@ -1813,7 +1835,7 @@ ${this.#backendStderrTail.join(`
|
|
|
1813
1835
|
this.#wakeFromIdle(`${message.type} arrived while suspended`);
|
|
1814
1836
|
return;
|
|
1815
1837
|
}
|
|
1816
|
-
if (message.type === "build-csr" && this.env.AKAN_DEV_CSR_REBUILD !== "1") {
|
|
1838
|
+
if (message.type === "build-csr" && !message.shell && this.env.AKAN_DEV_CSR_REBUILD !== "1") {
|
|
1817
1839
|
Object.assign(this.env, { AKAN_DEV_CSR_REBUILD: "1" });
|
|
1818
1840
|
this.logger.verbose(`[csr] armed dev CSR rebuilds (${message.reason})`);
|
|
1819
1841
|
}
|
|
@@ -1867,7 +1889,7 @@ ${uniqueCandidates.map((candidate) => ` - ${candidate}`).join(`
|
|
|
1867
1889
|
|
|
1868
1890
|
// pkgs/@akanjs/cli/application/application.runner.ts
|
|
1869
1891
|
import { Logger as Logger3 } from "akanjs/common";
|
|
1870
|
-
var loadBuildRunner = async () => (await import("./applicationBuildRunner-
|
|
1892
|
+
var loadBuildRunner = async () => (await import("./applicationBuildRunner-1yaqsrdq.js")).ApplicationBuildRunner;
|
|
1871
1893
|
var loadPrompts = async () => await import("@inquirer/prompts");
|
|
1872
1894
|
|
|
1873
1895
|
class ApplicationRunner extends runner("application") {
|
|
@@ -2024,6 +2046,18 @@ try {
|
|
|
2024
2046
|
async typecheck(app, options = {}) {
|
|
2025
2047
|
await new (await loadBuildRunner())(app).typecheck(options);
|
|
2026
2048
|
}
|
|
2049
|
+
async typecheckLibrary(lib, options = {}) {
|
|
2050
|
+
const { ProjectTypecheck } = await import("./projectTypecheck-cvtkrzp2.js");
|
|
2051
|
+
const root = lib.workspace.workspaceRoot;
|
|
2052
|
+
await new ProjectTypecheck(lib.cwdPath, root, { ...process.env, AKAN_WORKSPACE_ROOT: root }).run([
|
|
2053
|
+
"../../server.ts",
|
|
2054
|
+
"../../client.ts",
|
|
2055
|
+
"../../index.ts",
|
|
2056
|
+
"../../page/**/*.ts",
|
|
2057
|
+
"../../page/**/*.tsx",
|
|
2058
|
+
"../../../../pkgs/akanjs/*/types/**/*.d.ts"
|
|
2059
|
+
], options);
|
|
2060
|
+
}
|
|
2027
2061
|
async test(exec) {
|
|
2028
2062
|
const isSignalTarget = exec instanceof AppExecutor || exec instanceof LibExecutor;
|
|
2029
2063
|
const preloadPath = isSignalTarget ? await resolveSignalTestPreloadPath(exec) : null;
|
|
@@ -2043,9 +2077,10 @@ try {
|
|
|
2043
2077
|
async build(app, {
|
|
2044
2078
|
fast = false,
|
|
2045
2079
|
reporter,
|
|
2046
|
-
spinner = false
|
|
2080
|
+
spinner = false,
|
|
2081
|
+
profile
|
|
2047
2082
|
} = {}) {
|
|
2048
|
-
return new (await loadBuildRunner())(app, { fast, reporter }).build({ spinner });
|
|
2083
|
+
return new (await loadBuildRunner())(app, { fast, reporter, profile }).build({ spinner });
|
|
2049
2084
|
}
|
|
2050
2085
|
async start(app, {
|
|
2051
2086
|
open = false,
|
|
@@ -2060,7 +2095,15 @@ try {
|
|
|
2060
2095
|
setTimeout(() => openBrowser(`http://localhost:${env.AKAN_PUBLIC_CLIENT_PORT ?? env.PORT ?? "8282"}`), 3000);
|
|
2061
2096
|
return appHost;
|
|
2062
2097
|
}
|
|
2063
|
-
async buildMobile(app, platform, {
|
|
2098
|
+
async buildMobile(app, platform, {
|
|
2099
|
+
target,
|
|
2100
|
+
env = "debug",
|
|
2101
|
+
profile = "release",
|
|
2102
|
+
installer = false,
|
|
2103
|
+
arch,
|
|
2104
|
+
sign = false,
|
|
2105
|
+
notarize = false
|
|
2106
|
+
} = {}) {
|
|
2064
2107
|
const targets = await resolveMobileTargets(app, target);
|
|
2065
2108
|
NativeApp.assertInstaller(platform, installer);
|
|
2066
2109
|
if (arch && platform !== "macos" && platform !== "windows" && platform !== "linux")
|
|
@@ -2073,7 +2116,9 @@ try {
|
|
|
2073
2116
|
profile,
|
|
2074
2117
|
...carried && ApplicationRunner.carriesServer(mobileTarget, platform) ? { server: carried } : {},
|
|
2075
2118
|
...installer ? { installer } : {},
|
|
2076
|
-
...arch ? { arch } : {}
|
|
2119
|
+
...arch ? { arch } : {},
|
|
2120
|
+
sign,
|
|
2121
|
+
notarize
|
|
2077
2122
|
}));
|
|
2078
2123
|
});
|
|
2079
2124
|
}
|
|
@@ -2163,20 +2208,26 @@ try {
|
|
|
2163
2208
|
if (!mobileTarget || targets.length > 1)
|
|
2164
2209
|
throw new Error("pack-update packs one native target at a time; pass --target <name>.");
|
|
2165
2210
|
await this.#buildMobileCsr(app, env);
|
|
2166
|
-
const
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
const compat = await NativeApp.compareBundles(app.cwdPath, against, bundle);
|
|
2173
|
-
await Bun.write(path5.join(packed.out, "compat.json"), `${JSON.stringify({ against, ...compat }, null, 2)}
|
|
2211
|
+
const { pack } = await new NativeApp(app, mobileTarget, env).packUpdate(platform, { out });
|
|
2212
|
+
app.logger.info(`packed ${mobileTarget.name} ${platform} for channel '${pack.channel}' to ${pack.out}: ${pack.files} files, ${(pack.size / 1024).toFixed(0)} KiB, native API ${pack.nativeApi}`);
|
|
2213
|
+
if (against) {
|
|
2214
|
+
const compat = await NativeApp.compareBundles(app.cwdPath, against, path5.join(pack.out, "bundle.json"));
|
|
2215
|
+
pack.compat = { against, ...compat };
|
|
2216
|
+
await Bun.write(path5.join(pack.out, "compat.json"), `${JSON.stringify(pack.compat, null, 2)}
|
|
2174
2217
|
`);
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2218
|
+
}
|
|
2219
|
+
await NativeApp.writePack(pack);
|
|
2220
|
+
if (!pack.compat)
|
|
2221
|
+
return pack;
|
|
2222
|
+
if (pack.compat.compatible) {
|
|
2223
|
+
app.logger.info(`runs in the store build of ${against}`);
|
|
2224
|
+
return pack;
|
|
2225
|
+
}
|
|
2226
|
+
app.logger.error(`This bundle needs a new store build; the one ${against} came from provides another native API:
|
|
2227
|
+
- ${pack.compat.problems.join(`
|
|
2178
2228
|
- `)}`);
|
|
2179
|
-
|
|
2229
|
+
process.exitCode = 2;
|
|
2230
|
+
return pack;
|
|
2180
2231
|
}
|
|
2181
2232
|
async updateKeygen(app, platform, target) {
|
|
2182
2233
|
const nativePlatform = platform === "desktop" ? NativeApp.desktopPlatform() : platform;
|
|
@@ -2188,30 +2239,47 @@ try {
|
|
|
2188
2239
|
seen.add(appId);
|
|
2189
2240
|
const { publicKey, keyPath, created } = await new NativeApp(app, mobileTarget).updateKeygen(nativePlatform);
|
|
2190
2241
|
app.log(`${appId}: ${created ? "made" : "read"} ${keyPath}${created ? " (keep it private and backed up: without it, installed apps take no more updates)" : ""}`);
|
|
2191
|
-
app.log(` native: { updates: { url: "https://\u2026/${app.name}",
|
|
2192
|
-
const
|
|
2193
|
-
|
|
2194
|
-
|
|
2242
|
+
app.log(` native: { updates: { url: "https://\u2026/${app.name}", publicKeys: [${JSON.stringify(publicKey)}] } }`);
|
|
2243
|
+
const { publicKey: one, publicKeys } = mobileTarget.config.updates ?? {};
|
|
2244
|
+
const declared = publicKeys ?? (one ? [one] : null);
|
|
2245
|
+
if (declared && !declared.includes(publicKey))
|
|
2246
|
+
app.logger.warn(`native.targets.${mobileTarget.name}.updates.publicKeys does not hold this key; releases it signs would not verify.`);
|
|
2195
2247
|
}
|
|
2196
2248
|
}
|
|
2197
|
-
async publishUpdate(app, platform, { target, env = "main", channel } = {}) {
|
|
2249
|
+
async publishUpdate(app, platform, { target, env = "main", channel, upload, arch, sign = false, notarize = false } = {}) {
|
|
2250
|
+
if (arch && platform !== "desktop")
|
|
2251
|
+
throw new Error(`--arch picks a desktop release's CPU; ${platform} publishes its web bundle.`);
|
|
2198
2252
|
const targets = await resolveMobileTargets(app, target);
|
|
2253
|
+
if (upload && targets.length > 1)
|
|
2254
|
+
throw new Error(`--upload takes one target's release; name it with --target (${targets.map(({ name }) => name).join(", ")}).`);
|
|
2255
|
+
const uploader = upload ? UpdateUploader.forTarget(upload) : null;
|
|
2199
2256
|
const nativePlatform = platform === "desktop" ? NativeApp.desktopPlatform() : platform;
|
|
2257
|
+
if (arch === "x64" && nativePlatform === "macos")
|
|
2258
|
+
throw new Error("A macOS app is built for Apple silicon (arm64) only.");
|
|
2200
2259
|
for (const mobileTarget of targets)
|
|
2201
2260
|
await new NativeApp(app, mobileTarget, env).assertPublishable(nativePlatform, {
|
|
2202
2261
|
server: ApplicationRunner.carriesServer(mobileTarget, nativePlatform),
|
|
2203
|
-
...channel ? { channel } : {}
|
|
2262
|
+
...channel ? { channel } : {},
|
|
2263
|
+
...arch ? { arch } : {}
|
|
2204
2264
|
});
|
|
2205
|
-
const carried = await this.#stageMobile(app, nativePlatform, targets, env);
|
|
2265
|
+
const carried = await this.#stageMobile(app, nativePlatform, targets, env, arch);
|
|
2206
2266
|
for (const mobileTarget of targets) {
|
|
2207
2267
|
const nativeApp = new NativeApp(app, mobileTarget, env);
|
|
2208
2268
|
const published = await nativeApp.publishUpdate(nativePlatform, {
|
|
2209
2269
|
...channel ? { channel } : {},
|
|
2270
|
+
...arch ? { arch } : {},
|
|
2271
|
+
sign,
|
|
2272
|
+
notarize,
|
|
2210
2273
|
...carried && ApplicationRunner.carriesServer(mobileTarget, nativePlatform) ? { server: carried } : {}
|
|
2211
2274
|
});
|
|
2212
2275
|
this.#reportBuild(app, mobileTarget, published.build);
|
|
2213
2276
|
app.log(`${app.name}/${mobileTarget.name} ${published.bundle}: ${published.dir}/${published.channel}.json, ${published.files} files, ${Math.round(published.size / 1024)} KiB`);
|
|
2214
|
-
|
|
2277
|
+
if (!uploader) {
|
|
2278
|
+
app.log(`Upload ${nativeApp.updatesDir} to ${mobileTarget.config.updates?.url}, the manifests last.`);
|
|
2279
|
+
continue;
|
|
2280
|
+
}
|
|
2281
|
+
const { uploaded, skipped } = await uploader.upload(nativeApp.updatesDir);
|
|
2282
|
+
app.log(`Uploaded ${uploaded} file(s) to ${upload}, the manifests last; ${skipped} the bucket already held. Installed apps read ${mobileTarget.config.updates?.url}.`);
|
|
2215
2283
|
}
|
|
2216
2284
|
}
|
|
2217
2285
|
#reportBuild(app, mobileTarget, { artifacts, warnings, signing }) {
|
|
@@ -2225,24 +2293,45 @@ try {
|
|
|
2225
2293
|
static carriesServer({ config }, platform = NativeApp.desktopPlatform()) {
|
|
2226
2294
|
return platform !== "ios" && platform !== "android" && !!config.desktop?.server;
|
|
2227
2295
|
}
|
|
2228
|
-
static
|
|
2296
|
+
static carriedServer(targets, platform) {
|
|
2229
2297
|
const carrying = targets.filter((target) => ApplicationRunner.carriesServer(target, platform));
|
|
2230
|
-
const
|
|
2298
|
+
const servers = carrying.map(({ config }) => {
|
|
2231
2299
|
const server = config.desktop?.server;
|
|
2232
|
-
|
|
2300
|
+
if (typeof server !== "object")
|
|
2301
|
+
return { omit: [], modules: [] };
|
|
2302
|
+
const { omit = [], modules = [], profile, env, restart, watchdog } = server;
|
|
2303
|
+
return {
|
|
2304
|
+
omit,
|
|
2305
|
+
modules,
|
|
2306
|
+
...profile ? { profile } : {},
|
|
2307
|
+
...env ? { env } : {},
|
|
2308
|
+
...restart !== undefined ? { restart } : {},
|
|
2309
|
+
...typeof watchdog === "object" ? { watchdog } : {}
|
|
2310
|
+
};
|
|
2233
2311
|
});
|
|
2234
|
-
const [first = [], ...rest] =
|
|
2235
|
-
|
|
2236
|
-
|
|
2312
|
+
const [first = { omit: [], modules: [] }, ...rest] = servers;
|
|
2313
|
+
const agree = (what, of) => {
|
|
2314
|
+
if (rest.every((server) => of(server) === of(first)))
|
|
2315
|
+
return;
|
|
2316
|
+
throw new Error(`The targets that carry the server ${what} (${carrying.map(({ name }, idx) => `${name}: ${servers[idx] && of(servers[idx]) || "none"}`).join("; ")}); build them one --target at a time.`);
|
|
2317
|
+
};
|
|
2318
|
+
agree("omit different packages", ({ omit }) => omit.join(", "));
|
|
2319
|
+
agree("name different env profiles", ({ profile }) => profile ?? "");
|
|
2320
|
+
agree("mount different modules", ({ modules }) => modules.join(", "));
|
|
2321
|
+
agree("set a different env", ({ env }) => env ? JSON.stringify(env) : "");
|
|
2322
|
+
agree("restart differently", ({ restart }) => String(restart ?? ""));
|
|
2323
|
+
agree("watch it differently", ({ watchdog }) => watchdog ? JSON.stringify(watchdog) : "");
|
|
2237
2324
|
return first;
|
|
2238
2325
|
}
|
|
2239
2326
|
async#stageMobile(app, platform, targets, env, arch) {
|
|
2240
2327
|
const stage = targets.some((mobileTarget) => ApplicationRunner.carriesServer(mobileTarget, platform)) ? new DesktopServerStage(app) : null;
|
|
2241
|
-
|
|
2242
|
-
await
|
|
2243
|
-
|
|
2328
|
+
const server = ApplicationRunner.carriedServer(targets, platform);
|
|
2329
|
+
await stage?.install(arch, server.omit);
|
|
2330
|
+
await this.#buildMobileCsr(app, env, stage ? server.profile : undefined);
|
|
2331
|
+
const { modules, env: serverEnv, restart, watchdog } = server;
|
|
2332
|
+
return await stage?.prepare(env, { modules, env: serverEnv, restart, watchdog });
|
|
2244
2333
|
}
|
|
2245
|
-
async#buildMobileCsr(app, env) {
|
|
2334
|
+
async#buildMobileCsr(app, env, profile) {
|
|
2246
2335
|
const prevEnv = {
|
|
2247
2336
|
AKAN_PUBLIC_ENV: process.env.AKAN_PUBLIC_ENV,
|
|
2248
2337
|
AKAN_PUBLIC_OPERATION_MODE: process.env.AKAN_PUBLIC_OPERATION_MODE,
|
|
@@ -2254,7 +2343,7 @@ try {
|
|
|
2254
2343
|
APP_OPERATION_MODE: "release"
|
|
2255
2344
|
});
|
|
2256
2345
|
try {
|
|
2257
|
-
await new (await loadBuildRunner())(app, { environment: env }).build({ spinner: true });
|
|
2346
|
+
await new (await loadBuildRunner())(app, { environment: env, profile }).build({ spinner: true });
|
|
2258
2347
|
} finally {
|
|
2259
2348
|
for (const [key, value] of Object.entries(prevEnv)) {
|
|
2260
2349
|
if (value === undefined)
|
|
@@ -3213,12 +3302,17 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
|
|
|
3213
3302
|
async logs(app, options) {
|
|
3214
3303
|
await this.applicationRunner.runLogs(app, options);
|
|
3215
3304
|
}
|
|
3216
|
-
async build(app, {
|
|
3305
|
+
async build(app, {
|
|
3306
|
+
write = true,
|
|
3307
|
+
fast = false,
|
|
3308
|
+
quiet = false,
|
|
3309
|
+
profile
|
|
3310
|
+
} = {}) {
|
|
3217
3311
|
await app.scanSync({ write });
|
|
3218
3312
|
if (!quiet)
|
|
3219
3313
|
Logger6.rawLog(`Creating an optimized production build for ${app.name}...`);
|
|
3220
3314
|
try {
|
|
3221
|
-
const result = await this.applicationRunner.build(app, { fast, spinner: !quiet });
|
|
3315
|
+
const result = await this.applicationRunner.build(app, { fast, spinner: !quiet, profile });
|
|
3222
3316
|
Logger6.rawLog(`${app.name} built in dist/apps/${app.name}`);
|
|
3223
3317
|
if (!quiet)
|
|
3224
3318
|
ApplicationBuildReporter.printSummary(result);
|
|
@@ -3228,14 +3322,22 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
|
|
|
3228
3322
|
throw error;
|
|
3229
3323
|
}
|
|
3230
3324
|
}
|
|
3231
|
-
async typecheck(
|
|
3232
|
-
|
|
3233
|
-
|
|
3325
|
+
async typecheck(exec, { write = true, clean = false, incremental = true, tests = false } = {}) {
|
|
3326
|
+
if (!(exec instanceof AppExecutor) && !(exec instanceof LibExecutor))
|
|
3327
|
+
throw new Error(`akan typecheck takes an app or a library; ${exec.name} is a package, checked by its own tsconfig.`);
|
|
3328
|
+
if (exec instanceof LibExecutor)
|
|
3329
|
+
await this.libraryScript.syncLibrary(exec);
|
|
3330
|
+
else
|
|
3331
|
+
await exec.scanSync({ write });
|
|
3332
|
+
const spinner = exec.spinning(`Typechecking ${exec.name}${tests ? " with its tests" : ""}...`);
|
|
3234
3333
|
try {
|
|
3235
|
-
|
|
3236
|
-
|
|
3334
|
+
if (exec instanceof LibExecutor)
|
|
3335
|
+
await this.applicationRunner.typecheckLibrary(exec, { clean, incremental, tests });
|
|
3336
|
+
else
|
|
3337
|
+
await this.applicationRunner.typecheck(exec, { clean, incremental, tests });
|
|
3338
|
+
spinner.succeed(`${exec.name} typechecked`);
|
|
3237
3339
|
} catch (error) {
|
|
3238
|
-
spinner.fail(`${
|
|
3340
|
+
spinner.fail(`${exec.name} typecheck failed`);
|
|
3239
3341
|
Logger6.rawLog(ApplicationBuildReporter.formatError(error), undefined, "error");
|
|
3240
3342
|
throw error;
|
|
3241
3343
|
}
|
|
@@ -3437,7 +3539,7 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
|
|
|
3437
3539
|
} = {}) {
|
|
3438
3540
|
await app.scanSync({ write });
|
|
3439
3541
|
ApplicationScript.#assertReleaseEnv("packUpdate", options.env ?? "main", allowLocalRelease);
|
|
3440
|
-
await this.applicationRunner.packUpdate(app, platform, options);
|
|
3542
|
+
return await this.applicationRunner.packUpdate(app, platform, options);
|
|
3441
3543
|
}
|
|
3442
3544
|
async updateKeygen(app, platform, { target } = {}) {
|
|
3443
3545
|
await this.applicationRunner.updateKeygen(app, platform, target);
|
|
@@ -3491,7 +3593,7 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
|
|
|
3491
3593
|
await Promise.all(shares.map(async (share) => await share.close()));
|
|
3492
3594
|
}, "Abandoning the tunnel release; the shares expire on their own.");
|
|
3493
3595
|
await Promise.all(apps.map(async (app) => {
|
|
3494
|
-
const { TunnelShare } = await import("./TunnelShare-
|
|
3596
|
+
const { TunnelShare } = await import("./TunnelShare-21mm6dr5.js");
|
|
3495
3597
|
const share = await TunnelShare.open(app, { workspace: app.workspace });
|
|
3496
3598
|
shares.push(share);
|
|
3497
3599
|
urls.set(app.name, share.url);
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// pkgs/@akanjs/devkit/mobile/mobileTarget.ts
|
|
3
|
+
var trimSlashes = (value) => value.replace(/^\/+|\/+$/g, "");
|
|
4
|
+
var getMobileTargets = async (app) => {
|
|
5
|
+
const config = await app.getConfig();
|
|
6
|
+
return Object.entries(config.native.targets).map(([name, target]) => ({ name, config: target }));
|
|
7
|
+
};
|
|
8
|
+
var isTemplateOnly = ({ basePaths, native }) => basePaths.size > 0 && Object.values(native.targets).every((target) => !target.basePath);
|
|
9
|
+
var getMobileTargetChoices = async (app) => {
|
|
10
|
+
const config = await app.getConfig();
|
|
11
|
+
const targetNames = Object.keys(config.native.targets);
|
|
12
|
+
if (targetNames.length > 0 && !isTemplateOnly(config))
|
|
13
|
+
return targetNames;
|
|
14
|
+
return [...config.basePaths];
|
|
15
|
+
};
|
|
16
|
+
var resolveMobileTargetByBasePath = (targets, basePath) => {
|
|
17
|
+
const normalizedBasePath = trimSlashes(basePath);
|
|
18
|
+
const byBasePath = targets.find(({ config }) => config.basePath !== undefined && trimSlashes(config.basePath) === normalizedBasePath);
|
|
19
|
+
if (byBasePath)
|
|
20
|
+
return byBasePath;
|
|
21
|
+
const [template] = targets;
|
|
22
|
+
if (!template)
|
|
23
|
+
return;
|
|
24
|
+
return {
|
|
25
|
+
name: normalizedBasePath,
|
|
26
|
+
config: { ...template.config, name: normalizedBasePath, basePath: normalizedBasePath }
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
var resolveMobileTargets = async (app, selection) => {
|
|
30
|
+
const config = await app.getConfig();
|
|
31
|
+
const targets = await getMobileTargets(app);
|
|
32
|
+
if (targets.length === 0)
|
|
33
|
+
throw new Error(`No native targets configured for ${app.name}`);
|
|
34
|
+
if (!selection && targets.length === 1 && !isTemplateOnly(config))
|
|
35
|
+
return targets;
|
|
36
|
+
if (!selection) {
|
|
37
|
+
const choices = await getMobileTargetChoices(app);
|
|
38
|
+
if (choices.length === 1)
|
|
39
|
+
return resolveMobileTargets(app, choices[0]);
|
|
40
|
+
throw new Error(`Multiple native targets found for ${app.name}. Pass --target <${choices.join("|")}|all>.`);
|
|
41
|
+
}
|
|
42
|
+
if (selection === "all") {
|
|
43
|
+
if (Object.keys(config.native.targets).length > 1)
|
|
44
|
+
return targets;
|
|
45
|
+
const basePaths = [...config.basePaths];
|
|
46
|
+
if (basePaths.length > 1 || isTemplateOnly(config)) {
|
|
47
|
+
return basePaths.flatMap((basePath) => {
|
|
48
|
+
const resolved = resolveMobileTargetByBasePath(targets, basePath);
|
|
49
|
+
return resolved ? [resolved] : [];
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return targets;
|
|
53
|
+
}
|
|
54
|
+
const target = targets.find((candidate) => candidate.name === selection);
|
|
55
|
+
if (target)
|
|
56
|
+
return [target];
|
|
57
|
+
const basePathTarget = resolveMobileTargetByBasePath(targets, selection);
|
|
58
|
+
if (basePathTarget && config.basePaths.has(trimSlashes(selection)))
|
|
59
|
+
return [basePathTarget];
|
|
60
|
+
const choices = await getMobileTargetChoices(app);
|
|
61
|
+
throw new Error(`Native target '${selection}' was not found. Available: ${choices.join(", ")}`);
|
|
62
|
+
};
|
|
63
|
+
var resolveAppId = (appId, platform) => {
|
|
64
|
+
if (typeof appId === "string")
|
|
65
|
+
return appId;
|
|
66
|
+
const id = appId[platform] ?? appId.default;
|
|
67
|
+
if (!id)
|
|
68
|
+
throw new Error(`native.appId names no id for ${platform}; give it ${platform} or default.`);
|
|
69
|
+
return id;
|
|
70
|
+
};
|
|
71
|
+
var appIdsOf = (appId) => typeof appId === "string" ? [appId] : Object.values(appId).filter((id) => !!id);
|
|
72
|
+
var targetHtmlFilename = (target) => {
|
|
73
|
+
const basePath = trimSlashes(target.basePath ?? "");
|
|
74
|
+
return basePath ? `${basePath}.html` : "index.html";
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export { getMobileTargets, getMobileTargetChoices, resolveMobileTargets, resolveAppId, appIdsOf, targetHtmlFilename };
|
|
@@ -52,6 +52,11 @@ class GlobalConfig {
|
|
|
52
52
|
await GlobalConfig.#setAkanGlobalConfig(mutate(await GlobalConfig.#getAkanGlobalConfig()));
|
|
53
53
|
});
|
|
54
54
|
}
|
|
55
|
+
static async hostFor(workspace, host) {
|
|
56
|
+
if (host)
|
|
57
|
+
return host;
|
|
58
|
+
return (await workspace.getConfig()).cloudHost ?? GlobalConfig.akanCloudHost;
|
|
59
|
+
}
|
|
55
60
|
static async getHostConfig(host = GlobalConfig.akanCloudHost) {
|
|
56
61
|
const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
|
|
57
62
|
return GlobalConfig.toHostConfig(akanConfig.cloudHost[host] ?? getDefaultHostConfig(host));
|
|
@@ -197,6 +202,10 @@ class HttpClient {
|
|
|
197
202
|
}
|
|
198
203
|
|
|
199
204
|
class CloudApi {
|
|
205
|
+
static statusOf(error) {
|
|
206
|
+
const status = Number(/(?:^|: )(\d{3}) /.exec(error instanceof Error ? error.message : String(error))?.[1]);
|
|
207
|
+
return Number.isNaN(status) ? null : status;
|
|
208
|
+
}
|
|
200
209
|
#api;
|
|
201
210
|
#accessToken = null;
|
|
202
211
|
#workspace;
|
|
@@ -231,6 +240,32 @@ class CloudApi {
|
|
|
231
240
|
formData.append("file", file);
|
|
232
241
|
return await this.#api.post(`/uploadEnv/${devProjectId}`, formData);
|
|
233
242
|
}
|
|
243
|
+
async uploadSecret(devProjectId, secret) {
|
|
244
|
+
return await this.#api.post(`/uploadSecret/${encodeURIComponent(devProjectId)}`, secret);
|
|
245
|
+
}
|
|
246
|
+
async listSecrets(devProjectId) {
|
|
247
|
+
return await this.#api.get(`/listSecrets/${encodeURIComponent(devProjectId)}`);
|
|
248
|
+
}
|
|
249
|
+
async removeSecret(devProjectId, secret) {
|
|
250
|
+
return await this.#api.post(`/removeSecret/${encodeURIComponent(devProjectId)}`, secret);
|
|
251
|
+
}
|
|
252
|
+
async requestUpdateUpload(devProjectId, upload) {
|
|
253
|
+
return await this.#api.post(`/requestUpdateUpload/${encodeURIComponent(devProjectId)}`, upload);
|
|
254
|
+
}
|
|
255
|
+
async commitUpdateUpload(devProjectId, uploadId) {
|
|
256
|
+
return await this.#api.post(`/commitUpdateUpload/${encodeURIComponent(devProjectId)}`, { uploadId }, { signal: AbortSignal.timeout(11 * 60000) });
|
|
257
|
+
}
|
|
258
|
+
async registerAppBinary(devProjectId, binary) {
|
|
259
|
+
const formData = new FormData;
|
|
260
|
+
for (const key of ["appName", "target", "distribution"])
|
|
261
|
+
formData.append(key, binary[key]);
|
|
262
|
+
if (binary.channel)
|
|
263
|
+
formData.append("channel", binary.channel);
|
|
264
|
+
formData.append("bundle", binary.bundle, "bundle.json");
|
|
265
|
+
if (binary.pack)
|
|
266
|
+
formData.append("pack", binary.pack, "pack.tgz");
|
|
267
|
+
return await this.#api.post(`/registerAppBinary/${encodeURIComponent(devProjectId)}`, formData);
|
|
268
|
+
}
|
|
234
269
|
async downloadEnv(devProjectId) {
|
|
235
270
|
const localPath = `${this.#workspace.workspaceRoot}/local/env.tar`;
|
|
236
271
|
await this.#api.getFile(`/downloadEnv/${devProjectId}`, localPath);
|
|
@@ -263,4 +298,95 @@ class CloudApi {
|
|
|
263
298
|
}
|
|
264
299
|
}
|
|
265
300
|
}
|
|
266
|
-
|
|
301
|
+
// pkgs/@akanjs/devkit/cloud/updatePackUpload.ts
|
|
302
|
+
import { Logger, sleep } from "akanjs/common";
|
|
303
|
+
class UpdatePackUpload {
|
|
304
|
+
static maxBytes = 200 * 1024 * 1024;
|
|
305
|
+
static #transientPut = new Set([0, 408, 429, 500, 502, 503, 504]);
|
|
306
|
+
#api;
|
|
307
|
+
#devProjectId;
|
|
308
|
+
#putRetryMs;
|
|
309
|
+
#commitRetryMs;
|
|
310
|
+
#cutOffWindowMs;
|
|
311
|
+
#commitLimitMs;
|
|
312
|
+
constructor(api, devProjectId, {
|
|
313
|
+
putRetryMs = 1000,
|
|
314
|
+
commitRetryMs = 1e4,
|
|
315
|
+
cutOffWindowMs = 15 * 60000,
|
|
316
|
+
commitLimitMs = 60 * 60000
|
|
317
|
+
} = {}) {
|
|
318
|
+
this.#api = api;
|
|
319
|
+
this.#devProjectId = devProjectId;
|
|
320
|
+
this.#putRetryMs = putRetryMs;
|
|
321
|
+
this.#commitRetryMs = commitRetryMs;
|
|
322
|
+
this.#cutOffWindowMs = cutOffWindowMs;
|
|
323
|
+
this.#commitLimitMs = commitLimitMs;
|
|
324
|
+
}
|
|
325
|
+
async send(archive, fields) {
|
|
326
|
+
const file = Bun.file(archive);
|
|
327
|
+
if (file.size < 1 || file.size > UpdatePackUpload.maxBytes)
|
|
328
|
+
throw new Error(`The pack archive is ${file.size} bytes; a project takes 1 byte to 200 MiB.`);
|
|
329
|
+
const hasher = new Bun.CryptoHasher("sha256");
|
|
330
|
+
for await (const chunk of file.stream())
|
|
331
|
+
hasher.update(chunk);
|
|
332
|
+
const upload = { ...fields, size: file.size, sha256: hasher.digest("hex") };
|
|
333
|
+
for (let ticket = 1;; ticket++) {
|
|
334
|
+
const { uploadId, uploadUrl, contentType } = await this.#request(upload);
|
|
335
|
+
const status = await this.#put(uploadUrl, contentType, file);
|
|
336
|
+
if (status >= 200 && status < 300)
|
|
337
|
+
return await this.#commit(uploadId);
|
|
338
|
+
if (status !== 403 || ticket === 2)
|
|
339
|
+
throw new Error(`The storage refused the pack upload (${status ? `HTTP ${status}` : "no response"}).`);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
async#request(upload) {
|
|
343
|
+
return await this.#api.requestUpdateUpload(this.#devProjectId, upload).catch((error) => {
|
|
344
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
345
|
+
if (CloudApi.statusOf(error) === 404 && !/"error"\s*:\s*"[\w$-]+\.error\.[\w$-]+"/.test(message))
|
|
346
|
+
throw new Error("The project's server does not take direct pack uploads yet: update akasys and try again, or upload the pack from the project's release screen.");
|
|
347
|
+
throw error;
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
async#put(url, contentType, file) {
|
|
351
|
+
for (let retry = 0;; retry++) {
|
|
352
|
+
const status = await fetch(url, { method: "PUT", body: file, headers: { "Content-Type": contentType } }).then(async (response) => {
|
|
353
|
+
await response.arrayBuffer().catch(() => {
|
|
354
|
+
return;
|
|
355
|
+
});
|
|
356
|
+
return response.status;
|
|
357
|
+
}).catch(() => 0);
|
|
358
|
+
if (retry === 3 || !UpdatePackUpload.#transientPut.has(status))
|
|
359
|
+
return status;
|
|
360
|
+
await sleep(this.#putRetryMs * (retry + 1));
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
async#commit(uploadId) {
|
|
364
|
+
const limit = performance.now() + this.#commitLimitMs;
|
|
365
|
+
let cutOffSince = null;
|
|
366
|
+
for (;; ) {
|
|
367
|
+
try {
|
|
368
|
+
return await this.#api.commitUpdateUpload(this.#devProjectId, uploadId);
|
|
369
|
+
} catch (error) {
|
|
370
|
+
const now = performance.now();
|
|
371
|
+
if (CloudApi.statusOf(error) === 409)
|
|
372
|
+
cutOffSince = null;
|
|
373
|
+
else if (UpdatePackUpload.#cutOff(error))
|
|
374
|
+
cutOffSince ??= now;
|
|
375
|
+
else
|
|
376
|
+
throw error;
|
|
377
|
+
const deadline = cutOffSince === null ? limit : Math.min(limit, cutOffSince + this.#cutOffWindowMs);
|
|
378
|
+
if (now + this.#commitRetryMs > deadline)
|
|
379
|
+
throw error;
|
|
380
|
+
Logger.rawLog(`The project is still taking the pack; asking again in ${Math.round(this.#commitRetryMs / 1000)}s.`);
|
|
381
|
+
await sleep(this.#commitRetryMs);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
static #cutOff(error) {
|
|
386
|
+
const status = CloudApi.statusOf(error);
|
|
387
|
+
if (status === null)
|
|
388
|
+
return !(error instanceof SyntaxError);
|
|
389
|
+
return status === 502 || status === 504 || status >= 520 && status <= 527;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
export { getDefaultHostConfig, GlobalConfig, CloudApi, UpdatePackUpload };
|