@spfn/core 0.3.0-beta.3 → 0.3.0-beta.31
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 +304 -12
- package/dist/app-config/index.d.ts +39 -1
- package/dist/app-config/index.js.map +1 -1
- package/dist/authz/index.js +47 -391
- package/dist/authz/index.js.map +1 -1
- package/dist/{boss-D16fO2oG.d.ts → boss-BiDCbbAQ.d.ts} +60 -7
- package/dist/codegen/index.d.ts +157 -16
- package/dist/codegen/index.js +772 -166
- package/dist/codegen/index.js.map +1 -1
- package/dist/config/index.js +4 -4
- package/dist/config/index.js.map +1 -1
- package/dist/contract/index.d.ts +39 -16
- package/dist/contract/index.js +147 -23
- package/dist/contract/index.js.map +1 -1
- package/dist/db/index.d.ts +230 -35
- package/dist/db/index.js +316 -160
- package/dist/db/index.js.map +1 -1
- package/dist/env/index.d.ts +6 -442
- package/dist/env/index.js +13 -16
- package/dist/env/index.js.map +1 -1
- package/dist/env/loader.js +24 -1
- package/dist/env/loader.js.map +1 -1
- package/dist/error-CIZlYJlL.d.ts +157 -0
- package/dist/errors/index.d.ts +18 -1
- package/dist/errors/index.js +47 -391
- package/dist/errors/index.js.map +1 -1
- package/dist/event/index.d.ts +5 -5
- package/dist/event/index.js +202 -3
- package/dist/event/index.js.map +1 -1
- package/dist/event/sse/client.d.ts +18 -4
- package/dist/event/sse/client.js +94 -18
- package/dist/event/sse/client.js.map +1 -1
- package/dist/event/sse/index.d.ts +18 -5
- package/dist/event/sse/index.js +452 -114
- package/dist/event/sse/index.js.map +1 -1
- package/dist/event/ws/client.d.ts +3 -2
- package/dist/event/ws/index.d.ts +4 -3
- package/dist/job/index.d.ts +48 -3
- package/dist/job/index.js +131 -52
- package/dist/job/index.js.map +1 -1
- package/dist/logger/index.js +0 -12
- package/dist/logger/index.js.map +1 -1
- package/dist/middleware/index.js +52 -397
- package/dist/middleware/index.js.map +1 -1
- package/dist/nextjs/index.d.ts +75 -14
- package/dist/nextjs/index.js +200 -84
- package/dist/nextjs/index.js.map +1 -1
- package/dist/nextjs/server.d.ts +46 -8
- package/dist/nextjs/server.js +15 -1
- package/dist/nextjs/server.js.map +1 -1
- package/dist/ops/index.d.ts +61 -42
- package/dist/ops/index.js +648 -97
- package/dist/ops/index.js.map +1 -1
- package/dist/registry-C2KQCh0m.d.ts +473 -0
- package/dist/route/index.d.ts +5 -2
- package/dist/route/index.js +107 -28
- package/dist/route/index.js.map +1 -1
- package/dist/route/types.d.ts +7 -1
- package/dist/{router-Cy7rAfmj.d.ts → route-builder-DRW-MSCJ.d.ts} +51 -126
- package/dist/router-C57y-vz1.d.ts +184 -0
- package/dist/router-CX5uVjmU.d.ts +406 -0
- package/dist/server/index.d.ts +130 -7
- package/dist/server/index.js +1174 -164
- package/dist/server/index.js.map +1 -1
- package/dist/state/client.d.ts +206 -0
- package/dist/state/client.js +678 -0
- package/dist/state/client.js.map +1 -0
- package/dist/state/index.d.ts +443 -0
- package/dist/state/index.js +644 -0
- package/dist/state/index.js.map +1 -0
- package/dist/state/react.d.ts +49 -0
- package/dist/state/react.js +50 -0
- package/dist/state/react.js.map +1 -0
- package/dist/surface/index.d.ts +115 -0
- package/dist/surface/index.js +1013 -0
- package/dist/surface/index.js.map +1 -0
- package/dist/token-manager-Ckjt2-qq.d.ts +122 -0
- package/dist/{types-CfYVhIQ9.d.ts → types-5Rl11_Nb.d.ts} +43 -4
- package/dist/types-CKH0D3Dy.d.ts +441 -0
- package/dist/{types-ZQODsBft.d.ts → types-CurMab2Q.d.ts} +52 -2
- package/dist/{types-2AbaW4Ie.d.ts → types-DncqXfWN.d.ts} +4 -3
- package/docs/file-upload.md +195 -333
- package/package.json +41 -11
- package/src/cache/README.md +330 -0
- package/src/codegen/README.md +721 -0
- package/src/config/README.md +333 -0
- package/src/contract/README.md +442 -0
- package/src/db/README.md +589 -0
- package/src/db/manager/README.md +500 -0
- package/src/db/schema/README.md +354 -0
- package/src/db/transaction/README.md +845 -0
- package/src/env/README.md +787 -0
- package/src/errors/README.md +445 -0
- package/src/event/README.md +994 -0
- package/src/job/README.md +613 -0
- package/src/logger/README.md +321 -0
- package/src/middleware/README.md +634 -0
- package/src/nextjs/README.md +756 -0
- package/src/route/README.md +763 -0
- package/src/security/README.md +100 -0
- package/src/server/README.md +704 -0
- package/src/state/README.md +806 -0
- package/dist/token-manager-BT5EnUAR.d.ts +0 -278
- package/dist/types-9oszaJqp.d.ts +0 -250
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { TSchema, Static } from '@sinclair/typebox';
|
|
2
|
+
import { SSEClient } from '@spfn/core/event/sse/client';
|
|
3
|
+
import { ApiConfig } from '@spfn/core/nextjs';
|
|
4
|
+
import { StateRouter, StatesSnapshot } from '@spfn/core/state';
|
|
5
|
+
export { InferStateInput, InferStateKey, InferStateValue } from '@spfn/core/state';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* State Client Types
|
|
9
|
+
*
|
|
10
|
+
* Everything the browser side knows about a state router is its type,
|
|
11
|
+
* `typeof states`, imported type-only. These types turn it into the ids, keys,
|
|
12
|
+
* values and write inputs the client and the hook accept. Nothing here is
|
|
13
|
+
* runtime: the client bundle never contains server code.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** Any state router, as `typeof states`. */
|
|
17
|
+
type AnyStateRouter = StateRouter<any>;
|
|
18
|
+
type StateOf<TStates extends AnyStateRouter> = TStates['states'][keyof TStates['states']];
|
|
19
|
+
type Schema<T> = T extends TSchema ? Static<T> : undefined;
|
|
20
|
+
/**
|
|
21
|
+
* What the client needs of each state, computed once per router: key, value,
|
|
22
|
+
* data and write input by id. Every signature below indexes it, rather than
|
|
23
|
+
* re-deriving a state's shape per argument.
|
|
24
|
+
*/
|
|
25
|
+
type StateCatalog<TStates extends AnyStateRouter> = {
|
|
26
|
+
[S in StateOf<TStates> as S['id']]: {
|
|
27
|
+
key: Schema<S['_types']['key']>;
|
|
28
|
+
value: Schema<S['_types']['value']>;
|
|
29
|
+
data: Schema<S['_types']['data']>;
|
|
30
|
+
input: S['_types']['input'] extends TSchema ? Static<S['_types']['input']> : never;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
/** The ids of a router's states. */
|
|
34
|
+
type StateId<TStates extends AnyStateRouter> = keyof StateCatalog<TStates> & string;
|
|
35
|
+
/** The data type of state `Id`, `undefined` when it declares no `.data()`. */
|
|
36
|
+
type InferStateData<TStates extends AnyStateRouter, Id extends StateId<TStates>> = StateCatalog<TStates>[Id]['data'];
|
|
37
|
+
/** The ids of the states that declare a `.write()`. */
|
|
38
|
+
type WritableStateId<TStates extends AnyStateRouter> = {
|
|
39
|
+
[Id in StateId<TStates>]: [StateCatalog<TStates>[Id]['input']] extends [never] ? never : Id;
|
|
40
|
+
}[StateId<TStates>];
|
|
41
|
+
/** The key argument of state `Id`: one key object when keyed, none when keyless. */
|
|
42
|
+
type StateKeyArgs<TStates extends AnyStateRouter, Id extends StateId<TStates>> = [
|
|
43
|
+
StateCatalog<TStates>[Id]['key']
|
|
44
|
+
] extends [undefined] ? [] : [key: StateCatalog<TStates>[Id]['key']];
|
|
45
|
+
/** The frame type of state `Id`. */
|
|
46
|
+
type StateFrameOf<TStates extends AnyStateRouter, Id extends StateId<TStates>> = StateFrame<StateCatalog<TStates>[Id]['value'], StateCatalog<TStates>[Id]['data']>;
|
|
47
|
+
/** A value as a read, a write or the SSE event answers it, stamped with the `at` of its read. */
|
|
48
|
+
interface StateFrame<V = unknown, D = unknown> {
|
|
49
|
+
at: string;
|
|
50
|
+
value: V;
|
|
51
|
+
data?: D;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* What the client holds for one `(id, key)`: the frame that last changed
|
|
55
|
+
* `status`, `value` or `data` — its `at` is that read's, not the newest `at`
|
|
56
|
+
* the client has seen — and whether the server still serves it. A state the
|
|
57
|
+
* server stopped serving before any value arrived is `{ status: 'revoked' }` alone.
|
|
58
|
+
*/
|
|
59
|
+
type StateEntry<V = unknown, D = unknown> = Readonly<StateFrame<V, D> & {
|
|
60
|
+
status: 'ready' | 'revoked';
|
|
61
|
+
}> | Readonly<{
|
|
62
|
+
at?: undefined;
|
|
63
|
+
value?: undefined;
|
|
64
|
+
data?: undefined;
|
|
65
|
+
status: 'revoked';
|
|
66
|
+
}>;
|
|
67
|
+
/** Called after the entry of a subscribed `(id, key)` changed. */
|
|
68
|
+
type StateListener = () => void;
|
|
69
|
+
/**
|
|
70
|
+
* Whether the client's stream is live. `'reconnecting'` until a stream opens and while the SSE
|
|
71
|
+
* client retries a dropped one — `attempt` is its count, `0` before its first retry;
|
|
72
|
+
* `'failed'` when the retries are exhausted (the SSE client's `maxReconnectAttempts`, the
|
|
73
|
+
* client's `maxRetries` for the first snapshot), until `retry()`, a new `subscribe` or `online`.
|
|
74
|
+
*/
|
|
75
|
+
type ConnectionStatus = {
|
|
76
|
+
status: 'connected';
|
|
77
|
+
} | {
|
|
78
|
+
status: 'reconnecting';
|
|
79
|
+
attempt: number;
|
|
80
|
+
} | {
|
|
81
|
+
status: 'failed';
|
|
82
|
+
};
|
|
83
|
+
/** Called with the new status after the client's connection status changed. */
|
|
84
|
+
type ConnectionListener = (status: ConnectionStatus) => void;
|
|
85
|
+
/**
|
|
86
|
+
* The snapshot a server render read, for a client to start from (`StateClientConfig.initial`).
|
|
87
|
+
* Pass what `api.getStates` answered: a snapshot whose manifest names a state the server does not
|
|
88
|
+
* serve keeps the stream from opening, as the SSE handler refuses that event. The router type
|
|
89
|
+
* parameter (`StateClientInitial<typeof states>`, `createStateClient<typeof states>`) is what types
|
|
90
|
+
* `snapshot`; without it the client is untyped, as before.
|
|
91
|
+
*/
|
|
92
|
+
interface StateClientInitial<TStates extends AnyStateRouter = any> {
|
|
93
|
+
/** What `api.getStates` (or the snapshot route) answered for the render. */
|
|
94
|
+
snapshot: StatesSnapshot<TStates['states']>;
|
|
95
|
+
/** The query that snapshot was read with; keyed entries are stored under its key. @default {} */
|
|
96
|
+
query?: Record<string, string>;
|
|
97
|
+
}
|
|
98
|
+
interface StateClientConfig<TStates extends AnyStateRouter = any> {
|
|
99
|
+
/**
|
|
100
|
+
* The SSE client the stream is opened on — `createAuthSSEClient()` for an
|
|
101
|
+
* authenticated app. Give the state client its own: an `SSEClient` holds
|
|
102
|
+
* one subscription, and the state client's supersedes any other on it.
|
|
103
|
+
*/
|
|
104
|
+
sse: SSEClient<any>;
|
|
105
|
+
/** Passed to `createApi` for the read, write and snapshot routes. */
|
|
106
|
+
api?: ApiConfig;
|
|
107
|
+
/**
|
|
108
|
+
* Something the client ran on its own failed: a snapshot (the first, or the
|
|
109
|
+
* one after a stream opened), the read after a grant, or a `subscribe` the
|
|
110
|
+
* manifest refuses. Calls the app makes reject instead.
|
|
111
|
+
* @default console.error
|
|
112
|
+
*/
|
|
113
|
+
onError?: (error: unknown) => void;
|
|
114
|
+
/**
|
|
115
|
+
* Milliseconds before a failed first snapshot is read again, while
|
|
116
|
+
* subscriptions wait on it — the SSE client's `reconnectDelay` for a
|
|
117
|
+
* stream that does not exist yet.
|
|
118
|
+
* @default 3000
|
|
119
|
+
*/
|
|
120
|
+
retryDelay?: number;
|
|
121
|
+
/**
|
|
122
|
+
* How many times a failed first snapshot is read again before the client
|
|
123
|
+
* gives up: the status turns `'failed'` and no retry is set, until
|
|
124
|
+
* `retry()`, a new `subscribe` or `online`. The first read is not a retry.
|
|
125
|
+
* `0` retries until the snapshot succeeds.
|
|
126
|
+
* @default 0
|
|
127
|
+
*/
|
|
128
|
+
maxRetries?: number;
|
|
129
|
+
/**
|
|
130
|
+
* The snapshot the server rendered with. The client installs its manifest
|
|
131
|
+
* and applies its states at construction, so `current()` answers at once
|
|
132
|
+
* and the first `subscribe` opens the stream without reading the snapshot
|
|
133
|
+
* first. The stream's open still re-reads it.
|
|
134
|
+
*/
|
|
135
|
+
initial?: StateClientInitial<TStates>;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* The browser side of a state router: one store per `(id, key)`, one SSE
|
|
139
|
+
* stream for the whole client.
|
|
140
|
+
*/
|
|
141
|
+
interface StateClient<TStates extends AnyStateRouter> {
|
|
142
|
+
/** Read one state; the answer is applied to the store and returned. */
|
|
143
|
+
get<Id extends StateId<TStates>>(id: Id, ...key: StateKeyArgs<TStates, Id>): Promise<StateFrameOf<TStates, Id>>;
|
|
144
|
+
/** Read every state the query names a key for, and the manifest; each entry is applied and the snapshot returned. */
|
|
145
|
+
snapshot(query?: Record<string, string>): Promise<StatesSnapshot<TStates['states']>>;
|
|
146
|
+
/**
|
|
147
|
+
* Watch one `(id, key)`. The first subscriber reads the snapshot — unless
|
|
148
|
+
* the client was built with `initial` — then opens the stream. A key whose fields are not the state's goes to `onError` once
|
|
149
|
+
* the manifest is known. Returns the unsubscribe.
|
|
150
|
+
*/
|
|
151
|
+
subscribe<Id extends StateId<TStates>>(id: Id, ...args: [...key: StateKeyArgs<TStates, Id>, listener: StateListener]): () => void;
|
|
152
|
+
/** Write a state through its write route; the answer is applied at once and returned. */
|
|
153
|
+
write<Id extends WritableStateId<TStates>>(id: Id, input: StateCatalog<TStates>[Id]['input'], ...key: StateKeyArgs<TStates, Id>): Promise<StateFrameOf<TStates, Id>>;
|
|
154
|
+
/** The entry held for `(id, key)`, the same object until it changes. */
|
|
155
|
+
current<Id extends StateId<TStates>>(id: Id, ...key: StateKeyArgs<TStates, Id>): StateEntry<StateCatalog<TStates>[Id]['value'], StateCatalog<TStates>[Id]['data']> | undefined;
|
|
156
|
+
/** The connection status, a frozen object: the same reference until it changes. */
|
|
157
|
+
connection(): ConnectionStatus;
|
|
158
|
+
/**
|
|
159
|
+
* Call `listener` with the new status on every change of `connection()`.
|
|
160
|
+
* Returns the unsubscribe (idempotent).
|
|
161
|
+
*/
|
|
162
|
+
subscribeConnection(listener: ConnectionListener): () => void;
|
|
163
|
+
/**
|
|
164
|
+
* Restart now when `'failed'` or `'reconnecting'`: the first snapshot is
|
|
165
|
+
* read again, its retry count reset, or the stream reopened. A no-op when
|
|
166
|
+
* `'connected'`, while the first snapshot is in flight, or with nothing
|
|
167
|
+
* subscribed — so after `close()`, until a new `subscribe`, which `retry()`
|
|
168
|
+
* then restarts as before. `online` is not listened to again after `close()`.
|
|
169
|
+
*/
|
|
170
|
+
retry(): void;
|
|
171
|
+
/** Close the stream, drop every listener and stop listening to `online`. */
|
|
172
|
+
close(): void;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* State Client
|
|
177
|
+
*
|
|
178
|
+
* The browser side of a state router (`@spfn/core/state`): it calls the derived
|
|
179
|
+
* read, write and snapshot routes, keeps one SSE stream open for every state of
|
|
180
|
+
* the router, and orders snapshots against frames per `(id, key)`. It knows the
|
|
181
|
+
* router by type — `typeof states` — and at runtime by the manifest every
|
|
182
|
+
* snapshot carries; it imports no server code.
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* ```typescript
|
|
186
|
+
* import { createStateClient } from '@spfn/core/state/client';
|
|
187
|
+
* import { createAuthSSEClient } from '@spfn/core/event/sse/client';
|
|
188
|
+
* import type { states } from '@/server/states';
|
|
189
|
+
*
|
|
190
|
+
* export const state = createStateClient<typeof states>({ sse: createAuthSSEClient() });
|
|
191
|
+
*
|
|
192
|
+
* const stop = state.subscribe('runtime', { workspaceId }, () => render(state.current('runtime', { workspaceId })));
|
|
193
|
+
* ```
|
|
194
|
+
*/
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Build the client for `typeof states`. The first subscription (or call)
|
|
198
|
+
* reads the snapshot, whose manifest names every state — or takes it from
|
|
199
|
+
* `initial`, the snapshot the server rendered with; the stream then
|
|
200
|
+
* requests every state event — the server's `grant` can only activate an
|
|
201
|
+
* event the connection requested. The router type parameter is what types
|
|
202
|
+
* `initial.snapshot`; without it the client is untyped, as before.
|
|
203
|
+
*/
|
|
204
|
+
declare function createStateClient<TStates extends AnyStateRouter>(config: StateClientConfig<TStates>): StateClient<TStates>;
|
|
205
|
+
|
|
206
|
+
export { type AnyStateRouter, type ConnectionListener, type ConnectionStatus, type InferStateData, type StateCatalog, type StateClient, type StateClientConfig, type StateClientInitial, type StateEntry, type StateFrame, type StateFrameOf, type StateId, type StateKeyArgs, type StateListener, type WritableStateId, createStateClient };
|