@swoff/cli 0.3.9 → 0.3.10
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 +8 -17
- package/dist/__tests__/assemble-sw.test.js.map +1 -1
- package/dist/__tests__/cli-integration.test.js +2 -2
- package/dist/__tests__/cli-integration.test.js.map +1 -1
- package/dist/__tests__/config-types.test.js +18 -8
- package/dist/__tests__/config-types.test.js.map +1 -1
- package/dist/__tests__/file-generators.test.js +3 -3
- package/dist/__tests__/file-generators.test.js.map +1 -1
- package/dist/__tests__/loader.test.js +5 -1
- package/dist/__tests__/loader.test.js.map +1 -1
- package/dist/__tests__/validator.test.js +6 -13
- package/dist/__tests__/validator.test.js.map +1 -1
- package/dist/index.js +39 -35
- package/dist/index.js.map +1 -1
- package/dist/lib/cli/help.js +13 -8
- package/dist/lib/cli/help.js.map +1 -1
- package/dist/lib/commands/add.js +38 -8
- package/dist/lib/commands/add.js.map +1 -1
- package/dist/lib/commands/assets.js +37 -0
- package/dist/lib/commands/assets.js.map +1 -0
- package/dist/lib/commands/clean.js +33 -17
- package/dist/lib/commands/clean.js.map +1 -1
- package/dist/lib/commands/generate-assets.js +44 -0
- package/dist/lib/commands/generate-assets.js.map +1 -0
- package/dist/lib/commands/generate-guide.js +22 -29
- package/dist/lib/commands/generate-guide.js.map +1 -1
- package/dist/lib/commands/generate.js +16 -9
- package/dist/lib/commands/generate.js.map +1 -1
- package/dist/lib/commands/info.js +36 -45
- package/dist/lib/commands/info.js.map +1 -1
- package/dist/lib/commands/init.js +25 -3
- package/dist/lib/commands/init.js.map +1 -1
- package/dist/lib/commands/validate.js +1 -1
- package/dist/lib/commands/validate.js.map +1 -1
- package/dist/lib/config/loader.js +25 -20
- package/dist/lib/config/loader.js.map +1 -1
- package/dist/lib/config/validator.js +20 -11
- package/dist/lib/config/validator.js.map +1 -1
- package/dist/lib/generators/asset-generator/dependency-resolver.js +76 -0
- package/dist/lib/generators/asset-generator/dependency-resolver.js.map +1 -0
- package/dist/lib/generators/asset-generator/generate.js +111 -0
- package/dist/lib/generators/asset-generator/generate.js.map +1 -0
- package/dist/lib/generators/asset-generator/guide.js +43 -0
- package/dist/lib/generators/asset-generator/guide.js.map +1 -0
- package/dist/lib/generators/asset-generator/html-patcher.js +65 -0
- package/dist/lib/generators/asset-generator/html-patcher.js.map +1 -0
- package/dist/lib/generators/asset-generator/ico-encoder.js +29 -0
- package/dist/lib/generators/asset-generator/ico-encoder.js.map +1 -0
- package/dist/lib/generators/asset-generator/manifest-patcher.js +23 -0
- package/dist/lib/generators/asset-generator/manifest-patcher.js.map +1 -0
- package/dist/lib/generators/asset-generator/maskable.js +15 -0
- package/dist/lib/generators/asset-generator/maskable.js.map +1 -0
- package/dist/lib/generators/asset-generator/rasterize.js +32 -0
- package/dist/lib/generators/asset-generator/rasterize.js.map +1 -0
- package/dist/lib/generators/asset-generator/sizes.js +25 -0
- package/dist/lib/generators/asset-generator/sizes.js.map +1 -0
- package/dist/lib/generators/file-generators/api-config.js +6 -0
- package/dist/lib/generators/file-generators/api-config.js.map +1 -0
- package/dist/lib/generators/file-generators/auth-state.js +2 -34
- package/dist/lib/generators/file-generators/auth-state.js.map +1 -1
- package/dist/lib/generators/file-generators/auth-store.js +2 -250
- package/dist/lib/generators/file-generators/auth-store.js.map +1 -1
- package/dist/lib/generators/file-generators/auth-user.js +3 -81
- package/dist/lib/generators/file-generators/auth-user.js.map +1 -1
- package/dist/lib/generators/file-generators/background-sync.js +2 -57
- package/dist/lib/generators/file-generators/background-sync.js.map +1 -1
- package/dist/lib/generators/file-generators/cache.js +2 -30
- package/dist/lib/generators/file-generators/cache.js.map +1 -1
- package/dist/lib/generators/file-generators/client-injector.js +2 -130
- package/dist/lib/generators/file-generators/client-injector.js.map +1 -1
- package/dist/lib/generators/file-generators/fetch-state.js +6 -0
- package/dist/lib/generators/file-generators/fetch-state.js.map +1 -0
- package/dist/lib/generators/file-generators/fetch-wrapper.js +3 -295
- package/dist/lib/generators/file-generators/fetch-wrapper.js.map +1 -1
- package/dist/lib/generators/file-generators/generate-framework-adapters.js +56 -0
- package/dist/lib/generators/file-generators/generate-framework-adapters.js.map +1 -0
- package/dist/lib/generators/file-generators/generate-hooks.js +4 -3
- package/dist/lib/generators/file-generators/generate-hooks.js.map +1 -1
- package/dist/lib/generators/file-generators/gql-wrapper.js +3 -132
- package/dist/lib/generators/file-generators/gql-wrapper.js.map +1 -1
- package/dist/lib/generators/file-generators/guide-generator.js +29 -1
- package/dist/lib/generators/file-generators/guide-generator.js.map +1 -1
- package/dist/lib/generators/file-generators/invalidation-tags.js +3 -258
- package/dist/lib/generators/file-generators/invalidation-tags.js.map +1 -1
- package/dist/lib/generators/file-generators/manifest.js +13 -3
- package/dist/lib/generators/file-generators/manifest.js.map +1 -1
- package/dist/lib/generators/file-generators/mutation-queue.js +3 -305
- package/dist/lib/generators/file-generators/mutation-queue.js.map +1 -1
- package/dist/lib/generators/file-generators/mutation-state.js +2 -117
- package/dist/lib/generators/file-generators/mutation-state.js.map +1 -1
- package/dist/lib/generators/file-generators/push.js +6 -138
- package/dist/lib/generators/file-generators/push.js.map +1 -1
- package/dist/lib/generators/file-generators/pwa-install.js +11 -84
- package/dist/lib/generators/file-generators/pwa-install.js.map +1 -1
- package/dist/lib/generators/file-generators/reset.js +6 -0
- package/dist/lib/generators/file-generators/reset.js.map +1 -0
- package/dist/lib/generators/file-generators/server-push.js +3 -134
- package/dist/lib/generators/file-generators/server-push.js.map +1 -1
- package/dist/lib/generators/file-generators/sw-generator-build.js +4 -4
- package/dist/lib/generators/file-generators/sw-injector.js +9 -230
- package/dist/lib/generators/file-generators/sw-injector.js.map +1 -1
- package/dist/lib/generators/file-generators/type-definitions.js +2 -111
- package/dist/lib/generators/file-generators/type-definitions.js.map +1 -1
- package/dist/lib/generators/sw-generator.js +5 -5
- package/dist/lib/generators/sw-generator.js.map +1 -1
- package/dist/lib/generators/sw-sections/activate-handler.js +25 -3
- package/dist/lib/generators/sw-sections/activate-handler.js.map +1 -1
- package/dist/lib/generators/sw-sections/assemble-sw.js +13 -12
- package/dist/lib/generators/sw-sections/assemble-sw.js.map +1 -1
- package/dist/lib/generators/sw-sections/background-sync-handler.js +14 -7
- package/dist/lib/generators/sw-sections/background-sync-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 +165 -104
- package/dist/lib/generators/sw-sections/fetch-handler.js.map +1 -1
- package/dist/lib/generators/sw-sections/glob-matcher-code.js.map +1 -0
- package/dist/lib/generators/sw-sections/server-push-handler.js +12 -0
- package/dist/lib/generators/sw-sections/server-push-handler.js.map +1 -1
- package/dist/lib/generators/sw-sections/tag-management.js +6 -4
- package/dist/lib/generators/sw-sections/tag-management.js.map +1 -1
- package/dist/lib/generators/swoff-files-generator.js +66 -35
- package/dist/lib/generators/swoff-files-generator.js.map +1 -1
- package/dist/lib/shared/config-types.js +89 -28
- package/dist/lib/shared/config-types.js.map +1 -1
- package/dist/runtime/api-config.js +18 -0
- package/dist/runtime/api-config.js.map +1 -0
- package/dist/runtime/auth-state.js +35 -0
- package/dist/runtime/auth-state.js.map +1 -0
- package/dist/runtime/auth-store.js +273 -0
- package/dist/runtime/auth-store.js.map +1 -0
- package/dist/runtime/auth-user.js +168 -0
- package/dist/runtime/auth-user.js.map +1 -0
- package/dist/runtime/background-sync.js +59 -0
- package/dist/runtime/background-sync.js.map +1 -0
- package/dist/runtime/cache.js +30 -0
- package/dist/runtime/cache.js.map +1 -0
- package/dist/runtime/client-injector.js +136 -0
- package/dist/runtime/client-injector.js.map +1 -0
- package/dist/runtime/fetch-state.js +42 -0
- package/dist/runtime/fetch-state.js.map +1 -0
- package/dist/runtime/fetch-wrapper.js +355 -0
- package/dist/runtime/fetch-wrapper.js.map +1 -0
- package/dist/runtime/gql-wrapper.js +135 -0
- package/dist/runtime/gql-wrapper.js.map +1 -0
- package/dist/runtime/invalidation-tags.js +260 -0
- package/dist/runtime/invalidation-tags.js.map +1 -0
- package/dist/runtime/mutation-queue.js +304 -0
- package/dist/runtime/mutation-queue.js.map +1 -0
- package/dist/runtime/mutation-state.js +117 -0
- package/dist/runtime/mutation-state.js.map +1 -0
- package/dist/runtime/push.js +138 -0
- package/dist/runtime/push.js.map +1 -0
- package/dist/runtime/pwa-index.js +11 -0
- package/dist/runtime/pwa-index.js.map +1 -0
- package/dist/runtime/pwa-injector.js +44 -0
- package/dist/runtime/pwa-injector.js.map +1 -0
- package/dist/runtime/pwa-install.js +83 -0
- package/dist/runtime/pwa-install.js.map +1 -0
- package/dist/runtime/pwa-prompt.js +54 -0
- package/dist/runtime/pwa-prompt.js.map +1 -0
- package/dist/runtime/reset.js +148 -0
- package/dist/runtime/reset.js.map +1 -0
- package/dist/runtime/server-push.js +148 -0
- package/dist/runtime/server-push.js.map +1 -0
- package/dist/runtime/sw-injector.js +236 -0
- package/dist/runtime/sw-injector.js.map +1 -0
- package/dist/runtime/type-definitions.js +138 -0
- package/dist/runtime/type-definitions.js.map +1 -0
- package/dist/runtime/utils.js +27 -0
- package/dist/runtime/utils.js.map +1 -0
- package/package.json +3 -2
- package/templates/react/useAuth.jsx +106 -0
- package/templates/react/useAuth.tsx +118 -0
- package/templates/{hooks → react}/useBackgroundSync.jsx +6 -4
- package/templates/{hooks → react}/useBackgroundSync.tsx +6 -4
- package/templates/{hooks → react}/useCacheInvalidation.jsx +2 -2
- package/templates/react/useCacheInvalidation.tsx +52 -0
- package/templates/react/useCachedFetch.jsx +140 -0
- package/templates/react/useCachedFetch.tsx +160 -0
- package/templates/react/useIsFetching.jsx +32 -0
- package/templates/react/useIsFetching.tsx +32 -0
- package/templates/react/useMutation.jsx +141 -0
- package/templates/react/useMutation.tsx +180 -0
- package/templates/react/useMutationQueue.jsx +69 -0
- package/templates/react/useMutationQueue.tsx +83 -0
- package/templates/react/useNetworkStatus.jsx +61 -0
- package/templates/react/useNetworkStatus.tsx +76 -0
- package/templates/react/usePrefetch.jsx +32 -0
- package/templates/react/usePrefetch.tsx +42 -0
- package/templates/{hooks → react}/usePushSubscription.jsx +4 -4
- package/templates/{hooks → react}/usePushSubscription.tsx +4 -4
- package/templates/{hooks → react}/useSWUpdate.jsx +3 -3
- package/templates/{hooks → react}/useSWUpdate.tsx +4 -4
- package/templates/react/useSwoffReset.jsx +32 -0
- package/templates/react/useSwoffReset.tsx +39 -0
- package/docs/API.md +0 -565
- package/docs/ARCHITECTURE.md +0 -374
- package/docs/CLI.md +0 -148
- package/docs/COMPARISON.md +0 -192
- package/docs/CONFIG.md +0 -277
- package/docs/ECOSYSTEM.md +0 -33
- package/templates/hooks/useAuth.jsx +0 -30
- package/templates/hooks/useAuth.tsx +0 -30
- package/templates/hooks/useCacheInvalidation.tsx +0 -19
- package/templates/hooks/useCachedFetch.jsx +0 -69
- package/templates/hooks/useCachedFetch.tsx +0 -81
- package/templates/hooks/useMutation.jsx +0 -76
- package/templates/hooks/useMutation.tsx +0 -109
- package/templates/hooks/useMutationQueue.jsx +0 -43
- package/templates/hooks/useMutationQueue.tsx +0 -50
- package/templates/hooks/useNetworkStatus.jsx +0 -19
- package/templates/hooks/useNetworkStatus.tsx +0 -19
- package/templates/hooks/usePrefetch.jsx +0 -10
- package/templates/hooks/usePrefetch.tsx +0 -25
- /package/templates/{hooks → react}/useMutationState.jsx +0 -0
- /package/templates/{hooks → react}/useMutationState.tsx +0 -0
|
@@ -22,21 +22,25 @@
|
|
|
22
22
|
* On successful refresh, CACHE_UPDATED is posted to all clients.
|
|
23
23
|
*/
|
|
24
24
|
export function generateFetchHandler(swConfig, tagInvalidation, mutationQueueEnabled) {
|
|
25
|
-
const { strategy: { default: defaultStrategy, patterns: strategies, mode: cacheStrategy = "all", normalizeKey: normalizeCacheKey, ignoreQueryParams }, navigation: { mode: navMode = "spa", preload: navigationPreload, fallback: spaPath = "/index.html" }, refetchQueue: { batchSize: refetchBatchSize = 5, batchDelayMs: refetchBatchDelayMs = 1000, maxRetries: refetchMaxRetries = 3, retryDelayMs: refetchRetryDelayMs = 1000 } } = swConfig;
|
|
26
|
-
const { staleTime: globalStaleTime, refetchInterval: globalRefetchInterval, refetchOnReconnect: globalRefetchOnReconnect, refetchOnFocus: globalRefetchOnFocus } = swConfig.strategy.reactive?.defaults || {};
|
|
27
|
-
const staleVersionCode = tagInvalidation
|
|
25
|
+
const { strategy: { default: defaultStrategy, patterns: strategies, mode: cacheStrategy = "all", normalizeKey: normalizeCacheKey, ignoreQueryParams, }, navigation: { mode: navMode = "spa", preload: navigationPreload, fallback: spaPath = "/index.html", }, refetchQueue: { batchSize: refetchBatchSize = 5, batchDelayMs: refetchBatchDelayMs = 1000, maxRetries: refetchMaxRetries = 3, retryDelayMs: refetchRetryDelayMs = 1000, }, } = swConfig;
|
|
26
|
+
const { staleTime: globalStaleTime, refetchInterval: globalRefetchInterval, refetchOnReconnect: globalRefetchOnReconnect, refetchOnFocus: globalRefetchOnFocus, } = swConfig.strategy.reactive?.defaults || {};
|
|
27
|
+
const staleVersionCode = tagInvalidation
|
|
28
|
+
? `
|
|
28
29
|
cleanStaleVersions();
|
|
29
30
|
if (staleVersions.has(cacheKey(request))) {
|
|
30
31
|
queueRefresh(cacheKey(request), new URL(request.url).href);
|
|
31
|
-
}`
|
|
32
|
-
|
|
32
|
+
}`
|
|
33
|
+
: "";
|
|
34
|
+
const tagCode = tagInvalidation
|
|
35
|
+
? `
|
|
33
36
|
const tagsHeader = request.headers.get("X-SW-Cache-Tags");
|
|
34
37
|
if (tagsHeader) {
|
|
35
38
|
const cacheKeyUrl = cacheKey(request);
|
|
36
39
|
const actualUrl = new URL(request.url).href;
|
|
37
40
|
const tags = tagsHeader.split(",").map((t) => t.trim());
|
|
38
41
|
await cacheTagUrl(cacheKeyUrl, actualUrl, tags);
|
|
39
|
-
}`
|
|
42
|
+
}`
|
|
43
|
+
: "";
|
|
40
44
|
const reactGlobalDefaults = {
|
|
41
45
|
staleTime: globalStaleTime,
|
|
42
46
|
refetchInterval: globalRefetchInterval,
|
|
@@ -64,44 +68,42 @@ const REFRESH_MAX_RETRIES = ${refetchMaxRetries};
|
|
|
64
68
|
const REFRESH_RETRY_DELAY_MS = ${refetchRetryDelayMs};`;
|
|
65
69
|
const GLOB_CODE = "\n" +
|
|
66
70
|
"// --- Glob Pattern Matching ---\n" +
|
|
67
|
-
"// NOTE: This is an inline copy of the algorithm in shared/glob-matcher.ts.\n" +
|
|
68
|
-
"// Keep the two implementations in sync when making changes.\n" +
|
|
69
71
|
"\n" +
|
|
70
72
|
"function escapeGlobMeta(s) {\n" +
|
|
71
|
-
|
|
73
|
+
' return s.replace(/[.+^${}()|[\\]\\\\]/g, "\\\\$$&");\n' +
|
|
72
74
|
"}\n" +
|
|
73
75
|
"\n" +
|
|
74
76
|
"function globPartRe(part) {\n" +
|
|
75
|
-
|
|
77
|
+
' for (var o = "", i = 0; i < part.length; i++) {\n' +
|
|
76
78
|
" var c = part[i];\n" +
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
' if (c === "*") { o += "[^/]*"; }\n' +
|
|
80
|
+
' else if (c === "?") { o += "[^/]"; }\n' +
|
|
81
|
+
' else if (c === "{") {\n' +
|
|
82
|
+
' var cl = part.indexOf("}", i);\n' +
|
|
83
|
+
' if (cl === -1) { o += "\\\\" + c; }\n' +
|
|
82
84
|
" else {\n" +
|
|
83
|
-
|
|
85
|
+
' o += "(?:" + part.slice(i + 1, cl).split(",").map(function(s) { return escapeGlobMeta(s.trim()); }).join("|") + ")";\n' +
|
|
84
86
|
" i = cl;\n" +
|
|
85
87
|
" }\n" +
|
|
86
|
-
|
|
88
|
+
' } else { o += "\\\\" + c; }\n' +
|
|
87
89
|
" }\n" +
|
|
88
90
|
" return o;\n" +
|
|
89
91
|
"}\n" +
|
|
90
92
|
"\n" +
|
|
91
93
|
"function matchGlob(path, pattern) {\n" +
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
' if (pattern.charAt(0) === "!") return !matchGlob(path, pattern.slice(1));\n' +
|
|
95
|
+
' var parts = pattern.split("/").filter(Boolean);\n' +
|
|
96
|
+
' var pps = path.split("/").filter(Boolean);\n' +
|
|
95
97
|
" var pi = 0, ppi = 0;\n" +
|
|
96
98
|
" while (pi < parts.length && ppi < pps.length) {\n" +
|
|
97
99
|
" var part = parts[pi];\n" +
|
|
98
|
-
|
|
100
|
+
' if (part === "**") {\n' +
|
|
99
101
|
" if (pi === parts.length - 1) return true;\n" +
|
|
100
102
|
" var nxt = parts[pi + 1];\n" +
|
|
101
103
|
" var found = -1;\n" +
|
|
102
104
|
" for (var j = ppi; j < pps.length; j++) {\n" +
|
|
103
|
-
|
|
104
|
-
|
|
105
|
+
' if (nxt.indexOf("*") > -1 || nxt.indexOf("?") > -1 || nxt.indexOf("{") > -1) {\n' +
|
|
106
|
+
' if (new RegExp("^" + globPartRe(nxt) + "$").test(pps[j])) { found = j; break; }\n' +
|
|
105
107
|
" } else if (nxt === pps[j]) { found = j; break; }\n" +
|
|
106
108
|
" }\n" +
|
|
107
109
|
" if (found === -1) return false;\n" +
|
|
@@ -109,8 +111,8 @@ const REFRESH_RETRY_DELAY_MS = ${refetchRetryDelayMs};`;
|
|
|
109
111
|
" pi++;\n" +
|
|
110
112
|
" continue;\n" +
|
|
111
113
|
" }\n" +
|
|
112
|
-
|
|
113
|
-
|
|
114
|
+
' if (part.indexOf("*") > -1 || part.indexOf("?") > -1 || part.indexOf("{") > -1) {\n' +
|
|
115
|
+
' if (!new RegExp("^" + globPartRe(part) + "$").test(pps[ppi])) return false;\n' +
|
|
114
116
|
" } else if (part !== pps[ppi]) return false;\n" +
|
|
115
117
|
" pi++;\n" +
|
|
116
118
|
" ppi++;\n" +
|
|
@@ -122,86 +124,105 @@ const REFRESH_RETRY_DELAY_MS = ${refetchRetryDelayMs};`;
|
|
|
122
124
|
// --- Batch Refresh Queue ---
|
|
123
125
|
|
|
124
126
|
const _refreshQueue = new Map();
|
|
125
|
-
let _refreshQueueProcessing = false;
|
|
126
127
|
let _refreshQueuePromise = null;
|
|
127
128
|
|
|
128
|
-
function queueRefresh(cacheKeyUrl, actualUrl${tagInvalidation ? ", tags" : ""}) {
|
|
129
|
-
// Use Map keyed by cacheKey for proper deduplication${tagInvalidation
|
|
129
|
+
function queueRefresh(cacheKeyUrl, actualUrl${tagInvalidation ? ", tags" : ""}${tagInvalidation ? ", method, body, contentType" : ""}) {
|
|
130
|
+
// Use Map keyed by cacheKey for proper deduplication${tagInvalidation
|
|
131
|
+
? `
|
|
130
132
|
// Don't let a tagless (SWR/reactive) refresh override an invalidation-triggered entry with tags
|
|
131
|
-
if (_refreshQueue.has(cacheKeyUrl) && !tags) return;`
|
|
132
|
-
|
|
133
|
+
if (_refreshQueue.has(cacheKeyUrl) && !tags) return;`
|
|
134
|
+
: ""}
|
|
135
|
+
_refreshQueue.set(cacheKeyUrl, { cacheKey: cacheKeyUrl, actualUrl: actualUrl || cacheKeyUrl, retryCount: 0${tagInvalidation ? ", tags: tags || null, method: method || null, body: body || null, contentType: contentType || null" : ""} });
|
|
133
136
|
if (!_refreshQueuePromise) {
|
|
134
|
-
_refreshQueuePromise = _processRefreshQueue()
|
|
135
|
-
_refreshQueuePromise = null;
|
|
136
|
-
if (_refreshQueue.size > 0) queueRefresh();
|
|
137
|
-
});
|
|
137
|
+
_refreshQueuePromise = _processRefreshQueue();
|
|
138
138
|
}
|
|
139
139
|
return _refreshQueuePromise;
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
function resolveActualUrl(entry) {
|
|
143
|
-
|
|
142
|
+
async function resolveActualUrl(entry) {
|
|
143
|
+
if (entry.actualUrl) return entry.actualUrl;
|
|
144
|
+
const url = entry.cacheKey;
|
|
144
145
|
if (url.includes("/__swc/")) {
|
|
145
|
-
// Virtual cache key —
|
|
146
|
-
|
|
146
|
+
// Virtual cache key — look up the real URL from tag registry
|
|
147
|
+
try {
|
|
148
|
+
const db = await openTagDB();
|
|
149
|
+
const tx = db.transaction(TAG_STORE_NAME, "readonly");
|
|
150
|
+
const store = tx.objectStore(TAG_STORE_NAME);
|
|
151
|
+
const stored = await new Promise((resolve) => {
|
|
152
|
+
const req = store.get(url);
|
|
153
|
+
req.onsuccess = () => resolve(req.result);
|
|
154
|
+
req.onerror = () => resolve(null);
|
|
155
|
+
});
|
|
156
|
+
db.close();
|
|
157
|
+
if (stored?.actualUrl) return stored.actualUrl;
|
|
158
|
+
} catch {}
|
|
147
159
|
}
|
|
148
160
|
return url;
|
|
149
161
|
}
|
|
150
162
|
|
|
151
163
|
async function _processRefreshQueue() {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
const
|
|
169
|
-
|
|
164
|
+
try {
|
|
165
|
+
while (_refreshQueue.size > 0) {
|
|
166
|
+
const batch = [];
|
|
167
|
+
for (const [cacheKey, entry] of _refreshQueue) {
|
|
168
|
+
if (batch.length >= REFETCH_BATCH_SIZE) break;
|
|
169
|
+
if (entry.nextRetryAt && entry.nextRetryAt > Date.now()) continue;
|
|
170
|
+
batch.push(entry);
|
|
171
|
+
_refreshQueue.delete(cacheKey);
|
|
172
|
+
}
|
|
173
|
+
if (batch.length === 0) break;
|
|
174
|
+
|
|
175
|
+
const clients = await self.clients.matchAll();
|
|
176
|
+
|
|
177
|
+
await Promise.allSettled(batch.map(async (entry) => {
|
|
178
|
+
const fetchUrl = await resolveActualUrl(entry);
|
|
179
|
+
try {
|
|
180
|
+
const fetchOpts = {};
|
|
181
|
+
if (entry.method && entry.method !== "GET" && entry.method !== "HEAD") {
|
|
182
|
+
fetchOpts.method = entry.method;
|
|
183
|
+
if (entry.body) fetchOpts.body = entry.body;
|
|
184
|
+
if (entry.contentType) fetchOpts.headers = { "Content-Type": entry.contentType };
|
|
185
|
+
}
|
|
186
|
+
const response = await fetch(fetchUrl, fetchOpts);
|
|
187
|
+
if (response.ok) {
|
|
188
|
+
const request = new Request(entry.cacheKey);
|
|
189
|
+
await storeRuntime(request, response);${tagInvalidation
|
|
190
|
+
? `
|
|
170
191
|
if (entry.tags && typeof cacheTagUrl !== "undefined") {
|
|
171
|
-
await cacheTagUrl(entry.cacheKey, fetchUrl, entry.tags);
|
|
172
|
-
}`
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
staleVersions.
|
|
192
|
+
await cacheTagUrl(entry.cacheKey, fetchUrl, entry.tags, entry.method, entry.body, entry.contentType);
|
|
193
|
+
}`
|
|
194
|
+
: ""}
|
|
195
|
+
// Clean up stale version tracking on successful refresh
|
|
196
|
+
if (typeof staleVersions !== "undefined" && staleVersions.has(entry.cacheKey)) {
|
|
197
|
+
staleVersions.delete(entry.cacheKey);
|
|
198
|
+
}
|
|
199
|
+
for (const client of clients) {
|
|
200
|
+
client.postMessage({ type: "CACHE_UPDATED", url: fetchUrl });
|
|
201
|
+
}
|
|
176
202
|
}
|
|
177
|
-
|
|
178
|
-
|
|
203
|
+
} catch {
|
|
204
|
+
// Refresh failed — retry with exponential backoff
|
|
205
|
+
if (entry.retryCount < REFRESH_MAX_RETRIES) {
|
|
206
|
+
entry.retryCount++;
|
|
207
|
+
const delay = REFRESH_RETRY_DELAY_MS * Math.pow(2, entry.retryCount - 1);
|
|
208
|
+
entry.nextRetryAt = Date.now() + delay;
|
|
209
|
+
_refreshQueue.set(entry.cacheKey, entry);
|
|
210
|
+
setTimeout(() => {
|
|
211
|
+
if (!_refreshQueuePromise) {
|
|
212
|
+
_refreshQueuePromise = _processRefreshQueue();
|
|
213
|
+
}
|
|
214
|
+
}, delay);
|
|
179
215
|
}
|
|
180
216
|
}
|
|
181
|
-
}
|
|
182
|
-
// Refresh failed — retry with exponential backoff
|
|
183
|
-
if (entry.retryCount < REFRESH_MAX_RETRIES) {
|
|
184
|
-
entry.retryCount++;
|
|
185
|
-
const delay = REFRESH_RETRY_DELAY_MS * Math.pow(2, entry.retryCount - 1);
|
|
186
|
-
_refreshQueue.set(entry.cacheKey, entry);
|
|
187
|
-
// Schedule re-processing after delay
|
|
188
|
-
setTimeout(() => {
|
|
189
|
-
if (!_refreshQueuePromise) {
|
|
190
|
-
_refreshQueuePromise = _processRefreshQueue().finally(() => {
|
|
191
|
-
_refreshQueuePromise = null;
|
|
192
|
-
if (_refreshQueue.size > 0) queueRefresh();
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
}, delay);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}));
|
|
217
|
+
}));
|
|
199
218
|
|
|
200
|
-
|
|
201
|
-
|
|
219
|
+
if (_refreshQueue.size > 0 && REFETCH_BATCH_DELAY_MS > 0) {
|
|
220
|
+
await new Promise(r => setTimeout(r, REFETCH_BATCH_DELAY_MS));
|
|
221
|
+
}
|
|
202
222
|
}
|
|
223
|
+
} finally {
|
|
224
|
+
_refreshQueuePromise = null;
|
|
203
225
|
}
|
|
204
|
-
_refreshQueueProcessing = false;
|
|
205
226
|
}
|
|
206
227
|
|
|
207
228
|
// --- Reactive Patterns (extracted for interval/focus/reconnect) ---
|
|
@@ -230,7 +251,8 @@ ${(() => {
|
|
|
230
251
|
return "";
|
|
231
252
|
return `// Start intervals for reactive patterns with refetchInterval
|
|
232
253
|
(async () => {
|
|
233
|
-
${patternsWithInterval
|
|
254
|
+
${patternsWithInterval
|
|
255
|
+
.map((p) => ` setInterval(async () => {
|
|
234
256
|
const cache = await caches.open(CACHE_NAME_RUNTIME);
|
|
235
257
|
const keys = await cache.keys();
|
|
236
258
|
for (const request of keys) {
|
|
@@ -244,7 +266,8 @@ ${patternsWithInterval.map(p => ` setInterval(async () => {
|
|
|
244
266
|
queueRefresh(request.url, url.href);
|
|
245
267
|
}
|
|
246
268
|
}
|
|
247
|
-
}, ${p.refetchInterval * 1000});`)
|
|
269
|
+
}, ${p.refetchInterval * 1000});`)
|
|
270
|
+
.join("\n")}
|
|
248
271
|
})();
|
|
249
272
|
`;
|
|
250
273
|
})()}
|
|
@@ -295,13 +318,15 @@ async function handleOnFocus() {
|
|
|
295
318
|
function cacheKey(request) {
|
|
296
319
|
const key = request.headers.get("X-SW-Cache-Key");
|
|
297
320
|
if (key) return new URL("/__swc/" + key, self.location.origin).href;
|
|
298
|
-
const url = new URL(request.url);${normalizeCacheKey
|
|
321
|
+
const url = new URL(request.url);${normalizeCacheKey
|
|
322
|
+
? `
|
|
299
323
|
// Sort query params alphabetically for consistent cache keys
|
|
300
324
|
if (url.search) {
|
|
301
325
|
const params = new URLSearchParams(url.search);
|
|
302
326
|
params.sort();
|
|
303
327
|
url.search = params.toString();
|
|
304
|
-
}`
|
|
328
|
+
}`
|
|
329
|
+
: ""}${ignoreQueryParams && ignoreQueryParams.length > 0
|
|
305
330
|
? `
|
|
306
331
|
// Strip configured query params from cache key
|
|
307
332
|
const ignore = ${JSON.stringify(ignoreQueryParams)};
|
|
@@ -339,7 +364,23 @@ async function storeRuntime(request, response) {
|
|
|
339
364
|
}
|
|
340
365
|
|
|
341
366
|
async function cacheResponse(request, response) {
|
|
342
|
-
await storeRuntime(request, response)
|
|
367
|
+
await storeRuntime(request, response);
|
|
368
|
+
const tagsHeader = request.headers.get("X-SW-Cache-Tags");
|
|
369
|
+
if (tagsHeader) {
|
|
370
|
+
const cacheKeyUrl = cacheKey(request);
|
|
371
|
+
const actualUrl = new URL(request.url).href;
|
|
372
|
+
const tags = tagsHeader.split(",").map((t) => t.trim());
|
|
373
|
+
const method = request.method;
|
|
374
|
+
let body = null;
|
|
375
|
+
let contentType = null;
|
|
376
|
+
if (method !== "GET" && method !== "HEAD") {
|
|
377
|
+
contentType = request.headers.get("Content-Type");
|
|
378
|
+
try {
|
|
379
|
+
body = await request.clone().text();
|
|
380
|
+
} catch {}
|
|
381
|
+
}
|
|
382
|
+
await cacheTagUrl(cacheKeyUrl, actualUrl, tags, method, body, contentType);
|
|
383
|
+
}
|
|
343
384
|
}
|
|
344
385
|
|
|
345
386
|
async function fromSpaFallback(request) {
|
|
@@ -362,7 +403,7 @@ function markFromCache(response) {
|
|
|
362
403
|
}
|
|
363
404
|
|
|
364
405
|
function isStale(response, staleTimeSeconds) {
|
|
365
|
-
if (
|
|
406
|
+
if (staleTimeSeconds == null || staleTimeSeconds <= 0) return false;
|
|
366
407
|
const cachedAt = response.headers.get("X-SW-Cached-At");
|
|
367
408
|
if (!cachedAt) return false;
|
|
368
409
|
return Date.now() - Number(cachedAt) > staleTimeSeconds * 1000;
|
|
@@ -377,7 +418,14 @@ function resolveStrategyEntry(entry) {
|
|
|
377
418
|
function determineCacheStrategy(request, customStrategies, globalDefaults) {
|
|
378
419
|
const override = request.headers.get("X-SW-Strategy");
|
|
379
420
|
if (override) {
|
|
380
|
-
|
|
421
|
+
const cfg = { strategy: override };
|
|
422
|
+
const hStale = request.headers.get("X-SW-Stale-Time");
|
|
423
|
+
if (hStale !== null) cfg.staleTime = Number(hStale);
|
|
424
|
+
const hFocus = request.headers.get("X-SW-Refetch-On-Focus");
|
|
425
|
+
if (hFocus !== null) cfg.refetchOnFocus = hFocus !== "false";
|
|
426
|
+
const hReconnect = request.headers.get("X-SW-Refetch-On-Reconnect");
|
|
427
|
+
if (hReconnect !== null) cfg.refetchOnReconnect = hReconnect !== "false";
|
|
428
|
+
return cfg;
|
|
381
429
|
}
|
|
382
430
|
const path = new URL(request.url).pathname;
|
|
383
431
|
for (const [pattern, entry] of Object.entries(customStrategies)) {
|
|
@@ -404,7 +452,8 @@ function applyStrategy(event, request, config) {
|
|
|
404
452
|
const { strategy } = config;
|
|
405
453
|
if (strategy === "reactive") {
|
|
406
454
|
const reactiveCfg = findReactiveConfig(new URL(request.url).href);
|
|
407
|
-
|
|
455
|
+
const staleTime = config.staleTime !== undefined ? config.staleTime : reactiveCfg?.staleTime;
|
|
456
|
+
event.respondWith(reactiveStrategy(event, request, staleTime));
|
|
408
457
|
} else if (strategy === "stale-while-revalidate") {
|
|
409
458
|
event.respondWith(staleWhileRevalidate(event, request));
|
|
410
459
|
} else if (strategy === "network-first") {
|
|
@@ -418,14 +467,17 @@ function applyStrategy(event, request, config) {
|
|
|
418
467
|
}
|
|
419
468
|
}
|
|
420
469
|
|
|
421
|
-
${mutationQueueEnabled
|
|
470
|
+
${mutationQueueEnabled
|
|
471
|
+
? `// --- Mutation Queue IDB Helpers ---
|
|
422
472
|
|
|
423
473
|
const MUTATION_DB_NAME = "swoff-queue";
|
|
424
474
|
const MUTATION_STORE_NAME = "mutations";
|
|
475
|
+
// Bump this when adding new indexes/stores for schema migration
|
|
476
|
+
const MUTATION_DB_VERSION = 1;
|
|
425
477
|
|
|
426
478
|
function openMutationQueueDB() {
|
|
427
479
|
return new Promise((resolve, reject) => {
|
|
428
|
-
const request = indexedDB.open(MUTATION_DB_NAME,
|
|
480
|
+
const request = indexedDB.open(MUTATION_DB_NAME, MUTATION_DB_VERSION);
|
|
429
481
|
request.onupgradeneeded = (e) => {
|
|
430
482
|
const db = e.target.result;
|
|
431
483
|
if (!db.objectStoreNames.contains(MUTATION_STORE_NAME)) {
|
|
@@ -459,7 +511,7 @@ async function storeMutationInSW(request) {
|
|
|
459
511
|
url: new URL(request.url).href,
|
|
460
512
|
body,
|
|
461
513
|
bodyType,
|
|
462
|
-
headers: {},
|
|
514
|
+
headers: request.headers.get("Content-Type") ? { "Content-Type": request.headers.get("Content-Type") } : {},
|
|
463
515
|
timestamp: Date.now(),
|
|
464
516
|
retryCount: 0,
|
|
465
517
|
nextRetryAt: 0,
|
|
@@ -494,15 +546,18 @@ async function handleMutation(event) {
|
|
|
494
546
|
}
|
|
495
547
|
}
|
|
496
548
|
|
|
497
|
-
`
|
|
498
|
-
|
|
549
|
+
`
|
|
550
|
+
: ""}self.addEventListener("fetch", (event) => {
|
|
551
|
+
const { request } = event;${mutationQueueEnabled
|
|
552
|
+
? `
|
|
499
553
|
if (request.method !== "GET" && request.method !== "HEAD") {
|
|
500
554
|
if (request.headers.get("X-SW-Cache-Strategy") === "mutation") {
|
|
501
555
|
event.respondWith(handleMutation(event));
|
|
502
556
|
return;
|
|
503
557
|
}
|
|
504
558
|
if (!request.headers.get("X-SW-Cache-Key")) return;
|
|
505
|
-
}`
|
|
559
|
+
}`
|
|
560
|
+
: `
|
|
506
561
|
if (request.method !== "GET" && request.method !== "HEAD") {
|
|
507
562
|
if (!request.headers.get("X-SW-Cache-Key")) return;
|
|
508
563
|
}`}
|
|
@@ -512,7 +567,8 @@ async function handleMutation(event) {
|
|
|
512
567
|
|
|
513
568
|
// --- Strategies ---
|
|
514
569
|
|
|
515
|
-
${navigationPreload
|
|
570
|
+
${navigationPreload
|
|
571
|
+
? `
|
|
516
572
|
async function fetchWithPreload(event, request) {
|
|
517
573
|
try {
|
|
518
574
|
const preload = await event.preloadResponse;
|
|
@@ -520,7 +576,8 @@ async function fetchWithPreload(event, request) {
|
|
|
520
576
|
} catch {}
|
|
521
577
|
return fetch(request);
|
|
522
578
|
}
|
|
523
|
-
`
|
|
579
|
+
`
|
|
580
|
+
: ""}const _fetch = ${navigationPreload ? "fetchWithPreload" : `(event, request) => fetch(request)`};
|
|
524
581
|
|
|
525
582
|
async function cacheFirst(event, request) {
|
|
526
583
|
const cached = await fromRuntime(request);
|
|
@@ -534,20 +591,22 @@ async function cacheFirst(event, request) {
|
|
|
534
591
|
const fallback = await fromSpaFallback(request);
|
|
535
592
|
if (fallback) return fallback;
|
|
536
593
|
|
|
594
|
+
const reqForCache = request.clone();
|
|
537
595
|
const response = await _fetch(event, request);
|
|
538
596
|
if (response.ok) {
|
|
539
597
|
const responseToCache = response.clone();
|
|
540
|
-
event.waitUntil(cacheResponse(
|
|
598
|
+
event.waitUntil(cacheResponse(reqForCache, responseToCache));
|
|
541
599
|
}
|
|
542
600
|
return response;
|
|
543
601
|
}
|
|
544
602
|
|
|
545
603
|
async function networkFirst(event, request) {
|
|
546
604
|
try {
|
|
605
|
+
const reqForCache = request.clone();
|
|
547
606
|
const response = await _fetch(event, request);
|
|
548
607
|
if (response.ok) {
|
|
549
608
|
const responseToCache = response.clone();
|
|
550
|
-
event.waitUntil(cacheResponse(
|
|
609
|
+
event.waitUntil(cacheResponse(reqForCache, responseToCache));
|
|
551
610
|
}
|
|
552
611
|
return response;
|
|
553
612
|
} catch {
|
|
@@ -579,10 +638,11 @@ async function staleWhileRevalidate(event, request) {
|
|
|
579
638
|
return markFromCache(precached);
|
|
580
639
|
}
|
|
581
640
|
|
|
641
|
+
const reqForCache = request.clone();
|
|
582
642
|
const response = await _fetch(event, request);
|
|
583
643
|
if (response.ok) {
|
|
584
644
|
const responseToCache = response.clone();
|
|
585
|
-
await cacheResponse(
|
|
645
|
+
await cacheResponse(reqForCache, responseToCache);
|
|
586
646
|
}
|
|
587
647
|
return response;
|
|
588
648
|
}
|
|
@@ -605,10 +665,11 @@ async function reactiveStrategy(event, request, staleTime) {
|
|
|
605
665
|
const fallback = await fromSpaFallback(request);
|
|
606
666
|
if (fallback) return fallback;
|
|
607
667
|
|
|
668
|
+
const reqForCache = request.clone();
|
|
608
669
|
const response = await _fetch(event, request);
|
|
609
670
|
if (response.ok) {
|
|
610
671
|
const responseToCache = response.clone();
|
|
611
|
-
await cacheResponse(
|
|
672
|
+
await cacheResponse(reqForCache, responseToCache);
|
|
612
673
|
}
|
|
613
674
|
return response;
|
|
614
675
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-handler.js","sourceRoot":"","sources":["../../../../src/lib/generators/sw-sections/fetch-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,UAAU,oBAAoB,CAClC,
|
|
1
|
+
{"version":3,"file":"fetch-handler.js","sourceRoot":"","sources":["../../../../src/lib/generators/sw-sections/fetch-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,UAAU,oBAAoB,CAClC,QAqCC,EACD,eAAwB,EACxB,oBAA6B;IAE7B,MAAM,EACJ,QAAQ,EAAE,EACR,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,UAAU,EACpB,IAAI,EAAE,aAAa,GAAG,KAAK,EAC3B,YAAY,EAAE,iBAAiB,EAC/B,iBAAiB,GAClB,EACD,UAAU,EAAE,EACV,IAAI,EAAE,OAAO,GAAG,KAAK,EACrB,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,OAAO,GAAG,aAAa,GAClC,EACD,YAAY,EAAE,EACZ,SAAS,EAAE,gBAAgB,GAAG,CAAC,EAC/B,YAAY,EAAE,mBAAmB,GAAG,IAAI,EACxC,UAAU,EAAE,iBAAiB,GAAG,CAAC,EACjC,YAAY,EAAE,mBAAmB,GAAG,IAAI,GACzC,GACF,GAAG,QAAQ,CAAC;IACb,MAAM,EACJ,SAAS,EAAE,eAAe,EAC1B,eAAe,EAAE,qBAAqB,EACtC,kBAAkB,EAAE,wBAAwB,EAC5C,cAAc,EAAE,oBAAoB,GACrC,GAAG,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,IAAI,EAAE,CAAC;IAE/C,MAAM,gBAAgB,GAAG,eAAe;QACtC,CAAC,CAAC;;;;MAIA;QACF,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,OAAO,GAAG,eAAe;QAC7B,CAAC,CAAC;;;;;;;IAOF;QACA,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,mBAAmB,GAAG;QAC1B,SAAS,EAAE,eAAe;QAC1B,eAAe,EAAE,qBAAqB;QACtC,kBAAkB,EAAE,wBAAwB;QAC5C,cAAc,EAAE,oBAAoB;KACrC,CAAC;IAEF,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC;SAChD,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE;QACpB,MAAM,QAAQ,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;QACzE,OAAO,QAAQ,CAAC,QAAQ,KAAK,UAAU,CAAC;IAC1C,CAAC,CAAC;SACD,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE;QACxB,MAAM,QAAQ,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;QACzE,OAAO;YACL,OAAO;YACP,SAAS,EAAE,QAAQ,CAAC,SAAS,IAAI,mBAAmB,CAAC,SAAS;YAC9D,eAAe,EACb,QAAQ,CAAC,eAAe,IAAI,mBAAmB,CAAC,eAAe;YACjE,kBAAkB,EAChB,QAAQ,CAAC,kBAAkB,IAAI,mBAAmB,CAAC,kBAAkB;YACvE,cAAc,EACZ,QAAQ,CAAC,cAAc,IAAI,mBAAmB,CAAC,cAAc;SAChE,CAAC;IACJ,CAAC,CAAC,CAAC;IAEL,MAAM,QAAQ,GAAG,8BAA8B,gBAAgB;iCAChC,mBAAmB;8BACtB,iBAAiB;iCACd,mBAAmB,GAAG,CAAC;IAEtD,MAAM,SAAS,GAAG,IAAI;QACxB,oCAAoC;QACpC,IAAI;QACJ,gCAAgC;QAChC,0DAA0D;QAC1D,KAAK;QACL,IAAI;QACJ,+BAA+B;QAC/B,qDAAqD;QACrD,wBAAwB;QACxB,wCAAwC;QACxC,4CAA4C;QAC5C,6BAA6B;QAC7B,wCAAwC;QACxC,6CAA6C;QAC7C,gBAAgB;QAChB,gIAAgI;QAChI,mBAAmB;QACnB,WAAW;QACX,mCAAmC;QACnC,OAAO;QACP,eAAe;QACf,KAAK;QACL,IAAI;QACJ,uCAAuC;QACvC,+EAA+E;QAC/E,qDAAqD;QACrD,gDAAgD;QAChD,0BAA0B;QAC1B,qDAAqD;QACrD,6BAA6B;QAC7B,4BAA4B;QAC5B,mDAAmD;QACnD,kCAAkC;QAClC,yBAAyB;QACzB,kDAAkD;QAClD,0FAA0F;QAC1F,6FAA6F;QAC7F,4DAA4D;QAC5D,WAAW;QACX,yCAAyC;QACzC,sBAAsB;QACtB,eAAe;QACf,mBAAmB;QACnB,SAAS;QACT,yFAAyF;QACzF,qFAAqF;QACrF,mDAAmD;QACnD,aAAa;QACb,cAAc;QACd,OAAO;QACP,uDAAuD;QACvD,KAAK;QACL,IAAI,CAAC;IAEH,OAAO,GAAG,QAAQ;;;;;;8CAOhB,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAC/B,GACE,eAAe,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC,EACpD;yDAEE,eAAe;QACb,CAAC,CAAC;;uDAE+C;QACjD,CAAC,CAAC,EACN;8GAEE,eAAe,CAAC,CAAC,CAAC,oGAAoG,CAAC,CAAC,CAAC,EAC3H;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oDAuDY,eAAe;QACb,CAAC,CAAC;;;YAGN;QACI,CAAC,CAAC,EACN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAoCgB,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC;;;;;;;;;;;;;;;;;;EAkB1D,CAAC,GAAG,EAAE;QACN,MAAM,oBAAoB,GAAG,gBAAgB,CAAC,MAAM,CAClD,CAAC,CAAC,EAA+C,EAAE,CACjD,CAAC,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,CAAC,eAAe,GAAG,CAAC,CAC/C,CAAC;QACF,IAAI,oBAAoB,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QACjD,OAAO;;EAEP,oBAAoB;aACnB,GAAG,CACF,CAAC,CAAC,EAAE,EAAE,CACJ;;;;;;sCAMgC,CAAC,CAAC,OAAO;;;;;;;;OAQxC,CAAC,CAAC,eAAe,GAAG,IAAI,IAAI,CAChC;aACA,IAAI,CAAC,IAAI,CAAC;;CAEZ,CAAC;IACF,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qCAiDA,iBAAiB;QACf,CAAC,CAAC;;;;;;IAMJ;QACE,CAAC,CAAC,EACN,GACE,iBAAiB,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC;QAC/C,CAAC,CAAC;;mBAEW,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC;;;;;IAKhD;QACE,CAAC,CAAC,EACN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BAmDwB,OAAO;;;;;;;;;;;;;;;;;;;;;;;EAuB/B,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2DT,oBAAoB;QAClB,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8EL;QACG,CAAC,CAAC,EACN;8BAEI,oBAAoB;QAClB,CAAC,CAAC;;;;;;;IAOJ;QACE,CAAC,CAAC;;;IAIN;IACE,aAAa,KAAK,eAAe,CAAC,CAAC,CAAC,0DAA0D,CAAC,CAAC,CAAC,EAAE;wEAC/B,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,yBAAyB,eAAe;;;;;EAMxI,iBAAiB;QACf,CAAC,CAAC;;;;;;;;CAQL;QACG,CAAC,CAAC,EACN,kBAAkB,iBAAiB,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,oCAAoC;;;;iBAI9E,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuEhB,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;iBAwBhB,gBAAgB;;;;;;;;;;;;EAY/B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glob-matcher-code.js","sourceRoot":"","sources":["../../../../src/lib/generators/sw-sections/glob-matcher-code.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI;IACrC,oCAAoC;IACpC,IAAI;IACJ,gCAAgC;IAChC,0DAA0D;IAC1D,KAAK;IACL,IAAI;IACJ,+BAA+B;IAC/B,qDAAqD;IACrD,wBAAwB;IACxB,wCAAwC;IACxC,4CAA4C;IAC5C,6BAA6B;IAC7B,wCAAwC;IACxC,6CAA6C;IAC7C,gBAAgB;IAChB,gIAAgI;IAChI,mBAAmB;IACnB,WAAW;IACX,mCAAmC;IACnC,OAAO;IACP,eAAe;IACf,KAAK;IACL,IAAI;IACJ,uCAAuC;IACvC,+EAA+E;IAC/E,qDAAqD;IACrD,gDAAgD;IAChD,0BAA0B;IAC1B,qDAAqD;IACrD,6BAA6B;IAC7B,4BAA4B;IAC5B,mDAAmD;IACnD,kCAAkC;IAClC,yBAAyB;IACzB,kDAAkD;IAClD,0FAA0F;IAC1F,6FAA6F;IAC7F,4DAA4D;IAC5D,WAAW;IACX,yCAAyC;IACzC,sBAAsB;IACtB,eAAe;IACf,mBAAmB;IACnB,SAAS;IACT,yFAAyF;IACzF,qFAAqF;IACrF,mDAAmD;IACnD,aAAa;IACb,cAAc;IACd,OAAO;IACP,uDAAuD;IACvD,KAAK;IACL,IAAI,CAAC"}
|
|
@@ -48,6 +48,14 @@ self.addEventListener("activate", (event) => {
|
|
|
48
48
|
return `
|
|
49
49
|
// --- Server Push Events (SSE) ---
|
|
50
50
|
|
|
51
|
+
function notifyClientsSSE(connected) {
|
|
52
|
+
self.clients.matchAll().then(function(clients) {
|
|
53
|
+
clients.forEach(function(client) {
|
|
54
|
+
client.postMessage({ type: "SSE_STATUS", connected: !!connected });
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
51
59
|
let pushReconnectTimer = null;
|
|
52
60
|
let pushAbortController = null;
|
|
53
61
|
|
|
@@ -56,12 +64,15 @@ async function connectPushEvents() {
|
|
|
56
64
|
pushAbortController = new AbortController();
|
|
57
65
|
const response = await fetch("${endpoint}", {
|
|
58
66
|
headers: { Accept: "text/event-stream" },
|
|
67
|
+
credentials: "include",
|
|
59
68
|
signal: pushAbortController.signal,
|
|
60
69
|
});
|
|
61
70
|
if (!response.ok || !response.body) {
|
|
71
|
+
notifyClientsSSE(false);
|
|
62
72
|
scheduleReconnect();
|
|
63
73
|
return;
|
|
64
74
|
}
|
|
75
|
+
notifyClientsSSE(true);
|
|
65
76
|
const reader = response.body.getReader();
|
|
66
77
|
const decoder = new TextDecoder();
|
|
67
78
|
let buffer = "";
|
|
@@ -98,6 +109,7 @@ async function connectPushEvents() {
|
|
|
98
109
|
} catch {
|
|
99
110
|
// Connection lost or aborted
|
|
100
111
|
}
|
|
112
|
+
notifyClientsSSE(false);
|
|
101
113
|
scheduleReconnect();
|
|
102
114
|
}
|
|
103
115
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-push-handler.js","sourceRoot":"","sources":["../../../../src/lib/generators/sw-sections/server-push-handler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,UAAU,yBAAyB,CACvC,IAAyB,EACzB,QAAgB,EAChB,gBAAwB;IAExB,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;QACzB,OAAO;;;;;;;;8BAQmB,QAAQ;;;;;;;;;;;;;;;;;;;;;;;uDAuBiB,gBAAgB;;;;;;CAMtE,CAAC;IACA,CAAC;IAED,qCAAqC;IACrC,OAAO
|
|
1
|
+
{"version":3,"file":"server-push-handler.js","sourceRoot":"","sources":["../../../../src/lib/generators/sw-sections/server-push-handler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,UAAU,yBAAyB,CACvC,IAAyB,EACzB,QAAgB,EAChB,gBAAwB;IAExB,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;QACzB,OAAO;;;;;;;;8BAQmB,QAAQ;;;;;;;;;;;;;;;;;;;;;;;uDAuBiB,gBAAgB;;;;;;CAMtE,CAAC;IACA,CAAC;IAED,qCAAqC;IACrC,OAAO;;;;;;;;;;;;;;;;;oCAiB2B,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uDAqDW,gBAAgB;;;;;;CAMtE,CAAC;AACF,CAAC"}
|
|
@@ -12,6 +12,8 @@ const STALE_VERSIONS_MAX = 100;
|
|
|
12
12
|
const STALE_VERSION_TTL = 30 * 60 * 1000;
|
|
13
13
|
const TAG_DB_NAME = "swoff-cache-tags";
|
|
14
14
|
const TAG_STORE_NAME = "tags";
|
|
15
|
+
// Bump this when adding new indexes/stores for schema migration
|
|
16
|
+
const TAG_DB_VERSION = 1;
|
|
15
17
|
|
|
16
18
|
function cleanStaleVersions() {
|
|
17
19
|
const now = Date.now();
|
|
@@ -24,7 +26,7 @@ function cleanStaleVersions() {
|
|
|
24
26
|
|
|
25
27
|
function openTagDB() {
|
|
26
28
|
return new Promise((resolve, reject) => {
|
|
27
|
-
const request = indexedDB.open(TAG_DB_NAME,
|
|
29
|
+
const request = indexedDB.open(TAG_DB_NAME, TAG_DB_VERSION);
|
|
28
30
|
request.onupgradeneeded = (e) => {
|
|
29
31
|
const db = e.target.result;
|
|
30
32
|
if (!db.objectStoreNames.contains(TAG_STORE_NAME)) {
|
|
@@ -37,11 +39,11 @@ function openTagDB() {
|
|
|
37
39
|
});
|
|
38
40
|
}
|
|
39
41
|
|
|
40
|
-
async function cacheTagUrl(url, actualUrl, tags) {
|
|
42
|
+
async function cacheTagUrl(url, actualUrl, tags, method, body, contentType) {
|
|
41
43
|
const db = await openTagDB();
|
|
42
44
|
const tx = db.transaction(TAG_STORE_NAME, "readwrite");
|
|
43
45
|
const store = tx.objectStore(TAG_STORE_NAME);
|
|
44
|
-
store.put({ url, actualUrl, tags });
|
|
46
|
+
store.put({ url, actualUrl, tags, method: method || "GET", body: body || null, contentType: contentType || null });
|
|
45
47
|
await new Promise((resolve, reject) => {
|
|
46
48
|
tx.oncomplete = () => resolve();
|
|
47
49
|
tx.onerror = () => reject(tx.error);
|
|
@@ -81,7 +83,7 @@ async function invalidateByTag(tag) {
|
|
|
81
83
|
// Enqueue background refetch through batched refresh queue
|
|
82
84
|
for (const entry of entries) {
|
|
83
85
|
staleVersions.set(entry.url, Date.now());
|
|
84
|
-
queueRefresh(entry.url, entry.actualUrl, entry.tags);
|
|
86
|
+
queueRefresh(entry.url, entry.actualUrl, entry.tags, entry.method, entry.body, entry.contentType);
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
const clients = await self.clients.matchAll();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tag-management.js","sourceRoot":"","sources":["../../../../src/lib/generators/sw-sections/tag-management.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,UAAU,qBAAqB;IACnC,OAAO
|
|
1
|
+
{"version":3,"file":"tag-management.js","sourceRoot":"","sources":["../../../../src/lib/generators/sw-sections/tag-management.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,UAAU,qBAAqB;IACnC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoIP,CAAC;AACH,CAAC"}
|