@voltro/runtime 0.62.2 → 0.63.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 CHANGED
@@ -39,6 +39,33 @@ _Changes staged for the next release accumulate here (rolled up from
39
39
 
40
40
  ---
41
41
 
42
+ ## [0.63.0] — 2026-09-03
43
+
44
+ ### ⚠ BREAKING
45
+
46
+ - **@voltro/client, @voltro/runtime, @voltro/cli, @voltro/web, @voltro/react-native** — Short transport gaps now have one bounded recovery contract. Raw diagnostics remain immediate, while `useConnectionStatus` exposes `recovering` during a configurable grace window and `useOnRpcError` emits exactly one visible transport failure only if the gap remains open. Same-subject runtime swaps keep subscription bases, revisions and optimistic patches; subject changes discard them. Interrupted mutations report `outcome: unknown` and replay once with the same key only after the deployed API proves that server idempotency is active. The codemod explains the new status member and the raw versus presentation error channels.
47
+
48
+ **`voltro update` carries you across this** — codemod `0.63.0/01_recovery-presentation`. If you pin versions by hand and never run it, print the notes without changing anything: `voltro update --codemods-only --from <your current version> --dry-run` (this one ships in 0.63.0).
49
+
50
+ ### Fixed
51
+
52
+ - **@voltro/database, @voltro/sql-turso, @voltro/sql-sqlite, @voltro/sql-mssql** — Framework-table evolution now converges under real SQLite and both local Turso transports, and has a live MSSQL fixture. The new Turso runs also fixed internal table protection, boolean/number introspection normalization, and case-insensitive SQLite-family index-name comparison. The MSSQL fixture exposed and fixes a second convergence bug: unbounded text that MSSQL auto-bounds for an index is now rendered and compared with the same indexed-column rule, so a second plan no longer tries to widen an indexed `NVARCHAR(450)` to `NVARCHAR(MAX)`.
53
+
54
+ ---
55
+
56
+ ## [0.62.3] — 2026-09-03
57
+
58
+ ### Added
59
+
60
+ - **@voltro/runtime** — `EffectStore` now exposes the complete Promise-store mutation surface plus transactions that roll back while preserving an inner Effect Cause. `defineSubscriber` accepts `eachReplica: true` so local per-replica work can state its topology explicitly; it cannot be combined with `once`.
61
+
62
+ ### Fixed
63
+
64
+ - **@voltro/cli** — `voltro build` no longer starts Vite's HMR WebSocket while pre-rendering. A `RedirectError` from a static loader is now emitted as redirect metadata and served by `voltro start` with its exact status and `Location`; unrelated loader errors still fail the build.
65
+ - **@voltro/cli, @voltro/database, @voltro/plugin-storage** — `voltro doctor` now resolves grouped event bindings and narrows its hand-roll, junction, ownership, nullable-write, singleton-read, and UI reachability checks to evidence they can actually prove. Ids owned by external systems can be declared with `.externalId()`; plugin references and non-FK asset references carry that metadata automatically.
66
+
67
+ ---
68
+
42
69
  ## [0.62.2] — 2026-09-03
43
70
 
44
71
  ### Added
package/dist/index.d.ts CHANGED
@@ -3605,10 +3605,29 @@ export declare interface EffectStoreOps {
3605
3605
  * hand-built descriptor. */
3606
3606
  readonly query: <R = Row>(descriptor: QueryDescriptor<R>) => Effect.Effect<ReadonlyArray<R>, StoreError>;
3607
3607
  readonly insert: (table: string, row: Row) => Effect.Effect<Row, StoreError>;
3608
+ readonly insertMany: (table: string, rows: ReadonlyArray<Row>) => Effect.Effect<ReadonlyArray<Row>, StoreError>;
3609
+ readonly patchJson: (table: string, primaryKey: string, path: string, value: unknown) => Effect.Effect<Row | null, StoreError>;
3608
3610
  readonly update: (table: string, primaryKey: string, patch: Readonly<Record<string, unknown>>) => Effect.Effect<Row | null, StoreError>;
3611
+ readonly updateMany: (table: string, patch: Readonly<Record<string, unknown>>, options: {
3612
+ readonly where: Predicate;
3613
+ }) => Effect.Effect<number, StoreError>;
3609
3614
  readonly delete: (table: string, primaryKey: string) => Effect.Effect<boolean, StoreError>;
3615
+ readonly deleteMany: (table: string, options: {
3616
+ readonly where: Predicate;
3617
+ }) => Effect.Effect<number, StoreError>;
3618
+ readonly upsert: (table: string, row: Row, options: {
3619
+ readonly conflictColumns: ReadonlyArray<string>;
3620
+ readonly update?: ReadonlyArray<string> | ((existing: Row) => Readonly<Record<string, unknown>>);
3621
+ }) => Effect.Effect<Row, StoreError>;
3622
+ readonly insertIgnore: (table: string, row: Row, options: {
3623
+ readonly conflictColumns: ReadonlyArray<string>;
3624
+ }) => Effect.Effect<Row, StoreError>;
3610
3625
  /** Bypass soft-delete. See `MutationStore.hardDelete`. */
3611
3626
  readonly hardDelete: (table: string, primaryKey: string) => Effect.Effect<boolean, StoreError>;
3627
+ /** Run one Effect program atomically against the transaction-scoped store.
3628
+ * The inner Effect's typed failures and defects are preserved; database /
3629
+ * store failures join the error channel as `StoreError`. */
3630
+ readonly transactional: <A, E, R>(work: (transaction: EffectStoreOps) => Effect.Effect<A, E, R>) => Effect.Effect<A, E | StoreError, R>;
3612
3631
  }
3613
3632
 
3614
3633
  /** Empty registry — handy for tests + the rare bootstrap path with no
@@ -8779,6 +8798,10 @@ export declare interface RpcServerOptions<Rpcs extends Rpc.Any> {
8779
8798
  */
8780
8799
  readonly host?: string;
8781
8800
  readonly path?: `/${string}`;
8801
+ /** Whether WS mutations are durably idempotent. Exposed as a non-secret
8802
+ * runtime capability so clients replay only when the deployed server proves
8803
+ * the same key will be deduplicated. */
8804
+ readonly mutationReplay?: boolean;
8782
8805
  /** Non-sensitive fleet identity written on the rpc WebSocket open/close
8783
8806
  * records. Defaults to the process identity resolver (POD_NAME/HOSTNAME).
8784
8807
  * Embedders may state it explicitly when they own process identity. */
@@ -10242,6 +10265,15 @@ export declare interface SubscriberDefinition {
10242
10265
  * from a `*.reaction.tsx`, where the durability is the primitive's job.
10243
10266
  */
10244
10267
  readonly once?: true | ((event: SubscribeEvent) => string);
10268
+ /**
10269
+ * State explicitly that this handler must run on every replica.
10270
+ *
10271
+ * This is the executable counterpart to omitting `once`: it documents that
10272
+ * multiplication is intentional and lets `voltro doctor` distinguish an
10273
+ * unmade fleet decision from a cache/index refresh that genuinely belongs on
10274
+ * every process.
10275
+ */
10276
+ readonly eachReplica?: true;
10245
10277
  readonly handler: SubscribeHandler;
10246
10278
  }
10247
10279