@mauroandre/velojs 0.0.60 → 0.0.61

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.
@@ -19,6 +19,13 @@ interface BuildSubscriptionOptions {
19
19
  * "slice", data }`. `next()` keeps the slice-1 contract: the raw `data`.
20
20
  */
21
21
  channelEvents?: boolean;
22
+ /**
23
+ * Live-action mode: a server-reported `error` event (the source failed) is
24
+ * recorded discriminated in `nextEvent()` as `{ type: "error", data }` and
25
+ * does NOT enter `events`/`next()` — an error is not a payload. Snapshots
26
+ * keep the `channelEvents` behavior.
27
+ */
28
+ liveEvents?: boolean;
22
29
  }
23
30
  export declare function buildSubscription<TEvent, TSnapshot>(opts: BuildSubscriptionOptions): Promise<TestSubscription<TEvent, TSnapshot> & {
24
31
  /** Next arrival discriminated by the mode that delivered it. */
@@ -107,6 +107,17 @@ export interface ChannelSubscribeOptions extends SubscribeOptions {
107
107
  /** Route params the connection declares (serialized into `?_route=`). */
108
108
  params?: Params;
109
109
  }
110
+ /**
111
+ * Options of a live action subscription.
112
+ *
113
+ * `args` are the arguments the subscription declares — the same ones the hook
114
+ * serializes into `?_args=`. They are the subscription's identity and the
115
+ * `body` of every (re-)execution; the size guard and the scope run for real.
116
+ */
117
+ export interface LiveActionSubscribeOptions extends SubscribeOptions {
118
+ /** The action's declared args (serialized into `?_args=`). */
119
+ args?: Record<string, unknown>;
120
+ }
110
121
  export interface NextOptions {
111
122
  /** Reject if no event arrives within this many ms. */
112
123
  timeoutMs: number;
@@ -169,9 +180,13 @@ export interface TestChannelSubscription<T = any> extends TestSubscription<T, T>
169
180
  /** Next arrival, discriminated by the mode that delivered it. */
170
181
  nextEvent(opts: NextOptions): Promise<ChannelEvent<T>>;
171
182
  }
172
- /** One channel arrival: a whole snapshot or a slice to be merged. */
183
+ /**
184
+ * One channel arrival: a whole snapshot, a slice to be merged, or a reported
185
+ * failure of the source (a live action subscription receives `{ message }` —
186
+ * its last valid value stays in place on the client).
187
+ */
173
188
  export interface ChannelEvent<T = any> {
174
- type: "snapshot" | "slice";
189
+ type: "snapshot" | "slice" | "error";
175
190
  data: T;
176
191
  }
177
192
  /** The module (or moduleId) a channel belongs to, as `app.channel()` accepts it. */
@@ -253,6 +268,32 @@ export interface TestApp {
253
268
  * ```
254
269
  */
255
270
  channel<T = any>(module: ChannelModuleRef, name: string, opts?: ChannelSubscribeOptions): Promise<TestChannelSubscription<T>>;
271
+ /**
272
+ * Open a live action subscription — the server-side twin of
273
+ * `useLiveAction(action, args)`.
274
+ *
275
+ * The module may be the imported route module (its `metadata.moduleId` is
276
+ * read) or a moduleId string; `name` is the action name WITHOUT the
277
+ * `action_` prefix. Cookies (and therefore the principal) come from the
278
+ * options or from `app.as(user)`; the route node's middlewares run for
279
+ * real, so an unauthenticated subscription is denied exactly as in
280
+ * production. `opts.args` are the declared arguments — serialized into
281
+ * `?_args=`, validated by the size guard and consumed by the scope.
282
+ *
283
+ * `next()` delivers the payloads in arrival order (the connect snapshot
284
+ * first — it is the loading gesture); `nextEvent()` discriminates the
285
+ * arrival (`{ type: "snapshot" | "error", data }`); `close()` ends the
286
+ * subscription.
287
+ *
288
+ * ```ts
289
+ * const sub = await app.as({ id: 1 }).liveAction(Project, "abrirFicha", { args: { id: 7 } });
290
+ * expect(await sub.next({ timeoutMs: 1000 })).toEqual({ nome: "Site" }); // connect
291
+ *
292
+ * await emit("fichaProjeto", { args: { id: 7 } });
293
+ * expect(await sub.next({ timeoutMs: 1000 })).toEqual({ nome: "Site", fase: "review" });
294
+ * ```
295
+ */
296
+ liveAction<T = any>(module: ChannelModuleRef, name: string, opts?: LiveActionSubscribeOptions): Promise<TestChannelSubscription<T>>;
256
297
  /**
257
298
  * Open an in-memory session against a `socket_*` handler.
258
299
  *
package/dist/types.d.ts CHANGED
@@ -29,6 +29,18 @@ export interface RouteModule {
29
29
  * dev/build error. Requires an entry per name in `app/channels.ts`.
30
30
  */
31
31
  channels?: readonly string[];
32
+ /**
33
+ * Live actions — the tab-facing twin of `channels`. The key is the action
34
+ * name WITHOUT the `action_` prefix (the same form as the
35
+ * `/_action/{moduleId}/{name}` path); the value is the list of channel
36
+ * names — a `useLiveAction(action, args)` subscription enters the groups
37
+ * of all of them, so an `emit` in any one re-executes the action with the
38
+ * subscription's own args and pushes the fresh value. Requires the action
39
+ * to exist in the module and an entry per channel in `app/channels.ts`.
40
+ * A live action is, by contract, a parameterized read: re-executing it
41
+ * must be side-effect free.
42
+ */
43
+ liveActions?: Readonly<Record<string, readonly string[]>>;
32
44
  staticPaths?: () => Promise<Record<string, string>[]>;
33
45
  metadata?: Metadata;
34
46
  [key: `action_${string}`]: (args: ActionArgs<any>) => Promise<any>;
package/dist/vite.d.ts CHANGED
@@ -3,7 +3,7 @@ import type { VeloConfig } from "./config.js";
3
3
  import * as t from "@babel/types";
4
4
  export declare function injectMetadata(code: string, moduleId: string, fullPath?: string, path?: string): string;
5
5
  export declare function transformLoaderFunctions(code: string, moduleId: string): string;
6
- export declare function transformActionsForClient(code: string, moduleId: string): string;
6
+ export declare function transformActionsForClient(code: string, moduleId: string, liveNames?: ReadonlySet<string> | undefined): string;
7
7
  /**
8
8
  * Transforma `export const stream_xxx = createEventStream({...})` no client em
9
9
  * um stub com apenas { __isVeloEventStream: true, __path: "/_event/{moduleId}/{name}" }.
@@ -81,6 +81,16 @@ export declare function declaredChannelNames(code: string): string[] | null;
81
81
  * A missing file yields an empty set, which makes every declaration unknown.
82
82
  */
83
83
  export declare function readChannelMapNames(file: string): Set<string>;
84
+ /**
85
+ * Actions declared live by a module's `liveActions` export — `null` when the
86
+ * module does not declare the convention.
87
+ *
88
+ * The canonical form is the object literal `{ actionName: [channel, …] }` (the
89
+ * key WITHOUT the `action_` prefix, the value an array of channel-name
90
+ * literals); anything else is left alone — the registration guard on the
91
+ * server side is the backstop for runtime-computed declarations.
92
+ */
93
+ export declare function declaredLiveActions(code: string): Record<string, string[]> | null;
84
94
  export interface ModuleTransformOptions {
85
95
  /** Absolute module id (the Vite module id). */
86
96
  id: string;