@swoff/cli 0.4.1 → 0.4.4

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 (116) hide show
  1. package/dist/lib/commands/generate-guide.js +15 -15
  2. package/dist/lib/commands/generate-guide.js.map +1 -1
  3. package/dist/lib/commands/init.js +52 -6
  4. package/dist/lib/commands/init.js.map +1 -1
  5. package/dist/lib/config/validator.js +1 -1
  6. package/dist/lib/config/validator.js.map +1 -1
  7. package/dist/lib/generators/file-generators/client-injector-bundle.js +2 -1
  8. package/dist/lib/generators/file-generators/client-injector-bundle.js.map +1 -1
  9. package/dist/lib/generators/file-generators/client-injector.js +2 -1
  10. package/dist/lib/generators/file-generators/client-injector.js.map +1 -1
  11. package/dist/lib/generators/file-generators/context.js +4 -1
  12. package/dist/lib/generators/file-generators/context.js.map +1 -1
  13. package/dist/lib/generators/file-generators/generate-framework-adapters.js +28 -22
  14. package/dist/lib/generators/file-generators/generate-framework-adapters.js.map +1 -1
  15. package/dist/lib/generators/sw-sections/activate-handler.js +1 -5
  16. package/dist/lib/generators/sw-sections/activate-handler.js.map +1 -1
  17. package/dist/lib/generators/sw-sections/background-precache.js +8 -8
  18. package/dist/lib/generators/sw-sections/batch-refresh-queue.js +2 -5
  19. package/dist/lib/generators/sw-sections/batch-refresh-queue.js.map +1 -1
  20. package/dist/lib/generators/sw-sections/fetch-handler.js +14 -3
  21. package/dist/lib/generators/sw-sections/fetch-handler.js.map +1 -1
  22. package/dist/lib/shared/config-types.js +1 -0
  23. package/dist/lib/shared/config-types.js.map +1 -1
  24. package/dist/lib/utils/detect-framework.js +16 -0
  25. package/dist/lib/utils/detect-framework.js.map +1 -1
  26. package/dist/runtime/client-injector-bundle.js +2 -2
  27. package/dist/runtime/client-injector-bundle.js.map +1 -1
  28. package/dist/runtime/client-injector.js +3 -2
  29. package/dist/runtime/client-injector.js.map +1 -1
  30. package/dist/runtime/gql-wrapper.js +3 -1
  31. package/dist/runtime/gql-wrapper.js.map +1 -1
  32. package/dist/runtime/swoff-api-bundle.js +2 -1
  33. package/dist/runtime/swoff-api-bundle.js.map +1 -1
  34. package/package.json +1 -1
  35. package/templates/react/{useOfflineAnalytics.jsx → useSwoffAnalytics.jsx} +3 -3
  36. package/templates/react/{useOfflineAnalytics.tsx → useSwoffAnalytics.tsx} +3 -3
  37. package/templates/react/{useAuth.jsx → useSwoffAuth.jsx} +2 -2
  38. package/templates/react/{useAuth.tsx → useSwoffAuth.tsx} +2 -2
  39. package/templates/react/{useCachedFetch.jsx → useSwoffFetch.jsx} +6 -6
  40. package/templates/react/{useCachedFetch.tsx → useSwoffFetch.tsx} +7 -7
  41. package/templates/react/{useMutation.jsx → useSwoffMutation.jsx} +3 -3
  42. package/templates/react/{useMutation.tsx → useSwoffMutation.tsx} +3 -3
  43. package/templates/react/{useMutationState.jsx → useSwoffMutationState.jsx} +1 -1
  44. package/templates/react/{useMutationState.tsx → useSwoffMutationState.tsx} +2 -2
  45. package/templates/react/{useNetworkStatus.jsx → useSwoffNetwork.jsx} +2 -2
  46. package/templates/react/{useNetworkStatus.tsx → useSwoffNetwork.tsx} +2 -2
  47. package/templates/react/{usePrecacheProgress.jsx → useSwoffPrecache.jsx} +4 -7
  48. package/templates/react/{usePrecacheProgress.tsx → useSwoffPrecache.tsx} +4 -7
  49. package/templates/react/{usePrefetch.jsx → useSwoffPrefetch.jsx} +2 -2
  50. package/templates/react/{usePrefetch.tsx → useSwoffPrefetch.tsx} +2 -2
  51. package/templates/react/{usePushSubscription.jsx → useSwoffPush.jsx} +1 -1
  52. package/templates/react/{usePushSubscription.tsx → useSwoffPush.tsx} +1 -1
  53. package/templates/react/{usePwaInstall.jsx → useSwoffPwa.jsx} +1 -1
  54. package/templates/react/{usePwaInstall.tsx → useSwoffPwa.tsx} +1 -1
  55. package/templates/react/{useMutationQueue.jsx → useSwoffQueue.jsx} +2 -2
  56. package/templates/react/{useMutationQueue.tsx → useSwoffQueue.tsx} +2 -2
  57. package/templates/react/{useStorageEstimate.jsx → useSwoffStorage.jsx} +2 -2
  58. package/templates/react/{useStorageEstimate.tsx → useSwoffStorage.tsx} +2 -2
  59. package/templates/react/{useBackgroundSync.jsx → useSwoffSync.jsx} +1 -1
  60. package/templates/react/{useBackgroundSync.tsx → useSwoffSync.tsx} +1 -1
  61. package/templates/svelte/useSwoffAnalytics.js +31 -0
  62. package/templates/svelte/useSwoffAnalytics.ts +37 -0
  63. package/templates/svelte/useSwoffAuth.js +95 -0
  64. package/templates/svelte/useSwoffAuth.ts +96 -0
  65. package/templates/svelte/useSwoffFetch.js +97 -0
  66. package/templates/svelte/useSwoffFetch.ts +112 -0
  67. package/templates/svelte/useSwoffMutation.js +110 -0
  68. package/templates/svelte/useSwoffMutation.ts +141 -0
  69. package/templates/svelte/useSwoffMutationState.js +27 -0
  70. package/templates/svelte/useSwoffMutationState.ts +28 -0
  71. package/templates/svelte/useSwoffNetwork.js +75 -0
  72. package/templates/svelte/useSwoffNetwork.ts +75 -0
  73. package/templates/svelte/useSwoffPrecache.js +19 -0
  74. package/templates/svelte/useSwoffPrecache.ts +19 -0
  75. package/templates/svelte/useSwoffPrefetch.js +19 -0
  76. package/templates/svelte/useSwoffPrefetch.ts +20 -0
  77. package/templates/svelte/useSwoffPush.js +82 -0
  78. package/templates/svelte/useSwoffPush.ts +82 -0
  79. package/templates/svelte/useSwoffPwa.js +27 -0
  80. package/templates/svelte/useSwoffPwa.ts +27 -0
  81. package/templates/svelte/useSwoffQueue.js +57 -0
  82. package/templates/svelte/useSwoffQueue.ts +67 -0
  83. package/templates/svelte/useSwoffReset.js +21 -0
  84. package/templates/svelte/useSwoffReset.ts +32 -0
  85. package/templates/svelte/useSwoffStorage.js +47 -0
  86. package/templates/svelte/useSwoffStorage.ts +47 -0
  87. package/templates/svelte/useSwoffSync.js +31 -0
  88. package/templates/svelte/useSwoffSync.ts +31 -0
  89. package/templates/vue/useSwoffAnalytics.js +46 -0
  90. package/templates/vue/useSwoffAnalytics.ts +54 -0
  91. package/templates/vue/useSwoffAuth.js +106 -0
  92. package/templates/vue/useSwoffAuth.ts +118 -0
  93. package/templates/vue/useSwoffFetch.js +127 -0
  94. package/templates/vue/useSwoffFetch.ts +143 -0
  95. package/templates/vue/useSwoffMutation.js +124 -0
  96. package/templates/vue/useSwoffMutation.ts +155 -0
  97. package/templates/vue/useSwoffMutationState.js +35 -0
  98. package/templates/vue/useSwoffMutationState.ts +36 -0
  99. package/templates/vue/useSwoffNetwork.js +86 -0
  100. package/templates/vue/useSwoffNetwork.ts +89 -0
  101. package/templates/vue/useSwoffPrecache.js +19 -0
  102. package/templates/vue/useSwoffPrecache.ts +19 -0
  103. package/templates/vue/useSwoffPrefetch.js +33 -0
  104. package/templates/vue/useSwoffPrefetch.ts +41 -0
  105. package/templates/vue/useSwoffPush.js +81 -0
  106. package/templates/vue/useSwoffPush.ts +81 -0
  107. package/templates/vue/useSwoffPwa.js +27 -0
  108. package/templates/vue/useSwoffPwa.ts +27 -0
  109. package/templates/vue/useSwoffQueue.js +70 -0
  110. package/templates/vue/useSwoffQueue.ts +82 -0
  111. package/templates/vue/useSwoffReset.js +32 -0
  112. package/templates/vue/useSwoffReset.ts +39 -0
  113. package/templates/vue/useSwoffStorage.js +56 -0
  114. package/templates/vue/useSwoffStorage.ts +57 -0
  115. package/templates/vue/useSwoffSync.js +30 -0
  116. package/templates/vue/useSwoffSync.ts +30 -0
@@ -0,0 +1,110 @@
1
+ import { writable } from "svelte/store";
2
+ import { fetchWithCache } from "../fetch/core.js";
3
+ import {
4
+ trackMutation,
5
+ resolveMutation,
6
+ rejectMutation,
7
+ } from "../mutation/state.js";
8
+
9
+ export function useSwoffMutation(url, options = {}) {
10
+ const lastResult = writable(null);
11
+ const isLoading = writable(false);
12
+ const mutationId = writable(null);
13
+
14
+ const inFlightKeys = new Set();
15
+
16
+ async function mutate(body, callbacks) {
17
+ const key = options.mutationKey;
18
+ if (key && inFlightKeys.has(key)) return { status: "skipped" };
19
+ if (key) inFlightKeys.add(key);
20
+
21
+ let retriesLeft =
22
+ options.retry === true
23
+ ? Infinity
24
+ : typeof options.retry === "number"
25
+ ? options.retry
26
+ : 0;
27
+
28
+ const mid = "mut-" + crypto.randomUUID();
29
+ mutationId.set(mid);
30
+ trackMutation(mid, "pending");
31
+ isLoading.set(true);
32
+
33
+ options.onMutate?.();
34
+
35
+ const attempt = async () => {
36
+ try {
37
+ const {
38
+ mutationKey,
39
+ onMutate,
40
+ onSuccess,
41
+ onError,
42
+ onSettled,
43
+ retry,
44
+ ...fetchOnlyOptions
45
+ } = options;
46
+ const fetchOptions = { ...fetchOnlyOptions, body };
47
+ const { response, queued } = await fetchWithCache(url, fetchOptions);
48
+ if (queued) {
49
+ resolveMutation(mid, null);
50
+ isLoading.set(false);
51
+ const r = { status: "queued" };
52
+ lastResult.set(r);
53
+ options.onSettled?.();
54
+ callbacks?.onSettled?.();
55
+ if (key) inFlightKeys.delete(key);
56
+ return r;
57
+ }
58
+ const data = await response.json();
59
+ resolveMutation(mid, data);
60
+ isLoading.set(false);
61
+ const r = { status: "success", data };
62
+ lastResult.set(r);
63
+ options.onSuccess?.(data);
64
+ callbacks?.onSuccess?.(data);
65
+ options.onSettled?.();
66
+ callbacks?.onSettled?.();
67
+ if (key) inFlightKeys.delete(key);
68
+ return r;
69
+ } catch (err) {
70
+ if (retriesLeft > 0) {
71
+ retriesLeft--;
72
+ await new Promise((r) => setTimeout(r, 1000));
73
+ return attempt();
74
+ }
75
+ const error = err instanceof Error ? err : new Error(String(err));
76
+ rejectMutation(mid, error);
77
+ isLoading.set(false);
78
+ const r = { status: "error", error };
79
+ lastResult.set(r);
80
+ options.onError?.(error);
81
+ callbacks?.onError?.(error);
82
+ options.onSettled?.();
83
+ callbacks?.onSettled?.();
84
+ if (key) inFlightKeys.delete(key);
85
+ return r;
86
+ }
87
+ };
88
+
89
+ return attempt();
90
+ }
91
+
92
+ function reset() {
93
+ lastResult.set(null);
94
+ isLoading.set(false);
95
+ }
96
+
97
+ return {
98
+ mutate,
99
+ isLoading,
100
+ isIdle: lastResult,
101
+ isQueued: lastResult,
102
+ isSuccess: lastResult,
103
+ isError: lastResult,
104
+ data: lastResult,
105
+ error: lastResult,
106
+ lastResult,
107
+ reset,
108
+ mutationId,
109
+ };
110
+ }
@@ -0,0 +1,141 @@
1
+ import { writable } from "svelte/store";
2
+ import { fetchWithCache } from "../fetch/core";
3
+ import {
4
+ trackMutation,
5
+ resolveMutation,
6
+ rejectMutation,
7
+ } from "../mutation/state";
8
+ import type { FetchWithCacheOptions } from "../fetch/core";
9
+
10
+ export interface MutateCallbacks<TData> {
11
+ onSuccess?: (data: TData) => void;
12
+ onError?: (error: Error) => void;
13
+ onSettled?: () => void;
14
+ }
15
+
16
+ export interface UseMutationOptions<TData> extends FetchWithCacheOptions {
17
+ onMutate?: () => void;
18
+ onSuccess?: (data: TData) => void;
19
+ onError?: (error: Error) => void;
20
+ onSettled?: () => void;
21
+ mutationKey?: string;
22
+ retry?: number | boolean;
23
+ }
24
+
25
+ export type MutateResult<T> =
26
+ | { status: "skipped" }
27
+ | { status: "queued" }
28
+ | { status: "success"; data: T }
29
+ | { status: "error"; error: Error };
30
+
31
+ export function useSwoffMutation<TData = unknown>(
32
+ url: string,
33
+ options: UseMutationOptions<TData> = {},
34
+ ) {
35
+ const lastResult = writable<MutateResult<TData> | null>(null);
36
+ const isLoading = writable(false);
37
+ const mutationId = writable<string | null>(null);
38
+
39
+ const inFlightKeys = new Set<string>();
40
+
41
+ async function mutate(
42
+ body?: unknown,
43
+ callbacks?: MutateCallbacks<TData>,
44
+ ): Promise<MutateResult<TData>> {
45
+ const key = options.mutationKey;
46
+ if (key && inFlightKeys.has(key)) return { status: "skipped" };
47
+ if (key) inFlightKeys.add(key);
48
+
49
+ let retriesLeft: number =
50
+ options.retry === true
51
+ ? Infinity
52
+ : typeof options.retry === "number"
53
+ ? options.retry
54
+ : 0;
55
+
56
+ const mid = "mut-" + crypto.randomUUID();
57
+ mutationId.set(mid);
58
+ trackMutation(mid, "pending");
59
+ isLoading.set(true);
60
+
61
+ options.onMutate?.();
62
+
63
+ const attempt = async (): Promise<MutateResult<TData>> => {
64
+ try {
65
+ const {
66
+ mutationKey,
67
+ onMutate,
68
+ onSuccess,
69
+ onError,
70
+ onSettled,
71
+ retry,
72
+ ...fetchOnlyOptions
73
+ } = options;
74
+ const fetchOptions = { ...fetchOnlyOptions, body };
75
+ const { response, queued } = await fetchWithCache<TData>(
76
+ url,
77
+ fetchOptions as FetchWithCacheOptions,
78
+ );
79
+ if (queued) {
80
+ resolveMutation(mid, null);
81
+ isLoading.set(false);
82
+ const r: MutateResult<TData> = { status: "queued" };
83
+ lastResult.set(r);
84
+ options.onSettled?.();
85
+ callbacks?.onSettled?.();
86
+ if (key) inFlightKeys.delete(key);
87
+ return r;
88
+ }
89
+ const data: TData = await response.json();
90
+ resolveMutation(mid, data);
91
+ isLoading.set(false);
92
+ const r: MutateResult<TData> = { status: "success", data };
93
+ lastResult.set(r);
94
+ options.onSuccess?.(data);
95
+ callbacks?.onSuccess?.(data);
96
+ options.onSettled?.();
97
+ callbacks?.onSettled?.();
98
+ if (key) inFlightKeys.delete(key);
99
+ return r;
100
+ } catch (err) {
101
+ if (retriesLeft > 0) {
102
+ retriesLeft--;
103
+ await new Promise((r) => setTimeout(r, 1000));
104
+ return attempt();
105
+ }
106
+ const error = err instanceof Error ? err : new Error(String(err));
107
+ rejectMutation(mid, error);
108
+ isLoading.set(false);
109
+ const r: MutateResult<TData> = { status: "error", error };
110
+ lastResult.set(r);
111
+ options.onError?.(error);
112
+ callbacks?.onError?.(error);
113
+ options.onSettled?.();
114
+ callbacks?.onSettled?.();
115
+ if (key) inFlightKeys.delete(key);
116
+ return r;
117
+ }
118
+ };
119
+
120
+ return attempt();
121
+ }
122
+
123
+ function reset() {
124
+ lastResult.set(null);
125
+ isLoading.set(false);
126
+ }
127
+
128
+ return {
129
+ mutate,
130
+ isLoading,
131
+ isIdle: lastResult,
132
+ isQueued: lastResult,
133
+ isSuccess: lastResult,
134
+ isError: lastResult,
135
+ data: lastResult,
136
+ error: lastResult,
137
+ lastResult,
138
+ reset,
139
+ mutationId,
140
+ };
141
+ }
@@ -0,0 +1,27 @@
1
+ import { writable } from "svelte/store";
2
+ import { onMount } from "svelte";
3
+ import { getMutationState, onMutationStateChange } from "../mutation/state.js";
4
+
5
+ export function useSwoffMutationState(id) {
6
+ const state = writable(null);
7
+
8
+ function update() {
9
+ state.set(id ? (getMutationState(id) ?? null) : null);
10
+ }
11
+
12
+ onMount(update);
13
+
14
+ let cleanup;
15
+
16
+ onMount(() => {
17
+ const unsub = onMutationStateChange(update);
18
+ if (typeof unsub === "function") {
19
+ cleanup = unsub;
20
+ }
21
+ return () => {
22
+ cleanup?.();
23
+ };
24
+ });
25
+
26
+ return state;
27
+ }
@@ -0,0 +1,28 @@
1
+ import { writable } from "svelte/store";
2
+ import { onMount } from "svelte";
3
+ import { getMutationState, onMutationStateChange } from "../mutation/state";
4
+ import type { MutationState } from "../mutation/state";
5
+
6
+ export function useSwoffMutationState(id: string | null) {
7
+ const state = writable<MutationState | null>(null);
8
+
9
+ function update() {
10
+ state.set(id ? (getMutationState(id) ?? null) : null);
11
+ }
12
+
13
+ onMount(update);
14
+
15
+ let cleanup: (() => void) | undefined;
16
+
17
+ onMount(() => {
18
+ const unsub = onMutationStateChange(update);
19
+ if (typeof unsub === "function") {
20
+ cleanup = unsub;
21
+ }
22
+ return () => {
23
+ cleanup?.();
24
+ };
25
+ });
26
+
27
+ return state;
28
+ }
@@ -0,0 +1,75 @@
1
+ import { writable } from "svelte/store";
2
+ import { onMount } from "svelte";
3
+ import {
4
+ CONNECTIVITY_EVENT,
5
+ forceRetry,
6
+ getCurrentOnlineStatus,
7
+ } from "../connectivity.js";
8
+
9
+ export function useSwoffNetwork() {
10
+ const online = writable(true);
11
+ const wasOffline = writable(false);
12
+ const lastChangedAt = writable(null);
13
+ const effectiveType = writable(null);
14
+ const downlink = writable(null);
15
+ const isRetrying = writable(false);
16
+
17
+ let wasOfflineFlag = false;
18
+
19
+ onMount(() => {
20
+ if (!getCurrentOnlineStatus()) {
21
+ wasOfflineFlag = true;
22
+ online.set(false);
23
+ wasOffline.set(true);
24
+ lastChangedAt.set(Date.now());
25
+ }
26
+
27
+ const connection = navigator.connection;
28
+
29
+ function handleConnectivityChange(e) {
30
+ const isTrulyOnline = e.detail.online;
31
+ if (!isTrulyOnline) {
32
+ wasOfflineFlag = true;
33
+ } else {
34
+ wasOfflineFlag = false;
35
+ }
36
+ online.set(isTrulyOnline);
37
+ wasOffline.set(wasOfflineFlag);
38
+ lastChangedAt.set(Date.now());
39
+ }
40
+
41
+ function onTypeChange() {
42
+ if (!connection) return;
43
+ effectiveType.set(connection.effectiveType);
44
+ downlink.set(connection.downlink);
45
+ }
46
+
47
+ window.addEventListener(CONNECTIVITY_EVENT, handleConnectivityChange);
48
+ if (connection) {
49
+ connection.addEventListener("change", onTypeChange);
50
+ }
51
+
52
+ return () => {
53
+ window.removeEventListener(CONNECTIVITY_EVENT, handleConnectivityChange);
54
+ if (connection) {
55
+ connection.removeEventListener("change", onTypeChange);
56
+ }
57
+ };
58
+ });
59
+
60
+ async function retry() {
61
+ isRetrying.set(true);
62
+ await forceRetry();
63
+ isRetrying.set(false);
64
+ }
65
+
66
+ return {
67
+ online,
68
+ wasOffline,
69
+ lastChangedAt,
70
+ effectiveType,
71
+ downlink,
72
+ isRetrying,
73
+ retry,
74
+ };
75
+ }
@@ -0,0 +1,75 @@
1
+ import { writable } from "svelte/store";
2
+ import { onMount } from "svelte";
3
+ import {
4
+ CONNECTIVITY_EVENT,
5
+ forceRetry,
6
+ getCurrentOnlineStatus,
7
+ } from "../connectivity";
8
+
9
+ export function useSwoffNetwork() {
10
+ const online = writable(true);
11
+ const wasOffline = writable(false);
12
+ const lastChangedAt = writable<number | null>(null);
13
+ const effectiveType = writable<string | null>(null);
14
+ const downlink = writable<number | null>(null);
15
+ const isRetrying = writable(false);
16
+
17
+ let wasOfflineFlag = false;
18
+
19
+ onMount(() => {
20
+ if (!getCurrentOnlineStatus()) {
21
+ wasOfflineFlag = true;
22
+ online.set(false);
23
+ wasOffline.set(true);
24
+ lastChangedAt.set(Date.now());
25
+ }
26
+
27
+ const connection = navigator.connection;
28
+
29
+ function handleConnectivityChange(e: Event) {
30
+ const isTrulyOnline = (e as CustomEvent).detail.online;
31
+ if (!isTrulyOnline) {
32
+ wasOfflineFlag = true;
33
+ } else {
34
+ wasOfflineFlag = false;
35
+ }
36
+ online.set(isTrulyOnline);
37
+ wasOffline.set(wasOfflineFlag);
38
+ lastChangedAt.set(Date.now());
39
+ }
40
+
41
+ function onTypeChange() {
42
+ if (!connection) return;
43
+ effectiveType.set(connection.effectiveType);
44
+ downlink.set(connection.downlink);
45
+ }
46
+
47
+ window.addEventListener(CONNECTIVITY_EVENT, handleConnectivityChange);
48
+ if (connection) {
49
+ connection.addEventListener("change", onTypeChange);
50
+ }
51
+
52
+ return () => {
53
+ window.removeEventListener(CONNECTIVITY_EVENT, handleConnectivityChange);
54
+ if (connection) {
55
+ connection.removeEventListener("change", onTypeChange);
56
+ }
57
+ };
58
+ });
59
+
60
+ async function retry() {
61
+ isRetrying.set(true);
62
+ await forceRetry();
63
+ isRetrying.set(false);
64
+ }
65
+
66
+ return {
67
+ online,
68
+ wasOffline,
69
+ lastChangedAt,
70
+ effectiveType,
71
+ downlink,
72
+ isRetrying,
73
+ retry,
74
+ };
75
+ }
@@ -0,0 +1,19 @@
1
+ import { writable } from "svelte/store";
2
+ import { onMount } from "svelte";
3
+
4
+ export function useSwoffPrecache() {
5
+ const progress = writable(0);
6
+
7
+ function onProgress(e) {
8
+ progress.set(e.detail.percent);
9
+ }
10
+
11
+ onMount(() => {
12
+ window.addEventListener("sw-progress", onProgress);
13
+ return () => {
14
+ window.removeEventListener("sw-progress", onProgress);
15
+ };
16
+ });
17
+
18
+ return { progress };
19
+ }
@@ -0,0 +1,19 @@
1
+ import { writable } from "svelte/store";
2
+ import { onMount } from "svelte";
3
+
4
+ export function useSwoffPrecache() {
5
+ const progress = writable(0);
6
+
7
+ function onProgress(e: WindowEventMap["sw-progress"]) {
8
+ progress.set(e.detail.percent);
9
+ }
10
+
11
+ onMount(() => {
12
+ window.addEventListener("sw-progress", onProgress);
13
+ return () => {
14
+ window.removeEventListener("sw-progress", onProgress);
15
+ };
16
+ });
17
+
18
+ return { progress };
19
+ }
@@ -0,0 +1,19 @@
1
+ import { writable } from "svelte/store";
2
+ import { prefetchCache } from "../fetch/core.js";
3
+
4
+ export function useSwoffPrefetch() {
5
+ const prefetchList = writable([]);
6
+
7
+ function prefetch(url, options) {
8
+ prefetchCache(url, options);
9
+ prefetchList.update((list) =>
10
+ list.includes(url) ? list : [...list, url],
11
+ );
12
+ }
13
+
14
+ function clear() {
15
+ prefetchList.set([]);
16
+ }
17
+
18
+ return { prefetch, prefetchList, clear };
19
+ }
@@ -0,0 +1,20 @@
1
+ import { writable } from "svelte/store";
2
+ import { prefetchCache } from "../fetch/core";
3
+ import type { FetchWithCacheOptions } from "../fetch/core";
4
+
5
+ export function useSwoffPrefetch() {
6
+ const prefetchList = writable<string[]>([]);
7
+
8
+ function prefetch(url: string, options?: FetchWithCacheOptions) {
9
+ prefetchCache(url, options);
10
+ prefetchList.update((list) =>
11
+ list.includes(url) ? list : [...list, url],
12
+ );
13
+ }
14
+
15
+ function clear() {
16
+ prefetchList.set([]);
17
+ }
18
+
19
+ return { prefetch, prefetchList, clear };
20
+ }
@@ -0,0 +1,82 @@
1
+ import { writable } from "svelte/store";
2
+ import { onMount } from "svelte";
3
+ import {
4
+ subscribeToPush,
5
+ unsubscribeFromPush,
6
+ isSubscribed,
7
+ getPushSubscription,
8
+ } from "../realtime/notifications.js";
9
+
10
+ export function useSwoffPush() {
11
+ const subscribed = writable(false);
12
+ const subscription = writable(null);
13
+ const permission = writable(
14
+ typeof Notification !== "undefined" ? Notification.permission : "denied",
15
+ );
16
+ const loading = writable(true);
17
+
18
+ onMount(() => {
19
+ let cancelled = false;
20
+
21
+ isSubscribed().then((subd) => {
22
+ if (cancelled) return;
23
+ if (subd) {
24
+ getPushSubscription().then((sub) => {
25
+ if (cancelled) return;
26
+ subscribed.set(true);
27
+ subscription.set(sub);
28
+ permission.set(Notification.permission);
29
+ loading.set(false);
30
+ });
31
+ } else {
32
+ subscribed.set(false);
33
+ subscription.set(null);
34
+ permission.set(Notification.permission);
35
+ loading.set(false);
36
+ }
37
+ });
38
+
39
+ function onSubChanged(e) {
40
+ if (cancelled) return;
41
+ if (!e.detail.subscribed) {
42
+ subscribed.set(false);
43
+ subscription.set(null);
44
+ permission.set(Notification.permission);
45
+ loading.set(false);
46
+ } else {
47
+ getPushSubscription().then((sub) => {
48
+ if (cancelled) return;
49
+ subscribed.set(true);
50
+ subscription.set(sub);
51
+ permission.set(Notification.permission);
52
+ loading.set(false);
53
+ });
54
+ }
55
+ }
56
+
57
+ function onPermissionChanged(e) {
58
+ if (cancelled) return;
59
+ permission.set(e.detail.permission);
60
+ }
61
+
62
+ window.addEventListener("push-subscription-changed", onSubChanged);
63
+ window.addEventListener("push-permission-changed", onPermissionChanged);
64
+
65
+ return () => {
66
+ cancelled = true;
67
+ window.removeEventListener("push-subscription-changed", onSubChanged);
68
+ window.removeEventListener("push-permission-changed", onPermissionChanged);
69
+ };
70
+ });
71
+
72
+ async function subscribe() {
73
+ const sub = await subscribeToPush();
74
+ return sub !== null;
75
+ }
76
+
77
+ async function unsubscribe() {
78
+ await unsubscribeFromPush();
79
+ }
80
+
81
+ return { subscribed, subscription, permission, loading, subscribe, unsubscribe };
82
+ }
@@ -0,0 +1,82 @@
1
+ import { writable } from "svelte/store";
2
+ import { onMount } from "svelte";
3
+ import {
4
+ subscribeToPush,
5
+ unsubscribeFromPush,
6
+ isSubscribed,
7
+ getPushSubscription,
8
+ } from "../realtime/notifications";
9
+
10
+ export function useSwoffPush() {
11
+ const subscribed = writable(false);
12
+ const subscription = writable<PushSubscription | null>(null);
13
+ const permission = writable(
14
+ typeof Notification !== "undefined" ? Notification.permission : "denied",
15
+ );
16
+ const loading = writable(true);
17
+
18
+ onMount(() => {
19
+ let cancelled = false;
20
+
21
+ isSubscribed().then((subd) => {
22
+ if (cancelled) return;
23
+ if (subd) {
24
+ getPushSubscription().then((sub) => {
25
+ if (cancelled) return;
26
+ subscribed.set(true);
27
+ subscription.set(sub);
28
+ permission.set(Notification.permission);
29
+ loading.set(false);
30
+ });
31
+ } else {
32
+ subscribed.set(false);
33
+ subscription.set(null);
34
+ permission.set(Notification.permission);
35
+ loading.set(false);
36
+ }
37
+ });
38
+
39
+ function onSubChanged(e: CustomEvent) {
40
+ if (cancelled) return;
41
+ if (!e.detail.subscribed) {
42
+ subscribed.set(false);
43
+ subscription.set(null);
44
+ permission.set(Notification.permission);
45
+ loading.set(false);
46
+ } else {
47
+ getPushSubscription().then((sub) => {
48
+ if (cancelled) return;
49
+ subscribed.set(true);
50
+ subscription.set(sub);
51
+ permission.set(Notification.permission);
52
+ loading.set(false);
53
+ });
54
+ }
55
+ }
56
+
57
+ function onPermissionChanged(e: CustomEvent) {
58
+ if (cancelled) return;
59
+ permission.set(e.detail.permission);
60
+ }
61
+
62
+ window.addEventListener("push-subscription-changed", onSubChanged);
63
+ window.addEventListener("push-permission-changed", onPermissionChanged);
64
+
65
+ return () => {
66
+ cancelled = true;
67
+ window.removeEventListener("push-subscription-changed", onSubChanged);
68
+ window.removeEventListener("push-permission-changed", onPermissionChanged);
69
+ };
70
+ });
71
+
72
+ async function subscribe() {
73
+ const sub = await subscribeToPush();
74
+ return sub !== null;
75
+ }
76
+
77
+ async function unsubscribe() {
78
+ await unsubscribeFromPush();
79
+ }
80
+
81
+ return { subscribed, subscription, permission, loading, subscribe, unsubscribe };
82
+ }