edges-svelte 2.2.0 → 3.0.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.
@@ -1,28 +1,14 @@
1
- import { stateSerialize, getStateMap } from '../store/State.svelte.js';
1
+ import { stateSerialize } from '../store/State.svelte.js';
2
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
- 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
- return value;
16
- };
17
- /**
18
- * Wraps request handling in an AsyncLocalStorage context
19
- */
5
+ let requestRevision = 0;
20
6
  export const edgesHandle = async (event, callback, silentChromeDevtools = false) => {
21
7
  const requestSymbol = Symbol('request');
22
8
  return await storage.run({
23
9
  event: event,
24
10
  symbol: requestSymbol,
25
- data: { providers: new Map() }
11
+ data: { providers: new Map(), edgesDirtyKeys: new Set(), edgesRevision: ++requestRevision }
26
12
  }, async () => {
27
13
  RequestContext.init(() => {
28
14
  const context = storage.getStore();
@@ -44,56 +30,15 @@ export const edgesHandle = async (event, callback, silentChromeDevtools = false)
44
30
  }
45
31
  const response = await callback({
46
32
  edgesEvent: event,
47
- serialize: (html, options) => {
33
+ serialize: (html) => {
48
34
  if (!html)
49
35
  return html ?? '';
50
- const serialized = stateSerialize({
51
- compress: options?.compress,
52
- threshold: options?.compressionThreshold
53
- });
36
+ const serialized = stateSerialize();
54
37
  if (!serialized)
55
38
  return html;
56
39
  return html.replace('</body>', `${serialized}</body>`);
57
40
  }
58
41
  });
59
- const contentType = response.headers.get('content-type');
60
- if (contentType?.includes('application/json')) {
61
- const stateMap = getStateMap();
62
- if (stateMap && stateMap.size > 0) {
63
- try {
64
- const text = await response.text();
65
- try {
66
- const stateObj = {};
67
- for (const [key, value] of stateMap) {
68
- stateObj[key] = JSON.stringify(value, safeReplacer);
69
- }
70
- const modifiedBody = JSON.stringify({
71
- ...JSON.parse(text),
72
- __edges_state__: stateObj
73
- });
74
- const newHeaders = new Headers(response.headers);
75
- newHeaders.set('content-length', String(textEncoder.encode(modifiedBody).length));
76
- return new Response(modifiedBody, {
77
- status: response.status,
78
- statusText: response.statusText,
79
- headers: newHeaders
80
- });
81
- }
82
- catch {
83
- return new Response(text, {
84
- status: response.status,
85
- statusText: response.statusText,
86
- headers: response.headers
87
- });
88
- }
89
- }
90
- catch (e) {
91
- console.error('[edges] Failed to inject state into JSON response:', e);
92
- // Original response
93
- return response;
94
- }
95
- }
96
- }
97
42
  return response;
98
43
  });
99
44
  };
@@ -1,24 +1,12 @@
1
1
  import type { Handle, RequestEvent, ResolveOptions } from '@sveltejs/kit';
2
- interface SerializeOptions {
3
- compress?: boolean;
4
- compressionThreshold?: number;
5
- }
6
2
  type SimplifiedCallback = (params: {
7
- serialize: (html: string, options?: SerializeOptions) => string;
3
+ serialize: (html: string) => string;
8
4
  edgesEvent: RequestEvent;
9
5
  resolve: (event: RequestEvent, opts?: ResolveOptions) => Response | Promise<Response>;
10
6
  }) => Response | Promise<Response>;
11
7
  /**
12
- * Simplified wrapper around edgesHandle that provides a more convenient API.
13
- *
14
8
  * @example
15
9
  * ```ts
16
- * // Simple usage with default behavior
17
- * export const handle = edgesHandle(({ serialize, edgesEvent, resolve }) =>
18
- * resolve(edgesEvent, { transformPageChunk: ({ html }) => serialize(html) })
19
- * );
20
- *
21
- * // You can still access resolve for custom logic
22
10
  * export const handle = edgesHandle(({ serialize, edgesEvent, resolve }) => {
23
11
  * // Custom logic here
24
12
  * return resolve(edgesEvent, { transformPageChunk: ({ html }) => serialize(html) });
@@ -1,15 +1,7 @@
1
1
  import { edgesHandle as originalEdgesHandle } from './EdgesHandle.js';
2
2
  /**
3
- * Simplified wrapper around edgesHandle that provides a more convenient API.
4
- *
5
3
  * @example
6
4
  * ```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
5
  * export const handle = edgesHandle(({ serialize, edgesEvent, resolve }) => {
14
6
  * // Custom logic here
15
7
  * return resolve(edgesEvent, { transformPageChunk: ({ html }) => serialize(html) });
@@ -0,0 +1,3 @@
1
+ export declare const __withEdgesServerLoad: <T extends (...args: unknown[]) => unknown>(load: T) => T;
2
+ export declare const __withEdgesActions: <T extends Record<string, (...args: unknown[]) => unknown>>(actions: T) => T;
3
+ export declare const __withEdgesUniversalLoad: <T extends (...args: unknown[]) => unknown>(load: T) => T;
@@ -0,0 +1,125 @@
1
+ import { getStateMap } from '../store/State.svelte.js';
2
+ import { RequestContext } from '../context/Context.js';
3
+ import { build, dev } from '../utils/environment.js';
4
+ const UNDEFINED_MARKER = '__EDGES_UNDEFINED__';
5
+ const NULL_MARKER = '__EDGES_NULL__';
6
+ const BIGINT_MARKER = '__EDGES_BIGINT__';
7
+ const EDGES_STATE_FIELD = '__edges_state__';
8
+ const EDGES_REV_FIELD = '__edges_rev__';
9
+ const isObjectRecord = (value) => {
10
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
11
+ };
12
+ const PROFILE_EDGES_DELTA = dev && !build;
13
+ const encodeEdgesValue = (value) => {
14
+ if (value === undefined)
15
+ return { [UNDEFINED_MARKER]: true };
16
+ if (value === null)
17
+ return { [NULL_MARKER]: true };
18
+ if (typeof value === 'bigint')
19
+ return { [BIGINT_MARKER]: value.toString() };
20
+ if (Array.isArray(value)) {
21
+ return value.map((item) => encodeEdgesValue(item));
22
+ }
23
+ if (typeof value === 'object' && value !== null) {
24
+ const encoded = {};
25
+ for (const [key, nested] of Object.entries(value)) {
26
+ encoded[key] = encodeEdgesValue(nested);
27
+ }
28
+ return encoded;
29
+ }
30
+ return value;
31
+ };
32
+ const getEdgesDelta = () => {
33
+ const startedAt = PROFILE_EDGES_DELTA ? performance.now() : 0;
34
+ try {
35
+ const context = RequestContext.current();
36
+ const dirtyKeys = context.data.edgesDirtyKeys;
37
+ const rev = context.data.edgesRevision ?? 0;
38
+ const stateMap = getStateMap();
39
+ if (!dirtyKeys || dirtyKeys.size === 0 || !stateMap || stateMap.size === 0)
40
+ return undefined;
41
+ const state = {};
42
+ for (const key of dirtyKeys) {
43
+ if (!stateMap.has(key))
44
+ continue;
45
+ state[key] = encodeEdgesValue(stateMap.get(key));
46
+ }
47
+ if (Object.keys(state).length === 0)
48
+ return undefined;
49
+ return { state, rev };
50
+ }
51
+ catch {
52
+ return undefined;
53
+ }
54
+ finally {
55
+ if (PROFILE_EDGES_DELTA) {
56
+ const duration = performance.now() - startedAt;
57
+ if (duration > 4) {
58
+ console.debug(`[edges-svelte] edges delta encode took ${duration.toFixed(2)}ms`);
59
+ }
60
+ }
61
+ }
62
+ };
63
+ const mergePayloadWithEdges = (payload) => {
64
+ const edges = getEdgesDelta();
65
+ if (!edges)
66
+ return payload;
67
+ if (isObjectRecord(payload)) {
68
+ return {
69
+ ...payload,
70
+ [EDGES_STATE_FIELD]: edges.state,
71
+ [EDGES_REV_FIELD]: edges.rev
72
+ };
73
+ }
74
+ if (payload === undefined) {
75
+ return {
76
+ [EDGES_STATE_FIELD]: edges.state,
77
+ [EDGES_REV_FIELD]: edges.rev
78
+ };
79
+ }
80
+ return payload;
81
+ };
82
+ export const __withEdgesServerLoad = (load) => {
83
+ const wrapped = (async (...args) => {
84
+ const result = await load(...args);
85
+ return mergePayloadWithEdges(result);
86
+ });
87
+ return wrapped;
88
+ };
89
+ export const __withEdgesActions = (actions) => {
90
+ const wrapped = {};
91
+ for (const [name, action] of Object.entries(actions)) {
92
+ wrapped[name] = async (...args) => {
93
+ const result = await action(...args);
94
+ return mergePayloadWithEdges(result);
95
+ };
96
+ }
97
+ return wrapped;
98
+ };
99
+ export const __withEdgesUniversalLoad = (load) => {
100
+ const wrapped = (async (...args) => {
101
+ const event = args[0];
102
+ const result = await load(...args);
103
+ if (!isObjectRecord(event?.data))
104
+ return result;
105
+ const inheritedState = event.data[EDGES_STATE_FIELD];
106
+ const inheritedRev = event.data[EDGES_REV_FIELD];
107
+ if (!inheritedState)
108
+ return result;
109
+ if (isObjectRecord(result)) {
110
+ return {
111
+ ...result,
112
+ [EDGES_STATE_FIELD]: inheritedState,
113
+ [EDGES_REV_FIELD]: inheritedRev
114
+ };
115
+ }
116
+ if (result === undefined) {
117
+ return {
118
+ [EDGES_STATE_FIELD]: inheritedState,
119
+ [EDGES_REV_FIELD]: inheritedRev
120
+ };
121
+ }
122
+ return result;
123
+ });
124
+ return wrapped;
125
+ };
@@ -1,3 +1,4 @@
1
1
  export { edgesHandle as edgesHandleRaw } from './EdgesHandle.js';
2
2
  export { edgesHandle } from './EdgesHandleSimplified.js';
3
3
  export { __autoWrapHandle } from './AutoWrapHandle.js';
4
+ export { __withEdgesServerLoad, __withEdgesActions, __withEdgesUniversalLoad } from './ServerSync.js';
@@ -1,3 +1,4 @@
1
1
  export { edgesHandle as edgesHandleRaw } from './EdgesHandle.js';
2
2
  export { edgesHandle } from './EdgesHandleSimplified.js';
3
3
  export { __autoWrapHandle } from './AutoWrapHandle.js';
4
+ export { __withEdgesServerLoad, __withEdgesActions, __withEdgesUniversalLoad } from './ServerSync.js';
@@ -5,10 +5,7 @@ declare global {
5
5
  __EDGES_DEVTOOLS__: Record<string, unknown>;
6
6
  }
7
7
  }
8
- export declare const stateSerialize: (options?: {
9
- compress?: boolean;
10
- threshold?: number;
11
- }) => string;
8
+ export declare const stateSerialize: () => string;
12
9
  export declare const getStateMap: () => Map<string, unknown> | undefined;
13
10
  export declare const createRawState: <T>(key: string, initial: () => T) => {
14
11
  value: T;
@@ -2,11 +2,12 @@ import { RequestContext } from '../context/Context.js';
2
2
  import { browser } from '../utils/environment.js';
3
3
  import { derived, writable } from 'svelte/store';
4
4
  import { registerStateUpdate } from '../client/NavigationSync.svelte.js';
5
+ import { queueUpdate, isBatching } from '../utils/batch.js';
5
6
  const RequestStores = new WeakMap();
6
7
  const UNDEFINED_MARKER = '__EDGES_UNDEFINED__';
7
8
  const NULL_MARKER = '__EDGES_NULL__';
8
- // Pre-compiled reviver code for better performance (cached once instead of regenerated per request)
9
- const REVIVER_CODE = `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};`;
9
+ const BIGINT_MARKER = '__EDGES_BIGINT__';
10
+ const REVIVER_CODE = `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;if('${BIGINT_MARKER}' in v)return BigInt(v['${BIGINT_MARKER}'])}return v};`;
10
11
  const safeReplacer = (key, value) => {
11
12
  if (value === undefined) {
12
13
  return { [UNDEFINED_MARKER]: true };
@@ -14,53 +15,34 @@ const safeReplacer = (key, value) => {
14
15
  if (value === null) {
15
16
  return { [NULL_MARKER]: true };
16
17
  }
18
+ if (typeof value === 'bigint') {
19
+ return { [BIGINT_MARKER]: value.toString() };
20
+ }
17
21
  if (typeof value === 'function' || typeof value === 'symbol') {
18
22
  return undefined;
19
23
  }
20
24
  return value;
21
25
  };
22
- // const safeReviver = (key: string, value: unknown): unknown => {
23
- // if (value && typeof value === 'object') {
24
- // if (UNDEFINED_MARKER in value) {
25
- // return undefined;
26
- // }
27
- // if (NULL_MARKER in value) {
28
- // return null;
29
- // }
30
- // }
31
- // return value;
32
- // };
33
- export const stateSerialize = (options) => {
26
+ const escapeInlineScriptString = (value) => value
27
+ .replace(/[\\']/g, (ch) => '\\' + ch)
28
+ .replace(/</g, '\\u003C')
29
+ .replace(/>/g, '\\u003E')
30
+ .replace(/&/g, '\\u0026')
31
+ .replace(/\u2028/g, '\\u2028')
32
+ .replace(/\u2029/g, '\\u2029');
33
+ export const stateSerialize = () => {
34
34
  const map = getRequestContext();
35
35
  if (!map || map.size === 0)
36
36
  return '';
37
37
  const entries = [];
38
- const shouldCompress = options?.compress ?? false;
39
- const threshold = options?.threshold ?? 1024; // 1KB default
40
38
  for (const [key, value] of map) {
41
39
  const serialized = JSON.stringify(value, safeReplacer);
42
- // Check if we should compress this entry
43
- if (shouldCompress && serialized.length > threshold) {
44
- // For large values, use base64 encoding as a simple compression
45
- // Optimized: Use Array.from instead of reduce for 10x performance improvement
46
- const bytes = new TextEncoder().encode(serialized);
47
- const binary = Array.from(bytes, (byte) => String.fromCharCode(byte)).join('');
48
- const encoded = btoa(binary);
49
- entries.push(`{
50
- const binary = atob('${encoded}');
51
- const bytes = new Uint8Array(binary.length);
52
- for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
53
- const decoded = new TextDecoder().decode(bytes);
54
- window.__SAFE_SSR_STATE__.set('${key}', JSON.parse(decoded, window.__EDGES_REVIVER__));
55
- }`);
56
- }
57
- else {
58
- // Optimized: Single-pass escape instead of two separate replace calls
59
- const escaped = serialized.replace(/[\\']/g, (ch) => '\\' + ch);
60
- entries.push(`window.__SAFE_SSR_STATE__.set('${key}',JSON.parse('${escaped}',window.__EDGES_REVIVER__))`);
61
- }
40
+ if (serialized === undefined)
41
+ continue;
42
+ const escapedKey = escapeInlineScriptString(key);
43
+ const escaped = escapeInlineScriptString(serialized);
44
+ entries.push(`window.__SAFE_SSR_STATE__.set('${escapedKey}',JSON.parse('${escaped}',window.__EDGES_REVIVER__))`);
62
45
  }
63
- // Use pre-compiled reviver code for better performance
64
46
  return `<script>${REVIVER_CODE}window.__SAFE_SSR_STATE__=new Map();${entries.join(';')}</script>`;
65
47
  };
66
48
  const getRequestContext = () => {
@@ -73,6 +55,17 @@ const getRequestContext = () => {
73
55
  return RequestStores.get(sym);
74
56
  }
75
57
  };
58
+ const markStateDirty = (key) => {
59
+ if (browser)
60
+ return;
61
+ try {
62
+ const context = RequestContext.current();
63
+ (context.data.edgesDirtyKeys ??= new Set()).add(key);
64
+ }
65
+ catch {
66
+ // no request context, ignore
67
+ }
68
+ };
76
69
  export const getStateMap = () => {
77
70
  try {
78
71
  return getRequestContext();
@@ -94,23 +87,30 @@ const getBrowserState = (key, initial) => {
94
87
  export const createRawState = (key, initial) => {
95
88
  if (browser) {
96
89
  let state = $state(getBrowserState(key, initial()));
97
- const callback = (newValue) => {
98
- state = newValue;
99
- };
100
- registerStateUpdate(key, callback);
101
90
  const updateWindowState = (val) => {
102
91
  if (!window.__SAFE_SSR_STATE__) {
103
92
  window.__SAFE_SSR_STATE__ = new Map();
104
93
  }
105
94
  window.__SAFE_SSR_STATE__.set(key, val);
106
95
  };
96
+ const applyValue = (val) => {
97
+ state = val;
98
+ updateWindowState(val);
99
+ };
100
+ const callback = (newValue) => {
101
+ queueUpdate(key, newValue, (next) => applyValue(next));
102
+ };
103
+ registerStateUpdate(key, callback);
107
104
  return {
108
105
  get value() {
109
106
  return state;
110
107
  },
111
108
  set value(val) {
112
- state = val;
113
- updateWindowState(val);
109
+ if (isBatching()) {
110
+ queueUpdate(key, val, (next) => applyValue(next));
111
+ return;
112
+ }
113
+ applyValue(val);
114
114
  }
115
115
  };
116
116
  }
@@ -121,9 +121,7 @@ export const createRawState = (key, initial) => {
121
121
  get value() {
122
122
  return val;
123
123
  },
124
- set value(_) {
125
- /* noop */
126
- }
124
+ set value(_) { }
127
125
  };
128
126
  }
129
127
  return {
@@ -135,6 +133,7 @@ export const createRawState = (key, initial) => {
135
133
  },
136
134
  set value(val) {
137
135
  map.set(key, val);
136
+ markStateDirty(key);
138
137
  }
139
138
  };
140
139
  };
@@ -142,22 +141,45 @@ export const createState = (key, initial) => {
142
141
  if (browser) {
143
142
  const initialValue = getBrowserState(key, initial());
144
143
  const state = writable(initialValue);
144
+ let currentValue = initialValue;
145
145
  const callback = (newValue) => {
146
- state.set(newValue);
146
+ queueUpdate(key, newValue, (next) => {
147
+ applyValue(next);
148
+ });
147
149
  };
148
150
  registerStateUpdate(key, callback);
149
151
  const originalSet = state.set;
150
152
  const originalUpdate = state.update;
151
- state.set = (value) => {
153
+ const applyValue = (value) => {
154
+ currentValue = value;
152
155
  originalSet(value);
153
156
  if (!window.__SAFE_SSR_STATE__) {
154
157
  window.__SAFE_SSR_STATE__ = new Map();
155
158
  }
156
159
  window.__SAFE_SSR_STATE__.set(key, value);
157
160
  };
161
+ state.set = (value) => {
162
+ if (isBatching()) {
163
+ currentValue = value;
164
+ queueUpdate(key, value, (next) => {
165
+ applyValue(next);
166
+ });
167
+ return;
168
+ }
169
+ applyValue(value);
170
+ };
158
171
  state.update = (updater) => {
172
+ if (isBatching()) {
173
+ const nextValue = updater(currentValue);
174
+ currentValue = nextValue;
175
+ queueUpdate(key, nextValue, (next) => {
176
+ applyValue(next);
177
+ });
178
+ return;
179
+ }
159
180
  originalUpdate((current) => {
160
181
  const newValue = updater(current);
182
+ currentValue = newValue;
161
183
  if (!window.__SAFE_SSR_STATE__) {
162
184
  window.__SAFE_SSR_STATE__ = new Map();
163
185
  }
@@ -189,11 +211,13 @@ export const createState = (key, initial) => {
189
211
  },
190
212
  set(val) {
191
213
  map.set(key, val);
214
+ markStateDirty(key);
192
215
  },
193
216
  update(updater) {
194
217
  const oldVal = map.get(key);
195
218
  const newVal = updater(oldVal);
196
219
  map.set(key, newVal);
220
+ markStateDirty(key);
197
221
  }
198
222
  };
199
223
  };
package/dist/types.d.ts CHANGED
@@ -1,25 +1,8 @@
1
1
  import type { Writable, Readable } from 'svelte/store';
2
- /**
3
- * Configuration for store creation with minification resistance
4
- */
5
2
  export interface StoreConfig {
6
- /**
7
- * Explicit key for the store to avoid minification issues
8
- * @example
9
- * ```ts
10
- * const factory = (deps) => { ... };
11
- * factory.__storeKey__ = 'userStore';
12
- * ```
13
- */
14
3
  __storeKey__?: string;
15
- /**
16
- * Display name for debugging
17
- */
18
4
  displayName?: string;
19
5
  }
20
- /**
21
- * Store factory function with configuration
22
- */
23
6
  export type StoreFactory<T, I = Record<string, unknown>> = ((args: {
24
7
  createState: <T>(initial: T | (() => T)) => Writable<T>;
25
8
  createRawState: <T>(initial: T | (() => T)) => {
@@ -27,89 +10,20 @@ export type StoreFactory<T, I = Record<string, unknown>> = ((args: {
27
10
  };
28
11
  createDerivedState: <T extends Readable<unknown>[], D>(stores: T, deriveFn: (values: unknown[]) => D) => Readable<D>;
29
12
  } & I) => T) & StoreConfig;
30
- /**
31
- * Presenter factory function with configuration
32
- */
33
13
  export type PresenterFactory<T, I = Record<string, unknown>> = ((args: I) => T) & StoreConfig;
34
- /**
35
- * Options for batched state updates
36
- */
37
14
  export interface BatchOptions {
38
- /**
39
- * Whether to defer DOM updates to the next microtask
40
- * @default true
41
- */
42
15
  defer?: boolean;
43
- /**
44
- * Callback when batch completes
45
- */
46
16
  onComplete?: () => void;
47
17
  }
48
- /**
49
- * Compression options for state serialization
50
- */
51
- export interface CompressionOptions {
52
- /**
53
- * Enable compression for large state objects
54
- * @default false
55
- */
56
- enabled?: boolean;
57
- /**
58
- * Minimum size in bytes before compression is applied
59
- * @default 1024 (1KB)
60
- */
61
- threshold?: number;
62
- /**
63
- * Compression algorithm to use
64
- * @default 'base64'
65
- */
66
- algorithm?: 'base64' | 'gzip' | 'brotli';
67
- }
68
- /**
69
- * Development tools configuration
70
- */
71
18
  export interface DevToolsConfig {
72
- /**
73
- * Enable development mode validations
74
- * @default true in dev, false in production
75
- */
76
19
  enabled?: boolean;
77
- /**
78
- * Warn about large state objects
79
- * @default true
80
- */
81
20
  warnLargeState?: boolean;
82
- /**
83
- * Size threshold for large state warnings (in bytes)
84
- * @default 50000 (50KB)
85
- */
86
21
  largeStateThreshold?: number;
87
- /**
88
- * Check for direct state mutations
89
- * @default true
90
- */
91
22
  checkMutations?: boolean;
92
- /**
93
- * Log performance metrics
94
- * @default false
95
- */
96
23
  logPerformance?: boolean;
97
24
  }
98
- /**
99
- * Global configuration for edges-svelte
100
- */
101
25
  export interface EdgesConfig {
102
- /**
103
- * Development tools configuration
104
- */
105
26
  devTools?: DevToolsConfig;
106
- /**
107
- * Default compression options for state serialization
108
- */
109
- compression?: CompressionOptions;
110
- /**
111
- * Default batch options
112
- */
113
27
  batch?: BatchOptions;
114
28
  }
115
29
  export type UnknownFunc = {
@@ -1,25 +1,5 @@
1
- /**
2
- * Batch multiple state updates to avoid unnecessary re-renders
3
- *
4
- * @example
5
- * ```ts
6
- * batch(() => {
7
- * store1.set(value1);
8
- * store2.set(value2);
9
- * store3.set(value3);
10
- * });
11
- * ```
12
- */
13
1
  export declare const batch: (fn: () => void) => void;
14
- /**
15
- * Queue an update for batching (internal use)
16
- */
17
2
  export declare const queueUpdate: (key: string, value: unknown, callback?: (value: unknown) => void) => void;
18
- /**
19
- * Register a callback for batch completion (internal use)
20
- */
21
3
  export declare const onBatchComplete: (callback: () => void) => void;
22
- /**
23
- * Transaction-like API for complex state updates
24
- */
4
+ export declare const isBatching: () => boolean;
25
5
  export declare const transaction: <T>(fn: () => Promise<T>) => Promise<T>;