@go-go-scope/adapter-svelte 2.7.0
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.
- package/LICENSE +21 -0
- package/README.md +73 -0
- package/dist/index.d.mts +280 -0
- package/dist/index.mjs +222 -0
- package/package.json +49 -0
- package/src/index.ts +609 -0
- package/tests/TestComponent.svelte +189 -0
- package/tests/svelte.test.ts +199 -0
- package/tsconfig.json +11 -0
- package/vitest.config.ts +13 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 thelinuxlich (Alisson Cavalcante Agiani)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# @go-go-scope/adapter-svelte
|
|
2
|
+
|
|
3
|
+
Svelte 5 runes integration for go-go-scope. Provides reactive stores that work with Svelte's `$` prefix.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @go-go-scope/adapter-svelte
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```svelte
|
|
14
|
+
<script>
|
|
15
|
+
import { createScope, createTask, createChannel } from '@go-go-scope/adapter-svelte';
|
|
16
|
+
|
|
17
|
+
// Create a reactive scope
|
|
18
|
+
const scope = createScope({ name: 'my-component' });
|
|
19
|
+
|
|
20
|
+
// Execute tasks with reactive state
|
|
21
|
+
const task = createTask(async () => {
|
|
22
|
+
const response = await fetch('/api/data');
|
|
23
|
+
return response.json();
|
|
24
|
+
}, { immediate: true });
|
|
25
|
+
|
|
26
|
+
// Use channels for communication
|
|
27
|
+
const channel = createChannel<string>();
|
|
28
|
+
|
|
29
|
+
async function sendMessage() {
|
|
30
|
+
await channel.send('Hello!');
|
|
31
|
+
}
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<div>
|
|
35
|
+
{#if $task.isLoading}
|
|
36
|
+
<p>Loading...</p>
|
|
37
|
+
{:else if $task.error}
|
|
38
|
+
<p>Error: {$task.error.message}</p>
|
|
39
|
+
{:else}
|
|
40
|
+
<p>Data: {$task.data}</p>
|
|
41
|
+
{/if}
|
|
42
|
+
|
|
43
|
+
<button onclick={sendMessage}>Send Message</button>
|
|
44
|
+
<p>Latest: {$channel.latest}</p>
|
|
45
|
+
</div>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## API
|
|
49
|
+
|
|
50
|
+
### `createScope(options?)`
|
|
51
|
+
Creates a reactive scope that auto-disposes on component destroy.
|
|
52
|
+
|
|
53
|
+
### `createTask(factory, options?)`
|
|
54
|
+
Creates a reactive task store with `data`, `error`, `isLoading`, `isReady`, and `execute()`.
|
|
55
|
+
|
|
56
|
+
### `createParallel(factories, options?)`
|
|
57
|
+
Executes tasks in parallel with reactive progress tracking.
|
|
58
|
+
|
|
59
|
+
### `createChannel(options?)`
|
|
60
|
+
Creates a reactive channel for Go-style communication.
|
|
61
|
+
|
|
62
|
+
### `createBroadcast()`
|
|
63
|
+
Creates a reactive broadcast channel for pub/sub patterns.
|
|
64
|
+
|
|
65
|
+
### `createPolling(factory, options)`
|
|
66
|
+
Creates a reactive polling mechanism.
|
|
67
|
+
|
|
68
|
+
### `createStore(initialValue)`
|
|
69
|
+
Creates a simple reactive store compatible with Svelte's `$` prefix.
|
|
70
|
+
|
|
71
|
+
## License
|
|
72
|
+
|
|
73
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import * as svelte_store from 'svelte/store';
|
|
2
|
+
import { Readable } from 'svelte/store';
|
|
3
|
+
import { Result, Scope } from 'go-go-scope';
|
|
4
|
+
export { BroadcastChannel, Channel, Result, Scope } from 'go-go-scope';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Options for creating a scope
|
|
8
|
+
*/
|
|
9
|
+
interface CreateScopeOptions {
|
|
10
|
+
/** Scope name for debugging */
|
|
11
|
+
name?: string;
|
|
12
|
+
/** Timeout in milliseconds */
|
|
13
|
+
timeout?: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Reactive scope with automatic cleanup
|
|
17
|
+
*/
|
|
18
|
+
interface ReactiveScope extends Scope {
|
|
19
|
+
/** Whether the scope is currently active */
|
|
20
|
+
readonly isActive: Readable<boolean>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Create a reactive scope that automatically disposes on component destroy.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```svelte
|
|
27
|
+
* <script>
|
|
28
|
+
* const s = createScope({ name: "my-component" });
|
|
29
|
+
*
|
|
30
|
+
* // Scope is automatically disposed when component is destroyed
|
|
31
|
+
* const [err, result] = await s.task(() => fetchData());
|
|
32
|
+
* </script>
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
declare function createScope(options?: CreateScopeOptions): ReactiveScope;
|
|
36
|
+
/**
|
|
37
|
+
* Options for creating a task
|
|
38
|
+
*/
|
|
39
|
+
interface CreateTaskOptions<T> {
|
|
40
|
+
/** Task name for debugging */
|
|
41
|
+
name?: string;
|
|
42
|
+
/** Whether to execute immediately */
|
|
43
|
+
immediate?: boolean;
|
|
44
|
+
/** Timeout in milliseconds */
|
|
45
|
+
timeout?: number;
|
|
46
|
+
/** Retry options */
|
|
47
|
+
retry?: {
|
|
48
|
+
maxRetries?: number;
|
|
49
|
+
delay?: number;
|
|
50
|
+
};
|
|
51
|
+
/** Initial data value */
|
|
52
|
+
initialData?: T;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Reactive task state
|
|
56
|
+
*/
|
|
57
|
+
interface TaskState<T> {
|
|
58
|
+
/** Current data (undefined if not loaded) */
|
|
59
|
+
readonly data: Readable<T | undefined>;
|
|
60
|
+
/** Error if task failed */
|
|
61
|
+
readonly error: Readable<Error | undefined>;
|
|
62
|
+
/** Whether task is currently running */
|
|
63
|
+
readonly isLoading: Readable<boolean>;
|
|
64
|
+
/** Whether task has been executed */
|
|
65
|
+
readonly isReady: Readable<boolean>;
|
|
66
|
+
/** Execute the task */
|
|
67
|
+
readonly execute: () => Promise<Result<Error, T>>;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Create a reactive task that integrates with Svelte's store system.
|
|
71
|
+
* Returns a store-like object that can be used with `$` prefix.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```svelte
|
|
75
|
+
* <script>
|
|
76
|
+
* const task = createTask(
|
|
77
|
+
* async () => fetchUser(userId),
|
|
78
|
+
* { immediate: true }
|
|
79
|
+
* );
|
|
80
|
+
* </script>
|
|
81
|
+
*
|
|
82
|
+
* {#if $task.isLoading}
|
|
83
|
+
* <p>Loading...</p>
|
|
84
|
+
* {:else if $task.error}
|
|
85
|
+
* <p>Error: {$task.error.message}</p>
|
|
86
|
+
* {:else}
|
|
87
|
+
* <p>{$task.data.name}</p>
|
|
88
|
+
* {/if}
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
declare function createTask<T>(factory: () => Promise<T>, options?: CreateTaskOptions<T>): TaskState<T>;
|
|
92
|
+
/**
|
|
93
|
+
* Options for parallel execution
|
|
94
|
+
*/
|
|
95
|
+
interface CreateParallelOptions {
|
|
96
|
+
/** Concurrency limit */
|
|
97
|
+
concurrency?: number;
|
|
98
|
+
/** Whether to execute immediately */
|
|
99
|
+
immediate?: boolean;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Reactive parallel task state
|
|
103
|
+
*/
|
|
104
|
+
interface ParallelState<T> {
|
|
105
|
+
/** Results from all tasks */
|
|
106
|
+
readonly results: Readable<(T | undefined)[]>;
|
|
107
|
+
/** Errors from failed tasks */
|
|
108
|
+
readonly errors: Readable<(Error | undefined)[]>;
|
|
109
|
+
/** Whether any task is running */
|
|
110
|
+
readonly isLoading: Readable<boolean>;
|
|
111
|
+
/** Progress percentage (0-100) */
|
|
112
|
+
readonly progress: Readable<number>;
|
|
113
|
+
/** Execute all tasks */
|
|
114
|
+
readonly execute: () => Promise<Result<Error, T>[]>;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Create reactive parallel task execution.
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```svelte
|
|
121
|
+
* <script>
|
|
122
|
+
* const parallel = createParallel(
|
|
123
|
+
* urls.map(url => () => fetch(url).then(r => r.json())),
|
|
124
|
+
* { concurrency: 3, immediate: true }
|
|
125
|
+
* );
|
|
126
|
+
* </script>
|
|
127
|
+
*
|
|
128
|
+
* <progress value={$parallel.progress} max="100" />
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
declare function createParallel<T>(factories: (() => Promise<T>)[], options?: CreateParallelOptions): ParallelState<T>;
|
|
132
|
+
/**
|
|
133
|
+
* Options for creating a channel
|
|
134
|
+
*/
|
|
135
|
+
interface CreateChannelOptions {
|
|
136
|
+
/** Buffer size */
|
|
137
|
+
bufferSize?: number;
|
|
138
|
+
/** Maximum history to keep */
|
|
139
|
+
historySize?: number;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Reactive channel state
|
|
143
|
+
*/
|
|
144
|
+
interface ChannelState<T> {
|
|
145
|
+
/** Latest received value */
|
|
146
|
+
readonly latest: Readable<T | undefined>;
|
|
147
|
+
/** History of values */
|
|
148
|
+
readonly history: Readable<readonly T[]>;
|
|
149
|
+
/** Whether channel is closed */
|
|
150
|
+
readonly isClosed: Readable<boolean>;
|
|
151
|
+
/** Send a value */
|
|
152
|
+
readonly send: (value: T) => Promise<void>;
|
|
153
|
+
/** Close the channel */
|
|
154
|
+
readonly close: () => void;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Create a reactive channel for Go-style communication.
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```svelte
|
|
161
|
+
* <script>
|
|
162
|
+
* const ch = createChannel<string>();
|
|
163
|
+
*
|
|
164
|
+
* async function sendMessage() {
|
|
165
|
+
* await ch.send("Hello!");
|
|
166
|
+
* }
|
|
167
|
+
* </script>
|
|
168
|
+
*
|
|
169
|
+
* <p>Latest: {$ch.latest}</p>
|
|
170
|
+
* <button onclick={sendMessage}>Send</button>
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
declare function createChannel<T>(options?: CreateChannelOptions): ChannelState<T>;
|
|
174
|
+
/**
|
|
175
|
+
* Reactive broadcast state
|
|
176
|
+
*/
|
|
177
|
+
interface BroadcastState<T> {
|
|
178
|
+
/** Latest broadcasted value */
|
|
179
|
+
readonly latest: Readable<T | undefined>;
|
|
180
|
+
/** Subscribe to broadcasts */
|
|
181
|
+
readonly subscribe: (callback: (value: T) => void) => {
|
|
182
|
+
unsubscribe: () => void;
|
|
183
|
+
};
|
|
184
|
+
/** Broadcast a value */
|
|
185
|
+
readonly broadcast: (value: T) => void;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Create a reactive broadcast channel.
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* ```svelte
|
|
192
|
+
* <script>
|
|
193
|
+
* const bus = createBroadcast<string>();
|
|
194
|
+
*
|
|
195
|
+
* // Subscribe
|
|
196
|
+
* bus.subscribe(msg => console.log(msg));
|
|
197
|
+
*
|
|
198
|
+
* function send() {
|
|
199
|
+
* bus.broadcast("Hello!");
|
|
200
|
+
* }
|
|
201
|
+
* </script>
|
|
202
|
+
*
|
|
203
|
+
* <p>Latest: {$bus.latest}</p>
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
declare function createBroadcast<T>(): BroadcastState<T>;
|
|
207
|
+
/**
|
|
208
|
+
* Options for polling
|
|
209
|
+
*/
|
|
210
|
+
interface CreatePollingOptions {
|
|
211
|
+
/** Interval in milliseconds */
|
|
212
|
+
interval: number;
|
|
213
|
+
/** Whether to start immediately */
|
|
214
|
+
immediate?: boolean;
|
|
215
|
+
/** Continue when tab is hidden */
|
|
216
|
+
continueOnHidden?: boolean;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Reactive polling state
|
|
220
|
+
*/
|
|
221
|
+
interface PollingState<T> {
|
|
222
|
+
/** Latest data */
|
|
223
|
+
readonly data: Readable<T | undefined>;
|
|
224
|
+
/** Error if polling failed */
|
|
225
|
+
readonly error: Readable<Error | undefined>;
|
|
226
|
+
/** Whether currently polling */
|
|
227
|
+
readonly isPolling: Readable<boolean>;
|
|
228
|
+
/** Number of polls completed */
|
|
229
|
+
readonly pollCount: Readable<number>;
|
|
230
|
+
/** Start polling */
|
|
231
|
+
readonly start: () => void;
|
|
232
|
+
/** Stop polling */
|
|
233
|
+
readonly stop: () => void;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Create a reactive polling mechanism.
|
|
237
|
+
*
|
|
238
|
+
* @example
|
|
239
|
+
* ```svelte
|
|
240
|
+
* <script>
|
|
241
|
+
* const poller = createPolling(
|
|
242
|
+
* async () => fetchLatestData(),
|
|
243
|
+
* { interval: 5000, immediate: true }
|
|
244
|
+
* );
|
|
245
|
+
* </script>
|
|
246
|
+
*
|
|
247
|
+
* {#if $poller.data}
|
|
248
|
+
* <p>{$poller.data}</p>
|
|
249
|
+
* {/if}
|
|
250
|
+
* <button onclick={() => $poller.stop()}>Stop</button>
|
|
251
|
+
* ```
|
|
252
|
+
*/
|
|
253
|
+
declare function createPolling<T>(factory: () => Promise<T>, options: CreatePollingOptions): PollingState<T>;
|
|
254
|
+
/**
|
|
255
|
+
* Create a reactive value that can be subscribed to (Svelte store contract).
|
|
256
|
+
* Compatible with Svelte 5's `$` prefix.
|
|
257
|
+
*
|
|
258
|
+
* @example
|
|
259
|
+
* ```svelte
|
|
260
|
+
* <script>
|
|
261
|
+
* const count = createStore(0);
|
|
262
|
+
*
|
|
263
|
+
* function increment() {
|
|
264
|
+
* $count++;
|
|
265
|
+
* }
|
|
266
|
+
* </script>
|
|
267
|
+
*
|
|
268
|
+
* <button onclick={increment}>
|
|
269
|
+
* Count: {$count}
|
|
270
|
+
* </button>
|
|
271
|
+
* ```
|
|
272
|
+
*/
|
|
273
|
+
declare function createStore<T>(initialValue: T): {
|
|
274
|
+
subscribe: (this: void, run: svelte_store.Subscriber<T>, invalidate?: () => void) => svelte_store.Unsubscriber;
|
|
275
|
+
set: (this: void, value: T) => void;
|
|
276
|
+
update: (this: void, updater: svelte_store.Updater<T>) => void;
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
export { createBroadcast, createChannel, createParallel, createPolling, createScope, createStore, createTask };
|
|
280
|
+
export type { BroadcastState, ChannelState, CreateChannelOptions, CreateParallelOptions, CreatePollingOptions, CreateScopeOptions, CreateTaskOptions, ParallelState, PollingState, ReactiveScope, TaskState };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { scope, BroadcastChannel } from 'go-go-scope';
|
|
2
|
+
import { onDestroy } from 'svelte';
|
|
3
|
+
import { writable } from 'svelte/store';
|
|
4
|
+
|
|
5
|
+
function createScope(options = {}) {
|
|
6
|
+
const isActive = writable(true);
|
|
7
|
+
const s = scope({
|
|
8
|
+
name: options.name,
|
|
9
|
+
timeout: options.timeout
|
|
10
|
+
});
|
|
11
|
+
onDestroy(() => {
|
|
12
|
+
isActive.set(false);
|
|
13
|
+
s[Symbol.asyncDispose]().catch(() => {
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
return Object.assign(s, {
|
|
17
|
+
isActive: { subscribe: isActive.subscribe }
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
function createTask(factory, options = {}) {
|
|
21
|
+
const s = createScope({ name: options.name ?? "createTask" });
|
|
22
|
+
const data = writable(options.initialData);
|
|
23
|
+
const error = writable(void 0);
|
|
24
|
+
const isLoading = writable(false);
|
|
25
|
+
const isReady = writable(false);
|
|
26
|
+
const execute = async () => {
|
|
27
|
+
isLoading.set(true);
|
|
28
|
+
error.set(void 0);
|
|
29
|
+
try {
|
|
30
|
+
const [err, result] = await s.task(
|
|
31
|
+
async () => await factory(),
|
|
32
|
+
{
|
|
33
|
+
timeout: options.timeout,
|
|
34
|
+
retry: options.retry
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
if (err) {
|
|
38
|
+
error.set(err instanceof Error ? err : new Error(String(err)));
|
|
39
|
+
data.set(void 0);
|
|
40
|
+
return [err, void 0];
|
|
41
|
+
}
|
|
42
|
+
data.set(result);
|
|
43
|
+
isReady.set(true);
|
|
44
|
+
return [void 0, result];
|
|
45
|
+
} finally {
|
|
46
|
+
isLoading.set(false);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
if (options.immediate) {
|
|
50
|
+
execute();
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
data: { subscribe: data.subscribe },
|
|
54
|
+
error: { subscribe: error.subscribe },
|
|
55
|
+
isLoading: { subscribe: isLoading.subscribe },
|
|
56
|
+
isReady: { subscribe: isReady.subscribe },
|
|
57
|
+
execute
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function createParallel(factories, options = {}) {
|
|
61
|
+
const s = createScope({ name: "createParallel" });
|
|
62
|
+
const results = writable([]);
|
|
63
|
+
const errors = writable([]);
|
|
64
|
+
const isLoading = writable(false);
|
|
65
|
+
const progress = writable(0);
|
|
66
|
+
const execute = async () => {
|
|
67
|
+
isLoading.set(true);
|
|
68
|
+
progress.set(0);
|
|
69
|
+
results.set(new Array(factories.length).fill(void 0));
|
|
70
|
+
errors.set(new Array(factories.length).fill(void 0));
|
|
71
|
+
try {
|
|
72
|
+
const taskFactories = factories.map((factory, index) => {
|
|
73
|
+
return async () => {
|
|
74
|
+
const [err, result] = await s.task(async () => await factory());
|
|
75
|
+
if (err) {
|
|
76
|
+
errors.update((e) => {
|
|
77
|
+
e[index] = err instanceof Error ? err : new Error(String(err));
|
|
78
|
+
return e;
|
|
79
|
+
});
|
|
80
|
+
} else {
|
|
81
|
+
results.update((r) => {
|
|
82
|
+
r[index] = result;
|
|
83
|
+
return r;
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
progress.set(Math.round((index + 1) / factories.length * 100));
|
|
87
|
+
return [err, result];
|
|
88
|
+
};
|
|
89
|
+
});
|
|
90
|
+
return await s.parallel(taskFactories, {
|
|
91
|
+
concurrency: options.concurrency
|
|
92
|
+
});
|
|
93
|
+
} finally {
|
|
94
|
+
isLoading.set(false);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
if (options.immediate) {
|
|
98
|
+
execute();
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
results: { subscribe: results.subscribe },
|
|
102
|
+
errors: { subscribe: errors.subscribe },
|
|
103
|
+
isLoading: { subscribe: isLoading.subscribe },
|
|
104
|
+
progress: { subscribe: progress.subscribe },
|
|
105
|
+
execute
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function createChannel(options = {}) {
|
|
109
|
+
const s = createScope({ name: "createChannel" });
|
|
110
|
+
const ch = s.channel(options.bufferSize ?? 0);
|
|
111
|
+
const latest = writable(void 0);
|
|
112
|
+
const history = writable([]);
|
|
113
|
+
const isClosed = writable(false);
|
|
114
|
+
const receiveLoop = async () => {
|
|
115
|
+
for await (const value of ch) {
|
|
116
|
+
latest.set(value);
|
|
117
|
+
history.update((h) => [...h.slice(-(options.historySize ?? 100)), value]);
|
|
118
|
+
}
|
|
119
|
+
isClosed.set(true);
|
|
120
|
+
};
|
|
121
|
+
receiveLoop();
|
|
122
|
+
return {
|
|
123
|
+
latest: { subscribe: latest.subscribe },
|
|
124
|
+
history: { subscribe: history.subscribe },
|
|
125
|
+
isClosed: { subscribe: isClosed.subscribe },
|
|
126
|
+
send: async (value) => {
|
|
127
|
+
await ch.send(value);
|
|
128
|
+
},
|
|
129
|
+
close: () => {
|
|
130
|
+
ch.close();
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function createBroadcast() {
|
|
135
|
+
const bc = new BroadcastChannel();
|
|
136
|
+
const latest = writable(void 0);
|
|
137
|
+
return {
|
|
138
|
+
latest: { subscribe: latest.subscribe },
|
|
139
|
+
subscribe: (callback) => {
|
|
140
|
+
(async () => {
|
|
141
|
+
for await (const value of bc.subscribe()) {
|
|
142
|
+
latest.set(value);
|
|
143
|
+
callback(value);
|
|
144
|
+
}
|
|
145
|
+
})();
|
|
146
|
+
return {
|
|
147
|
+
unsubscribe: () => bc.close()
|
|
148
|
+
};
|
|
149
|
+
},
|
|
150
|
+
broadcast: async (value) => {
|
|
151
|
+
await bc.send(value);
|
|
152
|
+
latest.set(value);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function createPolling(factory, options) {
|
|
157
|
+
const s = createScope({ name: "createPolling" });
|
|
158
|
+
const data = writable(void 0);
|
|
159
|
+
const error = writable(void 0);
|
|
160
|
+
const isPolling = writable(false);
|
|
161
|
+
const pollCount = writable(0);
|
|
162
|
+
const poller = s.poll(
|
|
163
|
+
async () => {
|
|
164
|
+
try {
|
|
165
|
+
const result = await factory();
|
|
166
|
+
return { success: true, value: result };
|
|
167
|
+
} catch (e) {
|
|
168
|
+
return { success: false, error: e };
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
(result) => {
|
|
172
|
+
pollCount.update((c) => c + 1);
|
|
173
|
+
if (result.success) {
|
|
174
|
+
data.set(result.value);
|
|
175
|
+
} else {
|
|
176
|
+
error.set(result.error instanceof Error ? result.error : new Error(String(result.error)));
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
{ interval: options.interval, immediate: options.immediate }
|
|
180
|
+
);
|
|
181
|
+
const updateStatus = () => {
|
|
182
|
+
const status = poller.status();
|
|
183
|
+
isPolling.set(status.running);
|
|
184
|
+
};
|
|
185
|
+
if (!options.continueOnHidden && typeof document !== "undefined") {
|
|
186
|
+
const handler = () => {
|
|
187
|
+
if (document.hidden) {
|
|
188
|
+
poller.stop();
|
|
189
|
+
updateStatus();
|
|
190
|
+
} else if (options.immediate !== false) {
|
|
191
|
+
poller.start();
|
|
192
|
+
updateStatus();
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
document.addEventListener("visibilitychange", handler);
|
|
196
|
+
}
|
|
197
|
+
updateStatus();
|
|
198
|
+
return {
|
|
199
|
+
data: { subscribe: data.subscribe },
|
|
200
|
+
error: { subscribe: error.subscribe },
|
|
201
|
+
isPolling: { subscribe: isPolling.subscribe },
|
|
202
|
+
pollCount: { subscribe: pollCount.subscribe },
|
|
203
|
+
start: () => {
|
|
204
|
+
poller.start();
|
|
205
|
+
updateStatus();
|
|
206
|
+
},
|
|
207
|
+
stop: () => {
|
|
208
|
+
poller.stop();
|
|
209
|
+
updateStatus();
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
function createStore(initialValue) {
|
|
214
|
+
const { subscribe, set, update } = writable(initialValue);
|
|
215
|
+
return {
|
|
216
|
+
subscribe,
|
|
217
|
+
set,
|
|
218
|
+
update
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export { createBroadcast, createChannel, createParallel, createPolling, createScope, createStore, createTask };
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@go-go-scope/adapter-svelte",
|
|
3
|
+
"version": "2.7.0",
|
|
4
|
+
"description": "Svelte 5 runes integration for go-go-scope",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.mts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.mts",
|
|
11
|
+
"default": "./dist/index.mjs"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"go-go-scope",
|
|
16
|
+
"svelte",
|
|
17
|
+
"svelte5",
|
|
18
|
+
"runes",
|
|
19
|
+
"reactivity"
|
|
20
|
+
],
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=24.0.0"
|
|
23
|
+
},
|
|
24
|
+
"author": "thelinuxlich",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"svelte": "^5.0.0",
|
|
28
|
+
"go-go-scope": "2.7.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@biomejs/biome": "^2.4.4",
|
|
32
|
+
"@sveltejs/vite-plugin-svelte": "^4.0.0",
|
|
33
|
+
"@testing-library/svelte": "^5.2.0",
|
|
34
|
+
"@types/node": "^24",
|
|
35
|
+
"jsdom": "^24.0.0",
|
|
36
|
+
"pkgroll": "^2.26.3",
|
|
37
|
+
"svelte": "^5.0.0",
|
|
38
|
+
"typescript": "^5.9.3",
|
|
39
|
+
"vitest": "^4.0.18",
|
|
40
|
+
"go-go-scope": "2.7.0"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "pkgroll --clean-dist",
|
|
44
|
+
"lint": "biome check --write src/",
|
|
45
|
+
"test": "vitest run",
|
|
46
|
+
"clean": "rm -rf dist",
|
|
47
|
+
"typecheck": "tsc --noEmit"
|
|
48
|
+
}
|
|
49
|
+
}
|