@rotorsoft/act-http 1.2.0 → 1.3.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.
Files changed (60) hide show
  1. package/README.md +44 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/@types/api/errors.d.ts.map +1 -1
  4. package/dist/@types/receiver/start.d.ts +1 -1
  5. package/dist/@types/sse/apply-patch.d.ts +3 -3
  6. package/dist/@types/sse/broadcast.d.ts +6 -6
  7. package/dist/@types/sse/broadcast.d.ts.map +1 -1
  8. package/dist/@types/sse/presence.d.ts +7 -7
  9. package/dist/@types/sse/presence.d.ts.map +1 -1
  10. package/dist/@types/trpc/index.d.ts +168 -0
  11. package/dist/@types/trpc/index.d.ts.map +1 -0
  12. package/dist/@types/webhook/classify.d.ts +6 -6
  13. package/dist/@types/webhook/classify.d.ts.map +1 -1
  14. package/dist/@types/webhook/index.d.ts +1 -1
  15. package/dist/@types/webhook/index.d.ts.map +1 -1
  16. package/dist/@types/webhook/sign.d.ts +1 -1
  17. package/dist/@types/webhook/sign.d.ts.map +1 -1
  18. package/dist/api/index.cjs +2 -2
  19. package/dist/api/index.cjs.map +1 -1
  20. package/dist/api/index.js +4 -55
  21. package/dist/api/index.js.map +1 -1
  22. package/dist/{chunk-NOIXOF2I.js → chunk-4CGAUB5H.js} +13 -13
  23. package/dist/chunk-4CGAUB5H.js.map +1 -0
  24. package/dist/{chunk-F7VWYZ37.js → chunk-K4HAOBRF.js} +4 -4
  25. package/dist/{chunk-F7VWYZ37.js.map → chunk-K4HAOBRF.js.map} +1 -1
  26. package/dist/chunk-Z6FVXDDU.js +63 -0
  27. package/dist/chunk-Z6FVXDDU.js.map +1 -0
  28. package/dist/receiver/express/index.cjs +14 -14
  29. package/dist/receiver/express/index.cjs.map +1 -1
  30. package/dist/receiver/express/index.js +3 -3
  31. package/dist/receiver/express/index.js.map +1 -1
  32. package/dist/receiver/fastify/index.cjs +12 -12
  33. package/dist/receiver/fastify/index.cjs.map +1 -1
  34. package/dist/receiver/fastify/index.js +1 -1
  35. package/dist/receiver/hono/index.cjs +14 -14
  36. package/dist/receiver/hono/index.cjs.map +1 -1
  37. package/dist/receiver/hono/index.js +2 -2
  38. package/dist/receiver/index.cjs +19 -2746
  39. package/dist/receiver/index.cjs.map +1 -1
  40. package/dist/receiver/index.js +5 -2077
  41. package/dist/receiver/index.js.map +1 -1
  42. package/dist/receiver/trpc/index.cjs +12 -12
  43. package/dist/receiver/trpc/index.cjs.map +1 -1
  44. package/dist/receiver/trpc/index.js +1 -1
  45. package/dist/sse/index.cjs +21 -21
  46. package/dist/sse/index.cjs.map +1 -1
  47. package/dist/sse/index.js +24 -24
  48. package/dist/sse/index.js.map +1 -1
  49. package/dist/trpc/index.cjs +169 -0
  50. package/dist/trpc/index.cjs.map +1 -0
  51. package/dist/trpc/index.js +95 -0
  52. package/dist/trpc/index.js.map +1 -0
  53. package/dist/webhook/index.cjs +14 -34
  54. package/dist/webhook/index.cjs.map +1 -1
  55. package/dist/webhook/index.js +14 -32
  56. package/dist/webhook/index.js.map +1 -1
  57. package/package.json +52 -30
  58. package/dist/chunk-NOIXOF2I.js.map +0 -1
  59. package/dist/dist-NWMJQI4E.js +0 -647
  60. package/dist/dist-NWMJQI4E.js.map +0 -1
package/README.md CHANGED
@@ -135,6 +135,42 @@ On failure: the adapter responds with the framework's idiomatic 400 (`missing-ke
135
135
 
136
136
  The framework-agnostic core (`checkWebhook`) and the underlying primitives (`extractIdempotencyKey`, `verifyWebhook`) are exported from `@rotorsoft/act-http/receiver` for receivers whose framework isn't in the adapter list (Koa, raw Node `http`, gRPC-over-HTTP, …) or for receivers with custom policy (e.g. "missing key falls back to body-derived dedup"). Use the `receiver` builder when you can; fall back to the framework `webhookMiddleware`, then the primitives.
137
137
 
138
+ ### `trpc` — auto-generated tRPC router
139
+
140
+ ```ts
141
+ import { trpc } from "@rotorsoft/act-http/trpc";
142
+ import { initTRPC } from "@trpc/server";
143
+ import { createHTTPServer } from "@trpc/server/adapters/standalone";
144
+
145
+ const router = trpc(app, {
146
+ // ActorExtractor from `@rotorsoft/act-http/api` — host's auth seam.
147
+ actor: (ctx) => ({ id: ctx.user.id, name: ctx.user.name }),
148
+ // Resolve the target stream per call; singleton aggregates return a constant.
149
+ stream: (action, input, ctx) => `tenant-${ctx.tenant}`,
150
+ // Optional optimistic concurrency — return `undefined` to skip the check.
151
+ expectedVersion: (action, input, ctx) => readIfMatchHeader(ctx),
152
+ });
153
+
154
+ createHTTPServer({ router }).listen(4000);
155
+
156
+ // Client (same types, no codegen):
157
+ // await client.OpenTicket.mutate({ title: "support" });
158
+ ```
159
+
160
+ The generator walks `app.registry.actions` once and emits a flat top-level mutation per action. The internal `authenticated(extractor)` middleware runs `options.actor` once per call and injects the resolved `Actor` onto `ctx.actor`, so any procedure logic downstream of the chain sees the same actor. `actor` and `stream` are required; `idempotency` is optional — when configured, the mutation reads `Idempotency-Key` via `keyFrom(ctx)` and throws `CONFLICT` on duplicate claims (the contract intentionally doesn't cache original results, matching the receiver-side "ack the duplicate" semantics).
161
+
162
+ Errors map through the shared `toApiError(...)` table at `@rotorsoft/act-http/api`: `ConcurrencyError` → `CONFLICT`, `InvariantError` → `CONFLICT`, `ValidationError` → `UNPROCESSABLE_CONTENT`, `StreamClosedError` → `PRECONDITION_FAILED`, `NonRetryableError` → `BAD_REQUEST`, anything else → `INTERNAL_SERVER_ERROR`. The same envelope flows from every transport sibling so a client speaking two of them never sees two shapes for the same framework error.
163
+
164
+ ```ts
165
+ // Compose the auth middleware into your own procedure chain instead:
166
+ import { authenticated } from "@rotorsoft/act-http/trpc";
167
+
168
+ const t = initTRPC.context<MyCtx>().create();
169
+ const authed = t.procedure.use(authenticated(myExtractor));
170
+ // `authed` carries `ctx.actor: Actor` downstream — use it for hand-written
171
+ // procedures alongside the generated ones.
172
+ ```
173
+
138
174
  ### `sse` — live state broadcast
139
175
 
140
176
  ```ts
@@ -200,6 +236,14 @@ Shared utilities consumed by every transport in the auto-generated API umbrella
200
236
  - **`withIdempotency(store, key, handler)`** — wraps an action handler in an `Idempotency-Key` claim. Reuses `@rotorsoft/act-ops/idempotency` — same contract `@rotorsoft/act-http/receiver` already speaks, so one `IdempotencyStore` covers both halves of the "Act over the wire" surface. Returns `{ deduped: false, result }` on fresh claim, `{ deduped: true }` on duplicate (handler is not called).
201
237
  - **Types**: `IdempotencyResult<T>`, `ErrorMapEntry`.
202
238
 
239
+ ### `/trpc` subpath
240
+
241
+ Auto-generated tRPC router for the act-http-api epic (#835).
242
+
243
+ - **`trpc(app, options) → Router`** — generator function. Walks `app.registry.actions` once and emits a flat top-level mutation per action. Each procedure runs the internal `authenticated(options.actor)` middleware (so `ctx.actor: Actor` is set on the downstream context), resolves the target stream via `options.stream(action, input, ctx)`, and calls `app.do(action, { stream, actor }, input)`. Known framework errors map through `toApiError` to the conventional tRPC codes; unknown throws surface as `INTERNAL_SERVER_ERROR`.
244
+ - **`authenticated(extractor) → middleware`** — standalone export of the auth middleware the generator uses internally. Hosts composing their own procedure chain (logging + tracing + custom auth flavors) use `t.procedure.use(authenticated(extractor))` to inject `ctx.actor` without going through the generator. The middleware is structurally-typed so any host `t` instance accepts it.
245
+ - **`TrpcOptions<Ctx>`** — `{ actor, stream, expectedVersion?, idempotency? }`. `actor` is the `ActorExtractor` from `@rotorsoft/act-http/api`. `stream` returns the target stream per call. `expectedVersion` is optional — `(action, input, ctx) => number | undefined` — when set, the procedure threads the resolved value through `Target.expectedVersion` so `app.do` enforces optimistic concurrency; hosts typically read it from an `If-Match` header or the client's last-known snapshot, and returning `undefined` skips the check for that call. `idempotency` is optional — `{ store: IdempotencyStore; keyFrom: (ctx) => string | undefined }` — when set, the procedure honors `Idempotency-Key` via `withIdempotency`. Duplicate claims throw `CONFLICT` (the contract intentionally doesn't cache the original handler's result).
246
+
203
247
  ### `/sse` subpath
204
248
 
205
249
  - **`BroadcastChannel<S>`** — server-side broadcast manager with per-stream subscriber sets and an LRU state cache.