@reidelsaltres/pureper 0.2.14 → 0.2.17

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 (65) hide show
  1. package/out/foundation/Fetcher.d.ts.map +1 -1
  2. package/out/foundation/Fetcher.js +8 -13
  3. package/out/foundation/Fetcher.js.map +1 -1
  4. package/out/foundation/Injection.d.ts +87 -0
  5. package/out/foundation/Injection.d.ts.map +1 -0
  6. package/out/foundation/Injection.js +149 -0
  7. package/out/foundation/Injection.js.map +1 -0
  8. package/out/foundation/Theme.d.ts.map +1 -1
  9. package/out/foundation/Theme.js +16 -1
  10. package/out/foundation/Theme.js.map +1 -1
  11. package/out/foundation/Triplet.d.ts +30 -25
  12. package/out/foundation/Triplet.d.ts.map +1 -1
  13. package/out/foundation/Triplet.js +96 -115
  14. package/out/foundation/Triplet.js.map +1 -1
  15. package/out/foundation/TripletDecorator.d.ts +11 -0
  16. package/out/foundation/TripletDecorator.d.ts.map +1 -1
  17. package/out/foundation/TripletDecorator.js +25 -8
  18. package/out/foundation/TripletDecorator.js.map +1 -1
  19. package/out/foundation/component_api/Component.d.ts.map +1 -1
  20. package/out/foundation/component_api/Component.js +1 -0
  21. package/out/foundation/component_api/Component.js.map +1 -1
  22. package/out/foundation/component_api/UniHtml.d.ts +6 -1
  23. package/out/foundation/component_api/UniHtml.d.ts.map +1 -1
  24. package/out/foundation/component_api/UniHtml.js +32 -7
  25. package/out/foundation/component_api/UniHtml.js.map +1 -1
  26. package/out/foundation/engine/Expression.d.ts +2 -0
  27. package/out/foundation/engine/Expression.d.ts.map +1 -1
  28. package/out/foundation/engine/Expression.js +26 -11
  29. package/out/foundation/engine/Expression.js.map +1 -1
  30. package/out/foundation/engine/StylePreprocessor.js +2 -1
  31. package/out/foundation/engine/StylePreprocessor.js.map +1 -1
  32. package/out/foundation/engine/TemplateEngine.d.ts +3 -1
  33. package/out/foundation/engine/TemplateEngine.d.ts.map +1 -1
  34. package/out/foundation/engine/TemplateEngine.js +44 -15
  35. package/out/foundation/engine/TemplateEngine.js.map +1 -1
  36. package/out/foundation/worker/Router.d.ts.map +1 -1
  37. package/out/foundation/worker/Router.js +6 -0
  38. package/out/foundation/worker/Router.js.map +1 -1
  39. package/out/foundation/worker/ServiceWorker.d.ts +48 -17
  40. package/out/foundation/worker/ServiceWorker.d.ts.map +1 -1
  41. package/out/foundation/worker/ServiceWorker.js +186 -119
  42. package/out/foundation/worker/ServiceWorker.js.map +1 -1
  43. package/out/index.d.ts +3 -2
  44. package/out/index.d.ts.map +1 -1
  45. package/out/index.js +2 -1
  46. package/out/index.js.map +1 -1
  47. package/package.json +1 -1
  48. package/src/foundation/Fetcher.ts +9 -14
  49. package/src/foundation/Injection.ts +183 -0
  50. package/src/foundation/Theme.ts +17 -3
  51. package/src/foundation/Triplet.ts +114 -141
  52. package/src/foundation/TripletDecorator.ts +32 -8
  53. package/src/foundation/component_api/Component.ts +1 -0
  54. package/src/foundation/component_api/UniHtml.ts +35 -7
  55. package/src/foundation/engine/Expression.ts +34 -20
  56. package/src/foundation/engine/StylePreprocessor.ts +1 -1
  57. package/src/foundation/engine/TemplateEngine.ts +42 -15
  58. package/src/foundation/worker/Router.ts +10 -3
  59. package/src/foundation/worker/ServiceWorker.ts +203 -129
  60. package/src/foundation/worker/serviceworker.js +191 -0
  61. package/src/index.ts +7 -4
  62. package/out/foundation/worker/serviceworker.d.ts +0 -1
  63. package/out/foundation/worker/serviceworker.d.ts.map +0 -1
  64. package/out/foundation/worker/serviceworker.js +0 -2
  65. package/out/foundation/worker/serviceworker.js.map +0 -1
@@ -1,144 +1,211 @@
1
- const swSelf = self;
2
- // Автоматически генерируем CACHE_NAME из base.json
3
- //import base from '../../../data/base.json';
4
- const CACHE_NAME = `pureper-v1`;
5
- const STATIC_ASSETS = [
6
- '/index.html'
7
- ];
8
- /*if ('serviceWorker' in navigator) {
9
- window.addEventListener('load', () => {
10
- navigator.serviceWorker.register('./serviceWorker.js', { type: 'module' })
11
- .then((registration) => {
12
- console.log('ServiceWorker registration successful:', registration.scope);
13
- })
14
- .catch((error) => {
15
- console.error('ServiceWorker registration failed:', error);
16
- });
17
- });
18
- window.addEventListener('fetch', (event: FetchEvent) => {
19
- event.respondWith(
20
- caches.match(event.request).then((cachedResponse) => {
21
- console.log(`[ServiceWorker]: Fetching ${event.request.url}`);
22
- return cachedResponse || fetch(event.request);
23
- })
24
- );
25
- });
26
- }
27
-
1
+ import Observable from "../api/Observer.js";
28
2
  /**
29
- * Install event - cache static assets
3
+ * Client-side Service Worker manager for Purper SPA.
4
+ *
5
+ * Provides:
6
+ * - Registration with one call (`ServiceWorker.register()`)
7
+ * - Cache management: add / remove / list / clear
8
+ * - Connectivity detection with reactive `online` observable
9
+ *
10
+ * Usage:
11
+ * ```ts
12
+ * await ServiceWorker.register(); // defaults to './serviceworker.js'
13
+ * await ServiceWorker.addToCache('/data.json');
14
+ * await ServiceWorker.removeFromCache('/old.css');
15
+ * ServiceWorker.online.subscribe(v => console.log('online:', v));
16
+ * ```
30
17
  */
31
- /*window.addEventListener('install', (event: ExtendableEvent) => {
32
- console.log('ServiceWorker: Installing...');
33
- const assetsToCache = [
34
- ...STATIC_ASSETS
35
- ];
36
- // Remove duplicates
37
- const uniqueAssets = Array.from(new Set(assetsToCache));
38
- event.waitUntil(
39
- caches.open(CACHE_NAME)
40
- .then((cache: Cache) => {
41
- console.log('ServiceWorker: Caching static assets and SPA routes');
42
- return cache.addAll(uniqueAssets);
43
- })
44
- .then(() => {
45
- console.log('ServiceWorker: Installation complete');
46
- return swSelf.skipWaiting();
47
- })
48
- );
49
- });*/
50
18
  export default class ServiceWorker {
51
- /**
52
- * Sends a message to the service worker to cache a specific URL.
53
- * @param url The URL of the resource to cache.
54
- */
55
- static async addToCache(url) {
56
- if ('serviceWorker' in navigator && navigator.serviceWorker.controller) {
57
- navigator.serviceWorker.controller.postMessage({
58
- type: 'CACHE_URL',
59
- url: url
19
+ static _registration;
20
+ /** Observable connectivity state subscribe for real-time changes. */
21
+ static online = new Observable(navigator.onLine);
22
+ // ── Connectivity listeners (bound once) ─────────────────────────
23
+ static _connectivityBound = false;
24
+ static _bindConnectivity() {
25
+ if (this._connectivityBound)
26
+ return;
27
+ this._connectivityBound = true;
28
+ window.addEventListener('online', () => {
29
+ console.log('[ServiceWorker]: Browser went online');
30
+ this.online.setObject(true);
31
+ });
32
+ window.addEventListener('offline', () => {
33
+ console.log('[ServiceWorker]: Browser went offline');
34
+ this.online.setObject(false);
35
+ });
36
+ }
37
+ // ── Registration ────────────────────────────────────────────────
38
+ static async register(config) {
39
+ if (!('serviceWorker' in navigator)) {
40
+ console.warn('[ServiceWorker]: Service Workers are not supported in this browser');
41
+ return undefined;
42
+ }
43
+ this._bindConnectivity();
44
+ const scriptURL = config?.scriptURL ?? './serviceworker.js';
45
+ const scope = config?.scope ?? '/';
46
+ try {
47
+ const reg = await navigator.serviceWorker.register(scriptURL, { scope });
48
+ this._registration = reg;
49
+ console.log(`[ServiceWorker]: Registered "${scriptURL}" with scope "${reg.scope}"`);
50
+ reg.addEventListener('updatefound', () => {
51
+ const newWorker = reg.installing;
52
+ if (!newWorker)
53
+ return;
54
+ console.log('[ServiceWorker]: New version installing...');
55
+ newWorker.addEventListener('statechange', () => {
56
+ if (newWorker.state === 'activated') {
57
+ console.log('[ServiceWorker]: New version activated');
58
+ }
59
+ });
60
60
  });
61
+ // Wait for the controller to be available
62
+ if (!navigator.serviceWorker.controller) {
63
+ await new Promise((resolve) => {
64
+ navigator.serviceWorker.addEventListener('controllerchange', () => resolve(), { once: true });
65
+ });
66
+ }
67
+ return reg;
61
68
  }
62
- else {
63
- // Fallback: try to cache directly using the Cache API
64
- try {
65
- const cache = await caches.open('pureper-v1');
66
- const response = await fetch(url);
67
- if (response.ok) {
68
- await cache.put(url, response);
69
- console.log('[ServiceWorker]: Resource cached directly:', url);
70
- }
69
+ catch (err) {
70
+ console.error('[ServiceWorker]: Registration failed', err);
71
+ return undefined;
72
+ }
73
+ }
74
+ // ── Helpers ─────────────────────────────────────────────────────
75
+ static _postMessage(msg) {
76
+ navigator.serviceWorker?.controller?.postMessage(msg);
77
+ }
78
+ static _request(msg) {
79
+ return new Promise((resolve, reject) => {
80
+ if (!navigator.serviceWorker?.controller) {
81
+ reject('[ServiceWorker]: No active controller');
82
+ return;
71
83
  }
72
- catch (e) {
73
- console.warn('[ServiceWorker]: Failed to cache resource:', url, e);
84
+ const mc = new MessageChannel();
85
+ mc.port1.onmessage = (ev) => resolve(ev.data);
86
+ navigator.serviceWorker.controller.postMessage(msg, [mc.port2]);
87
+ });
88
+ }
89
+ // ── Cache Management ────────────────────────────────────────────
90
+ /** Add a single URL to the SW cache. */
91
+ static async addToCache(url) {
92
+ if (navigator.serviceWorker?.controller) {
93
+ this._postMessage({ type: 'CACHE_URL', url });
94
+ return;
95
+ }
96
+ // Fallback: use Cache API directly
97
+ try {
98
+ const cache = await caches.open('purper-v1');
99
+ const response = await fetch(url);
100
+ if (response.ok) {
101
+ await cache.put(url, response);
102
+ console.log('[ServiceWorker]: Resource cached directly:', url);
74
103
  }
75
104
  }
76
- }
77
- /**
78
- * Asks the service worker to skip waiting and activate the new version.
79
- */
80
- static skipWaiting() {
81
- if ('serviceWorker' in navigator && navigator.serviceWorker.controller) {
82
- navigator.serviceWorker.controller.postMessage({ type: 'SKIP_WAITING' });
105
+ catch (e) {
106
+ console.warn('[ServiceWorker]: Failed to cache resource:', url, e);
83
107
  }
84
108
  }
85
- /**
86
- * Gets the version of the currently active service worker.
87
- * @returns A promise that resolves with the version string.
88
- */
89
- static getVersion() {
90
- return new Promise((resolve, reject) => {
91
- if ('serviceWorker' in navigator && navigator.serviceWorker.controller) {
92
- const messageChannel = new MessageChannel();
93
- messageChannel.port1.onmessage = (event) => {
94
- if (event.data.error) {
95
- reject(event.data.error);
96
- }
97
- else {
98
- resolve(event.data.version);
99
- }
100
- };
101
- navigator.serviceWorker.controller.postMessage({ type: 'GET_VERSION' }, [messageChannel.port2]);
109
+ /** Add multiple URLs to the SW cache in one batch. */
110
+ static addAllToCache(urls) {
111
+ this._postMessage({ type: 'CACHE_URLS', urls });
112
+ }
113
+ /** Remove a URL from the SW cache. Returns true if it was found and deleted. */
114
+ static async removeFromCache(url) {
115
+ try {
116
+ const data = await this._request({ type: 'REMOVE_URL', url });
117
+ return data.deleted;
118
+ }
119
+ catch {
120
+ // Fallback
121
+ try {
122
+ const cache = await caches.open('purper-v1');
123
+ return await cache.delete(url);
102
124
  }
103
- else {
104
- reject('Service worker not available.');
125
+ catch {
126
+ return false;
105
127
  }
106
- });
128
+ }
107
129
  }
108
- /**
109
- * Checks if the given URL is present in the Service Worker's cache.
110
- */
111
- static isCached(url) {
112
- return new Promise((resolve) => {
113
- if ('serviceWorker' in navigator && navigator.serviceWorker.controller) {
114
- const mc = new MessageChannel();
115
- mc.port1.onmessage = (ev) => {
116
- if (ev.data && typeof ev.data.cached === 'boolean') {
117
- resolve(ev.data.cached);
118
- }
119
- else {
120
- resolve(false);
121
- }
122
- };
123
- navigator.serviceWorker.controller.postMessage({ type: 'HAS_URL', url }, [mc.port2]);
130
+ /** Return all URLs currently in the SW cache. */
131
+ static async getCacheKeys() {
132
+ try {
133
+ const data = await this._request({ type: 'GET_CACHE_KEYS' });
134
+ return data.keys;
135
+ }
136
+ catch {
137
+ return [];
138
+ }
139
+ }
140
+ /** Wipe the entire SW cache. */
141
+ static async clearCache() {
142
+ try {
143
+ const data = await this._request({ type: 'CLEAR_CACHE' });
144
+ return data.cleared;
145
+ }
146
+ catch {
147
+ return false;
148
+ }
149
+ }
150
+ /** Check whether a URL exists in the SW cache. */
151
+ static async isCached(url) {
152
+ try {
153
+ const data = await this._request({ type: 'HAS_URL', url });
154
+ return data.cached;
155
+ }
156
+ catch {
157
+ // Fallback: CacheStorage directly
158
+ try {
159
+ return !!(await caches.match(url));
124
160
  }
125
- else {
126
- // Fallback: try CacheStorage directly (same-origin only)
127
- caches.match(url).then(match => resolve(!!match)).catch(() => resolve(false));
161
+ catch {
162
+ return false;
128
163
  }
129
- });
164
+ }
130
165
  }
166
+ // ── Version & lifecycle ─────────────────────────────────────────
167
+ /** Ask the waiting SW to activate immediately. */
168
+ static skipWaiting() {
169
+ this._postMessage({ type: 'SKIP_WAITING' });
170
+ }
171
+ /** Get the version string from the running SW. */
172
+ static async getVersion() {
173
+ const data = await this._request({ type: 'GET_VERSION' });
174
+ return data.version;
175
+ }
176
+ // ── Connectivity ────────────────────────────────────────────────
131
177
  /**
132
- * Checks if the browser is online.
178
+ * Active connectivity probe makes a real network request.
179
+ * Unlike `online` observable (which relies on browser events), this
180
+ * detects captive portals and lie-fi.
133
181
  */
134
- static async isOnline() {
182
+ static async isOnline(probeURL) {
135
183
  try {
136
- const response = await fetch('./index.html', { cache: 'no-store' });
137
- return response && response.ok;
184
+ // Try SW-side probe first
185
+ const data = await this._request({
186
+ type: 'IS_ONLINE',
187
+ url: probeURL ?? '/index.html'
188
+ });
189
+ this.online.setObject(data.online);
190
+ return data.online;
138
191
  }
139
192
  catch {
140
- return false;
193
+ // Fallback: client-side probe
194
+ try {
195
+ const response = await fetch(probeURL ?? './index.html', { cache: 'no-store', method: 'HEAD' });
196
+ const result = response.ok;
197
+ this.online.setObject(result);
198
+ return result;
199
+ }
200
+ catch {
201
+ this.online.setObject(false);
202
+ return false;
203
+ }
141
204
  }
142
205
  }
206
+ /** Current registration, if any. */
207
+ static get registration() {
208
+ return this._registration;
209
+ }
143
210
  }
144
211
  //# sourceMappingURL=ServiceWorker.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ServiceWorker.js","sourceRoot":"","sources":["../../../src/foundation/worker/ServiceWorker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ServiceWorker.js","sourceRoot":"","sources":["../../../src/foundation/worker/ServiceWorker.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,oBAAoB,CAAC;AAO5C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,OAAO,OAAO,aAAa;IACtB,MAAM,CAAC,aAAa,CAA6B;IAEzD,uEAAuE;IACvE,MAAM,CAAU,MAAM,GAAwB,IAAI,UAAU,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAE/E,mEAAmE;IAC3D,MAAM,CAAC,kBAAkB,GAAG,KAAK,CAAC;IAClC,MAAM,CAAC,iBAAiB;QAC5B,IAAI,IAAI,CAAC,kBAAkB;YAAE,OAAO;QACpC,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC;QAE/B,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,GAAG,EAAE;YACnC,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;YACpD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,GAAG,EAAE;YACpC,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;YACrD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;IACP,CAAC;IAED,mEAAmE;IACnE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAA4B;QAC9C,IAAI,CAAC,CAAC,eAAe,IAAI,SAAS,CAAC,EAAE,CAAC;YAClC,OAAO,CAAC,IAAI,CAAC,oEAAoE,CAAC,CAAC;YACnF,OAAO,SAAS,CAAC;QACrB,CAAC;QAED,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAEzB,MAAM,SAAS,GAAG,MAAM,EAAE,SAAS,IAAI,oBAAoB,CAAC;QAC5D,MAAM,KAAK,GAAG,MAAM,EAAE,KAAK,IAAI,GAAG,CAAC;QAEnC,IAAI,CAAC;YACD,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,aAAa,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;YACzE,IAAI,CAAC,aAAa,GAAG,GAAG,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,gCAAgC,SAAS,iBAAiB,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC;YAEpF,GAAG,CAAC,gBAAgB,CAAC,aAAa,EAAE,GAAG,EAAE;gBACrC,MAAM,SAAS,GAAG,GAAG,CAAC,UAAU,CAAC;gBACjC,IAAI,CAAC,SAAS;oBAAE,OAAO;gBACvB,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;gBAC1D,SAAS,CAAC,gBAAgB,CAAC,aAAa,EAAE,GAAG,EAAE;oBAC3C,IAAI,SAAS,CAAC,KAAK,KAAK,WAAW,EAAE,CAAC;wBAClC,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;oBAC1D,CAAC;gBACL,CAAC,CAAC,CAAC;YACP,CAAC,CAAC,CAAC;YAEH,0CAA0C;YAC1C,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,UAAU,EAAE,CAAC;gBACtC,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;oBAChC,SAAS,CAAC,aAAa,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;gBAClG,CAAC,CAAC,CAAC;YACP,CAAC;YAED,OAAO,GAAG,CAAC;QACf,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,GAAG,CAAC,CAAC;YAC3D,OAAO,SAAS,CAAC;QACrB,CAAC;IACL,CAAC;IAED,mEAAmE;IAC3D,MAAM,CAAC,YAAY,CAAC,GAAW;QACnC,SAAS,CAAC,aAAa,EAAE,UAAU,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC;IAC1D,CAAC;IAEO,MAAM,CAAC,QAAQ,CAAI,GAAW;QAClC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACnC,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,UAAU,EAAE,CAAC;gBACvC,MAAM,CAAC,uCAAuC,CAAC,CAAC;gBAChD,OAAO;YACX,CAAC;YACD,MAAM,EAAE,GAAG,IAAI,cAAc,EAAE,CAAC;YAChC,EAAE,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,IAAS,CAAC,CAAC;YACnD,SAAS,CAAC,aAAa,CAAC,UAAU,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QACpE,CAAC,CAAC,CAAC;IACP,CAAC;IAED,mEAAmE;IAEnE,wCAAwC;IACxC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,GAAW;QAC/B,IAAI,SAAS,CAAC,aAAa,EAAE,UAAU,EAAE,CAAC;YACtC,IAAI,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;YAC9C,OAAO;QACX,CAAC;QACD,mCAAmC;QACnC,IAAI,CAAC;YACD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC7C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;YAClC,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACd,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;gBAC/B,OAAO,CAAC,GAAG,CAAC,4CAA4C,EAAE,GAAG,CAAC,CAAC;YACnE,CAAC;QACL,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACT,OAAO,CAAC,IAAI,CAAC,4CAA4C,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;QACvE,CAAC;IACL,CAAC;IAED,sDAAsD;IACtD,MAAM,CAAC,aAAa,CAAC,IAAc;QAC/B,IAAI,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC;IAED,gFAAgF;IAChF,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,GAAW;QACpC,IAAI,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAuB,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC;YACpF,OAAO,IAAI,CAAC,OAAO,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACL,WAAW;YACX,IAAI,CAAC;gBACD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;gBAC7C,OAAO,MAAM,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACnC,CAAC;YAAC,MAAM,CAAC;gBACL,OAAO,KAAK,CAAC;YACjB,CAAC;QACL,CAAC;IACL,CAAC;IAED,iDAAiD;IACjD,MAAM,CAAC,KAAK,CAAC,YAAY;QACrB,IAAI,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAqB,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,CAAC;YACjF,OAAO,IAAI,CAAC,IAAI,CAAC;QACrB,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,EAAE,CAAC;QACd,CAAC;IACL,CAAC;IAED,gCAAgC;IAChC,MAAM,CAAC,KAAK,CAAC,UAAU;QACnB,IAAI,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAuB,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC;YAChF,OAAO,IAAI,CAAC,OAAO,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,KAAK,CAAC;QACjB,CAAC;IACL,CAAC;IAED,kDAAkD;IAClD,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAW;QAC7B,IAAI,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAsB,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;YAChF,OAAO,IAAI,CAAC,MAAM,CAAC;QACvB,CAAC;QAAC,MAAM,CAAC;YACL,kCAAkC;YAClC,IAAI,CAAC;gBACD,OAAO,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;YACvC,CAAC;YAAC,MAAM,CAAC;gBACL,OAAO,KAAK,CAAC;YACjB,CAAC;QACL,CAAC;IACL,CAAC;IAED,mEAAmE;IAEnE,kDAAkD;IAClD,MAAM,CAAC,WAAW;QACd,IAAI,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,kDAAkD;IAClD,MAAM,CAAC,KAAK,CAAC,UAAU;QACnB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAsB,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC;QAC/E,OAAO,IAAI,CAAC,OAAO,CAAC;IACxB,CAAC;IAED,mEAAmE;IAEnE;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAiB;QACnC,IAAI,CAAC;YACD,0BAA0B;YAC1B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAsB;gBAClD,IAAI,EAAE,WAAW;gBACjB,GAAG,EAAE,QAAQ,IAAI,aAAa;aACjC,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACnC,OAAO,IAAI,CAAC,MAAM,CAAC;QACvB,CAAC;QAAC,MAAM,CAAC;YACL,8BAA8B;YAC9B,IAAI,CAAC;gBACD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,IAAI,cAAc,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;gBAChG,MAAM,MAAM,GAAG,QAAQ,CAAC,EAAE,CAAC;gBAC3B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;gBAC9B,OAAO,MAAM,CAAC;YAClB,CAAC;YAAC,MAAM,CAAC;gBACL,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;gBAC7B,OAAO,KAAK,CAAC;YACjB,CAAC;QACL,CAAC;IACL,CAAC;IAED,oCAAoC;IACpC,MAAM,KAAK,YAAY;QACnB,OAAO,IAAI,CAAC,aAAa,CAAC;IAC9B,CAAC"}
package/out/index.d.ts CHANGED
@@ -8,11 +8,12 @@ export { default as Page } from './foundation/component_api/Page.js';
8
8
  export { default as Component } from './foundation/component_api/Component.js';
9
9
  export { default as Attribute } from './foundation/component_api/Attribute.js';
10
10
  export { default as Triplet, TripletStruct, AccessType } from './foundation/Triplet.js';
11
- export { ReComponent, RePage } from './foundation/TripletDecorator.js';
11
+ export { ReComponent, RePage, ReImplementation } from './foundation/TripletDecorator.js';
12
+ export { Implementation, ImplementationStruct, Placeholder } from './foundation/Injection.js';
12
13
  export { default as Fetcher } from './foundation/Fetcher.js';
13
14
  export * from './foundation/engine/TemplateEngine.js';
14
15
  export { Router } from './foundation/worker/Router.js';
15
- export { default as ServiceWorker } from './foundation/worker/ServiceWorker.js';
16
+ export { default as ServiceWorker, ServiceWorkerConfig } from './foundation/worker/ServiceWorker.js';
16
17
  export * from './foundation/Hosting.js';
17
18
  export * from './foundation/Theme.js';
18
19
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAE3D,cAAc,2CAA2C,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,UAAU,EAC7B,SAAS,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAC3F,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAEnD,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,uCAAuC,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAE/E,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACxF,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAC;AAEvE,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAE7D,cAAc,uCAAuC,CAAC;AAEtD,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,sCAAsC,CAAC;AAEhF,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAE3D,cAAc,2CAA2C,CAAC;AAC1D,OAAO,EACN,OAAO,IAAI,UAAU,EACrB,SAAS,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAC3F,YAAY,EACZ,MAAM,8BAA8B,CAAA;AAErC,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,uCAAuC,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAE/E,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACxF,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAEzF,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC9F,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAE7D,cAAc,uCAAuC,CAAC;AAEtD,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAErG,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC"}
package/out/index.js CHANGED
@@ -6,7 +6,8 @@ export { default as Page } from './foundation/component_api/Page.js';
6
6
  export { default as Component } from './foundation/component_api/Component.js';
7
7
  export { default as Attribute } from './foundation/component_api/Attribute.js';
8
8
  export { default as Triplet, AccessType } from './foundation/Triplet.js';
9
- export { ReComponent, RePage } from './foundation/TripletDecorator.js';
9
+ export { ReComponent, RePage, ReImplementation } from './foundation/TripletDecorator.js';
10
+ export { Implementation, Placeholder } from './foundation/Injection.js';
10
11
  export { default as Fetcher } from './foundation/Fetcher.js';
11
12
  export * from './foundation/engine/TemplateEngine.js';
12
13
  export { Router } from './foundation/worker/Router.js';
package/out/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAE3D,cAAc,2CAA2C,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,UAAU,EACuB,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAC3F,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAEnD,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,uCAAuC,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAE/E,OAAO,EAAE,OAAO,IAAI,OAAO,EAAiB,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACxF,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAC;AAEvE,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAE7D,cAAc,uCAAuC,CAAC;AAEtD,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,sCAAsC,CAAC;AAEhF,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AAGtC,qEAAqE;AACrE;;WAEQ;AAER,yEAAyE"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAE3D,cAAc,2CAA2C,CAAC;AAC1D,OAAO,EACN,OAAO,IAAI,UAAU,EAC+B,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAC3F,YAAY,EACZ,MAAM,8BAA8B,CAAA;AAErC,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,uCAAuC,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAE/E,OAAO,EAAE,OAAO,IAAI,OAAO,EAAiB,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACxF,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAEzF,OAAO,EAAE,cAAc,EAAwB,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC9F,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAE7D,cAAc,uCAAuC,CAAC;AAEtD,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAuB,MAAM,sCAAsC,CAAC;AAErG,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AAGtC,qEAAqE;AACrE;;WAEQ;AAER,yEAAyE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reidelsaltres/pureper",
3
- "version": "0.2.14",
3
+ "version": "0.2.17",
4
4
  "description": "Minimal library extracted from the Pureper SPA foundation — utilities and base classes for components/pages.",
5
5
  "type": "module",
6
6
  "main": "out/src/index.js",
@@ -1,45 +1,34 @@
1
- import { HOSTING, HOSTING_ORIGIN } from "./Hosting.js";
1
+ import { HOSTING_ORIGIN } from "./Hosting.js";
2
2
 
3
- // cache stores response bodies (text) by resolved URL so we can reuse them safely
4
- const temporaryCache: Map<string, string> = new Map();
5
3
  // keep in-flight promises to deduplicate concurrent identical requests
6
4
  const inFlightText: Map<string, Promise<string>> = new Map();
7
5
  const inFlightJSON: Map<string, Promise<any>> = new Map();
8
6
  export default class Fetcher {
9
7
  static async fetchText(url: string): Promise<string> {
10
8
  const resolved = this.resolveUrl(url);
11
- if (temporaryCache.has(resolved))
12
- return temporaryCache.get(resolved)!;
13
9
 
14
10
  // If a request for the same URL is already in-flight, reuse its promise
15
11
  if (inFlightText.has(resolved)) return inFlightText.get(resolved)!;
16
12
 
17
13
  const p = (async () => {
18
14
  const response = await this.internalFetch(resolved);
19
- const text = await response.text();
20
- temporaryCache.set(resolved, text);
21
- return text;
15
+ return response.text();
22
16
  })();
23
17
 
24
18
  inFlightText.set(resolved, p);
25
- // cleanup entry when finished
26
19
  p.finally(() => inFlightText.delete(resolved));
27
20
 
28
21
  return p;
29
22
  }
30
23
  static async fetchJSON(url: string): Promise<any> {
31
24
  const resolved = this.resolveUrl(url);
32
- if (temporaryCache.has(resolved))
33
- return JSON.parse(temporaryCache.get(resolved)!);
34
25
 
35
26
  // If a request for the same URL is already in-flight, reuse its promise
36
27
  if (inFlightJSON.has(resolved)) return inFlightJSON.get(resolved)!;
37
28
 
38
29
  const p = (async () => {
39
30
  const response = await this.internalFetch(resolved);
40
- const json = await response.json();
41
- temporaryCache.set(resolved, JSON.stringify(json));
42
- return json;
31
+ return response.json();
43
32
  })();
44
33
 
45
34
  inFlightJSON.set(resolved, p);
@@ -65,6 +54,12 @@ export default class Fetcher {
65
54
  }
66
55
 
67
56
  private static async internalFetch(resolvedUrl: string): Promise<Response> {
57
+ // L2: check ServiceWorker CacheStorage before hitting the network
58
+ if ('caches' in window) {
59
+ const cached = await caches.match(resolvedUrl);
60
+ if (cached) return cached;
61
+ }
62
+
68
63
  const response = await fetch(resolvedUrl, { cache: 'default' });
69
64
  if (!response.ok) {
70
65
  throw new Error(`HTTP error! ${resolvedUrl} status: ${response.status}`);