@archie/devtools 0.1.12 → 0.1.13
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/client/client.d.mts
CHANGED
|
@@ -50,6 +50,9 @@ interface ArchieRouteObjectLike {
|
|
|
50
50
|
id?: string;
|
|
51
51
|
path?: string;
|
|
52
52
|
index?: boolean;
|
|
53
|
+
Component?: unknown;
|
|
54
|
+
element?: unknown;
|
|
55
|
+
lazy?: unknown;
|
|
53
56
|
children?: readonly ArchieRouteObjectLike[];
|
|
54
57
|
}
|
|
55
58
|
interface ArchieRouteMatchLike {
|
|
@@ -66,10 +69,19 @@ interface ArchieRouterStateLike {
|
|
|
66
69
|
hash: string;
|
|
67
70
|
};
|
|
68
71
|
matches: readonly ArchieRouteMatchLike[];
|
|
72
|
+
navigation?: {
|
|
73
|
+
state: string;
|
|
74
|
+
};
|
|
75
|
+
fetchers?: ReadonlyMap<string, {
|
|
76
|
+
state: string;
|
|
77
|
+
}>;
|
|
69
78
|
}
|
|
70
79
|
interface ArchieRouterLike {
|
|
71
80
|
routes: readonly ArchieRouteObjectLike[];
|
|
72
81
|
state: ArchieRouterStateLike;
|
|
82
|
+
navigate?(to: string, opts?: {
|
|
83
|
+
replace?: boolean;
|
|
84
|
+
}): Promise<void> | void;
|
|
73
85
|
subscribe(listener: (state: ArchieRouterStateLike) => void): () => void;
|
|
74
86
|
}
|
|
75
87
|
|
|
@@ -77,12 +89,14 @@ interface ArchieDevToolsRuntimeOptions {
|
|
|
77
89
|
router: ArchieRouterLike;
|
|
78
90
|
inspector?: boolean;
|
|
79
91
|
inspectorOptions?: InjectOptions;
|
|
92
|
+
/** Origins allowed to send NAVIGATE / SNAPSHOT_DOM to the route listener. */
|
|
93
|
+
routeListenerOrigins?: readonly string[];
|
|
80
94
|
}
|
|
81
95
|
|
|
82
96
|
interface ArchieDevToolProviderProps extends ArchieDevToolsRuntimeOptions {
|
|
83
97
|
children: ReactNode;
|
|
84
98
|
}
|
|
85
|
-
declare function ArchieDevToolProvider({ children, router, inspector, inspectorOptions, }: ArchieDevToolProviderProps): react_jsx_runtime.JSX.Element;
|
|
99
|
+
declare function ArchieDevToolProvider({ children, router, inspector, inspectorOptions, routeListenerOrigins, }: ArchieDevToolProviderProps): react_jsx_runtime.JSX.Element;
|
|
86
100
|
|
|
87
101
|
interface DndProviderProps {
|
|
88
102
|
children: React.ReactNode;
|
package/dist/client/client.d.ts
CHANGED
|
@@ -50,6 +50,9 @@ interface ArchieRouteObjectLike {
|
|
|
50
50
|
id?: string;
|
|
51
51
|
path?: string;
|
|
52
52
|
index?: boolean;
|
|
53
|
+
Component?: unknown;
|
|
54
|
+
element?: unknown;
|
|
55
|
+
lazy?: unknown;
|
|
53
56
|
children?: readonly ArchieRouteObjectLike[];
|
|
54
57
|
}
|
|
55
58
|
interface ArchieRouteMatchLike {
|
|
@@ -66,10 +69,19 @@ interface ArchieRouterStateLike {
|
|
|
66
69
|
hash: string;
|
|
67
70
|
};
|
|
68
71
|
matches: readonly ArchieRouteMatchLike[];
|
|
72
|
+
navigation?: {
|
|
73
|
+
state: string;
|
|
74
|
+
};
|
|
75
|
+
fetchers?: ReadonlyMap<string, {
|
|
76
|
+
state: string;
|
|
77
|
+
}>;
|
|
69
78
|
}
|
|
70
79
|
interface ArchieRouterLike {
|
|
71
80
|
routes: readonly ArchieRouteObjectLike[];
|
|
72
81
|
state: ArchieRouterStateLike;
|
|
82
|
+
navigate?(to: string, opts?: {
|
|
83
|
+
replace?: boolean;
|
|
84
|
+
}): Promise<void> | void;
|
|
73
85
|
subscribe(listener: (state: ArchieRouterStateLike) => void): () => void;
|
|
74
86
|
}
|
|
75
87
|
|
|
@@ -77,12 +89,14 @@ interface ArchieDevToolsRuntimeOptions {
|
|
|
77
89
|
router: ArchieRouterLike;
|
|
78
90
|
inspector?: boolean;
|
|
79
91
|
inspectorOptions?: InjectOptions;
|
|
92
|
+
/** Origins allowed to send NAVIGATE / SNAPSHOT_DOM to the route listener. */
|
|
93
|
+
routeListenerOrigins?: readonly string[];
|
|
80
94
|
}
|
|
81
95
|
|
|
82
96
|
interface ArchieDevToolProviderProps extends ArchieDevToolsRuntimeOptions {
|
|
83
97
|
children: ReactNode;
|
|
84
98
|
}
|
|
85
|
-
declare function ArchieDevToolProvider({ children, router, inspector, inspectorOptions, }: ArchieDevToolProviderProps): react_jsx_runtime.JSX.Element;
|
|
99
|
+
declare function ArchieDevToolProvider({ children, router, inspector, inspectorOptions, routeListenerOrigins, }: ArchieDevToolProviderProps): react_jsx_runtime.JSX.Element;
|
|
86
100
|
|
|
87
101
|
interface DndProviderProps {
|
|
88
102
|
children: React.ReactNode;
|
package/dist/client/client.js
CHANGED
|
@@ -10271,7 +10271,7 @@ function isPreviewOrigin(origin) {
|
|
|
10271
10271
|
var DEFAULT_SCRIPT_ID = "archie-inspector-script";
|
|
10272
10272
|
var R2_INSPECTOR_BASE_URL = "https://pub-bf238c278d9644b39ec34ecaca1d315c.r2.dev";
|
|
10273
10273
|
function readBuildVersion() {
|
|
10274
|
-
return "0.1.
|
|
10274
|
+
return "0.1.13" ? "0.1.13" : null;
|
|
10275
10275
|
}
|
|
10276
10276
|
var REMOTE_INSPECTOR_VERSION = readBuildVersion();
|
|
10277
10277
|
var isRemoteInspectorUrlVersioned = REMOTE_INSPECTOR_VERSION !== null;
|
|
@@ -10351,25 +10351,238 @@ function injectInspector(opts = {}) {
|
|
|
10351
10351
|
document.head.appendChild(script);
|
|
10352
10352
|
}
|
|
10353
10353
|
|
|
10354
|
+
// src/client/route-listener/domSnapshot.ts
|
|
10355
|
+
var STRIP_SELECTOR = [
|
|
10356
|
+
"script",
|
|
10357
|
+
"noscript",
|
|
10358
|
+
"iframe",
|
|
10359
|
+
"[data-inspector-badge]",
|
|
10360
|
+
"[data-inspector-context-menu]",
|
|
10361
|
+
"#archie-inspector-styles"
|
|
10362
|
+
].join(",");
|
|
10363
|
+
var PALETTE_SELECTOR = "#archie-design-palette";
|
|
10364
|
+
var CSS_FETCH_TIMEOUT_MS = 2e3;
|
|
10365
|
+
var IDLE_TIMEOUT_MS = 500;
|
|
10366
|
+
var CSS_URL_RE = /url\(\s*(['"]?)([^'")]+)\1\s*\)/g;
|
|
10367
|
+
function absolutizeCssUrls(css, baseHref) {
|
|
10368
|
+
return css.replace(CSS_URL_RE, (full, _quote, raw) => {
|
|
10369
|
+
if (!raw || raw.startsWith("data:") || raw.startsWith("#")) return full;
|
|
10370
|
+
try {
|
|
10371
|
+
return `url(${new URL(raw, baseHref).href})`;
|
|
10372
|
+
} catch {
|
|
10373
|
+
return full;
|
|
10374
|
+
}
|
|
10375
|
+
});
|
|
10376
|
+
}
|
|
10377
|
+
function isExcludedSheet(sheet) {
|
|
10378
|
+
const owner = sheet.ownerNode;
|
|
10379
|
+
return !!owner?.matches?.(`${STRIP_SELECTOR},${PALETTE_SELECTOR}`);
|
|
10380
|
+
}
|
|
10381
|
+
async function fetchCssText(href) {
|
|
10382
|
+
const controller = new AbortController();
|
|
10383
|
+
const timer = setTimeout(() => controller.abort(), CSS_FETCH_TIMEOUT_MS);
|
|
10384
|
+
try {
|
|
10385
|
+
const response = await fetch(href, {
|
|
10386
|
+
mode: "cors",
|
|
10387
|
+
signal: controller.signal
|
|
10388
|
+
});
|
|
10389
|
+
return response.ok ? await response.text() : "";
|
|
10390
|
+
} catch {
|
|
10391
|
+
return "";
|
|
10392
|
+
} finally {
|
|
10393
|
+
clearTimeout(timer);
|
|
10394
|
+
}
|
|
10395
|
+
}
|
|
10396
|
+
async function collectSheetCss(sheet, inlinedHrefs) {
|
|
10397
|
+
if (sheet.disabled || isExcludedSheet(sheet)) return "";
|
|
10398
|
+
const baseHref = sheet.href || document.baseURI;
|
|
10399
|
+
let css = "";
|
|
10400
|
+
try {
|
|
10401
|
+
css = Array.from(sheet.cssRules, (rule) => rule.cssText).join("\n");
|
|
10402
|
+
} catch {
|
|
10403
|
+
css = sheet.href ? await fetchCssText(sheet.href) : "";
|
|
10404
|
+
}
|
|
10405
|
+
if (!css) {
|
|
10406
|
+
const owner = sheet.ownerNode;
|
|
10407
|
+
if (owner?.tagName === "STYLE") css = owner.textContent ?? "";
|
|
10408
|
+
}
|
|
10409
|
+
if (!css) return "";
|
|
10410
|
+
if (sheet.href) inlinedHrefs.add(sheet.href);
|
|
10411
|
+
css = absolutizeCssUrls(css, baseHref);
|
|
10412
|
+
const media = sheet.media?.mediaText;
|
|
10413
|
+
return media && media !== "all" ? `@media ${media}{${css}}` : css;
|
|
10414
|
+
}
|
|
10415
|
+
async function collectDocumentCss(inlinedHrefs) {
|
|
10416
|
+
const sheets = Array.from(document.styleSheets);
|
|
10417
|
+
const parts = await Promise.all(
|
|
10418
|
+
sheets.map((sheet) => collectSheetCss(sheet, inlinedHrefs))
|
|
10419
|
+
);
|
|
10420
|
+
return parts.filter(Boolean).join("\n");
|
|
10421
|
+
}
|
|
10422
|
+
function waitForIdle() {
|
|
10423
|
+
return new Promise((resolve) => {
|
|
10424
|
+
const w = window;
|
|
10425
|
+
if (typeof w.requestIdleCallback === "function") {
|
|
10426
|
+
w.requestIdleCallback(() => resolve(), { timeout: IDLE_TIMEOUT_MS });
|
|
10427
|
+
} else {
|
|
10428
|
+
setTimeout(resolve, 50);
|
|
10429
|
+
}
|
|
10430
|
+
});
|
|
10431
|
+
}
|
|
10432
|
+
async function captureDomSnapshot() {
|
|
10433
|
+
if (document.fonts?.ready) {
|
|
10434
|
+
await document.fonts.ready;
|
|
10435
|
+
}
|
|
10436
|
+
await waitForIdle();
|
|
10437
|
+
const inlinedHrefs = /* @__PURE__ */ new Set();
|
|
10438
|
+
const css = await collectDocumentCss(inlinedHrefs);
|
|
10439
|
+
const clone = document.documentElement.cloneNode(true);
|
|
10440
|
+
clone.querySelectorAll(`${STRIP_SELECTOR}, style:not(${PALETTE_SELECTOR})`).forEach((el) => el.remove());
|
|
10441
|
+
clone.querySelectorAll('link[rel~="stylesheet"]').forEach((link) => {
|
|
10442
|
+
const href = link.href;
|
|
10443
|
+
if (inlinedHrefs.has(href)) {
|
|
10444
|
+
link.remove();
|
|
10445
|
+
} else {
|
|
10446
|
+
link.setAttribute("href", href);
|
|
10447
|
+
}
|
|
10448
|
+
});
|
|
10449
|
+
for (const el of [clone, ...Array.from(clone.querySelectorAll("*"))]) {
|
|
10450
|
+
for (const attr of Array.from(el.attributes)) {
|
|
10451
|
+
if (/^on[a-z]+$/i.test(attr.name)) {
|
|
10452
|
+
el.removeAttribute(attr.name);
|
|
10453
|
+
}
|
|
10454
|
+
}
|
|
10455
|
+
}
|
|
10456
|
+
let head = clone.querySelector("head");
|
|
10457
|
+
if (!head) {
|
|
10458
|
+
head = document.createElement("head");
|
|
10459
|
+
clone.insertBefore(head, clone.firstChild);
|
|
10460
|
+
}
|
|
10461
|
+
const style = document.createElement("style");
|
|
10462
|
+
style.textContent = css;
|
|
10463
|
+
head.insertBefore(style, head.firstChild);
|
|
10464
|
+
if (!head.querySelector("base")) {
|
|
10465
|
+
const base = document.createElement("base");
|
|
10466
|
+
base.setAttribute("href", document.baseURI);
|
|
10467
|
+
head.insertBefore(base, head.firstChild);
|
|
10468
|
+
}
|
|
10469
|
+
return {
|
|
10470
|
+
html: "<!doctype html>" + clone.outerHTML,
|
|
10471
|
+
path: location.pathname + location.search + location.hash,
|
|
10472
|
+
viewport: { width: window.innerWidth, height: window.innerHeight },
|
|
10473
|
+
capturedAt: Date.now()
|
|
10474
|
+
};
|
|
10475
|
+
}
|
|
10476
|
+
|
|
10354
10477
|
// src/client/route-listener/routeListener.ts
|
|
10355
|
-
|
|
10478
|
+
var GUARD_NAME_RE = /guard|protect|require|auth(?!or)/i;
|
|
10479
|
+
var GUARD_PRIVATE_RE = /\bprivate|Private(?=[A-Z]|$)/;
|
|
10480
|
+
var NON_GUARD_SUFFIX_RE = /(Layout|Provider|Context|Page|Form|Screen|View)$/;
|
|
10481
|
+
function isGuardName(name) {
|
|
10482
|
+
return !NON_GUARD_SUFFIX_RE.test(name) && (GUARD_NAME_RE.test(name) || GUARD_PRIVATE_RE.test(name));
|
|
10483
|
+
}
|
|
10484
|
+
var GUARD_PROP_NAMES = [
|
|
10485
|
+
"roles",
|
|
10486
|
+
"allowedRoles",
|
|
10487
|
+
"requiredRoles",
|
|
10488
|
+
"permission",
|
|
10489
|
+
"permissions"
|
|
10490
|
+
];
|
|
10491
|
+
var MAX_ELEMENT_DEPTH = 6;
|
|
10492
|
+
function typeName(type) {
|
|
10493
|
+
if (typeof type === "string") return type;
|
|
10494
|
+
if (typeof type === "function") {
|
|
10495
|
+
const fn = type;
|
|
10496
|
+
return fn.displayName || fn.name || null;
|
|
10497
|
+
}
|
|
10498
|
+
if (type && typeof type === "object") {
|
|
10499
|
+
const obj = type;
|
|
10500
|
+
return obj.displayName || typeName(obj.render) || typeName(obj.type);
|
|
10501
|
+
}
|
|
10502
|
+
return null;
|
|
10503
|
+
}
|
|
10504
|
+
function isElementLike(node) {
|
|
10505
|
+
return !!node && typeof node === "object" && "type" in node && "props" in node;
|
|
10506
|
+
}
|
|
10507
|
+
function literalRoles(value) {
|
|
10508
|
+
if (typeof value === "string") return [value];
|
|
10509
|
+
if (Array.isArray(value) && value.every((v) => typeof v === "string")) {
|
|
10510
|
+
return value;
|
|
10511
|
+
}
|
|
10512
|
+
return void 0;
|
|
10513
|
+
}
|
|
10514
|
+
function collectGuards(node, depth, out) {
|
|
10515
|
+
if (depth > MAX_ELEMENT_DEPTH || node == null) return;
|
|
10516
|
+
if (Array.isArray(node)) {
|
|
10517
|
+
for (const child of node) collectGuards(child, depth, out);
|
|
10518
|
+
return;
|
|
10519
|
+
}
|
|
10520
|
+
if (!isElementLike(node)) return;
|
|
10521
|
+
const props = node.props ?? {};
|
|
10522
|
+
const name = typeName(node.type);
|
|
10523
|
+
const roleProps = GUARD_PROP_NAMES.filter((p) => p in props);
|
|
10524
|
+
const isNamedGuard = typeof node.type !== "string" && !!name && isGuardName(name);
|
|
10525
|
+
if (isNamedGuard || roleProps.length > 0) {
|
|
10526
|
+
const roles = roleProps.flatMap((p) => literalRoles(props[p]) ?? []);
|
|
10527
|
+
out.push({
|
|
10528
|
+
componentName: name ?? "Anonymous",
|
|
10529
|
+
...roles.length > 0 ? { roles } : {}
|
|
10530
|
+
});
|
|
10531
|
+
}
|
|
10532
|
+
collectGuards(props.children, depth + 1, out);
|
|
10533
|
+
}
|
|
10534
|
+
function routeComponentName(route) {
|
|
10535
|
+
if (route.Component) return typeName(route.Component);
|
|
10536
|
+
if (isElementLike(route.element)) return typeName(route.element.type);
|
|
10537
|
+
return null;
|
|
10538
|
+
}
|
|
10539
|
+
function extractAllRoutes(routes, parentPath = "", parentId = null, inheritedGuards = []) {
|
|
10356
10540
|
const result = [];
|
|
10357
10541
|
for (const route of routes) {
|
|
10358
10542
|
const path = route.path ? (parentPath + "/" + route.path).replace(/\/+/g, "/") : parentPath || "/";
|
|
10359
|
-
|
|
10543
|
+
const hasChildren = !!(route.children && route.children.length > 0);
|
|
10544
|
+
const isLayout = !route.path && !route.index && hasChildren;
|
|
10545
|
+
const own = [];
|
|
10546
|
+
collectGuards(route.element, 0, own);
|
|
10547
|
+
if (route.path !== void 0 || route.index || isLayout) {
|
|
10360
10548
|
result.push({
|
|
10361
10549
|
id: route.id,
|
|
10362
10550
|
path: route.index ? parentPath || "/" : path,
|
|
10363
|
-
hasChildren
|
|
10551
|
+
hasChildren,
|
|
10552
|
+
parentId,
|
|
10553
|
+
index: !!route.index,
|
|
10554
|
+
isLayout,
|
|
10555
|
+
componentName: routeComponentName(route),
|
|
10556
|
+
guardEvidence: [
|
|
10557
|
+
...own.map((g) => ({ ...g, source: "self" })),
|
|
10558
|
+
...inheritedGuards
|
|
10559
|
+
]
|
|
10364
10560
|
});
|
|
10365
10561
|
}
|
|
10366
10562
|
if (route.children) {
|
|
10367
|
-
|
|
10563
|
+
const forChildren = [
|
|
10564
|
+
...own.map(
|
|
10565
|
+
(g) => ({
|
|
10566
|
+
...g,
|
|
10567
|
+
source: "ancestor",
|
|
10568
|
+
...route.id !== void 0 ? { ancestorId: route.id } : {}
|
|
10569
|
+
})
|
|
10570
|
+
),
|
|
10571
|
+
...inheritedGuards
|
|
10572
|
+
];
|
|
10573
|
+
result.push(
|
|
10574
|
+
...extractAllRoutes(
|
|
10575
|
+
route.children,
|
|
10576
|
+
path,
|
|
10577
|
+
route.id ?? parentId,
|
|
10578
|
+
forChildren
|
|
10579
|
+
)
|
|
10580
|
+
);
|
|
10368
10581
|
}
|
|
10369
10582
|
}
|
|
10370
10583
|
return result;
|
|
10371
10584
|
}
|
|
10372
|
-
function broadcastRouteState(target, state,
|
|
10585
|
+
function broadcastRouteState(target, state, routes) {
|
|
10373
10586
|
try {
|
|
10374
10587
|
const message = {
|
|
10375
10588
|
type: "ARCHIE_ROUTE_UPDATE",
|
|
@@ -10382,7 +10595,9 @@ function broadcastRouteState(target, state, allRoutes) {
|
|
|
10382
10595
|
pathname: m.pathname,
|
|
10383
10596
|
params: m.params
|
|
10384
10597
|
})),
|
|
10385
|
-
allRoutes
|
|
10598
|
+
// Layouts stay out of allRoutes so consumers that predate them don't list duplicates.
|
|
10599
|
+
allRoutes: routes.filter((r) => !r.isLayout),
|
|
10600
|
+
layoutRoutes: routes.filter((r) => r.isLayout),
|
|
10386
10601
|
timestamp: Date.now()
|
|
10387
10602
|
}
|
|
10388
10603
|
};
|
|
@@ -10390,21 +10605,174 @@ function broadcastRouteState(target, state, allRoutes) {
|
|
|
10390
10605
|
} catch {
|
|
10391
10606
|
}
|
|
10392
10607
|
}
|
|
10393
|
-
|
|
10608
|
+
var SETTLE_QUIET_MS = 400;
|
|
10609
|
+
var SETTLE_TIMEOUT_MS = 8e3;
|
|
10610
|
+
var SETTLE_POLL_MS = 50;
|
|
10611
|
+
function readPackageVersion() {
|
|
10612
|
+
return true ? "0.1.13" : "unknown";
|
|
10613
|
+
}
|
|
10614
|
+
var DEFAULT_ARCHIE_COMMAND_ORIGINS = getAllowedOrigins(true);
|
|
10615
|
+
function originPatternToRegExp(pattern) {
|
|
10616
|
+
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/:\*$/, ":\\d+").replace(/\*/g, "[a-z0-9.-]+");
|
|
10617
|
+
return new RegExp(`^${escaped}$`, "i");
|
|
10618
|
+
}
|
|
10619
|
+
function isAllowedCommandOrigin(origin, allowed) {
|
|
10620
|
+
return allowed.some((pattern) => originPatternToRegExp(pattern).test(origin));
|
|
10621
|
+
}
|
|
10622
|
+
function postToTarget(target, message, targetOrigin = "*") {
|
|
10623
|
+
try {
|
|
10624
|
+
target.postMessage(message, targetOrigin);
|
|
10625
|
+
} catch {
|
|
10626
|
+
}
|
|
10627
|
+
}
|
|
10628
|
+
function isRouterBusy(router) {
|
|
10629
|
+
const { navigation, fetchers } = router.state;
|
|
10630
|
+
if (navigation && navigation.state !== "idle") return true;
|
|
10631
|
+
if (fetchers) {
|
|
10632
|
+
for (const fetcher of fetchers.values()) {
|
|
10633
|
+
if (fetcher.state !== "idle") return true;
|
|
10634
|
+
}
|
|
10635
|
+
}
|
|
10636
|
+
return false;
|
|
10637
|
+
}
|
|
10638
|
+
function waitForSettled(router, navigation) {
|
|
10639
|
+
return new Promise((resolve) => {
|
|
10640
|
+
const startedAt = Date.now();
|
|
10641
|
+
let lastMutationAt = Date.now();
|
|
10642
|
+
let navigationDone = false;
|
|
10643
|
+
const observer = new MutationObserver(() => {
|
|
10644
|
+
lastMutationAt = Date.now();
|
|
10645
|
+
});
|
|
10646
|
+
observer.observe(document, {
|
|
10647
|
+
subtree: true,
|
|
10648
|
+
childList: true,
|
|
10649
|
+
attributes: true,
|
|
10650
|
+
characterData: true
|
|
10651
|
+
});
|
|
10652
|
+
navigation.then(
|
|
10653
|
+
() => {
|
|
10654
|
+
navigationDone = true;
|
|
10655
|
+
},
|
|
10656
|
+
() => {
|
|
10657
|
+
navigationDone = true;
|
|
10658
|
+
}
|
|
10659
|
+
);
|
|
10660
|
+
const finish = (settled) => {
|
|
10661
|
+
clearInterval(timer);
|
|
10662
|
+
observer.disconnect();
|
|
10663
|
+
resolve(settled);
|
|
10664
|
+
};
|
|
10665
|
+
const timer = setInterval(() => {
|
|
10666
|
+
const now = Date.now();
|
|
10667
|
+
if (navigationDone && !isRouterBusy(router) && now - lastMutationAt >= SETTLE_QUIET_MS) {
|
|
10668
|
+
finish(true);
|
|
10669
|
+
} else if (now - startedAt >= SETTLE_TIMEOUT_MS) {
|
|
10670
|
+
finish(false);
|
|
10671
|
+
}
|
|
10672
|
+
}, SETTLE_POLL_MS);
|
|
10673
|
+
});
|
|
10674
|
+
}
|
|
10675
|
+
function pathnameOf(path) {
|
|
10676
|
+
return path.split(/[?#]/, 1)[0];
|
|
10677
|
+
}
|
|
10678
|
+
async function handleNavigate(router, target, targetOrigin, data) {
|
|
10679
|
+
if (typeof router.navigate !== "function") {
|
|
10680
|
+
const { location: location3 } = router.state;
|
|
10681
|
+
postToTarget(target, {
|
|
10682
|
+
type: "ARCHIE_NAVIGATE_RESULT",
|
|
10683
|
+
requestId: data.requestId,
|
|
10684
|
+
requestedPath: data.path,
|
|
10685
|
+
finalPath: location3.pathname + location3.search + location3.hash,
|
|
10686
|
+
matchedRouteIds: [],
|
|
10687
|
+
redirected: false,
|
|
10688
|
+
settled: false
|
|
10689
|
+
}, targetOrigin);
|
|
10690
|
+
return;
|
|
10691
|
+
}
|
|
10692
|
+
let navigation = Promise.resolve();
|
|
10693
|
+
try {
|
|
10694
|
+
navigation = Promise.resolve(
|
|
10695
|
+
router.navigate(data.path, { replace: data.replace })
|
|
10696
|
+
);
|
|
10697
|
+
} catch {
|
|
10698
|
+
navigation = Promise.resolve();
|
|
10699
|
+
}
|
|
10700
|
+
const settled = await waitForSettled(router, navigation);
|
|
10701
|
+
const { location: location2, matches } = router.state;
|
|
10702
|
+
postToTarget(target, {
|
|
10703
|
+
type: "ARCHIE_NAVIGATE_RESULT",
|
|
10704
|
+
requestId: data.requestId,
|
|
10705
|
+
requestedPath: data.path,
|
|
10706
|
+
finalPath: location2.pathname + location2.search + location2.hash,
|
|
10707
|
+
matchedRouteIds: matches.map((m) => m.route.id).filter((id) => typeof id === "string"),
|
|
10708
|
+
redirected: location2.pathname !== pathnameOf(data.path),
|
|
10709
|
+
settled
|
|
10710
|
+
}, targetOrigin);
|
|
10711
|
+
}
|
|
10712
|
+
async function handleSnapshot(target, targetOrigin, requestId) {
|
|
10713
|
+
try {
|
|
10714
|
+
const snapshot = await captureDomSnapshot();
|
|
10715
|
+
postToTarget(target, {
|
|
10716
|
+
type: "ARCHIE_SNAPSHOT_DOM_RESULT",
|
|
10717
|
+
requestId,
|
|
10718
|
+
...snapshot
|
|
10719
|
+
}, targetOrigin);
|
|
10720
|
+
} catch (error) {
|
|
10721
|
+
postToTarget(target, {
|
|
10722
|
+
type: "ARCHIE_SNAPSHOT_DOM_FAILED",
|
|
10723
|
+
requestId,
|
|
10724
|
+
error: error instanceof Error ? error.message : String(error)
|
|
10725
|
+
}, targetOrigin);
|
|
10726
|
+
}
|
|
10727
|
+
}
|
|
10728
|
+
function broadcastCapabilities(router, target) {
|
|
10729
|
+
postToTarget(target, {
|
|
10730
|
+
type: "ARCHIE_CAPABILITIES",
|
|
10731
|
+
version: readPackageVersion(),
|
|
10732
|
+
capabilities: {
|
|
10733
|
+
navigate: typeof router.navigate === "function",
|
|
10734
|
+
snapshot: true,
|
|
10735
|
+
identityOverride: false
|
|
10736
|
+
}
|
|
10737
|
+
});
|
|
10738
|
+
}
|
|
10739
|
+
function setupArchieRouteListener(router, options = {}) {
|
|
10740
|
+
const allowedOrigins = options.allowedOrigins ?? DEFAULT_ARCHIE_COMMAND_ORIGINS;
|
|
10394
10741
|
const target = window.parent !== window ? window.parent : window.opener;
|
|
10395
10742
|
if (!target) {
|
|
10396
10743
|
return () => {
|
|
10397
10744
|
};
|
|
10398
10745
|
}
|
|
10399
10746
|
broadcastRouteState(target, router.state, extractAllRoutes(router.routes));
|
|
10747
|
+
broadcastCapabilities(router, target);
|
|
10400
10748
|
const unsubscribe = router.subscribe((state) => {
|
|
10401
10749
|
const currentRoutes = extractAllRoutes(router.routes);
|
|
10402
10750
|
broadcastRouteState(target, state, currentRoutes);
|
|
10403
10751
|
});
|
|
10404
10752
|
const handleMessage = (event) => {
|
|
10405
|
-
if (event.
|
|
10406
|
-
|
|
10407
|
-
|
|
10753
|
+
if (event.source !== target) return;
|
|
10754
|
+
const data = event.data;
|
|
10755
|
+
switch (data?.type) {
|
|
10756
|
+
case "ARCHIE_QUERY_ROUTES":
|
|
10757
|
+
broadcastRouteState(
|
|
10758
|
+
target,
|
|
10759
|
+
router.state,
|
|
10760
|
+
extractAllRoutes(router.routes)
|
|
10761
|
+
);
|
|
10762
|
+
break;
|
|
10763
|
+
case "ARCHIE_QUERY_CAPABILITIES":
|
|
10764
|
+
broadcastCapabilities(router, target);
|
|
10765
|
+
break;
|
|
10766
|
+
case "ARCHIE_NAVIGATE":
|
|
10767
|
+
if (isAllowedCommandOrigin(event.origin, allowedOrigins) && typeof data.requestId === "string" && typeof data.path === "string") {
|
|
10768
|
+
void handleNavigate(router, target, event.origin, data);
|
|
10769
|
+
}
|
|
10770
|
+
break;
|
|
10771
|
+
case "ARCHIE_SNAPSHOT_DOM":
|
|
10772
|
+
if (isAllowedCommandOrigin(event.origin, allowedOrigins) && typeof data.requestId === "string") {
|
|
10773
|
+
void handleSnapshot(target, event.origin, data.requestId);
|
|
10774
|
+
}
|
|
10775
|
+
break;
|
|
10408
10776
|
}
|
|
10409
10777
|
};
|
|
10410
10778
|
window.addEventListener("message", handleMessage);
|
|
@@ -10444,7 +10812,8 @@ function installDomMetaSanitizer() {
|
|
|
10444
10812
|
function useArchieDevToolsRuntime({
|
|
10445
10813
|
router,
|
|
10446
10814
|
inspector,
|
|
10447
|
-
inspectorOptions
|
|
10815
|
+
inspectorOptions,
|
|
10816
|
+
routeListenerOrigins
|
|
10448
10817
|
}) {
|
|
10449
10818
|
installDomMetaSanitizer();
|
|
10450
10819
|
const stableOptionsKey = JSON.stringify(inspectorOptions ?? null);
|
|
@@ -10454,7 +10823,9 @@ function useArchieDevToolsRuntime({
|
|
|
10454
10823
|
if (process.env.NODE_ENV !== "development") {
|
|
10455
10824
|
return;
|
|
10456
10825
|
}
|
|
10457
|
-
const unsubscribe = setupArchieRouteListener(router
|
|
10826
|
+
const unsubscribe = setupArchieRouteListener(router, {
|
|
10827
|
+
allowedOrigins: routeListenerOrigins
|
|
10828
|
+
});
|
|
10458
10829
|
if (inspector !== false) {
|
|
10459
10830
|
const useLocalInspector = readArchieLocalInspectorFlag();
|
|
10460
10831
|
injectInspector({
|
|
@@ -10472,9 +10843,15 @@ function ArchieDevToolProvider({
|
|
|
10472
10843
|
children,
|
|
10473
10844
|
router,
|
|
10474
10845
|
inspector,
|
|
10475
|
-
inspectorOptions
|
|
10846
|
+
inspectorOptions,
|
|
10847
|
+
routeListenerOrigins
|
|
10476
10848
|
}) {
|
|
10477
|
-
useArchieDevToolsRuntime({
|
|
10849
|
+
useArchieDevToolsRuntime({
|
|
10850
|
+
router,
|
|
10851
|
+
inspector,
|
|
10852
|
+
inspectorOptions,
|
|
10853
|
+
routeListenerOrigins
|
|
10854
|
+
});
|
|
10478
10855
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DndProvider, { children });
|
|
10479
10856
|
}
|
|
10480
10857
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/client/client.mjs
CHANGED
|
@@ -10236,7 +10236,7 @@ function isPreviewOrigin(origin) {
|
|
|
10236
10236
|
var DEFAULT_SCRIPT_ID = "archie-inspector-script";
|
|
10237
10237
|
var R2_INSPECTOR_BASE_URL = "https://pub-bf238c278d9644b39ec34ecaca1d315c.r2.dev";
|
|
10238
10238
|
function readBuildVersion() {
|
|
10239
|
-
return "0.1.
|
|
10239
|
+
return "0.1.13" ? "0.1.13" : null;
|
|
10240
10240
|
}
|
|
10241
10241
|
var REMOTE_INSPECTOR_VERSION = readBuildVersion();
|
|
10242
10242
|
var isRemoteInspectorUrlVersioned = REMOTE_INSPECTOR_VERSION !== null;
|
|
@@ -10316,25 +10316,238 @@ function injectInspector(opts = {}) {
|
|
|
10316
10316
|
document.head.appendChild(script);
|
|
10317
10317
|
}
|
|
10318
10318
|
|
|
10319
|
+
// src/client/route-listener/domSnapshot.ts
|
|
10320
|
+
var STRIP_SELECTOR = [
|
|
10321
|
+
"script",
|
|
10322
|
+
"noscript",
|
|
10323
|
+
"iframe",
|
|
10324
|
+
"[data-inspector-badge]",
|
|
10325
|
+
"[data-inspector-context-menu]",
|
|
10326
|
+
"#archie-inspector-styles"
|
|
10327
|
+
].join(",");
|
|
10328
|
+
var PALETTE_SELECTOR = "#archie-design-palette";
|
|
10329
|
+
var CSS_FETCH_TIMEOUT_MS = 2e3;
|
|
10330
|
+
var IDLE_TIMEOUT_MS = 500;
|
|
10331
|
+
var CSS_URL_RE = /url\(\s*(['"]?)([^'")]+)\1\s*\)/g;
|
|
10332
|
+
function absolutizeCssUrls(css, baseHref) {
|
|
10333
|
+
return css.replace(CSS_URL_RE, (full, _quote, raw) => {
|
|
10334
|
+
if (!raw || raw.startsWith("data:") || raw.startsWith("#")) return full;
|
|
10335
|
+
try {
|
|
10336
|
+
return `url(${new URL(raw, baseHref).href})`;
|
|
10337
|
+
} catch {
|
|
10338
|
+
return full;
|
|
10339
|
+
}
|
|
10340
|
+
});
|
|
10341
|
+
}
|
|
10342
|
+
function isExcludedSheet(sheet) {
|
|
10343
|
+
const owner = sheet.ownerNode;
|
|
10344
|
+
return !!owner?.matches?.(`${STRIP_SELECTOR},${PALETTE_SELECTOR}`);
|
|
10345
|
+
}
|
|
10346
|
+
async function fetchCssText(href) {
|
|
10347
|
+
const controller = new AbortController();
|
|
10348
|
+
const timer = setTimeout(() => controller.abort(), CSS_FETCH_TIMEOUT_MS);
|
|
10349
|
+
try {
|
|
10350
|
+
const response = await fetch(href, {
|
|
10351
|
+
mode: "cors",
|
|
10352
|
+
signal: controller.signal
|
|
10353
|
+
});
|
|
10354
|
+
return response.ok ? await response.text() : "";
|
|
10355
|
+
} catch {
|
|
10356
|
+
return "";
|
|
10357
|
+
} finally {
|
|
10358
|
+
clearTimeout(timer);
|
|
10359
|
+
}
|
|
10360
|
+
}
|
|
10361
|
+
async function collectSheetCss(sheet, inlinedHrefs) {
|
|
10362
|
+
if (sheet.disabled || isExcludedSheet(sheet)) return "";
|
|
10363
|
+
const baseHref = sheet.href || document.baseURI;
|
|
10364
|
+
let css = "";
|
|
10365
|
+
try {
|
|
10366
|
+
css = Array.from(sheet.cssRules, (rule) => rule.cssText).join("\n");
|
|
10367
|
+
} catch {
|
|
10368
|
+
css = sheet.href ? await fetchCssText(sheet.href) : "";
|
|
10369
|
+
}
|
|
10370
|
+
if (!css) {
|
|
10371
|
+
const owner = sheet.ownerNode;
|
|
10372
|
+
if (owner?.tagName === "STYLE") css = owner.textContent ?? "";
|
|
10373
|
+
}
|
|
10374
|
+
if (!css) return "";
|
|
10375
|
+
if (sheet.href) inlinedHrefs.add(sheet.href);
|
|
10376
|
+
css = absolutizeCssUrls(css, baseHref);
|
|
10377
|
+
const media = sheet.media?.mediaText;
|
|
10378
|
+
return media && media !== "all" ? `@media ${media}{${css}}` : css;
|
|
10379
|
+
}
|
|
10380
|
+
async function collectDocumentCss(inlinedHrefs) {
|
|
10381
|
+
const sheets = Array.from(document.styleSheets);
|
|
10382
|
+
const parts = await Promise.all(
|
|
10383
|
+
sheets.map((sheet) => collectSheetCss(sheet, inlinedHrefs))
|
|
10384
|
+
);
|
|
10385
|
+
return parts.filter(Boolean).join("\n");
|
|
10386
|
+
}
|
|
10387
|
+
function waitForIdle() {
|
|
10388
|
+
return new Promise((resolve) => {
|
|
10389
|
+
const w = window;
|
|
10390
|
+
if (typeof w.requestIdleCallback === "function") {
|
|
10391
|
+
w.requestIdleCallback(() => resolve(), { timeout: IDLE_TIMEOUT_MS });
|
|
10392
|
+
} else {
|
|
10393
|
+
setTimeout(resolve, 50);
|
|
10394
|
+
}
|
|
10395
|
+
});
|
|
10396
|
+
}
|
|
10397
|
+
async function captureDomSnapshot() {
|
|
10398
|
+
if (document.fonts?.ready) {
|
|
10399
|
+
await document.fonts.ready;
|
|
10400
|
+
}
|
|
10401
|
+
await waitForIdle();
|
|
10402
|
+
const inlinedHrefs = /* @__PURE__ */ new Set();
|
|
10403
|
+
const css = await collectDocumentCss(inlinedHrefs);
|
|
10404
|
+
const clone = document.documentElement.cloneNode(true);
|
|
10405
|
+
clone.querySelectorAll(`${STRIP_SELECTOR}, style:not(${PALETTE_SELECTOR})`).forEach((el) => el.remove());
|
|
10406
|
+
clone.querySelectorAll('link[rel~="stylesheet"]').forEach((link) => {
|
|
10407
|
+
const href = link.href;
|
|
10408
|
+
if (inlinedHrefs.has(href)) {
|
|
10409
|
+
link.remove();
|
|
10410
|
+
} else {
|
|
10411
|
+
link.setAttribute("href", href);
|
|
10412
|
+
}
|
|
10413
|
+
});
|
|
10414
|
+
for (const el of [clone, ...Array.from(clone.querySelectorAll("*"))]) {
|
|
10415
|
+
for (const attr of Array.from(el.attributes)) {
|
|
10416
|
+
if (/^on[a-z]+$/i.test(attr.name)) {
|
|
10417
|
+
el.removeAttribute(attr.name);
|
|
10418
|
+
}
|
|
10419
|
+
}
|
|
10420
|
+
}
|
|
10421
|
+
let head = clone.querySelector("head");
|
|
10422
|
+
if (!head) {
|
|
10423
|
+
head = document.createElement("head");
|
|
10424
|
+
clone.insertBefore(head, clone.firstChild);
|
|
10425
|
+
}
|
|
10426
|
+
const style = document.createElement("style");
|
|
10427
|
+
style.textContent = css;
|
|
10428
|
+
head.insertBefore(style, head.firstChild);
|
|
10429
|
+
if (!head.querySelector("base")) {
|
|
10430
|
+
const base = document.createElement("base");
|
|
10431
|
+
base.setAttribute("href", document.baseURI);
|
|
10432
|
+
head.insertBefore(base, head.firstChild);
|
|
10433
|
+
}
|
|
10434
|
+
return {
|
|
10435
|
+
html: "<!doctype html>" + clone.outerHTML,
|
|
10436
|
+
path: location.pathname + location.search + location.hash,
|
|
10437
|
+
viewport: { width: window.innerWidth, height: window.innerHeight },
|
|
10438
|
+
capturedAt: Date.now()
|
|
10439
|
+
};
|
|
10440
|
+
}
|
|
10441
|
+
|
|
10319
10442
|
// src/client/route-listener/routeListener.ts
|
|
10320
|
-
|
|
10443
|
+
var GUARD_NAME_RE = /guard|protect|require|auth(?!or)/i;
|
|
10444
|
+
var GUARD_PRIVATE_RE = /\bprivate|Private(?=[A-Z]|$)/;
|
|
10445
|
+
var NON_GUARD_SUFFIX_RE = /(Layout|Provider|Context|Page|Form|Screen|View)$/;
|
|
10446
|
+
function isGuardName(name) {
|
|
10447
|
+
return !NON_GUARD_SUFFIX_RE.test(name) && (GUARD_NAME_RE.test(name) || GUARD_PRIVATE_RE.test(name));
|
|
10448
|
+
}
|
|
10449
|
+
var GUARD_PROP_NAMES = [
|
|
10450
|
+
"roles",
|
|
10451
|
+
"allowedRoles",
|
|
10452
|
+
"requiredRoles",
|
|
10453
|
+
"permission",
|
|
10454
|
+
"permissions"
|
|
10455
|
+
];
|
|
10456
|
+
var MAX_ELEMENT_DEPTH = 6;
|
|
10457
|
+
function typeName(type) {
|
|
10458
|
+
if (typeof type === "string") return type;
|
|
10459
|
+
if (typeof type === "function") {
|
|
10460
|
+
const fn = type;
|
|
10461
|
+
return fn.displayName || fn.name || null;
|
|
10462
|
+
}
|
|
10463
|
+
if (type && typeof type === "object") {
|
|
10464
|
+
const obj = type;
|
|
10465
|
+
return obj.displayName || typeName(obj.render) || typeName(obj.type);
|
|
10466
|
+
}
|
|
10467
|
+
return null;
|
|
10468
|
+
}
|
|
10469
|
+
function isElementLike(node) {
|
|
10470
|
+
return !!node && typeof node === "object" && "type" in node && "props" in node;
|
|
10471
|
+
}
|
|
10472
|
+
function literalRoles(value) {
|
|
10473
|
+
if (typeof value === "string") return [value];
|
|
10474
|
+
if (Array.isArray(value) && value.every((v) => typeof v === "string")) {
|
|
10475
|
+
return value;
|
|
10476
|
+
}
|
|
10477
|
+
return void 0;
|
|
10478
|
+
}
|
|
10479
|
+
function collectGuards(node, depth, out) {
|
|
10480
|
+
if (depth > MAX_ELEMENT_DEPTH || node == null) return;
|
|
10481
|
+
if (Array.isArray(node)) {
|
|
10482
|
+
for (const child of node) collectGuards(child, depth, out);
|
|
10483
|
+
return;
|
|
10484
|
+
}
|
|
10485
|
+
if (!isElementLike(node)) return;
|
|
10486
|
+
const props = node.props ?? {};
|
|
10487
|
+
const name = typeName(node.type);
|
|
10488
|
+
const roleProps = GUARD_PROP_NAMES.filter((p) => p in props);
|
|
10489
|
+
const isNamedGuard = typeof node.type !== "string" && !!name && isGuardName(name);
|
|
10490
|
+
if (isNamedGuard || roleProps.length > 0) {
|
|
10491
|
+
const roles = roleProps.flatMap((p) => literalRoles(props[p]) ?? []);
|
|
10492
|
+
out.push({
|
|
10493
|
+
componentName: name ?? "Anonymous",
|
|
10494
|
+
...roles.length > 0 ? { roles } : {}
|
|
10495
|
+
});
|
|
10496
|
+
}
|
|
10497
|
+
collectGuards(props.children, depth + 1, out);
|
|
10498
|
+
}
|
|
10499
|
+
function routeComponentName(route) {
|
|
10500
|
+
if (route.Component) return typeName(route.Component);
|
|
10501
|
+
if (isElementLike(route.element)) return typeName(route.element.type);
|
|
10502
|
+
return null;
|
|
10503
|
+
}
|
|
10504
|
+
function extractAllRoutes(routes, parentPath = "", parentId = null, inheritedGuards = []) {
|
|
10321
10505
|
const result = [];
|
|
10322
10506
|
for (const route of routes) {
|
|
10323
10507
|
const path = route.path ? (parentPath + "/" + route.path).replace(/\/+/g, "/") : parentPath || "/";
|
|
10324
|
-
|
|
10508
|
+
const hasChildren = !!(route.children && route.children.length > 0);
|
|
10509
|
+
const isLayout = !route.path && !route.index && hasChildren;
|
|
10510
|
+
const own = [];
|
|
10511
|
+
collectGuards(route.element, 0, own);
|
|
10512
|
+
if (route.path !== void 0 || route.index || isLayout) {
|
|
10325
10513
|
result.push({
|
|
10326
10514
|
id: route.id,
|
|
10327
10515
|
path: route.index ? parentPath || "/" : path,
|
|
10328
|
-
hasChildren
|
|
10516
|
+
hasChildren,
|
|
10517
|
+
parentId,
|
|
10518
|
+
index: !!route.index,
|
|
10519
|
+
isLayout,
|
|
10520
|
+
componentName: routeComponentName(route),
|
|
10521
|
+
guardEvidence: [
|
|
10522
|
+
...own.map((g) => ({ ...g, source: "self" })),
|
|
10523
|
+
...inheritedGuards
|
|
10524
|
+
]
|
|
10329
10525
|
});
|
|
10330
10526
|
}
|
|
10331
10527
|
if (route.children) {
|
|
10332
|
-
|
|
10528
|
+
const forChildren = [
|
|
10529
|
+
...own.map(
|
|
10530
|
+
(g) => ({
|
|
10531
|
+
...g,
|
|
10532
|
+
source: "ancestor",
|
|
10533
|
+
...route.id !== void 0 ? { ancestorId: route.id } : {}
|
|
10534
|
+
})
|
|
10535
|
+
),
|
|
10536
|
+
...inheritedGuards
|
|
10537
|
+
];
|
|
10538
|
+
result.push(
|
|
10539
|
+
...extractAllRoutes(
|
|
10540
|
+
route.children,
|
|
10541
|
+
path,
|
|
10542
|
+
route.id ?? parentId,
|
|
10543
|
+
forChildren
|
|
10544
|
+
)
|
|
10545
|
+
);
|
|
10333
10546
|
}
|
|
10334
10547
|
}
|
|
10335
10548
|
return result;
|
|
10336
10549
|
}
|
|
10337
|
-
function broadcastRouteState(target, state,
|
|
10550
|
+
function broadcastRouteState(target, state, routes) {
|
|
10338
10551
|
try {
|
|
10339
10552
|
const message = {
|
|
10340
10553
|
type: "ARCHIE_ROUTE_UPDATE",
|
|
@@ -10347,7 +10560,9 @@ function broadcastRouteState(target, state, allRoutes) {
|
|
|
10347
10560
|
pathname: m.pathname,
|
|
10348
10561
|
params: m.params
|
|
10349
10562
|
})),
|
|
10350
|
-
allRoutes
|
|
10563
|
+
// Layouts stay out of allRoutes so consumers that predate them don't list duplicates.
|
|
10564
|
+
allRoutes: routes.filter((r) => !r.isLayout),
|
|
10565
|
+
layoutRoutes: routes.filter((r) => r.isLayout),
|
|
10351
10566
|
timestamp: Date.now()
|
|
10352
10567
|
}
|
|
10353
10568
|
};
|
|
@@ -10355,21 +10570,174 @@ function broadcastRouteState(target, state, allRoutes) {
|
|
|
10355
10570
|
} catch {
|
|
10356
10571
|
}
|
|
10357
10572
|
}
|
|
10358
|
-
|
|
10573
|
+
var SETTLE_QUIET_MS = 400;
|
|
10574
|
+
var SETTLE_TIMEOUT_MS = 8e3;
|
|
10575
|
+
var SETTLE_POLL_MS = 50;
|
|
10576
|
+
function readPackageVersion() {
|
|
10577
|
+
return true ? "0.1.13" : "unknown";
|
|
10578
|
+
}
|
|
10579
|
+
var DEFAULT_ARCHIE_COMMAND_ORIGINS = getAllowedOrigins(true);
|
|
10580
|
+
function originPatternToRegExp(pattern) {
|
|
10581
|
+
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/:\*$/, ":\\d+").replace(/\*/g, "[a-z0-9.-]+");
|
|
10582
|
+
return new RegExp(`^${escaped}$`, "i");
|
|
10583
|
+
}
|
|
10584
|
+
function isAllowedCommandOrigin(origin, allowed) {
|
|
10585
|
+
return allowed.some((pattern) => originPatternToRegExp(pattern).test(origin));
|
|
10586
|
+
}
|
|
10587
|
+
function postToTarget(target, message, targetOrigin = "*") {
|
|
10588
|
+
try {
|
|
10589
|
+
target.postMessage(message, targetOrigin);
|
|
10590
|
+
} catch {
|
|
10591
|
+
}
|
|
10592
|
+
}
|
|
10593
|
+
function isRouterBusy(router) {
|
|
10594
|
+
const { navigation, fetchers } = router.state;
|
|
10595
|
+
if (navigation && navigation.state !== "idle") return true;
|
|
10596
|
+
if (fetchers) {
|
|
10597
|
+
for (const fetcher of fetchers.values()) {
|
|
10598
|
+
if (fetcher.state !== "idle") return true;
|
|
10599
|
+
}
|
|
10600
|
+
}
|
|
10601
|
+
return false;
|
|
10602
|
+
}
|
|
10603
|
+
function waitForSettled(router, navigation) {
|
|
10604
|
+
return new Promise((resolve) => {
|
|
10605
|
+
const startedAt = Date.now();
|
|
10606
|
+
let lastMutationAt = Date.now();
|
|
10607
|
+
let navigationDone = false;
|
|
10608
|
+
const observer = new MutationObserver(() => {
|
|
10609
|
+
lastMutationAt = Date.now();
|
|
10610
|
+
});
|
|
10611
|
+
observer.observe(document, {
|
|
10612
|
+
subtree: true,
|
|
10613
|
+
childList: true,
|
|
10614
|
+
attributes: true,
|
|
10615
|
+
characterData: true
|
|
10616
|
+
});
|
|
10617
|
+
navigation.then(
|
|
10618
|
+
() => {
|
|
10619
|
+
navigationDone = true;
|
|
10620
|
+
},
|
|
10621
|
+
() => {
|
|
10622
|
+
navigationDone = true;
|
|
10623
|
+
}
|
|
10624
|
+
);
|
|
10625
|
+
const finish = (settled) => {
|
|
10626
|
+
clearInterval(timer);
|
|
10627
|
+
observer.disconnect();
|
|
10628
|
+
resolve(settled);
|
|
10629
|
+
};
|
|
10630
|
+
const timer = setInterval(() => {
|
|
10631
|
+
const now = Date.now();
|
|
10632
|
+
if (navigationDone && !isRouterBusy(router) && now - lastMutationAt >= SETTLE_QUIET_MS) {
|
|
10633
|
+
finish(true);
|
|
10634
|
+
} else if (now - startedAt >= SETTLE_TIMEOUT_MS) {
|
|
10635
|
+
finish(false);
|
|
10636
|
+
}
|
|
10637
|
+
}, SETTLE_POLL_MS);
|
|
10638
|
+
});
|
|
10639
|
+
}
|
|
10640
|
+
function pathnameOf(path) {
|
|
10641
|
+
return path.split(/[?#]/, 1)[0];
|
|
10642
|
+
}
|
|
10643
|
+
async function handleNavigate(router, target, targetOrigin, data) {
|
|
10644
|
+
if (typeof router.navigate !== "function") {
|
|
10645
|
+
const { location: location3 } = router.state;
|
|
10646
|
+
postToTarget(target, {
|
|
10647
|
+
type: "ARCHIE_NAVIGATE_RESULT",
|
|
10648
|
+
requestId: data.requestId,
|
|
10649
|
+
requestedPath: data.path,
|
|
10650
|
+
finalPath: location3.pathname + location3.search + location3.hash,
|
|
10651
|
+
matchedRouteIds: [],
|
|
10652
|
+
redirected: false,
|
|
10653
|
+
settled: false
|
|
10654
|
+
}, targetOrigin);
|
|
10655
|
+
return;
|
|
10656
|
+
}
|
|
10657
|
+
let navigation = Promise.resolve();
|
|
10658
|
+
try {
|
|
10659
|
+
navigation = Promise.resolve(
|
|
10660
|
+
router.navigate(data.path, { replace: data.replace })
|
|
10661
|
+
);
|
|
10662
|
+
} catch {
|
|
10663
|
+
navigation = Promise.resolve();
|
|
10664
|
+
}
|
|
10665
|
+
const settled = await waitForSettled(router, navigation);
|
|
10666
|
+
const { location: location2, matches } = router.state;
|
|
10667
|
+
postToTarget(target, {
|
|
10668
|
+
type: "ARCHIE_NAVIGATE_RESULT",
|
|
10669
|
+
requestId: data.requestId,
|
|
10670
|
+
requestedPath: data.path,
|
|
10671
|
+
finalPath: location2.pathname + location2.search + location2.hash,
|
|
10672
|
+
matchedRouteIds: matches.map((m) => m.route.id).filter((id) => typeof id === "string"),
|
|
10673
|
+
redirected: location2.pathname !== pathnameOf(data.path),
|
|
10674
|
+
settled
|
|
10675
|
+
}, targetOrigin);
|
|
10676
|
+
}
|
|
10677
|
+
async function handleSnapshot(target, targetOrigin, requestId) {
|
|
10678
|
+
try {
|
|
10679
|
+
const snapshot = await captureDomSnapshot();
|
|
10680
|
+
postToTarget(target, {
|
|
10681
|
+
type: "ARCHIE_SNAPSHOT_DOM_RESULT",
|
|
10682
|
+
requestId,
|
|
10683
|
+
...snapshot
|
|
10684
|
+
}, targetOrigin);
|
|
10685
|
+
} catch (error) {
|
|
10686
|
+
postToTarget(target, {
|
|
10687
|
+
type: "ARCHIE_SNAPSHOT_DOM_FAILED",
|
|
10688
|
+
requestId,
|
|
10689
|
+
error: error instanceof Error ? error.message : String(error)
|
|
10690
|
+
}, targetOrigin);
|
|
10691
|
+
}
|
|
10692
|
+
}
|
|
10693
|
+
function broadcastCapabilities(router, target) {
|
|
10694
|
+
postToTarget(target, {
|
|
10695
|
+
type: "ARCHIE_CAPABILITIES",
|
|
10696
|
+
version: readPackageVersion(),
|
|
10697
|
+
capabilities: {
|
|
10698
|
+
navigate: typeof router.navigate === "function",
|
|
10699
|
+
snapshot: true,
|
|
10700
|
+
identityOverride: false
|
|
10701
|
+
}
|
|
10702
|
+
});
|
|
10703
|
+
}
|
|
10704
|
+
function setupArchieRouteListener(router, options = {}) {
|
|
10705
|
+
const allowedOrigins = options.allowedOrigins ?? DEFAULT_ARCHIE_COMMAND_ORIGINS;
|
|
10359
10706
|
const target = window.parent !== window ? window.parent : window.opener;
|
|
10360
10707
|
if (!target) {
|
|
10361
10708
|
return () => {
|
|
10362
10709
|
};
|
|
10363
10710
|
}
|
|
10364
10711
|
broadcastRouteState(target, router.state, extractAllRoutes(router.routes));
|
|
10712
|
+
broadcastCapabilities(router, target);
|
|
10365
10713
|
const unsubscribe = router.subscribe((state) => {
|
|
10366
10714
|
const currentRoutes = extractAllRoutes(router.routes);
|
|
10367
10715
|
broadcastRouteState(target, state, currentRoutes);
|
|
10368
10716
|
});
|
|
10369
10717
|
const handleMessage = (event) => {
|
|
10370
|
-
if (event.
|
|
10371
|
-
|
|
10372
|
-
|
|
10718
|
+
if (event.source !== target) return;
|
|
10719
|
+
const data = event.data;
|
|
10720
|
+
switch (data?.type) {
|
|
10721
|
+
case "ARCHIE_QUERY_ROUTES":
|
|
10722
|
+
broadcastRouteState(
|
|
10723
|
+
target,
|
|
10724
|
+
router.state,
|
|
10725
|
+
extractAllRoutes(router.routes)
|
|
10726
|
+
);
|
|
10727
|
+
break;
|
|
10728
|
+
case "ARCHIE_QUERY_CAPABILITIES":
|
|
10729
|
+
broadcastCapabilities(router, target);
|
|
10730
|
+
break;
|
|
10731
|
+
case "ARCHIE_NAVIGATE":
|
|
10732
|
+
if (isAllowedCommandOrigin(event.origin, allowedOrigins) && typeof data.requestId === "string" && typeof data.path === "string") {
|
|
10733
|
+
void handleNavigate(router, target, event.origin, data);
|
|
10734
|
+
}
|
|
10735
|
+
break;
|
|
10736
|
+
case "ARCHIE_SNAPSHOT_DOM":
|
|
10737
|
+
if (isAllowedCommandOrigin(event.origin, allowedOrigins) && typeof data.requestId === "string") {
|
|
10738
|
+
void handleSnapshot(target, event.origin, data.requestId);
|
|
10739
|
+
}
|
|
10740
|
+
break;
|
|
10373
10741
|
}
|
|
10374
10742
|
};
|
|
10375
10743
|
window.addEventListener("message", handleMessage);
|
|
@@ -10409,7 +10777,8 @@ function installDomMetaSanitizer() {
|
|
|
10409
10777
|
function useArchieDevToolsRuntime({
|
|
10410
10778
|
router,
|
|
10411
10779
|
inspector,
|
|
10412
|
-
inspectorOptions
|
|
10780
|
+
inspectorOptions,
|
|
10781
|
+
routeListenerOrigins
|
|
10413
10782
|
}) {
|
|
10414
10783
|
installDomMetaSanitizer();
|
|
10415
10784
|
const stableOptionsKey = JSON.stringify(inspectorOptions ?? null);
|
|
@@ -10419,7 +10788,9 @@ function useArchieDevToolsRuntime({
|
|
|
10419
10788
|
if (process.env.NODE_ENV !== "development") {
|
|
10420
10789
|
return;
|
|
10421
10790
|
}
|
|
10422
|
-
const unsubscribe = setupArchieRouteListener(router
|
|
10791
|
+
const unsubscribe = setupArchieRouteListener(router, {
|
|
10792
|
+
allowedOrigins: routeListenerOrigins
|
|
10793
|
+
});
|
|
10423
10794
|
if (inspector !== false) {
|
|
10424
10795
|
const useLocalInspector = readArchieLocalInspectorFlag();
|
|
10425
10796
|
injectInspector({
|
|
@@ -10437,9 +10808,15 @@ function ArchieDevToolProvider({
|
|
|
10437
10808
|
children,
|
|
10438
10809
|
router,
|
|
10439
10810
|
inspector,
|
|
10440
|
-
inspectorOptions
|
|
10811
|
+
inspectorOptions,
|
|
10812
|
+
routeListenerOrigins
|
|
10441
10813
|
}) {
|
|
10442
|
-
useArchieDevToolsRuntime({
|
|
10814
|
+
useArchieDevToolsRuntime({
|
|
10815
|
+
router,
|
|
10816
|
+
inspector,
|
|
10817
|
+
inspectorOptions,
|
|
10818
|
+
routeListenerOrigins
|
|
10819
|
+
});
|
|
10443
10820
|
return /* @__PURE__ */ jsx6(DndProvider, { children });
|
|
10444
10821
|
}
|
|
10445
10822
|
export {
|
package/package.json
CHANGED
|
File without changes
|