@swoff/cli 0.3.5 → 0.3.7

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 (121) hide show
  1. package/README.md +610 -24
  2. package/bin/swoff +8 -14
  3. package/dist/__tests__/assemble-sw.test.js +17 -3
  4. package/dist/__tests__/assemble-sw.test.js.map +1 -1
  5. package/dist/__tests__/cli-integration.test.js +9 -9
  6. package/dist/__tests__/cli-integration.test.js.map +1 -1
  7. package/dist/__tests__/config-types.test.js +10 -9
  8. package/dist/__tests__/config-types.test.js.map +1 -1
  9. package/dist/__tests__/file-generators.test.js +65 -68
  10. package/dist/__tests__/file-generators.test.js.map +1 -1
  11. package/dist/__tests__/loader.test.js +12 -14
  12. package/dist/__tests__/loader.test.js.map +1 -1
  13. package/dist/__tests__/validator.test.js +41 -22
  14. package/dist/__tests__/validator.test.js.map +1 -1
  15. package/dist/index.js +2 -2
  16. package/dist/index.js.map +1 -1
  17. package/dist/lib/cli/help.js +3 -3
  18. package/dist/lib/cli/help.js.map +1 -1
  19. package/dist/lib/commands/add.js +11 -5
  20. package/dist/lib/commands/add.js.map +1 -1
  21. package/dist/lib/commands/clean.js +5 -0
  22. package/dist/lib/commands/clean.js.map +1 -1
  23. package/dist/lib/commands/generate-guide.js +43 -13
  24. package/dist/lib/commands/generate-guide.js.map +1 -1
  25. package/dist/lib/commands/generate.js +7 -3
  26. package/dist/lib/commands/generate.js.map +1 -1
  27. package/dist/lib/commands/info.js +149 -32
  28. package/dist/lib/commands/info.js.map +1 -1
  29. package/dist/lib/commands/init.js +6 -2
  30. package/dist/lib/commands/init.js.map +1 -1
  31. package/dist/lib/commands/validate.js +3 -1
  32. package/dist/lib/commands/validate.js.map +1 -1
  33. package/dist/lib/config/validator.js +25 -16
  34. package/dist/lib/config/validator.js.map +1 -1
  35. package/dist/lib/generators/file-generators/auth-fetch.js +29 -34
  36. package/dist/lib/generators/file-generators/auth-fetch.js.map +1 -1
  37. package/dist/lib/generators/file-generators/auth-state.js +8 -5
  38. package/dist/lib/generators/file-generators/auth-state.js.map +1 -1
  39. package/dist/lib/generators/file-generators/auth-store.js +181 -41
  40. package/dist/lib/generators/file-generators/auth-store.js.map +1 -1
  41. package/dist/lib/generators/file-generators/auth-user.js +28 -32
  42. package/dist/lib/generators/file-generators/auth-user.js.map +1 -1
  43. package/dist/lib/generators/file-generators/background-sync.js +9 -5
  44. package/dist/lib/generators/file-generators/background-sync.js.map +1 -1
  45. package/dist/lib/generators/file-generators/cache.js +8 -5
  46. package/dist/lib/generators/file-generators/cache.js.map +1 -1
  47. package/dist/lib/generators/file-generators/client-injector.js +101 -0
  48. package/dist/lib/generators/file-generators/client-injector.js.map +1 -0
  49. package/dist/lib/generators/file-generators/context.js +7 -6
  50. package/dist/lib/generators/file-generators/context.js.map +1 -1
  51. package/dist/lib/generators/file-generators/fetch-wrapper.js +196 -41
  52. package/dist/lib/generators/file-generators/fetch-wrapper.js.map +1 -1
  53. package/dist/lib/generators/file-generators/generate-hooks.js +23 -151
  54. package/dist/lib/generators/file-generators/generate-hooks.js.map +1 -1
  55. package/dist/lib/generators/file-generators/guide-generator.js +450 -0
  56. package/dist/lib/generators/file-generators/guide-generator.js.map +1 -0
  57. package/dist/lib/generators/file-generators/invalidation-tags.js +12 -10
  58. package/dist/lib/generators/file-generators/invalidation-tags.js.map +1 -1
  59. package/dist/lib/generators/file-generators/mutation-queue.js +65 -87
  60. package/dist/lib/generators/file-generators/mutation-queue.js.map +1 -1
  61. package/dist/lib/generators/file-generators/mutation-reconcile.js +57 -0
  62. package/dist/lib/generators/file-generators/mutation-reconcile.js.map +1 -0
  63. package/dist/lib/generators/file-generators/push.js +143 -0
  64. package/dist/lib/generators/file-generators/push.js.map +1 -0
  65. package/dist/lib/generators/file-generators/pwa-install.js +41 -9
  66. package/dist/lib/generators/file-generators/pwa-install.js.map +1 -1
  67. package/dist/lib/generators/file-generators/quick-readme.js +88 -0
  68. package/dist/lib/generators/file-generators/quick-readme.js.map +1 -0
  69. package/dist/lib/generators/file-generators/reconcile.js +7 -12
  70. package/dist/lib/generators/file-generators/reconcile.js.map +1 -1
  71. package/dist/lib/generators/file-generators/store.js +30 -20
  72. package/dist/lib/generators/file-generators/store.js.map +1 -1
  73. package/dist/lib/generators/file-generators/sw-generator-build.js +38 -17
  74. package/dist/lib/generators/file-generators/sw-generator-build.js.map +1 -1
  75. package/dist/lib/generators/file-generators/sw-injector.js +82 -111
  76. package/dist/lib/generators/file-generators/sw-injector.js.map +1 -1
  77. package/dist/lib/generators/file-generators/sw-push.js +67 -0
  78. package/dist/lib/generators/file-generators/sw-push.js.map +1 -0
  79. package/dist/lib/generators/file-generators/sw-template.js +3 -1
  80. package/dist/lib/generators/file-generators/sw-template.js.map +1 -1
  81. package/dist/lib/generators/file-generators/type-definitions.js +45 -22
  82. package/dist/lib/generators/file-generators/type-definitions.js.map +1 -1
  83. package/dist/lib/generators/sw-generator.js +27 -19
  84. package/dist/lib/generators/sw-generator.js.map +1 -1
  85. package/dist/lib/generators/sw-sections/activate-handler.js +6 -2
  86. package/dist/lib/generators/sw-sections/activate-handler.js.map +1 -1
  87. package/dist/lib/generators/sw-sections/assemble-sw.js +36 -12
  88. package/dist/lib/generators/sw-sections/assemble-sw.js.map +1 -1
  89. package/dist/lib/generators/sw-sections/config-header.js +1 -1
  90. package/dist/lib/generators/sw-sections/config-header.js.map +1 -1
  91. package/dist/lib/generators/sw-sections/default-template.js +1 -30
  92. package/dist/lib/generators/sw-sections/default-template.js.map +1 -1
  93. package/dist/lib/generators/sw-sections/fetch-handler.js +176 -90
  94. package/dist/lib/generators/sw-sections/fetch-handler.js.map +1 -1
  95. package/dist/lib/generators/sw-sections/install-handler.js +12 -10
  96. package/dist/lib/generators/sw-sections/install-handler.js.map +1 -1
  97. package/dist/lib/generators/sw-sections/tag-management.js +36 -5
  98. package/dist/lib/generators/sw-sections/tag-management.js.map +1 -1
  99. package/dist/lib/generators/swoff-files-generator.js +14 -12
  100. package/dist/lib/generators/swoff-files-generator.js.map +1 -1
  101. package/dist/lib/shared/config-types.js +26 -9
  102. package/dist/lib/shared/config-types.js.map +1 -1
  103. package/dist/lib/utils/build-script.js +35 -0
  104. package/dist/lib/utils/build-script.js.map +1 -0
  105. package/package.json +3 -2
  106. package/templates/hooks/useAuth.jsx +30 -0
  107. package/templates/hooks/useAuth.tsx +30 -0
  108. package/templates/hooks/useBackgroundSync.jsx +31 -0
  109. package/templates/hooks/useBackgroundSync.tsx +31 -0
  110. package/templates/hooks/useCacheInvalidation.jsx +19 -0
  111. package/templates/hooks/useCacheInvalidation.tsx +19 -0
  112. package/templates/hooks/useCachedFetch.jsx +55 -0
  113. package/templates/hooks/useCachedFetch.tsx +69 -0
  114. package/templates/hooks/useMutationQueue.jsx +34 -0
  115. package/templates/hooks/useMutationQueue.tsx +34 -0
  116. package/templates/hooks/useNetworkStatus.jsx +19 -0
  117. package/templates/hooks/useNetworkStatus.tsx +19 -0
  118. package/templates/hooks/usePushSubscription.jsx +67 -0
  119. package/templates/hooks/usePushSubscription.tsx +67 -0
  120. package/templates/hooks/useSWUpdate.jsx +76 -0
  121. package/templates/hooks/useSWUpdate.tsx +76 -0
@@ -0,0 +1,67 @@
1
+ import { useState, useEffect, useCallback } from "react";
2
+ import {
3
+ subscribeToPush,
4
+ unsubscribeFromPush,
5
+ isSubscribed,
6
+ getPushSubscription,
7
+ } from "../push.ts";
8
+
9
+ export function usePushSubscription(vapidPublicKey: string) {
10
+ const [state, setState] = useState({
11
+ subscribed: false,
12
+ subscription: null as PushSubscription | null,
13
+ permission: Notification.permission,
14
+ loading: true,
15
+ });
16
+
17
+ useEffect(() => {
18
+ let cancelled = false;
19
+
20
+ isSubscribed().then((subscribed) => {
21
+ if (cancelled) return;
22
+ if (subscribed) {
23
+ getPushSubscription().then((sub) => {
24
+ if (cancelled) return;
25
+ setState({ subscribed: true, subscription: sub, permission: Notification.permission, loading: false });
26
+ });
27
+ } else {
28
+ setState({ subscribed: false, subscription: null, permission: Notification.permission, loading: false });
29
+ }
30
+ });
31
+
32
+ const onSubChanged = (e: CustomEvent) => {
33
+ if (cancelled) return;
34
+ if (!e.detail.subscribed) {
35
+ setState({ subscribed: false, subscription: null, permission: Notification.permission, loading: false });
36
+ } else {
37
+ getPushSubscription().then((sub) => {
38
+ if (cancelled) return;
39
+ setState({ subscribed: true, subscription: sub, permission: Notification.permission, loading: false });
40
+ });
41
+ }
42
+ };
43
+ const onPermissionChanged = (e: CustomEvent) => {
44
+ if (cancelled) return;
45
+ setState((s) => ({ ...s, permission: e.detail.permission }));
46
+ };
47
+
48
+ window.addEventListener("push-subscription-changed", onSubChanged);
49
+ window.addEventListener("push-permission-changed", onPermissionChanged);
50
+ return () => {
51
+ cancelled = true;
52
+ window.removeEventListener("push-subscription-changed", onSubChanged);
53
+ window.removeEventListener("push-permission-changed", onPermissionChanged);
54
+ };
55
+ }, []);
56
+
57
+ const subscribe = useCallback(async () => {
58
+ const sub = await subscribeToPush(vapidPublicKey);
59
+ return sub !== null;
60
+ }, [vapidPublicKey]);
61
+
62
+ const unsubscribe = useCallback(async () => {
63
+ await unsubscribeFromPush();
64
+ }, []);
65
+
66
+ return { ...state, subscribe, unsubscribe };
67
+ }
@@ -0,0 +1,76 @@
1
+ import { useState, useEffect, useCallback } from "react";
2
+ import { handleUpdateApproved } from "../sw/injector.js";
3
+
4
+ export function useSWUpdate() {
5
+ const [state, setState] = useState({
6
+ updateStatus: "idle",
7
+ currentVersion: window.currentSWVersion || null,
8
+ availableVersion: null,
9
+ progress: 0,
10
+ forceUpdate: false,
11
+ error: null,
12
+ });
13
+
14
+ useEffect(() => {
15
+ if (sessionStorage.getItem("sw-dismissed-update") === "true") return;
16
+
17
+ const onAvailable = (e) =>
18
+ setState((s) => ({
19
+ ...s,
20
+ updateStatus: "available",
21
+ availableVersion: e.detail.version,
22
+ forceUpdate: window.swUpdateRequired || false,
23
+ }));
24
+ const onProgress = (e) =>
25
+ setState((s) => ({ ...s, updateStatus: "downloading", progress: e.detail.percent }));
26
+ const onReady = () =>
27
+ setState((s) => ({ ...s, updateStatus: "idle", progress: 0 }));
28
+ const onError = () =>
29
+ setState((s) => ({ ...s, error: "SW registration failed" }));
30
+
31
+ window.addEventListener("sw-update-available", onAvailable);
32
+ window.addEventListener("sw-progress", onProgress);
33
+ window.addEventListener("sw-ready", onReady);
34
+ window.addEventListener("sw-error", onError);
35
+ return () => {
36
+ window.removeEventListener("sw-update-available", onAvailable);
37
+ window.removeEventListener("sw-progress", onProgress);
38
+ window.removeEventListener("sw-ready", onReady);
39
+ window.removeEventListener("sw-error", onError);
40
+ };
41
+ }, []);
42
+
43
+ const acceptUpdate = useCallback(async () => {
44
+ if (!state.availableVersion) return;
45
+ await handleUpdateApproved(state.availableVersion);
46
+ }, [state.availableVersion]);
47
+
48
+ const dismissUpdate = useCallback(() => {
49
+ sessionStorage.setItem("sw-dismissed-update", "true");
50
+ setState((s) => ({ ...s, updateStatus: "idle" }));
51
+ }, []);
52
+
53
+ return { ...state, acceptUpdate, dismissUpdate };
54
+ }
55
+
56
+ export function useSWProgress() {
57
+ const [state, setState] = useState({
58
+ status: "idle",
59
+ progress: 0,
60
+ });
61
+
62
+ useEffect(() => {
63
+ const onProgress = (e) =>
64
+ setState({ status: "installing", progress: e.detail.percent });
65
+ const onReady = () => setState({ status: "idle", progress: 0 });
66
+
67
+ window.addEventListener("sw-progress", onProgress);
68
+ window.addEventListener("sw-ready", onReady);
69
+ return () => {
70
+ window.removeEventListener("sw-progress", onProgress);
71
+ window.removeEventListener("sw-ready", onReady);
72
+ };
73
+ }, []);
74
+
75
+ return state;
76
+ }
@@ -0,0 +1,76 @@
1
+ import { useState, useEffect, useCallback } from "react";
2
+ import { handleUpdateApproved } from "../sw/injector.ts";
3
+
4
+ export function useSWUpdate() {
5
+ const [state, setState] = useState({
6
+ updateStatus: "idle" as "idle" | "available" | "downloading" | "ready",
7
+ currentVersion: (window.currentSWVersion as string | undefined) || null,
8
+ availableVersion: null as string | null,
9
+ progress: 0 as number,
10
+ forceUpdate: false,
11
+ error: null as string | null,
12
+ });
13
+
14
+ useEffect(() => {
15
+ if (sessionStorage.getItem("sw-dismissed-update") === "true") return;
16
+
17
+ const onAvailable = (e: WindowEventMap["sw-update-available"]) =>
18
+ setState((s) => ({
19
+ ...s,
20
+ updateStatus: "available",
21
+ availableVersion: e.detail.version,
22
+ forceUpdate: window.swUpdateRequired || false,
23
+ }));
24
+ const onProgress = (e: WindowEventMap["sw-progress"]) =>
25
+ setState((s) => ({ ...s, updateStatus: "downloading", progress: e.detail.percent }));
26
+ const onReady = () =>
27
+ setState((s) => ({ ...s, updateStatus: "idle", progress: 0 }));
28
+ const onError = () =>
29
+ setState((s) => ({ ...s, error: "SW registration failed" }));
30
+
31
+ window.addEventListener("sw-update-available", onAvailable);
32
+ window.addEventListener("sw-progress", onProgress);
33
+ window.addEventListener("sw-ready", onReady);
34
+ window.addEventListener("sw-error", onError);
35
+ return () => {
36
+ window.removeEventListener("sw-update-available", onAvailable);
37
+ window.removeEventListener("sw-progress", onProgress);
38
+ window.removeEventListener("sw-ready", onReady);
39
+ window.removeEventListener("sw-error", onError);
40
+ };
41
+ }, []);
42
+
43
+ const acceptUpdate = useCallback(async () => {
44
+ if (!state.availableVersion) return;
45
+ await handleUpdateApproved(state.availableVersion);
46
+ }, [state.availableVersion]);
47
+
48
+ const dismissUpdate = useCallback(() => {
49
+ sessionStorage.setItem("sw-dismissed-update", "true");
50
+ setState((s) => ({ ...s, updateStatus: "idle" }));
51
+ }, []);
52
+
53
+ return { ...state, acceptUpdate, dismissUpdate };
54
+ }
55
+
56
+ export function useSWProgress() {
57
+ const [state, setState] = useState({
58
+ status: "idle" as "idle" | "installing",
59
+ progress: 0 as number,
60
+ });
61
+
62
+ useEffect(() => {
63
+ const onProgress = (e: WindowEventMap["sw-progress"]) =>
64
+ setState({ status: "installing", progress: e.detail.percent });
65
+ const onReady = () => setState({ status: "idle", progress: 0 });
66
+
67
+ window.addEventListener("sw-progress", onProgress);
68
+ window.addEventListener("sw-ready", onReady);
69
+ return () => {
70
+ window.removeEventListener("sw-progress", onProgress);
71
+ window.removeEventListener("sw-ready", onReady);
72
+ };
73
+ }, []);
74
+
75
+ return state;
76
+ }