@nice-code/action 0.20.0 → 0.21.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/README.md CHANGED
@@ -33,7 +33,7 @@ The pieces:
33
33
  | **ActionRuntime** | One per runtime; identifies it and dispatches actions to handlers |
34
34
  | **Channel** | The transport-agnostic routing contract between two runtimes, declared *by role* (`toAcceptor` / `toConnector`) — `defineChannel` (plain) or `defineSecureChannel` (binary + encryption) |
35
35
  | **Carrier** | How bytes actually move: `wsCarrier` / `httpCarrier` / `inMemoryCarrier` / `rtcCarrier` (connector side), `wsAcceptorCarrier` / `httpAcceptorCarrier` (acceptor side) |
36
- | **Transport** | A carrier wrapped with a security policy: `secureTransport` (handshake + optional encryption) or `plainTransport` |
36
+ | **Transport** | A carrier wrapped with a security policy (handshake + optional encryption, or plain). You don't build these directly — `connectChannel` / `serveChannel` apply the policy to each carrier for you |
37
37
  | **RuntimeCoordinate** | Identifies an environment (frontend, backend, worker…) and is how actions are routed |
38
38
 
39
39
  > **One runtime per client.** A client (a frontend, a backend, a worker) has a *single* `ActionRuntime`
@@ -243,9 +243,12 @@ Key options: `clientEnv` (required), `storage` (required only when a carrier is
243
243
 
244
244
  ### Connecting — `connectChannel`
245
245
 
246
- The connector has one runtime and `connectChannel`s to each acceptor it talks to. It routes the channel's
247
- `toAcceptor` domains out over the transports (first = preferred, rest = fallback) and registers local
248
- handlers for the `toConnector` pushes from `onPush` all derived from the channel, no restated lists.
246
+ The connector has one runtime and `connectChannel`s to each acceptor it talks to. One call binds the
247
+ shared facts the channel (its codec + routing), the runtime, and one crypto identity over `storage` —
248
+ into every transport, so you state them *once*. It routes the channel's `toAcceptor` domains out over the
249
+ transports (first = preferred, rest = fallback) and registers local handlers for the `toConnector` pushes
250
+ from `onPush` — all derived from the channel, no restated lists. It's the exact dial-out dual of
251
+ `serveChannel`.
249
252
 
250
253
  ```ts
251
254
  import {
@@ -253,39 +256,35 @@ import {
253
256
  RuntimeCoordinate,
254
257
  ESecurityLevel,
255
258
  connectChannel,
256
- secureTransport,
257
- plainTransport,
258
259
  wsCarrier,
259
260
  httpCarrier,
260
261
  } from "@nice-code/action";
261
262
 
262
263
  export const clientRuntime = new ActionRuntime(RuntimeCoordinate.env("frontend"));
263
264
 
264
- // A carrier wrapped in a security policy = a transport.
265
- const wsTransport = secureTransport({
266
- channel: appChannel,
267
- runtime: clientRuntime, // its coordinate is the authenticated identity in the handshake
268
- storageAdapter, // persists this client's crypto identity across reloads
265
+ connectChannel(clientRuntime, appChannel, {
266
+ peer: serverCoord,
267
+ storage, // one crypto identity, fanned across every secure transport
269
268
  securityLevel: ESecurityLevel.encrypted,
270
- carrier: wsCarrier("wss://api.example.com/resolve_action/ws"),
271
- });
272
- const httpTransport = plainTransport({
273
- carrier: httpCarrier(() => ({ url: "https://api.example.com/resolve_action" })),
274
- });
275
-
276
- connectChannel(clientRuntime, serverCoord, {
277
- channel: appChannel,
278
- transports: [wsTransport, httpTransport], // secure WS preferred, HTTP fallback
269
+ transports: [
270
+ { carrier: wsCarrier("wss://api.example.com/resolve_action/ws") }, // secure WS, preferred
271
+ { carrier: httpCarrier(() => ({ url: "https://api.example.com/resolve_action" })), secure: false }, // plain HTTP fallback
272
+ ],
279
273
  // onPush: { ... } // handlers for the channel's toConnector pushes (see below)
280
274
  });
281
275
  ```
282
276
 
283
- `connectChannel(runtime, acceptorCoordinate, options)` returns the `ConnectorHandler` so you can later
277
+ `connectChannel(runtime, channel, options)` returns the `ConnectorHandler` so you can later
284
278
  `handler.clearTransportCache()` (which also closes any live sockets) on teardown. Options:
285
279
 
286
- - **`channel`** — the shared channel; its `toAcceptor`/`toConnector` drive all routing.
287
- - **`transports`** — to the acceptor, in preference order; all carry the same `toAcceptor` domains and the
288
- manager falls through on failure.
280
+ - **`peer`** — the acceptor's `RuntimeCoordinate` this connection dials.
281
+ - **`transports`** — declared by *carrier* `{ carrier, secure? }`, in preference order; all carry the
282
+ channel's `toAcceptor` domains and the manager falls through on failure. `secure` defaults to `true`.
283
+ - **`storage`** — one backing store for the connection's crypto identity, fanned across every secure
284
+ transport. Required when any transport is secure; omit for a fully-plain connection. (`link` shares an
285
+ existing identity instead.)
286
+ - **`securityLevel`** — default level for secure transports (`authenticated` if omitted; override per
287
+ transport with `securityLevel` on the descriptor).
289
288
  - **`onPush`** — handlers for the channel's `toConnector` pushes (optional; omit for send-only).
290
289
  - **`defaultTimeout`** — default per-action timeout.
291
290
 
@@ -348,9 +347,10 @@ export const appChannel = defineSecureChannel({
348
347
  ### Connector side — handle pushes with `onPush`
349
348
 
350
349
  ```ts
351
- connectChannel(clientRuntime, serverCoord, {
352
- channel: appChannel,
353
- transports: [wsTransport, httpTransport],
350
+ connectChannel(clientRuntime, appChannel, {
351
+ peer: serverCoord,
352
+ storage,
353
+ transports: [{ carrier: wsCarrier(wsUrl) }, { carrier: httpCarrier(httpUrl), secure: false }],
354
354
  onPush: {
355
355
  // Keyed by the toConnector action id; input + output typed from the channel.
356
356
  position_update: async ({ player, x, y }) => {
@@ -489,7 +489,7 @@ and pushes still route to the right socket after the object wakes from eviction.
489
489
 
490
490
  ## Security levels
491
491
 
492
- `ESecurityLevel` (used by `secureTransport` and `serveChannel`):
492
+ `ESecurityLevel` (used by `connectChannel` and `serveChannel`):
493
493
 
494
494
  - **`none`** — identity self-asserted, no handshake. Fastest; fine for dev/trusted networks.
495
495
  - **`authenticated`** — the handshake verifies identity (sign/verify + trust-on-first-use key pin);
@@ -502,7 +502,7 @@ crypto identity; the server pins client keys trust-on-first-use. Persisting the
502
502
  hibernatable carrier) lets an `authenticated`/`encrypted` connection resume after eviction without
503
503
  re-handshaking.
504
504
 
505
- The whole thing rides one channel: the same `secureTransport({ carrier: wsCarrier(...) })` works at any
505
+ The whole thing rides one channel: the same secure `{ carrier: wsCarrier(...) }` transport works at any
506
506
  level, and `httpCarrier` runs the *same* secure session over HTTP (handshake → token → encrypted frames),
507
507
  with the request/reply correlation provided for free by the HTTP transaction. Pair a secure WS with a
508
508
  plain HTTP fallback by giving the acceptor a `httpAcceptorCarrier({ secure: false })`.
@@ -542,17 +542,19 @@ holds, with no reconnect.
542
542
 
543
543
  ```ts
544
544
  // Prefer the secure socket, but only once a session id exists; fall back to HTTP meanwhile.
545
- const wsTransport = secureTransport({
546
- channel, runtime, storageAdapter, securityLevel,
547
- available: () => sessionId != null,
548
- carrier: wsCarrier(`${url}/ws`, {
549
- // Only ever called once `available` passes, so no need for a placeholder cache key.
550
- getTransportCacheKey: () => [sessionId],
551
- }),
552
- });
553
-
554
- connectChannel(runtime, serverCoord, {
555
- transports: [wsTransport, httpTransport], // ws preferred; HTTP serves while ws is gated off
545
+ connectChannel(runtime, appChannel, {
546
+ peer: serverCoord,
547
+ storage,
548
+ transports: [
549
+ {
550
+ carrier: wsCarrier(`${url}/ws`, {
551
+ // Only ever called once `available` passes, so no need for a placeholder cache key.
552
+ getTransportCacheKey: () => [sessionId],
553
+ }),
554
+ available: () => sessionId != null, // ws preferred; HTTP serves while ws is gated off
555
+ },
556
+ { carrier: httpCarrier(httpUrl), secure: false },
557
+ ],
556
558
  });
557
559
  ```
558
560
 
@@ -656,17 +658,14 @@ try {
656
658
 
657
659
  ## Lower-level building blocks
658
660
 
659
- `connectChannel` and `serveChannel` are sugar; reach for these when you need finer control.
660
-
661
- - **`ActionRuntime.connectTo(coordinate, { transports, domains, actions, localHandlers, defaultTimeout })`**
662
- — what `connectChannel` desugars to: build a `ConnectorHandler` for a peer, route domains/actions to
663
- it, register it (plus any local push handlers), and apply — in one call. Use it directly when your
664
- routing isn't expressed as a single channel.
661
+ `connectChannel` and `serveChannel` are the supported entry points they bind the channel, runtime, and
662
+ crypto identity for you. The pieces below are what they're built on; reach for them only for the rare
663
+ routing that isn't a single channel.
665
664
 
666
665
  - **Carriers vs transports.** A *carrier* (`wsCarrier`, `httpCarrier`, `inMemoryCarrier`, `rtcCarrier`) is
667
- raw byte movement; a *transport* (`secureTransport`, `plainTransport`) wraps one with a security policy.
668
- `connectTo` takes transports; `serveChannel` takes acceptor carriers (`wsAcceptorCarrier`,
669
- `httpAcceptorCarrier`) and applies the security policy itself.
666
+ raw byte movement; a *transport* wraps one with a security policy. You name carriers in
667
+ `connectChannel`'s `transports` (the `secure` flag picks the policy) and in `serveChannel`'s `carriers`;
668
+ the transport wrapping happens internally, so there's no separate transport-builder to call.
670
669
 
671
670
  - **`acceptChannel(runtime, channel, { clientEnv, storageAdapter, send, ... })`** — build the secure
672
671
  `AcceptorHandler` for a channel by hand (the accept-in counterpart to a single transport), when you're
@@ -695,5 +694,5 @@ try {
695
694
  same-process peers) with no network.
696
695
 
697
696
  - **Custom carriers** — for any channel nice-action doesn't model natively, implement an
698
- `IDuplexCarrierSource` / `IExchangeCarrierSource` and hand it to `secureTransport` / `plainTransport`
697
+ `IDuplexCarrierSource` / `IExchangeCarrierSource` and name it in `connectChannel`'s `transports`
699
698
  (connector) or build an acceptor carrier for `serveChannel`.
@@ -1,4 +1,4 @@
1
- import { Lr as IRuntimeCoordinate, _ as TActionProgress } from "./ActionPayload.types-D0DM-g65.mjs";
1
+ import { Pr as IRuntimeCoordinate, _ as TActionProgress } from "./ActionPayload.types-DXGiw1SF.mjs";
2
2
  //#region ../nice-devtools-shared/src/components/PanelChrome.d.ts
3
3
  /** Where a devtools panel is docked. */
4
4
  type TDevtoolsPosition = "dock-bottom" | "dock-top" | "dock-left" | "dock-right";
@@ -76,4 +76,4 @@ declare class ActionDevtoolsCore {
76
76
  }
77
77
  //#endregion
78
78
  export { TDevtoolsActionStatus as a, IDevtoolsObservableDomain as i, IActionDevtoolsCoreOptions as n, TDevtoolsListener as o, IDevtoolsActionEntry as r, TDevtoolsPosition as s, ActionDevtoolsCore as t };
79
- //# sourceMappingURL=ActionDevtoolsCore-D_JvgPmz.d.mts.map
79
+ //# sourceMappingURL=ActionDevtoolsCore-baIHExfj.d.mts.map
@@ -1,4 +1,4 @@
1
- import { Lr as IRuntimeCoordinate, _ as TActionProgress } from "./ActionPayload.types-CnfWlkA1.cjs";
1
+ import { Pr as IRuntimeCoordinate, _ as TActionProgress } from "./ActionPayload.types-CQM1HRw_.cjs";
2
2
  //#region ../nice-devtools-shared/src/components/PanelChrome.d.ts
3
3
  /** Where a devtools panel is docked. */
4
4
  type TDevtoolsPosition = "dock-bottom" | "dock-top" | "dock-left" | "dock-right";
@@ -76,4 +76,4 @@ declare class ActionDevtoolsCore {
76
76
  }
77
77
  //#endregion
78
78
  export { TDevtoolsActionStatus as a, IDevtoolsObservableDomain as i, IActionDevtoolsCoreOptions as n, TDevtoolsListener as o, IDevtoolsActionEntry as r, TDevtoolsPosition as s, ActionDevtoolsCore as t };
79
- //# sourceMappingURL=ActionDevtoolsCore-dV-IVPcP.d.cts.map
79
+ //# sourceMappingURL=ActionDevtoolsCore-dApyYvTS.d.cts.map