@voltro/protocol 0.69.1 → 0.71.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 +1369 -111
- package/dist/apikey.d.ts +5 -0
- package/dist/index.d.ts +770 -23
- package/dist/index.js +615 -567
- package/dist/inspect.d.ts +100 -0
- package/dist/inspect.js +160 -0
- package/dist/jwt.d.ts +5 -0
- package/dist/rest.d.ts +464 -21
- package/dist/rest.js +408 -174
- package/dist/restFormat-ChSVyufA.js +287 -0
- package/dist/{scopes-DVtiKKsm.js → scopes-CW9_LbDO.js} +69 -40
- package/dist/session.d.ts +19 -8
- package/dist/session.js +6 -6
- package/package.json +9 -4
- package/dist/serverErrorBus-BTnTpMqj.js +0 -60
package/dist/rest.d.ts
CHANGED
|
@@ -126,7 +126,7 @@ export declare const coerceQueryValue: (value: unknown, ast: AST.AST) => unknown
|
|
|
126
126
|
* route, in stable (path) order. The boot layer feeds these straight into
|
|
127
127
|
* `restRoutesToHttpRoutes` alongside any hand-authored `restRoutes`.
|
|
128
128
|
*/
|
|
129
|
-
export declare const collectPublicApiRoutes: (entries: ReadonlyArray<PublicApiEntry
|
|
129
|
+
export declare const collectPublicApiRoutes: (entries: ReadonlyArray<PublicApiEntry>, options?: PublicApiProjectionOptions) => ReadonlyArray<RestRouteDescriptor<Record<string, unknown>, unknown>>;
|
|
130
130
|
|
|
131
131
|
/**
|
|
132
132
|
* What a descriptor CARRIES: the author's guards, or the erased form of their
|
|
@@ -159,11 +159,22 @@ declare interface DeleteTarget<Input = unknown> extends NestedTargetFields<Input
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
/** query→GET, mutation/action→POST, unless the spec overrides. */
|
|
162
|
-
export declare const derivePublicMethod: (kind: PublicApiDescriptor["kind"], spec: PublicApiSpec) => RestMethod;
|
|
162
|
+
export declare const derivePublicMethod: (kind: PublicApiDescriptor["kind"], spec: PublicApiSpec, descriptor?: ResourceDescriptorFacts) => RestMethod;
|
|
163
163
|
|
|
164
164
|
/** `/<version>/<tag-with-dots-as-slashes>` unless the spec gives an explicit
|
|
165
|
-
* path. `orders.create` @ v1 → `/v1/orders/create`. */
|
|
166
|
-
export declare const derivePublicPath: (tag: string, spec: PublicApiSpec) => string;
|
|
165
|
+
* path, or `resource` derives one. `orders.create` @ v1 → `/v1/orders/create`. */
|
|
166
|
+
export declare const derivePublicPath: (tag: string, spec: PublicApiSpec, descriptor?: ResourceDescriptorFacts) => string;
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* `publicApi.resource`: method and path from the resource, the descriptor's
|
|
170
|
+
* kind and target, and whether the input identifies one row — the convention
|
|
171
|
+
* `crud.*` already follows, so a surface of hundreds of projections is not
|
|
172
|
+
* hundreds of hand-written paths.
|
|
173
|
+
*/
|
|
174
|
+
export declare const deriveResource: (tag: string, spec: PublicApiSpec, descriptor: ResourceDescriptorFacts) => {
|
|
175
|
+
readonly method: RestMethod;
|
|
176
|
+
readonly path: string;
|
|
177
|
+
};
|
|
167
178
|
|
|
168
179
|
/**
|
|
169
180
|
* Dispatch a request across REST routes that SHARE a path. Every REST route
|
|
@@ -182,6 +193,21 @@ export declare const derivePublicPath: (tag: string, spec: PublicApiSpec) => str
|
|
|
182
193
|
*/
|
|
183
194
|
export declare const dispatchSharedPath: (group: ReadonlyArray<PluginHttpRoute>, req: PluginHttpRouteRequest) => Promise<PluginHttpRouteResult>;
|
|
184
195
|
|
|
196
|
+
/** Encode a failure under `format`: the tagged body the desugar always wrote
|
|
197
|
+
* (`{ error, …fields }`), Problem Details, or the format's own encoder. */
|
|
198
|
+
export declare const encodeRestError: (format: RestFormat, error: RestFormatError, ctx: RestFormatContext) => RestFormatResponse;
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Encode a success value under `format`: the bare value, `{ data, next? }`, or
|
|
202
|
+
* a JSON:API document; a cursor becomes a `Link` header under `link-header`.
|
|
203
|
+
* `value` is already in wire form (dates, naming applied by `restViewSchema`).
|
|
204
|
+
*/
|
|
205
|
+
export declare const encodeRestSuccess: (format: RestFormat, value: unknown, ctx: RestFormatContext) => RestFormatResponse;
|
|
206
|
+
|
|
207
|
+
/** The member of an error union that declares `tag`, as a schema of its own —
|
|
208
|
+
* for the spec's per-status responses. */
|
|
209
|
+
export declare const errorMemberSchema: (error: Schema.Schema.All | undefined, tag: string) => Schema.Schema.All | undefined;
|
|
210
|
+
|
|
185
211
|
/** Normalize the `exposeAsTool` shorthand. `true` is only valid when the
|
|
186
212
|
* descriptor carries a top-level `description`; callers pass that in. */
|
|
187
213
|
declare type ExposeAsTool = boolean | ExposeAsToolSpec;
|
|
@@ -306,6 +332,8 @@ export declare const isRestResponse: (value: unknown) => value is RestResponse<u
|
|
|
306
332
|
|
|
307
333
|
export declare const isRestStreamResponse: (v: unknown) => v is RestStreamResponse;
|
|
308
334
|
|
|
335
|
+
export declare const JSONAPI_MEDIA_TYPE = "application/vnd.api+json; charset=utf-8";
|
|
336
|
+
|
|
309
337
|
/** Extract `:name` path params by aligning the route PATTERN with the request
|
|
310
338
|
* path segment-by-segment (`/projects/:project/deploy` + `/projects/acme/deploy`
|
|
311
339
|
* → `{ project: 'acme' }`). `PluginHttpRouteRequest` carries no matched params,
|
|
@@ -327,6 +355,8 @@ declare interface MutationProcedureDescriptor<Name extends string, Input extends
|
|
|
327
355
|
* re-executes on a new server-owned WebSocket identity and rejects HTTP RPC.
|
|
328
356
|
* This does not grant access or restore application membership by itself. */
|
|
329
357
|
readonly idempotencyScope?: MutationIdempotencyScope | undefined;
|
|
358
|
+
/** Same-key calls run in invocation order on the client — see `defineMutation`. */
|
|
359
|
+
readonly serialize?: MutationSerialization<Schema.Schema.Type<Input>> | undefined;
|
|
330
360
|
/** Declarative target(s) — drives auto-optimistic on the client AND
|
|
331
361
|
* surfaces which tables this mutation touches (debug, future
|
|
332
362
|
* query-invalidation analytics). Mutations without a target run
|
|
@@ -375,6 +405,14 @@ declare interface MutationProcedureDescriptor<Name extends string, Input extends
|
|
|
375
405
|
readonly internal: boolean | undefined;
|
|
376
406
|
}
|
|
377
407
|
|
|
408
|
+
/** Same-resource ordering for a mutation's calls on the client — see `defineMutation`'s `serialize`. */
|
|
409
|
+
declare interface MutationSerialization<Input = unknown> {
|
|
410
|
+
/** The resource a call writes, from its input; calls sharing it run in order. */
|
|
411
|
+
readonly key: (input: Input) => string;
|
|
412
|
+
/** Bound for active plus waiting calls per subject. Default 32. */
|
|
413
|
+
readonly maxPending?: number;
|
|
414
|
+
}
|
|
415
|
+
|
|
378
416
|
declare interface NestedTargetFields<Input = unknown> {
|
|
379
417
|
/** Dot-path to the nested array within the query VALUE to patch (e.g.
|
|
380
418
|
* `'snapshot.projects'`). Absent → patch the top-level row array (default). */
|
|
@@ -390,6 +428,15 @@ declare interface NestedTargetFields<Input = unknown> {
|
|
|
390
428
|
readonly match?: ((value: unknown, input: Input) => boolean) | undefined;
|
|
391
429
|
}
|
|
392
430
|
|
|
431
|
+
/** `Link: <path?cursor=…>; rel="next"` — the current query with the cursor
|
|
432
|
+
* parameter replaced. */
|
|
433
|
+
export declare const nextLink: (ctx: RestFormatContext, cursor: string, param: string) => string;
|
|
434
|
+
|
|
435
|
+
/** `{teamId}` — the form every guideline writes first — is the same route as
|
|
436
|
+
* `:teamId`; the desugar matches the colon form, so the path is normalised
|
|
437
|
+
* once here. */
|
|
438
|
+
export declare const normalizePathParams: (path: string) => string;
|
|
439
|
+
|
|
393
440
|
/**
|
|
394
441
|
* The runtime-erased form of a procedure's `openAccess:` — a DECLARED decision
|
|
395
442
|
* that this procedure needs no authorization check, and the reason.
|
|
@@ -411,6 +458,50 @@ declare interface OpenAccessSpec {
|
|
|
411
458
|
readonly open: string;
|
|
412
459
|
}
|
|
413
460
|
|
|
461
|
+
/** The rpc tag as an `operationId`: `teams.list` → `teamsList`. */
|
|
462
|
+
export declare const operationIdOf: (tag: string) => string;
|
|
463
|
+
|
|
464
|
+
/** The parameter names a route pattern binds, in order. */
|
|
465
|
+
export declare const pathParamNames: (path: string) => ReadonlyArray<string>;
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* A cross-cutting error schema a plugin merges into EVERY procedure's
|
|
469
|
+
* wire error union. Use when a plugin interceptor can fail with a typed
|
|
470
|
+
* error (e.g. a rate-limit `RateLimited`) that must decode TYPED on the
|
|
471
|
+
* client rather than crossing as an untyped defect.
|
|
472
|
+
*
|
|
473
|
+
* Two halves because the error must be applied in two places that can't
|
|
474
|
+
* share a value:
|
|
475
|
+
* - `schema`: the live `effect/Schema` — used at runtime when the cli
|
|
476
|
+
* assembles the SERVER rpc group.
|
|
477
|
+
* - `import`: where to import the same schema from — used by codegen to
|
|
478
|
+
* emit the import into the generated CLIENT rpc group, so both ends
|
|
479
|
+
* agree on the wire shape. `name` must be the exported identifier.
|
|
480
|
+
*
|
|
481
|
+
* Requires the plugin to ship the schema as a NAMED export from `module`.
|
|
482
|
+
*/
|
|
483
|
+
declare interface PluginErrorSchema {
|
|
484
|
+
readonly schema: Schema.Schema.All;
|
|
485
|
+
readonly import: {
|
|
486
|
+
readonly module: string;
|
|
487
|
+
readonly name: string;
|
|
488
|
+
};
|
|
489
|
+
/**
|
|
490
|
+
* How the `publicApi` REST projection answers this error. The projection
|
|
491
|
+
* encodes a plugin's cross-cutting error the way it encodes a descriptor's
|
|
492
|
+
* own declared error — tag and fields as the body — under this status
|
|
493
|
+
* (`422` when absent, the status an undeclared-status descriptor error
|
|
494
|
+
* gets), with these headers. A rate limiter names `429` and the
|
|
495
|
+
* `Retry-After` / `RateLimit-*` headers here; a descriptor's own
|
|
496
|
+
* `errorStatus` entry for the tag still wins. Without this the same
|
|
497
|
+
* rejection that decoded typed on the rpc wire was a `500` on `/v1`.
|
|
498
|
+
*/
|
|
499
|
+
readonly rest?: {
|
|
500
|
+
readonly status: number;
|
|
501
|
+
readonly headers?: (error: unknown) => Readonly<Record<string, string>>;
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
|
|
414
505
|
/** A public raw-HTTP route a plugin serves on the framework listener. */
|
|
415
506
|
declare interface PluginHttpRoute {
|
|
416
507
|
/** HTTP method, or `'*'` for any (the handler decides). PATCH/HEAD/OPTIONS
|
|
@@ -418,9 +509,22 @@ declare interface PluginHttpRoute {
|
|
|
418
509
|
* this union lacked PATCH; that reason is gone (the `'*'` mount remains
|
|
419
510
|
* for its other job: one dispatcher per shared path + a precise 405). */
|
|
420
511
|
readonly method: '*' | 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
|
|
421
|
-
/** Absolute path
|
|
422
|
-
*
|
|
512
|
+
/** Absolute path, e.g. `/_voltro/storage`. Matched byte for byte: the
|
|
513
|
+
* router folds case and a trailing slash to FIND the route, the dispatcher
|
|
514
|
+
* then asks whether the request's path is one the route declared — so
|
|
515
|
+
* `/Metrics` and `/metrics/` are not `/metrics`. A `:name` segment takes one
|
|
516
|
+
* non-empty segment. Whether the route also owns its sub-paths is
|
|
517
|
+
* `match`. */
|
|
423
518
|
readonly path: string;
|
|
519
|
+
/**
|
|
520
|
+
* `'prefix'` (default): the route answers its path AND every sub-path
|
|
521
|
+
* (`/_voltro/storage/abc123`) — a plugin that branches on the tail mounts
|
|
522
|
+
* once. `'exact'`: the path alone — no sub-path, no trailing slash — which is
|
|
523
|
+
* what a single document or a scrape endpoint is (`/openapi.json`,
|
|
524
|
+
* `/metrics`), and what a path guard at the ingress can cover, because
|
|
525
|
+
* exactly one spelling answers. A path ending in `/*` is a prefix either way.
|
|
526
|
+
*/
|
|
527
|
+
readonly match?: 'prefix' | 'exact';
|
|
424
528
|
readonly handle: (req: PluginHttpRouteRequest) => Promise<PluginHttpRouteResult>;
|
|
425
529
|
/** Per-route body cap override (bytes) — wins over the listener's shared
|
|
426
530
|
* `maxBodyBytes`. NOTE: routes SHARING a path share one body read, so the
|
|
@@ -593,6 +697,13 @@ declare interface PluginHttpRouteResult {
|
|
|
593
697
|
/** Stream the response (SSE) instead of sending `body`. See
|
|
594
698
|
* {@link PluginHttpRouteStream}. */
|
|
595
699
|
readonly stream?: PluginHttpRouteStream;
|
|
700
|
+
/**
|
|
701
|
+
* The error behind a `5xx` — for the server log line that names the
|
|
702
|
+
* status, never for the wire. A route that maps a throw into a response
|
|
703
|
+
* value has swallowed the reason by the time the transport logs the value;
|
|
704
|
+
* this carries it alongside.
|
|
705
|
+
*/
|
|
706
|
+
readonly cause?: unknown;
|
|
596
707
|
/** Stream a BINARY response (a download, an export) instead of sending
|
|
597
708
|
* `body` — see {@link PluginHttpRouteByteStream}. Never buffered by the
|
|
598
709
|
* serve layer; never compressed (flush timing + Content-Length are the
|
|
@@ -641,7 +752,7 @@ declare interface PluginHttpRouteStream {
|
|
|
641
752
|
*/
|
|
642
753
|
declare interface PolicyGuardSpec<Input = unknown> {
|
|
643
754
|
/** The action to authorize, as named in the resource policy's `actions`. */
|
|
644
|
-
readonly action: string;
|
|
755
|
+
readonly action: string | ((input: Input) => string);
|
|
645
756
|
/** Which registered resource policy governs the check. */
|
|
646
757
|
readonly resourceType: string;
|
|
647
758
|
/** PURE `input → resource id`. Returning undefined DENIES — an unidentifiable
|
|
@@ -649,15 +760,47 @@ declare interface PolicyGuardSpec<Input = unknown> {
|
|
|
649
760
|
readonly resource: (input: Input) => string | undefined;
|
|
650
761
|
}
|
|
651
762
|
|
|
763
|
+
export declare const PROBLEM_JSON = "application/problem+json; charset=utf-8";
|
|
764
|
+
|
|
765
|
+
/** RFC 9457 Problem Details for one failure: `type` from the tag, `title` from
|
|
766
|
+
* the tag's words, `status`, `detail` from the message, the error's own fields
|
|
767
|
+
* as extension members. */
|
|
768
|
+
export declare const problemDetails: (error: RestFormatError) => Record<string, unknown>;
|
|
769
|
+
|
|
770
|
+
/** A stable, non-resolving URI for an error type: the tag as a URN. */
|
|
771
|
+
export declare const problemTypeOf: (tag: string) => string;
|
|
772
|
+
|
|
652
773
|
/**
|
|
653
774
|
* Translate a handler's failure into the response the projection promised:
|
|
654
775
|
* a DECLARED typed error becomes a `RestRouteError` with the tag, the fields
|
|
655
776
|
* and the status `errorStatus` assigns (`422` by default, the status the
|
|
656
|
-
* OpenAPI projection already documents for a typed error)
|
|
657
|
-
*
|
|
658
|
-
*
|
|
777
|
+
* OpenAPI projection already documents for a typed error); a plugin's
|
|
778
|
+
* cross-cutting error answers under the status the plugin names. Anything
|
|
779
|
+
* else is rethrown for the desugar's shared mapping (`ScopeError` → 403/401, a
|
|
780
|
+
* `status`-carrying error → itself, the rest → 500). The body is the tagged
|
|
781
|
+
* `{ error, …fields }` form; `projectedFailureFor` speaks the profile.
|
|
659
782
|
*/
|
|
660
|
-
export declare const projectedFailure: (err: unknown, descriptor: PublicApiDescriptor, spec: PublicApiSpec) => unknown;
|
|
783
|
+
export declare const projectedFailure: (err: unknown, descriptor: PublicApiDescriptor, spec: PublicApiSpec, pluginErrors?: ReadonlyArray<PluginErrorSchema>) => unknown;
|
|
784
|
+
|
|
785
|
+
/** The generated TypeScript client, as the app declares it. */
|
|
786
|
+
export declare interface PublicApiClientConfig {
|
|
787
|
+
/** The npm package name. Default `@app/api-client`. */
|
|
788
|
+
readonly package?: string;
|
|
789
|
+
/** Where the package is written, relative to the app root. Default `sdk/typescript`. */
|
|
790
|
+
readonly out?: string;
|
|
791
|
+
/** `'plain'` — the Promise client, no Effect anywhere; `'effect'` — the
|
|
792
|
+
* Effect service; `'both'` — `.` plain and `./effect` Effect, with `effect`
|
|
793
|
+
* an optional peer. Default `'both'`. */
|
|
794
|
+
readonly flavor?: 'plain' | 'effect' | 'both';
|
|
795
|
+
/** The package's `license` field (an SPDX id). */
|
|
796
|
+
readonly license?: string;
|
|
797
|
+
/** The package's version. Default `0.1.0`. */
|
|
798
|
+
readonly packageVersion?: string;
|
|
799
|
+
/** Generate for ONE API version (`'v2'`). */
|
|
800
|
+
readonly apiVersion?: string;
|
|
801
|
+
/** The client's default base URL. */
|
|
802
|
+
readonly baseUrl?: string;
|
|
803
|
+
}
|
|
661
804
|
|
|
662
805
|
/** A descriptor kind that can be projected to REST (streams are not, in v1). */
|
|
663
806
|
export declare type PublicApiDescriptor = QueryProcedureDescriptor<string, Schema.Schema.Any, Schema.Schema.Any, Schema.Schema.All> | MutationProcedureDescriptor<string, Schema.Schema.Any, Schema.Schema.Any, Schema.Schema.All> | ActionProcedureDescriptor<string, Schema.Schema.Any, Schema.Schema.Any, Schema.Schema.All>;
|
|
@@ -677,23 +820,87 @@ export declare interface PublicApiEntry {
|
|
|
677
820
|
* handler through the SAME AuthMiddleware/RBAC/tenant/audit as the rpc path. */
|
|
678
821
|
export declare type PublicApiInvoke = (input: unknown, ctx: RestRouteContext) => Promise<unknown> | unknown;
|
|
679
822
|
|
|
823
|
+
/** The `publicApi:` block of an api `app.config.ts`, and the shape of a
|
|
824
|
+
* descriptor's `publicApi.format` override (every field optional there). */
|
|
825
|
+
export declare interface PublicApiProfileConfig {
|
|
826
|
+
/** The profile every projection speaks. Default `'rpc'` — today's wire. */
|
|
827
|
+
readonly profile?: PublicApiProfileName | RestFormat;
|
|
828
|
+
readonly dates?: RestDates;
|
|
829
|
+
readonly errors?: RestErrors;
|
|
830
|
+
readonly envelope?: RestEnvelope;
|
|
831
|
+
readonly pagination?: RestPagination;
|
|
832
|
+
readonly cursorField?: string;
|
|
833
|
+
readonly cursorParam?: string;
|
|
834
|
+
readonly naming?: RestNaming;
|
|
835
|
+
readonly etag?: boolean;
|
|
836
|
+
/** `'required'`: `voltro doctor` reports a projection without a
|
|
837
|
+
* `description` and an input/output field without a `description`
|
|
838
|
+
* annotation — so a new projection does not reach the surface without text.
|
|
839
|
+
* Default `'optional'`. */
|
|
840
|
+
readonly docs?: 'required' | 'optional';
|
|
841
|
+
/**
|
|
842
|
+
* Files `voltro dev` writes beside `rpcGroup.generated.ts` on every boot, from
|
|
843
|
+
* the mounted surface: `'openapi'` (`openapi.generated.json`) and the
|
|
844
|
+
* collections — `'postman'`, `'bruno'`, `'insomnia'`, `'hoppscotch'` — as
|
|
845
|
+
* committed, generated files, so a review diff shows the surface change and
|
|
846
|
+
* a client imported once cannot drift; `'typescript'` keeps the generated
|
|
847
|
+
* client package (`client`) written the same way. Off by default.
|
|
848
|
+
*/
|
|
849
|
+
readonly artifacts?: ReadonlyArray<'openapi' | 'postman' | 'bruno' | 'insomnia' | 'hoppscotch' | 'typescript'>;
|
|
850
|
+
/**
|
|
851
|
+
* The app's decision about its generated TypeScript client — what
|
|
852
|
+
* `voltro build api --target typescript` (and `voltro api-client build`)
|
|
853
|
+
* produces without flags, and what `voltro dev` keeps written when
|
|
854
|
+
* `artifacts` names `'typescript'`. `voltro api-client set …` writes this
|
|
855
|
+
* block; a flag on the command line overrides a field for one run.
|
|
856
|
+
*/
|
|
857
|
+
readonly client?: PublicApiClientConfig;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
export declare type PublicApiProfileName = 'rpc' | 'standard' | 'jsonapi';
|
|
861
|
+
|
|
862
|
+
/** What a projection needs beyond its descriptor: the errors every mounted
|
|
863
|
+
* plugin may fail a call with, and the app's `publicApi` profile. */
|
|
864
|
+
export declare interface PublicApiProjectionOptions {
|
|
865
|
+
readonly pluginErrors?: ReadonlyArray<PluginErrorSchema>;
|
|
866
|
+
/** The `publicApi:` block of the api's `app.config.ts`. Absent → `'rpc'`. */
|
|
867
|
+
readonly profile?: PublicApiProfileConfig;
|
|
868
|
+
}
|
|
869
|
+
|
|
680
870
|
/**
|
|
681
|
-
* Synthesize the public REST route for ONE descriptor.
|
|
682
|
-
*
|
|
683
|
-
*
|
|
684
|
-
*
|
|
685
|
-
*
|
|
686
|
-
*
|
|
687
|
-
*
|
|
688
|
-
*
|
|
871
|
+
* Synthesize the public REST route for ONE descriptor.
|
|
872
|
+
*
|
|
873
|
+
* The input arrives as `{ query, params, body }` from the desugar and is
|
|
874
|
+
* assembled into ONE object — the query (GET) or body (else), plus every
|
|
875
|
+
* path parameter bound to the input field of the same name — coerced toward
|
|
876
|
+
* the input's encoded shape (a query string and a path carry strings), then
|
|
877
|
+
* decoded by the input schema in the profile's wire form (`restViewSchema`).
|
|
878
|
+
* The handler receives the descriptor's typed input; its output is encoded to
|
|
879
|
+
* the wire form and enveloped by the profile. A query is drained to its first
|
|
880
|
+
* snapshot by the serve layer — same as POST /rpc — unless `stream: 'sse'`
|
|
881
|
+
* streams it. The guards are `requireAuthenticated()` unless the descriptor
|
|
882
|
+
* declares `openAccess`, then one `requireScope` per `scopes` entry, on top of
|
|
883
|
+
* the handler's own RBAC.
|
|
689
884
|
*/
|
|
690
|
-
export declare const publicApiRoute: (descriptor: PublicApiDescriptor, invoke: PublicApiInvoke, subscribe?: PublicApiSubscribe) => RestRouteDescriptor<Record<string, unknown>, unknown>;
|
|
885
|
+
export declare const publicApiRoute: (descriptor: PublicApiDescriptor, invoke: PublicApiInvoke, subscribe?: PublicApiSubscribe, options?: PublicApiProjectionOptions) => RestRouteDescriptor<Record<string, unknown>, unknown>;
|
|
691
886
|
|
|
692
887
|
declare interface PublicApiSpec {
|
|
693
888
|
/** Derived by kind when omitted: query→GET, mutation/action→POST. */
|
|
694
889
|
readonly method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
695
890
|
/** Derived from the tag + version when omitted: `/<version>/<tag-as-path>`. */
|
|
696
891
|
readonly path?: string;
|
|
892
|
+
/**
|
|
893
|
+
* Derive method and path from the resource instead of writing them — the
|
|
894
|
+
* convention `crud.*` already follows, opt-in per descriptor. `'teams'` on a
|
|
895
|
+
* query whose input carries `teamId` or `id` → `GET /v1/teams/{teamId}`,
|
|
896
|
+
* without one → `GET /v1/teams`; on a mutation whose `target.op` is
|
|
897
|
+
* `insert` → `POST /v1/teams`, `update` → `PATCH /v1/teams/{teamId}`,
|
|
898
|
+
* `delete` → `DELETE /v1/teams/{teamId}`; an action, or a mutation without
|
|
899
|
+
* a target, → `POST /v1/teams/{teamId}/<verb>` (the tag's last segment) when
|
|
900
|
+
* the input carries the id, else `POST /v1/teams/<verb>`. An explicit
|
|
901
|
+
* `method` or `path` wins over the derivation.
|
|
902
|
+
*/
|
|
903
|
+
readonly resource?: string;
|
|
697
904
|
/** Path version segment; multiple versions coexist as separate descriptors. */
|
|
698
905
|
readonly version?: string;
|
|
699
906
|
/** Additional API-key scopes required ON TOP of the handler's RBAC. */
|
|
@@ -725,6 +932,37 @@ declare interface PublicApiSpec {
|
|
|
725
932
|
* publicApi: { errorStatus: { AccessDeniedError: 403, NotFoundError: 404 } }
|
|
726
933
|
*/
|
|
727
934
|
readonly errorStatus?: Readonly<Record<string, number>>;
|
|
935
|
+
/**
|
|
936
|
+
* The spec's tag group(s) for this operation. Default: the rpc tag's prefix
|
|
937
|
+
* (`teams.list` → `teams`) — the first path segment, what a consumer looks
|
|
938
|
+
* for, and what an SDK generator turns into a client class.
|
|
939
|
+
*/
|
|
940
|
+
readonly tags?: ReadonlyArray<string>;
|
|
941
|
+
/**
|
|
942
|
+
* The spec's `operationId`. Default: the rpc tag in camelCase (`teams.list`
|
|
943
|
+
* → `teamsList`) — the stable identifier a generator names methods from.
|
|
944
|
+
*/
|
|
945
|
+
readonly operationId?: string;
|
|
946
|
+
/**
|
|
947
|
+
* Whether the operation documents a bearer requirement. Default: `'required'`
|
|
948
|
+
* unless the descriptor declares `openAccess` — then `'optional'` (the key
|
|
949
|
+
* strategy authenticates a bearer when one is sent, and an anonymous caller
|
|
950
|
+
* is allowed through), which Swagger UI and generated clients read as
|
|
951
|
+
* "send the token when you have one". `false` documents no scheme at all.
|
|
952
|
+
*/
|
|
953
|
+
readonly security?: 'required' | 'optional' | false;
|
|
954
|
+
/** A request/response example for the spec — the same semantics as a
|
|
955
|
+
* `defineRestRoute` example. */
|
|
956
|
+
readonly example?: {
|
|
957
|
+
readonly request?: unknown;
|
|
958
|
+
readonly response?: unknown;
|
|
959
|
+
};
|
|
960
|
+
/**
|
|
961
|
+
* This projection's wire format, overriding the app's `publicApi` profile
|
|
962
|
+
* (`app.config.ts`) for the one endpoint that must differ — every field
|
|
963
|
+
* optional, the rest inherited. See `PublicApiProfileConfig`.
|
|
964
|
+
*/
|
|
965
|
+
readonly format?: PublicApiProfileConfig;
|
|
728
966
|
}
|
|
729
967
|
|
|
730
968
|
/**
|
|
@@ -739,6 +977,16 @@ export declare type PublicApiSubscribe = (input: unknown, ctx: RestRouteContext,
|
|
|
739
977
|
readonly [k: string]: unknown;
|
|
740
978
|
}) => void) => () => void;
|
|
741
979
|
|
|
980
|
+
/**
|
|
981
|
+
* The digest of a public surface: every projection's facts (tag, method, path,
|
|
982
|
+
* parameters, version, security, the typed errors and their statuses) and the
|
|
983
|
+
* SHAPE of its wire schemas, in tag order. The OpenAPI document publishes it as
|
|
984
|
+
* `x-voltro-surface-digest`, a generated client carries the one it was built
|
|
985
|
+
* from, and `voltro check --public-api --against` compares the two — so one
|
|
986
|
+
* number says whether a consumer's client still describes the API it calls.
|
|
987
|
+
*/
|
|
988
|
+
export declare const publicSurfaceDigest: (routes: ReadonlyArray<RestRouteDescriptor<any, any>>) => string;
|
|
989
|
+
|
|
742
990
|
/**
|
|
743
991
|
* Server-side snapshot caching for a query (see `defineQuery`). When set,
|
|
744
992
|
* the dispatcher caches the initial snapshot result and auto-invalidates it
|
|
@@ -861,11 +1109,35 @@ export declare const requireAuthenticated: () => RestGuard;
|
|
|
861
1109
|
*/
|
|
862
1110
|
export declare const requireScope: (scope: string) => RestGuard;
|
|
863
1111
|
|
|
1112
|
+
/**
|
|
1113
|
+
* The format one projection speaks: the app profile, then its building-block
|
|
1114
|
+
* overrides, then the descriptor's own `format`. A named profile is a
|
|
1115
|
+
* `RestFormat` with a name; an object is taken as-is and its fields overridden
|
|
1116
|
+
* the same way.
|
|
1117
|
+
*/
|
|
1118
|
+
export declare const resolveRestFormat: (config: PublicApiProfileConfig | undefined, override?: Partial<PublicApiProfileConfig> | undefined) => RestFormat;
|
|
1119
|
+
|
|
1120
|
+
/** What `resource` derivation reads off a descriptor. */
|
|
1121
|
+
export declare interface ResourceDescriptorFacts {
|
|
1122
|
+
readonly kind: 'query' | 'mutation' | 'action' | 'stream';
|
|
1123
|
+
readonly input?: unknown;
|
|
1124
|
+
readonly target?: {
|
|
1125
|
+
readonly op?: string;
|
|
1126
|
+
} | undefined;
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
/** The input field that identifies one row of `resource`: `<singular>Id`,
|
|
1130
|
+
* then `id`; `undefined` when the input names neither (a list, a create). */
|
|
1131
|
+
export declare const resourceIdField: (resource: string, input: unknown) => string | undefined;
|
|
1132
|
+
|
|
864
1133
|
export declare const response: <O>(body: O, options?: {
|
|
865
1134
|
readonly status?: number;
|
|
866
1135
|
readonly headers?: Readonly<Record<string, string | ReadonlyArray<string>>>;
|
|
1136
|
+
readonly contentType?: string;
|
|
867
1137
|
}) => RestResponse<O>;
|
|
868
1138
|
|
|
1139
|
+
export declare const REST_PROFILE_NAMES: ReadonlyArray<PublicApiProfileName>;
|
|
1140
|
+
|
|
869
1141
|
/** A BINARY streaming response (download/export). The serve layer pipes the
|
|
870
1142
|
* ReadableStream without buffering — a body larger than the heap is fine.
|
|
871
1143
|
* The LAZY thunk form defers opening the source until the response streams. */
|
|
@@ -881,8 +1153,85 @@ export declare interface RestByteResponse {
|
|
|
881
1153
|
readonly headers?: Readonly<Record<string, string | ReadonlyArray<string>>>;
|
|
882
1154
|
}
|
|
883
1155
|
|
|
1156
|
+
export declare type RestDates = 'iso' | 'epoch-ms';
|
|
1157
|
+
|
|
1158
|
+
export declare type RestEnvelope = 'none' | 'data' | 'jsonapi';
|
|
1159
|
+
|
|
884
1160
|
export declare const restError: (status: number, body: unknown, headers?: Readonly<Record<string, string | ReadonlyArray<string>>>) => RestRouteError;
|
|
885
1161
|
|
|
1162
|
+
export declare type RestErrors = 'problem-details' | 'tagged';
|
|
1163
|
+
|
|
1164
|
+
/**
|
|
1165
|
+
* The wire format of one `publicApi` surface. `'standard'` and `'jsonapi'` are
|
|
1166
|
+
* named instances of this; an app's own object is the custom case.
|
|
1167
|
+
*/
|
|
1168
|
+
export declare interface RestFormat {
|
|
1169
|
+
readonly name: string;
|
|
1170
|
+
/** `timestampMs` fields: RFC 3339 strings, or the epoch milliseconds the rpc wire carries. */
|
|
1171
|
+
readonly dates: RestDates;
|
|
1172
|
+
/** Failures: RFC 9457 `application/problem+json`, or the tagged object rpc carries. */
|
|
1173
|
+
readonly errors: RestErrors;
|
|
1174
|
+
/** Success bodies: the bare value, `{ data }`, or the JSON:API document. */
|
|
1175
|
+
readonly envelope: RestEnvelope;
|
|
1176
|
+
/** A cursor the handler returns in `cursorField`: as a `Link: <…>; rel="next"`
|
|
1177
|
+
* header (and `next` beside `data`), or left where the handler put it. */
|
|
1178
|
+
readonly pagination: RestPagination;
|
|
1179
|
+
/** The cursor field a paginated output carries. Default `nextCursor`. */
|
|
1180
|
+
readonly cursorField: string;
|
|
1181
|
+
/** The query parameter a cursor travels back in. Default `cursor`. */
|
|
1182
|
+
readonly cursorParam: string;
|
|
1183
|
+
/** Property names on the wire. */
|
|
1184
|
+
readonly naming: RestNaming;
|
|
1185
|
+
/** Weak `ETag` on GET answers, `If-None-Match` → 304. */
|
|
1186
|
+
readonly etag: boolean;
|
|
1187
|
+
/** Custom success encoding — receives the value already in wire form (dates,
|
|
1188
|
+
* naming applied). Replaces the envelope/pagination steps. */
|
|
1189
|
+
readonly encodeSuccess?: (value: unknown, ctx: RestFormatContext) => RestFormatResponse;
|
|
1190
|
+
/** Custom error encoding. Replaces `errors`. */
|
|
1191
|
+
readonly encodeError?: (error: RestFormatError, ctx: RestFormatContext) => RestFormatResponse;
|
|
1192
|
+
/** A hook over the OpenAPI operation the plugin emits for a projection. */
|
|
1193
|
+
readonly describe?: (operation: Record<string, unknown>, ctx: {
|
|
1194
|
+
readonly tag: string;
|
|
1195
|
+
readonly method: string;
|
|
1196
|
+
readonly path: string;
|
|
1197
|
+
}) => Record<string, unknown>;
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
/** What a format sees when it encodes one response. */
|
|
1201
|
+
export declare interface RestFormatContext {
|
|
1202
|
+
/** The rpc tag, e.g. `teams.list`. */
|
|
1203
|
+
readonly tag: string;
|
|
1204
|
+
readonly method: string;
|
|
1205
|
+
/** The request path, for `Link` headers. */
|
|
1206
|
+
readonly path: string;
|
|
1207
|
+
/** The request's query string (without `?`). */
|
|
1208
|
+
readonly query: string;
|
|
1209
|
+
/** The first `source` table of the procedure, when it declares one — the
|
|
1210
|
+
* JSON:API resource `type`. */
|
|
1211
|
+
readonly source: string | undefined;
|
|
1212
|
+
readonly status: number;
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
/** A failure the desugar or the projection is about to answer with. */
|
|
1216
|
+
export declare interface RestFormatError {
|
|
1217
|
+
readonly status: number;
|
|
1218
|
+
/** The typed error's `_tag` (`AccessDeniedError`), or a stable name for a
|
|
1219
|
+
* transport failure (`InvalidRequest`, `Unauthorized`, `Forbidden`, …). */
|
|
1220
|
+
readonly tag: string;
|
|
1221
|
+
/** A human-readable line. */
|
|
1222
|
+
readonly message: string;
|
|
1223
|
+
/** The error's own fields (a typed error), without `_tag`. */
|
|
1224
|
+
readonly fields: Readonly<Record<string, unknown>>;
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
/** A response a format produced: body (already wire-shaped), headers, and the
|
|
1228
|
+
* media type when it is not `application/json`. */
|
|
1229
|
+
export declare interface RestFormatResponse {
|
|
1230
|
+
readonly body: unknown;
|
|
1231
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
1232
|
+
readonly contentType?: string;
|
|
1233
|
+
}
|
|
1234
|
+
|
|
886
1235
|
export declare type RestGuard = (ctx: RestRouteContext) => RestGuardRejection | undefined | Promise<RestGuardRejection | undefined>;
|
|
887
1236
|
|
|
888
1237
|
/**
|
|
@@ -897,6 +1246,10 @@ export declare interface RestGuardRejection {
|
|
|
897
1246
|
|
|
898
1247
|
export declare type RestMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
|
|
899
1248
|
|
|
1249
|
+
export declare type RestNaming = 'camelCase' | 'snake_case';
|
|
1250
|
+
|
|
1251
|
+
export declare type RestPagination = 'link-header' | 'body-cursor';
|
|
1252
|
+
|
|
900
1253
|
/** A schema-encoded REST body with an application-selected HTTP status and
|
|
901
1254
|
* response headers. The marker keeps ordinary domain objects unambiguous.
|
|
902
1255
|
* `output` still validates/encodes `body`; use `Schema.Void` with a 204 when
|
|
@@ -906,6 +1259,8 @@ export declare interface RestResponse<O> {
|
|
|
906
1259
|
readonly status: number;
|
|
907
1260
|
readonly body: O;
|
|
908
1261
|
readonly headers?: Readonly<Record<string, string | ReadonlyArray<string>>>;
|
|
1262
|
+
/** A media type other than `application/json` (a JSON:API document). */
|
|
1263
|
+
readonly contentType?: string;
|
|
909
1264
|
}
|
|
910
1265
|
|
|
911
1266
|
/**
|
|
@@ -953,6 +1308,17 @@ export declare interface RestRouteDescriptor<I, O> {
|
|
|
953
1308
|
readonly summary?: string;
|
|
954
1309
|
readonly description?: string;
|
|
955
1310
|
readonly example?: RestRouteExample;
|
|
1311
|
+
/** The spec's `operationId` — set by a `publicApi` projection from its tag. */
|
|
1312
|
+
readonly operationId?: string;
|
|
1313
|
+
/** The spec's tag group(s) — set by a projection from its tag prefix. */
|
|
1314
|
+
readonly tags?: ReadonlyArray<string>;
|
|
1315
|
+
/**
|
|
1316
|
+
* Present on a `publicApi` projection: what the route projects, in the wire
|
|
1317
|
+
* form its profile speaks. The OpenAPI generator documents parameters,
|
|
1318
|
+
* bodies, responses and security from it; the desugar answers every refusal
|
|
1319
|
+
* through its format.
|
|
1320
|
+
*/
|
|
1321
|
+
readonly projection?: RestRouteProjection;
|
|
956
1322
|
/** Replacement hint. Sets a `Deprecation: true` response header. */
|
|
957
1323
|
readonly deprecated?: string;
|
|
958
1324
|
/** ISO date. Sets a `Sunset:` header; past the date the route returns
|
|
@@ -1004,7 +1370,9 @@ export declare class RestRouteError extends Error {
|
|
|
1004
1370
|
readonly status: number;
|
|
1005
1371
|
readonly body: unknown;
|
|
1006
1372
|
readonly headers: Readonly<Record<string, string | ReadonlyArray<string>>> | undefined;
|
|
1007
|
-
|
|
1373
|
+
/** A media type other than `application/json` (`application/problem+json`). */
|
|
1374
|
+
readonly contentType: string | undefined;
|
|
1375
|
+
constructor(status: number, body: unknown, headers?: Readonly<Record<string, string | ReadonlyArray<string>>>, contentType?: string);
|
|
1008
1376
|
}
|
|
1009
1377
|
|
|
1010
1378
|
export declare interface RestRouteExample {
|
|
@@ -1012,6 +1380,39 @@ export declare interface RestRouteExample {
|
|
|
1012
1380
|
readonly response?: unknown;
|
|
1013
1381
|
}
|
|
1014
1382
|
|
|
1383
|
+
/**
|
|
1384
|
+
* What a `publicApi` projection is, for the two readers that need more than
|
|
1385
|
+
* the route: the OpenAPI generator and the desugar's refusals. `input` and
|
|
1386
|
+
* `output` are the WIRE schemas — the descriptor's, rewritten by the profile
|
|
1387
|
+
* (`restViewSchema`): a `timestampMs` is a `date-time` string under
|
|
1388
|
+
* `dates: 'iso'`, keys are snake_case under that naming. `input` carries the
|
|
1389
|
+
* path parameters as fields; `pathParams` says which.
|
|
1390
|
+
*/
|
|
1391
|
+
export declare interface RestRouteProjection {
|
|
1392
|
+
readonly tag: string;
|
|
1393
|
+
readonly kind: 'query' | 'mutation' | 'action';
|
|
1394
|
+
readonly version: string;
|
|
1395
|
+
readonly security: 'required' | 'optional' | 'none';
|
|
1396
|
+
/** `publicApi.idempotent` — the route honours `Idempotency-Key` (under the
|
|
1397
|
+
* app's idempotency binding); a client sends one per attempt. */
|
|
1398
|
+
readonly idempotent: boolean;
|
|
1399
|
+
readonly input: Schema.Schema.All;
|
|
1400
|
+
/** The wire names of the input fields bound from the path. */
|
|
1401
|
+
readonly pathParams: ReadonlyArray<string>;
|
|
1402
|
+
readonly output: Schema.Schema.All;
|
|
1403
|
+
/** The first `source` table, when the procedure declares one. */
|
|
1404
|
+
readonly source: string | undefined;
|
|
1405
|
+
/** Every failure the operation answers with a typed body, and its status:
|
|
1406
|
+
* the descriptor's `errorStatus` entries, `422` for the union's other tags,
|
|
1407
|
+
* and each plugin error that names a REST status. */
|
|
1408
|
+
readonly errorResponses: ReadonlyArray<{
|
|
1409
|
+
readonly status: number;
|
|
1410
|
+
readonly tag: string;
|
|
1411
|
+
readonly schema: Schema.Schema.All;
|
|
1412
|
+
}>;
|
|
1413
|
+
readonly format: RestFormat;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1015
1416
|
/**
|
|
1016
1417
|
* Desugar a list of REST descriptors into `PluginHttpRoute[]` ready to
|
|
1017
1418
|
* spread into a plugin/app's `httpRoutes`. `bindings` is supplied by the
|
|
@@ -1059,6 +1460,33 @@ export declare interface RestStreamResponse {
|
|
|
1059
1460
|
readonly stream: PluginHttpRouteStream;
|
|
1060
1461
|
}
|
|
1061
1462
|
|
|
1463
|
+
/**
|
|
1464
|
+
* Rewrite a descriptor's schema into the shape the profile puts on the wire:
|
|
1465
|
+
* `timestampMs` (`DateFromNumber`) becomes an RFC 3339 string under
|
|
1466
|
+
* `dates: 'iso'`, and every struct's property names become `snake_case` under
|
|
1467
|
+
* `naming: 'snake_case'` — as a transformation, so decoding a wire value yields
|
|
1468
|
+
* the descriptor's own typed value and encoding the typed value yields the
|
|
1469
|
+
* wire form. `JSONSchema.make` of the result documents the wire (a
|
|
1470
|
+
* `format: date-time` string, the snake keys). Classes and other opaque
|
|
1471
|
+
* transformations pass through unchanged; a struct inside one keeps its keys.
|
|
1472
|
+
*/
|
|
1473
|
+
export declare const restViewSchema: (schema: Schema.Schema.All, format: RestFormat) => Schema.Schema.All;
|
|
1474
|
+
|
|
1475
|
+
/**
|
|
1476
|
+
* Whether `path` is one the route declared. The underlying router folds case
|
|
1477
|
+
* and trailing slashes when selecting candidates; this dispatcher deliberately
|
|
1478
|
+
* rejects those undeclared aliases. It checks byte for byte: a literal
|
|
1479
|
+
* segment must be equal, a `:name` segment takes one non-empty segment, and
|
|
1480
|
+
* beyond the declared segments a `'prefix'` route (the default) owns any
|
|
1481
|
+
* sub-path while an `'exact'` route owns nothing. A trailing slash alone is
|
|
1482
|
+
* not a sub-path — `/metrics/` is nobody's, whatever the mode. An explicit
|
|
1483
|
+
* `/*` tail is a prefix by itself.
|
|
1484
|
+
*/
|
|
1485
|
+
export declare const routeAcceptsPath: (route: {
|
|
1486
|
+
readonly path: string;
|
|
1487
|
+
readonly match?: "prefix" | "exact" | undefined;
|
|
1488
|
+
}, path: string) => boolean;
|
|
1489
|
+
|
|
1062
1490
|
/**
|
|
1063
1491
|
* Build a streaming (Server-Sent Events) handler result. `subscribe` gets an
|
|
1064
1492
|
* `emit` for one already-framed SSE chunk and MUST return an unsubscribe, which
|
|
@@ -1093,6 +1521,11 @@ declare const Subject: Schema.Union<[Schema.Struct<{
|
|
|
1093
1521
|
type: Schema.Literal<["serviceAccount"]>;
|
|
1094
1522
|
id: typeof Schema.String;
|
|
1095
1523
|
tenantId: typeof Schema.String;
|
|
1524
|
+
/** Application actor used for audit columns; null means machine work with
|
|
1525
|
+
* no application actor. Identity only, never a permission grant. */
|
|
1526
|
+
auditActorId: Schema.optionalWith<Schema.NullOr<typeof Schema.String>, {
|
|
1527
|
+
exact: true;
|
|
1528
|
+
}>;
|
|
1096
1529
|
scopes: Schema.optional<Schema.Array$<typeof Schema.String>>;
|
|
1097
1530
|
metadata: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.Unknown>>;
|
|
1098
1531
|
}>, Schema.Struct<{
|
|
@@ -1177,6 +1610,8 @@ declare type TargetRelations = Readonly<Record<string, TargetRelation>>;
|
|
|
1177
1610
|
|
|
1178
1611
|
declare type TargetSpec<Input = unknown, Row = unknown> = InsertTarget<Input, Row> | UpdateTarget<Input, Row> | DeleteTarget<Input>;
|
|
1179
1612
|
|
|
1613
|
+
export declare const toSnakeCase: (key: string) => string;
|
|
1614
|
+
|
|
1180
1615
|
declare interface UpdateTarget<Input = unknown, Row = unknown, Item = Record<string, unknown>> extends NestedTargetFields<Input> {
|
|
1181
1616
|
readonly table: string;
|
|
1182
1617
|
readonly op: 'update';
|
|
@@ -1194,4 +1629,12 @@ declare interface UpdateTarget<Input = unknown, Row = unknown, Item = Record<str
|
|
|
1194
1629
|
readonly shapeItem?: ((input: Input, current: Item) => Item) | undefined;
|
|
1195
1630
|
}
|
|
1196
1631
|
|
|
1632
|
+
export declare const wireExample: (example: {
|
|
1633
|
+
readonly request?: unknown;
|
|
1634
|
+
readonly response?: unknown;
|
|
1635
|
+
}, wireInput: Schema.Schema.All, wireOutput: Schema.Schema.All) => {
|
|
1636
|
+
readonly request?: unknown;
|
|
1637
|
+
readonly response?: unknown;
|
|
1638
|
+
};
|
|
1639
|
+
|
|
1197
1640
|
export { }
|