@swoff/cli 0.3.13 → 0.3.15
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/README.md +28 -32
- package/dist/index.js +4 -15
- package/dist/index.js.map +1 -1
- package/dist/lib/cli/help.js +4 -9
- package/dist/lib/cli/help.js.map +1 -1
- package/dist/lib/commands/clean.js +8 -17
- package/dist/lib/commands/clean.js.map +1 -1
- package/dist/lib/commands/generate-guide.js +16 -30
- package/dist/lib/commands/generate-guide.js.map +1 -1
- package/dist/lib/commands/generate.js +33 -7
- package/dist/lib/commands/generate.js.map +1 -1
- package/dist/lib/commands/init.js +259 -23
- package/dist/lib/commands/init.js.map +1 -1
- package/dist/lib/commands/validate.js +2 -4
- package/dist/lib/commands/validate.js.map +1 -1
- package/dist/lib/config/loader.js +34 -25
- package/dist/lib/config/loader.js.map +1 -1
- package/dist/lib/config/minimal-config.js +64 -0
- package/dist/lib/config/minimal-config.js.map +1 -0
- package/dist/lib/config/validator.js +219 -110
- package/dist/lib/config/validator.js.map +1 -1
- package/dist/lib/generators/file-generators/api-config.js +1 -1
- package/dist/lib/generators/file-generators/api-config.js.map +1 -1
- package/dist/lib/generators/file-generators/auth-adapter.js +13 -0
- package/dist/lib/generators/file-generators/auth-adapter.js.map +1 -0
- package/dist/lib/generators/file-generators/auth-check.js +40 -0
- package/dist/lib/generators/file-generators/auth-check.js.map +1 -0
- package/dist/lib/generators/file-generators/auth-store.js +2 -5
- package/dist/lib/generators/file-generators/auth-store.js.map +1 -1
- package/dist/lib/generators/file-generators/background-sync.js +1 -1
- package/dist/lib/generators/file-generators/background-sync.js.map +1 -1
- package/dist/lib/generators/file-generators/cache.js +2 -1
- package/dist/lib/generators/file-generators/cache.js.map +1 -1
- package/dist/lib/generators/file-generators/client-injector-bundle.js +15 -0
- package/dist/lib/generators/file-generators/client-injector-bundle.js.map +1 -0
- package/dist/lib/generators/file-generators/client-injector.js +2 -1
- package/dist/lib/generators/file-generators/client-injector.js.map +1 -1
- package/dist/lib/generators/file-generators/connectivity.js +12 -0
- package/dist/lib/generators/file-generators/connectivity.js.map +1 -0
- package/dist/lib/generators/file-generators/context.js +7 -0
- package/dist/lib/generators/file-generators/context.js.map +1 -1
- package/dist/lib/generators/file-generators/fetch-wrapper.js +1 -1
- package/dist/lib/generators/file-generators/fetch-wrapper.js.map +1 -1
- package/dist/lib/generators/file-generators/generate-framework-adapters.js +29 -20
- package/dist/lib/generators/file-generators/generate-framework-adapters.js.map +1 -1
- package/dist/lib/generators/file-generators/gql-wrapper.js +2 -2
- package/dist/lib/generators/file-generators/gql-wrapper.js.map +1 -1
- package/dist/lib/generators/file-generators/guide-generator.js +51 -1
- package/dist/lib/generators/file-generators/guide-generator.js.map +1 -1
- package/dist/lib/generators/file-generators/invalidation-tags.js +2 -3
- package/dist/lib/generators/file-generators/invalidation-tags.js.map +1 -1
- package/dist/lib/generators/file-generators/mutation-queue.js +2 -2
- package/dist/lib/generators/file-generators/mutation-queue.js.map +1 -1
- package/dist/lib/generators/file-generators/mutation-state.js +1 -1
- package/dist/lib/generators/file-generators/mutation-state.js.map +1 -1
- package/dist/lib/generators/file-generators/open-db.js +6 -0
- package/dist/lib/generators/file-generators/open-db.js.map +1 -0
- package/dist/lib/generators/file-generators/push.js +1 -2
- package/dist/lib/generators/file-generators/push.js.map +1 -1
- package/dist/lib/generators/file-generators/pwa-install.js +2 -6
- package/dist/lib/generators/file-generators/pwa-install.js.map +1 -1
- package/dist/lib/generators/file-generators/server-push.js +1 -1
- package/dist/lib/generators/file-generators/server-push.js.map +1 -1
- package/dist/lib/generators/file-generators/storage.js +6 -0
- package/dist/lib/generators/file-generators/storage.js.map +1 -0
- package/dist/lib/generators/file-generators/sw-generator-build.js +105 -48
- package/dist/lib/generators/file-generators/sw-generator-build.js.map +1 -1
- package/dist/lib/generators/file-generators/sw-injector.js +0 -4
- package/dist/lib/generators/file-generators/sw-injector.js.map +1 -1
- package/dist/lib/generators/file-generators/sw-template.js +8 -9
- package/dist/lib/generators/file-generators/sw-template.js.map +1 -1
- package/dist/lib/generators/file-generators/swoff-api-bundle.js +51 -0
- package/dist/lib/generators/file-generators/swoff-api-bundle.js.map +1 -0
- package/dist/lib/generators/sw-build-utils.js +69 -0
- package/dist/lib/generators/sw-build-utils.js.map +1 -0
- package/dist/lib/generators/sw-generator.js +23 -34
- package/dist/lib/generators/sw-generator.js.map +1 -1
- package/dist/lib/generators/sw-sections/activate-handler.js +77 -23
- package/dist/lib/generators/sw-sections/activate-handler.js.map +1 -1
- package/dist/lib/generators/sw-sections/assemble-sw.js +20 -95
- package/dist/lib/generators/sw-sections/assemble-sw.js.map +1 -1
- package/dist/lib/generators/sw-sections/background-precache.js +126 -0
- package/dist/lib/generators/sw-sections/background-precache.js.map +1 -0
- package/dist/lib/generators/sw-sections/background-sync-handler.js +74 -72
- package/dist/lib/generators/sw-sections/background-sync-handler.js.map +1 -1
- package/dist/lib/generators/sw-sections/batch-refresh-queue.js +102 -0
- package/dist/lib/generators/sw-sections/batch-refresh-queue.js.map +1 -0
- package/dist/lib/generators/sw-sections/config-header.js +2 -3
- package/dist/lib/generators/sw-sections/config-header.js.map +1 -1
- package/dist/lib/generators/sw-sections/default-template.js +64 -7
- package/dist/lib/generators/sw-sections/default-template.js.map +1 -1
- package/dist/lib/generators/sw-sections/fetch-handler.js +621 -495
- package/dist/lib/generators/sw-sections/fetch-handler.js.map +1 -1
- package/dist/lib/generators/sw-sections/install-handler.js +41 -23
- package/dist/lib/generators/sw-sections/install-handler.js.map +1 -1
- package/dist/lib/generators/sw-sections/message-handler.js +34 -8
- package/dist/lib/generators/sw-sections/message-handler.js.map +1 -1
- package/dist/lib/generators/sw-sections/server-push-handler.js +10 -14
- package/dist/lib/generators/sw-sections/server-push-handler.js.map +1 -1
- package/dist/lib/generators/sw-sections/shared.js +70 -0
- package/dist/lib/generators/sw-sections/shared.js.map +1 -0
- package/dist/lib/generators/sw-sections/sw-push.js +2 -6
- package/dist/lib/generators/sw-sections/sw-push.js.map +1 -1
- package/dist/lib/generators/sw-sections/tag-management.js +55 -86
- package/dist/lib/generators/sw-sections/tag-management.js.map +1 -1
- package/dist/lib/generators/swoff-files-generator.js +183 -59
- package/dist/lib/generators/swoff-files-generator.js.map +1 -1
- package/dist/lib/shared/config-types.js +84 -79
- package/dist/lib/shared/config-types.js.map +1 -1
- package/dist/lib/shared/feature-registry.js +198 -0
- package/dist/lib/shared/feature-registry.js.map +1 -0
- package/dist/lib/utils/detect-framework.js +52 -9
- package/dist/lib/utils/detect-framework.js.map +1 -1
- package/dist/runtime/api-config.js +2 -2
- package/dist/runtime/api-config.js.map +1 -1
- package/dist/runtime/auth-adapter.js +179 -0
- package/dist/runtime/auth-adapter.js.map +1 -0
- package/dist/runtime/auth-state.js +16 -6
- package/dist/runtime/auth-state.js.map +1 -1
- package/dist/runtime/auth-store.js +219 -213
- package/dist/runtime/auth-store.js.map +1 -1
- package/dist/runtime/background-sync.js +5 -2
- package/dist/runtime/background-sync.js.map +1 -1
- package/dist/runtime/cache.js +91 -3
- package/dist/runtime/cache.js.map +1 -1
- package/dist/runtime/client-injector-bundle.js +314 -0
- package/dist/runtime/client-injector-bundle.js.map +1 -0
- package/dist/runtime/client-injector.js +188 -30
- package/dist/runtime/client-injector.js.map +1 -1
- package/dist/runtime/connectivity.js +83 -0
- package/dist/runtime/connectivity.js.map +1 -0
- package/dist/runtime/fetch-wrapper.js +26 -59
- package/dist/runtime/fetch-wrapper.js.map +1 -1
- package/dist/runtime/gql-wrapper.js +15 -9
- package/dist/runtime/gql-wrapper.js.map +1 -1
- package/dist/runtime/invalidation-tags.js +12 -89
- package/dist/runtime/invalidation-tags.js.map +1 -1
- package/dist/runtime/mutation-queue.js +83 -31
- package/dist/runtime/mutation-queue.js.map +1 -1
- package/dist/runtime/mutation-state.js +3 -3
- package/dist/runtime/mutation-state.js.map +1 -1
- package/dist/runtime/open-db.js +41 -0
- package/dist/runtime/open-db.js.map +1 -0
- package/dist/runtime/push.js +15 -27
- package/dist/runtime/push.js.map +1 -1
- package/dist/runtime/pwa-prompt.js +35 -3
- package/dist/runtime/pwa-prompt.js.map +1 -1
- package/dist/runtime/reset.js +39 -42
- package/dist/runtime/reset.js.map +1 -1
- package/dist/runtime/server-push.js +23 -13
- package/dist/runtime/server-push.js.map +1 -1
- package/dist/runtime/storage.js +32 -0
- package/dist/runtime/storage.js.map +1 -0
- package/dist/runtime/sw-injector.js +19 -178
- package/dist/runtime/sw-injector.js.map +1 -1
- package/dist/runtime/swoff-api-bundle.js +1491 -0
- package/dist/runtime/swoff-api-bundle.js.map +1 -0
- package/dist/runtime/type-definitions.js +8 -7
- package/dist/runtime/type-definitions.js.map +1 -1
- package/dist/runtime/utils.js +4 -0
- package/dist/runtime/utils.js.map +1 -1
- package/package.json +9 -3
- package/templates/react/useAuth.jsx +7 -4
- package/templates/react/useAuth.tsx +14 -14
- package/templates/react/useBackgroundSync.jsx +5 -4
- package/templates/react/useBackgroundSync.tsx +5 -4
- package/templates/react/useCachedFetch.jsx +8 -0
- package/templates/react/useCachedFetch.tsx +8 -0
- package/templates/react/useMutation.jsx +60 -56
- package/templates/react/useMutation.tsx +65 -64
- package/templates/react/useMutationQueue.jsx +5 -1
- package/templates/react/useMutationQueue.tsx +8 -2
- package/templates/react/useMutationState.jsx +3 -4
- package/templates/react/useMutationState.tsx +4 -8
- package/templates/react/useNetworkStatus.jsx +57 -17
- package/templates/react/useNetworkStatus.tsx +42 -20
- package/templates/react/useOfflineAnalytics.jsx +42 -0
- package/templates/react/useOfflineAnalytics.tsx +50 -0
- package/templates/react/usePwaInstall.jsx +26 -0
- package/templates/react/usePwaInstall.tsx +26 -0
- package/templates/react/useSWUpdate.jsx +7 -52
- package/templates/react/useSWUpdate.tsx +12 -51
- package/templates/react/useStorageEstimate.jsx +56 -0
- package/templates/react/useStorageEstimate.tsx +67 -0
- package/dist/__tests__/assemble-sw.test.js +0 -145
- package/dist/__tests__/assemble-sw.test.js.map +0 -1
- package/dist/__tests__/cli-integration.test.js +0 -231
- package/dist/__tests__/cli-integration.test.js.map +0 -1
- package/dist/__tests__/config-types.test.js +0 -124
- package/dist/__tests__/config-types.test.js.map +0 -1
- package/dist/__tests__/detect-language.test.js +0 -51
- package/dist/__tests__/detect-language.test.js.map +0 -1
- package/dist/__tests__/file-generators.test.js +0 -228
- package/dist/__tests__/file-generators.test.js.map +0 -1
- package/dist/__tests__/glob-matcher.test.js +0 -86
- package/dist/__tests__/glob-matcher.test.js.map +0 -1
- package/dist/__tests__/invalidation-tags.test.js +0 -283
- package/dist/__tests__/invalidation-tags.test.js.map +0 -1
- package/dist/__tests__/loader.test.js +0 -77
- package/dist/__tests__/loader.test.js.map +0 -1
- package/dist/__tests__/validator.test.js +0 -340
- package/dist/__tests__/validator.test.js.map +0 -1
- package/dist/lib/commands/add.js +0 -120
- package/dist/lib/commands/add.js.map +0 -1
- package/dist/lib/commands/assets.js +0 -45
- package/dist/lib/commands/assets.js.map +0 -1
- package/dist/lib/commands/generate-assets.js +0 -44
- package/dist/lib/commands/generate-assets.js.map +0 -1
- package/dist/lib/commands/info.js +0 -183
- package/dist/lib/commands/info.js.map +0 -1
- package/dist/lib/generators/asset-generator/dependency-resolver.js +0 -85
- package/dist/lib/generators/asset-generator/dependency-resolver.js.map +0 -1
- package/dist/lib/generators/asset-generator/generate.js +0 -111
- package/dist/lib/generators/asset-generator/generate.js.map +0 -1
- package/dist/lib/generators/asset-generator/guide.js +0 -43
- package/dist/lib/generators/asset-generator/guide.js.map +0 -1
- package/dist/lib/generators/asset-generator/html-patcher.js +0 -65
- package/dist/lib/generators/asset-generator/html-patcher.js.map +0 -1
- package/dist/lib/generators/asset-generator/ico-encoder.js +0 -29
- package/dist/lib/generators/asset-generator/ico-encoder.js.map +0 -1
- package/dist/lib/generators/asset-generator/manifest-patcher.js +0 -23
- package/dist/lib/generators/asset-generator/manifest-patcher.js.map +0 -1
- package/dist/lib/generators/asset-generator/maskable.js +0 -15
- package/dist/lib/generators/asset-generator/maskable.js.map +0 -1
- package/dist/lib/generators/asset-generator/rasterize.js +0 -32
- package/dist/lib/generators/asset-generator/rasterize.js.map +0 -1
- package/dist/lib/generators/asset-generator/sizes.js +0 -25
- package/dist/lib/generators/asset-generator/sizes.js.map +0 -1
- package/dist/lib/generators/file-generators/auth-fetch.js +0 -151
- package/dist/lib/generators/file-generators/auth-fetch.js.map +0 -1
- package/dist/lib/generators/file-generators/auth-user.js +0 -13
- package/dist/lib/generators/file-generators/auth-user.js.map +0 -1
- package/dist/lib/generators/file-generators/fetch-state.js +0 -6
- package/dist/lib/generators/file-generators/fetch-state.js.map +0 -1
- package/dist/lib/generators/file-generators/generate-hooks.js +0 -44
- package/dist/lib/generators/file-generators/generate-hooks.js.map +0 -1
- package/dist/lib/generators/file-generators/indexeddb.js +0 -74
- package/dist/lib/generators/file-generators/indexeddb.js.map +0 -1
- package/dist/lib/generators/file-generators/manifest.js +0 -46
- package/dist/lib/generators/file-generators/manifest.js.map +0 -1
- package/dist/lib/generators/file-generators/mutation-reconcile.js +0 -57
- package/dist/lib/generators/file-generators/mutation-reconcile.js.map +0 -1
- package/dist/lib/generators/file-generators/quick-readme.js +0 -21
- package/dist/lib/generators/file-generators/quick-readme.js.map +0 -1
- package/dist/lib/generators/file-generators/reconcile.js +0 -50
- package/dist/lib/generators/file-generators/reconcile.js.map +0 -1
- package/dist/lib/generators/file-generators/store.js +0 -86
- package/dist/lib/generators/file-generators/store.js.map +0 -1
- package/dist/lib/generators/file-generators/sw-push.js +0 -67
- package/dist/lib/generators/file-generators/sw-push.js.map +0 -1
- package/dist/lib/generators/sw-sections/glob-matcher-code.js.map +0 -1
- package/dist/lib/utils/build-script.js +0 -35
- package/dist/lib/utils/build-script.js.map +0 -1
- package/dist/lib/utils/tty-status.js +0 -21
- package/dist/lib/utils/tty-status.js.map +0 -1
- package/dist/runtime/auth-user.js +0 -168
- package/dist/runtime/auth-user.js.map +0 -1
- package/dist/runtime/fetch-state.js +0 -42
- package/dist/runtime/fetch-state.js.map +0 -1
- package/dist/runtime/pwa-index.js +0 -11
- package/dist/runtime/pwa-index.js.map +0 -1
- package/dist/runtime/pwa-injector.js +0 -44
- package/dist/runtime/pwa-injector.js.map +0 -1
- package/dist/runtime/pwa-install.js +0 -83
- package/dist/runtime/pwa-install.js.map +0 -1
- package/templates/react/useCacheInvalidation.jsx +0 -19
- package/templates/react/useCacheInvalidation.tsx +0 -52
- package/templates/react/useIsFetching.jsx +0 -32
- package/templates/react/useIsFetching.tsx +0 -32
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { T } from "./utils.js";
|
|
2
|
+
export function generateConnectivityCode(ctx) {
|
|
3
|
+
const { ts } = ctx;
|
|
4
|
+
return `/**
|
|
5
|
+
**/
|
|
6
|
+
export const CONNECTIVITY_EVENT = 'app-connectivity-change'
|
|
7
|
+
|
|
8
|
+
let heartbeatIntervalId${T(ts, "ReturnType<typeof setInterval> | null")} = null
|
|
9
|
+
const HEARTBEAT_DELAY = 30000
|
|
10
|
+
|
|
11
|
+
let _currentOnlineStatus = typeof navigator !== 'undefined' ? navigator.onLine : true
|
|
12
|
+
|
|
13
|
+
export function getCurrentOnlineStatus(): boolean {
|
|
14
|
+
return _currentOnlineStatus
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function createTimeoutSignal(ms) {
|
|
18
|
+
if (typeof AbortSignal.timeout === "function") return AbortSignal.timeout(ms);
|
|
19
|
+
var ctrl = new AbortController();
|
|
20
|
+
setTimeout(function() { ctrl.abort(); }, ms);
|
|
21
|
+
return ctrl.signal;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function verifyAndNotify() {
|
|
25
|
+
if (typeof window === 'undefined') return false
|
|
26
|
+
|
|
27
|
+
if (!navigator.onLine) {
|
|
28
|
+
dispatchState(false)
|
|
29
|
+
return false
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
await fetch(\`/\${Date.now()}?hb=1\`, {
|
|
34
|
+
method: 'HEAD',
|
|
35
|
+
cache: 'no-cache',
|
|
36
|
+
signal: createTimeoutSignal(5000),
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
if (navigator.serviceWorker.controller) {
|
|
40
|
+
navigator.serviceWorker.controller.postMessage({ type: 'ONLINE' })
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
dispatchState(true)
|
|
44
|
+
return true
|
|
45
|
+
} catch (error) {
|
|
46
|
+
if (navigator.serviceWorker.controller) {
|
|
47
|
+
navigator.serviceWorker.controller.postMessage({ type: 'OFFLINE' })
|
|
48
|
+
}
|
|
49
|
+
dispatchState(false)
|
|
50
|
+
return false
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function dispatchState(isTrulyOnline: boolean) {
|
|
55
|
+
_currentOnlineStatus = isTrulyOnline
|
|
56
|
+
const event = new CustomEvent(CONNECTIVITY_EVENT, {
|
|
57
|
+
detail: { online: isTrulyOnline },
|
|
58
|
+
})
|
|
59
|
+
window.dispatchEvent(event)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function startHeartbeat() {
|
|
63
|
+
if (heartbeatIntervalId) return
|
|
64
|
+
heartbeatIntervalId = setInterval(async () => {
|
|
65
|
+
if (document.hidden) return
|
|
66
|
+
await verifyAndNotify()
|
|
67
|
+
}, HEARTBEAT_DELAY)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function stopHeartbeat() {
|
|
71
|
+
if (!heartbeatIntervalId) return
|
|
72
|
+
clearInterval(heartbeatIntervalId)
|
|
73
|
+
heartbeatIntervalId = null
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export async function forceRetry() {
|
|
77
|
+
stopHeartbeat()
|
|
78
|
+
await verifyAndNotify()
|
|
79
|
+
startHeartbeat()
|
|
80
|
+
}
|
|
81
|
+
`;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=connectivity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connectivity.js","sourceRoot":"","sources":["../../src/runtime/connectivity.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;AAE/B,MAAM,UAAU,wBAAwB,CAAC,GAAmB;IAC1D,MAAM,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC;IACnB,OAAO;;;;yBAIgB,CAAC,CAAC,EAAE,EAAE,uCAAuC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyEtE,CAAC;AACF,CAAC"}
|
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
import { T, R, G } from "./utils.js";
|
|
2
|
-
export function generateFetchWrapperCode(ctx, authEnabled,
|
|
1
|
+
import { T, R, G, AS } from "./utils.js";
|
|
2
|
+
export function generateFetchWrapperCode(ctx, authEnabled, mutationQueue, requestBatchWindowMs) {
|
|
3
3
|
const { ext, ts } = ctx;
|
|
4
4
|
const importLines = [
|
|
5
|
-
`import {
|
|
6
|
-
`import {
|
|
7
|
-
`import { invalidateByTags } from "../cache/index.${ext}";`,
|
|
5
|
+
`import { generateTags } from "../cache/tags.${ext}";`,
|
|
6
|
+
`import { invalidateByTags, invalidateUrl${mutationQueue ? ", expandCascading" : ""} } from "../cache/invalidate.${ext}";`,
|
|
8
7
|
authEnabled
|
|
9
|
-
? `import { getAuth,
|
|
8
|
+
? `import { getAuth, withAuthHeaders, AUTH_WITH_CREDENTIALS } from "../auth/store.${ext}";`
|
|
10
9
|
: "",
|
|
11
10
|
mutationQueue
|
|
12
|
-
? `import { queueMutation } from "../
|
|
11
|
+
? `import { queueMutation } from "../mutation/queue.${ext}";`
|
|
13
12
|
: "",
|
|
14
|
-
`import { incrementFetchCount, decrementFetchCount } from "../fetch/state.${ext}";`,
|
|
15
13
|
]
|
|
16
14
|
.filter(Boolean)
|
|
17
15
|
.join("\n");
|
|
@@ -41,8 +39,7 @@ export interface FetchWithCacheOptions extends RequestInit {
|
|
|
41
39
|
validateSuccess?: (response: Response) => boolean | Promise<boolean>;
|
|
42
40
|
/** Override the URL used for auto-invalidation. Defaults to the request URL. Useful when the mutation URL differs from the cache tag URL. */
|
|
43
41
|
invalidateUrl?: string;
|
|
44
|
-
|
|
45
|
-
skipFetchCount?: boolean;
|
|
42
|
+
|
|
46
43
|
}
|
|
47
44
|
`
|
|
48
45
|
: "";
|
|
@@ -51,48 +48,12 @@ export interface FetchWithCacheOptions extends RequestInit {
|
|
|
51
48
|
if (options.auth) {
|
|
52
49
|
const auth = await getAuth();
|
|
53
50
|
withAuthHeaders(headers, auth);
|
|
54
|
-
}`
|
|
55
|
-
: "";
|
|
56
|
-
const authUrlsBlock = authEnabled
|
|
57
|
-
? `
|
|
58
|
-
// Auth endpoints bypass SW cache
|
|
59
|
-
if (options.auth && isAuthUrl(url) && !headers.has("X-SW-Cache-Strategy")) {
|
|
60
|
-
headers.set("X-SW-Cache-Strategy", "mutation");
|
|
61
51
|
}`
|
|
62
52
|
: "";
|
|
63
53
|
const authCredentialsBlock = authEnabled
|
|
64
54
|
? `
|
|
65
55
|
if (AUTH_WITH_CREDENTIALS) {
|
|
66
56
|
fetchOptions.credentials = "include";
|
|
67
|
-
}`
|
|
68
|
-
: "";
|
|
69
|
-
const auth401Block = authEnabled
|
|
70
|
-
? `
|
|
71
|
-
if (options.auth && response.status === 401) {
|
|
72
|
-
// Check if the token is actually expired by probing the user endpoint
|
|
73
|
-
try {
|
|
74
|
-
const authCheck = await fetch(API_BASE + "${userEndpoint}", {
|
|
75
|
-
headers: { "Authorization": headers.get("Authorization") } as HeadersInit,
|
|
76
|
-
credentials: AUTH_WITH_CREDENTIALS ? "include" : undefined,
|
|
77
|
-
});
|
|
78
|
-
if (authCheck.status === 401) {
|
|
79
|
-
// Token expired — try silent refresh
|
|
80
|
-
const refreshed = await ensureValidAuth();
|
|
81
|
-
if (refreshed?.token) {
|
|
82
|
-
// Retry original request with fresh token
|
|
83
|
-
const retryHeaders = new Headers(options.headers);
|
|
84
|
-
withAuthHeaders(retryHeaders, refreshed);
|
|
85
|
-
response = await fetch(resolvedInput, { ...fetchOptions, headers: retryHeaders });
|
|
86
|
-
} else {
|
|
87
|
-
await clearAuth();
|
|
88
|
-
window.dispatchEvent(new CustomEvent("sw-auth-unauthorized"));
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
// authCheck 200: user IS authenticated but lacks permission — let original 401 propagate
|
|
92
|
-
} catch {
|
|
93
|
-
await clearAuth();
|
|
94
|
-
window.dispatchEvent(new CustomEvent("sw-auth-unauthorized"));
|
|
95
|
-
}
|
|
96
57
|
}`
|
|
97
58
|
: "";
|
|
98
59
|
const mutationTagsBlock = mutationQueue
|
|
@@ -228,18 +189,16 @@ const BATCH_WINDOW_MS = ${requestBatchWindowMs};
|
|
|
228
189
|
|
|
229
190
|
/** Fetch with caching, auth, offline queue, auto-invalidation, and per-request strategy override. Returns { response, fromCache }. Use { auth: true } for authenticated requests — works with bearer, cookie, and custom auth types. */
|
|
230
191
|
export async function fetchWithCache${G(ts, "T")}(input${T(ts, "RequestInfo")}, options${T(ts, "RequestInit & FetchWithCacheOptions")} = {})${R(ts, "Promise<FetchWithCacheResult<T>>")}{
|
|
231
|
-
if (!options.skipFetchCount) incrementFetchCount();
|
|
232
|
-
try {
|
|
233
192
|
const method = (options.method || "GET").toUpperCase();
|
|
234
193
|
const isRead = options.type === "read" || (options.type !== "mutation" && (method === "GET" || method === "HEAD" || method === "OPTIONS"));
|
|
235
|
-
const resolvedInput =
|
|
194
|
+
const resolvedInput = input;
|
|
236
195
|
const url = typeof resolvedInput === "string" ? resolvedInput : resolvedInput.url;
|
|
237
196
|
|
|
238
197
|
const headers = new Headers(options.headers);
|
|
239
198
|
|
|
240
199
|
// Set cache strategy
|
|
241
|
-
if (!headers.has("X-SW-
|
|
242
|
-
headers.set("X-SW-
|
|
200
|
+
if (!headers.has("X-SW-Type")) {
|
|
201
|
+
headers.set("X-SW-Type", isRead ? "read" : "mutation");
|
|
243
202
|
}
|
|
244
203
|
${autoTagsBlock}
|
|
245
204
|
// Custom tags override auto-generated
|
|
@@ -262,7 +221,7 @@ ${autoTagsBlock}
|
|
|
262
221
|
if (options.refetchOnReconnect !== undefined) {
|
|
263
222
|
headers.set("X-SW-Refetch-On-Reconnect", String(options.refetchOnReconnect));
|
|
264
223
|
}
|
|
265
|
-
${authBlock}
|
|
224
|
+
${authBlock}
|
|
266
225
|
// Forward no-queue option to SW
|
|
267
226
|
if (options.queueOffline === false) {
|
|
268
227
|
headers.set("X-SW-No-Queue", "true");
|
|
@@ -288,12 +247,18 @@ ${mutationTagsBlock}
|
|
|
288
247
|
} else {
|
|
289
248
|
const abortHandler = () => {
|
|
290
249
|
inFlightRequests.delete(url);
|
|
250
|
+
if (pendingBatches.has(url)) {
|
|
251
|
+
const batch = pendingBatches.get(url)!;
|
|
252
|
+
clearTimeout(batch.timer);
|
|
253
|
+
pendingBatches.delete(url);
|
|
254
|
+
batch.rejectors.forEach((rej) => rej(new DOMException("The operation was aborted", "AbortError")));
|
|
255
|
+
}
|
|
291
256
|
};
|
|
292
257
|
if (options.signal) {
|
|
293
258
|
options.signal.addEventListener("abort", abortHandler, { once: true });
|
|
294
259
|
}
|
|
295
260
|
if (isRead && BATCH_WINDOW_MS > 0) {
|
|
296
|
-
const batch${T(ts, "{ resolvers: Array<(r: Response) => void>; rejectors: Array<(e: unknown) => void>; timer: ReturnType<typeof setTimeout> }")} = { resolvers: [], rejectors: [], timer: 0 };
|
|
261
|
+
const batch${T(ts, "{ resolvers: Array<(r: Response) => void>; rejectors: Array<(e: unknown) => void>; timer: ReturnType<typeof setTimeout> }")} = { resolvers: [], rejectors: [], timer: 0${AS(ts, "unknown as ReturnType<typeof setTimeout>")} };
|
|
297
262
|
pendingBatches.set(url, batch);
|
|
298
263
|
batch.timer = setTimeout(() => {
|
|
299
264
|
pendingBatches.delete(url);
|
|
@@ -316,7 +281,12 @@ ${mutationTagsBlock}
|
|
|
316
281
|
batch.rejectors.push(reject);
|
|
317
282
|
});
|
|
318
283
|
} else {
|
|
319
|
-
responsePromise = fetch(resolvedInput, fetchOptions)
|
|
284
|
+
responsePromise = fetch(resolvedInput, fetchOptions).finally(() => {
|
|
285
|
+
inFlightRequests.delete(url);
|
|
286
|
+
if (options.signal) {
|
|
287
|
+
options.signal.removeEventListener("abort", abortHandler);
|
|
288
|
+
}
|
|
289
|
+
});
|
|
320
290
|
}
|
|
321
291
|
}
|
|
322
292
|
|
|
@@ -335,18 +305,15 @@ ${offlineWriteFallbackBlock}
|
|
|
335
305
|
}
|
|
336
306
|
throw err;
|
|
337
307
|
}
|
|
338
|
-
${autoInvalidateBlock}
|
|
308
|
+
${autoInvalidateBlock}
|
|
339
309
|
const fromCache = response.headers.get("X-SW-From-Cache") === "true";
|
|
340
310
|
const queued = response.headers.get("X-SW-Mutation-Queued") === "true";
|
|
341
311
|
return { response, fromCache, queued };
|
|
342
|
-
} finally {
|
|
343
|
-
if (!options.skipFetchCount) decrementFetchCount();
|
|
344
|
-
}
|
|
345
312
|
}
|
|
346
313
|
|
|
347
314
|
/** Fire-and-forget prefetch: warms the cache for a URL without blocking. Useful for route prefetching or link hover prefetching. */
|
|
348
315
|
export function prefetchCache(input${T(ts, "RequestInfo")}, options${T(ts, "RequestInit & FetchWithCacheOptions")} = {})${R(ts, "void")}{
|
|
349
|
-
fetchWithCache(input,
|
|
316
|
+
fetchWithCache(input, options).catch(() => {
|
|
350
317
|
// Prefetch failures are intentionally silent
|
|
351
318
|
});
|
|
352
319
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-wrapper.js","sourceRoot":"","sources":["../../src/runtime/fetch-wrapper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"fetch-wrapper.js","sourceRoot":"","sources":["../../src/runtime/fetch-wrapper.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { T, R, G, AS } from "./utils.js";
|
|
2
|
-
export function generateGqlWrapperCode(ctx,
|
|
2
|
+
export function generateGqlWrapperCode(ctx, endpoints) {
|
|
3
3
|
const { ext, ts } = ctx;
|
|
4
4
|
const optionsInterface = ts
|
|
5
5
|
? `
|
|
@@ -50,6 +50,8 @@ export interface GqlOptions {
|
|
|
50
50
|
import { fetchWithCache } from "../fetch/core.${ext}";
|
|
51
51
|
import type { GqlResult } from "../swoff";
|
|
52
52
|
${optionsInterface}
|
|
53
|
+
const GQL_ENDPOINTS = ${JSON.stringify(endpoints)};
|
|
54
|
+
|
|
53
55
|
/** Extract operation name from a GraphQL document. Returns null for anonymous queries (e.g. "{ todos { id } }"). */
|
|
54
56
|
function getOperationName(query${T(ts, "string")})${T(ts, "string | null")}{
|
|
55
57
|
const match = query.match(/(query|mutation|subscription)\\s+(\\w+)/);
|
|
@@ -76,23 +78,25 @@ function tagsFromOpName(name${T(ts, "string | null")})${T(ts, "string[]")}{
|
|
|
76
78
|
if (!name) return [];
|
|
77
79
|
const stripped = name.replace(/^(get|fetch|list|all|query)/i, "").replace(/^(create|set|add|new|update|delete|remove)/i, "");
|
|
78
80
|
if (!stripped) return [name.toLowerCase()];
|
|
79
|
-
const tag = stripped.
|
|
81
|
+
const tag = stripped.toLowerCase();
|
|
80
82
|
const plural = tag.replace(/s$/, "") + "s";
|
|
81
83
|
return [plural, tag];
|
|
82
84
|
}
|
|
83
85
|
|
|
84
|
-
/** Fetch a GraphQL endpoint with Swoff's caching, auth, offline queue, and auto-invalidation. Hashes query + variables for deterministic cache keys. */
|
|
86
|
+
/** Fetch a GraphQL endpoint with Swoff's caching, auth, offline queue, and auto-invalidation. Hashes query + variables for deterministic cache keys. Uses GQL_ENDPOINTS[0] by default. Pass endpointIndex to use a different endpoint. */
|
|
85
87
|
export async function fetchWithGql${G(ts, "T")}(
|
|
86
88
|
query${T(ts, "string")},
|
|
87
|
-
options${T(ts, "GqlOptions")} = {}
|
|
89
|
+
options${T(ts, "GqlOptions")} = {},
|
|
90
|
+
endpointIndex${T(ts, "number")} = 0
|
|
88
91
|
)${R(ts, "Promise<GqlResult<T>>")}{
|
|
89
92
|
const isRead = isReadOperation(query);
|
|
90
93
|
const opName = getOperationName(query);
|
|
91
94
|
const variables = options.variables;
|
|
92
95
|
const hash = await bodyHash({ query, variables });
|
|
93
96
|
const tags = options.tags || tagsFromOpName(opName);
|
|
97
|
+
const endpoint = GQL_ENDPOINTS[endpointIndex] || GQL_ENDPOINTS[0];
|
|
94
98
|
|
|
95
|
-
const { response, fromCache } = await fetchWithCache(
|
|
99
|
+
const { response, fromCache } = await fetchWithCache(endpoint, {
|
|
96
100
|
method: "POST",
|
|
97
101
|
body: JSON.stringify({ query, variables }),
|
|
98
102
|
headers: {
|
|
@@ -117,18 +121,20 @@ export async function fetchWithGql${G(ts, "T")}(
|
|
|
117
121
|
export async function queryGql${G(ts, "T")}(
|
|
118
122
|
query${T(ts, "string")},
|
|
119
123
|
variables${T(ts, "Record<string, unknown> | undefined")} = undefined,
|
|
120
|
-
options${T(ts, "GqlOptions")} = {}
|
|
124
|
+
options${T(ts, "GqlOptions")} = {},
|
|
125
|
+
endpointIndex${T(ts, "number")} = 0
|
|
121
126
|
)${R(ts, "Promise<GqlResult<T>>")}{
|
|
122
|
-
return fetchWithGql${G(ts, "T")}(query, { ...options, variables });
|
|
127
|
+
return fetchWithGql${G(ts, "T")}(query, { ...options, variables }, endpointIndex);
|
|
123
128
|
}
|
|
124
129
|
|
|
125
130
|
/** Shorthand for GraphQL mutations (type: "mutation"). Auto-invalidates related cache tags. */
|
|
126
131
|
export async function mutateGql${G(ts, "T")}(
|
|
127
132
|
mutation${T(ts, "string")},
|
|
128
133
|
variables${T(ts, "Record<string, unknown> | undefined")} = undefined,
|
|
129
|
-
options${T(ts, "GqlOptions")} = {}
|
|
134
|
+
options${T(ts, "GqlOptions")} = {},
|
|
135
|
+
endpointIndex${T(ts, "number")} = 0
|
|
130
136
|
)${R(ts, "Promise<GqlResult<T>>")}{
|
|
131
|
-
return fetchWithGql${G(ts, "T")}(mutation, { ...options, variables });
|
|
137
|
+
return fetchWithGql${G(ts, "T")}(mutation, { ...options, variables }, endpointIndex);
|
|
132
138
|
}
|
|
133
139
|
`;
|
|
134
140
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gql-wrapper.js","sourceRoot":"","sources":["../../src/runtime/gql-wrapper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,UAAU,sBAAsB,CACpC,GAAmB,EACnB,
|
|
1
|
+
{"version":3,"file":"gql-wrapper.js","sourceRoot":"","sources":["../../src/runtime/gql-wrapper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,UAAU,sBAAsB,CACpC,GAAmB,EACnB,SAAmB;IAEnB,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC;IAExB,MAAM,gBAAgB,GAAG,EAAE;QACzB,CAAC,CAAC;;;;;;;;CAQL;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO;;;;;;;8EAOqE,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;gDA4BjC,GAAG;;EAEjD,gBAAgB;wBACM,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC;;;iCAGhB,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;;;gCAM1C,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC;;;;;;;6BAOtC,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,iBAAiB,CAAC;;;;;;;;8BAQ3C,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,UAAU,CAAC;;;;;;;;;;oCAUrC,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC;SACrC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;WACb,CAAC,CAAC,EAAE,EAAE,YAAY,CAAC;iBACb,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;GAC7B,CAAC,CAAC,EAAE,EAAE,uBAAuB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;8BA0BH,EAAE,CAAC,EAAE,EAAE,GAAG,CAAC;;;;gCAIT,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC;SACjC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;aACX,CAAC,CAAC,EAAE,EAAE,qCAAqC,CAAC;WAC9C,CAAC,CAAC,EAAE,EAAE,YAAY,CAAC;iBACb,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;GAC7B,CAAC,CAAC,EAAE,EAAE,uBAAuB,CAAC;uBACV,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC;;;;iCAIA,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC;YAC/B,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;aACd,CAAC,CAAC,EAAE,EAAE,qCAAqC,CAAC;WAC9C,CAAC,CAAC,EAAE,EAAE,YAAY,CAAC;iBACb,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;GAC7B,CAAC,CAAC,EAAE,EAAE,uBAAuB,CAAC;uBACV,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC;;CAEhC,CAAC;AACF,CAAC"}
|
|
@@ -74,24 +74,17 @@ function generateSingularizationCode(singularization) {
|
|
|
74
74
|
return "null";
|
|
75
75
|
return JSON.stringify(singularization);
|
|
76
76
|
}
|
|
77
|
-
function
|
|
78
|
-
if (!cascading || Object.keys(cascading).length === 0)
|
|
79
|
-
return "null";
|
|
80
|
-
return JSON.stringify(cascading);
|
|
81
|
-
}
|
|
82
|
-
export function generateInvalidationTagsCode(ctx, prefixes, patterns, singularization, cascading) {
|
|
77
|
+
export function generateInvalidationTagsCode(ctx, prefixes, patterns, singularization) {
|
|
83
78
|
const { ext, ts } = ctx;
|
|
84
79
|
const patternCode = generatePatternCode(patterns);
|
|
85
80
|
const singularizationCode = generateSingularizationCode(singularization);
|
|
86
|
-
const cascadingCode = generateCascadingCode(cascading);
|
|
87
81
|
const prefixesCode = JSON.stringify(prefixes);
|
|
88
82
|
return `/**
|
|
89
83
|
* Swoff Invalidation Tags Helper
|
|
90
|
-
*
|
|
91
|
-
* prefix skipping, singularization, and cascading invalidation.
|
|
84
|
+
* Segment- and pattern-based tag generation from URLs.
|
|
92
85
|
*
|
|
93
86
|
* Usage:
|
|
94
|
-
* import { generateTags
|
|
87
|
+
* import { generateTags } from './swoff/cache/tags.${ext}';
|
|
95
88
|
*
|
|
96
89
|
* // Generate tags from URL
|
|
97
90
|
* generateTags("/api/todos"); // ["todos"]
|
|
@@ -102,11 +95,9 @@ export function generateInvalidationTagsCode(ctx, prefixes, patterns, singulariz
|
|
|
102
95
|
* tags: generateTags("/api/todos"),
|
|
103
96
|
* });
|
|
104
97
|
*
|
|
105
|
-
* //
|
|
106
|
-
*
|
|
98
|
+
* // Generate method-prefixed tags for mutations
|
|
99
|
+
* generateTagsFromMethod("POST", "/api/todos"); // ["post-todos"]
|
|
107
100
|
*/
|
|
108
|
-
|
|
109
|
-
import { invalidateByTags } from "./index.${ext}";
|
|
110
101
|
${ts ? `
|
|
111
102
|
interface TagPattern {
|
|
112
103
|
re: RegExp;
|
|
@@ -123,12 +114,15 @@ const SKIP_PREFIXES = ${prefixesCode};
|
|
|
123
114
|
// Custom singularization map (plural → singular)
|
|
124
115
|
const SINGULARIZATION${T(ts, "Record<string, string> | null")} = ${singularizationCode};
|
|
125
116
|
|
|
126
|
-
// Cascading invalidation map (tag → dependent tags)
|
|
127
|
-
const CASCADING${T(ts, "Record<string, string[]> | null")} = ${cascadingCode};
|
|
128
|
-
|
|
129
117
|
/** Generate cache invalidation tags from a URL path. Tries configured patterns first, falls back to segment-based generation. */
|
|
130
118
|
export function generateTags(url${T(ts, "string | URL")})${R(ts, "string[]")}{
|
|
131
|
-
const
|
|
119
|
+
const base = typeof window !== "undefined" ? window.location.origin : "";
|
|
120
|
+
let parsed;
|
|
121
|
+
try {
|
|
122
|
+
parsed = typeof url === "string" ? new URL(url, base) : url;
|
|
123
|
+
} catch {
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
132
126
|
const path = parsed.pathname;
|
|
133
127
|
|
|
134
128
|
// Try configured patterns first
|
|
@@ -184,77 +178,6 @@ export function generateTagsFromMethod(method${T(ts, "string")}, url${T(ts, "str
|
|
|
184
178
|
if (method === "GET" || method === "HEAD") return tags;
|
|
185
179
|
return tags.map((tag) => \`\${method.toLowerCase()}-\${tag}\`);
|
|
186
180
|
}
|
|
187
|
-
|
|
188
|
-
/** Invalidate cached responses related to a URL, including cascading dependencies. */
|
|
189
|
-
export async function invalidateUrl(url${T(ts, "string | URL")})${R(ts, "Promise<void>")}{
|
|
190
|
-
const tags = generateTags(url);
|
|
191
|
-
const allTags = CASCADING ? expandCascading(tags) : tags;
|
|
192
|
-
await invalidateByTags(allTags);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/** Invalidate cached responses tagged with method-prefixed tags, including cascading dependencies. */
|
|
196
|
-
export async function invalidateByMethod(method${T(ts, "string")}, url${T(ts, "string | URL")})${R(ts, "Promise<void>")}{
|
|
197
|
-
const tags = generateTagsFromMethod(method, url);
|
|
198
|
-
const allTags = CASCADING ? expandCascading(tags) : tags;
|
|
199
|
-
await invalidateByTags(allTags);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/** Expand tags with their cascading dependencies, deduplicated. */
|
|
203
|
-
export function expandCascading(tags${T(ts, "string[]")})${R(ts, "string[]")}{
|
|
204
|
-
if (!CASCADING) return [...tags];
|
|
205
|
-
const result = new Set(tags);
|
|
206
|
-
for (const tag of tags) {
|
|
207
|
-
const deps = CASCADING[tag];
|
|
208
|
-
if (deps) {
|
|
209
|
-
for (const dep of deps) {
|
|
210
|
-
result.add(dep);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
return [...result];
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/** Introspect: get all URLs cached under a given tag. */
|
|
218
|
-
export async function getUrlsForTag(tag${T(ts, "string")})${R(ts, "Promise<{ url: string; actualUrl: string }[]>")}{
|
|
219
|
-
const controller = navigator.serviceWorker?.controller;
|
|
220
|
-
if (!controller) return [];
|
|
221
|
-
return new Promise((resolve) => {
|
|
222
|
-
const channel = new MessageChannel();
|
|
223
|
-
channel.port1.onmessage = (event) => {
|
|
224
|
-
resolve(event.data.urls || []);
|
|
225
|
-
};
|
|
226
|
-
controller.postMessage(
|
|
227
|
-
{ type: "GET_URLS_FOR_TAG", tag },
|
|
228
|
-
[channel.port2],
|
|
229
|
-
);
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
/** Introspect: get all tags associated with a given URL. */
|
|
234
|
-
export async function getTagsForUrl(url${T(ts, "string")})${R(ts, "Promise<string[]>")}{
|
|
235
|
-
const controller = navigator.serviceWorker?.controller;
|
|
236
|
-
if (!controller) return [];
|
|
237
|
-
return new Promise((resolve) => {
|
|
238
|
-
const channel = new MessageChannel();
|
|
239
|
-
channel.port1.onmessage = (event) => {
|
|
240
|
-
resolve(event.data.tags || []);
|
|
241
|
-
};
|
|
242
|
-
controller.postMessage(
|
|
243
|
-
{ type: "GET_TAGS_FOR_URL", url },
|
|
244
|
-
[channel.port2],
|
|
245
|
-
);
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/** Invalidate all cached responses whose URL matches the given glob pattern. */
|
|
250
|
-
export async function invalidateMatching(glob${T(ts, "string")})${R(ts, "Promise<void>")}{
|
|
251
|
-
const controller = navigator.serviceWorker?.controller;
|
|
252
|
-
if (!controller) return;
|
|
253
|
-
controller.postMessage({
|
|
254
|
-
type: "INVALIDATE_MATCHING",
|
|
255
|
-
glob,
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
181
|
`;
|
|
259
182
|
}
|
|
260
183
|
//# sourceMappingURL=invalidation-tags.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invalidation-tags.js","sourceRoot":"","sources":["../../src/runtime/invalidation-tags.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"invalidation-tags.js","sourceRoot":"","sources":["../../src/runtime/invalidation-tags.ts"],"names":[],"mappings":"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"}
|