@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.
Files changed (104) hide show
  1. package/README.md +304 -12
  2. package/dist/app-config/index.d.ts +39 -1
  3. package/dist/app-config/index.js.map +1 -1
  4. package/dist/authz/index.js +47 -391
  5. package/dist/authz/index.js.map +1 -1
  6. package/dist/{boss-D16fO2oG.d.ts → boss-BiDCbbAQ.d.ts} +60 -7
  7. package/dist/codegen/index.d.ts +157 -16
  8. package/dist/codegen/index.js +772 -166
  9. package/dist/codegen/index.js.map +1 -1
  10. package/dist/config/index.js +4 -4
  11. package/dist/config/index.js.map +1 -1
  12. package/dist/contract/index.d.ts +39 -16
  13. package/dist/contract/index.js +147 -23
  14. package/dist/contract/index.js.map +1 -1
  15. package/dist/db/index.d.ts +230 -35
  16. package/dist/db/index.js +316 -160
  17. package/dist/db/index.js.map +1 -1
  18. package/dist/env/index.d.ts +6 -442
  19. package/dist/env/index.js +13 -16
  20. package/dist/env/index.js.map +1 -1
  21. package/dist/env/loader.js +24 -1
  22. package/dist/env/loader.js.map +1 -1
  23. package/dist/error-CIZlYJlL.d.ts +157 -0
  24. package/dist/errors/index.d.ts +18 -1
  25. package/dist/errors/index.js +47 -391
  26. package/dist/errors/index.js.map +1 -1
  27. package/dist/event/index.d.ts +5 -5
  28. package/dist/event/index.js +202 -3
  29. package/dist/event/index.js.map +1 -1
  30. package/dist/event/sse/client.d.ts +18 -4
  31. package/dist/event/sse/client.js +94 -18
  32. package/dist/event/sse/client.js.map +1 -1
  33. package/dist/event/sse/index.d.ts +18 -5
  34. package/dist/event/sse/index.js +452 -114
  35. package/dist/event/sse/index.js.map +1 -1
  36. package/dist/event/ws/client.d.ts +3 -2
  37. package/dist/event/ws/index.d.ts +4 -3
  38. package/dist/job/index.d.ts +48 -3
  39. package/dist/job/index.js +131 -52
  40. package/dist/job/index.js.map +1 -1
  41. package/dist/logger/index.js +0 -12
  42. package/dist/logger/index.js.map +1 -1
  43. package/dist/middleware/index.js +52 -397
  44. package/dist/middleware/index.js.map +1 -1
  45. package/dist/nextjs/index.d.ts +75 -14
  46. package/dist/nextjs/index.js +200 -84
  47. package/dist/nextjs/index.js.map +1 -1
  48. package/dist/nextjs/server.d.ts +46 -8
  49. package/dist/nextjs/server.js +15 -1
  50. package/dist/nextjs/server.js.map +1 -1
  51. package/dist/ops/index.d.ts +61 -42
  52. package/dist/ops/index.js +648 -97
  53. package/dist/ops/index.js.map +1 -1
  54. package/dist/registry-C2KQCh0m.d.ts +473 -0
  55. package/dist/route/index.d.ts +5 -2
  56. package/dist/route/index.js +107 -28
  57. package/dist/route/index.js.map +1 -1
  58. package/dist/route/types.d.ts +7 -1
  59. package/dist/{router-Cy7rAfmj.d.ts → route-builder-DRW-MSCJ.d.ts} +51 -126
  60. package/dist/router-C57y-vz1.d.ts +184 -0
  61. package/dist/router-CX5uVjmU.d.ts +406 -0
  62. package/dist/server/index.d.ts +130 -7
  63. package/dist/server/index.js +1174 -164
  64. package/dist/server/index.js.map +1 -1
  65. package/dist/state/client.d.ts +206 -0
  66. package/dist/state/client.js +678 -0
  67. package/dist/state/client.js.map +1 -0
  68. package/dist/state/index.d.ts +443 -0
  69. package/dist/state/index.js +644 -0
  70. package/dist/state/index.js.map +1 -0
  71. package/dist/state/react.d.ts +49 -0
  72. package/dist/state/react.js +50 -0
  73. package/dist/state/react.js.map +1 -0
  74. package/dist/surface/index.d.ts +115 -0
  75. package/dist/surface/index.js +1013 -0
  76. package/dist/surface/index.js.map +1 -0
  77. package/dist/token-manager-Ckjt2-qq.d.ts +122 -0
  78. package/dist/{types-CfYVhIQ9.d.ts → types-5Rl11_Nb.d.ts} +43 -4
  79. package/dist/types-CKH0D3Dy.d.ts +441 -0
  80. package/dist/{types-ZQODsBft.d.ts → types-CurMab2Q.d.ts} +52 -2
  81. package/dist/{types-2AbaW4Ie.d.ts → types-DncqXfWN.d.ts} +4 -3
  82. package/docs/file-upload.md +195 -333
  83. package/package.json +41 -11
  84. package/src/cache/README.md +330 -0
  85. package/src/codegen/README.md +721 -0
  86. package/src/config/README.md +333 -0
  87. package/src/contract/README.md +442 -0
  88. package/src/db/README.md +589 -0
  89. package/src/db/manager/README.md +500 -0
  90. package/src/db/schema/README.md +354 -0
  91. package/src/db/transaction/README.md +845 -0
  92. package/src/env/README.md +787 -0
  93. package/src/errors/README.md +445 -0
  94. package/src/event/README.md +994 -0
  95. package/src/job/README.md +613 -0
  96. package/src/logger/README.md +321 -0
  97. package/src/middleware/README.md +634 -0
  98. package/src/nextjs/README.md +756 -0
  99. package/src/route/README.md +763 -0
  100. package/src/security/README.md +100 -0
  101. package/src/server/README.md +704 -0
  102. package/src/state/README.md +806 -0
  103. package/dist/token-manager-BT5EnUAR.d.ts +0 -278
  104. 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 };