@inglorious/store 12.1.1 → 12.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 +74 -2
- package/package.json +4 -4
- package/src/behaviors/async.js +29 -10
- package/src/behaviors/optimistic.js +84 -41
- package/src/behaviors/state-machine/fsm.js +0 -6
- package/src/behaviors/state-machine/scenes.js +0 -6
- package/src/client/devtools.js +10 -34
- package/src/client/multiplayer-middleware.js +1 -14
- package/src/event-map.js +4 -2
- package/src/migration/rtk.js +0 -24
- package/src/store.js +20 -50
- package/types/api.d.ts +10 -4
- package/types/behaviors/async.d.ts +19 -5
- package/types/behaviors/optimistic.d.ts +9 -2
- package/types/events.d.ts +149 -0
- package/types/index.d.ts +1 -0
- package/types/migration/rtk.d.ts +0 -2
- package/types/store.d.ts +78 -6
package/types/store.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Api } from "./api"
|
|
2
|
+
import type { AnyEvents, Notify } from "./events"
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* What every entity has. Declare an entity's other fields on its own interface:
|
|
@@ -111,6 +112,68 @@ export type TypeDefinition<
|
|
|
111
112
|
*/
|
|
112
113
|
export type AnyTypeDefinition = TypeDefinition<never, never>
|
|
113
114
|
|
|
115
|
+
/**
|
|
116
|
+
* What each member of a type must be, told by its name: `render(props, api)`
|
|
117
|
+
* draws the type, and a type's props are its entity; any other `render…` is
|
|
118
|
+
* a sub-renderer, `renderX(props, ownProps, api)`, which keeps the types it
|
|
119
|
+
* declares; every other member handles an event.
|
|
120
|
+
*/
|
|
121
|
+
export type CheckedType<
|
|
122
|
+
TType,
|
|
123
|
+
TEntity extends BaseEntity = BaseEntity,
|
|
124
|
+
TApi extends Api = Api,
|
|
125
|
+
> = {
|
|
126
|
+
[K in keyof TType]: K extends "render"
|
|
127
|
+
? Renderer<TEntity, TApi>
|
|
128
|
+
: K extends `render${string}`
|
|
129
|
+
? TType[K]
|
|
130
|
+
: EventHandler<TEntity, TApi>
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* For TypeScript only. At runtime it hands back the behavior it is given, and
|
|
135
|
+
* JavaScript apps never need it: it exists so that TypeScript can check a
|
|
136
|
+
* behavior that a plain annotation cannot describe, the same trick as Vue's
|
|
137
|
+
* `defineComponent` or Vite's `defineConfig`.
|
|
138
|
+
*
|
|
139
|
+
* Why it is needed: an annotation such as `EntityType<ScoreboardEntity, AppApi>`
|
|
140
|
+
* checks every member as an event handler, `(entity, payload, api)`. That is
|
|
141
|
+
* wrong for a template's sub-renderers, `renderX(props, ownProps, api)`,
|
|
142
|
+
* whose first parameter is the component's props rather than the entity, so
|
|
143
|
+
* the annotation rejects them. TypeScript cannot exempt members by their name
|
|
144
|
+
* in an annotation; it can only check them one by one after inferring the
|
|
145
|
+
* object, which takes a generic function. This is that function.
|
|
146
|
+
*
|
|
147
|
+
* What it checks, member by member: `render(props, api)` takes the entity as
|
|
148
|
+
* its props; any other `render…` keeps the types it declares; every other
|
|
149
|
+
* member is an event handler, whose entity and api are inferred. Inside its
|
|
150
|
+
* methods, `this` is the behavior itself.
|
|
151
|
+
*
|
|
152
|
+
* Use it only for a behavior whose sub-renderers take props; otherwise an
|
|
153
|
+
* annotation is enough. It takes the entity and the api first, then the
|
|
154
|
+
* behavior, because TypeScript cannot infer the behavior while being told
|
|
155
|
+
* the rest:
|
|
156
|
+
*
|
|
157
|
+
* ```ts
|
|
158
|
+
* export const Scoreboard = defineType<ScoreboardEntity, AppApi>()({
|
|
159
|
+
* ...template, // renderScoreboard(props, api), renderContender(props, speaker, api), ...
|
|
160
|
+
* render(props, api) {
|
|
161
|
+
* return this.renderScoreboard({ ...props, memory: readMemory(api) }, api)
|
|
162
|
+
* },
|
|
163
|
+
* })
|
|
164
|
+
* ```
|
|
165
|
+
*
|
|
166
|
+
* The result is an `EntityType` for the entity, so it goes wherever a
|
|
167
|
+
* behavior goes: in the store's `types`, or in a list of behaviors such as
|
|
168
|
+
* `[Chat, handlers, fsm(states), defineType<DebateEntity, AppApi>()({ ... })]`.
|
|
169
|
+
*/
|
|
170
|
+
export function defineType<
|
|
171
|
+
TEntity extends BaseEntity,
|
|
172
|
+
TApi extends Api = Api,
|
|
173
|
+
>(): <TType>(
|
|
174
|
+
behavior: CheckedType<TType, TEntity, TApi> & ThisType<TType>,
|
|
175
|
+
) => EntityType<TEntity, TApi>
|
|
176
|
+
|
|
114
177
|
/**
|
|
115
178
|
* System definition with event handlers
|
|
116
179
|
*/
|
|
@@ -134,12 +197,13 @@ export type EntitiesState<TEntity extends BaseEntity = BaseEntity> = {
|
|
|
134
197
|
export type TypesConfig<
|
|
135
198
|
TEntity extends BaseEntity = BaseEntity,
|
|
136
199
|
TState extends EntitiesState<TEntity> = EntitiesState<TEntity>,
|
|
200
|
+
TEvents = AnyEvents,
|
|
137
201
|
> = string extends TEntity["type"]
|
|
138
202
|
? { [typeName: string]: AnyTypeDefinition }
|
|
139
203
|
: {
|
|
140
204
|
[TName in TEntity["type"]]?: TypeDefinition<
|
|
141
205
|
Extract<TEntity, { type: TName }>,
|
|
142
|
-
Api<TEntity, TState>
|
|
206
|
+
Api<TEntity, TState, TEvents>
|
|
143
207
|
>
|
|
144
208
|
} & { [typeName: string]: unknown }
|
|
145
209
|
|
|
@@ -172,10 +236,11 @@ export type UpdateStrategy = "structural-sharing" | "copy-on-dispatch"
|
|
|
172
236
|
export interface StoreConfig<
|
|
173
237
|
TEntity extends BaseEntity = BaseEntity,
|
|
174
238
|
TState extends EntitiesState<TEntity> = EntitiesState<TEntity>,
|
|
239
|
+
TEvents = AnyEvents,
|
|
175
240
|
> {
|
|
176
241
|
// The entity type comes from the type arguments, `entities` or
|
|
177
242
|
// `middlewares`, never from `types`, which are checked against it.
|
|
178
|
-
types?: NoInfer<TypesConfig<TEntity, TState>>
|
|
243
|
+
types?: NoInfer<TypesConfig<TEntity, TState, TEvents>>
|
|
179
244
|
/** The initial entities. With `autoCreateEntities`, those the store creates itself can be left out. */
|
|
180
245
|
entities?: Partial<TState>
|
|
181
246
|
systems?: System<TState>[]
|
|
@@ -201,10 +266,12 @@ export type Unsubscribe = () => void
|
|
|
201
266
|
export interface Store<
|
|
202
267
|
TEntity extends BaseEntity = BaseEntity,
|
|
203
268
|
TState extends EntitiesState<TEntity> = EntitiesState<TEntity>,
|
|
269
|
+
TEvents = AnyEvents,
|
|
204
270
|
> {
|
|
205
271
|
subscribe: (listener: Listener) => Unsubscribe
|
|
206
272
|
update: () => Event[]
|
|
207
|
-
|
|
273
|
+
/** Sends an event; told the store's events, it checks them (see `Notify`). */
|
|
274
|
+
notify: Notify<TEvents, TEntity>
|
|
208
275
|
dispatch: (event: Event) => void
|
|
209
276
|
getTypes: () => Record<string, EntityType>
|
|
210
277
|
getType: (typeName: string) => EntityType
|
|
@@ -218,7 +285,7 @@ export interface Store<
|
|
|
218
285
|
}
|
|
219
286
|
setState: (nextState: TState) => void
|
|
220
287
|
reset: () => void
|
|
221
|
-
_api?: Api<TEntity, TState>
|
|
288
|
+
_api?: Api<TEntity, TState, TEvents>
|
|
222
289
|
extras?: Record<string, any>
|
|
223
290
|
}
|
|
224
291
|
|
|
@@ -248,9 +315,14 @@ export type AddEventPayload<TEntity extends BaseEntity = BaseEntity> =
|
|
|
248
315
|
export type RemoveEventPayload = string
|
|
249
316
|
|
|
250
317
|
/**
|
|
251
|
-
* Creates a store to manage state and events
|
|
318
|
+
* Creates a store to manage state and events. Told the app's events as a
|
|
319
|
+
* third type argument, its `notify` and its handlers' api check them:
|
|
320
|
+
* `createStore<AppEntity, AppState, AppEvents>({ ... })`.
|
|
252
321
|
*/
|
|
253
322
|
export function createStore<
|
|
254
323
|
TEntity extends BaseEntity = BaseEntity,
|
|
255
324
|
TState extends EntitiesState<TEntity> = EntitiesState<TEntity>,
|
|
256
|
-
|
|
325
|
+
TEvents = AnyEvents,
|
|
326
|
+
>(
|
|
327
|
+
config: StoreConfig<TEntity, TState, TEvents>,
|
|
328
|
+
): Store<TEntity, TState, TEvents>
|