peachsim 0.1.637 → 0.1.639
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/README.md +8 -5
- package/cli/bridge-flow-runner.ts +442 -14
- package/cli/command-registry.ts +1 -0
- package/cli/commands/control.ts +42 -5
- package/cli/commands/inspect/core.ts +93 -24
- package/cli/commands/maestro.ts +2 -2
- package/cli/commands/serve.ts +13 -1
- package/cli/commands/swift.ts +326 -0
- package/cli/drivers/playwright-provisioning.ts +8 -16
- package/cli/drivers/playwright-sim-host.ts +3 -0
- package/cli/drivers/playwright.ts +1 -0
- package/cli/internal-child.ts +51 -8
- package/cli/main.ts +11 -0
- package/cli/outbound-endpoints.ts +5 -1
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +3 -2
- package/dist-lib/bridge-contract-input.mjs +3 -2
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +1 -1
- package/dist-lib/cloud.mjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +1 -1
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +4 -2
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +88 -23
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/kotlin-host.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +1 -1
- package/dist-lib/native-app-identity.cjs +1 -1
- package/dist-lib/native-app-identity.mjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +78 -20
- package/dist-lib/sdk.mjs +77 -20
- package/dist-lib/skills.cjs +441 -94
- package/dist-lib/swift-compile.cjs +89 -7
- package/dist-lib/swift-compile.mjs +89 -7
- package/dist-lib/swift-package.cjs +1 -1
- package/dist-lib/swift-package.mjs +1 -1
- package/dist-lib/swift-submit.cjs +89 -8
- package/dist-lib/swift-submit.mjs +78 -8
- package/dist-lib/swift.cjs +16 -33220
- package/dist-lib/vite-swift.cjs +510 -253
- package/dist-lib/vite.cjs +13 -4
- package/package.json +1 -1
- package/skills/contrast/SKILL.md +1 -0
- package/src/assetCatalogContract.ts +16 -0
- package/src/bridge-contract-input.ts +3 -2
- package/src/bridge-contract.ts +8 -0
- package/src/host/bridge-host.ts +5 -5
- package/src/metro-runtime-source.ts +15 -0
- package/src/native-seam-manifest.ts +4 -6
- package/src/swift-compile.ts +105 -9
- package/src/swift-guest.ts +51 -0
- package/src/swift-host.ts +900 -0
- package/src/swift-submit.ts +97 -6
- package/src/swift.ts +36 -8
- package/src/swiftContract.ts +52 -0
- package/src/vite-plugin-one.ts +4 -3
- package/src/vite-plugin-swift.ts +43 -755
package/dist-lib/vite-swift.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.639 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
|
@@ -45,6 +45,31 @@ __export(vite_plugin_swift_exports, {
|
|
|
45
45
|
swiftPlugin: () => swiftPlugin
|
|
46
46
|
});
|
|
47
47
|
module.exports = __toCommonJS(vite_plugin_swift_exports);
|
|
48
|
+
var import_node_fs5 = __toESM(require("node:fs"), 1);
|
|
49
|
+
var import_node_path6 = __toESM(require("node:path"), 1);
|
|
50
|
+
|
|
51
|
+
// ../sootsim-swift/src/entryModule.ts
|
|
52
|
+
function nativeExportLines(args, commonjs) {
|
|
53
|
+
const native = args.native;
|
|
54
|
+
if (!native) return [];
|
|
55
|
+
return Object.entries(native.modules).map(([name, methods]) => {
|
|
56
|
+
const calls = methods.map(
|
|
57
|
+
(method) => `${method}: (...args) => callSwiftModule(options, ${JSON.stringify(`${native.packageId}.${name}`)}, ${JSON.stringify(method)}, args, ${JSON.stringify(native.contractHash)})`
|
|
58
|
+
).join(", ");
|
|
59
|
+
return commonjs ? `module.exports.${name} = Object.freeze({ ${calls} })` : `export const ${name} = Object.freeze({ ${calls} })`;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
function swiftEntryModuleEsm(args) {
|
|
63
|
+
return [
|
|
64
|
+
`import { createSwiftEntry, callSwiftModule } from 'peachsim/swift'`,
|
|
65
|
+
`const options = ${JSON.stringify({ url: args.url, hash: args.hash, icuUrl: args.icuUrl, rootId: args.rootId, resources: args.resources, bundleFiles: args.bundleFiles, colors: args.colors, symbols: args.symbols })}`,
|
|
66
|
+
...!args.native || args.native.defaultView ? ["export default createSwiftEntry(options)"] : [],
|
|
67
|
+
...nativeExportLines(args, false),
|
|
68
|
+
""
|
|
69
|
+
].join("\n");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// src/swift-host.ts
|
|
48
73
|
var import_node_crypto3 = require("node:crypto");
|
|
49
74
|
var import_node_fs4 = __toESM(require("node:fs"), 1);
|
|
50
75
|
var import_node_os3 = __toESM(require("node:os"), 1);
|
|
@@ -82,8 +107,8 @@ function pickImagesetFile(images) {
|
|
|
82
107
|
scale: pick.scale === "2x" ? 2 : pick.scale === "3x" ? 3 : 1
|
|
83
108
|
};
|
|
84
109
|
}
|
|
85
|
-
function flatScale(
|
|
86
|
-
const match = /@([23])x\.[^./]+$/.exec(
|
|
110
|
+
function flatScale(path6) {
|
|
111
|
+
const match = /@([23])x\.[^./]+$/.exec(path6);
|
|
87
112
|
return match ? Number(match[1]) : 1;
|
|
88
113
|
}
|
|
89
114
|
function providesNamespace(text) {
|
|
@@ -110,13 +135,13 @@ function catalogEntryName(contentsPath, kind, readText) {
|
|
|
110
135
|
}
|
|
111
136
|
return segments.join("/");
|
|
112
137
|
}
|
|
113
|
-
function isFlatResourceImage(
|
|
114
|
-
return
|
|
138
|
+
function isFlatResourceImage(path6) {
|
|
139
|
+
return path6.split("/").includes("Resources") && RASTER_EXTENSIONS.has(extOf(path6));
|
|
115
140
|
}
|
|
116
141
|
function enumerateBundleImages(paths, readText) {
|
|
117
142
|
const table = [];
|
|
118
143
|
const seen = /* @__PURE__ */ new Set();
|
|
119
|
-
const catalogs = paths.filter((
|
|
144
|
+
const catalogs = paths.filter((path6) => baseOf(path6) === "Contents.json");
|
|
120
145
|
for (const contentsPath of catalogs) {
|
|
121
146
|
const name = catalogEntryName(contentsPath, ".imageset", readText);
|
|
122
147
|
if (name === null || seen.has(name)) continue;
|
|
@@ -137,12 +162,12 @@ function enumerateBundleImages(paths, readText) {
|
|
|
137
162
|
seen.add(name);
|
|
138
163
|
table.push({ name, file: `${dir}/${pick.filename}`, scale: pick.scale });
|
|
139
164
|
}
|
|
140
|
-
for (const
|
|
141
|
-
if (!isFlatResourceImage(
|
|
142
|
-
const name = baseOf(
|
|
165
|
+
for (const path6 of paths) {
|
|
166
|
+
if (!isFlatResourceImage(path6)) continue;
|
|
167
|
+
const name = baseOf(path6).slice(0, -extOf(path6).length);
|
|
143
168
|
if (name === "" || seen.has(name)) continue;
|
|
144
169
|
seen.add(name);
|
|
145
|
-
table.push({ name, file:
|
|
170
|
+
table.push({ name, file: path6, scale: flatScale(path6) });
|
|
146
171
|
}
|
|
147
172
|
return table;
|
|
148
173
|
}
|
|
@@ -171,7 +196,7 @@ function colorsetValue(color) {
|
|
|
171
196
|
}
|
|
172
197
|
function enumerateBundleColors(paths, readText) {
|
|
173
198
|
const table = {};
|
|
174
|
-
for (const contentsPath of paths.filter((
|
|
199
|
+
for (const contentsPath of paths.filter((path6) => baseOf(path6) === "Contents.json")) {
|
|
175
200
|
const name = catalogEntryName(contentsPath, ".colorset", readText);
|
|
176
201
|
if (name === null || name in table) continue;
|
|
177
202
|
let colors;
|
|
@@ -236,8 +261,8 @@ function axisExtremes(points) {
|
|
|
236
261
|
function pathBounds(d) {
|
|
237
262
|
const xs = [];
|
|
238
263
|
const ys = [];
|
|
239
|
-
for (const
|
|
240
|
-
(0, import_svgpath.default)(
|
|
264
|
+
for (const path6 of d)
|
|
265
|
+
(0, import_svgpath.default)(path6).abs().unshort().unarc().iterate((segment, _index, x, y) => {
|
|
241
266
|
const [command, ...args] = segment;
|
|
242
267
|
if (command === "M" || command === "L") {
|
|
243
268
|
xs.push(Number(args[0]));
|
|
@@ -264,7 +289,7 @@ function guide(svg, id, axis) {
|
|
|
264
289
|
}
|
|
265
290
|
function enumerateBundleSymbols(paths, readText) {
|
|
266
291
|
const table = {};
|
|
267
|
-
for (const contentsPath of paths.filter((
|
|
292
|
+
for (const contentsPath of paths.filter((path6) => baseOf(path6) === "Contents.json")) {
|
|
268
293
|
const name = catalogEntryName(contentsPath, ".symbolset", readText);
|
|
269
294
|
if (name === null || name in table) continue;
|
|
270
295
|
let symbols;
|
|
@@ -297,8 +322,8 @@ function enumerateBundleSymbols(paths, readText) {
|
|
|
297
322
|
viewBox: "0 0 24 24",
|
|
298
323
|
advance,
|
|
299
324
|
box: [12 - advance / 2, 12 - tall / 2, advance, tall],
|
|
300
|
-
layers: d.map((
|
|
301
|
-
d: (0, import_svgpath.default)(
|
|
325
|
+
layers: d.map((path6) => ({
|
|
326
|
+
d: (0, import_svgpath.default)(path6).abs().scale(scale).translate(translateX, translateY).round(3).toString()
|
|
302
327
|
}))
|
|
303
328
|
};
|
|
304
329
|
}
|
|
@@ -308,7 +333,7 @@ function enumerateBundleJson(paths) {
|
|
|
308
333
|
const found = [];
|
|
309
334
|
const seen = /* @__PURE__ */ new Set();
|
|
310
335
|
const ordered = [...paths].filter(
|
|
311
|
-
(
|
|
336
|
+
(path6) => path6.split("/").includes("Resources") && path6.split("/").every((segment) => segment !== "" && segment !== "..") && (extOf(path6) === ".json" || extOf(path6) === ".xcstrings")
|
|
312
337
|
).sort((a, b) => {
|
|
313
338
|
const aDepth = a.split("/").length;
|
|
314
339
|
const bDepth = b.split("/").length;
|
|
@@ -323,27 +348,6 @@ function enumerateBundleJson(paths) {
|
|
|
323
348
|
return found;
|
|
324
349
|
}
|
|
325
350
|
|
|
326
|
-
// ../sootsim-swift/src/entryModule.ts
|
|
327
|
-
function nativeExportLines(args, commonjs) {
|
|
328
|
-
const native = args.native;
|
|
329
|
-
if (!native) return [];
|
|
330
|
-
return Object.entries(native.modules).map(([name, methods]) => {
|
|
331
|
-
const calls = methods.map(
|
|
332
|
-
(method) => `${method}: (...args) => callSwiftModule(options, ${JSON.stringify(`${native.packageId}.${name}`)}, ${JSON.stringify(method)}, args, ${JSON.stringify(native.contractHash)})`
|
|
333
|
-
).join(", ");
|
|
334
|
-
return commonjs ? `module.exports.${name} = Object.freeze({ ${calls} })` : `export const ${name} = Object.freeze({ ${calls} })`;
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
function swiftEntryModuleEsm(args) {
|
|
338
|
-
return [
|
|
339
|
-
`import { createSwiftEntry, callSwiftModule } from 'peachsim/swift'`,
|
|
340
|
-
`const options = ${JSON.stringify({ url: args.url, hash: args.hash, icuUrl: args.icuUrl, rootId: args.rootId, resources: args.resources, bundleFiles: args.bundleFiles, colors: args.colors, symbols: args.symbols })}`,
|
|
341
|
-
...!args.native || args.native.defaultView ? ["export default createSwiftEntry(options)"] : [],
|
|
342
|
-
...nativeExportLines(args, false),
|
|
343
|
-
""
|
|
344
|
-
].join("\n");
|
|
345
|
-
}
|
|
346
|
-
|
|
347
351
|
// src/auth/shared-session.ts
|
|
348
352
|
var import_node_fs = require("node:fs");
|
|
349
353
|
var import_node_path2 = require("node:path");
|
|
@@ -817,7 +821,7 @@ var ONE_IMPLICIT_FLAGS = ', "-Xfrontend", "-import-module", "-Xfrontend", "One"'
|
|
|
817
821
|
var MULTI_MANIFEST_VERSION = 5;
|
|
818
822
|
function swiftArtifactHash(input, release, moduleRoot) {
|
|
819
823
|
const hash = (0, import_node_crypto2.createHash)("sha256");
|
|
820
|
-
hash.update(`swift-compile/
|
|
824
|
+
hash.update(`swift-compile/v3
|
|
821
825
|
${release}
|
|
822
826
|
`);
|
|
823
827
|
if (input.oneModule) hash.update("one-module\n");
|
|
@@ -917,13 +921,95 @@ function syncSwiftTree(base, files) {
|
|
|
917
921
|
(0, import_node_fs3.writeFileSync)(full, contents, "utf8");
|
|
918
922
|
}
|
|
919
923
|
}
|
|
920
|
-
var
|
|
924
|
+
var DIRECTIVE = /^[ \t]*#(?:if|elseif)\b/;
|
|
921
925
|
var OS_IOS = /\bos\(\s*iOS\s*\)/g;
|
|
922
926
|
function swiftSourceAsIOS(source) {
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
+
const code = swiftCodeLineStarts(source);
|
|
928
|
+
let offset = 0;
|
|
929
|
+
return source.split("\n").map((line) => {
|
|
930
|
+
const start = offset;
|
|
931
|
+
offset += line.length + 1;
|
|
932
|
+
if (!code.has(start) || !DIRECTIVE.test(line)) return line;
|
|
933
|
+
return line.replace(OS_IOS, (match) => "true".padEnd(match.length));
|
|
934
|
+
}).join("\n");
|
|
935
|
+
}
|
|
936
|
+
function swiftCodeLineStarts(source) {
|
|
937
|
+
const starts = /* @__PURE__ */ new Set();
|
|
938
|
+
const stack = [{ kind: "code", parens: 0 }];
|
|
939
|
+
const hashesAt = (at) => {
|
|
940
|
+
let end = at;
|
|
941
|
+
while (source[end] === "#") end++;
|
|
942
|
+
return end - at;
|
|
943
|
+
};
|
|
944
|
+
const closes = (at, hashes) => source.startsWith("#".repeat(hashes), at);
|
|
945
|
+
let i = 0;
|
|
946
|
+
while (i < source.length) {
|
|
947
|
+
const top = stack[stack.length - 1];
|
|
948
|
+
if ((i === 0 || source[i - 1] === "\n") && top.kind === "code" && stack.length === 1)
|
|
949
|
+
starts.add(i);
|
|
950
|
+
const char = source[i];
|
|
951
|
+
if (top.kind === "block") {
|
|
952
|
+
if (source.startsWith("/*", i)) {
|
|
953
|
+
top.depth++;
|
|
954
|
+
i += 2;
|
|
955
|
+
} else if (source.startsWith("*/", i)) {
|
|
956
|
+
if (--top.depth === 0) stack.pop();
|
|
957
|
+
i += 2;
|
|
958
|
+
} else i++;
|
|
959
|
+
continue;
|
|
960
|
+
}
|
|
961
|
+
if (top.kind === "string") {
|
|
962
|
+
if (char === "\\" && closes(i + 1, top.hashes)) {
|
|
963
|
+
const after = i + 1 + top.hashes;
|
|
964
|
+
if (source[after] === "(") {
|
|
965
|
+
stack.push({ kind: "code", parens: 0 });
|
|
966
|
+
i = after + 1;
|
|
967
|
+
} else i = after + 1;
|
|
968
|
+
continue;
|
|
969
|
+
}
|
|
970
|
+
const quote = top.multiline ? '"""' : '"';
|
|
971
|
+
if (source.startsWith(quote, i) && closes(i + quote.length, top.hashes)) {
|
|
972
|
+
stack.pop();
|
|
973
|
+
i += quote.length + top.hashes;
|
|
974
|
+
} else i++;
|
|
975
|
+
continue;
|
|
976
|
+
}
|
|
977
|
+
if (top.kind === "regex") {
|
|
978
|
+
if (char === "/" && closes(i + 1, top.hashes)) {
|
|
979
|
+
stack.pop();
|
|
980
|
+
i += 1 + top.hashes;
|
|
981
|
+
} else i++;
|
|
982
|
+
continue;
|
|
983
|
+
}
|
|
984
|
+
if (source.startsWith("//", i)) {
|
|
985
|
+
const end = source.indexOf("\n", i);
|
|
986
|
+
i = end === -1 ? source.length : end;
|
|
987
|
+
} else if (source.startsWith("/*", i)) {
|
|
988
|
+
stack.push({ kind: "block", depth: 1 });
|
|
989
|
+
i += 2;
|
|
990
|
+
} else if (char === '"' || char === "#") {
|
|
991
|
+
const hashes = hashesAt(i);
|
|
992
|
+
const at = i + hashes;
|
|
993
|
+
if (source.startsWith('"""', at)) {
|
|
994
|
+
stack.push({ kind: "string", hashes, multiline: true });
|
|
995
|
+
i = at + 3;
|
|
996
|
+
} else if (source[at] === '"') {
|
|
997
|
+
stack.push({ kind: "string", hashes, multiline: false });
|
|
998
|
+
i = at + 1;
|
|
999
|
+
} else if (hashes > 0 && source[at] === "/") {
|
|
1000
|
+
stack.push({ kind: "regex", hashes });
|
|
1001
|
+
i = at + 1;
|
|
1002
|
+
} else i = Math.max(at, i + 1);
|
|
1003
|
+
} else if (char === "(") {
|
|
1004
|
+
top.parens++;
|
|
1005
|
+
i++;
|
|
1006
|
+
} else if (char === ")") {
|
|
1007
|
+
if (top.parens === 0 && stack.length > 1) stack.pop();
|
|
1008
|
+
else top.parens--;
|
|
1009
|
+
i++;
|
|
1010
|
+
} else i++;
|
|
1011
|
+
}
|
|
1012
|
+
return starts;
|
|
927
1013
|
}
|
|
928
1014
|
var compiledSource = (file, contents) => file.endsWith(".swift") ? swiftSourceAsIOS(contents) : contents;
|
|
929
1015
|
function writeSwiftProject(layout, input, moduleRoot) {
|
|
@@ -1073,7 +1159,15 @@ function compileSwiftProjectUnit(input, options) {
|
|
|
1073
1159
|
|
|
1074
1160
|
// src/swift-submit.ts
|
|
1075
1161
|
var SWIFT_COMPILE_PATH = "/api/swift-compile";
|
|
1076
|
-
var
|
|
1162
|
+
var MAX_SWIFT_COMPILE_FILES = 256;
|
|
1163
|
+
var MAX_SWIFT_COMPILE_SOURCE_BYTES = 2 * 1024 * 1024;
|
|
1164
|
+
var MAX_SWIFT_COMPILE_RESOURCES = 128;
|
|
1165
|
+
var MAX_SWIFT_COMPILE_RESOURCE_BYTES = 2 * 1024 * 1024;
|
|
1166
|
+
var MAX_SWIFT_COMPILE_RESOURCE_TOTAL_BYTES = 8 * 1024 * 1024;
|
|
1167
|
+
var MAX_SWIFT_COMPILE_IMAGES = 128;
|
|
1168
|
+
var MAX_SWIFT_COMPILE_IMAGE_BYTES = 4 * 1024 * 1024;
|
|
1169
|
+
var MAX_SWIFT_COMPILE_IMAGE_TOTAL_BYTES = 16 * 1024 * 1024;
|
|
1170
|
+
var SWIFT_HOST_ABI = 2;
|
|
1077
1171
|
var POLL_INTERVAL_MS = 1500;
|
|
1078
1172
|
function swiftNativeEntry(native, file) {
|
|
1079
1173
|
return {
|
|
@@ -1094,6 +1188,7 @@ function httpSwiftCompileSubmit(context) {
|
|
|
1094
1188
|
try {
|
|
1095
1189
|
response = await fetch(url, {
|
|
1096
1190
|
method: "POST",
|
|
1191
|
+
signal: context.signal,
|
|
1097
1192
|
headers: {
|
|
1098
1193
|
"content-type": "application/json",
|
|
1099
1194
|
...authorization ? { authorization } : {}
|
|
@@ -1116,30 +1211,78 @@ function httpSwiftCompileSubmit(context) {
|
|
|
1116
1211
|
`contrast-bundler: the swift compile for ${work.entry} answered ${response.status}${detail ? `: ${detail}` : ""}`
|
|
1117
1212
|
);
|
|
1118
1213
|
}
|
|
1119
|
-
|
|
1214
|
+
const outcome = await response.json();
|
|
1215
|
+
if (!isSwiftCompileOutcome(outcome)) {
|
|
1216
|
+
throw new Error("swift compile: the service returned invalid artifact metadata");
|
|
1217
|
+
}
|
|
1218
|
+
return outcome;
|
|
1120
1219
|
};
|
|
1121
1220
|
}
|
|
1221
|
+
function isRecord(value) {
|
|
1222
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1223
|
+
}
|
|
1224
|
+
function isSwiftNativeModules(value) {
|
|
1225
|
+
return isRecord(value) && typeof value.packageId === "string" && typeof value.hash === "string" && isRecord(value.files) && isRecord(value.modules) && [...Object.values(value.files), ...Object.values(value.modules)].every(
|
|
1226
|
+
(names) => Array.isArray(names) && names.every((name) => typeof name === "string")
|
|
1227
|
+
) && Array.isArray(value.defaultViewFiles) && value.defaultViewFiles.every((file) => typeof file === "string");
|
|
1228
|
+
}
|
|
1229
|
+
function isSwiftCompileOutcome(value) {
|
|
1230
|
+
if (!isRecord(value)) return false;
|
|
1231
|
+
switch (value.status) {
|
|
1232
|
+
case "published":
|
|
1233
|
+
return typeof value.artifactUrl === "string" && typeof value.icuUrl === "string" && typeof value.hash === "string" && /^[a-f0-9]{64}$/.test(value.hash) && (value.imageUrls === void 0 || isRecord(value.imageUrls) && Object.values(value.imageUrls).every((url) => typeof url === "string")) && (value.native === void 0 || isSwiftNativeModules(value.native));
|
|
1234
|
+
case "compiling":
|
|
1235
|
+
return typeof value.hash === "string" && /^[a-f0-9]{64}$/.test(value.hash);
|
|
1236
|
+
case "refused":
|
|
1237
|
+
case "failed":
|
|
1238
|
+
return typeof value.detail === "string";
|
|
1239
|
+
default:
|
|
1240
|
+
return false;
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
function compileAssetUrl(value, origin) {
|
|
1244
|
+
const url = new URL(value, origin);
|
|
1245
|
+
if (url.protocol !== "http:" && url.protocol !== "https:" || url.username || url.password || url.origin !== new URL(origin).origin) {
|
|
1246
|
+
throw new Error("swift compile: artifact address escapes the compile origin");
|
|
1247
|
+
}
|
|
1248
|
+
return url.href;
|
|
1249
|
+
}
|
|
1122
1250
|
function resolveImageUrls(urls, origin) {
|
|
1123
1251
|
const resolved = {};
|
|
1124
1252
|
for (const [name, url] of Object.entries(urls)) {
|
|
1125
|
-
resolved[name] =
|
|
1253
|
+
resolved[name] = compileAssetUrl(url, origin);
|
|
1126
1254
|
}
|
|
1127
1255
|
return resolved;
|
|
1128
1256
|
}
|
|
1129
|
-
async function compileSwiftProject(submit, work, origin) {
|
|
1257
|
+
async function compileSwiftProject(submit, work, origin, signal) {
|
|
1130
1258
|
while (true) {
|
|
1259
|
+
signal?.throwIfAborted();
|
|
1131
1260
|
const outcome = await submit(work);
|
|
1132
1261
|
switch (outcome.status) {
|
|
1133
1262
|
case "published":
|
|
1134
1263
|
return {
|
|
1135
|
-
url:
|
|
1264
|
+
url: compileAssetUrl(outcome.artifactUrl, origin),
|
|
1136
1265
|
hash: outcome.hash,
|
|
1137
|
-
icuUrl:
|
|
1266
|
+
icuUrl: compileAssetUrl(outcome.icuUrl, origin),
|
|
1138
1267
|
...outcome.imageUrls === void 0 ? {} : { imageUrls: resolveImageUrls(outcome.imageUrls, origin) },
|
|
1139
1268
|
...outcome.native === void 0 ? {} : { native: outcome.native }
|
|
1140
1269
|
};
|
|
1141
1270
|
case "compiling":
|
|
1142
|
-
await new Promise((resolve2) =>
|
|
1271
|
+
await new Promise((resolve2, reject) => {
|
|
1272
|
+
const finish = () => {
|
|
1273
|
+
signal?.removeEventListener("abort", abort);
|
|
1274
|
+
resolve2();
|
|
1275
|
+
};
|
|
1276
|
+
const timer = setTimeout(finish, POLL_INTERVAL_MS);
|
|
1277
|
+
const abort = () => {
|
|
1278
|
+
clearTimeout(timer);
|
|
1279
|
+
signal?.removeEventListener("abort", abort);
|
|
1280
|
+
const reason = signal?.reason;
|
|
1281
|
+
reject(reason instanceof Error ? reason : new Error(String(reason)));
|
|
1282
|
+
};
|
|
1283
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
1284
|
+
if (signal?.aborted) abort();
|
|
1285
|
+
});
|
|
1143
1286
|
continue;
|
|
1144
1287
|
case "refused":
|
|
1145
1288
|
case "failed":
|
|
@@ -1150,11 +1293,10 @@ async function compileSwiftProject(submit, work, origin) {
|
|
|
1150
1293
|
}
|
|
1151
1294
|
}
|
|
1152
1295
|
|
|
1153
|
-
// src/
|
|
1296
|
+
// src/swift-host.ts
|
|
1154
1297
|
var ARTIFACT_PATH = "/__peach/swift/";
|
|
1155
1298
|
var RESOURCE_PATH = "/__peach/swift-res/";
|
|
1156
1299
|
var ICU_PATH = "/__peach/swift-icu/";
|
|
1157
|
-
var VIRTUAL_PREFIX = "\0peach-swift:";
|
|
1158
1300
|
var SKIP_SOURCE_DIRS = /* @__PURE__ */ new Set([
|
|
1159
1301
|
"node_modules",
|
|
1160
1302
|
"ios",
|
|
@@ -1169,89 +1311,124 @@ function swiftPackageId(packagePath) {
|
|
|
1169
1311
|
return import_node_path5.default.basename(packagePath).replace(/[^A-Za-z0-9_]/g, "_").replace(/^(\d)/, "_$1");
|
|
1170
1312
|
}
|
|
1171
1313
|
function nativeSourceDescriptor(packagePath) {
|
|
1314
|
+
packagePath = import_node_fs4.default.realpathSync(packagePath);
|
|
1172
1315
|
const file = import_node_path5.default.join(packagePath, NATIVE_DESCRIPTOR);
|
|
1173
1316
|
if (!import_node_fs4.default.existsSync(file)) return null;
|
|
1174
|
-
const value = JSON.parse(
|
|
1317
|
+
const value = JSON.parse(
|
|
1318
|
+
readPackageFile(packagePath, file, MAX_SWIFT_COMPILE_SOURCE_BYTES).toString("utf8")
|
|
1319
|
+
);
|
|
1175
1320
|
const invalid = () => new Error(`${file}: invalid One native source descriptor; run one typegen`);
|
|
1176
1321
|
if (!value || typeof value !== "object" || Reflect.get(value, "generatedBy") !== "one typegen" || !import_node_fs4.default.existsSync(import_node_path5.default.join(packagePath, NATIVE_GLUE))) {
|
|
1177
1322
|
throw invalid();
|
|
1178
1323
|
}
|
|
1179
|
-
|
|
1180
|
-
const hash = Reflect.get(value, "hash");
|
|
1181
|
-
const rawFiles = Reflect.get(value, "files");
|
|
1182
|
-
const rawModules = Reflect.get(value, "modules");
|
|
1183
|
-
const rawDefaults = Reflect.get(value, "defaultViewFiles");
|
|
1184
|
-
if (typeof packageId !== "string" || typeof hash !== "string" || !rawFiles || typeof rawFiles !== "object" || !rawModules || typeof rawModules !== "object" || !Array.isArray(rawDefaults) || !rawDefaults.every((name) => typeof name === "string")) {
|
|
1324
|
+
if (!isSwiftNativeModules(value) || value.packageId !== swiftPackageId(packagePath)) {
|
|
1185
1325
|
throw invalid();
|
|
1186
1326
|
}
|
|
1187
|
-
|
|
1188
|
-
const modules = {};
|
|
1189
|
-
for (const [key, names] of Object.entries(rawFiles)) {
|
|
1190
|
-
if (!Array.isArray(names) || !names.every((name) => typeof name === "string"))
|
|
1191
|
-
throw invalid();
|
|
1192
|
-
files[key] = names;
|
|
1193
|
-
}
|
|
1194
|
-
for (const [key, names] of Object.entries(rawModules)) {
|
|
1195
|
-
if (!Array.isArray(names) || !names.every((name) => typeof name === "string"))
|
|
1196
|
-
throw invalid();
|
|
1197
|
-
modules[key] = names;
|
|
1198
|
-
}
|
|
1199
|
-
if (packageId !== swiftPackageId(packagePath)) {
|
|
1200
|
-
throw new Error(`${file}: invalid One native source descriptor; run one typegen`);
|
|
1201
|
-
}
|
|
1202
|
-
return { packageId, hash, files, modules, defaultViewFiles: rawDefaults };
|
|
1327
|
+
return value;
|
|
1203
1328
|
}
|
|
1204
1329
|
function nativeSourceFiles(packagePath) {
|
|
1330
|
+
packagePath = import_node_fs4.default.realpathSync(packagePath);
|
|
1205
1331
|
return [NATIVE_DESCRIPTOR, NATIVE_GLUE].map((name) => import_node_path5.default.join(packagePath, name)).filter((file) => import_node_fs4.default.existsSync(file));
|
|
1206
1332
|
}
|
|
1207
1333
|
var projects = /* @__PURE__ */ new Map();
|
|
1208
|
-
|
|
1209
|
-
|
|
1334
|
+
function projectFor(packagePath, hosted) {
|
|
1335
|
+
packagePath = import_node_fs4.default.realpathSync(packagePath);
|
|
1210
1336
|
const existing = projects.get(packagePath);
|
|
1211
|
-
if (existing)
|
|
1337
|
+
if (existing) {
|
|
1338
|
+
if (hosted && !existing.hosted) {
|
|
1339
|
+
throw new Error("a Swift package cannot share local and hosted compile ownership");
|
|
1340
|
+
}
|
|
1341
|
+
return existing;
|
|
1342
|
+
}
|
|
1212
1343
|
const created = {
|
|
1213
1344
|
packagePath,
|
|
1214
1345
|
artifact: null,
|
|
1215
1346
|
building: null,
|
|
1216
|
-
resourceFiles: /* @__PURE__ */ new Map()
|
|
1347
|
+
resourceFiles: /* @__PURE__ */ new Map(),
|
|
1348
|
+
resourcesPrevious: /* @__PURE__ */ new Map(),
|
|
1349
|
+
artifacts: [],
|
|
1350
|
+
hosted
|
|
1217
1351
|
};
|
|
1218
1352
|
projects.set(packagePath, created);
|
|
1219
1353
|
return created;
|
|
1220
1354
|
}
|
|
1221
|
-
function
|
|
1222
|
-
const
|
|
1223
|
-
const walk = (dir) => {
|
|
1224
|
-
for (const entry of import_node_fs4.default.readdirSync(dir, { withFileTypes: true })) {
|
|
1225
|
-
if (entry.name.startsWith(".") || SKIP_SOURCE_DIRS.has(entry.name)) continue;
|
|
1226
|
-
const full = import_node_path5.default.join(dir, entry.name);
|
|
1227
|
-
if (entry.isDirectory()) {
|
|
1228
|
-
if (full !== root && import_node_fs4.default.existsSync(import_node_path5.default.join(full, "Package.swift"))) continue;
|
|
1229
|
-
walk(full);
|
|
1230
|
-
} else if (entry.name.endsWith(".swift") && (entry.isFile() || entry.isSymbolicLink() && import_node_fs4.default.statSync(full).isFile()))
|
|
1231
|
-
found.push(full);
|
|
1232
|
-
}
|
|
1233
|
-
};
|
|
1234
|
-
walk(root);
|
|
1235
|
-
return found;
|
|
1236
|
-
}
|
|
1237
|
-
function resourceCandidateFiles(root) {
|
|
1355
|
+
function packageFiles(root) {
|
|
1356
|
+
const canonicalRoot = import_node_fs4.default.realpathSync(root);
|
|
1238
1357
|
const found = [];
|
|
1239
1358
|
const walk = (dir) => {
|
|
1240
|
-
for (const entry of import_node_fs4.default.readdirSync(dir, { withFileTypes: true })) {
|
|
1241
|
-
if (entry.name.startsWith(".")
|
|
1359
|
+
for (const entry of import_node_fs4.default.readdirSync(dir, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name))) {
|
|
1360
|
+
if (entry.name.startsWith(".") && entry.name !== NATIVE_DESCRIPTOR && entry.name !== NATIVE_GLUE || SKIP_SOURCE_DIRS.has(entry.name))
|
|
1242
1361
|
continue;
|
|
1243
1362
|
const full = import_node_path5.default.join(dir, entry.name);
|
|
1363
|
+
if (entry.isSymbolicLink()) throw new Error(`swift input is a symlink: ${full}`);
|
|
1364
|
+
const real = import_node_fs4.default.realpathSync(full);
|
|
1365
|
+
const relative = import_node_path5.default.relative(canonicalRoot, real);
|
|
1366
|
+
if (relative.startsWith(`..${import_node_path5.default.sep}`) || relative === ".." || import_node_path5.default.isAbsolute(relative)) {
|
|
1367
|
+
throw new Error(`swift input escapes the selected package: ${full}`);
|
|
1368
|
+
}
|
|
1244
1369
|
if (entry.isDirectory()) {
|
|
1245
|
-
if (
|
|
1370
|
+
if (import_node_fs4.default.existsSync(import_node_path5.default.join(full, "Package.swift"))) continue;
|
|
1246
1371
|
walk(full);
|
|
1247
|
-
} else {
|
|
1372
|
+
} else if (entry.isFile()) {
|
|
1248
1373
|
found.push(full);
|
|
1374
|
+
if (found.length > 4096) throw new Error("swift package exceeds 4096 input files");
|
|
1249
1375
|
}
|
|
1250
1376
|
}
|
|
1251
1377
|
};
|
|
1252
|
-
walk(
|
|
1378
|
+
walk(canonicalRoot);
|
|
1253
1379
|
return found;
|
|
1254
1380
|
}
|
|
1381
|
+
function readPackageFile(root, file, maxBytes) {
|
|
1382
|
+
const canonicalRoot = import_node_fs4.default.realpathSync(root);
|
|
1383
|
+
const relative = import_node_path5.default.relative(canonicalRoot, import_node_fs4.default.realpathSync(file));
|
|
1384
|
+
if (relative === ".." || relative.startsWith(`..${import_node_path5.default.sep}`) || import_node_path5.default.isAbsolute(relative)) {
|
|
1385
|
+
throw new Error(`swift input escapes the selected package: ${file}`);
|
|
1386
|
+
}
|
|
1387
|
+
let ancestor = import_node_path5.default.resolve(file);
|
|
1388
|
+
while (ancestor !== canonicalRoot) {
|
|
1389
|
+
if (import_node_fs4.default.lstatSync(ancestor).isSymbolicLink()) {
|
|
1390
|
+
throw new Error(`swift input is a symlink: ${ancestor}`);
|
|
1391
|
+
}
|
|
1392
|
+
const parent = import_node_path5.default.dirname(ancestor);
|
|
1393
|
+
if (parent === ancestor)
|
|
1394
|
+
throw new Error(`swift input escapes the selected package: ${file}`);
|
|
1395
|
+
ancestor = parent;
|
|
1396
|
+
}
|
|
1397
|
+
const expected = import_node_fs4.default.statSync(file);
|
|
1398
|
+
const fd = import_node_fs4.default.openSync(file, import_node_fs4.default.constants.O_RDONLY | import_node_fs4.default.constants.O_NOFOLLOW);
|
|
1399
|
+
try {
|
|
1400
|
+
const stat = import_node_fs4.default.fstatSync(fd);
|
|
1401
|
+
if (stat.dev !== expected.dev || stat.ino !== expected.ino) {
|
|
1402
|
+
throw new Error(`swift input changed while opening: ${file}`);
|
|
1403
|
+
}
|
|
1404
|
+
if (!stat.isFile() || stat.size > maxBytes) {
|
|
1405
|
+
throw new Error(`swift input exceeds ${maxBytes} bytes: ${file}`);
|
|
1406
|
+
}
|
|
1407
|
+
const bytes = Buffer.alloc(stat.size + 1);
|
|
1408
|
+
let offset = 0;
|
|
1409
|
+
while (offset < bytes.length) {
|
|
1410
|
+
const count = import_node_fs4.default.readSync(fd, bytes, offset, bytes.length - offset, null);
|
|
1411
|
+
if (count === 0) break;
|
|
1412
|
+
offset += count;
|
|
1413
|
+
}
|
|
1414
|
+
if (offset !== stat.size || import_node_fs4.default.fstatSync(fd).size !== stat.size) {
|
|
1415
|
+
throw new Error(`swift input changed while reading: ${file}`);
|
|
1416
|
+
}
|
|
1417
|
+
return bytes.subarray(0, offset);
|
|
1418
|
+
} finally {
|
|
1419
|
+
import_node_fs4.default.closeSync(fd);
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
function sourceFiles(root) {
|
|
1423
|
+
const files = packageFiles(root).filter((file) => file.endsWith(".swift"));
|
|
1424
|
+
if (files.length > MAX_SWIFT_COMPILE_FILES || files.reduce((total, file) => total + import_node_fs4.default.statSync(file).size, 0) > MAX_SWIFT_COMPILE_SOURCE_BYTES) {
|
|
1425
|
+
throw new Error("swift sources exceed the compile service caps");
|
|
1426
|
+
}
|
|
1427
|
+
return files;
|
|
1428
|
+
}
|
|
1429
|
+
function resourceCandidateFiles(root) {
|
|
1430
|
+
return packageFiles(root).filter((file) => !file.endsWith(".swift"));
|
|
1431
|
+
}
|
|
1255
1432
|
var RESOURCE_CONTENT_TYPES = {
|
|
1256
1433
|
".avif": "image/avif",
|
|
1257
1434
|
".bmp": "image/bmp",
|
|
@@ -1272,11 +1449,11 @@ function buildSwiftResourceTable(project, baseUrl) {
|
|
|
1272
1449
|
const file = byRelative.get(candidate);
|
|
1273
1450
|
if (!file || !/(^|\/)Contents\.json$|\.symbolset\/[^/]+\.svg$/.test(candidate))
|
|
1274
1451
|
return null;
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1452
|
+
return readPackageFile(
|
|
1453
|
+
project.packagePath,
|
|
1454
|
+
file,
|
|
1455
|
+
MAX_SWIFT_COMPILE_RESOURCE_BYTES
|
|
1456
|
+
).toString("utf8");
|
|
1280
1457
|
};
|
|
1281
1458
|
const found = enumerateBundleImages(relative, readContents);
|
|
1282
1459
|
const colors = enumerateBundleColors(relative, readContents);
|
|
@@ -1285,15 +1462,19 @@ function buildSwiftResourceTable(project, baseUrl) {
|
|
|
1285
1462
|
const images = {};
|
|
1286
1463
|
const watched = [];
|
|
1287
1464
|
const registered = /* @__PURE__ */ new Map();
|
|
1465
|
+
let imageBytes = 0;
|
|
1288
1466
|
for (const { name, file, scale } of found) {
|
|
1289
1467
|
const disk = byRelative.get(file);
|
|
1290
1468
|
if (!disk) continue;
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
bytes = import_node_fs4.default.readFileSync(disk);
|
|
1294
|
-
} catch {
|
|
1295
|
-
continue;
|
|
1469
|
+
if (Object.keys(images).length >= MAX_SWIFT_COMPILE_IMAGES || imageBytes + import_node_fs4.default.statSync(disk).size > MAX_SWIFT_COMPILE_IMAGE_TOTAL_BYTES) {
|
|
1470
|
+
throw new Error("swift image pack exceeds the compile service caps");
|
|
1296
1471
|
}
|
|
1472
|
+
const bytes = readPackageFile(
|
|
1473
|
+
project.packagePath,
|
|
1474
|
+
disk,
|
|
1475
|
+
MAX_SWIFT_COMPILE_IMAGE_BYTES
|
|
1476
|
+
);
|
|
1477
|
+
imageBytes += bytes.length;
|
|
1297
1478
|
const hash = (0, import_node_crypto3.createHash)("sha256").update(bytes).digest("hex").slice(0, 16);
|
|
1298
1479
|
const ext = import_node_path5.default.posix.extname(file).toLowerCase();
|
|
1299
1480
|
table[name] = { uri: `${baseUrl}${RESOURCE_PATH}${hash}${ext}`, scale };
|
|
@@ -1304,65 +1485,60 @@ function buildSwiftResourceTable(project, baseUrl) {
|
|
|
1304
1485
|
watched.push(file);
|
|
1305
1486
|
const contents = file.replace(/\/[^/]+$/, "/Contents.json");
|
|
1306
1487
|
if (byRelative.has(contents)) watched.push(contents);
|
|
1307
|
-
registered.set(`${hash}${ext}`,
|
|
1488
|
+
registered.set(`${hash}${ext}`, {
|
|
1489
|
+
bytes,
|
|
1490
|
+
contentType: RESOURCE_CONTENT_TYPES[ext] ?? "application/octet-stream"
|
|
1491
|
+
});
|
|
1308
1492
|
}
|
|
1309
1493
|
for (const file of relative) {
|
|
1310
1494
|
if (file.endsWith(".colorset/Contents.json") || file.includes(".symbolset/"))
|
|
1311
1495
|
watched.push(file);
|
|
1312
1496
|
}
|
|
1313
|
-
project.resourceFiles
|
|
1497
|
+
if (registered.size !== project.resourceFiles.size || [...registered].some(
|
|
1498
|
+
([key, value]) => !project.resourceFiles.get(key)?.bytes.equals(value.bytes)
|
|
1499
|
+
)) {
|
|
1500
|
+
project.resourcesPrevious = project.resourceFiles;
|
|
1501
|
+
project.resourceFiles = registered;
|
|
1502
|
+
}
|
|
1314
1503
|
return { table, images, colors, symbols, watched };
|
|
1315
1504
|
}
|
|
1316
|
-
var BUNDLE_MAX_FILES =
|
|
1317
|
-
var BUNDLE_MAX_FILE_BYTES =
|
|
1318
|
-
var BUNDLE_MAX_TOTAL_BYTES =
|
|
1505
|
+
var BUNDLE_MAX_FILES = MAX_SWIFT_COMPILE_RESOURCES;
|
|
1506
|
+
var BUNDLE_MAX_FILE_BYTES = MAX_SWIFT_COMPILE_RESOURCE_BYTES;
|
|
1507
|
+
var BUNDLE_MAX_TOTAL_BYTES = MAX_SWIFT_COMPILE_RESOURCE_TOTAL_BYTES;
|
|
1319
1508
|
function buildSwiftBundleFiles(packagePath) {
|
|
1509
|
+
packagePath = import_node_fs4.default.realpathSync(packagePath);
|
|
1320
1510
|
const relative = resourceCandidateFiles(packagePath).map(
|
|
1321
1511
|
(file) => import_node_path5.default.relative(packagePath, file).split(import_node_path5.default.sep).join(import_node_path5.default.posix.sep)
|
|
1322
1512
|
);
|
|
1323
1513
|
const files = {};
|
|
1324
1514
|
const watched = [];
|
|
1325
|
-
const skipped = [];
|
|
1326
1515
|
let total = 0;
|
|
1327
1516
|
for (const { base, file } of enumerateBundleJson(relative)) {
|
|
1328
1517
|
watched.push(file);
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
continue;
|
|
1334
|
-
}
|
|
1335
|
-
if (bytes.length > BUNDLE_MAX_FILE_BYTES) {
|
|
1336
|
-
skipped.push(`${file} (${bytes.length} bytes past the per-file cap)`);
|
|
1337
|
-
continue;
|
|
1338
|
-
}
|
|
1339
|
-
if (Object.keys(files).length >= BUNDLE_MAX_FILES || total + bytes.length > BUNDLE_MAX_TOTAL_BYTES) {
|
|
1340
|
-
skipped.push(
|
|
1341
|
-
`${file} (pack caps: ${BUNDLE_MAX_FILES} files / ${BUNDLE_MAX_TOTAL_BYTES} bytes)`
|
|
1518
|
+
const disk = import_node_path5.default.join(packagePath, ...file.split("/"));
|
|
1519
|
+
if (Object.keys(files).length >= BUNDLE_MAX_FILES || total + import_node_fs4.default.statSync(disk).size > BUNDLE_MAX_TOTAL_BYTES) {
|
|
1520
|
+
throw new Error(
|
|
1521
|
+
`swift bundle pack exceeds ${BUNDLE_MAX_FILES} files / ${BUNDLE_MAX_TOTAL_BYTES} bytes`
|
|
1342
1522
|
);
|
|
1343
|
-
continue;
|
|
1344
1523
|
}
|
|
1524
|
+
const bytes = readPackageFile(packagePath, disk, BUNDLE_MAX_FILE_BYTES);
|
|
1345
1525
|
files[base] = bytes.toString("base64");
|
|
1346
1526
|
total += bytes.length;
|
|
1347
1527
|
}
|
|
1348
|
-
return { files, watched
|
|
1528
|
+
return { files, watched };
|
|
1349
1529
|
}
|
|
1350
1530
|
function serveSwiftResource(project, key) {
|
|
1351
|
-
|
|
1352
|
-
if (!disk) return null;
|
|
1353
|
-
try {
|
|
1354
|
-
return {
|
|
1355
|
-
bytes: import_node_fs4.default.readFileSync(disk),
|
|
1356
|
-
contentType: RESOURCE_CONTENT_TYPES[import_node_path5.default.extname(disk).toLowerCase()] ?? "application/octet-stream"
|
|
1357
|
-
};
|
|
1358
|
-
} catch {
|
|
1359
|
-
return null;
|
|
1360
|
-
}
|
|
1531
|
+
return project.resourceFiles.get(key) ?? project.resourcesPrevious.get(key) ?? null;
|
|
1361
1532
|
}
|
|
1362
1533
|
function linkedModuleRoots(packagePath) {
|
|
1534
|
+
packagePath = import_node_fs4.default.realpathSync(packagePath);
|
|
1363
1535
|
let manifest;
|
|
1364
1536
|
try {
|
|
1365
|
-
manifest =
|
|
1537
|
+
manifest = readPackageFile(
|
|
1538
|
+
packagePath,
|
|
1539
|
+
import_node_path5.default.join(packagePath, "Package.swift"),
|
|
1540
|
+
MAX_SWIFT_COMPILE_SOURCE_BYTES
|
|
1541
|
+
).toString("utf8");
|
|
1366
1542
|
} catch {
|
|
1367
1543
|
return [];
|
|
1368
1544
|
}
|
|
@@ -1374,25 +1550,16 @@ function linkedModuleRoots(packagePath) {
|
|
|
1374
1550
|
}
|
|
1375
1551
|
return [...roots].sort();
|
|
1376
1552
|
}
|
|
1377
|
-
function sourceStamp(packagePath, moduleRootOverride) {
|
|
1553
|
+
function sourceStamp(packagePath, moduleRootOverride, hosted = false) {
|
|
1378
1554
|
const hash = (0, import_node_crypto3.createHash)("sha256");
|
|
1379
1555
|
hash.update(packagePath);
|
|
1380
|
-
const projectInputs =
|
|
1381
|
-
import_node_path5.default.join(packagePath, "Package.swift"),
|
|
1382
|
-
...sourceFiles(packagePath),
|
|
1383
|
-
...nativeSourceFiles(packagePath),
|
|
1384
|
-
...buildSwiftBundleFiles(packagePath).watched.map(
|
|
1385
|
-
(file) => import_node_path5.default.join(packagePath, ...file.split(import_node_path5.default.posix.sep))
|
|
1386
|
-
),
|
|
1387
|
-
...buildSwiftResourceTable(projectFor(packagePath), "").watched.map(
|
|
1388
|
-
(file) => import_node_path5.default.join(packagePath, ...file.split(import_node_path5.default.posix.sep))
|
|
1389
|
-
)
|
|
1390
|
-
]);
|
|
1556
|
+
const projectInputs = new Set(packageFiles(packagePath));
|
|
1391
1557
|
for (const file of [...projectInputs].sort()) {
|
|
1392
1558
|
hash.update(import_node_path5.default.relative(packagePath, file));
|
|
1393
|
-
|
|
1559
|
+
const stat = import_node_fs4.default.statSync(file);
|
|
1560
|
+
hash.update(`${stat.mtimeMs}/${stat.ctimeMs}/${stat.size}`);
|
|
1394
1561
|
}
|
|
1395
|
-
const moduleRoot = moduleRootOverride ?? linkedModuleRoots(packagePath).find(
|
|
1562
|
+
const moduleRoot = hosted ? void 0 : moduleRootOverride ?? linkedModuleRoots(packagePath).find(
|
|
1396
1563
|
(root) => import_node_fs4.default.existsSync(import_node_path5.default.join(root, "toolchain.json"))
|
|
1397
1564
|
);
|
|
1398
1565
|
if (moduleRoot) {
|
|
@@ -1408,46 +1575,85 @@ function entryRootId(packagePath, file) {
|
|
|
1408
1575
|
const relative = import_node_path5.default.relative(packagePath, file).split(import_node_path5.default.sep).join(import_node_path5.default.posix.sep);
|
|
1409
1576
|
return `${import_node_path5.default.basename(packagePath)}${import_node_path5.default.posix.sep}${relative}`;
|
|
1410
1577
|
}
|
|
1411
|
-
function serverOrigin() {
|
|
1412
|
-
const address = devServer?.httpServer?.address();
|
|
1413
|
-
const port = address && typeof address === "object" ? address.port : devServer?.config.server.port;
|
|
1414
|
-
if (!port) throw new Error("the swift urls need the dev server port");
|
|
1415
|
-
return `http://localhost:${port}`;
|
|
1416
|
-
}
|
|
1417
|
-
function artifactUrl(project, artifact) {
|
|
1418
|
-
return `${serverOrigin()}${ARTIFACT_PATH}${artifact.hash}.wasm`;
|
|
1419
|
-
}
|
|
1420
1578
|
function icuUrl(origin, artifact) {
|
|
1421
1579
|
return "url" in artifact.icu ? artifact.icu.url : `${origin}${ICU_PATH}${artifact.icu.sha256}`;
|
|
1422
1580
|
}
|
|
1423
1581
|
function packageSources(packagePath) {
|
|
1582
|
+
const sources = sourceFiles(packagePath);
|
|
1583
|
+
if (sources.length > MAX_SWIFT_COMPILE_FILES)
|
|
1584
|
+
throw new Error("swift source file cap exceeded");
|
|
1585
|
+
let total = 0;
|
|
1586
|
+
for (const file of sources) total += import_node_fs4.default.statSync(file).size;
|
|
1587
|
+
if (total > MAX_SWIFT_COMPILE_SOURCE_BYTES)
|
|
1588
|
+
throw new Error("swift source byte cap exceeded");
|
|
1424
1589
|
const files = {};
|
|
1425
|
-
for (const file of
|
|
1590
|
+
for (const file of sources) {
|
|
1426
1591
|
const relative = import_node_path5.default.relative(packagePath, file).split(import_node_path5.default.sep).join(import_node_path5.default.posix.sep);
|
|
1427
|
-
files[relative] =
|
|
1592
|
+
files[relative] = readPackageFile(
|
|
1593
|
+
packagePath,
|
|
1594
|
+
file,
|
|
1595
|
+
MAX_SWIFT_COMPILE_SOURCE_BYTES
|
|
1596
|
+
).toString("utf8");
|
|
1428
1597
|
}
|
|
1429
|
-
const manifest = import_node_path5.default.join(packagePath, "Package.swift");
|
|
1430
|
-
if (import_node_fs4.default.existsSync(manifest)) files["Package.swift"] = import_node_fs4.default.readFileSync(manifest, "utf8");
|
|
1431
1598
|
return files;
|
|
1432
1599
|
}
|
|
1433
|
-
function
|
|
1600
|
+
function packageSnapshot(project) {
|
|
1601
|
+
const files = packageSources(project.packagePath);
|
|
1602
|
+
const native = nativeSourceDescriptor(project.packagePath);
|
|
1603
|
+
return {
|
|
1604
|
+
files,
|
|
1605
|
+
resources: buildSwiftResourceTable(project, ""),
|
|
1606
|
+
bundleFiles: buildSwiftBundleFiles(project.packagePath),
|
|
1607
|
+
native,
|
|
1608
|
+
...native ? {
|
|
1609
|
+
glue: readPackageFile(
|
|
1610
|
+
project.packagePath,
|
|
1611
|
+
import_node_path5.default.join(project.packagePath, NATIVE_GLUE),
|
|
1612
|
+
MAX_SWIFT_COMPILE_SOURCE_BYTES
|
|
1613
|
+
).toString("utf8")
|
|
1614
|
+
} : {}
|
|
1615
|
+
};
|
|
1616
|
+
}
|
|
1617
|
+
function snapshotCompileInput(snapshot, entry) {
|
|
1434
1618
|
const input = {
|
|
1435
|
-
files:
|
|
1436
|
-
resources:
|
|
1437
|
-
images:
|
|
1619
|
+
files: snapshot.files,
|
|
1620
|
+
resources: snapshot.bundleFiles.files,
|
|
1621
|
+
images: snapshot.resources.images,
|
|
1438
1622
|
entry,
|
|
1439
1623
|
oneModule: true
|
|
1440
1624
|
};
|
|
1441
|
-
return
|
|
1442
|
-
input,
|
|
1443
|
-
import_node_fs4.default.readFileSync(import_node_path5.default.join(packagePath, NATIVE_GLUE), "utf8")
|
|
1444
|
-
) : input;
|
|
1625
|
+
return snapshot.glue ? withNativeSourceGlue(input, snapshot.glue) : input;
|
|
1445
1626
|
}
|
|
1446
|
-
|
|
1627
|
+
function compileInput(packagePath, entry) {
|
|
1628
|
+
return snapshotCompileInput(packageSnapshot(projectFor(packagePath)), entry);
|
|
1629
|
+
}
|
|
1630
|
+
async function compile(packagePath, entry, stamp, moduleRootOverride, hosted, snapshot) {
|
|
1631
|
+
const resources = {
|
|
1632
|
+
table: snapshot.resources.table,
|
|
1633
|
+
colors: snapshot.resources.colors,
|
|
1634
|
+
symbols: snapshot.resources.symbols,
|
|
1635
|
+
watched: snapshot.resources.watched
|
|
1636
|
+
};
|
|
1637
|
+
const content = {
|
|
1638
|
+
resources,
|
|
1639
|
+
bundleFiles: snapshot.bundleFiles,
|
|
1640
|
+
native: snapshot.native
|
|
1641
|
+
};
|
|
1642
|
+
if (hosted)
|
|
1643
|
+
return {
|
|
1644
|
+
...await compileRemote(packagePath, entry, snapshot, hosted),
|
|
1645
|
+
stamp,
|
|
1646
|
+
package: content
|
|
1647
|
+
};
|
|
1447
1648
|
const moduleRoot = moduleRootOverride ?? linkedModuleRoots(packagePath).find(
|
|
1448
1649
|
(root) => import_node_fs4.default.existsSync(import_node_path5.default.join(root, "toolchain.json"))
|
|
1449
1650
|
);
|
|
1450
|
-
if (!moduleRoot)
|
|
1651
|
+
if (!moduleRoot)
|
|
1652
|
+
return {
|
|
1653
|
+
...await compileRemote(packagePath, entry, snapshot),
|
|
1654
|
+
stamp,
|
|
1655
|
+
package: content
|
|
1656
|
+
};
|
|
1451
1657
|
const toolchain = JSON.parse(
|
|
1452
1658
|
import_node_fs4.default.readFileSync(import_node_path5.default.join(moduleRoot, "toolchain.json"), "utf8")
|
|
1453
1659
|
);
|
|
@@ -1455,7 +1661,7 @@ async function compile(packagePath, entry, stamp, moduleRootOverride) {
|
|
|
1455
1661
|
if (typeof release !== "string") {
|
|
1456
1662
|
throw new Error(`swift toolchain manifest at ${moduleRoot} has no release`);
|
|
1457
1663
|
}
|
|
1458
|
-
const artifact = await compileSwiftProjectUnit(
|
|
1664
|
+
const artifact = await compileSwiftProjectUnit(snapshotCompileInput(snapshot, entry), {
|
|
1459
1665
|
// the compile rewrites Sources/App in its root before swiftpm builds, and
|
|
1460
1666
|
// its lock orders one process only: two vites on one root (a lane's dev
|
|
1461
1667
|
// server and a capture, or two checkouts) build each other's sources. so
|
|
@@ -1473,50 +1679,75 @@ async function compile(packagePath, entry, stamp, moduleRootOverride) {
|
|
|
1473
1679
|
`Library/Developer/Toolchains/${release}.xctoolchain/usr/bin`
|
|
1474
1680
|
)
|
|
1475
1681
|
});
|
|
1476
|
-
return { ...artifact, stamp };
|
|
1682
|
+
return { ...artifact, stamp, package: content };
|
|
1477
1683
|
}
|
|
1478
|
-
async function compileRemote(packagePath, entry) {
|
|
1479
|
-
const auth = resolveCliAuth();
|
|
1480
|
-
if (!auth || auth.kind === "github") {
|
|
1684
|
+
async function compileRemote(packagePath, entry, snapshot, hosted) {
|
|
1685
|
+
const auth = hosted ? null : resolveCliAuth();
|
|
1686
|
+
if (!hosted && (!auth || auth.kind === "github")) {
|
|
1481
1687
|
throw new Error(
|
|
1482
1688
|
`compiling ${import_node_path5.default.basename(packagePath)} for Peach needs \`peach login\` or PEACH_API_KEY: this peachsim has no local SwiftUI module, so Contrast compiles it`
|
|
1483
1689
|
);
|
|
1484
1690
|
}
|
|
1485
|
-
const origin = resolveContrastBackendOrigin(
|
|
1486
|
-
|
|
1487
|
-
|
|
1691
|
+
const origin = hosted?.origin ?? resolveContrastBackendOrigin(auth?.kind === "session" ? auth.origin : null);
|
|
1692
|
+
const authorization = hosted?.authorization ?? (auth ? authHeaderValue(auth) : void 0);
|
|
1693
|
+
const signal = AbortSignal.any([
|
|
1694
|
+
...hosted ? [hosted.signal] : [],
|
|
1695
|
+
AbortSignal.timeout(5 * 6e4)
|
|
1696
|
+
]);
|
|
1488
1697
|
const submit = httpSwiftCompileSubmit({
|
|
1489
1698
|
endpoint: origin,
|
|
1490
|
-
authorization
|
|
1699
|
+
authorization,
|
|
1700
|
+
signal
|
|
1491
1701
|
});
|
|
1492
1702
|
if (!submit) throw new Error("swift compile: no credential to submit with");
|
|
1493
|
-
const descriptor =
|
|
1703
|
+
const descriptor = snapshot.native;
|
|
1494
1704
|
const address = await compileSwiftProject(
|
|
1495
1705
|
submit,
|
|
1496
1706
|
{
|
|
1497
|
-
files:
|
|
1707
|
+
files: snapshot.files,
|
|
1708
|
+
resources: snapshot.bundleFiles.files,
|
|
1709
|
+
images: snapshot.resources.images,
|
|
1498
1710
|
entry,
|
|
1499
1711
|
packageId: descriptor?.packageId ?? swiftPackageId(packagePath)
|
|
1500
1712
|
},
|
|
1501
|
-
origin
|
|
1713
|
+
origin,
|
|
1714
|
+
signal
|
|
1502
1715
|
);
|
|
1503
1716
|
if (descriptor && address.native?.hash !== descriptor.hash) {
|
|
1504
1717
|
throw new Error(
|
|
1505
1718
|
`${import_node_path5.default.basename(packagePath)}: Contrast compiled native contract ${address.native?.hash ?? "none"} but one typegen wrote ${descriptor.hash}; the app's One and the compile host's differ, or the compile host is older than this peachsim`
|
|
1506
1719
|
);
|
|
1507
1720
|
}
|
|
1508
|
-
const response = await fetch(address.url);
|
|
1721
|
+
const response = await fetch(address.url, { signal });
|
|
1509
1722
|
if (!response.ok) {
|
|
1510
1723
|
throw new Error(`swift compile: ${address.url} answered ${response.status}`);
|
|
1511
1724
|
}
|
|
1725
|
+
const maxArtifactBytes = 64 * 1024 * 1024;
|
|
1726
|
+
if (Number(response.headers.get("content-length")) > maxArtifactBytes || !response.body) {
|
|
1727
|
+
throw new Error("swift compile: artifact exceeds 64 MiB or has no body");
|
|
1728
|
+
}
|
|
1729
|
+
const reader = response.body.getReader();
|
|
1730
|
+
const chunks = [];
|
|
1731
|
+
let total = 0;
|
|
1732
|
+
for (; ; ) {
|
|
1733
|
+
signal.throwIfAborted();
|
|
1734
|
+
const next = await reader.read();
|
|
1735
|
+
if (next.done) break;
|
|
1736
|
+
total += next.value.byteLength;
|
|
1737
|
+
if (total > maxArtifactBytes) {
|
|
1738
|
+
await reader.cancel();
|
|
1739
|
+
throw new Error("swift compile: artifact exceeds 64 MiB");
|
|
1740
|
+
}
|
|
1741
|
+
chunks.push(next.value);
|
|
1742
|
+
}
|
|
1512
1743
|
return {
|
|
1513
1744
|
hash: address.hash,
|
|
1514
|
-
bytes: Buffer.
|
|
1745
|
+
bytes: Buffer.concat(chunks),
|
|
1515
1746
|
icu: { url: address.icuUrl }
|
|
1516
1747
|
};
|
|
1517
1748
|
}
|
|
1518
1749
|
function artifactFor(project, entry, moduleRoot) {
|
|
1519
|
-
const stamp = sourceStamp(project.packagePath, moduleRoot);
|
|
1750
|
+
const stamp = sourceStamp(project.packagePath, moduleRoot, Boolean(project.hosted));
|
|
1520
1751
|
if (project.artifact?.stamp === stamp) return Promise.resolve(project.artifact);
|
|
1521
1752
|
if (project.building) {
|
|
1522
1753
|
const running = project.building;
|
|
@@ -1524,9 +1755,24 @@ function artifactFor(project, entry, moduleRoot) {
|
|
|
1524
1755
|
const again = () => artifactFor(project, entry, moduleRoot);
|
|
1525
1756
|
return running.promise.then(again, again);
|
|
1526
1757
|
}
|
|
1527
|
-
const
|
|
1758
|
+
const snapshot = packageSnapshot(project);
|
|
1759
|
+
if (sourceStamp(project.packagePath, moduleRoot, Boolean(project.hosted)) !== stamp) {
|
|
1760
|
+
return artifactFor(project, entry, moduleRoot);
|
|
1761
|
+
}
|
|
1762
|
+
const promise = compile(
|
|
1763
|
+
project.packagePath,
|
|
1764
|
+
entry,
|
|
1765
|
+
stamp,
|
|
1766
|
+
moduleRoot,
|
|
1767
|
+
project.hosted,
|
|
1768
|
+
snapshot
|
|
1769
|
+
).then(
|
|
1528
1770
|
(artifact) => {
|
|
1529
1771
|
project.artifact = artifact;
|
|
1772
|
+
project.artifacts = [
|
|
1773
|
+
artifact,
|
|
1774
|
+
...project.artifacts.filter((old) => old.hash !== artifact.hash)
|
|
1775
|
+
].slice(0, 2);
|
|
1530
1776
|
project.building = null;
|
|
1531
1777
|
return artifact;
|
|
1532
1778
|
},
|
|
@@ -1535,10 +1781,14 @@ function artifactFor(project, entry, moduleRoot) {
|
|
|
1535
1781
|
throw error;
|
|
1536
1782
|
}
|
|
1537
1783
|
);
|
|
1538
|
-
|
|
1539
|
-
|
|
1784
|
+
const fresh = promise.then(
|
|
1785
|
+
(artifact) => sourceStamp(project.packagePath, moduleRoot, Boolean(project.hosted)) === artifact.stamp ? artifact : artifactFor(project, entry, moduleRoot)
|
|
1786
|
+
);
|
|
1787
|
+
project.building = { stamp, promise: fresh };
|
|
1788
|
+
return fresh;
|
|
1540
1789
|
}
|
|
1541
1790
|
function swiftPackageWatchFiles(packagePath, moduleRoot) {
|
|
1791
|
+
packagePath = import_node_fs4.default.realpathSync(packagePath);
|
|
1542
1792
|
return [
|
|
1543
1793
|
import_node_path5.default.join(packagePath, "Package.swift"),
|
|
1544
1794
|
...sourceFiles(packagePath),
|
|
@@ -1547,9 +1797,12 @@ function swiftPackageWatchFiles(packagePath, moduleRoot) {
|
|
|
1547
1797
|
...moduleRoot ? swiftModuleInputFiles(moduleRoot).map((file) => import_node_path5.default.join(moduleRoot, file)) : []
|
|
1548
1798
|
];
|
|
1549
1799
|
}
|
|
1550
|
-
async function swiftPackageMetadata(packagePath, packageName, moduleRoot, origin) {
|
|
1800
|
+
async function swiftPackageMetadata(packagePath, packageName, moduleRoot, origin, hosted) {
|
|
1801
|
+
packagePath = import_node_fs4.default.realpathSync(packagePath);
|
|
1551
1802
|
const mains = sourceFiles(packagePath).filter(
|
|
1552
|
-
(file) => /@main\s+(?:public\s+)?struct\s+\w+\s*:/.test(
|
|
1803
|
+
(file) => /@main\s+(?:public\s+)?struct\s+\w+\s*:/.test(
|
|
1804
|
+
readPackageFile(packagePath, file, MAX_SWIFT_COMPILE_SOURCE_BYTES).toString("utf8")
|
|
1805
|
+
)
|
|
1553
1806
|
);
|
|
1554
1807
|
const native = nativeSourceDescriptor(packagePath);
|
|
1555
1808
|
if (mains.length > 1 || mains.length === 0 && !native) {
|
|
@@ -1557,27 +1810,32 @@ async function swiftPackageMetadata(packagePath, packageName, moduleRoot, origin
|
|
|
1557
1810
|
`swift package ${packageName} needs exactly one @main source or generated native modules; found ${mains.length}`
|
|
1558
1811
|
);
|
|
1559
1812
|
}
|
|
1560
|
-
const project = projectFor(packagePath);
|
|
1813
|
+
const project = projectFor(packagePath, hosted);
|
|
1561
1814
|
const entry = mains.length === 1 ? import_node_path5.default.relative(packagePath, mains[0]).split(import_node_path5.default.sep).join(import_node_path5.default.posix.sep) : Object.entries(native?.files ?? {}).find(
|
|
1562
1815
|
([_file, names]) => names.length > 0
|
|
1563
1816
|
)?.[0];
|
|
1564
1817
|
if (!entry) throw new Error(`swift package ${packageName} has no native module source`);
|
|
1565
1818
|
const artifact = await artifactFor(project, entry, moduleRoot);
|
|
1566
|
-
const resources =
|
|
1567
|
-
const bundleFiles =
|
|
1819
|
+
const resources = artifact.package.resources;
|
|
1820
|
+
const bundleFiles = artifact.package.bundleFiles;
|
|
1568
1821
|
return {
|
|
1569
1822
|
url: `${origin}${ARTIFACT_PATH}${artifact.hash}.wasm`,
|
|
1570
1823
|
hash: artifact.hash,
|
|
1571
1824
|
icuUrl: icuUrl(origin, artifact),
|
|
1572
1825
|
rootId: `${packageName}/${entry}`,
|
|
1573
|
-
resources:
|
|
1826
|
+
resources: Object.fromEntries(
|
|
1827
|
+
Object.entries(resources.table).map(([name, image]) => [
|
|
1828
|
+
name,
|
|
1829
|
+
{ ...image, uri: `${origin}${image.uri}` }
|
|
1830
|
+
])
|
|
1831
|
+
),
|
|
1574
1832
|
bundleFiles: bundleFiles.files,
|
|
1575
1833
|
colors: resources.colors,
|
|
1576
1834
|
symbols: resources.symbols,
|
|
1577
|
-
native: native ? {
|
|
1578
|
-
packageId: native.packageId,
|
|
1579
|
-
contractHash: native.hash,
|
|
1580
|
-
modules: native.modules,
|
|
1835
|
+
native: artifact.package.native ? {
|
|
1836
|
+
packageId: artifact.package.native.packageId,
|
|
1837
|
+
contractHash: artifact.package.native.hash,
|
|
1838
|
+
modules: artifact.package.native.modules,
|
|
1581
1839
|
defaultView: mains.length === 1
|
|
1582
1840
|
} : void 0
|
|
1583
1841
|
};
|
|
@@ -1598,7 +1856,9 @@ function serveSwiftPackageAsset(pathname, res) {
|
|
|
1598
1856
|
}
|
|
1599
1857
|
if (pathname.startsWith(ICU_PATH)) {
|
|
1600
1858
|
for (const project of projects.values()) {
|
|
1601
|
-
const icu = project.
|
|
1859
|
+
const icu = project.artifacts.find(
|
|
1860
|
+
(artifact) => "sha256" in artifact.icu && pathname === `${ICU_PATH}${artifact.icu.sha256}`
|
|
1861
|
+
)?.icu;
|
|
1602
1862
|
if (!icu || "url" in icu || pathname !== `${ICU_PATH}${icu.sha256}`) continue;
|
|
1603
1863
|
res.setHeader("access-control-allow-origin", "*");
|
|
1604
1864
|
res.setHeader("content-type", "application/gzip");
|
|
@@ -1612,7 +1872,9 @@ function serveSwiftPackageAsset(pathname, res) {
|
|
|
1612
1872
|
}
|
|
1613
1873
|
if (!pathname.startsWith(ARTIFACT_PATH)) return false;
|
|
1614
1874
|
for (const project of projects.values()) {
|
|
1615
|
-
const artifact = project.
|
|
1875
|
+
const artifact = project.artifacts.find(
|
|
1876
|
+
(artifact2) => pathname === `${ARTIFACT_PATH}${artifact2.hash}.wasm`
|
|
1877
|
+
);
|
|
1616
1878
|
if (!artifact || pathname !== `${ARTIFACT_PATH}${artifact.hash}.wasm`) continue;
|
|
1617
1879
|
res.setHeader("access-control-allow-origin", "*");
|
|
1618
1880
|
res.setHeader("content-type", "application/wasm");
|
|
@@ -1623,13 +1885,27 @@ function serveSwiftPackageAsset(pathname, res) {
|
|
|
1623
1885
|
res.end("swift artifact is stale");
|
|
1624
1886
|
return true;
|
|
1625
1887
|
}
|
|
1888
|
+
|
|
1889
|
+
// src/vite-plugin-swift.ts
|
|
1890
|
+
var ARTIFACT_PATH2 = "/__peach/swift/";
|
|
1891
|
+
var VIRTUAL_PREFIX = "\0peach-swift:";
|
|
1892
|
+
var devServer;
|
|
1893
|
+
function serverOrigin() {
|
|
1894
|
+
const address = devServer?.httpServer?.address();
|
|
1895
|
+
const port = address && typeof address === "object" ? address.port : devServer?.config.server.port;
|
|
1896
|
+
if (!port) throw new Error("the swift urls need the dev server port");
|
|
1897
|
+
return `http://localhost:${port}`;
|
|
1898
|
+
}
|
|
1899
|
+
function artifactUrl(project, artifact) {
|
|
1900
|
+
return `${serverOrigin()}${ARTIFACT_PATH2}${artifact.hash}.wasm`;
|
|
1901
|
+
}
|
|
1626
1902
|
function packageFor(file) {
|
|
1627
|
-
let dir =
|
|
1903
|
+
let dir = import_node_path6.default.dirname(file);
|
|
1628
1904
|
const stop = devServer?.config.root;
|
|
1629
1905
|
for (; ; ) {
|
|
1630
|
-
if (
|
|
1631
|
-
if (stop !== void 0 && dir === stop ||
|
|
1632
|
-
dir =
|
|
1906
|
+
if (import_node_fs5.default.existsSync(import_node_path6.default.join(dir, "Package.swift"))) return dir;
|
|
1907
|
+
if (stop !== void 0 && dir === stop || import_node_path6.default.dirname(dir) === dir) break;
|
|
1908
|
+
dir = import_node_path6.default.dirname(dir);
|
|
1633
1909
|
}
|
|
1634
1910
|
throw new Error(
|
|
1635
1911
|
`no Package.swift above ${file}${stop === void 0 ? "" : ` (searched up to ${stop})`}; a .swift import needs a swiftpm package like the one in packages/sootsim-swift/example`
|
|
@@ -1650,9 +1926,9 @@ function swiftPlugin(options = {}) {
|
|
|
1650
1926
|
if (!resolved) throw new Error(`cannot resolve swift source ${source}`);
|
|
1651
1927
|
let id = resolved.id;
|
|
1652
1928
|
if (importer && (source.startsWith("./") || source.startsWith("../"))) {
|
|
1653
|
-
const raw2 =
|
|
1929
|
+
const raw2 = import_node_path6.default.resolve(import_node_path6.default.dirname(importer.split("?")[0] ?? importer), source);
|
|
1654
1930
|
try {
|
|
1655
|
-
if (
|
|
1931
|
+
if (import_node_fs5.default.realpathSync(raw2) === import_node_fs5.default.realpathSync(resolved.id)) id = raw2;
|
|
1656
1932
|
} catch {
|
|
1657
1933
|
}
|
|
1658
1934
|
}
|
|
@@ -1661,16 +1937,16 @@ function swiftPlugin(options = {}) {
|
|
|
1661
1937
|
async load(id) {
|
|
1662
1938
|
if (!id.startsWith(VIRTUAL_PREFIX)) return null;
|
|
1663
1939
|
const file = id.slice(VIRTUAL_PREFIX.length);
|
|
1664
|
-
if (!
|
|
1940
|
+
if (!import_node_fs5.default.existsSync(file)) throw new Error(`swift source ${file} no longer exists`);
|
|
1665
1941
|
const packagePath = options.packagePath ?? packageFor(file);
|
|
1666
1942
|
const project = projectFor(packagePath);
|
|
1667
|
-
const entry =
|
|
1943
|
+
const entry = import_node_path6.default.relative(packagePath, file).split(import_node_path6.default.sep).join(import_node_path6.default.posix.sep);
|
|
1668
1944
|
for (const source of [
|
|
1669
1945
|
...sourceFiles(packagePath),
|
|
1670
1946
|
...nativeSourceFiles(packagePath)
|
|
1671
1947
|
])
|
|
1672
1948
|
this.addWatchFile(source);
|
|
1673
|
-
this.addWatchFile(
|
|
1949
|
+
this.addWatchFile(import_node_path6.default.join(packagePath, "Package.swift"));
|
|
1674
1950
|
for (const root of linkedModuleRoots(packagePath)) {
|
|
1675
1951
|
for (const source of sourceFiles(root)) this.addWatchFile(source);
|
|
1676
1952
|
}
|
|
@@ -1682,39 +1958,20 @@ function swiftPlugin(options = {}) {
|
|
|
1682
1958
|
this.warn(error instanceof Error ? error.message : String(error));
|
|
1683
1959
|
artifact = project.artifact;
|
|
1684
1960
|
}
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
);
|
|
1700
|
-
}
|
|
1701
|
-
let bundleFiles = {};
|
|
1702
|
-
try {
|
|
1703
|
-
const packed = buildSwiftBundleFiles(packagePath);
|
|
1704
|
-
bundleFiles = packed.files;
|
|
1705
|
-
for (const watched of packed.watched) {
|
|
1706
|
-
this.addWatchFile(import_node_path5.default.join(packagePath, ...watched.split(import_node_path5.default.posix.sep)));
|
|
1707
|
-
}
|
|
1708
|
-
if (packed.skipped.length > 0) {
|
|
1709
|
-
this.warn(
|
|
1710
|
-
`swift bundle files skipped for ${packagePath}: ${packed.skipped.join("; ")}`
|
|
1711
|
-
);
|
|
1712
|
-
}
|
|
1713
|
-
} catch (error) {
|
|
1714
|
-
this.warn(
|
|
1715
|
-
`swift bundle files for ${packagePath}: ${error instanceof Error ? error.message : String(error)}`
|
|
1716
|
-
);
|
|
1717
|
-
}
|
|
1961
|
+
const resources = Object.fromEntries(
|
|
1962
|
+
Object.entries(artifact.package.resources.table).map(([name, image]) => [
|
|
1963
|
+
name,
|
|
1964
|
+
{ ...image, uri: `${serverOrigin()}${image.uri}` }
|
|
1965
|
+
])
|
|
1966
|
+
);
|
|
1967
|
+
for (const watched of [
|
|
1968
|
+
...artifact.package.resources.watched,
|
|
1969
|
+
...artifact.package.bundleFiles.watched
|
|
1970
|
+
])
|
|
1971
|
+
this.addWatchFile(import_node_path6.default.join(packagePath, ...watched.split(import_node_path6.default.posix.sep)));
|
|
1972
|
+
const colors = artifact.package.resources.colors;
|
|
1973
|
+
const symbols = artifact.package.resources.symbols;
|
|
1974
|
+
const bundleFiles = artifact.package.bundleFiles.files;
|
|
1718
1975
|
const native = nativeSourceDescriptor(packagePath);
|
|
1719
1976
|
return swiftEntryModuleEsm({
|
|
1720
1977
|
url: artifactUrl(project, artifact),
|