rnxsim 0.1.522 → 0.1.524
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/cli/commands/control.ts +31 -15
- 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 +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- 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.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 +1 -1
- 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 +1 -1
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.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/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 +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +26 -12
- package/dist-lib/swift.cjs +151 -72
- package/dist-lib/vite.cjs +189 -24
- package/package.json +1 -1
- package/src/swift.ts +2 -3
- package/src/vite-plugin-swift.ts +185 -41
package/dist-lib/swift.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.524 | (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;
|
|
@@ -32,8 +32,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
32
32
|
// src/swift.ts
|
|
33
33
|
var swift_exports = {};
|
|
34
34
|
__export(swift_exports, {
|
|
35
|
-
|
|
36
|
-
createSwiftView: () => createSwiftView
|
|
35
|
+
createSwiftEntry: () => createSwiftEntry
|
|
37
36
|
});
|
|
38
37
|
module.exports = __toCommonJS(swift_exports);
|
|
39
38
|
|
|
@@ -45,6 +44,17 @@ var import_ui = require("contrast-kit/ui");
|
|
|
45
44
|
var import_react = require("react");
|
|
46
45
|
var import_react_native = require("react-native");
|
|
47
46
|
var import_react_native_bottom_tabs = __toESM(require("react-native-bottom-tabs"), 1);
|
|
47
|
+
|
|
48
|
+
// ../sootsim-swift/src/bundleAssets.ts
|
|
49
|
+
function resolveImageSource(source, table, onMiss) {
|
|
50
|
+
if (typeof source !== "string") return source;
|
|
51
|
+
const url = table[source];
|
|
52
|
+
if (typeof url === "string") return { uri: url };
|
|
53
|
+
onMiss(source);
|
|
54
|
+
return source;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ../sootsim-swift/src/mount.tsx
|
|
48
58
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
49
59
|
function isRecord(value) {
|
|
50
60
|
return typeof value === "object" && value !== null;
|
|
@@ -190,20 +200,6 @@ function pointerExport(exports2, name) {
|
|
|
190
200
|
return result;
|
|
191
201
|
};
|
|
192
202
|
}
|
|
193
|
-
function maybePointerExport(exports2, name) {
|
|
194
|
-
const value = exports2[name];
|
|
195
|
-
if (value === void 0) return void 0;
|
|
196
|
-
if (typeof value !== "function") {
|
|
197
|
-
throw new Error(`swift export ${name} is not a function`);
|
|
198
|
-
}
|
|
199
|
-
return (...args) => {
|
|
200
|
-
const result = Reflect.apply(value, void 0, args);
|
|
201
|
-
if (typeof result !== "number") {
|
|
202
|
-
throw new Error(`swift export ${name} returned ${typeof result}`);
|
|
203
|
-
}
|
|
204
|
-
return result;
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
203
|
function voidExport(exports2, name) {
|
|
208
204
|
const fn = rawExport(exports2, name);
|
|
209
205
|
return (...args) => {
|
|
@@ -236,13 +232,35 @@ function instantiate(module2) {
|
|
|
236
232
|
const initialize = voidExport(instance.exports, "_initialize");
|
|
237
233
|
const mainArgv = voidExport(instance.exports, "__main_argc_argv");
|
|
238
234
|
const mount = pointerExport(instance.exports, "rnx_mount");
|
|
239
|
-
const mountViewExport =
|
|
240
|
-
const hasViewExport =
|
|
235
|
+
const mountViewExport = pointerExport(instance.exports, "rnx_mount_view");
|
|
236
|
+
const hasViewExport = pointerExport(instance.exports, "rnx_has_view");
|
|
241
237
|
const event = pointerExport(instance.exports, "rnx_event");
|
|
242
238
|
const stateExport = pointerExport(instance.exports, "rnx_state_export");
|
|
243
239
|
const stateImport = voidExport(instance.exports, "rnx_state_import");
|
|
244
240
|
const alloc = pointerExport(instance.exports, "rnx_alloc");
|
|
245
241
|
const free = voidExport(instance.exports, "rnx_free");
|
|
242
|
+
const openURLDrain = typeof instance.exports.rnx_open_url_drain === "function" ? pointerExport(instance.exports, "rnx_open_url_drain") : null;
|
|
243
|
+
const drainOpenURLs = () => {
|
|
244
|
+
if (!openURLDrain) return;
|
|
245
|
+
let urls;
|
|
246
|
+
try {
|
|
247
|
+
urls = JSON.parse(readBuffer(openURLDrain()));
|
|
248
|
+
} catch {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
if (!Array.isArray(urls)) return;
|
|
252
|
+
for (const url of urls) {
|
|
253
|
+
if (typeof url !== "string") continue;
|
|
254
|
+
import_react_native.Linking.canOpenURL(url).then(
|
|
255
|
+
(open) => {
|
|
256
|
+
if (open) import_react_native.Linking.openURL(url).catch(() => {
|
|
257
|
+
});
|
|
258
|
+
},
|
|
259
|
+
() => {
|
|
260
|
+
}
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
};
|
|
246
264
|
const readBuffer = (ptr) => {
|
|
247
265
|
const view = new DataView(requireMemory().buffer);
|
|
248
266
|
const length = view.getUint32(ptr, true);
|
|
@@ -262,41 +280,44 @@ function instantiate(module2) {
|
|
|
262
280
|
mainArgv(0, 0);
|
|
263
281
|
return {
|
|
264
282
|
mount: () => {
|
|
265
|
-
if (
|
|
283
|
+
if (hasViewExport() === 1) {
|
|
266
284
|
throw new Error(
|
|
267
285
|
"swift package has an RNXPackage entry, not an App entry; mount it as a view or make its @main type conform to App"
|
|
268
286
|
);
|
|
269
287
|
}
|
|
270
|
-
|
|
288
|
+
const tree = readTree(readBuffer(mount()));
|
|
289
|
+
drainOpenURLs();
|
|
290
|
+
return tree;
|
|
271
291
|
},
|
|
272
292
|
mountView: (props) => {
|
|
273
|
-
if (
|
|
274
|
-
throw new Error(
|
|
275
|
-
"swift artifact has no rnx_mount_view export; rebuild the swift package"
|
|
276
|
-
);
|
|
277
|
-
}
|
|
278
|
-
if ((hasViewExport?.() ?? 0) !== 1) {
|
|
293
|
+
if (hasViewExport() !== 1) {
|
|
279
294
|
throw new Error(
|
|
280
295
|
"swift package has no RNXPackage entry; its @main type must conform to RNXPackage to mount as a view"
|
|
281
296
|
);
|
|
282
297
|
}
|
|
283
|
-
|
|
298
|
+
const tree = readTree(
|
|
284
299
|
readBuffer(withPayload(props, (ptr, length) => mountViewExport(ptr, length)))
|
|
285
300
|
);
|
|
301
|
+
drainOpenURLs();
|
|
302
|
+
return tree;
|
|
286
303
|
},
|
|
287
|
-
hasView: () =>
|
|
288
|
-
deliver: (handlerId2, payload) =>
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
304
|
+
hasView: () => hasViewExport() === 1,
|
|
305
|
+
deliver: (handlerId2, payload) => {
|
|
306
|
+
const tree = readTree(
|
|
307
|
+
readBuffer(
|
|
308
|
+
withPayload(
|
|
309
|
+
payload,
|
|
310
|
+
(ptr, length) => (
|
|
311
|
+
// handler ids are opaque to the tenant: they come from the tree
|
|
312
|
+
// this instance just returned and they are only meaningful to it
|
|
313
|
+
event(handlerId2, ptr, length)
|
|
314
|
+
)
|
|
296
315
|
)
|
|
297
316
|
)
|
|
298
|
-
)
|
|
299
|
-
|
|
317
|
+
);
|
|
318
|
+
drainOpenURLs();
|
|
319
|
+
return tree;
|
|
320
|
+
},
|
|
300
321
|
exportState: () => readBuffer(stateExport()),
|
|
301
322
|
importState: (state) => {
|
|
302
323
|
withPayload(JSON.parse(state), (ptr, length) => {
|
|
@@ -378,6 +399,18 @@ function resolveModifier(modifier) {
|
|
|
378
399
|
}
|
|
379
400
|
return { ...modifier, color: resolveColor(color) };
|
|
380
401
|
}
|
|
402
|
+
var SwiftResourcesContext = (0, import_react.createContext)(void 0);
|
|
403
|
+
function SwiftImage(props) {
|
|
404
|
+
const table = (0, import_react.useContext)(SwiftResourcesContext);
|
|
405
|
+
const { source, ...rest } = props ?? {};
|
|
406
|
+
const resolved = resolveImageSource(source, table ?? {}, (name) => {
|
|
407
|
+
console.error(`swift: no bundle asset named '${name}' in this mount's resources`);
|
|
408
|
+
});
|
|
409
|
+
return (0, import_react.createElement)(import_ui.Image, {
|
|
410
|
+
...rest,
|
|
411
|
+
...source === void 0 ? {} : { source: resolved }
|
|
412
|
+
});
|
|
413
|
+
}
|
|
381
414
|
var NODE_COMPONENTS = {
|
|
382
415
|
Alert: SwiftAlert,
|
|
383
416
|
BottomSheet: import_ui.BottomSheet,
|
|
@@ -390,14 +423,17 @@ var NODE_COMPONENTS = {
|
|
|
390
423
|
Divider: import_ui.Divider,
|
|
391
424
|
Ellipse: import_ui.Ellipse,
|
|
392
425
|
Form: import_ui.Form,
|
|
426
|
+
GeometryReader: import_ui.GeometryReader,
|
|
393
427
|
GlassEffectContainer: import_ui.GlassEffectContainer,
|
|
394
428
|
Group: import_ui.Group,
|
|
395
429
|
HStack: import_ui.HStack,
|
|
396
|
-
Image:
|
|
430
|
+
Image: SwiftImage,
|
|
397
431
|
Label: import_ui.Label,
|
|
398
432
|
LazyVStack: import_ui.LazyVStack,
|
|
433
|
+
LinearGradient: import_ui.LinearGradient,
|
|
399
434
|
List: import_ui.List,
|
|
400
435
|
Menu: import_ui.Menu,
|
|
436
|
+
Path: import_ui.Path,
|
|
401
437
|
Picker: import_ui.Picker,
|
|
402
438
|
ProgressView: import_ui.ProgressView,
|
|
403
439
|
Rectangle: import_ui.Rectangle,
|
|
@@ -613,6 +649,12 @@ function nodeProps(node, deliver) {
|
|
|
613
649
|
const size = typeof font?.size === "number" ? font.size : void 0;
|
|
614
650
|
return {
|
|
615
651
|
...typeof props.systemName === "string" ? { systemName: props.systemName } : {},
|
|
652
|
+
// a bundle asset name rides as the kit image source; the kit paints
|
|
653
|
+
// resolved { uri } sources and keeps its placeholder for names the
|
|
654
|
+
// table could not resolve.
|
|
655
|
+
...typeof props.name === "string" ? { source: props.name } : {},
|
|
656
|
+
...props.resizable === true ? { resizable: true } : {},
|
|
657
|
+
...typeof props.renderingMode === "string" ? { renderingMode: props.renderingMode } : {},
|
|
616
658
|
...size === void 0 ? {} : { size },
|
|
617
659
|
...pressProps(node, deliver)
|
|
618
660
|
};
|
|
@@ -1095,10 +1137,26 @@ function SplitViewHost({
|
|
|
1095
1137
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.View, { style: { flex: 1 }, children: pushed.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NavigationStackHost, { node: { ...node, c: pushed }, deliver }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: detail.map((child) => renderNode(child, deliver, cache)) }) })
|
|
1096
1138
|
] });
|
|
1097
1139
|
}
|
|
1140
|
+
function SwiftAppear({
|
|
1141
|
+
node,
|
|
1142
|
+
deliver,
|
|
1143
|
+
children
|
|
1144
|
+
}) {
|
|
1145
|
+
const onAppear = handlerId(node, "onAppear");
|
|
1146
|
+
const onDisappear = handlerId(node, "onDisappear");
|
|
1147
|
+
(0, import_react.useEffect)(() => {
|
|
1148
|
+
if (onAppear !== void 0) deliver(onAppear, null);
|
|
1149
|
+
return () => {
|
|
1150
|
+
if (onDisappear !== void 0) deliver(onDisappear, null);
|
|
1151
|
+
};
|
|
1152
|
+
}, []);
|
|
1153
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
|
|
1154
|
+
}
|
|
1098
1155
|
function renderNode(node, deliver, cache) {
|
|
1099
1156
|
const cached = cache?.entries.get(node.id);
|
|
1100
1157
|
if (cached && sameNode(cached.node, node)) return cached.element;
|
|
1101
|
-
const
|
|
1158
|
+
const built = buildNode(node, deliver, cache);
|
|
1159
|
+
const element = node.h?.onAppear !== void 0 || node.h?.onDisappear !== void 0 ? (0, import_react.createElement)(SwiftAppear, { key: node.id, node, deliver }, built) : built;
|
|
1102
1160
|
cache?.entries.set(node.id, { node, element });
|
|
1103
1161
|
return element;
|
|
1104
1162
|
}
|
|
@@ -1140,20 +1198,29 @@ function buildNode(node, deliver, cache) {
|
|
|
1140
1198
|
function SwiftTree({
|
|
1141
1199
|
tree,
|
|
1142
1200
|
deliver,
|
|
1143
|
-
cache
|
|
1201
|
+
cache,
|
|
1202
|
+
resources
|
|
1144
1203
|
}) {
|
|
1145
1204
|
return (
|
|
1146
1205
|
// a navigation stack at the root lays its own bar out under the status
|
|
1147
1206
|
// bar and insets each screen itself, so the host must not also pad it
|
|
1148
1207
|
// down: that pad would move the whole stack a status bar lower
|
|
1208
|
+
// a swiftui scene is opaque: the window behind every screen is
|
|
1209
|
+
// systemBackground, and lists paint their grouped fill over it (the kit's
|
|
1210
|
+
// grouped container already does). without this a listless screen shows
|
|
1211
|
+
// whatever sits beneath the mount. RAN on the safeArea probe (iphone 17
|
|
1212
|
+
// pro): (600,1300) reads #ffffff ios against #f2f2f7 rnx, 99.92% of the
|
|
1213
|
+
// frame; dark matches on both legs (the oracle's falsifier: the two
|
|
1214
|
+
// fills coincide there). PlatformColor is this lane's spelling for a
|
|
1215
|
+
// semantic color.
|
|
1149
1216
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1150
1217
|
import_ui.Host,
|
|
1151
1218
|
{
|
|
1152
|
-
style: { flex: 1 },
|
|
1219
|
+
style: { flex: 1, backgroundColor: (0, import_react_native.PlatformColor)("systemBackground") },
|
|
1153
1220
|
ignoreSafeArea: tree.some(
|
|
1154
1221
|
(node) => node.t === "NavigationStack" || node.t === "NavigationSplitView"
|
|
1155
1222
|
),
|
|
1156
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_native.NavigationIndependentTree, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_native.NavigationContainer, { children: tree.map((node) => renderNode(node, deliver, cache)) }) })
|
|
1223
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_native.NavigationIndependentTree, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_native.NavigationContainer, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SwiftResourcesContext.Provider, { value: resources, children: tree.map((node) => renderNode(node, deliver, cache)) }) }) })
|
|
1157
1224
|
}
|
|
1158
1225
|
)
|
|
1159
1226
|
);
|
|
@@ -1166,19 +1233,19 @@ function rootRegistry() {
|
|
|
1166
1233
|
Reflect.set(globalThis, ROOT_KEY, created);
|
|
1167
1234
|
return created;
|
|
1168
1235
|
}
|
|
1169
|
-
function slotFor(rootId, mountTree
|
|
1236
|
+
function slotFor(rootId, mountTree) {
|
|
1170
1237
|
const registry = rootRegistry();
|
|
1171
1238
|
const existing = registry.get(rootId);
|
|
1172
1239
|
if (existing) return existing;
|
|
1173
|
-
const created = { root: createRoot(mountTree
|
|
1240
|
+
const created = { root: createRoot(mountTree) };
|
|
1174
1241
|
registry.set(rootId, created);
|
|
1175
1242
|
return created;
|
|
1176
1243
|
}
|
|
1177
|
-
function createRoot(mountTree
|
|
1244
|
+
function createRoot(mountTree) {
|
|
1178
1245
|
let instance = null;
|
|
1179
1246
|
let source = null;
|
|
1180
1247
|
let refresh;
|
|
1181
|
-
let state = { tree: null, error: null };
|
|
1248
|
+
let state = { tree: null, isView: false, error: null };
|
|
1182
1249
|
let swap = Promise.resolve();
|
|
1183
1250
|
const listeners = /* @__PURE__ */ new Set();
|
|
1184
1251
|
const cache = { entries: /* @__PURE__ */ new Map() };
|
|
@@ -1186,13 +1253,14 @@ function createRoot(mountTree, props) {
|
|
|
1186
1253
|
state = next;
|
|
1187
1254
|
for (const listener of listeners) listener();
|
|
1188
1255
|
};
|
|
1189
|
-
const apply = async (options) => {
|
|
1256
|
+
const apply = async (options, props) => {
|
|
1190
1257
|
const carried = instance?.exportState() ?? null;
|
|
1191
1258
|
const created = instantiate(await compile(options.url));
|
|
1192
1259
|
if (carried !== null) created.importState(carried);
|
|
1193
1260
|
if (source !== options) return;
|
|
1194
1261
|
instance = created;
|
|
1195
|
-
|
|
1262
|
+
const mounted = mountTree(created, props);
|
|
1263
|
+
publish({ tree: mounted.tree, isView: mounted.isView, error: null });
|
|
1196
1264
|
};
|
|
1197
1265
|
const component = function SwiftRoot() {
|
|
1198
1266
|
const rendered = (0, import_react.useSyncExternalStore)(
|
|
@@ -1206,24 +1274,41 @@ function createRoot(mountTree, props) {
|
|
|
1206
1274
|
if (!rendered.tree) return null;
|
|
1207
1275
|
const deliver = (handlerId2, payload) => {
|
|
1208
1276
|
if (!instance) throw new Error("swift app received an event before it mounted");
|
|
1209
|
-
publish({
|
|
1277
|
+
publish({
|
|
1278
|
+
tree: instance.deliver(handlerId2, payload),
|
|
1279
|
+
isView: rendered.isView,
|
|
1280
|
+
error: null
|
|
1281
|
+
});
|
|
1210
1282
|
};
|
|
1211
|
-
|
|
1283
|
+
const resources = source?.resources;
|
|
1284
|
+
if (rendered.isView)
|
|
1285
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SwiftResourcesContext.Provider, { value: resources, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: rendered.tree.map((node) => renderNode(node, deliver, cache)) }) });
|
|
1286
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1287
|
+
SwiftTree,
|
|
1288
|
+
{
|
|
1289
|
+
tree: rendered.tree,
|
|
1290
|
+
deliver,
|
|
1291
|
+
cache,
|
|
1292
|
+
resources
|
|
1293
|
+
}
|
|
1294
|
+
);
|
|
1212
1295
|
};
|
|
1213
1296
|
return {
|
|
1214
1297
|
component,
|
|
1215
|
-
use(options, refreshKey) {
|
|
1216
|
-
const changed = source === null || source.hash !== options.hash || source.url !== options.url || refreshKey !== void 0 && refreshKey !== refresh;
|
|
1298
|
+
use(options, refreshKey, props) {
|
|
1299
|
+
const changed = source === null || source.hash !== options.hash || source.url !== options.url || JSON.stringify(source.resources ?? null) !== JSON.stringify(options.resources ?? null) || refreshKey !== void 0 && refreshKey !== refresh;
|
|
1217
1300
|
if (changed) {
|
|
1218
1301
|
source = options;
|
|
1219
1302
|
refresh = refreshKey;
|
|
1303
|
+
const next = props ?? {};
|
|
1220
1304
|
swap = swap.then(
|
|
1221
|
-
() => apply(options),
|
|
1222
|
-
() => apply(options)
|
|
1305
|
+
() => apply(options, next),
|
|
1306
|
+
() => apply(options, next)
|
|
1223
1307
|
);
|
|
1224
1308
|
swap.catch((error) => {
|
|
1225
1309
|
publish({
|
|
1226
1310
|
tree: null,
|
|
1311
|
+
isView: false,
|
|
1227
1312
|
error: error instanceof Error ? error : new Error(String(error))
|
|
1228
1313
|
});
|
|
1229
1314
|
});
|
|
@@ -1232,11 +1317,6 @@ function createRoot(mountTree, props) {
|
|
|
1232
1317
|
}
|
|
1233
1318
|
};
|
|
1234
1319
|
}
|
|
1235
|
-
function createSwiftModule(options) {
|
|
1236
|
-
const rootId = options.rootId ?? "root";
|
|
1237
|
-
const slot = slotFor(rootId, (instance) => instance.mount(), { current: {} });
|
|
1238
|
-
return slot.root.use(options);
|
|
1239
|
-
}
|
|
1240
1320
|
function propsSignature(props) {
|
|
1241
1321
|
try {
|
|
1242
1322
|
return JSON.stringify(props, (_key, value) => {
|
|
@@ -1253,22 +1333,21 @@ function propsSignature(props) {
|
|
|
1253
1333
|
);
|
|
1254
1334
|
}
|
|
1255
1335
|
}
|
|
1256
|
-
function
|
|
1257
|
-
const rootId = options.rootId ?? "
|
|
1258
|
-
const slot = slotFor(
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1336
|
+
function createSwiftEntry(options) {
|
|
1337
|
+
const rootId = options.rootId ?? "root";
|
|
1338
|
+
const slot = slotFor(
|
|
1339
|
+
rootId,
|
|
1340
|
+
(instance, props) => instance.hasView() ? { tree: instance.mountView(props), isView: true } : { tree: instance.mount(), isView: false }
|
|
1341
|
+
);
|
|
1342
|
+
return function SwiftEntry(props) {
|
|
1262
1343
|
if (props.children !== void 0) {
|
|
1263
|
-
throw new Error("swift
|
|
1344
|
+
throw new Error("swift entries take data props, not children");
|
|
1264
1345
|
}
|
|
1265
|
-
slot.
|
|
1266
|
-
const component = slot.root.use(options, propsSignature(props));
|
|
1346
|
+
const component = slot.root.use(options, propsSignature(props), props);
|
|
1267
1347
|
return (0, import_react.createElement)(component);
|
|
1268
1348
|
};
|
|
1269
1349
|
}
|
|
1270
1350
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1271
1351
|
0 && (module.exports = {
|
|
1272
|
-
|
|
1273
|
-
createSwiftView
|
|
1352
|
+
createSwiftEntry
|
|
1274
1353
|
});
|
package/dist-lib/vite.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.524 | (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;
|
|
@@ -763,6 +763,75 @@ var import_node_os2 = __toESM(require("node:os"), 1);
|
|
|
763
763
|
var import_node_path4 = __toESM(require("node:path"), 1);
|
|
764
764
|
var import_node_util = require("node:util");
|
|
765
765
|
|
|
766
|
+
// ../sootsim-swift/src/bundleAssets.ts
|
|
767
|
+
var RASTER_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
768
|
+
".avif",
|
|
769
|
+
".bmp",
|
|
770
|
+
".gif",
|
|
771
|
+
".ico",
|
|
772
|
+
".jpeg",
|
|
773
|
+
".jpg",
|
|
774
|
+
".png",
|
|
775
|
+
".webp"
|
|
776
|
+
]);
|
|
777
|
+
function extOf(file) {
|
|
778
|
+
const dot = file.lastIndexOf(".");
|
|
779
|
+
return dot < 0 ? "" : file.slice(dot).toLowerCase();
|
|
780
|
+
}
|
|
781
|
+
function baseOf(file) {
|
|
782
|
+
const slash = file.lastIndexOf("/");
|
|
783
|
+
return slash < 0 ? file : file.slice(slash + 1);
|
|
784
|
+
}
|
|
785
|
+
function pickImagesetFile(images) {
|
|
786
|
+
const rasters = images.filter(
|
|
787
|
+
(image) => typeof image.filename === "string" && RASTER_EXTENSIONS.has(extOf(image.filename))
|
|
788
|
+
);
|
|
789
|
+
if (rasters.length === 0) return null;
|
|
790
|
+
const rank = (scale) => scale === "2x" ? 0 : scale === "3x" ? 1 : scale === "1x" ? 2 : 3;
|
|
791
|
+
return [...rasters].sort((a, b) => rank(a.scale) - rank(b.scale))[0].filename;
|
|
792
|
+
}
|
|
793
|
+
function imagesetName(contentsPath) {
|
|
794
|
+
const dir = contentsPath.split("/").slice(0, -1).join("/");
|
|
795
|
+
const leaf = baseOf(dir);
|
|
796
|
+
if (!leaf.endsWith(".imageset")) return null;
|
|
797
|
+
return leaf.slice(0, -".imageset".length) || null;
|
|
798
|
+
}
|
|
799
|
+
function isFlatResourceImage(path7) {
|
|
800
|
+
return path7.split("/").includes("Resources") && RASTER_EXTENSIONS.has(extOf(path7));
|
|
801
|
+
}
|
|
802
|
+
function enumerateBundleImages(paths, readText) {
|
|
803
|
+
const table = [];
|
|
804
|
+
const seen = /* @__PURE__ */ new Set();
|
|
805
|
+
const catalogs = paths.filter((path7) => baseOf(path7) === "Contents.json");
|
|
806
|
+
for (const contentsPath of catalogs) {
|
|
807
|
+
const name = imagesetName(contentsPath);
|
|
808
|
+
if (name === null || seen.has(name)) continue;
|
|
809
|
+
let parsed;
|
|
810
|
+
try {
|
|
811
|
+
const text = readText(contentsPath);
|
|
812
|
+
if (text === null) continue;
|
|
813
|
+
parsed = JSON.parse(text);
|
|
814
|
+
} catch {
|
|
815
|
+
continue;
|
|
816
|
+
}
|
|
817
|
+
const images = parsed?.images;
|
|
818
|
+
if (!Array.isArray(images)) continue;
|
|
819
|
+
const dir = contentsPath.split("/").slice(0, -1).join("/");
|
|
820
|
+
const file = pickImagesetFile(images);
|
|
821
|
+
if (file === null || file.includes("/") || file.includes("\\")) continue;
|
|
822
|
+
seen.add(name);
|
|
823
|
+
table.push({ name, file: `${dir}/${file}` });
|
|
824
|
+
}
|
|
825
|
+
for (const path7 of paths) {
|
|
826
|
+
if (!isFlatResourceImage(path7)) continue;
|
|
827
|
+
const name = baseOf(path7).slice(0, -extOf(path7).length);
|
|
828
|
+
if (name === "" || seen.has(name)) continue;
|
|
829
|
+
seen.add(name);
|
|
830
|
+
table.push({ name, file: path7 });
|
|
831
|
+
}
|
|
832
|
+
return table;
|
|
833
|
+
}
|
|
834
|
+
|
|
766
835
|
// ../sootsim-swift/toolchain.json
|
|
767
836
|
var toolchain_default = {
|
|
768
837
|
release: "swift-6.3-RELEASE",
|
|
@@ -778,13 +847,19 @@ var TOOLCHAIN_BIN = import_node_path4.default.join(
|
|
|
778
847
|
var WASM_SDK = `${toolchain_default.release}_wasm`;
|
|
779
848
|
var WASM_TRIPLE = "wasm32-unknown-wasip1";
|
|
780
849
|
var ARTIFACT_PATH = "/__rnx/swift/";
|
|
850
|
+
var RESOURCE_PATH = "/__rnx/swift-res/";
|
|
781
851
|
var VIRTUAL_PREFIX = "\0rnx-swift:";
|
|
782
852
|
var projects = /* @__PURE__ */ new Map();
|
|
783
853
|
var devServer;
|
|
784
854
|
function projectFor(packagePath) {
|
|
785
855
|
const existing = projects.get(packagePath);
|
|
786
856
|
if (existing) return existing;
|
|
787
|
-
const created = {
|
|
857
|
+
const created = {
|
|
858
|
+
packagePath,
|
|
859
|
+
artifact: null,
|
|
860
|
+
building: null,
|
|
861
|
+
resourceFiles: /* @__PURE__ */ new Map()
|
|
862
|
+
};
|
|
788
863
|
projects.set(packagePath, created);
|
|
789
864
|
return created;
|
|
790
865
|
}
|
|
@@ -803,6 +878,84 @@ function sourceFiles(root) {
|
|
|
803
878
|
walk(root);
|
|
804
879
|
return found;
|
|
805
880
|
}
|
|
881
|
+
function resourceCandidateFiles(root) {
|
|
882
|
+
const found = [];
|
|
883
|
+
const walk = (dir) => {
|
|
884
|
+
for (const entry of import_node_fs3.default.readdirSync(dir, { withFileTypes: true })) {
|
|
885
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === ".build")
|
|
886
|
+
continue;
|
|
887
|
+
const full = import_node_path4.default.join(dir, entry.name);
|
|
888
|
+
if (entry.isDirectory()) {
|
|
889
|
+
if (full !== root && import_node_fs3.default.existsSync(import_node_path4.default.join(full, "Package.swift"))) continue;
|
|
890
|
+
walk(full);
|
|
891
|
+
} else {
|
|
892
|
+
found.push(full);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
};
|
|
896
|
+
walk(root);
|
|
897
|
+
return found;
|
|
898
|
+
}
|
|
899
|
+
var RESOURCE_CONTENT_TYPES = {
|
|
900
|
+
".avif": "image/avif",
|
|
901
|
+
".bmp": "image/bmp",
|
|
902
|
+
".gif": "image/gif",
|
|
903
|
+
".ico": "image/x-icon",
|
|
904
|
+
".jpeg": "image/jpeg",
|
|
905
|
+
".jpg": "image/jpeg",
|
|
906
|
+
".png": "image/png",
|
|
907
|
+
".webp": "image/webp"
|
|
908
|
+
};
|
|
909
|
+
function buildSwiftResourceTable(project, baseUrl) {
|
|
910
|
+
const absolute = resourceCandidateFiles(project.packagePath);
|
|
911
|
+
const relative2 = absolute.map(
|
|
912
|
+
(file) => import_node_path4.default.relative(project.packagePath, file).split(import_node_path4.default.sep).join(import_node_path4.default.posix.sep)
|
|
913
|
+
);
|
|
914
|
+
const byRelative = new Map(absolute.map((file, index) => [relative2[index], file]));
|
|
915
|
+
const found = enumerateBundleImages(relative2, (candidate) => {
|
|
916
|
+
const file = byRelative.get(candidate);
|
|
917
|
+
if (!file || import_node_path4.default.basename(file) !== "Contents.json") return null;
|
|
918
|
+
try {
|
|
919
|
+
return import_node_fs3.default.readFileSync(file, "utf8");
|
|
920
|
+
} catch {
|
|
921
|
+
return null;
|
|
922
|
+
}
|
|
923
|
+
});
|
|
924
|
+
const table = {};
|
|
925
|
+
const watched = [];
|
|
926
|
+
const registered = /* @__PURE__ */ new Map();
|
|
927
|
+
for (const { name, file } of found) {
|
|
928
|
+
const disk = byRelative.get(file);
|
|
929
|
+
if (!disk) continue;
|
|
930
|
+
let bytes;
|
|
931
|
+
try {
|
|
932
|
+
bytes = import_node_fs3.default.readFileSync(disk);
|
|
933
|
+
} catch {
|
|
934
|
+
continue;
|
|
935
|
+
}
|
|
936
|
+
const hash = (0, import_node_crypto2.createHash)("sha256").update(bytes).digest("hex").slice(0, 16);
|
|
937
|
+
const ext = import_node_path4.default.posix.extname(file).toLowerCase();
|
|
938
|
+
table[name] = `${baseUrl}${RESOURCE_PATH}${hash}${ext}`;
|
|
939
|
+
watched.push(file);
|
|
940
|
+
const contents = file.replace(/\/[^/]+$/, "/Contents.json");
|
|
941
|
+
if (byRelative.has(contents)) watched.push(contents);
|
|
942
|
+
registered.set(`${hash}${ext}`, disk);
|
|
943
|
+
}
|
|
944
|
+
project.resourceFiles = registered;
|
|
945
|
+
return { table, watched };
|
|
946
|
+
}
|
|
947
|
+
function serveSwiftResource(project, key) {
|
|
948
|
+
const disk = project.resourceFiles.get(key);
|
|
949
|
+
if (!disk) return null;
|
|
950
|
+
try {
|
|
951
|
+
return {
|
|
952
|
+
bytes: import_node_fs3.default.readFileSync(disk),
|
|
953
|
+
contentType: RESOURCE_CONTENT_TYPES[import_node_path4.default.extname(disk).toLowerCase()] ?? "application/octet-stream"
|
|
954
|
+
};
|
|
955
|
+
} catch {
|
|
956
|
+
return null;
|
|
957
|
+
}
|
|
958
|
+
}
|
|
806
959
|
function linkedModuleRoots(packagePath) {
|
|
807
960
|
let manifest;
|
|
808
961
|
try {
|
|
@@ -829,14 +982,18 @@ function sourceStamp(packagePath) {
|
|
|
829
982
|
}
|
|
830
983
|
return hash.digest("hex").slice(0, 16);
|
|
831
984
|
}
|
|
832
|
-
function
|
|
833
|
-
|
|
985
|
+
function entryRootId(packagePath, file) {
|
|
986
|
+
const relative2 = import_node_path4.default.relative(packagePath, file).split(import_node_path4.default.sep).join(import_node_path4.default.posix.sep);
|
|
987
|
+
return `${import_node_path4.default.basename(packagePath)}${import_node_path4.default.posix.sep}${relative2}`;
|
|
834
988
|
}
|
|
835
|
-
function
|
|
989
|
+
function serverOrigin() {
|
|
836
990
|
const address = devServer?.httpServer?.address();
|
|
837
991
|
const port = address && typeof address === "object" ? address.port : devServer?.config.server.port;
|
|
838
|
-
if (!port) throw new Error("the swift
|
|
839
|
-
return `http://localhost:${port}
|
|
992
|
+
if (!port) throw new Error("the swift urls need the dev server port");
|
|
993
|
+
return `http://localhost:${port}`;
|
|
994
|
+
}
|
|
995
|
+
function artifactUrl(project, artifact) {
|
|
996
|
+
return `${serverOrigin()}${ARTIFACT_PATH}${artifact.hash}.wasm`;
|
|
840
997
|
}
|
|
841
998
|
function builtArtifact(packagePath) {
|
|
842
999
|
const binDir = import_node_path4.default.join(packagePath, ".build", WASM_TRIPLE, "release");
|
|
@@ -927,14 +1084,6 @@ function packageFor(file) {
|
|
|
927
1084
|
`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`
|
|
928
1085
|
);
|
|
929
1086
|
}
|
|
930
|
-
function isViewPackage(packagePath) {
|
|
931
|
-
const main = /@main\s+(?:\w+\s+)*(?:struct|class|enum|actor)\s+\w+[^{]*:\s*[^{]*\bRNXPackage\b/;
|
|
932
|
-
for (const file of sourceFiles(packagePath)) {
|
|
933
|
-
const text = import_node_fs3.default.readFileSync(file, "utf8").replace(/^\s*\/\/.*$/gm, "");
|
|
934
|
-
if (main.test(text)) return true;
|
|
935
|
-
}
|
|
936
|
-
return false;
|
|
937
|
-
}
|
|
938
1087
|
function swiftPlugin(options = {}) {
|
|
939
1088
|
return {
|
|
940
1089
|
name: "rnx-swift",
|
|
@@ -968,17 +1117,19 @@ function swiftPlugin(options = {}) {
|
|
|
968
1117
|
this.warn(error instanceof Error ? error.message : String(error));
|
|
969
1118
|
artifact = project.artifact;
|
|
970
1119
|
}
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
1120
|
+
let resources = {};
|
|
1121
|
+
try {
|
|
1122
|
+
const built = buildSwiftResourceTable(project, serverOrigin());
|
|
1123
|
+
resources = built.table;
|
|
1124
|
+
for (const watched of built.watched) this.addWatchFile(watched);
|
|
1125
|
+
} catch (error) {
|
|
1126
|
+
this.warn(
|
|
1127
|
+
`swift resources for ${packagePath}: ${error instanceof Error ? error.message : String(error)}`
|
|
1128
|
+
);
|
|
978
1129
|
}
|
|
979
1130
|
return [
|
|
980
|
-
`import {
|
|
981
|
-
`export default
|
|
1131
|
+
`import { createSwiftEntry } from 'rnxsim/swift'`,
|
|
1132
|
+
`export default createSwiftEntry({ url: ${JSON.stringify(artifactUrl(project, artifact))}, hash: ${JSON.stringify(artifact.hash)}, rootId: ${JSON.stringify(entryRootId(packagePath, file))}, resources: ${JSON.stringify(resources)} })`,
|
|
982
1133
|
""
|
|
983
1134
|
].join("\n");
|
|
984
1135
|
},
|
|
@@ -986,6 +1137,20 @@ function swiftPlugin(options = {}) {
|
|
|
986
1137
|
devServer = server;
|
|
987
1138
|
server.middlewares.use((req, res, next) => {
|
|
988
1139
|
const url = (req.url ?? "").split("?")[0];
|
|
1140
|
+
if (url.startsWith(RESOURCE_PATH)) {
|
|
1141
|
+
for (const project of projects.values()) {
|
|
1142
|
+
const served = serveSwiftResource(project, url.slice(RESOURCE_PATH.length));
|
|
1143
|
+
if (served) {
|
|
1144
|
+
res.setHeader("access-control-allow-origin", "*");
|
|
1145
|
+
res.setHeader("content-type", served.contentType);
|
|
1146
|
+
res.end(served.bytes);
|
|
1147
|
+
return;
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
res.statusCode = 404;
|
|
1151
|
+
res.end("swift resource is stale");
|
|
1152
|
+
return;
|
|
1153
|
+
}
|
|
989
1154
|
if (!url.startsWith(ARTIFACT_PATH)) {
|
|
990
1155
|
next();
|
|
991
1156
|
return;
|