@swoff/cli 0.3.0 → 0.3.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.
- package/dist/__tests__/assemble-sw.test.js +11 -1
- package/dist/__tests__/assemble-sw.test.js.map +1 -1
- package/dist/__tests__/cli-integration.test.js +2 -3
- package/dist/__tests__/cli-integration.test.js.map +1 -1
- package/dist/__tests__/config-types.test.js +0 -1
- package/dist/__tests__/config-types.test.js.map +1 -1
- package/dist/__tests__/file-generators.test.js +36 -12
- package/dist/__tests__/file-generators.test.js.map +1 -1
- package/dist/__tests__/loader.test.js +1 -1
- package/dist/__tests__/loader.test.js.map +1 -1
- package/dist/__tests__/validator.test.js +8 -1
- package/dist/__tests__/validator.test.js.map +1 -1
- package/dist/lib/commands/add.js +2 -4
- package/dist/lib/commands/add.js.map +1 -1
- package/dist/lib/config/validator.js +5 -0
- package/dist/lib/config/validator.js.map +1 -1
- package/dist/lib/generators/file-generators/background-sync.js +4 -3
- package/dist/lib/generators/file-generators/background-sync.js.map +1 -1
- package/dist/lib/generators/file-generators/cache.js +6 -22
- package/dist/lib/generators/file-generators/cache.js.map +1 -1
- package/dist/lib/generators/file-generators/fetch-wrapper.js +3 -2
- package/dist/lib/generators/file-generators/fetch-wrapper.js.map +1 -1
- package/dist/lib/generators/file-generators/indexeddb.js +3 -2
- package/dist/lib/generators/file-generators/indexeddb.js.map +1 -1
- package/dist/lib/generators/file-generators/invalidation-tags.js +4 -3
- package/dist/lib/generators/file-generators/invalidation-tags.js.map +1 -1
- package/dist/lib/generators/file-generators/mutation-queue.js +8 -7
- package/dist/lib/generators/file-generators/mutation-queue.js.map +1 -1
- package/dist/lib/generators/file-generators/pwa-install.js +10 -54
- package/dist/lib/generators/file-generators/pwa-install.js.map +1 -1
- package/dist/lib/generators/file-generators/reconcile.js +4 -3
- package/dist/lib/generators/file-generators/reconcile.js.map +1 -1
- package/dist/lib/generators/file-generators/store.js +3 -2
- package/dist/lib/generators/file-generators/store.js.map +1 -1
- package/dist/lib/generators/file-generators/sw-injector.js +71 -18
- package/dist/lib/generators/file-generators/sw-injector.js.map +1 -1
- package/dist/lib/generators/file-generators/sw-template.js +9 -132
- package/dist/lib/generators/file-generators/sw-template.js.map +1 -1
- package/dist/lib/generators/sw-sections/activate-handler.js +10 -17
- package/dist/lib/generators/sw-sections/activate-handler.js.map +1 -1
- package/dist/lib/generators/sw-sections/config-header.js +1 -1
- package/dist/lib/generators/sw-sections/config-header.js.map +1 -1
- package/dist/lib/generators/sw-sections/fetch-handler.js +22 -2
- package/dist/lib/generators/sw-sections/fetch-handler.js.map +1 -1
- package/dist/lib/generators/swoff-files-generator.js +2 -2
- package/dist/lib/generators/swoff-files-generator.js.map +1 -1
- package/dist/lib/shared/config-types.js +0 -2
- package/dist/lib/shared/config-types.js.map +1 -1
- package/package.json +1 -1
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { writeFile } from "./context.js";
|
|
5
5
|
export function generateFetchWrapper(ctx) {
|
|
6
|
+
const ext = ctx.ext;
|
|
6
7
|
const code = `/**
|
|
7
8
|
* Swoff Fetch Wrapper
|
|
8
9
|
* Framework-agnostic fetch with cache strategy, tags, and query deduplication.
|
|
9
10
|
*
|
|
10
11
|
* Usage:
|
|
11
|
-
* import { fetchWithCache } from './swoff/fetch-wrapper
|
|
12
|
+
* import { fetchWithCache } from './swoff/fetch-wrapper.${ext}';
|
|
12
13
|
*
|
|
13
14
|
* // GET - cached with tag
|
|
14
15
|
* const todos = await fetchWithCache("/api/todos", { tags: ["todos"] }).then(r => r.json());
|
|
@@ -75,6 +76,6 @@ export async function fetchWithCacheOrQueue(input, options = {}) {
|
|
|
75
76
|
return fetchWithCache(input, options);
|
|
76
77
|
}
|
|
77
78
|
`;
|
|
78
|
-
writeFile(ctx,
|
|
79
|
+
writeFile(ctx, `fetch-wrapper.${ext}`, code);
|
|
79
80
|
}
|
|
80
81
|
//# sourceMappingURL=fetch-wrapper.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-wrapper.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/fetch-wrapper.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,oBAAoB,CAAC,GAAqB;IACxD,MAAM,IAAI,GAAG
|
|
1
|
+
{"version":3,"file":"fetch-wrapper.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/fetch-wrapper.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,oBAAoB,CAAC,GAAqB;IACxD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,IAAI,GAAG;;;;;6DAK8C,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkE/D,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,iBAAiB,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { writeFile } from "./context.js";
|
|
5
5
|
export function generateIndexedDB(ctx) {
|
|
6
|
+
const ext = ctx.ext;
|
|
6
7
|
const dbName = ctx.config.features.indexeddb?.name || "app-db";
|
|
7
8
|
const stores = ctx.config.features.indexeddb?.stores || [];
|
|
8
9
|
const storesCode = stores.length > 0
|
|
@@ -19,7 +20,7 @@ export function generateIndexedDB(ctx) {
|
|
|
19
20
|
* Database initialization with schema migrations.
|
|
20
21
|
*
|
|
21
22
|
* Usage:
|
|
22
|
-
* import { openDB } from './swoff/indexeddb
|
|
23
|
+
* import { openDB } from './swoff/indexeddb.${ext}';
|
|
23
24
|
*
|
|
24
25
|
* const db = await openDB();
|
|
25
26
|
*/
|
|
@@ -68,6 +69,6 @@ export async function monitorStorage() {
|
|
|
68
69
|
};
|
|
69
70
|
}
|
|
70
71
|
`;
|
|
71
|
-
writeFile(ctx,
|
|
72
|
+
writeFile(ctx, `indexeddb.${ext}`, code);
|
|
72
73
|
}
|
|
73
74
|
//# sourceMappingURL=indexeddb.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indexeddb.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/indexeddb.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,iBAAiB,CAAC,GAAqB;IACrD,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,IAAI,IAAI,QAAQ,CAAC;IAC/D,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,IAAI,EAAE,CAAC;IAE3D,MAAM,UAAU,GACd,MAAM,CAAC,MAAM,GAAG,CAAC;QACf,CAAC,CAAC,MAAM;aACH,GAAG,CACF,CAAC,KAAa,EAAE,CAAS,EAAE,EAAE,CAC3B,0BAA0B,CAAC,GAAG,CAAC,sCAAsC,KAAK,iCAAiC,CAC9G;aACA,IAAI,CAAC,MAAM,CAAC;QACjB,CAAC,CAAC;;;;WAIG,CAAC;IAEV,MAAM,IAAI,GAAG
|
|
1
|
+
{"version":3,"file":"indexeddb.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/indexeddb.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,iBAAiB,CAAC,GAAqB;IACrD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,IAAI,IAAI,QAAQ,CAAC;IAC/D,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,IAAI,EAAE,CAAC;IAE3D,MAAM,UAAU,GACd,MAAM,CAAC,MAAM,GAAG,CAAC;QACf,CAAC,CAAC,MAAM;aACH,GAAG,CACF,CAAC,KAAa,EAAE,CAAS,EAAE,EAAE,CAC3B,0BAA0B,CAAC,GAAG,CAAC,sCAAsC,KAAK,iCAAiC,CAC9G;aACA,IAAI,CAAC,MAAM,CAAC;QACjB,CAAC,CAAC;;;;WAIG,CAAC;IAEV,MAAM,IAAI,GAAG;;;;;iDAKkC,GAAG;;;;;mBAKjC,MAAM;;;;;;;;;;;EAWvB,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCX,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC3C,CAAC"}
|
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { writeFile } from "./context.js";
|
|
5
5
|
export function generateInvalidationTags(ctx) {
|
|
6
|
+
const ext = ctx.ext;
|
|
6
7
|
const code = `/**
|
|
7
8
|
* Swoff Invalidation Tags Helper
|
|
8
9
|
* URL-based tag generation from REST endpoints for automatic cache invalidation.
|
|
9
10
|
*
|
|
10
11
|
* Usage:
|
|
11
|
-
* import { generateTags, invalidateUrl } from './swoff/invalidation-tags
|
|
12
|
+
* import { generateTags, invalidateUrl } from './swoff/invalidation-tags.${ext}';
|
|
12
13
|
*
|
|
13
14
|
* // Generate tags from URL
|
|
14
15
|
* generateTags("/api/todos"); // ["todos"]
|
|
@@ -24,7 +25,7 @@ export function generateInvalidationTags(ctx) {
|
|
|
24
25
|
* await invalidateUrl("/api/todos/42");
|
|
25
26
|
*/
|
|
26
27
|
|
|
27
|
-
import { invalidateByTag, invalidateByTags } from "./cache
|
|
28
|
+
import { invalidateByTag, invalidateByTags } from "./cache.${ext}";
|
|
28
29
|
|
|
29
30
|
export function generateTags(url) {
|
|
30
31
|
const parsed = typeof url === "string" ? new URL(url, window.location.origin) : url;
|
|
@@ -86,6 +87,6 @@ export async function invalidateByMethod(method, url) {
|
|
|
86
87
|
await invalidateByTags(tags);
|
|
87
88
|
}
|
|
88
89
|
`;
|
|
89
|
-
writeFile(ctx,
|
|
90
|
+
writeFile(ctx, `invalidation-tags.${ext}`, code);
|
|
90
91
|
}
|
|
91
92
|
//# sourceMappingURL=invalidation-tags.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invalidation-tags.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/invalidation-tags.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,wBAAwB,CAAC,GAAqB;IAC5D,MAAM,IAAI,GAAG
|
|
1
|
+
{"version":3,"file":"invalidation-tags.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/invalidation-tags.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,wBAAwB,CAAC,GAAqB;IAC5D,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,IAAI,GAAG;;;;;8EAK+D,GAAG;;;;;;;;;;;;;;;;6DAgBpB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6D/D,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,qBAAqB,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AACnD,CAAC"}
|
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { writeFile } from "./context.js";
|
|
5
5
|
export function generateMutationQueue(ctx) {
|
|
6
|
+
const ext = ctx.ext;
|
|
6
7
|
const code = `/**
|
|
7
8
|
* Swoff Mutation Queue
|
|
8
9
|
* Queue offline writes and sync when connection returns.
|
|
9
10
|
*
|
|
10
11
|
* Usage:
|
|
11
|
-
* import { queueMutation, processMutationQueue, getPendingCount } from './swoff/mutation-queue
|
|
12
|
+
* import { queueMutation, processMutationQueue, getPendingCount } from './swoff/mutation-queue.${ext}';
|
|
12
13
|
*
|
|
13
14
|
* // Queue a mutation
|
|
14
15
|
* await queueMutation({
|
|
@@ -116,7 +117,7 @@ export async function processMutationQueue() {
|
|
|
116
117
|
}
|
|
117
118
|
|
|
118
119
|
if (item.tags && item.tags.length > 0) {
|
|
119
|
-
const { invalidateByTags } = await import("./cache
|
|
120
|
+
const { invalidateByTags } = await import("./cache.${ext}");
|
|
120
121
|
await invalidateByTags(item.tags);
|
|
121
122
|
}
|
|
122
123
|
|
|
@@ -164,16 +165,16 @@ async function rollbackMutation(item) {
|
|
|
164
165
|
if (!item.storeName) return;
|
|
165
166
|
|
|
166
167
|
if (item.method === "POST" && item.tempId) {
|
|
167
|
-
const { deleteRecord } = await import("./store
|
|
168
|
+
const { deleteRecord } = await import("./store.${ext}");
|
|
168
169
|
await deleteRecord(item.storeName, item.tempId);
|
|
169
170
|
} else if (
|
|
170
171
|
(item.method === "PUT" || item.method === "PATCH") &&
|
|
171
172
|
item.previousData
|
|
172
173
|
) {
|
|
173
|
-
const { putRecord } = await import("./store
|
|
174
|
+
const { putRecord } = await import("./store.${ext}");
|
|
174
175
|
await putRecord(item.storeName, { ...item.previousData, $synced: true });
|
|
175
176
|
} else if (item.method === "DELETE" && item.tempId && item.previousData) {
|
|
176
|
-
const { putRecord } = await import("./store
|
|
177
|
+
const { putRecord } = await import("./store.${ext}");
|
|
177
178
|
await putRecord(item.storeName, { ...item.previousData, $synced: true });
|
|
178
179
|
}
|
|
179
180
|
|
|
@@ -190,7 +191,7 @@ async function rollbackMutation(item) {
|
|
|
190
191
|
}
|
|
191
192
|
|
|
192
193
|
async function reconcileRecord(storeName, tempId, serverData) {
|
|
193
|
-
const { getRecord, putRecord, deleteRecord } = await import("./store
|
|
194
|
+
const { getRecord, putRecord, deleteRecord } = await import("./store.${ext}");
|
|
194
195
|
const existing = await getRecord(storeName, tempId);
|
|
195
196
|
if (!existing) return;
|
|
196
197
|
|
|
@@ -221,6 +222,6 @@ export async function getPendingCount() {
|
|
|
221
222
|
|
|
222
223
|
window.addEventListener("online", processMutationQueue);
|
|
223
224
|
`;
|
|
224
|
-
writeFile(ctx,
|
|
225
|
+
writeFile(ctx, `mutation-queue.${ext}`, code);
|
|
225
226
|
}
|
|
226
227
|
//# sourceMappingURL=mutation-queue.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mutation-queue.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/mutation-queue.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,qBAAqB,CAAC,GAAqB;IACzD,MAAM,IAAI,GAAG
|
|
1
|
+
{"version":3,"file":"mutation-queue.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/mutation-queue.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,qBAAqB,CAAC,GAAqB;IACzD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,IAAI,GAAG;;;;;oGAKqF,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+DA4GxC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qDAgDb,GAAG;;;;;;kDAMN,GAAG;;;kDAGH,GAAG;;;;;;;;;;;;;;;;;yEAiBoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8B3E,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,kBAAkB,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -1,70 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Generates pwa-install.js - PWA install prompt
|
|
2
|
+
* Generates pwa-install.{js|ts} - PWA install prompt utility.
|
|
3
3
|
*/
|
|
4
4
|
import { writeFile } from "./context.js";
|
|
5
5
|
export function generatePwaInstall(ctx) {
|
|
6
|
-
const
|
|
6
|
+
const ext = ctx.ext;
|
|
7
7
|
const code = `/**
|
|
8
|
-
* Swoff PWA Install Prompt
|
|
9
|
-
*
|
|
8
|
+
* Swoff PWA Install Prompt
|
|
9
|
+
* Manual install trigger and installability check.
|
|
10
|
+
* Event listeners are registered in sw-injector at app entry.
|
|
10
11
|
*
|
|
11
12
|
* Usage:
|
|
12
|
-
* import { isInstallable, promptInstall } from './swoff/pwa-install
|
|
13
|
+
* import { isInstallable, promptInstall } from './swoff/pwa-install.${ext}';
|
|
13
14
|
*
|
|
14
|
-
*
|
|
15
|
-
* window.addEventListener('pwa-installable', (e) => {
|
|
16
|
-
* console.log('PWA can be installed:', e.detail.isInstallable);
|
|
17
|
-
* // Show your custom install button
|
|
18
|
-
* });
|
|
19
|
-
*
|
|
20
|
-
* // When user clicks install button
|
|
21
|
-
* async function onInstallClick() {
|
|
15
|
+
* if (isInstallable()) {
|
|
22
16
|
* const result = await promptInstall();
|
|
23
|
-
* console.log('User choice:', result);
|
|
17
|
+
* console.log('User choice:', result.outcome);
|
|
24
18
|
* }
|
|
25
19
|
*
|
|
26
|
-
* Window
|
|
27
|
-
* pwa-installable - PWA can be installed (detail: { isInstallable: true })
|
|
28
|
-
* pwa-installed - User accepted install (detail: { outcome: 'accepted' })
|
|
29
|
-
* pwa-dismissed - User dismissed install (detail: { outcome: 'dismissed' })
|
|
30
|
-
*
|
|
31
|
-
* Window properties:
|
|
20
|
+
* Window properties (set by sw-injector):
|
|
32
21
|
* window.deferredInstallPrompt - The captured BeforeInstallPromptEvent
|
|
33
|
-
* window.pwaInstallable - Whether PWA can be installed
|
|
34
22
|
*/
|
|
35
23
|
|
|
36
|
-
const PREVENT_DEFAULT_INSTALL = ${preventDefault};
|
|
37
|
-
|
|
38
|
-
window.addEventListener("beforeinstallprompt", (e) => {
|
|
39
|
-
// Always capture the event so we never lose it
|
|
40
|
-
window.deferredInstallPrompt = e;
|
|
41
|
-
window.pwaInstallable = true;
|
|
42
|
-
|
|
43
|
-
if (PREVENT_DEFAULT_INSTALL) {
|
|
44
|
-
// Suppress browser's native prompt
|
|
45
|
-
e.preventDefault();
|
|
46
|
-
}
|
|
47
|
-
// When false, browser shows native prompt naturally
|
|
48
|
-
// but we still capture the event for manual triggering
|
|
49
|
-
|
|
50
|
-
window.dispatchEvent(
|
|
51
|
-
new CustomEvent("pwa-installable", {
|
|
52
|
-
detail: { isInstallable: true },
|
|
53
|
-
})
|
|
54
|
-
);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
window.addEventListener("appinstalled", () => {
|
|
58
|
-
window.deferredInstallPrompt = null;
|
|
59
|
-
window.pwaInstallable = false;
|
|
60
|
-
|
|
61
|
-
window.dispatchEvent(
|
|
62
|
-
new CustomEvent("pwa-installed", {
|
|
63
|
-
detail: { outcome: "accepted" },
|
|
64
|
-
})
|
|
65
|
-
);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
24
|
export function isInstallable() {
|
|
69
25
|
return !!window.deferredInstallPrompt;
|
|
70
26
|
}
|
|
@@ -97,6 +53,6 @@ export async function promptInstall() {
|
|
|
97
53
|
return choice;
|
|
98
54
|
}
|
|
99
55
|
`;
|
|
100
|
-
writeFile(ctx,
|
|
56
|
+
writeFile(ctx, `pwa-install.${ext}`, code);
|
|
101
57
|
}
|
|
102
58
|
//# sourceMappingURL=pwa-install.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pwa-install.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/pwa-install.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,kBAAkB,CAAC,GAAqB;IACtD,MAAM,
|
|
1
|
+
{"version":3,"file":"pwa-install.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/pwa-install.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,kBAAkB,CAAC,GAAqB;IACtD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IAEpB,MAAM,IAAI,GAAG;;;;;;yEAM0D,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0C3E,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,eAAe,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -3,17 +3,18 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { writeFile } from "./context.js";
|
|
5
5
|
export function generateReconcile(ctx) {
|
|
6
|
+
const ext = ctx.ext;
|
|
6
7
|
const code = `/**
|
|
7
8
|
* Swoff ID Reconciliation
|
|
8
9
|
* Update local records with server data after mutation sync.
|
|
9
10
|
*
|
|
10
11
|
* Usage:
|
|
11
|
-
* import { reconcileRecord } from './swoff/reconcile
|
|
12
|
+
* import { reconcileRecord } from './swoff/reconcile.${ext}';
|
|
12
13
|
*
|
|
13
14
|
* await reconcileRecord('todos', 'temp_abc123', serverData);
|
|
14
15
|
*/
|
|
15
16
|
|
|
16
|
-
import { getRecord, putRecord, deleteRecord } from './store
|
|
17
|
+
import { getRecord, putRecord, deleteRecord } from './store.${ext}';
|
|
17
18
|
|
|
18
19
|
export async function reconcileRecord(storeName, tempId, serverData) {
|
|
19
20
|
const existing = await getRecord(storeName, tempId);
|
|
@@ -49,6 +50,6 @@ export async function reconcileReferences(storeName, oldId, newId) {
|
|
|
49
50
|
// }
|
|
50
51
|
}
|
|
51
52
|
`;
|
|
52
|
-
writeFile(ctx,
|
|
53
|
+
writeFile(ctx, `reconcile.${ext}`, code);
|
|
53
54
|
}
|
|
54
55
|
//# sourceMappingURL=reconcile.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reconcile.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/reconcile.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,iBAAiB,CAAC,GAAqB;IACrD,MAAM,IAAI,GAAG
|
|
1
|
+
{"version":3,"file":"reconcile.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/reconcile.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,iBAAiB,CAAC,GAAqB;IACrD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,IAAI,GAAG;;;;;0DAK2C,GAAG;;;;;8DAKC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmChE,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC3C,CAAC"}
|
|
@@ -3,13 +3,14 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { writeFile } from "./context.js";
|
|
5
5
|
export function generateStore(ctx) {
|
|
6
|
+
const ext = ctx.ext;
|
|
6
7
|
const dbName = ctx.config.features.indexeddb?.name || "app-db";
|
|
7
8
|
const code = `/**
|
|
8
9
|
* Swoff IndexedDB Store
|
|
9
10
|
* Generic CRUD operations for app's IndexedDB database.
|
|
10
11
|
*
|
|
11
12
|
* Usage:
|
|
12
|
-
* import { getRecord, putRecord, deleteRecord, openAppDB } from './swoff/store
|
|
13
|
+
* import { getRecord, putRecord, deleteRecord, openAppDB } from './swoff/store.${ext}';
|
|
13
14
|
*
|
|
14
15
|
* const record = await getRecord('todos', 'todo-123');
|
|
15
16
|
* await putRecord('todos', { id: 'todo-123', title: 'New task', $synced: false });
|
|
@@ -70,6 +71,6 @@ export async function getAllRecords(storeName) {
|
|
|
70
71
|
});
|
|
71
72
|
}
|
|
72
73
|
`;
|
|
73
|
-
writeFile(ctx,
|
|
74
|
+
writeFile(ctx, `store.${ext}`, code);
|
|
74
75
|
}
|
|
75
76
|
//# sourceMappingURL=store.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/store.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,aAAa,CAAC,GAAqB;IACjD,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,IAAI,IAAI,QAAQ,CAAC;IAE/D,MAAM,IAAI,GAAG
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/store.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,aAAa,CAAC,GAAqB;IACjD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,IAAI,IAAI,QAAQ,CAAC;IAE/D,MAAM,IAAI,GAAG;;;;;oFAKqE,GAAG;;;;;;;mBAOpE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDxB,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,SAAS,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AACvC,CAAC"}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Generates sw-injector.{js|ts} - client-side SW registration
|
|
2
|
+
* Generates sw-injector.{js|ts} - client-side SW registration + PWA + cross-tab sync.
|
|
3
3
|
*/
|
|
4
4
|
import { writeFile } from "./context.js";
|
|
5
5
|
export function generateSwInjector(ctx) {
|
|
6
6
|
const autoRegister = ctx.config.serviceWorker.autoRegister;
|
|
7
7
|
const autoActivate = ctx.config.serviceWorker.autoActivate;
|
|
8
|
+
const pwaEnabled = ctx.config.features.pwa.enabled;
|
|
9
|
+
const preventDefaultInstall = ctx.config.features.pwa.preventDefaultInstall;
|
|
10
|
+
const crossTabSync = ctx.config.features.crossTabSync;
|
|
8
11
|
const ext = ctx.ext;
|
|
9
12
|
const code = `/**
|
|
10
|
-
* Swoff
|
|
11
|
-
* Framework-agnostic
|
|
13
|
+
* Swoff SW Injector
|
|
14
|
+
* Framework-agnostic SW registration, PWA install support, and cross-tab sync.
|
|
12
15
|
*
|
|
13
16
|
* Usage:
|
|
14
17
|
* import { initServiceWorker } from './swoff/sw-injector.${ext}';
|
|
@@ -16,15 +19,15 @@ export function generateSwInjector(ctx) {
|
|
|
16
19
|
* // Call in your app entry point (e.g., main.tsx, app.js):
|
|
17
20
|
* initServiceWorker();
|
|
18
21
|
*
|
|
19
|
-
* // Or defer until after onboarding, but still call initServiceWorker():
|
|
20
|
-
* // (edit the shouldRegister function below instead)
|
|
21
|
-
*
|
|
22
22
|
* Window events:
|
|
23
23
|
* sw-version-detected - Version info available on window
|
|
24
24
|
* sw-update-available - New version ready for user consent (detail: { version })
|
|
25
25
|
* sw-progress - Download progress (detail: { percent, downloaded, total })
|
|
26
26
|
* sw-ready - SW active and controlling page
|
|
27
27
|
* sw-error - SW registration failed
|
|
28
|
+
* pwa-installable - PWA can be installed (detail: { isInstallable: true })
|
|
29
|
+
* pwa-installed - User accepted install (detail: { outcome: 'accepted' })
|
|
30
|
+
* cache-invalidated - Cache entries with given tags cleared (detail: { tags })
|
|
28
31
|
*
|
|
29
32
|
* Window properties:
|
|
30
33
|
* window.latestSWVersion - Latest version from version.json
|
|
@@ -34,11 +37,15 @@ export function generateSwInjector(ctx) {
|
|
|
34
37
|
* window.swMinSupportedVersion - Minimum supported version from version.json
|
|
35
38
|
* window.swReady - SW is active
|
|
36
39
|
* window.swError - Registration failed
|
|
40
|
+
* window.deferredInstallPrompt - Captured BeforeInstallPromptEvent
|
|
41
|
+
* window.pwaInstallable - Whether PWA can be installed
|
|
37
42
|
*/
|
|
38
43
|
|
|
39
44
|
const AUTO_REGISTER = ${autoRegister};
|
|
40
45
|
const AUTO_ACTIVATE = ${autoActivate};
|
|
41
46
|
|
|
47
|
+
// --- SW Registration ---
|
|
48
|
+
|
|
42
49
|
async function checkForUpdate() {
|
|
43
50
|
const response = await fetch("/version.json");
|
|
44
51
|
if (!response.ok) {
|
|
@@ -47,6 +54,16 @@ async function checkForUpdate() {
|
|
|
47
54
|
return response.json();
|
|
48
55
|
}
|
|
49
56
|
|
|
57
|
+
async function waitForController() {
|
|
58
|
+
return new Promise((resolve) => {
|
|
59
|
+
if (navigator.serviceWorker.controller) {
|
|
60
|
+
resolve();
|
|
61
|
+
} else {
|
|
62
|
+
navigator.serviceWorker.addEventListener("controllerchange", resolve, { once: true });
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
50
67
|
async function doRegisterServiceWorker(version) {
|
|
51
68
|
const swUrl = \`/sw-v\${version}.js\`;
|
|
52
69
|
const registration = await navigator.serviceWorker.register(swUrl);
|
|
@@ -54,16 +71,12 @@ async function doRegisterServiceWorker(version) {
|
|
|
54
71
|
window.currentSWVersion = version;
|
|
55
72
|
window.swRegisteredVersion = version;
|
|
56
73
|
window.dispatchEvent(new CustomEvent("sw-version-detected"));
|
|
74
|
+
await waitForController();
|
|
57
75
|
window.dispatchEvent(new CustomEvent("sw-ready"));
|
|
58
76
|
return registration;
|
|
59
77
|
}
|
|
60
78
|
|
|
61
79
|
function shouldRegister() {
|
|
62
|
-
// Add custom preconditions here. Return false to prevent registration.
|
|
63
|
-
// Examples:
|
|
64
|
-
// if (!localStorage.getItem("onboarding-complete")) return false;
|
|
65
|
-
// if (navigator.connection?.effectiveType === "slow-2g") return false;
|
|
66
|
-
|
|
67
80
|
return true;
|
|
68
81
|
}
|
|
69
82
|
|
|
@@ -86,7 +99,10 @@ export async function initServiceWorker() {
|
|
|
86
99
|
if (registration && registration.active) {
|
|
87
100
|
window.currentSWVersion = currentVersion;
|
|
88
101
|
window.dispatchEvent(new CustomEvent("sw-version-detected"));
|
|
89
|
-
|
|
102
|
+
await waitForController();
|
|
103
|
+
if (!window.swReady) {
|
|
104
|
+
window.dispatchEvent(new CustomEvent("sw-ready"));
|
|
105
|
+
}
|
|
90
106
|
}
|
|
91
107
|
} else if (currentVersion && currentVersion !== manifest.version) {
|
|
92
108
|
window.swAvailableVersion = manifest.version;
|
|
@@ -128,18 +144,18 @@ export async function initServiceWorker() {
|
|
|
128
144
|
await doRegisterServiceWorker(manifest.version);
|
|
129
145
|
}
|
|
130
146
|
} catch (error) {
|
|
131
|
-
// Offline or version.json fetch failed — try using existing registration
|
|
132
147
|
try {
|
|
133
148
|
const existing = await navigator.serviceWorker.getRegistration();
|
|
134
149
|
if (existing && existing.active) {
|
|
135
150
|
window.currentSWVersion = localStorage.getItem("swRegisteredVersion") || "unknown";
|
|
136
151
|
window.dispatchEvent(new CustomEvent("sw-version-detected"));
|
|
137
|
-
|
|
152
|
+
await waitForController();
|
|
153
|
+
if (!window.swReady) {
|
|
154
|
+
window.dispatchEvent(new CustomEvent("sw-ready"));
|
|
155
|
+
}
|
|
138
156
|
return;
|
|
139
157
|
}
|
|
140
|
-
} catch {
|
|
141
|
-
// Registration check also failed, nothing we can do
|
|
142
|
-
}
|
|
158
|
+
} catch {}
|
|
143
159
|
|
|
144
160
|
console.error("Service Worker initialization failed:", error);
|
|
145
161
|
window.swError = true;
|
|
@@ -169,6 +185,35 @@ export async function skipWaiting() {
|
|
|
169
185
|
}
|
|
170
186
|
}
|
|
171
187
|
|
|
188
|
+
// --- PWA Install Support ---
|
|
189
|
+
${pwaEnabled ? `
|
|
190
|
+
window.addEventListener("beforeinstallprompt", (e) => {
|
|
191
|
+
window.deferredInstallPrompt = e;
|
|
192
|
+
window.pwaInstallable = true;
|
|
193
|
+
|
|
194
|
+
if (${preventDefaultInstall}) {
|
|
195
|
+
e.preventDefault();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
window.dispatchEvent(
|
|
199
|
+
new CustomEvent("pwa-installable", {
|
|
200
|
+
detail: { isInstallable: true },
|
|
201
|
+
})
|
|
202
|
+
);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
window.addEventListener("appinstalled", () => {
|
|
206
|
+
window.deferredInstallPrompt = null;
|
|
207
|
+
window.pwaInstallable = false;
|
|
208
|
+
|
|
209
|
+
window.dispatchEvent(
|
|
210
|
+
new CustomEvent("pwa-installed", {
|
|
211
|
+
detail: { outcome: "accepted" },
|
|
212
|
+
})
|
|
213
|
+
);
|
|
214
|
+
});
|
|
215
|
+
` : ""}
|
|
216
|
+
// --- SW Message Listener ---
|
|
172
217
|
if (typeof window !== "undefined" && "serviceWorker" in navigator) {
|
|
173
218
|
navigator.serviceWorker.addEventListener("message", (event) => {
|
|
174
219
|
if (event.data.type === "SW_PROGRESS") {
|
|
@@ -193,7 +238,15 @@ if (typeof window !== "undefined" && "serviceWorker" in navigator) {
|
|
|
193
238
|
}
|
|
194
239
|
window.dispatchEvent(new CustomEvent("mutation-queue-changed"));
|
|
195
240
|
}
|
|
196
|
-
|
|
241
|
+
${crossTabSync ? `
|
|
242
|
+
if (event.data.type === "TAG_INVALIDATED" && event.data.tag) {
|
|
243
|
+
window.dispatchEvent(
|
|
244
|
+
new CustomEvent("cache-invalidated", {
|
|
245
|
+
detail: { tags: [event.data.tag] },
|
|
246
|
+
})
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
` : ""} });
|
|
197
250
|
}
|
|
198
251
|
`;
|
|
199
252
|
writeFile(ctx, `sw-injector.${ext}`, code);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sw-injector.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/sw-injector.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,kBAAkB,CAAC,GAAqB;IACtD,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC;IAC3D,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC;IAC3D,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IAEpB,MAAM,IAAI,GAAG;;;;;8DAK+C,GAAG
|
|
1
|
+
{"version":3,"file":"sw-injector.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/sw-injector.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,kBAAkB,CAAC,GAAqB;IACtD,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC;IAC3D,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC;IAC3D,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC;IACnD,MAAM,qBAAqB,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,qBAAqB,CAAC;IAC5E,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC;IACtD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IAEpB,MAAM,IAAI,GAAG;;;;;8DAK+C,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA2BzC,YAAY;wBACZ,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgJlC,UAAU,CAAC,CAAC,CAAC;;;;;QAKP,qBAAqB;;;;;;;;;;;;;;;;;;;;;CAqB5B,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;EA0BJ,YAAY,CAAC,CAAC,CAAC;;;;;;;;CAQhB,CAAC,CAAC,CAAC,EAAE;;CAEL,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,eAAe,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -1,139 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Generates sw-template.js - the SW template with
|
|
2
|
+
* Generates sw-template.js - the SW template with config features baked in.
|
|
3
|
+
* Placeholders are replaced during build by sw-generator.js.
|
|
3
4
|
*/
|
|
4
5
|
import { writeFile } from "./context.js";
|
|
6
|
+
import { assembleSW } from "../sw-sections/assemble-sw.js";
|
|
5
7
|
export function generateSwTemplate(ctx) {
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
* Placeholders:
|
|
13
|
-
* [[CACHE_NAME]] - Replaced with versioned cache name
|
|
14
|
-
* [[ASSETS_LIST]] - Replaced with assets to cache
|
|
15
|
-
* [[AUTO_SKIP_WAITING]] - Replaced with autoActivate config
|
|
16
|
-
*
|
|
17
|
-
* You can customize this template before running the build script.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
let CACHE_NAME = "";
|
|
21
|
-
let ASSETS_TO_CACHE = [];
|
|
22
|
-
|
|
23
|
-
// [[CACHE_NAME]]
|
|
24
|
-
// [[ASSETS_LIST]]
|
|
25
|
-
// [[AUTO_SKIP_WAITING]]
|
|
26
|
-
|
|
27
|
-
const CACHE_NAME_RUNTIME = "swoff-runtime";
|
|
28
|
-
|
|
29
|
-
// Install - download assets with progress tracking
|
|
30
|
-
self.addEventListener("install", (event) => {
|
|
31
|
-
event.waitUntil(
|
|
32
|
-
(async () => {
|
|
33
|
-
const cache = await caches.open(CACHE_NAME);
|
|
34
|
-
let downloaded = 0;
|
|
35
|
-
for (const asset of ASSETS_TO_CACHE) {
|
|
36
|
-
try {
|
|
37
|
-
const request = new Request(asset.url, asset.options);
|
|
38
|
-
await cache.add(request);
|
|
39
|
-
downloaded++;
|
|
40
|
-
const percent = Math.round((downloaded / ASSETS_TO_CACHE.length) * 100);
|
|
41
|
-
const clients = await self.clients.matchAll({ includeUncontrolled: true });
|
|
42
|
-
clients.forEach((client) => {
|
|
43
|
-
client.postMessage({
|
|
44
|
-
type: "SW_PROGRESS",
|
|
45
|
-
percent,
|
|
46
|
-
downloaded,
|
|
47
|
-
total: ASSETS_TO_CACHE.length,
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
} catch (err) {
|
|
51
|
-
console.error(\`Failed to cache \${asset.url}:\`, err);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
if (AUTO_SKIP_WAITING) self.skipWaiting();
|
|
55
|
-
})(),
|
|
56
|
-
);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
// Activate - clean old caches
|
|
60
|
-
self.addEventListener("activate", (event) => {
|
|
61
|
-
event.waitUntil(
|
|
62
|
-
caches.keys().then((keys) =>
|
|
63
|
-
Promise.all(
|
|
64
|
-
keys.filter((key) => key !== CACHE_NAME && key !== CACHE_NAME_RUNTIME).map((key) => caches.delete(key))
|
|
65
|
-
)
|
|
66
|
-
)
|
|
67
|
-
);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
// Message - skip waiting and cache invalidation
|
|
71
|
-
self.addEventListener("message", (event) => {
|
|
72
|
-
if (event.data.type === "SKIP_WAITING") {
|
|
73
|
-
self.skipWaiting();
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// Fetch - cache strategies
|
|
78
|
-
self.addEventListener("fetch", (event) => {
|
|
79
|
-
if (event.request.method !== "GET" && event.request.method !== "HEAD") return;
|
|
80
|
-
|
|
81
|
-
event.respondWith(
|
|
82
|
-
(async () => {
|
|
83
|
-
const cache = await caches.open(CACHE_NAME);
|
|
84
|
-
const runtimeCache = await caches.open(CACHE_NAME_RUNTIME);
|
|
85
|
-
const url = new URL(event.request.url);
|
|
86
|
-
|
|
87
|
-
const byPath = await cache.match(url.pathname);
|
|
88
|
-
if (byPath) return byPath;
|
|
89
|
-
|
|
90
|
-
const cached = await runtimeCache.match(event.request);
|
|
91
|
-
if (cached) return cached;
|
|
92
|
-
|
|
93
|
-
if (event.request.mode === "navigate") {
|
|
94
|
-
const spa = await cache.match("/index.html");
|
|
95
|
-
if (spa) return spa;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const response = await fetch(event.request);
|
|
99
|
-
if (response.ok) {
|
|
100
|
-
await runtimeCache.put(event.request, response.clone());
|
|
101
|
-
}
|
|
102
|
-
return response;
|
|
103
|
-
})(),
|
|
104
|
-
);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
const SWOFF = {
|
|
108
|
-
cache: {
|
|
109
|
-
async get(key) {
|
|
110
|
-
const cache = await caches.open(CACHE_NAME);
|
|
111
|
-
return cache.match(key);
|
|
112
|
-
},
|
|
113
|
-
async put(request, response) {
|
|
114
|
-
const cache = await caches.open(CACHE_NAME);
|
|
115
|
-
await cache.put(request, response);
|
|
116
|
-
},
|
|
117
|
-
async delete(request) {
|
|
118
|
-
const cache = await caches.open(CACHE_NAME);
|
|
119
|
-
return cache.delete(request);
|
|
120
|
-
}
|
|
121
|
-
},
|
|
122
|
-
network: {
|
|
123
|
-
async fetch(request, options = {}) {
|
|
124
|
-
try {
|
|
125
|
-
return await fetch(request, options);
|
|
126
|
-
} catch (error) {
|
|
127
|
-
throw new Error(\`Network request failed: \${error.message}\`);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
if (typeof self !== 'undefined') {
|
|
134
|
-
self.SWOFF = SWOFF;
|
|
135
|
-
}
|
|
136
|
-
`;
|
|
8
|
+
const placeholderVersion = "0.0.0";
|
|
9
|
+
const full = assembleSW(ctx.config, placeholderVersion);
|
|
10
|
+
let code = full;
|
|
11
|
+
code = code.replace(`CACHE_NAME = 'sw-v${placeholderVersion}'`, "// [[CACHE_NAME]]");
|
|
12
|
+
code = code.replace(/^ASSETS_TO_CACHE = \[[\s\S]*?\]$/m, "// [[ASSETS_LIST]]");
|
|
13
|
+
code = code.replace(/^const AUTO_SKIP_WAITING = (true|false);?$/m, "// [[AUTO_SKIP_WAITING]]");
|
|
137
14
|
writeFile(ctx, "sw-template.js", code);
|
|
138
15
|
}
|
|
139
16
|
//# sourceMappingURL=sw-template.js.map
|