@jami-studio/core 0.92.29 → 0.92.31
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/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +30 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/production-agent.ts +7360 -7302
- package/corpus/core/src/client/route-warmup.tsx +565 -543
- package/corpus/core/src/collab/param.ts +24 -0
- package/corpus/core/src/collab/routes.ts +187 -191
- package/corpus/core/src/collab/struct-routes.ts +134 -133
- package/dist/agent/production-agent.d.ts +15 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +61 -15
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/client/route-warmup.d.ts +10 -0
- package/dist/client/route-warmup.d.ts.map +1 -1
- package/dist/client/route-warmup.js +18 -1
- package/dist/client/route-warmup.js.map +1 -1
- package/dist/collab/param.d.ts +3 -0
- package/dist/collab/param.d.ts.map +1 -0
- package/dist/collab/param.js +26 -0
- package/dist/collab/param.js.map +1 -0
- package/dist/collab/routes.d.ts.map +1 -1
- package/dist/collab/routes.js +6 -5
- package/dist/collab/routes.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts.map +1 -1
- package/dist/collab/struct-routes.js +5 -4
- package/dist/collab/struct-routes.js.map +1 -1
- package/package.json +1 -1
|
@@ -5,6 +5,8 @@ type ReactRouterManifestRoute = {
|
|
|
5
5
|
path?: string;
|
|
6
6
|
index?: boolean;
|
|
7
7
|
module?: string;
|
|
8
|
+
hasLoader?: boolean;
|
|
9
|
+
hasAction?: boolean;
|
|
8
10
|
clientActionModule?: string;
|
|
9
11
|
clientLoaderModule?: string;
|
|
10
12
|
hydrateFallbackModule?: string;
|
|
@@ -32,6 +34,13 @@ export interface AgentNativeRouteWarmupProps {
|
|
|
32
34
|
}
|
|
33
35
|
declare function parseBuildTimeRouteWarmupConfig(raw: AgentNativeRouteWarmupConfigInput | string | undefined): AgentNativeRouteWarmupConfigInput | undefined;
|
|
34
36
|
declare function hasReactRouterManifestRoutes(): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Whether ANY route in the client manifest advertises a server loader or
|
|
39
|
+
* action. Static-shell deployments (Cloudflare Pages worker without a React
|
|
40
|
+
* Router request handler) strip these flags at build time — `.data` requests
|
|
41
|
+
* can never be served there, so warming them only produces 404 noise.
|
|
42
|
+
*/
|
|
43
|
+
declare function manifestAdvertisesServerData(): boolean;
|
|
35
44
|
declare function getManifestRouteTree(manifest: ReactRouterManifest): WarmupRouteObject[];
|
|
36
45
|
declare function hasWarmableRouteAssets(): boolean;
|
|
37
46
|
declare function routeAssetUrlsForHref(href: string): string[];
|
|
@@ -52,6 +61,7 @@ export declare const __routeWarmupInternalsForTests: {
|
|
|
52
61
|
getManifestRouteTree: typeof getManifestRouteTree;
|
|
53
62
|
hasReactRouterManifestRoutes: typeof hasReactRouterManifestRoutes;
|
|
54
63
|
hasWarmableRouteAssets: typeof hasWarmableRouteAssets;
|
|
64
|
+
manifestAdvertisesServerData: typeof manifestAdvertisesServerData;
|
|
55
65
|
parseBuildTimeRouteWarmupConfig: typeof parseBuildTimeRouteWarmupConfig;
|
|
56
66
|
renderWarmupLinksForSelector: typeof renderWarmupLinksForSelector;
|
|
57
67
|
routeAssetUrlsForHref: typeof routeAssetUrlsForHref;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-warmup.d.ts","sourceRoot":"","sources":["../../src/client/route-warmup.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,iCAAiC,EAGvC,MAAM,kCAAkC,CAAC;AAO1C,KAAK,wBAAwB,GAAG;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC;CACnD,CAAC;AAEF,KAAK,iBAAiB,GAAG;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,iBAAiB,EAAE,CAAC;CAChC,CAAC;AAIF,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,oBAAoB,CAAC,EAAE;YAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAC7C,qBAAqB,CAAC,EAAE,mBAAmB,CAAC;KAC7C;CACF;AAUD,MAAM,WAAW,2BAA2B;IAC1C,MAAM,CAAC,EAAE,iCAAiC,CAAC;CAC5C;AAED,iBAAS,+BAA+B,CACtC,GAAG,EAAE,iCAAiC,GAAG,MAAM,GAAG,SAAS,GAC1D,iCAAiC,GAAG,SAAS,CAU/C;AAqFD,iBAAS,4BAA4B,IAAI,OAAO,CAG/C;AAkBD,iBAAS,oBAAoB,CAC3B,QAAQ,EAAE,mBAAmB,GAC5B,iBAAiB,EAAE,CAoCrB;AAkBD,iBAAS,sBAAsB,IAAI,OAAO,CAezC;AAED,iBAAS,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAmCrD;AAgDD,iBAAS,4BAA4B,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAqB3E;AAED,iBAAS,8BAA8B,SAMtC;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,MAAM,GACP,EAAE,2BAA2B,
|
|
1
|
+
{"version":3,"file":"route-warmup.d.ts","sourceRoot":"","sources":["../../src/client/route-warmup.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,iCAAiC,EAGvC,MAAM,kCAAkC,CAAC;AAO1C,KAAK,wBAAwB,GAAG;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC;CACnD,CAAC;AAEF,KAAK,iBAAiB,GAAG;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,iBAAiB,EAAE,CAAC;CAChC,CAAC;AAIF,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,oBAAoB,CAAC,EAAE;YAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAC7C,qBAAqB,CAAC,EAAE,mBAAmB,CAAC;KAC7C;CACF;AAUD,MAAM,WAAW,2BAA2B;IAC1C,MAAM,CAAC,EAAE,iCAAiC,CAAC;CAC5C;AAED,iBAAS,+BAA+B,CACtC,GAAG,EAAE,iCAAiC,GAAG,MAAM,GAAG,SAAS,GAC1D,iCAAiC,GAAG,SAAS,CAU/C;AAqFD,iBAAS,4BAA4B,IAAI,OAAO,CAG/C;AAED;;;;;GAKG;AACH,iBAAS,4BAA4B,IAAI,OAAO,CAO/C;AAkBD,iBAAS,oBAAoB,CAC3B,QAAQ,EAAE,mBAAmB,GAC5B,iBAAiB,EAAE,CAoCrB;AAkBD,iBAAS,sBAAsB,IAAI,OAAO,CAezC;AAED,iBAAS,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAmCrD;AAgDD,iBAAS,4BAA4B,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAqB3E;AAED,iBAAS,8BAA8B,SAMtC;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,MAAM,GACP,EAAE,2BAA2B,QAgK7B;AAED,eAAO,MAAM,8BAA8B;;;;;;;;;CAS1C,CAAC"}
|
|
@@ -100,6 +100,19 @@ function hasReactRouterManifestRoutes() {
|
|
|
100
100
|
const routes = window.__reactRouterManifest?.routes;
|
|
101
101
|
return Boolean(routes && Object.keys(routes).length > 0);
|
|
102
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Whether ANY route in the client manifest advertises a server loader or
|
|
105
|
+
* action. Static-shell deployments (Cloudflare Pages worker without a React
|
|
106
|
+
* Router request handler) strip these flags at build time — `.data` requests
|
|
107
|
+
* can never be served there, so warming them only produces 404 noise.
|
|
108
|
+
*/
|
|
109
|
+
function manifestAdvertisesServerData() {
|
|
110
|
+
for (const route of Object.values(window.__reactRouterManifest?.routes ?? {})) {
|
|
111
|
+
if (route.hasLoader || route.hasAction)
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
103
116
|
function manifestRoutesSignature(routes) {
|
|
104
117
|
return Object.values(routes ?? {})
|
|
105
118
|
.map((route) => [
|
|
@@ -303,7 +316,10 @@ export function AgentNativeRouteWarmup({ config, }) {
|
|
|
303
316
|
// manifests that point at built JS assets, where SSR `.data` requests have
|
|
304
317
|
// the CDN cache headers this feature relies on.
|
|
305
318
|
const hasRouteAssets = hasManifestRoutes && hasWarmableRouteAssets();
|
|
306
|
-
|
|
319
|
+
// `.data` warmup only makes sense when the deployment can actually serve
|
|
320
|
+
// React Router single-fetch requests — static-shell workers strip the
|
|
321
|
+
// hasLoader/hasAction flags, and warming there guarantees a 404 per link.
|
|
322
|
+
const warmData = resolved.data && hasRouteAssets && manifestAdvertisesServerData();
|
|
307
323
|
const warmModules = resolved.modules && hasRouteAssets;
|
|
308
324
|
if (!warmData && !warmModules)
|
|
309
325
|
return;
|
|
@@ -448,6 +464,7 @@ export const __routeWarmupInternalsForTests = {
|
|
|
448
464
|
getManifestRouteTree,
|
|
449
465
|
hasReactRouterManifestRoutes,
|
|
450
466
|
hasWarmableRouteAssets,
|
|
467
|
+
manifestAdvertisesServerData,
|
|
451
468
|
parseBuildTimeRouteWarmupConfig,
|
|
452
469
|
renderWarmupLinksForSelector,
|
|
453
470
|
routeAssetUrlsForHref,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-warmup.js","sourceRoot":"","sources":["../../src/client/route-warmup.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,OAAO,EAAE,WAAW,EAAoB,MAAM,cAAc,CAAC;AAE7D,OAAO,EACL,iCAAiC,GAIlC,MAAM,kCAAkC,CAAC;AAuC1C,MAAM,aAAa,GAAG,kBAAkB,CAAC;AACzC,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAU,CAAC;AAC3C,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAU,CAAC;AAE5C,IAAI,cAA+C,CAAC;AACpD,IAAI,6BAA6B,GAAG,EAAE,CAAC;AACvC,IAAI,uBAAuB,GAAwB,EAAE,CAAC;AAMtD,SAAS,+BAA+B,CACtC,GAA2D;IAE3D,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC;IACxC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC/B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAsC,CAAC;IAClE,CAAC;IAAC,MAAM,CAAC;QACP,2EAA2E;QAC3E,OAAO,GAAwC,CAAC;IAClD,CAAC;AACH,CAAC;AAED,SAAS,6BAA6B;IAGpC,IAAI,CAAC;QACH,IAAI,OAAO,oCAAoC,KAAK,WAAW,EAAE,CAAC;YAChE,OAAO,+BAA+B,CACpC,oCAAoC,CACrC,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,6DAA6D;IAC/D,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,oBAAoB,CAC3B,MAAqD;IAErD,OAAO,iCAAiC,CACtC,6BAA6B,EAAE,EAC/B,MAAM,CACP,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,QAA4B;IACrD,IAAI,CAAC,QAAQ,IAAI,QAAQ,KAAK,GAAG;QAAE,OAAO,GAAG,CAAC;IAC9C,OAAO,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AACvE,CAAC;AAED,SAAS,aAAa,CAAC,QAAgB;IACrC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,MAAM,CAAC,oBAAoB,EAAE,QAAQ,CAAC,CAAC;IAC1E,IAAI,QAAQ,KAAK,GAAG;QAAE,OAAO,QAAQ,CAAC;IACtC,IAAI,QAAQ,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC;IACtC,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,QAAQ,GAAG,CAAC,EAAE,CAAC;QACxC,OAAO,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC;IAChD,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,oBAAoB,CAAC,QAAgB;IAC5C,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IACxC,OAAO,CACL,OAAO,KAAK,gBAAgB;QAC5B,OAAO,CAAC,UAAU,CAAC,iBAAiB,CAAC;QACrC,OAAO,KAAK,MAAM;QAClB,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAC5B,CAAC;AACJ,CAAC;AAED,SAAS,OAAO,CAAC,IAAY;IAC3B,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,kBAAkB,CAAC,GAAQ;IAClC,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC,QAAQ,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACxD,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,CAAC,QAAQ,CAAC,QAAQ,IAAI,GAAG,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACxE,IAAI,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IACrD,IAAI,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9C,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAuB;IAC/C,IAAI,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC;QAAE,OAAO,KAAK,CAAC;IAChD,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,KAAK,OAAO;QAAE,OAAO,KAAK,CAAC;IACzD,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/B,OAAO,GAAG,CAAC,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC/C,CAAC;AAED,SAAS,mBAAmB,CAAC,IAAY;IACvC,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,CAAC,GAAG,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAElD,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC;IACzD,IAAI,QAAQ,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IAClC,GAAG,CAAC,QAAQ,GAAG,GAAG,QAAQ,OAAO,CAAC;IAClC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;IACd,OAAO,GAAG,CAAC,IAAI,CAAC;AAClB,CAAC;AAED,SAAS,4BAA4B;IACnC,MAAM,MAAM,GAAG,MAAM,CAAC,qBAAqB,EAAE,MAAM,CAAC;IACpD,OAAO,OAAO,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,SAAS,uBAAuB,CAC9B,MAA4D;IAE5D,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC;SAC/B,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACb;QACE,KAAK,CAAC,EAAE;QACR,KAAK,CAAC,QAAQ,IAAI,EAAE;QACpB,KAAK,CAAC,IAAI,IAAI,EAAE;QAChB,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;KACxB,CAAC,IAAI,CAAC,IAAI,CAAC,CACb;SACA,IAAI,EAAE;SACN,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,SAAS,oBAAoB,CAC3B,QAA6B;IAE7B,MAAM,eAAe,GAAG,uBAAuB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACjE,IACE,QAAQ,KAAK,cAAc;QAC3B,eAAe,KAAK,6BAA6B,EACjD,CAAC;QACD,OAAO,uBAAuB,CAAC;IACjC,CAAC;IAED,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IAC5D,MAAM,KAAK,GAAG,IAAI,GAAG,EAA6B,CAAC;IACnD,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE,CAAC;QACnC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE;YAClB,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,SAAS;SAChC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,IAAI,GAAwB,EAAE,CAAC;IACrC,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE,CAAC;QACnC,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACjC,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACjE,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,QAAQ,KAAK,EAAE,CAAC;YACvB,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,cAAc,GAAG,QAAQ,CAAC;IAC1B,6BAA6B,GAAG,eAAe,CAAC;IAChD,uBAAuB,GAAG,IAAI,CAAC;IAC/B,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,uBAAuB,CAAC,SAAiB;IAChD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACvD,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC,QAAQ,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QACvD,yEAAyE;QACzE,wEAAwE;QACxE,0EAA0E;QAC1E,0EAA0E;QAC1E,uEAAuE;QACvE,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAC;QAChE,OAAO,GAAG,CAAC,IAAI,CAAC;IAClB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,sBAAsB;IAC7B,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAC/B,MAAM,CAAC,qBAAqB,EAAE,MAAM,IAAI,EAAE,CAC3C,EAAE,CAAC;QACF,KAAK,MAAM,SAAS,IAAI;YACtB,KAAK,CAAC,MAAM;YACZ,KAAK,CAAC,kBAAkB;YACxB,KAAK,CAAC,kBAAkB;YACxB,KAAK,CAAC,qBAAqB;YAC3B,GAAG,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC;SACzB,EAAE,CAAC;YACF,IAAI,SAAS,IAAI,uBAAuB,CAAC,SAAS,CAAC;gBAAE,OAAO,IAAI,CAAC;QACnE,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAY;IACzC,MAAM,QAAQ,GAAG,MAAM,CAAC,qBAAqB,CAAC;IAC9C,IAAI,CAAC,QAAQ,EAAE,MAAM;QAAE,OAAO,EAAE,CAAC;IAEjC,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,CAAC,GAAG,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAEhD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,MAAM,CAAC,oBAAoB,EAAE,QAAQ,CAAC,CAAC;IAC1E,MAAM,OAAO,GACX,WAAW,CACT,oBAAoB,CAAC,QAAQ,CAA6B,EAC1D,GAAG,CAAC,QAAQ,EACZ,QAAQ,CACT,IAAI,EAAE,CAAC;IACV,MAAM,SAAS,GAAa,EAAE,CAAC;IAE/B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/B,IAAI,CAAC,OAAO;YAAE,SAAS;QACvB,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,KAAK,MAAM,SAAS,IAAI;YACtB,KAAK,CAAC,MAAM;YACZ,KAAK,CAAC,kBAAkB;YACxB,KAAK,CAAC,kBAAkB;YACxB,KAAK,CAAC,qBAAqB;YAC3B,GAAG,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC;SACzB,EAAE,CAAC;YACF,IAAI,CAAC,SAAS;gBAAE,SAAS;YACzB,MAAM,QAAQ,GAAG,uBAAuB,CAAC,SAAS,CAAC,CAAC;YACpD,IAAI,QAAQ;gBAAE,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,0BAA0B;IACjC,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,gBAAgB,CAC1C,iCAAiC,CAClC,EAAE,CAAC;QACF,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;AACH,CAAC;AAED,SAAS,sBAAsB,CAAC,IAAY;IAC1C,KAAK,MAAM,QAAQ,IAAI,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,IAAI,iBAAiB,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,SAAS;QAC9C,iBAAiB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAEhC,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,CAAC,GAAG,GAAG,eAAe,CAAC;QAC3B,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC;QACrB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CACrB,IAAuB,EACvB,QAAwC;IAExC,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACxE,IAAI,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,KAAK,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACtE,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IACE,QAAQ,KAAK,QAAQ;QACrB,QAAQ,KAAK,QAAQ;QACrB,QAAQ,KAAK,UAAU,EACvB,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,IAAI,QAAQ,KAAK,KAAK,IAAI,QAAQ,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC;IAC/D,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAuB;IACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACxE,OAAO,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,KAAK,IAAI,QAAQ,KAAK,OAAO;QACtE,CAAC,CAAC,MAAM;QACR,CAAC,CAAC,QAAQ,CAAC;AACf,CAAC;AAED,SAAS,4BAA4B,CAAC,QAAgB;IACpD,IAAI,QAAmB,CAAC;IACxB,IAAI,CAAC;QACH,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,KAAK,GAAwB,EAAE,CAAC;IACtC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC1C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,IAAI,GACR,OAAO,YAAY,iBAAiB;YAClC,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAoB,SAAS,CAAC;gBACpD,OAAO,CAAC,OAAO,CAAoB,SAAS,CAAC,CAAC,CAAC;QACrD,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS;QACtC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,8BAA8B;IACrC,cAAc,GAAG,SAAS,CAAC;IAC3B,6BAA6B,GAAG,EAAE,CAAC;IACnC,uBAAuB,GAAG,EAAE,CAAC;IAC7B,gBAAgB,CAAC,KAAK,EAAE,CAAC;IACzB,iBAAiB,CAAC,KAAK,EAAE,CAAC;AAC5B,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,sBAAsB,CAAC,EACrC,MAAM,GACsB;IAC5B,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,QAAQ,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;QAC9C,IAAI,QAAQ,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;YAChC,OAAO;QACT,CAAC;QACD,uEAAuE;QACvE,0EAA0E;QAC1E,yEAAyE;QACzE,sEAAsE;QACtE,MAAM,iBAAiB,GAAG,4BAA4B,EAAE,CAAC;QACzD,uEAAuE;QACvE,yEAAyE;QACzE,yEAAyE;QACzE,2EAA2E;QAC3E,gDAAgD;QAChD,MAAM,cAAc,GAAG,iBAAiB,IAAI,sBAAsB,EAAE,CAAC;QACrE,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,IAAI,cAAc,CAAC;QACjD,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,IAAI,cAAc,CAAC;QACvD,IAAI,CAAC,QAAQ,IAAI,CAAC,WAAW;YAAE,OAAO;QAEtC,MAAM,UAAU,GACd,SACD,CAAC,UAAU,CAAC;QACb,IAAI,UAAU,EAAE,QAAQ;YAAE,OAAO;QAEjC,IAAI,WAAW;YAAE,0BAA0B,EAAE,CAAC;QAE9C,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAU,CAAC;QAC3C,MAAM,aAAa,GAAG,IAAI,OAAO,EAAqB,CAAC;QACvD,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,aAAiC,CAAC;QAEtC,MAAM,IAAI,GAAG,GAAG,EAAE;YAChB,IAAI,OAAO,IAAI,CAAC,QAAQ;gBAAE,OAAO;YACjC,OAAO,MAAM,GAAG,QAAQ,CAAC,aAAa,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC3D,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;gBAC3B,IAAI,CAAC,IAAI;oBAAE,SAAS;gBACpB,MAAM,IAAI,CAAC,CAAC;gBACZ,MAAM;qBACH,KAAK,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;qBACjE,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC;qBACf,OAAO,CAAC,GAAG,EAAE;oBACZ,MAAM,IAAI,CAAC,CAAC;oBACZ,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBAC9B,CAAC,CAAC,CAAC;YACP,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,EAAE;YAChC,IAAI,WAAW;gBAAE,sBAAsB,CAAC,IAAI,CAAC,CAAC;YAC9C,IAAI,CAAC,QAAQ;gBAAE,OAAO;YACtB,MAAM,OAAO,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;YAC1C,IAAI,CAAC,OAAO,IAAI,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC;gBAAE,OAAO;YACtD,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAC9B,IAAI,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC;gBAAE,OAAO;YAC1C,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACpB,IAAI,EAAE,CAAC;QACT,CAAC,CAAC;QAEF,MAAM,gBAAgB,GACpB,OAAO,oBAAoB,KAAK,WAAW;YACzC,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,IAAI,oBAAoB,CAAC,CAAC,OAAO,EAAE,EAAE;gBACnC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;oBAC5B,IAAI,CAAC,KAAK,CAAC,cAAc;wBAAE,SAAS;oBACpC,MAAM,IAAI,GAAG,KAAK,CAAC,MAA2B,CAAC;oBAC/C,gBAAgB,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;oBAClC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACtB,CAAC;YACH,CAAC,CAAC,CAAC;QAET,MAAM,IAAI,GAAG,GAAG,EAAE;YAChB,IAAI,WAAW;gBAAE,0BAA0B,EAAE,CAAC;YAE9C,KAAK,MAAM,IAAI,IAAI,4BAA4B,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACnE,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC;oBAAE,SAAS;gBACtC,MAAM,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;gBACtC,IAAI,IAAI,KAAK,MAAM;oBAAE,SAAS;gBAC9B,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACtB,CAAC;YAED,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,gBAAgB,CAC1C,SAAS,CACV,EAAE,CAAC;gBACF,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC;oBAAE,SAAS;gBACtC,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;gBACrD,IAAI,IAAI,KAAK,MAAM;oBAAE,SAAS;gBAC9B,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;oBACtB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBACpB,SAAS;gBACX,CAAC;gBACD,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;oBACxB,IAAI,CAAC,gBAAgB,EAAE,CAAC;wBACtB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBACtB,CAAC;yBAAM,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;wBACpC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;wBACxB,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;oBACjC,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,QAAQ,GAAG,GAAG,EAAE;YACpB,IAAI,aAAa,KAAK,SAAS;gBAAE,MAAM,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;YACpE,aAAa,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE;gBACrC,aAAa,GAAG,SAAS,CAAC;gBAC1B,IAAI,EAAE,CAAC;YACT,CAAC,EAAE,CAAC,CAAC,CAAC;QACR,CAAC,CAAC;QAEF,MAAM,cAAc,GAAG,CAAC,KAAY,EAAE,EAAE;YACtC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;YAC5B,IAAI,CAAC,CAAC,MAAM,YAAY,OAAO,CAAC;gBAAE,OAAO;YACzC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAoB,SAAS,CAAC,CAAC;YAC1D,IAAI,CAAC,IAAI,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC;gBAAE,OAAO;YAC7C,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACrD,IAAI,IAAI,KAAK,MAAM;gBAAE,OAAO;YAC5B,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC,CAAC;QAEF,QAAQ,EAAE,CAAC;QACX,MAAM,QAAQ,GAAG,IAAI,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAChD,2EAA2E;QAC3E,4EAA4E;QAC5E,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,eAAe,EAAE;YACzC,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,IAAI;YACf,UAAU,EAAE,IAAI;SACjB,CAAC,CAAC;QAEH,QAAQ,CAAC,gBAAgB,CAAC,aAAa,EAAE,cAAc,EAAE;YACvD,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;QACH,QAAQ,CAAC,gBAAgB,CAAC,YAAY,EAAE,cAAc,EAAE;YACtD,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;QACH,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,cAAc,EAAE,IAAI,CAAC,CAAC;QAE3D,OAAO,GAAG,EAAE;YACV,OAAO,GAAG,IAAI,CAAC;YACf,IAAI,aAAa,KAAK,SAAS;gBAAE,MAAM,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;YACpE,QAAQ,CAAC,UAAU,EAAE,CAAC;YACtB,gBAAgB,EAAE,UAAU,EAAE,CAAC;YAC/B,QAAQ,CAAC,mBAAmB,CAAC,aAAa,EAAE,cAAc,EAAE,IAAI,CAAC,CAAC;YAClE,QAAQ,CAAC,mBAAmB,CAAC,YAAY,EAAE,cAAc,EAAE,IAAI,CAAC,CAAC;YACjE,QAAQ,CAAC,mBAAmB,CAAC,SAAS,EAAE,cAAc,EAAE,IAAI,CAAC,CAAC;QAChE,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEb,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,MAAM,8BAA8B,GAAG;IAC5C,oBAAoB;IACpB,4BAA4B;IAC5B,sBAAsB;IACtB,+BAA+B;IAC/B,4BAA4B;IAC5B,qBAAqB;IACrB,8BAA8B;CAC/B,CAAC","sourcesContent":["import { useEffect } from \"react\";\r\nimport { matchRoutes, type RouteObject } from \"react-router\";\r\n\r\nimport {\r\n mergeAgentNativeRouteWarmupConfig,\r\n type AgentNativeRouteWarmupConfigInput,\r\n type AgentNativeRouteWarmupResolvedConfig,\r\n type AgentNativeRouteWarmupStrategy,\r\n} from \"../shared/route-warmup-config.js\";\r\n\r\ndeclare const __AGENT_NATIVE_ROUTE_WARMUP_CONFIG__:\r\n | AgentNativeRouteWarmupConfigInput\r\n | string\r\n | undefined;\r\n\r\ntype ReactRouterManifestRoute = {\r\n id: string;\r\n parentId?: string;\r\n path?: string;\r\n index?: boolean;\r\n module?: string;\r\n clientActionModule?: string;\r\n clientLoaderModule?: string;\r\n hydrateFallbackModule?: string;\r\n imports?: string[];\r\n};\r\n\r\ntype ReactRouterManifest = {\r\n routes?: Record<string, ReactRouterManifestRoute>;\r\n};\r\n\r\ntype WarmupRouteObject = {\r\n id: string;\r\n path?: string;\r\n index?: boolean;\r\n children?: WarmupRouteObject[];\r\n};\r\n\r\ntype LinkWarmupMode = Exclude<AgentNativeRouteWarmupStrategy, \"off\" | \"marked\">;\r\n\r\ndeclare global {\r\n interface Window {\r\n __reactRouterContext?: { basename?: string };\r\n __reactRouterManifest?: ReactRouterManifest;\r\n }\r\n}\r\n\r\nconst PREFETCH_ATTR = \"data-an-prefetch\";\r\nconst warmedDataRoutes = new Set<string>();\r\nconst warmedRouteAssets = new Set<string>();\r\n\r\nlet cachedManifest: ReactRouterManifest | undefined;\r\nlet cachedManifestRoutesSignature = \"\";\r\nlet cachedManifestRouteTree: WarmupRouteObject[] = [];\r\n\r\nexport interface AgentNativeRouteWarmupProps {\r\n config?: AgentNativeRouteWarmupConfigInput;\r\n}\r\n\r\nfunction parseBuildTimeRouteWarmupConfig(\r\n raw: AgentNativeRouteWarmupConfigInput | string | undefined,\r\n): AgentNativeRouteWarmupConfigInput | undefined {\r\n if (typeof raw !== \"string\") return raw;\r\n const trimmed = raw.trim();\r\n if (!trimmed) return undefined;\r\n try {\r\n return JSON.parse(trimmed) as AgentNativeRouteWarmupConfigInput;\r\n } catch {\r\n // Some test/build paths may inject a bare strategy string instead of JSON.\r\n return raw as AgentNativeRouteWarmupConfigInput;\r\n }\r\n}\r\n\r\nfunction getBuildTimeRouteWarmupConfig():\r\n | AgentNativeRouteWarmupConfigInput\r\n | undefined {\r\n try {\r\n if (typeof __AGENT_NATIVE_ROUTE_WARMUP_CONFIG__ !== \"undefined\") {\r\n return parseBuildTimeRouteWarmupConfig(\r\n __AGENT_NATIVE_ROUTE_WARMUP_CONFIG__,\r\n );\r\n }\r\n } catch {\r\n // Some non-Vite test/runtime paths do not define the global.\r\n }\r\n return undefined;\r\n}\r\n\r\nfunction getRouteWarmupConfig(\r\n config: AgentNativeRouteWarmupConfigInput | undefined,\r\n): AgentNativeRouteWarmupResolvedConfig {\r\n return mergeAgentNativeRouteWarmupConfig(\r\n getBuildTimeRouteWarmupConfig(),\r\n config,\r\n );\r\n}\r\n\r\nfunction normalizeBasename(basename: string | undefined): string {\r\n if (!basename || basename === \"/\") return \"/\";\r\n return basename.startsWith(\"/\") ? basename.replace(/\\/+$/, \"\") : \"/\";\r\n}\r\n\r\nfunction stripBasename(pathname: string): string {\r\n const basename = normalizeBasename(window.__reactRouterContext?.basename);\r\n if (basename === \"/\") return pathname;\r\n if (pathname === basename) return \"/\";\r\n if (pathname.startsWith(`${basename}/`)) {\r\n return pathname.slice(basename.length) || \"/\";\r\n }\r\n return pathname;\r\n}\r\n\r\nfunction isFrameworkOrApiPath(pathname: string): boolean {\r\n const appPath = stripBasename(pathname);\r\n return (\r\n appPath === \"/_agent-native\" ||\r\n appPath.startsWith(\"/_agent-native/\") ||\r\n appPath === \"/api\" ||\r\n appPath.startsWith(\"/api/\")\r\n );\r\n}\r\n\r\nfunction hrefUrl(href: string): URL | null {\r\n try {\r\n return new URL(href, window.location.href);\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nfunction isWarmableRouteUrl(url: URL): boolean {\r\n if (url.origin !== window.location.origin) return false;\r\n if (url.pathname === window.location.pathname && url.hash) return false;\r\n if (isFrameworkOrApiPath(url.pathname)) return false;\r\n if (/\\.\\w+$/.test(url.pathname)) return false;\r\n return true;\r\n}\r\n\r\nfunction isWarmableAnchor(link: HTMLAnchorElement): boolean {\r\n if (link.hasAttribute(\"download\")) return false;\r\n if (link.target && link.target !== \"_self\") return false;\r\n const url = hrefUrl(link.href);\r\n return url ? isWarmableRouteUrl(url) : false;\r\n}\r\n\r\nfunction dataRouteUrlForHref(href: string): string | null {\r\n const url = hrefUrl(href);\r\n if (!url || !isWarmableRouteUrl(url)) return null;\r\n\r\n const pathname = url.pathname.replace(/\\/+$/, \"\") || \"/\";\r\n if (pathname === \"/\") return null;\r\n url.pathname = `${pathname}.data`;\r\n url.hash = \"\";\r\n return url.href;\r\n}\r\n\r\nfunction hasReactRouterManifestRoutes(): boolean {\r\n const routes = window.__reactRouterManifest?.routes;\r\n return Boolean(routes && Object.keys(routes).length > 0);\r\n}\r\n\r\nfunction manifestRoutesSignature(\r\n routes: Record<string, ReactRouterManifestRoute> | undefined,\r\n): string {\r\n return Object.values(routes ?? {})\r\n .map((route) =>\r\n [\r\n route.id,\r\n route.parentId ?? \"\",\r\n route.path ?? \"\",\r\n route.index ? \"1\" : \"0\",\r\n ].join(\"\\0\"),\r\n )\r\n .sort()\r\n .join(\"\\n\");\r\n}\r\n\r\nfunction getManifestRouteTree(\r\n manifest: ReactRouterManifest,\r\n): WarmupRouteObject[] {\r\n const routesSignature = manifestRoutesSignature(manifest.routes);\r\n if (\r\n manifest === cachedManifest &&\r\n routesSignature === cachedManifestRoutesSignature\r\n ) {\r\n return cachedManifestRouteTree;\r\n }\r\n\r\n const manifestRoutes = Object.values(manifest.routes ?? {});\r\n const nodes = new Map<string, WarmupRouteObject>();\r\n for (const route of manifestRoutes) {\r\n nodes.set(route.id, {\r\n id: route.id,\r\n path: route.path,\r\n index: route.index || undefined,\r\n });\r\n }\r\n\r\n const tree: WarmupRouteObject[] = [];\r\n for (const route of manifestRoutes) {\r\n const node = nodes.get(route.id);\r\n if (!node) continue;\r\n const parent = route.parentId ? nodes.get(route.parentId) : null;\r\n if (parent) {\r\n parent.children ??= [];\r\n parent.children.push(node);\r\n } else {\r\n tree.push(node);\r\n }\r\n }\r\n\r\n cachedManifest = manifest;\r\n cachedManifestRoutesSignature = routesSignature;\r\n cachedManifestRouteTree = tree;\r\n return tree;\r\n}\r\n\r\nfunction assetUrlForManifestPath(assetPath: string): string | null {\r\n try {\r\n const url = new URL(assetPath, window.location.origin);\r\n if (url.origin !== window.location.origin) return null;\r\n // The framework package is often consumed from prebuilt core dist, where\r\n // Vite does not replace `import.meta.env` in this module. Use the React\r\n // Router manifest itself to distinguish production client assets from dev\r\n // source module ids. Production manifests point at immutable Vite chunks;\r\n // dev manifests point at raw TS/TSX modules that should not be warmed.\r\n if (!/\\/assets\\/[^/?#]+\\.m?js$/.test(url.pathname)) return null;\r\n return url.href;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nfunction hasWarmableRouteAssets(): boolean {\r\n for (const route of Object.values(\r\n window.__reactRouterManifest?.routes ?? {},\r\n )) {\r\n for (const assetPath of [\r\n route.module,\r\n route.clientActionModule,\r\n route.clientLoaderModule,\r\n route.hydrateFallbackModule,\r\n ...(route.imports ?? []),\r\n ]) {\r\n if (assetPath && assetUrlForManifestPath(assetPath)) return true;\r\n }\r\n }\r\n return false;\r\n}\r\n\r\nfunction routeAssetUrlsForHref(href: string): string[] {\r\n const manifest = window.__reactRouterManifest;\r\n if (!manifest?.routes) return [];\r\n\r\n const url = hrefUrl(href);\r\n if (!url || !isWarmableRouteUrl(url)) return [];\r\n\r\n const basename = normalizeBasename(window.__reactRouterContext?.basename);\r\n const matches =\r\n matchRoutes(\r\n getManifestRouteTree(manifest) as unknown as RouteObject[],\r\n url.pathname,\r\n basename,\r\n ) ?? [];\r\n const assetUrls: string[] = [];\r\n\r\n for (const match of matches) {\r\n const routeId = match.route.id;\r\n if (!routeId) continue;\r\n const route = manifest.routes[routeId];\r\n if (!route) continue;\r\n for (const assetPath of [\r\n route.module,\r\n route.clientActionModule,\r\n route.clientLoaderModule,\r\n route.hydrateFallbackModule,\r\n ...(route.imports ?? []),\r\n ]) {\r\n if (!assetPath) continue;\r\n const assetUrl = assetUrlForManifestPath(assetPath);\r\n if (assetUrl) assetUrls.push(assetUrl);\r\n }\r\n }\r\n\r\n return assetUrls;\r\n}\r\n\r\nfunction seedExistingModulepreloads() {\r\n for (const link of document.querySelectorAll<HTMLLinkElement>(\r\n 'link[rel=\"modulepreload\"][href]',\r\n )) {\r\n warmedRouteAssets.add(link.href);\r\n }\r\n}\r\n\r\nfunction warmRouteAssetsForHref(href: string) {\r\n for (const assetUrl of routeAssetUrlsForHref(href)) {\r\n if (warmedRouteAssets.has(assetUrl)) continue;\r\n warmedRouteAssets.add(assetUrl);\r\n\r\n const link = document.createElement(\"link\");\r\n link.rel = \"modulepreload\";\r\n link.href = assetUrl;\r\n document.head.appendChild(link);\r\n }\r\n}\r\n\r\nfunction linkWarmupMode(\r\n link: HTMLAnchorElement,\r\n strategy: AgentNativeRouteWarmupStrategy,\r\n): LinkWarmupMode | \"none\" {\r\n const explicit = link.getAttribute(PREFETCH_ATTR)?.trim().toLowerCase();\r\n if (explicit === \"none\" || explicit === \"off\" || explicit === \"false\") {\r\n return \"none\";\r\n }\r\n if (\r\n explicit === \"render\" ||\r\n explicit === \"intent\" ||\r\n explicit === \"viewport\"\r\n ) {\r\n return explicit;\r\n }\r\n if (strategy === \"off\" || strategy === \"marked\") return \"none\";\r\n return strategy;\r\n}\r\n\r\nfunction selectorWarmupMode(link: HTMLAnchorElement): \"render\" | \"none\" {\r\n const explicit = link.getAttribute(PREFETCH_ATTR)?.trim().toLowerCase();\r\n return explicit === \"none\" || explicit === \"off\" || explicit === \"false\"\r\n ? \"none\"\r\n : \"render\";\r\n}\r\n\r\nfunction renderWarmupLinksForSelector(selector: string): HTMLAnchorElement[] {\r\n let elements: Element[];\r\n try {\r\n elements = Array.from(document.querySelectorAll(selector));\r\n } catch {\r\n return [];\r\n }\r\n\r\n const links: HTMLAnchorElement[] = [];\r\n const seen = new Set<HTMLAnchorElement>();\r\n for (const element of elements) {\r\n const link =\r\n element instanceof HTMLAnchorElement\r\n ? element\r\n : (element.querySelector<HTMLAnchorElement>(\"a[href]\") ??\r\n element.closest<HTMLAnchorElement>(\"a[href]\"));\r\n if (!link || seen.has(link)) continue;\r\n seen.add(link);\r\n links.push(link);\r\n }\r\n return links;\r\n}\r\n\r\nfunction resetRouteWarmupCachesForTests() {\r\n cachedManifest = undefined;\r\n cachedManifestRoutesSignature = \"\";\r\n cachedManifestRouteTree = [];\r\n warmedDataRoutes.clear();\r\n warmedRouteAssets.clear();\r\n}\r\n\r\n/**\r\n * Warms React Router route data and matched route JS without using native link\r\n * prefetch. React Router's built-in `<Link prefetch>` does both pieces, but\r\n * its data side emits `<link rel=\"prefetch\" as=\"fetch\">`; Chrome sends\r\n * `Sec-Purpose: prefetch` for that request and Cloudflare Speed Brain can 503\r\n * dynamic `.data` routes before the CDN/origin can serve the cacheable result.\r\n *\r\n * Keep `.data` warmup as ordinary `fetch()` and JS warmup as `modulepreload`\r\n * unless production providers stop rejecting `Sec-Purpose: prefetch`.\r\n */\r\nexport function AgentNativeRouteWarmup({\r\n config,\r\n}: AgentNativeRouteWarmupProps) {\r\n useEffect(() => {\r\n const resolved = getRouteWarmupConfig(config);\r\n if (resolved.strategy === \"off\") {\r\n return;\r\n }\r\n // Legacy SPA builds still mount the AgentPanel but do not expose React\r\n // Router framework `.data` endpoints or a route asset manifest. Only warm\r\n // route data/modules when that manifest is present; otherwise this would\r\n // generate noisy `/<path>.data` 404s for apps that cannot serve them.\r\n const hasManifestRoutes = hasReactRouterManifestRoutes();\r\n // Vite dev manifests contain raw source module ids. Warming those with\r\n // modulepreload can route through React Router's dev SSR loader and make\r\n // local servers log false-positive internal errors. Keep route warmup to\r\n // manifests that point at built JS assets, where SSR `.data` requests have\r\n // the CDN cache headers this feature relies on.\r\n const hasRouteAssets = hasManifestRoutes && hasWarmableRouteAssets();\r\n const warmData = resolved.data && hasRouteAssets;\r\n const warmModules = resolved.modules && hasRouteAssets;\r\n if (!warmData && !warmModules) return;\r\n\r\n const connection = (\r\n navigator as Navigator & { connection?: { saveData?: boolean } }\r\n ).connection;\r\n if (connection?.saveData) return;\r\n\r\n if (warmModules) seedExistingModulepreloads();\r\n\r\n const queue: string[] = [];\r\n const queuedDataRoutes = new Set<string>();\r\n const observedLinks = new WeakSet<HTMLAnchorElement>();\r\n let active = 0;\r\n let stopped = false;\r\n let scheduleTimer: number | undefined;\r\n\r\n const pump = () => {\r\n if (stopped || !warmData) return;\r\n while (active < resolved.maxConcurrent && queue.length > 0) {\r\n const href = queue.shift();\r\n if (!href) continue;\r\n active += 1;\r\n window\r\n .fetch(href, { credentials: \"same-origin\", cache: \"force-cache\" })\r\n .catch(() => {})\r\n .finally(() => {\r\n active -= 1;\r\n window.setTimeout(pump, 50);\r\n });\r\n }\r\n };\r\n\r\n const warmHref = (href: string) => {\r\n if (warmModules) warmRouteAssetsForHref(href);\r\n if (!warmData) return;\r\n const dataUrl = dataRouteUrlForHref(href);\r\n if (!dataUrl || warmedDataRoutes.has(dataUrl)) return;\r\n warmedDataRoutes.add(dataUrl);\r\n if (queuedDataRoutes.has(dataUrl)) return;\r\n queuedDataRoutes.add(dataUrl);\r\n queue.push(dataUrl);\r\n pump();\r\n };\r\n\r\n const viewportObserver =\r\n typeof IntersectionObserver === \"undefined\"\r\n ? null\r\n : new IntersectionObserver((entries) => {\r\n for (const entry of entries) {\r\n if (!entry.isIntersecting) continue;\r\n const link = entry.target as HTMLAnchorElement;\r\n viewportObserver?.unobserve(link);\r\n warmHref(link.href);\r\n }\r\n });\r\n\r\n const scan = () => {\r\n if (warmModules) seedExistingModulepreloads();\r\n\r\n for (const link of renderWarmupLinksForSelector(resolved.selector)) {\r\n if (!isWarmableAnchor(link)) continue;\r\n const mode = selectorWarmupMode(link);\r\n if (mode === \"none\") continue;\r\n warmHref(link.href);\r\n }\r\n\r\n for (const link of document.querySelectorAll<HTMLAnchorElement>(\r\n \"a[href]\",\r\n )) {\r\n if (!isWarmableAnchor(link)) continue;\r\n const mode = linkWarmupMode(link, resolved.strategy);\r\n if (mode === \"none\") continue;\r\n if (mode === \"render\") {\r\n warmHref(link.href);\r\n continue;\r\n }\r\n if (mode === \"viewport\") {\r\n if (!viewportObserver) {\r\n warmHref(link.href);\r\n } else if (!observedLinks.has(link)) {\r\n observedLinks.add(link);\r\n viewportObserver.observe(link);\r\n }\r\n }\r\n }\r\n };\r\n\r\n const schedule = () => {\r\n if (scheduleTimer !== undefined) window.clearTimeout(scheduleTimer);\r\n scheduleTimer = window.setTimeout(() => {\r\n scheduleTimer = undefined;\r\n scan();\r\n }, 0);\r\n };\r\n\r\n const warmFromIntent = (event: Event) => {\r\n const target = event.target;\r\n if (!(target instanceof Element)) return;\r\n const link = target.closest<HTMLAnchorElement>(\"a[href]\");\r\n if (!link || !isWarmableAnchor(link)) return;\r\n const mode = linkWarmupMode(link, resolved.strategy);\r\n if (mode === \"none\") return;\r\n warmHref(link.href);\r\n };\r\n\r\n schedule();\r\n const observer = new MutationObserver(schedule);\r\n // The render-warmup selector is configurable, so it may depend on class or\r\n // custom data attributes. Watch all attribute changes and debounce rescans.\r\n observer.observe(document.documentElement, {\r\n subtree: true,\r\n childList: true,\r\n attributes: true,\r\n });\r\n\r\n document.addEventListener(\"pointerover\", warmFromIntent, {\r\n capture: true,\r\n passive: true,\r\n });\r\n document.addEventListener(\"touchstart\", warmFromIntent, {\r\n capture: true,\r\n passive: true,\r\n });\r\n document.addEventListener(\"focusin\", warmFromIntent, true);\r\n\r\n return () => {\r\n stopped = true;\r\n if (scheduleTimer !== undefined) window.clearTimeout(scheduleTimer);\r\n observer.disconnect();\r\n viewportObserver?.disconnect();\r\n document.removeEventListener(\"pointerover\", warmFromIntent, true);\r\n document.removeEventListener(\"touchstart\", warmFromIntent, true);\r\n document.removeEventListener(\"focusin\", warmFromIntent, true);\r\n };\r\n }, [config]);\r\n\r\n return null;\r\n}\r\n\r\nexport const __routeWarmupInternalsForTests = {\r\n getManifestRouteTree,\r\n hasReactRouterManifestRoutes,\r\n hasWarmableRouteAssets,\r\n parseBuildTimeRouteWarmupConfig,\r\n renderWarmupLinksForSelector,\r\n routeAssetUrlsForHref,\r\n resetRouteWarmupCachesForTests,\r\n};\r\n"]}
|
|
1
|
+
{"version":3,"file":"route-warmup.js","sourceRoot":"","sources":["../../src/client/route-warmup.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect } from \"react\";\nimport { matchRoutes, type RouteObject } from \"react-router\";\n\nimport {\n mergeAgentNativeRouteWarmupConfig,\n type AgentNativeRouteWarmupConfigInput,\n type AgentNativeRouteWarmupResolvedConfig,\n type AgentNativeRouteWarmupStrategy,\n} from \"../shared/route-warmup-config.js\";\n\ndeclare const __AGENT_NATIVE_ROUTE_WARMUP_CONFIG__:\n | AgentNativeRouteWarmupConfigInput\n | string\n | undefined;\n\ntype ReactRouterManifestRoute = {\n id: string;\n parentId?: string;\n path?: string;\n index?: boolean;\n module?: string;\n hasLoader?: boolean;\n hasAction?: boolean;\n clientActionModule?: string;\n clientLoaderModule?: string;\n hydrateFallbackModule?: string;\n imports?: string[];\n};\n\ntype ReactRouterManifest = {\n routes?: Record<string, ReactRouterManifestRoute>;\n};\n\ntype WarmupRouteObject = {\n id: string;\n path?: string;\n index?: boolean;\n children?: WarmupRouteObject[];\n};\n\ntype LinkWarmupMode = Exclude<AgentNativeRouteWarmupStrategy, \"off\" | \"marked\">;\n\ndeclare global {\n interface Window {\n __reactRouterContext?: { basename?: string };\n __reactRouterManifest?: ReactRouterManifest;\n }\n}\n\nconst PREFETCH_ATTR = \"data-an-prefetch\";\nconst warmedDataRoutes = new Set<string>();\nconst warmedRouteAssets = new Set<string>();\n\nlet cachedManifest: ReactRouterManifest | undefined;\nlet cachedManifestRoutesSignature = \"\";\nlet cachedManifestRouteTree: WarmupRouteObject[] = [];\n\nexport interface AgentNativeRouteWarmupProps {\n config?: AgentNativeRouteWarmupConfigInput;\n}\n\nfunction parseBuildTimeRouteWarmupConfig(\n raw: AgentNativeRouteWarmupConfigInput | string | undefined,\n): AgentNativeRouteWarmupConfigInput | undefined {\n if (typeof raw !== \"string\") return raw;\n const trimmed = raw.trim();\n if (!trimmed) return undefined;\n try {\n return JSON.parse(trimmed) as AgentNativeRouteWarmupConfigInput;\n } catch {\n // Some test/build paths may inject a bare strategy string instead of JSON.\n return raw as AgentNativeRouteWarmupConfigInput;\n }\n}\n\nfunction getBuildTimeRouteWarmupConfig():\n | AgentNativeRouteWarmupConfigInput\n | undefined {\n try {\n if (typeof __AGENT_NATIVE_ROUTE_WARMUP_CONFIG__ !== \"undefined\") {\n return parseBuildTimeRouteWarmupConfig(\n __AGENT_NATIVE_ROUTE_WARMUP_CONFIG__,\n );\n }\n } catch {\n // Some non-Vite test/runtime paths do not define the global.\n }\n return undefined;\n}\n\nfunction getRouteWarmupConfig(\n config: AgentNativeRouteWarmupConfigInput | undefined,\n): AgentNativeRouteWarmupResolvedConfig {\n return mergeAgentNativeRouteWarmupConfig(\n getBuildTimeRouteWarmupConfig(),\n config,\n );\n}\n\nfunction normalizeBasename(basename: string | undefined): string {\n if (!basename || basename === \"/\") return \"/\";\n return basename.startsWith(\"/\") ? basename.replace(/\\/+$/, \"\") : \"/\";\n}\n\nfunction stripBasename(pathname: string): string {\n const basename = normalizeBasename(window.__reactRouterContext?.basename);\n if (basename === \"/\") return pathname;\n if (pathname === basename) return \"/\";\n if (pathname.startsWith(`${basename}/`)) {\n return pathname.slice(basename.length) || \"/\";\n }\n return pathname;\n}\n\nfunction isFrameworkOrApiPath(pathname: string): boolean {\n const appPath = stripBasename(pathname);\n return (\n appPath === \"/_agent-native\" ||\n appPath.startsWith(\"/_agent-native/\") ||\n appPath === \"/api\" ||\n appPath.startsWith(\"/api/\")\n );\n}\n\nfunction hrefUrl(href: string): URL | null {\n try {\n return new URL(href, window.location.href);\n } catch {\n return null;\n }\n}\n\nfunction isWarmableRouteUrl(url: URL): boolean {\n if (url.origin !== window.location.origin) return false;\n if (url.pathname === window.location.pathname && url.hash) return false;\n if (isFrameworkOrApiPath(url.pathname)) return false;\n if (/\\.\\w+$/.test(url.pathname)) return false;\n return true;\n}\n\nfunction isWarmableAnchor(link: HTMLAnchorElement): boolean {\n if (link.hasAttribute(\"download\")) return false;\n if (link.target && link.target !== \"_self\") return false;\n const url = hrefUrl(link.href);\n return url ? isWarmableRouteUrl(url) : false;\n}\n\nfunction dataRouteUrlForHref(href: string): string | null {\n const url = hrefUrl(href);\n if (!url || !isWarmableRouteUrl(url)) return null;\n\n const pathname = url.pathname.replace(/\\/+$/, \"\") || \"/\";\n if (pathname === \"/\") return null;\n url.pathname = `${pathname}.data`;\n url.hash = \"\";\n return url.href;\n}\n\nfunction hasReactRouterManifestRoutes(): boolean {\n const routes = window.__reactRouterManifest?.routes;\n return Boolean(routes && Object.keys(routes).length > 0);\n}\n\n/**\n * Whether ANY route in the client manifest advertises a server loader or\n * action. Static-shell deployments (Cloudflare Pages worker without a React\n * Router request handler) strip these flags at build time — `.data` requests\n * can never be served there, so warming them only produces 404 noise.\n */\nfunction manifestAdvertisesServerData(): boolean {\n for (const route of Object.values(\n window.__reactRouterManifest?.routes ?? {},\n )) {\n if (route.hasLoader || route.hasAction) return true;\n }\n return false;\n}\n\nfunction manifestRoutesSignature(\n routes: Record<string, ReactRouterManifestRoute> | undefined,\n): string {\n return Object.values(routes ?? {})\n .map((route) =>\n [\n route.id,\n route.parentId ?? \"\",\n route.path ?? \"\",\n route.index ? \"1\" : \"0\",\n ].join(\"\\0\"),\n )\n .sort()\n .join(\"\\n\");\n}\n\nfunction getManifestRouteTree(\n manifest: ReactRouterManifest,\n): WarmupRouteObject[] {\n const routesSignature = manifestRoutesSignature(manifest.routes);\n if (\n manifest === cachedManifest &&\n routesSignature === cachedManifestRoutesSignature\n ) {\n return cachedManifestRouteTree;\n }\n\n const manifestRoutes = Object.values(manifest.routes ?? {});\n const nodes = new Map<string, WarmupRouteObject>();\n for (const route of manifestRoutes) {\n nodes.set(route.id, {\n id: route.id,\n path: route.path,\n index: route.index || undefined,\n });\n }\n\n const tree: WarmupRouteObject[] = [];\n for (const route of manifestRoutes) {\n const node = nodes.get(route.id);\n if (!node) continue;\n const parent = route.parentId ? nodes.get(route.parentId) : null;\n if (parent) {\n parent.children ??= [];\n parent.children.push(node);\n } else {\n tree.push(node);\n }\n }\n\n cachedManifest = manifest;\n cachedManifestRoutesSignature = routesSignature;\n cachedManifestRouteTree = tree;\n return tree;\n}\n\nfunction assetUrlForManifestPath(assetPath: string): string | null {\n try {\n const url = new URL(assetPath, window.location.origin);\n if (url.origin !== window.location.origin) return null;\n // The framework package is often consumed from prebuilt core dist, where\n // Vite does not replace `import.meta.env` in this module. Use the React\n // Router manifest itself to distinguish production client assets from dev\n // source module ids. Production manifests point at immutable Vite chunks;\n // dev manifests point at raw TS/TSX modules that should not be warmed.\n if (!/\\/assets\\/[^/?#]+\\.m?js$/.test(url.pathname)) return null;\n return url.href;\n } catch {\n return null;\n }\n}\n\nfunction hasWarmableRouteAssets(): boolean {\n for (const route of Object.values(\n window.__reactRouterManifest?.routes ?? {},\n )) {\n for (const assetPath of [\n route.module,\n route.clientActionModule,\n route.clientLoaderModule,\n route.hydrateFallbackModule,\n ...(route.imports ?? []),\n ]) {\n if (assetPath && assetUrlForManifestPath(assetPath)) return true;\n }\n }\n return false;\n}\n\nfunction routeAssetUrlsForHref(href: string): string[] {\n const manifest = window.__reactRouterManifest;\n if (!manifest?.routes) return [];\n\n const url = hrefUrl(href);\n if (!url || !isWarmableRouteUrl(url)) return [];\n\n const basename = normalizeBasename(window.__reactRouterContext?.basename);\n const matches =\n matchRoutes(\n getManifestRouteTree(manifest) as unknown as RouteObject[],\n url.pathname,\n basename,\n ) ?? [];\n const assetUrls: string[] = [];\n\n for (const match of matches) {\n const routeId = match.route.id;\n if (!routeId) continue;\n const route = manifest.routes[routeId];\n if (!route) continue;\n for (const assetPath of [\n route.module,\n route.clientActionModule,\n route.clientLoaderModule,\n route.hydrateFallbackModule,\n ...(route.imports ?? []),\n ]) {\n if (!assetPath) continue;\n const assetUrl = assetUrlForManifestPath(assetPath);\n if (assetUrl) assetUrls.push(assetUrl);\n }\n }\n\n return assetUrls;\n}\n\nfunction seedExistingModulepreloads() {\n for (const link of document.querySelectorAll<HTMLLinkElement>(\n 'link[rel=\"modulepreload\"][href]',\n )) {\n warmedRouteAssets.add(link.href);\n }\n}\n\nfunction warmRouteAssetsForHref(href: string) {\n for (const assetUrl of routeAssetUrlsForHref(href)) {\n if (warmedRouteAssets.has(assetUrl)) continue;\n warmedRouteAssets.add(assetUrl);\n\n const link = document.createElement(\"link\");\n link.rel = \"modulepreload\";\n link.href = assetUrl;\n document.head.appendChild(link);\n }\n}\n\nfunction linkWarmupMode(\n link: HTMLAnchorElement,\n strategy: AgentNativeRouteWarmupStrategy,\n): LinkWarmupMode | \"none\" {\n const explicit = link.getAttribute(PREFETCH_ATTR)?.trim().toLowerCase();\n if (explicit === \"none\" || explicit === \"off\" || explicit === \"false\") {\n return \"none\";\n }\n if (\n explicit === \"render\" ||\n explicit === \"intent\" ||\n explicit === \"viewport\"\n ) {\n return explicit;\n }\n if (strategy === \"off\" || strategy === \"marked\") return \"none\";\n return strategy;\n}\n\nfunction selectorWarmupMode(link: HTMLAnchorElement): \"render\" | \"none\" {\n const explicit = link.getAttribute(PREFETCH_ATTR)?.trim().toLowerCase();\n return explicit === \"none\" || explicit === \"off\" || explicit === \"false\"\n ? \"none\"\n : \"render\";\n}\n\nfunction renderWarmupLinksForSelector(selector: string): HTMLAnchorElement[] {\n let elements: Element[];\n try {\n elements = Array.from(document.querySelectorAll(selector));\n } catch {\n return [];\n }\n\n const links: HTMLAnchorElement[] = [];\n const seen = new Set<HTMLAnchorElement>();\n for (const element of elements) {\n const link =\n element instanceof HTMLAnchorElement\n ? element\n : (element.querySelector<HTMLAnchorElement>(\"a[href]\") ??\n element.closest<HTMLAnchorElement>(\"a[href]\"));\n if (!link || seen.has(link)) continue;\n seen.add(link);\n links.push(link);\n }\n return links;\n}\n\nfunction resetRouteWarmupCachesForTests() {\n cachedManifest = undefined;\n cachedManifestRoutesSignature = \"\";\n cachedManifestRouteTree = [];\n warmedDataRoutes.clear();\n warmedRouteAssets.clear();\n}\n\n/**\n * Warms React Router route data and matched route JS without using native link\n * prefetch. React Router's built-in `<Link prefetch>` does both pieces, but\n * its data side emits `<link rel=\"prefetch\" as=\"fetch\">`; Chrome sends\n * `Sec-Purpose: prefetch` for that request and Cloudflare Speed Brain can 503\n * dynamic `.data` routes before the CDN/origin can serve the cacheable result.\n *\n * Keep `.data` warmup as ordinary `fetch()` and JS warmup as `modulepreload`\n * unless production providers stop rejecting `Sec-Purpose: prefetch`.\n */\nexport function AgentNativeRouteWarmup({\n config,\n}: AgentNativeRouteWarmupProps) {\n useEffect(() => {\n const resolved = getRouteWarmupConfig(config);\n if (resolved.strategy === \"off\") {\n return;\n }\n // Legacy SPA builds still mount the AgentPanel but do not expose React\n // Router framework `.data` endpoints or a route asset manifest. Only warm\n // route data/modules when that manifest is present; otherwise this would\n // generate noisy `/<path>.data` 404s for apps that cannot serve them.\n const hasManifestRoutes = hasReactRouterManifestRoutes();\n // Vite dev manifests contain raw source module ids. Warming those with\n // modulepreload can route through React Router's dev SSR loader and make\n // local servers log false-positive internal errors. Keep route warmup to\n // manifests that point at built JS assets, where SSR `.data` requests have\n // the CDN cache headers this feature relies on.\n const hasRouteAssets = hasManifestRoutes && hasWarmableRouteAssets();\n // `.data` warmup only makes sense when the deployment can actually serve\n // React Router single-fetch requests — static-shell workers strip the\n // hasLoader/hasAction flags, and warming there guarantees a 404 per link.\n const warmData =\n resolved.data && hasRouteAssets && manifestAdvertisesServerData();\n const warmModules = resolved.modules && hasRouteAssets;\n if (!warmData && !warmModules) return;\n\n const connection = (\n navigator as Navigator & { connection?: { saveData?: boolean } }\n ).connection;\n if (connection?.saveData) return;\n\n if (warmModules) seedExistingModulepreloads();\n\n const queue: string[] = [];\n const queuedDataRoutes = new Set<string>();\n const observedLinks = new WeakSet<HTMLAnchorElement>();\n let active = 0;\n let stopped = false;\n let scheduleTimer: number | undefined;\n\n const pump = () => {\n if (stopped || !warmData) return;\n while (active < resolved.maxConcurrent && queue.length > 0) {\n const href = queue.shift();\n if (!href) continue;\n active += 1;\n window\n .fetch(href, { credentials: \"same-origin\", cache: \"force-cache\" })\n .catch(() => {})\n .finally(() => {\n active -= 1;\n window.setTimeout(pump, 50);\n });\n }\n };\n\n const warmHref = (href: string) => {\n if (warmModules) warmRouteAssetsForHref(href);\n if (!warmData) return;\n const dataUrl = dataRouteUrlForHref(href);\n if (!dataUrl || warmedDataRoutes.has(dataUrl)) return;\n warmedDataRoutes.add(dataUrl);\n if (queuedDataRoutes.has(dataUrl)) return;\n queuedDataRoutes.add(dataUrl);\n queue.push(dataUrl);\n pump();\n };\n\n const viewportObserver =\n typeof IntersectionObserver === \"undefined\"\n ? null\n : new IntersectionObserver((entries) => {\n for (const entry of entries) {\n if (!entry.isIntersecting) continue;\n const link = entry.target as HTMLAnchorElement;\n viewportObserver?.unobserve(link);\n warmHref(link.href);\n }\n });\n\n const scan = () => {\n if (warmModules) seedExistingModulepreloads();\n\n for (const link of renderWarmupLinksForSelector(resolved.selector)) {\n if (!isWarmableAnchor(link)) continue;\n const mode = selectorWarmupMode(link);\n if (mode === \"none\") continue;\n warmHref(link.href);\n }\n\n for (const link of document.querySelectorAll<HTMLAnchorElement>(\n \"a[href]\",\n )) {\n if (!isWarmableAnchor(link)) continue;\n const mode = linkWarmupMode(link, resolved.strategy);\n if (mode === \"none\") continue;\n if (mode === \"render\") {\n warmHref(link.href);\n continue;\n }\n if (mode === \"viewport\") {\n if (!viewportObserver) {\n warmHref(link.href);\n } else if (!observedLinks.has(link)) {\n observedLinks.add(link);\n viewportObserver.observe(link);\n }\n }\n }\n };\n\n const schedule = () => {\n if (scheduleTimer !== undefined) window.clearTimeout(scheduleTimer);\n scheduleTimer = window.setTimeout(() => {\n scheduleTimer = undefined;\n scan();\n }, 0);\n };\n\n const warmFromIntent = (event: Event) => {\n const target = event.target;\n if (!(target instanceof Element)) return;\n const link = target.closest<HTMLAnchorElement>(\"a[href]\");\n if (!link || !isWarmableAnchor(link)) return;\n const mode = linkWarmupMode(link, resolved.strategy);\n if (mode === \"none\") return;\n warmHref(link.href);\n };\n\n schedule();\n const observer = new MutationObserver(schedule);\n // The render-warmup selector is configurable, so it may depend on class or\n // custom data attributes. Watch all attribute changes and debounce rescans.\n observer.observe(document.documentElement, {\n subtree: true,\n childList: true,\n attributes: true,\n });\n\n document.addEventListener(\"pointerover\", warmFromIntent, {\n capture: true,\n passive: true,\n });\n document.addEventListener(\"touchstart\", warmFromIntent, {\n capture: true,\n passive: true,\n });\n document.addEventListener(\"focusin\", warmFromIntent, true);\n\n return () => {\n stopped = true;\n if (scheduleTimer !== undefined) window.clearTimeout(scheduleTimer);\n observer.disconnect();\n viewportObserver?.disconnect();\n document.removeEventListener(\"pointerover\", warmFromIntent, true);\n document.removeEventListener(\"touchstart\", warmFromIntent, true);\n document.removeEventListener(\"focusin\", warmFromIntent, true);\n };\n }, [config]);\n\n return null;\n}\n\nexport const __routeWarmupInternalsForTests = {\n getManifestRouteTree,\n hasReactRouterManifestRoutes,\n hasWarmableRouteAssets,\n manifestAdvertisesServerData,\n parseBuildTimeRouteWarmupConfig,\n renderWarmupLinksForSelector,\n routeAssetUrlsForHref,\n resetRouteWarmupCachesForTests,\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"param.d.ts","sourceRoot":"","sources":["../../src/collab/param.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAElC,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAStE"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Router-param helper for collab routes.
|
|
3
|
+
*
|
|
4
|
+
* Collab docIds are structured (`plan:<id>:<block>`) and go into the URL
|
|
5
|
+
* path. Well-behaved HTTP clients percent-encode path segments
|
|
6
|
+
* (`encodeURIComponent(docId)` → `plan%3A...`), but h3 router params are NOT
|
|
7
|
+
* decoded by default — resolvers then see the encoded form, prefix checks
|
|
8
|
+
* (`docId.startsWith("plan:")`) fail, and the request 404s even though the
|
|
9
|
+
* raw-colon form works. Decode the param, tolerating docIds that contain a
|
|
10
|
+
* literal `%` (malformed escape sequences fall back to the raw value).
|
|
11
|
+
*/
|
|
12
|
+
import { getRouterParam } from "h3";
|
|
13
|
+
export function getCollabDocIdParam(event) {
|
|
14
|
+
const raw = getRouterParam(event, "docId");
|
|
15
|
+
if (!raw)
|
|
16
|
+
return raw ?? undefined;
|
|
17
|
+
if (!raw.includes("%"))
|
|
18
|
+
return raw;
|
|
19
|
+
try {
|
|
20
|
+
return decodeURIComponent(raw);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return raw;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=param.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"param.js","sourceRoot":"","sources":["../../src/collab/param.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,IAAI,CAAC;AAGpC,MAAM,UAAU,mBAAmB,CAAC,KAAc;IAChD,MAAM,GAAG,GAAG,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC3C,IAAI,CAAC,GAAG;QAAE,OAAO,GAAG,IAAI,SAAS,CAAC;IAClC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC;IACnC,IAAI,CAAC;QACH,OAAO,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC;IACb,CAAC;AACH,CAAC","sourcesContent":["/**\n * Router-param helper for collab routes.\n *\n * Collab docIds are structured (`plan:<id>:<block>`) and go into the URL\n * path. Well-behaved HTTP clients percent-encode path segments\n * (`encodeURIComponent(docId)` → `plan%3A...`), but h3 router params are NOT\n * decoded by default — resolvers then see the encoded form, prefix checks\n * (`docId.startsWith(\"plan:\")`) fail, and the request 404s even though the\n * raw-colon form works. Decode the param, tolerating docIds that contain a\n * literal `%` (malformed escape sequences fall back to the raw value).\n */\nimport { getRouterParam } from \"h3\";\nimport type { H3Event } from \"h3\";\n\nexport function getCollabDocIdParam(event: H3Event): string | undefined {\n const raw = getRouterParam(event, \"docId\");\n if (!raw) return raw ?? undefined;\n if (!raw.includes(\"%\")) return raw;\n try {\n return decodeURIComponent(raw);\n } catch {\n return raw;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/collab/routes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/collab/routes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAgCH;;;;GAIG;AACH,eAAO,MAAM,cAAc;;;;;;;;GA4BzB,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB;;;;;;GAyB3B,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc;;;;;;;;GA8BzB,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;GAgCnC,CAAC"}
|
package/dist/collab/routes.js
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Mounted under /_agent-native/collab/ by the collab plugin.
|
|
5
5
|
*/
|
|
6
|
-
import { defineEventHandler, setResponseStatus,
|
|
6
|
+
import { defineEventHandler, setResponseStatus, getQuery } from "h3";
|
|
7
7
|
import { readBody } from "../server/h3-helpers.js";
|
|
8
|
+
import { getCollabDocIdParam } from "./param.js";
|
|
8
9
|
import { uint8ArrayToBase64, base64ToUint8Array } from "./storage.js";
|
|
9
10
|
import * as manager from "./ydoc-manager.js";
|
|
10
11
|
import { searchAndReplace as doSearchAndReplace } from "./ydoc-manager.js";
|
|
@@ -32,7 +33,7 @@ function enforcePayloadLimit(event, body) {
|
|
|
32
33
|
* Returns full Yjs document state as base64 for initial client load.
|
|
33
34
|
*/
|
|
34
35
|
export const getCollabState = defineEventHandler(async (event) => {
|
|
35
|
-
const docId =
|
|
36
|
+
const docId = getCollabDocIdParam(event);
|
|
36
37
|
if (!docId) {
|
|
37
38
|
setResponseStatus(event, 400);
|
|
38
39
|
return { error: "docId required" };
|
|
@@ -66,7 +67,7 @@ export const getCollabState = defineEventHandler(async (event) => {
|
|
|
66
67
|
* Body: { update: string (base64), requestSource?: string }
|
|
67
68
|
*/
|
|
68
69
|
export const postCollabUpdate = defineEventHandler(async (event) => {
|
|
69
|
-
const docId =
|
|
70
|
+
const docId = getCollabDocIdParam(event);
|
|
70
71
|
if (!docId) {
|
|
71
72
|
setResponseStatus(event, 400);
|
|
72
73
|
return { error: "docId required" };
|
|
@@ -93,7 +94,7 @@ export const postCollabUpdate = defineEventHandler(async (event) => {
|
|
|
93
94
|
* Body: { text: string, fieldName?: string, requestSource?: string }
|
|
94
95
|
*/
|
|
95
96
|
export const postCollabText = defineEventHandler(async (event) => {
|
|
96
|
-
const docId =
|
|
97
|
+
const docId = getCollabDocIdParam(event);
|
|
97
98
|
if (!docId) {
|
|
98
99
|
setResponseStatus(event, 400);
|
|
99
100
|
return { error: "docId required" };
|
|
@@ -119,7 +120,7 @@ export const postCollabText = defineEventHandler(async (event) => {
|
|
|
119
120
|
* Body: { find: string, replace: string, requestSource?: string }
|
|
120
121
|
*/
|
|
121
122
|
export const postCollabSearchReplace = defineEventHandler(async (event) => {
|
|
122
|
-
const docId =
|
|
123
|
+
const docId = getCollabDocIdParam(event);
|
|
123
124
|
if (!docId) {
|
|
124
125
|
setResponseStatus(event, 400);
|
|
125
126
|
return { error: "docId required" };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/collab/routes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * HTTP route handlers for collaborative editing.\r\n *\r\n * Mounted under /_agent-native/collab/ by the collab plugin.\r\n */\r\n\r\nimport {\r\n defineEventHandler,\r\n setResponseStatus,\r\n getRouterParam,\r\n getQuery,\r\n} from \"h3\";\r\nimport type { H3Event } from \"h3\";\r\n\r\nimport { readBody } from \"../server/h3-helpers.js\";\r\nimport { uint8ArrayToBase64, base64ToUint8Array } from \"./storage.js\";\r\nimport * as manager from \"./ydoc-manager.js\";\r\nimport { searchAndReplace as doSearchAndReplace } from \"./ydoc-manager.js\";\r\n\r\n/** Default maximum payload size (2 MB). Overridden by plugin via event.context. */\r\nconst DEFAULT_MAX_BYTES = 2 * 1024 * 1024;\r\n\r\nfunction getMaxPayloadBytes(event: H3Event): number {\r\n return (event.context as any)?._collabMaxPayloadBytes ?? DEFAULT_MAX_BYTES;\r\n}\r\n\r\n/**\r\n * Check the serialized body length against the configured limit.\r\n * Returns true if within limits; sets 413 status and returns false otherwise.\r\n */\r\nfunction enforcePayloadLimit(event: H3Event, body: unknown): boolean {\r\n const maxBytes = getMaxPayloadBytes(event);\r\n const encoded = typeof body === \"string\" ? body : JSON.stringify(body ?? \"\");\r\n if (encoded.length > maxBytes) {\r\n setResponseStatus(event, 413);\r\n return false;\r\n }\r\n return true;\r\n}\r\n\r\n/**\r\n * GET /_agent-native/collab/:docId/state\r\n *\r\n * Returns full Yjs document state as base64 for initial client load.\r\n */\r\nexport const getCollabState = defineEventHandler(async (event: H3Event) => {\r\n const docId = getRouterParam(event, \"docId\");\r\n if (!docId) {\r\n setResponseStatus(event, 400);\r\n return { error: \"docId required\" };\r\n }\r\n\r\n const query = getQuery(event);\r\n const encodedStateVector =\r\n typeof query.stateVector === \"string\" ? query.stateVector : null;\r\n let state: Uint8Array;\r\n if (encodedStateVector) {\r\n try {\r\n state = await manager.getIncUpdate(\r\n docId,\r\n base64ToUint8Array(encodedStateVector),\r\n );\r\n } catch {\r\n setResponseStatus(event, 400);\r\n return { error: \"stateVector must be base64-encoded\" };\r\n }\r\n } else {\r\n state = await manager.getState(docId);\r\n }\r\n return {\r\n docId,\r\n state: uint8ArrayToBase64(state),\r\n };\r\n});\r\n\r\n/**\r\n * POST /_agent-native/collab/:docId/update\r\n *\r\n * Client sends a Yjs update (base64). Server applies it, persists, and\r\n * emits a change event so other clients pick it up via polling.\r\n *\r\n * Body: { update: string (base64), requestSource?: string }\r\n */\r\nexport const postCollabUpdate = defineEventHandler(async (event: H3Event) => {\r\n const docId = getRouterParam(event, \"docId\");\r\n if (!docId) {\r\n setResponseStatus(event, 400);\r\n return { error: \"docId required\" };\r\n }\r\n\r\n const rawBody = await readBody(event);\r\n if (!enforcePayloadLimit(event, rawBody)) {\r\n return { error: \"Payload too large\" };\r\n }\r\n const { update, requestSource } = rawBody as {\r\n update?: string;\r\n requestSource?: string;\r\n };\r\n\r\n if (!update) {\r\n setResponseStatus(event, 400);\r\n return { error: \"update (base64) required\" };\r\n }\r\n\r\n const binary = base64ToUint8Array(update);\r\n await manager.applyUpdate(docId, binary, requestSource);\r\n\r\n return { ok: true };\r\n});\r\n\r\n/**\r\n * POST /_agent-native/collab/:docId/text\r\n *\r\n * Agent sends full text content. Server computes diff against current\r\n * Yjs state and applies minimal operations.\r\n *\r\n * Body: { text: string, fieldName?: string, requestSource?: string }\r\n */\r\nexport const postCollabText = defineEventHandler(async (event: H3Event) => {\r\n const docId = getRouterParam(event, \"docId\");\r\n if (!docId) {\r\n setResponseStatus(event, 400);\r\n return { error: \"docId required\" };\r\n }\r\n\r\n const rawBody = await readBody(event);\r\n if (!enforcePayloadLimit(event, rawBody)) {\r\n return { error: \"Payload too large\" };\r\n }\r\n const { text, fieldName, requestSource } = rawBody as {\r\n text?: string;\r\n fieldName?: string;\r\n requestSource?: string;\r\n };\r\n\r\n if (text === undefined) {\r\n setResponseStatus(event, 400);\r\n return { error: \"text required\" };\r\n }\r\n\r\n const result = await manager.applyText(\r\n docId,\r\n text,\r\n fieldName ?? \"content\",\r\n requestSource ?? \"agent\",\r\n );\r\n\r\n return { ok: true, text: result };\r\n});\r\n\r\n/**\r\n * POST /_agent-native/collab/:docId/search-replace\r\n *\r\n * Search-and-replace text in the Y.XmlFragment (ProseMirror tree).\r\n * Produces minimal Yjs operations for cursor-preserving updates.\r\n *\r\n * Body: { find: string, replace: string, requestSource?: string }\r\n */\r\nexport const postCollabSearchReplace = defineEventHandler(\r\n async (event: H3Event) => {\r\n const docId = getRouterParam(event, \"docId\");\r\n if (!docId) {\r\n setResponseStatus(event, 400);\r\n return { error: \"docId required\" };\r\n }\r\n\r\n const rawBody = await readBody(event);\r\n if (!enforcePayloadLimit(event, rawBody)) {\r\n return { error: \"Payload too large\" };\r\n }\r\n const { find, replace, requestSource } = rawBody as {\r\n find?: string;\r\n replace?: string;\r\n requestSource?: string;\r\n };\r\n\r\n if (!find) {\r\n setResponseStatus(event, 400);\r\n return { error: \"find required\" };\r\n }\r\n\r\n const result = await doSearchAndReplace(\r\n docId,\r\n find,\r\n replace ?? \"\",\r\n requestSource ?? \"agent\",\r\n );\r\n\r\n return { ok: true, found: result.found };\r\n },\r\n);\r\n"]}
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/collab/routes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * HTTP route handlers for collaborative editing.\n *\n * Mounted under /_agent-native/collab/ by the collab plugin.\n */\n\nimport { defineEventHandler, setResponseStatus, getQuery } from \"h3\";\nimport type { H3Event } from \"h3\";\n\nimport { readBody } from \"../server/h3-helpers.js\";\nimport { getCollabDocIdParam } from \"./param.js\";\nimport { uint8ArrayToBase64, base64ToUint8Array } from \"./storage.js\";\nimport * as manager from \"./ydoc-manager.js\";\nimport { searchAndReplace as doSearchAndReplace } from \"./ydoc-manager.js\";\n\n/** Default maximum payload size (2 MB). Overridden by plugin via event.context. */\nconst DEFAULT_MAX_BYTES = 2 * 1024 * 1024;\n\nfunction getMaxPayloadBytes(event: H3Event): number {\n return (event.context as any)?._collabMaxPayloadBytes ?? DEFAULT_MAX_BYTES;\n}\n\n/**\n * Check the serialized body length against the configured limit.\n * Returns true if within limits; sets 413 status and returns false otherwise.\n */\nfunction enforcePayloadLimit(event: H3Event, body: unknown): boolean {\n const maxBytes = getMaxPayloadBytes(event);\n const encoded = typeof body === \"string\" ? body : JSON.stringify(body ?? \"\");\n if (encoded.length > maxBytes) {\n setResponseStatus(event, 413);\n return false;\n }\n return true;\n}\n\n/**\n * GET /_agent-native/collab/:docId/state\n *\n * Returns full Yjs document state as base64 for initial client load.\n */\nexport const getCollabState = defineEventHandler(async (event: H3Event) => {\n const docId = getCollabDocIdParam(event);\n if (!docId) {\n setResponseStatus(event, 400);\n return { error: \"docId required\" };\n }\n\n const query = getQuery(event);\n const encodedStateVector =\n typeof query.stateVector === \"string\" ? query.stateVector : null;\n let state: Uint8Array;\n if (encodedStateVector) {\n try {\n state = await manager.getIncUpdate(\n docId,\n base64ToUint8Array(encodedStateVector),\n );\n } catch {\n setResponseStatus(event, 400);\n return { error: \"stateVector must be base64-encoded\" };\n }\n } else {\n state = await manager.getState(docId);\n }\n return {\n docId,\n state: uint8ArrayToBase64(state),\n };\n});\n\n/**\n * POST /_agent-native/collab/:docId/update\n *\n * Client sends a Yjs update (base64). Server applies it, persists, and\n * emits a change event so other clients pick it up via polling.\n *\n * Body: { update: string (base64), requestSource?: string }\n */\nexport const postCollabUpdate = defineEventHandler(async (event: H3Event) => {\n const docId = getCollabDocIdParam(event);\n if (!docId) {\n setResponseStatus(event, 400);\n return { error: \"docId required\" };\n }\n\n const rawBody = await readBody(event);\n if (!enforcePayloadLimit(event, rawBody)) {\n return { error: \"Payload too large\" };\n }\n const { update, requestSource } = rawBody as {\n update?: string;\n requestSource?: string;\n };\n\n if (!update) {\n setResponseStatus(event, 400);\n return { error: \"update (base64) required\" };\n }\n\n const binary = base64ToUint8Array(update);\n await manager.applyUpdate(docId, binary, requestSource);\n\n return { ok: true };\n});\n\n/**\n * POST /_agent-native/collab/:docId/text\n *\n * Agent sends full text content. Server computes diff against current\n * Yjs state and applies minimal operations.\n *\n * Body: { text: string, fieldName?: string, requestSource?: string }\n */\nexport const postCollabText = defineEventHandler(async (event: H3Event) => {\n const docId = getCollabDocIdParam(event);\n if (!docId) {\n setResponseStatus(event, 400);\n return { error: \"docId required\" };\n }\n\n const rawBody = await readBody(event);\n if (!enforcePayloadLimit(event, rawBody)) {\n return { error: \"Payload too large\" };\n }\n const { text, fieldName, requestSource } = rawBody as {\n text?: string;\n fieldName?: string;\n requestSource?: string;\n };\n\n if (text === undefined) {\n setResponseStatus(event, 400);\n return { error: \"text required\" };\n }\n\n const result = await manager.applyText(\n docId,\n text,\n fieldName ?? \"content\",\n requestSource ?? \"agent\",\n );\n\n return { ok: true, text: result };\n});\n\n/**\n * POST /_agent-native/collab/:docId/search-replace\n *\n * Search-and-replace text in the Y.XmlFragment (ProseMirror tree).\n * Produces minimal Yjs operations for cursor-preserving updates.\n *\n * Body: { find: string, replace: string, requestSource?: string }\n */\nexport const postCollabSearchReplace = defineEventHandler(\n async (event: H3Event) => {\n const docId = getCollabDocIdParam(event);\n if (!docId) {\n setResponseStatus(event, 400);\n return { error: \"docId required\" };\n }\n\n const rawBody = await readBody(event);\n if (!enforcePayloadLimit(event, rawBody)) {\n return { error: \"Payload too large\" };\n }\n const { find, replace, requestSource } = rawBody as {\n find?: string;\n replace?: string;\n requestSource?: string;\n };\n\n if (!find) {\n setResponseStatus(event, 400);\n return { error: \"find required\" };\n }\n\n const result = await doSearchAndReplace(\n docId,\n find,\n replace ?? \"\",\n requestSource ?? \"agent\",\n );\n\n return { ok: true, found: result.found };\n },\n);\n"]}
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
* Body: { json: any, fieldName?: string, type?: "map"|"array", requestSource?: string }
|
|
14
14
|
*/
|
|
15
15
|
export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
16
|
-
error: string;
|
|
17
16
|
ok?: undefined;
|
|
17
|
+
error: string;
|
|
18
18
|
} | {
|
|
19
19
|
error?: undefined;
|
|
20
20
|
ok: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"struct-routes.d.ts","sourceRoot":"","sources":["../../src/collab/struct-routes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"struct-routes.d.ts","sourceRoot":"","sources":["../../src/collab/struct-routes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA4BH;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc;;;;;;GAgCzB,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,eAAe;;;;;;GA8B1B,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,aAAa;;;;;;;;GAYxB,CAAC"}
|
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
* Mounted under /_agent-native/collab/ by the collab plugin alongside
|
|
5
5
|
* the text-based routes in routes.ts.
|
|
6
6
|
*/
|
|
7
|
-
import { defineEventHandler, setResponseStatus
|
|
7
|
+
import { defineEventHandler, setResponseStatus } from "h3";
|
|
8
8
|
import { getQuery } from "h3";
|
|
9
9
|
import { readBody } from "../server/h3-helpers.js";
|
|
10
|
+
import { getCollabDocIdParam } from "./param.js";
|
|
10
11
|
import * as manager from "./ydoc-manager.js";
|
|
11
12
|
/** Default maximum payload size (2 MB). Overridden by plugin via event.context. */
|
|
12
13
|
const DEFAULT_MAX_BYTES = 2 * 1024 * 1024;
|
|
@@ -31,7 +32,7 @@ function enforcePayloadLimit(event, body) {
|
|
|
31
32
|
* Body: { json: any, fieldName?: string, type?: "map"|"array", requestSource?: string }
|
|
32
33
|
*/
|
|
33
34
|
export const postCollabJson = defineEventHandler(async (event) => {
|
|
34
|
-
const docId =
|
|
35
|
+
const docId = getCollabDocIdParam(event);
|
|
35
36
|
if (!docId) {
|
|
36
37
|
setResponseStatus(event, 400);
|
|
37
38
|
return { error: "docId required" };
|
|
@@ -56,7 +57,7 @@ export const postCollabJson = defineEventHandler(async (event) => {
|
|
|
56
57
|
* Body: { ops: PatchOp[], fieldName?: string, requestSource?: string }
|
|
57
58
|
*/
|
|
58
59
|
export const postCollabPatch = defineEventHandler(async (event) => {
|
|
59
|
-
const docId =
|
|
60
|
+
const docId = getCollabDocIdParam(event);
|
|
60
61
|
if (!docId) {
|
|
61
62
|
setResponseStatus(event, 400);
|
|
62
63
|
return { error: "docId required" };
|
|
@@ -81,7 +82,7 @@ export const postCollabPatch = defineEventHandler(async (event) => {
|
|
|
81
82
|
* Query param: fieldName (default: "data")
|
|
82
83
|
*/
|
|
83
84
|
export const getCollabJson = defineEventHandler(async (event) => {
|
|
84
|
-
const docId =
|
|
85
|
+
const docId = getCollabDocIdParam(event);
|
|
85
86
|
if (!docId) {
|
|
86
87
|
setResponseStatus(event, 400);
|
|
87
88
|
return { error: "docId required" };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"struct-routes.js","sourceRoot":"","sources":["../../src/collab/struct-routes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"struct-routes.js","sourceRoot":"","sources":["../../src/collab/struct-routes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * HTTP route handlers for structured (JSON) collaborative editing.\n *\n * Mounted under /_agent-native/collab/ by the collab plugin alongside\n * the text-based routes in routes.ts.\n */\n\nimport { defineEventHandler, setResponseStatus } from \"h3\";\nimport type { H3Event } from \"h3\";\nimport { getQuery } from \"h3\";\n\nimport { readBody } from \"../server/h3-helpers.js\";\nimport type { PatchOp } from \"./json-to-yjs.js\";\nimport { getCollabDocIdParam } from \"./param.js\";\nimport * as manager from \"./ydoc-manager.js\";\n\n/** Default maximum payload size (2 MB). Overridden by plugin via event.context. */\nconst DEFAULT_MAX_BYTES = 2 * 1024 * 1024;\n\nfunction getMaxPayloadBytes(event: H3Event): number {\n return (event.context as any)?._collabMaxPayloadBytes ?? DEFAULT_MAX_BYTES;\n}\n\nfunction enforcePayloadLimit(event: H3Event, body: unknown): boolean {\n const maxBytes = getMaxPayloadBytes(event);\n const encoded = typeof body === \"string\" ? body : JSON.stringify(body ?? \"\");\n if (encoded.length > maxBytes) {\n setResponseStatus(event, 413);\n return false;\n }\n return true;\n}\n\n/**\n * POST /_agent-native/collab/:docId/json\n *\n * Apply full JSON content to a collaborative document. The server diffs\n * against the current Yjs state and applies minimal operations.\n *\n * Body: { json: any, fieldName?: string, type?: \"map\"|\"array\", requestSource?: string }\n */\nexport const postCollabJson = defineEventHandler(async (event: H3Event) => {\n const docId = getCollabDocIdParam(event);\n if (!docId) {\n setResponseStatus(event, 400);\n return { error: \"docId required\" };\n }\n\n const rawBody = await readBody(event);\n if (!enforcePayloadLimit(event, rawBody)) {\n return { error: \"Payload too large\" };\n }\n const { json, fieldName, type, requestSource } = rawBody as {\n json?: any;\n fieldName?: string;\n type?: \"map\" | \"array\";\n requestSource?: string;\n };\n\n if (json === undefined) {\n setResponseStatus(event, 400);\n return { error: \"json required\" };\n }\n\n await manager.applyJson(\n docId,\n json,\n fieldName ?? \"data\",\n type ?? (Array.isArray(json) ? \"array\" : \"map\"),\n requestSource ?? \"agent\",\n );\n\n return { ok: true };\n});\n\n/**\n * POST /_agent-native/collab/:docId/patch\n *\n * Apply surgical JSON patch operations to a collaborative document.\n *\n * Body: { ops: PatchOp[], fieldName?: string, requestSource?: string }\n */\nexport const postCollabPatch = defineEventHandler(async (event: H3Event) => {\n const docId = getCollabDocIdParam(event);\n if (!docId) {\n setResponseStatus(event, 400);\n return { error: \"docId required\" };\n }\n\n const rawBody = await readBody(event);\n if (!enforcePayloadLimit(event, rawBody)) {\n return { error: \"Payload too large\" };\n }\n const { ops, fieldName, requestSource } = rawBody as {\n ops?: PatchOp[];\n fieldName?: string;\n requestSource?: string;\n };\n\n if (!ops || !Array.isArray(ops)) {\n setResponseStatus(event, 400);\n return { error: \"ops (array) required\" };\n }\n\n await manager.applyPatchOps(\n docId,\n ops,\n fieldName ?? \"data\",\n requestSource ?? \"agent\",\n );\n\n return { ok: true };\n});\n\n/**\n * GET /_agent-native/collab/:docId/json\n *\n * Returns the current JSON state of a collaborative document.\n *\n * Query param: fieldName (default: \"data\")\n */\nexport const getCollabJson = defineEventHandler(async (event: H3Event) => {\n const docId = getCollabDocIdParam(event);\n if (!docId) {\n setResponseStatus(event, 400);\n return { error: \"docId required\" };\n }\n\n const query = getQuery(event);\n const fieldName = (query.fieldName as string) ?? \"data\";\n\n const data = await manager.getJson(docId, fieldName);\n return { docId, data };\n});\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jami-studio/core",
|
|
3
|
-
"version": "0.92.
|
|
3
|
+
"version": "0.92.31",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/studio-jami/jami-studio#readme",
|
|
6
6
|
"bugs": {
|