@swoff/cli 0.3.13 → 0.3.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/README.md +28 -32
  2. package/dist/index.js +2 -13
  3. package/dist/index.js.map +1 -1
  4. package/dist/lib/cli/help.js +3 -8
  5. package/dist/lib/cli/help.js.map +1 -1
  6. package/dist/lib/commands/add.js +29 -87
  7. package/dist/lib/commands/add.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 +31 -6
  11. package/dist/lib/commands/generate.js.map +1 -1
  12. package/dist/lib/commands/init.js +188 -11
  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/validator.js +202 -96
  19. package/dist/lib/config/validator.js.map +1 -1
  20. package/dist/lib/generators/file-generators/api-config.js +1 -1
  21. package/dist/lib/generators/file-generators/api-config.js.map +1 -1
  22. package/dist/lib/generators/file-generators/auth-adapter.js +13 -0
  23. package/dist/lib/generators/file-generators/auth-adapter.js.map +1 -0
  24. package/dist/lib/generators/file-generators/auth-check.js +40 -0
  25. package/dist/lib/generators/file-generators/auth-check.js.map +1 -0
  26. package/dist/lib/generators/file-generators/auth-store.js +2 -5
  27. package/dist/lib/generators/file-generators/auth-store.js.map +1 -1
  28. package/dist/lib/generators/file-generators/background-sync.js +1 -1
  29. package/dist/lib/generators/file-generators/background-sync.js.map +1 -1
  30. package/dist/lib/generators/file-generators/cache.js +2 -1
  31. package/dist/lib/generators/file-generators/cache.js.map +1 -1
  32. package/dist/lib/generators/file-generators/client-injector-bundle.js +15 -0
  33. package/dist/lib/generators/file-generators/client-injector-bundle.js.map +1 -0
  34. package/dist/lib/generators/file-generators/client-injector.js +2 -1
  35. package/dist/lib/generators/file-generators/client-injector.js.map +1 -1
  36. package/dist/lib/generators/file-generators/connectivity-manager.js +12 -0
  37. package/dist/lib/generators/file-generators/connectivity-manager.js.map +1 -0
  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/notification-generator.js +6 -0
  57. package/dist/lib/generators/file-generators/notification-generator.js.map +1 -0
  58. package/dist/lib/generators/file-generators/open-db.js +6 -0
  59. package/dist/lib/generators/file-generators/open-db.js.map +1 -0
  60. package/dist/lib/generators/file-generators/push.js +1 -2
  61. package/dist/lib/generators/file-generators/push.js.map +1 -1
  62. package/dist/lib/generators/file-generators/pwa-install.js +2 -6
  63. package/dist/lib/generators/file-generators/pwa-install.js.map +1 -1
  64. package/dist/lib/generators/file-generators/server-push.js +1 -1
  65. package/dist/lib/generators/file-generators/server-push.js.map +1 -1
  66. package/dist/lib/generators/file-generators/storage-generator.js +6 -0
  67. package/dist/lib/generators/file-generators/storage-generator.js.map +1 -0
  68. package/dist/lib/generators/file-generators/storage-notify.js +6 -0
  69. package/dist/lib/generators/file-generators/storage-notify.js.map +1 -0
  70. package/dist/lib/generators/file-generators/storage.js +6 -0
  71. package/dist/lib/generators/file-generators/storage.js.map +1 -0
  72. package/dist/lib/generators/file-generators/sw-generator-build.js +96 -45
  73. package/dist/lib/generators/file-generators/sw-generator-build.js.map +1 -1
  74. package/dist/lib/generators/file-generators/sw-injector.js +0 -4
  75. package/dist/lib/generators/file-generators/sw-injector.js.map +1 -1
  76. package/dist/lib/generators/file-generators/sw-template.js +8 -9
  77. package/dist/lib/generators/file-generators/sw-template.js.map +1 -1
  78. package/dist/lib/generators/file-generators/sw-version-gen.js +32 -0
  79. package/dist/lib/generators/file-generators/sw-version-gen.js.map +1 -0
  80. package/dist/lib/generators/file-generators/swoff-api-bundle.js +51 -0
  81. package/dist/lib/generators/file-generators/swoff-api-bundle.js.map +1 -0
  82. package/dist/lib/generators/sw-build-utils.js +69 -0
  83. package/dist/lib/generators/sw-build-utils.js.map +1 -0
  84. package/dist/lib/generators/sw-generator.js +23 -34
  85. package/dist/lib/generators/sw-generator.js.map +1 -1
  86. package/dist/lib/generators/sw-sections/activate-handler.js +74 -23
  87. package/dist/lib/generators/sw-sections/activate-handler.js.map +1 -1
  88. package/dist/lib/generators/sw-sections/assemble-sw.js +15 -94
  89. package/dist/lib/generators/sw-sections/assemble-sw.js.map +1 -1
  90. package/dist/lib/generators/sw-sections/background-sync-handler.js +74 -72
  91. package/dist/lib/generators/sw-sections/background-sync-handler.js.map +1 -1
  92. package/dist/lib/generators/sw-sections/batch-refresh-queue.js +102 -0
  93. package/dist/lib/generators/sw-sections/batch-refresh-queue.js.map +1 -0
  94. package/dist/lib/generators/sw-sections/config-header.js +2 -3
  95. package/dist/lib/generators/sw-sections/config-header.js.map +1 -1
  96. package/dist/lib/generators/sw-sections/default-template.js +59 -6
  97. package/dist/lib/generators/sw-sections/default-template.js.map +1 -1
  98. package/dist/lib/generators/sw-sections/fetch-handler.js +621 -495
  99. package/dist/lib/generators/sw-sections/fetch-handler.js.map +1 -1
  100. package/dist/lib/generators/sw-sections/install-handler.js +40 -23
  101. package/dist/lib/generators/sw-sections/install-handler.js.map +1 -1
  102. package/dist/lib/generators/sw-sections/message-handler.js +25 -8
  103. package/dist/lib/generators/sw-sections/message-handler.js.map +1 -1
  104. package/dist/lib/generators/sw-sections/server-push-handler.js +10 -14
  105. package/dist/lib/generators/sw-sections/server-push-handler.js.map +1 -1
  106. package/dist/lib/generators/sw-sections/shared.js +68 -0
  107. package/dist/lib/generators/sw-sections/shared.js.map +1 -0
  108. package/dist/lib/generators/sw-sections/sw-push.js +2 -6
  109. package/dist/lib/generators/sw-sections/sw-push.js.map +1 -1
  110. package/dist/lib/generators/sw-sections/tag-management.js +55 -86
  111. package/dist/lib/generators/sw-sections/tag-management.js.map +1 -1
  112. package/dist/lib/generators/swoff-files-generator.js +183 -59
  113. package/dist/lib/generators/swoff-files-generator.js.map +1 -1
  114. package/dist/lib/shared/config-types.js +67 -63
  115. package/dist/lib/shared/config-types.js.map +1 -1
  116. package/dist/lib/shared/feature-registry.js +198 -0
  117. package/dist/lib/shared/feature-registry.js.map +1 -0
  118. package/dist/lib/utils/detect-framework.js +52 -9
  119. package/dist/lib/utils/detect-framework.js.map +1 -1
  120. package/dist/runtime/api-config.js +2 -2
  121. package/dist/runtime/api-config.js.map +1 -1
  122. package/dist/runtime/auth-adapter.js +179 -0
  123. package/dist/runtime/auth-adapter.js.map +1 -0
  124. package/dist/runtime/auth-state.js +16 -6
  125. package/dist/runtime/auth-state.js.map +1 -1
  126. package/dist/runtime/auth-store.js +219 -213
  127. package/dist/runtime/auth-store.js.map +1 -1
  128. package/dist/runtime/auth-user.js +5 -19
  129. package/dist/runtime/auth-user.js.map +1 -1
  130. package/dist/runtime/background-sync.js +5 -2
  131. package/dist/runtime/background-sync.js.map +1 -1
  132. package/dist/runtime/cache.js +91 -3
  133. package/dist/runtime/cache.js.map +1 -1
  134. package/dist/runtime/client-injector-bundle.js +314 -0
  135. package/dist/runtime/client-injector-bundle.js.map +1 -0
  136. package/dist/runtime/client-injector.js +173 -30
  137. package/dist/runtime/client-injector.js.map +1 -1
  138. package/dist/runtime/connectivity-manager.js +83 -0
  139. package/dist/runtime/connectivity-manager.js.map +1 -0
  140. package/dist/runtime/connectivity.js +83 -0
  141. package/dist/runtime/connectivity.js.map +1 -0
  142. package/dist/runtime/fetch-wrapper.js +26 -59
  143. package/dist/runtime/fetch-wrapper.js.map +1 -1
  144. package/dist/runtime/gql-wrapper.js +15 -9
  145. package/dist/runtime/gql-wrapper.js.map +1 -1
  146. package/dist/runtime/invalidation-tags.js +12 -89
  147. package/dist/runtime/invalidation-tags.js.map +1 -1
  148. package/dist/runtime/mutation-queue.js +83 -31
  149. package/dist/runtime/mutation-queue.js.map +1 -1
  150. package/dist/runtime/mutation-state.js +3 -3
  151. package/dist/runtime/mutation-state.js.map +1 -1
  152. package/dist/runtime/notification.js +65 -0
  153. package/dist/runtime/notification.js.map +1 -0
  154. package/dist/runtime/open-db.js +41 -0
  155. package/dist/runtime/open-db.js.map +1 -0
  156. package/dist/runtime/push.js +15 -27
  157. package/dist/runtime/push.js.map +1 -1
  158. package/dist/runtime/pwa-injector.js +3 -32
  159. package/dist/runtime/pwa-injector.js.map +1 -1
  160. package/dist/runtime/pwa-prompt.js +35 -3
  161. package/dist/runtime/pwa-prompt.js.map +1 -1
  162. package/dist/runtime/reset.js +39 -42
  163. package/dist/runtime/reset.js.map +1 -1
  164. package/dist/runtime/server-push.js +23 -13
  165. package/dist/runtime/server-push.js.map +1 -1
  166. package/dist/runtime/storage.js +32 -0
  167. package/dist/runtime/storage.js.map +1 -0
  168. package/dist/runtime/sw-injector.js +19 -178
  169. package/dist/runtime/sw-injector.js.map +1 -1
  170. package/dist/runtime/sw-version.js +13 -0
  171. package/dist/runtime/sw-version.js.map +1 -0
  172. package/dist/runtime/swoff-api-bundle.js +1491 -0
  173. package/dist/runtime/swoff-api-bundle.js.map +1 -0
  174. package/dist/runtime/type-definitions.js +8 -7
  175. package/dist/runtime/type-definitions.js.map +1 -1
  176. package/dist/runtime/utils.js +4 -0
  177. package/dist/runtime/utils.js.map +1 -1
  178. package/dist/swoff-nkdhhmw8. +18 -0
  179. package/dist/swoff.js +5 -0
  180. package/package.json +1 -1
  181. package/templates/react/useAuth.jsx +7 -4
  182. package/templates/react/useAuth.tsx +14 -14
  183. package/templates/react/useBackgroundSync.jsx +5 -4
  184. package/templates/react/useBackgroundSync.tsx +5 -4
  185. package/templates/react/useCachedFetch.jsx +8 -0
  186. package/templates/react/useCachedFetch.tsx +8 -0
  187. package/templates/react/useMutation.jsx +60 -56
  188. package/templates/react/useMutation.tsx +65 -64
  189. package/templates/react/useMutationQueue.jsx +5 -1
  190. package/templates/react/useMutationQueue.tsx +8 -2
  191. package/templates/react/useMutationState.jsx +3 -4
  192. package/templates/react/useMutationState.tsx +4 -8
  193. package/templates/react/useNetworkStatus.jsx +57 -17
  194. package/templates/react/useNetworkStatus.tsx +42 -20
  195. package/templates/react/useOfflineAnalytics.jsx +42 -0
  196. package/templates/react/useOfflineAnalytics.tsx +50 -0
  197. package/templates/react/usePwaInstall.jsx +26 -0
  198. package/templates/react/usePwaInstall.tsx +26 -0
  199. package/templates/react/useSWUpdate.jsx +7 -52
  200. package/templates/react/useSWUpdate.tsx +12 -51
  201. package/templates/react/useStorageEstimate.jsx +56 -0
  202. package/templates/react/useStorageEstimate.tsx +67 -0
  203. package/dist/__tests__/assemble-sw.test.js +0 -145
  204. package/dist/__tests__/assemble-sw.test.js.map +0 -1
  205. package/dist/__tests__/cli-integration.test.js +0 -231
  206. package/dist/__tests__/cli-integration.test.js.map +0 -1
  207. package/dist/__tests__/config-types.test.js +0 -124
  208. package/dist/__tests__/config-types.test.js.map +0 -1
  209. package/dist/__tests__/detect-language.test.js +0 -51
  210. package/dist/__tests__/detect-language.test.js.map +0 -1
  211. package/dist/__tests__/file-generators.test.js +0 -228
  212. package/dist/__tests__/file-generators.test.js.map +0 -1
  213. package/dist/__tests__/glob-matcher.test.js +0 -86
  214. package/dist/__tests__/glob-matcher.test.js.map +0 -1
  215. package/dist/__tests__/invalidation-tags.test.js +0 -283
  216. package/dist/__tests__/invalidation-tags.test.js.map +0 -1
  217. package/dist/__tests__/loader.test.js +0 -77
  218. package/dist/__tests__/loader.test.js.map +0 -1
  219. package/dist/__tests__/validator.test.js +0 -340
  220. package/dist/__tests__/validator.test.js.map +0 -1
  221. package/templates/react/useCacheInvalidation.jsx +0 -19
  222. package/templates/react/useCacheInvalidation.tsx +0 -52
  223. package/templates/react/useIsFetching.jsx +0 -32
  224. package/templates/react/useIsFetching.tsx +0 -32
@@ -1,259 +1,177 @@
1
- import { T, R, PT, AS } from "./utils.js";
2
- function generateWithAuthHeaders(authType, ts) {
3
- const hd = T(ts, "Headers");
4
- const a = T(ts, "AuthData | null");
5
- switch (authType) {
6
- case "cookie":
7
- return `/** Inject auth headers. For cookie auth, credentials are handled via AUTH_WITH_CREDENTIALS. */
8
- export function withAuthHeaders(headers${hd}, _auth${a})${hd}{
9
- return headers;
10
- }`;
11
- case "bearer":
12
- return `/** Inject Bearer token into request headers. */
13
- export function withAuthHeaders(headers${hd}, auth${a})${hd}{
14
- if (auth?.token) {
15
- headers.set("Authorization", \`Bearer \${auth.token}\`);
16
- }
17
- return headers;
18
- }`;
19
- case "custom":
20
- return `/** Inject custom auth headers. Edit this function to match your backend. */
21
- export function withAuthHeaders(headers${hd}, auth${a})${hd}{
22
- // --- EDIT THIS BLOCK FOR YOUR BACKEND ---
23
- // if (auth?.token) {
24
- // headers.set("X-Auth-Token", auth.token);
25
- // }
26
- // --- END OF EDITABLE BLOCK ---
27
- return headers;
28
- }`;
29
- default:
30
- return `export function withAuthHeaders(headers${hd}, auth${a})${hd}{
31
- if (auth?.token) {
32
- headers.set("Authorization", \`Bearer \${auth.token}\`);
33
- }
34
- return headers;
35
- }`;
36
- }
37
- }
38
- function generateIsAuthUrl(refreshPath, userEndpoint, ts) {
39
- return `/** Check if a URL is an auth endpoint that should bypass the SW cache. */
40
- export function isAuthUrl(url${T(ts, "string")})${R(ts, "boolean")}{
41
- const authPaths = [
1
+ import { T, R, PT } from "./utils.js";
2
+ const DEFAULT_AUTH_ROUTES = [
42
3
  "/login",
43
4
  "/logout",
44
5
  "/register",
45
6
  "/api/login",
46
7
  "/api/logout",
47
8
  "/api/register",
48
- "${refreshPath}",
49
- "${userEndpoint}",
50
- ];
51
- return authPaths.some((path) => url.includes(path));
52
- }`;
53
- }
54
- function generateEnsureValidAuth(cookieAuth, ts, refreshPath, ext) {
55
- const tokenArg = cookieAuth ? "" : "auth?.token";
56
- return `/** Try to restore the session after page refresh — delegates to refreshSession() in ./user.${ext}. */
57
- let restorePromise${T(ts, "Promise<AuthData | null> | null")} = null;
58
-
59
- async function tryRestoreSession()${R(ts, "Promise<AuthData | null>")}{
60
- if (restorePromise) {
61
- try { return await restorePromise; } finally { restorePromise = null; }
62
- }
63
- restorePromise = (async () => {
64
- try {
65
- const response = await refreshSession();
66
- if (!response.ok) return null;
67
- const data = await response.json();
68
- const userData = await loadUserData();
69
- const auth = { ...userData, token: data.token, expiresAt: data.expiresAt };
70
- await setAuth(auth);
71
- return auth;
72
- } catch { return null; }
73
- })();
74
- try { return await restorePromise; } finally { restorePromise = null; }
75
- }
76
-
77
- let refreshPromise${T(ts, "Promise<AuthData | null> | null")} = null;
78
-
79
- export async function ensureValidAuth()${R(ts, "Promise<AuthData | null>")}{
80
- const auth = await getAuth();
81
- if (!auth) return null;
82
-
83
- // Token missing after page refresh — try silent session restoration
84
- if (!auth.token) {
85
- return tryRestoreSession();
86
- }
87
-
88
- if (!auth.expiresAt || Date.now() < auth.expiresAt) return auth;
89
-
90
- if (!refreshPromise) {
91
- refreshPromise = (async () => {
92
- try {
93
- const response = await refreshSession(${tokenArg});
94
- if (!response.ok) {
95
- await clearAuth();
96
- window.dispatchEvent(new CustomEvent("sw-auth-unauthorized"));
97
- return null;
98
- }
99
-
100
- const data = await response.json();
101
- const updated = { ...auth, token: data.token, expiresAt: data.expiresAt };
102
- await setAuth(updated);
103
- return updated;
104
- } catch {
105
- await clearAuth();
106
- window.dispatchEvent(new CustomEvent("sw-auth-unauthorized"));
107
- return null;
108
- }
109
- })();
110
- }
111
-
112
- try {
113
- return await refreshPromise;
114
- } finally {
115
- refreshPromise = null;
116
- }
117
- }`;
118
- }
119
- export function generateAuthStoreCode(ctx, authType, refreshPath, userEndpoint) {
9
+ "/api/refresh",
10
+ "/api/me",
11
+ ];
12
+ export function generateAuthStoreCode(ctx, authType, authRoutePaths = DEFAULT_AUTH_ROUTES, mutationQueueEnabled = false) {
120
13
  const { ext, ts } = ctx;
121
- const authDataInterface = ts
122
- ? `export interface AuthData {
123
- token?: string;
124
- user?: Record<string, unknown>;
125
- expiresAt?: number;
126
- }
127
-
128
- export interface AuthResponse extends Record<string, unknown> {
129
- // Uncomment and type the fields your backend's login response returns:
130
- // token: string;
131
- // user: Record<string, unknown>;
132
- // expiresAt?: number;
133
- }
134
-
135
- `
136
- : "";
137
- const createAuthFromResponseBlock = ts
138
- ? `/** Extract AuthData from your backend's login response. Edit this function to match your backend's response shape. */
139
- export function createAuthFromResponse(response: AuthResponse): AuthData {
140
- // --- EDIT THIS TO MATCH YOUR BACKEND ---
141
- const data = response as Record<string, unknown>;
142
- return {
143
- token: data.token as string,
144
- user: data.user as Record<string, unknown> | undefined,
145
- expiresAt: data.expiresAt as number | undefined,
146
- };
147
- // --- END OF EDITABLE BLOCK ---
148
- }
149
- `
150
- : `/** Extract AuthData from your backend's login response. Edit this function to match your backend's response shape. */
151
- export function createAuthFromResponse(response) {
152
- // --- EDIT THIS TO MATCH YOUR BACKEND ---
153
- return {
154
- token: response.token,
155
- user: response.user,
156
- expiresAt: response.expiresAt,
157
- };
158
- // --- END OF EDITABLE BLOCK ---
159
- }
160
- `;
14
+ const isCookie = authType === "cookie";
15
+ const cookieAuthComment = isCookie
16
+ ? ` *
17
+ * Cookie auth: the server manages the session. setAuth() stores user info
18
+ * for offline display. The browser sends the session cookie automatically.`
19
+ : ` *
20
+ * Bearer auth: token lives in memory only — cleared on page refresh.
21
+ * ensureValidAuth() calls adapter.refresh() when the token expires.
22
+ * Only { user, expiresAt } persists to IndexedDB for offline display.`;
161
23
  return `/**
162
- * Auth Store — Token in memory only; user info in IndexedDB for offline access.
24
+ * Auth Store — Token in memory only; user info in IndexedDB for offline access.${cookieAuthComment}
163
25
  *
164
- * Security:
165
- * The Bearer token lives in JavaScript memory and is cleared on page refresh.
166
- * Only { user, expiresAt } is persisted to IndexedDB so the app can display
167
- * user info offline. After a page refresh, re-login is required.
26
+ * Public API (functions listed here):
27
+ * setAuth, getAuth, clearAuth, clearMemoryAuth, isAuthValid,
28
+ * ensureValidAuth, withAuthHeaders,
29
+ * AUTH_WITH_CREDENTIALS, isAuthUrl
30
+ *
31
+ * Internal helpers (not exported — used by Swoff internally):
32
+ * persistUserData, loadUserData, clearPersistedData
168
33
  *
169
34
  * Usage:
170
- * import { setAuth, getAuth, clearAuth, isAuthValid } from "./auth/store.${ext}";
35
+ * import { setAuth, getAuth, clearAuth, clearMemoryAuth, isAuthValid, ensureValidAuth, withAuthHeaders } from "./auth/store.${ext}";
171
36
  *
172
- * await setAuth({ token, user, expiresAt });
37
+ * await setAuth({ user });
173
38
  * const auth = await getAuth();
174
39
  * await clearAuth();
40
+ * await clearMemoryAuth();
41
+ * await ensureValidAuth();
175
42
  */
176
43
 
177
- import { refreshSession } from "./user.${ext}";
44
+ import { adapter } from "./adapter.${ext}";
45
+ ${ts ? `import type { AuthData } from "./adapter.${ext}";` : ""}
46
+ import { openDB } from "../db.${ext}";
47
+ ${mutationQueueEnabled ? `import { clearQueue } from "../mutation/queue.${ext}";\n` : ""}
178
48
 
179
- ${authDataInterface}const DB_NAME = "swoff-auth";
49
+ const DB_NAME = "swoff-auth";
180
50
  const STORE_NAME = "auth";
181
- // Bump this when adding new indexes/stores for schema migration
182
- const DB_VERSION = 1;
183
-
184
51
  let memoryAuth${T(ts, "AuthData | null")} = null;
52
+ let _fetchingUser = false;
185
53
 
186
- ${createAuthFromResponseBlock}
187
- function openAuthDB()${R(ts, "Promise<IDBDatabase>")}{
188
- return new Promise${PT(ts, "IDBDatabase")}((resolve, reject) => {
189
- const request = indexedDB.open(DB_NAME, DB_VERSION);
190
- request.onupgradeneeded = (e) => {
191
- const db = (e.target${AS(ts, "IDBOpenDBRequest")}).result;
192
- if (!db.objectStoreNames.contains(STORE_NAME)) {
193
- db.createObjectStore(STORE_NAME, { keyPath: "key" });
194
- }
195
- };
196
- request.onsuccess = (e) => resolve((e.target${AS(ts, "IDBOpenDBRequest")}).result);
197
- request.onerror = (e) => reject((e.target${AS(ts, "IDBRequest")}).error);
198
- });
199
- }
54
+ // ── Internal: persistence helpers ────────────────────────────────────
200
55
 
201
56
  async function persistUserData(authData${T(ts, "AuthData | null")})${R(ts, "Promise<void>")}{
202
- // Only persist { user, expiresAt } — never the token
203
57
  const userData = { user: authData?.user, expiresAt: authData?.expiresAt };
204
- const db = await openAuthDB();
205
- return new Promise${PT(ts, "void")}((resolve, reject) => {
206
- const tx = db.transaction(STORE_NAME, "readwrite");
207
- const store = tx.objectStore(STORE_NAME);
208
- const request = store.put({ key: "session", value: userData });
209
- request.onsuccess = () => resolve();
210
- request.onerror = () => reject((request${AS(ts, "IDBRequest")}).error);
211
- });
58
+ const db = await openDB(DB_NAME, STORE_NAME, "key");
59
+ try {
60
+ await new Promise${PT(ts, "void")}((resolve, reject) => {
61
+ const tx = db.transaction(STORE_NAME, "readwrite");
62
+ const store = tx.objectStore(STORE_NAME);
63
+ const request = store.put({ key: "session", value: userData });
64
+ request.onsuccess = () => resolve();
65
+ request.onerror = () => reject(request.error);
66
+ });
67
+ } finally {
68
+ db.close();
69
+ }
212
70
  }
213
71
 
214
- async function loadUserData()${R(ts, "Promise<{ user?: Record<string, unknown>; expiresAt?: number } | null>")}{
215
- const db = await openAuthDB();
216
- return new Promise((resolve, reject) => {
217
- const tx = db.transaction(STORE_NAME, "readonly");
218
- const store = tx.objectStore(STORE_NAME);
219
- const request = store.get("session");
220
- request.onsuccess = () => resolve((request${AS(ts, "IDBRequest")}).result?.value ?? null);
221
- request.onerror = () => reject((request${AS(ts, "IDBRequest")}).error);
222
- });
72
+ async function loadUserData()${R(ts, "Promise<AuthData | null>")}{
73
+ const db = await openDB(DB_NAME, STORE_NAME, "key");
74
+ try {
75
+ return await new Promise((resolve, reject) => {
76
+ const tx = db.transaction(STORE_NAME, "readonly");
77
+ const store = tx.objectStore(STORE_NAME);
78
+ const request = store.get("session");
79
+ request.onsuccess = () => resolve(request.result?.value ?? null);
80
+ request.onerror = () => reject(request.error);
81
+ });
82
+ } finally {
83
+ db.close();
84
+ }
223
85
  }
224
86
 
225
87
  async function clearPersistedData()${R(ts, "Promise<void>")}{
226
- const db = await openAuthDB();
227
- return new Promise${PT(ts, "void")}((resolve, reject) => {
228
- const tx = db.transaction(STORE_NAME, "readwrite");
229
- const store = tx.objectStore(STORE_NAME);
230
- const request = store.delete("session");
231
- request.onsuccess = () => resolve();
232
- request.onerror = () => reject((request${AS(ts, "IDBRequest")}).error);
233
- });
88
+ const db = await openDB(DB_NAME, STORE_NAME, "key");
89
+ try {
90
+ await new Promise${PT(ts, "void")}((resolve, reject) => {
91
+ const tx = db.transaction(STORE_NAME, "readwrite");
92
+ const store = tx.objectStore(STORE_NAME);
93
+ const request = store.delete("session");
94
+ request.onsuccess = () => resolve();
95
+ request.onerror = () => reject(request.error);
96
+ });
97
+ } finally {
98
+ db.close();
99
+ }
234
100
  }
235
101
 
102
+ // ── Public API: auth data operations ─────────────────────────────────
103
+
236
104
  /** Store auth data in memory and persist user info to IndexedDB for offline access. */
237
105
  export async function setAuth(authData${T(ts, "AuthData")})${R(ts, "Promise<void>")}{
238
106
  memoryAuth = authData;
239
107
  await persistUserData(authData);
240
108
  }
241
109
 
242
- /** Get auth data from memory (or IndexedDB if memory is empty after page refresh). */
110
+ /** Get auth data from memory, then adapter, then IndexedDB fallback (user info only). */
243
111
  export async function getAuth()${R(ts, "Promise<AuthData | null>")}{
244
112
  if (memoryAuth) return memoryAuth;
245
113
 
114
+ // Try adapter first (for provider-managed auth like Better Auth)
115
+ try {
116
+ const adapterAuth = await adapter.getAuth();
117
+ if (adapterAuth) {
118
+ memoryAuth = adapterAuth;
119
+ await persistUserData(adapterAuth);
120
+ return memoryAuth;
121
+ }
122
+ // Adapter confirmed no session — don't fall through to stale IDB
123
+ return null;
124
+ } catch {
125
+ // Adapter error (network failure) — fall through to IndexedDB
126
+ }
127
+
128
+ // Fall back to IndexedDB user cache (only reached on adapter error)
246
129
  const userData = await loadUserData();
247
130
  if (userData) {
248
131
  memoryAuth = userData;
132
+ return memoryAuth;
249
133
  }
250
- return memoryAuth;
134
+
135
+ // Last resort — try server fetch
136
+ if (_fetchingUser) return null;
137
+ _fetchingUser = true;
138
+ try {
139
+ const fetched = await adapter.fetchUser();
140
+ if (fetched) {
141
+ memoryAuth = fetched;
142
+ await persistUserData(fetched);
143
+ return memoryAuth;
144
+ }
145
+ } catch {
146
+ // Server unreachable — no auth data available
147
+ } finally {
148
+ _fetchingUser = false;
149
+ }
150
+
151
+ return null;
152
+ }
153
+
154
+ /** Null memory auth only. Use for cross-tab sync — SW broadcasts AUTH_CLEARED, other tabs call this. */
155
+ export function clearMemoryAuth()${R(ts, "void")}{
156
+ memoryAuth = null;
251
157
  }
252
158
 
253
- /** Clear auth from memory and IndexedDB. Call on logout or 401. */
254
- export async function clearAuth()${R(ts, "Promise<void>")}{
159
+ /** Clear auth from memory, IndexedDB, runtime caches, and dispatch event. Sends AUTH_CLEARED to SW so other tabs clear memory too. Call once on logout. */
160
+ export async function clearAuth(options${T(ts, "{ broadcast?: boolean }")} = {})${R(ts, "Promise<void>")}{
161
+ if (options.broadcast !== false) {
162
+ navigator.serviceWorker.controller?.postMessage({ type: "AUTH_CLEARED" });
163
+ }
255
164
  memoryAuth = null;
256
165
  await clearPersistedData();
166
+ try {
167
+ const cacheNames = await caches.keys();
168
+ await Promise.all(
169
+ cacheNames
170
+ .filter(name => name.startsWith("swoff-runtime"))
171
+ .map(name => caches.delete(name))
172
+ );
173
+ } catch { /* caches API unavailable */ }
174
+ ${mutationQueueEnabled ? `await clearQueue();\n` : ""} window.dispatchEvent(new CustomEvent("sw-auth-state-change", { detail: { type: "clear" } }));
257
175
  }
258
176
 
259
177
  /** Check if auth exists and has not expired. Returns true if no expiresAt is set. */
@@ -263,11 +181,99 @@ export function isAuthValid(auth${T(ts, "AuthData | null")})${R(ts, "boolean")}{
263
181
  return Date.now() < auth.expiresAt;
264
182
  }
265
183
 
266
- ${authType === "cookie" ? `export const AUTH_WITH_CREDENTIALS = true;` : `export const AUTH_WITH_CREDENTIALS = false;`}
184
+ // ── Public API: adapter-delegated ────────────────────────────────────
185
+
186
+ /** Whether to use credentials: "include" for fetch requests. True for cookie-based auth. */
187
+ export const AUTH_WITH_CREDENTIALS = adapter.type === "cookie";
188
+
189
+ /** Inject auth headers into a Headers object. Delegates to the auth adapter. */
190
+ export function withAuthHeaders(headers${T(ts, "Headers")}, auth${T(ts, "AuthData | null")})${R(ts, "Headers")}{
191
+ const adapterHeaders = adapter.getHeaders(auth);
192
+ for (const [key, value] of Object.entries(adapterHeaders)) {
193
+ headers.set(key, value);
194
+ }
195
+ return headers;
196
+ }
197
+
198
+ /** Check if a URL is an auth endpoint that should bypass the SW cache. */
199
+ export function isAuthUrl(url${T(ts, "string")})${R(ts, "boolean")}{
200
+ var urlPath = url.indexOf("://") !== -1 ? new URL(url).pathname.replace(/\/$/, "") : url.replace(/\/$/, "");
201
+ return ${JSON.stringify(authRoutePaths)}.some(function(path) { return urlPath === path; });
202
+ }
203
+
204
+ // ── Public API: session refresh ──────────────────────────────────────
205
+
206
+ ${isCookie
207
+ ? `
208
+ /**
209
+ * Cookie auth: the server manages the session. No token to restore or refresh.
210
+ * The browser sends the session cookie automatically.
211
+ * getAuth() + IndexedDB user cache provides offline access.
212
+ */
213
+ export async function ensureValidAuth()${R(ts, "Promise<AuthData | null>")}{
214
+ return getAuth();
215
+ }
216
+ `
217
+ : `
218
+ /** Try to restore session after page refresh. Delegates to adapter.refresh(). */
219
+ async function tryRestoreSession()${R(ts, "Promise<AuthData | null>")}{
220
+ try {
221
+ const auth = await getAuth();
222
+ if (!auth) return null;
223
+ const refreshed = await adapter.refresh(auth);
224
+ if (refreshed) {
225
+ await setAuth(refreshed);
226
+ return refreshed;
227
+ }
228
+ return null;
229
+ } catch { return null; }
230
+ }
231
+
232
+ let restorePromise${T(ts, "Promise<AuthData | null> | null")} = null;
233
+ let refreshPromise${T(ts, "Promise<AuthData | null> | null")} = null;
234
+
235
+ /**
236
+ * Bearer auth: token expires — try silent refresh via adapter.refresh().
237
+ * If refresh fails, auth is cleared and sw-auth-unauthorized is dispatched.
238
+ */
239
+ export async function ensureValidAuth()${R(ts, "Promise<AuthData | null>")}{
240
+ const auth = await getAuth();
241
+ if (!auth) return null;
242
+
243
+ // No token after page refresh — try silent session restoration
244
+ if (!auth.token) {
245
+ if (restorePromise) {
246
+ try { return await restorePromise; } finally { restorePromise = null; }
247
+ }
248
+ restorePromise = tryRestoreSession();
249
+ try { return await restorePromise; } finally { restorePromise = null; }
250
+ }
251
+
252
+ // Not expired yet
253
+ if (!auth.expiresAt || Date.now() < auth.expiresAt) return auth;
254
+
255
+ // Token expired — try refresh via adapter
256
+ if (!refreshPromise) {
257
+ refreshPromise = (async () => {
258
+ try {
259
+ const refreshed = await adapter.refresh(auth);
260
+ if (refreshed) {
261
+ await setAuth(refreshed);
262
+ return refreshed;
263
+ }
264
+ await clearAuth();
265
+ return null;
266
+ } catch {
267
+ await clearAuth();
268
+ return null;
269
+ }
270
+ })();
271
+ }
272
+
273
+ try { return await refreshPromise; } finally { refreshPromise = null; }
274
+ }
275
+ `}
267
276
 
268
- ${generateWithAuthHeaders(authType, ts)}
269
- ${generateIsAuthUrl(refreshPath, userEndpoint, ts)}
270
- ${generateEnsureValidAuth(authType === "cookie", ts, refreshPath, ext)}
271
277
  `;
272
278
  }
273
279
  //# sourceMappingURL=auth-store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth-store.js","sourceRoot":"","sources":["../../src/runtime/auth-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth-store.js","sourceRoot":"","sources":["../../src/runtime/auth-store.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAEtC,MAAM,mBAAmB,GAAG;IAC1B,QAAQ;IACR,SAAS;IACT,WAAW;IACX,YAAY;IACZ,aAAa;IACb,eAAe;IACf,cAAc;IACd,SAAS;CACV,CAAC;AAEF,MAAM,UAAU,qBAAqB,CACnC,GAAmB,EACnB,QAAgB,EAChB,iBAA2B,mBAAmB,EAC9C,uBAAgC,KAAK;IAErC,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC;IACxB,MAAM,QAAQ,GAAG,QAAQ,KAAK,QAAQ,CAAC;IAEvC,MAAM,iBAAiB,GAAG,QAAQ;QAChC,CAAC,CAAC;;4EAEsE;QACxE,CAAC,CAAC;;;uEAGiE,CAAC;IAEtE,OAAO;kFACyE,iBAAiB;;;;;;;;;;;iIAW8B,GAAG;;;;;;;;;qCAS/F,GAAG;EACtC,EAAE,CAAC,CAAC,CAAC,4CAA4C,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE;gCAC/B,GAAG;EACjC,oBAAoB,CAAC,CAAC,CAAC,iDAAiD,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE;;;;gBAIxE,CAAC,CAAC,EAAE,EAAE,iBAAiB,CAAC;;;;;yCAKC,CAAC,CAAC,EAAE,EAAE,iBAAiB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;uBAIpE,EAAE,CAAC,EAAE,EAAE,MAAM,CAAC;;;;;;;;;;;;+BAYN,CAAC,CAAC,EAAE,EAAE,0BAA0B,CAAC;;;;;;;;;;;;;;;qCAe3B,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;uBAGpC,EAAE,CAAC,EAAE,EAAE,MAAM,CAAC;;;;;;;;;;;;;;;wCAeG,CAAC,CAAC,EAAE,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;;;iCAMlD,CAAC,CAAC,EAAE,EAAE,0BAA0B,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mCA4C/B,CAAC,CAAC,EAAE,EAAE,MAAM,CAAC;;;;;yCAKP,CAAC,CAAC,EAAE,EAAE,yBAAyB,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;;;;;;;;;;;IAcpG,oBAAoB,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,EAAE;;;;kCAIrB,CAAC,CAAC,EAAE,EAAE,iBAAiB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC;;;;;;;;;;;;yCAYrC,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,iBAAiB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC;;;;;;;;;+BAS/E,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC;;WAEvD,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC;;;;;EAMvC,QAAQ;QACN,CAAC,CAAC;;;;;;yCAMmC,CAAC,CAAC,EAAE,EAAE,0BAA0B,CAAC;;;CAGzE;QACG,CAAC,CAAC;;oCAE8B,CAAC,CAAC,EAAE,EAAE,0BAA0B,CAAC;;;;;;;;;;;;;oBAajD,CAAC,CAAC,EAAE,EAAE,iCAAiC,CAAC;oBACxC,CAAC,CAAC,EAAE,EAAE,iCAAiC,CAAC;;;;;;yCAMnB,CAAC,CAAC,EAAE,EAAE,0BAA0B,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqC1E;;CAEC,CAAC;AACF,CAAC"}
@@ -68,24 +68,10 @@ export function generateAuthUserCode(ctx, refreshPath, userEndpoint, authType) {
68
68
 
69
69
  import { API_BASE } from "../config.${ext}";
70
70
 
71
+ import { openDB } from "../db.${ext}";
72
+
71
73
  const DB_NAME = "swoff-auth-user";
72
74
  const STORE_NAME = "current-user";
73
- // Bump this when adding new indexes/stores for schema migration
74
- const DB_VERSION = 1;
75
-
76
- function openAuthDB()${R(ts, "Promise<IDBDatabase>")}{
77
- return new Promise${PT(ts, "IDBDatabase")}((resolve, reject) => {
78
- const request = indexedDB.open(DB_NAME, DB_VERSION);
79
- request.onupgradeneeded = (e) => {
80
- const db = (e.target${AS(ts, "IDBOpenDBRequest")}).result;
81
- if (!db.objectStoreNames.contains(STORE_NAME)) {
82
- db.createObjectStore(STORE_NAME, { keyPath: "key" });
83
- }
84
- };
85
- request.onsuccess = (e) => resolve((e.target${AS(ts, "IDBOpenDBRequest")}).result);
86
- request.onerror = (e) => reject((e.target${AS(ts, "IDBRequest")}).error);
87
- });
88
- }
89
75
 
90
76
  /**
91
77
  * Refresh the auth session.
@@ -130,7 +116,7 @@ export async function fetchCurrentUser()${R(ts, "Promise<Record<string, unknown>
130
116
 
131
117
  /** Persist user data to IndexedDB for offline access. */
132
118
  export async function cacheUser(user${T(ts, "Record<string, unknown>")})${R(ts, "Promise<void>")}{
133
- const db = await openAuthDB();
119
+ const db = await openDB(DB_NAME, STORE_NAME, "key");
134
120
  return new Promise<void>((resolve, reject) => {
135
121
  const tx = db.transaction(STORE_NAME, "readwrite");
136
122
  const store = tx.objectStore(STORE_NAME);
@@ -142,7 +128,7 @@ export async function cacheUser(user${T(ts, "Record<string, unknown>")})${R(ts,
142
128
 
143
129
  /** Load user data from IndexedDB cache (no token — only user object survives refresh). */
144
130
  export async function getCachedUser()${R(ts, "Promise<Record<string, unknown> | null>")}{
145
- const db = await openAuthDB();
131
+ const db = await openDB(DB_NAME, STORE_NAME, "key");
146
132
  return new Promise${PT(ts, "Record<string, unknown> | null")}((resolve, reject) => {
147
133
  const tx = db.transaction(STORE_NAME, "readonly");
148
134
  const store = tx.objectStore(STORE_NAME);
@@ -154,7 +140,7 @@ export async function getCachedUser()${R(ts, "Promise<Record<string, unknown> |
154
140
 
155
141
  /** Remove user data from IndexedDB cache. Call on logout. */
156
142
  export async function clearCachedUser()${R(ts, "Promise<void>")}{
157
- const db = await openAuthDB();
143
+ const db = await openDB(DB_NAME, STORE_NAME, "key");
158
144
  return new Promise${PT(ts, "void")}((resolve, reject) => {
159
145
  const tx = db.transaction(STORE_NAME, "readwrite");
160
146
  const store = tx.objectStore(STORE_NAME);
@@ -1 +1 @@
1
- {"version":3,"file":"auth-user.js","sourceRoot":"","sources":["../../src/runtime/auth-user.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,UAAU,oBAAoB,CAClC,GAAmB,EACnB,WAAmB,EACnB,YAAoB,EACpB,QAAgB;IAEhB,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC;IACxB,MAAM,UAAU,GAAG,QAAQ,KAAK,QAAQ,CAAC;IACzC,MAAM,YAAY,GAAG,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;IAEtD,MAAM,WAAW,GAAG,UAAU;QAC5B,CAAC,CAAC;;;;;;;sBAOgB;QAClB,CAAC,CAAC;;;;;;;;yEAQmE,CAAC;IAExE,MAAM,QAAQ,GAAG,UAAU;QACzB,CAAC,CAAC;;;;;;;WAOK;QACP,CAAC,CAAC;;;0CAGoC,GAAG;;kDAEK,YAAY;;;+EAGiB,CAAC;IAE9E,OAAO;;;;;;;mEAO0D,GAAG;;;;gHAI0C,GAAG;;;;;;;;;;;;;;;;sCAgB7E,GAAG;;;;;;;uBAOlB,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;;;;;;;;;;KAU9D,YAAY,aAAa,WAAW;;KAEpC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,sFAAsF;;;;uCAItE,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,GAAC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,mBAAmB,CAAC;IAC1G,UAAU;QACV,CAAC,CAAC,4BAA4B,WAAW;;;MAGvC;QACF,CAAC,CAAC,gBAAgB,CAAC,CAAC,EAAE,EAAE,wBAAwB,CAAC;;6BAExB,WAAW;;;MAGlC;;;KAGD,QAAQ;;0CAE6B,CAAC,CAAC,EAAE,EAAE,kCAAkC,CAAC;IAC/E,UAAU;QACV,CAAC,CAAC,4CAA4C,YAAY;;MAExD;QACF,CAAC,CAAC,4CAA4C,YAAY,KAAK;;;;;;;;;sCAS7B,CAAC,CAAC,EAAE,EAAE,yBAAyB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;;;;;;;;;uCAYzD,CAAC,CAAC,EAAE,EAAE,yCAAyC,CAAC;;sBAEjE,EAAE,CAAC,EAAE,EAAE,gCAAgC,CAAC;;;;gDAId,EAAE,CAAC,EAAE,EAAE,YAAY,CAAC;6CACvB,EAAE,CAAC,EAAE,EAAE,YAAY,CAAC;;;;;yCAKxB,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;sBAEzC,EAAE,CAAC,EAAE,EAAE,MAAM,CAAC;;;;;mCAKD,EAAE,CAAC,EAAE,EAAE,gBAAgB,CAAC;;;CAG1D,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"auth-user.js","sourceRoot":"","sources":["../../src/runtime/auth-user.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,UAAU,oBAAoB,CAClC,GAAmB,EACnB,WAAmB,EACnB,YAAoB,EACpB,QAAgB;IAEhB,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC;IACxB,MAAM,UAAU,GAAG,QAAQ,KAAK,QAAQ,CAAC;IACzC,MAAM,YAAY,GAAG,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;IAEtD,MAAM,WAAW,GAAG,UAAU;QAC5B,CAAC,CAAC;;;;;;;sBAOgB;QAClB,CAAC,CAAC;;;;;;;;yEAQmE,CAAC;IAExE,MAAM,QAAQ,GAAG,UAAU;QACzB,CAAC,CAAC;;;;;;;WAOK;QACP,CAAC,CAAC;;;0CAGoC,GAAG;;kDAEK,YAAY;;;+EAGiB,CAAC;IAE9E,OAAO;;;;;;;mEAO0D,GAAG;;;;gHAI0C,GAAG;;;;;;;;;;;;;;;;sCAgB7E,GAAG;;gCAET,GAAG;;;;;;;;;;;KAW9B,YAAY,aAAa,WAAW;;KAEpC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,sFAAsF;;;;uCAItE,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,GAAC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,mBAAmB,CAAC;IAC1G,UAAU;QACV,CAAC,CAAC,4BAA4B,WAAW;;;MAGvC;QACF,CAAC,CAAC,gBAAgB,CAAC,CAAC,EAAE,EAAE,wBAAwB,CAAC;;6BAExB,WAAW;;;MAGlC;;;KAGD,QAAQ;;0CAE6B,CAAC,CAAC,EAAE,EAAE,kCAAkC,CAAC;IAC/E,UAAU;QACV,CAAC,CAAC,4CAA4C,YAAY;;MAExD;QACF,CAAC,CAAC,4CAA4C,YAAY,KAAK;;;;;;;;;sCAS7B,CAAC,CAAC,EAAE,EAAE,yBAAyB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;;;;;;;;;uCAYzD,CAAC,CAAC,EAAE,EAAE,yCAAyC,CAAC;;sBAEjE,EAAE,CAAC,EAAE,EAAE,gCAAgC,CAAC;;;;gDAId,EAAE,CAAC,EAAE,EAAE,YAAY,CAAC;6CACvB,EAAE,CAAC,EAAE,EAAE,YAAY,CAAC;;;;;yCAKxB,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;sBAEzC,EAAE,CAAC,EAAE,EAAE,MAAM,CAAC;;;;;mCAKD,EAAE,CAAC,EAAE,EAAE,gBAAgB,CAAC;;;CAG1D,CAAC;AACF,CAAC"}
@@ -14,7 +14,6 @@ export function generateBackgroundSyncCode(ctx) {
14
14
  * url: "/api/todos",
15
15
  * body: { title: "Grocery" },
16
16
  * tags: ["todos"],
17
- * tags: ["todos"],
18
17
  * });
19
18
  */
20
19
 
@@ -44,6 +43,10 @@ export async function syncWhenPossible(mutation${T(ts, "object")})${R(ts, "Promi
44
43
 
45
44
  /** Re-register a background sync if mutations are still pending. Called automatically after each sync cycle. */
46
45
  export async function retrySync()${R(ts, "Promise<void>")}{
46
+ // Re-register self-cleaning listener for next cycle
47
+ if (typeof window !== "undefined") {
48
+ window.addEventListener("mutation-sync-complete", retrySync, { once: true });
49
+ }
47
50
  if (!("serviceWorker" in navigator) || !("SyncManager" in window)) return;
48
51
  const count = await getPendingCount();
49
52
  if (count > 0) {
@@ -52,7 +55,7 @@ export async function retrySync()${R(ts, "Promise<void>")}{
52
55
  }
53
56
 
54
57
  if (typeof window !== "undefined") {
55
- window.addEventListener("mutation-sync-complete", retrySync);
58
+ window.addEventListener("mutation-sync-complete", retrySync, { once: true });
56
59
  }
57
60
  `;
58
61
  }
@@ -1 +1 @@
1
- {"version":3,"file":"background-sync.js","sourceRoot":"","sources":["../../src/runtime/background-sync.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;AAElC,MAAM,UAAU,0BAA0B,CAAC,GAAmB;IAC5D,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC;IACxB,OAAO;;;;;;iEAMwD,GAAG;;;;;;;;;;;gFAWY,GAAG;;;;+BAIpD,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;;;;;;;;;;;;iDAeJ,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;;;mCAMvD,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;;;;;;;;CAWxD,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"background-sync.js","sourceRoot":"","sources":["../../src/runtime/background-sync.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;AAElC,MAAM,UAAU,0BAA0B,CAAC,GAAmB;IAC5D,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC;IACxB,OAAO;;;;;;iEAMwD,GAAG;;;;;;;;;;gFAUY,GAAG;;;;+BAIpD,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;;;;;;;;;;;;iDAeJ,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;;;mCAMvD,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC;;;;;;;;;;;;;;;CAexD,CAAC;AACF,CAAC"}