@swoff/cli 0.3.6 → 0.3.8

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 (109) hide show
  1. package/README.md +43 -326
  2. package/bin/swoff +8 -14
  3. package/dist/__tests__/assemble-sw.test.js +6 -6
  4. package/dist/__tests__/assemble-sw.test.js.map +1 -1
  5. package/dist/__tests__/cli-integration.test.js +0 -1
  6. package/dist/__tests__/cli-integration.test.js.map +1 -1
  7. package/dist/__tests__/config-types.test.js +9 -5
  8. package/dist/__tests__/config-types.test.js.map +1 -1
  9. package/dist/__tests__/file-generators.test.js +12 -23
  10. package/dist/__tests__/file-generators.test.js.map +1 -1
  11. package/dist/__tests__/loader.test.js +0 -1
  12. package/dist/__tests__/loader.test.js.map +1 -1
  13. package/dist/__tests__/validator.test.js +50 -2
  14. package/dist/__tests__/validator.test.js.map +1 -1
  15. package/dist/index.js +1 -1
  16. package/dist/index.js.map +1 -1
  17. package/dist/lib/commands/add.js +7 -6
  18. package/dist/lib/commands/add.js.map +1 -1
  19. package/dist/lib/commands/generate-guide.js +36 -9
  20. package/dist/lib/commands/generate-guide.js.map +1 -1
  21. package/dist/lib/commands/info.js +45 -8
  22. package/dist/lib/commands/info.js.map +1 -1
  23. package/dist/lib/commands/init.js +6 -2
  24. package/dist/lib/commands/init.js.map +1 -1
  25. package/dist/lib/config/validator.js +85 -4
  26. package/dist/lib/config/validator.js.map +1 -1
  27. package/dist/lib/generators/file-generators/auth-fetch.js +3 -3
  28. package/dist/lib/generators/file-generators/auth-fetch.js.map +1 -1
  29. package/dist/lib/generators/file-generators/auth-store.js +114 -5
  30. package/dist/lib/generators/file-generators/auth-store.js.map +1 -1
  31. package/dist/lib/generators/file-generators/auth-user.js +2 -2
  32. package/dist/lib/generators/file-generators/auth-user.js.map +1 -1
  33. package/dist/lib/generators/file-generators/cache.js +1 -3
  34. package/dist/lib/generators/file-generators/cache.js.map +1 -1
  35. package/dist/lib/generators/file-generators/client-injector.js +5 -17
  36. package/dist/lib/generators/file-generators/client-injector.js.map +1 -1
  37. package/dist/lib/generators/file-generators/fetch-wrapper.js +86 -20
  38. package/dist/lib/generators/file-generators/fetch-wrapper.js.map +1 -1
  39. package/dist/lib/generators/file-generators/generate-hooks.js +28 -210
  40. package/dist/lib/generators/file-generators/generate-hooks.js.map +1 -1
  41. package/dist/lib/generators/file-generators/gql-wrapper.js +152 -0
  42. package/dist/lib/generators/file-generators/gql-wrapper.js.map +1 -0
  43. package/dist/lib/generators/file-generators/guide-generator.js +357 -36
  44. package/dist/lib/generators/file-generators/guide-generator.js.map +1 -1
  45. package/dist/lib/generators/file-generators/mutation-queue.js +130 -34
  46. package/dist/lib/generators/file-generators/mutation-queue.js.map +1 -1
  47. package/dist/lib/generators/file-generators/mutation-state.js +126 -0
  48. package/dist/lib/generators/file-generators/mutation-state.js.map +1 -0
  49. package/dist/lib/generators/file-generators/push.js +143 -0
  50. package/dist/lib/generators/file-generators/push.js.map +1 -0
  51. package/dist/lib/generators/file-generators/quick-readme.js +71 -11
  52. package/dist/lib/generators/file-generators/quick-readme.js.map +1 -1
  53. package/dist/lib/generators/file-generators/server-push.js +136 -0
  54. package/dist/lib/generators/file-generators/server-push.js.map +1 -0
  55. package/dist/lib/generators/file-generators/sw-generator-build.js +1 -1
  56. package/dist/lib/generators/file-generators/sw-injector.js +1 -1
  57. package/dist/lib/generators/file-generators/sw-push.js +67 -0
  58. package/dist/lib/generators/file-generators/sw-push.js.map +1 -0
  59. package/dist/lib/generators/file-generators/sw-template.js +2 -0
  60. package/dist/lib/generators/file-generators/sw-template.js.map +1 -1
  61. package/dist/lib/generators/file-generators/type-definitions.js +39 -11
  62. package/dist/lib/generators/file-generators/type-definitions.js.map +1 -1
  63. package/dist/lib/generators/sw-generator.js +8 -9
  64. package/dist/lib/generators/sw-generator.js.map +1 -1
  65. package/dist/lib/generators/sw-sections/activate-handler.js +6 -2
  66. package/dist/lib/generators/sw-sections/activate-handler.js.map +1 -1
  67. package/dist/lib/generators/sw-sections/assemble-sw.js +11 -2
  68. package/dist/lib/generators/sw-sections/assemble-sw.js.map +1 -1
  69. package/dist/lib/generators/sw-sections/background-sync-handler.js +22 -8
  70. package/dist/lib/generators/sw-sections/background-sync-handler.js.map +1 -1
  71. package/dist/lib/generators/sw-sections/config-header.js +1 -1
  72. package/dist/lib/generators/sw-sections/config-header.js.map +1 -1
  73. package/dist/lib/generators/sw-sections/default-template.js +2 -30
  74. package/dist/lib/generators/sw-sections/default-template.js.map +1 -1
  75. package/dist/lib/generators/sw-sections/fetch-handler.js +230 -120
  76. package/dist/lib/generators/sw-sections/fetch-handler.js.map +1 -1
  77. package/dist/lib/generators/sw-sections/install-handler.js +12 -10
  78. package/dist/lib/generators/sw-sections/install-handler.js.map +1 -1
  79. package/dist/lib/generators/sw-sections/server-push-handler.js +114 -0
  80. package/dist/lib/generators/sw-sections/server-push-handler.js.map +1 -0
  81. package/dist/lib/generators/sw-sections/tag-management.js +17 -5
  82. package/dist/lib/generators/sw-sections/tag-management.js.map +1 -1
  83. package/dist/lib/generators/swoff-files-generator.js +16 -10
  84. package/dist/lib/generators/swoff-files-generator.js.map +1 -1
  85. package/dist/lib/shared/config-types.js +44 -4
  86. package/dist/lib/shared/config-types.js.map +1 -1
  87. package/package.json +3 -2
  88. package/templates/hooks/useAuth.jsx +30 -0
  89. package/templates/hooks/useAuth.tsx +30 -0
  90. package/templates/hooks/useBackgroundSync.jsx +31 -0
  91. package/templates/hooks/useBackgroundSync.tsx +31 -0
  92. package/templates/hooks/useCacheInvalidation.jsx +19 -0
  93. package/templates/hooks/useCacheInvalidation.tsx +19 -0
  94. package/templates/hooks/useCachedFetch.jsx +94 -0
  95. package/templates/hooks/useCachedFetch.tsx +112 -0
  96. package/templates/hooks/useMutation.jsx +76 -0
  97. package/templates/hooks/useMutation.tsx +97 -0
  98. package/templates/hooks/useMutationQueue.jsx +42 -0
  99. package/templates/hooks/useMutationQueue.tsx +49 -0
  100. package/templates/hooks/useMutationState.jsx +27 -0
  101. package/templates/hooks/useMutationState.tsx +41 -0
  102. package/templates/hooks/useNetworkStatus.jsx +19 -0
  103. package/templates/hooks/useNetworkStatus.tsx +19 -0
  104. package/templates/hooks/usePrefetch.jsx +10 -0
  105. package/templates/hooks/usePrefetch.tsx +25 -0
  106. package/templates/hooks/usePushSubscription.jsx +67 -0
  107. package/templates/hooks/usePushSubscription.tsx +67 -0
  108. package/templates/hooks/useSWUpdate.jsx +76 -0
  109. package/templates/hooks/useSWUpdate.tsx +76 -0
@@ -6,9 +6,20 @@
6
6
  export function generateTagManagement() {
7
7
  return `
8
8
  const staleVersions = new Map();
9
+ const STALE_VERSIONS_MAX = 100;
10
+ const STALE_VERSION_TTL = 30 * 60 * 1000;
9
11
  const TAG_DB_NAME = "swoff-cache-tags";
10
12
  const TAG_STORE_NAME = "tags";
11
13
 
14
+ function cleanStaleVersions() {
15
+ const now = Date.now();
16
+ for (const [url, ts] of staleVersions) {
17
+ if (staleVersions.size > STALE_VERSIONS_MAX || now - ts > STALE_VERSION_TTL) {
18
+ staleVersions.delete(url);
19
+ }
20
+ }
21
+ }
22
+
12
23
  function openTagDB() {
13
24
  return new Promise((resolve, reject) => {
14
25
  const request = indexedDB.open(TAG_DB_NAME, 1);
@@ -24,20 +35,21 @@ function openTagDB() {
24
35
  });
25
36
  }
26
37
 
27
- async function cacheTagUrl(url, tags) {
38
+ async function cacheTagUrl(url, actualUrl, tags) {
28
39
  const db = await openTagDB();
29
40
  const tx = db.transaction(TAG_STORE_NAME, "readwrite");
30
41
  const store = tx.objectStore(TAG_STORE_NAME);
31
- store.put({ url, tags });
42
+ store.put({ url, actualUrl, tags });
32
43
  await new Promise((resolve, reject) => {
33
44
  tx.oncomplete = () => resolve();
34
45
  tx.onerror = () => reject(tx.error);
35
46
  });
36
47
  }
37
48
 
38
- async function refetchAfterInvalidation(url) {
49
+ async function refetchAfterInvalidation(url, actualUrl) {
50
+ const fetchUrl = actualUrl || url;
39
51
  try {
40
- const response = await fetch(url);
52
+ const response = await fetch(fetchUrl);
41
53
  if (response.ok) {
42
54
  const runtimeCache = await caches.open(CACHE_NAME_RUNTIME);
43
55
  await runtimeCache.put(url, response);
@@ -77,7 +89,7 @@ async function invalidateByTag(tag) {
77
89
 
78
90
  // Background refetch each deleted URL; keep stale on failure
79
91
  for (const entry of entries) {
80
- refetchAfterInvalidation(entry.url);
92
+ refetchAfterInvalidation(entry.url, entry.actualUrl);
81
93
  }
82
94
 
83
95
  const clients = await self.clients.matchAll();
@@ -1 +1 @@
1
- {"version":3,"file":"tag-management.js","sourceRoot":"","sources":["../../../../src/lib/generators/sw-sections/tag-management.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,UAAU,qBAAqB;IACnC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgFP,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"tag-management.js","sourceRoot":"","sources":["../../../../src/lib/generators/sw-sections/tag-management.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,UAAU,qBAAqB;IACnC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4FP,CAAC;AACH,CAAC"}
@@ -24,11 +24,14 @@ import { generateBackgroundSync } from "./file-generators/background-sync.js";
24
24
  import { generatePwaInstall } from "./file-generators/pwa-install.js";
25
25
  import { generateManifest } from "./file-generators/manifest.js";
26
26
  import { generateInvalidationTags } from "./file-generators/invalidation-tags.js";
27
+ import { generatePush } from "./file-generators/push.js";
28
+ import { generateMutationState } from "./file-generators/mutation-state.js";
29
+ import { generateServerPush } from "./file-generators/server-push.js";
27
30
  import { generateAuthStore } from "./file-generators/auth-store.js";
28
- import { generateAuthFetch } from "./file-generators/auth-fetch.js";
29
31
  import { generateAuthUser } from "./file-generators/auth-user.js";
30
32
  import { generateAuthState } from "./file-generators/auth-state.js";
31
33
  import { generateSwGeneratorBuild } from "./file-generators/sw-generator-build.js";
34
+ import { generateGqlWrapper } from "./file-generators/gql-wrapper.js";
32
35
  import { generateTypeDefinitions } from "./file-generators/type-definitions.js";
33
36
  import { generateHooks } from "./file-generators/generate-hooks.js";
34
37
  import { generateGuide } from "./file-generators/guide-generator.js";
@@ -36,14 +39,14 @@ import { generateReadme } from "./file-generators/quick-readme.js";
36
39
  export function generateFiles(ctx, onFile) {
37
40
  const steps = [
38
41
  { name: "sw-template", gen: () => generateSwTemplate(ctx), enabled: true },
39
- { name: "sw-injector", gen: () => generateSwInjector(ctx), enabled: ctx.config.features.clientRegistration },
40
- { name: "client-injector", gen: () => generateClientInjector(ctx), enabled: ctx.config.features.clientRegistration || ctx.config.features.pwa.enabled || ctx.config.features.crossTabSync },
42
+ { name: "sw-injector", gen: () => generateSwInjector(ctx), enabled: true },
43
+ { name: "client-injector", gen: () => generateClientInjector(ctx), enabled: true },
41
44
  { name: "fetch-wrapper", gen: () => generateFetchWrapper(ctx), enabled: true },
42
45
  { name: "cache", gen: () => generateCache(ctx), enabled: ctx.config.features.tagInvalidation },
43
- { name: "mutation-queue", gen: () => generateMutationQueue(ctx), enabled: ctx.config.features.mutationQueue },
46
+ { name: "mutation-queue", gen: () => generateMutationQueue(ctx), enabled: ctx.config.features.mutationQueue.enabled },
47
+ { name: "mutation-state", gen: () => generateMutationState(ctx), enabled: ctx.config.features.mutationQueue.enabled },
44
48
  { name: "background-sync", gen: () => generateBackgroundSync(ctx), enabled: ctx.config.features.backgroundSync },
45
49
  { name: "auth-store", gen: () => generateAuthStore(ctx), enabled: ctx.config.features.auth.enabled },
46
- { name: "auth-fetch", gen: () => generateAuthFetch(ctx), enabled: ctx.config.features.auth.enabled },
47
50
  { name: "auth-user", gen: () => generateAuthUser(ctx), enabled: ctx.config.features.auth.enabled },
48
51
  { name: "auth-state", gen: () => generateAuthState(ctx), enabled: ctx.config.features.auth.enabled },
49
52
  { name: "sw-generator", gen: () => generateSwGeneratorBuild(ctx), enabled: true },
@@ -51,6 +54,9 @@ export function generateFiles(ctx, onFile) {
51
54
  { name: "pwa-install", gen: () => generatePwaInstall(ctx), enabled: ctx.config.features.pwa.enabled },
52
55
  { name: "manifest.json", gen: () => generateManifest(ctx), enabled: ctx.config.features.pwa.enabled },
53
56
  { name: "invalidation-tags", gen: () => generateInvalidationTags(ctx), enabled: ctx.config.features.tagInvalidation },
57
+ { name: "gql-wrapper", gen: () => generateGqlWrapper(ctx), enabled: ctx.config.features.graphql.enabled },
58
+ { name: "push", gen: () => generatePush(ctx), enabled: ctx.config.features.pushNotifications?.enabled ?? false },
59
+ { name: "server-push", gen: () => generateServerPush(ctx), enabled: ctx.config.features.serverPush.enabled },
54
60
  { name: "hooks", gen: () => generateHooks(ctx), enabled: ctx.config.framework === "react" },
55
61
  { name: "GUIDE.md", gen: () => generateGuide(ctx), enabled: true },
56
62
  { name: "README.md", gen: () => generateReadme(ctx), enabled: true },
@@ -64,12 +70,12 @@ export function generateFiles(ctx, onFile) {
64
70
  return ctx.generatedFiles;
65
71
  }
66
72
  // --- CLI entry point ---
67
- const args = process.argv.slice(2);
68
- function getArg(name) {
69
- const idx = args.findIndex((arg) => arg === `--${name}`);
70
- return idx !== -1 ? args[idx + 1] : null;
71
- }
72
73
  if (fileURLToPath(import.meta.url) === fileURLToPath(new URL(process.argv[1], "file:"))) {
74
+ const args = process.argv.slice(2);
75
+ const getArg = (name) => {
76
+ const idx = args.indexOf(`--${name}`);
77
+ return idx !== -1 ? args[idx + 1] : null;
78
+ };
73
79
  const projectRoot = getArg("project-root") || process.cwd();
74
80
  const language = getArg("language") || "ts";
75
81
  const configPath = getArg("config-path") || join(projectRoot, "swoff.config.json");
@@ -1 +1 @@
1
- {"version":3,"file":"swoff-files-generator.js","sourceRoot":"","sources":["../../../src/lib/generators/swoff-files-generator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"swoff-files-generator.js","sourceRoot":"","sources":["../../../src/lib/generators/swoff-files-generator.ts"],"names":[],"mappings":"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"}
@@ -4,9 +4,11 @@ export const KNOWN_FEATURES = [
4
4
  "auth",
5
5
  "crossTabSync",
6
6
  "tagInvalidation",
7
- "clientRegistration",
7
+ "graphql",
8
+ "pushNotifications",
9
+ "serverPush",
8
10
  ];
9
- export const OBJECT_FEATURES = ["pwa", "serviceWorker", "auth"];
11
+ export const OBJECT_FEATURES = ["pwa", "serviceWorker", "auth", "pushNotifications", "graphql", "serverPush"];
10
12
  export const VALID_STRATEGIES = [
11
13
  "cache-first",
12
14
  "network-first",
@@ -27,6 +29,20 @@ function normalizeSwVersion(ver) {
27
29
  return { ...defaultVersionConfig, ...ver };
28
30
  return defaultVersionConfig;
29
31
  }
32
+ function normalizeGql(val) {
33
+ if (typeof val === "boolean")
34
+ return { ...defaultGql, enabled: val };
35
+ if (val && typeof val === "object")
36
+ return { ...defaultGql, ...val };
37
+ return defaultGql;
38
+ }
39
+ function normalizeMutationQueue(val) {
40
+ if (typeof val === "boolean")
41
+ return { ...defaultMutationQueue, enabled: val };
42
+ if (val && typeof val === "object")
43
+ return { ...defaultMutationQueue, ...val };
44
+ return defaultMutationQueue;
45
+ }
30
46
  export function mergeConfigs(base, override) {
31
47
  return {
32
48
  ...base,
@@ -41,6 +57,9 @@ export function mergeConfigs(base, override) {
41
57
  version: normalizeSwVersion(override.features?.serviceWorker?.version),
42
58
  },
43
59
  auth: normalizeAuth(override.features?.auth),
60
+ mutationQueue: normalizeMutationQueue(override.features?.mutationQueue),
61
+ graphql: normalizeGql(override.features?.graphql),
62
+ serverPush: { ...defaultServerPush, ...override.features?.serverPush },
44
63
  },
45
64
  build: { ...base.build, ...override.build },
46
65
  };
@@ -56,6 +75,23 @@ export const defaultVersionConfig = {
56
75
  source: "from-package",
57
76
  minSupportedVersion: "0.0.0",
58
77
  };
78
+ export const defaultGql = {
79
+ enabled: false,
80
+ endpoint: "/graphql",
81
+ };
82
+ export const defaultMutationQueue = {
83
+ enabled: false,
84
+ batchSize: 1,
85
+ batchDelayMs: 0,
86
+ maxRetries: 5,
87
+ retryBackoffMs: 1000,
88
+ };
89
+ export const defaultServerPush = {
90
+ enabled: false,
91
+ type: "sse",
92
+ endpoint: "/api/events",
93
+ reconnectDelayMs: 5000,
94
+ };
59
95
  export const defaultConfig = {
60
96
  enabled: true,
61
97
  features: {
@@ -69,16 +105,20 @@ export const defaultConfig = {
69
105
  autoActivate: false,
70
106
  defaultStrategy: "cache-first",
71
107
  strategies: {},
108
+ cacheStrategy: "all",
72
109
  clearRuntimeOnUpdate: false,
110
+ navigationPreload: true,
73
111
  navigationMode: "spa",
74
112
  spaEntry: "/index.html",
75
113
  },
76
- mutationQueue: false,
114
+ mutationQueue: { ...defaultMutationQueue },
77
115
  backgroundSync: false,
78
116
  auth: { ...defaultAuth },
79
117
  crossTabSync: true,
80
118
  tagInvalidation: true,
81
- clientRegistration: true,
119
+ graphql: { ...defaultGql },
120
+ pushNotifications: { enabled: false },
121
+ serverPush: { ...defaultServerPush },
82
122
  },
83
123
  build: {
84
124
  outputDir: "dist",
@@ -1 +1 @@
1
- {"version":3,"file":"config-types.js","sourceRoot":"","sources":["../../../src/lib/shared/config-types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config-types.js","sourceRoot":"","sources":["../../../src/lib/shared/config-types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swoff/cli",
3
- "version": "0.3.6",
3
+ "version": "0.3.8",
4
4
  "type": "module",
5
5
  "description": "CLI for Swoff - Offline-first web apps made easy",
6
6
  "bin": {
@@ -18,7 +18,8 @@
18
18
  },
19
19
  "files": [
20
20
  "bin/",
21
- "dist/"
21
+ "dist/",
22
+ "templates/"
22
23
  ],
23
24
  "keywords": [
24
25
  "service-worker",
@@ -0,0 +1,30 @@
1
+ import { useState, useEffect } from "react";
2
+ import { getAuthState } from "../auth/state.js";
3
+
4
+ export function useAuth() {
5
+ const [state, setState] = useState({
6
+ authenticated: false,
7
+ user: null,
8
+ online: navigator.onLine,
9
+ });
10
+
11
+ useEffect(() => {
12
+ getAuthState().then(setState);
13
+
14
+ const onOnline = () => setState((s) => ({ ...s, online: true }));
15
+ const onOffline = () => setState((s) => ({ ...s, online: false }));
16
+ const onAuthChange = () => getAuthState().then(setState);
17
+
18
+ window.addEventListener("online", onOnline);
19
+ window.addEventListener("offline", onOffline);
20
+ window.addEventListener("sw-auth-state-change", onAuthChange);
21
+
22
+ return () => {
23
+ window.removeEventListener("online", onOnline);
24
+ window.removeEventListener("offline", onOffline);
25
+ window.removeEventListener("sw-auth-state-change", onAuthChange);
26
+ };
27
+ }, []);
28
+
29
+ return state;
30
+ }
@@ -0,0 +1,30 @@
1
+ import { useState, useEffect } from "react";
2
+ import { getAuthState } from "../auth/state.ts";
3
+
4
+ export function useAuth() {
5
+ const [state, setState] = useState({
6
+ authenticated: false,
7
+ user: null as Record<string, unknown> | null,
8
+ online: navigator.onLine,
9
+ });
10
+
11
+ useEffect(() => {
12
+ getAuthState().then(setState);
13
+
14
+ const onOnline = () => setState((s) => ({ ...s, online: true }));
15
+ const onOffline = () => setState((s) => ({ ...s, online: false }));
16
+ const onAuthChange = () => getAuthState().then(setState);
17
+
18
+ window.addEventListener("online", onOnline);
19
+ window.addEventListener("offline", onOffline);
20
+ window.addEventListener("sw-auth-state-change", onAuthChange);
21
+
22
+ return () => {
23
+ window.removeEventListener("online", onOnline);
24
+ window.removeEventListener("offline", onOffline);
25
+ window.removeEventListener("sw-auth-state-change", onAuthChange);
26
+ };
27
+ }, []);
28
+
29
+ return state;
30
+ }
@@ -0,0 +1,31 @@
1
+ import { useState, useEffect, useCallback } from "react";
2
+ import { retrySync } from "../background-sync.js";
3
+
4
+ export function useBackgroundSync() {
5
+ const [state, setState] = useState({
6
+ supported: "serviceWorker" in navigator && "SyncManager" in window,
7
+ registered: false,
8
+ lastSync: null,
9
+ });
10
+
11
+ useEffect(() => {
12
+ const onSyncComplete = (e) => {
13
+ setState((s) => ({
14
+ ...s,
15
+ registered: true,
16
+ lastSync: { succeeded: e.detail.succeeded, failed: e.detail.failed },
17
+ }));
18
+ };
19
+
20
+ window.addEventListener("background-sync-complete", onSyncComplete);
21
+ return () => {
22
+ window.removeEventListener("background-sync-complete", onSyncComplete);
23
+ };
24
+ }, []);
25
+
26
+ const triggerSync = useCallback(async () => {
27
+ await retrySync();
28
+ }, []);
29
+
30
+ return { ...state, triggerSync };
31
+ }
@@ -0,0 +1,31 @@
1
+ import { useState, useEffect, useCallback } from "react";
2
+ import { retrySync } from "../background-sync.ts";
3
+
4
+ export function useBackgroundSync() {
5
+ const [state, setState] = useState({
6
+ supported: "serviceWorker" in navigator && "SyncManager" in window,
7
+ registered: false,
8
+ lastSync: null as { succeeded: number; failed: number } | null,
9
+ });
10
+
11
+ useEffect(() => {
12
+ const onSyncComplete = (e: CustomEvent) => {
13
+ setState((s) => ({
14
+ ...s,
15
+ registered: true,
16
+ lastSync: { succeeded: e.detail.succeeded, failed: e.detail.failed },
17
+ }));
18
+ };
19
+
20
+ window.addEventListener("background-sync-complete", onSyncComplete);
21
+ return () => {
22
+ window.removeEventListener("background-sync-complete", onSyncComplete);
23
+ };
24
+ }, []);
25
+
26
+ const triggerSync = useCallback(async () => {
27
+ await retrySync();
28
+ }, []);
29
+
30
+ return { ...state, triggerSync };
31
+ }
@@ -0,0 +1,19 @@
1
+ import { useCallback } from "react";
2
+ import { invalidateByTag, invalidateByTags } from "../cache.js";
3
+ import { invalidateUrl } from "../invalidation-tags.js";
4
+
5
+ export function useCacheInvalidation() {
6
+ const invalidateTag = useCallback(async (tag) => {
7
+ await invalidateByTag(tag);
8
+ }, []);
9
+
10
+ const invalidateTags = useCallback(async (tags) => {
11
+ await invalidateByTags(tags);
12
+ }, []);
13
+
14
+ const invalidateCacheUrl = useCallback(async (url) => {
15
+ await invalidateUrl(url);
16
+ }, []);
17
+
18
+ return { invalidateByTag: invalidateTag, invalidateByTags: invalidateTags, invalidateUrl: invalidateCacheUrl };
19
+ }
@@ -0,0 +1,19 @@
1
+ import { useCallback } from "react";
2
+ import { invalidateByTag, invalidateByTags } from "../cache.ts";
3
+ import { invalidateUrl } from "../invalidation-tags.ts";
4
+
5
+ export function useCacheInvalidation() {
6
+ const invalidateTag = useCallback(async (tag: string) => {
7
+ await invalidateByTag(tag);
8
+ }, []);
9
+
10
+ const invalidateTags = useCallback(async (tags: string[]) => {
11
+ await invalidateByTags(tags);
12
+ }, []);
13
+
14
+ const invalidateCacheUrl = useCallback(async (url: string) => {
15
+ await invalidateUrl(url);
16
+ }, []);
17
+
18
+ return { invalidateByTag: invalidateTag, invalidateByTags: invalidateTags, invalidateUrl: invalidateCacheUrl };
19
+ }
@@ -0,0 +1,94 @@
1
+ import { useState, useEffect, useCallback, useRef, startTransition } from "react";
2
+ import { fetchWithCache } from "../fetch-wrapper.js";
3
+ import { generateTags } from "../invalidation-tags.js";
4
+
5
+ export function useCachedFetch(url, options = {}) {
6
+ const [data, setData] = useState(null);
7
+ const [error, setError] = useState(null);
8
+ const [loading, setLoading] = useState(true);
9
+ const [refetchCount, setRefetchCount] = useState(0);
10
+ const optionsRef = useRef(options);
11
+ useEffect(() => { optionsRef.current = options; }, [options]);
12
+
13
+ const refetch = useCallback(() => setRefetchCount((c) => c + 1), []);
14
+
15
+ const isEnabled = options.enabled !== false && url != null;
16
+
17
+ useEffect(() => {
18
+ if (!isEnabled) {
19
+ setLoading(false);
20
+ return;
21
+ }
22
+ let cancelled = false;
23
+ const controller = new AbortController();
24
+ startTransition(() => setLoading(true));
25
+
26
+ const doFetch = async () => {
27
+ try {
28
+ const { response } = await fetchWithCache(url, {
29
+ ...optionsRef.current,
30
+ signal: controller.signal,
31
+ });
32
+ if (cancelled) return;
33
+ if (response) {
34
+ setData(await response.json());
35
+ } else {
36
+ setData(null);
37
+ }
38
+ if (!cancelled) setError(null);
39
+ } catch (err) {
40
+ if (!cancelled && err instanceof DOMException && err.name === "AbortError") return;
41
+ if (!cancelled) setError(err instanceof Error ? err : new Error(String(err)));
42
+ } finally {
43
+ if (!cancelled) setLoading(false);
44
+ }
45
+ };
46
+
47
+ doFetch();
48
+ return () => {
49
+ cancelled = true;
50
+ controller.abort();
51
+ };
52
+ }, [url, refetchCount, isEnabled]);
53
+
54
+ // Auto-refetch on cache invalidation
55
+ useEffect(() => {
56
+ if (!isEnabled) return;
57
+ const onInvalidated = (e) => {
58
+ const detail = e.detail;
59
+ const tags = detail?.tags;
60
+ if (!tags || !Array.isArray(tags)) return;
61
+ const urlTags = generateTags(url);
62
+ if (tags.some((t) => urlTags.includes(t))) {
63
+ setRefetchCount((c) => c + 1);
64
+ }
65
+ };
66
+ window.addEventListener("cache-invalidated", onInvalidated);
67
+ return () => window.removeEventListener("cache-invalidated", onInvalidated);
68
+ }, [url, isEnabled]);
69
+
70
+ // Auto-refetch on window focus
71
+ useEffect(() => {
72
+ if (!options.refetchOnWindowFocus || !isEnabled) return;
73
+ const onFocus = () => refetch();
74
+ window.addEventListener("focus", onFocus);
75
+ return () => window.removeEventListener("focus", onFocus);
76
+ }, [options.refetchOnWindowFocus, refetch, isEnabled]);
77
+
78
+ // Auto-refetch on reconnect
79
+ useEffect(() => {
80
+ if (!options.refetchOnReconnect || !isEnabled) return;
81
+ const onOnline = () => refetch();
82
+ window.addEventListener("online", onOnline);
83
+ return () => window.removeEventListener("online", onOnline);
84
+ }, [options.refetchOnReconnect, refetch, isEnabled]);
85
+
86
+ // Auto-refetch on interval
87
+ useEffect(() => {
88
+ if (!options.refetchInterval || options.refetchInterval <= 0 || !isEnabled) return;
89
+ const id = setInterval(refetch, options.refetchInterval * 1000);
90
+ return () => clearInterval(id);
91
+ }, [options.refetchInterval, refetch, isEnabled]);
92
+
93
+ return { data, error, loading, refetch };
94
+ }
@@ -0,0 +1,112 @@
1
+ import {
2
+ useState,
3
+ useEffect,
4
+ useCallback,
5
+ useRef,
6
+ startTransition,
7
+ } from "react";
8
+ import { fetchWithCache } from "../fetch-wrapper.ts";
9
+ import { generateTags } from "../invalidation-tags.ts";
10
+ import type { FetchWithCacheOptions } from "../fetch-wrapper.ts";
11
+
12
+ export function useCachedFetch<T>(
13
+ url: string | null,
14
+ options: FetchWithCacheOptions & {
15
+ refetchOnWindowFocus?: boolean;
16
+ refetchOnReconnect?: boolean;
17
+ refetchInterval?: number;
18
+ enabled?: boolean;
19
+ } = {},
20
+ ) {
21
+ const [data, setData] = useState<T | null>(null);
22
+ const [error, setError] = useState<Error | null>(null);
23
+ const [loading, setLoading] = useState(true);
24
+ const [refetchCount, setRefetchCount] = useState(0);
25
+ const optionsRef = useRef(options);
26
+ useEffect(() => {
27
+ optionsRef.current = options;
28
+ }, [options]);
29
+
30
+ const refetch = useCallback(() => setRefetchCount((c) => c + 1), []);
31
+
32
+ const isEnabled = options.enabled !== false && url != null;
33
+
34
+ useEffect(() => {
35
+ if (!isEnabled) {
36
+ setLoading(false);
37
+ return;
38
+ }
39
+ let cancelled = false;
40
+ const controller = new AbortController();
41
+ startTransition(() => setLoading(true));
42
+
43
+ const doFetch = async () => {
44
+ try {
45
+ const { response } = await fetchWithCache(url, {
46
+ ...optionsRef.current,
47
+ signal: controller.signal,
48
+ });
49
+ if (cancelled) return;
50
+ if (response) {
51
+ setData(await response.json());
52
+ } else {
53
+ setData(null);
54
+ }
55
+ if (!cancelled) setError(null);
56
+ } catch (err) {
57
+ if (!cancelled && err instanceof DOMException && err.name === "AbortError") return;
58
+ if (!cancelled)
59
+ setError(err instanceof Error ? err : new Error(String(err)));
60
+ } finally {
61
+ if (!cancelled) setLoading(false);
62
+ }
63
+ };
64
+
65
+ doFetch();
66
+ return () => {
67
+ cancelled = true;
68
+ controller.abort();
69
+ };
70
+ }, [url, refetchCount, isEnabled]);
71
+
72
+ // Auto-refetch on cache invalidation
73
+ useEffect(() => {
74
+ if (!isEnabled) return;
75
+ const onInvalidated = (e: Event) => {
76
+ const detail = (e as CustomEvent).detail;
77
+ const tags = detail?.tags;
78
+ if (!tags || !Array.isArray(tags)) return;
79
+ const urlTags = generateTags(url!);
80
+ if (tags.some((t: string) => urlTags.includes(t))) {
81
+ setRefetchCount((c) => c + 1);
82
+ }
83
+ };
84
+ window.addEventListener("cache-invalidated", onInvalidated);
85
+ return () => window.removeEventListener("cache-invalidated", onInvalidated);
86
+ }, [url, isEnabled]);
87
+
88
+ // Auto-refetch on window focus
89
+ useEffect(() => {
90
+ if (!options.refetchOnWindowFocus || !isEnabled) return;
91
+ const onFocus = () => refetch();
92
+ window.addEventListener("focus", onFocus);
93
+ return () => window.removeEventListener("focus", onFocus);
94
+ }, [options.refetchOnWindowFocus, refetch, isEnabled]);
95
+
96
+ // Auto-refetch on reconnect
97
+ useEffect(() => {
98
+ if (!options.refetchOnReconnect || !isEnabled) return;
99
+ const onOnline = () => refetch();
100
+ window.addEventListener("online", onOnline);
101
+ return () => window.removeEventListener("online", onOnline);
102
+ }, [options.refetchOnReconnect, refetch, isEnabled]);
103
+
104
+ // Auto-refetch on interval
105
+ useEffect(() => {
106
+ if (!options.refetchInterval || options.refetchInterval <= 0 || !isEnabled) return;
107
+ const id = setInterval(refetch, options.refetchInterval * 1000);
108
+ return () => clearInterval(id);
109
+ }, [options.refetchInterval, refetch, isEnabled]);
110
+
111
+ return { data, error, loading, refetch };
112
+ }