@absolutejs/absolute 0.19.0-beta.851 → 0.19.0-beta.852
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
- package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
- package/dist/dev/client/handlers/angular.ts +17 -234
- package/dist/dev/client/handlers/angularRuntime.ts +0 -476
- package/dist/react/browser.js.map +1 -1
- package/dist/react/index.js.map +1 -1
- package/dist/src/react/UniversalRouter.d.ts +3 -1
- package/dist/types/globals.d.ts +0 -12
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
var __require = import.meta.require;
|
|
3
3
|
|
|
4
|
-
// .angular-partial-tmp-
|
|
4
|
+
// .angular-partial-tmp-FGqhVS/src/core/streamingSlotRegistrar.ts
|
|
5
5
|
var STREAMING_SLOT_REGISTRAR_KEY = Symbol.for("absolutejs.streamingSlotRegistrar");
|
|
6
6
|
var STREAMING_SLOT_WARNING_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotWarningController");
|
|
7
7
|
var STREAMING_SLOT_COLLECTION_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotCollectionController");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
var __require = import.meta.require;
|
|
3
3
|
|
|
4
|
-
// .angular-partial-tmp-
|
|
4
|
+
// .angular-partial-tmp-FGqhVS/src/core/streamingSlotRegistrar.ts
|
|
5
5
|
var STREAMING_SLOT_REGISTRAR_KEY = Symbol.for("absolutejs.streamingSlotRegistrar");
|
|
6
6
|
var STREAMING_SLOT_WARNING_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotWarningController");
|
|
7
7
|
var STREAMING_SLOT_COLLECTION_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotCollectionController");
|
|
@@ -48,7 +48,7 @@ var warnMissingStreamingSlotCollector = (primitiveName) => {
|
|
|
48
48
|
getWarningController()?.maybeWarn(primitiveName);
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
-
// .angular-partial-tmp-
|
|
51
|
+
// .angular-partial-tmp-FGqhVS/src/core/streamingSlotRegistry.ts
|
|
52
52
|
var STREAMING_SLOT_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotAsyncLocalStorage");
|
|
53
53
|
var isObjectRecord2 = (value) => Boolean(value) && typeof value === "object";
|
|
54
54
|
var isAsyncLocalStorage = (value) => isObjectRecord2(value) && ("getStore" in value) && typeof value.getStore === "function" && ("run" in value) && typeof value.run === "function";
|
|
@@ -67,15 +67,6 @@ type HMRMessage = {
|
|
|
67
67
|
|
|
68
68
|
type AngularHmrApi = {
|
|
69
69
|
applyUpdate: (id: string, newCtor: unknown) => boolean;
|
|
70
|
-
applyStyleUpdate?: (id: string, newCtor: unknown) => boolean;
|
|
71
|
-
applyTemplateUpdate?: (id: string, newCtor: unknown) => boolean;
|
|
72
|
-
applyServiceUpdate?: (id: string, newCtor: unknown) => boolean;
|
|
73
|
-
beginStyleUpdateBatch?: () => void;
|
|
74
|
-
endStyleUpdateBatch?: () => Array<{ id: string; ok: boolean }>;
|
|
75
|
-
beginTemplateUpdateBatch?: () => void;
|
|
76
|
-
endTemplateUpdateBatch?: () => Array<{ id: string; ok: boolean }>;
|
|
77
|
-
beginServiceUpdateBatch?: () => void;
|
|
78
|
-
endServiceUpdateBatch?: () => Array<{ id: string; ok: boolean }>;
|
|
79
70
|
getRegistry?: () => Map<string, unknown>;
|
|
80
71
|
refresh: () => void;
|
|
81
72
|
hasPageExportsChanged?: (sourceId: string) => boolean;
|
|
@@ -348,237 +339,29 @@ const handleFastUpdate = async (message: HMRMessage) => {
|
|
|
348
339
|
let activeMessage: Promise<void> | null = null;
|
|
349
340
|
let pendingMessage: HMRMessage | null = null;
|
|
350
341
|
|
|
351
|
-
/*
|
|
352
|
-
* returns false to signal "couldn't handle, fall through to reboot",
|
|
353
|
-
* letting Phase 2 ship piecewise — we land §2.1 (this dispatch table)
|
|
354
|
-
* first, then §2.4 / §2.3 / §2.2 fill in the stubs one at a time
|
|
355
|
-
* without further plumbing changes. */
|
|
356
|
-
/* Template HMR — re-imports the rebuilt page chunk under FAST_PATCH +
|
|
357
|
-
* TEMPLATE_UPDATE_MODE, then asks the runtime to swap the template
|
|
358
|
-
* subgraph of `ɵcmp` (template factory, slot counts, queries,
|
|
359
|
-
* dependencies, host bindings) on every re-registered component.
|
|
342
|
+
/* Surgical fast-path stubs.
|
|
360
343
|
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
*
|
|
344
|
+
* Phase 2's dynamic-import-based handlers (component-style /
|
|
345
|
+
* template / service-method-only) are intentionally absent here —
|
|
346
|
+
* they were architecturally wrong (dynamic-importing the rebuilt
|
|
347
|
+
* page chunk created a parallel class identity, tripping NG0912
|
|
348
|
+
* collisions and producing scope-ID drift on Emulated styles). The
|
|
349
|
+
* surgical pipeline that replaces them uses Angular'''s
|
|
350
|
+
* `ɵɵreplaceMetadata` primitive — see SURGICAL_HMR.md.
|
|
365
351
|
*
|
|
366
|
-
*
|
|
367
|
-
* through to
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
const handleTemplateUpdate = async (message: HMRMessage): Promise<boolean> => {
|
|
373
|
-
const hmr = window.__ANGULAR_HMR__;
|
|
374
|
-
if (
|
|
375
|
-
!hmr ||
|
|
376
|
-
!hmr.applyTemplateUpdate ||
|
|
377
|
-
!hmr.beginTemplateUpdateBatch ||
|
|
378
|
-
!hmr.endTemplateUpdateBatch
|
|
379
|
-
) {
|
|
380
|
-
return false;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
const indexPath = findIndexPath(
|
|
384
|
-
message.data.manifest,
|
|
385
|
-
message.data.sourceFile,
|
|
386
|
-
'angular'
|
|
387
|
-
);
|
|
388
|
-
if (!indexPath) return false;
|
|
389
|
-
|
|
390
|
-
const w = window as TemplateUpdateWindow;
|
|
391
|
-
w.__ANGULAR_HMR_FAST_PATCH__ = true;
|
|
392
|
-
w.__ANGULAR_HMR_TEMPLATE_UPDATE_MODE__ = true;
|
|
393
|
-
hmr.beginTemplateUpdateBatch();
|
|
394
|
-
|
|
395
|
-
const origWarn = suppressNg0912();
|
|
396
|
-
try {
|
|
397
|
-
await import(`${indexPath}?t=${Date.now()}`);
|
|
398
|
-
|
|
399
|
-
// Page-level routes/providers cannot ride a template update.
|
|
400
|
-
if (hmr.hasPageExportsChanged?.(message.data.sourceFile || '')) {
|
|
401
|
-
return false;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
const results = hmr.endTemplateUpdateBatch();
|
|
405
|
-
// Empty batch = the chunk's components weren't already in the
|
|
406
|
-
// registry (off-page broadcast). No-op success — see the
|
|
407
|
-
// matching comment in `handleComponentStyleUpdate`.
|
|
408
|
-
if (results.length === 0) {
|
|
409
|
-
console.warn = origWarn;
|
|
410
|
-
return true;
|
|
411
|
-
}
|
|
412
|
-
if (!results.every((r) => r.ok)) return false;
|
|
413
|
-
|
|
414
|
-
console.warn = origWarn;
|
|
415
|
-
hmr.refresh();
|
|
416
|
-
|
|
417
|
-
return true;
|
|
418
|
-
} catch (err) {
|
|
419
|
-
console.warn = origWarn;
|
|
420
|
-
console.warn(
|
|
421
|
-
'[HMR] Angular template update failed, falling back:',
|
|
422
|
-
err
|
|
423
|
-
);
|
|
424
|
-
return false;
|
|
425
|
-
} finally {
|
|
426
|
-
delete w.__ANGULAR_HMR_FAST_PATCH__;
|
|
427
|
-
delete w.__ANGULAR_HMR_TEMPLATE_UPDATE_MODE__;
|
|
428
|
-
console.warn = origWarn;
|
|
429
|
-
}
|
|
430
|
-
};
|
|
431
|
-
|
|
432
|
-
/* Component-style HMR — re-imports the rebuilt page chunk under the
|
|
433
|
-
* combined `FAST_PATCH` and `STYLE_UPDATE_MODE` flags so:
|
|
434
|
-
* - the chunk's bootstrap section is skipped (FAST_PATCH)
|
|
435
|
-
* - every per-file auto-registration block routes its new ctor
|
|
436
|
-
* through `applyStyleUpdate` instead of a no-op (STYLE_UPDATE_MODE)
|
|
437
|
-
*
|
|
438
|
-
* The registration-block path is the only way to reach CHILD
|
|
439
|
-
* components — the page chunk's `export *` only re-exports the page's
|
|
440
|
-
* own module, so a top-level export walk would miss imported
|
|
441
|
-
* components like `LayoutComponent`. Each compiled .ts file emits a
|
|
442
|
-
* registration block for its own component classes, so the chunk
|
|
443
|
-
* covers the whole tree on re-evaluation.
|
|
444
|
-
*
|
|
445
|
-
* Returns true iff every component the chunk re-registered swapped
|
|
446
|
-
* its styles cleanly. Any failure (Shadow DOM, length change, missing
|
|
447
|
-
* live <style> tag) → reboot. The transactional check inside
|
|
448
|
-
* `applyStyleUpdate` means we never apply a partial update — either
|
|
449
|
-
* the page restyles coherently or we reboot. */
|
|
450
|
-
type StyleUpdateWindow = FastPatchWindow & {
|
|
451
|
-
__ANGULAR_HMR_STYLE_UPDATE_MODE__?: boolean;
|
|
452
|
-
};
|
|
352
|
+
* Until that pipeline lands, classifications other than
|
|
353
|
+
* `class-component` fall through to the existing reboot path. The
|
|
354
|
+
* toast tells the developer why. */
|
|
355
|
+
const handleTemplateUpdate = async (_message: HMRMessage): Promise<boolean> =>
|
|
356
|
+
false;
|
|
453
357
|
|
|
454
358
|
const handleComponentStyleUpdate = async (
|
|
455
|
-
|
|
456
|
-
): Promise<boolean> =>
|
|
457
|
-
const hmr = window.__ANGULAR_HMR__;
|
|
458
|
-
if (
|
|
459
|
-
!hmr ||
|
|
460
|
-
!hmr.applyStyleUpdate ||
|
|
461
|
-
!hmr.beginStyleUpdateBatch ||
|
|
462
|
-
!hmr.endStyleUpdateBatch
|
|
463
|
-
) {
|
|
464
|
-
return false;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
const indexPath = findIndexPath(
|
|
468
|
-
message.data.manifest,
|
|
469
|
-
message.data.sourceFile,
|
|
470
|
-
'angular'
|
|
471
|
-
);
|
|
472
|
-
if (!indexPath) return false;
|
|
473
|
-
|
|
474
|
-
const w = window as StyleUpdateWindow;
|
|
475
|
-
w.__ANGULAR_HMR_FAST_PATCH__ = true;
|
|
476
|
-
w.__ANGULAR_HMR_STYLE_UPDATE_MODE__ = true;
|
|
477
|
-
hmr.beginStyleUpdateBatch();
|
|
478
|
-
|
|
479
|
-
try {
|
|
480
|
-
await import(`${indexPath}?t=${Date.now()}`);
|
|
481
|
-
|
|
482
|
-
// Page-level routes/providers cannot ride a style update — they
|
|
483
|
-
// are read once during bootstrap. If they changed in this
|
|
484
|
-
// rebuild, reboot rather than risk a stale router/injector.
|
|
485
|
-
if (hmr.hasPageExportsChanged?.(message.data.sourceFile || '')) {
|
|
486
|
-
return false;
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
const results = hmr.endStyleUpdateBatch();
|
|
490
|
-
// Empty batch is a no-op success: the chunk re-evaluated but
|
|
491
|
-
// none of its components were already in the registry, so they
|
|
492
|
-
// couldn't be live on the page right now. Common when a CSS
|
|
493
|
-
// edit affects multiple page bundles (the server broadcasts
|
|
494
|
-
// once per page) and the user is only looking at one of them —
|
|
495
|
-
// the off-page broadcasts add fresh entries to the registry but
|
|
496
|
-
// produce no batch updates. Treating that as a failure forced
|
|
497
|
-
// fallthrough to reboot for every off-page broadcast, which
|
|
498
|
-
// fired `startViewTransition` repeatedly and produced the
|
|
499
|
-
// "Transition was skipped" abort when the second reboot
|
|
500
|
-
// superseded the first mid-flight.
|
|
501
|
-
if (results.length === 0) return true;
|
|
502
|
-
return results.every((r) => r.ok);
|
|
503
|
-
} catch (err) {
|
|
504
|
-
console.warn('[HMR] Angular style update failed, falling back:', err);
|
|
505
|
-
return false;
|
|
506
|
-
} finally {
|
|
507
|
-
delete w.__ANGULAR_HMR_FAST_PATCH__;
|
|
508
|
-
delete w.__ANGULAR_HMR_STYLE_UPDATE_MODE__;
|
|
509
|
-
}
|
|
510
|
-
};
|
|
511
|
-
|
|
512
|
-
/* Service HMR — re-imports the rebuilt page chunk under FAST_PATCH +
|
|
513
|
-
* SERVICE_UPDATE_MODE so the page's auto-registration block routes
|
|
514
|
-
* each new service ctor through `applyServiceUpdate`. The runtime
|
|
515
|
-
* does prototype method-swap (always) and best-effort field merge on
|
|
516
|
-
* the live singleton (when reachable via the root injector and
|
|
517
|
-
* donor-instantiable). Live components keep their references — they
|
|
518
|
-
* just call into the new method bodies on next invocation.
|
|
519
|
-
*
|
|
520
|
-
* This path only runs when the server-side classifier returned
|
|
521
|
-
* `service-method-only` — services with side-effecting constructors
|
|
522
|
-
* never get here, so the live singleton's existing subscriptions /
|
|
523
|
-
* timers / listeners stay intact and we don't double-register them. */
|
|
524
|
-
type ServiceUpdateWindow = FastPatchWindow & {
|
|
525
|
-
__ANGULAR_HMR_SERVICE_UPDATE_MODE__?: boolean;
|
|
526
|
-
};
|
|
359
|
+
_message: HMRMessage
|
|
360
|
+
): Promise<boolean> => false;
|
|
527
361
|
|
|
528
362
|
const handleServiceMethodSwap = async (
|
|
529
|
-
|
|
530
|
-
): Promise<boolean> =>
|
|
531
|
-
const hmr = window.__ANGULAR_HMR__;
|
|
532
|
-
if (
|
|
533
|
-
!hmr ||
|
|
534
|
-
!hmr.applyServiceUpdate ||
|
|
535
|
-
!hmr.beginServiceUpdateBatch ||
|
|
536
|
-
!hmr.endServiceUpdateBatch
|
|
537
|
-
) {
|
|
538
|
-
return false;
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
const indexPath = findIndexPath(
|
|
542
|
-
message.data.manifest,
|
|
543
|
-
message.data.sourceFile,
|
|
544
|
-
'angular'
|
|
545
|
-
);
|
|
546
|
-
if (!indexPath) return false;
|
|
547
|
-
|
|
548
|
-
const w = window as ServiceUpdateWindow;
|
|
549
|
-
w.__ANGULAR_HMR_FAST_PATCH__ = true;
|
|
550
|
-
w.__ANGULAR_HMR_SERVICE_UPDATE_MODE__ = true;
|
|
551
|
-
hmr.beginServiceUpdateBatch();
|
|
552
|
-
|
|
553
|
-
try {
|
|
554
|
-
await import(`${indexPath}?t=${Date.now()}`);
|
|
555
|
-
|
|
556
|
-
// Page-level routes/providers cannot ride a service update.
|
|
557
|
-
if (hmr.hasPageExportsChanged?.(message.data.sourceFile || '')) {
|
|
558
|
-
return false;
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
const results = hmr.endServiceUpdateBatch();
|
|
562
|
-
// Empty batch = off-page broadcast, see comment in
|
|
563
|
-
// `handleComponentStyleUpdate`.
|
|
564
|
-
if (results.length === 0) return true;
|
|
565
|
-
if (!results.every((r) => r.ok)) return false;
|
|
566
|
-
|
|
567
|
-
// New method bodies might compute new values for observable-fed
|
|
568
|
-
// fields, so the existing component subtree should re-render.
|
|
569
|
-
// `refresh()` ticks the app + marks any pending fast-patch
|
|
570
|
-
// components dirty.
|
|
571
|
-
hmr.refresh();
|
|
572
|
-
|
|
573
|
-
return true;
|
|
574
|
-
} catch (err) {
|
|
575
|
-
console.warn('[HMR] Angular service update failed, falling back:', err);
|
|
576
|
-
return false;
|
|
577
|
-
} finally {
|
|
578
|
-
delete w.__ANGULAR_HMR_FAST_PATCH__;
|
|
579
|
-
delete w.__ANGULAR_HMR_SERVICE_UPDATE_MODE__;
|
|
580
|
-
}
|
|
581
|
-
};
|
|
363
|
+
_message: HMRMessage
|
|
364
|
+
): Promise<boolean> => false;
|
|
582
365
|
|
|
583
366
|
const logRebootReason = (message: HMRMessage) => {
|
|
584
367
|
const reason = message.data.reason;
|
|
@@ -26,21 +26,6 @@ type AngularComponentDefinition = {
|
|
|
26
26
|
providers?: unknown;
|
|
27
27
|
providersResolver?: unknown;
|
|
28
28
|
selectors?: unknown[];
|
|
29
|
-
styles?: string[];
|
|
30
|
-
encapsulation?: number;
|
|
31
|
-
template?: unknown;
|
|
32
|
-
consts?: unknown;
|
|
33
|
-
decls?: number;
|
|
34
|
-
vars?: number;
|
|
35
|
-
viewQuery?: unknown;
|
|
36
|
-
contentQueries?: unknown;
|
|
37
|
-
ngContentSelectors?: unknown;
|
|
38
|
-
dependencies?: unknown;
|
|
39
|
-
hostBindings?: unknown;
|
|
40
|
-
hostVars?: number;
|
|
41
|
-
hostAttrs?: unknown;
|
|
42
|
-
inputs?: unknown;
|
|
43
|
-
outputs?: unknown;
|
|
44
29
|
};
|
|
45
30
|
|
|
46
31
|
type ComponentCtor = (abstract new (...args: never[]) => unknown) & {
|
|
@@ -160,45 +145,6 @@ const hasProviderChanges = (oldCtor: ComponentCtor, newCtor: ComponentCtor) => {
|
|
|
160
145
|
return false;
|
|
161
146
|
};
|
|
162
147
|
|
|
163
|
-
/* Style-update batch buffer.
|
|
164
|
-
*
|
|
165
|
-
* When a component-CSS edit triggers HMR, the rebuilt page chunk
|
|
166
|
-
* re-evaluates with `__ANGULAR_HMR_STYLE_UPDATE_MODE__` set on the
|
|
167
|
-
* window. Inside that mode, every `register(id, newCtor)` call from
|
|
168
|
-
* the chunk's auto-registration block routes its newCtor straight
|
|
169
|
-
* into `applyStyleUpdate(id, newCtor)` instead of being a no-op
|
|
170
|
-
* (which is the default for already-registered IDs).
|
|
171
|
-
*
|
|
172
|
-
* This is the only way to reach CHILD-component classes — the page
|
|
173
|
-
* chunk only `export *`s the page's own module, so a top-level
|
|
174
|
-
* `Object.keys(newModule)` walk wouldn't find imported components.
|
|
175
|
-
* The registration block runs once per compiled file (page + every
|
|
176
|
-
* imported component), so it covers the whole subtree.
|
|
177
|
-
*
|
|
178
|
-
* The batch is consulted by `handleComponentStyleUpdate` after the
|
|
179
|
-
* chunk import resolves: if any registration's update returned false,
|
|
180
|
-
* the orchestrator falls through to a full reboot rather than leaving
|
|
181
|
-
* the page partially restyled. */
|
|
182
|
-
|
|
183
|
-
type StyleUpdateMode = typeof globalThis & {
|
|
184
|
-
__ANGULAR_HMR_STYLE_UPDATE_MODE__?: boolean;
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
type StyleBatchEntry = { id: string; ok: boolean };
|
|
188
|
-
|
|
189
|
-
const styleUpdateBatch: StyleBatchEntry[] = [];
|
|
190
|
-
|
|
191
|
-
const beginStyleUpdateBatch = () => {
|
|
192
|
-
styleUpdateBatch.length = 0;
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
const endStyleUpdateBatch = (): StyleBatchEntry[] => {
|
|
196
|
-
const out = styleUpdateBatch.slice();
|
|
197
|
-
styleUpdateBatch.length = 0;
|
|
198
|
-
|
|
199
|
-
return out;
|
|
200
|
-
};
|
|
201
|
-
|
|
202
148
|
const register = (id: string, ctor: unknown) => {
|
|
203
149
|
if (!id || !isComponentCtor(ctor)) return;
|
|
204
150
|
if (!componentRegistry.has(id)) {
|
|
@@ -208,34 +154,6 @@ const register = (id: string, ctor: unknown) => {
|
|
|
208
154
|
registeredAt: Date.now(),
|
|
209
155
|
updateCount: 0
|
|
210
156
|
});
|
|
211
|
-
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Already registered. If we're inside an HMR style-update or
|
|
216
|
-
// template-update window, route this re-registration's new ctor
|
|
217
|
-
// through the appropriate surgical patcher. The per-file
|
|
218
|
-
// auto-registration block is the only place to intercept new ctors
|
|
219
|
-
// for CHILD components — the page chunk's `export *` only re-exports
|
|
220
|
-
// the page's own module.
|
|
221
|
-
const styleScope = globalThis as StyleUpdateMode;
|
|
222
|
-
if (styleScope.__ANGULAR_HMR_STYLE_UPDATE_MODE__) {
|
|
223
|
-
const ok = applyStyleUpdate(id, ctor);
|
|
224
|
-
styleUpdateBatch.push({ id, ok });
|
|
225
|
-
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
const tmplScope = globalThis as TemplateUpdateMode;
|
|
229
|
-
if (tmplScope.__ANGULAR_HMR_TEMPLATE_UPDATE_MODE__) {
|
|
230
|
-
const ok = applyTemplateUpdate(id, ctor);
|
|
231
|
-
templateUpdateBatch.push({ id, ok });
|
|
232
|
-
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
const svcScope = globalThis as ServiceUpdateMode;
|
|
236
|
-
if (svcScope.__ANGULAR_HMR_SERVICE_UPDATE_MODE__) {
|
|
237
|
-
const ok = applyServiceUpdate(id, ctor);
|
|
238
|
-
serviceUpdateBatch.push({ id, ok });
|
|
239
157
|
}
|
|
240
158
|
};
|
|
241
159
|
|
|
@@ -349,391 +267,6 @@ const markPatchedDirty = (ctor: ComponentCtor) => {
|
|
|
349
267
|
}
|
|
350
268
|
};
|
|
351
269
|
|
|
352
|
-
/* Component-style HMR — swaps `ɵcmp.styles` and replaces matching
|
|
353
|
-
* `<style>` tags in the document so the visible page reflects the new
|
|
354
|
-
* CSS without a re-bootstrap.
|
|
355
|
-
*
|
|
356
|
-
* Why this is safe with Emulated encapsulation (the default): Angular's
|
|
357
|
-
* compiler rewrites the CSS at build time, prefixing every selector
|
|
358
|
-
* with `[_ngcontent-c<scopeId>]`. The scope ID is deterministic per
|
|
359
|
-
* component def — the same source file produces the same scope ID
|
|
360
|
-
* across rebuilds — so the rewritten DOM still matches the new CSS.
|
|
361
|
-
* We only need to update the style *content*; the elements wearing
|
|
362
|
-
* `_ngcontent-c<scopeId>` attributes are still on the page from the
|
|
363
|
-
* initial bootstrap.
|
|
364
|
-
*
|
|
365
|
-
* ShadowDOM encapsulation (3) is not yet handled — each component
|
|
366
|
-
* instance has its own shadow root with its own style tags, requiring
|
|
367
|
-
* a per-instance walk. Falls through to reboot for now.
|
|
368
|
-
*
|
|
369
|
-
* The matching strategy: walk every `<style>` tag in `document.head`
|
|
370
|
-
* and `document.body`, find ones whose `textContent` exactly matches a
|
|
371
|
-
* string in the OLD `ɵcmp.styles` array, and replace it with the
|
|
372
|
-
* corresponding string from the NEW array. Equal-length arrays only —
|
|
373
|
-
* adding or removing a `styleUrl` entry triggers a reboot.
|
|
374
|
-
*
|
|
375
|
-
* Returns true on full success, false if we couldn't safely apply
|
|
376
|
-
* (length mismatch, ShadowDOM, missing styles array, or any old
|
|
377
|
-
* style had no DOM match — meaning we'd leave the page in a partially
|
|
378
|
-
* updated state). */
|
|
379
|
-
|
|
380
|
-
const SHADOW_DOM_ENCAPSULATION = 3;
|
|
381
|
-
|
|
382
|
-
type StyleHost = {
|
|
383
|
-
host: ParentNode;
|
|
384
|
-
tags: HTMLStyleElement[];
|
|
385
|
-
};
|
|
386
|
-
|
|
387
|
-
const collectStyleHosts = (): StyleHost[] => {
|
|
388
|
-
const hosts: StyleHost[] = [];
|
|
389
|
-
const headTags = Array.from(
|
|
390
|
-
document.head.querySelectorAll('style')
|
|
391
|
-
) as HTMLStyleElement[];
|
|
392
|
-
const bodyTags = Array.from(
|
|
393
|
-
document.body.querySelectorAll('style')
|
|
394
|
-
) as HTMLStyleElement[];
|
|
395
|
-
if (headTags.length > 0)
|
|
396
|
-
hosts.push({ host: document.head, tags: headTags });
|
|
397
|
-
if (bodyTags.length > 0)
|
|
398
|
-
hosts.push({ host: document.body, tags: bodyTags });
|
|
399
|
-
|
|
400
|
-
return hosts;
|
|
401
|
-
};
|
|
402
|
-
|
|
403
|
-
const findStyleTagByContent = (
|
|
404
|
-
hosts: StyleHost[],
|
|
405
|
-
content: string,
|
|
406
|
-
consumed: Set<HTMLStyleElement>
|
|
407
|
-
): HTMLStyleElement | null => {
|
|
408
|
-
for (const { tags } of hosts) {
|
|
409
|
-
for (const tag of tags) {
|
|
410
|
-
if (consumed.has(tag)) continue;
|
|
411
|
-
if (tag.textContent === content) return tag;
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
return null;
|
|
416
|
-
};
|
|
417
|
-
|
|
418
|
-
const applyStyleUpdate = (id: string, newCtor: unknown) => {
|
|
419
|
-
if (!isComponentCtor(newCtor)) return false;
|
|
420
|
-
|
|
421
|
-
const entry = componentRegistry.get(id);
|
|
422
|
-
if (!entry) {
|
|
423
|
-
// First time we've seen this component — register it but no styles
|
|
424
|
-
// to swap yet. The next edit will pick up the now-registered ctor.
|
|
425
|
-
register(id, newCtor);
|
|
426
|
-
|
|
427
|
-
return true;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
const { liveCtor } = entry;
|
|
431
|
-
if (liveCtor === newCtor) return true;
|
|
432
|
-
|
|
433
|
-
const liveCmp = liveCtor.ɵcmp;
|
|
434
|
-
const newCmp = newCtor.ɵcmp;
|
|
435
|
-
if (!liveCmp || !newCmp) return false;
|
|
436
|
-
|
|
437
|
-
if (
|
|
438
|
-
liveCmp.encapsulation === SHADOW_DOM_ENCAPSULATION ||
|
|
439
|
-
newCmp.encapsulation === SHADOW_DOM_ENCAPSULATION
|
|
440
|
-
) {
|
|
441
|
-
// Shadow DOM scopes styles per-instance — out of scope for v1.
|
|
442
|
-
return false;
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
const oldStyles = liveCmp.styles;
|
|
446
|
-
const nextStyles = newCmp.styles;
|
|
447
|
-
if (!Array.isArray(oldStyles) || !Array.isArray(nextStyles)) return false;
|
|
448
|
-
if (oldStyles.length !== nextStyles.length) return false;
|
|
449
|
-
if (oldStyles.length === 0) {
|
|
450
|
-
// No styles to swap, no work to do — succeed trivially.
|
|
451
|
-
liveCmp.styles = nextStyles;
|
|
452
|
-
|
|
453
|
-
return true;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
// Always update `ɵcmp.styles` first so future mounts of this
|
|
457
|
-
// component pick up the new content. The DOM `<style>` swap below
|
|
458
|
-
// handles currently-mounted instances; any component that isn't on
|
|
459
|
-
// the page right now (an unopened modal, a route view that hasn't
|
|
460
|
-
// been visited yet) simply has no `<style>` tag to find — and
|
|
461
|
-
// that's fine. The next time it mounts, Angular reads from
|
|
462
|
-
// `ɵcmp.styles` and injects the new content. Treating that case
|
|
463
|
-
// as a failure was the source of the "Transition was skipped"
|
|
464
|
-
// bug: the SPA at /portal/dashboard registered dozens of
|
|
465
|
-
// components whose styles weren't injected (modals, sibling tabs,
|
|
466
|
-
// etc.), and each missing live `<style>` tag forced fallthrough
|
|
467
|
-
// to the reboot path, firing `startViewTransition` while the
|
|
468
|
-
// previous one was still finishing.
|
|
469
|
-
liveCmp.styles = nextStyles;
|
|
470
|
-
|
|
471
|
-
const hosts = collectStyleHosts();
|
|
472
|
-
const consumed = new Set<HTMLStyleElement>();
|
|
473
|
-
|
|
474
|
-
for (let i = 0; i < oldStyles.length; i++) {
|
|
475
|
-
const oldContent = oldStyles[i] ?? '';
|
|
476
|
-
const nextContent = nextStyles[i] ?? '';
|
|
477
|
-
if (oldContent === nextContent) continue;
|
|
478
|
-
const tag = findStyleTagByContent(hosts, oldContent, consumed);
|
|
479
|
-
if (!tag) {
|
|
480
|
-
// Component not currently mounted (or already-swapped style).
|
|
481
|
-
// Skip the DOM swap; `ɵcmp.styles` is already updated above
|
|
482
|
-
// so the next mount picks up the new content.
|
|
483
|
-
continue;
|
|
484
|
-
}
|
|
485
|
-
consumed.add(tag);
|
|
486
|
-
tag.textContent = nextContent;
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
updateCounter.value++;
|
|
490
|
-
entry.updateCount++;
|
|
491
|
-
entry.registeredAt = Date.now();
|
|
492
|
-
|
|
493
|
-
return true;
|
|
494
|
-
};
|
|
495
|
-
|
|
496
|
-
/* Template HMR — surgical swap of the template-related fields on a
|
|
497
|
-
* registered component's `ɵcmp` so the live instance re-renders with
|
|
498
|
-
* the new template WITHOUT re-instantiating. Inputs, outputs, host
|
|
499
|
-
* bindings, providers, and lifecycle hooks live on the class
|
|
500
|
-
* prototype + ɵcmp, and we leave those alone — only the template
|
|
501
|
-
* factory and the slot counts/queries that depend on it are replaced.
|
|
502
|
-
*
|
|
503
|
-
* Why a defined list of fields and not a full `ɵcmp` swap: a wholesale
|
|
504
|
-
* `Object.assign(liveCmp, newCmp)` would also overwrite `providers /
|
|
505
|
-
* providersResolver` and other class-level metadata. Those changes
|
|
506
|
-
* already require a full reboot (the existing fast-path handler in
|
|
507
|
-
* `angular.ts` checks `hasProviderChanges` and bails). For a pure
|
|
508
|
-
* template edit, restricting the patch to the template subgraph
|
|
509
|
-
* keeps live instances on the same DI tokens, queryList references,
|
|
510
|
-
* input bindings, etc. — only the rendered output changes.
|
|
511
|
-
*
|
|
512
|
-
* After the swap, the component's TView (the cached view layout) is
|
|
513
|
-
* stale because slot counts may have changed. Angular regenerates the
|
|
514
|
-
* TView lazily on the first re-render, but only if the existing one
|
|
515
|
-
* is invalidated — which happens automatically when we walk the live
|
|
516
|
-
* instances and call `applyChanges`. The same `markPatchedDirty`
|
|
517
|
-
* helper used by `applyUpdate` covers OnPush views too. */
|
|
518
|
-
|
|
519
|
-
const TEMPLATE_PATCH_FIELDS = [
|
|
520
|
-
'template',
|
|
521
|
-
'consts',
|
|
522
|
-
'decls',
|
|
523
|
-
'vars',
|
|
524
|
-
'viewQuery',
|
|
525
|
-
'contentQueries',
|
|
526
|
-
'ngContentSelectors',
|
|
527
|
-
'dependencies',
|
|
528
|
-
'hostBindings',
|
|
529
|
-
'hostVars',
|
|
530
|
-
'hostAttrs',
|
|
531
|
-
'inputs',
|
|
532
|
-
'outputs'
|
|
533
|
-
] as const;
|
|
534
|
-
|
|
535
|
-
const applyTemplateUpdate = (id: string, newCtor: unknown) => {
|
|
536
|
-
if (!isComponentCtor(newCtor)) return false;
|
|
537
|
-
|
|
538
|
-
const entry = componentRegistry.get(id);
|
|
539
|
-
if (!entry) {
|
|
540
|
-
register(id, newCtor);
|
|
541
|
-
|
|
542
|
-
return true;
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
const { liveCtor } = entry;
|
|
546
|
-
if (liveCtor === newCtor) return true;
|
|
547
|
-
|
|
548
|
-
const liveCmp = liveCtor.ɵcmp as Record<string, unknown> | undefined;
|
|
549
|
-
const nextCmp = newCtor.ɵcmp as Record<string, unknown> | undefined;
|
|
550
|
-
if (!liveCmp || !nextCmp) return false;
|
|
551
|
-
|
|
552
|
-
// If providers changed, this isn't a pure template edit anymore —
|
|
553
|
-
// fall back to reboot via the caller.
|
|
554
|
-
if (hasProviderChanges(liveCtor, newCtor)) return false;
|
|
555
|
-
|
|
556
|
-
for (const field of TEMPLATE_PATCH_FIELDS) {
|
|
557
|
-
if (Object.prototype.hasOwnProperty.call(nextCmp, field)) {
|
|
558
|
-
liveCmp[field] = nextCmp[field];
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
pendingFastPatchRefresh.add(liveCtor);
|
|
563
|
-
updateCounter.value++;
|
|
564
|
-
entry.updateCount++;
|
|
565
|
-
entry.registeredAt = Date.now();
|
|
566
|
-
|
|
567
|
-
return true;
|
|
568
|
-
};
|
|
569
|
-
|
|
570
|
-
type TemplateUpdateMode = typeof globalThis & {
|
|
571
|
-
__ANGULAR_HMR_TEMPLATE_UPDATE_MODE__?: boolean;
|
|
572
|
-
};
|
|
573
|
-
|
|
574
|
-
const templateUpdateBatch: StyleBatchEntry[] = [];
|
|
575
|
-
|
|
576
|
-
const beginTemplateUpdateBatch = () => {
|
|
577
|
-
templateUpdateBatch.length = 0;
|
|
578
|
-
};
|
|
579
|
-
|
|
580
|
-
const endTemplateUpdateBatch = (): StyleBatchEntry[] => {
|
|
581
|
-
const out = templateUpdateBatch.slice();
|
|
582
|
-
templateUpdateBatch.length = 0;
|
|
583
|
-
|
|
584
|
-
return out;
|
|
585
|
-
};
|
|
586
|
-
|
|
587
|
-
/* Service HMR — Level 3 hybrid:
|
|
588
|
-
* 1. Always swap prototype methods on the live ctor. Reaches every
|
|
589
|
-
* live instance (singletons + transient injectees) because they
|
|
590
|
-
* all share the same prototype.
|
|
591
|
-
* 2. If the live singleton is reachable via the root injector,
|
|
592
|
-
* attempt to instantiate a donor with the new ctor and copy any
|
|
593
|
-
* OWN PROPERTIES that the live singleton is missing — this picks
|
|
594
|
-
* up new class-field initializers without overwriting accumulated
|
|
595
|
-
* runtime state. Donor instantiation is best-effort: services
|
|
596
|
-
* using `inject()` outside of an injection context will throw,
|
|
597
|
-
* and we just skip the field merge in that case (the prototype
|
|
598
|
-
* swap still applies, so method changes take effect).
|
|
599
|
-
* 3. The classifier only routes here for services with NO
|
|
600
|
-
* side-effecting calls in the constructor / field initializers
|
|
601
|
-
* (no `subscribe / setInterval / addEventListener / effect /
|
|
602
|
-
* new Worker / new EventSource / etc.`). Anything that touches
|
|
603
|
-
* external state at construction time falls through to reboot
|
|
604
|
-
* via the server-side classification, never reaching this code
|
|
605
|
-
* path. */
|
|
606
|
-
|
|
607
|
-
type AppRefWithInjector = {
|
|
608
|
-
injector?: { get?: (token: unknown, notFoundValue?: unknown) => unknown };
|
|
609
|
-
};
|
|
610
|
-
|
|
611
|
-
const getRootInjector = (): {
|
|
612
|
-
get: (token: unknown, notFoundValue?: unknown) => unknown;
|
|
613
|
-
} | null => {
|
|
614
|
-
const app = window.__ANGULAR_APP__ as AppRefWithInjector | null;
|
|
615
|
-
if (!app || !app.injector || typeof app.injector.get !== 'function') {
|
|
616
|
-
return null;
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
return app.injector as {
|
|
620
|
-
get: (token: unknown, notFoundValue?: unknown) => unknown;
|
|
621
|
-
};
|
|
622
|
-
};
|
|
623
|
-
|
|
624
|
-
const swapPrototypeMethods = (
|
|
625
|
-
liveCtor: ComponentCtor,
|
|
626
|
-
newCtor: ComponentCtor
|
|
627
|
-
) => {
|
|
628
|
-
const newProto = newCtor.prototype as Record<string, unknown>;
|
|
629
|
-
const liveProto = liveCtor.prototype as Record<string, unknown>;
|
|
630
|
-
Object.getOwnPropertyNames(newProto).forEach((prop) => {
|
|
631
|
-
if (prop === 'constructor') return;
|
|
632
|
-
try {
|
|
633
|
-
const desc = Object.getOwnPropertyDescriptor(newProto, prop);
|
|
634
|
-
if (desc) Object.defineProperty(liveProto, prop, desc);
|
|
635
|
-
} catch {
|
|
636
|
-
/* non-configurable property — skip */
|
|
637
|
-
}
|
|
638
|
-
});
|
|
639
|
-
};
|
|
640
|
-
|
|
641
|
-
const tryInstantiateServiceDonor = (newCtor: ComponentCtor): unknown | null => {
|
|
642
|
-
try {
|
|
643
|
-
// `new newCtor()` with no args. Works for services with no
|
|
644
|
-
// constructor params and no `inject()` calls at field-init time.
|
|
645
|
-
// Anything more sophisticated (services that use `inject()`
|
|
646
|
-
// outside an injection context) throws here and we fall back to
|
|
647
|
-
// prototype-only swap.
|
|
648
|
-
return Reflect.construct(newCtor as unknown as new () => unknown, []);
|
|
649
|
-
} catch {
|
|
650
|
-
return null;
|
|
651
|
-
}
|
|
652
|
-
};
|
|
653
|
-
|
|
654
|
-
const mergeMissingFields = (
|
|
655
|
-
liveInstance: Record<string, unknown>,
|
|
656
|
-
donor: Record<string, unknown>
|
|
657
|
-
) => {
|
|
658
|
-
let merged = 0;
|
|
659
|
-
Object.getOwnPropertyNames(donor).forEach((prop) => {
|
|
660
|
-
if (Object.prototype.hasOwnProperty.call(liveInstance, prop)) return;
|
|
661
|
-
try {
|
|
662
|
-
const desc = Object.getOwnPropertyDescriptor(donor, prop);
|
|
663
|
-
if (desc) {
|
|
664
|
-
Object.defineProperty(liveInstance, prop, desc);
|
|
665
|
-
merged++;
|
|
666
|
-
}
|
|
667
|
-
} catch {
|
|
668
|
-
/* defining the property failed — skip */
|
|
669
|
-
}
|
|
670
|
-
});
|
|
671
|
-
|
|
672
|
-
return merged;
|
|
673
|
-
};
|
|
674
|
-
|
|
675
|
-
const applyServiceUpdate = (id: string, newCtor: unknown) => {
|
|
676
|
-
if (!isComponentCtor(newCtor)) return false;
|
|
677
|
-
|
|
678
|
-
const entry = componentRegistry.get(id);
|
|
679
|
-
if (!entry) {
|
|
680
|
-
register(id, newCtor);
|
|
681
|
-
|
|
682
|
-
return true;
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
const { liveCtor } = entry;
|
|
686
|
-
if (liveCtor === newCtor) return true;
|
|
687
|
-
|
|
688
|
-
// Method swap — reaches every live instance.
|
|
689
|
-
swapPrototypeMethods(liveCtor, newCtor);
|
|
690
|
-
|
|
691
|
-
// Best-effort field merge on the live singleton.
|
|
692
|
-
const injector = getRootInjector();
|
|
693
|
-
if (injector) {
|
|
694
|
-
try {
|
|
695
|
-
const liveInstance = injector.get(liveCtor, null) as Record<
|
|
696
|
-
string,
|
|
697
|
-
unknown
|
|
698
|
-
> | null;
|
|
699
|
-
if (liveInstance) {
|
|
700
|
-
const donor = tryInstantiateServiceDonor(newCtor) as Record<
|
|
701
|
-
string,
|
|
702
|
-
unknown
|
|
703
|
-
> | null;
|
|
704
|
-
if (donor) mergeMissingFields(liveInstance, donor);
|
|
705
|
-
}
|
|
706
|
-
} catch {
|
|
707
|
-
/* injector lookup failed — service may not be `providedIn:
|
|
708
|
-
"root"`, or the type-token mismatched. Prototype swap is
|
|
709
|
-
already applied, so methods take effect either way. */
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
updateCounter.value++;
|
|
714
|
-
entry.updateCount++;
|
|
715
|
-
entry.registeredAt = Date.now();
|
|
716
|
-
|
|
717
|
-
return true;
|
|
718
|
-
};
|
|
719
|
-
|
|
720
|
-
type ServiceUpdateMode = typeof globalThis & {
|
|
721
|
-
__ANGULAR_HMR_SERVICE_UPDATE_MODE__?: boolean;
|
|
722
|
-
};
|
|
723
|
-
|
|
724
|
-
const serviceUpdateBatch: StyleBatchEntry[] = [];
|
|
725
|
-
|
|
726
|
-
const beginServiceUpdateBatch = () => {
|
|
727
|
-
serviceUpdateBatch.length = 0;
|
|
728
|
-
};
|
|
729
|
-
|
|
730
|
-
const endServiceUpdateBatch = (): StyleBatchEntry[] => {
|
|
731
|
-
const out = serviceUpdateBatch.slice();
|
|
732
|
-
serviceUpdateBatch.length = 0;
|
|
733
|
-
|
|
734
|
-
return out;
|
|
735
|
-
};
|
|
736
|
-
|
|
737
270
|
const applyUpdate = (id: string, newCtor: unknown) => {
|
|
738
271
|
if (!isComponentCtor(newCtor)) return false;
|
|
739
272
|
|
|
@@ -869,16 +402,7 @@ const hasPageExportsChanged = (sourceId: string): boolean => {
|
|
|
869
402
|
export const installAngularHMRRuntime = () => {
|
|
870
403
|
if (typeof window === 'undefined') return;
|
|
871
404
|
window.__ANGULAR_HMR__ = {
|
|
872
|
-
applyServiceUpdate,
|
|
873
|
-
applyStyleUpdate,
|
|
874
|
-
applyTemplateUpdate,
|
|
875
405
|
applyUpdate,
|
|
876
|
-
beginServiceUpdateBatch,
|
|
877
|
-
beginStyleUpdateBatch,
|
|
878
|
-
beginTemplateUpdateBatch,
|
|
879
|
-
endServiceUpdateBatch,
|
|
880
|
-
endStyleUpdateBatch,
|
|
881
|
-
endTemplateUpdateBatch,
|
|
882
406
|
getStats: getAngularHmrStats,
|
|
883
407
|
hasPageExportsChanged,
|
|
884
408
|
recordPageExports,
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"import type { RuntimeIslandRenderProps } from '../../types/island';\nimport { getIslandMarkerAttributes } from '../core/islandMarkupAttributes';\n\ntype PreservedIslandMarkup = {\n\tattributes: Record<string, string>;\n\tinnerHTML: string;\n};\n\ntype IslandMarkerElement = HTMLElement & {\n\tdataset: DOMStringMap & {\n\t\tcomponent?: string;\n\t\tframework?: string;\n\t\thydrate?: string;\n\t\tisland?: string;\n\t\tislandId?: string;\n\t\tprops?: string;\n\t};\n};\n\nconst getClaimMap = () => {\n\tif (typeof window === 'undefined') {\n\t\treturn null;\n\t}\n\n\twindow.__ABS_CLAIMED_ISLAND_MARKUP__ ??= new Map<string, number>();\n\n\treturn window.__ABS_CLAIMED_ISLAND_MARKUP__;\n};\n\nconst getSnapshotMap = () => {\n\tif (typeof window === 'undefined') {\n\t\treturn null;\n\t}\n\n\twindow.__ABS_SERVER_ISLAND_HTML__ ??= new Map<\n\t\tstring,\n\t\tPreservedIslandMarkup[]\n\t>();\n\n\treturn window.__ABS_SERVER_ISLAND_HTML__;\n};\n\nconst getIslandSignature = (props: RuntimeIslandRenderProps) => {\n\tconst attributes = getIslandMarkerAttributes(props);\n\n\treturn [\n\t\tattributes['data-component'],\n\t\tattributes['data-framework'],\n\t\tattributes['data-hydrate'],\n\t\tattributes['data-props']\n\t].join('::');\n};\n\nconst isMatchingIslandElement = (\n\telement: Element,\n\tprops: RuntimeIslandRenderProps\n): element is IslandMarkerElement => {\n\tif (!(element instanceof HTMLElement)) {\n\t\treturn false;\n\t}\n\n\tconst attributes = getIslandMarkerAttributes(props);\n\n\treturn (\n\t\telement.dataset.island === 'true' &&\n\t\telement.dataset.component === attributes['data-component'] &&\n\t\telement.dataset.framework === attributes['data-framework'] &&\n\t\t(element.dataset.hydrate ?? 'load') === attributes['data-hydrate'] &&\n\t\t(element.dataset.props ?? '{}') === attributes['data-props']\n\t);\n};\n\nconst snapshotIslandElement = (\n\telement: HTMLElement,\n\tsnapshotMap: Map<string, PreservedIslandMarkup[]>\n) => {\n\tconst signature = [\n\t\telement.dataset.component,\n\t\telement.dataset.framework,\n\t\telement.dataset.hydrate ?? 'load',\n\t\telement.dataset.props ?? '{}'\n\t].join('::');\n\tconst existing = snapshotMap.get(signature) ?? [];\n\tconst attributes = Object.fromEntries(\n\t\telement\n\t\t\t.getAttributeNames()\n\t\t\t.map((name) => [name, element.getAttribute(name) ?? ''])\n\t);\n\texisting.push({\n\t\tattributes,\n\t\tinnerHTML: element.innerHTML\n\t});\n\tsnapshotMap.set(signature, existing);\n};\n\nexport const initializeIslandMarkupSnapshot = () => {\n\tif (typeof document === 'undefined') {\n\t\treturn;\n\t}\n\n\tconst snapshotMap = getSnapshotMap();\n\tif (!snapshotMap || snapshotMap.size > 0) {\n\t\treturn;\n\t}\n\n\tconst elements = Array.from(\n\t\tdocument.querySelectorAll<HTMLElement>('[data-island=\"true\"]')\n\t);\n\tfor (const element of elements) {\n\t\tsnapshotIslandElement(element, snapshotMap);\n\t}\n};\n\nexport const preserveIslandMarkup = (props: RuntimeIslandRenderProps) => {\n\tif (typeof document === 'undefined') {\n\t\treturn {\n\t\t\tattributes: getIslandMarkerAttributes(props),\n\t\t\tinnerHTML: ''\n\t\t};\n\t}\n\n\tconst claimMap = getClaimMap();\n\tconst snapshotMap = getSnapshotMap();\n\tconst signature = getIslandSignature(props);\n\tconst claimedCount = claimMap?.get(signature) ?? 0;\n\tconst snapshotCandidate = snapshotMap?.get(signature)?.[claimedCount];\n\tconst candidates = Array.from(\n\t\tdocument.querySelectorAll('[data-island=\"true\"]')\n\t).filter((element) => isMatchingIslandElement(element, props));\n\tconst candidate = candidates[claimedCount];\n\tif (claimMap) {\n\t\tclaimMap.set(signature, claimedCount + 1);\n\t}\n\n\treturn {\n\t\tattributes:\n\t\t\tsnapshotCandidate?.attributes ?? getIslandMarkerAttributes(props),\n\t\tinnerHTML: snapshotCandidate?.innerHTML ?? candidate?.innerHTML ?? ''\n\t};\n};\n",
|
|
9
9
|
"import type { RuntimeIslandRenderProps } from '../../types/island';\nimport { preserveIslandMarkup } from '../client/preserveIslandMarkup';\n\nexport const Island = (props: RuntimeIslandRenderProps) => {\n\tconst { attributes, innerHTML } = preserveIslandMarkup(props);\n\n\treturn (\n\t\t<div\n\t\t\t{...attributes}\n\t\t\tdangerouslySetInnerHTML={{ __html: innerHTML }}\n\t\t\tsuppressHydrationWarning\n\t\t/>\n\t);\n};\n",
|
|
10
10
|
"import type {\n\tIslandRegistry,\n\tIslandRegistryInput,\n\tTypedIslandRenderProps\n} from '../../types/island';\nimport { preserveIslandMarkup } from '../client/preserveIslandMarkup';\n\nexport const createTypedIsland = <T extends IslandRegistryInput>(\n\t_registry: IslandRegistry<T>\n) => {\n\tconst Island = (props: TypedIslandRenderProps<T>) => {\n\t\tconst { attributes, innerHTML } = preserveIslandMarkup(props);\n\n\t\treturn (\n\t\t\t<div\n\t\t\t\t{...attributes}\n\t\t\t\tdangerouslySetInnerHTML={{ __html: innerHTML }}\n\t\t\t\tsuppressHydrationWarning\n\t\t\t/>\n\t\t);\n\t};\n\n\treturn Island;\n};\n",
|
|
11
|
-
"import { createElement, type ReactNode } from 'react';\n\nexport type UniversalRouterProps = {\n\t/** The request URL to seed `<StaticRouter>` with on the server. Pages\n\t * typically forward `props.url` (auto-injected by handleReactPageRequest\n\t * from `request.url`). Ignored in the browser, where `<BrowserRouter>`\n\t * reads `window.location` directly. Defaults to '/'. */\n\turl?: string;\n\tchildren?: ReactNode;\n};\n\n/** SSR-safe wrapper around react-router that picks `<StaticRouter>` on the\n * server and `<BrowserRouter>` in the browser. Without it, every SPA page\n * has to write its own `typeof window === 'undefined'` branch and import\n * both routers — boilerplate that's the same in every page.\n *\n * Usage:\n *\n * export const MySpa = ({ url }: { url?: string }) => (\n * <html>\n * <Head />\n * <body>\n * <UniversalRouter url={url}>\n * <Routes>\n * <Route path=\"/foo\" element={<Foo />} />\n * </Routes>\n * </UniversalRouter>\n * </body>\n * </html>\n * );\n *\n * Implementation note: `react-router` is required lazily via\n * `createRequire` so consumers who don't use `UniversalRouter` aren't\n * forced to install react-router just to import other things from\n * `@absolutejs/absolute/react` (the previous eager static import made\n * `dist/react/index.js` carry a `import \"react-router\"` that broke\n * every consumer's bundle who hadn't installed it). Bun resolves the\n * CJS interop synchronously, so render is still purely synchronous.\n *\n * `<BrowserRouter>` reads `window.history` at construction, so it\n * throws if instantiated on the server. The `typeof window` check has\n * to live at render time (not import time) because the module is\n * loaded in both environments. */\n\ntype ReactRouterModule = {\n\tBrowserRouter:
|
|
11
|
+
"import { createElement, type ComponentType, type ReactNode } from 'react';\n\nexport type UniversalRouterProps = {\n\t/** The request URL to seed `<StaticRouter>` with on the server. Pages\n\t * typically forward `props.url` (auto-injected by handleReactPageRequest\n\t * from `request.url`). Ignored in the browser, where `<BrowserRouter>`\n\t * reads `window.location` directly. Defaults to '/'. */\n\turl?: string;\n\tchildren?: ReactNode;\n};\n\n/** SSR-safe wrapper around react-router that picks `<StaticRouter>` on the\n * server and `<BrowserRouter>` in the browser. Without it, every SPA page\n * has to write its own `typeof window === 'undefined'` branch and import\n * both routers — boilerplate that's the same in every page.\n *\n * Usage:\n *\n * export const MySpa = ({ url }: { url?: string }) => (\n * <html>\n * <Head />\n * <body>\n * <UniversalRouter url={url}>\n * <Routes>\n * <Route path=\"/foo\" element={<Foo />} />\n * </Routes>\n * </UniversalRouter>\n * </body>\n * </html>\n * );\n *\n * Implementation note: `react-router` is required lazily via\n * `createRequire` so consumers who don't use `UniversalRouter` aren't\n * forced to install react-router just to import other things from\n * `@absolutejs/absolute/react` (the previous eager static import made\n * `dist/react/index.js` carry a `import \"react-router\"` that broke\n * every consumer's bundle who hadn't installed it). Bun resolves the\n * CJS interop synchronously, so render is still purely synchronous.\n *\n * `<BrowserRouter>` reads `window.history` at construction, so it\n * throws if instantiated on the server. The `typeof window` check has\n * to live at render time (not import time) because the module is\n * loaded in both environments. */\n\ntype ReactRouterModule = {\n\tBrowserRouter: ComponentType<{ children?: ReactNode }>;\n\tStaticRouter: ComponentType<{ location: string; children?: ReactNode }>;\n};\n\nlet cachedReactRouter: ReactRouterModule | null = null;\n\nconst loadReactRouter = (): ReactRouterModule => {\n\tif (cachedReactRouter) return cachedReactRouter;\n\n\t// Hide the bare specifier behind a Function-constructor so static\n\t// bundlers can't analyze it — they only see a `Function(string)`\n\t// call, not an `import \"react-router\"`. Resolution happens at\n\t// render time and only on the first call to `UniversalRouter`,\n\t// so consumers who never use it never pay the install cost.\n\t// `require` is available in Bun's CJS-interop context (server)\n\t// and in any bundle output that emitted a CJS-compatible runtime.\n\ttry {\n\t\tconst dynamicRequire = new Function('spec', 'return require(spec)') as (\n\t\t\tspec: string\n\t\t) => ReactRouterModule;\n\t\tcachedReactRouter = dynamicRequire('react-router');\n\n\t\treturn cachedReactRouter;\n\t} catch {\n\t\tconst fromWindow = (\n\t\t\tglobalThis as { ReactRouterDOM?: ReactRouterModule }\n\t\t).ReactRouterDOM;\n\t\tif (fromWindow) {\n\t\t\tcachedReactRouter = fromWindow;\n\n\t\t\treturn cachedReactRouter;\n\t\t}\n\t\tthrow new Error(\n\t\t\t'[UniversalRouter] react-router is not installed. Install it with `bun add react-router` to use UniversalRouter.'\n\t\t);\n\t}\n};\n\nexport const UniversalRouter = ({ url, children }: UniversalRouterProps) => {\n\tconst { BrowserRouter, StaticRouter } = loadReactRouter();\n\tif (typeof window === 'undefined') {\n\t\treturn createElement(StaticRouter, { location: url ?? '/' }, children);\n\t}\n\n\treturn createElement(BrowserRouter, null, children);\n};\n",
|
|
12
12
|
"import { useSyncExternalStore } from 'react';\nimport type { StoreApi } from 'zustand/vanilla';\nimport {\n\tgetIslandStoreServerSnapshot,\n\treadIslandStore,\n\tsubscribeIslandStore,\n\ttype IslandStoreState\n} from '../../client/islandStore';\n\nexport const useIslandStore = <TState extends IslandStoreState, TSelected>(\n\tstore: StoreApi<TState>,\n\tselector: (state: TState) => TSelected\n) =>\n\tuseSyncExternalStore(\n\t\t(listener) =>\n\t\t\tsubscribeIslandStore(store, selector, () => {\n\t\t\t\tlistener();\n\t\t\t}),\n\t\t() => readIslandStore(store, selector),\n\t\t() => getIslandStoreServerSnapshot(store, selector)\n\t);\n",
|
|
13
13
|
"const createStoreImpl = (createState) => {\n let state;\n const listeners = /* @__PURE__ */ new Set();\n const setState = (partial, replace) => {\n const nextState = typeof partial === \"function\" ? partial(state) : partial;\n if (!Object.is(nextState, state)) {\n const previousState = state;\n state = (replace != null ? replace : typeof nextState !== \"object\" || nextState === null) ? nextState : Object.assign({}, state, nextState);\n listeners.forEach((listener) => listener(state, previousState));\n }\n };\n const getState = () => state;\n const getInitialState = () => initialState;\n const subscribe = (listener) => {\n listeners.add(listener);\n return () => listeners.delete(listener);\n };\n const api = { setState, getState, getInitialState, subscribe };\n const initialState = state = createState(setState, getState, api);\n return api;\n};\nconst createStore = ((createState) => createState ? createStoreImpl(createState) : createStoreImpl);\n\nexport { createStore };\n",
|
|
14
14
|
"const reduxImpl = (reducer, initial) => (set, _get, api) => {\n api.dispatch = (action) => {\n set((state) => reducer(state, action), false, action);\n return action;\n };\n api.dispatchFromDevtools = true;\n return { dispatch: (...args) => api.dispatch(...args), ...initial };\n};\nconst redux = reduxImpl;\n\nconst shouldDispatchFromDevtools = (api) => !!api.dispatchFromDevtools && typeof api.dispatch === \"function\";\nconst trackedConnections = /* @__PURE__ */ new Map();\nconst getTrackedConnectionState = (name) => {\n const api = trackedConnections.get(name);\n if (!api) return {};\n return Object.fromEntries(\n Object.entries(api.stores).map(([key, api2]) => [key, api2.getState()])\n );\n};\nconst extractConnectionInformation = (store, extensionConnector, options) => {\n if (store === void 0) {\n return {\n type: \"untracked\",\n connection: extensionConnector.connect(options)\n };\n }\n const existingConnection = trackedConnections.get(options.name);\n if (existingConnection) {\n return { type: \"tracked\", store, ...existingConnection };\n }\n const newConnection = {\n connection: extensionConnector.connect(options),\n stores: {}\n };\n trackedConnections.set(options.name, newConnection);\n return { type: \"tracked\", store, ...newConnection };\n};\nconst removeStoreFromTrackedConnections = (name, store) => {\n if (store === void 0) return;\n const connectionInfo = trackedConnections.get(name);\n if (!connectionInfo) return;\n delete connectionInfo.stores[store];\n if (Object.keys(connectionInfo.stores).length === 0) {\n trackedConnections.delete(name);\n }\n};\nconst findCallerName = (stack) => {\n var _a, _b;\n if (!stack) return void 0;\n const traceLines = stack.split(\"\\n\");\n const apiSetStateLineIndex = traceLines.findIndex(\n (traceLine) => traceLine.includes(\"api.setState\")\n );\n if (apiSetStateLineIndex < 0) return void 0;\n const callerLine = ((_a = traceLines[apiSetStateLineIndex + 1]) == null ? void 0 : _a.trim()) || \"\";\n return (_b = /.+ (.+) .+/.exec(callerLine)) == null ? void 0 : _b[1];\n};\nconst devtoolsImpl = (fn, devtoolsOptions = {}) => (set, get, api) => {\n const { enabled, anonymousActionType, store, ...options } = devtoolsOptions;\n let extensionConnector;\n try {\n extensionConnector = (enabled != null ? enabled : (import.meta.env ? import.meta.env.MODE : void 0) !== \"production\") && window.__REDUX_DEVTOOLS_EXTENSION__;\n } catch (e) {\n }\n if (!extensionConnector) {\n return fn(set, get, api);\n }\n const { connection, ...connectionInformation } = extractConnectionInformation(store, extensionConnector, options);\n let isRecording = true;\n api.setState = ((state, replace, nameOrAction) => {\n const r = set(state, replace);\n if (!isRecording) return r;\n const action = nameOrAction === void 0 ? {\n type: anonymousActionType || findCallerName(new Error().stack) || \"anonymous\"\n } : typeof nameOrAction === \"string\" ? { type: nameOrAction } : nameOrAction;\n if (store === void 0) {\n connection == null ? void 0 : connection.send(action, get());\n return r;\n }\n connection == null ? void 0 : connection.send(\n {\n ...action,\n type: `${store}/${action.type}`\n },\n {\n ...getTrackedConnectionState(options.name),\n [store]: api.getState()\n }\n );\n return r;\n });\n api.devtools = {\n cleanup: () => {\n if (connection && typeof connection.unsubscribe === \"function\") {\n connection.unsubscribe();\n }\n removeStoreFromTrackedConnections(options.name, store);\n }\n };\n const setStateFromDevtools = (...a) => {\n const originalIsRecording = isRecording;\n isRecording = false;\n set(...a);\n isRecording = originalIsRecording;\n };\n const initialState = fn(api.setState, get, api);\n if (connectionInformation.type === \"untracked\") {\n connection == null ? void 0 : connection.init(initialState);\n } else {\n connectionInformation.stores[connectionInformation.store] = api;\n connection == null ? void 0 : connection.init(\n Object.fromEntries(\n Object.entries(connectionInformation.stores).map(([key, store2]) => [\n key,\n key === connectionInformation.store ? initialState : store2.getState()\n ])\n )\n );\n }\n if (shouldDispatchFromDevtools(api)) {\n let didWarnAboutReservedActionType = false;\n const originalDispatch = api.dispatch;\n api.dispatch = (...args) => {\n if ((import.meta.env ? import.meta.env.MODE : void 0) !== \"production\" && args[0].type === \"__setState\" && !didWarnAboutReservedActionType) {\n console.warn(\n '[zustand devtools middleware] \"__setState\" action type is reserved to set state from the devtools. Avoid using it.'\n );\n didWarnAboutReservedActionType = true;\n }\n originalDispatch(...args);\n };\n }\n connection.subscribe((message) => {\n var _a;\n switch (message.type) {\n case \"ACTION\":\n if (typeof message.payload !== \"string\") {\n console.error(\n \"[zustand devtools middleware] Unsupported action format\"\n );\n return;\n }\n return parseJsonThen(\n message.payload,\n (action) => {\n if (action.type === \"__setState\") {\n if (store === void 0) {\n setStateFromDevtools(action.state);\n return;\n }\n if (Object.keys(action.state).length !== 1) {\n console.error(\n `\n [zustand devtools middleware] Unsupported __setState action format.\n When using 'store' option in devtools(), the 'state' should have only one key, which is a value of 'store' that was passed in devtools(),\n and value of this only key should be a state object. Example: { \"type\": \"__setState\", \"state\": { \"abc123Store\": { \"foo\": \"bar\" } } }\n `\n );\n }\n const stateFromDevtools = action.state[store];\n if (stateFromDevtools === void 0 || stateFromDevtools === null) {\n return;\n }\n if (JSON.stringify(api.getState()) !== JSON.stringify(stateFromDevtools)) {\n setStateFromDevtools(stateFromDevtools);\n }\n return;\n }\n if (shouldDispatchFromDevtools(api)) {\n api.dispatch(action);\n }\n }\n );\n case \"DISPATCH\":\n switch (message.payload.type) {\n case \"RESET\":\n setStateFromDevtools(initialState);\n if (store === void 0) {\n return connection == null ? void 0 : connection.init(api.getState());\n }\n return connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));\n case \"COMMIT\":\n if (store === void 0) {\n connection == null ? void 0 : connection.init(api.getState());\n return;\n }\n return connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));\n case \"ROLLBACK\":\n return parseJsonThen(message.state, (state) => {\n if (store === void 0) {\n setStateFromDevtools(state);\n connection == null ? void 0 : connection.init(api.getState());\n return;\n }\n setStateFromDevtools(state[store]);\n connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));\n });\n case \"JUMP_TO_STATE\":\n case \"JUMP_TO_ACTION\":\n return parseJsonThen(message.state, (state) => {\n if (store === void 0) {\n setStateFromDevtools(state);\n return;\n }\n if (JSON.stringify(api.getState()) !== JSON.stringify(state[store])) {\n setStateFromDevtools(state[store]);\n }\n });\n case \"IMPORT_STATE\": {\n const { nextLiftedState } = message.payload;\n const lastComputedState = (_a = nextLiftedState.computedStates.slice(-1)[0]) == null ? void 0 : _a.state;\n if (!lastComputedState) return;\n if (store === void 0) {\n setStateFromDevtools(lastComputedState);\n } else {\n setStateFromDevtools(lastComputedState[store]);\n }\n connection == null ? void 0 : connection.send(\n null,\n // FIXME no-any\n nextLiftedState\n );\n return;\n }\n case \"PAUSE_RECORDING\":\n return isRecording = !isRecording;\n }\n return;\n }\n });\n return initialState;\n};\nconst devtools = devtoolsImpl;\nconst parseJsonThen = (stringified, fn) => {\n let parsed;\n try {\n parsed = JSON.parse(stringified);\n } catch (e) {\n console.error(\n \"[zustand devtools middleware] Could not parse the received json\",\n e\n );\n }\n if (parsed !== void 0) fn(parsed);\n};\n\nconst subscribeWithSelectorImpl = (fn) => (set, get, api) => {\n const origSubscribe = api.subscribe;\n api.subscribe = ((selector, optListener, options) => {\n let listener = selector;\n if (optListener) {\n const equalityFn = (options == null ? void 0 : options.equalityFn) || Object.is;\n let currentSlice = selector(api.getState());\n listener = (state) => {\n const nextSlice = selector(state);\n if (!equalityFn(currentSlice, nextSlice)) {\n const previousSlice = currentSlice;\n optListener(currentSlice = nextSlice, previousSlice);\n }\n };\n if (options == null ? void 0 : options.fireImmediately) {\n optListener(currentSlice, currentSlice);\n }\n }\n return origSubscribe(listener);\n });\n const initialState = fn(set, get, api);\n return initialState;\n};\nconst subscribeWithSelector = subscribeWithSelectorImpl;\n\nfunction combine(initialState, create) {\n return (...args) => Object.assign({}, initialState, create(...args));\n}\n\nfunction createJSONStorage(getStorage, options) {\n let storage;\n try {\n storage = getStorage();\n } catch (e) {\n return;\n }\n const persistStorage = {\n getItem: (name) => {\n var _a;\n const parse = (str2) => {\n if (str2 === null) {\n return null;\n }\n return JSON.parse(str2, options == null ? void 0 : options.reviver);\n };\n const str = (_a = storage.getItem(name)) != null ? _a : null;\n if (str instanceof Promise) {\n return str.then(parse);\n }\n return parse(str);\n },\n setItem: (name, newValue) => storage.setItem(name, JSON.stringify(newValue, options == null ? void 0 : options.replacer)),\n removeItem: (name) => storage.removeItem(name)\n };\n return persistStorage;\n}\nconst toThenable = (fn) => (input) => {\n try {\n const result = fn(input);\n if (result instanceof Promise) {\n return result;\n }\n return {\n then(onFulfilled) {\n return toThenable(onFulfilled)(result);\n },\n catch(_onRejected) {\n return this;\n }\n };\n } catch (e) {\n return {\n then(_onFulfilled) {\n return this;\n },\n catch(onRejected) {\n return toThenable(onRejected)(e);\n }\n };\n }\n};\nconst persistImpl = (config, baseOptions) => (set, get, api) => {\n let options = {\n storage: createJSONStorage(() => window.localStorage),\n partialize: (state) => state,\n version: 0,\n merge: (persistedState, currentState) => ({\n ...currentState,\n ...persistedState\n }),\n ...baseOptions\n };\n let hasHydrated = false;\n let hydrationVersion = 0;\n const hydrationListeners = /* @__PURE__ */ new Set();\n const finishHydrationListeners = /* @__PURE__ */ new Set();\n let storage = options.storage;\n if (!storage) {\n return config(\n (...args) => {\n console.warn(\n `[zustand persist middleware] Unable to update item '${options.name}', the given storage is currently unavailable.`\n );\n set(...args);\n },\n get,\n api\n );\n }\n const setItem = () => {\n const state = options.partialize({ ...get() });\n return storage.setItem(options.name, {\n state,\n version: options.version\n });\n };\n const savedSetState = api.setState;\n api.setState = (state, replace) => {\n savedSetState(state, replace);\n return setItem();\n };\n const configResult = config(\n (...args) => {\n set(...args);\n return setItem();\n },\n get,\n api\n );\n api.getInitialState = () => configResult;\n let stateFromStorage;\n const hydrate = () => {\n var _a, _b;\n if (!storage) return;\n const currentVersion = ++hydrationVersion;\n hasHydrated = false;\n hydrationListeners.forEach((cb) => {\n var _a2;\n return cb((_a2 = get()) != null ? _a2 : configResult);\n });\n const postRehydrationCallback = ((_b = options.onRehydrateStorage) == null ? void 0 : _b.call(options, (_a = get()) != null ? _a : configResult)) || void 0;\n return toThenable(storage.getItem.bind(storage))(options.name).then((deserializedStorageValue) => {\n if (deserializedStorageValue) {\n if (typeof deserializedStorageValue.version === \"number\" && deserializedStorageValue.version !== options.version) {\n if (options.migrate) {\n const migration = options.migrate(\n deserializedStorageValue.state,\n deserializedStorageValue.version\n );\n if (migration instanceof Promise) {\n return migration.then((result) => [true, result]);\n }\n return [true, migration];\n }\n console.error(\n `State loaded from storage couldn't be migrated since no migrate function was provided`\n );\n } else {\n return [false, deserializedStorageValue.state];\n }\n }\n return [false, void 0];\n }).then((migrationResult) => {\n var _a2;\n if (currentVersion !== hydrationVersion) {\n return;\n }\n const [migrated, migratedState] = migrationResult;\n stateFromStorage = options.merge(\n migratedState,\n (_a2 = get()) != null ? _a2 : configResult\n );\n set(stateFromStorage, true);\n if (migrated) {\n return setItem();\n }\n }).then(() => {\n if (currentVersion !== hydrationVersion) {\n return;\n }\n postRehydrationCallback == null ? void 0 : postRehydrationCallback(get(), void 0);\n stateFromStorage = get();\n hasHydrated = true;\n finishHydrationListeners.forEach((cb) => cb(stateFromStorage));\n }).catch((e) => {\n if (currentVersion !== hydrationVersion) {\n return;\n }\n postRehydrationCallback == null ? void 0 : postRehydrationCallback(void 0, e);\n });\n };\n api.persist = {\n setOptions: (newOptions) => {\n options = {\n ...options,\n ...newOptions\n };\n if (newOptions.storage) {\n storage = newOptions.storage;\n }\n },\n clearStorage: () => {\n storage == null ? void 0 : storage.removeItem(options.name);\n },\n getOptions: () => options,\n rehydrate: () => hydrate(),\n hasHydrated: () => hasHydrated,\n onHydrate: (cb) => {\n hydrationListeners.add(cb);\n return () => {\n hydrationListeners.delete(cb);\n };\n },\n onFinishHydration: (cb) => {\n finishHydrationListeners.add(cb);\n return () => {\n finishHydrationListeners.delete(cb);\n };\n }\n };\n if (!options.skipHydration) {\n hydrate();\n }\n return stateFromStorage || configResult;\n};\nconst persist = persistImpl;\n\nfunction ssrSafe(config, isSSR = typeof window === \"undefined\") {\n return (set, get, api) => {\n if (!isSSR) {\n return config(set, get, api);\n }\n const ssrSet = () => {\n throw new Error(\"Cannot set state of Zustand store in SSR\");\n };\n api.setState = ssrSet;\n return config(ssrSet, get, api);\n };\n}\n\nexport { combine, createJSONStorage, devtools, persist, redux, subscribeWithSelector, ssrSafe as unstable_ssrSafe };\n",
|
package/dist/react/index.js.map
CHANGED
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"import { basename } from 'node:path';\nimport type { ConventionsMap } from '../../types/conventions';\nimport { toPascal } from './stringModifiers';\n\n// Use globalThis so the conventions map is shared across all bundles.\n// The main bundle (dist/index.js) calls setConventions, but framework\n// bundles (dist/svelte/index.js, etc.) need to read the same map.\nconst CONVENTIONS_KEY = '__absoluteConventions';\n\nconst isConventionsMap = (value: unknown): value is ConventionsMap =>\n\tBoolean(value) && typeof value === 'object';\n\nconst getMap = () => {\n\tconst value: unknown = Reflect.get(globalThis, CONVENTIONS_KEY);\n\tif (isConventionsMap(value)) return value;\n\n\tconst empty: ConventionsMap = {};\n\n\treturn empty;\n};\n\nexport const derivePageName = (pagePath: string) => {\n\tconst base = basename(pagePath);\n\t// Strip hash and extension: \"SvelteExample.abc123.js\" → \"SvelteExample\"\n\tconst dotIndex = base.indexOf('.');\n\tconst name = dotIndex > 0 ? base.slice(0, dotIndex) : base;\n\n\treturn toPascal(name);\n};\nexport const getConventions = () => getMap();\n\nconst normalizeConventionPageName = (name: string) =>\n\ttoPascal(name).replace(/\\d+$/, '');\n\nexport const resolveErrorConventionPath = (\n\tframework: keyof ConventionsMap,\n\tpageName: string\n) => {\n\tconst conventions = getMap()[framework];\n\tif (!conventions) return undefined;\n\n\tconst exact = conventions.pages?.[pageName]?.error;\n\tif (exact) return exact;\n\n\tconst normalizedPageName = normalizeConventionPageName(pageName);\n\tfor (const [candidate, page] of Object.entries(conventions.pages ?? {})) {\n\t\tif (normalizeConventionPageName(candidate) === normalizedPageName) {\n\t\t\treturn page.error ?? conventions.defaults?.error;\n\t\t}\n\t}\n\n\treturn conventions.defaults?.error;\n};\nexport const resolveNotFoundConventionPath = (\n\tframework: keyof ConventionsMap\n) => getMap()[framework]?.defaults?.notFound;\n\nexport const hasErrorConvention = (framework: keyof ConventionsMap) => {\n\tconst conventions = getMap()[framework];\n\tif (!conventions) return false;\n\tif (conventions.defaults?.error) return true;\n\n\treturn Object.values(conventions.pages ?? {}).some((page) =>\n\t\tBoolean(page.error)\n\t);\n};\n\nexport const setConventions = (map: ConventionsMap) => {\n\tReflect.set(globalThis, CONVENTIONS_KEY, map);\n};\n\nconst isDev = () => process.env.NODE_ENV === 'development';\n\nconst buildErrorProps = (error: unknown) => {\n\tconst message = error instanceof Error ? error.message : String(error);\n\tconst stack = isDev() && error instanceof Error ? error.stack : undefined;\n\n\treturn { error: { message, stack } };\n};\n\nconst renderReactError = async (\n\tconventionPath: string,\n\terrorProps: ReturnType<typeof buildErrorProps>\n) => {\n\tconst { createElement } = await import('react');\n\tconst { renderToReadableStream } = await import('react-dom/server');\n\tconst mod = await import(conventionPath);\n\tconst [firstKey] = Object.keys(mod);\n\tconst ErrorComponent =\n\t\tmod.default ?? (firstKey ? mod[firstKey] : undefined);\n\tconst element = createElement(ErrorComponent, errorProps);\n\tconst stream = await renderToReadableStream(element);\n\n\treturn new Response(stream, {\n\t\theaders: { 'Content-Type': 'text/html' },\n\t\tstatus: 500\n\t});\n};\n\nconst renderSvelteError = async (\n\tconventionPath: string,\n\terrorProps: ReturnType<typeof buildErrorProps>\n) => {\n\tconst { render } = await import('svelte/server');\n\tconst mod = await import(conventionPath);\n\tconst ErrorComponent = mod.default;\n\tconst { head, body } = render(ErrorComponent, {\n\t\tprops: errorProps\n\t});\n\tconst html = `<!DOCTYPE html><html><head>${head}</head><body>${body}</body></html>`;\n\n\treturn new Response(html, {\n\t\theaders: { 'Content-Type': 'text/html' },\n\t\tstatus: 500\n\t});\n};\n\nconst unescapeVueStyles = (ssrBody: string) => {\n\tlet styles = '';\n\tconst body = ssrBody.replace(\n\t\t/<style>([\\s\\S]*?)<\\/style>/g,\n\t\t(_, css: string) => {\n\t\t\tstyles += `<style>${css\n\t\t\t\t.replace(/"/g, '\"')\n\t\t\t\t.replace(/&/g, '&')\n\t\t\t\t.replace(/</g, '<')\n\t\t\t\t.replace(/>/g, '>')}</style>`;\n\n\t\t\treturn '';\n\t\t}\n\t);\n\n\treturn { body, styles };\n};\n\nconst renderVueError = async (\n\tconventionPath: string,\n\terrorProps: ReturnType<typeof buildErrorProps>\n) => {\n\tconst { createSSRApp, h } = await import('vue');\n\tconst { renderToString } = await import('vue/server-renderer');\n\tconst mod = await import(conventionPath);\n\tconst ErrorComponent = mod.default;\n\tconst app = createSSRApp({\n\t\trender: () => h(ErrorComponent, errorProps)\n\t});\n\tconst rawBody = await renderToString(app);\n\n\t// Vue SSR escapes quotes inside <component is=\"style\"> tags.\n\t// Extract style content, unescape it, and move to <head>.\n\tconst { styles, body } = unescapeVueStyles(rawBody);\n\tconst html = `<!DOCTYPE html><html><head>${styles}</head><body><div id=\"root\">${body}</div></body></html>`;\n\n\treturn new Response(html, {\n\t\theaders: { 'Content-Type': 'text/html' },\n\t\tstatus: 500\n\t});\n};\n\nconst renderAngularError = async (\n\tconventionPath: string,\n\terrorProps: ReturnType<typeof buildErrorProps>\n) => {\n\t// Angular error pages are rendered as plain HTML templates\n\t// since the full Angular SSR pipeline is too heavy for error pages\n\tconst mod = await import(conventionPath);\n\tconst renderError = mod.default ?? mod.renderError;\n\tif (typeof renderError !== 'function') return null;\n\n\tconst html = renderError(errorProps);\n\n\treturn new Response(html, {\n\t\theaders: { 'Content-Type': 'text/html' },\n\t\tstatus: 500\n\t});\n};\n\nconst logConventionRenderError = (\n\tframework: keyof ConventionsMap,\n\tlabel: string,\n\trenderError: unknown\n) => {\n\tconst message = renderError instanceof Error ? renderError.message : '';\n\tif (\n\t\tmessage.includes('Cannot find module') ||\n\t\tmessage.includes('Cannot find package') ||\n\t\tmessage.includes('not found in module')\n\t) {\n\t\tconsole.error(\n\t\t\t`[SSR] Convention ${label} page for ${framework} failed: missing framework package. ` +\n\t\t\t\t`Ensure the ${framework} runtime is installed (e.g. bun add ${framework === 'react' ? 'react react-dom' : framework}).`\n\t\t);\n\n\t\treturn;\n\t}\n\n\tconsole.error(\n\t\t`[SSR] Failed to render ${framework} convention ${label} page:`,\n\t\trenderError\n\t);\n};\n\n// Phase 1 Ember adapter: convention pages aren't wired yet (no\n// renderEmberError analog ships in v1). Returning null falls through to\n// the generic ssrErrorPage. Phase 1.5 replaces this stub with a real\n// renderer once the convention scanner knows about .gjs/.gts files.\nconst renderEmberError = async () => null;\nconst renderEmberNotFound = async () => null;\n\nconst ERROR_RENDERERS: Record<\n\tkeyof ConventionsMap,\n\t(\n\t\tconventionPath: string,\n\t\terrorProps: ReturnType<typeof buildErrorProps>\n\t) => Promise<Response | null>\n> = {\n\tangular: renderAngularError,\n\tember: renderEmberError,\n\treact: renderReactError,\n\tsvelte: renderSvelteError,\n\tvue: renderVueError\n};\n\nexport const renderConventionError = async (\n\tframework: keyof ConventionsMap,\n\tpageName: string,\n\terror: unknown\n) => {\n\tlet conventionPath = resolveErrorConventionPath(framework, pageName);\n\tif (!conventionPath && error instanceof Error && error.stack) {\n\t\tfor (const match of error.stack.matchAll(\n\t\t\t/^\\s*at\\s+([A-Za-z_$][\\w$]*)/gm\n\t\t)) {\n\t\t\tconst candidate = match[1];\n\t\t\tif (!candidate) continue;\n\n\t\t\tconventionPath = resolveErrorConventionPath(framework, candidate);\n\t\t\tif (conventionPath) break;\n\t\t}\n\t}\n\tif (!conventionPath) return null;\n\n\tconst errorProps = buildErrorProps(error);\n\tconst renderer = ERROR_RENDERERS[framework];\n\tif (!renderer) return null;\n\n\ttry {\n\t\treturn await renderer(conventionPath, errorProps);\n\t} catch (renderError) {\n\t\tlogConventionRenderError(framework, 'error', renderError);\n\t}\n\n\treturn null;\n};\n\nconst renderReactNotFound = async (conventionPath: string) => {\n\tconst { createElement } = await import('react');\n\tconst { renderToReadableStream } = await import('react-dom/server');\n\tconst mod = await import(conventionPath);\n\tconst [nfKey] = Object.keys(mod);\n\tconst NotFoundComponent = mod.default ?? (nfKey ? mod[nfKey] : undefined);\n\tconst element = createElement(NotFoundComponent);\n\tconst stream = await renderToReadableStream(element);\n\n\treturn new Response(stream, {\n\t\theaders: { 'Content-Type': 'text/html' },\n\t\tstatus: 404\n\t});\n};\n\nconst renderSvelteNotFound = async (conventionPath: string) => {\n\tconst { render } = await import('svelte/server');\n\tconst mod = await import(conventionPath);\n\tconst NotFoundComponent = mod.default;\n\tconst { head, body } = render(NotFoundComponent);\n\tconst html = `<!DOCTYPE html><html><head>${head}</head><body>${body}</body></html>`;\n\n\treturn new Response(html, {\n\t\theaders: { 'Content-Type': 'text/html' },\n\t\tstatus: 404\n\t});\n};\n\nconst renderVueNotFound = async (conventionPath: string) => {\n\tconst { createSSRApp, h } = await import('vue');\n\tconst { renderToString } = await import('vue/server-renderer');\n\tconst mod = await import(conventionPath);\n\tconst NotFoundComponent = mod.default;\n\tconst app = createSSRApp({\n\t\trender: () => h(NotFoundComponent)\n\t});\n\tconst rawBody = await renderToString(app);\n\n\tconst { styles, body } = unescapeVueStyles(rawBody);\n\tconst html = `<!DOCTYPE html><html><head>${styles}</head><body><div id=\"root\">${body}</div></body></html>`;\n\n\treturn new Response(html, {\n\t\theaders: { 'Content-Type': 'text/html' },\n\t\tstatus: 404\n\t});\n};\n\nconst renderAngularNotFound = async (conventionPath: string) => {\n\tconst mod = await import(conventionPath);\n\tconst renderNotFound = mod.default ?? mod.renderNotFound;\n\tif (typeof renderNotFound !== 'function') return null;\n\n\tconst html = renderNotFound();\n\n\treturn new Response(html, {\n\t\theaders: { 'Content-Type': 'text/html' },\n\t\tstatus: 404\n\t});\n};\n\nconst NOT_FOUND_RENDERERS: Record<\n\tkeyof ConventionsMap,\n\t(conventionPath: string) => Promise<Response | null>\n> = {\n\tangular: renderAngularNotFound,\n\tember: renderEmberNotFound,\n\treact: renderReactNotFound,\n\tsvelte: renderSvelteNotFound,\n\tvue: renderVueNotFound\n};\n\nexport const renderConventionNotFound = async (\n\tframework: keyof ConventionsMap\n) => {\n\tconst conventionPath = resolveNotFoundConventionPath(framework);\n\tif (!conventionPath) return null;\n\n\tconst renderer = NOT_FOUND_RENDERERS[framework];\n\tif (!renderer) return null;\n\n\ttry {\n\t\treturn await renderer(conventionPath);\n\t} catch (renderError) {\n\t\tlogConventionRenderError(framework, 'not-found', renderError);\n\t}\n\n\treturn null;\n};\n\nconst NOT_FOUND_PRIORITY: (keyof ConventionsMap)[] = [\n\t'react',\n\t'svelte',\n\t'vue',\n\t'angular'\n];\n\nexport const renderFirstNotFound = async () => {\n\tconst renderNext = async (frameworks: (keyof ConventionsMap)[]) => {\n\t\tconst [framework, ...remaining] = frameworks;\n\t\tif (!framework) {\n\t\t\treturn null;\n\t\t}\n\t\tif (!getMap()[framework]?.defaults?.notFound) {\n\t\t\treturn renderNext(remaining);\n\t\t}\n\n\t\tconst response = await renderConventionNotFound(framework);\n\t\tif (response) {\n\t\t\treturn response;\n\t\t}\n\n\t\treturn renderNext(remaining);\n\t};\n\n\treturn renderNext(NOT_FOUND_PRIORITY);\n};\n",
|
|
43
43
|
"import type { RuntimeIslandRenderProps } from '../../types/island';\nimport { getIslandMarkerAttributes } from '../core/islandMarkupAttributes';\nimport { requireCurrentIslandRegistry } from '../core/currentIslandRegistry';\nimport { renderIslandResult } from '../core/renderIslandMarkup';\n\nexport const Island = async (props: RuntimeIslandRenderProps) => {\n\tif (typeof window !== 'undefined') {\n\t\treturn (\n\t\t\t<div\n\t\t\t\t{...getIslandMarkerAttributes(props)}\n\t\t\t\tsuppressHydrationWarning\n\t\t\t/>\n\t\t);\n\t}\n\n\tconst result = await renderIslandResult(\n\t\trequireCurrentIslandRegistry(),\n\t\tprops\n\t);\n\n\treturn (\n\t\t<div\n\t\t\t{...result.attributes}\n\t\t\tdangerouslySetInnerHTML={{ __html: result.html }}\n\t\t/>\n\t);\n};\n",
|
|
44
44
|
"import type {\n\tIslandRegistry,\n\tIslandRegistryInput,\n\tTypedIslandRenderProps\n} from '../../types/island';\nimport { getIslandMarkerAttributes } from '../core/islandMarkupAttributes';\nimport { renderIslandResult } from '../core/renderIslandMarkup';\n\nexport const createTypedIsland = <T extends IslandRegistryInput>(\n\tregistry: IslandRegistry<T>\n) => {\n\tconst Island = async (props: TypedIslandRenderProps<T>) => {\n\t\tif (typeof window !== 'undefined') {\n\t\t\treturn (\n\t\t\t\t<div\n\t\t\t\t\t{...getIslandMarkerAttributes(props)}\n\t\t\t\t\tsuppressHydrationWarning\n\t\t\t\t/>\n\t\t\t);\n\t\t}\n\t\tconst result = await renderIslandResult(registry, props);\n\n\t\treturn (\n\t\t\t<div\n\t\t\t\t{...result.attributes}\n\t\t\t\tdangerouslySetInnerHTML={{ __html: result.html }}\n\t\t\t/>\n\t\t);\n\t};\n\n\treturn Island;\n};\n",
|
|
45
|
-
"import { createElement, type ReactNode } from 'react';\n\nexport type UniversalRouterProps = {\n\t/** The request URL to seed `<StaticRouter>` with on the server. Pages\n\t * typically forward `props.url` (auto-injected by handleReactPageRequest\n\t * from `request.url`). Ignored in the browser, where `<BrowserRouter>`\n\t * reads `window.location` directly. Defaults to '/'. */\n\turl?: string;\n\tchildren?: ReactNode;\n};\n\n/** SSR-safe wrapper around react-router that picks `<StaticRouter>` on the\n * server and `<BrowserRouter>` in the browser. Without it, every SPA page\n * has to write its own `typeof window === 'undefined'` branch and import\n * both routers — boilerplate that's the same in every page.\n *\n * Usage:\n *\n * export const MySpa = ({ url }: { url?: string }) => (\n * <html>\n * <Head />\n * <body>\n * <UniversalRouter url={url}>\n * <Routes>\n * <Route path=\"/foo\" element={<Foo />} />\n * </Routes>\n * </UniversalRouter>\n * </body>\n * </html>\n * );\n *\n * Implementation note: `react-router` is required lazily via\n * `createRequire` so consumers who don't use `UniversalRouter` aren't\n * forced to install react-router just to import other things from\n * `@absolutejs/absolute/react` (the previous eager static import made\n * `dist/react/index.js` carry a `import \"react-router\"` that broke\n * every consumer's bundle who hadn't installed it). Bun resolves the\n * CJS interop synchronously, so render is still purely synchronous.\n *\n * `<BrowserRouter>` reads `window.history` at construction, so it\n * throws if instantiated on the server. The `typeof window` check has\n * to live at render time (not import time) because the module is\n * loaded in both environments. */\n\ntype ReactRouterModule = {\n\tBrowserRouter:
|
|
45
|
+
"import { createElement, type ComponentType, type ReactNode } from 'react';\n\nexport type UniversalRouterProps = {\n\t/** The request URL to seed `<StaticRouter>` with on the server. Pages\n\t * typically forward `props.url` (auto-injected by handleReactPageRequest\n\t * from `request.url`). Ignored in the browser, where `<BrowserRouter>`\n\t * reads `window.location` directly. Defaults to '/'. */\n\turl?: string;\n\tchildren?: ReactNode;\n};\n\n/** SSR-safe wrapper around react-router that picks `<StaticRouter>` on the\n * server and `<BrowserRouter>` in the browser. Without it, every SPA page\n * has to write its own `typeof window === 'undefined'` branch and import\n * both routers — boilerplate that's the same in every page.\n *\n * Usage:\n *\n * export const MySpa = ({ url }: { url?: string }) => (\n * <html>\n * <Head />\n * <body>\n * <UniversalRouter url={url}>\n * <Routes>\n * <Route path=\"/foo\" element={<Foo />} />\n * </Routes>\n * </UniversalRouter>\n * </body>\n * </html>\n * );\n *\n * Implementation note: `react-router` is required lazily via\n * `createRequire` so consumers who don't use `UniversalRouter` aren't\n * forced to install react-router just to import other things from\n * `@absolutejs/absolute/react` (the previous eager static import made\n * `dist/react/index.js` carry a `import \"react-router\"` that broke\n * every consumer's bundle who hadn't installed it). Bun resolves the\n * CJS interop synchronously, so render is still purely synchronous.\n *\n * `<BrowserRouter>` reads `window.history` at construction, so it\n * throws if instantiated on the server. The `typeof window` check has\n * to live at render time (not import time) because the module is\n * loaded in both environments. */\n\ntype ReactRouterModule = {\n\tBrowserRouter: ComponentType<{ children?: ReactNode }>;\n\tStaticRouter: ComponentType<{ location: string; children?: ReactNode }>;\n};\n\nlet cachedReactRouter: ReactRouterModule | null = null;\n\nconst loadReactRouter = (): ReactRouterModule => {\n\tif (cachedReactRouter) return cachedReactRouter;\n\n\t// Hide the bare specifier behind a Function-constructor so static\n\t// bundlers can't analyze it — they only see a `Function(string)`\n\t// call, not an `import \"react-router\"`. Resolution happens at\n\t// render time and only on the first call to `UniversalRouter`,\n\t// so consumers who never use it never pay the install cost.\n\t// `require` is available in Bun's CJS-interop context (server)\n\t// and in any bundle output that emitted a CJS-compatible runtime.\n\ttry {\n\t\tconst dynamicRequire = new Function('spec', 'return require(spec)') as (\n\t\t\tspec: string\n\t\t) => ReactRouterModule;\n\t\tcachedReactRouter = dynamicRequire('react-router');\n\n\t\treturn cachedReactRouter;\n\t} catch {\n\t\tconst fromWindow = (\n\t\t\tglobalThis as { ReactRouterDOM?: ReactRouterModule }\n\t\t).ReactRouterDOM;\n\t\tif (fromWindow) {\n\t\t\tcachedReactRouter = fromWindow;\n\n\t\t\treturn cachedReactRouter;\n\t\t}\n\t\tthrow new Error(\n\t\t\t'[UniversalRouter] react-router is not installed. Install it with `bun add react-router` to use UniversalRouter.'\n\t\t);\n\t}\n};\n\nexport const UniversalRouter = ({ url, children }: UniversalRouterProps) => {\n\tconst { BrowserRouter, StaticRouter } = loadReactRouter();\n\tif (typeof window === 'undefined') {\n\t\treturn createElement(StaticRouter, { location: url ?? '/' }, children);\n\t}\n\n\treturn createElement(BrowserRouter, null, children);\n};\n",
|
|
46
46
|
"import { useSyncExternalStore } from 'react';\nimport type { StoreApi } from 'zustand/vanilla';\nimport {\n\tgetIslandStoreServerSnapshot,\n\treadIslandStore,\n\tsubscribeIslandStore,\n\ttype IslandStoreState\n} from '../../client/islandStore';\n\nexport const useIslandStore = <TState extends IslandStoreState, TSelected>(\n\tstore: StoreApi<TState>,\n\tselector: (state: TState) => TSelected\n) =>\n\tuseSyncExternalStore(\n\t\t(listener) =>\n\t\t\tsubscribeIslandStore(store, selector, () => {\n\t\t\t\tlistener();\n\t\t\t}),\n\t\t() => readIslandStore(store, selector),\n\t\t() => getIslandStoreServerSnapshot(store, selector)\n\t);\n",
|
|
47
47
|
"const createStoreImpl = (createState) => {\n let state;\n const listeners = /* @__PURE__ */ new Set();\n const setState = (partial, replace) => {\n const nextState = typeof partial === \"function\" ? partial(state) : partial;\n if (!Object.is(nextState, state)) {\n const previousState = state;\n state = (replace != null ? replace : typeof nextState !== \"object\" || nextState === null) ? nextState : Object.assign({}, state, nextState);\n listeners.forEach((listener) => listener(state, previousState));\n }\n };\n const getState = () => state;\n const getInitialState = () => initialState;\n const subscribe = (listener) => {\n listeners.add(listener);\n return () => listeners.delete(listener);\n };\n const api = { setState, getState, getInitialState, subscribe };\n const initialState = state = createState(setState, getState, api);\n return api;\n};\nconst createStore = ((createState) => createState ? createStoreImpl(createState) : createStoreImpl);\n\nexport { createStore };\n",
|
|
48
48
|
"const reduxImpl = (reducer, initial) => (set, _get, api) => {\n api.dispatch = (action) => {\n set((state) => reducer(state, action), false, action);\n return action;\n };\n api.dispatchFromDevtools = true;\n return { dispatch: (...args) => api.dispatch(...args), ...initial };\n};\nconst redux = reduxImpl;\n\nconst shouldDispatchFromDevtools = (api) => !!api.dispatchFromDevtools && typeof api.dispatch === \"function\";\nconst trackedConnections = /* @__PURE__ */ new Map();\nconst getTrackedConnectionState = (name) => {\n const api = trackedConnections.get(name);\n if (!api) return {};\n return Object.fromEntries(\n Object.entries(api.stores).map(([key, api2]) => [key, api2.getState()])\n );\n};\nconst extractConnectionInformation = (store, extensionConnector, options) => {\n if (store === void 0) {\n return {\n type: \"untracked\",\n connection: extensionConnector.connect(options)\n };\n }\n const existingConnection = trackedConnections.get(options.name);\n if (existingConnection) {\n return { type: \"tracked\", store, ...existingConnection };\n }\n const newConnection = {\n connection: extensionConnector.connect(options),\n stores: {}\n };\n trackedConnections.set(options.name, newConnection);\n return { type: \"tracked\", store, ...newConnection };\n};\nconst removeStoreFromTrackedConnections = (name, store) => {\n if (store === void 0) return;\n const connectionInfo = trackedConnections.get(name);\n if (!connectionInfo) return;\n delete connectionInfo.stores[store];\n if (Object.keys(connectionInfo.stores).length === 0) {\n trackedConnections.delete(name);\n }\n};\nconst findCallerName = (stack) => {\n var _a, _b;\n if (!stack) return void 0;\n const traceLines = stack.split(\"\\n\");\n const apiSetStateLineIndex = traceLines.findIndex(\n (traceLine) => traceLine.includes(\"api.setState\")\n );\n if (apiSetStateLineIndex < 0) return void 0;\n const callerLine = ((_a = traceLines[apiSetStateLineIndex + 1]) == null ? void 0 : _a.trim()) || \"\";\n return (_b = /.+ (.+) .+/.exec(callerLine)) == null ? void 0 : _b[1];\n};\nconst devtoolsImpl = (fn, devtoolsOptions = {}) => (set, get, api) => {\n const { enabled, anonymousActionType, store, ...options } = devtoolsOptions;\n let extensionConnector;\n try {\n extensionConnector = (enabled != null ? enabled : (import.meta.env ? import.meta.env.MODE : void 0) !== \"production\") && window.__REDUX_DEVTOOLS_EXTENSION__;\n } catch (e) {\n }\n if (!extensionConnector) {\n return fn(set, get, api);\n }\n const { connection, ...connectionInformation } = extractConnectionInformation(store, extensionConnector, options);\n let isRecording = true;\n api.setState = ((state, replace, nameOrAction) => {\n const r = set(state, replace);\n if (!isRecording) return r;\n const action = nameOrAction === void 0 ? {\n type: anonymousActionType || findCallerName(new Error().stack) || \"anonymous\"\n } : typeof nameOrAction === \"string\" ? { type: nameOrAction } : nameOrAction;\n if (store === void 0) {\n connection == null ? void 0 : connection.send(action, get());\n return r;\n }\n connection == null ? void 0 : connection.send(\n {\n ...action,\n type: `${store}/${action.type}`\n },\n {\n ...getTrackedConnectionState(options.name),\n [store]: api.getState()\n }\n );\n return r;\n });\n api.devtools = {\n cleanup: () => {\n if (connection && typeof connection.unsubscribe === \"function\") {\n connection.unsubscribe();\n }\n removeStoreFromTrackedConnections(options.name, store);\n }\n };\n const setStateFromDevtools = (...a) => {\n const originalIsRecording = isRecording;\n isRecording = false;\n set(...a);\n isRecording = originalIsRecording;\n };\n const initialState = fn(api.setState, get, api);\n if (connectionInformation.type === \"untracked\") {\n connection == null ? void 0 : connection.init(initialState);\n } else {\n connectionInformation.stores[connectionInformation.store] = api;\n connection == null ? void 0 : connection.init(\n Object.fromEntries(\n Object.entries(connectionInformation.stores).map(([key, store2]) => [\n key,\n key === connectionInformation.store ? initialState : store2.getState()\n ])\n )\n );\n }\n if (shouldDispatchFromDevtools(api)) {\n let didWarnAboutReservedActionType = false;\n const originalDispatch = api.dispatch;\n api.dispatch = (...args) => {\n if ((import.meta.env ? import.meta.env.MODE : void 0) !== \"production\" && args[0].type === \"__setState\" && !didWarnAboutReservedActionType) {\n console.warn(\n '[zustand devtools middleware] \"__setState\" action type is reserved to set state from the devtools. Avoid using it.'\n );\n didWarnAboutReservedActionType = true;\n }\n originalDispatch(...args);\n };\n }\n connection.subscribe((message) => {\n var _a;\n switch (message.type) {\n case \"ACTION\":\n if (typeof message.payload !== \"string\") {\n console.error(\n \"[zustand devtools middleware] Unsupported action format\"\n );\n return;\n }\n return parseJsonThen(\n message.payload,\n (action) => {\n if (action.type === \"__setState\") {\n if (store === void 0) {\n setStateFromDevtools(action.state);\n return;\n }\n if (Object.keys(action.state).length !== 1) {\n console.error(\n `\n [zustand devtools middleware] Unsupported __setState action format.\n When using 'store' option in devtools(), the 'state' should have only one key, which is a value of 'store' that was passed in devtools(),\n and value of this only key should be a state object. Example: { \"type\": \"__setState\", \"state\": { \"abc123Store\": { \"foo\": \"bar\" } } }\n `\n );\n }\n const stateFromDevtools = action.state[store];\n if (stateFromDevtools === void 0 || stateFromDevtools === null) {\n return;\n }\n if (JSON.stringify(api.getState()) !== JSON.stringify(stateFromDevtools)) {\n setStateFromDevtools(stateFromDevtools);\n }\n return;\n }\n if (shouldDispatchFromDevtools(api)) {\n api.dispatch(action);\n }\n }\n );\n case \"DISPATCH\":\n switch (message.payload.type) {\n case \"RESET\":\n setStateFromDevtools(initialState);\n if (store === void 0) {\n return connection == null ? void 0 : connection.init(api.getState());\n }\n return connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));\n case \"COMMIT\":\n if (store === void 0) {\n connection == null ? void 0 : connection.init(api.getState());\n return;\n }\n return connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));\n case \"ROLLBACK\":\n return parseJsonThen(message.state, (state) => {\n if (store === void 0) {\n setStateFromDevtools(state);\n connection == null ? void 0 : connection.init(api.getState());\n return;\n }\n setStateFromDevtools(state[store]);\n connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));\n });\n case \"JUMP_TO_STATE\":\n case \"JUMP_TO_ACTION\":\n return parseJsonThen(message.state, (state) => {\n if (store === void 0) {\n setStateFromDevtools(state);\n return;\n }\n if (JSON.stringify(api.getState()) !== JSON.stringify(state[store])) {\n setStateFromDevtools(state[store]);\n }\n });\n case \"IMPORT_STATE\": {\n const { nextLiftedState } = message.payload;\n const lastComputedState = (_a = nextLiftedState.computedStates.slice(-1)[0]) == null ? void 0 : _a.state;\n if (!lastComputedState) return;\n if (store === void 0) {\n setStateFromDevtools(lastComputedState);\n } else {\n setStateFromDevtools(lastComputedState[store]);\n }\n connection == null ? void 0 : connection.send(\n null,\n // FIXME no-any\n nextLiftedState\n );\n return;\n }\n case \"PAUSE_RECORDING\":\n return isRecording = !isRecording;\n }\n return;\n }\n });\n return initialState;\n};\nconst devtools = devtoolsImpl;\nconst parseJsonThen = (stringified, fn) => {\n let parsed;\n try {\n parsed = JSON.parse(stringified);\n } catch (e) {\n console.error(\n \"[zustand devtools middleware] Could not parse the received json\",\n e\n );\n }\n if (parsed !== void 0) fn(parsed);\n};\n\nconst subscribeWithSelectorImpl = (fn) => (set, get, api) => {\n const origSubscribe = api.subscribe;\n api.subscribe = ((selector, optListener, options) => {\n let listener = selector;\n if (optListener) {\n const equalityFn = (options == null ? void 0 : options.equalityFn) || Object.is;\n let currentSlice = selector(api.getState());\n listener = (state) => {\n const nextSlice = selector(state);\n if (!equalityFn(currentSlice, nextSlice)) {\n const previousSlice = currentSlice;\n optListener(currentSlice = nextSlice, previousSlice);\n }\n };\n if (options == null ? void 0 : options.fireImmediately) {\n optListener(currentSlice, currentSlice);\n }\n }\n return origSubscribe(listener);\n });\n const initialState = fn(set, get, api);\n return initialState;\n};\nconst subscribeWithSelector = subscribeWithSelectorImpl;\n\nfunction combine(initialState, create) {\n return (...args) => Object.assign({}, initialState, create(...args));\n}\n\nfunction createJSONStorage(getStorage, options) {\n let storage;\n try {\n storage = getStorage();\n } catch (e) {\n return;\n }\n const persistStorage = {\n getItem: (name) => {\n var _a;\n const parse = (str2) => {\n if (str2 === null) {\n return null;\n }\n return JSON.parse(str2, options == null ? void 0 : options.reviver);\n };\n const str = (_a = storage.getItem(name)) != null ? _a : null;\n if (str instanceof Promise) {\n return str.then(parse);\n }\n return parse(str);\n },\n setItem: (name, newValue) => storage.setItem(name, JSON.stringify(newValue, options == null ? void 0 : options.replacer)),\n removeItem: (name) => storage.removeItem(name)\n };\n return persistStorage;\n}\nconst toThenable = (fn) => (input) => {\n try {\n const result = fn(input);\n if (result instanceof Promise) {\n return result;\n }\n return {\n then(onFulfilled) {\n return toThenable(onFulfilled)(result);\n },\n catch(_onRejected) {\n return this;\n }\n };\n } catch (e) {\n return {\n then(_onFulfilled) {\n return this;\n },\n catch(onRejected) {\n return toThenable(onRejected)(e);\n }\n };\n }\n};\nconst persistImpl = (config, baseOptions) => (set, get, api) => {\n let options = {\n storage: createJSONStorage(() => window.localStorage),\n partialize: (state) => state,\n version: 0,\n merge: (persistedState, currentState) => ({\n ...currentState,\n ...persistedState\n }),\n ...baseOptions\n };\n let hasHydrated = false;\n let hydrationVersion = 0;\n const hydrationListeners = /* @__PURE__ */ new Set();\n const finishHydrationListeners = /* @__PURE__ */ new Set();\n let storage = options.storage;\n if (!storage) {\n return config(\n (...args) => {\n console.warn(\n `[zustand persist middleware] Unable to update item '${options.name}', the given storage is currently unavailable.`\n );\n set(...args);\n },\n get,\n api\n );\n }\n const setItem = () => {\n const state = options.partialize({ ...get() });\n return storage.setItem(options.name, {\n state,\n version: options.version\n });\n };\n const savedSetState = api.setState;\n api.setState = (state, replace) => {\n savedSetState(state, replace);\n return setItem();\n };\n const configResult = config(\n (...args) => {\n set(...args);\n return setItem();\n },\n get,\n api\n );\n api.getInitialState = () => configResult;\n let stateFromStorage;\n const hydrate = () => {\n var _a, _b;\n if (!storage) return;\n const currentVersion = ++hydrationVersion;\n hasHydrated = false;\n hydrationListeners.forEach((cb) => {\n var _a2;\n return cb((_a2 = get()) != null ? _a2 : configResult);\n });\n const postRehydrationCallback = ((_b = options.onRehydrateStorage) == null ? void 0 : _b.call(options, (_a = get()) != null ? _a : configResult)) || void 0;\n return toThenable(storage.getItem.bind(storage))(options.name).then((deserializedStorageValue) => {\n if (deserializedStorageValue) {\n if (typeof deserializedStorageValue.version === \"number\" && deserializedStorageValue.version !== options.version) {\n if (options.migrate) {\n const migration = options.migrate(\n deserializedStorageValue.state,\n deserializedStorageValue.version\n );\n if (migration instanceof Promise) {\n return migration.then((result) => [true, result]);\n }\n return [true, migration];\n }\n console.error(\n `State loaded from storage couldn't be migrated since no migrate function was provided`\n );\n } else {\n return [false, deserializedStorageValue.state];\n }\n }\n return [false, void 0];\n }).then((migrationResult) => {\n var _a2;\n if (currentVersion !== hydrationVersion) {\n return;\n }\n const [migrated, migratedState] = migrationResult;\n stateFromStorage = options.merge(\n migratedState,\n (_a2 = get()) != null ? _a2 : configResult\n );\n set(stateFromStorage, true);\n if (migrated) {\n return setItem();\n }\n }).then(() => {\n if (currentVersion !== hydrationVersion) {\n return;\n }\n postRehydrationCallback == null ? void 0 : postRehydrationCallback(get(), void 0);\n stateFromStorage = get();\n hasHydrated = true;\n finishHydrationListeners.forEach((cb) => cb(stateFromStorage));\n }).catch((e) => {\n if (currentVersion !== hydrationVersion) {\n return;\n }\n postRehydrationCallback == null ? void 0 : postRehydrationCallback(void 0, e);\n });\n };\n api.persist = {\n setOptions: (newOptions) => {\n options = {\n ...options,\n ...newOptions\n };\n if (newOptions.storage) {\n storage = newOptions.storage;\n }\n },\n clearStorage: () => {\n storage == null ? void 0 : storage.removeItem(options.name);\n },\n getOptions: () => options,\n rehydrate: () => hydrate(),\n hasHydrated: () => hasHydrated,\n onHydrate: (cb) => {\n hydrationListeners.add(cb);\n return () => {\n hydrationListeners.delete(cb);\n };\n },\n onFinishHydration: (cb) => {\n finishHydrationListeners.add(cb);\n return () => {\n finishHydrationListeners.delete(cb);\n };\n }\n };\n if (!options.skipHydration) {\n hydrate();\n }\n return stateFromStorage || configResult;\n};\nconst persist = persistImpl;\n\nfunction ssrSafe(config, isSSR = typeof window === \"undefined\") {\n return (set, get, api) => {\n if (!isSSR) {\n return config(set, get, api);\n }\n const ssrSet = () => {\n throw new Error(\"Cannot set state of Zustand store in SSR\");\n };\n api.setState = ssrSet;\n return config(ssrSet, get, api);\n };\n}\n\nexport { combine, createJSONStorage, devtools, persist, redux, subscribeWithSelector, ssrSafe as unstable_ssrSafe };\n",
|
|
@@ -7,4 +7,6 @@ export type UniversalRouterProps = {
|
|
|
7
7
|
url?: string;
|
|
8
8
|
children?: ReactNode;
|
|
9
9
|
};
|
|
10
|
-
export declare const UniversalRouter: ({ url, children }: UniversalRouterProps) => import("react").
|
|
10
|
+
export declare const UniversalRouter: ({ url, children }: UniversalRouterProps) => import("react").ReactElement<{
|
|
11
|
+
children?: ReactNode;
|
|
12
|
+
}, string | import("react").JSXElementConstructor<any>>;
|
package/dist/types/globals.d.ts
CHANGED
|
@@ -67,15 +67,6 @@ declare global {
|
|
|
67
67
|
__ANGULAR_HMR__?: {
|
|
68
68
|
register: (id: string, ctor: unknown) => void;
|
|
69
69
|
applyUpdate: (id: string, newCtor: unknown) => boolean;
|
|
70
|
-
applyStyleUpdate: (id: string, newCtor: unknown) => boolean;
|
|
71
|
-
applyTemplateUpdate: (id: string, newCtor: unknown) => boolean;
|
|
72
|
-
applyServiceUpdate: (id: string, newCtor: unknown) => boolean;
|
|
73
|
-
beginStyleUpdateBatch: () => void;
|
|
74
|
-
endStyleUpdateBatch: () => Array<{ id: string; ok: boolean }>;
|
|
75
|
-
beginTemplateUpdateBatch: () => void;
|
|
76
|
-
endTemplateUpdateBatch: () => Array<{ id: string; ok: boolean }>;
|
|
77
|
-
beginServiceUpdateBatch: () => void;
|
|
78
|
-
endServiceUpdateBatch: () => Array<{ id: string; ok: boolean }>;
|
|
79
70
|
refresh: () => void;
|
|
80
71
|
getStats: () => { componentCount: number; updateCount: number };
|
|
81
72
|
getRegistry: () => Map<
|
|
@@ -94,9 +85,6 @@ declare global {
|
|
|
94
85
|
) => void;
|
|
95
86
|
hasPageExportsChanged: (sourceId: string) => boolean;
|
|
96
87
|
};
|
|
97
|
-
__ANGULAR_HMR_STYLE_UPDATE_MODE__?: boolean;
|
|
98
|
-
__ANGULAR_HMR_TEMPLATE_UPDATE_MODE__?: boolean;
|
|
99
|
-
__ANGULAR_HMR_SERVICE_UPDATE_MODE__?: boolean;
|
|
100
88
|
__VUE_APP__?:
|
|
101
89
|
| ({
|
|
102
90
|
unmount: () => void;
|
package/package.json
CHANGED