specnav-core 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/adaptive.js +4 -1
  3. package/dist/adaptive.js.map +1 -1
  4. package/dist/{adaptive.cjs → adaptive.mjs} +3 -6
  5. package/dist/adaptive.mjs.map +1 -0
  6. package/dist/cache.js +6 -1
  7. package/dist/cache.js.map +1 -1
  8. package/dist/{cache.cjs → cache.mjs} +5 -6
  9. package/dist/cache.mjs.map +1 -0
  10. package/dist/graph.js +5 -1
  11. package/dist/graph.js.map +1 -1
  12. package/dist/{graph.cjs → graph.mjs} +3 -7
  13. package/dist/graph.mjs.map +1 -0
  14. package/dist/index.js +20 -1
  15. package/dist/index.js.map +1 -1
  16. package/dist/{index.cjs → index.mjs} +5 -20
  17. package/dist/index.mjs.map +1 -0
  18. package/dist/morpher.js +5 -1
  19. package/dist/morpher.js.map +1 -1
  20. package/dist/{morpher.cjs → morpher.mjs} +3 -7
  21. package/dist/morpher.mjs.map +1 -0
  22. package/dist/performance.js +4 -1
  23. package/dist/performance.js.map +1 -1
  24. package/dist/{performance.cjs → performance.mjs} +3 -6
  25. package/dist/performance.mjs.map +1 -0
  26. package/dist/speculator.js +4 -1
  27. package/dist/speculator.js.map +1 -1
  28. package/dist/{speculator.cjs → speculator.mjs} +3 -6
  29. package/dist/speculator.mjs.map +1 -0
  30. package/dist/trajectory.js +4 -1
  31. package/dist/trajectory.js.map +1 -1
  32. package/dist/{trajectory.cjs → trajectory.mjs} +3 -6
  33. package/dist/trajectory.mjs.map +1 -0
  34. package/package.json +1 -1
  35. package/dist/adaptive.cjs.map +0 -1
  36. package/dist/cache.cjs.map +0 -1
  37. package/dist/graph.cjs.map +0 -1
  38. package/dist/index.cjs.map +0 -1
  39. package/dist/morpher.cjs.map +0 -1
  40. package/dist/performance.cjs.map +0 -1
  41. package/dist/speculator.cjs.map +0 -1
  42. package/dist/trajectory.cjs.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @specnav/core
2
2
 
3
+ ## 0.2.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Allow Next.js inline module scripts and data-nscript attributes in cache validation
8
+
9
+ ## 0.2.1
10
+
11
+ ### Patch Changes
12
+
13
+ - Fix build output to generate .mjs files for ESM instead of .js files, matching package.json exports configuration
14
+
3
15
  ## 0.2.0
4
16
 
5
17
  ### Minor Changes
package/dist/adaptive.js CHANGED
@@ -1,3 +1,5 @@
1
+ 'use strict';
2
+
1
3
  // src/adaptive.ts
2
4
  var DEFAULT_CONFIG = {
3
5
  batteryThreshold: 0.2,
@@ -100,6 +102,7 @@ function createAdaptiveMode(config) {
100
102
  return new AdaptiveMode(config);
101
103
  }
102
104
 
103
- export { AdaptiveMode, createAdaptiveMode };
105
+ exports.AdaptiveMode = AdaptiveMode;
106
+ exports.createAdaptiveMode = createAdaptiveMode;
104
107
  //# sourceMappingURL=adaptive.js.map
105
108
  //# sourceMappingURL=adaptive.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/adaptive.ts"],"names":[],"mappings":";AAEA,IAAM,cAAA,GAAiC;AAAA,EACrC,gBAAA,EAAkB,GAAA;AAAA,EAClB,eAAA,EAAiB;AAAA,IACf,IAAA,EAAM,CAAC,IAAA,EAAM,IAAA,EAAM,SAAS,CAAA;AAAA,IAC5B,IAAA,EAAM,CAAC,IAAI;AAAA,GACb;AAAA,EACA,eAAA,EAAiB,IAAA;AAAA,EACjB,oBAAA,EAAsB;AACxB,CAAA;AAEO,IAAM,eAAN,MAAmB;AAAA,EAChB,MAAA;AAAA,EACA,OAAA,GAAe,IAAA;AAAA,EACf,UAAA,GAAkB,IAAA;AAAA,EAClB,WAAA;AAAA,EAER,WAAA,CAAY,MAAA,GAAkC,EAAC,EAAG;AAChD,IAAA,IAAA,CAAK,MAAA,GAAS,EAAE,GAAG,cAAA,EAAgB,GAAG,MAAA,EAAO;AAC7C,IAAA,IAAA,CAAK,WAAA,GAAc,KAAK,UAAA,EAAW;AAAA,EACrC;AAAA,EAEA,MAAM,WAAA,GAA6B;AACjC,IAAA,MAAM,IAAA,CAAK,WAAA;AAAA,EACb;AAAA,EAEA,MAAc,UAAA,GAA4B;AACxC,IAAA,IAAI,OAAO,cAAc,WAAA,EAAa;AAGtC,IAAA,IAAI,gBAAgB,SAAA,EAAW;AAC7B,MAAA,IAAI;AACF,QAAA,IAAA,CAAK,OAAA,GAAU,MAAO,SAAA,CAAkB,UAAA,EAAW;AAAA,MACrD,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF;AAGA,IAAA,IAAI,YAAA,IAAgB,SAAA,IAAa,eAAA,IAAmB,SAAA,IAAa,sBAAsB,SAAA,EAAW;AAChG,MAAA,IAAA,CAAK,UAAA,GACF,SAAA,CAAkB,UAAA,IAClB,SAAA,CAAkB,iBAClB,SAAA,CAAkB,gBAAA;AAAA,IACvB;AAAA,EACF;AAAA,EAEA,YAAY,YAAA,EAAkC;AAC5C,IAAA,IAAI,YAAA,KAAiB,OAAO,OAAO,KAAA;AACnC,IAAA,IAAI,YAAA,KAAiB,QAAQ,OAAO,YAAA;AAGpC,IAAA,IAAI,IAAA,CAAK,MAAA,CAAO,eAAA,IAAmB,IAAA,CAAK,aAAY,EAAG;AACrD,MAAA,OAAO,KAAA;AAAA,IACT;AAGA,IAAA,IAAI,IAAA,CAAK,cAAa,EAAG;AACvB,MAAA,OAAO,cAAA;AAAA,IACT;AAGA,IAAA,IAAI,IAAA,CAAK,kBAAiB,EAAG;AAC3B,MAAA,OAAO,cAAA;AAAA,IACT;AAEA,IAAA,OAAO,YAAA;AAAA,EACT;AAAA,EAEA,cAAA,GAA0B;AACxB,IAAA,IAAI,IAAA,CAAK,MAAA,CAAO,eAAA,IAAmB,IAAA,CAAK,aAAY,EAAG;AACrD,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,IAAI,IAAA,CAAK,cAAa,EAAG;AACvB,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEA,eAAA,GAA2B;AACzB,IAAA,IAAI,CAAC,IAAA,CAAK,cAAA,EAAe,EAAG;AAC1B,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,IAAI,IAAA,CAAK,kBAAiB,EAAG;AAC3B,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEA,oBAAA,GAAgC;AAC9B,IAAA,IAAI,CAAC,IAAA,CAAK,MAAA,CAAO,oBAAA,EAAsB,OAAO,IAAA;AAE9C,IAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,OAAO,IAAA;AAE1C,IAAA,OAAO,CAAC,MAAA,CAAO,UAAA,CAAW,kCAAkC,CAAA,CAAE,OAAA;AAAA,EAChE;AAAA,EAEQ,WAAA,GAAuB;AAC7B,IAAA,IAAI,OAAO,SAAA,KAAc,WAAA,EAAa,OAAO,KAAA;AAE7C,IAAA,OACG,SAAA,CAAkB,UAAA,EAAY,QAAA,KAAa,IAAA,IAC3C,SAAA,CAAkB,eAAe,QAAA,KAAa,IAAA,IAC9C,SAAA,CAAkB,gBAAA,EAAkB,QAAA,KAAa,IAAA;AAAA,EAEtD;AAAA,EAEQ,YAAA,GAAwB;AAC9B,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,EAAS,OAAO,KAAA;AAE1B,IAAA,OACE,CAAC,KAAK,OAAA,CAAQ,QAAA,IACd,KAAK,OAAA,CAAQ,KAAA,GAAQ,KAAK,MAAA,CAAO,gBAAA;AAAA,EAErC;AAAA,EAEQ,gBAAA,GAA4B;AAClC,IAAA,IAAI,CAAC,IAAA,CAAK,UAAA,EAAY,OAAO,KAAA;AAE7B,IAAA,MAAM,aAAA,GAAgB,KAAK,UAAA,CAAW,aAAA;AACtC,IAAA,IAAI,CAAC,eAAe,OAAO,KAAA;AAE3B,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,eAAA,CAAgB,IAAA,CAAK,SAAS,aAAa,CAAA;AAAA,EAChE;AAAA,EAEA,gBAAA,GAA4B;AAC1B,IAAA,IAAI,CAAC,IAAA,CAAK,UAAA,EAAY,OAAO,IAAA;AAE7B,IAAA,MAAM,aAAA,GAAgB,KAAK,UAAA,CAAW,aAAA;AACtC,IAAA,IAAI,CAAC,eAAe,OAAO,IAAA;AAE3B,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,eAAA,CAAgB,IAAA,CAAK,SAAS,aAAa,CAAA;AAAA,EAChE;AAAA,EAEA,eAAA,GAAiC;AAC/B,IAAA,OAAO,IAAA,CAAK,SAAS,KAAA,IAAS,IAAA;AAAA,EAChC;AAAA,EAEA,iBAAA,GAAmC;AACjC,IAAA,OAAO,IAAA,CAAK,YAAY,aAAA,IAAiB,IAAA;AAAA,EAC3C;AACF;AAEO,SAAS,mBACd,MAAA,EACc;AACd,EAAA,OAAO,IAAI,aAAa,MAAM,CAAA;AAChC","file":"adaptive.js","sourcesContent":["import type { AdaptiveConfig, Strategy } from \"./types\";\n\nconst DEFAULT_CONFIG: AdaptiveConfig = {\n batteryThreshold: 0.2,\n connectionTypes: {\n slow: [\"2g\", \"3g\", \"slow-2g\"],\n fast: [\"4g\"],\n },\n respectSaveData: true,\n respectReducedMotion: true,\n};\n\nexport class AdaptiveMode {\n private config: AdaptiveConfig;\n private battery: any = null;\n private connection: any = null;\n private initPromise: Promise<void>;\n\n constructor(config: Partial<AdaptiveConfig> = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.initPromise = this.initialize();\n }\n\n async waitForInit(): Promise<void> {\n await this.initPromise;\n }\n\n private async initialize(): Promise<void> {\n if (typeof navigator === \"undefined\") return;\n\n // Battery API\n if (\"getBattery\" in navigator) {\n try {\n this.battery = await (navigator as any).getBattery();\n } catch {\n // Not available\n }\n }\n\n // Network Information API\n if (\"connection\" in navigator || \"mozConnection\" in navigator || \"webkitConnection\" in navigator) {\n this.connection =\n (navigator as any).connection ||\n (navigator as any).mozConnection ||\n (navigator as any).webkitConnection;\n }\n }\n\n getStrategy(baseStrategy: Strategy): Strategy {\n if (baseStrategy === \"off\") return \"off\";\n if (baseStrategy !== \"auto\") return baseStrategy;\n\n // Check Save-Data\n if (this.config.respectSaveData && this.hasSaveData()) {\n return \"off\";\n }\n\n // Check battery\n if (this.isLowBattery()) {\n return \"conservative\";\n }\n\n // Check connection\n if (this.isSlowConnection()) {\n return \"conservative\";\n }\n\n return \"aggressive\";\n }\n\n shouldPrefetch(): boolean {\n if (this.config.respectSaveData && this.hasSaveData()) {\n return false;\n }\n\n if (this.isLowBattery()) {\n return false;\n }\n\n return true;\n }\n\n shouldSpeculate(): boolean {\n if (!this.shouldPrefetch()) {\n return false;\n }\n\n if (this.isSlowConnection()) {\n return false;\n }\n\n return true;\n }\n\n shouldUseTransitions(): boolean {\n if (!this.config.respectReducedMotion) return true;\n\n if (typeof window === \"undefined\") return true;\n\n return !window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n }\n\n private hasSaveData(): boolean {\n if (typeof navigator === \"undefined\") return false;\n\n return (\n (navigator as any).connection?.saveData === true ||\n (navigator as any).mozConnection?.saveData === true ||\n (navigator as any).webkitConnection?.saveData === true\n );\n }\n\n private isLowBattery(): boolean {\n if (!this.battery) return false;\n\n return (\n !this.battery.charging &&\n this.battery.level < this.config.batteryThreshold\n );\n }\n\n private isSlowConnection(): boolean {\n if (!this.connection) return false;\n\n const effectiveType = this.connection.effectiveType;\n if (!effectiveType) return false;\n\n return this.config.connectionTypes.slow.includes(effectiveType);\n }\n\n isFastConnection(): boolean {\n if (!this.connection) return true; // Assume fast if unknown\n\n const effectiveType = this.connection.effectiveType;\n if (!effectiveType) return true;\n\n return this.config.connectionTypes.fast.includes(effectiveType);\n }\n\n getBatteryLevel(): number | null {\n return this.battery?.level ?? null;\n }\n\n getConnectionType(): string | null {\n return this.connection?.effectiveType ?? null;\n }\n}\n\nexport function createAdaptiveMode(\n config?: Partial<AdaptiveConfig>\n): AdaptiveMode {\n return new AdaptiveMode(config);\n}\n"]}
1
+ {"version":3,"sources":["../src/adaptive.ts"],"names":[],"mappings":"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","file":"adaptive.js","sourcesContent":["import type { AdaptiveConfig, Strategy } from \"./types\";\n\nconst DEFAULT_CONFIG: AdaptiveConfig = {\n batteryThreshold: 0.2,\n connectionTypes: {\n slow: [\"2g\", \"3g\", \"slow-2g\"],\n fast: [\"4g\"],\n },\n respectSaveData: true,\n respectReducedMotion: true,\n};\n\nexport class AdaptiveMode {\n private config: AdaptiveConfig;\n private battery: any = null;\n private connection: any = null;\n private initPromise: Promise<void>;\n\n constructor(config: Partial<AdaptiveConfig> = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.initPromise = this.initialize();\n }\n\n async waitForInit(): Promise<void> {\n await this.initPromise;\n }\n\n private async initialize(): Promise<void> {\n if (typeof navigator === \"undefined\") return;\n\n // Battery API\n if (\"getBattery\" in navigator) {\n try {\n this.battery = await (navigator as any).getBattery();\n } catch {\n // Not available\n }\n }\n\n // Network Information API\n if (\"connection\" in navigator || \"mozConnection\" in navigator || \"webkitConnection\" in navigator) {\n this.connection =\n (navigator as any).connection ||\n (navigator as any).mozConnection ||\n (navigator as any).webkitConnection;\n }\n }\n\n getStrategy(baseStrategy: Strategy): Strategy {\n if (baseStrategy === \"off\") return \"off\";\n if (baseStrategy !== \"auto\") return baseStrategy;\n\n // Check Save-Data\n if (this.config.respectSaveData && this.hasSaveData()) {\n return \"off\";\n }\n\n // Check battery\n if (this.isLowBattery()) {\n return \"conservative\";\n }\n\n // Check connection\n if (this.isSlowConnection()) {\n return \"conservative\";\n }\n\n return \"aggressive\";\n }\n\n shouldPrefetch(): boolean {\n if (this.config.respectSaveData && this.hasSaveData()) {\n return false;\n }\n\n if (this.isLowBattery()) {\n return false;\n }\n\n return true;\n }\n\n shouldSpeculate(): boolean {\n if (!this.shouldPrefetch()) {\n return false;\n }\n\n if (this.isSlowConnection()) {\n return false;\n }\n\n return true;\n }\n\n shouldUseTransitions(): boolean {\n if (!this.config.respectReducedMotion) return true;\n\n if (typeof window === \"undefined\") return true;\n\n return !window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n }\n\n private hasSaveData(): boolean {\n if (typeof navigator === \"undefined\") return false;\n\n return (\n (navigator as any).connection?.saveData === true ||\n (navigator as any).mozConnection?.saveData === true ||\n (navigator as any).webkitConnection?.saveData === true\n );\n }\n\n private isLowBattery(): boolean {\n if (!this.battery) return false;\n\n return (\n !this.battery.charging &&\n this.battery.level < this.config.batteryThreshold\n );\n }\n\n private isSlowConnection(): boolean {\n if (!this.connection) return false;\n\n const effectiveType = this.connection.effectiveType;\n if (!effectiveType) return false;\n\n return this.config.connectionTypes.slow.includes(effectiveType);\n }\n\n isFastConnection(): boolean {\n if (!this.connection) return true; // Assume fast if unknown\n\n const effectiveType = this.connection.effectiveType;\n if (!effectiveType) return true;\n\n return this.config.connectionTypes.fast.includes(effectiveType);\n }\n\n getBatteryLevel(): number | null {\n return this.battery?.level ?? null;\n }\n\n getConnectionType(): string | null {\n return this.connection?.effectiveType ?? null;\n }\n}\n\nexport function createAdaptiveMode(\n config?: Partial<AdaptiveConfig>\n): AdaptiveMode {\n return new AdaptiveMode(config);\n}\n"]}
@@ -1,5 +1,3 @@
1
- 'use strict';
2
-
3
1
  // src/adaptive.ts
4
2
  var DEFAULT_CONFIG = {
5
3
  batteryThreshold: 0.2,
@@ -102,7 +100,6 @@ function createAdaptiveMode(config) {
102
100
  return new AdaptiveMode(config);
103
101
  }
104
102
 
105
- exports.AdaptiveMode = AdaptiveMode;
106
- exports.createAdaptiveMode = createAdaptiveMode;
107
- //# sourceMappingURL=adaptive.cjs.map
108
- //# sourceMappingURL=adaptive.cjs.map
103
+ export { AdaptiveMode, createAdaptiveMode };
104
+ //# sourceMappingURL=adaptive.mjs.map
105
+ //# sourceMappingURL=adaptive.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adaptive.ts"],"names":[],"mappings":"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","file":"adaptive.mjs","sourcesContent":["import type { AdaptiveConfig, Strategy } from \"./types\";\n\nconst DEFAULT_CONFIG: AdaptiveConfig = {\n batteryThreshold: 0.2,\n connectionTypes: {\n slow: [\"2g\", \"3g\", \"slow-2g\"],\n fast: [\"4g\"],\n },\n respectSaveData: true,\n respectReducedMotion: true,\n};\n\nexport class AdaptiveMode {\n private config: AdaptiveConfig;\n private battery: any = null;\n private connection: any = null;\n private initPromise: Promise<void>;\n\n constructor(config: Partial<AdaptiveConfig> = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.initPromise = this.initialize();\n }\n\n async waitForInit(): Promise<void> {\n await this.initPromise;\n }\n\n private async initialize(): Promise<void> {\n if (typeof navigator === \"undefined\") return;\n\n // Battery API\n if (\"getBattery\" in navigator) {\n try {\n this.battery = await (navigator as any).getBattery();\n } catch {\n // Not available\n }\n }\n\n // Network Information API\n if (\"connection\" in navigator || \"mozConnection\" in navigator || \"webkitConnection\" in navigator) {\n this.connection =\n (navigator as any).connection ||\n (navigator as any).mozConnection ||\n (navigator as any).webkitConnection;\n }\n }\n\n getStrategy(baseStrategy: Strategy): Strategy {\n if (baseStrategy === \"off\") return \"off\";\n if (baseStrategy !== \"auto\") return baseStrategy;\n\n // Check Save-Data\n if (this.config.respectSaveData && this.hasSaveData()) {\n return \"off\";\n }\n\n // Check battery\n if (this.isLowBattery()) {\n return \"conservative\";\n }\n\n // Check connection\n if (this.isSlowConnection()) {\n return \"conservative\";\n }\n\n return \"aggressive\";\n }\n\n shouldPrefetch(): boolean {\n if (this.config.respectSaveData && this.hasSaveData()) {\n return false;\n }\n\n if (this.isLowBattery()) {\n return false;\n }\n\n return true;\n }\n\n shouldSpeculate(): boolean {\n if (!this.shouldPrefetch()) {\n return false;\n }\n\n if (this.isSlowConnection()) {\n return false;\n }\n\n return true;\n }\n\n shouldUseTransitions(): boolean {\n if (!this.config.respectReducedMotion) return true;\n\n if (typeof window === \"undefined\") return true;\n\n return !window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n }\n\n private hasSaveData(): boolean {\n if (typeof navigator === \"undefined\") return false;\n\n return (\n (navigator as any).connection?.saveData === true ||\n (navigator as any).mozConnection?.saveData === true ||\n (navigator as any).webkitConnection?.saveData === true\n );\n }\n\n private isLowBattery(): boolean {\n if (!this.battery) return false;\n\n return (\n !this.battery.charging &&\n this.battery.level < this.config.batteryThreshold\n );\n }\n\n private isSlowConnection(): boolean {\n if (!this.connection) return false;\n\n const effectiveType = this.connection.effectiveType;\n if (!effectiveType) return false;\n\n return this.config.connectionTypes.slow.includes(effectiveType);\n }\n\n isFastConnection(): boolean {\n if (!this.connection) return true; // Assume fast if unknown\n\n const effectiveType = this.connection.effectiveType;\n if (!effectiveType) return true;\n\n return this.config.connectionTypes.fast.includes(effectiveType);\n }\n\n getBatteryLevel(): number | null {\n return this.battery?.level ?? null;\n }\n\n getConnectionType(): string | null {\n return this.connection?.effectiveType ?? null;\n }\n}\n\nexport function createAdaptiveMode(\n config?: Partial<AdaptiveConfig>\n): AdaptiveMode {\n return new AdaptiveMode(config);\n}\n"]}
package/dist/cache.js CHANGED
@@ -1,3 +1,5 @@
1
+ 'use strict';
2
+
1
3
  // src/cache.ts
2
4
  var DEFAULT_CONFIG = {
3
5
  memory: {
@@ -87,6 +89,8 @@ var CacheManager = class {
87
89
  if (/src\s*=/.test(attrs)) continue;
88
90
  if (/type\s*=\s*["']?(application\/json|application\/ld\+json|text\/template)["']?/i.test(attrs)) continue;
89
91
  if (/id\s*=\s*["']__NEXT_DATA__["']/i.test(attrs)) continue;
92
+ if (/data-nscript\s*=/i.test(attrs)) continue;
93
+ if (/type\s*=\s*["']?module["']?/i.test(attrs)) continue;
90
94
  return true;
91
95
  }
92
96
  return dangerousPatterns.some((pattern) => pattern.test(html));
@@ -216,6 +220,7 @@ function createCacheManager(config, callbacks) {
216
220
  return new CacheManager(config, callbacks);
217
221
  }
218
222
 
219
- export { CacheManager, createCacheManager };
223
+ exports.CacheManager = CacheManager;
224
+ exports.createCacheManager = createCacheManager;
220
225
  //# sourceMappingURL=cache.js.map
221
226
  //# sourceMappingURL=cache.js.map
package/dist/cache.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cache.ts"],"names":[],"mappings":"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","file":"cache.js","sourcesContent":["import type { CacheConfig, CachedPage, CacheLayer } from \"./types\";\n\nconst DEFAULT_CONFIG: CacheConfig = {\n memory: {\n enabled: true,\n maxPages: 10,\n },\n serviceWorker: {\n enabled: true,\n ttl: 300,\n cacheName: \"specnav-v1\",\n crossTabSync: true,\n broadcastChannel: \"specnav-sync\",\n },\n edge: {\n enabled: true,\n maxAge: 60,\n staleWhileRevalidate: 300,\n },\n exclude: [],\n};\n\nexport class CacheManager {\n private config: CacheConfig;\n private memoryCache: Map<string, CachedPage> = new Map();\n private accessOrder: string[] = [];\n private broadcastChannel?: BroadcastChannel;\n private onCacheHit?: (href: string, layer: CacheLayer) => void;\n\n constructor(\n config: Partial<CacheConfig> = {},\n callbacks?: { onCacheHit?: (href: string, layer: CacheLayer) => void }\n ) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.onCacheHit = callbacks?.onCacheHit;\n\n if (\n this.config.serviceWorker.enabled &&\n this.config.serviceWorker.crossTabSync &&\n typeof BroadcastChannel !== \"undefined\"\n ) {\n this.broadcastChannel = new BroadcastChannel(\n this.config.serviceWorker.broadcastChannel\n );\n this.broadcastChannel.onmessage = this.handleBroadcast;\n }\n }\n\n async get(href: string): Promise<string | null> {\n if (this.isExcluded(href)) return null;\n\n // L1: Memory cache\n const memoryHit = this.getFromMemory(href);\n if (memoryHit) {\n this.onCacheHit?.(href, 1);\n return memoryHit;\n }\n\n // L2: Service Worker cache\n if (this.config.serviceWorker.enabled) {\n const swHit = await this.getFromServiceWorker(href);\n if (swHit) {\n this.onCacheHit?.(href, 2);\n this.setInMemory(href, swHit);\n return swHit;\n }\n }\n\n return null;\n }\n\n async set(href: string, html: string): Promise<void> {\n if (this.isExcluded(href)) return;\n\n // Sanitize href to prevent cache poisoning\n const sanitizedHref = this.sanitizeHref(href);\n if (!sanitizedHref) return;\n\n // Validate HTML doesn't contain dangerous inline scripts\n if (this.containsDangerousContent(html)) {\n console.warn(`Refusing to cache potentially dangerous content from ${sanitizedHref}`);\n return;\n }\n\n const page: CachedPage = {\n href: sanitizedHref,\n html,\n timestamp: Date.now(),\n ttl: this.config.serviceWorker.ttl,\n };\n\n // L1: Memory\n if (this.config.memory.enabled) {\n this.setInMemory(sanitizedHref, html);\n }\n\n // L2: Service Worker\n if (this.config.serviceWorker.enabled) {\n await this.setInServiceWorker(page);\n this.broadcastSet(sanitizedHref);\n }\n }\n\n private containsDangerousContent(html: string): boolean {\n // Check for inline event handlers and javascript: URLs\n const dangerousPatterns = [\n /on\\w+\\s*=\\s*[\"'][^\"']*[\"']/i, // Inline event handlers\n /javascript:/i, // javascript: URLs\n ];\n\n // Check for inline scripts, but exclude safe types\n const scriptRegex = /<script([^>]*)>([\\s\\S]*?)<\\/script>/gi;\n let match;\n while ((match = scriptRegex.exec(html)) !== null) {\n const attrs = match[1] || \"\";\n \n // Allow scripts with src attribute\n if (/src\\s*=/.test(attrs)) continue;\n \n // Allow safe script types (JSON data, templates)\n if (/type\\s*=\\s*[\"']?(application\\/json|application\\/ld\\+json|text\\/template)[\"']?/i.test(attrs)) continue;\n \n // Allow Next.js data script\n if (/id\\s*=\\s*[\"']__NEXT_DATA__[\"']/i.test(attrs)) continue;\n \n // If we get here, it's an inline script without safe type\n return true;\n }\n\n return dangerousPatterns.some(pattern => pattern.test(html));\n }\n\n private sanitizeHref(href: string): string | null {\n try {\n const url = new URL(href, window.location.origin);\n // Only allow same-origin URLs\n if (url.origin !== window.location.origin) return null;\n return url.pathname + url.search + url.hash;\n } catch {\n return null;\n }\n }\n\n clear(href?: string): void {\n if (href) {\n this.memoryCache.delete(href);\n this.accessOrder = this.accessOrder.filter((h) => h !== href);\n this.clearFromServiceWorker(href);\n } else {\n this.memoryCache.clear();\n this.accessOrder = [];\n this.clearAllServiceWorker();\n }\n }\n\n getSize(): number {\n return this.memoryCache.size;\n }\n\n destroy(): void {\n this.memoryCache.clear();\n this.accessOrder = [];\n this.broadcastChannel?.close();\n }\n\n private getFromMemory(href: string): string | null {\n const page = this.memoryCache.get(href);\n if (!page) return null;\n\n // Update LRU order\n this.accessOrder = this.accessOrder.filter((h) => h !== href);\n this.accessOrder.push(href);\n\n return page.html;\n }\n\n private setInMemory(href: string, html: string): void {\n // Prevent memory exhaustion - limit individual page size\n const maxPageSize = 5 * 1024 * 1024; // 5MB per page\n if (html.length > maxPageSize) {\n console.warn(`Page ${href} exceeds max size, not caching`);\n return;\n }\n\n this.memoryCache.set(href, {\n href,\n html,\n timestamp: Date.now(),\n ttl: this.config.serviceWorker.ttl,\n });\n\n // Deduplicate before adding to accessOrder\n const existingIndex = this.accessOrder.indexOf(href);\n if (existingIndex !== -1) {\n this.accessOrder.splice(existingIndex, 1);\n }\n this.accessOrder.push(href);\n\n // LRU eviction\n if (this.memoryCache.size > this.config.memory.maxPages) {\n const oldest = this.accessOrder.shift();\n if (oldest) this.memoryCache.delete(oldest);\n }\n }\n\n private async getFromServiceWorker(href: string): Promise<string | null> {\n if (typeof caches === \"undefined\") return null;\n\n try {\n const cache = await caches.open(this.config.serviceWorker.cacheName);\n const response = await cache.match(href);\n\n if (!response) return null;\n\n const data = await response.json();\n const page = data as CachedPage;\n\n // Check TTL\n const age = Date.now() - page.timestamp;\n if (age > page.ttl * 1000) {\n await cache.delete(href);\n return null;\n }\n\n return page.html;\n } catch {\n return null;\n }\n }\n\n private async setInServiceWorker(page: CachedPage): Promise<void> {\n if (typeof caches === \"undefined\") return;\n\n try {\n const cache = await caches.open(this.config.serviceWorker.cacheName);\n const response = new Response(JSON.stringify(page), {\n headers: {\n \"Content-Type\": \"application/json\",\n \"Cache-Control\": `max-age=${this.config.edge.maxAge}, stale-while-revalidate=${this.config.edge.staleWhileRevalidate}`,\n },\n });\n await cache.put(page.href, response);\n } catch {\n // Silently fail\n }\n }\n\n private async clearFromServiceWorker(href: string): Promise<void> {\n if (typeof caches === \"undefined\") return;\n\n try {\n const cache = await caches.open(this.config.serviceWorker.cacheName);\n await cache.delete(href);\n } catch {\n // Silently fail\n }\n }\n\n private async clearAllServiceWorker(): Promise<void> {\n if (typeof caches === \"undefined\") return;\n\n try {\n await caches.delete(this.config.serviceWorker.cacheName);\n } catch {\n // Silently fail\n }\n }\n\n private isExcluded(href: string): boolean {\n return this.config.exclude.some((pattern) => {\n if (typeof pattern === \"string\") {\n return pattern.includes(\"*\")\n ? new RegExp(pattern.replace(/\\*/g, \".*\")).test(href)\n : href === pattern;\n }\n return pattern.test(href);\n });\n }\n\n private broadcastSet(href: string): void {\n this.broadcastChannel?.postMessage({ type: \"set\", href });\n }\n\n private handleBroadcast = (event: MessageEvent): void => {\n if (event.data.type === \"set\") {\n // Invalidate memory cache to force fetch from SW\n this.memoryCache.delete(event.data.href);\n }\n };\n}\n\nexport function createCacheManager(\n config?: Partial<CacheConfig>,\n callbacks?: { onCacheHit?: (href: string, layer: CacheLayer) => void }\n): CacheManager {\n return new CacheManager(config, callbacks);\n}\n"]}
1
+ {"version":3,"sources":["../src/cache.ts"],"names":[],"mappings":"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","file":"cache.js","sourcesContent":["import type { CacheConfig, CachedPage, CacheLayer } from \"./types\";\n\nconst DEFAULT_CONFIG: CacheConfig = {\n memory: {\n enabled: true,\n maxPages: 10,\n },\n serviceWorker: {\n enabled: true,\n ttl: 300,\n cacheName: \"specnav-v1\",\n crossTabSync: true,\n broadcastChannel: \"specnav-sync\",\n },\n edge: {\n enabled: true,\n maxAge: 60,\n staleWhileRevalidate: 300,\n },\n exclude: [],\n};\n\nexport class CacheManager {\n private config: CacheConfig;\n private memoryCache: Map<string, CachedPage> = new Map();\n private accessOrder: string[] = [];\n private broadcastChannel?: BroadcastChannel;\n private onCacheHit?: (href: string, layer: CacheLayer) => void;\n\n constructor(\n config: Partial<CacheConfig> = {},\n callbacks?: { onCacheHit?: (href: string, layer: CacheLayer) => void }\n ) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.onCacheHit = callbacks?.onCacheHit;\n\n if (\n this.config.serviceWorker.enabled &&\n this.config.serviceWorker.crossTabSync &&\n typeof BroadcastChannel !== \"undefined\"\n ) {\n this.broadcastChannel = new BroadcastChannel(\n this.config.serviceWorker.broadcastChannel\n );\n this.broadcastChannel.onmessage = this.handleBroadcast;\n }\n }\n\n async get(href: string): Promise<string | null> {\n if (this.isExcluded(href)) return null;\n\n // L1: Memory cache\n const memoryHit = this.getFromMemory(href);\n if (memoryHit) {\n this.onCacheHit?.(href, 1);\n return memoryHit;\n }\n\n // L2: Service Worker cache\n if (this.config.serviceWorker.enabled) {\n const swHit = await this.getFromServiceWorker(href);\n if (swHit) {\n this.onCacheHit?.(href, 2);\n this.setInMemory(href, swHit);\n return swHit;\n }\n }\n\n return null;\n }\n\n async set(href: string, html: string): Promise<void> {\n if (this.isExcluded(href)) return;\n\n // Sanitize href to prevent cache poisoning\n const sanitizedHref = this.sanitizeHref(href);\n if (!sanitizedHref) return;\n\n // Validate HTML doesn't contain dangerous inline scripts\n if (this.containsDangerousContent(html)) {\n console.warn(`Refusing to cache potentially dangerous content from ${sanitizedHref}`);\n return;\n }\n\n const page: CachedPage = {\n href: sanitizedHref,\n html,\n timestamp: Date.now(),\n ttl: this.config.serviceWorker.ttl,\n };\n\n // L1: Memory\n if (this.config.memory.enabled) {\n this.setInMemory(sanitizedHref, html);\n }\n\n // L2: Service Worker\n if (this.config.serviceWorker.enabled) {\n await this.setInServiceWorker(page);\n this.broadcastSet(sanitizedHref);\n }\n }\n\n private containsDangerousContent(html: string): boolean {\n // Check for inline event handlers and javascript: URLs\n const dangerousPatterns = [\n /on\\w+\\s*=\\s*[\"'][^\"']*[\"']/i, // Inline event handlers\n /javascript:/i, // javascript: URLs\n ];\n\n // Check for inline scripts, but exclude safe types\n const scriptRegex = /<script([^>]*)>([\\s\\S]*?)<\\/script>/gi;\n let match;\n while ((match = scriptRegex.exec(html)) !== null) {\n const attrs = match[1] || \"\";\n \n // Allow scripts with src attribute\n if (/src\\s*=/.test(attrs)) continue;\n \n // Allow safe script types (JSON data, templates)\n if (/type\\s*=\\s*[\"']?(application\\/json|application\\/ld\\+json|text\\/template)[\"']?/i.test(attrs)) continue;\n \n // Allow Next.js scripts\n if (/id\\s*=\\s*[\"']__NEXT_DATA__[\"']/i.test(attrs)) continue;\n if (/data-nscript\\s*=/i.test(attrs)) continue;\n \n // Allow module scripts (Next.js uses these for hydration)\n if (/type\\s*=\\s*[\"']?module[\"']?/i.test(attrs)) continue;\n \n // If we get here, it's an inline script without safe type\n return true;\n }\n\n return dangerousPatterns.some(pattern => pattern.test(html));\n }\n\n private sanitizeHref(href: string): string | null {\n try {\n const url = new URL(href, window.location.origin);\n // Only allow same-origin URLs\n if (url.origin !== window.location.origin) return null;\n return url.pathname + url.search + url.hash;\n } catch {\n return null;\n }\n }\n\n clear(href?: string): void {\n if (href) {\n this.memoryCache.delete(href);\n this.accessOrder = this.accessOrder.filter((h) => h !== href);\n this.clearFromServiceWorker(href);\n } else {\n this.memoryCache.clear();\n this.accessOrder = [];\n this.clearAllServiceWorker();\n }\n }\n\n getSize(): number {\n return this.memoryCache.size;\n }\n\n destroy(): void {\n this.memoryCache.clear();\n this.accessOrder = [];\n this.broadcastChannel?.close();\n }\n\n private getFromMemory(href: string): string | null {\n const page = this.memoryCache.get(href);\n if (!page) return null;\n\n // Update LRU order\n this.accessOrder = this.accessOrder.filter((h) => h !== href);\n this.accessOrder.push(href);\n\n return page.html;\n }\n\n private setInMemory(href: string, html: string): void {\n // Prevent memory exhaustion - limit individual page size\n const maxPageSize = 5 * 1024 * 1024; // 5MB per page\n if (html.length > maxPageSize) {\n console.warn(`Page ${href} exceeds max size, not caching`);\n return;\n }\n\n this.memoryCache.set(href, {\n href,\n html,\n timestamp: Date.now(),\n ttl: this.config.serviceWorker.ttl,\n });\n\n // Deduplicate before adding to accessOrder\n const existingIndex = this.accessOrder.indexOf(href);\n if (existingIndex !== -1) {\n this.accessOrder.splice(existingIndex, 1);\n }\n this.accessOrder.push(href);\n\n // LRU eviction\n if (this.memoryCache.size > this.config.memory.maxPages) {\n const oldest = this.accessOrder.shift();\n if (oldest) this.memoryCache.delete(oldest);\n }\n }\n\n private async getFromServiceWorker(href: string): Promise<string | null> {\n if (typeof caches === \"undefined\") return null;\n\n try {\n const cache = await caches.open(this.config.serviceWorker.cacheName);\n const response = await cache.match(href);\n\n if (!response) return null;\n\n const data = await response.json();\n const page = data as CachedPage;\n\n // Check TTL\n const age = Date.now() - page.timestamp;\n if (age > page.ttl * 1000) {\n await cache.delete(href);\n return null;\n }\n\n return page.html;\n } catch {\n return null;\n }\n }\n\n private async setInServiceWorker(page: CachedPage): Promise<void> {\n if (typeof caches === \"undefined\") return;\n\n try {\n const cache = await caches.open(this.config.serviceWorker.cacheName);\n const response = new Response(JSON.stringify(page), {\n headers: {\n \"Content-Type\": \"application/json\",\n \"Cache-Control\": `max-age=${this.config.edge.maxAge}, stale-while-revalidate=${this.config.edge.staleWhileRevalidate}`,\n },\n });\n await cache.put(page.href, response);\n } catch {\n // Silently fail\n }\n }\n\n private async clearFromServiceWorker(href: string): Promise<void> {\n if (typeof caches === \"undefined\") return;\n\n try {\n const cache = await caches.open(this.config.serviceWorker.cacheName);\n await cache.delete(href);\n } catch {\n // Silently fail\n }\n }\n\n private async clearAllServiceWorker(): Promise<void> {\n if (typeof caches === \"undefined\") return;\n\n try {\n await caches.delete(this.config.serviceWorker.cacheName);\n } catch {\n // Silently fail\n }\n }\n\n private isExcluded(href: string): boolean {\n return this.config.exclude.some((pattern) => {\n if (typeof pattern === \"string\") {\n return pattern.includes(\"*\")\n ? new RegExp(pattern.replace(/\\*/g, \".*\")).test(href)\n : href === pattern;\n }\n return pattern.test(href);\n });\n }\n\n private broadcastSet(href: string): void {\n this.broadcastChannel?.postMessage({ type: \"set\", href });\n }\n\n private handleBroadcast = (event: MessageEvent): void => {\n if (event.data.type === \"set\") {\n // Invalidate memory cache to force fetch from SW\n this.memoryCache.delete(event.data.href);\n }\n };\n}\n\nexport function createCacheManager(\n config?: Partial<CacheConfig>,\n callbacks?: { onCacheHit?: (href: string, layer: CacheLayer) => void }\n): CacheManager {\n return new CacheManager(config, callbacks);\n}\n"]}
@@ -1,5 +1,3 @@
1
- 'use strict';
2
-
3
1
  // src/cache.ts
4
2
  var DEFAULT_CONFIG = {
5
3
  memory: {
@@ -89,6 +87,8 @@ var CacheManager = class {
89
87
  if (/src\s*=/.test(attrs)) continue;
90
88
  if (/type\s*=\s*["']?(application\/json|application\/ld\+json|text\/template)["']?/i.test(attrs)) continue;
91
89
  if (/id\s*=\s*["']__NEXT_DATA__["']/i.test(attrs)) continue;
90
+ if (/data-nscript\s*=/i.test(attrs)) continue;
91
+ if (/type\s*=\s*["']?module["']?/i.test(attrs)) continue;
92
92
  return true;
93
93
  }
94
94
  return dangerousPatterns.some((pattern) => pattern.test(html));
@@ -218,7 +218,6 @@ function createCacheManager(config, callbacks) {
218
218
  return new CacheManager(config, callbacks);
219
219
  }
220
220
 
221
- exports.CacheManager = CacheManager;
222
- exports.createCacheManager = createCacheManager;
223
- //# sourceMappingURL=cache.cjs.map
224
- //# sourceMappingURL=cache.cjs.map
221
+ export { CacheManager, createCacheManager };
222
+ //# sourceMappingURL=cache.mjs.map
223
+ //# sourceMappingURL=cache.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cache.ts"],"names":[],"mappings":"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","file":"cache.mjs","sourcesContent":["import type { CacheConfig, CachedPage, CacheLayer } from \"./types\";\n\nconst DEFAULT_CONFIG: CacheConfig = {\n memory: {\n enabled: true,\n maxPages: 10,\n },\n serviceWorker: {\n enabled: true,\n ttl: 300,\n cacheName: \"specnav-v1\",\n crossTabSync: true,\n broadcastChannel: \"specnav-sync\",\n },\n edge: {\n enabled: true,\n maxAge: 60,\n staleWhileRevalidate: 300,\n },\n exclude: [],\n};\n\nexport class CacheManager {\n private config: CacheConfig;\n private memoryCache: Map<string, CachedPage> = new Map();\n private accessOrder: string[] = [];\n private broadcastChannel?: BroadcastChannel;\n private onCacheHit?: (href: string, layer: CacheLayer) => void;\n\n constructor(\n config: Partial<CacheConfig> = {},\n callbacks?: { onCacheHit?: (href: string, layer: CacheLayer) => void }\n ) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.onCacheHit = callbacks?.onCacheHit;\n\n if (\n this.config.serviceWorker.enabled &&\n this.config.serviceWorker.crossTabSync &&\n typeof BroadcastChannel !== \"undefined\"\n ) {\n this.broadcastChannel = new BroadcastChannel(\n this.config.serviceWorker.broadcastChannel\n );\n this.broadcastChannel.onmessage = this.handleBroadcast;\n }\n }\n\n async get(href: string): Promise<string | null> {\n if (this.isExcluded(href)) return null;\n\n // L1: Memory cache\n const memoryHit = this.getFromMemory(href);\n if (memoryHit) {\n this.onCacheHit?.(href, 1);\n return memoryHit;\n }\n\n // L2: Service Worker cache\n if (this.config.serviceWorker.enabled) {\n const swHit = await this.getFromServiceWorker(href);\n if (swHit) {\n this.onCacheHit?.(href, 2);\n this.setInMemory(href, swHit);\n return swHit;\n }\n }\n\n return null;\n }\n\n async set(href: string, html: string): Promise<void> {\n if (this.isExcluded(href)) return;\n\n // Sanitize href to prevent cache poisoning\n const sanitizedHref = this.sanitizeHref(href);\n if (!sanitizedHref) return;\n\n // Validate HTML doesn't contain dangerous inline scripts\n if (this.containsDangerousContent(html)) {\n console.warn(`Refusing to cache potentially dangerous content from ${sanitizedHref}`);\n return;\n }\n\n const page: CachedPage = {\n href: sanitizedHref,\n html,\n timestamp: Date.now(),\n ttl: this.config.serviceWorker.ttl,\n };\n\n // L1: Memory\n if (this.config.memory.enabled) {\n this.setInMemory(sanitizedHref, html);\n }\n\n // L2: Service Worker\n if (this.config.serviceWorker.enabled) {\n await this.setInServiceWorker(page);\n this.broadcastSet(sanitizedHref);\n }\n }\n\n private containsDangerousContent(html: string): boolean {\n // Check for inline event handlers and javascript: URLs\n const dangerousPatterns = [\n /on\\w+\\s*=\\s*[\"'][^\"']*[\"']/i, // Inline event handlers\n /javascript:/i, // javascript: URLs\n ];\n\n // Check for inline scripts, but exclude safe types\n const scriptRegex = /<script([^>]*)>([\\s\\S]*?)<\\/script>/gi;\n let match;\n while ((match = scriptRegex.exec(html)) !== null) {\n const attrs = match[1] || \"\";\n \n // Allow scripts with src attribute\n if (/src\\s*=/.test(attrs)) continue;\n \n // Allow safe script types (JSON data, templates)\n if (/type\\s*=\\s*[\"']?(application\\/json|application\\/ld\\+json|text\\/template)[\"']?/i.test(attrs)) continue;\n \n // Allow Next.js scripts\n if (/id\\s*=\\s*[\"']__NEXT_DATA__[\"']/i.test(attrs)) continue;\n if (/data-nscript\\s*=/i.test(attrs)) continue;\n \n // Allow module scripts (Next.js uses these for hydration)\n if (/type\\s*=\\s*[\"']?module[\"']?/i.test(attrs)) continue;\n \n // If we get here, it's an inline script without safe type\n return true;\n }\n\n return dangerousPatterns.some(pattern => pattern.test(html));\n }\n\n private sanitizeHref(href: string): string | null {\n try {\n const url = new URL(href, window.location.origin);\n // Only allow same-origin URLs\n if (url.origin !== window.location.origin) return null;\n return url.pathname + url.search + url.hash;\n } catch {\n return null;\n }\n }\n\n clear(href?: string): void {\n if (href) {\n this.memoryCache.delete(href);\n this.accessOrder = this.accessOrder.filter((h) => h !== href);\n this.clearFromServiceWorker(href);\n } else {\n this.memoryCache.clear();\n this.accessOrder = [];\n this.clearAllServiceWorker();\n }\n }\n\n getSize(): number {\n return this.memoryCache.size;\n }\n\n destroy(): void {\n this.memoryCache.clear();\n this.accessOrder = [];\n this.broadcastChannel?.close();\n }\n\n private getFromMemory(href: string): string | null {\n const page = this.memoryCache.get(href);\n if (!page) return null;\n\n // Update LRU order\n this.accessOrder = this.accessOrder.filter((h) => h !== href);\n this.accessOrder.push(href);\n\n return page.html;\n }\n\n private setInMemory(href: string, html: string): void {\n // Prevent memory exhaustion - limit individual page size\n const maxPageSize = 5 * 1024 * 1024; // 5MB per page\n if (html.length > maxPageSize) {\n console.warn(`Page ${href} exceeds max size, not caching`);\n return;\n }\n\n this.memoryCache.set(href, {\n href,\n html,\n timestamp: Date.now(),\n ttl: this.config.serviceWorker.ttl,\n });\n\n // Deduplicate before adding to accessOrder\n const existingIndex = this.accessOrder.indexOf(href);\n if (existingIndex !== -1) {\n this.accessOrder.splice(existingIndex, 1);\n }\n this.accessOrder.push(href);\n\n // LRU eviction\n if (this.memoryCache.size > this.config.memory.maxPages) {\n const oldest = this.accessOrder.shift();\n if (oldest) this.memoryCache.delete(oldest);\n }\n }\n\n private async getFromServiceWorker(href: string): Promise<string | null> {\n if (typeof caches === \"undefined\") return null;\n\n try {\n const cache = await caches.open(this.config.serviceWorker.cacheName);\n const response = await cache.match(href);\n\n if (!response) return null;\n\n const data = await response.json();\n const page = data as CachedPage;\n\n // Check TTL\n const age = Date.now() - page.timestamp;\n if (age > page.ttl * 1000) {\n await cache.delete(href);\n return null;\n }\n\n return page.html;\n } catch {\n return null;\n }\n }\n\n private async setInServiceWorker(page: CachedPage): Promise<void> {\n if (typeof caches === \"undefined\") return;\n\n try {\n const cache = await caches.open(this.config.serviceWorker.cacheName);\n const response = new Response(JSON.stringify(page), {\n headers: {\n \"Content-Type\": \"application/json\",\n \"Cache-Control\": `max-age=${this.config.edge.maxAge}, stale-while-revalidate=${this.config.edge.staleWhileRevalidate}`,\n },\n });\n await cache.put(page.href, response);\n } catch {\n // Silently fail\n }\n }\n\n private async clearFromServiceWorker(href: string): Promise<void> {\n if (typeof caches === \"undefined\") return;\n\n try {\n const cache = await caches.open(this.config.serviceWorker.cacheName);\n await cache.delete(href);\n } catch {\n // Silently fail\n }\n }\n\n private async clearAllServiceWorker(): Promise<void> {\n if (typeof caches === \"undefined\") return;\n\n try {\n await caches.delete(this.config.serviceWorker.cacheName);\n } catch {\n // Silently fail\n }\n }\n\n private isExcluded(href: string): boolean {\n return this.config.exclude.some((pattern) => {\n if (typeof pattern === \"string\") {\n return pattern.includes(\"*\")\n ? new RegExp(pattern.replace(/\\*/g, \".*\")).test(href)\n : href === pattern;\n }\n return pattern.test(href);\n });\n }\n\n private broadcastSet(href: string): void {\n this.broadcastChannel?.postMessage({ type: \"set\", href });\n }\n\n private handleBroadcast = (event: MessageEvent): void => {\n if (event.data.type === \"set\") {\n // Invalidate memory cache to force fetch from SW\n this.memoryCache.delete(event.data.href);\n }\n };\n}\n\nexport function createCacheManager(\n config?: Partial<CacheConfig>,\n callbacks?: { onCacheHit?: (href: string, layer: CacheLayer) => void }\n): CacheManager {\n return new CacheManager(config, callbacks);\n}\n"]}
package/dist/graph.js CHANGED
@@ -1,3 +1,5 @@
1
+ 'use strict';
2
+
1
3
  // src/graph.ts
2
4
  var DEFAULT_CONFIG = {
3
5
  enabled: true,
@@ -123,6 +125,8 @@ function getNavigationGraph(storageKey = "specnav-graph") {
123
125
  }
124
126
  }
125
127
 
126
- export { NavigationGraphLearner, createNavigationGraphLearner, getNavigationGraph };
128
+ exports.NavigationGraphLearner = NavigationGraphLearner;
129
+ exports.createNavigationGraphLearner = createNavigationGraphLearner;
130
+ exports.getNavigationGraph = getNavigationGraph;
127
131
  //# sourceMappingURL=graph.js.map
128
132
  //# sourceMappingURL=graph.js.map
package/dist/graph.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/graph.ts"],"names":[],"mappings":"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","file":"graph.js","sourcesContent":["import type { GraphConfig, NavigationGraph } from \"./types\";\n\nconst DEFAULT_CONFIG: GraphConfig = {\n enabled: true,\n minConfidence: 0.6,\n sessionWeight: 0.7,\n storageKey: \"specnav-graph\",\n maxNodes: 50,\n};\n\nexport class NavigationGraphLearner {\n private config: GraphConfig;\n private graph: NavigationGraph = {};\n private sessionGraph: NavigationGraph = {};\n\n constructor(config: Partial<GraphConfig> = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n if (this.config.enabled) {\n this.loadGraph();\n }\n }\n\n recordNavigation(fromHref: string, toHref: string): void {\n if (!this.config.enabled) return;\n\n // Update session graph\n if (!this.sessionGraph[fromHref]) {\n this.sessionGraph[fromHref] = {};\n }\n const current = this.sessionGraph[fromHref]![toHref] ?? 0;\n this.sessionGraph[fromHref]![toHref] = current + 1;\n\n // Update persistent graph\n if (!this.graph[fromHref]) {\n this.graph[fromHref] = {};\n }\n const persistentCurrent = this.graph[fromHref]![toHref] ?? 0;\n this.graph[fromHref]![toHref] = persistentCurrent + 1;\n\n this.saveGraph();\n }\n\n getPredictions(fromHref: string): string[] {\n if (!this.config.enabled) return [];\n\n const sessionEdges = this.sessionGraph[fromHref] ?? {};\n const persistentEdges = this.graph[fromHref] ?? {};\n\n // Merge session and persistent with weighting\n const merged: Record<string, number> = {};\n\n Object.entries(persistentEdges).forEach(([href, count]) => {\n merged[href] = count * (1 - this.config.sessionWeight);\n });\n\n Object.entries(sessionEdges).forEach(([href, count]) => {\n merged[href] = (merged[href] ?? 0) + count * this.config.sessionWeight;\n });\n\n // Calculate total for normalization\n const total = Object.values(merged).reduce((sum, val) => sum + val, 0);\n if (total === 0) return [];\n\n // Convert to confidence scores and filter\n const predictions = Object.entries(merged)\n .map(([href, count]) => ({\n href,\n confidence: count / total,\n }))\n .filter((p) => p.confidence >= this.config.minConfidence)\n .sort((a, b) => b.confidence - a.confidence)\n .map((p) => p.href);\n\n return predictions;\n }\n\n getGraph(): NavigationGraph {\n return { ...this.graph };\n }\n\n clearGraph(): void {\n this.graph = {};\n this.sessionGraph = {};\n this.saveGraph();\n }\n\n private loadGraph(): void {\n if (typeof localStorage === \"undefined\") return;\n\n try {\n const stored = localStorage.getItem(this.config.storageKey);\n if (stored) {\n this.graph = JSON.parse(stored);\n this.pruneGraph();\n }\n } catch {\n // Silently fail\n }\n }\n\n private saveGraph(): void {\n if (typeof localStorage === \"undefined\") return;\n\n try {\n this.pruneGraph();\n const serialized = JSON.stringify(this.graph);\n \n // Check size before saving (localStorage typically has 5-10MB limit)\n if (serialized.length > 4 * 1024 * 1024) { // 4MB safety limit\n console.warn(\"Navigation graph too large, pruning more aggressively\");\n // Prune to half the max nodes (use local variable)\n const reducedMaxNodes = Math.floor(this.config.maxNodes / 2);\n const originalMaxNodes = this.config.maxNodes;\n this.config.maxNodes = reducedMaxNodes;\n this.pruneGraph();\n this.config.maxNodes = originalMaxNodes; // Restore original\n }\n \n localStorage.setItem(this.config.storageKey, JSON.stringify(this.graph));\n } catch (error) {\n // Handle quota exceeded error\n if (error instanceof Error && error.name === \"QuotaExceededError\") {\n console.warn(\"localStorage quota exceeded, clearing navigation graph\");\n this.clearGraph();\n }\n }\n }\n\n private pruneGraph(): void {\n const nodes = Object.keys(this.graph);\n if (nodes.length <= this.config.maxNodes) return;\n\n // Calculate total transitions per node\n const nodeCounts = nodes.map((node) => ({\n node,\n count: Object.values(this.graph[node]!).reduce(\n (sum, val) => sum + val,\n 0\n ),\n }));\n\n // Sort by count and keep top maxNodes\n nodeCounts.sort((a, b) => b.count - a.count);\n const toKeep = new Set(\n nodeCounts.slice(0, this.config.maxNodes).map((n) => n.node)\n );\n\n // Remove nodes not in top set\n Object.keys(this.graph).forEach((node) => {\n if (!toKeep.has(node)) {\n delete this.graph[node];\n }\n });\n }\n}\n\nexport function createNavigationGraphLearner(\n config?: Partial<GraphConfig>\n): NavigationGraphLearner {\n return new NavigationGraphLearner(config);\n}\n\nexport function getNavigationGraph(\n storageKey = \"specnav-graph\"\n): NavigationGraph {\n if (typeof localStorage === \"undefined\") return {};\n\n try {\n const stored = localStorage.getItem(storageKey);\n return stored ? JSON.parse(stored) : {};\n } catch {\n return {};\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/graph.ts"],"names":[],"mappings":"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","file":"graph.js","sourcesContent":["import type { GraphConfig, NavigationGraph } from \"./types\";\n\nconst DEFAULT_CONFIG: GraphConfig = {\n enabled: true,\n minConfidence: 0.6,\n sessionWeight: 0.7,\n storageKey: \"specnav-graph\",\n maxNodes: 50,\n};\n\nexport class NavigationGraphLearner {\n private config: GraphConfig;\n private graph: NavigationGraph = {};\n private sessionGraph: NavigationGraph = {};\n\n constructor(config: Partial<GraphConfig> = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n if (this.config.enabled) {\n this.loadGraph();\n }\n }\n\n recordNavigation(fromHref: string, toHref: string): void {\n if (!this.config.enabled) return;\n\n // Update session graph\n if (!this.sessionGraph[fromHref]) {\n this.sessionGraph[fromHref] = {};\n }\n const current = this.sessionGraph[fromHref]![toHref] ?? 0;\n this.sessionGraph[fromHref]![toHref] = current + 1;\n\n // Update persistent graph\n if (!this.graph[fromHref]) {\n this.graph[fromHref] = {};\n }\n const persistentCurrent = this.graph[fromHref]![toHref] ?? 0;\n this.graph[fromHref]![toHref] = persistentCurrent + 1;\n\n this.saveGraph();\n }\n\n getPredictions(fromHref: string): string[] {\n if (!this.config.enabled) return [];\n\n const sessionEdges = this.sessionGraph[fromHref] ?? {};\n const persistentEdges = this.graph[fromHref] ?? {};\n\n // Merge session and persistent with weighting\n const merged: Record<string, number> = {};\n\n Object.entries(persistentEdges).forEach(([href, count]) => {\n merged[href] = count * (1 - this.config.sessionWeight);\n });\n\n Object.entries(sessionEdges).forEach(([href, count]) => {\n merged[href] = (merged[href] ?? 0) + count * this.config.sessionWeight;\n });\n\n // Calculate total for normalization\n const total = Object.values(merged).reduce((sum, val) => sum + val, 0);\n if (total === 0) return [];\n\n // Convert to confidence scores and filter\n const predictions = Object.entries(merged)\n .map(([href, count]) => ({\n href,\n confidence: count / total,\n }))\n .filter((p) => p.confidence >= this.config.minConfidence)\n .sort((a, b) => b.confidence - a.confidence)\n .map((p) => p.href);\n\n return predictions;\n }\n\n getGraph(): NavigationGraph {\n return { ...this.graph };\n }\n\n clearGraph(): void {\n this.graph = {};\n this.sessionGraph = {};\n this.saveGraph();\n }\n\n private loadGraph(): void {\n if (typeof localStorage === \"undefined\") return;\n\n try {\n const stored = localStorage.getItem(this.config.storageKey);\n if (stored) {\n this.graph = JSON.parse(stored);\n this.pruneGraph();\n }\n } catch {\n // Silently fail\n }\n }\n\n private saveGraph(): void {\n if (typeof localStorage === \"undefined\") return;\n\n try {\n this.pruneGraph();\n const serialized = JSON.stringify(this.graph);\n \n // Check size before saving (localStorage typically has 5-10MB limit)\n if (serialized.length > 4 * 1024 * 1024) { // 4MB safety limit\n console.warn(\"Navigation graph too large, pruning more aggressively\");\n // Prune to half the max nodes (use local variable)\n const reducedMaxNodes = Math.floor(this.config.maxNodes / 2);\n const originalMaxNodes = this.config.maxNodes;\n this.config.maxNodes = reducedMaxNodes;\n this.pruneGraph();\n this.config.maxNodes = originalMaxNodes; // Restore original\n }\n \n localStorage.setItem(this.config.storageKey, JSON.stringify(this.graph));\n } catch (error) {\n // Handle quota exceeded error\n if (error instanceof Error && error.name === \"QuotaExceededError\") {\n console.warn(\"localStorage quota exceeded, clearing navigation graph\");\n this.clearGraph();\n }\n }\n }\n\n private pruneGraph(): void {\n const nodes = Object.keys(this.graph);\n if (nodes.length <= this.config.maxNodes) return;\n\n // Calculate total transitions per node\n const nodeCounts = nodes.map((node) => ({\n node,\n count: Object.values(this.graph[node]!).reduce(\n (sum, val) => sum + val,\n 0\n ),\n }));\n\n // Sort by count and keep top maxNodes\n nodeCounts.sort((a, b) => b.count - a.count);\n const toKeep = new Set(\n nodeCounts.slice(0, this.config.maxNodes).map((n) => n.node)\n );\n\n // Remove nodes not in top set\n Object.keys(this.graph).forEach((node) => {\n if (!toKeep.has(node)) {\n delete this.graph[node];\n }\n });\n }\n}\n\nexport function createNavigationGraphLearner(\n config?: Partial<GraphConfig>\n): NavigationGraphLearner {\n return new NavigationGraphLearner(config);\n}\n\nexport function getNavigationGraph(\n storageKey = \"specnav-graph\"\n): NavigationGraph {\n if (typeof localStorage === \"undefined\") return {};\n\n try {\n const stored = localStorage.getItem(storageKey);\n return stored ? JSON.parse(stored) : {};\n } catch {\n return {};\n }\n}\n"]}
@@ -1,5 +1,3 @@
1
- 'use strict';
2
-
3
1
  // src/graph.ts
4
2
  var DEFAULT_CONFIG = {
5
3
  enabled: true,
@@ -125,8 +123,6 @@ function getNavigationGraph(storageKey = "specnav-graph") {
125
123
  }
126
124
  }
127
125
 
128
- exports.NavigationGraphLearner = NavigationGraphLearner;
129
- exports.createNavigationGraphLearner = createNavigationGraphLearner;
130
- exports.getNavigationGraph = getNavigationGraph;
131
- //# sourceMappingURL=graph.cjs.map
132
- //# sourceMappingURL=graph.cjs.map
126
+ export { NavigationGraphLearner, createNavigationGraphLearner, getNavigationGraph };
127
+ //# sourceMappingURL=graph.mjs.map
128
+ //# sourceMappingURL=graph.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/graph.ts"],"names":[],"mappings":"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","file":"graph.mjs","sourcesContent":["import type { GraphConfig, NavigationGraph } from \"./types\";\n\nconst DEFAULT_CONFIG: GraphConfig = {\n enabled: true,\n minConfidence: 0.6,\n sessionWeight: 0.7,\n storageKey: \"specnav-graph\",\n maxNodes: 50,\n};\n\nexport class NavigationGraphLearner {\n private config: GraphConfig;\n private graph: NavigationGraph = {};\n private sessionGraph: NavigationGraph = {};\n\n constructor(config: Partial<GraphConfig> = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n if (this.config.enabled) {\n this.loadGraph();\n }\n }\n\n recordNavigation(fromHref: string, toHref: string): void {\n if (!this.config.enabled) return;\n\n // Update session graph\n if (!this.sessionGraph[fromHref]) {\n this.sessionGraph[fromHref] = {};\n }\n const current = this.sessionGraph[fromHref]![toHref] ?? 0;\n this.sessionGraph[fromHref]![toHref] = current + 1;\n\n // Update persistent graph\n if (!this.graph[fromHref]) {\n this.graph[fromHref] = {};\n }\n const persistentCurrent = this.graph[fromHref]![toHref] ?? 0;\n this.graph[fromHref]![toHref] = persistentCurrent + 1;\n\n this.saveGraph();\n }\n\n getPredictions(fromHref: string): string[] {\n if (!this.config.enabled) return [];\n\n const sessionEdges = this.sessionGraph[fromHref] ?? {};\n const persistentEdges = this.graph[fromHref] ?? {};\n\n // Merge session and persistent with weighting\n const merged: Record<string, number> = {};\n\n Object.entries(persistentEdges).forEach(([href, count]) => {\n merged[href] = count * (1 - this.config.sessionWeight);\n });\n\n Object.entries(sessionEdges).forEach(([href, count]) => {\n merged[href] = (merged[href] ?? 0) + count * this.config.sessionWeight;\n });\n\n // Calculate total for normalization\n const total = Object.values(merged).reduce((sum, val) => sum + val, 0);\n if (total === 0) return [];\n\n // Convert to confidence scores and filter\n const predictions = Object.entries(merged)\n .map(([href, count]) => ({\n href,\n confidence: count / total,\n }))\n .filter((p) => p.confidence >= this.config.minConfidence)\n .sort((a, b) => b.confidence - a.confidence)\n .map((p) => p.href);\n\n return predictions;\n }\n\n getGraph(): NavigationGraph {\n return { ...this.graph };\n }\n\n clearGraph(): void {\n this.graph = {};\n this.sessionGraph = {};\n this.saveGraph();\n }\n\n private loadGraph(): void {\n if (typeof localStorage === \"undefined\") return;\n\n try {\n const stored = localStorage.getItem(this.config.storageKey);\n if (stored) {\n this.graph = JSON.parse(stored);\n this.pruneGraph();\n }\n } catch {\n // Silently fail\n }\n }\n\n private saveGraph(): void {\n if (typeof localStorage === \"undefined\") return;\n\n try {\n this.pruneGraph();\n const serialized = JSON.stringify(this.graph);\n \n // Check size before saving (localStorage typically has 5-10MB limit)\n if (serialized.length > 4 * 1024 * 1024) { // 4MB safety limit\n console.warn(\"Navigation graph too large, pruning more aggressively\");\n // Prune to half the max nodes (use local variable)\n const reducedMaxNodes = Math.floor(this.config.maxNodes / 2);\n const originalMaxNodes = this.config.maxNodes;\n this.config.maxNodes = reducedMaxNodes;\n this.pruneGraph();\n this.config.maxNodes = originalMaxNodes; // Restore original\n }\n \n localStorage.setItem(this.config.storageKey, JSON.stringify(this.graph));\n } catch (error) {\n // Handle quota exceeded error\n if (error instanceof Error && error.name === \"QuotaExceededError\") {\n console.warn(\"localStorage quota exceeded, clearing navigation graph\");\n this.clearGraph();\n }\n }\n }\n\n private pruneGraph(): void {\n const nodes = Object.keys(this.graph);\n if (nodes.length <= this.config.maxNodes) return;\n\n // Calculate total transitions per node\n const nodeCounts = nodes.map((node) => ({\n node,\n count: Object.values(this.graph[node]!).reduce(\n (sum, val) => sum + val,\n 0\n ),\n }));\n\n // Sort by count and keep top maxNodes\n nodeCounts.sort((a, b) => b.count - a.count);\n const toKeep = new Set(\n nodeCounts.slice(0, this.config.maxNodes).map((n) => n.node)\n );\n\n // Remove nodes not in top set\n Object.keys(this.graph).forEach((node) => {\n if (!toKeep.has(node)) {\n delete this.graph[node];\n }\n });\n }\n}\n\nexport function createNavigationGraphLearner(\n config?: Partial<GraphConfig>\n): NavigationGraphLearner {\n return new NavigationGraphLearner(config);\n}\n\nexport function getNavigationGraph(\n storageKey = \"specnav-graph\"\n): NavigationGraph {\n if (typeof localStorage === \"undefined\") return {};\n\n try {\n const stored = localStorage.getItem(storageKey);\n return stored ? JSON.parse(stored) : {};\n } catch {\n return {};\n }\n}\n"]}
package/dist/index.js CHANGED
@@ -1,3 +1,5 @@
1
+ 'use strict';
2
+
1
3
  // src/trajectory.ts
2
4
  var DEFAULT_CONFIG = {
3
5
  lookaheadMs: 120,
@@ -227,6 +229,8 @@ var CacheManager = class {
227
229
  if (/src\s*=/.test(attrs)) continue;
228
230
  if (/type\s*=\s*["']?(application\/json|application\/ld\+json|text\/template)["']?/i.test(attrs)) continue;
229
231
  if (/id\s*=\s*["']__NEXT_DATA__["']/i.test(attrs)) continue;
232
+ if (/data-nscript\s*=/i.test(attrs)) continue;
233
+ if (/type\s*=\s*["']?module["']?/i.test(attrs)) continue;
230
234
  return true;
231
235
  }
232
236
  return dangerousPatterns.some((pattern) => pattern.test(html));
@@ -821,6 +825,21 @@ var PerformanceMonitor = class {
821
825
  };
822
826
  var performanceMonitor = new PerformanceMonitor();
823
827
 
824
- export { AdaptiveMode, CacheManager, DOMmorpher, NavigationGraphLearner, PerformanceMonitor, SpeculativeRenderer, TrajectoryEngine, createAdaptiveMode, createCacheManager, createMorpher, createNavigationGraphLearner, createSpeculativeRenderer, createTrajectoryEngine, getNavigationGraph, morph, performanceMonitor };
828
+ exports.AdaptiveMode = AdaptiveMode;
829
+ exports.CacheManager = CacheManager;
830
+ exports.DOMmorpher = DOMmorpher;
831
+ exports.NavigationGraphLearner = NavigationGraphLearner;
832
+ exports.PerformanceMonitor = PerformanceMonitor;
833
+ exports.SpeculativeRenderer = SpeculativeRenderer;
834
+ exports.TrajectoryEngine = TrajectoryEngine;
835
+ exports.createAdaptiveMode = createAdaptiveMode;
836
+ exports.createCacheManager = createCacheManager;
837
+ exports.createMorpher = createMorpher;
838
+ exports.createNavigationGraphLearner = createNavigationGraphLearner;
839
+ exports.createSpeculativeRenderer = createSpeculativeRenderer;
840
+ exports.createTrajectoryEngine = createTrajectoryEngine;
841
+ exports.getNavigationGraph = getNavigationGraph;
842
+ exports.morph = morph;
843
+ exports.performanceMonitor = performanceMonitor;
825
844
  //# sourceMappingURL=index.js.map
826
845
  //# sourceMappingURL=index.js.map