browser-module-runtime 0.0.0-stage → 0.0.1

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.
@@ -0,0 +1,2044 @@
1
+ import { createPackagePolicy, PackageVersionResolutionError } from "./package-resolution/index.js";
2
+ import {
3
+ CircularDependencyError,
4
+ ModuleCompileError,
5
+ ModuleResolutionError,
6
+ ModuleWaitTimeoutError,
7
+ ModuleRuntimeError,
8
+ } from "./errors.js";
9
+ import { createDefaultModuleUrlBackend } from "./url-backend.js";
10
+ import { createEventDispatcher } from "./events.js";
11
+ import { approximateByteSize, createCompileCache, sha256, stableSerialize } from "./compile-cache.js";
12
+
13
+ const HOST_REGISTRY_KEY = "__browserModuleRuntimeHostModules__";
14
+ const COMPILED_ARTIFACT_ABI = "browser-module-runtime:compiled-artifact:v1";
15
+ const COMPILED_ARTIFACT_SCHEMA = 1;
16
+ let runtimeSequence = 0;
17
+
18
+ export function createRuntime(options = {}) {
19
+ const normalizedCompileCacheOption = normalizeCompileCacheAlias(options);
20
+ const {
21
+ compiler,
22
+ modules = {},
23
+ urls = {},
24
+ allowNativeImports = true,
25
+ resolve: customResolve,
26
+ fallbackResolve: customFallbackResolve,
27
+ moduleUrlBackend = createDefaultModuleUrlBackend(),
28
+ compileCache: _compileCacheOptions,
29
+ cache: _cacheAlias,
30
+ packages,
31
+ _solidFamilyRules,
32
+ } = options;
33
+ const compileCacheOptions = normalizedCompileCacheOption;
34
+ const packagePolicy = createPackagePolicy(packages, { familyRules: _solidFamilyRules });
35
+ for (const name of Object.keys(modules)) {
36
+ if (packagePolicy.pins.has(name)) {
37
+ throw new PackageVersionResolutionError("PACKAGE_VERSION_CONFLICT", `Package pin ${JSON.stringify(name)} conflicts with an explicit modules entry. Remove the pin or module override.`, { packageName: name });
38
+ }
39
+ }
40
+
41
+
42
+ if (!compiler || (typeof compiler.compile !== "function" && (typeof compiler.analyze !== "function" || typeof compiler.transform !== "function"))) {
43
+ throw new TypeError("createRuntime() requires compile(), or analyze() + transform(), on its compiler.");
44
+ }
45
+
46
+ const runtimeId = `browser-module-runtime-${++runtimeSequence}-${randomId()}`;
47
+ const records = new Map();
48
+ const moduleWaiters = new Map();
49
+ let anonymousSequence = 0;
50
+ let disposed = false;
51
+ const events = createEventDispatcher({
52
+ onListenerError(error) {
53
+ globalThis.console?.error?.("browser-module-runtime lifecycle subscriber error", error);
54
+ },
55
+ });
56
+ let eventBufferDepth = 0;
57
+ const eventBuffer = [];
58
+ const memoryCompileArtifacts = new Map();
59
+ const inFlightCompiles = new Map();
60
+ const compileCacheConfig = normalizeCompileCacheOptions(compileCacheOptions);
61
+ let warnedMissingCompilerFingerprint = false;
62
+
63
+ const globalRegistry = getHostRegistry();
64
+ const hostNamespaces = new Map();
65
+ globalRegistry.set(runtimeId, hostNamespaces);
66
+
67
+ const api = {
68
+ define,
69
+ defineMany,
70
+ defineModule,
71
+ defineUrl,
72
+ update,
73
+ import: importModule,
74
+ waitForModule,
75
+ compile,
76
+ toModule,
77
+ toComponent,
78
+ has,
79
+ invalidate,
80
+ remove,
81
+ clear,
82
+ subscribe,
83
+ modules: listModules,
84
+ dependencies,
85
+ dependents,
86
+ getModuleInfo,
87
+ getPrivateImports,
88
+ dispose,
89
+ resolve: resolvePublic,
90
+ inspectPackageResolution: packagePolicy.inspect,
91
+ compileCache: createCompileCacheManager(),
92
+ };
93
+
94
+ for (const [id, namespace] of Object.entries(modules)) defineModule(id, namespace);
95
+ for (const [id, url] of Object.entries(urls)) defineUrl(id, url);
96
+
97
+ return api;
98
+
99
+ function assertActive() {
100
+ if (disposed) throw new ModuleRuntimeError("This browser-module-runtime instance has been disposed.");
101
+ }
102
+
103
+ function define(id, source, defineOptions = {}) {
104
+ return defineSource(id, source, defineOptions, "define");
105
+ }
106
+
107
+ function defineMany(definitions) {
108
+ assertActive();
109
+ if (!Array.isArray(definitions)) {
110
+ throw new TypeError("defineMany(definitions) expects an array of source module definitions.");
111
+ }
112
+
113
+ const prepared = definitions.map((definition, index) => {
114
+ if (!definition || typeof definition !== "object") {
115
+ throw new TypeError(`defineMany() item ${index} must be an object with id and source.`);
116
+ }
117
+ if (definition.id == null) {
118
+ throw new TypeError(`defineMany() item ${index} is missing id.`);
119
+ }
120
+ const id = normalizeDefinedId(definition.id);
121
+ return {
122
+ id,
123
+ source: String(definition.source ?? ""),
124
+ format: definition.format ?? "jsx",
125
+ imports: definition.imports,
126
+ };
127
+ });
128
+
129
+ const seen = new Set();
130
+ for (const item of prepared) {
131
+ if (seen.has(item.id)) {
132
+ throw new ModuleRuntimeError(`defineMany() contains duplicate module id ${JSON.stringify(item.id)}.`);
133
+ }
134
+ seen.add(item.id);
135
+ }
136
+
137
+ eventBufferDepth += 1;
138
+ try {
139
+ const ids = prepared.map(item => defineSource(item.id, item.source, {
140
+ format: item.format,
141
+ imports: item.imports,
142
+ }, "defineMany"));
143
+ emit({
144
+ type: "modules-defined",
145
+ ids: [...ids],
146
+ modules: ids.map(id => toModuleInfo(records.get(id))),
147
+ });
148
+ return ids;
149
+ } finally {
150
+ eventBufferDepth -= 1;
151
+ if (eventBufferDepth === 0) flushEventBuffer();
152
+ }
153
+ }
154
+
155
+ function update(id, source, updateOptions = {}) {
156
+ return defineSource(id, source, updateOptions, "update");
157
+ }
158
+
159
+ // A later explicit runtime module intentionally shadows an exact root pin.
160
+ // Consumers previously linked against the provider URL must be relinked so
161
+ // the new registered module actually wins (not merely future import calls).
162
+ function invalidatePinnedUrlConsumers(id, reason) {
163
+ const pinned = packagePolicy.inspect(id);
164
+ if (!pinned || pinned.subpath) return;
165
+ for (const record of [...records.values()]) {
166
+ if (record.kind === "source" && record.dependencies?.has(pinned.url)) {
167
+ invalidate(record.id, { dependents: true, reason: `pinned-override:${reason}` });
168
+ }
169
+ }
170
+ }
171
+
172
+ function defineSource(id, source, defineOptions = {}, operation = "define") {
173
+ assertActive();
174
+ const normalized = normalizeDefinedId(id);
175
+ const existing = records.get(normalized);
176
+ const preservePrivateImports = operation === "update"
177
+ && !Object.prototype.hasOwnProperty.call(defineOptions, "imports")
178
+ && existing?.kind === "source";
179
+ const privateImports = normalizePrivateImports(
180
+ preservePrivateImports ? privateImportDefinitions(existing) : defineOptions.imports,
181
+ normalized,
182
+ );
183
+
184
+ if (existing) invalidate(normalized, { dependents: true, reason: operation });
185
+ invalidatePinnedUrlConsumers(normalized, operation);
186
+
187
+ const record = {
188
+ id: normalized,
189
+ kind: "source",
190
+ source: String(source),
191
+ format: defineOptions.format ?? "jsx",
192
+ version: (existing?.version ?? 0) + 1,
193
+ state: "defined",
194
+ dependencies: new Set(),
195
+ dependents: existing?.dependents ?? new Set(),
196
+ compiledCode: undefined,
197
+ compiledArtifact: undefined,
198
+ compiledArtifactKey: undefined,
199
+ compileCacheInfo: createInitialCompileCacheInfo(),
200
+ forceCompileRefresh: false,
201
+ diagnostics: [],
202
+ privateImports,
203
+ url: undefined,
204
+ importPromise: undefined,
205
+ namespace: undefined,
206
+ };
207
+
208
+ records.set(normalized, record);
209
+ notifyModuleWaiters(record);
210
+ emit({
211
+ type: "module-defined",
212
+ id: normalized,
213
+ kind: record.kind,
214
+ version: record.version,
215
+ operation,
216
+ replaced: Boolean(existing),
217
+ module: toModuleInfo(record),
218
+ });
219
+ if (operation === "update") {
220
+ emit({
221
+ type: "module-updated",
222
+ id: normalized,
223
+ kind: record.kind,
224
+ previousVersion: existing?.version ?? 0,
225
+ version: record.version,
226
+ format: record.format,
227
+ module: toModuleInfo(record),
228
+ });
229
+ }
230
+ return normalized;
231
+ }
232
+
233
+ function defineModule(id, namespace) {
234
+ assertActive();
235
+ const normalized = normalizeDefinedId(id);
236
+ const existing = records.get(normalized);
237
+ if (existing) invalidate(normalized, { dependents: true, reason: "defineModule" });
238
+ invalidatePinnedUrlConsumers(normalized, "defineModule");
239
+
240
+ if ((typeof namespace !== "object" || namespace === null) && typeof namespace !== "function") {
241
+ throw new TypeError("defineModule(id, namespace) expects an object, function, or ES module namespace-like value.");
242
+ }
243
+
244
+ hostNamespaces.set(normalized, namespace);
245
+
246
+ const record = {
247
+ id: normalized,
248
+ kind: "host",
249
+ namespace,
250
+ version: (existing?.version ?? 0) + 1,
251
+ state: "ready",
252
+ dependencies: new Set(),
253
+ dependents: existing?.dependents ?? new Set(),
254
+ url: undefined,
255
+ };
256
+ records.set(normalized, record);
257
+ notifyModuleWaiters(record);
258
+ emit({
259
+ type: "module-defined",
260
+ id: normalized,
261
+ kind: record.kind,
262
+ version: record.version,
263
+ operation: "defineModule",
264
+ replaced: Boolean(existing),
265
+ module: toModuleInfo(record),
266
+ });
267
+
268
+ return normalized;
269
+ }
270
+
271
+ function defineUrl(id, url) {
272
+ assertActive();
273
+ const normalized = normalizeDefinedId(id);
274
+ const existing = records.get(normalized);
275
+ if (existing) invalidate(normalized, { dependents: true, reason: "defineUrl" });
276
+ invalidatePinnedUrlConsumers(normalized, "defineUrl");
277
+
278
+ const href = String(url);
279
+ const record = {
280
+ id: normalized,
281
+ kind: "url",
282
+ externalUrl: href,
283
+ version: (existing?.version ?? 0) + 1,
284
+ state: "defined",
285
+ dependencies: new Set(),
286
+ dependents: existing?.dependents ?? new Set(),
287
+ importPromise: undefined,
288
+ namespace: undefined,
289
+ };
290
+ records.set(normalized, record);
291
+ notifyModuleWaiters(record);
292
+ emit({
293
+ type: "module-defined",
294
+ id: normalized,
295
+ kind: record.kind,
296
+ version: record.version,
297
+ operation: "defineUrl",
298
+ replaced: Boolean(existing),
299
+ module: toModuleInfo(record),
300
+ });
301
+
302
+ return normalized;
303
+ }
304
+
305
+ function waitForModule(id, waitOptions = {}) {
306
+ assertActive();
307
+ return waitForRegisteredModule(id, null, waitOptions, record => importRecord(record, []));
308
+ }
309
+
310
+ function waitForRegisteredModule(id, importer, waitOptions = {}, onAvailable) {
311
+ assertActive();
312
+ const raw = String(id);
313
+ const normalized = normalizeWaitForModuleId(raw, importer);
314
+ const options = normalizeWaitForModuleOptions(waitOptions);
315
+
316
+ if (options.signal?.aborted) {
317
+ return Promise.reject(createAbortError(options.signal));
318
+ }
319
+
320
+ const existing = records.get(normalized);
321
+ if (existing) {
322
+ return Promise.resolve().then(() => onAvailable(existing));
323
+ }
324
+
325
+ return new Promise((resolve, reject) => {
326
+ const waiter = {
327
+ id: normalized,
328
+ raw,
329
+ importer,
330
+ settled: false,
331
+ timeoutId: undefined,
332
+ signal: options.signal,
333
+ abortHandler: undefined,
334
+ resolve,
335
+ reject,
336
+ onAvailable,
337
+ };
338
+
339
+ let waiters = moduleWaiters.get(normalized);
340
+ if (!waiters) {
341
+ waiters = new Set();
342
+ moduleWaiters.set(normalized, waiters);
343
+ }
344
+ waiters.add(waiter);
345
+
346
+ if (options.timeout != null) {
347
+ waiter.timeoutId = setTimeout(() => {
348
+ if (!settleModuleWaiter(waiter)) return;
349
+ reject(new ModuleWaitTimeoutError(normalized, options.timeout));
350
+ }, options.timeout);
351
+ }
352
+
353
+ if (options.signal) {
354
+ waiter.abortHandler = () => {
355
+ if (!settleModuleWaiter(waiter)) return;
356
+ reject(createAbortError(options.signal));
357
+ };
358
+ options.signal.addEventListener("abort", waiter.abortHandler, { once: true });
359
+ }
360
+
361
+ // Guard against a definition racing between the initial lookup and waiter registration.
362
+ const raced = records.get(normalized);
363
+ if (raced) notifyModuleWaiters(raced);
364
+ });
365
+ }
366
+
367
+ function notifyModuleWaiters(record) {
368
+ const waiters = moduleWaiters.get(record.id);
369
+ if (!waiters?.size) return;
370
+ moduleWaiters.delete(record.id);
371
+
372
+ for (const waiter of [...waiters]) {
373
+ if (!settleModuleWaiter(waiter, false)) continue;
374
+ Promise.resolve()
375
+ .then(() => waiter.onAvailable(record))
376
+ .then(waiter.resolve, waiter.reject);
377
+ }
378
+ }
379
+
380
+ function settleModuleWaiter(waiter, removeFromRegistry = true) {
381
+ if (waiter.settled) return false;
382
+ waiter.settled = true;
383
+
384
+ if (waiter.timeoutId !== undefined) {
385
+ clearTimeout(waiter.timeoutId);
386
+ waiter.timeoutId = undefined;
387
+ }
388
+ if (waiter.signal && waiter.abortHandler) {
389
+ waiter.signal.removeEventListener("abort", waiter.abortHandler);
390
+ waiter.abortHandler = undefined;
391
+ }
392
+ if (removeFromRegistry) {
393
+ const waiters = moduleWaiters.get(waiter.id);
394
+ waiters?.delete(waiter);
395
+ if (waiters?.size === 0) moduleWaiters.delete(waiter.id);
396
+ }
397
+ return true;
398
+ }
399
+
400
+ function rejectAllModuleWaiters(error) {
401
+ const pending = [...moduleWaiters.values()].flatMap(waiters => [...waiters]);
402
+ moduleWaiters.clear();
403
+ for (const waiter of pending) {
404
+ if (!settleModuleWaiter(waiter, false)) continue;
405
+ waiter.reject(error);
406
+ }
407
+ }
408
+
409
+ async function importModule(id) {
410
+ assertActive();
411
+ const raw = String(id);
412
+ const resolved = resolveSpecifier(raw, null);
413
+ const record = records.get(resolved);
414
+
415
+ if (!record) {
416
+ // Top-level virtual path imports follow the same rule as static imports:
417
+ // unresolved relative/absolute virtual IDs are runtime resolution errors,
418
+ // not native browser fetches. Native fallback is reserved for absolute
419
+ // URLs and unresolved bare specifiers when allowNativeImports is enabled.
420
+ if (isRelativeSpecifier(raw) || raw.startsWith("/")) {
421
+ throw new ModuleResolutionError(id, null);
422
+ }
423
+ if (!allowNativeImports && !isAbsoluteUrl(resolved)) {
424
+ throw new ModuleResolutionError(id, null);
425
+ }
426
+ return import(resolved);
427
+ }
428
+
429
+ return importRecord(record, []);
430
+ }
431
+
432
+ async function importRecord(record, stack) {
433
+ if (record.kind === "host") return record.namespace;
434
+
435
+ if (record.kind === "url") {
436
+ if (!record.importPromise) {
437
+ record.state = "evaluating";
438
+ emit({ type: "module-evaluating", id: record.id, kind: record.kind, version: record.version });
439
+ record.importPromise = import(record.externalUrl).then(namespace => {
440
+ record.namespace = namespace;
441
+ record.state = "ready";
442
+ emit({ type: "module-evaluated", id: record.id, kind: record.kind, version: record.version, module: toModuleInfo(record) });
443
+ return namespace;
444
+ }).catch(error => {
445
+ record.importPromise = undefined;
446
+ record.state = "error";
447
+ emitError(record, "evaluate", error);
448
+ throw error;
449
+ });
450
+ }
451
+ return record.importPromise;
452
+ }
453
+
454
+ if (stack.includes(record.id)) {
455
+ const cycleStart = stack.indexOf(record.id);
456
+ const error = new CircularDependencyError([...stack.slice(cycleStart), record.id]);
457
+ emitError(record, "link", error);
458
+ throw error;
459
+ }
460
+
461
+ if (!record.importPromise) {
462
+ record.importPromise = ensureSourceUrl(record, stack).then(url => {
463
+ record.state = "evaluating";
464
+ emit({ type: "module-evaluating", id: record.id, kind: record.kind, version: record.version });
465
+ return import(url);
466
+ }).then(namespace => {
467
+ record.namespace = namespace;
468
+ record.state = "ready";
469
+ emit({ type: "module-evaluated", id: record.id, kind: record.kind, version: record.version, module: toModuleInfo(record) });
470
+ return namespace;
471
+ }).catch(error => {
472
+ record.importPromise = undefined;
473
+ const alreadyReported = record.state === "error";
474
+ record.state = "error";
475
+ if (!alreadyReported) emitError(record, "evaluate", error);
476
+ throw error;
477
+ });
478
+ }
479
+
480
+ return record.importPromise;
481
+ }
482
+
483
+ async function compile(id, compileOptions = {}) {
484
+ assertActive();
485
+ const resolved = resolveSpecifier(String(id), null);
486
+ const record = records.get(resolved);
487
+ if (!record) throw new ModuleResolutionError(id, null);
488
+ if (record.kind !== "source") {
489
+ return {
490
+ id: record.id,
491
+ kind: record.kind,
492
+ code: undefined,
493
+ url: record.kind === "url" ? record.externalUrl : await ensureHostUrl(record),
494
+ dependencies: [...record.dependencies],
495
+ diagnostics: [],
496
+ };
497
+ }
498
+
499
+ const cacheMode = normalizeCompileCacheMode(compileOptions.cache);
500
+ if (cacheMode !== "use") {
501
+ // A fresh linked URL for the requested module makes any already-linked
502
+ // dependents stale as well. Invalidate the executable graph while
503
+ // preserving their reusable compiler artifacts.
504
+ invalidate(record.id, { dependents: true, reason: `compile-cache-${cacheMode}` });
505
+ }
506
+ const url = await ensureSourceUrl(record, [], { cacheMode });
507
+ return {
508
+ id: record.id,
509
+ kind: record.kind,
510
+ code: record.compiledCode,
511
+ url,
512
+ dependencies: [...record.dependencies],
513
+ diagnostics: [...(record.diagnostics ?? [])],
514
+ assets: [...(record.compiledArtifact?.assets ?? [])],
515
+ };
516
+ }
517
+
518
+ async function toModule(source, moduleOptions = {}) {
519
+ assertActive();
520
+ const id = moduleOptions.id ?? `/__solid_tag_runtime__/anonymous-${++anonymousSequence}.jsx`;
521
+ const normalized = define(id, source, {
522
+ format: moduleOptions.format ?? "jsx",
523
+ imports: moduleOptions.imports,
524
+ });
525
+ return importModule(normalized);
526
+ }
527
+
528
+ async function toComponent(source, componentOptions = {}) {
529
+ const namespace = await toModule(source, componentOptions);
530
+ const exportName = componentOptions.exportName ?? "default";
531
+
532
+ if (!(exportName in namespace)) {
533
+ throw new ModuleRuntimeError(
534
+ `Module does not export ${JSON.stringify(exportName)}. Available exports: ${Object.keys(namespace).join(", ") || "(none)"}.`
535
+ );
536
+ }
537
+
538
+ const component = namespace[exportName];
539
+ if (typeof component !== "function") {
540
+ throw new ModuleRuntimeError(
541
+ `Export ${JSON.stringify(exportName)} is not callable and cannot be used as a Solid component.`
542
+ );
543
+ }
544
+
545
+ return component;
546
+ }
547
+
548
+ function has(id) {
549
+ return records.has(normalizeLookupId(id));
550
+ }
551
+
552
+ function invalidate(id, invalidateOptions = {}) {
553
+ assertActive();
554
+ const normalized = normalizeLookupId(id);
555
+ const includeDependents = invalidateOptions.dependents ?? true;
556
+ const reason = invalidateOptions.reason ?? "explicit";
557
+ const forceCompile = invalidateOptions.compile === true;
558
+ const seen = new Set();
559
+
560
+ invalidateOne(normalized, true);
561
+ return [...seen];
562
+
563
+ function invalidateOne(targetId, isRequestedModule = false) {
564
+ if (seen.has(targetId)) return;
565
+ seen.add(targetId);
566
+ const record = records.get(targetId);
567
+ if (!record) return;
568
+
569
+ if (includeDependents) {
570
+ for (const dependent of record.dependents) invalidateOne(dependent, false);
571
+ }
572
+
573
+ if (record.kind === "source") {
574
+ revokeRecordUrl(record);
575
+ revokePrivateImportUrls(record);
576
+ record.compiledCode = undefined;
577
+ record.importPromise = undefined;
578
+ record.namespace = undefined;
579
+ record.state = "defined";
580
+
581
+ // Normal graph invalidation preserves the pre-link compiler artifact.
582
+ // compile:true only applies to the explicitly requested module, never
583
+ // to its transitive dependents.
584
+ if (forceCompile && isRequestedModule) {
585
+ if (record.compiledArtifactKey) memoryCompileArtifacts.delete(record.compiledArtifactKey);
586
+ record.compiledArtifact = undefined;
587
+ record.compiledArtifactKey = undefined;
588
+ record.forceCompileRefresh = true;
589
+ record.compileCacheInfo = createInitialCompileCacheInfo();
590
+ record.diagnostics = [];
591
+ }
592
+ } else if (record.kind === "host") {
593
+ revokeRecordUrl(record);
594
+ record.state = "ready";
595
+ } else if (record.kind === "url") {
596
+ record.importPromise = undefined;
597
+ record.namespace = undefined;
598
+ record.state = "defined";
599
+ }
600
+
601
+ emit({
602
+ type: "module-invalidated",
603
+ id: record.id,
604
+ kind: record.kind,
605
+ version: record.version,
606
+ reason,
607
+ });
608
+ }
609
+ }
610
+
611
+ function remove(id, removeOptions = {}) {
612
+ assertActive();
613
+ const normalized = normalizeLookupId(id);
614
+ const record = records.get(normalized);
615
+ if (!record) return false;
616
+
617
+ if (removeOptions.invalidateDependents !== false) {
618
+ for (const dependent of [...record.dependents]) {
619
+ invalidate(dependent, { dependents: true, reason: `dependency-removed:${normalized}` });
620
+ }
621
+ }
622
+
623
+ for (const dependency of record.dependencies) {
624
+ records.get(dependency)?.dependents.delete(normalized);
625
+ }
626
+
627
+ revokeRecordUrl(record);
628
+ if (record.kind === "source") revokePrivateImportUrls(record);
629
+ if (record.kind === "host") hostNamespaces.delete(normalized);
630
+ records.delete(normalized);
631
+
632
+ emit({
633
+ type: "module-removed",
634
+ id: normalized,
635
+ kind: record.kind,
636
+ version: record.version,
637
+ invalidateDependents: removeOptions.invalidateDependents !== false,
638
+ });
639
+ return true;
640
+ }
641
+
642
+ function clear(clearOptions = {}) {
643
+ assertActive();
644
+ const preserveHostModules = clearOptions.preserveHostModules !== false;
645
+ const ids = [...records.values()]
646
+ .filter(record => !(preserveHostModules && record.kind === "host"))
647
+ .map(record => record.id);
648
+
649
+ for (const id of ids) remove(id, { invalidateDependents: false });
650
+
651
+ emit({
652
+ type: "runtime-cleared",
653
+ ids: [...ids],
654
+ preserveHostModules,
655
+ });
656
+ return ids;
657
+ }
658
+
659
+ function subscribe(typesOrListener, maybeListener) {
660
+ assertActive();
661
+ return events.subscribe(typesOrListener, maybeListener);
662
+ }
663
+
664
+ function listModules() {
665
+ return [...records.values()].map(toModuleInfo);
666
+ }
667
+
668
+ function dependencies(id) {
669
+ const record = records.get(normalizeLookupId(id));
670
+ return record ? [...record.dependencies] : [];
671
+ }
672
+
673
+ function dependents(id) {
674
+ const record = records.get(normalizeLookupId(id));
675
+ return record ? [...record.dependents] : [];
676
+ }
677
+
678
+ function getModuleInfo(id) {
679
+ const record = records.get(normalizeLookupId(id));
680
+ return record ? toModuleInfo(record) : undefined;
681
+ }
682
+
683
+ function getPrivateImports(id) {
684
+ const record = records.get(normalizeLookupId(id));
685
+ if (!record || record.kind !== "source") return undefined;
686
+ return new Map([...record.privateImports].map(([specifier, entry]) => [specifier, entry.definition]));
687
+ }
688
+
689
+ function dispose() {
690
+ if (disposed) return;
691
+ disposed = true;
692
+ emit({ type: "runtime-disposed" });
693
+ rejectAllModuleWaiters(new ModuleRuntimeError("This browser-module-runtime instance was disposed while waiting for a module."));
694
+
695
+ for (const record of records.values()) {
696
+ revokeRecordUrl(record);
697
+ if (record.kind === "source") revokePrivateImportUrls(record);
698
+ }
699
+ records.clear();
700
+ hostNamespaces.clear();
701
+ globalRegistry.delete(runtimeId);
702
+ events.clear();
703
+ }
704
+
705
+ function resolvePublic(specifier, importer) {
706
+ return resolveSpecifier(specifier, importer ?? null);
707
+ }
708
+
709
+ function createInitialCompileCacheInfo() {
710
+ return {
711
+ enabled: Boolean(compileCacheConfig),
712
+ status: "none",
713
+ source: undefined,
714
+ key: undefined,
715
+ compilerFingerprint: undefined,
716
+ sourceHash: undefined,
717
+ compileContextHash: undefined,
718
+ };
719
+ }
720
+
721
+ function createCompileCacheManager() {
722
+ return {
723
+ enabled: Boolean(compileCacheConfig),
724
+ namespace: compileCacheConfig?.namespace,
725
+ version: compileCacheConfig?.version,
726
+ store: compileCacheConfig?.store?.kind ?? (compileCacheConfig ? "custom" : undefined),
727
+ async invalidate(id) {
728
+ assertActive();
729
+ if (!compileCacheConfig) return false;
730
+ const record = records.get(normalizeLookupId(id));
731
+ if (!record || record.kind !== "source") return false;
732
+
733
+ const identity = await createCompileIdentity(record);
734
+ if (!identity?.key) {
735
+ record.compiledArtifact = undefined;
736
+ record.compiledArtifactKey = undefined;
737
+ record.forceCompileRefresh = true;
738
+ return false;
739
+ }
740
+
741
+ memoryCompileArtifacts.delete(identity.key);
742
+ if (record.compiledArtifactKey === identity.key) {
743
+ record.compiledArtifact = undefined;
744
+ record.compiledArtifactKey = undefined;
745
+ }
746
+ record.forceCompileRefresh = true;
747
+ record.compileCacheInfo = createInitialCompileCacheInfo();
748
+
749
+ if (!compileCacheConfig || !identity.persistable) return false;
750
+ const physicalKey = compileCacheStorageKey(identity.key);
751
+ try {
752
+ const deleted = await compileCacheConfig.store.delete(physicalKey);
753
+ return deleted !== false;
754
+ } catch (error) {
755
+ emitCompileCacheError(record, "delete", error, identity);
756
+ throw error;
757
+ }
758
+ },
759
+ async clear(clearOptions = {}) {
760
+ assertActive();
761
+ if (!compileCacheConfig) return 0;
762
+ memoryCompileArtifacts.clear();
763
+ for (const record of records.values()) {
764
+ if (record.kind !== "source") continue;
765
+ record.compiledArtifact = undefined;
766
+ record.compiledArtifactKey = undefined;
767
+ record.forceCompileRefresh = true;
768
+ record.compileCacheInfo = createInitialCompileCacheInfo();
769
+ }
770
+
771
+ const prefix = clearOptions.allVersions === true
772
+ ? compileCacheNamespacePrefix()
773
+ : compileCacheVersionPrefix();
774
+ try {
775
+ if (typeof compileCacheConfig.store.clear === "function") {
776
+ return Number(await compileCacheConfig.store.clear({ prefix })) || 0;
777
+ }
778
+ if (typeof compileCacheConfig.store.entries === "function") {
779
+ const entries = await compileCacheConfig.store.entries({ prefix });
780
+ let count = 0;
781
+ for (const [key] of entries) {
782
+ await compileCacheConfig.store.delete(key);
783
+ count += 1;
784
+ }
785
+ return count;
786
+ }
787
+ throw new Error("Compile cache store does not support clear() or entries().");
788
+ } catch (error) {
789
+ emitCompileCacheError(undefined, "clear", error);
790
+ throw error;
791
+ }
792
+ },
793
+ };
794
+ }
795
+
796
+ async function ensureCompiledArtifact(record, requestedMode = "use") {
797
+ let mode = normalizeCompileCacheMode(requestedMode);
798
+ if (record.forceCompileRefresh && mode === "use") mode = "refresh";
799
+
800
+ if (mode === "use" && record.compiledArtifact) {
801
+ record.compileCacheInfo = {
802
+ ...record.compileCacheInfo,
803
+ status: "hit",
804
+ source: "record",
805
+ };
806
+ return record.compiledArtifact;
807
+ }
808
+
809
+ let identity;
810
+ let identityFailed = false;
811
+ if (compileCacheConfig) {
812
+ try {
813
+ identity = await createCompileIdentity(record);
814
+ } catch (error) {
815
+ identityFailed = true;
816
+ emitCompileCacheError(record, "identity", error);
817
+ }
818
+ }
819
+ const canUseSharedCache = Boolean(identity?.key && identity.persistable);
820
+
821
+ if (compileCacheConfig && identity && !identity.persistable) {
822
+ if (identity.reason === "missing-compiler-fingerprint" && !warnedMissingCompilerFingerprint) {
823
+ warnedMissingCompilerFingerprint = true;
824
+ globalThis.console?.warn?.(
825
+ "browser-module-runtime: persistent compile caching is disabled for this compiler because it does not provide a stable fingerprint.",
826
+ );
827
+ }
828
+ emit({
829
+ type: "compile-cache-bypass",
830
+ id: record.id,
831
+ key: identity?.key,
832
+ reason: identity.reason ?? "missing-compiler-fingerprint",
833
+ source: "compiler",
834
+ store: compileCacheConfig.store.kind ?? "custom",
835
+ });
836
+ } else if (compileCacheConfig && identityFailed) {
837
+ emit({
838
+ type: "compile-cache-bypass",
839
+ id: record.id,
840
+ reason: "identity-error",
841
+ source: "compiler",
842
+ store: compileCacheConfig.store.kind ?? "custom",
843
+ });
844
+ }
845
+
846
+ if (mode === "bypass") {
847
+ emit({
848
+ type: "compile-cache-bypass",
849
+ id: record.id,
850
+ key: identity?.key,
851
+ reason: "requested",
852
+ source: "compiler",
853
+ store: compileCacheConfig?.store?.kind,
854
+ });
855
+ const artifact = await compileFreshArtifact(record);
856
+ record.compiledArtifact = artifact;
857
+ record.compiledArtifactKey = undefined;
858
+ record.forceCompileRefresh = false;
859
+ record.diagnostics = [...(artifact.diagnostics ?? [])];
860
+ record.compileCacheInfo = compileCacheInfoFrom(identity, "bypass", "compiler");
861
+ return artifact;
862
+ }
863
+
864
+ if (mode === "refresh") {
865
+ emit({
866
+ type: "compile-cache-refresh",
867
+ id: record.id,
868
+ key: identity?.key,
869
+ source: "compiler",
870
+ store: compileCacheConfig?.store?.kind,
871
+ });
872
+ } else if (canUseSharedCache) {
873
+ const memoryArtifact = memoryCompileArtifacts.get(identity.key);
874
+ if (memoryArtifact) {
875
+ record.compiledArtifact = memoryArtifact;
876
+ record.compiledArtifactKey = identity.key;
877
+ record.forceCompileRefresh = false;
878
+ record.diagnostics = [...(memoryArtifact.diagnostics ?? [])];
879
+ record.compileCacheInfo = compileCacheInfoFrom(identity, "hit", "memory");
880
+ emit({
881
+ type: "compile-cache-hit",
882
+ id: record.id,
883
+ key: identity.key,
884
+ source: "memory",
885
+ store: "memory",
886
+ byteSize: approximateByteSize(memoryArtifact),
887
+ });
888
+ return memoryArtifact;
889
+ }
890
+
891
+ const started = now();
892
+ try {
893
+ const cachedRecord = await compileCacheConfig.store.get(compileCacheStorageKey(identity.key));
894
+ const durationMs = now() - started;
895
+ if (cachedRecord !== undefined) {
896
+ const validation = validateCachedCompileRecord(cachedRecord, identity);
897
+ if (validation.valid && !isCacheRecordExpired(cachedRecord)) {
898
+ const artifact = normalizeCompiledArtifact(cachedRecord.artifact);
899
+ memoryCompileArtifacts.set(identity.key, artifact);
900
+ record.compiledArtifact = artifact;
901
+ record.compiledArtifactKey = identity.key;
902
+ record.forceCompileRefresh = false;
903
+ record.diagnostics = [...(artifact.diagnostics ?? [])];
904
+ record.compileCacheInfo = compileCacheInfoFrom(identity, "hit", compileCacheConfig.store.kind ?? "persistent");
905
+ cachedRecord.lastUsedAt = Date.now();
906
+ emit({
907
+ type: "compile-cache-hit",
908
+ id: record.id,
909
+ key: identity.key,
910
+ source: compileCacheConfig.store.kind ?? "persistent",
911
+ store: compileCacheConfig.store.kind ?? "custom",
912
+ durationMs,
913
+ byteSize: cachedRecord.byteSize,
914
+ });
915
+ return artifact;
916
+ }
917
+
918
+ try {
919
+ await compileCacheConfig.store.delete(compileCacheStorageKey(identity.key));
920
+ emit({
921
+ type: "compile-cache-evict",
922
+ id: record.id,
923
+ key: identity.key,
924
+ reason: validation.valid ? "maxAge" : "invalid",
925
+ store: compileCacheConfig.store.kind ?? "custom",
926
+ });
927
+ } catch (error) {
928
+ emitCompileCacheError(record, "delete", error, identity);
929
+ }
930
+ }
931
+
932
+ emit({
933
+ type: "compile-cache-miss",
934
+ id: record.id,
935
+ key: identity.key,
936
+ source: compileCacheConfig.store.kind ?? "persistent",
937
+ store: compileCacheConfig.store.kind ?? "custom",
938
+ durationMs,
939
+ });
940
+ } catch (error) {
941
+ emitCompileCacheError(record, "read", error, identity);
942
+ try { await compileCacheConfig.store.delete(compileCacheStorageKey(identity.key)); } catch {}
943
+ }
944
+ }
945
+
946
+ const inFlightKey = canUseSharedCache ? identity.key : undefined;
947
+ if (mode === "use" && inFlightKey && inFlightCompiles.has(inFlightKey)) {
948
+ const artifact = await inFlightCompiles.get(inFlightKey);
949
+ record.compiledArtifact = artifact;
950
+ record.compiledArtifactKey = inFlightKey;
951
+ record.forceCompileRefresh = false;
952
+ record.diagnostics = [...(artifact.diagnostics ?? [])];
953
+ record.compileCacheInfo = compileCacheInfoFrom(identity, "hit", "inflight");
954
+ return artifact;
955
+ }
956
+
957
+ const compilePromise = compileFreshArtifact(record);
958
+ if (inFlightKey) inFlightCompiles.set(inFlightKey, compilePromise);
959
+
960
+ let artifact;
961
+ try {
962
+ artifact = await compilePromise;
963
+ } finally {
964
+ if (inFlightKey && inFlightCompiles.get(inFlightKey) === compilePromise) inFlightCompiles.delete(inFlightKey);
965
+ }
966
+
967
+ record.compiledArtifact = artifact;
968
+ record.compiledArtifactKey = canUseSharedCache ? identity.key : undefined;
969
+ record.forceCompileRefresh = false;
970
+ record.diagnostics = [...(artifact.diagnostics ?? [])];
971
+ record.compileCacheInfo = compileCacheInfoFrom(identity, mode === "refresh" ? "refresh" : "miss", "compiler");
972
+
973
+ if (canUseSharedCache) {
974
+ memoryCompileArtifacts.set(identity.key, artifact);
975
+ const persistentRecord = {
976
+ schema: COMPILED_ARTIFACT_SCHEMA,
977
+ key: identity.key,
978
+ artifactAbi: COMPILED_ARTIFACT_ABI,
979
+ sourceHash: identity.sourceHash,
980
+ format: record.format,
981
+ compilerFingerprint: identity.compilerFingerprint,
982
+ compileContextHash: identity.compileContextHash,
983
+ artifact,
984
+ createdAt: Date.now(),
985
+ lastUsedAt: Date.now(),
986
+ };
987
+ persistentRecord.byteSize = approximateByteSize(persistentRecord);
988
+
989
+ await writePersistentCompileRecord(record, identity, persistentRecord);
990
+ }
991
+
992
+ return artifact;
993
+ }
994
+
995
+ async function compileFreshArtifact(record) {
996
+ try {
997
+ let artifact;
998
+ const context = { id: record.id, format: record.format };
999
+ if (typeof compiler.compile === "function") {
1000
+ artifact = await compiler.compile(record.source, context);
1001
+ } else {
1002
+ let code = record.source;
1003
+ let diagnostics = [];
1004
+ let sourceMap;
1005
+ if (record.format !== "js") {
1006
+ const transformed = await compiler.transform(record.source, {
1007
+ ...context,
1008
+ htmlImportSource: "@solidjs/html",
1009
+ });
1010
+ code = transformed.code;
1011
+ diagnostics = [...(transformed.diagnostics ?? [])];
1012
+ sourceMap = transformed.sourceMap;
1013
+ }
1014
+ const analysis = await compiler.analyze(code, context);
1015
+ artifact = {
1016
+ schema: COMPILED_ARTIFACT_SCHEMA,
1017
+ code,
1018
+ imports: analysis.imports ?? [],
1019
+ diagnostics,
1020
+ ...(sourceMap == null ? {} : { sourceMap }),
1021
+ };
1022
+ }
1023
+ return normalizeCompiledArtifact(artifact);
1024
+ } catch (error) {
1025
+ record.state = "error";
1026
+ const wrapped = error instanceof ModuleCompileError ? error : new ModuleCompileError(record.id, error);
1027
+ emitError(record, "compile", wrapped);
1028
+ throw wrapped;
1029
+ }
1030
+ }
1031
+
1032
+ async function createCompileIdentity(record) {
1033
+ const context = { id: record.id, format: record.format };
1034
+ let compilerFingerprint;
1035
+ try {
1036
+ const fingerprint = typeof compiler.fingerprint === "function"
1037
+ ? await compiler.fingerprint(context)
1038
+ : compiler.fingerprint;
1039
+ if (typeof fingerprint === "string" && fingerprint) compilerFingerprint = fingerprint;
1040
+ } catch (error) {
1041
+ emitCompileCacheError(record, "fingerprint", error);
1042
+ return {
1043
+ key: undefined,
1044
+ persistable: false,
1045
+ reason: "fingerprint-error",
1046
+ compilerFingerprint: undefined,
1047
+ format: record.format,
1048
+ };
1049
+ }
1050
+
1051
+ const sourceHash = await sha256(record.source);
1052
+ const cacheContext = typeof compiler.cacheContext === "function"
1053
+ ? await compiler.cacheContext(context)
1054
+ : { format: record.format };
1055
+ const compileContextHash = await sha256(stableSerialize(cacheContext ?? {}));
1056
+
1057
+ const persistable = Boolean(compilerFingerprint);
1058
+ if (!persistable) {
1059
+ return {
1060
+ key: undefined,
1061
+ persistable: false,
1062
+ reason: "missing-compiler-fingerprint",
1063
+ compilerFingerprint: undefined,
1064
+ sourceHash,
1065
+ compileContextHash,
1066
+ format: record.format,
1067
+ };
1068
+ }
1069
+
1070
+ const key = await sha256(stableSerialize({
1071
+ artifactAbi: COMPILED_ARTIFACT_ABI,
1072
+ compilerFingerprint,
1073
+ format: record.format,
1074
+ compileContextHash,
1075
+ sourceHash,
1076
+ }));
1077
+
1078
+ return {
1079
+ key,
1080
+ persistable: true,
1081
+ compilerFingerprint,
1082
+ sourceHash,
1083
+ compileContextHash,
1084
+ format: record.format,
1085
+ };
1086
+ }
1087
+
1088
+ function compileCacheInfoFrom(identity, status, source) {
1089
+ return {
1090
+ enabled: Boolean(compileCacheConfig),
1091
+ status,
1092
+ source,
1093
+ key: identity?.key,
1094
+ compilerFingerprint: identity?.compilerFingerprint,
1095
+ sourceHash: identity?.sourceHash,
1096
+ compileContextHash: identity?.compileContextHash,
1097
+ };
1098
+ }
1099
+
1100
+ function validateCachedCompileRecord(cachedRecord, identity) {
1101
+ if (!cachedRecord || typeof cachedRecord !== "object") return { valid: false, reason: "record" };
1102
+ if (cachedRecord.schema !== COMPILED_ARTIFACT_SCHEMA) return { valid: false, reason: "schema" };
1103
+ if (cachedRecord.artifactAbi !== COMPILED_ARTIFACT_ABI) return { valid: false, reason: "artifact-abi" };
1104
+ if (cachedRecord.key !== identity.key) return { valid: false, reason: "key" };
1105
+ if (cachedRecord.sourceHash !== identity.sourceHash) return { valid: false, reason: "source-hash" };
1106
+ if (cachedRecord.format !== identity.format) return { valid: false, reason: "format" };
1107
+ if (cachedRecord.compilerFingerprint !== identity.compilerFingerprint) return { valid: false, reason: "compiler-fingerprint" };
1108
+ if (cachedRecord.compileContextHash !== identity.compileContextHash) return { valid: false, reason: "compile-context" };
1109
+ try {
1110
+ normalizeCompiledArtifact(cachedRecord.artifact);
1111
+ } catch {
1112
+ return { valid: false, reason: "artifact" };
1113
+ }
1114
+ return { valid: true };
1115
+ }
1116
+
1117
+ function isCacheRecordExpired(cachedRecord) {
1118
+ const maxAge = compileCacheConfig?.maxAge;
1119
+ return Number.isFinite(maxAge) && maxAge >= 0 && Date.now() - Number(cachedRecord.createdAt ?? 0) > maxAge;
1120
+ }
1121
+
1122
+ async function writePersistentCompileRecord(record, identity, persistentRecord) {
1123
+ const storageKey = compileCacheStorageKey(identity.key);
1124
+ try {
1125
+ await compileCacheConfig.store.set(storageKey, persistentRecord);
1126
+ } catch (error) {
1127
+ if (!isQuotaError(error)) {
1128
+ emitCompileCacheError(record, "write", error, identity);
1129
+ return false;
1130
+ }
1131
+
1132
+ await pruneCompileCache(record, { quotaRecovery: true });
1133
+ try {
1134
+ await compileCacheConfig.store.set(storageKey, persistentRecord);
1135
+ } catch (retryError) {
1136
+ emitCompileCacheError(record, "write", retryError, identity);
1137
+ return false;
1138
+ }
1139
+ }
1140
+
1141
+ emit({
1142
+ type: "compile-cache-write",
1143
+ id: record.id,
1144
+ key: identity.key,
1145
+ source: "compiler",
1146
+ store: compileCacheConfig.store.kind ?? "custom",
1147
+ byteSize: persistentRecord.byteSize,
1148
+ });
1149
+ await pruneCompileCache(record);
1150
+ return true;
1151
+ }
1152
+
1153
+ async function pruneCompileCache(record, pruneOptions = {}) {
1154
+ if (!compileCacheConfig || typeof compileCacheConfig.store.entries !== "function") return 0;
1155
+ const { maxEntries, maxBytes, maxAge } = compileCacheConfig;
1156
+ const quotaRecovery = pruneOptions.quotaRecovery === true;
1157
+ if (!quotaRecovery && !Number.isFinite(maxEntries) && !Number.isFinite(maxBytes) && !Number.isFinite(maxAge)) return 0;
1158
+
1159
+ try {
1160
+ const entries = await compileCacheConfig.store.entries({ prefix: compileCacheVersionPrefix() });
1161
+ const nowValue = Date.now();
1162
+ const live = [];
1163
+ let evicted = 0;
1164
+ for (const [key, value] of entries) {
1165
+ if (Number.isFinite(maxAge) && maxAge >= 0 && nowValue - Number(value?.createdAt ?? 0) > maxAge) {
1166
+ await compileCacheConfig.store.delete(key);
1167
+ evicted += 1;
1168
+ emit({ type: "compile-cache-evict", id: record?.id, key: value?.key, reason: "maxAge", store: compileCacheConfig.store.kind ?? "custom" });
1169
+ continue;
1170
+ }
1171
+ live.push([key, value]);
1172
+ }
1173
+
1174
+ live.sort((a, b) => Number(a[1]?.lastUsedAt ?? a[1]?.createdAt ?? 0) - Number(b[1]?.lastUsedAt ?? b[1]?.createdAt ?? 0));
1175
+ let totalBytes = live.reduce((sum, [, value]) => sum + Number(value?.byteSize ?? 0), 0);
1176
+
1177
+ while (
1178
+ (Number.isFinite(maxEntries) && live.length > maxEntries) ||
1179
+ (Number.isFinite(maxBytes) && totalBytes > maxBytes)
1180
+ ) {
1181
+ const [key, value] = live.shift();
1182
+ await compileCacheConfig.store.delete(key);
1183
+ totalBytes -= Number(value?.byteSize ?? 0);
1184
+ evicted += 1;
1185
+ emit({
1186
+ type: "compile-cache-evict",
1187
+ id: record?.id,
1188
+ key: value?.key,
1189
+ reason: Number.isFinite(maxEntries) && live.length + 1 > maxEntries ? "maxEntries" : "maxBytes",
1190
+ store: compileCacheConfig.store.kind ?? "custom",
1191
+ byteSize: value?.byteSize,
1192
+ });
1193
+ }
1194
+
1195
+ if (quotaRecovery && evicted === 0 && live.length > 0) {
1196
+ const removeCount = Math.max(1, Math.ceil(live.length * 0.1));
1197
+ for (let index = 0; index < removeCount && live.length > 0; index += 1) {
1198
+ const [key, value] = live.shift();
1199
+ await compileCacheConfig.store.delete(key);
1200
+ evicted += 1;
1201
+ emit({
1202
+ type: "compile-cache-evict",
1203
+ id: record?.id,
1204
+ key: value?.key,
1205
+ reason: "quota",
1206
+ store: compileCacheConfig.store.kind ?? "custom",
1207
+ byteSize: value?.byteSize,
1208
+ });
1209
+ }
1210
+ }
1211
+ return evicted;
1212
+ } catch (error) {
1213
+ emitCompileCacheError(record, "prune", error);
1214
+ return 0;
1215
+ }
1216
+ }
1217
+
1218
+ function emitCompileCacheError(record, operation, error, identity) {
1219
+ emit({
1220
+ type: "compile-cache-error",
1221
+ id: record?.id,
1222
+ key: identity?.key,
1223
+ operation,
1224
+ store: compileCacheConfig?.store?.kind ?? (compileCacheConfig ? "custom" : undefined),
1225
+ error,
1226
+ });
1227
+ }
1228
+
1229
+ function compileCacheNamespacePrefix() {
1230
+ return `browser-module-runtime/compile/${encodeURIComponent(compileCacheConfig.namespace)}/`;
1231
+ }
1232
+
1233
+ function compileCacheVersionPrefix() {
1234
+ return `${compileCacheNamespacePrefix()}${encodeURIComponent(compileCacheConfig.version)}/`;
1235
+ }
1236
+
1237
+ function compileCacheStorageKey(key) {
1238
+ return `${compileCacheVersionPrefix()}${key}`;
1239
+ }
1240
+
1241
+ async function ensureSourceUrl(record, stack, linkOptions = {}) {
1242
+ if (record.url) return record.url;
1243
+
1244
+ if (stack.includes(record.id)) {
1245
+ const cycleStart = stack.indexOf(record.id);
1246
+ const error = new CircularDependencyError([...stack.slice(cycleStart), record.id]);
1247
+ emitError(record, "link", error);
1248
+ throw error;
1249
+ }
1250
+
1251
+ const nextStack = [...stack, record.id];
1252
+ record.state = "linking";
1253
+ emit({
1254
+ type: "module-linking",
1255
+ id: record.id,
1256
+ kind: record.kind,
1257
+ version: record.version,
1258
+ });
1259
+
1260
+ const artifact = await ensureCompiledArtifact(record, linkOptions.cacheMode ?? "use");
1261
+ const resolvedImports = [];
1262
+ const linkedDependencies = [];
1263
+ const nextDependencies = new Set();
1264
+
1265
+ for (const reference of artifact.imports ?? []) {
1266
+ let resolution;
1267
+ try {
1268
+ resolution = resolveSpecifierDetailed(reference.specifier, record.id);
1269
+ } catch (error) {
1270
+ record.state = "error";
1271
+ emitError(record, "resolve", error);
1272
+ throw error;
1273
+ }
1274
+
1275
+ const { resolved, resolutionKind } = resolution;
1276
+ const dependencyRecord = resolutionKind === "private" ? undefined : records.get(resolved);
1277
+ let replacement = resolved;
1278
+
1279
+ try {
1280
+ if (resolutionKind === "private") {
1281
+ replacement = await ensurePrivateHostUrl(
1282
+ record,
1283
+ reference.specifier,
1284
+ nextStack,
1285
+ nextDependencies,
1286
+ [],
1287
+ );
1288
+ } else if (dependencyRecord) {
1289
+ nextDependencies.add(dependencyRecord.id);
1290
+
1291
+ if (dependencyRecord.kind === "source") {
1292
+ replacement = await ensureSourceUrl(dependencyRecord, nextStack, { cacheMode: "use" });
1293
+ } else if (dependencyRecord.kind === "host") {
1294
+ replacement = await ensureHostUrl(dependencyRecord);
1295
+ } else {
1296
+ replacement = dependencyRecord.externalUrl;
1297
+ }
1298
+ } else if (isRelativeSpecifier(reference.specifier) || reference.specifier.startsWith("/")) {
1299
+ throw new ModuleResolutionError(reference.specifier, record.id);
1300
+ } else if (!allowNativeImports && !isAbsoluteUrl(resolved)) {
1301
+ throw new ModuleResolutionError(reference.specifier, record.id);
1302
+ }
1303
+ } catch (error) {
1304
+ record.state = "error";
1305
+ emitError(record, error instanceof ModuleResolutionError ? "resolve" : "link", error);
1306
+ throw error;
1307
+ }
1308
+
1309
+ resolvedImports.push({ ...reference, replacement });
1310
+ linkedDependencies.push({
1311
+ specifier: reference.specifier,
1312
+ resolvedId: dependencyRecord?.id ?? resolved,
1313
+ });
1314
+ }
1315
+
1316
+ let linkedSource;
1317
+ try {
1318
+ linkedSource = applyImportReplacements(artifact.code, resolvedImports);
1319
+ syncDependencyEdges(record, nextDependencies);
1320
+ emit({
1321
+ type: "module-linked",
1322
+ id: record.id,
1323
+ kind: record.kind,
1324
+ version: record.version,
1325
+ dependencies: linkedDependencies,
1326
+ module: toModuleInfo(record),
1327
+ });
1328
+ record.compiledCode = linkedSource;
1329
+ record.diagnostics = [...(artifact.diagnostics ?? [])];
1330
+ } catch (error) {
1331
+ record.state = "error";
1332
+ emitError(record, error instanceof ModuleResolutionError ? "resolve" : "link", error);
1333
+ throw error;
1334
+ }
1335
+
1336
+ try {
1337
+ record.url = moduleUrlBackend.create(appendSourceUrl(record.compiledCode, record.id));
1338
+ } catch (error) {
1339
+ record.state = "error";
1340
+ emitError(record, "url-create", error);
1341
+ throw error;
1342
+ }
1343
+ record.state = "compiled";
1344
+ emit({
1345
+ type: "module-compiled",
1346
+ id: record.id,
1347
+ kind: record.kind,
1348
+ version: record.version,
1349
+ module: toModuleInfo(record),
1350
+ });
1351
+ return record.url;
1352
+ }
1353
+
1354
+ async function ensureHostUrl(record) {
1355
+ if (record.url) return record.url;
1356
+
1357
+ const namespace = hostNamespaces.get(record.id);
1358
+ try {
1359
+ record.url = moduleUrlBackend.create(appendSourceUrl(
1360
+ createHostBridgeSource(record.id, namespace, `Host module ${record.id} is unavailable.`),
1361
+ `host:${record.id}`,
1362
+ ));
1363
+ } catch (error) {
1364
+ emitError(record, "host-bridge", error);
1365
+ throw error;
1366
+ }
1367
+ return record.url;
1368
+ }
1369
+
1370
+ async function ensurePrivateHostUrl(importerRecord, specifier, stack, nextDependencies, providerStack) {
1371
+ const entry = importerRecord.privateImports?.get(specifier);
1372
+ if (!entry) throw new ModuleResolutionError(specifier, importerRecord.id);
1373
+ if (entry.url) {
1374
+ for (const dependencyId of entry.dependencies ?? []) nextDependencies?.add(dependencyId);
1375
+ return entry.url;
1376
+ }
1377
+
1378
+ const namespace = await resolvePrivateImportNamespace(
1379
+ importerRecord,
1380
+ specifier,
1381
+ entry,
1382
+ stack,
1383
+ nextDependencies,
1384
+ providerStack,
1385
+ );
1386
+ const registryKey = `${importerRecord.id}\u0000${specifier}\u0000${importerRecord.version}`;
1387
+ entry.registryKey = registryKey;
1388
+ hostNamespaces.set(registryKey, namespace);
1389
+
1390
+ try {
1391
+ entry.url = moduleUrlBackend.create(appendSourceUrl(
1392
+ createHostBridgeSource(
1393
+ registryKey,
1394
+ namespace,
1395
+ `Private import ${specifier} for ${importerRecord.id} is unavailable.`,
1396
+ ),
1397
+ `private:${importerRecord.id}:${specifier}`,
1398
+ ));
1399
+ } catch (error) {
1400
+ hostNamespaces.delete(registryKey);
1401
+ entry.registryKey = undefined;
1402
+ emitError(importerRecord, "host-bridge", error);
1403
+ throw error;
1404
+ }
1405
+ return entry.url;
1406
+ }
1407
+
1408
+ async function resolvePrivateImportNamespace(importerRecord, specifier, entry, stack, nextDependencies, providerStack) {
1409
+ if (entry.kind === "static") return entry.namespace;
1410
+
1411
+ if (entry.resolved) {
1412
+ for (const dependencyId of entry.dependencies) nextDependencies?.add(dependencyId);
1413
+ return entry.namespace;
1414
+ }
1415
+
1416
+ if (entry.kind === "promise") {
1417
+ if (!entry.promise) {
1418
+ entry.promise = Promise.resolve(entry.definition).then(namespace => {
1419
+ validatePrivateImportNamespace(namespace, specifier, importerRecord.id, "Promise private import");
1420
+ entry.namespace = namespace;
1421
+ entry.resolved = true;
1422
+ return namespace;
1423
+ }).catch(error => {
1424
+ entry.promise = undefined;
1425
+ throw error;
1426
+ });
1427
+ }
1428
+ return entry.promise;
1429
+ }
1430
+
1431
+ const providerKey = `${importerRecord.id}::${specifier}`;
1432
+ if (providerStack.includes(providerKey)) {
1433
+ const cycleStart = providerStack.indexOf(providerKey);
1434
+ throw new CircularDependencyError([
1435
+ ...providerStack.slice(cycleStart).map(key => `private:${key}`),
1436
+ `private:${providerKey}`,
1437
+ ]);
1438
+ }
1439
+
1440
+ if (!entry.promise) {
1441
+ const nextProviderStack = [...providerStack, providerKey];
1442
+ entry.promise = (async () => {
1443
+ const providerDependencies = new Set();
1444
+ const context = {
1445
+ runtime: api,
1446
+ importer: importerRecord.id,
1447
+ import: async requested => importPrivateProviderDependency(
1448
+ requested,
1449
+ importerRecord,
1450
+ stack,
1451
+ providerDependencies,
1452
+ nextProviderStack,
1453
+ ),
1454
+ waitForModule: async (requested, waitOptions) => importPrivateProviderWaitForModule(
1455
+ requested,
1456
+ importerRecord,
1457
+ stack,
1458
+ providerDependencies,
1459
+ nextProviderStack,
1460
+ waitOptions,
1461
+ ),
1462
+ };
1463
+
1464
+ let namespace;
1465
+ try {
1466
+ namespace = await entry.definition(context);
1467
+ } catch (error) {
1468
+ entry.promise = undefined;
1469
+ throw error;
1470
+ }
1471
+
1472
+ try {
1473
+ validatePrivateImportNamespace(namespace, specifier, importerRecord.id, "Private import provider");
1474
+ } catch (error) {
1475
+ entry.promise = undefined;
1476
+ throw error;
1477
+ }
1478
+
1479
+ entry.namespace = namespace;
1480
+ entry.resolved = true;
1481
+ entry.dependencies = providerDependencies;
1482
+ return namespace;
1483
+ })();
1484
+ }
1485
+
1486
+ const namespace = await entry.promise;
1487
+ for (const dependencyId of entry.dependencies) nextDependencies?.add(dependencyId);
1488
+ return namespace;
1489
+ }
1490
+
1491
+ async function importPrivateProviderDependency(specifier, importerRecord, stack, providerDependencies, providerStack) {
1492
+ const raw = String(specifier);
1493
+ const { resolved, resolutionKind } = resolveSpecifierDetailed(raw, importerRecord.id);
1494
+
1495
+ if (resolutionKind === "private") {
1496
+ const entry = importerRecord.privateImports?.get(raw);
1497
+ if (!entry) throw new ModuleResolutionError(raw, importerRecord.id);
1498
+ return resolvePrivateImportNamespace(
1499
+ importerRecord,
1500
+ raw,
1501
+ entry,
1502
+ stack,
1503
+ providerDependencies,
1504
+ providerStack,
1505
+ );
1506
+ }
1507
+
1508
+ const dependencyRecord = records.get(resolved);
1509
+ if (dependencyRecord) {
1510
+ providerDependencies.add(dependencyRecord.id);
1511
+ return importRecord(dependencyRecord, stack);
1512
+ }
1513
+
1514
+ if (isRelativeSpecifier(raw) || raw.startsWith("/")) {
1515
+ throw new ModuleResolutionError(raw, importerRecord.id);
1516
+ }
1517
+ if (!allowNativeImports && !isAbsoluteUrl(resolved)) {
1518
+ throw new ModuleResolutionError(raw, importerRecord.id);
1519
+ }
1520
+ return import(resolved);
1521
+ }
1522
+
1523
+ async function importPrivateProviderWaitForModule(specifier, importerRecord, stack, providerDependencies, providerStack, waitOptions) {
1524
+ const raw = String(specifier);
1525
+ return waitForRegisteredModule(raw, importerRecord.id, waitOptions, async dependencyRecord => {
1526
+ providerDependencies.add(dependencyRecord.id);
1527
+ return importRecord(dependencyRecord, stack);
1528
+ });
1529
+ }
1530
+
1531
+ function createHostBridgeSource(registryKey, namespace, unavailableMessage) {
1532
+ const exportNames = Object.keys(namespace ?? {}).filter(name => name !== "default" && isIdentifierName(name));
1533
+ const lines = [
1534
+ `const __registry = globalThis[${JSON.stringify(HOST_REGISTRY_KEY)}];`,
1535
+ `const __runtime = __registry && __registry.get(${JSON.stringify(runtimeId)});`,
1536
+ `const __module = __runtime && __runtime.get(${JSON.stringify(registryKey)});`,
1537
+ `if (!__module) throw new Error(${JSON.stringify(unavailableMessage)});`,
1538
+ ];
1539
+
1540
+ exportNames.forEach((name, index) => {
1541
+ lines.push(`const __export${index} = __module[${JSON.stringify(name)}];`);
1542
+ });
1543
+
1544
+ if (namespace && Object.prototype.hasOwnProperty.call(namespace, "default")) {
1545
+ lines.push("export default __module.default;");
1546
+ }
1547
+
1548
+ if (exportNames.length) {
1549
+ lines.push(`export { ${exportNames.map((name, index) => `__export${index} as ${name}`).join(", ")} };`);
1550
+ }
1551
+ return lines.join("\n");
1552
+ }
1553
+
1554
+ function resolveSpecifier(specifier, importer) {
1555
+ return resolveSpecifierDetailed(specifier, importer).resolved;
1556
+ }
1557
+
1558
+ function resolveSpecifierDetailed(specifier, importer) {
1559
+ const raw = String(specifier);
1560
+ emit({
1561
+ type: "module-resolving",
1562
+ specifier: raw,
1563
+ importer: importer ?? null,
1564
+ });
1565
+
1566
+ let resolved;
1567
+ let resolutionKind;
1568
+
1569
+ try {
1570
+ const pin = packagePolicy.inspect(raw);
1571
+ if (typeof customResolve === "function") {
1572
+ const custom = customResolve(raw, importer, api);
1573
+ if (typeof custom === "string" && custom) {
1574
+ const target = normalizeResolved(custom, importer);
1575
+ if (pin && target !== pin.url) {
1576
+ throw new PackageVersionResolutionError("PACKAGE_VERSION_CONFLICT", `Custom resolver returned ${JSON.stringify(target)} for pinned import ${JSON.stringify(raw)}, expected ${JSON.stringify(pin.url)}.`, { specifier: raw, importer, expected: pin.url, actual: target });
1577
+ }
1578
+ resolved = target;
1579
+ resolutionKind = "custom";
1580
+ }
1581
+ }
1582
+
1583
+ if (resolved == null && importer) {
1584
+ const importerRecord = records.get(normalizeLookupId(importer));
1585
+ if (importerRecord?.kind === "source" && importerRecord.privateImports?.has(raw)) {
1586
+ resolved = raw;
1587
+ resolutionKind = "private";
1588
+ }
1589
+ }
1590
+
1591
+ if (resolved == null && records.has(raw)) {
1592
+ resolved = raw;
1593
+ resolutionKind = "registered";
1594
+ }
1595
+ if (resolved == null && isAbsoluteUrl(raw)) {
1596
+ resolved = raw;
1597
+ resolutionKind = "url";
1598
+ }
1599
+ if (resolved == null && raw.startsWith("/")) {
1600
+ resolved = normalizePath(raw);
1601
+ resolutionKind = "absolute";
1602
+ }
1603
+ if (resolved == null && isRelativeSpecifier(raw)) {
1604
+ if (!importer) resolved = normalizePath(`/${raw}`);
1605
+ else if (isAbsoluteUrl(importer)) resolved = new URL(raw, importer).href;
1606
+ else resolved = normalizePath(`${dirname(importer)}/${raw}`);
1607
+ resolutionKind = "relative";
1608
+ }
1609
+ if (resolved == null && pin) {
1610
+ resolved = pin.url;
1611
+ resolutionKind = pin.kind;
1612
+ }
1613
+ if (resolved == null && isBareSpecifier(raw) && typeof customFallbackResolve === "function") {
1614
+ const fallback = customFallbackResolve(raw, importer, api);
1615
+ if (typeof fallback === "string" && fallback) {
1616
+ const fallbackResolved = normalizeResolved(fallback, importer);
1617
+
1618
+ // fallbackResolve() is allowed to redirect a bare specifier to a
1619
+ // runtime-owned virtual module, but missing virtual paths must keep
1620
+ // the runtime's normal no-network-fallback semantics. Resolver hooks
1621
+ // are deliberately not re-entered for the returned target.
1622
+ if ((fallback.startsWith("/") || isRelativeSpecifier(fallback)) && !records.has(fallbackResolved)) {
1623
+ throw new ModuleResolutionError(
1624
+ raw,
1625
+ importer,
1626
+ `fallbackResolve() returned unresolved virtual module ${JSON.stringify(fallback)} for ${JSON.stringify(raw)} from ${JSON.stringify(importer ?? "<runtime>")}.`,
1627
+ );
1628
+ }
1629
+
1630
+ resolved = fallbackResolved;
1631
+ resolutionKind = "fallback";
1632
+ }
1633
+ }
1634
+ if (resolved == null) {
1635
+ resolved = raw;
1636
+ resolutionKind = "native";
1637
+ }
1638
+ } catch (error) {
1639
+ throw error;
1640
+ }
1641
+
1642
+ emit({
1643
+ type: "module-resolved",
1644
+ specifier: raw,
1645
+ importer: importer ?? null,
1646
+ resolvedId: resolved,
1647
+ resolutionKind,
1648
+ });
1649
+ return { resolved, resolutionKind };
1650
+ }
1651
+
1652
+ function syncDependencyEdges(record, nextDependencies) {
1653
+ for (const previous of record.dependencies) {
1654
+ if (!nextDependencies.has(previous)) records.get(previous)?.dependents.delete(record.id);
1655
+ }
1656
+
1657
+ for (const next of nextDependencies) records.get(next)?.dependents.add(record.id);
1658
+ record.dependencies = nextDependencies;
1659
+ }
1660
+
1661
+ function revokeRecordUrl(record) {
1662
+ if (!record?.url) return;
1663
+ try {
1664
+ moduleUrlBackend.revoke?.(record.url);
1665
+ } finally {
1666
+ record.url = undefined;
1667
+ }
1668
+ }
1669
+
1670
+ function revokePrivateImportUrls(record) {
1671
+ for (const entry of record?.privateImports?.values?.() ?? []) {
1672
+ if (entry.url) {
1673
+ try {
1674
+ moduleUrlBackend.revoke?.(entry.url);
1675
+ } finally {
1676
+ entry.url = undefined;
1677
+ }
1678
+ }
1679
+ if (entry.registryKey) {
1680
+ hostNamespaces.delete(entry.registryKey);
1681
+ entry.registryKey = undefined;
1682
+ }
1683
+ if (entry.kind !== "static") {
1684
+ entry.namespace = undefined;
1685
+ entry.promise = undefined;
1686
+ entry.resolved = false;
1687
+ entry.dependencies = new Set();
1688
+ }
1689
+ }
1690
+ }
1691
+
1692
+ function emit(event) {
1693
+ if (events.size === 0) return;
1694
+ const payload = {
1695
+ runtimeId,
1696
+ timestamp: Date.now(),
1697
+ ...event,
1698
+ };
1699
+ if (eventBufferDepth > 0) {
1700
+ eventBuffer.push(payload);
1701
+ return;
1702
+ }
1703
+ events.emit(payload);
1704
+ }
1705
+
1706
+ function flushEventBuffer() {
1707
+ if (eventBuffer.length === 0) return;
1708
+ const pending = eventBuffer.splice(0, eventBuffer.length);
1709
+ for (const event of pending) events.emit(event);
1710
+ }
1711
+
1712
+ function emitError(record, phase, error) {
1713
+ emit({
1714
+ type: "module-error",
1715
+ id: record?.id,
1716
+ kind: record?.kind,
1717
+ version: record?.version,
1718
+ phase,
1719
+ error,
1720
+ });
1721
+ }
1722
+
1723
+ function toModuleInfo(record) {
1724
+ return {
1725
+ id: record.id,
1726
+ kind: record.kind,
1727
+ state: record.state,
1728
+ version: record.version,
1729
+ format: record.format,
1730
+ dependencies: [...record.dependencies],
1731
+ dependents: [...record.dependents],
1732
+ url: record.kind === "url" ? record.externalUrl : record.url,
1733
+ diagnostics: [...(record.diagnostics ?? [])],
1734
+ ...(record.kind === "source" ? {
1735
+ compileCache: { ...record.compileCacheInfo },
1736
+ privateImports: [...record.privateImports].map(([specifier, entry]) => ({
1737
+ specifier,
1738
+ shadowsRuntimeModule: records.has(specifier),
1739
+ kind: entry.kind,
1740
+ resolved: entry.resolved,
1741
+ ...(entry.kind === "provider" ? { provider: true } : {}),
1742
+ ...(entry.kind !== "static" ? { dependencies: [...entry.dependencies] } : {}),
1743
+ })),
1744
+ } : {}),
1745
+ };
1746
+ }
1747
+ }
1748
+
1749
+ function normalizePrivateImports(value, moduleId) {
1750
+ if (value == null) return new Map();
1751
+ if (typeof value !== "object" || Array.isArray(value)) {
1752
+ throw new TypeError(`Private imports for ${JSON.stringify(moduleId)} must be an object keyed by # specifiers.`);
1753
+ }
1754
+
1755
+ const result = new Map();
1756
+ for (const [specifier, definition] of Object.entries(value)) {
1757
+ if (!specifier.startsWith("#") || specifier.length < 2) {
1758
+ throw new TypeError(
1759
+ `Private import ${JSON.stringify(specifier)} for ${JSON.stringify(moduleId)} must use a #-prefixed specifier.`,
1760
+ );
1761
+ }
1762
+
1763
+ const provider = isPrivateImportProviderDefinition(definition);
1764
+ const promise = !provider && isPromiseLike(definition);
1765
+ const kind = provider ? "provider" : promise ? "promise" : "static";
1766
+ if (kind === "static" && (typeof definition !== "object" || definition === null) && typeof definition !== "function") {
1767
+ throw new TypeError(
1768
+ `Private import ${JSON.stringify(specifier)} for ${JSON.stringify(moduleId)} must be a namespace object, PromiseLike namespace, or lazy provider function.`,
1769
+ );
1770
+ }
1771
+
1772
+ result.set(specifier, {
1773
+ definition,
1774
+ provider,
1775
+ kind,
1776
+ namespace: kind === "static" ? definition : undefined,
1777
+ resolved: kind === "static",
1778
+ promise: undefined,
1779
+ dependencies: new Set(),
1780
+ url: undefined,
1781
+ registryKey: undefined,
1782
+ });
1783
+ }
1784
+ return result;
1785
+ }
1786
+
1787
+ function isPrivateImportProviderDefinition(value) {
1788
+ if (typeof value !== "function") return false;
1789
+
1790
+ // Callable namespace objects with explicit own exports keep the 0.0.27
1791
+ // static-namespace behavior. A plain function with no namespace-shaped own
1792
+ // exports is interpreted as the new lazy sync/async provider form.
1793
+ return Object.keys(value).length === 0 && !Object.prototype.hasOwnProperty.call(value, "default");
1794
+ }
1795
+
1796
+ function isPromiseLike(value) {
1797
+ return value != null && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
1798
+ }
1799
+
1800
+ function validatePrivateImportNamespace(namespace, specifier, importer, label) {
1801
+ if ((typeof namespace !== "object" || namespace === null) && typeof namespace !== "function") {
1802
+ throw new TypeError(
1803
+ `${label} ${JSON.stringify(specifier)} for ${JSON.stringify(importer)} must resolve to an object, function, or ES module namespace-like value.`,
1804
+ );
1805
+ }
1806
+ }
1807
+
1808
+ function normalizeWaitForModuleId(id, importer) {
1809
+ const raw = String(id);
1810
+ if (isAbsoluteUrl(raw) || isBareSpecifier(raw)) return raw;
1811
+ if (raw.startsWith("/")) return normalizePath(raw);
1812
+ if (isRelativeSpecifier(raw) && importer) {
1813
+ if (isAbsoluteUrl(importer)) return new URL(raw, importer).href;
1814
+ return normalizePath(`${dirname(importer)}/${raw}`);
1815
+ }
1816
+ return normalizePath(`/${raw}`);
1817
+ }
1818
+
1819
+ function normalizeWaitForModuleOptions(options) {
1820
+ if (options == null) return { timeout: undefined, signal: undefined };
1821
+ if (typeof options !== "object") throw new TypeError("waitForModule() options must be an object.");
1822
+
1823
+ let timeout;
1824
+ if (options.timeout != null) {
1825
+ timeout = Number(options.timeout);
1826
+ if (!Number.isFinite(timeout) || timeout < 0) {
1827
+ throw new TypeError("waitForModule() timeout must be a finite number greater than or equal to 0 milliseconds.");
1828
+ }
1829
+ }
1830
+
1831
+ const signal = options.signal;
1832
+ if (signal != null && (typeof signal !== "object" || typeof signal.addEventListener !== "function" || typeof signal.removeEventListener !== "function")) {
1833
+ throw new TypeError("waitForModule() signal must be an AbortSignal.");
1834
+ }
1835
+ return { timeout, signal };
1836
+ }
1837
+
1838
+ function createAbortError(signal) {
1839
+ if (signal?.reason !== undefined) return signal.reason;
1840
+ if (typeof DOMException === "function") return new DOMException("The operation was aborted.", "AbortError");
1841
+ const error = new Error("The operation was aborted.");
1842
+ error.name = "AbortError";
1843
+ return error;
1844
+ }
1845
+
1846
+ function privateImportDefinitions(record) {
1847
+ const result = {};
1848
+ for (const [specifier, entry] of record?.privateImports ?? []) result[specifier] = entry.definition;
1849
+ return result;
1850
+ }
1851
+
1852
+ function getHostRegistry() {
1853
+ let registry = globalThis[HOST_REGISTRY_KEY];
1854
+ if (!(registry instanceof Map)) {
1855
+ registry = new Map();
1856
+ Object.defineProperty(globalThis, HOST_REGISTRY_KEY, {
1857
+ value: registry,
1858
+ configurable: true,
1859
+ writable: true,
1860
+ });
1861
+ }
1862
+ return registry;
1863
+ }
1864
+
1865
+ function applyImportReplacements(source, references) {
1866
+ const replacements = references
1867
+ .map(reference => ({
1868
+ start: reference.start,
1869
+ end: reference.end,
1870
+ text: JSON.stringify(reference.replacement),
1871
+ }))
1872
+ .sort((a, b) => b.start - a.start);
1873
+
1874
+ let output = source;
1875
+ for (const replacement of replacements) {
1876
+ output = output.slice(0, replacement.start) + replacement.text + output.slice(replacement.end);
1877
+ }
1878
+ return output;
1879
+ }
1880
+
1881
+ function normalizeDefinedId(id) {
1882
+ const value = String(id);
1883
+ if (isAbsoluteUrl(value) || isBareSpecifier(value)) return value;
1884
+ if (value.startsWith("/")) return normalizePath(value);
1885
+ return normalizePath(`/${value}`);
1886
+ }
1887
+
1888
+ function normalizeLookupId(id) {
1889
+ const value = String(id);
1890
+ if (isAbsoluteUrl(value) || isBareSpecifier(value)) return value;
1891
+ if (value.startsWith("/")) return normalizePath(value);
1892
+ return normalizePath(`/${value}`);
1893
+ }
1894
+
1895
+ function normalizeResolved(value, importer) {
1896
+ if (isAbsoluteUrl(value) || isBareSpecifier(value)) return value;
1897
+ if (value.startsWith("/")) return normalizePath(value);
1898
+ if (isRelativeSpecifier(value) && importer) {
1899
+ if (isAbsoluteUrl(importer)) return new URL(value, importer).href;
1900
+ return normalizePath(`${dirname(importer)}/${value}`);
1901
+ }
1902
+ return normalizePath(`/${value}`);
1903
+ }
1904
+
1905
+ function isBareSpecifier(value) {
1906
+ return !value.startsWith(".") && !value.startsWith("/") && !isAbsoluteUrl(value);
1907
+ }
1908
+
1909
+ function isRelativeSpecifier(value) {
1910
+ return value === "." || value === ".." || value.startsWith("./") || value.startsWith("../");
1911
+ }
1912
+
1913
+ function isAbsoluteUrl(value) {
1914
+ return /^[A-Za-z][A-Za-z\d+.-]*:/.test(value);
1915
+ }
1916
+
1917
+ function dirname(id) {
1918
+ const index = id.lastIndexOf("/");
1919
+ return index <= 0 ? "/" : id.slice(0, index);
1920
+ }
1921
+
1922
+ function normalizePath(path) {
1923
+ const absolute = path.startsWith("/");
1924
+ const parts = [];
1925
+
1926
+ for (const part of path.split("/")) {
1927
+ if (!part || part === ".") continue;
1928
+ if (part === "..") {
1929
+ parts.pop();
1930
+ } else {
1931
+ parts.push(part);
1932
+ }
1933
+ }
1934
+
1935
+ return `${absolute ? "/" : ""}${parts.join("/")}` || "/";
1936
+ }
1937
+
1938
+ function isIdentifierName(name) {
1939
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name);
1940
+ }
1941
+
1942
+ function appendSourceUrl(code, id) {
1943
+ return `${code}\n//# sourceURL=${sanitizeSourceUrl(id)}`;
1944
+ }
1945
+
1946
+ function sanitizeSourceUrl(id) {
1947
+ return `browser-module-runtime:${String(id).replace(/[\r\n]/g, "")}`;
1948
+ }
1949
+
1950
+ function randomId() {
1951
+ if (globalThis.crypto?.randomUUID) return globalThis.crypto.randomUUID();
1952
+ return Math.random().toString(36).slice(2);
1953
+ }
1954
+
1955
+ function normalizeCompileCacheAlias(options) {
1956
+ const hasCache = Object.prototype.hasOwnProperty.call(options ?? {}, "cache");
1957
+ const hasCompileCache = Object.prototype.hasOwnProperty.call(options ?? {}, "compileCache")
1958
+ && options.compileCache !== undefined;
1959
+ if (hasCache && hasCompileCache) {
1960
+ throw new TypeError("createRuntime() received both cache and compileCache. Use compileCache as the canonical option.");
1961
+ }
1962
+ if (!hasCache) return options?.compileCache;
1963
+ if (options.cache !== true && options.cache !== false && options.cache != null) {
1964
+ throw new TypeError("createRuntime().cache must be true or false.");
1965
+ }
1966
+ return options.cache ?? false;
1967
+ }
1968
+
1969
+ function normalizeCompileCacheOptions(options) {
1970
+ if (options == null || options === false) return undefined;
1971
+ if (options === true) options = createCompileCache();
1972
+ if (typeof options !== "object") {
1973
+ throw new TypeError("compileCache must be true, false, or an options object with a store.");
1974
+ }
1975
+ if (options.enabled === false) return undefined;
1976
+ const store = options.store;
1977
+ if (!store || typeof store.get !== "function" || typeof store.set !== "function" || typeof store.delete !== "function") {
1978
+ throw new TypeError("compileCache.store must provide async get(), set(), and delete() methods.");
1979
+ }
1980
+ return {
1981
+ store,
1982
+ namespace: String(options.namespace ?? "default"),
1983
+ version: String(options.version ?? "1"),
1984
+ maxEntries: normalizeLimit(options.maxEntries),
1985
+ maxBytes: normalizeLimit(options.maxBytes),
1986
+ maxAge: normalizeLimit(options.maxAge),
1987
+ };
1988
+ }
1989
+
1990
+ function normalizeCompileCacheMode(mode) {
1991
+ if (mode == null) return "use";
1992
+ if (mode === "use" || mode === "refresh" || mode === "bypass") return mode;
1993
+ throw new TypeError(`Unknown compile cache mode ${JSON.stringify(mode)}. Expected "use", "refresh", or "bypass".`);
1994
+ }
1995
+
1996
+ function normalizeCompiledArtifact(artifact) {
1997
+ if (!artifact || typeof artifact !== "object") {
1998
+ throw new TypeError("Compiler returned an invalid compiled artifact.");
1999
+ }
2000
+ const code = String(artifact.code ?? "");
2001
+ const imports = Array.isArray(artifact.imports) ? artifact.imports.map((reference, index) => {
2002
+ if (!reference || typeof reference !== "object") {
2003
+ throw new TypeError(`Compiled artifact import ${index} is invalid.`);
2004
+ }
2005
+ const start = Number(reference.start);
2006
+ const end = Number(reference.end);
2007
+ const specifier = String(reference.specifier ?? "");
2008
+ if (!Number.isInteger(start) || !Number.isInteger(end) || start < 0 || end <= start || end > code.length) {
2009
+ throw new TypeError(`Compiled artifact import ${JSON.stringify(specifier)} has invalid source offsets.`);
2010
+ }
2011
+ return {
2012
+ specifier,
2013
+ start,
2014
+ end,
2015
+ kind: reference.kind ?? "static",
2016
+ };
2017
+ }) : [];
2018
+
2019
+ return {
2020
+ schema: COMPILED_ARTIFACT_SCHEMA,
2021
+ code,
2022
+ imports,
2023
+ diagnostics: Array.isArray(artifact.diagnostics) ? [...artifact.diagnostics] : [],
2024
+ assets: Array.isArray(artifact.assets) ? artifact.assets.map(asset => ({type:String(asset.type),id:String(asset.id??""),content:String(asset.content??"")})) : [],
2025
+ ...(artifact.sourceMap == null ? {} : { sourceMap: String(artifact.sourceMap) }),
2026
+ ...(artifact.changed == null ? {} : { changed: Boolean(artifact.changed) }),
2027
+ };
2028
+ }
2029
+
2030
+ function isQuotaError(error) {
2031
+ const name = error?.name;
2032
+ const code = error?.code;
2033
+ return name === "QuotaExceededError" || name === "NS_ERROR_DOM_QUOTA_REACHED" || code === 22 || code === 1014;
2034
+ }
2035
+
2036
+ function normalizeLimit(value) {
2037
+ if (value == null) return undefined;
2038
+ const number = Number(value);
2039
+ return Number.isFinite(number) && number >= 0 ? number : undefined;
2040
+ }
2041
+
2042
+ function now() {
2043
+ return globalThis.performance?.now?.() ?? Date.now();
2044
+ }