@steerprotocol/app-loader 3.0.5 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +86 -0
  2. package/lib/browser.d.ts +5 -2
  3. package/lib/browser.mjs +253 -73
  4. package/lib/browser.mjs.map +1 -1
  5. package/lib/index.cjs +3693 -108
  6. package/lib/index.cjs.map +1 -1
  7. package/lib/index.d.ts +5 -2
  8. package/lib/index.mjs +3693 -108
  9. package/lib/index.mjs.map +1 -1
  10. package/lib/internal/asyncHostCalls.d.ts +37 -0
  11. package/lib/internal/instantiate.d.ts +3 -4
  12. package/lib/internal/loadOptions.d.ts +1 -0
  13. package/lib/internal/panoptic/deps.d.ts +24 -0
  14. package/lib/internal/panoptic/dynamicJobs/fragments.d.ts +10 -0
  15. package/lib/internal/panoptic/dynamicJobs/renderExecuteJob.d.ts +8 -0
  16. package/lib/internal/panoptic/fragments/collateral.d.ts +5 -0
  17. package/lib/internal/panoptic/fragments/erc20.d.ts +3 -0
  18. package/lib/internal/panoptic/fragments/hypovault.d.ts +12 -0
  19. package/lib/internal/panoptic/fragments/merkle.d.ts +22 -0
  20. package/lib/internal/panoptic/fragments/panoptic.d.ts +17 -0
  21. package/lib/internal/panoptic/fragments/permit2.d.ts +3 -0
  22. package/lib/internal/panoptic/fragments/support.d.ts +16 -0
  23. package/lib/internal/panoptic/fragments/uniswap.d.ts +10 -0
  24. package/lib/internal/panoptic/fragments/weth.d.ts +19 -0
  25. package/lib/internal/panoptic/handlers.d.ts +27 -0
  26. package/lib/internal/panoptic/protocol.d.ts +29 -0
  27. package/lib/internal/panoptic/reads/account.d.ts +11 -0
  28. package/lib/internal/panoptic/reads/greeks.d.ts +5 -0
  29. package/lib/internal/panoptic/reads/hypovault.d.ts +7 -0
  30. package/lib/internal/panoptic/reads/pool.d.ts +10 -0
  31. package/lib/internal/panoptic/reads/uniswap.d.ts +6 -0
  32. package/lib/internal/panoptic/support.d.ts +20 -0
  33. package/lib/internal/panopticBrowserRuntime.d.ts +6 -0
  34. package/lib/internal/panopticDtos.d.ts +72 -0
  35. package/lib/internal/panopticHostEnvelope.d.ts +2 -0
  36. package/lib/internal/panopticHostImport.d.ts +17 -0
  37. package/lib/internal/panopticJsonArgs.d.ts +26 -0
  38. package/lib/internal/panopticRuntime.d.ts +12 -0
  39. package/lib/internal/panopticScalars.d.ts +10 -0
  40. package/lib/internal/panopticSerialization.d.ts +19 -0
  41. package/lib/internal/panopticSources.d.ts +22 -0
  42. package/lib/loadOptions.d.ts +5 -0
  43. package/lib/node.cjs +3640 -73
  44. package/lib/node.cjs.map +1 -1
  45. package/lib/node.d.ts +5 -2
  46. package/lib/node.mjs +3640 -73
  47. package/lib/node.mjs.map +1 -1
  48. package/lib/panoptic.cjs +19 -0
  49. package/lib/panoptic.cjs.map +1 -0
  50. package/lib/panoptic.d.ts +56 -0
  51. package/lib/panoptic.mjs +1 -0
  52. package/lib/panoptic.mjs.map +1 -0
  53. package/package.json +44 -3
package/README.md CHANGED
@@ -126,6 +126,79 @@ The returned wasm wrapper exposes the module surface when available, including:
126
126
  - `transform()`
127
127
  - `reset()`
128
128
 
129
+ ### Panoptic RuntimeAdapter
130
+
131
+ The Panoptic RuntimeAdapter is an additive Node-only feature. It is intended as
132
+ a minor release surface, not a major-version runtime contract change:
133
+
134
+ - existing `as-fetch` imports keep the same module names, function names, and
135
+ argument shapes
136
+ - existing `env.ccxt_fetchOHLCV` keeps the same import name and argument shape
137
+ - `env.panoptic_call` is added for wasm bundles that opt into Panoptic helpers
138
+ - Panoptic SDK dependencies are optional unless a Panoptic method is called
139
+
140
+ Browser entrypoints reject `panoptic` options explicitly until browser support
141
+ is designed.
142
+
143
+ Panoptic support is optional. Consumers that call Panoptic methods must install
144
+ the optional peers used by the adapter:
145
+
146
+ ```bash
147
+ npm install @panoptic-eng/sdk@1.0.15 viem
148
+ ```
149
+
150
+ Some SDK entrypoints also declare React/Wagmi peers; packaged SDK smoke tests
151
+ install the full SDK peer set.
152
+
153
+ WASM calls the adapter through the additive async import:
154
+
155
+ ```ts
156
+ env.panoptic_call(methodPtr, paramsJsonPtr)
157
+ ```
158
+
159
+ Only JSON-serializable DTOs cross that boundary. SDK objects, viem clients,
160
+ providers, wallet clients, signers, and transaction submission helpers stay in
161
+ the JavaScript host. The adapter returns deterministic reads, protocol calldata
162
+ parts, and DynamicJobs fragments; it does not sign or submit transactions.
163
+
164
+ The stable helper families are:
165
+
166
+ - read snapshots: `pool.*`, `account.*`, `greeks.*`, `hypovault.*`, and
167
+ `uniswap.*` read/quote helpers
168
+ - protocol fragments: `erc20.*Fragment`, `permit2.*Fragment`,
169
+ `collateral.*Fragment`, `hypovault.*Fragment`, `merkle.*Fragment`, and
170
+ `panoptic.*Fragment`
171
+ - calldata parts for nested composition: Panoptic dispatch, HypoVault manager
172
+ `manage`, WETH wrap/unwrap calls, and Universal Router v3 exact-in execute
173
+ - DynamicJobs rendering: `dynamicJobs.renderExecuteJob`
174
+
175
+ DynamicJobs fragments use the same shape the strategy already emits:
176
+ `target + userProvidedData + strategyProvidedData`. Fragment builders take
177
+ semantic contract inputs and return that fragment shape directly. App-loader
178
+ does not duplicate the orchestrator/job registration manifest:
179
+
180
+ ```ts
181
+ await loadWasm(wasmBytes, {}, {
182
+ panoptic: {
183
+ sourceRegistry: {
184
+ sources: [{ sourceId: 'base-mainnet', chainId: '8453', rpcUrl: 'https://base.example' }],
185
+ },
186
+ },
187
+ });
188
+ ```
189
+
190
+ `dynamicJobs.renderExecuteJob` renders fragments into
191
+ `executeJob(address[],bytes[],bytes[])`. It validates only fragment shape,
192
+ zero native value, and serializable bytes, then returns the payload arrays.
193
+ Whether `target + userProvidedData` is registered/executable is handled later
194
+ by the orchestrator and DynamicJobs/contracts. The actual execution boundary
195
+ remains the DynamicJobs registration, the orchestrator caller check, and the
196
+ destination contracts.
197
+
198
+ The adapter intentionally does not expose host signing, wallet clients, write
199
+ transaction helpers, or SDK object graphs across the wasm boundary.
200
+ `calldata.*` names are not part of the stable RuntimeAdapter API.
201
+
129
202
  ## Development
130
203
 
131
204
  ### Build
@@ -161,6 +234,19 @@ npm run test:consumers
161
234
  This command builds the package, packs it, installs the tarball into fixture apps, validates the packed export artifacts,
162
235
  and runs each fixture check.
163
236
 
237
+ The Panoptic SDK package smoke test additionally installs `@panoptic-eng/sdk@1.0.15`
238
+ and exercises a real SDK-backed AS fixture:
239
+
240
+ ```bash
241
+ npm run test:panoptic-sdk-smoke
242
+ ```
243
+
244
+ The full verification gate is:
245
+
246
+ ```bash
247
+ npm run verify:phase0
248
+ ```
249
+
164
250
  ## Migration Notes
165
251
 
166
252
  Version 2 changes the package runtime contract.
package/lib/browser.d.ts CHANGED
@@ -2,6 +2,7 @@
2
2
  * Browser-only entrypoints for loading Steer wasm bundles.
3
3
  */
4
4
  import { Candle, RawTradeData } from './internal/instantiate';
5
+ import type { LoadWasmOptions } from './loadOptions';
5
6
  import type { WasmModule } from './WasmModule';
6
7
  /**
7
8
  * Load a wasm bundle synchronously. Only accepts the actual binary data.
@@ -9,13 +10,15 @@ import type { WasmModule } from './WasmModule';
9
10
  * @param imports - Imports
10
11
  * @returns
11
12
  */
12
- declare function loadWasmSync(input: ArrayBuffer, imports?: {}): WasmModule;
13
+ declare function loadWasmSync(input: ArrayBuffer, imports?: {}, options?: LoadWasmOptions): WasmModule;
13
14
  /**
14
15
  * Load a wasm bundle asynchronously. Accepts the actual binary data or URL.
15
16
  * @param input - Wasm bundle data or URL
16
17
  * @param imports - Imports
17
18
  * @returns
18
19
  */
19
- declare function loadWasm(input: string | ArrayBuffer, imports?: {}): Promise<WasmModule>;
20
+ declare function loadWasm(input: string | ArrayBuffer, imports?: {}, options?: LoadWasmOptions): Promise<WasmModule>;
20
21
  export type { WasmModule } from './WasmModule';
22
+ export type { LoadWasmOptions } from './loadOptions';
23
+ export type { PanopticAuditEvent, PanopticClientCacheOptions, PanopticJsonValue, PanopticOperationOptions, PanopticRpcSource, PanopticRuntimeOptions, PanopticSourceRegistry, PanopticSubgraphSource, SourceMeta, } from './panoptic';
21
24
  export { loadWasm, loadWasmSync, Candle, RawTradeData };
package/lib/browser.mjs CHANGED
@@ -173,6 +173,144 @@ var RawTradeData = class {
173
173
  }
174
174
  };
175
175
 
176
+ // src/internal/asyncHostCalls.ts
177
+ function createAsyncHostCallSlot() {
178
+ let stagedHostCall = null;
179
+ let completedHostCall = null;
180
+ function stage(call) {
181
+ if (stagedHostCall || completedHostCall) {
182
+ throw new Error("Only one async host call can be staged per asyncify unwind.");
183
+ }
184
+ stagedHostCall = call;
185
+ }
186
+ async function complete() {
187
+ if (!stagedHostCall) {
188
+ throw new Error("Asyncify unwound without a staged host call.");
189
+ }
190
+ const call = stagedHostCall;
191
+ stagedHostCall = null;
192
+ if (call.kind === "fetch-buffer") {
193
+ completedHostCall = { kind: "fetch-buffer", value: await call.run() };
194
+ return;
195
+ }
196
+ if (call.kind === "ccxt-ohlcv") {
197
+ completedHostCall = { kind: "ccxt-ohlcv", value: await call.run() };
198
+ return;
199
+ }
200
+ completedHostCall = { kind: "panoptic-json", value: await call.run() };
201
+ }
202
+ function take(kind) {
203
+ if (!completedHostCall) {
204
+ throw new Error(`Asyncify rewind for ${kind} did not have a completed host result.`);
205
+ }
206
+ if (completedHostCall.kind !== kind) {
207
+ throw new Error(`Asyncify rewind expected ${kind} but found ${completedHostCall.kind}.`);
208
+ }
209
+ const call = completedHostCall;
210
+ completedHostCall = null;
211
+ return call;
212
+ }
213
+ function reset() {
214
+ stagedHostCall = null;
215
+ completedHostCall = null;
216
+ }
217
+ return { stage, complete, take, reset };
218
+ }
219
+
220
+ // src/internal/panoptic/protocol.ts
221
+ var DEFAULT_MAX_REQUEST_BYTES = 512 * 1024;
222
+ function parsePanopticRequest(value, maxBytes = DEFAULT_MAX_REQUEST_BYTES) {
223
+ if (utf8ByteLength(value) > maxBytes) {
224
+ throw new Error(`Invalid Panoptic request JSON: request exceeds maximum size ${maxBytes} bytes.`);
225
+ }
226
+ let parsed;
227
+ try {
228
+ parsed = JSON.parse(value);
229
+ } catch (error) {
230
+ throw new Error(`Invalid Panoptic request JSON: ${error instanceof Error ? error.message : String(error)}`);
231
+ }
232
+ if (!isJsonObject(parsed) || !isJsonValue(parsed)) {
233
+ throw new Error("Invalid Panoptic request JSON: expected a JSON-safe object envelope.");
234
+ }
235
+ return parsed;
236
+ }
237
+ function assertPanopticSuccessResponse(value) {
238
+ const keys = isJsonObject(value) ? Object.keys(value) : [];
239
+ if (!isJsonObject(value) || value.ok !== true || !("result" in value) || !isJsonValue(value.result) || keys.length !== 2 || !keys.includes("ok") || !keys.includes("result")) {
240
+ throw new Error("Panoptic runtime adapter returned an invalid success response.");
241
+ }
242
+ }
243
+ function isJsonObject(value) {
244
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
245
+ return false;
246
+ }
247
+ const prototype = Object.getPrototypeOf(value);
248
+ return prototype === Object.prototype || prototype === null;
249
+ }
250
+ function isJsonValue(value) {
251
+ if (value === null) return true;
252
+ const valueType = typeof value;
253
+ if (valueType === "string" || valueType === "number" || valueType === "boolean") {
254
+ return Number.isFinite(value) || valueType !== "number";
255
+ }
256
+ if (Array.isArray(value)) {
257
+ return value.every(isJsonValue);
258
+ }
259
+ if (isJsonObject(value)) {
260
+ return Object.values(value).every(isJsonValue);
261
+ }
262
+ return false;
263
+ }
264
+ function utf8ByteLength(value) {
265
+ let bytes = 0;
266
+ for (let i = 0; i < value.length; i++) {
267
+ const codePoint = value.codePointAt(i) || 0;
268
+ if (codePoint <= 127) {
269
+ bytes += 1;
270
+ } else if (codePoint <= 2047) {
271
+ bytes += 2;
272
+ } else if (codePoint <= 65535) {
273
+ bytes += 3;
274
+ } else {
275
+ bytes += 4;
276
+ i += 1;
277
+ }
278
+ }
279
+ return bytes;
280
+ }
281
+
282
+ // src/internal/panopticHostImport.ts
283
+ function createPanopticHostImport(options) {
284
+ return (methodPtr, paramsJsonPtr) => {
285
+ if (options.getAsyncifyState() === options.rewindingState) {
286
+ options.stopRewind();
287
+ const completed = options.hostCalls.take("panoptic-json");
288
+ return options.lowerString(completed.value, "wasm");
289
+ }
290
+ const method = options.liftString(methodPtr);
291
+ const paramsJson = options.liftString(paramsJsonPtr) || "{}";
292
+ options.hostCalls.stage({
293
+ kind: "panoptic-json",
294
+ run: async () => {
295
+ if (!method) {
296
+ throw new Error("Panoptic method not provided.");
297
+ }
298
+ const request = parsePanopticRequest(paramsJson);
299
+ const response = await callPanopticOrThrow(options.runtime, method, request);
300
+ assertPanopticSuccessResponse(response);
301
+ return JSON.stringify({ ok: true, result: response.result });
302
+ }
303
+ });
304
+ options.startUnwind();
305
+ };
306
+ }
307
+ async function callPanopticOrThrow(runtime, method, request) {
308
+ if (!runtime.callPanoptic) {
309
+ throw new Error("Panoptic runtime adapter is not available in this runtime.");
310
+ }
311
+ return runtime.callPanoptic(method, request);
312
+ }
313
+
176
314
  // src/internal/instantiate.ts
177
315
  function instantiate(module, imports = {}, runtime = {}) {
178
316
  let WASM_MEMORY;
@@ -181,9 +319,7 @@ function instantiate(module, imports = {}, runtime = {}) {
181
319
  let ASYNCIFY_PTR = 0;
182
320
  let ASYNCIFY_MEM;
183
321
  let ASYNCIFY_INITIALIZED = false;
184
- let fetchFn = null;
185
- let ccxtFn = null;
186
- let detachedValue = null;
322
+ const hostCalls = createAsyncHostCallSlot();
187
323
  let executeInFlight = false;
188
324
  const pinScopes = [];
189
325
  const adaptedImports = Object.assign(
@@ -281,31 +417,50 @@ function instantiate(module, imports = {}, runtime = {}) {
281
417
  const currentState = WASM_EXPORTS.asyncify_get_state();
282
418
  if (currentState === 2 /* Rewinding */) {
283
419
  WASM_EXPORTS.asyncify_stop_rewind();
420
+ const completed = hostCalls.take("ccxt-ohlcv");
284
421
  const ptr = __lowerStaticArray(
285
422
  (pointer, value) => {
286
- __setU32(pointer, __lowerStaticArray(__setF64, 7, 3, value, Float64Array));
423
+ __setU32(pointer, __lowerStaticArray(__setF64, 7, 3, value, Float64Array, "wasm"));
287
424
  },
288
425
  8,
289
426
  2,
290
- detachedValue
427
+ completed.value,
428
+ null,
429
+ "host"
291
430
  );
292
431
  return ptr;
293
432
  }
294
433
  const _exchange = __liftString(exchangeId);
295
434
  const _symbol = __liftString(symbol);
296
435
  const _timeframe = __liftString(timeframe);
297
- ccxtFn = async () => {
298
- if (!_exchange || !_symbol || !_timeframe)
299
- throw new Error("Exchange, Symbol, or Timeframe not provided when fetching OHCLV data.");
300
- const ccxt = await getCcxtOrThrow(runtime);
301
- const data = await new ccxt[_exchange]({
302
- apiKey: "",
303
- secret: ""
304
- }).fetchOHLCV(_symbol, _timeframe, since, limit);
305
- return data;
306
- };
436
+ hostCalls.stage({
437
+ kind: "ccxt-ohlcv",
438
+ run: async () => {
439
+ if (!_exchange || !_symbol || !_timeframe)
440
+ throw new Error("Exchange, Symbol, or Timeframe not provided when fetching OHCLV data.");
441
+ const ccxt = await getCcxtOrThrow(runtime);
442
+ const data = await new ccxt[_exchange]({
443
+ apiKey: "",
444
+ secret: ""
445
+ }).fetchOHLCV(_symbol, _timeframe, since, limit);
446
+ return data;
447
+ }
448
+ });
307
449
  WASM_EXPORTS.asyncify_start_unwind(ASYNCIFY_PTR);
308
- }
450
+ },
451
+ panoptic_call: createPanopticHostImport({
452
+ runtime,
453
+ hostCalls,
454
+ // @ts-ignore
455
+ getAsyncifyState: () => WASM_EXPORTS.asyncify_get_state(),
456
+ rewindingState: 2 /* Rewinding */,
457
+ // @ts-ignore
458
+ stopRewind: () => WASM_EXPORTS.asyncify_stop_rewind(),
459
+ // @ts-ignore
460
+ startUnwind: () => WASM_EXPORTS.asyncify_start_unwind(ASYNCIFY_PTR),
461
+ liftString: __liftString,
462
+ lowerString: __lowerString
463
+ })
309
464
  },
310
465
  "as-fetch": {
311
466
  /**
@@ -336,25 +491,28 @@ function instantiate(module, imports = {}, runtime = {}) {
336
491
  const currentState = WASM_EXPORTS.asyncify_get_state();
337
492
  if (currentState === 2 /* Rewinding */) {
338
493
  WASM_EXPORTS.asyncify_stop_rewind();
339
- const ptr = __lowerBuffer(detachedValue);
340
- detachedValue = null;
494
+ const completed = hostCalls.take("fetch-buffer");
495
+ const ptr = __lowerBuffer(completed.value, "wasm");
341
496
  return ptr;
342
497
  }
343
- fetchFn = async () => {
344
- const fetchImpl = await getFetchOrThrow(runtime);
345
- const res = await fetchImpl(__liftString(url) || "", {
346
- method: "POST",
347
- mode: modeToString(mode) || "cors",
348
- headers: __liftArray(
349
- (pointer) => __liftArray((pointer2) => __liftString(__getU32(pointer2)), 2, __getU32(pointer)),
350
- 2,
351
- headers
352
- ) || [],
353
- body: __liftBuffer(body)
354
- });
355
- const value = await res.arrayBuffer();
356
- return value;
357
- };
498
+ hostCalls.stage({
499
+ kind: "fetch-buffer",
500
+ run: async () => {
501
+ const fetchImpl = await getFetchOrThrow(runtime);
502
+ const res = await fetchImpl(__liftString(url) || "", {
503
+ method: "POST",
504
+ mode: modeToString(mode) || "cors",
505
+ headers: __liftArray(
506
+ (pointer) => __liftArray((pointer2) => __liftString(__getU32(pointer2)), 2, __getU32(pointer)),
507
+ 2,
508
+ headers
509
+ ) || [],
510
+ body: __liftBuffer(body)
511
+ });
512
+ const value = await res.arrayBuffer();
513
+ return value;
514
+ }
515
+ });
358
516
  WASM_EXPORTS.asyncify_start_unwind(ASYNCIFY_PTR);
359
517
  },
360
518
  /**
@@ -368,24 +526,27 @@ function instantiate(module, imports = {}, runtime = {}) {
368
526
  const currentState = WASM_EXPORTS.asyncify_get_state();
369
527
  if (currentState === 2 /* Rewinding */) {
370
528
  WASM_EXPORTS.asyncify_stop_rewind();
371
- const ptr = __lowerBuffer(detachedValue);
372
- detachedValue = null;
529
+ const completed = hostCalls.take("fetch-buffer");
530
+ const ptr = __lowerBuffer(completed.value, "wasm");
373
531
  return ptr;
374
532
  }
375
- fetchFn = async () => {
376
- const fetchImpl = await getFetchOrThrow(runtime);
377
- const res = await fetchImpl(__liftString(url) || "", {
378
- method: "GET",
379
- mode: modeToString(mode) || "cors",
380
- headers: __liftArray(
381
- (pointer) => __liftArray((pointer2) => __liftString(__getU32(pointer2)), 2, __getU32(pointer)),
382
- 2,
383
- headers
384
- ) || []
385
- });
386
- const value = await res.arrayBuffer();
387
- return value;
388
- };
533
+ hostCalls.stage({
534
+ kind: "fetch-buffer",
535
+ run: async () => {
536
+ const fetchImpl = await getFetchOrThrow(runtime);
537
+ const res = await fetchImpl(__liftString(url) || "", {
538
+ method: "GET",
539
+ mode: modeToString(mode) || "cors",
540
+ headers: __liftArray(
541
+ (pointer) => __liftArray((pointer2) => __liftString(__getU32(pointer2)), 2, __getU32(pointer)),
542
+ 2,
543
+ headers
544
+ ) || []
545
+ });
546
+ const value = await res.arrayBuffer();
547
+ return value;
548
+ }
549
+ });
389
550
  WASM_EXPORTS.asyncify_start_unwind(ASYNCIFY_PTR);
390
551
  },
391
552
  /**
@@ -501,6 +662,7 @@ function instantiate(module, imports = {}, runtime = {}) {
501
662
  }
502
663
  executeInFlight = true;
503
664
  const replayArgs = snapshotLogicalArgs(params);
665
+ pinScopes.push([]);
504
666
  try {
505
667
  let result;
506
668
  try {
@@ -515,25 +677,18 @@ function instantiate(module, imports = {}, runtime = {}) {
515
677
  if (ASYNCIFY_INITIALIZED) {
516
678
  while (WASM_EXPORTS.asyncify_get_state() === 1 /* Unwinding */) {
517
679
  WASM_EXPORTS.asyncify_stop_unwind();
518
- if (fetchFn) {
519
- const pendingFetch = fetchFn;
520
- fetchFn = null;
521
- detachedValue = await pendingFetch();
522
- }
523
- if (ccxtFn) {
524
- const pendingCcxt = ccxtFn;
525
- ccxtFn = null;
526
- detachedValue = await pendingCcxt();
527
- }
680
+ await hostCalls.complete();
528
681
  WASM_EXPORTS.asyncify_start_rewind(ASYNCIFY_PTR);
529
682
  result = executeWithReplayArgs(replayArgs);
530
683
  }
531
684
  }
532
685
  return __liftString(result);
533
686
  } finally {
534
- fetchFn = null;
535
- ccxtFn = null;
536
- detachedValue = null;
687
+ const scope = pinScopes.pop() || [];
688
+ for (let i = scope.length - 1; i >= 0; i--) {
689
+ WASM_EXPORTS.__unpin(scope[i]);
690
+ }
691
+ hostCalls.reset();
537
692
  executeInFlight = false;
538
693
  }
539
694
  },
@@ -592,7 +747,7 @@ function instantiate(module, imports = {}, runtime = {}) {
592
747
  });
593
748
  }
594
749
  function executeWithReplayArgs(values) {
595
- return withPinScope(() => WASM_EXPORTS.execute(...lowerArgs(values)));
750
+ return withAutoPinScope(() => WASM_EXPORTS.execute(...lowerArgs(values)));
596
751
  }
597
752
  function withPinScope(fn) {
598
753
  pinScopes.push([]);
@@ -627,10 +782,10 @@ function instantiate(module, imports = {}, runtime = {}) {
627
782
  while (end - start > 1024) string += String.fromCharCode(...memoryU16.subarray(start, start += 1024));
628
783
  return string + String.fromCharCode(...memoryU16.subarray(start, end));
629
784
  }
630
- function __lowerString(value) {
785
+ function __lowerString(value, owner = "host") {
631
786
  if (value == null) return 0;
632
787
  const length = value.length;
633
- const ptr = trackPinnedPointer(WASM_EXPORTS.__pin(WASM_EXPORTS.__new(length << 1, 2) >>> 0));
788
+ const ptr = allocateLoweredPointer(length << 1, 2, owner);
634
789
  const memoryU16 = new Uint16Array(WASM_MEMORY.buffer);
635
790
  for (let i = 0; i < length; ++i) memoryU16[(ptr >>> 1) + i] = value.charCodeAt(i);
636
791
  return ptr;
@@ -639,9 +794,9 @@ function instantiate(module, imports = {}, runtime = {}) {
639
794
  if (!ptr) return null;
640
795
  return WASM_MEMORY.buffer.slice(ptr, ptr + new Uint32Array(WASM_MEMORY.buffer)[ptr - 4 >>> 2]);
641
796
  }
642
- function __lowerBuffer(value) {
797
+ function __lowerBuffer(value, owner = "host") {
643
798
  if (value == null) return 0;
644
- const ptr = trackPinnedPointer(WASM_EXPORTS.__pin(WASM_EXPORTS.__new(value.byteLength, 1) >>> 0));
799
+ const ptr = allocateLoweredPointer(value.byteLength, 1, owner);
645
800
  new Uint8Array(WASM_MEMORY.buffer).set(new Uint8Array(value), ptr);
646
801
  return ptr;
647
802
  }
@@ -653,10 +808,10 @@ function instantiate(module, imports = {}, runtime = {}) {
653
808
  for (let i = 0; i < length; ++i) values[i] = liftElement(dataStart + (i << align >>> 0));
654
809
  return values;
655
810
  }
656
- function __lowerStaticArray(lowerElement, id, align, values, typedConstructor = null) {
811
+ function __lowerStaticArray(lowerElement, id, align, values, typedConstructor = null, owner = "host") {
657
812
  if (values == null) return 0;
658
813
  const length = values.length;
659
- const buffer = trackPinnedPointer(WASM_EXPORTS.__pin(WASM_EXPORTS.__new(length << align, id)) >>> 0) >>> 0;
814
+ const buffer = allocateLoweredPointer(length << align, id, owner) >>> 0;
660
815
  if (typedConstructor) {
661
816
  new typedConstructor(WASM_MEMORY.buffer, buffer, length).set(values);
662
817
  } else {
@@ -664,6 +819,13 @@ function instantiate(module, imports = {}, runtime = {}) {
664
819
  }
665
820
  return buffer;
666
821
  }
822
+ function allocateLoweredPointer(size, id, owner) {
823
+ const ptr = WASM_EXPORTS.__new(size, id) >>> 0;
824
+ if (owner === "wasm") {
825
+ return ptr;
826
+ }
827
+ return trackPinnedPointer(WASM_EXPORTS.__pin(ptr) >>> 0);
828
+ }
667
829
  function __setU32(ptr, value) {
668
830
  try {
669
831
  WASM_DV.setUint32(ptr, value, true);
@@ -710,20 +872,38 @@ function modeToString(mode) {
710
872
  return null;
711
873
  }
712
874
 
875
+ // src/internal/panopticBrowserRuntime.ts
876
+ async function callBrowserPanoptic(method, request) {
877
+ void method;
878
+ void request;
879
+ throw new Error(
880
+ "Panoptic runtime adapter is not enabled for browser runtimes yet. Phase 8 must choose globalThis SDK globals or dynamic browser imports first."
881
+ );
882
+ }
883
+
713
884
  // src/browser.ts
714
- function loadWasmSync(input, imports = {}) {
885
+ function loadWasmSync(input, imports = {}, options = {}) {
886
+ assertBrowserOptionsSupported(options);
715
887
  return instantiate(new WebAssembly.Module(input), imports, {
716
888
  getFetch: getBrowserFetch,
717
- getCcxt: getBrowserCcxt
889
+ getCcxt: getBrowserCcxt,
890
+ callPanoptic: callBrowserPanoptic
718
891
  });
719
892
  }
720
- async function loadWasm(input, imports = {}) {
893
+ async function loadWasm(input, imports = {}, options = {}) {
894
+ assertBrowserOptionsSupported(options);
721
895
  const module = typeof input === "string" ? await compileFromUrl(input) : await WebAssembly.compile(input);
722
896
  return instantiate(module, imports, {
723
897
  getFetch: getBrowserFetch,
724
- getCcxt: getBrowserCcxt
898
+ getCcxt: getBrowserCcxt,
899
+ callPanoptic: callBrowserPanoptic
725
900
  });
726
901
  }
902
+ function assertBrowserOptionsSupported(options) {
903
+ if (options.panoptic) {
904
+ throw new Error("Panoptic runtime adapter is Node-only until browser support lands.");
905
+ }
906
+ }
727
907
  async function compileFromUrl(url) {
728
908
  const fetchImpl = await getBrowserFetch();
729
909
  const response = await fetchImpl(url);