edges-svelte 1.1.0 → 1.3.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/README.md +14 -44
- package/dist/client/NavigationSync.svelte.d.ts +3 -0
- package/dist/client/NavigationSync.svelte.js +115 -0
- package/dist/context/Context.d.ts +2 -2
- package/dist/context/Context.js +1 -1
- package/dist/plugin/EdgesAutoHandlePlugin.d.ts +49 -0
- package/dist/plugin/EdgesAutoHandlePlugin.js +97 -0
- package/dist/plugin/index.d.ts +1 -0
- package/dist/plugin/index.js +1 -0
- package/dist/provider/Provider.d.ts +26 -5
- package/dist/provider/Provider.js +94 -18
- package/dist/server/AutoWrapHandle.d.ts +11 -0
- package/dist/server/AutoWrapHandle.js +31 -0
- package/dist/server/EdgesHandle.d.ts +1 -9
- package/dist/server/EdgesHandle.js +71 -14
- package/dist/server/EdgesHandleSimplified.d.ts +25 -0
- package/dist/server/EdgesHandleSimplified.js +25 -0
- package/dist/server/index.d.ts +3 -1
- package/dist/server/index.js +3 -1
- package/dist/store/State.svelte.d.ts +1 -0
- package/dist/store/State.svelte.js +121 -28
- package/dist/store/index.d.ts +1 -1
- package/dist/store/index.js +1 -1
- package/package.json +7 -3
package/README.md
CHANGED
@@ -26,23 +26,17 @@ npm install edges-svelte
|
|
26
26
|
|
27
27
|
## Setup
|
28
28
|
|
29
|
-
To enable **EdgeS
|
29
|
+
To enable **EdgeS** install edgesPlugin, it will wrap your SvelteKit `handle` hook with AsyncLocalStorage:
|
30
30
|
|
31
31
|
```ts
|
32
|
-
//
|
33
|
-
import {
|
34
|
-
import {
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
//...Your handle code, use edgesEvent as a default svelte event (RequestEvent)
|
41
|
-
return resolve(edgesEvent, { transformPageChunk: ({ html }) => serialize(html) });
|
42
|
-
},
|
43
|
-
dev
|
44
|
-
);
|
45
|
-
};
|
32
|
+
// vite.config.ts
|
33
|
+
import { sveltekit } from '@sveltejs/kit/vite';
|
34
|
+
import { defineConfig } from 'vite';
|
35
|
+
import { edgesPlugin } from 'edges-svelte/plugin';
|
36
|
+
|
37
|
+
export default defineConfig({
|
38
|
+
plugins: [sveltekit(), edgesPlugin()]
|
39
|
+
});
|
46
40
|
```
|
47
41
|
|
48
42
|
---
|
@@ -53,8 +47,7 @@ export const handle: Handle = async ({ event, resolve }) => {
|
|
53
47
|
|
54
48
|
```ts
|
55
49
|
import { createStore } from 'edges-svelte';
|
56
|
-
|
57
|
-
const myStore = createStore('MyStore', ({ createState, createDerivedState }) => {
|
50
|
+
const myStore = createStore(({ createState, createDerivedState }) => {
|
58
51
|
// createState creates a writable, SSR-safe store with a unique key
|
59
52
|
const collection = createState<number[]>([]);
|
60
53
|
// createDerivedState creates a derived store, SSR-safe as well
|
@@ -94,7 +87,7 @@ const myStore = createStore('MyStore', ({ createState, createDerivedState }) =>
|
|
94
87
|
Stores are cached per request by their unique name (cache key). Calling the same store multiple times in the same request returns the cached instance.
|
95
88
|
|
96
89
|
```ts
|
97
|
-
const myCachedStore = createStore(
|
90
|
+
const myCachedStore = createStore(({ createState }) => {
|
98
91
|
const data = createState(() => 'cached data');
|
99
92
|
return { data };
|
100
93
|
});
|
@@ -154,12 +147,12 @@ counter.value += 1;
|
|
154
147
|
|
155
148
|
## Dependency Injection
|
156
149
|
|
157
|
-
You can inject dependencies into
|
150
|
+
You can inject dependencies into stores with `createStoreFactory`:
|
158
151
|
|
159
152
|
```ts
|
160
153
|
const withDeps = createStoreFactory({ user: getUserFromSession });
|
161
154
|
|
162
|
-
const useUserStore = withDeps(
|
155
|
+
const useUserStore = withDeps(({ user, createState }) => {
|
163
156
|
const userState = createState(user);
|
164
157
|
return { userState };
|
165
158
|
});
|
@@ -190,30 +183,7 @@ While createStore provides state primitives (createState, createDerivedState, cr
|
|
190
183
|
| Feature | Import from |
|
191
184
|
| -------------------------------------------------------------------------------- | --------------------- |
|
192
185
|
| `createStore`, `createStoreFactory`, `createPresenter`, `createPresenterFactory` | `edges-svelte` |
|
193
|
-
| `
|
194
|
-
|
195
|
-
---
|
196
|
-
|
197
|
-
## About `edgesHandle`
|
198
|
-
|
199
|
-
```ts
|
200
|
-
/**
|
201
|
-
* Wraps request handling in an AsyncLocalStorage context and provides a `serialize` function
|
202
|
-
* for injecting state into the HTML response.
|
203
|
-
*
|
204
|
-
* @param event - The SvelteKit RequestEvent for the current request.
|
205
|
-
* @param callback - A function that receives the edgesEvent and a serialize function,
|
206
|
-
* and expects resolve of edgesEvent as a return result.
|
207
|
-
* @param silentChromeDevtools - If true, intercepts requests to
|
208
|
-
* `/.well-known/appspecific/com.chrome.devtools.json` (triggered by Chrome DevTools)
|
209
|
-
* and returns a 204 No Content response just to avoid spamming logs.
|
210
|
-
*/
|
211
|
-
type EdgesHandle = (
|
212
|
-
event: RequestEvent,
|
213
|
-
callback: (params: { edgesEvent: RequestEvent; serialize: (html: string) => string }) => Promise<Response> | Response,
|
214
|
-
silentChromeDevtools?: boolean
|
215
|
-
) => Promise<Response>;
|
216
|
-
```
|
186
|
+
| `edgesPlugin` | `edges-svelte/plugin` |
|
217
187
|
|
218
188
|
---
|
219
189
|
|
@@ -0,0 +1,115 @@
|
|
1
|
+
import { browser } from '$app/environment';
|
2
|
+
const stateUpdateCallbacks = new Map();
|
3
|
+
const UNDEFINED_MARKER = '__EDGES_UNDEFINED__';
|
4
|
+
const NULL_MARKER = '__EDGES_NULL__';
|
5
|
+
const safeReviver = (key, value) => {
|
6
|
+
if (value && typeof value === 'object') {
|
7
|
+
if (UNDEFINED_MARKER in value) {
|
8
|
+
return undefined;
|
9
|
+
}
|
10
|
+
if (NULL_MARKER in value) {
|
11
|
+
return null;
|
12
|
+
}
|
13
|
+
}
|
14
|
+
return value;
|
15
|
+
};
|
16
|
+
export function registerStateUpdate(key, callback) {
|
17
|
+
if (browser) {
|
18
|
+
stateUpdateCallbacks.set(key, callback);
|
19
|
+
}
|
20
|
+
}
|
21
|
+
export function unregisterStateUpdate(key) {
|
22
|
+
stateUpdateCallbacks.delete(key);
|
23
|
+
}
|
24
|
+
export function processEdgesState(edgesState) {
|
25
|
+
if (!window.__SAFE_SSR_STATE__) {
|
26
|
+
window.__SAFE_SSR_STATE__ = new Map();
|
27
|
+
}
|
28
|
+
for (const [key, value] of Object.entries(edgesState)) {
|
29
|
+
let processedValue = value;
|
30
|
+
if (typeof value === 'string') {
|
31
|
+
try {
|
32
|
+
processedValue = JSON.parse(value, safeReviver);
|
33
|
+
}
|
34
|
+
catch {
|
35
|
+
// If not JSON then use without handling
|
36
|
+
}
|
37
|
+
}
|
38
|
+
window.__SAFE_SSR_STATE__.set(key, processedValue);
|
39
|
+
const callback = stateUpdateCallbacks.get(key);
|
40
|
+
if (callback) {
|
41
|
+
callback(processedValue);
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
45
|
+
if (browser) {
|
46
|
+
const originalFetch = window.fetch;
|
47
|
+
let processingResponse = false;
|
48
|
+
window.fetch = async function (...args) {
|
49
|
+
const response = await originalFetch.apply(this, args);
|
50
|
+
if (processingResponse) {
|
51
|
+
return response;
|
52
|
+
}
|
53
|
+
const [input, init] = args;
|
54
|
+
const url = typeof input === 'string' ? input : input instanceof Request ? input.url : '';
|
55
|
+
const isSvelteKitGet = init.__sveltekit_fetch__ || url.includes('__data.json');
|
56
|
+
const isSvelteKitPost = input instanceof URL && input.search.startsWith('?/');
|
57
|
+
if (isSvelteKitGet || isSvelteKitPost) {
|
58
|
+
const contentType = response.headers.get('content-type');
|
59
|
+
if (contentType?.includes('application/json')) {
|
60
|
+
processingResponse = true;
|
61
|
+
try {
|
62
|
+
const cloned = response.clone();
|
63
|
+
const text = await cloned.text();
|
64
|
+
if (text) {
|
65
|
+
try {
|
66
|
+
const json = JSON.parse(text);
|
67
|
+
if (json && typeof json === 'object' && '__edges_state__' in json) {
|
68
|
+
processEdgesState(json.__edges_state__);
|
69
|
+
}
|
70
|
+
}
|
71
|
+
catch {
|
72
|
+
// ignore no JSON or parse Errors
|
73
|
+
}
|
74
|
+
}
|
75
|
+
}
|
76
|
+
catch {
|
77
|
+
// Ошибка клонирования или чтения - игнорируем
|
78
|
+
}
|
79
|
+
finally {
|
80
|
+
processingResponse = false;
|
81
|
+
}
|
82
|
+
}
|
83
|
+
}
|
84
|
+
return response;
|
85
|
+
};
|
86
|
+
if (typeof MutationObserver !== 'undefined') {
|
87
|
+
const observer = new MutationObserver((mutations) => {
|
88
|
+
for (const mutation of mutations) {
|
89
|
+
if (mutation.type === 'childList') {
|
90
|
+
for (const node of mutation.addedNodes) {
|
91
|
+
if (node instanceof HTMLScriptElement) {
|
92
|
+
const text = node.textContent || '';
|
93
|
+
if (text.includes('__SAFE_SSR_STATE__') && text.includes('__EDGES_REVIVER__')) {
|
94
|
+
setTimeout(() => {
|
95
|
+
if (window.__SAFE_SSR_STATE__) {
|
96
|
+
for (const [key, value] of window.__SAFE_SSR_STATE__) {
|
97
|
+
const callback = stateUpdateCallbacks.get(key);
|
98
|
+
if (callback) {
|
99
|
+
callback(value);
|
100
|
+
}
|
101
|
+
}
|
102
|
+
}
|
103
|
+
}, 0);
|
104
|
+
}
|
105
|
+
}
|
106
|
+
}
|
107
|
+
}
|
108
|
+
}
|
109
|
+
});
|
110
|
+
observer.observe(document.documentElement, {
|
111
|
+
childList: true,
|
112
|
+
subtree: true
|
113
|
+
});
|
114
|
+
}
|
115
|
+
}
|
package/dist/context/Context.js
CHANGED
@@ -0,0 +1,49 @@
|
|
1
|
+
import type { Plugin } from 'vite';
|
2
|
+
/**
|
3
|
+
* Vite plugin that automatically wraps the SvelteKit handle hook with edgesHandle.
|
4
|
+
*
|
5
|
+
* This eliminates the need to manually wrap your handle function, while still allowing
|
6
|
+
* full customization of the handle logic.
|
7
|
+
*
|
8
|
+
* @param isPackageDevelopment - Set to `true` when developing the edges-svelte package itself.
|
9
|
+
* This uses `$lib/server` imports. For all other cases (production or consuming the package), use `false` (default).
|
10
|
+
*
|
11
|
+
* @example
|
12
|
+
* ```ts
|
13
|
+
* // vite.config.ts (consuming the package)
|
14
|
+
* import { sveltekit } from '@sveltejs/kit/vite';
|
15
|
+
* import { defineConfig } from 'vite';
|
16
|
+
* import { edgesPlugin } from 'edges-svelte/plugin';
|
17
|
+
*
|
18
|
+
* export default defineConfig({
|
19
|
+
* plugins: [sveltekit(), edgesPlugin()]
|
20
|
+
* });
|
21
|
+
* ```
|
22
|
+
*
|
23
|
+
* @example
|
24
|
+
* ```ts
|
25
|
+
* // vite.config.ts (developing edges-svelte package)
|
26
|
+
* import { edgesPlugin } from './src/lib/plugin/index.js';
|
27
|
+
*
|
28
|
+
* export default defineConfig({
|
29
|
+
* plugins: [sveltekit(), edgesPlugin(true)] // true = package development mode
|
30
|
+
* });
|
31
|
+
* ```
|
32
|
+
*
|
33
|
+
* After adding the plugin, you can write your hooks.server.ts normally:
|
34
|
+
*
|
35
|
+
* @example
|
36
|
+
* ```ts
|
37
|
+
* // hooks.server.ts - No manual wrapping needed!
|
38
|
+
*
|
39
|
+
* // Option 1: No handle defined - plugin creates default
|
40
|
+
* // (nothing to write, it just works)
|
41
|
+
*
|
42
|
+
* // Option 2: Custom handle - plugin automatically wraps it
|
43
|
+
* export const handle = async ({ event, resolve }) => {
|
44
|
+
* console.log('My custom middleware');
|
45
|
+
* return resolve(event);
|
46
|
+
* };
|
47
|
+
* ```
|
48
|
+
*/
|
49
|
+
export declare function edgesPlugin(isPackageDevelopment?: boolean): Plugin;
|
@@ -0,0 +1,97 @@
|
|
1
|
+
/**
|
2
|
+
* Vite plugin that automatically wraps the SvelteKit handle hook with edgesHandle.
|
3
|
+
*
|
4
|
+
* This eliminates the need to manually wrap your handle function, while still allowing
|
5
|
+
* full customization of the handle logic.
|
6
|
+
*
|
7
|
+
* @param isPackageDevelopment - Set to `true` when developing the edges-svelte package itself.
|
8
|
+
* This uses `$lib/server` imports. For all other cases (production or consuming the package), use `false` (default).
|
9
|
+
*
|
10
|
+
* @example
|
11
|
+
* ```ts
|
12
|
+
* // vite.config.ts (consuming the package)
|
13
|
+
* import { sveltekit } from '@sveltejs/kit/vite';
|
14
|
+
* import { defineConfig } from 'vite';
|
15
|
+
* import { edgesPlugin } from 'edges-svelte/plugin';
|
16
|
+
*
|
17
|
+
* export default defineConfig({
|
18
|
+
* plugins: [sveltekit(), edgesPlugin()]
|
19
|
+
* });
|
20
|
+
* ```
|
21
|
+
*
|
22
|
+
* @example
|
23
|
+
* ```ts
|
24
|
+
* // vite.config.ts (developing edges-svelte package)
|
25
|
+
* import { edgesPlugin } from './src/lib/plugin/index.js';
|
26
|
+
*
|
27
|
+
* export default defineConfig({
|
28
|
+
* plugins: [sveltekit(), edgesPlugin(true)] // true = package development mode
|
29
|
+
* });
|
30
|
+
* ```
|
31
|
+
*
|
32
|
+
* After adding the plugin, you can write your hooks.server.ts normally:
|
33
|
+
*
|
34
|
+
* @example
|
35
|
+
* ```ts
|
36
|
+
* // hooks.server.ts - No manual wrapping needed!
|
37
|
+
*
|
38
|
+
* // Option 1: No handle defined - plugin creates default
|
39
|
+
* // (nothing to write, it just works)
|
40
|
+
*
|
41
|
+
* // Option 2: Custom handle - plugin automatically wraps it
|
42
|
+
* export const handle = async ({ event, resolve }) => {
|
43
|
+
* console.log('My custom middleware');
|
44
|
+
* return resolve(event);
|
45
|
+
* };
|
46
|
+
* ```
|
47
|
+
*/
|
48
|
+
export function edgesPlugin(isPackageDevelopment = false) {
|
49
|
+
return {
|
50
|
+
name: 'edges-auto-handle',
|
51
|
+
enforce: 'pre', // Run before SvelteKit
|
52
|
+
transform(code, id) {
|
53
|
+
// Only transform hooks.server.ts
|
54
|
+
if (!id.includes('hooks.server.ts'))
|
55
|
+
return null;
|
56
|
+
// If already wrapped by the plugin, skip
|
57
|
+
if (code.includes('__EDGES_AUTO_WRAPPED__'))
|
58
|
+
return null;
|
59
|
+
// If user is manually using edges-svelte, skip auto-wrapping
|
60
|
+
const hasManualEdgesImport = code.includes("from 'edges-svelte/server'") ||
|
61
|
+
code.includes('from "edges-svelte/server"') ||
|
62
|
+
code.includes("from '$lib/server'") ||
|
63
|
+
code.includes('from "$lib/server"');
|
64
|
+
if (hasManualEdgesImport) {
|
65
|
+
return null;
|
66
|
+
}
|
67
|
+
// Determine the correct import path
|
68
|
+
// If developing the package itself, use $lib
|
69
|
+
// Otherwise, use the published package path
|
70
|
+
const importPath = isPackageDevelopment ? '$lib/server/index.js' : 'edges-svelte/server';
|
71
|
+
// Check if user defined a handle export
|
72
|
+
const hasHandleExport = /export\s+const\s+handle/.test(code);
|
73
|
+
if (!hasHandleExport) {
|
74
|
+
// No handle defined - create default
|
75
|
+
return {
|
76
|
+
code: `// __EDGES_AUTO_WRAPPED__\n` +
|
77
|
+
`import { edgesHandle } from '${importPath}';\n\n` +
|
78
|
+
code +
|
79
|
+
`\n\n` +
|
80
|
+
`export const handle = edgesHandle(({ serialize, edgesEvent, resolve }) => ` +
|
81
|
+
`resolve(edgesEvent, { transformPageChunk: ({ html }) => serialize(html) }));`,
|
82
|
+
map: null
|
83
|
+
};
|
84
|
+
}
|
85
|
+
// User defined a handle - wrap it
|
86
|
+
const wrappedCode = `// __EDGES_AUTO_WRAPPED__\n` +
|
87
|
+
`import { __autoWrapHandle } from '${importPath}';\n\n` +
|
88
|
+
code.replace(/export\s+const\s+handle/, 'const __userHandle') +
|
89
|
+
`\n\n` +
|
90
|
+
`export const handle = __autoWrapHandle(__userHandle);`;
|
91
|
+
return {
|
92
|
+
code: wrappedCode,
|
93
|
+
map: null
|
94
|
+
};
|
95
|
+
}
|
96
|
+
};
|
97
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
export { edgesPlugin } from './EdgesAutoHandlePlugin.js';
|
@@ -0,0 +1 @@
|
|
1
|
+
export { edgesPlugin } from './EdgesAutoHandlePlugin.js';
|
@@ -4,7 +4,6 @@ type NoConflict<I, D> = {
|
|
4
4
|
[K in keyof I]: K extends keyof D ? never : I[K];
|
5
5
|
};
|
6
6
|
export declare const clearCache: (pattern?: string) => void;
|
7
|
-
export declare const createUiProvider: <T, F, D extends Record<string, unknown> | ((cacheKey: string) => Record<string, unknown>), I extends Record<string, unknown> = Record<string, unknown>>(name: string, factory: (deps: F) => T, dependencies: D, inject?: I) => (() => T);
|
8
7
|
type StoreDeps = {
|
9
8
|
createRawState: <T>(initial: T | (() => T)) => {
|
10
9
|
value: T;
|
@@ -12,8 +11,30 @@ type StoreDeps = {
|
|
12
11
|
createState: <T>(initial: T | (() => T)) => Writable<T>;
|
13
12
|
createDerivedState: typeof BaseCreateDerivedState;
|
14
13
|
};
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
export
|
14
|
+
/**
|
15
|
+
* Creates store without name needed
|
16
|
+
* @example
|
17
|
+
* export const useUserStore = createStore(({ createState }) => {
|
18
|
+
* const user = createState(null);
|
19
|
+
* return { user };
|
20
|
+
* });
|
21
|
+
*/
|
22
|
+
export declare function createStore<T, I extends Record<string, unknown> = Record<string, unknown>>(factory: (args: StoreDeps & NoConflict<I, StoreDeps>) => T, inject?: I): () => T;
|
23
|
+
export declare function createNamedStore<T, I extends Record<string, unknown> = Record<string, unknown>>(name: string, factory: (args: StoreDeps & NoConflict<I, StoreDeps>) => T, inject?: I): () => T;
|
24
|
+
/**
|
25
|
+
* Store factory
|
26
|
+
*/
|
27
|
+
export declare const createStoreFactory: <I extends Record<string, unknown>>(inject: I) => <T>(factory: (args: StoreDeps & NoConflict<I, StoreDeps>) => T) => () => T;
|
28
|
+
/**
|
29
|
+
* Presenter without name needed
|
30
|
+
*/
|
31
|
+
export declare function createPresenter<T, I extends Record<string, unknown> = Record<string, unknown>>(factory: (args: I) => T, inject?: I): () => T;
|
32
|
+
/**
|
33
|
+
* Named presenter
|
34
|
+
*/
|
35
|
+
export declare function createNamedPresenter<T, I extends Record<string, unknown> = Record<string, unknown>>(name: string, factory: (args: I) => T, inject?: I): () => T;
|
36
|
+
/**
|
37
|
+
* Presenter factory
|
38
|
+
*/
|
39
|
+
export declare const createPresenterFactory: <I extends Record<string, unknown>>(inject: I) => <T>(factory: (args: I) => T) => () => T;
|
19
40
|
export {};
|
@@ -1,7 +1,37 @@
|
|
1
1
|
import { createState as BaseCreateState, createDerivedState as BaseCreateDerivedState, createRawState as BaseCreateRawState } from '../store/index.js';
|
2
2
|
import { RequestContext } from '../context/index.js';
|
3
3
|
import { browser } from '$app/environment';
|
4
|
+
// Global client cache
|
4
5
|
const globalClientCache = new Map();
|
6
|
+
// Key auto-generate
|
7
|
+
class AutoKeyGenerator {
|
8
|
+
static cache = new WeakMap();
|
9
|
+
static counters = new Map();
|
10
|
+
static generate(factory) {
|
11
|
+
if (this.cache.has(factory)) {
|
12
|
+
return this.cache.get(factory);
|
13
|
+
}
|
14
|
+
const fnString = factory.toString();
|
15
|
+
let hash = 0;
|
16
|
+
for (let i = 0; i < fnString.length; i++) {
|
17
|
+
const char = fnString.charCodeAt(i);
|
18
|
+
hash = (hash << 5) - hash + char;
|
19
|
+
hash = hash & hash;
|
20
|
+
}
|
21
|
+
const baseKey = `store_${Math.abs(hash).toString(36)}`;
|
22
|
+
let finalKey = baseKey;
|
23
|
+
if (this.counters.has(baseKey)) {
|
24
|
+
const count = this.counters.get(baseKey) + 1;
|
25
|
+
this.counters.set(baseKey, count);
|
26
|
+
finalKey = `${baseKey}_${count}`;
|
27
|
+
}
|
28
|
+
else {
|
29
|
+
this.counters.set(baseKey, 0);
|
30
|
+
}
|
31
|
+
this.cache.set(factory, finalKey);
|
32
|
+
return finalKey;
|
33
|
+
}
|
34
|
+
}
|
5
35
|
export const clearCache = (pattern) => {
|
6
36
|
if (browser) {
|
7
37
|
if (pattern) {
|
@@ -16,21 +46,25 @@ export const clearCache = (pattern) => {
|
|
16
46
|
}
|
17
47
|
}
|
18
48
|
};
|
19
|
-
|
20
|
-
const cacheKey = name;
|
49
|
+
const createUiProvider = (cacheKey, factory, dependencies, inject) => {
|
21
50
|
return () => {
|
22
51
|
let contextMap;
|
23
52
|
if (browser) {
|
24
53
|
contextMap = globalClientCache;
|
25
54
|
}
|
26
55
|
else {
|
27
|
-
|
28
|
-
|
29
|
-
context.data.providers
|
56
|
+
try {
|
57
|
+
const context = RequestContext.current();
|
58
|
+
if (!context.data.providers) {
|
59
|
+
context.data.providers = new Map();
|
60
|
+
}
|
61
|
+
contextMap = context.data.providers;
|
62
|
+
}
|
63
|
+
catch {
|
64
|
+
contextMap = new Map();
|
30
65
|
}
|
31
|
-
contextMap = context.data.providers;
|
32
66
|
}
|
33
|
-
if (
|
67
|
+
if (contextMap.has(cacheKey)) {
|
34
68
|
const cached = contextMap.get(cacheKey);
|
35
69
|
if (cached !== undefined) {
|
36
70
|
return cached;
|
@@ -41,13 +75,39 @@ export const createUiProvider = (name, factory, dependencies, inject) => {
|
|
41
75
|
...inject
|
42
76
|
};
|
43
77
|
const instance = factory(deps);
|
44
|
-
|
45
|
-
contextMap.set(cacheKey, instance);
|
46
|
-
}
|
78
|
+
contextMap.set(cacheKey, instance);
|
47
79
|
return instance;
|
48
80
|
};
|
49
81
|
};
|
50
|
-
|
82
|
+
/**
|
83
|
+
* Creates store without name needed
|
84
|
+
* @example
|
85
|
+
* export const useUserStore = createStore(({ createState }) => {
|
86
|
+
* const user = createState(null);
|
87
|
+
* return { user };
|
88
|
+
* });
|
89
|
+
*/
|
90
|
+
export function createStore(factory, inject) {
|
91
|
+
const cacheKey = AutoKeyGenerator.generate(factory);
|
92
|
+
return createUiProvider(cacheKey, factory, (key) => {
|
93
|
+
let stateCounter = 0;
|
94
|
+
return {
|
95
|
+
createState: (initial) => {
|
96
|
+
const stateKey = `${key}::state::${stateCounter++}`;
|
97
|
+
const initFn = typeof initial === 'function' ? initial : () => initial;
|
98
|
+
return BaseCreateState(stateKey, initFn);
|
99
|
+
},
|
100
|
+
createRawState: (initial) => {
|
101
|
+
const stateKey = `${key}::rawstate::${stateCounter++}`;
|
102
|
+
const initFn = typeof initial === 'function' ? initial : () => initial;
|
103
|
+
return BaseCreateRawState(stateKey, initFn);
|
104
|
+
},
|
105
|
+
createDerivedState: BaseCreateDerivedState
|
106
|
+
};
|
107
|
+
}, inject);
|
108
|
+
}
|
109
|
+
// Creates store with nmame
|
110
|
+
export function createNamedStore(name, factory, inject) {
|
51
111
|
return createUiProvider(name, factory, (cacheKey) => {
|
52
112
|
let stateCounter = 0;
|
53
113
|
return {
|
@@ -64,17 +124,33 @@ export const createStore = (name, factory, inject) => {
|
|
64
124
|
createDerivedState: BaseCreateDerivedState
|
65
125
|
};
|
66
126
|
}, inject);
|
67
|
-
}
|
127
|
+
}
|
128
|
+
/**
|
129
|
+
* Store factory
|
130
|
+
*/
|
68
131
|
export const createStoreFactory = (inject) => {
|
69
|
-
return function
|
70
|
-
return createStore(
|
132
|
+
return function (factory) {
|
133
|
+
return createStore(factory, inject);
|
71
134
|
};
|
72
135
|
};
|
73
|
-
|
136
|
+
/**
|
137
|
+
* Presenter without name needed
|
138
|
+
*/
|
139
|
+
export function createPresenter(factory, inject) {
|
140
|
+
const cacheKey = AutoKeyGenerator.generate(factory);
|
141
|
+
return createUiProvider(cacheKey, factory, {}, inject);
|
142
|
+
}
|
143
|
+
/**
|
144
|
+
* Named presenter
|
145
|
+
*/
|
146
|
+
export function createNamedPresenter(name, factory, inject) {
|
74
147
|
return createUiProvider(name, factory, {}, inject);
|
75
|
-
}
|
148
|
+
}
|
149
|
+
/**
|
150
|
+
* Presenter factory
|
151
|
+
*/
|
76
152
|
export const createPresenterFactory = (inject) => {
|
77
|
-
return function
|
78
|
-
return createPresenter(
|
153
|
+
return function (factory) {
|
154
|
+
return createPresenter(factory, inject);
|
79
155
|
};
|
80
156
|
};
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import type { Handle } from '@sveltejs/kit';
|
2
|
+
/**
|
3
|
+
* Automatically wraps a user-defined handle function with edgesHandle.
|
4
|
+
* This is used internally by the Vite plugin to provide automatic state management.
|
5
|
+
*
|
6
|
+
* @internal This function is called automatically by the Vite plugin. You don't need to use it manually.
|
7
|
+
*
|
8
|
+
* @param userHandle - Optional user-defined handle function from hooks.server.ts
|
9
|
+
* @returns A handle function wrapped with edgesHandle for automatic state serialization
|
10
|
+
*/
|
11
|
+
export declare function __autoWrapHandle(userHandle?: Handle): Handle;
|
@@ -0,0 +1,31 @@
|
|
1
|
+
import { edgesHandle } from './EdgesHandleSimplified.js';
|
2
|
+
/**
|
3
|
+
* Automatically wraps a user-defined handle function with edgesHandle.
|
4
|
+
* This is used internally by the Vite plugin to provide automatic state management.
|
5
|
+
*
|
6
|
+
* @internal This function is called automatically by the Vite plugin. You don't need to use it manually.
|
7
|
+
*
|
8
|
+
* @param userHandle - Optional user-defined handle function from hooks.server.ts
|
9
|
+
* @returns A handle function wrapped with edgesHandle for automatic state serialization
|
10
|
+
*/
|
11
|
+
export function __autoWrapHandle(userHandle) {
|
12
|
+
if (!userHandle) {
|
13
|
+
// No user handle - return default edgesHandle
|
14
|
+
return edgesHandle(({ serialize, edgesEvent, resolve }) => resolve(edgesEvent, { transformPageChunk: ({ html }) => serialize(html) }));
|
15
|
+
}
|
16
|
+
// Wrap user's handle with edgesHandle
|
17
|
+
return edgesHandle(({ serialize, edgesEvent, resolve }) => {
|
18
|
+
return userHandle({
|
19
|
+
event: edgesEvent,
|
20
|
+
resolve: (e, opts) => resolve(e, {
|
21
|
+
...opts,
|
22
|
+
transformPageChunk: ({ html, done }) => {
|
23
|
+
// Apply user's transform first (if any)
|
24
|
+
const userTransformed = opts?.transformPageChunk?.({ html, done }) ?? html;
|
25
|
+
// Then apply edges serialization
|
26
|
+
return typeof userTransformed === 'string' ? serialize(userTransformed) : userTransformed;
|
27
|
+
}
|
28
|
+
})
|
29
|
+
});
|
30
|
+
});
|
31
|
+
}
|
@@ -4,15 +4,7 @@ type EdgesHandle = (event: RequestEvent, callback: (params: {
|
|
4
4
|
serialize: (html: string) => string;
|
5
5
|
}) => Promise<Response> | Response, silentChromeDevtools?: boolean) => Promise<Response>;
|
6
6
|
/**
|
7
|
-
* Wraps request handling in an AsyncLocalStorage context
|
8
|
-
* for injecting state into the HTML response.
|
9
|
-
*
|
10
|
-
* @param event - The SvelteKit RequestEvent for the current request.
|
11
|
-
* @param callback - A function that receives the event and a serialize function,
|
12
|
-
* and returns a Response or a Promise of one.
|
13
|
-
* @param silentChromeDevtools - If true, intercepts requests to
|
14
|
-
* `/.well-known/appspecific/com.chrome.devtools.json` (triggered by Chrome DevTools)
|
15
|
-
* and returns a 204 No Content response instead of a 404 error.
|
7
|
+
* Wraps request handling in an AsyncLocalStorage context
|
16
8
|
*/
|
17
9
|
export declare const edgesHandle: EdgesHandle;
|
18
10
|
export {};
|
@@ -1,20 +1,32 @@
|
|
1
|
-
import { stateSerialize } from '../store/State.svelte.js';
|
2
|
-
import { AsyncLocalStorage } from 'async_hooks';
|
1
|
+
import { stateSerialize, getStateMap } from '../store/State.svelte.js';
|
2
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
3
3
|
import RequestContext, {} from '../context/Context.js';
|
4
4
|
const storage = new AsyncLocalStorage();
|
5
|
+
const textEncoder = new TextEncoder();
|
6
|
+
// Маркеры для специальных значений
|
7
|
+
const UNDEFINED_MARKER = '__EDGES_UNDEFINED__';
|
8
|
+
const NULL_MARKER = '__EDGES_NULL__';
|
9
|
+
// Безопасный replacer для JSON
|
10
|
+
const safeReplacer = (key, value) => {
|
11
|
+
if (value === undefined) {
|
12
|
+
return { [UNDEFINED_MARKER]: true };
|
13
|
+
}
|
14
|
+
if (value === null) {
|
15
|
+
return { [NULL_MARKER]: true };
|
16
|
+
}
|
17
|
+
return value;
|
18
|
+
};
|
5
19
|
/**
|
6
|
-
* Wraps request handling in an AsyncLocalStorage context
|
7
|
-
* for injecting state into the HTML response.
|
8
|
-
*
|
9
|
-
* @param event - The SvelteKit RequestEvent for the current request.
|
10
|
-
* @param callback - A function that receives the event and a serialize function,
|
11
|
-
* and returns a Response or a Promise of one.
|
12
|
-
* @param silentChromeDevtools - If true, intercepts requests to
|
13
|
-
* `/.well-known/appspecific/com.chrome.devtools.json` (triggered by Chrome DevTools)
|
14
|
-
* and returns a 204 No Content response instead of a 404 error.
|
20
|
+
* Wraps request handling in an AsyncLocalStorage context
|
15
21
|
*/
|
16
22
|
export const edgesHandle = async (event, callback, silentChromeDevtools = false) => {
|
17
|
-
|
23
|
+
const requestSymbol = Symbol('request');
|
24
|
+
return await storage.run({
|
25
|
+
event: event,
|
26
|
+
symbol: requestSymbol,
|
27
|
+
data: { providers: new Map() }
|
28
|
+
}, async () => {
|
29
|
+
// Настраиваем RequestContext
|
18
30
|
RequestContext.current = () => {
|
19
31
|
const context = storage.getStore();
|
20
32
|
if (context === undefined) {
|
@@ -30,16 +42,61 @@ export const edgesHandle = async (event, callback, silentChromeDevtools = false)
|
|
30
42
|
}
|
31
43
|
return context;
|
32
44
|
};
|
45
|
+
// Chrome DevTools handling
|
33
46
|
if (silentChromeDevtools && event.url.pathname === '/.well-known/appspecific/com.chrome.devtools.json') {
|
34
47
|
return new Response(null, { status: 204 });
|
35
48
|
}
|
36
|
-
|
49
|
+
// Выполняем основной callback
|
50
|
+
const response = await callback({
|
37
51
|
edgesEvent: event,
|
38
52
|
serialize: (html) => {
|
39
53
|
if (!html)
|
40
54
|
return html ?? '';
|
41
|
-
|
55
|
+
// Вставляем сериализованное состояние перед </body>
|
56
|
+
const serialized = stateSerialize();
|
57
|
+
if (!serialized)
|
58
|
+
return html;
|
59
|
+
return html.replace('</body>', `${serialized}</body>`);
|
42
60
|
}
|
43
61
|
});
|
62
|
+
// Проверяем, нужно ли инжектить состояние в JSON
|
63
|
+
const contentType = response.headers.get('content-type');
|
64
|
+
if (contentType?.includes('application/json')) {
|
65
|
+
const stateMap = getStateMap();
|
66
|
+
// Если есть состояние для передачи
|
67
|
+
if (stateMap && stateMap.size > 0) {
|
68
|
+
try {
|
69
|
+
// Клонируем response для чтения
|
70
|
+
const clonedResponse = response.clone();
|
71
|
+
const json = await clonedResponse.json();
|
72
|
+
// Подготавливаем состояние для передачи
|
73
|
+
const stateObj = {};
|
74
|
+
for (const [key, value] of stateMap) {
|
75
|
+
// Сериализуем каждое значение отдельно с поддержкой undefined
|
76
|
+
stateObj[key] = JSON.stringify(value, safeReplacer);
|
77
|
+
}
|
78
|
+
// Добавляем состояние в JSON
|
79
|
+
const modifiedJson = {
|
80
|
+
...json,
|
81
|
+
__edges_state__: stateObj
|
82
|
+
};
|
83
|
+
const modifiedBody = JSON.stringify(modifiedJson);
|
84
|
+
// Создаем новые заголовки с правильной длиной
|
85
|
+
const newHeaders = new Headers(response.headers);
|
86
|
+
newHeaders.set('content-length', String(textEncoder.encode(modifiedBody).length));
|
87
|
+
return new Response(modifiedBody, {
|
88
|
+
status: response.status,
|
89
|
+
statusText: response.statusText,
|
90
|
+
headers: newHeaders
|
91
|
+
});
|
92
|
+
}
|
93
|
+
catch (e) {
|
94
|
+
console.error('[edges] Failed to inject state into JSON response:', e);
|
95
|
+
// При ошибке возвращаем оригинальный response
|
96
|
+
return response;
|
97
|
+
}
|
98
|
+
}
|
99
|
+
}
|
100
|
+
return response;
|
44
101
|
});
|
45
102
|
};
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import type { Handle, RequestEvent, ResolveOptions } from '@sveltejs/kit';
|
2
|
+
type SimplifiedCallback = (params: {
|
3
|
+
serialize: (html: string) => string;
|
4
|
+
edgesEvent: RequestEvent;
|
5
|
+
resolve: (event: RequestEvent, opts?: ResolveOptions) => Response | Promise<Response>;
|
6
|
+
}) => Response | Promise<Response>;
|
7
|
+
/**
|
8
|
+
* Simplified wrapper around edgesHandle that provides a more convenient API.
|
9
|
+
*
|
10
|
+
* @example
|
11
|
+
* ```ts
|
12
|
+
* // Simple usage with default behavior
|
13
|
+
* export const handle = edgesHandle(({ serialize, edgesEvent, resolve }) =>
|
14
|
+
* resolve(edgesEvent, { transformPageChunk: ({ html }) => serialize(html) })
|
15
|
+
* );
|
16
|
+
*
|
17
|
+
* // You can still access resolve for custom logic
|
18
|
+
* export const handle = edgesHandle(({ serialize, edgesEvent, resolve }) => {
|
19
|
+
* // Custom logic here
|
20
|
+
* return resolve(edgesEvent, { transformPageChunk: ({ html }) => serialize(html) });
|
21
|
+
* });
|
22
|
+
* ```
|
23
|
+
*/
|
24
|
+
export declare const edgesHandle: (callback: SimplifiedCallback, silentChromeDevtools?: boolean) => Handle;
|
25
|
+
export {};
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import { edgesHandle as originalEdgesHandle } from './EdgesHandle.js';
|
2
|
+
/**
|
3
|
+
* Simplified wrapper around edgesHandle that provides a more convenient API.
|
4
|
+
*
|
5
|
+
* @example
|
6
|
+
* ```ts
|
7
|
+
* // Simple usage with default behavior
|
8
|
+
* export const handle = edgesHandle(({ serialize, edgesEvent, resolve }) =>
|
9
|
+
* resolve(edgesEvent, { transformPageChunk: ({ html }) => serialize(html) })
|
10
|
+
* );
|
11
|
+
*
|
12
|
+
* // You can still access resolve for custom logic
|
13
|
+
* export const handle = edgesHandle(({ serialize, edgesEvent, resolve }) => {
|
14
|
+
* // Custom logic here
|
15
|
+
* return resolve(edgesEvent, { transformPageChunk: ({ html }) => serialize(html) });
|
16
|
+
* });
|
17
|
+
* ```
|
18
|
+
*/
|
19
|
+
export const edgesHandle = (callback, silentChromeDevtools = true) => {
|
20
|
+
return async ({ event, resolve }) => {
|
21
|
+
return originalEdgesHandle(event, ({ serialize, edgesEvent }) => {
|
22
|
+
return callback({ serialize, edgesEvent, resolve });
|
23
|
+
}, silentChromeDevtools);
|
24
|
+
};
|
25
|
+
};
|
package/dist/server/index.d.ts
CHANGED
package/dist/server/index.js
CHANGED
@@ -1,84 +1,177 @@
|
|
1
1
|
import RequestContext from '../context/Context.js';
|
2
|
-
import { uneval } from 'devalue';
|
3
2
|
import { browser } from '$app/environment';
|
4
3
|
import { derived, writable } from 'svelte/store';
|
4
|
+
import { registerStateUpdate } from '../client/NavigationSync.svelte.js';
|
5
5
|
const RequestStores = new WeakMap();
|
6
|
+
const UNDEFINED_MARKER = '__EDGES_UNDEFINED__';
|
7
|
+
const NULL_MARKER = '__EDGES_NULL__';
|
8
|
+
const safeReplacer = (key, value) => {
|
9
|
+
if (value === undefined) {
|
10
|
+
return { [UNDEFINED_MARKER]: true };
|
11
|
+
}
|
12
|
+
if (value === null) {
|
13
|
+
return { [NULL_MARKER]: true };
|
14
|
+
}
|
15
|
+
if (typeof value === 'function' || typeof value === 'symbol') {
|
16
|
+
return undefined;
|
17
|
+
}
|
18
|
+
return value;
|
19
|
+
};
|
20
|
+
// const safeReviver = (key: string, value: unknown): unknown => {
|
21
|
+
// if (value && typeof value === 'object') {
|
22
|
+
// if (UNDEFINED_MARKER in value) {
|
23
|
+
// return undefined;
|
24
|
+
// }
|
25
|
+
// if (NULL_MARKER in value) {
|
26
|
+
// return null;
|
27
|
+
// }
|
28
|
+
// }
|
29
|
+
// return value;
|
30
|
+
// };
|
6
31
|
export const stateSerialize = () => {
|
7
32
|
const map = getRequestContext();
|
8
|
-
if (map)
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
33
|
+
if (!map || map.size === 0)
|
34
|
+
return '';
|
35
|
+
const entries = [];
|
36
|
+
for (const [key, value] of map) {
|
37
|
+
const serialized = JSON.stringify(value, safeReplacer);
|
38
|
+
const escaped = serialized.replace(/'/g, "\\'").replace(/\\/g, '\\\\');
|
39
|
+
entries.push(`window.__SAFE_SSR_STATE__.set('${key}',JSON.parse('${escaped}',window.__EDGES_REVIVER__))`);
|
14
40
|
}
|
15
|
-
return ''
|
41
|
+
const reviverCode = `window.__EDGES_REVIVER__=function(k,v){if(v&&typeof v==='object'){if('${UNDEFINED_MARKER}' in v)return undefined;if('${NULL_MARKER}' in v)return null}return v};`;
|
42
|
+
return `<script>${reviverCode}window.__SAFE_SSR_STATE__=new Map();${entries.join(';')}</script>`;
|
16
43
|
};
|
17
44
|
const getRequestContext = () => {
|
18
|
-
const
|
45
|
+
const context = RequestContext.current();
|
46
|
+
const sym = context.symbol;
|
19
47
|
if (sym) {
|
20
|
-
|
48
|
+
if (!RequestStores.has(sym)) {
|
49
|
+
RequestStores.set(sym, new Map());
|
50
|
+
}
|
51
|
+
return RequestStores.get(sym);
|
52
|
+
}
|
53
|
+
};
|
54
|
+
export const getStateMap = () => {
|
55
|
+
try {
|
56
|
+
return getRequestContext();
|
57
|
+
}
|
58
|
+
catch {
|
59
|
+
return undefined;
|
21
60
|
}
|
22
61
|
};
|
23
62
|
const getBrowserState = (key, initial) => {
|
24
|
-
|
25
|
-
|
63
|
+
if (!window.__SAFE_SSR_STATE__) {
|
64
|
+
return initial;
|
65
|
+
}
|
66
|
+
const state = window.__SAFE_SSR_STATE__.get(key);
|
67
|
+
if (window.__SAFE_SSR_STATE__.has(key)) {
|
26
68
|
return state;
|
69
|
+
}
|
27
70
|
return initial;
|
28
71
|
};
|
29
72
|
export const createRawState = (key, initial) => {
|
30
73
|
if (browser) {
|
31
74
|
let state = $state(getBrowserState(key, initial()));
|
75
|
+
const callback = (newValue) => {
|
76
|
+
state = newValue;
|
77
|
+
};
|
78
|
+
registerStateUpdate(key, callback);
|
79
|
+
const updateWindowState = (val) => {
|
80
|
+
if (!window.__SAFE_SSR_STATE__) {
|
81
|
+
window.__SAFE_SSR_STATE__ = new Map();
|
82
|
+
}
|
83
|
+
window.__SAFE_SSR_STATE__.set(key, val);
|
84
|
+
};
|
32
85
|
return {
|
33
86
|
get value() {
|
34
87
|
return state;
|
35
88
|
},
|
36
89
|
set value(val) {
|
37
90
|
state = val;
|
91
|
+
updateWindowState(val);
|
38
92
|
}
|
39
93
|
};
|
40
94
|
}
|
41
95
|
const map = getRequestContext();
|
96
|
+
if (!map) {
|
97
|
+
const val = initial();
|
98
|
+
return {
|
99
|
+
get value() {
|
100
|
+
return val;
|
101
|
+
},
|
102
|
+
set value(_) {
|
103
|
+
/* noop */
|
104
|
+
}
|
105
|
+
};
|
106
|
+
}
|
42
107
|
return {
|
43
108
|
get value() {
|
44
|
-
if (!map)
|
45
|
-
|
46
|
-
|
47
|
-
map.set(key, structuredClone(initial()));
|
109
|
+
if (!map.has(key)) {
|
110
|
+
map.set(key, initial());
|
111
|
+
}
|
48
112
|
return map.get(key);
|
49
113
|
},
|
50
114
|
set value(val) {
|
51
|
-
|
52
|
-
map.set(key, val);
|
53
|
-
}
|
115
|
+
map.set(key, val);
|
54
116
|
}
|
55
117
|
};
|
56
118
|
};
|
57
119
|
export const createState = (key, initial) => {
|
58
120
|
if (browser) {
|
59
|
-
|
121
|
+
const initialValue = getBrowserState(key, initial());
|
122
|
+
const state = writable(initialValue);
|
123
|
+
const callback = (newValue) => {
|
124
|
+
state.set(newValue);
|
125
|
+
};
|
126
|
+
registerStateUpdate(key, callback);
|
127
|
+
const originalSet = state.set;
|
128
|
+
const originalUpdate = state.update;
|
129
|
+
state.set = (value) => {
|
130
|
+
originalSet(value);
|
131
|
+
if (!window.__SAFE_SSR_STATE__) {
|
132
|
+
window.__SAFE_SSR_STATE__ = new Map();
|
133
|
+
}
|
134
|
+
window.__SAFE_SSR_STATE__.set(key, value);
|
135
|
+
};
|
136
|
+
state.update = (updater) => {
|
137
|
+
originalUpdate((current) => {
|
138
|
+
const newValue = updater(current);
|
139
|
+
if (!window.__SAFE_SSR_STATE__) {
|
140
|
+
window.__SAFE_SSR_STATE__ = new Map();
|
141
|
+
}
|
142
|
+
window.__SAFE_SSR_STATE__.set(key, newValue);
|
143
|
+
return newValue;
|
144
|
+
});
|
145
|
+
};
|
146
|
+
return state;
|
60
147
|
}
|
61
148
|
const map = getRequestContext();
|
62
|
-
if (!map)
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
149
|
+
if (!map) {
|
150
|
+
const val = initial();
|
151
|
+
return {
|
152
|
+
subscribe(run) {
|
153
|
+
run(val);
|
154
|
+
return () => { };
|
155
|
+
},
|
156
|
+
set() { },
|
157
|
+
update() { }
|
158
|
+
};
|
159
|
+
}
|
160
|
+
if (!map.has(key)) {
|
161
|
+
map.set(key, initial());
|
162
|
+
}
|
67
163
|
return {
|
68
164
|
subscribe(run) {
|
69
165
|
run(map.get(key));
|
70
|
-
//subscribers.add(run);
|
71
166
|
return () => { };
|
72
167
|
},
|
73
168
|
set(val) {
|
74
169
|
map.set(key, val);
|
75
|
-
//subscribers.forEach((fn) => fn(val));
|
76
170
|
},
|
77
171
|
update(updater) {
|
78
172
|
const oldVal = map.get(key);
|
79
173
|
const newVal = updater(oldVal);
|
80
174
|
map.set(key, newVal);
|
81
|
-
//subscribers.forEach((fn) => fn(newVal));
|
82
175
|
}
|
83
176
|
};
|
84
177
|
};
|
package/dist/store/index.d.ts
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export { createState, createRawState, createDerivedState } from './State.svelte.js';
|
1
|
+
export { createState, createRawState, createDerivedState, getStateMap } from './State.svelte.js';
|
package/dist/store/index.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export { createState, createRawState, createDerivedState } from './State.svelte.js';
|
1
|
+
export { createState, createRawState, createDerivedState, getStateMap } from './State.svelte.js';
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "edges-svelte",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.3.0",
|
4
4
|
"license": "MIT",
|
5
5
|
"author": "Pixel1917",
|
6
6
|
"description": "A blazing-fast, extremely lightweight and SSR-friendly store for Svelte",
|
@@ -34,8 +34,8 @@
|
|
34
34
|
"svelte": "./dist/index.js"
|
35
35
|
},
|
36
36
|
"./server": {
|
37
|
-
"types": "./dist/server/
|
38
|
-
"svelte": "./dist/server/
|
37
|
+
"types": "./dist/server/index.d.ts",
|
38
|
+
"svelte": "./dist/server/index.js"
|
39
39
|
},
|
40
40
|
"./context": {
|
41
41
|
"types": "./dist/context/index.d.ts",
|
@@ -44,6 +44,10 @@
|
|
44
44
|
"./state": {
|
45
45
|
"types": "./dist/store/index.d.ts",
|
46
46
|
"svelte": "./dist/store/index.js"
|
47
|
+
},
|
48
|
+
"./plugin": {
|
49
|
+
"types": "./dist/plugin/index.d.ts",
|
50
|
+
"default": "./dist/plugin/index.js"
|
47
51
|
}
|
48
52
|
},
|
49
53
|
"peerDependencies": {
|