Skip to content

Commit 76aadd7

Browse files
committed
feat: new shared state utils
1 parent 9c81023 commit 76aadd7

File tree

6 files changed

+139
-43
lines changed

6 files changed

+139
-43
lines changed

packages/core/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"birpc-x": "catalog:deps",
6161
"cac": "catalog:deps",
6262
"debug": "catalog:deps",
63+
"immer": "catalog:deps",
6364
"launch-editor": "catalog:deps",
6465
"mlly": "catalog:deps",
6566
"open": "catalog:deps",

packages/core/src/node/rpc/anonymous/auth.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export const anonymousAuth = defineRpcFunction({
3939

4040
const message = [
4141
`A browser is requesting permissions to connect to the Vite DevTools.`,
42-
42+
'',
4343
`User Agent: ${c.yellow(c.bold(query.ua || 'Unknown'))}`,
4444
`Origin : ${c.cyan(c.bold(query.origin || 'Unknown'))}`,
4545
`Identifier: ${c.green(c.bold(query.authId))}`,

packages/kit/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@
4242
"dependencies": {
4343
"@vitejs/devtools-rpc": "workspace:*",
4444
"birpc": "catalog:deps",
45-
"birpc-x": "catalog:deps"
45+
"birpc-x": "catalog:deps",
46+
"immer": "catalog:deps"
4647
},
4748
"devDependencies": {
4849
"my-ua-parser": "catalog:frontend",

packages/kit/src/utils/state.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import type { Objectish, Patch } from 'immer'
2+
import type { EventEmitter } from '../types/events'
3+
import { applyPatches, produce, produceWithPatches } from 'immer'
4+
import { createEventEmitter } from './events'
5+
6+
// eslint-disable-next-line ts/no-unsafe-function-type
7+
type ImmutablePrimitive = undefined | null | boolean | string | number | Function
8+
9+
export type Immutable<T>
10+
= T extends ImmutablePrimitive ? T
11+
: T extends Array<infer U> ? ImmutableArray<U>
12+
: T extends Map<infer K, infer V> ? ImmutableMap<K, V>
13+
: T extends Set<infer M> ? ImmutableSet<M> : ImmutableObject<T>
14+
15+
export type ImmutableArray<T> = ReadonlyArray<Immutable<T>>
16+
export type ImmutableMap<K, V> = ReadonlyMap<Immutable<K>, Immutable<V>>
17+
export type ImmutableSet<T> = ReadonlySet<Immutable<T>>
18+
export type ImmutableObject<T> = { readonly [K in keyof T]: Immutable<T[K]> }
19+
20+
/**
21+
* State host that is immutable by default with explicit mutate.
22+
*/
23+
export interface SharedState<T> {
24+
/**
25+
* Get the current state. Immutable.
26+
*/
27+
get: () => Immutable<T>
28+
/**
29+
* Subscribe to state changes.
30+
*/
31+
on: EventEmitter<SharedStateEvents<T>>['on']
32+
/**
33+
* Mutate the state.
34+
*/
35+
mutate: (fn: (state: T) => void) => void
36+
/**
37+
* Apply patches to the state.
38+
*/
39+
patch: (patches: Patch[]) => void
40+
}
41+
42+
export interface SharedStateEvents<T> {
43+
updated: (state: T) => void
44+
patches: (patches: Patch[]) => void
45+
}
46+
47+
export interface SharedStateOptions<T> {
48+
/**
49+
* Initial state.
50+
*/
51+
initialState: T
52+
/**
53+
* Enable patches.
54+
*
55+
* @default false
56+
*/
57+
enablePatches?: boolean
58+
}
59+
60+
export function createSharedState<T extends Objectish>(
61+
options: SharedStateOptions<T>,
62+
): SharedState<T> {
63+
const {
64+
enablePatches = false,
65+
} = options
66+
67+
const events = createEventEmitter<SharedStateEvents<T>>()
68+
let state = options.initialState
69+
70+
return {
71+
on: events.on,
72+
get: () => state as Immutable<T>,
73+
patch: (patches: Patch[]) => {
74+
state = applyPatches<T>(state, patches)
75+
events.emit('updated', state)
76+
},
77+
mutate: (fn) => {
78+
if (enablePatches) {
79+
const [newState, patches] = produceWithPatches(state, fn)
80+
state = newState
81+
events.emit('patches', patches)
82+
}
83+
else {
84+
state = produce(state, fn)
85+
}
86+
events.emit('updated', state)
87+
},
88+
}
89+
}

pnpm-lock.yaml

Lines changed: 44 additions & 38 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-workspace.yaml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ catalogMode: prefer
22
ignoreWorkspaceRootCheck: true
33
shamefullyHoist: true
44
shellEmulator: true
5+
strictPeerDependencies: false
56
trustPolicy: no-downgrade
67

78
packages:
@@ -30,13 +31,13 @@ catalogs:
3031
'@rolldown/debug': ^1.0.0-beta.54
3132
ansis: ^4.2.0
3233
birpc: ^4.0.0
33-
# Unstable API, lock the version
3434
birpc-x: 0.0.6
3535
cac: ^6.7.14
3636
debug: ^4.4.3
3737
diff: ^8.0.2
3838
get-port-please: ^3.2.0
3939
h3: ^1.15.4
40+
immer: ^11.0.1
4041
launch-editor: ^2.12.0
4142
mlly: ^1.8.0
4243
mrmime: ^2.0.1
@@ -137,5 +138,3 @@ onlyBuiltDependencies:
137138
- rolldown
138139
- simple-git-hooks
139140
- unrs-resolver
140-
141-
strictPeerDependencies: false

0 commit comments

Comments
 (0)