@nice-code/action 0.0.21 → 0.1.1
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 +410 -0
- package/build/index.js +1148 -749
- package/build/react-query/index.js +170 -45
- package/build/types/ActionDomain/NiceActionDomain.d.ts +18 -46
- package/build/types/ActionDomain/NiceActionDomain.types.d.ts +9 -45
- package/build/types/ActionDomain/NiceActionDomainBase.d.ts +14 -0
- package/build/types/ActionDomain/RootDomain/NiceActionRootDomain.d.ts +22 -0
- package/build/types/ActionDomain/helpers/createRootActionDomain.d.ts +5 -0
- package/build/types/ActionRuntimeEnvironment/ActionConnect/ActionConnect.d.ts +24 -0
- package/build/types/ActionRuntimeEnvironment/ActionConnect/ActionConnect.types.d.ts +15 -0
- package/build/types/ActionRuntimeEnvironment/ActionConnect/ConnectionConfig/ConnectionConfig.d.ts +12 -0
- package/build/types/ActionRuntimeEnvironment/ActionConnect/ConnectionConfig/ConnectionConfig.types.d.ts +6 -0
- package/build/types/ActionRuntimeEnvironment/ActionConnect/Transport/Transport.d.ts +16 -0
- package/build/types/ActionRuntimeEnvironment/ActionConnect/Transport/Transport.types.d.ts +50 -0
- package/build/types/ActionRuntimeEnvironment/ActionConnect/Transport/TransportHttp.d.ts +9 -0
- package/build/types/ActionRuntimeEnvironment/ActionConnect/Transport/TransportWebSocket.d.ts +15 -0
- package/build/types/ActionRuntimeEnvironment/ActionConnect/Transport/err_nice_transport.d.ts +34 -0
- package/build/types/ActionRuntimeEnvironment/ActionConnect/Transport/err_nice_transport_ws.d.ts +18 -0
- package/build/types/ActionRuntimeEnvironment/ActionConnect/err_nice_connect.d.ts +5 -0
- package/build/types/ActionRuntimeEnvironment/ActionHandler/ActionHandler.d.ts +80 -0
- package/build/types/ActionRuntimeEnvironment/ActionHandler/ActionHandler.types.d.ts +68 -0
- package/build/types/ActionRuntimeEnvironment/ActionRuntimeEnvironment.d.ts +32 -0
- package/build/types/ActionRuntimeEnvironment/ActionRuntimeEnvironment.types.d.ts +15 -0
- package/build/types/ActionRuntimeEnvironment/utils/getAssumedRuntimeEnvironment.d.ts +2 -0
- package/build/types/ActionSchema/NiceActionSchema.d.ts +11 -7
- package/build/types/ActionSchema/NiceActionSchema.types.d.ts +1 -1
- package/build/types/NiceAction/MatchAction/MatchAction.d.ts +26 -0
- package/build/types/NiceAction/NiceAction.d.ts +19 -21
- package/build/types/NiceAction/NiceAction.enums.d.ts +5 -0
- package/build/types/NiceAction/NiceAction.types.d.ts +8 -11
- package/build/types/NiceAction/NiceActionCombined.types.d.ts +10 -0
- package/build/types/NiceAction/NiceActionPrimed.d.ts +19 -36
- package/build/types/NiceAction/NiceActionResponse.d.ts +15 -6
- package/build/types/NiceAction/utils/isNiceActionInstance.d.ts +3 -0
- package/build/types/errors/err_nice_action.d.ts +34 -12
- package/build/types/index.d.ts +22 -8
- package/build/types/react-query/index.d.ts +8 -10
- package/package.json +8 -6
- package/build/types/ActionDomain/createActionDomain.d.ts +0 -5
- package/build/types/ActionRequestResponse/ActionRequester/NiceActionRequester.d.ts +0 -31
- package/build/types/ActionRequestResponse/ActionResponder/NiceActionResponder.d.ts +0 -49
- package/build/types/ActionRequestResponse/ActionResponder/NiceActionResponder.types.d.ts +0 -7
- package/build/types/ActionRequestResponse/ActionResponder/NiceActionResponderEnvironment.d.ts +0 -42
- package/build/types/NiceAction/ActionSchema/NiceActionSchema.d.ts +0 -99
- package/build/types/NiceAction/ActionSchema/NiceActionSchema.types.d.ts +0 -31
- package/build/types/NiceAction/ActionSchema/NiceActionSchemaBuilder.d.ts +0 -1
- package/build/types/NiceAction/ActionSchema/action.d.ts +0 -2
- package/build/types/NiceAction/NiceActionPrimed.schema.d.ts +0 -8
- package/build/types/test/nice_action_test_schema.d.ts +0 -30
package/README.md
ADDED
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
# @nice-code/action
|
|
2
|
+
|
|
3
|
+
A fully-typed action-based RPC framework for TypeScript. Define actions once, execute them locally or over HTTP/WebSocket — same code, same types, everywhere.
|
|
4
|
+
|
|
5
|
+
## Why?
|
|
6
|
+
|
|
7
|
+
Modern apps split logic across server, client, and workers. Typed RPC frameworks help, but most still require separate client/server type definitions, custom serialization glue, and ad-hoc error handling. `@nice-code/action` solves this with:
|
|
8
|
+
|
|
9
|
+
- **One definition, every environment** — same action works locally, over HTTP, or WebSocket
|
|
10
|
+
- **Custom serialization baked in** — `Date`, `Map`, `Buffer` — define it once, it works across the wire automatically
|
|
11
|
+
- **Typed error unions** — declare which errors an action throws; TypeScript enforces handling them
|
|
12
|
+
- **Observable** — attach listeners for logging, analytics, or tracing with zero boilerplate
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
bun add @nice-code/action @nice-code/error valibot
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Core Concepts
|
|
25
|
+
|
|
26
|
+
Actions flow through three states:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
NiceAction (definition) → NiceActionPrimed (input attached) → NiceActionResponse (result)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
You mostly work with `NiceAction` and let the framework handle the rest.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
### 1. Define a domain and its actions
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { createActionRootDomain, action } from "@nice-code/action";
|
|
42
|
+
import * as v from "valibot";
|
|
43
|
+
|
|
44
|
+
const root = createActionRootDomain({ domain: "app" });
|
|
45
|
+
|
|
46
|
+
const orderDomain = root.createChildDomain({
|
|
47
|
+
domain: "order",
|
|
48
|
+
actions: {
|
|
49
|
+
placeOrder: action()
|
|
50
|
+
.input({ schema: v.object({ items: v.array(v.string()), total: v.number() }) })
|
|
51
|
+
.output({ schema: v.object({ orderId: v.string(), estimatedDelivery: v.string() }) }),
|
|
52
|
+
|
|
53
|
+
cancelOrder: action()
|
|
54
|
+
.input({ schema: v.object({ orderId: v.string(), reason: v.string() }) })
|
|
55
|
+
.output({ schema: v.object({ refundAmount: v.number() }) }),
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 2. Register handlers
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { ActionHandler, createActionRuntime } from "@nice-code/action";
|
|
64
|
+
|
|
65
|
+
const handler = new ActionHandler()
|
|
66
|
+
.forAction(orderDomain, "placeOrder", {
|
|
67
|
+
execution: async (primed) => {
|
|
68
|
+
const { items, total } = primed.input; // fully typed
|
|
69
|
+
const order = await db.orders.create({ items, total });
|
|
70
|
+
return primed.setResponse({
|
|
71
|
+
orderId: order.id,
|
|
72
|
+
estimatedDelivery: "2-3 business days",
|
|
73
|
+
});
|
|
74
|
+
},
|
|
75
|
+
})
|
|
76
|
+
.forAction(orderDomain, "cancelOrder", {
|
|
77
|
+
execution: async (primed) => {
|
|
78
|
+
const refund = await payments.refund(primed.input.orderId);
|
|
79
|
+
return primed.setResponse({ refundAmount: refund.amount });
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
root.setRuntimeEnvironment(
|
|
84
|
+
createActionRuntime({ envId: "server" }).addHandlers([handler])
|
|
85
|
+
);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 3. Execute
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
const result = await orderDomain.action("placeOrder").execute({
|
|
92
|
+
items: ["SKU-001", "SKU-002"],
|
|
93
|
+
total: 49.99,
|
|
94
|
+
});
|
|
95
|
+
// result: { orderId: "ord_abc123", estimatedDelivery: "2-3 business days" }
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Typed Error Handling
|
|
101
|
+
|
|
102
|
+
Declare errors your action can throw — TypeScript tracks them through `executeSafe()`.
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { err_auth, err_payment } from "@nice-code/common-errors";
|
|
106
|
+
|
|
107
|
+
const checkoutDomain = root.createChildDomain({
|
|
108
|
+
domain: "checkout",
|
|
109
|
+
actions: {
|
|
110
|
+
pay: action()
|
|
111
|
+
.input({ schema: v.object({ cartId: v.string(), cardToken: v.string() }) })
|
|
112
|
+
.output({ schema: v.object({ receiptId: v.string() }) })
|
|
113
|
+
.throws(err_auth, ["unauthenticated"]) // only this error from auth domain
|
|
114
|
+
.throws(err_payment), // all payment errors
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
const result = await checkoutDomain.action("pay").executeSafe({
|
|
121
|
+
cartId: "cart_xyz",
|
|
122
|
+
cardToken: "tok_...",
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
if (!result.ok) {
|
|
126
|
+
// result.error is a fully typed NiceError union
|
|
127
|
+
result.error.handleWithSync([
|
|
128
|
+
forId(err_auth, "unauthenticated", () => res.status(401).json({ error: "Login required" })),
|
|
129
|
+
forId(err_payment, "card_declined", (err) => {
|
|
130
|
+
const { last4 } = err.getContext();
|
|
131
|
+
res.status(402).json({ error: `Card ending in ${last4} was declined` });
|
|
132
|
+
}),
|
|
133
|
+
forDomain(err_payment, () => res.status(402).json({ error: "Payment failed" })),
|
|
134
|
+
]);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// result.output: { receiptId: string }
|
|
139
|
+
res.json({ receiptId: result.output.receiptId });
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Custom Serialization
|
|
145
|
+
|
|
146
|
+
Non-JSON types — `Date`, `Map`, binary — need serialization for transport. Define it once on the schema; the framework handles it on both ends.
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
const eventDomain = root.createChildDomain({
|
|
150
|
+
domain: "event",
|
|
151
|
+
actions: {
|
|
152
|
+
schedule: action()
|
|
153
|
+
.input(
|
|
154
|
+
{ schema: v.object({ name: v.string(), scheduledAt: v.date() }) },
|
|
155
|
+
// serialize: Date → ISO string for the wire
|
|
156
|
+
({ name, scheduledAt }) => ({ name, iso: scheduledAt.toISOString() }),
|
|
157
|
+
// deserialize: ISO string → Date on the other end
|
|
158
|
+
({ name, iso }) => ({ name, scheduledAt: new Date(iso) })
|
|
159
|
+
)
|
|
160
|
+
.output({ schema: v.object({ eventId: v.string() }) }),
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
// Client sends this:
|
|
167
|
+
await eventDomain.action("schedule").execute({
|
|
168
|
+
name: "Team meeting",
|
|
169
|
+
scheduledAt: new Date("2025-03-15T14:00:00Z"), // ← native Date
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// Wire format (what actually travels over HTTP):
|
|
173
|
+
// { name: "Team meeting", iso: "2025-03-15T14:00:00.000Z" }
|
|
174
|
+
|
|
175
|
+
// Server receives native Date automatically — no manual parsing
|
|
176
|
+
handler.forAction(eventDomain, "schedule", {
|
|
177
|
+
execution: async (primed) => {
|
|
178
|
+
console.log(primed.input.scheduledAt instanceof Date); // true
|
|
179
|
+
await calendar.create(primed.input.scheduledAt);
|
|
180
|
+
return primed.setResponse({ eventId: "evt_..." });
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Same Actions, Different Environments
|
|
188
|
+
|
|
189
|
+
The same domain definition works on both server (with handlers) and client (with remote transport). No code duplication.
|
|
190
|
+
|
|
191
|
+
### Server
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
// server.ts
|
|
195
|
+
const handler = new ActionHandler().forDomain(orderDomain, {
|
|
196
|
+
execution: async (primed) => {
|
|
197
|
+
/* ... real DB logic ... */
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
root.setRuntimeEnvironment(
|
|
202
|
+
createActionRuntime({ envId: "server" }).addHandlers([handler])
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
// One endpoint handles all actions
|
|
206
|
+
app.post("/actions", async (req, res) => {
|
|
207
|
+
const result = await handler.handleWire(req.body);
|
|
208
|
+
if (!result.handled) return res.status(404).end();
|
|
209
|
+
res.json(result.response.toJsonObject());
|
|
210
|
+
});
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Client
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
// client.ts — exact same domain, different runtime
|
|
217
|
+
import { ActionConnect, ConnectionConfig, createActionRuntime } from "@nice-code/action";
|
|
218
|
+
|
|
219
|
+
const connect = new ActionConnect(
|
|
220
|
+
[new ConnectionConfig({ transports: [{ type: "http", url: "/actions" }] })],
|
|
221
|
+
{ requestTimeout: 30_000 }
|
|
222
|
+
).routeDomain(orderDomain);
|
|
223
|
+
|
|
224
|
+
root.setRuntimeEnvironment(
|
|
225
|
+
createActionRuntime({ envId: "browser" }).addHandlers([connect])
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
// Works exactly like local execution — goes over HTTP transparently
|
|
229
|
+
const result = await orderDomain.action("placeOrder").execute({
|
|
230
|
+
items: ["SKU-001"],
|
|
231
|
+
total: 29.99,
|
|
232
|
+
});
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### WebSocket for real-time
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
new ConnectionConfig({
|
|
239
|
+
transports: [
|
|
240
|
+
{ type: "ws", url: "wss://api.example.com/ws" }, // persistent connection, no reconnect overhead
|
|
241
|
+
{ type: "http", url: "/actions" }, // fallback
|
|
242
|
+
],
|
|
243
|
+
})
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## Observability
|
|
249
|
+
|
|
250
|
+
Attach listeners to any domain — fire for every action without modifying handlers.
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
const unsubscribe = orderDomain.addActionListener({
|
|
254
|
+
execution: (primed, { runtime }) => {
|
|
255
|
+
logger.info(`[${runtime.name}] → ${primed.domain}::${primed.id}`, primed.input);
|
|
256
|
+
},
|
|
257
|
+
response: (response, { runtime }) => {
|
|
258
|
+
const { result } = response;
|
|
259
|
+
if (result.ok) {
|
|
260
|
+
metrics.increment(`action.success`, { action: response.id });
|
|
261
|
+
} else {
|
|
262
|
+
metrics.increment(`action.error`, { action: response.id, error: result.error.id });
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// Clean up when done
|
|
268
|
+
unsubscribe();
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## Pattern Matching
|
|
274
|
+
|
|
275
|
+
When you receive an action and need to branch on its identity:
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
import { matchAction } from "@nice-code/action";
|
|
279
|
+
|
|
280
|
+
await matchAction(incomingAction)
|
|
281
|
+
.with({
|
|
282
|
+
domain: orderDomain,
|
|
283
|
+
id: "placeOrder",
|
|
284
|
+
handler: async (action) => {
|
|
285
|
+
// action narrowed to NiceAction<OrderDomain, "placeOrder">
|
|
286
|
+
await notifyWarehouse(action.input);
|
|
287
|
+
},
|
|
288
|
+
})
|
|
289
|
+
.with({
|
|
290
|
+
domain: orderDomain,
|
|
291
|
+
id: "cancelOrder",
|
|
292
|
+
handler: async (action) => {
|
|
293
|
+
await notifyCustomer(action.input.orderId);
|
|
294
|
+
},
|
|
295
|
+
})
|
|
296
|
+
.otherwise(async (action) => {
|
|
297
|
+
logger.warn(`Unhandled action: ${action.domain}::${action.id}`);
|
|
298
|
+
})
|
|
299
|
+
.runAsync();
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## Wire Format
|
|
305
|
+
|
|
306
|
+
Every action state serializes to JSON — useful for logging, queuing, or replay:
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
const primed = orderDomain.action("placeOrder").prime({ items: ["SKU-001"], total: 29.99 });
|
|
310
|
+
|
|
311
|
+
const wire = primed.toJsonObject();
|
|
312
|
+
// {
|
|
313
|
+
// type: "primed",
|
|
314
|
+
// domain: "order",
|
|
315
|
+
// allDomains: ["order", "app"],
|
|
316
|
+
// id: "placeOrder",
|
|
317
|
+
// cuid: "abc123...",
|
|
318
|
+
// timeCreated: 1704067200000,
|
|
319
|
+
// timePrimed: 1704067201000,
|
|
320
|
+
// input: { items: ["SKU-001"], total: 29.99 }
|
|
321
|
+
// }
|
|
322
|
+
|
|
323
|
+
// Reconstruct anywhere
|
|
324
|
+
const rehydrated = orderDomain.hydratePrimed(wire);
|
|
325
|
+
await rehydrated.execute(); // executes with original input
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Store actions in a queue, ship them to a worker, execute on the other side — full round-trip with validation.
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## Named Handlers (Tags)
|
|
333
|
+
|
|
334
|
+
Route different action types to different handlers — useful for auth tiers, feature flags, or test overrides.
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
const adminHandler = new ActionHandler({ tag: "admin" })
|
|
338
|
+
.forAction(userDomain, "deleteUser", {
|
|
339
|
+
execution: async (primed) => { /* admin-only logic */ },
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
const publicHandler = new ActionHandler()
|
|
343
|
+
.forDomain(userDomain, { execution: handlePublicActions });
|
|
344
|
+
|
|
345
|
+
root.setRuntimeEnvironment(
|
|
346
|
+
createActionRuntime({ envId: "server" })
|
|
347
|
+
.addHandlers([adminHandler, publicHandler])
|
|
348
|
+
);
|
|
349
|
+
|
|
350
|
+
// Use the tagged handler explicitly
|
|
351
|
+
await userDomain.action("deleteUser").execute(input, { tag: "admin" });
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## API Reference
|
|
357
|
+
|
|
358
|
+
### Domain
|
|
359
|
+
|
|
360
|
+
| Method | Description |
|
|
361
|
+
|---|---|
|
|
362
|
+
| `createActionRootDomain({ domain })` | Create root domain |
|
|
363
|
+
| `root.createChildDomain({ domain, actions })` | Create child domain |
|
|
364
|
+
| `domain.action(id)` | Get action definition |
|
|
365
|
+
| `domain.addActionListener({ execution?, response? })` | Observe all actions; returns unsubscribe fn |
|
|
366
|
+
| `domain.hydratePrimed(wire)` | Reconstruct primed action from JSON |
|
|
367
|
+
| `domain.hydrateResponse(wire)` | Reconstruct response from JSON |
|
|
368
|
+
|
|
369
|
+
### Action
|
|
370
|
+
|
|
371
|
+
| Method | Description |
|
|
372
|
+
|---|---|
|
|
373
|
+
| `action.execute(input, meta?)` | Execute; throws on error |
|
|
374
|
+
| `action.executeSafe(input, meta?)` | Execute; returns `{ ok, output }` or `{ ok, error }` |
|
|
375
|
+
| `action.prime(input)` | Attach and validate input |
|
|
376
|
+
| `action.is(other)` | Type guard — check if action matches this definition |
|
|
377
|
+
|
|
378
|
+
### Schema Builder (`action()`)
|
|
379
|
+
|
|
380
|
+
| Method | Description |
|
|
381
|
+
|---|---|
|
|
382
|
+
| `.input({ schema }, serialize?, deserialize?)` | Declare input schema + optional serde |
|
|
383
|
+
| `.output({ schema }, serialize?, deserialize?)` | Declare output schema + optional serde |
|
|
384
|
+
| `.throws(errorDomain, [ids]?)` | Declare throwable errors (all or subset) |
|
|
385
|
+
|
|
386
|
+
### Handlers
|
|
387
|
+
|
|
388
|
+
| Class | Use case |
|
|
389
|
+
|---|---|
|
|
390
|
+
| `ActionHandler` | Local/same-process execution |
|
|
391
|
+
| `ActionConnect` | Remote execution over HTTP or WebSocket |
|
|
392
|
+
|
|
393
|
+
### ActionHandler
|
|
394
|
+
|
|
395
|
+
| Method | Description |
|
|
396
|
+
|---|---|
|
|
397
|
+
| `.forAction(domain, id, { execution, response? })` | Handle one action |
|
|
398
|
+
| `.forActionIds(domain, ids, { execution, response? })` | Handle a subset |
|
|
399
|
+
| `.forDomain(domain, { execution, response? })` | Handle all actions in domain |
|
|
400
|
+
| `.forDomainActionCases(domain, cases)` | Handle actions via case map |
|
|
401
|
+
| `.handleWire(body)` | Parse and dispatch raw JSON (for HTTP endpoints) |
|
|
402
|
+
|
|
403
|
+
### ActionConnect
|
|
404
|
+
|
|
405
|
+
| Method | Description |
|
|
406
|
+
|---|---|
|
|
407
|
+
| `.routeDomain(domain, route?)` | Route all domain actions remotely |
|
|
408
|
+
| `.routeAction(domain, id, route?)` | Route one action remotely |
|
|
409
|
+
| `.routeActionIds(domain, ids, route?)` | Route a subset remotely |
|
|
410
|
+
| `.disconnect()` | Close connections |
|