@voltro/protocol 0.53.0 → 0.55.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 +335 -0
- package/dist/index.d.ts +165 -13
- package/dist/index.js +494 -463
- package/dist/rest.d.ts +37 -6
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -696,6 +696,10 @@ export declare interface ClientTarget {
|
|
|
696
696
|
* `path` is set. 2nd arg is the optimistic id (insert) or the current item
|
|
697
697
|
* (update) — `unknown` here since the erased view spans both; normalize casts. */
|
|
698
698
|
readonly shapeItem?: ((input: Record<string, unknown>, currentOrOptimisticId: unknown) => Record<string, unknown>) | undefined;
|
|
699
|
+
/** Declared junction relations (see {@link TargetRelations}). Pure DATA —
|
|
700
|
+
* three strings per relation — so it crosses to the browser unchanged and
|
|
701
|
+
* drives junction auto-optimistic there. */
|
|
702
|
+
readonly relations?: TargetRelations | undefined;
|
|
699
703
|
}
|
|
700
704
|
|
|
701
705
|
export declare const composeAuthStrategies: (strategies: ReadonlyArray<AuthStrategy>, options?: {
|
|
@@ -2655,6 +2659,18 @@ export declare type PendingApproval = Schema.Schema.Type<typeof PendingApproval>
|
|
|
2655
2659
|
*/
|
|
2656
2660
|
export declare type PluginActivateHook = (ctx: PluginLifecycleContext) => Effect.Effect<void, unknown> | Promise<void> | void;
|
|
2657
2661
|
|
|
2662
|
+
/**
|
|
2663
|
+
* Derive the short alias used as the rpc-tag prefix for a plugin's routes.
|
|
2664
|
+
* Pure — depends only on the plugin name.
|
|
2665
|
+
*
|
|
2666
|
+
* Examples:
|
|
2667
|
+
* '@voltro/plugin-audit' → 'audit'
|
|
2668
|
+
* '@scope/plugin-rateLimit' → 'rateLimit'
|
|
2669
|
+
* 'plain-name' → 'plainName'
|
|
2670
|
+
* '@voltro/audit' → 'audit' (no plugin- prefix)
|
|
2671
|
+
*/
|
|
2672
|
+
export declare const pluginAlias: (pluginName: string) => string;
|
|
2673
|
+
|
|
2658
2674
|
/**
|
|
2659
2675
|
* Server-only context delivered to `bindDataStore`, ALONGSIDE the store,
|
|
2660
2676
|
* AFTER the framework has opened its store + pool. Gives a plugin the
|
|
@@ -3257,11 +3273,18 @@ export declare type PluginInstallHook = (ctx: PluginLifecycleContext) => Effect.
|
|
|
3257
3273
|
*
|
|
3258
3274
|
* **What an alias costs, stated because it is not obvious and nothing else
|
|
3259
3275
|
* says it:** the local and cloud dashboards fetch a plugin's inspect panel at
|
|
3260
|
-
* `/_voltro/inspect/plugins/<slug>/…` with the DEFAULT slug compiled in
|
|
3261
|
-
*
|
|
3262
|
-
*
|
|
3263
|
-
*
|
|
3264
|
-
*
|
|
3276
|
+
* `/_voltro/inspect/plugins/<slug>/…` with the DEFAULT slug compiled in, and
|
|
3277
|
+
* they are in different repositories, so they cannot follow an alias. That
|
|
3278
|
+
* used to mean an aliased plugin kept working while its panel 404'd. It no
|
|
3279
|
+
* longer does: `makePluginInspectRegistry` also mounts each plugin's inspect
|
|
3280
|
+
* endpoints under its CANONICAL slug, so the compiled-in path stays correct
|
|
3281
|
+
* however the app renames the plugin.
|
|
3282
|
+
*
|
|
3283
|
+
* The residue is `instance`, not `alias`. Two installs are two panels with one
|
|
3284
|
+
* canonical name, so they get NO shared mount — showing either under the
|
|
3285
|
+
* canonical path would hand a dashboard the other install's rows under a name
|
|
3286
|
+
* that looks right. Each is reachable at its own slug, which
|
|
3287
|
+
* `/_voltro/inspect/plugins` reports as `inspectSlug`.
|
|
3265
3288
|
*
|
|
3266
3289
|
* @param base the plugin's canonical package name, e.g. `'@voltro/plugin-cdc-out'`
|
|
3267
3290
|
* @param alias replaces the whole namespace — an app-chosen name
|
|
@@ -3508,6 +3531,55 @@ export declare interface PluginSchemaContribution {
|
|
|
3508
3531
|
readonly migrations?: ReadonlyArray<PluginMigration>;
|
|
3509
3532
|
}
|
|
3510
3533
|
|
|
3534
|
+
/**
|
|
3535
|
+
* Derive the URL slug for a plugin's HTTP-facing surfaces (the inspect mount
|
|
3536
|
+
* `/_voltro/inspect/plugins/<slug>/…`). Unlike `pluginAlias` (an identifier
|
|
3537
|
+
* for rpc tags / codegen, camelCase), the slug stays KEBAB-CASE — the shape
|
|
3538
|
+
* every dashboard fetches (`plugins/cdc-out/sinks`, never `plugins/cdcOut/…`)
|
|
3539
|
+
* and the shape the package name already carries. Instance-suffixed names
|
|
3540
|
+
* (`@voltro/plugin-cdc-out#analytics`) map `#` → `--` so the slug stays a
|
|
3541
|
+
* fetchable URL path segment.
|
|
3542
|
+
*
|
|
3543
|
+
* Examples:
|
|
3544
|
+
* '@voltro/plugin-audit' → 'audit'
|
|
3545
|
+
* '@voltro/plugin-cdc-out' → 'cdc-out'
|
|
3546
|
+
* '@scope/plugin-rateLimit' → 'rate-limit'
|
|
3547
|
+
* '@voltro/plugin-cdc-out#analytics'→ 'cdc-out--analytics'
|
|
3548
|
+
*/
|
|
3549
|
+
export declare const pluginSlug: (pluginName: string) => string;
|
|
3550
|
+
|
|
3551
|
+
/**
|
|
3552
|
+
* The wire tag a plugin's own client code must call for one of its routes.
|
|
3553
|
+
*
|
|
3554
|
+
* `pluginTag('@voltro/plugin-notifications', 'inbox')` is `'notifications.inbox'`
|
|
3555
|
+
* in a default app and `'inbox.inbox'` in an app that installed the plugin as
|
|
3556
|
+
* `notificationsPlugin({ alias: 'inbox' })`. Every hook a plugin ships goes
|
|
3557
|
+
* through this instead of spelling its own namespace, because the namespace is
|
|
3558
|
+
* the app's to choose and the hook is the half of the move that a literal
|
|
3559
|
+
* string cannot follow.
|
|
3560
|
+
*
|
|
3561
|
+
* **Resolution, and the one case that fails closed.** A base may have several
|
|
3562
|
+
* registered aliases when an app installs the same plugin twice
|
|
3563
|
+
* (`instance: 'analytics'` → `notifications#analytics`):
|
|
3564
|
+
*
|
|
3565
|
+
* - exactly one registered alias → that one;
|
|
3566
|
+
* - several, exactly one of which carries no `#` → the un-suffixed install.
|
|
3567
|
+
* Two installs of a plugin have a primary and a secondary, and a hook with
|
|
3568
|
+
* no way to name an install means the primary;
|
|
3569
|
+
* - several, none or more than one un-suffixed → **throws**. The hook is being
|
|
3570
|
+
* asked which of two servers it addresses and has no basis to pick; a guess
|
|
3571
|
+
* here writes to the wrong install's tables, which is worse than a stack
|
|
3572
|
+
* trace naming both candidates. Call the tag explicitly (`useSubscription(api,
|
|
3573
|
+
* 'notifications#analytics.inbox')`) to say which you mean.
|
|
3574
|
+
* - none registered → the canonical `pluginAlias(base)`. This is the path a
|
|
3575
|
+
* unit test rendering a hook in isolation takes, and the path an app takes
|
|
3576
|
+
* before its generated rpcGroup has loaded. It is NOT a fail-open guess: an
|
|
3577
|
+
* app that aliased and somehow lost its registration calls a tag the client
|
|
3578
|
+
* group does not contain, and the transport refuses it by name rather than
|
|
3579
|
+
* routing it somewhere plausible.
|
|
3580
|
+
*/
|
|
3581
|
+
export declare const pluginTag: (baseName: string, route: string) => string;
|
|
3582
|
+
|
|
3511
3583
|
/**
|
|
3512
3584
|
* A scaffold template a plugin contributes to `voltro init` /
|
|
3513
3585
|
* `voltro add-app`. Templates are listed under the plugin's name in
|
|
@@ -3887,10 +3959,29 @@ export declare type ReactivitySource = TableName | ReactivityChannel;
|
|
|
3887
3959
|
*/
|
|
3888
3960
|
export declare type ReactivitySourceValue = string | ReactivityChannel;
|
|
3889
3961
|
|
|
3962
|
+
/**
|
|
3963
|
+
* Declare, for this realm, what namespace each installed plugin actually
|
|
3964
|
+
* answers to. Emitted into `rpcGroup.generated.ts` by the codegen — one call
|
|
3965
|
+
* per api, mapping each plugin's CANONICAL base name to its EFFECTIVE alias.
|
|
3966
|
+
*
|
|
3967
|
+
* Emitted unconditionally whenever an app installs a plugin that contributes
|
|
3968
|
+
* client routes, not only when something was aliased. A registration that only
|
|
3969
|
+
* appeared in the aliased case would be a second code path exercised by nobody,
|
|
3970
|
+
* and the default case is where a regression would hide.
|
|
3971
|
+
*
|
|
3972
|
+
* Accumulates rather than overwrites: two apis in one browser bundle each
|
|
3973
|
+
* register their own map, and an app may install one plugin twice (`instance`).
|
|
3974
|
+
* The disambiguation happens at READ time — see `pluginTag`.
|
|
3975
|
+
*/
|
|
3976
|
+
export declare const registerPluginAliases: (aliases: Readonly<Record<string, string>>) => void;
|
|
3977
|
+
|
|
3890
3978
|
/** Gate a handler on a scope; fails with a typed `ScopeError` if missing.
|
|
3891
3979
|
* Checks the EFFECTIVE set so role-derived scopes count. */
|
|
3892
3980
|
export declare const requireScope: (subject: Subject, scope: string) => Effect.Effect<void, ScopeError>;
|
|
3893
3981
|
|
|
3982
|
+
/** Drop every registration. Tests only — production registers once at module load. */
|
|
3983
|
+
export declare const resetPluginAliases: () => void;
|
|
3984
|
+
|
|
3894
3985
|
/** The question the runtime asks a registered resource-scope resolver. */
|
|
3895
3986
|
export declare interface ResourceScopeRequest {
|
|
3896
3987
|
/** The authenticated caller. */
|
|
@@ -4704,21 +4795,52 @@ declare const TableValidationFailed_base: Schema.TaggedErrorClass<TableValidatio
|
|
|
4704
4795
|
|
|
4705
4796
|
export declare type Target<Input = unknown, Row = unknown> = TargetSpec<Input, Row> | ReadonlyArray<TargetSpec<Input, Row>>;
|
|
4706
4797
|
|
|
4798
|
+
/**
|
|
4799
|
+
* ONE declared many-to-many relation of a write target: the junction table
|
|
4800
|
+
* plus its two reference columns.
|
|
4801
|
+
*
|
|
4802
|
+
* **Why the columns are declared and not derived.** The server can derive
|
|
4803
|
+
* them (`store.relationLinks` reads the junction's `reference()` targets),
|
|
4804
|
+
* and it still does — but the same declaration drives JUNCTION AUTO-OPTIMISTIC
|
|
4805
|
+
* in the BROWSER, and the browser has no table registry to derive from
|
|
4806
|
+
* (`@voltro/database` is server-only by construction). Guessing a column name
|
|
4807
|
+
* from the table name is the failure mode this codebase refuses everywhere
|
|
4808
|
+
* else, so the pair is stated. It is not taken on trust: before it writes, the
|
|
4809
|
+
* server compares the declaration against the junction's real reference
|
|
4810
|
+
* columns and refuses — naming the right pair — if they disagree. A wrong
|
|
4811
|
+
* declaration is a boot-loud error, never a silent client/server divergence.
|
|
4812
|
+
*/
|
|
4813
|
+
export declare interface TargetRelation {
|
|
4814
|
+
/** The junction (link) table. */
|
|
4815
|
+
readonly junction: string;
|
|
4816
|
+
/** The junction's reference column pointing at the TARGET's own table. */
|
|
4817
|
+
readonly anchorColumn: string;
|
|
4818
|
+
/** The junction's other reference column — the linked row's id. */
|
|
4819
|
+
readonly targetColumn: string;
|
|
4820
|
+
}
|
|
4821
|
+
|
|
4707
4822
|
/**
|
|
4708
4823
|
* Declared many-to-many RELATIONS of a write target: `{ inputField:
|
|
4709
|
-
*
|
|
4824
|
+
* TargetRelation }`. After the executor succeeds — inside the SAME
|
|
4710
4825
|
* transaction — the framework reconciles the junction's links for the
|
|
4711
4826
|
* written row against `input[inputField]` (an array of target ids) via the
|
|
4712
4827
|
* diff-based `store.relationLinks`, so a form's multi-reference field saves
|
|
4713
|
-
* in one mutation with no hand-written junction code.
|
|
4714
|
-
*
|
|
4715
|
-
*
|
|
4828
|
+
* in one mutation with no hand-written junction code.
|
|
4829
|
+
*
|
|
4830
|
+
* The SAME declaration drives the client's junction auto-optimistic: the
|
|
4831
|
+
* cache reconciles the junction rows of every subscription sourced on
|
|
4832
|
+
* `junction` the moment the mutation is sent, so a multi-reference field
|
|
4833
|
+
* flips as instantly as a scalar one instead of waiting for the server delta.
|
|
4834
|
+
* Those patches ride the ordinary optimistic lane (staged under the mutation
|
|
4835
|
+
* id): reverted on failure, kept on success until the base actually moves.
|
|
4716
4836
|
*
|
|
4717
4837
|
* An ABSENT input field leaves the links untouched (absent ≠ empty — an
|
|
4718
4838
|
* empty array is the explicit "clear them all"). The row id is the
|
|
4719
|
-
* executor's `output.id`, falling back to `input.id
|
|
4839
|
+
* executor's `output.id`, falling back to `input.id`; the client, which
|
|
4840
|
+
* cannot see `output` yet, uses `input.id` (and, for an insert, the same
|
|
4841
|
+
* optimistic id it stamped on the new row).
|
|
4720
4842
|
*/
|
|
4721
|
-
export declare type TargetRelations = Readonly<Record<string,
|
|
4843
|
+
export declare type TargetRelations = Readonly<Record<string, TargetRelation>>;
|
|
4722
4844
|
|
|
4723
4845
|
export declare type TargetSpec<Input = unknown, Row = unknown> = InsertTarget<Input, Row> | UpdateTarget<Input, Row> | DeleteTarget<Input>;
|
|
4724
4846
|
|
|
@@ -5068,8 +5190,10 @@ export declare interface VoltroPlugin {
|
|
|
5068
5190
|
* declarations across seven plugins), so the escape hatch fires on all of
|
|
5069
5191
|
* them and the alias moves NOTHING on the rpc surface. A user aliasing
|
|
5070
5192
|
* `notifications` to escape a collision with their own `notifications.*`
|
|
5071
|
-
* routes would still collide — and would additionally
|
|
5072
|
-
* panel, which fetches the default slug. Worse than not
|
|
5193
|
+
* routes would still collide — and, at that time, would additionally have
|
|
5194
|
+
* lost the dashboard panel, which fetches the default slug. Worse than not
|
|
5195
|
+
* shipping the field. (The panel half is fixed since: see the canonical
|
|
5196
|
+
* mount in `makePluginInspectRegistry`.)
|
|
5073
5197
|
*
|
|
5074
5198
|
* With `baseName` set, both tag derivations strip a leading
|
|
5075
5199
|
* `<default-alias>.` before applying the EFFECTIVE alias, so
|
|
@@ -5497,6 +5621,34 @@ export declare const wireErrorUnion: (descriptor: {
|
|
|
5497
5621
|
readonly requiresApproval?: AnyApprovalPolicy | undefined;
|
|
5498
5622
|
}, kind: "query" | "mutation" | "action" | "stream") => Schema.Schema.All;
|
|
5499
5623
|
|
|
5624
|
+
/**
|
|
5625
|
+
* Re-tag a procedure descriptor for the wire.
|
|
5626
|
+
*
|
|
5627
|
+
* Every lifter below is `Rpc.make(descriptor.name, …)`, so the tag a procedure
|
|
5628
|
+
* answers to on the wire is the one baked into the DESCRIPTOR — not the one the
|
|
5629
|
+
* caller thinks it is emitting. That is fine for app-authored procedures, whose
|
|
5630
|
+
* descriptor and tag have one source. It was wrong for PLUGIN routes: an app
|
|
5631
|
+
* that installs a plugin under an `alias` moves the namespace, the server
|
|
5632
|
+
* registers the moved tag, and the generated client lifted the plugin's
|
|
5633
|
+
* descriptor unchanged — so the browser sent the tag the plugin AUTHORED to a
|
|
5634
|
+
* server that had stopped serving it. The identifier moved, the descriptor map
|
|
5635
|
+
* key moved, the type key moved; the only string the transport reads did not.
|
|
5636
|
+
*
|
|
5637
|
+
* The codegen wraps every plugin-contributed descriptor with this, always —
|
|
5638
|
+
* including the un-aliased case, where it is an identity in effect. A wrap that
|
|
5639
|
+
* only appeared under an alias would be a branch nothing exercises, and the
|
|
5640
|
+
* un-aliased case is the one a regression would hide in.
|
|
5641
|
+
*
|
|
5642
|
+
* Returns a COPY. The descriptor is imported by reference from the plugin's
|
|
5643
|
+
* browser-safe module and may be lifted by several apps in one process; mutating
|
|
5644
|
+
* `name` in place would re-tag it for all of them.
|
|
5645
|
+
*/
|
|
5646
|
+
export declare const withRpcTag: <D extends {
|
|
5647
|
+
readonly name: string;
|
|
5648
|
+
}, const T extends string>(descriptor: D, tag: T) => Omit<D, "name"> & {
|
|
5649
|
+
readonly name: T;
|
|
5650
|
+
};
|
|
5651
|
+
|
|
5500
5652
|
export declare const workflowCancelDescriptor: ActionProcedureDescriptor<"__voltro.workflow.cancel", Schema.Struct<{
|
|
5501
5653
|
workflowName: typeof Schema.String;
|
|
5502
5654
|
executionId: typeof Schema.String;
|