@swoff/cli 0.3.12 → 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.
Files changed (230) hide show
  1. package/README.md +32 -30
  2. package/dist/index.js +2 -32
  3. package/dist/index.js.map +1 -1
  4. package/dist/lib/cli/help.js +6 -16
  5. package/dist/lib/cli/help.js.map +1 -1
  6. package/dist/lib/cli/logger.js +1 -0
  7. package/dist/lib/cli/logger.js.map +1 -1
  8. package/dist/lib/commands/add.js +29 -87
  9. package/dist/lib/commands/add.js.map +1 -1
  10. package/dist/lib/commands/assets.js +11 -4
  11. package/dist/lib/commands/assets.js.map +1 -1
  12. package/dist/lib/commands/clean.js +2 -10
  13. package/dist/lib/commands/clean.js.map +1 -1
  14. package/dist/lib/commands/generate-guide.js +16 -30
  15. package/dist/lib/commands/generate-guide.js.map +1 -1
  16. package/dist/lib/commands/generate.js +55 -58
  17. package/dist/lib/commands/generate.js.map +1 -1
  18. package/dist/lib/commands/init.js +187 -31
  19. package/dist/lib/commands/init.js.map +1 -1
  20. package/dist/lib/commands/validate.js +2 -4
  21. package/dist/lib/commands/validate.js.map +1 -1
  22. package/dist/lib/config/loader.js +34 -25
  23. package/dist/lib/config/loader.js.map +1 -1
  24. package/dist/lib/config/validator.js +210 -89
  25. package/dist/lib/config/validator.js.map +1 -1
  26. package/dist/lib/generators/file-generators/api-config.js +1 -1
  27. package/dist/lib/generators/file-generators/api-config.js.map +1 -1
  28. package/dist/lib/generators/file-generators/auth-adapter.js +13 -0
  29. package/dist/lib/generators/file-generators/auth-adapter.js.map +1 -0
  30. package/dist/lib/generators/file-generators/auth-check.js +40 -0
  31. package/dist/lib/generators/file-generators/auth-check.js.map +1 -0
  32. package/dist/lib/generators/file-generators/auth-store.js +2 -5
  33. package/dist/lib/generators/file-generators/auth-store.js.map +1 -1
  34. package/dist/lib/generators/file-generators/background-sync.js +1 -1
  35. package/dist/lib/generators/file-generators/background-sync.js.map +1 -1
  36. package/dist/lib/generators/file-generators/cache.js +2 -1
  37. package/dist/lib/generators/file-generators/cache.js.map +1 -1
  38. package/dist/lib/generators/file-generators/client-injector-bundle.js +15 -0
  39. package/dist/lib/generators/file-generators/client-injector-bundle.js.map +1 -0
  40. package/dist/lib/generators/file-generators/client-injector.js +2 -1
  41. package/dist/lib/generators/file-generators/client-injector.js.map +1 -1
  42. package/dist/lib/generators/file-generators/connectivity-manager.js +12 -0
  43. package/dist/lib/generators/file-generators/connectivity-manager.js.map +1 -0
  44. package/dist/lib/generators/file-generators/connectivity.js +12 -0
  45. package/dist/lib/generators/file-generators/connectivity.js.map +1 -0
  46. package/dist/lib/generators/file-generators/context.js +7 -0
  47. package/dist/lib/generators/file-generators/context.js.map +1 -1
  48. package/dist/lib/generators/file-generators/fetch-wrapper.js +1 -1
  49. package/dist/lib/generators/file-generators/fetch-wrapper.js.map +1 -1
  50. package/dist/lib/generators/file-generators/generate-framework-adapters.js +29 -23
  51. package/dist/lib/generators/file-generators/generate-framework-adapters.js.map +1 -1
  52. package/dist/lib/generators/file-generators/gql-wrapper.js +2 -2
  53. package/dist/lib/generators/file-generators/gql-wrapper.js.map +1 -1
  54. package/dist/lib/generators/file-generators/guide-generator.js +57 -16
  55. package/dist/lib/generators/file-generators/guide-generator.js.map +1 -1
  56. package/dist/lib/generators/file-generators/invalidation-tags.js +2 -3
  57. package/dist/lib/generators/file-generators/invalidation-tags.js.map +1 -1
  58. package/dist/lib/generators/file-generators/mutation-queue.js +2 -2
  59. package/dist/lib/generators/file-generators/mutation-queue.js.map +1 -1
  60. package/dist/lib/generators/file-generators/mutation-state.js +1 -1
  61. package/dist/lib/generators/file-generators/mutation-state.js.map +1 -1
  62. package/dist/lib/generators/file-generators/notification-generator.js +6 -0
  63. package/dist/lib/generators/file-generators/notification-generator.js.map +1 -0
  64. package/dist/lib/generators/file-generators/open-db.js +6 -0
  65. package/dist/lib/generators/file-generators/open-db.js.map +1 -0
  66. package/dist/lib/generators/file-generators/push.js +1 -2
  67. package/dist/lib/generators/file-generators/push.js.map +1 -1
  68. package/dist/lib/generators/file-generators/pwa-install.js +2 -6
  69. package/dist/lib/generators/file-generators/pwa-install.js.map +1 -1
  70. package/dist/lib/generators/file-generators/server-push.js +1 -1
  71. package/dist/lib/generators/file-generators/server-push.js.map +1 -1
  72. package/dist/lib/generators/file-generators/storage-generator.js +6 -0
  73. package/dist/lib/generators/file-generators/storage-generator.js.map +1 -0
  74. package/dist/lib/generators/file-generators/storage-notify.js +6 -0
  75. package/dist/lib/generators/file-generators/storage-notify.js.map +1 -0
  76. package/dist/lib/generators/file-generators/storage.js +6 -0
  77. package/dist/lib/generators/file-generators/storage.js.map +1 -0
  78. package/dist/lib/generators/file-generators/sw-generator-build.js +96 -45
  79. package/dist/lib/generators/file-generators/sw-generator-build.js.map +1 -1
  80. package/dist/lib/generators/file-generators/sw-injector.js +1 -4
  81. package/dist/lib/generators/file-generators/sw-injector.js.map +1 -1
  82. package/dist/lib/generators/file-generators/sw-template.js +8 -9
  83. package/dist/lib/generators/file-generators/sw-template.js.map +1 -1
  84. package/dist/lib/generators/file-generators/sw-version-gen.js +32 -0
  85. package/dist/lib/generators/file-generators/sw-version-gen.js.map +1 -0
  86. package/dist/lib/generators/file-generators/swoff-api-bundle.js +51 -0
  87. package/dist/lib/generators/file-generators/swoff-api-bundle.js.map +1 -0
  88. package/dist/lib/generators/sw-build-utils.js +69 -0
  89. package/dist/lib/generators/sw-build-utils.js.map +1 -0
  90. package/dist/lib/generators/sw-generator.js +26 -45
  91. package/dist/lib/generators/sw-generator.js.map +1 -1
  92. package/dist/lib/generators/sw-sections/activate-handler.js +74 -23
  93. package/dist/lib/generators/sw-sections/activate-handler.js.map +1 -1
  94. package/dist/lib/generators/sw-sections/assemble-sw.js +15 -95
  95. package/dist/lib/generators/sw-sections/assemble-sw.js.map +1 -1
  96. package/dist/lib/generators/sw-sections/background-sync-handler.js +74 -72
  97. package/dist/lib/generators/sw-sections/background-sync-handler.js.map +1 -1
  98. package/dist/lib/generators/sw-sections/batch-refresh-queue.js +102 -0
  99. package/dist/lib/generators/sw-sections/batch-refresh-queue.js.map +1 -0
  100. package/dist/lib/generators/sw-sections/config-header.js +2 -3
  101. package/dist/lib/generators/sw-sections/config-header.js.map +1 -1
  102. package/dist/lib/generators/sw-sections/default-template.js +59 -6
  103. package/dist/lib/generators/sw-sections/default-template.js.map +1 -1
  104. package/dist/lib/generators/sw-sections/fetch-handler.js +621 -495
  105. package/dist/lib/generators/sw-sections/fetch-handler.js.map +1 -1
  106. package/dist/lib/generators/sw-sections/install-handler.js +40 -23
  107. package/dist/lib/generators/sw-sections/install-handler.js.map +1 -1
  108. package/dist/lib/generators/sw-sections/message-handler.js +25 -8
  109. package/dist/lib/generators/sw-sections/message-handler.js.map +1 -1
  110. package/dist/lib/generators/sw-sections/server-push-handler.js +10 -14
  111. package/dist/lib/generators/sw-sections/server-push-handler.js.map +1 -1
  112. package/dist/lib/generators/sw-sections/shared.js +68 -0
  113. package/dist/lib/generators/sw-sections/shared.js.map +1 -0
  114. package/dist/lib/generators/sw-sections/sw-push.js +2 -6
  115. package/dist/lib/generators/sw-sections/sw-push.js.map +1 -1
  116. package/dist/lib/generators/sw-sections/tag-management.js +55 -86
  117. package/dist/lib/generators/sw-sections/tag-management.js.map +1 -1
  118. package/dist/lib/generators/swoff-files-generator.js +185 -66
  119. package/dist/lib/generators/swoff-files-generator.js.map +1 -1
  120. package/dist/lib/shared/config-types.js +68 -72
  121. package/dist/lib/shared/config-types.js.map +1 -1
  122. package/dist/lib/shared/feature-registry.js +198 -0
  123. package/dist/lib/shared/feature-registry.js.map +1 -0
  124. package/dist/lib/utils/detect-framework.js +52 -9
  125. package/dist/lib/utils/detect-framework.js.map +1 -1
  126. package/dist/runtime/api-config.js +2 -2
  127. package/dist/runtime/api-config.js.map +1 -1
  128. package/dist/runtime/auth-adapter.js +179 -0
  129. package/dist/runtime/auth-adapter.js.map +1 -0
  130. package/dist/runtime/auth-state.js +16 -6
  131. package/dist/runtime/auth-state.js.map +1 -1
  132. package/dist/runtime/auth-store.js +219 -213
  133. package/dist/runtime/auth-store.js.map +1 -1
  134. package/dist/runtime/auth-user.js +5 -19
  135. package/dist/runtime/auth-user.js.map +1 -1
  136. package/dist/runtime/background-sync.js +5 -2
  137. package/dist/runtime/background-sync.js.map +1 -1
  138. package/dist/runtime/cache.js +91 -3
  139. package/dist/runtime/cache.js.map +1 -1
  140. package/dist/runtime/client-injector-bundle.js +314 -0
  141. package/dist/runtime/client-injector-bundle.js.map +1 -0
  142. package/dist/runtime/client-injector.js +173 -30
  143. package/dist/runtime/client-injector.js.map +1 -1
  144. package/dist/runtime/connectivity-manager.js +83 -0
  145. package/dist/runtime/connectivity-manager.js.map +1 -0
  146. package/dist/runtime/connectivity.js +83 -0
  147. package/dist/runtime/connectivity.js.map +1 -0
  148. package/dist/runtime/fetch-wrapper.js +26 -59
  149. package/dist/runtime/fetch-wrapper.js.map +1 -1
  150. package/dist/runtime/gql-wrapper.js +15 -9
  151. package/dist/runtime/gql-wrapper.js.map +1 -1
  152. package/dist/runtime/invalidation-tags.js +12 -89
  153. package/dist/runtime/invalidation-tags.js.map +1 -1
  154. package/dist/runtime/mutation-queue.js +83 -31
  155. package/dist/runtime/mutation-queue.js.map +1 -1
  156. package/dist/runtime/mutation-state.js +3 -3
  157. package/dist/runtime/mutation-state.js.map +1 -1
  158. package/dist/runtime/notification.js +65 -0
  159. package/dist/runtime/notification.js.map +1 -0
  160. package/dist/runtime/open-db.js +41 -0
  161. package/dist/runtime/open-db.js.map +1 -0
  162. package/dist/runtime/push.js +15 -27
  163. package/dist/runtime/push.js.map +1 -1
  164. package/dist/runtime/pwa-injector.js +3 -32
  165. package/dist/runtime/pwa-injector.js.map +1 -1
  166. package/dist/runtime/pwa-prompt.js +35 -3
  167. package/dist/runtime/pwa-prompt.js.map +1 -1
  168. package/dist/runtime/reset.js +39 -42
  169. package/dist/runtime/reset.js.map +1 -1
  170. package/dist/runtime/server-push.js +23 -13
  171. package/dist/runtime/server-push.js.map +1 -1
  172. package/dist/runtime/storage.js +32 -0
  173. package/dist/runtime/storage.js.map +1 -0
  174. package/dist/runtime/sw-injector.js +19 -178
  175. package/dist/runtime/sw-injector.js.map +1 -1
  176. package/dist/runtime/sw-version.js +13 -0
  177. package/dist/runtime/sw-version.js.map +1 -0
  178. package/dist/runtime/swoff-api-bundle.js +1491 -0
  179. package/dist/runtime/swoff-api-bundle.js.map +1 -0
  180. package/dist/runtime/type-definitions.js +8 -7
  181. package/dist/runtime/type-definitions.js.map +1 -1
  182. package/dist/runtime/utils.js +4 -0
  183. package/dist/runtime/utils.js.map +1 -1
  184. package/dist/swoff-nkdhhmw8. +18 -0
  185. package/dist/swoff.js +5 -0
  186. package/package.json +1 -3
  187. package/templates/react/useAuth.jsx +7 -4
  188. package/templates/react/useAuth.tsx +14 -14
  189. package/templates/react/useBackgroundSync.jsx +5 -4
  190. package/templates/react/useBackgroundSync.tsx +5 -4
  191. package/templates/react/useCachedFetch.jsx +8 -0
  192. package/templates/react/useCachedFetch.tsx +8 -0
  193. package/templates/react/useMutation.jsx +60 -56
  194. package/templates/react/useMutation.tsx +65 -64
  195. package/templates/react/useMutationQueue.jsx +5 -1
  196. package/templates/react/useMutationQueue.tsx +8 -2
  197. package/templates/react/useMutationState.jsx +3 -4
  198. package/templates/react/useMutationState.tsx +4 -8
  199. package/templates/react/useNetworkStatus.jsx +57 -17
  200. package/templates/react/useNetworkStatus.tsx +42 -20
  201. package/templates/react/useOfflineAnalytics.jsx +42 -0
  202. package/templates/react/useOfflineAnalytics.tsx +50 -0
  203. package/templates/react/usePwaInstall.jsx +26 -0
  204. package/templates/react/usePwaInstall.tsx +26 -0
  205. package/templates/react/useSWUpdate.jsx +7 -52
  206. package/templates/react/useSWUpdate.tsx +12 -51
  207. package/templates/react/useStorageEstimate.jsx +56 -0
  208. package/templates/react/useStorageEstimate.tsx +67 -0
  209. package/dist/__tests__/assemble-sw.test.js +0 -145
  210. package/dist/__tests__/assemble-sw.test.js.map +0 -1
  211. package/dist/__tests__/cli-integration.test.js +0 -231
  212. package/dist/__tests__/cli-integration.test.js.map +0 -1
  213. package/dist/__tests__/config-types.test.js +0 -124
  214. package/dist/__tests__/config-types.test.js.map +0 -1
  215. package/dist/__tests__/detect-language.test.js +0 -51
  216. package/dist/__tests__/detect-language.test.js.map +0 -1
  217. package/dist/__tests__/file-generators.test.js +0 -228
  218. package/dist/__tests__/file-generators.test.js.map +0 -1
  219. package/dist/__tests__/glob-matcher.test.js +0 -86
  220. package/dist/__tests__/glob-matcher.test.js.map +0 -1
  221. package/dist/__tests__/invalidation-tags.test.js +0 -283
  222. package/dist/__tests__/invalidation-tags.test.js.map +0 -1
  223. package/dist/__tests__/loader.test.js +0 -77
  224. package/dist/__tests__/loader.test.js.map +0 -1
  225. package/dist/__tests__/validator.test.js +0 -340
  226. package/dist/__tests__/validator.test.js.map +0 -1
  227. package/templates/react/useCacheInvalidation.jsx +0 -19
  228. package/templates/react/useCacheInvalidation.tsx +0 -52
  229. package/templates/react/useIsFetching.jsx +0 -32
  230. package/templates/react/useIsFetching.tsx +0 -32
@@ -1,5 +1,5 @@
1
1
  import { T, R, G, AS } from "./utils.js";
2
- export function generateGqlWrapperCode(ctx, endpoint) {
2
+ export function generateGqlWrapperCode(ctx, endpoints) {
3
3
  const { ext, ts } = ctx;
4
4
  const optionsInterface = ts
5
5
  ? `
@@ -50,6 +50,8 @@ export interface GqlOptions {
50
50
  import { fetchWithCache } from "../fetch/core.${ext}";
51
51
  import type { GqlResult } from "../swoff";
52
52
  ${optionsInterface}
53
+ const GQL_ENDPOINTS = ${JSON.stringify(endpoints)};
54
+
53
55
  /** Extract operation name from a GraphQL document. Returns null for anonymous queries (e.g. "{ todos { id } }"). */
54
56
  function getOperationName(query${T(ts, "string")})${T(ts, "string | null")}{
55
57
  const match = query.match(/(query|mutation|subscription)\\s+(\\w+)/);
@@ -76,23 +78,25 @@ function tagsFromOpName(name${T(ts, "string | null")})${T(ts, "string[]")}{
76
78
  if (!name) return [];
77
79
  const stripped = name.replace(/^(get|fetch|list|all|query)/i, "").replace(/^(create|set|add|new|update|delete|remove)/i, "");
78
80
  if (!stripped) return [name.toLowerCase()];
79
- const tag = stripped.charAt(0).toLowerCase() + stripped.slice(1);
81
+ const tag = stripped.toLowerCase();
80
82
  const plural = tag.replace(/s$/, "") + "s";
81
83
  return [plural, tag];
82
84
  }
83
85
 
84
- /** Fetch a GraphQL endpoint with Swoff's caching, auth, offline queue, and auto-invalidation. Hashes query + variables for deterministic cache keys. */
86
+ /** Fetch a GraphQL endpoint with Swoff's caching, auth, offline queue, and auto-invalidation. Hashes query + variables for deterministic cache keys. Uses GQL_ENDPOINTS[0] by default. Pass endpointIndex to use a different endpoint. */
85
87
  export async function fetchWithGql${G(ts, "T")}(
86
88
  query${T(ts, "string")},
87
- options${T(ts, "GqlOptions")} = {}
89
+ options${T(ts, "GqlOptions")} = {},
90
+ endpointIndex${T(ts, "number")} = 0
88
91
  )${R(ts, "Promise<GqlResult<T>>")}{
89
92
  const isRead = isReadOperation(query);
90
93
  const opName = getOperationName(query);
91
94
  const variables = options.variables;
92
95
  const hash = await bodyHash({ query, variables });
93
96
  const tags = options.tags || tagsFromOpName(opName);
97
+ const endpoint = GQL_ENDPOINTS[endpointIndex] || GQL_ENDPOINTS[0];
94
98
 
95
- const { response, fromCache } = await fetchWithCache("${endpoint}", {
99
+ const { response, fromCache } = await fetchWithCache(endpoint, {
96
100
  method: "POST",
97
101
  body: JSON.stringify({ query, variables }),
98
102
  headers: {
@@ -117,18 +121,20 @@ export async function fetchWithGql${G(ts, "T")}(
117
121
  export async function queryGql${G(ts, "T")}(
118
122
  query${T(ts, "string")},
119
123
  variables${T(ts, "Record<string, unknown> | undefined")} = undefined,
120
- options${T(ts, "GqlOptions")} = {}
124
+ options${T(ts, "GqlOptions")} = {},
125
+ endpointIndex${T(ts, "number")} = 0
121
126
  )${R(ts, "Promise<GqlResult<T>>")}{
122
- return fetchWithGql${G(ts, "T")}(query, { ...options, variables });
127
+ return fetchWithGql${G(ts, "T")}(query, { ...options, variables }, endpointIndex);
123
128
  }
124
129
 
125
130
  /** Shorthand for GraphQL mutations (type: "mutation"). Auto-invalidates related cache tags. */
126
131
  export async function mutateGql${G(ts, "T")}(
127
132
  mutation${T(ts, "string")},
128
133
  variables${T(ts, "Record<string, unknown> | undefined")} = undefined,
129
- options${T(ts, "GqlOptions")} = {}
134
+ options${T(ts, "GqlOptions")} = {},
135
+ endpointIndex${T(ts, "number")} = 0
130
136
  )${R(ts, "Promise<GqlResult<T>>")}{
131
- return fetchWithGql${G(ts, "T")}(mutation, { ...options, variables });
137
+ return fetchWithGql${G(ts, "T")}(mutation, { ...options, variables }, endpointIndex);
132
138
  }
133
139
  `;
134
140
  }
@@ -1 +1 @@
1
- {"version":3,"file":"gql-wrapper.js","sourceRoot":"","sources":["../../src/runtime/gql-wrapper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,UAAU,sBAAsB,CACpC,GAAmB,EACnB,QAAgB;IAEhB,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC;IAExB,MAAM,gBAAgB,GAAG,EAAE;QACzB,CAAC,CAAC;;;;;;;;CAQL;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO;;;;;;;8EAOqE,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;gDA4BjC,GAAG;;EAEjD,gBAAgB;;iCAEe,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;;;gCAM1C,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC;;;;;;;6BAOtC,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,iBAAiB,CAAC;;;;;;;;8BAQ3C,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,UAAU,CAAC;;;;;;;;;;oCAUrC,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC;SACrC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;WACb,CAAC,CAAC,EAAE,EAAE,YAAY,CAAC;GAC3B,CAAC,CAAC,EAAE,EAAE,uBAAuB,CAAC;;;;;;;0DAOyB,QAAQ;;;;;;;;;;;;;;;;;;8BAkBpC,EAAE,CAAC,EAAE,EAAE,GAAG,CAAC;;;;gCAIT,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC;SACjC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;aACX,CAAC,CAAC,EAAE,EAAE,qCAAqC,CAAC;WAC9C,CAAC,CAAC,EAAE,EAAE,YAAY,CAAC;GAC3B,CAAC,CAAC,EAAE,EAAE,uBAAuB,CAAC;uBACV,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC;;;;iCAIA,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC;YAC/B,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;aACd,CAAC,CAAC,EAAE,EAAE,qCAAqC,CAAC;WAC9C,CAAC,CAAC,EAAE,EAAE,YAAY,CAAC;GAC3B,CAAC,CAAC,EAAE,EAAE,uBAAuB,CAAC;uBACV,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC;;CAEhC,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"gql-wrapper.js","sourceRoot":"","sources":["../../src/runtime/gql-wrapper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,UAAU,sBAAsB,CACpC,GAAmB,EACnB,SAAmB;IAEnB,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC;IAExB,MAAM,gBAAgB,GAAG,EAAE;QACzB,CAAC,CAAC;;;;;;;;CAQL;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO;;;;;;;8EAOqE,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;gDA4BjC,GAAG;;EAEjD,gBAAgB;wBACM,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC;;;iCAGhB,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;;;gCAM1C,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC;;;;;;;6BAOtC,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,iBAAiB,CAAC;;;;;;;;8BAQ3C,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,UAAU,CAAC;;;;;;;;;;oCAUrC,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC;SACrC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;WACb,CAAC,CAAC,EAAE,EAAE,YAAY,CAAC;iBACb,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;GAC7B,CAAC,CAAC,EAAE,EAAE,uBAAuB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;8BA0BH,EAAE,CAAC,EAAE,EAAE,GAAG,CAAC;;;;gCAIT,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC;SACjC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;aACX,CAAC,CAAC,EAAE,EAAE,qCAAqC,CAAC;WAC9C,CAAC,CAAC,EAAE,EAAE,YAAY,CAAC;iBACb,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;GAC7B,CAAC,CAAC,EAAE,EAAE,uBAAuB,CAAC;uBACV,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC;;;;iCAIA,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC;YAC/B,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;aACd,CAAC,CAAC,EAAE,EAAE,qCAAqC,CAAC;WAC9C,CAAC,CAAC,EAAE,EAAE,YAAY,CAAC;iBACb,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;GAC7B,CAAC,CAAC,EAAE,EAAE,uBAAuB,CAAC;uBACV,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC;;CAEhC,CAAC;AACF,CAAC"}
@@ -74,24 +74,17 @@ function generateSingularizationCode(singularization) {
74
74
  return "null";
75
75
  return JSON.stringify(singularization);
76
76
  }
77
- function generateCascadingCode(cascading) {
78
- if (!cascading || Object.keys(cascading).length === 0)
79
- return "null";
80
- return JSON.stringify(cascading);
81
- }
82
- export function generateInvalidationTagsCode(ctx, prefixes, patterns, singularization, cascading) {
77
+ export function generateInvalidationTagsCode(ctx, prefixes, patterns, singularization) {
83
78
  const { ext, ts } = ctx;
84
79
  const patternCode = generatePatternCode(patterns);
85
80
  const singularizationCode = generateSingularizationCode(singularization);
86
- const cascadingCode = generateCascadingCode(cascading);
87
81
  const prefixesCode = JSON.stringify(prefixes);
88
82
  return `/**
89
83
  * Swoff Invalidation Tags Helper
90
- * Pattern-based tag generation from URLs with configurable glob patterns,
91
- * prefix skipping, singularization, and cascading invalidation.
84
+ * Segment- and pattern-based tag generation from URLs.
92
85
  *
93
86
  * Usage:
94
- * import { generateTags, invalidateUrl } from './swoff/cache/tags.${ext}';
87
+ * import { generateTags } from './swoff/cache/tags.${ext}';
95
88
  *
96
89
  * // Generate tags from URL
97
90
  * generateTags("/api/todos"); // ["todos"]
@@ -102,11 +95,9 @@ export function generateInvalidationTagsCode(ctx, prefixes, patterns, singulariz
102
95
  * tags: generateTags("/api/todos"),
103
96
  * });
104
97
  *
105
- * // Invalidate after mutation
106
- * await invalidateUrl("/api/todos/42");
98
+ * // Generate method-prefixed tags for mutations
99
+ * generateTagsFromMethod("POST", "/api/todos"); // ["post-todos"]
107
100
  */
108
-
109
- import { invalidateByTags } from "./index.${ext}";
110
101
  ${ts ? `
111
102
  interface TagPattern {
112
103
  re: RegExp;
@@ -123,12 +114,15 @@ const SKIP_PREFIXES = ${prefixesCode};
123
114
  // Custom singularization map (plural → singular)
124
115
  const SINGULARIZATION${T(ts, "Record<string, string> | null")} = ${singularizationCode};
125
116
 
126
- // Cascading invalidation map (tag → dependent tags)
127
- const CASCADING${T(ts, "Record<string, string[]> | null")} = ${cascadingCode};
128
-
129
117
  /** Generate cache invalidation tags from a URL path. Tries configured patterns first, falls back to segment-based generation. */
130
118
  export function generateTags(url${T(ts, "string | URL")})${R(ts, "string[]")}{
131
- const parsed = typeof url === "string" ? new URL(url, window.location.origin) : url;
119
+ const base = typeof window !== "undefined" ? window.location.origin : "";
120
+ let parsed;
121
+ try {
122
+ parsed = typeof url === "string" ? new URL(url, base) : url;
123
+ } catch {
124
+ return [];
125
+ }
132
126
  const path = parsed.pathname;
133
127
 
134
128
  // Try configured patterns first
@@ -184,77 +178,6 @@ export function generateTagsFromMethod(method${T(ts, "string")}, url${T(ts, "str
184
178
  if (method === "GET" || method === "HEAD") return tags;
185
179
  return tags.map((tag) => \`\${method.toLowerCase()}-\${tag}\`);
186
180
  }
187
-
188
- /** Invalidate cached responses related to a URL, including cascading dependencies. */
189
- export async function invalidateUrl(url${T(ts, "string | URL")})${R(ts, "Promise<void>")}{
190
- const tags = generateTags(url);
191
- const allTags = CASCADING ? expandCascading(tags) : tags;
192
- await invalidateByTags(allTags);
193
- }
194
-
195
- /** Invalidate cached responses tagged with method-prefixed tags, including cascading dependencies. */
196
- export async function invalidateByMethod(method${T(ts, "string")}, url${T(ts, "string | URL")})${R(ts, "Promise<void>")}{
197
- const tags = generateTagsFromMethod(method, url);
198
- const allTags = CASCADING ? expandCascading(tags) : tags;
199
- await invalidateByTags(allTags);
200
- }
201
-
202
- /** Expand tags with their cascading dependencies, deduplicated. */
203
- export function expandCascading(tags${T(ts, "string[]")})${R(ts, "string[]")}{
204
- if (!CASCADING) return [...tags];
205
- const result = new Set(tags);
206
- for (const tag of tags) {
207
- const deps = CASCADING[tag];
208
- if (deps) {
209
- for (const dep of deps) {
210
- result.add(dep);
211
- }
212
- }
213
- }
214
- return [...result];
215
- }
216
-
217
- /** Introspect: get all URLs cached under a given tag. */
218
- export async function getUrlsForTag(tag${T(ts, "string")})${R(ts, "Promise<{ url: string; actualUrl: string }[]>")}{
219
- const controller = navigator.serviceWorker?.controller;
220
- if (!controller) return [];
221
- return new Promise((resolve) => {
222
- const channel = new MessageChannel();
223
- channel.port1.onmessage = (event) => {
224
- resolve(event.data.urls || []);
225
- };
226
- controller.postMessage(
227
- { type: "GET_URLS_FOR_TAG", tag },
228
- [channel.port2],
229
- );
230
- });
231
- }
232
-
233
- /** Introspect: get all tags associated with a given URL. */
234
- export async function getTagsForUrl(url${T(ts, "string")})${R(ts, "Promise<string[]>")}{
235
- const controller = navigator.serviceWorker?.controller;
236
- if (!controller) return [];
237
- return new Promise((resolve) => {
238
- const channel = new MessageChannel();
239
- channel.port1.onmessage = (event) => {
240
- resolve(event.data.tags || []);
241
- };
242
- controller.postMessage(
243
- { type: "GET_TAGS_FOR_URL", url },
244
- [channel.port2],
245
- );
246
- });
247
- }
248
-
249
- /** Invalidate all cached responses whose URL matches the given glob pattern. */
250
- export async function invalidateMatching(glob${T(ts, "string")})${R(ts, "Promise<void>")}{
251
- const controller = navigator.serviceWorker?.controller;
252
- if (!controller) return;
253
- controller.postMessage({
254
- type: "INVALIDATE_MATCHING",
255
- glob,
256
- });
257
- }
258
181
  `;
259
182
  }
260
183
  //# sourceMappingURL=invalidation-tags.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"invalidation-tags.js","sourceRoot":"","sources":["../../src/runtime/invalidation-tags.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"invalidation-tags.js","sourceRoot":"","sources":["../../src/runtime/invalidation-tags.ts"],"names":[],"mappings":"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"}
@@ -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,65 @@
1
+ import { T, R } from "./utils.js";
2
+ export function generateNotificationCode(ctx) {
3
+ const { ext, ts } = ctx;
4
+ return `/**
5
+ * Swoff Notification
6
+ * Dispatches \`swoff:notification\` custom events so your app can
7
+ * show toast/alert UI for offline-first events (fetch failures,
8
+ * storage quota warnings, background sync errors, etc.).
9
+ *
10
+ * Usage:
11
+ * import { checkStorage } from "./swoff/notification.${ext}";
12
+ * const { usage, quota, percentUsed } = await checkStorage();
13
+ *
14
+ * Window events:
15
+ * swoff:notification — dispatched by the service worker or by checkStorage()
16
+ * detail: { level: "error"|"warn"|"info", code: string, message: string }
17
+ *
18
+ * ── Placeholder listener ────────────────────────────────
19
+ * Add a listener in your app entry point and replace the body
20
+ * with your own toast library (e.g. react-hot-toast, vue-toastification):
21
+ *
22
+ * window.addEventListener("swoff:notification", (event) => {
23
+ * const { level, code, message } = event.detail;
24
+ * // console.log(\`[swoff:\${level}] \${code}: \${message}\`);
25
+ * // alert(\`\${code}: \${message}\`);
26
+ * });
27
+ */
28
+
29
+ /** Get raw storage estimate without dispatching events. Reuse in your own UI. */
30
+ export async function getStorageEstimate()${R(ts, "Promise<{ usage: number; quota: number; percentUsed: number }>")}{
31
+ if (!navigator.storage?.estimate) {
32
+ return { usage: 0, quota: 0, percentUsed: 0 };
33
+ }
34
+ const { usage = 0, quota = 0 } = await navigator.storage.estimate();
35
+ const percentUsed = quota > 0 ? Math.round((usage / quota) * 100) : 0;
36
+ return { usage, quota, percentUsed };
37
+ }
38
+
39
+ /** Check available storage and dispatch a warning if >80% used. */
40
+ export async function checkStorage()${R(ts, "Promise<{ usage: number; quota: number; percentUsed: number }>")}{
41
+ const result = await getStorageEstimate();
42
+ if (result.percentUsed > 80) {
43
+ window.dispatchEvent(
44
+ new CustomEvent("swoff:notification", {
45
+ detail: {
46
+ level: "warn",
47
+ code: "STORAGE_QUOTA_HIGH",
48
+ message: \`Storage at \${result.percentUsed}% capacity (\${formatBytes(result.usage)} / \${formatBytes(result.quota)})\`,
49
+ },
50
+ }),
51
+ );
52
+ }
53
+ return result;
54
+ }
55
+
56
+ /** Format bytes to a human-readable string (e.g. "1.5 MB"). */
57
+ export function formatBytes(bytes${T(ts, "number")})${R(ts, "string")}{
58
+ if (bytes === 0) return "0 B";
59
+ const units = ["B", "KB", "MB", "GB"];
60
+ const i = Math.floor(Math.log(bytes) / Math.log(1024));
61
+ return \`\${(bytes / Math.pow(1024, i)).toFixed(1)} \${units[i]}\`;
62
+ }
63
+ `;
64
+ }
65
+ //# sourceMappingURL=notification.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification.js","sourceRoot":"","sources":["../../src/runtime/notification.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;AAElC,MAAM,UAAU,wBAAwB,CAAC,GAAmB;IAC1D,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC;IACxB,OAAO;;;;;;;0DAOiD,GAAG;;;;;;;;;;;;;;;;;;;4CAmBjB,CAAC,CAAC,EAAE,EAAE,gEAAgE,CAAC;;;;;;;;;;sCAU7E,CAAC,CAAC,EAAE,EAAE,gEAAgE,CAAC;;;;;;;;;;;;;;;;;mCAiB1E,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC;;;;;;CAMpE,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"}