atom.io 0.42.1 → 0.43.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/dist/data/index.js +4 -6
- package/dist/data/index.js.map +1 -1
- package/dist/internal/index.d.ts +1 -0
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +53 -97
- package/dist/internal/index.js.map +1 -1
- package/dist/introspection/index.js +2 -4
- package/dist/introspection/index.js.map +1 -1
- package/dist/react/index.d.ts +3 -4
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +17 -20
- package/dist/react/index.js.map +1 -1
- package/dist/react-devtools/index.js +6 -10
- package/dist/react-devtools/index.js.map +1 -1
- package/dist/realtime/index.js +2 -4
- package/dist/realtime/index.js.map +1 -1
- package/dist/realtime-client/index.js +4 -9
- package/dist/realtime-client/index.js.map +1 -1
- package/dist/realtime-react/index.d.ts +4 -4
- package/dist/realtime-react/index.d.ts.map +1 -1
- package/dist/realtime-react/index.js +16 -16
- package/dist/realtime-react/index.js.map +1 -1
- package/dist/realtime-server/index.js +8 -15
- package/dist/realtime-server/index.js.map +1 -1
- package/dist/realtime-testing/index.d.ts +3 -3
- package/dist/realtime-testing/index.d.ts.map +1 -1
- package/dist/realtime-testing/index.js +4 -2
- package/dist/realtime-testing/index.js.map +1 -1
- package/dist/transceivers/o-list/index.d.ts +6 -1
- package/dist/transceivers/o-list/index.d.ts.map +1 -1
- package/dist/transceivers/o-list/index.js +109 -42
- package/dist/transceivers/o-list/index.js.map +1 -1
- package/dist/transceivers/u-list/index.js +1 -2
- package/dist/transceivers/u-list/index.js.map +1 -1
- package/package.json +21 -20
- package/src/internal/atom/create-regular-atom.ts +1 -1
- package/src/internal/families/create-readonly-held-selector-family.ts +1 -1
- package/src/internal/families/create-readonly-pure-selector-family.ts +1 -1
- package/src/internal/families/create-regular-atom-family.ts +1 -1
- package/src/internal/families/create-writable-held-selector-family.ts +1 -1
- package/src/internal/families/create-writable-pure-selector-family.ts +1 -1
- package/src/internal/mutable/create-mutable-atom-family.ts +1 -1
- package/src/internal/mutable/create-mutable-atom.ts +1 -1
- package/src/internal/store/store.ts +3 -0
- package/src/react/store-context.tsx +2 -2
- package/src/react/use-i.ts +3 -3
- package/src/react/use-json.ts +2 -2
- package/src/react/use-loadable.ts +4 -4
- package/src/react/use-o.ts +4 -4
- package/src/react/use-tl.ts +6 -6
- package/src/realtime-testing/setup-realtime-test.tsx +5 -1
- package/src/transceivers/o-list/index.ts +1 -0
- package/src/transceivers/o-list/o-list-disposed-key-cleanup-effect.ts +153 -0
package/src/react/use-json.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { MutableAtomFamilyToken, MutableAtomToken } from "atom.io"
|
|
|
2
2
|
import type { AsJSON, Transceiver } from "atom.io/internal"
|
|
3
3
|
import { findInStore, getJsonToken } from "atom.io/internal"
|
|
4
4
|
import type { Canonical, Json } from "atom.io/json"
|
|
5
|
-
import
|
|
5
|
+
import { useContext } from "react"
|
|
6
6
|
|
|
7
7
|
import { StoreContext } from "./store-context"
|
|
8
8
|
import { useO } from "./use-o"
|
|
@@ -20,7 +20,7 @@ export function useJSON(
|
|
|
20
20
|
token: MutableAtomFamilyToken<any, any> | MutableAtomToken<any>,
|
|
21
21
|
key?: Canonical,
|
|
22
22
|
): Json.Serializable {
|
|
23
|
-
const store =
|
|
23
|
+
const store = useContext(StoreContext)
|
|
24
24
|
const stateToken: MutableAtomToken<any> =
|
|
25
25
|
token.type === `mutable_atom_family` ? findInStore(store, token, key) : token
|
|
26
26
|
const jsonToken = getJsonToken(store, stateToken)
|
|
@@ -3,7 +3,7 @@ import type { Loadable, ReadableFamilyToken, ReadableToken } from "atom.io"
|
|
|
3
3
|
import { findInStore, type ReadableState, withdraw } from "atom.io/internal"
|
|
4
4
|
import type { Canonical } from "atom.io/json"
|
|
5
5
|
import { StoreContext, useO } from "atom.io/react"
|
|
6
|
-
import
|
|
6
|
+
import { useContext, useRef } from "react"
|
|
7
7
|
|
|
8
8
|
export function useLoadable<T, E>(
|
|
9
9
|
token: ReadableToken<Loadable<T>, any, E>,
|
|
@@ -32,7 +32,7 @@ export function useLoadable(
|
|
|
32
32
|
| readonly [ReadableToken<any, any, any>, unknown]
|
|
33
33
|
| readonly [ReadableToken<any, any, any>]
|
|
34
34
|
): `LOADING` | { loading: boolean; value: unknown; error?: unknown } {
|
|
35
|
-
const store =
|
|
35
|
+
const store = useContext(StoreContext)
|
|
36
36
|
|
|
37
37
|
let value: unknown
|
|
38
38
|
let state: ReadableState<any, any>
|
|
@@ -65,12 +65,12 @@ export function useLoadable(
|
|
|
65
65
|
|
|
66
66
|
const isErr = `catch` in state && state.catch.some((E) => value instanceof E)
|
|
67
67
|
|
|
68
|
-
const wrapperRef =
|
|
68
|
+
const wrapperRef = useRef<{
|
|
69
69
|
loading: boolean
|
|
70
70
|
value: unknown
|
|
71
71
|
error?: unknown
|
|
72
72
|
}>({ loading: false, value: null as unknown })
|
|
73
|
-
const lastLoadedRef =
|
|
73
|
+
const lastLoadedRef = useRef(
|
|
74
74
|
fallback ?? (value instanceof Promise ? `LOADING` : value),
|
|
75
75
|
)
|
|
76
76
|
|
package/src/react/use-o.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ReadableFamilyToken, ReadableToken } from "atom.io"
|
|
2
2
|
import { getFromStore, subscribeToState } from "atom.io/internal"
|
|
3
3
|
import type { Canonical } from "atom.io/json"
|
|
4
|
-
import
|
|
4
|
+
import { useContext, useId, useSyncExternalStore } from "react"
|
|
5
5
|
|
|
6
6
|
import { parseStateOverloads } from "./parse-state-overloads"
|
|
7
7
|
import { StoreContext } from "./store-context"
|
|
@@ -18,10 +18,10 @@ export function useO<T, K extends Canonical, E>(
|
|
|
18
18
|
| [ReadableFamilyToken<T, K, E>, NoInfer<K>]
|
|
19
19
|
| [ReadableToken<T, any, E>]
|
|
20
20
|
): E | T {
|
|
21
|
-
const store =
|
|
21
|
+
const store = useContext(StoreContext)
|
|
22
22
|
const token = parseStateOverloads(store, ...params)
|
|
23
|
-
const id =
|
|
24
|
-
return
|
|
23
|
+
const id = useId()
|
|
24
|
+
return useSyncExternalStore<E | T>(
|
|
25
25
|
(dispatch) => subscribeToState(store, token, `use-o:${id}`, dispatch),
|
|
26
26
|
() => getFromStore(store, token),
|
|
27
27
|
() => getFromStore(store, token),
|
package/src/react/use-tl.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { TimelineToken } from "atom.io"
|
|
2
2
|
import { redo, undo } from "atom.io"
|
|
3
3
|
import { subscribeToTimeline, withdraw } from "atom.io/internal"
|
|
4
|
-
import
|
|
4
|
+
import { useContext, useId, useRef, useSyncExternalStore } from "react"
|
|
5
5
|
|
|
6
6
|
import { StoreContext } from "./store-context"
|
|
7
7
|
|
|
@@ -13,10 +13,10 @@ export type TimelineMeta = {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export function useTL(token: TimelineToken<any>): TimelineMeta {
|
|
16
|
-
const store =
|
|
17
|
-
const id =
|
|
16
|
+
const store = useContext(StoreContext)
|
|
17
|
+
const id = useId()
|
|
18
18
|
const timeline = withdraw(store, token)
|
|
19
|
-
const tokenRef =
|
|
19
|
+
const tokenRef = useRef(token)
|
|
20
20
|
const rebuildMeta = () => {
|
|
21
21
|
return {
|
|
22
22
|
at: timeline.at,
|
|
@@ -29,7 +29,7 @@ export function useTL(token: TimelineToken<any>): TimelineMeta {
|
|
|
29
29
|
},
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
-
const meta =
|
|
32
|
+
const meta = useRef<TimelineMeta>(rebuildMeta())
|
|
33
33
|
const retrieve = () => {
|
|
34
34
|
if (
|
|
35
35
|
meta.current.at !== timeline?.at ||
|
|
@@ -41,7 +41,7 @@ export function useTL(token: TimelineToken<any>): TimelineMeta {
|
|
|
41
41
|
}
|
|
42
42
|
return meta.current
|
|
43
43
|
}
|
|
44
|
-
return
|
|
44
|
+
return useSyncExternalStore<TimelineMeta>(
|
|
45
45
|
(dispatch) => subscribeToTimeline(store, token, `use-tl:${id}`, dispatch),
|
|
46
46
|
retrieve,
|
|
47
47
|
retrieve,
|
|
@@ -125,6 +125,7 @@ export const setupRealtimeTestServer = (
|
|
|
125
125
|
{
|
|
126
126
|
name: `SERVER-${testNumber}`,
|
|
127
127
|
lifespan: options.immortal?.server ? `immortal` : `ephemeral`,
|
|
128
|
+
isProduction: false,
|
|
128
129
|
},
|
|
129
130
|
IMPLICIT.STORE,
|
|
130
131
|
)
|
|
@@ -229,7 +230,10 @@ export const setupRealtimeTestClient = (
|
|
|
229
230
|
const socket: ClientSocket = io(`http://localhost:${port}/`, {
|
|
230
231
|
auth: { token: `test`, username: `${name}-${testNumber}` },
|
|
231
232
|
})
|
|
232
|
-
const silo = new AtomIO.Silo(
|
|
233
|
+
const silo = new AtomIO.Silo(
|
|
234
|
+
{ name, lifespan: `ephemeral`, isProduction: false },
|
|
235
|
+
IMPLICIT.STORE,
|
|
236
|
+
)
|
|
233
237
|
silo.setState(RTC.myUsernameState, `${name}-${testNumber}`)
|
|
234
238
|
|
|
235
239
|
const { document } = new Happy.Window()
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import type { AtomEffect } from "atom.io"
|
|
2
|
+
import { getFromStore, getUpdateToken, subscribeInStore } from "atom.io/internal"
|
|
3
|
+
import { type primitive, stringifyJson } from "atom.io/json"
|
|
4
|
+
|
|
5
|
+
import { OList } from "./o-list"
|
|
6
|
+
|
|
7
|
+
export function filterOutInPlace<T>(arr: T[], toRemove: T): T[] {
|
|
8
|
+
let writeIndex = 0
|
|
9
|
+
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
|
11
|
+
for (let readIndex = 0; readIndex < arr.length; readIndex++) {
|
|
12
|
+
if (toRemove !== arr[readIndex]) {
|
|
13
|
+
arr[writeIndex] = arr[readIndex]
|
|
14
|
+
writeIndex++
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
arr.length = writeIndex
|
|
19
|
+
return arr
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const oListDisposedKeyCleanupEffect: AtomEffect<OList<primitive>> = ({
|
|
23
|
+
token,
|
|
24
|
+
setSelf,
|
|
25
|
+
store,
|
|
26
|
+
}) => {
|
|
27
|
+
const disposalSubscriptions = new Map<primitive, () => void>()
|
|
28
|
+
const updateToken = getUpdateToken(token)
|
|
29
|
+
|
|
30
|
+
const addedValues = new Set<primitive>()
|
|
31
|
+
const removedValues = new Set<primitive>()
|
|
32
|
+
function updateSubscriptions() {
|
|
33
|
+
for (const addedValue of addedValues) {
|
|
34
|
+
const molecule = store.molecules.get(stringifyJson(addedValue))
|
|
35
|
+
if (molecule) {
|
|
36
|
+
disposalSubscriptions.set(
|
|
37
|
+
addedValue,
|
|
38
|
+
molecule.subject.subscribe(token.key, () => {
|
|
39
|
+
disposalSubscriptions.get(addedValue)?.()
|
|
40
|
+
disposalSubscriptions.delete(addedValue)
|
|
41
|
+
setSelf((self) => {
|
|
42
|
+
filterOutInPlace(self, addedValue)
|
|
43
|
+
return self
|
|
44
|
+
})
|
|
45
|
+
}),
|
|
46
|
+
)
|
|
47
|
+
} else {
|
|
48
|
+
store.logger.warn(
|
|
49
|
+
`❌`,
|
|
50
|
+
token.type,
|
|
51
|
+
token.key,
|
|
52
|
+
`Added "${addedValue}" to ${token.key} but it has not been allocated.`,
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
for (const removedValue of removedValues) {
|
|
57
|
+
if (disposalSubscriptions.has(removedValue)) {
|
|
58
|
+
disposalSubscriptions.get(removedValue)?.()
|
|
59
|
+
disposalSubscriptions.delete(removedValue)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
subscribeInStore(
|
|
64
|
+
store,
|
|
65
|
+
updateToken,
|
|
66
|
+
function manageAutoDeletionTriggers({ newValue }) {
|
|
67
|
+
const currentList = getFromStore(store, token)
|
|
68
|
+
const unpacked = OList.unpackUpdate(newValue)
|
|
69
|
+
switch (unpacked.type) {
|
|
70
|
+
case `extend`:
|
|
71
|
+
case `reverse`:
|
|
72
|
+
case `sort`:
|
|
73
|
+
break // these don't change what values are present in the list
|
|
74
|
+
|
|
75
|
+
case `set`:
|
|
76
|
+
{
|
|
77
|
+
const { next } = unpacked
|
|
78
|
+
if (`prev` in unpacked && !currentList.includes(unpacked.prev)) {
|
|
79
|
+
removedValues.add(unpacked.prev)
|
|
80
|
+
}
|
|
81
|
+
if (!disposalSubscriptions.has(next)) {
|
|
82
|
+
addedValues.add(next)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
break
|
|
86
|
+
case `truncate`:
|
|
87
|
+
{
|
|
88
|
+
for (const item of unpacked.items) {
|
|
89
|
+
if (!currentList.includes(item)) {
|
|
90
|
+
removedValues.add(item)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
break
|
|
95
|
+
case `shift`:
|
|
96
|
+
case `pop`:
|
|
97
|
+
{
|
|
98
|
+
const { value } = unpacked
|
|
99
|
+
if (value !== undefined && !currentList.includes(value)) {
|
|
100
|
+
removedValues.add(value)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
break
|
|
104
|
+
case `push`:
|
|
105
|
+
case `unshift`:
|
|
106
|
+
for (const item of unpacked.items) {
|
|
107
|
+
if (!disposalSubscriptions.has(item)) {
|
|
108
|
+
addedValues.add(item)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
break
|
|
112
|
+
case `copyWithin`:
|
|
113
|
+
for (const item of unpacked.prev) {
|
|
114
|
+
if (!currentList.includes(item)) {
|
|
115
|
+
removedValues.add(item)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
break
|
|
119
|
+
case `fill`:
|
|
120
|
+
{
|
|
121
|
+
const { value } = unpacked
|
|
122
|
+
if (value !== undefined) {
|
|
123
|
+
if (!disposalSubscriptions.has(value)) {
|
|
124
|
+
addedValues.add(value)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
for (const item of unpacked.prev) {
|
|
128
|
+
if (!currentList.includes(item)) {
|
|
129
|
+
removedValues.add(item)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
break
|
|
134
|
+
case `splice`:
|
|
135
|
+
for (const item of unpacked.deleted) {
|
|
136
|
+
if (!currentList.includes(item)) {
|
|
137
|
+
removedValues.add(item)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
for (const addedItem of unpacked.items) {
|
|
141
|
+
if (!disposalSubscriptions.has(addedItem)) {
|
|
142
|
+
addedValues.add(addedItem)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
break
|
|
146
|
+
}
|
|
147
|
+
updateSubscriptions()
|
|
148
|
+
addedValues.clear()
|
|
149
|
+
removedValues.clear()
|
|
150
|
+
},
|
|
151
|
+
`set-auto-deletion-triggers`,
|
|
152
|
+
)
|
|
153
|
+
}
|