@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.
Files changed (269) hide show
  1. package/README.md +28 -32
  2. package/dist/index.js +4 -15
  3. package/dist/index.js.map +1 -1
  4. package/dist/lib/cli/help.js +4 -9
  5. package/dist/lib/cli/help.js.map +1 -1
  6. package/dist/lib/commands/clean.js +8 -17
  7. package/dist/lib/commands/clean.js.map +1 -1
  8. package/dist/lib/commands/generate-guide.js +16 -30
  9. package/dist/lib/commands/generate-guide.js.map +1 -1
  10. package/dist/lib/commands/generate.js +33 -7
  11. package/dist/lib/commands/generate.js.map +1 -1
  12. package/dist/lib/commands/init.js +259 -23
  13. package/dist/lib/commands/init.js.map +1 -1
  14. package/dist/lib/commands/validate.js +2 -4
  15. package/dist/lib/commands/validate.js.map +1 -1
  16. package/dist/lib/config/loader.js +34 -25
  17. package/dist/lib/config/loader.js.map +1 -1
  18. package/dist/lib/config/minimal-config.js +64 -0
  19. package/dist/lib/config/minimal-config.js.map +1 -0
  20. package/dist/lib/config/validator.js +219 -110
  21. package/dist/lib/config/validator.js.map +1 -1
  22. package/dist/lib/generators/file-generators/api-config.js +1 -1
  23. package/dist/lib/generators/file-generators/api-config.js.map +1 -1
  24. package/dist/lib/generators/file-generators/auth-adapter.js +13 -0
  25. package/dist/lib/generators/file-generators/auth-adapter.js.map +1 -0
  26. package/dist/lib/generators/file-generators/auth-check.js +40 -0
  27. package/dist/lib/generators/file-generators/auth-check.js.map +1 -0
  28. package/dist/lib/generators/file-generators/auth-store.js +2 -5
  29. package/dist/lib/generators/file-generators/auth-store.js.map +1 -1
  30. package/dist/lib/generators/file-generators/background-sync.js +1 -1
  31. package/dist/lib/generators/file-generators/background-sync.js.map +1 -1
  32. package/dist/lib/generators/file-generators/cache.js +2 -1
  33. package/dist/lib/generators/file-generators/cache.js.map +1 -1
  34. package/dist/lib/generators/file-generators/client-injector-bundle.js +15 -0
  35. package/dist/lib/generators/file-generators/client-injector-bundle.js.map +1 -0
  36. package/dist/lib/generators/file-generators/client-injector.js +2 -1
  37. package/dist/lib/generators/file-generators/client-injector.js.map +1 -1
  38. package/dist/lib/generators/file-generators/connectivity.js +12 -0
  39. package/dist/lib/generators/file-generators/connectivity.js.map +1 -0
  40. package/dist/lib/generators/file-generators/context.js +7 -0
  41. package/dist/lib/generators/file-generators/context.js.map +1 -1
  42. package/dist/lib/generators/file-generators/fetch-wrapper.js +1 -1
  43. package/dist/lib/generators/file-generators/fetch-wrapper.js.map +1 -1
  44. package/dist/lib/generators/file-generators/generate-framework-adapters.js +29 -20
  45. package/dist/lib/generators/file-generators/generate-framework-adapters.js.map +1 -1
  46. package/dist/lib/generators/file-generators/gql-wrapper.js +2 -2
  47. package/dist/lib/generators/file-generators/gql-wrapper.js.map +1 -1
  48. package/dist/lib/generators/file-generators/guide-generator.js +51 -1
  49. package/dist/lib/generators/file-generators/guide-generator.js.map +1 -1
  50. package/dist/lib/generators/file-generators/invalidation-tags.js +2 -3
  51. package/dist/lib/generators/file-generators/invalidation-tags.js.map +1 -1
  52. package/dist/lib/generators/file-generators/mutation-queue.js +2 -2
  53. package/dist/lib/generators/file-generators/mutation-queue.js.map +1 -1
  54. package/dist/lib/generators/file-generators/mutation-state.js +1 -1
  55. package/dist/lib/generators/file-generators/mutation-state.js.map +1 -1
  56. package/dist/lib/generators/file-generators/open-db.js +6 -0
  57. package/dist/lib/generators/file-generators/open-db.js.map +1 -0
  58. package/dist/lib/generators/file-generators/push.js +1 -2
  59. package/dist/lib/generators/file-generators/push.js.map +1 -1
  60. package/dist/lib/generators/file-generators/pwa-install.js +2 -6
  61. package/dist/lib/generators/file-generators/pwa-install.js.map +1 -1
  62. package/dist/lib/generators/file-generators/server-push.js +1 -1
  63. package/dist/lib/generators/file-generators/server-push.js.map +1 -1
  64. package/dist/lib/generators/file-generators/storage.js +6 -0
  65. package/dist/lib/generators/file-generators/storage.js.map +1 -0
  66. package/dist/lib/generators/file-generators/sw-generator-build.js +105 -48
  67. package/dist/lib/generators/file-generators/sw-generator-build.js.map +1 -1
  68. package/dist/lib/generators/file-generators/sw-injector.js +0 -4
  69. package/dist/lib/generators/file-generators/sw-injector.js.map +1 -1
  70. package/dist/lib/generators/file-generators/sw-template.js +8 -9
  71. package/dist/lib/generators/file-generators/sw-template.js.map +1 -1
  72. package/dist/lib/generators/file-generators/swoff-api-bundle.js +51 -0
  73. package/dist/lib/generators/file-generators/swoff-api-bundle.js.map +1 -0
  74. package/dist/lib/generators/sw-build-utils.js +69 -0
  75. package/dist/lib/generators/sw-build-utils.js.map +1 -0
  76. package/dist/lib/generators/sw-generator.js +23 -34
  77. package/dist/lib/generators/sw-generator.js.map +1 -1
  78. package/dist/lib/generators/sw-sections/activate-handler.js +77 -23
  79. package/dist/lib/generators/sw-sections/activate-handler.js.map +1 -1
  80. package/dist/lib/generators/sw-sections/assemble-sw.js +20 -95
  81. package/dist/lib/generators/sw-sections/assemble-sw.js.map +1 -1
  82. package/dist/lib/generators/sw-sections/background-precache.js +126 -0
  83. package/dist/lib/generators/sw-sections/background-precache.js.map +1 -0
  84. package/dist/lib/generators/sw-sections/background-sync-handler.js +74 -72
  85. package/dist/lib/generators/sw-sections/background-sync-handler.js.map +1 -1
  86. package/dist/lib/generators/sw-sections/batch-refresh-queue.js +102 -0
  87. package/dist/lib/generators/sw-sections/batch-refresh-queue.js.map +1 -0
  88. package/dist/lib/generators/sw-sections/config-header.js +2 -3
  89. package/dist/lib/generators/sw-sections/config-header.js.map +1 -1
  90. package/dist/lib/generators/sw-sections/default-template.js +64 -7
  91. package/dist/lib/generators/sw-sections/default-template.js.map +1 -1
  92. package/dist/lib/generators/sw-sections/fetch-handler.js +621 -495
  93. package/dist/lib/generators/sw-sections/fetch-handler.js.map +1 -1
  94. package/dist/lib/generators/sw-sections/install-handler.js +41 -23
  95. package/dist/lib/generators/sw-sections/install-handler.js.map +1 -1
  96. package/dist/lib/generators/sw-sections/message-handler.js +34 -8
  97. package/dist/lib/generators/sw-sections/message-handler.js.map +1 -1
  98. package/dist/lib/generators/sw-sections/server-push-handler.js +10 -14
  99. package/dist/lib/generators/sw-sections/server-push-handler.js.map +1 -1
  100. package/dist/lib/generators/sw-sections/shared.js +70 -0
  101. package/dist/lib/generators/sw-sections/shared.js.map +1 -0
  102. package/dist/lib/generators/sw-sections/sw-push.js +2 -6
  103. package/dist/lib/generators/sw-sections/sw-push.js.map +1 -1
  104. package/dist/lib/generators/sw-sections/tag-management.js +55 -86
  105. package/dist/lib/generators/sw-sections/tag-management.js.map +1 -1
  106. package/dist/lib/generators/swoff-files-generator.js +183 -59
  107. package/dist/lib/generators/swoff-files-generator.js.map +1 -1
  108. package/dist/lib/shared/config-types.js +84 -79
  109. package/dist/lib/shared/config-types.js.map +1 -1
  110. package/dist/lib/shared/feature-registry.js +198 -0
  111. package/dist/lib/shared/feature-registry.js.map +1 -0
  112. package/dist/lib/utils/detect-framework.js +52 -9
  113. package/dist/lib/utils/detect-framework.js.map +1 -1
  114. package/dist/runtime/api-config.js +2 -2
  115. package/dist/runtime/api-config.js.map +1 -1
  116. package/dist/runtime/auth-adapter.js +179 -0
  117. package/dist/runtime/auth-adapter.js.map +1 -0
  118. package/dist/runtime/auth-state.js +16 -6
  119. package/dist/runtime/auth-state.js.map +1 -1
  120. package/dist/runtime/auth-store.js +219 -213
  121. package/dist/runtime/auth-store.js.map +1 -1
  122. package/dist/runtime/background-sync.js +5 -2
  123. package/dist/runtime/background-sync.js.map +1 -1
  124. package/dist/runtime/cache.js +91 -3
  125. package/dist/runtime/cache.js.map +1 -1
  126. package/dist/runtime/client-injector-bundle.js +314 -0
  127. package/dist/runtime/client-injector-bundle.js.map +1 -0
  128. package/dist/runtime/client-injector.js +188 -30
  129. package/dist/runtime/client-injector.js.map +1 -1
  130. package/dist/runtime/connectivity.js +83 -0
  131. package/dist/runtime/connectivity.js.map +1 -0
  132. package/dist/runtime/fetch-wrapper.js +26 -59
  133. package/dist/runtime/fetch-wrapper.js.map +1 -1
  134. package/dist/runtime/gql-wrapper.js +15 -9
  135. package/dist/runtime/gql-wrapper.js.map +1 -1
  136. package/dist/runtime/invalidation-tags.js +12 -89
  137. package/dist/runtime/invalidation-tags.js.map +1 -1
  138. package/dist/runtime/mutation-queue.js +83 -31
  139. package/dist/runtime/mutation-queue.js.map +1 -1
  140. package/dist/runtime/mutation-state.js +3 -3
  141. package/dist/runtime/mutation-state.js.map +1 -1
  142. package/dist/runtime/open-db.js +41 -0
  143. package/dist/runtime/open-db.js.map +1 -0
  144. package/dist/runtime/push.js +15 -27
  145. package/dist/runtime/push.js.map +1 -1
  146. package/dist/runtime/pwa-prompt.js +35 -3
  147. package/dist/runtime/pwa-prompt.js.map +1 -1
  148. package/dist/runtime/reset.js +39 -42
  149. package/dist/runtime/reset.js.map +1 -1
  150. package/dist/runtime/server-push.js +23 -13
  151. package/dist/runtime/server-push.js.map +1 -1
  152. package/dist/runtime/storage.js +32 -0
  153. package/dist/runtime/storage.js.map +1 -0
  154. package/dist/runtime/sw-injector.js +19 -178
  155. package/dist/runtime/sw-injector.js.map +1 -1
  156. package/dist/runtime/swoff-api-bundle.js +1491 -0
  157. package/dist/runtime/swoff-api-bundle.js.map +1 -0
  158. package/dist/runtime/type-definitions.js +8 -7
  159. package/dist/runtime/type-definitions.js.map +1 -1
  160. package/dist/runtime/utils.js +4 -0
  161. package/dist/runtime/utils.js.map +1 -1
  162. package/package.json +9 -3
  163. package/templates/react/useAuth.jsx +7 -4
  164. package/templates/react/useAuth.tsx +14 -14
  165. package/templates/react/useBackgroundSync.jsx +5 -4
  166. package/templates/react/useBackgroundSync.tsx +5 -4
  167. package/templates/react/useCachedFetch.jsx +8 -0
  168. package/templates/react/useCachedFetch.tsx +8 -0
  169. package/templates/react/useMutation.jsx +60 -56
  170. package/templates/react/useMutation.tsx +65 -64
  171. package/templates/react/useMutationQueue.jsx +5 -1
  172. package/templates/react/useMutationQueue.tsx +8 -2
  173. package/templates/react/useMutationState.jsx +3 -4
  174. package/templates/react/useMutationState.tsx +4 -8
  175. package/templates/react/useNetworkStatus.jsx +57 -17
  176. package/templates/react/useNetworkStatus.tsx +42 -20
  177. package/templates/react/useOfflineAnalytics.jsx +42 -0
  178. package/templates/react/useOfflineAnalytics.tsx +50 -0
  179. package/templates/react/usePwaInstall.jsx +26 -0
  180. package/templates/react/usePwaInstall.tsx +26 -0
  181. package/templates/react/useSWUpdate.jsx +7 -52
  182. package/templates/react/useSWUpdate.tsx +12 -51
  183. package/templates/react/useStorageEstimate.jsx +56 -0
  184. package/templates/react/useStorageEstimate.tsx +67 -0
  185. package/dist/__tests__/assemble-sw.test.js +0 -145
  186. package/dist/__tests__/assemble-sw.test.js.map +0 -1
  187. package/dist/__tests__/cli-integration.test.js +0 -231
  188. package/dist/__tests__/cli-integration.test.js.map +0 -1
  189. package/dist/__tests__/config-types.test.js +0 -124
  190. package/dist/__tests__/config-types.test.js.map +0 -1
  191. package/dist/__tests__/detect-language.test.js +0 -51
  192. package/dist/__tests__/detect-language.test.js.map +0 -1
  193. package/dist/__tests__/file-generators.test.js +0 -228
  194. package/dist/__tests__/file-generators.test.js.map +0 -1
  195. package/dist/__tests__/glob-matcher.test.js +0 -86
  196. package/dist/__tests__/glob-matcher.test.js.map +0 -1
  197. package/dist/__tests__/invalidation-tags.test.js +0 -283
  198. package/dist/__tests__/invalidation-tags.test.js.map +0 -1
  199. package/dist/__tests__/loader.test.js +0 -77
  200. package/dist/__tests__/loader.test.js.map +0 -1
  201. package/dist/__tests__/validator.test.js +0 -340
  202. package/dist/__tests__/validator.test.js.map +0 -1
  203. package/dist/lib/commands/add.js +0 -120
  204. package/dist/lib/commands/add.js.map +0 -1
  205. package/dist/lib/commands/assets.js +0 -45
  206. package/dist/lib/commands/assets.js.map +0 -1
  207. package/dist/lib/commands/generate-assets.js +0 -44
  208. package/dist/lib/commands/generate-assets.js.map +0 -1
  209. package/dist/lib/commands/info.js +0 -183
  210. package/dist/lib/commands/info.js.map +0 -1
  211. package/dist/lib/generators/asset-generator/dependency-resolver.js +0 -85
  212. package/dist/lib/generators/asset-generator/dependency-resolver.js.map +0 -1
  213. package/dist/lib/generators/asset-generator/generate.js +0 -111
  214. package/dist/lib/generators/asset-generator/generate.js.map +0 -1
  215. package/dist/lib/generators/asset-generator/guide.js +0 -43
  216. package/dist/lib/generators/asset-generator/guide.js.map +0 -1
  217. package/dist/lib/generators/asset-generator/html-patcher.js +0 -65
  218. package/dist/lib/generators/asset-generator/html-patcher.js.map +0 -1
  219. package/dist/lib/generators/asset-generator/ico-encoder.js +0 -29
  220. package/dist/lib/generators/asset-generator/ico-encoder.js.map +0 -1
  221. package/dist/lib/generators/asset-generator/manifest-patcher.js +0 -23
  222. package/dist/lib/generators/asset-generator/manifest-patcher.js.map +0 -1
  223. package/dist/lib/generators/asset-generator/maskable.js +0 -15
  224. package/dist/lib/generators/asset-generator/maskable.js.map +0 -1
  225. package/dist/lib/generators/asset-generator/rasterize.js +0 -32
  226. package/dist/lib/generators/asset-generator/rasterize.js.map +0 -1
  227. package/dist/lib/generators/asset-generator/sizes.js +0 -25
  228. package/dist/lib/generators/asset-generator/sizes.js.map +0 -1
  229. package/dist/lib/generators/file-generators/auth-fetch.js +0 -151
  230. package/dist/lib/generators/file-generators/auth-fetch.js.map +0 -1
  231. package/dist/lib/generators/file-generators/auth-user.js +0 -13
  232. package/dist/lib/generators/file-generators/auth-user.js.map +0 -1
  233. package/dist/lib/generators/file-generators/fetch-state.js +0 -6
  234. package/dist/lib/generators/file-generators/fetch-state.js.map +0 -1
  235. package/dist/lib/generators/file-generators/generate-hooks.js +0 -44
  236. package/dist/lib/generators/file-generators/generate-hooks.js.map +0 -1
  237. package/dist/lib/generators/file-generators/indexeddb.js +0 -74
  238. package/dist/lib/generators/file-generators/indexeddb.js.map +0 -1
  239. package/dist/lib/generators/file-generators/manifest.js +0 -46
  240. package/dist/lib/generators/file-generators/manifest.js.map +0 -1
  241. package/dist/lib/generators/file-generators/mutation-reconcile.js +0 -57
  242. package/dist/lib/generators/file-generators/mutation-reconcile.js.map +0 -1
  243. package/dist/lib/generators/file-generators/quick-readme.js +0 -21
  244. package/dist/lib/generators/file-generators/quick-readme.js.map +0 -1
  245. package/dist/lib/generators/file-generators/reconcile.js +0 -50
  246. package/dist/lib/generators/file-generators/reconcile.js.map +0 -1
  247. package/dist/lib/generators/file-generators/store.js +0 -86
  248. package/dist/lib/generators/file-generators/store.js.map +0 -1
  249. package/dist/lib/generators/file-generators/sw-push.js +0 -67
  250. package/dist/lib/generators/file-generators/sw-push.js.map +0 -1
  251. package/dist/lib/generators/sw-sections/glob-matcher-code.js.map +0 -1
  252. package/dist/lib/utils/build-script.js +0 -35
  253. package/dist/lib/utils/build-script.js.map +0 -1
  254. package/dist/lib/utils/tty-status.js +0 -21
  255. package/dist/lib/utils/tty-status.js.map +0 -1
  256. package/dist/runtime/auth-user.js +0 -168
  257. package/dist/runtime/auth-user.js.map +0 -1
  258. package/dist/runtime/fetch-state.js +0 -42
  259. package/dist/runtime/fetch-state.js.map +0 -1
  260. package/dist/runtime/pwa-index.js +0 -11
  261. package/dist/runtime/pwa-index.js.map +0 -1
  262. package/dist/runtime/pwa-injector.js +0 -44
  263. package/dist/runtime/pwa-injector.js.map +0 -1
  264. package/dist/runtime/pwa-install.js +0 -83
  265. package/dist/runtime/pwa-install.js.map +0 -1
  266. package/templates/react/useCacheInvalidation.jsx +0 -19
  267. package/templates/react/useCacheInvalidation.tsx +0 -52
  268. package/templates/react/useIsFetching.jsx +0 -32
  269. package/templates/react/useIsFetching.tsx +0 -32
@@ -1,11 +1,11 @@
1
1
  import { T, R, PT, AS } from "./utils.js";
2
- export function generateMutationQueueCode(ctx, authEnabled, batchSize, batchDelayMs, maxRetries, retryBackoffMs) {
2
+ export function generateMutationQueueCode(ctx, authEnabled, batchSize, batchDelayMs, maxRetries, retryBackoffMs, retryMaxBackoffMs, retryJitterMs) {
3
3
  const { ext, ts } = ctx;
4
- const importLines = authEnabled
5
- ? `import { getAuth } from "../auth/store.${ext}";
4
+ const authImports = authEnabled
5
+ ? `import { getAuth, ensureValidAuth, clearAuth } from "../auth/store.${ext}";
6
6
  `
7
7
  : "";
8
- const additionalImports = `import { invalidateByTags } from "../cache/index.${ext}";
8
+ const additionalImports = `import { invalidateByTags } from "../cache/invalidate.${ext}";
9
9
  ${ts
10
10
  ? `import type { MutationQueueItem } from "../swoff.d.ts";
11
11
  `
@@ -18,6 +18,41 @@ ${ts
18
18
  const authHeaderSpread = authEnabled
19
19
  ? ` ...authHeader,\n`
20
20
  : " ";
21
+ const auth401ReplayBlock = authEnabled
22
+ ? ` if (response.status === 401) {
23
+ // Auth failure — try silent refresh (/refresh endpoint)
24
+ const refreshed = await ensureValidAuth();
25
+ if (refreshed?.token) {
26
+ // Refresh succeeded — retry the mutation once
27
+ const retryHeader${T(ts, "Record<string, string>")} = refreshed?.token ? { Authorization: \`Bearer \${refreshed.token}\` } : {};
28
+ const retryResponse = await fetch(item.url, {
29
+ method: item.method,
30
+ headers: {
31
+ ...(contentType ? { "Content-Type": contentType } : {}),
32
+ ...item.headers,
33
+ ...retryHeader,
34
+ },
35
+ ...(replayBody != null ? { body: replayBody } : {}),
36
+ });
37
+ if (retryResponse.ok) {
38
+ // Success after auth refresh — normal flow
39
+ if (item.tags && item.tags.length > 0) {
40
+ await invalidateByTags(item.tags);
41
+ }
42
+ await removeFromQueue(item.id, db);
43
+ return true;
44
+ }
45
+ // Retry still failed — authenticated but not authorized for this resource
46
+ // Drop this mutation immediately (don't retry)
47
+ await removeFromQueue(item.id, db);
48
+ return true;
49
+ }
50
+ // Refresh failed — session expired. ClearAuth cascades to clear queue + caches.
51
+ await clearAuth();
52
+ return false;
53
+ }
54
+ `
55
+ : "";
21
56
  const code = `/**
22
57
  * Swoff Mutation Queue
23
58
  * Queue offline writes and sync when connection returns.
@@ -44,33 +79,36 @@ ${ts
44
79
  * batchDelayMs: ${batchDelayMs} — delay between mutations (rate limiting)
45
80
  * maxRetries: ${maxRetries} — max retries before dropping
46
81
  * retryBackoffMs: ${retryBackoffMs} — exponential backoff base
82
+ * retryMaxBackoffMs: ${retryMaxBackoffMs} — max backoff cap
83
+ * retryJitterMs: ${retryJitterMs} — jitter for randomization
47
84
  */
48
85
 
49
- ${importLines}${additionalImports}const DB_NAME = "swoff-queue";
86
+ ${authImports}${additionalImports}const DB_NAME = "swoff-queue";
50
87
  const STORE_NAME = "mutations";
51
- // Bump this when adding new indexes/stores for schema migration
52
- const DB_VERSION = 1;
53
88
  const BATCH_SIZE = ${batchSize};
54
89
  const BATCH_DELAY_MS = ${batchDelayMs};
55
90
  const MAX_RETRIES = ${maxRetries};
56
91
  const RETRY_BACKOFF_MS = ${retryBackoffMs};
92
+ const RETRY_MAX_BACKOFF_MS = ${retryMaxBackoffMs};
93
+ const RETRY_JITTER_MS = ${retryJitterMs};
94
+
95
+ function backoffDelay(attempt${T(ts, "number")}) {
96
+ const delay = Math.min(RETRY_BACKOFF_MS * Math.pow(2, attempt), RETRY_MAX_BACKOFF_MS);
97
+ return delay + (RETRY_JITTER_MS > 0 ? Math.random() * RETRY_JITTER_MS : 0);
98
+ }
57
99
 
58
100
  function sleep(ms${T(ts, "number")})${R(ts, "Promise<void>")}{
59
101
  return new Promise((r) => setTimeout(r, ms));
60
102
  }
61
103
 
104
+ import { openDB } from "../db.${ext}";
105
+
62
106
  function openQueueDB()${R(ts, "Promise<IDBDatabase>")}{
63
- return new Promise${PT(ts, "IDBDatabase")}((resolve, reject) => {
64
- const request = indexedDB.open(DB_NAME, DB_VERSION);
65
- request.onupgradeneeded = (e) => {
66
- const db = (e.target${AS(ts, "IDBOpenDBRequest")}).result;
67
- if (!db.objectStoreNames.contains(STORE_NAME)) {
68
- const store = db.createObjectStore(STORE_NAME, { keyPath: "id" });
69
- store.createIndex("by-timestamp", "timestamp");
70
- }
71
- };
72
- request.onsuccess = (e) => resolve((e.target${AS(ts, "IDBOpenDBRequest")}).result);
73
- request.onerror = (e) => reject((e.target${AS(ts, "IDBRequest")}).error);
107
+ return openDB(DB_NAME, STORE_NAME, "id", (db) => {
108
+ if (!db.objectStoreNames.contains(STORE_NAME)) {
109
+ const store = db.createObjectStore(STORE_NAME, { keyPath: "id" });
110
+ store.createIndex("by-timestamp", "timestamp");
111
+ }
74
112
  });
75
113
  }
76
114
 
@@ -114,8 +152,8 @@ export async function queueMutation(mutation${T(ts, "Partial<MutationQueueItem>"
114
152
  });
115
153
 
116
154
  await new Promise<void>((resolve, reject) => {
117
- tx.oncomplete = () => resolve();
118
- tx.onerror = () => reject(tx.error);
155
+ tx.oncomplete = () => { db.close(); resolve(); };
156
+ tx.onerror = () => { db.close(); reject(tx.error); };
119
157
  });
120
158
 
121
159
  window.dispatchEvent(new CustomEvent("mutation-queue-changed"));
@@ -151,7 +189,7 @@ ${authHeaderSpread} },
151
189
  ...(replayBody != null ? { body: replayBody } : {}),
152
190
  });
153
191
 
154
- if (!response.ok) throw new Error(\`HTTP \${response.status}\`);
192
+ ${auth401ReplayBlock} if (!response.ok) throw new Error(\`HTTP \${response.status}\`);
155
193
 
156
194
  if (item.tags && item.tags.length > 0) {
157
195
  await invalidateByTags(item.tags);
@@ -161,18 +199,30 @@ ${authHeaderSpread} },
161
199
  return true;
162
200
  } catch {
163
201
  item.retryCount++;
164
- item.nextRetryAt = Date.now() + RETRY_BACKOFF_MS * Math.pow(2, item.retryCount - 1);
202
+ item.nextRetryAt = Date.now() + backoffDelay(item.retryCount - 1);
165
203
  await updateInQueue(item, db);
166
204
  return false;
167
205
  }
168
206
  }
169
207
 
208
+ /** Clear all queued mutations. Called when auth context changes (logout, session expiry) — queued operations belong to the old session and must not leak. */
209
+ export async function clearQueue()${R(ts, "Promise<void>")}{
210
+ const db = await openQueueDB();
211
+ const tx = db.transaction(STORE_NAME, "readwrite");
212
+ tx.objectStore(STORE_NAME).clear();
213
+ await new Promise${PT(ts, "void")}((resolve, reject) => {
214
+ tx.oncomplete = () => { db.close(); resolve(); };
215
+ tx.onerror = () => { db.close(); reject(tx.error); };
216
+ });
217
+ window.dispatchEvent(new CustomEvent("mutation-queue-changed"));
218
+ }
219
+
170
220
  /** Process all queued mutations in order. Sends them to the server. Runs automatically when mutations are queued or on reconnection. Respects batchSize for progress reporting and batchDelayMs for rate limiting. */
171
221
  export async function processMutationQueue()${R(ts, "Promise<void>")}{
172
222
  if (isSyncing) return;
173
- isSyncing = true;
174
223
 
175
224
  const db = await openQueueDB();
225
+ isSyncing = true;
176
226
  try {
177
227
  const tx = db.transaction(STORE_NAME, "readonly");
178
228
  const store = tx.objectStore(STORE_NAME);
@@ -218,8 +268,8 @@ export async function processMutationQueue()${R(ts, "Promise<void>")}{
218
268
  // Emit progress after every BATCH_SIZE mutations
219
269
  if ((succeeded + failed) % BATCH_SIZE === 0 || succeeded + failed === total) {
220
270
  window.dispatchEvent(
221
- new CustomEvent("mutation-sync-complete", {
222
- detail: { succeeded, failed, total, current: succeeded + failed },
271
+ new CustomEvent("mutation-sync-progress", {
272
+ detail: { succeeded, failed, total },
223
273
  })
224
274
  );
225
275
  }
@@ -250,22 +300,24 @@ export async function flushMutations()${R(ts, "Promise<void>")}{
250
300
  }
251
301
 
252
302
  async function removeFromQueue(id${T(ts, "string")}, db${T(ts, "IDBDatabase | undefined")})${R(ts, "Promise<void>")}{
253
- if (!db) db = await openQueueDB();
303
+ var ownDb = false;
304
+ if (!db) { db = await openQueueDB(); ownDb = true; }
254
305
  const tx = db.transaction(STORE_NAME, "readwrite");
255
306
  tx.objectStore(STORE_NAME).delete(id);
256
307
  await new Promise${PT(ts, "void")}((resolve, reject) => {
257
- tx.oncomplete = () => resolve();
258
- tx.onerror = () => reject(tx.error);
308
+ tx.oncomplete = () => { if (ownDb) db.close(); resolve(); };
309
+ tx.onerror = () => { if (ownDb) db.close(); reject(tx.error); };
259
310
  });
260
311
  }
261
312
 
262
313
  async function updateInQueue(item${T(ts, "MutationQueueItem")}, db${T(ts, "IDBDatabase | undefined")})${R(ts, "Promise<void>")}{
263
- if (!db) db = await openQueueDB();
314
+ var ownDb = false;
315
+ if (!db) { db = await openQueueDB(); ownDb = true; }
264
316
  const tx = db.transaction(STORE_NAME, "readwrite");
265
317
  tx.objectStore(STORE_NAME).put(item);
266
318
  await new Promise${PT(ts, "void")}((resolve, reject) => {
267
- tx.oncomplete = () => resolve();
268
- tx.onerror = () => reject(tx.error);
319
+ tx.oncomplete = () => { if (ownDb) db.close(); resolve(); };
320
+ tx.onerror = () => { if (ownDb) db.close(); reject(tx.error); };
269
321
  });
270
322
  }
271
323
 
@@ -1 +1 @@
1
- {"version":3,"file":"mutation-queue.js","sourceRoot":"","sources":["../../src/runtime/mutation-queue.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mutation-queue.js","sourceRoot":"","sources":["../../src/runtime/mutation-queue.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { T, R } from "./utils.js";
1
+ import { T, R, G } from "./utils.js";
2
2
  export function generateMutationStateCode(ctx) {
3
3
  const { ext, ts } = ctx;
4
4
  return `/**
@@ -31,10 +31,10 @@ export interface MutationState {
31
31
  timestamp${T(ts, "number")};
32
32
  }
33
33
 
34
- const mutations = new Map<string, MutationState>();
34
+ const mutations = new Map${G(ts, "string, MutationState")}();
35
35
 
36
36
  let listenerId = 0;
37
- const listeners = new Map<number, (state: MutationState) => void>();
37
+ const listeners = new Map${G(ts, "number, (state: MutationState) => void")}();
38
38
 
39
39
  /** Track a mutation with the given ID and initial status. */
40
40
  export function trackMutation(id${T(ts, "string")}, status${T(ts, "MutationStatus")} = "idle")${R(ts, "MutationState")}{
@@ -1 +1 @@
1
- {"version":3,"file":"mutation-state.js","sourceRoot":"","sources":["../../src/runtime/mutation-state.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;AAElC,MAAM,UAAU,yBAAyB,CAAC,GAAmB;IAC3D,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC;IACxB,OAAO;;;;;;mGAM0F,GAAG;;;;;;;;;;;;;;;;;MAiBhG,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;UACX,CAAC,CAAC,EAAE,EAAE,gBAAgB,CAAC;SACxB,CAAC,CAAC,EAAE,EAAE,cAAc,CAAC;QACtB,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC;aACX,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;;;;;;;;;kCASM,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;;;;;;;;;;;;wCAe9E,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC,EAAE,EAAE,wBAAwB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,sBAAsB,CAAC;;;;;;;;;;;oCAW/F,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,MAAM,CAAC;;;;;mCAKjE,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,MAAM,CAAC;;;;;qCAKtD,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,2BAA2B,CAAC;;;;;uCAKnD,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,MAAM,CAAC;;;;;wCAK/B,CAAC,CAAC,EAAE,EAAE,iBAAiB,CAAC;;;;;yCAKvB,CAAC,CAAC,EAAE,EAAE,gBAAgB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;;;;;;;;;gDASnC,CAAC,CAAC,EAAE,EAAE,gCAAgC,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,YAAY,CAAC;;;;;;gCAM9E,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,MAAM,CAAC;;;;;;;;;CAStE,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"mutation-state.js","sourceRoot":"","sources":["../../src/runtime/mutation-state.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;AAErC,MAAM,UAAU,yBAAyB,CAAC,GAAmB;IAC3D,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC;IACxB,OAAO;;;;;;mGAM0F,GAAG;;;;;;;;;;;;;;;;;MAiBhG,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;UACX,CAAC,CAAC,EAAE,EAAE,gBAAgB,CAAC;SACxB,CAAC,CAAC,EAAE,EAAE,cAAc,CAAC;QACtB,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC;aACX,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;;;2BAGD,CAAC,CAAC,EAAE,EAAE,uBAAuB,CAAC;;;2BAG9B,CAAC,CAAC,EAAE,EAAE,wCAAwC,CAAC;;;kCAGxC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;;;;;;;;;;;;wCAe9E,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC,EAAE,EAAE,wBAAwB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,sBAAsB,CAAC;;;;;;;;;;;oCAW/F,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,MAAM,CAAC;;;;;mCAKjE,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,MAAM,CAAC;;;;;qCAKtD,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,2BAA2B,CAAC;;;;;uCAKnD,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,MAAM,CAAC;;;;;wCAK/B,CAAC,CAAC,EAAE,EAAE,iBAAiB,CAAC;;;;;yCAKvB,CAAC,CAAC,EAAE,EAAE,gBAAgB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;;;;;;;;;gDASnC,CAAC,CAAC,EAAE,EAAE,gCAAgC,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,YAAY,CAAC;;;;;;gCAM9E,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,MAAM,CAAC;;;;;;;;;CAStE,CAAC;AACF,CAAC"}
@@ -0,0 +1,41 @@
1
+ import { T, R, PT, AS, O } from "./utils.js";
2
+ export function generateOpenDBCode(ctx) {
3
+ const { ts } = ctx;
4
+ return `/**
5
+ * Swoff IndexedDB Helper
6
+ * Generic promise-based IndexedDB open helper used by auth, queue, and push modules.
7
+ *
8
+ * Usage:
9
+ * import { openDB } from "./db.${ctx.ext}";
10
+ *
11
+ * const db = await openDB("my-db", "my-store", "id");
12
+ * // optional upgrade callback for additional indexes:
13
+ * const db = await openDB("my-db", "my-store", "id", (db) => {
14
+ * db.createIndex("by-timestamp", "timestamp");
15
+ * });
16
+ */
17
+
18
+ export function openDB(
19
+ name${T(ts, "string")},
20
+ storeName${T(ts, "string")},
21
+ keyPath${T(ts, "string | string[]")},
22
+ upgradeCallback${O(ts, "(db: IDBDatabase) => void")},
23
+ version${O(ts, "number")}
24
+ )${R(ts, "Promise<IDBDatabase>")}{
25
+ return new Promise${PT(ts, "IDBDatabase")}((resolve, reject) => {
26
+ const request = indexedDB.open(name, version ?? 1);
27
+ request.onupgradeneeded = (e) => {
28
+ const db = (e.target${AS(ts, "IDBOpenDBRequest")}).result;
29
+ if (upgradeCallback) {
30
+ upgradeCallback(db);
31
+ } else if (!db.objectStoreNames.contains(storeName)) {
32
+ db.createObjectStore(storeName, { keyPath: keyPath${AS(ts, 'IDBObjectStoreParameters["keyPath"]')} });
33
+ }
34
+ };
35
+ request.onsuccess = (e) => resolve((e.target${AS(ts, "IDBOpenDBRequest")}).result);
36
+ request.onerror = (e) => reject((e.target${AS(ts, "IDBRequest")}).error);
37
+ });
38
+ }
39
+ `;
40
+ }
41
+ //# sourceMappingURL=open-db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"open-db.js","sourceRoot":"","sources":["../../src/runtime/open-db.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,UAAU,kBAAkB,CAAC,GAAmB;IACpD,MAAM,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC;IACnB,OAAO;;;;;oCAK2B,GAAG,CAAC,GAAG;;;;;;;;;;QAUnC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;aACV,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;WACjB,CAAC,CAAC,EAAE,EAAE,mBAAmB,CAAC;mBAClB,CAAC,CAAC,EAAE,EAAE,2BAA2B,CAAC;WAC1C,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;GACvB,CAAC,CAAC,EAAE,EAAE,sBAAsB,CAAC;sBACV,EAAE,CAAC,EAAE,EAAE,aAAa,CAAC;;;4BAGf,EAAE,CAAC,EAAE,EAAE,kBAAkB,CAAC;;;;4DAIM,EAAE,CAAC,EAAE,EAAE,qCAAqC,CAAC;;;kDAGvD,EAAE,CAAC,EAAE,EAAE,kBAAkB,CAAC;+CAC7B,EAAE,CAAC,EAAE,EAAE,YAAY,CAAC;;;CAGlE,CAAC;AACF,CAAC"}
@@ -1,13 +1,15 @@
1
- import { T, R, PT, AS } from "./utils.js";
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/realtime/notifications.${ext}';
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
- // Bump this when adding new indexes/stores for schema migration
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. Uses the VAPID public key from your swoff.config.json. */
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 openPushDB();
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 openPushDB();
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(
@@ -1 +1 @@
1
- {"version":3,"file":"push.js","sourceRoot":"","sources":["../../src/runtime/push.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,UAAU,gBAAgB,CAAC,GAA0C;IACzE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC;IACxB,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;IAC9B,OAAO;;;;;0GAKiG,GAAG;;;;;;;;;;;;;;;;;;;;;2BAqBlF,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;;qBAE9B,CAAC,CAAC,EAAE,EAAE,oCAAoC,CAAC;;uBAEzC,CAAC,CAAC,EAAE,EAAE,sBAAsB,CAAC;sBAC9B,EAAE,CAAC,EAAE,EAAE,aAAa,CAAC;;;4BAGf,EAAE,CAAC,EAAE,EAAE,kBAAkB,CAAC;;;;;kDAKJ,EAAE,CAAC,EAAE,EAAE,kBAAkB,CAAC;+CAC7B,EAAE,CAAC,EAAE,EAAE,YAAY,CAAC;;;;;uDAKZ,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
+ {"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,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 and manual prompt trigger.
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;AAE/B,MAAM,UAAU,qBAAqB,CAAC,GAAmB;IACvD,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC;IAExB,OAAO;;;;;wEAK+D,GAAG;;;;;;;;;;;iCAW1C,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC;;;;;uCAKV,CAAC,CAAC,EAAE,EAAE,8BAA8B,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2B3E,CAAC;AACF,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"}
@@ -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
- * unregister the service worker, then re-register from scratch.
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.unregistered, result.reregistered, result.warnings);
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: { unregistered, reregistered, warnings })
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${T(ts, "boolean")};
31
+ clearCache${O(ts, "boolean")};
29
32
  /** Delete all swoff-* IndexedDB databases (default: true) */
30
- clearIdb${T(ts, "boolean")};
33
+ clearIdb${O(ts, "boolean")};
31
34
  /** Clear localStorage keys like swRegisteredVersion (default: true) */
32
- clearStorage${T(ts, "boolean")};
33
- /** Unregister SW then re-register (default: true) */
34
- unregisterSW${T(ts, "boolean")};
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
- unregisterSW: true,
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, unregisters the SW, then re-registers from scratch. Returns detailed results. */
78
- export async function resetSwoff(opts${T(ts, "Partial<ResetSwoffOptions>")} = {})${R(ts, "Promise<{ unregistered: boolean; reregistered: boolean; warnings: string[] }>")}{
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. Unregister SW
111
- let unregistered = false;
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 reg = await navigator.serviceWorker.getRegistration();
116
- if (reg) {
117
- unregistered = await reg.unregister();
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 unregister SW: \${e}\`);
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 = { unregistered, reregistered, warnings };
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;AAElC,MAAM,UAAU,iBAAiB,CAAC,GAAmB;IACnD,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC;IACxB,OAAO;;;;;;iDAMwC,GAAG;;;;;;;;;;;;;;mDAcD,GAAG;;;;cAIxC,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;;;;;;;;;;;;;;;;;;;8CAmBc,CAAC,CAAC,EAAE,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;uCAyBlD,CAAC,CAAC,EAAE,EAAE,4BAA4B,CAAE,SAAS,CAAC,CAAC,EAAE,EAAE,+EAA+E,CAAC;iBACzJ,CAAC,CAAC,EAAE,EAAE,mBAAmB,CAAC;kBACzB,CAAC,CAAC,EAAE,EAAE,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkElC,CAAC;AACF,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"}