sygnal 7.0.0 → 7.2.0-preview.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/CHANGELOG.md +632 -0
- package/dist/agent-ui.cjs.js +592 -0
- package/dist/agent-ui.cjs.js.map +1 -0
- package/dist/agent-ui.esm.js +582 -0
- package/dist/agent-ui.esm.js.map +1 -0
- package/dist/api.cjs.js +63 -0
- package/dist/api.cjs.js.map +1 -0
- package/dist/api.esm.js +2 -0
- package/dist/api.esm.js.map +1 -0
- package/dist/astro/index.cjs.js +968 -4
- package/dist/astro/index.cjs.js.map +1 -1
- package/dist/astro/index.mjs +968 -4
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/server.cjs.js +73 -45
- package/dist/astro/server.cjs.js.map +1 -1
- package/dist/astro/server.mjs +73 -45
- package/dist/astro/server.mjs.map +1 -1
- package/dist/canvas.cjs.js +2919 -0
- package/dist/canvas.cjs.js.map +1 -0
- package/dist/canvas.esm.js +2866 -0
- package/dist/canvas.esm.js.map +1 -0
- package/dist/devtools.cjs.js +38 -6
- package/dist/devtools.cjs.js.map +1 -1
- package/dist/devtools.esm.js +38 -6
- package/dist/devtools.esm.js.map +1 -1
- package/dist/diagnostics.cjs.js +224 -20
- package/dist/diagnostics.cjs.js.map +1 -1
- package/dist/diagnostics.esm.js +224 -20
- package/dist/diagnostics.esm.js.map +1 -1
- package/dist/guide/accessibility.md +1 -1
- package/dist/guide/ai-compose.md +150 -0
- package/dist/guide/behaviors.md +2 -1
- package/dist/guide/collaborative-state.md +265 -0
- package/dist/guide/element-commands.md +36 -2
- package/dist/guide/forms-reference.md +5 -5
- package/dist/guide/forms.md +3 -2
- package/dist/guide/http.md +28 -1
- package/dist/guide/islands.md +240 -0
- package/dist/guide/recipes/code-editor.md +1 -1
- package/dist/guide/renderers/agent-ui.md +138 -0
- package/dist/guide/renderers/custom-targets.md +126 -0
- package/dist/guide/renderers/overview.md +120 -0
- package/dist/guide/renderers/react-native.md +128 -0
- package/dist/guide/renderers/terminal.md +306 -0
- package/dist/guide/renderers/three.md +332 -0
- package/dist/guide/renderers/write-once.md +137 -0
- package/dist/guide/resources.md +2 -0
- package/dist/guide/sandboxed-components.md +223 -0
- package/dist/guide/timers.md +32 -5
- package/dist/guide/typed-apis.md +442 -0
- package/dist/guide/ui/accordion.md +11 -0
- package/dist/guide/ui/combobox.md +112 -8
- package/dist/guide/ui/dialog.md +96 -20
- package/dist/guide/ui/menu.md +57 -5
- package/dist/guide/ui/overview.md +8 -4
- package/dist/guide/ui/popover.md +69 -9
- package/dist/guide/ui/select.md +54 -4
- package/dist/guide/ui/tabs.md +1 -1
- package/dist/guide/ui/tooltip.md +7 -5
- package/dist/guide/virtual-collections.md +3 -0
- package/dist/guide/widgets.md +90 -1
- package/dist/host.cjs.js +2181 -0
- package/dist/host.cjs.js.map +1 -0
- package/dist/host.esm.js +2146 -0
- package/dist/host.esm.js.map +1 -0
- package/dist/index.cjs.js +3948 -586
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +584 -44
- package/dist/index.esm.js +3918 -586
- package/dist/index.esm.js.map +1 -1
- package/dist/primitives.cjs.js +143 -0
- package/dist/primitives.cjs.js.map +1 -0
- package/dist/primitives.esm.js +133 -0
- package/dist/primitives.esm.js.map +1 -0
- package/dist/react-native.cjs.js +248 -0
- package/dist/react-native.cjs.js.map +1 -0
- package/dist/react-native.esm.js +244 -0
- package/dist/react-native.esm.js.map +1 -0
- package/dist/replay.cjs.js +39 -0
- package/dist/replay.cjs.js.map +1 -0
- package/dist/replay.esm.js +2 -0
- package/dist/replay.esm.js.map +1 -0
- package/dist/sandbox-build.cjs.js +140 -0
- package/dist/sandbox-build.cjs.js.map +1 -0
- package/dist/sandbox-build.esm.js +137 -0
- package/dist/sandbox-build.esm.js.map +1 -0
- package/dist/sandbox-kernel.esm.js +212 -0
- package/dist/sandbox-kernel.esm.js.map +1 -0
- package/dist/sandbox-worker.cjs.js +857 -0
- package/dist/sandbox-worker.cjs.js.map +1 -0
- package/dist/sandbox-worker.esm.js +854 -0
- package/dist/sandbox-worker.esm.js.map +1 -0
- package/dist/sandbox.cjs.js +1425 -0
- package/dist/sandbox.cjs.js.map +1 -0
- package/dist/sandbox.esm.js +1406 -0
- package/dist/sandbox.esm.js.map +1 -0
- package/dist/sygnal.min.js +1 -1
- package/dist/sygnal.min.js.map +1 -1
- package/dist/terminal.cjs.js +1314 -0
- package/dist/terminal.cjs.js.map +1 -0
- package/dist/terminal.esm.js +1304 -0
- package/dist/terminal.esm.js.map +1 -0
- package/dist/three.cjs.js +1111 -0
- package/dist/three.cjs.js.map +1 -0
- package/dist/three.esm.js +1079 -0
- package/dist/three.esm.js.map +1 -0
- package/dist/ui-combobox.cjs.js +256 -18
- package/dist/ui-combobox.cjs.js.map +1 -1
- package/dist/ui-combobox.esm.js +256 -18
- package/dist/ui-combobox.esm.js.map +1 -1
- package/dist/ui-menu.cjs.js +150 -16
- package/dist/ui-menu.cjs.js.map +1 -1
- package/dist/ui-menu.esm.js +151 -17
- package/dist/ui-menu.esm.js.map +1 -1
- package/dist/ui-select.cjs.js +95 -9
- package/dist/ui-select.cjs.js.map +1 -1
- package/dist/ui-select.esm.js +95 -9
- package/dist/ui-select.esm.js.map +1 -1
- package/dist/ui.cjs.js +679 -173
- package/dist/ui.cjs.js.map +1 -1
- package/dist/ui.esm.js +679 -175
- package/dist/ui.esm.js.map +1 -1
- package/dist/vike/config/package.json +1 -1
- package/dist/vite/plugin.cjs.js +968 -4
- package/dist/vite/plugin.cjs.js.map +1 -1
- package/dist/vite/plugin.mjs +968 -4
- package/dist/vite/plugin.mjs.map +1 -1
- package/dist/worker-page.cjs.js +669 -0
- package/dist/worker-page.cjs.js.map +1 -0
- package/dist/worker-page.esm.js +665 -0
- package/dist/worker-page.esm.js.map +1 -0
- package/dist/worker.cjs.js +377 -0
- package/dist/worker.cjs.js.map +1 -0
- package/dist/worker.esm.js +374 -0
- package/dist/worker.esm.js.map +1 -0
- package/dist/yjs-testing.cjs.js +98 -0
- package/dist/yjs-testing.cjs.js.map +1 -0
- package/dist/yjs-testing.esm.js +77 -0
- package/dist/yjs-testing.esm.js.map +1 -0
- package/dist/yjs.cjs.js +923 -0
- package/dist/yjs.cjs.js.map +1 -0
- package/dist/yjs.esm.js +900 -0
- package/dist/yjs.esm.js.map +1 -0
- package/dist/zag.cjs.js +11 -1
- package/dist/zag.cjs.js.map +1 -1
- package/dist/zag.esm.js +11 -1
- package/dist/zag.esm.js.map +1 -1
- package/llms/ai.md +65 -0
- package/llms/collaboration.md +5 -0
- package/llms/graphics.md +10 -0
- package/llms/renderers.md +7 -0
- package/llms/replay.md +5 -0
- package/llms/sandbox.md +5 -0
- package/llms/typed-apis.md +5 -0
- package/llms/ui.md +10 -0
- package/llms-full.txt +444 -0
- package/llms.txt +37 -35
- package/package.json +139 -3
- package/src/agent-ui/mcp.ts +152 -0
- package/src/agent-ui/snapshot.ts +212 -0
- package/src/agent-ui.d.ts +106 -0
- package/src/agent-ui.ts +249 -0
- package/src/ai.d.ts +95 -2
- package/src/api.d.ts +303 -0
- package/src/api.ts +9 -0
- package/src/canvas/Canvas.ts +585 -0
- package/src/canvas/backend.ts +627 -0
- package/src/canvas/geometry.ts +187 -0
- package/src/canvas/gesture.ts +23 -0
- package/src/canvas/image.ts +197 -0
- package/src/canvas/kit.ts +130 -0
- package/src/canvas/paint.ts +260 -0
- package/src/canvas/pointer.ts +25 -0
- package/src/canvas/snap.ts +68 -0
- package/src/canvas/svg.ts +99 -0
- package/src/canvas.d.ts +373 -0
- package/src/canvas.ts +46 -0
- package/src/core/actions.ts +14 -3
- package/src/core/cell.ts +12 -4
- package/src/core/debug.ts +8 -3
- package/src/core/hooks.ts +16 -2
- package/src/core/hosts/collection.ts +1 -1
- package/src/core/hosts/switchable.ts +26 -8
- package/src/core/instance.ts +98 -45
- package/src/core/markers/portal.ts +4 -0
- package/src/core/registry.ts +4 -0
- package/src/core/runtime.ts +34 -25
- package/src/core/statics.ts +5 -5
- package/src/cycle/dom/EventDelegator.ts +37 -33
- package/src/cycle/dom/MainDOMSource.ts +16 -14
- package/src/cycle/dom/enrichEventStream.ts +13 -9
- package/src/cycle/dom/fromEvent.ts +6 -10
- package/src/cycle/dom/index.ts +11 -7
- package/src/cycle/dom/isolate.ts +13 -6
- package/src/cycle/dom/makeDOMDriver.ts +6 -2
- package/src/cycle/dom/utils.ts +9 -2
- package/src/cycle/run/adapt.ts +4 -12
- package/src/devtools.d.ts +9 -0
- package/src/devtools.ts +2 -1
- package/src/extra/ai/compose/catalog.ts +2 -1
- package/src/extra/ai/compose/decisions.ts +1 -2
- package/src/extra/ai/compose/generated.ts +234 -0
- package/src/extra/ai/compose/index.ts +6 -2
- package/src/extra/ai/compose/layout.ts +3 -1
- package/src/extra/ai/compose/llm.ts +7 -3
- package/src/extra/ai/compose/types.ts +2 -2
- package/src/extra/ai/transports/shared.ts +3 -1
- package/src/extra/api/contract.ts +485 -0
- package/src/extra/api/index.ts +26 -0
- package/src/extra/behaviors.ts +3 -3
- package/src/extra/controlled.ts +44 -0
- package/src/extra/copyAsTest.ts +22 -0
- package/src/extra/devtools.ts +5 -3
- package/src/extra/devtoolsActions.ts +8 -0
- package/src/extra/devtoolsNext.ts +1 -1
- package/src/extra/diagnostics/checks/actionLog.ts +8 -3
- package/src/extra/diagnostics/checks/behaviors.ts +25 -0
- package/src/extra/diagnostics/checks/elementCommands.ts +17 -5
- package/src/extra/diagnostics/checks/index.ts +1 -1
- package/src/extra/diagnostics/checks/next.ts +78 -4
- package/src/extra/diagnostics/checks/props.ts +6 -1
- package/src/extra/diagnostics/checks/replies.ts +11 -7
- package/src/extra/diagnostics/checks/timers.ts +8 -2
- package/src/extra/diagnostics/checks/virtual.ts +11 -0
- package/src/extra/diagnostics/codes.ts +51 -1
- package/src/extra/elementCommands.ts +20 -4
- package/src/extra/fetchDriver.ts +4 -1
- package/src/extra/fetchEventSource.ts +6 -2
- package/src/extra/field.ts +29 -0
- package/src/extra/form.ts +42 -16
- package/src/extra/frame.ts +54 -0
- package/src/extra/keymap.ts +41 -0
- package/src/extra/pager.ts +2 -0
- package/src/extra/persist.ts +2 -1
- package/src/extra/pointer.ts +262 -0
- package/src/extra/processForm.ts +34 -1
- package/src/extra/replay/address.ts +49 -0
- package/src/extra/replay/entropy.ts +99 -0
- package/src/extra/replay/format.ts +263 -0
- package/src/extra/replay/index.ts +8 -0
- package/src/extra/replay/inert.ts +22 -0
- package/src/extra/replay/recorder.ts +247 -0
- package/src/extra/replay/replayer.ts +234 -0
- package/src/extra/replay/report.ts +126 -0
- package/src/extra/replay/schema.ts +52 -0
- package/src/extra/replay/version.ts +3 -0
- package/src/extra/router.ts +7 -3
- package/src/extra/selection.ts +2 -0
- package/src/extra/socketDriver.ts +51 -6
- package/src/extra/ssr.ts +128 -42
- package/src/extra/testing.ts +295 -39
- package/src/extra/timers.ts +96 -7
- package/src/extra/undo.ts +2 -0
- package/src/extra/virtual.ts +25 -2
- package/src/extra/widget.ts +106 -17
- package/src/host/actions.ts +383 -0
- package/src/host/delegation.ts +101 -0
- package/src/host/dom.ts +553 -0
- package/src/host/driver.ts +185 -0
- package/src/host/selector.ts +119 -0
- package/src/host/style.ts +51 -0
- package/src/host.d.ts +298 -0
- package/src/host.ts +46 -0
- package/src/index.d.ts +302 -38
- package/src/index.ts +15 -3
- package/src/pragma/blocks.ts +211 -0
- package/src/pragma/index.ts +44 -10
- package/src/primitives.d.ts +54 -0
- package/src/primitives.ts +136 -0
- package/src/react-native.d.ts +57 -0
- package/src/react-native.ts +285 -0
- package/src/react-peers.d.ts +21 -3
- package/src/replay.d.ts +185 -0
- package/src/replay.ts +6 -0
- package/src/sandbox/build.ts +119 -0
- package/src/sandbox/create.ts +187 -0
- package/src/sandbox/engine.ts +267 -0
- package/src/sandbox/generated.ts +195 -0
- package/src/sandbox/kernel.ts +180 -0
- package/src/sandbox/mirror.ts +269 -0
- package/src/sandbox/protocol.ts +128 -0
- package/src/sandbox/quickjs.ts +74 -0
- package/src/sandbox/ssr.ts +41 -0
- package/src/sandbox/widget.ts +60 -0
- package/src/sandbox/worker-entry.ts +59 -0
- package/src/sandbox/worker.ts +137 -0
- package/src/sandbox-build.d.ts +12 -0
- package/src/sandbox-build.ts +6 -0
- package/src/sandbox.d.ts +299 -0
- package/src/sandbox.ts +25 -0
- package/src/shared.ts +12 -0
- package/src/terminal/paint.ts +712 -0
- package/src/terminal.d.ts +167 -0
- package/src/terminal.ts +530 -0
- package/src/three/assets.ts +170 -0
- package/src/three/host.ts +36 -0
- package/src/three/scene.ts +217 -0
- package/src/three/target.ts +252 -0
- package/src/three.d.ts +221 -0
- package/src/three.ts +30 -0
- package/src/ui/accordion.ts +21 -7
- package/src/ui/dialog.ts +192 -90
- package/src/ui/disclosure.ts +2 -0
- package/src/ui/dom.ts +30 -0
- package/src/ui/layers.ts +132 -0
- package/src/ui/popover.ts +120 -21
- package/src/ui/shared.ts +98 -12
- package/src/ui/stack.ts +18 -0
- package/src/ui/tabs.ts +2 -0
- package/src/ui/toaster.ts +16 -15
- package/src/ui/tooltip.ts +24 -8
- package/src/ui/tooltips.ts +26 -14
- package/src/ui/zag/combobox.ts +180 -13
- package/src/ui/zag/menu.ts +97 -17
- package/src/ui/zag/select.ts +15 -4
- package/src/ui/zag/shared.ts +60 -8
- package/src/ui-combobox.d.ts +16 -1
- package/src/ui-menu.d.ts +22 -7
- package/src/ui-zag-types.d.ts +13 -5
- package/src/ui.d.ts +62 -7
- package/src/ui.ts +2 -2
- package/src/vite/api.ts +186 -0
- package/src/vite/compile.ts +280 -0
- package/src/vite/plugin.d.ts +34 -0
- package/src/vite/plugin.ts +78 -4
- package/src/vite/sandbox.ts +16 -0
- package/src/worker/page.ts +396 -0
- package/src/worker/protocol.ts +48 -0
- package/src/worker/target.ts +282 -0
- package/src/worker-page.d.ts +42 -0
- package/src/worker-page.ts +12 -0
- package/src/worker.d.ts +65 -0
- package/src/worker.ts +16 -0
- package/src/yjs/driver.ts +253 -0
- package/src/yjs/mapping.ts +389 -0
- package/src/yjs/shared.ts +138 -0
- package/src/yjs/testing.ts +91 -0
- package/src/yjs-testing.d.ts +34 -0
- package/src/yjs-testing.ts +7 -0
- package/src/yjs.d.ts +109 -0
- package/src/yjs.ts +18 -0
- package/src/zag.d.ts +2 -0
- package/src/zag.ts +8 -1
package/src/api.d.ts
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
// Types for 'sygnal/api' (dev preview). The implementation lives in src/extra/api/.
|
|
2
|
+
// Structural only: no oRPC, openapi-typescript or Hono types are imported, so an app needs only
|
|
3
|
+
// the library it uses.
|
|
4
|
+
import type { ResourceRequest, SseConnection, FetchFailure, StandardSchemaLike } from 'sygnal'
|
|
5
|
+
|
|
6
|
+
// ── JSON on the wire ───────────────────────────────────────────────────
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* What a value becomes after JSON: a `Date` is an ISO string, functions and symbols are gone,
|
|
10
|
+
* `undefined` properties are optional. Replies are typed with it (the server's `Date` arrives as
|
|
11
|
+
* a string).
|
|
12
|
+
*/
|
|
13
|
+
export type Jsonify<T> =
|
|
14
|
+
T extends Date ? string :
|
|
15
|
+
T extends string | number | boolean | null ? T :
|
|
16
|
+
T extends bigint | symbol | ((...args: any[]) => any) ? never :
|
|
17
|
+
T extends readonly (infer U)[] ? Jsonify<U>[] :
|
|
18
|
+
T extends object ? { [K in keyof T as T[K] extends ((...args: any[]) => any) | symbol ? never : K]: Jsonify<T[K]> } :
|
|
19
|
+
T
|
|
20
|
+
|
|
21
|
+
type SchemaIn<S> = S extends StandardSchemaLike<infer I, any> ? I : unknown
|
|
22
|
+
type SchemaOut<S> = S extends StandardSchemaLike<any, infer O> ? O : unknown
|
|
23
|
+
/** optional input (undefined allowed, or an object of optional fields): the argument may be left out */
|
|
24
|
+
type Args<IN, OPTS> = undefined extends IN ? [input?: IN, options?: OPTS] : {} extends IN ? [input?: IN, options?: OPTS] : [input: IN, options?: OPTS]
|
|
25
|
+
|
|
26
|
+
// ── endpoints and their requests ───────────────────────────────────────
|
|
27
|
+
|
|
28
|
+
/** A request built by an endpoint: a FetchRequest that remembers the reply and error types (phantom) */
|
|
29
|
+
export type ApiRequest<OUT = unknown, ERR = unknown> = Exclude<ResourceRequest, string> & {
|
|
30
|
+
/** the endpoint id (an app key: not sent) */
|
|
31
|
+
endpoint: string
|
|
32
|
+
readonly '~output'?: OUT
|
|
33
|
+
readonly '~error'?: ERR
|
|
34
|
+
}
|
|
35
|
+
/** A stream connection built by an endpoint, for the `connections` static */
|
|
36
|
+
export type ApiStream<OUT = unknown> = SseConnection & { endpoint: string; readonly '~output'?: OUT }
|
|
37
|
+
|
|
38
|
+
/** The fields a call may add to its request: reply actions, `latest`, `key`, cache and retry options, ... */
|
|
39
|
+
export type CallOptions = Omit<Exclude<ResourceRequest, string>, 'url' | 'method' | 'json' | 'body' | 'query' | 'multipart' | 'invalidates'> & {
|
|
40
|
+
/** After a 2xx reply, refetch the resources of these GET endpoints (or tags) */
|
|
41
|
+
invalidates?: ({ readonly id: string; readonly kind: 'query' | 'mutation' } | string)[]
|
|
42
|
+
[key: string]: any
|
|
43
|
+
}
|
|
44
|
+
/** The actions and options of a stream connection (`message: 'ARRIVED'`, `open`, `close`, `resume`, ...) */
|
|
45
|
+
export type StreamOptions = Omit<SseConnection, 'sse'>
|
|
46
|
+
|
|
47
|
+
type EndpointInfo<K> = {
|
|
48
|
+
/** `quotes.list` (oRPC: the router keys), `GET /quotes/{id}` (OpenAPI, Hono), `SSE /feed` */
|
|
49
|
+
readonly id: string
|
|
50
|
+
readonly kind: K
|
|
51
|
+
readonly method: string
|
|
52
|
+
/** The path as the contract declares it (`/quotes/{id}`, `/quotes/:id`) */
|
|
53
|
+
readonly path: string
|
|
54
|
+
/** Whether a request (in its `t.requests` form) was built by this endpoint */
|
|
55
|
+
match(request: unknown): boolean
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* One endpoint of a client: builds the request (or stream connection) for an input. `OUT` is the
|
|
60
|
+
* reply as JSON delivers it; `RAW` the server's value before JSON (a `Date` where OUT has a string)
|
|
61
|
+
*/
|
|
62
|
+
export type Endpoint<IN, OUT, ERR = unknown, K extends 'query' | 'mutation' | 'stream' = 'query' | 'mutation' | 'stream', RAW = OUT> =
|
|
63
|
+
(K extends 'stream'
|
|
64
|
+
? (...args: Args<IN, StreamOptions>) => ApiStream<OUT>
|
|
65
|
+
: (...args: Args<IN, CallOptions>) => ApiRequest<OUT, ERR>) & EndpointInfo<K> & { readonly '~raw'?: RAW }
|
|
66
|
+
/** The server's value of an endpoint's reply, before JSON (what fixture() takes) */
|
|
67
|
+
export type RawOutput<E> = E extends { readonly '~raw'?: infer R } ? R : Output<E>
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* The data of the endpoint's `ok` reply action (or of each stream event), as JSON delivers it:
|
|
71
|
+
* `type Actions = { LOADED: Output<typeof api.quotes.get> }`
|
|
72
|
+
*/
|
|
73
|
+
export type Output<E> =
|
|
74
|
+
E extends (...args: any[]) => { readonly '~output'?: infer O } ? O :
|
|
75
|
+
E extends { readonly '~output'?: infer O } ? O : never
|
|
76
|
+
/** The input an endpoint takes */
|
|
77
|
+
export type Input<E> = E extends (...args: infer A) => any ? A[0] : never
|
|
78
|
+
/** The body of the endpoint's error replies (oRPC: its declared errors, by `code`) */
|
|
79
|
+
export type ErrorBody<E> =
|
|
80
|
+
E extends (...args: any[]) => { readonly '~error'?: infer X } ? X :
|
|
81
|
+
E extends { readonly '~error'?: infer X } ? X : unknown
|
|
82
|
+
/**
|
|
83
|
+
* The data of the endpoint's `error` reply action: a FetchFailure whose `body` is typed:
|
|
84
|
+
* `type Actions = { FAILED: ApiFailure<typeof api.quotes.add> }`
|
|
85
|
+
*/
|
|
86
|
+
export type ApiFailure<E> = Omit<FetchFailure, 'body'> & { body?: ErrorBody<E> }
|
|
87
|
+
|
|
88
|
+
/** Client options shared by every adapter */
|
|
89
|
+
export type ClientOptions = {
|
|
90
|
+
/** Prefix of every path (oRPC: the handler's `prefix`, e.g. '/api') */
|
|
91
|
+
prefix?: string
|
|
92
|
+
/** Headers on every request and stream (e.g. `{ 'x-api-contract': contractHash(contract) }`) */
|
|
93
|
+
headers?: Record<string, string>
|
|
94
|
+
/** oRPC: validate replies against the output schemas on the client too (`validate` on each request; default false) */
|
|
95
|
+
validate?: boolean
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ── oRPC ───────────────────────────────────────────────────────────────
|
|
99
|
+
|
|
100
|
+
/** oRPC's error body (OpenAPIHandler): a declared error, by code, or an undeclared one */
|
|
101
|
+
export type OrpcErrorBody<EM> =
|
|
102
|
+
| { [C in keyof EM & string]: { defined: true; code: C; status: number; message: string; data: Jsonify<EM[C] extends { data?: infer D } ? SchemaOut<D> : undefined> } }[keyof EM & string]
|
|
103
|
+
| { defined: false; code: string; status: number; message: string; data?: { issues?: { message: string; path?: (string | number)[] }[] } & Record<string, unknown> }
|
|
104
|
+
|
|
105
|
+
type OrpcProcedure = { '~orpc': { route: unknown; errorMap: unknown; inputSchema?: unknown; outputSchema?: unknown } }
|
|
106
|
+
type OrpcEndpoint<P> = P extends { '~orpc': { inputSchema?: infer I; outputSchema?: infer O; errorMap: infer EM } }
|
|
107
|
+
? SchemaOut<O> extends AsyncIterable<infer Y>
|
|
108
|
+
? Endpoint<unknown extends SchemaIn<I> ? undefined : SchemaIn<I>, Jsonify<Y>, OrpcErrorBody<EM>, 'stream', Y>
|
|
109
|
+
: Endpoint<unknown extends SchemaIn<I> ? undefined : SchemaIn<I>, Jsonify<SchemaOut<O>>, OrpcErrorBody<EM>, 'query' | 'mutation', SchemaOut<O>>
|
|
110
|
+
: never
|
|
111
|
+
/** The client of an oRPC contract router: the same tree, each procedure an Endpoint */
|
|
112
|
+
export type OrpcClient<R> = R extends OrpcProcedure ? OrpcEndpoint<R> : { [K in keyof R]: OrpcClient<R[K]> }
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* A client for an oRPC contract router served by oRPC's **OpenAPIHandler** (plain JSON):
|
|
116
|
+
* `const api = orpcClient(contract, { prefix: '/api' })`; `api.quotes.list({ tag })` is a GET
|
|
117
|
+
* request (a resource), `api.quotes.add(input, { ok: 'ADDED', error: 'FAILED' })` a POST, and an
|
|
118
|
+
* event iterator procedure (`.route({ method: 'GET' })`) an SSE connection. GET input goes in the
|
|
119
|
+
* query string in bracket notation, so its non-string fields need coercing schemas (`z.coerce.number()`).
|
|
120
|
+
*/
|
|
121
|
+
export function orpcClient<R>(contract: R, options?: ClientOptions): OrpcClient<R>
|
|
122
|
+
|
|
123
|
+
// ── openapi-typescript ─────────────────────────────────────────────────
|
|
124
|
+
|
|
125
|
+
type Method = 'get' | 'post' | 'put' | 'patch' | 'delete'
|
|
126
|
+
type Op<P, Path extends keyof P, M extends Method> = P[Path] extends { [K in M]: infer O } ? O : never
|
|
127
|
+
type PathsWith<P, M extends Method> = { [K in keyof P]: P[K] extends { [X in M]: infer O } ? ([O] extends [never | undefined] ? never : K) : never }[keyof P] & string
|
|
128
|
+
type JsonOf<C> = C extends { content: { 'application/json': infer J } } ? J : C extends { content: { [k: string]: infer J } } ? J : undefined
|
|
129
|
+
type Ok = 200 | 201 | 202 | 203 | 204 | 206 | '200' | '201' | '202' | '203' | '204' | '206' | '2XX'
|
|
130
|
+
type OpOutput<O> = O extends { responses: infer R } ? { [S in keyof R]: S extends Ok ? JsonOf<R[S]> : never }[keyof R] : unknown
|
|
131
|
+
type OpError<O> = O extends { responses: infer R } ? { [S in keyof R]: S extends Ok ? never : JsonOf<R[S]> }[keyof R] : unknown
|
|
132
|
+
type Defined<T> = [T] extends [never] ? false : [T] extends [undefined] ? false : true
|
|
133
|
+
type OpParams<O> = O extends { parameters: infer PS }
|
|
134
|
+
? { [K in keyof PS as K extends 'path' | 'query' | 'header' ? (Defined<PS[K]> extends true ? K : never) : never]: PS[K] }
|
|
135
|
+
: {}
|
|
136
|
+
type OpInput<O> =
|
|
137
|
+
(keyof OpParams<O> extends never ? {} : {} extends OpParams<O> ? { params?: OpParams<O> } : { params: OpParams<O> }) &
|
|
138
|
+
(O extends { requestBody: infer B } ? { body: JsonOf<B> } : O extends { requestBody?: infer B } ? (Defined<B> extends true ? { body?: JsonOf<B> } : {}) : {})
|
|
139
|
+
type MaybeInput<I> = {} extends I ? I | undefined : I
|
|
140
|
+
|
|
141
|
+
/** A client for openapi-typescript's `paths` (types only): `openApiClient<paths>().get('/quotes/{id}')` is an endpoint */
|
|
142
|
+
export type OpenApiClient<P> = {
|
|
143
|
+
[M in Method]: <Path extends PathsWith<P, M>>(path: Path) =>
|
|
144
|
+
Endpoint<MaybeInput<OpInput<Op<P, Path, M>>>, Jsonify<OpOutput<Op<P, Path, M>>>, OpError<Op<P, Path, M>>, M extends 'get' ? 'query' : 'mutation'>
|
|
145
|
+
} & {
|
|
146
|
+
/** A GET path that answers with server-sent events; `T` is the type of one event's data */
|
|
147
|
+
sse<T = unknown, Path extends PathsWith<P, 'get'> = PathsWith<P, 'get'>>(path: Path): Endpoint<MaybeInput<OpInput<Op<P, Path, 'get'>>>, T, unknown, 'stream'>
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* A client for an OpenAPI API through openapi-typescript's generated `paths` (any back end:
|
|
151
|
+
* Go, Python, oRPC's OpenAPIGenerator, ...). Input is openapi-fetch's `{ params: { path, query },
|
|
152
|
+
* body }`; query arrays repeat the key, objects use `key[field]`.
|
|
153
|
+
*/
|
|
154
|
+
export function openApiClient<P = Record<string, any>>(options?: ClientOptions): OpenApiClient<P>
|
|
155
|
+
|
|
156
|
+
// ── Hono ───────────────────────────────────────────────────────────────
|
|
157
|
+
|
|
158
|
+
type HonoOk = 200 | 201 | 202 | 203 | 204 | 206
|
|
159
|
+
type HonoEp<S, Path extends keyof S, M extends Method> = S[Path] extends { [K in `$${M}`]: infer E } ? E : never
|
|
160
|
+
type HonoPaths<S, M extends Method> = { [K in keyof S]: S[K] extends { [X in `$${M}`]: any } ? K : never }[keyof S] & string
|
|
161
|
+
type HonoOutput<E> = E extends { output: infer O; status: infer St } ? (St extends HonoOk ? O : never) : never
|
|
162
|
+
type HonoError<E> = E extends { output: infer O; status: infer St } ? (St extends HonoOk ? never : O) : never
|
|
163
|
+
type HonoInput<E> = E extends { input: infer I } ? I : {}
|
|
164
|
+
|
|
165
|
+
/** A client for a Hono app's routes (types only): `honoClient<ExtractSchema<typeof app>>().get('/quotes/:id')` */
|
|
166
|
+
export type HonoClient<S> = {
|
|
167
|
+
[M in Method]: <Path extends HonoPaths<S, M>>(path: Path) =>
|
|
168
|
+
Endpoint<MaybeInput<HonoInput<HonoEp<S, Path, M>>>, Jsonify<HonoOutput<HonoEp<S, Path, M>>>, HonoError<HonoEp<S, Path, M>>, M extends 'get' ? 'query' : 'mutation'>
|
|
169
|
+
} & {
|
|
170
|
+
/** A GET route that streams server-sent events (`streamSSE`); `T` is the type of one event's data */
|
|
171
|
+
sse<T = unknown, Path extends HonoPaths<S, 'get'> = HonoPaths<S, 'get'>>(path: Path): Endpoint<MaybeInput<HonoInput<HonoEp<S, Path, 'get'>>>, T, unknown, 'stream'>
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* A client for Hono routes. Pass the app's schema with Hono's own `ExtractSchema<typeof app>`
|
|
175
|
+
* (from 'hono/types'). Input is hc's `{ param, query, json }`.
|
|
176
|
+
*/
|
|
177
|
+
export function honoClient<S = Record<string, any>>(options?: ClientOptions): HonoClient<S>
|
|
178
|
+
|
|
179
|
+
// ── contract hash and version skew ─────────────────────────────────────
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* A stable hash of a contract: for an oRPC router its ids, routes, input/output JSON Schemas
|
|
183
|
+
* (Standard JSON Schema) and error codes; for anything else (an OpenAPI document) its stable
|
|
184
|
+
* JSON. Send it as a header (`headers` option) and check it on the server with contractSkew.
|
|
185
|
+
*/
|
|
186
|
+
export function contractHash(contract: unknown): string
|
|
187
|
+
/**
|
|
188
|
+
* On the server, before the API handler: a request whose `header` carries another hash is
|
|
189
|
+
* answered 409 CONTRACT_SKEW (oRPC's error shape, `data: { client, server }`); otherwise
|
|
190
|
+
* undefined. Requests without the header pass unless `require: true`.
|
|
191
|
+
*/
|
|
192
|
+
export function contractSkew(request: Request, options: { hash: string; header: string; require?: boolean }): Response | undefined
|
|
193
|
+
/** Whether an `error` reply is a CONTRACT_SKEW answer (the app is older than the server's API) */
|
|
194
|
+
export function isContractSkew(failure: unknown): boolean
|
|
195
|
+
/**
|
|
196
|
+
* A `fetch` for makeFetchDriver / makeSocketDriver that notices CONTRACT_SKEW answers: reports
|
|
197
|
+
* SYG690 once and calls `onSkew` for each (e.g. to offer a reload).
|
|
198
|
+
*/
|
|
199
|
+
export function contractFetch(options?: {
|
|
200
|
+
fetch?: (input: any, init?: any) => Promise<Response>
|
|
201
|
+
onSkew?: (info: { server: string | null; url: string }) => void
|
|
202
|
+
}): (input: any, init?: any) => Promise<Response>
|
|
203
|
+
|
|
204
|
+
// ── test fixtures ──────────────────────────────────────────────────────
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* A reply body for `t.respond` (or one event for `t.push`): the server's value (a `Date` stays a
|
|
208
|
+
* `Date`), typed by the endpoint and, for an oRPC contract, checked against its output schema (a
|
|
209
|
+
* fixture that drifted from the contract throws). Returned as JSON delivers it.
|
|
210
|
+
*/
|
|
211
|
+
export function fixture<E extends Endpoint<any, any, any, any, any>>(endpoint: E, data: RawOutput<E>): Output<E>
|
|
212
|
+
/**
|
|
213
|
+
* An error reply in oRPC's shape, its data checked against the declared error's schema:
|
|
214
|
+
* `const e = errorFixture(api.quotes.add, 'DUPLICATE', { id: 1 }); await t.fail('HTTP', e.status, { body: e.body })`
|
|
215
|
+
*/
|
|
216
|
+
export function errorFixture<E extends Endpoint<any, any, any, any, any>, C extends DefinedCode<E>>(
|
|
217
|
+
endpoint: E, code: C, data?: Extract<ErrorBody<E>, { code: C }> extends { data: infer D } ? D : unknown, message?: string,
|
|
218
|
+
): { status: number; body: [Extract<ErrorBody<E>, { code: C }>] extends [never] ? { defined: true; code: C; status: number; message: string; data: unknown } : Extract<ErrorBody<E>, { code: C }> }
|
|
219
|
+
/** The codes of an endpoint's declared errors (oRPC), else any string */
|
|
220
|
+
type DefinedCode<E> = [Extract<ErrorBody<E>, { defined: true }>] extends [never] ? string : Extract<ErrorBody<E>, { defined: true }>['code']
|
|
221
|
+
|
|
222
|
+
// ── function-first: *.server.ts modules ────────────────────────────────
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* The `context` a server function gets: whatever the server passes to oRPC's
|
|
226
|
+
* `handler.handle(request, { context })`. Augment it for your app:
|
|
227
|
+
* `declare module 'sygnal/api' { interface ServerContext { user?: User } }`
|
|
228
|
+
*/
|
|
229
|
+
export interface ServerContext { [key: string]: unknown }
|
|
230
|
+
|
|
231
|
+
type ErrorMapOf = Record<string, { status?: number; message?: string; data?: StandardSchemaLike<any, any> }>
|
|
232
|
+
/** What a server function gets after its input: oRPC's handler options */
|
|
233
|
+
export type ServerFunctionOptions<EM = {}> = {
|
|
234
|
+
context: ServerContext
|
|
235
|
+
signal?: AbortSignal
|
|
236
|
+
lastEventId?: string
|
|
237
|
+
/** oRPC's declared-error constructors: `throw errors.DUPLICATE({ data: { id } })` */
|
|
238
|
+
errors: { [C in keyof EM & string]: (options?: { message?: string; data?: EM[C] extends { data?: infer D } ? SchemaIn<D> : undefined; cause?: unknown }) => Error }
|
|
239
|
+
}
|
|
240
|
+
type FnOptions<EM> = {
|
|
241
|
+
/** Validate the reply too (oRPC's `.output()`; each event of a stream) */
|
|
242
|
+
output?: StandardSchemaLike<any, any>
|
|
243
|
+
/** Declared errors, by code (oRPC's `.errors()`): typed on the client as `ErrorBody` */
|
|
244
|
+
errors?: EM
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* A query in a `*.server.ts` module: a POST that is a resource (tagged `api:<id>`, refetched by
|
|
249
|
+
* `invalidates`). Its input is always validated: pass a Standard Schema, or leave it out to take
|
|
250
|
+
* no input. `export const list = query(z.object({ tag: z.string() }), async ({ tag }) => db.list(tag))`
|
|
251
|
+
* gives the client (through sygnal/vite's stub) `list({ tag }, { ok: 'LISTED' })`.
|
|
252
|
+
*/
|
|
253
|
+
export function query<S extends StandardSchemaLike<any, any>, R, EM extends ErrorMapOf = {}>(
|
|
254
|
+
input: S, fn: (input: SchemaOut<S>, options: ServerFunctionOptions<EM>) => R, options?: FnOptions<EM>,
|
|
255
|
+
): Endpoint<SchemaIn<S>, Jsonify<Awaited<R>>, OrpcErrorBody<EM>, 'query', Awaited<R>>
|
|
256
|
+
export function query<R, EM extends ErrorMapOf = {}>(
|
|
257
|
+
fn: (input: undefined, options: ServerFunctionOptions<EM>) => R, options?: FnOptions<EM>,
|
|
258
|
+
): Endpoint<undefined, Jsonify<Awaited<R>>, OrpcErrorBody<EM>, 'query', Awaited<R>>
|
|
259
|
+
/** A mutation in a `*.server.ts` module: a POST with reply actions (`ok`, `error`, `invalidates`) */
|
|
260
|
+
export function mutation<S extends StandardSchemaLike<any, any>, R, EM extends ErrorMapOf = {}>(
|
|
261
|
+
input: S, fn: (input: SchemaOut<S>, options: ServerFunctionOptions<EM>) => R, options?: FnOptions<EM>,
|
|
262
|
+
): Endpoint<SchemaIn<S>, Jsonify<Awaited<R>>, OrpcErrorBody<EM>, 'mutation', Awaited<R>>
|
|
263
|
+
export function mutation<R, EM extends ErrorMapOf = {}>(
|
|
264
|
+
fn: (input: undefined, options: ServerFunctionOptions<EM>) => R, options?: FnOptions<EM>,
|
|
265
|
+
): Endpoint<undefined, Jsonify<Awaited<R>>, OrpcErrorBody<EM>, 'mutation', Awaited<R>>
|
|
266
|
+
/**
|
|
267
|
+
* A stream in a `*.server.ts` module: an async generator, one server-sent event per `yield`, for
|
|
268
|
+
* `connections`. It is a GET, so its input comes from the query string (strings: coerce numbers).
|
|
269
|
+
*/
|
|
270
|
+
export function stream<S extends StandardSchemaLike<any, any>, Y, EM extends ErrorMapOf = {}>(
|
|
271
|
+
input: S, fn: (input: SchemaOut<S>, options: ServerFunctionOptions<EM>) => AsyncIterable<Y>, options?: FnOptions<EM>,
|
|
272
|
+
): Endpoint<SchemaIn<S>, Jsonify<Y>, OrpcErrorBody<EM>, 'stream', Y>
|
|
273
|
+
export function stream<Y, EM extends ErrorMapOf = {}>(
|
|
274
|
+
fn: (input: undefined, options: ServerFunctionOptions<EM>) => AsyncIterable<Y>, options?: FnOptions<EM>,
|
|
275
|
+
): Endpoint<undefined, Jsonify<Y>, OrpcErrorBody<EM>, 'stream', Y>
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* On the server: the oRPC router of the app's `*.server.ts` modules (keys: their paths; the part
|
|
279
|
+
* after `dir/` names them, so `/src/quotes.server.ts` is `quotes`). Mount `router` with oRPC's
|
|
280
|
+
* OpenAPIHandler at the plugin's `api.prefix`, behind `skew(request)`:
|
|
281
|
+
* ```ts
|
|
282
|
+
* const fns = serverFunctions(import.meta.glob('/src/**\/*.server.ts', { eager: true }), { os })
|
|
283
|
+
* ```
|
|
284
|
+
*/
|
|
285
|
+
export function serverFunctions(modules: Record<string, unknown>, options: {
|
|
286
|
+
/** oRPC's `os` (from '@orpc/server'): Sygnal has no server of its own */
|
|
287
|
+
os: unknown
|
|
288
|
+
/** The folder the module paths are named from (default 'src', as the plugin's `api.dir`) */
|
|
289
|
+
dir?: string
|
|
290
|
+
/** The header the client stubs send `<file>:<hash>` in (default 'x-api-functions') */
|
|
291
|
+
header?: string
|
|
292
|
+
}): {
|
|
293
|
+
/** oRPC's router: `new OpenAPIHandler(router)` */
|
|
294
|
+
router: any
|
|
295
|
+
/** The contract the stubs are built from (plain data and the schemas) */
|
|
296
|
+
contract: unknown
|
|
297
|
+
/** Each file's contract hash */
|
|
298
|
+
hashes: Record<string, string>
|
|
299
|
+
/** 409 CONTRACT_SKEW for a request from a client built against another version of its file */
|
|
300
|
+
skew(request: Request): Response | undefined
|
|
301
|
+
}
|
|
302
|
+
/** Generated code only (sygnal/vite): a client stub, or a server function given its id */
|
|
303
|
+
export function __serverFunction(id: string, value: unknown, client?: ClientOptions): any
|
package/src/api.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// 'sygnal/api' (dev preview): typed clients for an API contract (oRPC, OpenAPI paths, Hono). The
|
|
2
|
+
// code lives in the main package (src/extra/api/), and this entry re-exports it from the external
|
|
3
|
+
// 'sygnal' (rollup maps './index' to it), as 'sygnal/ai' does: one copy of the diagnostics per app.
|
|
4
|
+
// Keep this list in sync with src/index.ts and src/api.d.ts.
|
|
5
|
+
export {orpcClient, openApiClient, honoClient} from './index'
|
|
6
|
+
export {contractHash, contractSkew, isContractSkew, contractFetch} from './index'
|
|
7
|
+
export {fixture, errorFixture} from './index'
|
|
8
|
+
// function-first: *.server.ts modules (sygnal/vite's api.functions); __serverFunction is for generated code
|
|
9
|
+
export {serverQuery as query, serverMutation as mutation, serverStream as stream, serverFunctions, __serverFunction} from './index'
|