@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/push.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { T, R,
|
|
1
|
+
import { T, R, AS } from "./utils.js";
|
|
2
2
|
export function generatePushCode(ctx) {
|
|
3
3
|
const { ext, ts } = ctx;
|
|
4
|
-
const vapidKey = ctx.vapidKey;
|
|
5
4
|
return `/**
|
|
6
5
|
* Swoff Push Notifications
|
|
7
6
|
* Push subscription management with IndexedDB persistence.
|
|
8
7
|
*
|
|
9
8
|
* Usage:
|
|
10
|
-
* import { subscribeToPush, unsubscribeFromPush, isSubscribed } from './swoff/
|
|
9
|
+
* import { subscribeToPush, unsubscribeFromPush, isSubscribed } from './swoff/push-notification/index.${ext}';
|
|
10
|
+
*
|
|
11
|
+
* // Replace with your VAPID public key:
|
|
12
|
+
* const VAPID_PUBLIC_KEY = "YOUR_VAPID_PUBLIC_KEY_HERE";
|
|
11
13
|
*
|
|
12
14
|
* // Enable (triggers permission prompt)
|
|
13
15
|
* const subscription = await subscribeToPush();
|
|
@@ -24,28 +26,14 @@ export function generatePushCode(ctx) {
|
|
|
24
26
|
* push-subscription-changed - Subscribed/unsubscribed (detail: { subscribed })
|
|
25
27
|
*/
|
|
26
28
|
|
|
29
|
+
import { openDB } from "../db.${ext}";
|
|
30
|
+
|
|
27
31
|
const SUBSCRIPTION_DB = "swoff-push";
|
|
28
32
|
const SUBSCRIPTION_STORE = "subscription";
|
|
29
|
-
|
|
30
|
-
const DB_VERSION = 1;
|
|
31
|
-
const VAPID_PUBLIC_KEY = ${JSON.stringify(vapidKey)};
|
|
33
|
+
const VAPID_PUBLIC_KEY = "";
|
|
32
34
|
|
|
33
35
|
let permissionState${T(ts, "NotificationPermission | undefined")} = typeof Notification !== "undefined" ? Notification.permission : undefined;
|
|
34
36
|
|
|
35
|
-
function openPushDB()${R(ts, "Promise<IDBDatabase>")}{
|
|
36
|
-
return new Promise${PT(ts, "IDBDatabase")}((resolve, reject) => {
|
|
37
|
-
const request = indexedDB.open(SUBSCRIPTION_DB, DB_VERSION);
|
|
38
|
-
request.onupgradeneeded = (e) => {
|
|
39
|
-
const db = (e.target${AS(ts, "IDBOpenDBRequest")}).result;
|
|
40
|
-
if (!db.objectStoreNames.contains(SUBSCRIPTION_STORE)) {
|
|
41
|
-
db.createObjectStore(SUBSCRIPTION_STORE, { keyPath: "id" });
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
request.onsuccess = (e) => resolve((e.target${AS(ts, "IDBOpenDBRequest")}).result);
|
|
45
|
-
request.onerror = (e) => reject((e.target${AS(ts, "IDBRequest")}).error);
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
|
|
49
37
|
/** Request notification permission from the user. Returns true if granted. */
|
|
50
38
|
export async function requestNotificationPermission()${R(ts, "Promise<boolean>")}{
|
|
51
39
|
if (permissionState === "granted") return true;
|
|
@@ -69,7 +57,7 @@ export async function getPushSubscription()${R(ts, "Promise<PushSubscription | n
|
|
|
69
57
|
}
|
|
70
58
|
}
|
|
71
59
|
|
|
72
|
-
/** Subscribe to push notifications. Returns the subscription or null if permission denied.
|
|
60
|
+
/** Subscribe to push notifications. Returns the subscription or null if permission denied. Update VAPID_PUBLIC_KEY at the top with your key. */
|
|
73
61
|
export async function subscribeToPush()${R(ts, "Promise<PushSubscription | null>")}{
|
|
74
62
|
const granted = await requestNotificationPermission();
|
|
75
63
|
if (!granted) return null;
|
|
@@ -80,7 +68,7 @@ export async function subscribeToPush()${R(ts, "Promise<PushSubscription | null>
|
|
|
80
68
|
applicationServerKey: urlBase64ToUint8Array(VAPID_PUBLIC_KEY)${AS(ts, "BufferSource")},
|
|
81
69
|
});
|
|
82
70
|
|
|
83
|
-
const db = await
|
|
71
|
+
const db = await openDB(SUBSCRIPTION_DB, SUBSCRIPTION_STORE, "id");
|
|
84
72
|
const tx = db.transaction(SUBSCRIPTION_STORE, "readwrite");
|
|
85
73
|
tx.objectStore(SUBSCRIPTION_STORE).put({
|
|
86
74
|
id: "current",
|
|
@@ -89,8 +77,8 @@ export async function subscribeToPush()${R(ts, "Promise<PushSubscription | null>
|
|
|
89
77
|
subscribedAt: Date.now(),
|
|
90
78
|
});
|
|
91
79
|
await new Promise<void>((resolve, reject) => {
|
|
92
|
-
tx.oncomplete = () => resolve();
|
|
93
|
-
tx.onerror = () => reject(tx.error);
|
|
80
|
+
tx.oncomplete = () => { db.close(); resolve(); };
|
|
81
|
+
tx.onerror = () => { db.close(); reject(tx.error); };
|
|
94
82
|
});
|
|
95
83
|
|
|
96
84
|
window.dispatchEvent(
|
|
@@ -107,12 +95,12 @@ export async function unsubscribeFromPush()${R(ts, "Promise<void>")}{
|
|
|
107
95
|
|
|
108
96
|
await subscription.unsubscribe();
|
|
109
97
|
|
|
110
|
-
const db = await
|
|
98
|
+
const db = await openDB(SUBSCRIPTION_DB, SUBSCRIPTION_STORE, "id");
|
|
111
99
|
const tx = db.transaction(SUBSCRIPTION_STORE, "readwrite");
|
|
112
100
|
tx.objectStore(SUBSCRIPTION_STORE).delete("current");
|
|
113
101
|
await new Promise<void>((resolve, reject) => {
|
|
114
|
-
tx.oncomplete = () => resolve();
|
|
115
|
-
tx.onerror = () => reject(tx.error);
|
|
102
|
+
tx.oncomplete = () => { db.close(); resolve(); };
|
|
103
|
+
tx.onerror = () => { db.close(); reject(tx.error); };
|
|
116
104
|
});
|
|
117
105
|
|
|
118
106
|
window.dispatchEvent(
|
package/dist/runtime/push.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"push.js","sourceRoot":"","sources":["../../src/runtime/push.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"push.js","sourceRoot":"","sources":["../../src/runtime/push.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,EAAM,EAAE,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,UAAU,gBAAgB,CAAC,GAAmB;IAClD,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC;IACxB,OAAO;;;;;2GAKkG,GAAG;;;;;;;;;;;;;;;;;;;;gCAoB9E,GAAG;;;;;;qBAMd,CAAC,CAAC,EAAE,EAAE,oCAAoC,CAAC;;;uDAGT,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC;;;;;;;;;;;;;6CAanC,CAAC,CAAC,EAAE,EAAE,kCAAkC,CAAC;;;;;;;;;;yCAU7C,CAAC,CAAC,EAAE,EAAE,kCAAkC,CAAC;;;;;;;mEAOf,EAAE,CAAC,EAAE,EAAE,cAAc,CAAC;;;;;;;;;;;;;;;;;;;;;;;;6CAwB5C,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;;;;;;;;;;;;;;;;;sCAoB7B,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC;;;;;;6CAMlB,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,YAAY,CAAC;;;;;;CAMlF,CAAC;AACF,CAAC"}
|
|
@@ -1,44 +1,15 @@
|
|
|
1
|
-
import { R } from "./utils.js";
|
|
2
1
|
export function generatePwaInjectorCode(ctx) {
|
|
3
|
-
const { ext
|
|
4
|
-
const preventLine = ctx.preventDefaultInstall ? " e.preventDefault();\n" : "";
|
|
2
|
+
const { ext } = ctx;
|
|
5
3
|
return `/**
|
|
6
4
|
* Swoff PWA Injector
|
|
7
|
-
*
|
|
5
|
+
* Re-exports setupPwaInstall from the prompt module.
|
|
8
6
|
*
|
|
9
7
|
* Usage:
|
|
10
8
|
* import { setupPwaInstall } from './swoff/pwa/injector.${ext}';
|
|
11
9
|
* setupPwaInstall();
|
|
12
|
-
*
|
|
13
|
-
* Window properties:
|
|
14
|
-
* window.deferredInstallPrompt - The captured BeforeInstallPromptEvent
|
|
15
10
|
*/
|
|
16
11
|
|
|
17
|
-
|
|
18
|
-
export function setupPwaInstall()${R(ts, "void")}{
|
|
19
|
-
window.addEventListener("beforeinstallprompt", (e) => {
|
|
20
|
-
window.deferredInstallPrompt = e as BeforeInstallPromptEvent;
|
|
21
|
-
window.pwaInstallable = true;
|
|
22
|
-
|
|
23
|
-
${preventLine}
|
|
24
|
-
window.dispatchEvent(
|
|
25
|
-
new CustomEvent("pwa-installable", {
|
|
26
|
-
detail: { isInstallable: true },
|
|
27
|
-
})
|
|
28
|
-
);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
window.addEventListener("appinstalled", () => {
|
|
32
|
-
window.deferredInstallPrompt = null;
|
|
33
|
-
window.pwaInstallable = false;
|
|
34
|
-
|
|
35
|
-
window.dispatchEvent(
|
|
36
|
-
new CustomEvent("pwa-installed", {
|
|
37
|
-
detail: { outcome: "accepted" },
|
|
38
|
-
})
|
|
39
|
-
);
|
|
40
|
-
});
|
|
41
|
-
}
|
|
12
|
+
export { setupPwaInstall } from "./prompt.${ext}";
|
|
42
13
|
`;
|
|
43
14
|
}
|
|
44
15
|
//# sourceMappingURL=pwa-injector.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pwa-injector.js","sourceRoot":"","sources":["../../src/runtime/pwa-injector.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pwa-injector.js","sourceRoot":"","sources":["../../src/runtime/pwa-injector.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,uBAAuB,CAAC,GAAmB;IACzD,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC;IAEpB,OAAO;;;;;6DAKoD,GAAG;;;;4CAIpB,GAAG;CAC9C,CAAC;AACF,CAAC"}
|
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
import { R } from "./utils.js";
|
|
1
|
+
import { R, AS } from "./utils.js";
|
|
2
2
|
export function generatePwaPromptCode(ctx) {
|
|
3
3
|
const { ext, ts } = ctx;
|
|
4
|
+
const preventLine = ctx.preventDefaultInstall
|
|
5
|
+
? " e.preventDefault();\n"
|
|
6
|
+
: "";
|
|
4
7
|
return `/**
|
|
5
8
|
* Swoff PWA Install Prompt
|
|
6
|
-
* Installability check
|
|
9
|
+
* Installability check, manual prompt trigger, and event listener setup.
|
|
7
10
|
*
|
|
8
11
|
* Usage:
|
|
9
|
-
* import { isInstallable, promptInstall } from './swoff/pwa/prompt.${ext}';
|
|
12
|
+
* import { setupPwaInstall, isInstallable, promptInstall } from './swoff/pwa/prompt.${ext}';
|
|
13
|
+
*
|
|
14
|
+
* setupPwaInstall(); // sets up beforeinstallprompt and appinstalled listeners
|
|
10
15
|
*
|
|
11
16
|
* if (isInstallable()) {
|
|
12
17
|
* const result = await promptInstall();
|
|
@@ -16,8 +21,35 @@ export function generatePwaPromptCode(ctx) {
|
|
|
16
21
|
* window.deferredInstallPrompt - The captured BeforeInstallPromptEvent
|
|
17
22
|
*/
|
|
18
23
|
|
|
24
|
+
/** Set up beforeinstallprompt and appinstalled event listeners. Call once at app startup. */
|
|
25
|
+
export function setupPwaInstall()${R(ts, "void")}{
|
|
26
|
+
window.addEventListener("beforeinstallprompt", (e) => {
|
|
27
|
+
window.deferredInstallPrompt = e${AS(ts, "BeforeInstallPromptEvent")};
|
|
28
|
+
window.pwaInstallable = true;
|
|
29
|
+
|
|
30
|
+
${preventLine}
|
|
31
|
+
window.dispatchEvent(
|
|
32
|
+
new CustomEvent("pwa-installable", {
|
|
33
|
+
detail: { isInstallable: true },
|
|
34
|
+
})
|
|
35
|
+
);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
window.addEventListener("appinstalled", () => {
|
|
39
|
+
window.deferredInstallPrompt = null;
|
|
40
|
+
window.pwaInstallable = false;
|
|
41
|
+
|
|
42
|
+
window.dispatchEvent(
|
|
43
|
+
new CustomEvent("pwa-installed", {
|
|
44
|
+
detail: { outcome: "accepted" },
|
|
45
|
+
})
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
19
50
|
/** Check if the PWA install prompt is available (user has met install criteria). */
|
|
20
51
|
export function isInstallable()${R(ts, "boolean")}{
|
|
52
|
+
if (typeof window === "undefined") return false;
|
|
21
53
|
return !!window.deferredInstallPrompt;
|
|
22
54
|
}
|
|
23
55
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pwa-prompt.js","sourceRoot":"","sources":["../../src/runtime/pwa-prompt.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"pwa-prompt.js","sourceRoot":"","sources":["../../src/runtime/pwa-prompt.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAEnC,MAAM,UAAU,qBAAqB,CACnC,GAAyD;IAEzD,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC;IACxB,MAAM,WAAW,GAAG,GAAG,CAAC,qBAAqB;QAC3C,CAAC,CAAC,2BAA2B;QAC7B,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO;;;;;yFAKgF,GAAG;;;;;;;;;;;;;mCAazD,CAAC,CAAC,EAAE,EAAE,MAAM,CAAC;;sCAEV,EAAE,CAAC,EAAE,EAAE,0BAA0B,CAAC;;;EAGtE,WAAW;;;;;;;;;;;;;;;;;;;;;iCAqBoB,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC;;;;;;uCAMV,CAAC,CAAC,EAAE,EAAE,8BAA8B,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2B3E,CAAC;AACF,CAAC"}
|
package/dist/runtime/reset.js
CHANGED
|
@@ -1,49 +1,51 @@
|
|
|
1
|
-
import { T, R } from "./utils.js";
|
|
1
|
+
import { T, O, R } from "./utils.js";
|
|
2
2
|
export function generateResetCode(ctx) {
|
|
3
3
|
const { ext, ts } = ctx;
|
|
4
4
|
return `/**
|
|
5
5
|
* Swoff Reset
|
|
6
6
|
* Nuclear option: wipe all swoff data (caches, IndexedDB, localStorage),
|
|
7
|
-
*
|
|
7
|
+
* then instruct the service worker to clear and re-precache all assets.
|
|
8
|
+
*
|
|
9
|
+
* Unlike the old approach of unregister + re-register (which often failed to
|
|
10
|
+
* trigger the install event for byte-identical scripts), this sends a
|
|
11
|
+
* RESET_CACHE message to the active SW, which handles cache clearing and
|
|
12
|
+
* re-precaching internally.
|
|
8
13
|
*
|
|
9
14
|
* Usage:
|
|
10
15
|
* import { resetSwoff } from './swoff/reset.${ext}';
|
|
11
16
|
*
|
|
12
17
|
* // Full reset (default)
|
|
13
18
|
* const result = await resetSwoff();
|
|
14
|
-
* console.log(result.
|
|
19
|
+
* console.log(result.warnings);
|
|
15
20
|
*
|
|
16
21
|
* // Selective reset — keep caches but reset IDB + SW
|
|
17
22
|
* await resetSwoff({ clearCache: false });
|
|
18
23
|
*
|
|
19
24
|
* Events dispatched:
|
|
20
25
|
* swoff:reset-start — before any cleanup begins
|
|
21
|
-
* swoff:reset-complete — after everything finishes (detail: {
|
|
26
|
+
* swoff:reset-complete — after everything finishes (detail: { warnings })
|
|
22
27
|
*/
|
|
23
28
|
|
|
24
|
-
import { initServiceWorker } from "./sw/injector.${ext}";
|
|
25
|
-
|
|
26
29
|
export interface ResetSwoffOptions {
|
|
27
30
|
/** Clear all Cache Storage caches (default: true) */
|
|
28
|
-
clearCache${
|
|
31
|
+
clearCache${O(ts, "boolean")};
|
|
29
32
|
/** Delete all swoff-* IndexedDB databases (default: true) */
|
|
30
|
-
clearIdb${
|
|
33
|
+
clearIdb${O(ts, "boolean")};
|
|
31
34
|
/** Clear localStorage keys like swRegisteredVersion (default: true) */
|
|
32
|
-
clearStorage${
|
|
33
|
-
/**
|
|
34
|
-
|
|
35
|
+
clearStorage${O(ts, "boolean")};
|
|
36
|
+
/** Reset SW caches (clear + re-precache) (default: true) */
|
|
37
|
+
resetSwCache${O(ts, "boolean")};
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
const DEFAULT_OPTIONS: ResetSwoffOptions = {
|
|
38
41
|
clearCache: true,
|
|
39
42
|
clearIdb: true,
|
|
40
43
|
clearStorage: true,
|
|
41
|
-
|
|
44
|
+
resetSwCache: true,
|
|
42
45
|
};
|
|
43
46
|
|
|
44
47
|
const KNOWN_DB_NAMES = [
|
|
45
48
|
"swoff-auth",
|
|
46
|
-
"swoff-auth-user",
|
|
47
49
|
"swoff-queue",
|
|
48
50
|
"swoff-cache-tags",
|
|
49
51
|
"swoff-push",
|
|
@@ -74,14 +76,14 @@ async function deleteSwoffDatabases(warnings${T(ts, "string[]")})${R(ts, "Promis
|
|
|
74
76
|
}
|
|
75
77
|
}
|
|
76
78
|
|
|
77
|
-
/** Nuclear reset: wipes all swoff-persisted data
|
|
78
|
-
export async function resetSwoff(opts${T(ts, "
|
|
79
|
+
/** Nuclear reset: wipes all swoff-persisted data and resets the SW cache. Returns detailed results. */
|
|
80
|
+
export async function resetSwoff(opts${T(ts, "ResetSwoffOptions")} = {})${R(ts, "Promise<{ warnings: string[] }>")}{
|
|
79
81
|
const options${T(ts, "ResetSwoffOptions")} = { ...DEFAULT_OPTIONS, ...opts };
|
|
80
82
|
const warnings${T(ts, "string[]")} = [];
|
|
81
83
|
|
|
82
84
|
window.dispatchEvent(new CustomEvent("swoff:reset-start"));
|
|
83
85
|
|
|
84
|
-
// 1. Clear Cache Storage
|
|
86
|
+
// 1. Clear Cache Storage (belt-and-suspenders — SW also clears them)
|
|
85
87
|
if (options.clearCache) {
|
|
86
88
|
try {
|
|
87
89
|
if (typeof caches !== "undefined") {
|
|
@@ -107,39 +109,34 @@ export async function resetSwoff(opts${T(ts, "Partial<ResetSwoffOptions>")} = {}
|
|
|
107
109
|
}
|
|
108
110
|
}
|
|
109
111
|
|
|
110
|
-
// 4.
|
|
111
|
-
|
|
112
|
-
if (options.unregisterSW) {
|
|
112
|
+
// 4. Tell the SW to clear its caches and re-precache all assets
|
|
113
|
+
if (options.resetSwCache) {
|
|
113
114
|
try {
|
|
114
|
-
if ("serviceWorker" in navigator) {
|
|
115
|
-
const
|
|
116
|
-
if (
|
|
117
|
-
|
|
115
|
+
if ("serviceWorker" in navigator && navigator.serviceWorker.controller) {
|
|
116
|
+
const registration = await navigator.serviceWorker.ready;
|
|
117
|
+
if (registration.active) {
|
|
118
|
+
await new Promise<void>((resolve) => {
|
|
119
|
+
const channel = new MessageChannel();
|
|
120
|
+
const timer = setTimeout(() => {
|
|
121
|
+
channel.port1.close();
|
|
122
|
+
resolve();
|
|
123
|
+
}, 10000);
|
|
124
|
+
channel.port1.onmessage = (event) => {
|
|
125
|
+
if (event.data.type === "RESET_CACHE_COMPLETE") {
|
|
126
|
+
clearTimeout(timer);
|
|
127
|
+
resolve();
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
registration.active?.postMessage({ type: "RESET_CACHE" }, [channel.port2]);
|
|
131
|
+
});
|
|
118
132
|
}
|
|
119
133
|
}
|
|
120
134
|
} catch (e) {
|
|
121
|
-
warnings.push(\`Failed to
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Always clear the version marker before re-registering so initServiceWorker
|
|
125
|
-
// detects a fresh install rather than trying to reuse a stale registration
|
|
126
|
-
try {
|
|
127
|
-
localStorage.removeItem("swRegisteredVersion");
|
|
128
|
-
} catch { /* ignore */ }
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// 5. Re-register SW
|
|
132
|
-
let reregistered = false;
|
|
133
|
-
if (options.unregisterSW) {
|
|
134
|
-
try {
|
|
135
|
-
await initServiceWorker();
|
|
136
|
-
reregistered = true;
|
|
137
|
-
} catch (e) {
|
|
138
|
-
warnings.push(\`Failed to re-register SW: \${e}\`);
|
|
135
|
+
warnings.push(\`Failed to reset SW cache: \${e}\`);
|
|
139
136
|
}
|
|
140
137
|
}
|
|
141
138
|
|
|
142
|
-
const result = {
|
|
139
|
+
const result = { warnings };
|
|
143
140
|
window.dispatchEvent(new CustomEvent("swoff:reset-complete", { detail: result }));
|
|
144
141
|
return result;
|
|
145
142
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reset.js","sourceRoot":"","sources":["../../src/runtime/reset.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"reset.js","sourceRoot":"","sources":["../../src/runtime/reset.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;AAErC,MAAM,UAAU,iBAAiB,CAAC,GAAmB;IACnD,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC;IACxB,OAAO;;;;;;;;;;;iDAWwC,GAAG;;;;;;;;;;;;;;;;cAgBtC,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC;;YAElB,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC;;gBAEZ,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC;;gBAEhB,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC;;;;;;;;;;;;;;;;;;8CAkBc,CAAC,CAAC,EAAE,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;uCAyBlD,CAAC,CAAC,EAAE,EAAE,mBAAmB,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,iCAAiC,CAAC;iBACjG,CAAC,CAAC,EAAE,EAAE,mBAAmB,CAAC;kBACzB,CAAC,CAAC,EAAE,EAAE,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6DlC,CAAC;AACF,CAAC"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { T, R } from "./utils.js";
|
|
1
|
+
import { T, R, AS } from "./utils.js";
|
|
2
2
|
export function generateServerPushCode(ctx, pushType, endpoint, reconnectDelayMs) {
|
|
3
3
|
const { ext, ts } = ctx;
|
|
4
4
|
const invalidate = `
|
|
5
5
|
// Forward to SW for cache invalidation
|
|
6
|
-
if (navigator.serviceWorker
|
|
6
|
+
if (navigator.serviceWorker?.controller) {
|
|
7
7
|
for (const tag of tags) {
|
|
8
8
|
navigator.serviceWorker.controller.postMessage({ type: "INVALIDATE_TAG", tag });
|
|
9
9
|
}
|
|
@@ -15,6 +15,8 @@ export function generateServerPushCode(ctx, pushType, endpoint, reconnectDelayMs
|
|
|
15
15
|
credentials: "include",
|
|
16
16
|
signal: options.signal,
|
|
17
17
|
}).then(async (response) => {
|
|
18
|
+
currentFetchController = null;
|
|
19
|
+
if (!active) { resolve(); return; }
|
|
18
20
|
if (!response.ok || !response.body) { resolve(); return; }
|
|
19
21
|
notifyStatus(true);
|
|
20
22
|
const reader = response.body.getReader();
|
|
@@ -51,14 +53,15 @@ export function generateServerPushCode(ctx, pushType, endpoint, reconnectDelayMs
|
|
|
51
53
|
return new Promise((resolve) => {
|
|
52
54
|
try {
|
|
53
55
|
const ws = new WebSocket(API_BASE + "${endpoint}");
|
|
56
|
+
currentWs = ws;
|
|
54
57
|
ws.onopen = () => notifyStatus(true);
|
|
55
58
|
ws.onmessage = (event) => {
|
|
56
59
|
try { const d = JSON.parse(event.data); if (d.type === "invalidate" && d.tags) handleInvalidation(d.tags); } catch {}
|
|
57
60
|
};
|
|
58
|
-
ws.onclose = () => { notifyStatus(false); resolve(); };
|
|
59
|
-
ws.onerror = () => { ws.close(); resolve(); };
|
|
61
|
+
ws.onclose = () => { currentWs = null; notifyStatus(false); resolve(); };
|
|
62
|
+
ws.onerror = () => { currentWs = null; ws.close(); resolve(); };
|
|
60
63
|
if (options.signal) {
|
|
61
|
-
options.signal.addEventListener("abort", () => ws.close());
|
|
64
|
+
options.signal.addEventListener("abort", () => { ws.close(); currentWs = null; });
|
|
62
65
|
}
|
|
63
66
|
} catch { resolve(); }
|
|
64
67
|
});`;
|
|
@@ -70,7 +73,7 @@ export function generateServerPushCode(ctx, pushType, endpoint, reconnectDelayMs
|
|
|
70
73
|
* This client-side helper provides status tracking and a manual start/stop API.
|
|
71
74
|
*
|
|
72
75
|
* Usage:
|
|
73
|
-
* import { startPushEvents, stopPushEvents, isPushConnected } from "./
|
|
76
|
+
* import { startPushEvents, stopPushEvents, isPushConnected } from "./server-push/client.${ext}";
|
|
74
77
|
* startPushEvents();
|
|
75
78
|
*
|
|
76
79
|
* Server sends:
|
|
@@ -87,6 +90,8 @@ type PushEventOptions= {
|
|
|
87
90
|
let active${T(ts, "boolean")} = false;
|
|
88
91
|
let swConnected${T(ts, "boolean")} = false;
|
|
89
92
|
let reconnectTimer${T(ts, "ReturnType<typeof setTimeout> | null")} = null;
|
|
93
|
+
let currentWs${T(ts, "WebSocket | null")} = null;
|
|
94
|
+
let currentFetchController${T(ts, "AbortController | null")} = null;
|
|
90
95
|
|
|
91
96
|
function handleInvalidation(tags${T(ts, "string[]")})${R(ts, "void")}{${invalidate}
|
|
92
97
|
window.dispatchEvent(new CustomEvent("cache-invalidated", { detail: { tags } }));
|
|
@@ -97,7 +102,7 @@ function notifyStatus(connected${T(ts, "boolean")})${R(ts, "void")}{
|
|
|
97
102
|
}
|
|
98
103
|
|
|
99
104
|
// Listen for SSE status from the SW
|
|
100
|
-
if (typeof navigator !== "undefined" && navigator
|
|
105
|
+
if (typeof navigator !== "undefined" && "serviceWorker" in navigator) {
|
|
101
106
|
navigator.serviceWorker.addEventListener("message", (event) => {
|
|
102
107
|
if (event.data?.type === "SSE_STATUS") {
|
|
103
108
|
swConnected = event.data.connected;
|
|
@@ -106,7 +111,10 @@ if (typeof navigator !== "undefined" && navigator.serviceWorker) {
|
|
|
106
111
|
});
|
|
107
112
|
}
|
|
108
113
|
|
|
109
|
-
async function connect(
|
|
114
|
+
async function connect()${R(ts, "Promise<void>")}{
|
|
115
|
+
const controller = new AbortController();
|
|
116
|
+
currentFetchController = controller;
|
|
117
|
+
const options = { signal: controller.signal }${AS(ts, "PushEventOptions")};
|
|
110
118
|
${pushType === "sse" ? sseConnect : wsConnect}
|
|
111
119
|
}
|
|
112
120
|
|
|
@@ -115,14 +123,14 @@ export async function startPushEvents(){
|
|
|
115
123
|
if (active) return;
|
|
116
124
|
|
|
117
125
|
// If SW is already controlling the page, skip client-side connection — the SW handles push events.
|
|
118
|
-
if (navigator.serviceWorker
|
|
126
|
+
if (navigator.serviceWorker?.controller) return;
|
|
119
127
|
|
|
120
128
|
// Listen for SW activation — if SW takes over, disconnect the client fallback.
|
|
121
129
|
const onControllerChange = () => { stopPushEvents(); };
|
|
122
|
-
navigator.serviceWorker
|
|
130
|
+
navigator.serviceWorker?.addEventListener("controllerchange", onControllerChange);
|
|
123
131
|
|
|
124
132
|
active = true;
|
|
125
|
-
let delay = ${reconnectDelayMs};
|
|
133
|
+
let delay = Math.max(1000, ${reconnectDelayMs});
|
|
126
134
|
while (active) {
|
|
127
135
|
await connect();
|
|
128
136
|
if (!active) break;
|
|
@@ -130,13 +138,15 @@ export async function startPushEvents(){
|
|
|
130
138
|
delay = Math.min(delay * 1.5, 30000); // cap at 30s
|
|
131
139
|
}
|
|
132
140
|
|
|
133
|
-
navigator.serviceWorker
|
|
141
|
+
navigator.serviceWorker?.removeEventListener("controllerchange", onControllerChange);
|
|
134
142
|
}
|
|
135
143
|
|
|
136
|
-
/** Stop listening for push events. */
|
|
144
|
+
/** Stop listening for push events and close the active connection. */
|
|
137
145
|
export function stopPushEvents(){
|
|
138
146
|
active = false;
|
|
139
147
|
if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; }
|
|
148
|
+
if (currentWs) { currentWs.close(); currentWs = null; }
|
|
149
|
+
if (currentFetchController) { currentFetchController.abort(); currentFetchController = null; }
|
|
140
150
|
}
|
|
141
151
|
|
|
142
152
|
/** Check if the push connection is currently established. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-push.js","sourceRoot":"","sources":["../../src/runtime/server-push.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"server-push.js","sourceRoot":"","sources":["../../src/runtime/server-push.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAEtC,MAAM,UAAU,sBAAsB,CACpC,GAAmB,EACnB,QAAgB,EAChB,QAAgB,EAChB,gBAAwB;IAExB,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC;IAExB,MAAM,UAAU,GAAG;;;;;;IAMjB,CAAC;IAEH,MAAM,UAAU,GAAG;;wBAEG,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAsC1B,CAAC;IAEL,MAAM,SAAS,GAAG;;;6CAGyB,QAAQ;;;;;;;;;;;;MAY/C,CAAC;IAEL,OAAO;;;oCAG2B,QAAQ;;;;;8FAKkD,GAAG;;;;;;;;sCAQ3D,GAAG;;;UAG/B,CAAC,CAAC,EAAE,EAAE,aAAa,CAAC;;;YAGlB,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC;iBACX,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC;oBACb,CAAC,CAAC,EAAE,EAAE,sCAAsC,CAAC;eAClD,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC;4BACZ,CAAC,CAAC,EAAE,EAAE,wBAAwB,CAAC;;kCAEzB,CAAC,CAAC,EAAE,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,UAAU;;;;iCAIjD,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,MAAM,CAAC;;;;;;;;;;;;;;0BAcxC,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;iDAGC,EAAE,CAAC,EAAE,EAAE,kBAAkB,CAAC;IACvE,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS;;;;;;;;;;;;;;;+BAehB,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;CAuB9C,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { T, R } from "./utils.js";
|
|
2
|
+
export function generateStorageCode(ctx) {
|
|
3
|
+
const { ext, ts } = ctx;
|
|
4
|
+
return `/**
|
|
5
|
+
* Swoff Storage
|
|
6
|
+
* Pure utility functions for storage estimation and formatting.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* import { getStorageEstimate, formatBytes } from "./swoff/storage.${ext}";
|
|
10
|
+
* const { usage, quota, percentUsed } = await getStorageEstimate();
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** Get raw storage estimate. */
|
|
14
|
+
export async function getStorageEstimate()${R(ts, "Promise<{ usage: number; quota: number; percentUsed: number }>")}{
|
|
15
|
+
if (!navigator.storage?.estimate) {
|
|
16
|
+
return { usage: 0, quota: 0, percentUsed: 0 };
|
|
17
|
+
}
|
|
18
|
+
const { usage = 0, quota = 0 } = await navigator.storage.estimate();
|
|
19
|
+
const percentUsed = quota > 0 ? Math.round((usage / quota) * 100) : 0;
|
|
20
|
+
return { usage, quota, percentUsed };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Format bytes to a human-readable string (e.g. "1.5 MB"). */
|
|
24
|
+
export function formatBytes(bytes${T(ts, "number")})${R(ts, "string")}{
|
|
25
|
+
if (bytes === 0) return "0 B";
|
|
26
|
+
const units = ["B", "KB", "MB", "GB"];
|
|
27
|
+
const i = Math.floor(Math.log(bytes) / Math.log(1024));
|
|
28
|
+
return \`\${(bytes / Math.pow(1024, i)).toFixed(1)} \${units[i]}\`;
|
|
29
|
+
}
|
|
30
|
+
`;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/runtime/storage.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;AAElC,MAAM,UAAU,mBAAmB,CAAC,GAAmB;IACrD,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC;IACxB,OAAO;;;;;wEAK+D,GAAG;;;;;4CAK/B,CAAC,CAAC,EAAE,EAAE,gEAAgE,CAAC;;;;;;;;;;mCAUhF,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;;;;;;CAMpE,CAAC;AACF,CAAC"}
|