edges-svelte 3.0.3 → 3.1.1
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 +55 -6
- package/dist/client/NavigationSync.svelte.js +3 -3
- package/dist/context/Context.js +2 -2
- package/dist/provider/Provider.js +18 -9
- package/dist/provider/Utils.d.ts +34 -0
- package/dist/provider/Utils.js +102 -0
- package/dist/server/EdgesHandle.js +2 -0
- package/dist/server/ServerSync.js +3 -4
- package/dist/store/State.svelte.d.ts +1 -1
- package/dist/store/State.svelte.js +5 -5
- package/dist/utils/DevTools.svelte +388 -0
- package/dist/utils/DevTools.svelte.d.ts +18 -0
- package/dist/utils/batch.js +7 -7
- package/dist/utils/dev.d.ts +68 -2
- package/dist/utils/dev.js +204 -22
- package/package.json +40 -37
- package/dist/utils/environment.d.ts +0 -3
- package/dist/utils/environment.js +0 -3
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# EdgeS
|
|
2
2
|
|
|
3
|
+
## Last new releases in package [@azure-net/edges](https://www.npmjs.com/package/@azure-net/edges). This package is no longer supported.
|
|
4
|
+
|
|
3
5
|
### A blazing-fast, extremely lightweight and SSR-friendly store for SvelteKit.
|
|
4
6
|
|
|
5
7
|
**EdgeS** brings seamless, per-request state management to Svelte apps.
|
|
@@ -13,6 +15,15 @@ No context boilerplate. No hydration headaches.
|
|
|
13
15
|
|
|
14
16
|
EdgeS is built to prevent state leaks. Its primary goal is to keep server-side state safely isolated per request while providing a clean developer experience with presenters, stores, and automatic client updates when fresh state arrives from the server. It is intentionally one-way sync from server to client and does not aim to provide full two-way state synchronization between client and server.
|
|
15
17
|
|
|
18
|
+
### Sync Scope & Limitations
|
|
19
|
+
|
|
20
|
+
EdgeS does **not** aim to provide full server-to-client synchronization for all SvelteKit flows.
|
|
21
|
+
|
|
22
|
+
- The main goal of this package is **server-side state isolation per request**.
|
|
23
|
+
- Server-to-client sync is a convenience layer for common cases, not a strict consistency protocol.
|
|
24
|
+
- `svelte actions` with redirects are **not fully synchronized** by design.
|
|
25
|
+
- Redirect-driven flows (and similar edge cases) should be handled with explicit app-level patterns (for example cookies/session/flash state) when you need guaranteed transfer of action results across navigation.
|
|
26
|
+
|
|
16
27
|
> Designed for **SvelteKit**.
|
|
17
28
|
|
|
18
29
|
---
|
|
@@ -245,6 +256,43 @@ window.__EDGES_DEVTOOLS__.clearCache(); // Clear state cache
|
|
|
245
256
|
// - Slow operations (>16ms)
|
|
246
257
|
```
|
|
247
258
|
|
|
259
|
+
### Built-in Dev Component (dev-only)
|
|
260
|
+
|
|
261
|
+
EdgeS provides a small in-app DevTools component for development.
|
|
262
|
+
|
|
263
|
+
- A `50x50` floating button appears in the bottom-right corner.
|
|
264
|
+
- Clicking it opens an inspector panel with tabs:
|
|
265
|
+
- `presenters`
|
|
266
|
+
- `stores`
|
|
267
|
+
- `info`
|
|
268
|
+
- `presenters` shows an accordion of registered presenters with key/runtime metadata.
|
|
269
|
+
- `stores` shows registered stores plus state tree entries, previews, and size estimates.
|
|
270
|
+
- `info` includes key uniqueness checks, cache stats, and high-level resource usage.
|
|
271
|
+
|
|
272
|
+
How to enable:
|
|
273
|
+
|
|
274
|
+
- `edges-svelte/dev` — enables DevTools runtime API (`window.__EDGES_DEVTOOLS__`) and mounts the in-app dev UI.
|
|
275
|
+
- `edges-svelte/dev-component` — exports the Svelte component itself if you want to mount it manually.
|
|
276
|
+
|
|
277
|
+
```ts
|
|
278
|
+
// e.g. in +layout.svelte or app bootstrap (dev only)
|
|
279
|
+
import 'edges-svelte/dev';
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
```svelte
|
|
283
|
+
<!-- manual mount variant -->
|
|
284
|
+
<script lang="ts">
|
|
285
|
+
import DevToolsComponent from 'edges-svelte/dev-component';
|
|
286
|
+
</script>
|
|
287
|
+
|
|
288
|
+
<DevToolsComponent />
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Notes:
|
|
292
|
+
|
|
293
|
+
- This UI is intended only for `dev` and is not a production UI feature.
|
|
294
|
+
- If you do not import `edges-svelte/dev` (or mount `edges-svelte/dev-component` manually), the UI will not appear.
|
|
295
|
+
|
|
248
296
|
---
|
|
249
297
|
|
|
250
298
|
## Monitoring & Debugging
|
|
@@ -304,12 +352,13 @@ EdgeS serializes SSR state as plain script payloads. Transport-level compression
|
|
|
304
352
|
|
|
305
353
|
## Exports summary
|
|
306
354
|
|
|
307
|
-
| Feature | Import from
|
|
308
|
-
| -------------------------------------------------------------------------------------------------------- |
|
|
309
|
-
| `createStore`, `createStoreFactory`, `createPresenter`, `createPresenterFactory`, `batch`, `transaction` | `edges-svelte`
|
|
310
|
-
| `edgesPlugin`, `createEdgesPluginFactory` | `edges-svelte/plugin`
|
|
311
|
-
| `edgesHandle` | `edges-svelte/server`
|
|
312
|
-
| `DevTools` | `edges-svelte/dev`
|
|
355
|
+
| Feature | Import from |
|
|
356
|
+
| -------------------------------------------------------------------------------------------------------- | ---------------------------- |
|
|
357
|
+
| `createStore`, `createStoreFactory`, `createPresenter`, `createPresenterFactory`, `batch`, `transaction` | `edges-svelte` |
|
|
358
|
+
| `edgesPlugin`, `createEdgesPluginFactory` | `edges-svelte/plugin` |
|
|
359
|
+
| `edgesHandle` | `edges-svelte/server` |
|
|
360
|
+
| `DevTools` | `edges-svelte/dev` |
|
|
361
|
+
| `DevToolsComponent` | `edges-svelte/dev-component` |
|
|
313
362
|
|
|
314
363
|
---
|
|
315
364
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BROWSER } from '@azure-net/tools/environment';
|
|
2
2
|
import { batch } from '../utils/batch.js';
|
|
3
3
|
const stateUpdateCallbacks = new Map();
|
|
4
4
|
const UNDEFINED_MARKER = '__EDGES_UNDEFINED__';
|
|
@@ -43,7 +43,7 @@ const tryDecodeLegacyString = (value) => {
|
|
|
43
43
|
}
|
|
44
44
|
};
|
|
45
45
|
export function registerStateUpdate(key, callback) {
|
|
46
|
-
if (
|
|
46
|
+
if (BROWSER) {
|
|
47
47
|
stateUpdateCallbacks.set(key, callback);
|
|
48
48
|
}
|
|
49
49
|
}
|
|
@@ -85,7 +85,7 @@ export function applyEdgesFromPayload(payload) {
|
|
|
85
85
|
}
|
|
86
86
|
processEdgesState(rawState);
|
|
87
87
|
}
|
|
88
|
-
if (
|
|
88
|
+
if (BROWSER) {
|
|
89
89
|
if (!window.__EDGES_NAVIGATION_SYNC_MOUNTED__) {
|
|
90
90
|
window.__EDGES_NAVIGATION_SYNC_MOUNTED__ = true;
|
|
91
91
|
void Promise.all([import('svelte'), import('./NavigationStateObserver.svelte')])
|
package/dist/context/Context.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BROWSER } from '@azure-net/tools/environment';
|
|
2
2
|
class RequestContextManager {
|
|
3
3
|
_currentGetter;
|
|
4
4
|
init(getter) {
|
|
5
5
|
this._currentGetter = getter;
|
|
6
6
|
}
|
|
7
7
|
current() {
|
|
8
|
-
if (
|
|
8
|
+
if (BROWSER) {
|
|
9
9
|
return { data: { message: 'Do not use request context on client side' } };
|
|
10
10
|
}
|
|
11
11
|
if (!this._currentGetter) {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { createState as BaseCreateState, createDerivedState as BaseCreateDerivedState, createRawState as BaseCreateRawState } from '../store/index.js';
|
|
2
|
+
import { BROWSER, DEV } from '@azure-net/tools/environment';
|
|
2
3
|
import { RequestContext } from '../context/index.js';
|
|
3
|
-
import {
|
|
4
|
-
import { DevTools } from '../utils/dev.js';
|
|
5
|
-
import { dev } from '../utils/environment.js';
|
|
4
|
+
import { recordProviderAccess, registerProviderDefinition, trackFactoryUniqueness, validateNamedProviderUniqueness } from './Utils.js';
|
|
6
5
|
const globalClientCache = new Map();
|
|
7
6
|
const globalConstructionStack = [];
|
|
8
7
|
const PROVIDER_FACTORY_MARK = Symbol.for('edges-svelte.provider.factory');
|
|
@@ -17,7 +16,7 @@ class AutoKeyGenerator {
|
|
|
17
16
|
cache = this.cache;
|
|
18
17
|
counters = this.counters;
|
|
19
18
|
};
|
|
20
|
-
if (
|
|
19
|
+
if (BROWSER) {
|
|
21
20
|
setGlobalCacheSystem();
|
|
22
21
|
}
|
|
23
22
|
else {
|
|
@@ -45,7 +44,7 @@ class AutoKeyGenerator {
|
|
|
45
44
|
counters.set(baseKey, 0);
|
|
46
45
|
}
|
|
47
46
|
cache.set(factory, finalKey);
|
|
48
|
-
|
|
47
|
+
trackFactoryUniqueness(factory, finalKey);
|
|
49
48
|
return finalKey;
|
|
50
49
|
}
|
|
51
50
|
static hash(str) {
|
|
@@ -58,7 +57,7 @@ class AutoKeyGenerator {
|
|
|
58
57
|
}
|
|
59
58
|
}
|
|
60
59
|
export const clearCache = (pattern) => {
|
|
61
|
-
if (
|
|
60
|
+
if (BROWSER) {
|
|
62
61
|
if (pattern) {
|
|
63
62
|
for (const [key] of globalClientCache) {
|
|
64
63
|
if (key.includes(pattern)) {
|
|
@@ -73,7 +72,7 @@ export const clearCache = (pattern) => {
|
|
|
73
72
|
};
|
|
74
73
|
const createUiProvider = (cacheKey, factory, dependencies, inject) => {
|
|
75
74
|
const readConstructionStack = () => {
|
|
76
|
-
if (
|
|
75
|
+
if (BROWSER)
|
|
77
76
|
return globalConstructionStack;
|
|
78
77
|
try {
|
|
79
78
|
const context = RequestContext.current();
|
|
@@ -89,7 +88,7 @@ const createUiProvider = (cacheKey, factory, dependencies, inject) => {
|
|
|
89
88
|
return `[edges-svelte] Circular provider dependency detected while constructing "${key}". Chain: ${chain.join(' -> ')}.`;
|
|
90
89
|
};
|
|
91
90
|
const validateLazyInjection = (ownerKey, injections) => {
|
|
92
|
-
if (!
|
|
91
|
+
if (!DEV || !injections)
|
|
93
92
|
return;
|
|
94
93
|
for (const [depKey, depValue] of Object.entries(injections)) {
|
|
95
94
|
if (depValue && typeof depValue === 'object') {
|
|
@@ -119,7 +118,7 @@ const createUiProvider = (cacheKey, factory, dependencies, inject) => {
|
|
|
119
118
|
};
|
|
120
119
|
const provider = (() => {
|
|
121
120
|
let contextMap;
|
|
122
|
-
if (
|
|
121
|
+
if (BROWSER) {
|
|
123
122
|
contextMap = globalClientCache;
|
|
124
123
|
}
|
|
125
124
|
else {
|
|
@@ -137,6 +136,7 @@ const createUiProvider = (cacheKey, factory, dependencies, inject) => {
|
|
|
137
136
|
if (contextMap.has(cacheKey)) {
|
|
138
137
|
const cached = contextMap.get(cacheKey);
|
|
139
138
|
if (cached !== undefined) {
|
|
139
|
+
recordProviderAccess(cacheKey, cached, BROWSER ? contextMap.size : undefined);
|
|
140
140
|
return cached;
|
|
141
141
|
}
|
|
142
142
|
}
|
|
@@ -161,6 +161,7 @@ const createUiProvider = (cacheKey, factory, dependencies, inject) => {
|
|
|
161
161
|
}
|
|
162
162
|
markProviderInstance(instance);
|
|
163
163
|
contextMap.set(cacheKey, instance);
|
|
164
|
+
recordProviderAccess(cacheKey, instance, BROWSER ? contextMap.size : undefined);
|
|
164
165
|
return instance;
|
|
165
166
|
});
|
|
166
167
|
try {
|
|
@@ -181,7 +182,11 @@ export function createStore(nameOrFactory, factoryOrInject, inject) {
|
|
|
181
182
|
const name = isNameProvided ? nameOrFactory : undefined;
|
|
182
183
|
const factory = isNameProvided ? factoryOrInject : nameOrFactory;
|
|
183
184
|
const injections = isNameProvided ? inject : factoryOrInject;
|
|
185
|
+
if (isNameProvided) {
|
|
186
|
+
validateNamedProviderUniqueness(name, 'store', factory);
|
|
187
|
+
}
|
|
184
188
|
const cacheKey = name || AutoKeyGenerator.generate(factory);
|
|
189
|
+
registerProviderDefinition(cacheKey, 'store', factory, Boolean(name));
|
|
185
190
|
return createUiProvider(cacheKey, factory, (key) => {
|
|
186
191
|
let stateCounter = 0;
|
|
187
192
|
return {
|
|
@@ -215,7 +220,11 @@ export function createPresenter(nameOrFactory, factoryOrInject, inject) {
|
|
|
215
220
|
const name = isNameProvided ? nameOrFactory : undefined;
|
|
216
221
|
const factory = isNameProvided ? factoryOrInject : nameOrFactory;
|
|
217
222
|
const injections = isNameProvided ? inject : factoryOrInject;
|
|
223
|
+
if (isNameProvided) {
|
|
224
|
+
validateNamedProviderUniqueness(name, 'presenter', factory);
|
|
225
|
+
}
|
|
218
226
|
const cacheKey = name || AutoKeyGenerator.generate(factory);
|
|
227
|
+
registerProviderDefinition(cacheKey, 'presenter', factory, Boolean(name));
|
|
219
228
|
return createUiProvider(cacheKey, factory, {}, injections);
|
|
220
229
|
}
|
|
221
230
|
export const createPresenterFactory = (inject) => {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { UnknownFunc } from '../types.js';
|
|
2
|
+
export type ProviderKind = 'store' | 'presenter';
|
|
3
|
+
export interface ProviderDevDefinitionSnapshot {
|
|
4
|
+
key: string;
|
|
5
|
+
kind: ProviderKind;
|
|
6
|
+
factoryName: string;
|
|
7
|
+
named: boolean;
|
|
8
|
+
registeredAt: number;
|
|
9
|
+
}
|
|
10
|
+
export interface ProviderDevRuntimeSnapshot {
|
|
11
|
+
key: string;
|
|
12
|
+
instantiated: boolean;
|
|
13
|
+
hits: number;
|
|
14
|
+
lastAccessedAt: number | null;
|
|
15
|
+
instanceSizeBytes: number;
|
|
16
|
+
}
|
|
17
|
+
export interface ProviderDevSnapshot {
|
|
18
|
+
definitions: ProviderDevDefinitionSnapshot[];
|
|
19
|
+
runtimes: ProviderDevRuntimeSnapshot[];
|
|
20
|
+
providerCacheEntries: number;
|
|
21
|
+
providerCacheSizeBytes: number;
|
|
22
|
+
}
|
|
23
|
+
export interface ProviderDuplicateAttempt {
|
|
24
|
+
key: string;
|
|
25
|
+
attemptedKind: ProviderKind;
|
|
26
|
+
existingKind: ProviderKind;
|
|
27
|
+
at: number;
|
|
28
|
+
}
|
|
29
|
+
export declare const trackFactoryUniqueness: (factory: UnknownFunc, key: string) => void;
|
|
30
|
+
export declare const validateNamedProviderUniqueness: (key: string, kind: ProviderKind, factory: UnknownFunc) => void;
|
|
31
|
+
export declare const registerProviderDefinition: (key: string, kind: ProviderKind, factory: UnknownFunc, named: boolean) => void;
|
|
32
|
+
export declare const recordProviderAccess: (key: string, instance: unknown, cacheEntriesHint?: number) => void;
|
|
33
|
+
export declare const getProviderDevSnapshot: () => ProviderDevSnapshot;
|
|
34
|
+
export declare const getProviderDuplicateAttempts: () => ProviderDuplicateAttempt[];
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { BROWSER, DEV } from '@azure-net/tools/environment';
|
|
2
|
+
const seenFactories = new WeakSet();
|
|
3
|
+
const namedProviderRegistry = new Map();
|
|
4
|
+
const duplicateNamedProviderEvents = [];
|
|
5
|
+
const providerDefinitions = new Map();
|
|
6
|
+
const providerRuntime = new Map();
|
|
7
|
+
let providerCacheEntries = 0;
|
|
8
|
+
let providerCacheSizeBytes = 0;
|
|
9
|
+
const safeJsonLength = (value) => {
|
|
10
|
+
try {
|
|
11
|
+
const serialized = JSON.stringify(value);
|
|
12
|
+
return serialized ? serialized.length : 0;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return 0;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const estimateSize = (value) => {
|
|
19
|
+
if (typeof value === 'bigint')
|
|
20
|
+
return value.toString().length;
|
|
21
|
+
if (typeof value === 'function' || typeof value === 'symbol')
|
|
22
|
+
return 0;
|
|
23
|
+
if (typeof value === 'string')
|
|
24
|
+
return value.length;
|
|
25
|
+
if (value === undefined || value === null)
|
|
26
|
+
return 0;
|
|
27
|
+
return safeJsonLength(value);
|
|
28
|
+
};
|
|
29
|
+
export const trackFactoryUniqueness = (factory, key) => {
|
|
30
|
+
if (!DEV)
|
|
31
|
+
return;
|
|
32
|
+
if (seenFactories.has(factory)) {
|
|
33
|
+
console.warn(`[edges-svelte] Factory collision detected for key "${key}". ` +
|
|
34
|
+
`This might cause unexpected behavior.` +
|
|
35
|
+
`Set a unique __storeKey__ property on your factory function.`);
|
|
36
|
+
}
|
|
37
|
+
seenFactories.add(factory);
|
|
38
|
+
};
|
|
39
|
+
export const validateNamedProviderUniqueness = (key, kind, factory) => {
|
|
40
|
+
if (!DEV)
|
|
41
|
+
return;
|
|
42
|
+
const existing = namedProviderRegistry.get(key);
|
|
43
|
+
if (!existing) {
|
|
44
|
+
namedProviderRegistry.set(key, { kind, factory });
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (existing.factory === factory && existing.kind === kind) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
duplicateNamedProviderEvents.push({
|
|
51
|
+
key,
|
|
52
|
+
attemptedKind: kind,
|
|
53
|
+
existingKind: existing.kind,
|
|
54
|
+
at: Date.now()
|
|
55
|
+
});
|
|
56
|
+
throw new Error(`[edges-svelte] Duplicate ${kind} key "${key}" detected. ` +
|
|
57
|
+
`This key is already used by a ${existing.kind}. Use unique names for createStore/createPresenter.`);
|
|
58
|
+
};
|
|
59
|
+
export const registerProviderDefinition = (key, kind, factory, named) => {
|
|
60
|
+
if (!DEV || !BROWSER)
|
|
61
|
+
return;
|
|
62
|
+
if (providerDefinitions.has(key))
|
|
63
|
+
return;
|
|
64
|
+
providerDefinitions.set(key, {
|
|
65
|
+
key,
|
|
66
|
+
kind,
|
|
67
|
+
factoryName: factory.displayName || factory.name || '(anonymous)',
|
|
68
|
+
named,
|
|
69
|
+
registeredAt: Date.now()
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
export const recordProviderAccess = (key, instance, cacheEntriesHint) => {
|
|
73
|
+
if (!DEV || !BROWSER)
|
|
74
|
+
return;
|
|
75
|
+
const runtime = providerRuntime.get(key) ?? {
|
|
76
|
+
key,
|
|
77
|
+
instantiated: false,
|
|
78
|
+
hits: 0,
|
|
79
|
+
lastAccessedAt: null,
|
|
80
|
+
instanceSizeBytes: 0
|
|
81
|
+
};
|
|
82
|
+
runtime.instantiated = true;
|
|
83
|
+
runtime.hits += 1;
|
|
84
|
+
runtime.lastAccessedAt = Date.now();
|
|
85
|
+
runtime.instanceSizeBytes = estimateSize(instance);
|
|
86
|
+
providerRuntime.set(key, runtime);
|
|
87
|
+
if (typeof cacheEntriesHint === 'number') {
|
|
88
|
+
providerCacheEntries = cacheEntriesHint;
|
|
89
|
+
}
|
|
90
|
+
providerCacheSizeBytes = 0;
|
|
91
|
+
for (const [providerKey, tracked] of providerRuntime) {
|
|
92
|
+
providerCacheSizeBytes += providerKey.length;
|
|
93
|
+
providerCacheSizeBytes += tracked.instanceSizeBytes;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
export const getProviderDevSnapshot = () => ({
|
|
97
|
+
definitions: Array.from(providerDefinitions.values()),
|
|
98
|
+
runtimes: Array.from(providerRuntime.values()),
|
|
99
|
+
providerCacheEntries,
|
|
100
|
+
providerCacheSizeBytes
|
|
101
|
+
});
|
|
102
|
+
export const getProviderDuplicateAttempts = () => [...duplicateNamedProviderEvents];
|
|
@@ -33,6 +33,8 @@ export const edgesHandle = async (event, callback, silentChromeDevtools = false)
|
|
|
33
33
|
serialize: (html) => {
|
|
34
34
|
if (!html)
|
|
35
35
|
return html ?? '';
|
|
36
|
+
if (!html.includes('</body>'))
|
|
37
|
+
return html;
|
|
36
38
|
const serialized = stateSerialize();
|
|
37
39
|
if (!serialized)
|
|
38
40
|
return html;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getStateMap } from '../store/State.svelte.js';
|
|
2
2
|
import { RequestContext } from '../context/Context.js';
|
|
3
|
-
import {
|
|
3
|
+
import { DEV } from '@azure-net/tools/environment';
|
|
4
4
|
const UNDEFINED_MARKER = '__EDGES_UNDEFINED__';
|
|
5
5
|
const NULL_MARKER = '__EDGES_NULL__';
|
|
6
6
|
const BIGINT_MARKER = '__EDGES_BIGINT__';
|
|
@@ -9,7 +9,6 @@ const EDGES_REV_FIELD = '__edges_rev__';
|
|
|
9
9
|
const isObjectRecord = (value) => {
|
|
10
10
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
11
11
|
};
|
|
12
|
-
const PROFILE_EDGES_DELTA = dev && !build;
|
|
13
12
|
const encodeEdgesValue = (value) => {
|
|
14
13
|
if (value === undefined)
|
|
15
14
|
return { [UNDEFINED_MARKER]: true };
|
|
@@ -30,7 +29,7 @@ const encodeEdgesValue = (value) => {
|
|
|
30
29
|
return value;
|
|
31
30
|
};
|
|
32
31
|
const getEdgesDelta = () => {
|
|
33
|
-
const startedAt =
|
|
32
|
+
const startedAt = DEV ? performance.now() : 0;
|
|
34
33
|
try {
|
|
35
34
|
const context = RequestContext.current();
|
|
36
35
|
const dirtyKeys = context.data.edgesDirtyKeys;
|
|
@@ -52,7 +51,7 @@ const getEdgesDelta = () => {
|
|
|
52
51
|
return undefined;
|
|
53
52
|
}
|
|
54
53
|
finally {
|
|
55
|
-
if (
|
|
54
|
+
if (DEV) {
|
|
56
55
|
const duration = performance.now() - startedAt;
|
|
57
56
|
if (duration > 4) {
|
|
58
57
|
console.debug(`[edges-svelte] edges delta encode took ${duration.toFixed(2)}ms`);
|
|
@@ -2,7 +2,7 @@ import { type Readable, type Writable } from 'svelte/store';
|
|
|
2
2
|
declare global {
|
|
3
3
|
interface Window {
|
|
4
4
|
__SAFE_SSR_STATE__?: Map<string, unknown>;
|
|
5
|
-
__EDGES_DEVTOOLS__
|
|
5
|
+
__EDGES_DEVTOOLS__?: Record<string, unknown>;
|
|
6
6
|
}
|
|
7
7
|
}
|
|
8
8
|
export declare const stateSerialize: () => string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RequestContext } from '../context/Context.js';
|
|
2
|
-
import {
|
|
2
|
+
import { BROWSER } from '@azure-net/tools/environment';
|
|
3
3
|
import { derived, writable } from 'svelte/store';
|
|
4
4
|
import { registerStateUpdate } from '../client/NavigationSync.svelte.js';
|
|
5
5
|
import { queueUpdate, isBatching } from '../utils/batch.js';
|
|
@@ -56,7 +56,7 @@ const getRequestContext = () => {
|
|
|
56
56
|
}
|
|
57
57
|
};
|
|
58
58
|
const markStateDirty = (key) => {
|
|
59
|
-
if (
|
|
59
|
+
if (BROWSER)
|
|
60
60
|
return;
|
|
61
61
|
try {
|
|
62
62
|
const context = RequestContext.current();
|
|
@@ -85,7 +85,7 @@ const getBrowserState = (key, initial) => {
|
|
|
85
85
|
return initial;
|
|
86
86
|
};
|
|
87
87
|
export const createRawState = (key, initial) => {
|
|
88
|
-
if (
|
|
88
|
+
if (BROWSER) {
|
|
89
89
|
let state = $state(getBrowserState(key, initial()));
|
|
90
90
|
const updateWindowState = (val) => {
|
|
91
91
|
if (!window.__SAFE_SSR_STATE__) {
|
|
@@ -138,7 +138,7 @@ export const createRawState = (key, initial) => {
|
|
|
138
138
|
};
|
|
139
139
|
};
|
|
140
140
|
export const createState = (key, initial) => {
|
|
141
|
-
if (
|
|
141
|
+
if (BROWSER) {
|
|
142
142
|
const initialValue = getBrowserState(key, initial());
|
|
143
143
|
const state = writable(initialValue);
|
|
144
144
|
let currentValue = initialValue;
|
|
@@ -222,7 +222,7 @@ export const createState = (key, initial) => {
|
|
|
222
222
|
};
|
|
223
223
|
};
|
|
224
224
|
export const createDerivedState = (stores, deriveFn) => {
|
|
225
|
-
if (
|
|
225
|
+
if (BROWSER) {
|
|
226
226
|
return derived(stores, deriveFn);
|
|
227
227
|
}
|
|
228
228
|
return {
|