@swoff/cli 0.3.5 → 0.3.6

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 (91) hide show
  1. package/README.md +327 -25
  2. package/dist/__tests__/assemble-sw.test.js +15 -1
  3. package/dist/__tests__/assemble-sw.test.js.map +1 -1
  4. package/dist/__tests__/cli-integration.test.js +9 -8
  5. package/dist/__tests__/cli-integration.test.js.map +1 -1
  6. package/dist/__tests__/config-types.test.js +6 -6
  7. package/dist/__tests__/config-types.test.js.map +1 -1
  8. package/dist/__tests__/file-generators.test.js +67 -59
  9. package/dist/__tests__/file-generators.test.js.map +1 -1
  10. package/dist/__tests__/loader.test.js +12 -13
  11. package/dist/__tests__/loader.test.js.map +1 -1
  12. package/dist/__tests__/validator.test.js +41 -21
  13. package/dist/__tests__/validator.test.js.map +1 -1
  14. package/dist/index.js +1 -1
  15. package/dist/index.js.map +1 -1
  16. package/dist/lib/cli/help.js +3 -3
  17. package/dist/lib/cli/help.js.map +1 -1
  18. package/dist/lib/commands/add.js +7 -1
  19. package/dist/lib/commands/add.js.map +1 -1
  20. package/dist/lib/commands/clean.js +5 -0
  21. package/dist/lib/commands/clean.js.map +1 -1
  22. package/dist/lib/commands/generate-guide.js +12 -9
  23. package/dist/lib/commands/generate-guide.js.map +1 -1
  24. package/dist/lib/commands/generate.js +7 -3
  25. package/dist/lib/commands/generate.js.map +1 -1
  26. package/dist/lib/commands/info.js +135 -32
  27. package/dist/lib/commands/info.js.map +1 -1
  28. package/dist/lib/commands/validate.js +3 -1
  29. package/dist/lib/commands/validate.js.map +1 -1
  30. package/dist/lib/config/validator.js +25 -16
  31. package/dist/lib/config/validator.js.map +1 -1
  32. package/dist/lib/generators/file-generators/auth-fetch.js +29 -34
  33. package/dist/lib/generators/file-generators/auth-fetch.js.map +1 -1
  34. package/dist/lib/generators/file-generators/auth-state.js +8 -5
  35. package/dist/lib/generators/file-generators/auth-state.js.map +1 -1
  36. package/dist/lib/generators/file-generators/auth-store.js +71 -40
  37. package/dist/lib/generators/file-generators/auth-store.js.map +1 -1
  38. package/dist/lib/generators/file-generators/auth-user.js +27 -31
  39. package/dist/lib/generators/file-generators/auth-user.js.map +1 -1
  40. package/dist/lib/generators/file-generators/background-sync.js +9 -5
  41. package/dist/lib/generators/file-generators/background-sync.js.map +1 -1
  42. package/dist/lib/generators/file-generators/cache.js +7 -2
  43. package/dist/lib/generators/file-generators/cache.js.map +1 -1
  44. package/dist/lib/generators/file-generators/client-injector.js +113 -0
  45. package/dist/lib/generators/file-generators/client-injector.js.map +1 -0
  46. package/dist/lib/generators/file-generators/context.js +7 -6
  47. package/dist/lib/generators/file-generators/context.js.map +1 -1
  48. package/dist/lib/generators/file-generators/fetch-wrapper.js +170 -40
  49. package/dist/lib/generators/file-generators/fetch-wrapper.js.map +1 -1
  50. package/dist/lib/generators/file-generators/generate-hooks.js +61 -3
  51. package/dist/lib/generators/file-generators/generate-hooks.js.map +1 -1
  52. package/dist/lib/generators/file-generators/guide-generator.js +333 -0
  53. package/dist/lib/generators/file-generators/guide-generator.js.map +1 -0
  54. package/dist/lib/generators/file-generators/invalidation-tags.js +12 -10
  55. package/dist/lib/generators/file-generators/invalidation-tags.js.map +1 -1
  56. package/dist/lib/generators/file-generators/mutation-queue.js +34 -84
  57. package/dist/lib/generators/file-generators/mutation-queue.js.map +1 -1
  58. package/dist/lib/generators/file-generators/mutation-reconcile.js +57 -0
  59. package/dist/lib/generators/file-generators/mutation-reconcile.js.map +1 -0
  60. package/dist/lib/generators/file-generators/pwa-install.js +41 -9
  61. package/dist/lib/generators/file-generators/pwa-install.js.map +1 -1
  62. package/dist/lib/generators/file-generators/quick-readme.js +78 -0
  63. package/dist/lib/generators/file-generators/quick-readme.js.map +1 -0
  64. package/dist/lib/generators/file-generators/reconcile.js +7 -12
  65. package/dist/lib/generators/file-generators/reconcile.js.map +1 -1
  66. package/dist/lib/generators/file-generators/store.js +30 -20
  67. package/dist/lib/generators/file-generators/store.js.map +1 -1
  68. package/dist/lib/generators/file-generators/sw-generator-build.js +37 -16
  69. package/dist/lib/generators/file-generators/sw-generator-build.js.map +1 -1
  70. package/dist/lib/generators/file-generators/sw-injector.js +81 -110
  71. package/dist/lib/generators/file-generators/sw-injector.js.map +1 -1
  72. package/dist/lib/generators/file-generators/sw-template.js +1 -1
  73. package/dist/lib/generators/file-generators/type-definitions.js +33 -10
  74. package/dist/lib/generators/file-generators/type-definitions.js.map +1 -1
  75. package/dist/lib/generators/sw-generator.js +19 -10
  76. package/dist/lib/generators/sw-generator.js.map +1 -1
  77. package/dist/lib/generators/sw-sections/assemble-sw.js +32 -12
  78. package/dist/lib/generators/sw-sections/assemble-sw.js.map +1 -1
  79. package/dist/lib/generators/sw-sections/config-header.js +1 -1
  80. package/dist/lib/generators/sw-sections/config-header.js.map +1 -1
  81. package/dist/lib/generators/sw-sections/fetch-handler.js +25 -10
  82. package/dist/lib/generators/sw-sections/fetch-handler.js.map +1 -1
  83. package/dist/lib/generators/sw-sections/tag-management.js +25 -5
  84. package/dist/lib/generators/sw-sections/tag-management.js.map +1 -1
  85. package/dist/lib/generators/swoff-files-generator.js +7 -5
  86. package/dist/lib/generators/swoff-files-generator.js.map +1 -1
  87. package/dist/lib/shared/config-types.js +21 -6
  88. package/dist/lib/shared/config-types.js.map +1 -1
  89. package/dist/lib/utils/build-script.js +35 -0
  90. package/dist/lib/utils/build-script.js.map +1 -0
  91. package/package.json +1 -1
@@ -1,34 +1,33 @@
1
1
  /**
2
- * Generates auth-fetch.ts/js — config-driven authenticated fetch wrapper.
3
- * Uses auth config to generate appropriate withAuthHeaders() and isAuthUrl().
2
+ * Generates auth-fetch.ts/js — thin auth wrapper around fetchWithCache.
4
3
  */
5
4
  import { writeFile } from "./context.js";
6
5
  export function generateAuthFetch(ctx) {
7
6
  const ext = ctx.ext;
7
+ const ts = ext === "ts";
8
+ const T = (type) => (ts ? `: ${type}` : "");
9
+ const R = (type) => (ts ? `: ${type} ` : " ");
8
10
  const authConfig = ctx.config.features.auth;
9
11
  const { refreshPath, userEndpoint, type } = authConfig;
10
12
  function generateWithAuthHeaders() {
13
+ const a = T("AuthData | null");
14
+ const h = T("Headers");
15
+ const hd = T("Headers");
11
16
  switch (type) {
12
17
  case "cookie":
13
- return `function withAuthHeaders(headers, _auth) {
14
- // Cookie/Session auth — browser auto-sends cookies.
15
- // No header modification needed.
18
+ return `function withAuthHeaders(headers${hd}, _auth${a})${h}{
16
19
  return headers;
17
20
  }`;
18
21
  case "bearer":
19
- return `function withAuthHeaders(headers, auth) {
20
- // --- EDIT THIS BLOCK FOR YOUR BACKEND ---
21
- // JWT Bearer token:
22
+ return `function withAuthHeaders(headers${hd}, auth${a})${h}{
22
23
  if (auth?.token) {
23
24
  headers.set("Authorization", \`Bearer \${auth.token}\`);
24
25
  }
25
- // --- END OF EDITABLE BLOCK ---
26
26
  return headers;
27
27
  }`;
28
28
  case "custom":
29
- return `function withAuthHeaders(headers, auth) {
29
+ return `function withAuthHeaders(headers${hd}, auth${a})${h}{
30
30
  // --- EDIT THIS BLOCK FOR YOUR BACKEND ---
31
- // Custom header (e.g., X-API-Key, X-Auth-Token):
32
31
  // if (auth?.token) {
33
32
  // headers.set("X-Auth-Token", auth.token);
34
33
  // }
@@ -36,30 +35,32 @@ export function generateAuthFetch(ctx) {
36
35
  return headers;
37
36
  }`;
38
37
  default:
39
- return `function withAuthHeaders(headers, auth) {
40
- // --- EDIT THIS BLOCK FOR YOUR BACKEND ---
38
+ return `function withAuthHeaders(headers${hd}, auth${a})${h}{
41
39
  if (auth?.token) {
42
40
  headers.set("Authorization", \`Bearer \${auth.token}\`);
43
41
  }
44
- // --- END OF EDITABLE BLOCK ---
45
42
  return headers;
46
43
  }`;
47
44
  }
48
45
  }
49
46
  const credentialsLine = type === "cookie"
50
- ? `const fetchOptions = { ...options, headers, credentials: "include" };`
51
- : `const fetchOptions = { ...options, headers };`;
47
+ ? ` const fetchOptions = { ...options, headers, credentials: "include" };`
48
+ : ` const fetchOptions = { ...options, headers };`;
52
49
  const code = `/**
53
- * Auth-Aware Fetch — attaches auth headers, excludes auth endpoints from cache,
54
- * and handles 401 responses.
50
+ * Auth-Fetch — attaches auth headers, excludes auth endpoints from cache,
51
+ * and handles 401 responses. Thin wrapper around fetchWithCache.
55
52
  *
56
53
  * Usage:
57
- * import { authenticatedFetch } from "./auth-fetch.${ext}";
54
+ * import { authenticatedFetch } from "./auth/fetch.${ext}";
58
55
  * const data = await authenticatedFetch("/api/data").then((r) => r.json());
56
+ *
57
+ * Or use fetchWithCache directly:
58
+ * import { fetchWithCache } from "../fetch-wrapper.${ext}";
59
+ * const data = await fetchWithCache("/api/me", { auth: true });
59
60
  */
60
61
 
61
- import { fetchWithCache } from "./fetch-wrapper.${ext}";
62
- import { getAuth, setAuth, clearAuth } from "./auth-store.${ext}";
62
+ import { fetchWithCache } from "../fetch-wrapper.${ext}";
63
+ import { getAuth, setAuth, clearAuth${ts ? ", type AuthData" : ""} } from "./store.${ext}";
63
64
 
64
65
  ${generateWithAuthHeaders()}
65
66
 
@@ -67,7 +68,7 @@ ${generateWithAuthHeaders()}
67
68
  * Auth endpoints that should never be cached by the SW.
68
69
  * Edit this list to match your backend's auth routes.
69
70
  */
70
- function isAuthUrl(url) {
71
+ function isAuthUrl(url${T("string")})${R("boolean")}{
71
72
  const authPaths = [
72
73
  "/login",
73
74
  "/logout",
@@ -81,18 +82,13 @@ function isAuthUrl(url) {
81
82
  return authPaths.some((path) => url.includes(path));
82
83
  }
83
84
 
84
- /**
85
- * Auth-aware fetch wrapper.
86
- * Attaches identity, excludes auth endpoints from cache, handles 401.
87
- */
88
- export async function authenticatedFetch(input, options = {}) {
85
+ /** Auth-aware fetch. Delegates to fetchWithCache with auth headers, cache bypass for auth endpoints, and 401 handling. */
86
+ export async function authenticatedFetch(input${T("RequestInfo")}, options${T("RequestInit")} = {})${R("Promise<Response>")}{
89
87
  const auth = await getAuth();
90
88
  const headers = new Headers(options.headers);
91
89
 
92
- // Attach auth headers (your backend determines how)
93
90
  withAuthHeaders(headers, auth);
94
91
 
95
- // Determine if this is an auth endpoint (login, logout, refresh)
96
92
  const url = typeof input === "string" ? input : input.url;
97
93
 
98
94
  // Mark auth endpoints as mutation to bypass SW cache
@@ -101,7 +97,7 @@ export async function authenticatedFetch(input, options = {}) {
101
97
  }
102
98
 
103
99
  ${credentialsLine}
104
- const response = await fetchWithCache(input, fetchOptions);
100
+ const { response } = await fetchWithCache(input, fetchOptions);
105
101
 
106
102
  // Handle 401 — auth expired or invalidated server-side
107
103
  if (response.status === 401) {
@@ -116,14 +112,13 @@ export async function authenticatedFetch(input, options = {}) {
116
112
  * Token refresh helper — called before requests when token may be expired.
117
113
  * Uses refreshPath from config.
118
114
  */
119
- let refreshPromise = null;
115
+ let refreshPromise${T("Promise<AuthData | null> | null")} = null;
120
116
 
121
- export async function ensureValidAuth() {
117
+ export async function ensureValidAuth()${R("Promise<AuthData | null>")}{
122
118
  const auth = await getAuth();
123
119
  if (!auth) return null;
124
120
  if (!auth.expiresAt || Date.now() < auth.expiresAt) return auth;
125
121
 
126
- // Token expired — refresh it (deduplicated)
127
122
  if (!refreshPromise) {
128
123
  refreshPromise = (async () => {
129
124
  const response = await authenticatedFetch("${refreshPath}", {
@@ -151,6 +146,6 @@ export async function ensureValidAuth() {
151
146
  }
152
147
  }
153
148
  `;
154
- writeFile(ctx, `auth-fetch.${ext}`, code);
149
+ writeFile(ctx, `auth/fetch.${ext}`, code);
155
150
  }
156
151
  //# sourceMappingURL=auth-fetch.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth-fetch.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/auth-fetch.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,iBAAiB,CAAC,GAAqB;IACrD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;IAC5C,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,IAAI,EAAE,GAAG,UAAU,CAAC;IAEvD,SAAS,uBAAuB;QAC9B,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,QAAQ;gBACX,OAAO;;;;EAIb,CAAC;YACG,KAAK,QAAQ;gBACX,OAAO;;;;;;;;EAQb,CAAC;YACG,KAAK,QAAQ;gBACX,OAAO;;;;;;;;EAQb,CAAC;YACG;gBACE,OAAO;;;;;;;EAOb,CAAC;QACC,CAAC;IACH,CAAC;IAED,MAAM,eAAe,GACnB,IAAI,KAAK,QAAQ;QACf,CAAC,CAAC,uEAAuE;QACzE,CAAC,CAAC,+CAA+C,CAAC;IAEtD,MAAM,IAAI,GAAG;;;;;wDAKyC,GAAG;;;;kDAIT,GAAG;4DACO,GAAG;;EAE7D,uBAAuB,EAAE;;;;;;;;;;;;;;OAcpB,WAAW;OACX,YAAY;;;;;;;;;;;;;;;;;;;;;;;;IAwBf,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;mDA0BgC,WAAW;;;;;;;;;;;;;;;;;;;;;;;;CAwB7D,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,cAAc,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC5C,CAAC"}
1
+ {"version":3,"file":"auth-fetch.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/auth-fetch.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,iBAAiB,CAAC,GAAqB;IACrD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,EAAE,GAAG,GAAG,KAAK,IAAI,CAAC;IACxB,MAAM,CAAC,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACpD,MAAM,CAAC,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAEtD,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;IAC5C,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,IAAI,EAAE,GAAG,UAAU,CAAC;IAEvD,SAAS,uBAAuB;QAC9B,MAAM,CAAC,GAAG,CAAC,CAAC,iBAAiB,CAAC,CAAC;QAC/B,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC;QACvB,MAAM,EAAE,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC;QACxB,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,QAAQ;gBACX,OAAO,mCAAmC,EAAE,UAAU,CAAC,IAAI,CAAC;;EAElE,CAAC;YACG,KAAK,QAAQ;gBACX,OAAO,mCAAmC,EAAE,SAAS,CAAC,IAAI,CAAC;;;;;EAKjE,CAAC;YACG,KAAK,QAAQ;gBACX,OAAO,mCAAmC,EAAE,SAAS,CAAC,IAAI,CAAC;;;;;;;EAOjE,CAAC;YACG;gBACE,OAAO,mCAAmC,EAAE,SAAS,CAAC,IAAI,CAAC;;;;;EAKjE,CAAC;QACC,CAAC;IACH,CAAC;IAED,MAAM,eAAe,GACnB,IAAI,KAAK,QAAQ;QACf,CAAC,CAAC,yEAAyE;QAC3E,CAAC,CAAC,iDAAiD,CAAC;IAExD,MAAM,IAAI,GAAG;;;;;wDAKyC,GAAG;;;;wDAIH,GAAG;;;;mDAIR,GAAG;sCAChB,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,oBAAoB,GAAG;;EAEtF,uBAAuB,EAAE;;;;;;wBAMH,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC;;;;;;;;OAQ5C,WAAW;OACX,YAAY;;;;;;gDAM6B,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,mBAAmB,CAAC;;;;;;;;;;;;;IAavH,eAAe;;;;;;;;;;;;;;;;oBAgBC,CAAC,CAAC,iCAAiC,CAAC;;yCAEf,CAAC,CAAC,0BAA0B,CAAC;;;;;;;mDAOnB,WAAW;;;;;;;;;;;;;;;;;;;;;;;;CAwB7D,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,cAAc,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC5C,CAAC"}
@@ -4,6 +4,8 @@
4
4
  import { writeFile } from "./context.js";
5
5
  export function generateAuthState(ctx) {
6
6
  const ext = ctx.ext;
7
+ const ts = ext === "ts";
8
+ const R = (type) => (ts ? `: ${type} ` : " ");
7
9
  const code = `/**
8
10
  * Auth State — detect the four auth states for offline/online handling.
9
11
  *
@@ -14,14 +16,15 @@ export function generateAuthState(ctx) {
14
16
  * 4. Offline + Unauthenticated → Strict offline (public content only)
15
17
  *
16
18
  * Usage:
17
- * import { getAuthState } from "./auth-state.${ext}";
19
+ * import { getAuthState } from "./auth/state.${ext}";
18
20
  * const { authenticated, user, online } = await getAuthState();
19
21
  */
20
22
 
21
- import { getAuth, isAuthValid } from "./auth-store.${ext}";
22
- import { getCachedUser } from "./auth-user.${ext}";
23
+ import { getAuth, isAuthValid } from "./store.${ext}";
24
+ import { getCachedUser } from "./user.${ext}";
23
25
 
24
- export async function getAuthState() {
26
+ /** Detect current auth state across the 4-state matrix (online/offline × authenticated/not). */
27
+ export async function getAuthState()${R("Promise<{ authenticated: boolean; user: Record<string, unknown> | null; online: boolean }>")}{
25
28
  const auth = await getAuth();
26
29
  const valid = isAuthValid(auth);
27
30
  const user = valid ? await getCachedUser() : null;
@@ -33,6 +36,6 @@ export async function getAuthState() {
33
36
  };
34
37
  }
35
38
  `;
36
- writeFile(ctx, `auth-state.${ext}`, code);
39
+ writeFile(ctx, `auth/state.${ext}`, code);
37
40
  }
38
41
  //# sourceMappingURL=auth-state.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth-state.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/auth-state.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,iBAAiB,CAAC,GAAqB;IACrD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IAEpB,MAAM,IAAI,GAAG;;;;;;;;;;kDAUmC,GAAG;;;;qDAIA,GAAG;6CACX,GAAG;;;;;;;;;;;;;CAa/C,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,cAAc,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC5C,CAAC"}
1
+ {"version":3,"file":"auth-state.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/auth-state.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,iBAAiB,CAAC,GAAqB;IACrD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,EAAE,GAAG,GAAG,KAAK,IAAI,CAAC;IACxB,MAAM,CAAC,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAEtD,MAAM,IAAI,GAAG;;;;;;;;;;kDAUmC,GAAG;;;;gDAIL,GAAG;wCACX,GAAG;;;sCAGL,CAAC,CAAC,4FAA4F,CAAC;;;;;;;;;;;CAWpI,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,cAAc,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC5C,CAAC"}
@@ -9,6 +9,49 @@
9
9
  import { writeFile } from "./context.js";
10
10
  export function generateAuthStore(ctx) {
11
11
  const ext = ctx.ext;
12
+ const ts = ext === "ts";
13
+ const T = (type) => (ts ? `: ${type}` : "");
14
+ const R = (type) => (ts ? `: ${type} ` : " ");
15
+ const PT = (type) => (ts ? `<${type}>` : "");
16
+ const AS = (type) => (ts ? ` as ${type}` : "");
17
+ const authDataInterface = ts ? `export interface AuthData {
18
+ token?: string;
19
+ user?: Record<string, unknown>;
20
+ expiresAt?: number;
21
+ }
22
+
23
+ export interface AuthResponse extends Record<string, unknown> {
24
+ // Uncomment and type the fields your backend's login response returns:
25
+ // token: string;
26
+ // user: Record<string, unknown>;
27
+ // expiresAt?: number;
28
+ }
29
+
30
+ ` : "";
31
+ const createAuthFromResponseBlock = ts
32
+ ? `/** Extract AuthData from your backend's login response. Edit this function to match your backend's response shape. */
33
+ export function createAuthFromResponse(response: AuthResponse): AuthData {
34
+ // --- EDIT THIS TO MATCH YOUR BACKEND ---
35
+ const data = response as Record<string, unknown>;
36
+ return {
37
+ token: data.token as string,
38
+ user: data.user as Record<string, unknown> | undefined,
39
+ expiresAt: data.expiresAt as number | undefined,
40
+ };
41
+ // --- END OF EDITABLE BLOCK ---
42
+ }
43
+ `
44
+ : `/** Extract AuthData from your backend's login response. Edit this function to match your backend's response shape. */
45
+ export function createAuthFromResponse(response) {
46
+ // --- EDIT THIS TO MATCH YOUR BACKEND ---
47
+ return {
48
+ token: response.token,
49
+ user: response.user,
50
+ expiresAt: response.expiresAt,
51
+ };
52
+ // --- END OF EDITABLE BLOCK ---
53
+ }
54
+ `;
12
55
  const code = `/**
13
56
  * Auth Store — Token in memory only; user info in IndexedDB for offline access.
14
57
  *
@@ -18,110 +61,98 @@ export function generateAuthStore(ctx) {
18
61
  * user info offline. After a page refresh, re-login is required.
19
62
  *
20
63
  * Usage:
21
- * import { setAuth, getAuth, clearAuth, isAuthValid } from "./auth-store.${ext}";
64
+ * import { setAuth, getAuth, clearAuth, isAuthValid } from "./auth/store.${ext}";
22
65
  *
23
66
  * await setAuth({ token, user, expiresAt });
24
67
  * const auth = await getAuth();
25
68
  * await clearAuth();
26
69
  */
27
70
 
28
- const DB_NAME = "swoff-auth";
71
+ ${authDataInterface}const DB_NAME = "swoff-auth";
29
72
  const STORE_NAME = "auth";
30
73
 
31
- let memoryAuth = null;
74
+ let memoryAuth${T("AuthData | null")} = null;
32
75
 
33
- function openAuthDB() {
34
- return new Promise((resolve, reject) => {
76
+ ${createAuthFromResponseBlock}
77
+ function openAuthDB()${R("Promise<IDBDatabase>")}{
78
+ return new Promise${PT("IDBDatabase")}((resolve, reject) => {
35
79
  const request = indexedDB.open(DB_NAME, 1);
36
80
  request.onupgradeneeded = (e) => {
37
- const db = e.target.result;
81
+ const db = (e.target${AS("IDBOpenDBRequest")}).result;
38
82
  if (!db.objectStoreNames.contains(STORE_NAME)) {
39
83
  db.createObjectStore(STORE_NAME, { keyPath: "key" });
40
84
  }
41
85
  };
42
- request.onsuccess = (e) => resolve(e.target.result);
43
- request.onerror = (e) => reject(e.target.error);
86
+ request.onsuccess = (e) => resolve((e.target${AS("IDBOpenDBRequest")}).result);
87
+ request.onerror = (e) => reject((e.target${AS("IDBRequest")}).error);
44
88
  });
45
89
  }
46
90
 
47
- async function persistUserData(authData) {
91
+ async function persistUserData(authData${T("AuthData | null")})${R("Promise<void>")}{
48
92
  // Only persist { user, expiresAt } — never the token
49
93
  const userData = { user: authData?.user, expiresAt: authData?.expiresAt };
50
94
  const db = await openAuthDB();
51
- return new Promise((resolve, reject) => {
95
+ return new Promise${PT("void")}((resolve, reject) => {
52
96
  const tx = db.transaction(STORE_NAME, "readwrite");
53
97
  const store = tx.objectStore(STORE_NAME);
54
98
  const request = store.put({ key: "session", value: userData });
55
99
  request.onsuccess = () => resolve();
56
- request.onerror = () => reject(request.error);
100
+ request.onerror = () => reject((request${AS("IDBRequest")}).error);
57
101
  });
58
102
  }
59
103
 
60
- async function loadUserData() {
104
+ async function loadUserData()${R("Promise<{ user?: Record<string, unknown>; expiresAt?: number } | null>")}{
61
105
  const db = await openAuthDB();
62
- return new Promise((resolve, reject) => {
106
+ return new Promise${PT("any")}((resolve, reject) => {
63
107
  const tx = db.transaction(STORE_NAME, "readonly");
64
108
  const store = tx.objectStore(STORE_NAME);
65
109
  const request = store.get("session");
66
- request.onsuccess = () => resolve(request.result?.value || null);
67
- request.onerror = () => reject(request.error);
110
+ request.onsuccess = () => resolve((request${AS("IDBRequest")}).result?.value ?? null);
111
+ request.onerror = () => reject((request${AS("IDBRequest")}).error);
68
112
  });
69
113
  }
70
114
 
71
- async function clearPersistedData() {
115
+ async function clearPersistedData()${R("Promise<void>")}{
72
116
  const db = await openAuthDB();
73
- return new Promise((resolve, reject) => {
117
+ return new Promise${PT("void")}((resolve, reject) => {
74
118
  const tx = db.transaction(STORE_NAME, "readwrite");
75
119
  const store = tx.objectStore(STORE_NAME);
76
120
  const request = store.delete("session");
77
121
  request.onsuccess = () => resolve();
78
- request.onerror = () => reject(request.error);
122
+ request.onerror = () => reject((request${AS("IDBRequest")}).error);
79
123
  });
80
124
  }
81
125
 
82
- /**
83
- * Store auth data — token stays in memory only.
84
- * Only user info and expiry are persisted to IndexedDB.
85
- * @param {{ token?: string, user?: object, expiresAt?: number }} authData
86
- */
87
- export async function setAuth(authData) {
126
+ /** Store auth data in memory and persist user info to IndexedDB for offline access. */
127
+ export async function setAuth(authData${T("AuthData")})${R("Promise<void>")}{
88
128
  memoryAuth = authData;
89
129
  await persistUserData(authData);
90
130
  }
91
131
 
92
- /**
93
- * Get stored auth — returns memory copy (with token) or
94
- * falls back to IndexedDB (user info only, no token after refresh).
95
- */
96
- export async function getAuth() {
132
+ /** Get auth data from memory (or IndexedDB if memory is empty after page refresh). */
133
+ export async function getAuth()${R("Promise<AuthData | null>")}{
97
134
  if (memoryAuth) return memoryAuth;
98
135
 
99
136
  const userData = await loadUserData();
100
137
  if (userData) {
101
- // After refresh: user info available, but no token — re-login required
102
138
  memoryAuth = userData;
103
139
  }
104
140
  return memoryAuth;
105
141
  }
106
142
 
107
- /**
108
- * Clear auth — removes from memory and IndexedDB.
109
- */
110
- export async function clearAuth() {
143
+ /** Clear auth from memory and IndexedDB. Call on logout or 401. */
144
+ export async function clearAuth()${R("Promise<void>")}{
111
145
  memoryAuth = null;
112
146
  await clearPersistedData();
113
147
  }
114
148
 
115
- /**
116
- * Check if auth exists and is not expired.
117
- * @param {object | null} auth — The auth object from getAuth()
118
- */
119
- export function isAuthValid(auth) {
149
+ /** Check if auth exists and has not expired. Returns true if no expiresAt is set. */
150
+ export function isAuthValid(auth${T("AuthData | null")})${R("boolean")}{
120
151
  if (!auth) return false;
121
152
  if (!auth.expiresAt) return true;
122
153
  return Date.now() < auth.expiresAt;
123
154
  }
124
155
  `;
125
- writeFile(ctx, `auth-store.${ext}`, code);
156
+ writeFile(ctx, `auth/store.${ext}`, code);
126
157
  }
127
158
  //# sourceMappingURL=auth-store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth-store.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/auth-store.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,iBAAiB,CAAC,GAAqB;IACrD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IAEpB,MAAM,IAAI,GAAG;;;;;;;;;8EAS+D,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuGhF,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,cAAc,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC5C,CAAC"}
1
+ {"version":3,"file":"auth-store.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/auth-store.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,iBAAiB,CAAC,GAAqB;IACrD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,EAAE,GAAG,GAAG,KAAK,IAAI,CAAC;IAExB,MAAM,CAAC,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACpD,MAAM,CAAC,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACtD,MAAM,EAAE,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACrD,MAAM,EAAE,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAEvD,MAAM,iBAAiB,GAAG,EAAE,CAAC,CAAC,CAAC;;;;;;;;;;;;;CAahC,CAAC,CAAC,CAAC,EAAE,CAAC;IAEL,MAAM,2BAA2B,GAAG,EAAE;QACpC,CAAC,CAAC;;;;;;;;;;;CAWL;QACG,CAAC,CAAC;;;;;;;;;;CAUL,CAAC;IAEA,MAAM,IAAI,GAAG;;;;;;;;;8EAS+D,GAAG;;;;;;;EAO/E,iBAAiB;;;gBAGH,CAAC,CAAC,iBAAiB,CAAC;;EAElC,2BAA2B;uBACN,CAAC,CAAC,sBAAsB,CAAC;sBAC1B,EAAE,CAAC,aAAa,CAAC;;;4BAGX,EAAE,CAAC,kBAAkB,CAAC;;;;;kDAKA,EAAE,CAAC,kBAAkB,CAAC;+CACzB,EAAE,CAAC,YAAY,CAAC;;;;yCAItB,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC;;;;sBAI7D,EAAE,CAAC,MAAM,CAAC;;;;;6CAKa,EAAE,CAAC,YAAY,CAAC;;;;+BAI9B,CAAC,CAAC,wEAAwE,CAAC;;sBAEpF,EAAE,CAAC,KAAK,CAAC;;;;gDAIiB,EAAE,CAAC,YAAY,CAAC;6CACnB,EAAE,CAAC,YAAY,CAAC;;;;qCAIxB,CAAC,CAAC,eAAe,CAAC;;sBAEjC,EAAE,CAAC,MAAM,CAAC;;;;;6CAKa,EAAE,CAAC,YAAY,CAAC;;;;;wCAKrB,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC;;;;;;iCAM1C,CAAC,CAAC,0BAA0B,CAAC;;;;;;;;;;;mCAW3B,CAAC,CAAC,eAAe,CAAC;;;;;;kCAMnB,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC;;;;;CAKrE,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,cAAc,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC5C,CAAC"}
@@ -4,42 +4,44 @@
4
4
  import { writeFile } from "./context.js";
5
5
  export function generateAuthUser(ctx) {
6
6
  const ext = ctx.ext;
7
+ const ts = ext === "ts";
8
+ const T = (type) => (ts ? `: ${type}` : "");
9
+ const R = (type) => (ts ? `: ${type} ` : " ");
10
+ const PT = (type) => (ts ? `<${type}>` : "");
11
+ const AS = (type) => (ts ? ` as ${type}` : "");
7
12
  const userEndpoint = ctx.config.features.auth.userEndpoint;
8
13
  const code = `/**
9
14
  * Current User — fetch, cache, and invalidate the current user for offline access.
10
15
  *
11
16
  * Usage:
12
- * import { fetchCurrentUser, cacheUser, getCachedUser, clearCachedUser } from "./auth-user.${ext}";
17
+ * import { fetchCurrentUser, cacheUser, getCachedUser, clearCachedUser } from "./auth/user.${ext}";
13
18
  *
14
19
  * await fetchCurrentUser(); // Fetch from server & cache
15
20
  * const user = await getCachedUser(); // Get cached (offline-capable)
16
21
  * await clearCachedUser(); // Clear on logout
17
22
  */
18
23
 
19
- import { authenticatedFetch } from "./auth-fetch.${ext}";
24
+ import { authenticatedFetch } from "./fetch.${ext}";
20
25
 
21
26
  const DB_NAME = "swoff-auth-user";
22
27
  const STORE_NAME = "current-user";
23
28
 
24
- function openAuthDB() {
25
- return new Promise((resolve, reject) => {
29
+ function openAuthDB()${R("Promise<IDBDatabase>")}{
30
+ return new Promise${PT("IDBDatabase")}((resolve, reject) => {
26
31
  const request = indexedDB.open(DB_NAME, 1);
27
32
  request.onupgradeneeded = (e) => {
28
- const db = e.target.result;
33
+ const db = (e.target${AS("IDBOpenDBRequest")}).result;
29
34
  if (!db.objectStoreNames.contains(STORE_NAME)) {
30
35
  db.createObjectStore(STORE_NAME, { keyPath: "key" });
31
36
  }
32
37
  };
33
- request.onsuccess = (e) => resolve(e.target.result);
34
- request.onerror = (e) => reject(e.target.error);
38
+ request.onsuccess = (e) => resolve((e.target${AS("IDBOpenDBRequest")}).result);
39
+ request.onerror = (e) => reject((e.target${AS("IDBRequest")}).error);
35
40
  });
36
41
  }
37
42
 
38
- /**
39
- * Fetch current user from your backend and cache locally.
40
- * Uses userEndpoint from swoff.config.json.
41
- */
42
- export async function fetchCurrentUser() {
43
+ /** Fetch current user from the user endpoint and cache the result in IndexedDB. */
44
+ export async function fetchCurrentUser()${R("Promise<Record<string, unknown>>")}{
43
45
  const response = await authenticatedFetch("${userEndpoint}");
44
46
  if (!response.ok) throw new Error("Failed to fetch user");
45
47
 
@@ -48,12 +50,10 @@ export async function fetchCurrentUser() {
48
50
  return user;
49
51
  }
50
52
 
51
- /**
52
- * Store user in IndexedDB for offline access.
53
- */
54
- export async function cacheUser(user) {
53
+ /** Persist user data to IndexedDB for offline access. */
54
+ export async function cacheUser(user${T("Record<string, unknown>")})${R("Promise<void>")}{
55
55
  const db = await openAuthDB();
56
- return new Promise((resolve, reject) => {
56
+ return new Promise<void>((resolve, reject) => {
57
57
  const tx = db.transaction(STORE_NAME, "readwrite");
58
58
  const store = tx.objectStore(STORE_NAME);
59
59
  store.put({ key: "user", value: user });
@@ -62,34 +62,30 @@ export async function cacheUser(user) {
62
62
  });
63
63
  }
64
64
 
65
- /**
66
- * Get cached user works offline.
67
- */
68
- export async function getCachedUser() {
65
+ /** Load user data from IndexedDB cache (no token — only user object survives refresh). */
66
+ export async function getCachedUser()${R("Promise<Record<string, unknown> | null>")}{
69
67
  const db = await openAuthDB();
70
- return new Promise((resolve, reject) => {
68
+ return new Promise${PT("Record<string, unknown> | null")}((resolve, reject) => {
71
69
  const tx = db.transaction(STORE_NAME, "readonly");
72
70
  const store = tx.objectStore(STORE_NAME);
73
71
  const request = store.get("user");
74
- request.onsuccess = () => resolve(request.result?.value || null);
75
- request.onerror = () => reject(request.error);
72
+ request.onsuccess = () => resolve((request${AS("IDBRequest")}).result?.value ?? null);
73
+ request.onerror = () => reject((request${AS("IDBRequest")}).error);
76
74
  });
77
75
  }
78
76
 
79
- /**
80
- * Clear cached user on logout.
81
- */
82
- export async function clearCachedUser() {
77
+ /** Remove user data from IndexedDB cache. Call on logout. */
78
+ export async function clearCachedUser()${R("Promise<void>")}{
83
79
  const db = await openAuthDB();
84
- return new Promise((resolve, reject) => {
80
+ return new Promise${PT("void")}((resolve, reject) => {
85
81
  const tx = db.transaction(STORE_NAME, "readwrite");
86
82
  const store = tx.objectStore(STORE_NAME);
87
83
  store.delete("user");
88
84
  tx.oncomplete = () => resolve();
89
- tx.onerror = () => reject(tx.error);
85
+ tx.onerror = () => reject((tx${AS("IDBTransaction")}).error);
90
86
  });
91
87
  }
92
88
  `;
93
- writeFile(ctx, `auth-user.${ext}`, code);
89
+ writeFile(ctx, `auth/user.${ext}`, code);
94
90
  }
95
91
  //# sourceMappingURL=auth-user.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth-user.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/auth-user.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,gBAAgB,CAAC,GAAqB;IACpD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC;IAE3D,MAAM,IAAI,GAAG;;;;gGAIiF,GAAG;;;;;;;mDAOhD,GAAG;;;;;;;;;;;;;;;;;;;;;;;;+CAwBP,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiD1D,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC3C,CAAC"}
1
+ {"version":3,"file":"auth-user.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/auth-user.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,gBAAgB,CAAC,GAAqB;IACpD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,EAAE,GAAG,GAAG,KAAK,IAAI,CAAC;IACxB,MAAM,CAAC,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACpD,MAAM,CAAC,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACtD,MAAM,EAAE,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACrD,MAAM,EAAE,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACvD,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC;IAE3D,MAAM,IAAI,GAAG;;;;gGAIiF,GAAG;;;;;;;8CAOrD,GAAG;;;;;uBAK1B,CAAC,CAAC,sBAAsB,CAAC;sBAC1B,EAAE,CAAC,aAAa,CAAC;;;4BAGX,EAAE,CAAC,kBAAkB,CAAC;;;;;kDAKA,EAAE,CAAC,kBAAkB,CAAC;+CACzB,EAAE,CAAC,YAAY,CAAC;;;;;0CAKrB,CAAC,CAAC,kCAAkC,CAAC;+CAChC,YAAY;;;;;;;;;sCASrB,CAAC,CAAC,yBAAyB,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC;;;;;;;;;;;;uCAYjD,CAAC,CAAC,yCAAyC,CAAC;;sBAE7D,EAAE,CAAC,gCAAgC,CAAC;;;;gDAIV,EAAE,CAAC,YAAY,CAAC;6CACnB,EAAE,CAAC,YAAY,CAAC;;;;;yCAKpB,CAAC,CAAC,eAAe,CAAC;;sBAErC,EAAE,CAAC,MAAM,CAAC;;;;;mCAKG,EAAE,CAAC,gBAAgB,CAAC;;;CAGtD,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC3C,CAAC"}
@@ -4,6 +4,9 @@
4
4
  import { writeFile } from "./context.js";
5
5
  export function generateBackgroundSync(ctx) {
6
6
  const ext = ctx.ext;
7
+ const ts = ext === "ts";
8
+ const T = (type) => (ts ? `: ${type}` : "");
9
+ const R = (type) => (ts ? `: ${type} ` : " ");
7
10
  const code = `/**
8
11
  * Swoff Background Sync
9
12
  * Register sync events for processing mutation queue after tab close.
@@ -17,8 +20,7 @@ export function generateBackgroundSync(ctx) {
17
20
  * url: "/api/todos",
18
21
  * body: { title: "Grocery" },
19
22
  * tags: ["todos"],
20
- * storeName: "todos",
21
- * tempId: "temp_abc123",
23
+ * tags: ["todos"],
22
24
  * });
23
25
  */
24
26
 
@@ -26,7 +28,7 @@ import { queueMutation, processMutationQueue, getPendingCount } from "./mutation
26
28
 
27
29
  const SYNC_TAG = "sync-mutations";
28
30
 
29
- async function registerSync() {
31
+ async function registerSync()${R("Promise<void>")}{
30
32
  if (!("serviceWorker" in navigator) || !("SyncManager" in window)) {
31
33
  window.addEventListener("online", processMutationQueue, { once: true });
32
34
  return;
@@ -40,12 +42,14 @@ async function registerSync() {
40
42
  }
41
43
  }
42
44
 
43
- export async function syncWhenPossible(mutation) {
45
+ /** Queue a mutation and register a background sync event so it runs even after tab close. */
46
+ export async function syncWhenPossible(mutation${T("object")})${R("Promise<void>")}{
44
47
  await queueMutation(mutation);
45
48
  await registerSync();
46
49
  }
47
50
 
48
- export async function retrySync() {
51
+ /** Re-register a background sync if mutations are still pending. Called automatically after each sync cycle. */
52
+ export async function retrySync()${R("Promise<void>")}{
49
53
  if (!("serviceWorker" in navigator) || !("SyncManager" in window)) return;
50
54
  const count = await getPendingCount();
51
55
  if (count > 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"background-sync.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/background-sync.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,sBAAsB,CAAC,GAAqB;IAC1D,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,IAAI,GAAG;;;;;;iEAMkD,GAAG;;;;;;;;;;;;yFAYqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgC3F,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,mBAAmB,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AACjD,CAAC"}
1
+ {"version":3,"file":"background-sync.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/background-sync.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,sBAAsB,CAAC,GAAqB;IAC1D,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,EAAE,GAAG,GAAG,KAAK,IAAI,CAAC;IACxB,MAAM,CAAC,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACpD,MAAM,CAAC,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAEtD,MAAM,IAAI,GAAG;;;;;;iEAMkD,GAAG;;;;;;;;;;;yFAWqB,GAAG;;;;+BAI7D,CAAC,CAAC,eAAe,CAAC;;;;;;;;;;;;;;;iDAeA,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC;;;;;;mCAM/C,CAAC,CAAC,eAAe,CAAC;;;;;;;;;CASpD,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,mBAAmB,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AACjD,CAAC"}
@@ -4,6 +4,9 @@
4
4
  import { writeFile } from "./context.js";
5
5
  export function generateCache(ctx) {
6
6
  const ext = ctx.ext;
7
+ const ts = ext === "ts";
8
+ const T = (type) => (ts ? `: ${type}` : "");
9
+ const R = (type) => (ts ? `: ${type} ` : " ");
7
10
  const code = `/**
8
11
  * Swoff Cache Invalidation
9
12
  * Framework-agnostic cache tag invalidation.
@@ -15,7 +18,8 @@ export function generateCache(ctx) {
15
18
  * await invalidateByTag("todos");
16
19
  */
17
20
 
18
- export async function invalidateByTag(tag) {
21
+ /** Invalidate all cached responses tagged with the given tag. Dispatches cache-invalidated event. */
22
+ export async function invalidateByTag(tag${T("string")})${R("Promise<void>")}{
19
23
  if (!navigator.serviceWorker?.controller) return;
20
24
 
21
25
  navigator.serviceWorker.controller.postMessage({
@@ -28,7 +32,8 @@ export async function invalidateByTag(tag) {
28
32
  );
29
33
  }
30
34
 
31
- export async function invalidateByTags(tags) {
35
+ /** Invalidate all cached responses matching any of the given tags. */
36
+ export async function invalidateByTags(tags${T("string[]")})${R("Promise<void>")}{
32
37
  for (const tag of tags) {
33
38
  await invalidateByTag(tag);
34
39
  }
@@ -1 +1 @@
1
- {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,aAAa,CAAC,GAAqB;IACjD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IAEpB,MAAM,IAAI,GAAG;;;;;sDAKuC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;CAwBxD,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,SAAS,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AACvC,CAAC"}
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../../src/lib/generators/file-generators/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,aAAa,CAAC,GAAqB;IACjD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,MAAM,EAAE,GAAG,GAAG,KAAK,IAAI,CAAC;IACxB,MAAM,CAAC,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACpD,MAAM,CAAC,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAEtD,MAAM,IAAI,GAAG;;;;;sDAKuC,GAAG;;;;;;;2CAOd,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC;;;;;;;;;;;;;;6CAc/B,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC;;;;;CAK/E,CAAC;IAEA,SAAS,CAAC,GAAG,EAAE,SAAS,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AACvC,CAAC"}