@swoff/cli 0.3.13 → 0.3.14
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 +2 -13
- package/dist/index.js.map +1 -1
- package/dist/lib/cli/help.js +3 -8
- package/dist/lib/cli/help.js.map +1 -1
- package/dist/lib/commands/add.js +29 -87
- package/dist/lib/commands/add.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 +31 -6
- package/dist/lib/commands/generate.js.map +1 -1
- package/dist/lib/commands/init.js +188 -11
- 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/validator.js +202 -96
- 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-manager.js +12 -0
- package/dist/lib/generators/file-generators/connectivity-manager.js.map +1 -0
- 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/notification-generator.js +6 -0
- package/dist/lib/generators/file-generators/notification-generator.js.map +1 -0
- 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-generator.js +6 -0
- package/dist/lib/generators/file-generators/storage-generator.js.map +1 -0
- package/dist/lib/generators/file-generators/storage-notify.js +6 -0
- package/dist/lib/generators/file-generators/storage-notify.js.map +1 -0
- 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 +96 -45
- 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/sw-version-gen.js +32 -0
- package/dist/lib/generators/file-generators/sw-version-gen.js.map +1 -0
- 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 +74 -23
- package/dist/lib/generators/sw-sections/activate-handler.js.map +1 -1
- package/dist/lib/generators/sw-sections/assemble-sw.js +15 -94
- package/dist/lib/generators/sw-sections/assemble-sw.js.map +1 -1
- 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 +59 -6
- 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 +40 -23
- package/dist/lib/generators/sw-sections/install-handler.js.map +1 -1
- package/dist/lib/generators/sw-sections/message-handler.js +25 -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 +68 -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 +67 -63
- 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/auth-user.js +5 -19
- package/dist/runtime/auth-user.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 +173 -30
- package/dist/runtime/client-injector.js.map +1 -1
- package/dist/runtime/connectivity-manager.js +83 -0
- package/dist/runtime/connectivity-manager.js.map +1 -0
- 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/notification.js +65 -0
- package/dist/runtime/notification.js.map +1 -0
- 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-injector.js +3 -32
- package/dist/runtime/pwa-injector.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/sw-version.js +13 -0
- package/dist/runtime/sw-version.js.map +1 -0
- 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/dist/swoff-nkdhhmw8. +18 -0
- package/dist/swoff.js +5 -0
- package/package.json +1 -1
- 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/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
package/dist/runtime/cache.js
CHANGED
|
@@ -1,17 +1,30 @@
|
|
|
1
1
|
import { T, R } from "./utils.js";
|
|
2
|
-
|
|
2
|
+
function generateCascadingCode(cascading) {
|
|
3
|
+
if (!cascading || Object.keys(cascading).length === 0)
|
|
4
|
+
return "null";
|
|
5
|
+
return JSON.stringify(cascading);
|
|
6
|
+
}
|
|
7
|
+
export function generateCacheCode(ctx, cascading) {
|
|
3
8
|
const { ext, ts } = ctx;
|
|
9
|
+
const cascadingCode = generateCascadingCode(cascading);
|
|
4
10
|
return `/**
|
|
5
11
|
* Swoff Cache Invalidation
|
|
6
|
-
* Framework-agnostic cache tag invalidation
|
|
12
|
+
* Framework-agnostic cache tag invalidation, URL-based invalidation,
|
|
13
|
+
* cascading dependency expansion, introspection, and glob matching.
|
|
7
14
|
*
|
|
8
15
|
* Usage:
|
|
9
|
-
* import { invalidateByTag, invalidateByTags } from './swoff/cache.${ext}';
|
|
16
|
+
* import { invalidateByTag, invalidateByTags, invalidateUrl } from './swoff/cache/invalidate.${ext}';
|
|
10
17
|
*
|
|
11
18
|
* // After a mutation, invalidate related cache
|
|
12
19
|
* await invalidateByTag("todos");
|
|
20
|
+
* await invalidateUrl("/api/todos/42");
|
|
13
21
|
*/
|
|
14
22
|
|
|
23
|
+
import { generateTags, generateTagsFromMethod } from "./tags.${ext}";
|
|
24
|
+
|
|
25
|
+
// Cascading invalidation map (tag → dependent tags)
|
|
26
|
+
const CASCADING${T(ts, "Record<string, string[]> | null")} = ${cascadingCode};
|
|
27
|
+
|
|
15
28
|
/** Invalidate all cached responses tagged with the given tag. Sends INVALIDATE_TAG to the SW; the client-injector dispatches cache-invalidated on SW confirmation. */
|
|
16
29
|
export async function invalidateByTag(tag${T(ts, "string")})${R(ts, "Promise<void>")}{
|
|
17
30
|
if (!navigator.serviceWorker?.controller) return;
|
|
@@ -25,6 +38,81 @@ export async function invalidateByTag(tag${T(ts, "string")})${R(ts, "Promise<voi
|
|
|
25
38
|
export async function invalidateByTags(tags${T(ts, "string[]")})${R(ts, "Promise<void>")}{
|
|
26
39
|
await Promise.all(tags.map((tag) => invalidateByTag(tag)));
|
|
27
40
|
}
|
|
41
|
+
|
|
42
|
+
/** Expand tags with their cascading dependencies, deduplicated. */
|
|
43
|
+
export function expandCascading(tags${T(ts, "string[]")})${R(ts, "string[]")}{
|
|
44
|
+
if (!CASCADING) return [...tags];
|
|
45
|
+
const result = new Set(tags);
|
|
46
|
+
for (const tag of tags) {
|
|
47
|
+
const deps = CASCADING[tag];
|
|
48
|
+
if (deps) {
|
|
49
|
+
for (const dep of deps) {
|
|
50
|
+
result.add(dep);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return [...result];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Invalidate cached responses related to a URL, including cascading dependencies. */
|
|
58
|
+
export async function invalidateUrl(url${T(ts, "string | URL")})${R(ts, "Promise<void>")}{
|
|
59
|
+
const tags = generateTags(url);
|
|
60
|
+
const allTags = CASCADING ? expandCascading(tags) : tags;
|
|
61
|
+
await invalidateByTags(allTags);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Invalidate cached responses tagged with method-prefixed tags, including cascading dependencies. */
|
|
65
|
+
export async function invalidateByMethod(method${T(ts, "string")}, url${T(ts, "string | URL")})${R(ts, "Promise<void>")}{
|
|
66
|
+
const tags = generateTagsFromMethod(method, url);
|
|
67
|
+
const allTags = CASCADING ? expandCascading(tags) : tags;
|
|
68
|
+
await invalidateByTags(allTags);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Invalidate all cached responses whose URL matches the given glob pattern. */
|
|
72
|
+
export async function invalidateMatching(glob${T(ts, "string")})${R(ts, "Promise<void>")}{
|
|
73
|
+
const controller = navigator.serviceWorker?.controller;
|
|
74
|
+
if (!controller) return;
|
|
75
|
+
controller.postMessage({
|
|
76
|
+
type: "INVALIDATE_MATCHING",
|
|
77
|
+
glob,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Introspect: get all URLs cached under a given tag. */
|
|
82
|
+
export async function getUrlsForTag(tag${T(ts, "string")})${R(ts, "Promise<{ url: string; actualUrl: string }[]>")}{
|
|
83
|
+
const controller = navigator.serviceWorker?.controller;
|
|
84
|
+
if (!controller) return [];
|
|
85
|
+
return new Promise((resolve) => {
|
|
86
|
+
const channel = new MessageChannel();
|
|
87
|
+
const timeout = setTimeout(() => { channel.port1.close(); resolve([]); }, 5000);
|
|
88
|
+
channel.port1.onmessage = (event) => {
|
|
89
|
+
clearTimeout(timeout);
|
|
90
|
+
resolve(event.data.urls || []);
|
|
91
|
+
};
|
|
92
|
+
controller.postMessage(
|
|
93
|
+
{ type: "GET_URLS_FOR_TAG", tag },
|
|
94
|
+
[channel.port2],
|
|
95
|
+
);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Introspect: get all tags associated with a given URL. */
|
|
100
|
+
export async function getTagsForUrl(url${T(ts, "string")})${R(ts, "Promise<string[]>")}{
|
|
101
|
+
const controller = navigator.serviceWorker?.controller;
|
|
102
|
+
if (!controller) return [];
|
|
103
|
+
return new Promise((resolve) => {
|
|
104
|
+
const channel = new MessageChannel();
|
|
105
|
+
const timeout = setTimeout(() => { channel.port1.close(); resolve([]); }, 5000);
|
|
106
|
+
channel.port1.onmessage = (event) => {
|
|
107
|
+
clearTimeout(timeout);
|
|
108
|
+
resolve(event.data.tags || []);
|
|
109
|
+
};
|
|
110
|
+
controller.postMessage(
|
|
111
|
+
{ type: "GET_TAGS_FOR_URL", url },
|
|
112
|
+
[channel.port2],
|
|
113
|
+
);
|
|
114
|
+
});
|
|
115
|
+
}
|
|
28
116
|
`;
|
|
29
117
|
}
|
|
30
118
|
//# sourceMappingURL=cache.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/runtime/cache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;AAElC,MAAM,UAAU,iBAAiB,
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/runtime/cache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;AAElC,SAAS,qBAAqB,CAAC,SAAmC;IAChE,IAAI,CAAC,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IACrE,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,GAAmB,EACnB,SAAmC;IAEnC,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC;IACxB,MAAM,aAAa,GAAG,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAEvD,OAAO;;;;;;kGAMyF,GAAG;;;;;;;+DAOtC,GAAG;;;iBAGjD,CAAC,CAAC,EAAE,EAAE,iCAAiC,CAAC,MAAM,aAAa;;;2CAGjC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;;;;;;6CASvC,CAAC,CAAC,EAAE,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;;sCAKlD,CAAC,CAAC,EAAE,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,UAAU,CAAC;;;;;;;;;;;;;;;yCAenC,CAAC,CAAC,EAAE,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;;;;iDAOvC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;;;;+CAOxE,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;;;;;;;yCAU/C,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,+CAA+C,CAAC;;;;;;;;;;;;;;;;;;yCAkBzE,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,mBAAmB,CAAC;;;;;;;;;;;;;;;;CAgBrF,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
export function generateClientInjectorBundleCode(ctx, autoActivate, swFilename, pwaEnabled, navMode, authEnabled, mutationQueueEnabled) {
|
|
2
|
+
const pwaCode = pwaEnabled ? `
|
|
3
|
+
// ── PWA Install Prompt ──
|
|
4
|
+
function setupPwaInstall() {
|
|
5
|
+
window.addEventListener("beforeinstallprompt", function (e) {
|
|
6
|
+
window.deferredInstallPrompt = e;
|
|
7
|
+
window.pwaInstallable = true;
|
|
8
|
+
e.preventDefault();
|
|
9
|
+
window.dispatchEvent(new CustomEvent("pwa-installable", { detail: { isInstallable: true } }));
|
|
10
|
+
});
|
|
11
|
+
window.addEventListener("appinstalled", function () {
|
|
12
|
+
window.deferredInstallPrompt = null;
|
|
13
|
+
window.pwaInstallable = false;
|
|
14
|
+
window.dispatchEvent(new CustomEvent("pwa-installed", { detail: { outcome: "accepted" } }));
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
if (typeof window !== "undefined" && typeof document !== "undefined") { setupPwaInstall(); }` : "";
|
|
18
|
+
const ssrPrefetch = navMode === "ssr" ? `
|
|
19
|
+
// ── Auto-prefetch HTML on client-side navigation (SSR mode) ──
|
|
20
|
+
// Guards against missing prefetchCache — only active when the user includes the fetch/core module.
|
|
21
|
+
if (typeof history !== "undefined") {
|
|
22
|
+
var origPushState = history.pushState.bind(history);
|
|
23
|
+
history.pushState = function (data, unused, url) {
|
|
24
|
+
origPushState(data, unused, url);
|
|
25
|
+
if (typeof url === "string" && url.startsWith("/") && typeof prefetchCache === "function") {
|
|
26
|
+
prefetchCache(url);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
var origReplaceState = history.replaceState.bind(history);
|
|
30
|
+
history.replaceState = function (data, unused, url) {
|
|
31
|
+
origReplaceState(data, unused, url);
|
|
32
|
+
if (typeof url === "string" && url.startsWith("/") && typeof prefetchCache === "function") {
|
|
33
|
+
prefetchCache(url);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}` : "";
|
|
37
|
+
return `(function () {
|
|
38
|
+
"use strict";
|
|
39
|
+
|
|
40
|
+
// ── Service Worker Registration ──
|
|
41
|
+
var AUTO_ACTIVATE = ${autoActivate};
|
|
42
|
+
|
|
43
|
+
function waitForController() {
|
|
44
|
+
return new Promise(function (resolve) {
|
|
45
|
+
if (navigator.serviceWorker.controller) {
|
|
46
|
+
resolve();
|
|
47
|
+
} else {
|
|
48
|
+
var timeout = setTimeout(function () { resolve(); }, 30000);
|
|
49
|
+
navigator.serviceWorker.addEventListener("controllerchange", function () {
|
|
50
|
+
clearTimeout(timeout);
|
|
51
|
+
resolve();
|
|
52
|
+
}, { once: true });
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function registerSW() {
|
|
58
|
+
if (!("serviceWorker" in navigator)) {
|
|
59
|
+
console.warn("Service Workers not supported");
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
var registration = await navigator.serviceWorker.register("/${swFilename}.js");
|
|
64
|
+
var swReadyDispatched = false;
|
|
65
|
+
if (registration.installing) {
|
|
66
|
+
var installingWorker = registration.installing;
|
|
67
|
+
installingWorker.addEventListener("statechange", function () {
|
|
68
|
+
if (installingWorker.state === "installed") {
|
|
69
|
+
if (AUTO_ACTIVATE) {
|
|
70
|
+
if (registration.waiting) {
|
|
71
|
+
registration.waiting.postMessage({ type: "SKIP_WAITING" });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
swReadyDispatched = true;
|
|
75
|
+
window.dispatchEvent(new CustomEvent("sw-ready"));
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
await waitForController();
|
|
80
|
+
if (!swReadyDispatched) {
|
|
81
|
+
window.dispatchEvent(new CustomEvent("sw-ready"));
|
|
82
|
+
}
|
|
83
|
+
} catch (error) {
|
|
84
|
+
console.error("Service Worker registration failed:", error);
|
|
85
|
+
window.swError = true;
|
|
86
|
+
window.dispatchEvent(new CustomEvent("sw-error"));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ── Connectivity ──
|
|
91
|
+
var CONNECTIVITY_EVENT = "app-connectivity-change";
|
|
92
|
+
var heartbeatIntervalId = null;
|
|
93
|
+
var HEARTBEAT_DELAY = 30000;
|
|
94
|
+
var _currentOnlineStatus = typeof navigator !== "undefined" ? navigator.onLine : true;
|
|
95
|
+
|
|
96
|
+
function getCurrentOnlineStatus() {
|
|
97
|
+
return _currentOnlineStatus;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function createTimeoutSignal(ms) {
|
|
101
|
+
if (typeof AbortSignal.timeout === "function") return AbortSignal.timeout(ms);
|
|
102
|
+
var ctrl = new AbortController();
|
|
103
|
+
setTimeout(function () { ctrl.abort(); }, ms);
|
|
104
|
+
return ctrl.signal;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function verifyAndNotify() {
|
|
108
|
+
if (typeof window === "undefined") return false;
|
|
109
|
+
if (!navigator.onLine) {
|
|
110
|
+
dispatchState(false);
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
await fetch("/" + Date.now() + "?hb=1", {
|
|
115
|
+
method: "HEAD",
|
|
116
|
+
cache: "no-cache",
|
|
117
|
+
signal: createTimeoutSignal(5000),
|
|
118
|
+
});
|
|
119
|
+
if (navigator.serviceWorker.controller) {
|
|
120
|
+
navigator.serviceWorker.controller.postMessage({ type: "ONLINE" });
|
|
121
|
+
}
|
|
122
|
+
dispatchState(true);
|
|
123
|
+
return true;
|
|
124
|
+
} catch (error) {
|
|
125
|
+
if (navigator.serviceWorker.controller) {
|
|
126
|
+
navigator.serviceWorker.controller.postMessage({ type: "OFFLINE" });
|
|
127
|
+
}
|
|
128
|
+
dispatchState(false);
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function dispatchState(isTrulyOnline) {
|
|
134
|
+
_currentOnlineStatus = isTrulyOnline;
|
|
135
|
+
window.dispatchEvent(new CustomEvent(CONNECTIVITY_EVENT, { detail: { online: isTrulyOnline } }));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function startHeartbeat() {
|
|
139
|
+
if (heartbeatIntervalId) return;
|
|
140
|
+
heartbeatIntervalId = setInterval(async function () {
|
|
141
|
+
if (document.hidden) return;
|
|
142
|
+
await verifyAndNotify();
|
|
143
|
+
}, HEARTBEAT_DELAY);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function stopHeartbeat() {
|
|
147
|
+
if (!heartbeatIntervalId) return;
|
|
148
|
+
clearInterval(heartbeatIntervalId);
|
|
149
|
+
heartbeatIntervalId = null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function forceRetry() {
|
|
153
|
+
stopHeartbeat();
|
|
154
|
+
return verifyAndNotify().then(function () {
|
|
155
|
+
startHeartbeat();
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// ── Storage ──
|
|
160
|
+
async function getStorageEstimate() {
|
|
161
|
+
if (!navigator.storage || !navigator.storage.estimate) {
|
|
162
|
+
return { usage: 0, quota: 0, percentUsed: 0 };
|
|
163
|
+
}
|
|
164
|
+
var est = await navigator.storage.estimate();
|
|
165
|
+
var usage = est.usage || 0;
|
|
166
|
+
var quota = est.quota || 0;
|
|
167
|
+
var percentUsed = quota > 0 ? Math.round((usage / quota) * 100) : 0;
|
|
168
|
+
return { usage: usage, quota: quota, percentUsed: percentUsed };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function formatBytes(bytes) {
|
|
172
|
+
if (bytes === 0) return "0 B";
|
|
173
|
+
var units = ["B", "KB", "MB", "GB"];
|
|
174
|
+
var i = Math.floor(Math.log(bytes) / Math.log(1024));
|
|
175
|
+
return (bytes / Math.pow(1024, i)).toFixed(1) + " " + units[i];
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ── Online / Offline / Visibility Listeners ──
|
|
179
|
+
if (typeof window !== "undefined") {
|
|
180
|
+
window.addEventListener("online", async function () {
|
|
181
|
+
await verifyAndNotify();
|
|
182
|
+
startHeartbeat();
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
window.addEventListener("offline", function () {
|
|
186
|
+
stopHeartbeat();
|
|
187
|
+
dispatchState(false);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
document.addEventListener("visibilitychange", function () {
|
|
191
|
+
if (!document.hidden) {
|
|
192
|
+
verifyAndNotify();
|
|
193
|
+
startHeartbeat();
|
|
194
|
+
} else {
|
|
195
|
+
stopHeartbeat();
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
if (navigator.onLine) {
|
|
200
|
+
verifyAndNotify();
|
|
201
|
+
startHeartbeat();
|
|
202
|
+
} else {
|
|
203
|
+
queueMicrotask(function () { dispatchState(false); });
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// ── Focus Listener (reactive strategy) ──
|
|
208
|
+
if (typeof document !== "undefined") {
|
|
209
|
+
document.addEventListener("visibilitychange", function () {
|
|
210
|
+
if (document.visibilityState === "visible" && navigator.serviceWorker.controller) {
|
|
211
|
+
navigator.serviceWorker.controller.postMessage({ type: "FOCUS" });
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
${pwaCode}${ssrPrefetch}
|
|
216
|
+
// ── SW Message Listener ──
|
|
217
|
+
if (typeof window !== "undefined" && "serviceWorker" in navigator) {
|
|
218
|
+
navigator.serviceWorker.addEventListener("message", function (event) {
|
|
219
|
+
if (event.data.type === "CACHE_UPDATED") {
|
|
220
|
+
window.dispatchEvent(new CustomEvent("swoff:cache-updated", { detail: { url: event.data.url } }));
|
|
221
|
+
}
|
|
222
|
+
if (event.data.type === "NAV_RETRY_SUCCESS") {
|
|
223
|
+
window.dispatchEvent(new CustomEvent("swoff:navigation-online", { detail: { url: event.data.url } }));
|
|
224
|
+
}
|
|
225
|
+
if (event.data.type === "OFFLINE_FALLBACK_ACTIVATED") {
|
|
226
|
+
window.dispatchEvent(new CustomEvent("swoff:offline-fallback", { detail: event.data.detail }));
|
|
227
|
+
}
|
|
228
|
+
if (event.data.type === "SW_PROGRESS") {
|
|
229
|
+
window.dispatchEvent(new CustomEvent("sw-progress", {
|
|
230
|
+
detail: { percent: event.data.percent, downloaded: event.data.downloaded, total: event.data.total },
|
|
231
|
+
}));
|
|
232
|
+
}
|
|
233
|
+
if (event.data.type === "SW_NOTIFICATION") {
|
|
234
|
+
window.dispatchEvent(new CustomEvent("swoff:notification", {
|
|
235
|
+
detail: { level: event.data.level, code: event.data.code, message: event.data.message },
|
|
236
|
+
}));
|
|
237
|
+
}
|
|
238
|
+
${mutationQueueEnabled ? `
|
|
239
|
+
if (event.data.type === "BACKGROUND_SYNC_PROGRESS") {
|
|
240
|
+
window.dispatchEvent(new CustomEvent("mutation-sync-progress", { detail: event.data.detail }));
|
|
241
|
+
}
|
|
242
|
+
if (event.data.type === "BACKGROUND_SYNC_COMPLETE") {
|
|
243
|
+
var _d = event.data.detail;
|
|
244
|
+
window.dispatchEvent(new CustomEvent("mutation-sync-complete", { detail: { succeeded: _d.succeeded, failed: _d.failed } }));
|
|
245
|
+
if (_d.tags && _d.tags.length > 0) {
|
|
246
|
+
window.dispatchEvent(new CustomEvent("cache-invalidated", { detail: { tags: _d.tags } }));
|
|
247
|
+
}
|
|
248
|
+
window.dispatchEvent(new CustomEvent("mutation-queue-changed"));
|
|
249
|
+
}
|
|
250
|
+
if (event.data.type === "MUTATION_STORED" && window.swoff && typeof window.swoff.flushMutations === "function") {
|
|
251
|
+
window.swoff.flushMutations();
|
|
252
|
+
}` : ""}
|
|
253
|
+
${authEnabled ? `
|
|
254
|
+
if (event.data.type === "AUTH_CLEARED" && window.swoff && typeof window.swoff.clearMemoryAuth === "function") {
|
|
255
|
+
window.swoff.clearMemoryAuth();
|
|
256
|
+
window.dispatchEvent(new CustomEvent("sw-auth-state-change", { detail: { type: "clear" } }));
|
|
257
|
+
}
|
|
258
|
+
if (event.data.type === "AUTH_FAILURE" && window.swoff && typeof window.swoff.ensureValidAuth === "function") {
|
|
259
|
+
(async function () {
|
|
260
|
+
var _refreshed = await window.swoff.ensureValidAuth();
|
|
261
|
+
if (!_refreshed) {
|
|
262
|
+
if (window.swoff && typeof window.swoff.clearQueue === "function") {
|
|
263
|
+
await window.swoff.clearQueue();
|
|
264
|
+
}
|
|
265
|
+
try {
|
|
266
|
+
var _names = ["swoff-runtime", "swoff-runtime-html"];
|
|
267
|
+
for (var _i = 0; _i < _names.length; _i++) {
|
|
268
|
+
var _cache = await caches.open(_names[_i]);
|
|
269
|
+
var _keys = await _cache.keys();
|
|
270
|
+
await Promise.all(_keys.map(function (k) { return _cache.delete(k); }));
|
|
271
|
+
}
|
|
272
|
+
} catch (e) {}
|
|
273
|
+
window.dispatchEvent(new CustomEvent("sw-auth-unauthorized"));
|
|
274
|
+
}
|
|
275
|
+
})();
|
|
276
|
+
}` : ""}
|
|
277
|
+
if (event.data.type === "TAG_INVALIDATED" && event.data.tag) {
|
|
278
|
+
window.dispatchEvent(new CustomEvent("cache-invalidated", {
|
|
279
|
+
detail: { tags: [event.data.tag] },
|
|
280
|
+
}));
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// ── Main Entry ──
|
|
286
|
+
async function initServiceWorker() {
|
|
287
|
+
await registerSW();
|
|
288
|
+
var storage = await getStorageEstimate();
|
|
289
|
+
if (storage.percentUsed > 80) {
|
|
290
|
+
window.dispatchEvent(new CustomEvent("swoff:notification", {
|
|
291
|
+
detail: {
|
|
292
|
+
level: "warn",
|
|
293
|
+
code: "STORAGE_QUOTA_HIGH",
|
|
294
|
+
message: "Storage at " + storage.percentUsed + "% capacity (" + formatBytes(storage.usage) + " / " + formatBytes(storage.quota) + ")",
|
|
295
|
+
},
|
|
296
|
+
}));
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// ── Bridge for swoff-api-bundle ──
|
|
301
|
+
if (typeof window !== "undefined") {
|
|
302
|
+
window.__SWOFF_FORCE_RETRY = forceRetry;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// ── Auto-initialize ──
|
|
306
|
+
if (typeof window !== "undefined" && "serviceWorker" in navigator) {
|
|
307
|
+
initServiceWorker().catch(function (err) {
|
|
308
|
+
console.warn("Swoff SW registration failed:", err);
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
})();
|
|
312
|
+
`;
|
|
313
|
+
}
|
|
314
|
+
//# sourceMappingURL=client-injector-bundle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-injector-bundle.js","sourceRoot":"","sources":["../../src/runtime/client-injector-bundle.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,gCAAgC,CAC9C,GAAmB,EACnB,YAAqB,EACrB,UAAkB,EAClB,UAAmB,EACnB,OAAgB,EAChB,WAAqB,EACrB,oBAA8B;IAE9B,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;+FAegE,CAAC,CAAC,CAAC,EAAE,CAAC;IAEnG,MAAM,WAAW,GAAG,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;IAkBtC,CAAC,CAAC,CAAC,EAAE,CAAC;IAER,OAAO;;;;wBAIe,YAAY;;;;;;;;;;;;;;;;;;;;;;oEAsBgC,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwJ5E,OAAO,GAAG,WAAW;;;;;;;;;;;;;;;;;;;;;;;EAuBrB,oBAAoB,CAAC,CAAC,CAAC;;;;;;;;;;;;;;QAcjB,CAAC,CAAC,CAAC,EAAE;EACX,WAAW,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;QAuBR,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoCZ,CAAC;AACF,CAAC"}
|