9 Commits

Author SHA1 Message Date
2b72289635 fix: split deadline/idleTimeout semantics in call protocol (M-03) 2026-05-16 11:18:29 +00:00
92936f4232 feat: implement ADR-007 subscription transport — PendingRequestMap.subscribe(), CallHandler dispatch, SSE AsyncGenerator handlers
Add remote subscription support so spokes can consume streaming operations
over pubsub transports (WebSocket, Redis). Extract checkAccess to access.ts
to break circular dep between call.ts and subscribe.ts.
2026-05-16 06:03:21 +00:00
95d9b95d13 feat(unified-callhandler): simplify CallHandler to delegate to registry.execute()
- Remove separate spec lookup, handler lookup, access control, and input validation from buildCallHandler
- Call registry.execute() directly; access control enforced via execute() (trusted not set)
- On error, look up spec for errorSchemas and pass to mapError()
- Make callMap required in CallHandlerConfig (no longer optional)
- Update tests: remove no-callMap tests, use callMap for all handler tests
- Add test for mapError with spec errorSchemas
- All 226 tests passing
2026-05-11 03:19:26 +00:00
e138866fcd feat(unified-execute): implement ADR-006 unified invocation path with access control
- Add access control to registry.execute(): checks requiredScopes, requiredScopesAny,
  and resourceType/resourceAction; rejects with ACCESS_DENIED when identity required
  but absent; skips when context.trusted is true
- Add trusted field to OperationContext schema (internal, set by buildEnv for
  nested calls to skip redundant scope checks)
- Simplify CallHandler to thin adapter: delegates to registry.execute() instead of
  duplicating lookup, validation, and access control
- Remove callMap option from buildEnv(): always uses execute(), propagates context
  with trusted: true for nested calls
- Add access control to subscribe(): same default-deny logic as execute()
- Change execute() to throw CallError instead of plain Error for not found,
  no handler, and validation errors
- Export checkAccess from call.ts and index.ts for external use
- Remove CallMap type export, update EnvOptions
- Update architecture docs: api-surface.md, call-protocol.md,
  ADR-006 status to implemented, source vs spec drift sections
- All 228 tests passing
2026-05-11 03:04:19 +00:00
b63c5ce3de Merge registry-envelope-integration into main (resolve conflicts with call-envelope-integration) 2026-05-11 02:23:52 +00:00
3150a49578 feat(registry-envelope-integration): update execute(), call, subscribe, env to return ResponseEnvelope
- OperationRegistry.execute() now returns Promise<ResponseEnvelope<TOutput>>
- Applies shared result pipeline: detect → wrap → normalize → validate
- Uses KindGuard.IsUnknown() to check if Value.Cast should be applied
- PendingRequestMap.call() returns Promise<ResponseEnvelope>
- PendingRequestMap.respond() validates envelope via isResponseEnvelope()
- CallHandler captures handler result, wraps, normalizes, validates, publishes
- CallEventSchema call.responded.output changed to ResponseEnvelopeSchema
- subscribe() yields ResponseEnvelope with isResponseEnvelope() passthrough
- OperationEnv inner functions return Promise<ResponseEnvelope>
- Tests updated for all new return types and behaviors
- 171 tests passing, build and lint clean
2026-05-11 02:19:05 +00:00
bf6d07938c feat(call-envelope-integration): integrate ResponseEnvelope into call protocol
- CallEventSchema['call.responded'].output changed from Type.Unknown() to ResponseEnvelopeSchema
- PendingRequestMap.respond() now validates output with isResponseEnvelope(), throws on raw values
- PendingRequestMap.call() return type changed from Promise<unknown> to Promise<ResponseEnvelope>
- CallHandler captures handler return value instead of discarding it
- CallHandler applies result pipeline: detect envelope → wrap with localEnvelope → normalize with Value.Cast → validate with collectErrors
- CallHandler publishes call.responded via callMap.respond() with the envelope
- CallHandler publishes call.error via callMap.emitError() when callMap is provided (instead of re-throwing)
- CallHandlerConfig changed from eventTarget? to callMap? (PendingRequestMap)
- Adapter handlers pass through via isResponseEnvelope() detection (mcpEnvelope/httpEnvelope)
- All 189 tests passing, including 23 new tests for envelope behavior
2026-05-11 02:14:01 +00:00
ac28c9308c fix(checkAccess): deny access when resourceType set but identity.resources undefined
The resource access check in checkAccess() was bypassed when identity.resources
was undefined because the condition  evaluated to false, falling through to .

Changed to  with an explicit
 check inside the block, implementing
default-deny semantics per ADR-006.

Added 7 test cases covering:
- undefined resources with resourceType set (denied)
- empty resources with resourceType set (denied)
- non-matching resource type (denied)
- matching type but wrong action (denied)
- matching type and action (granted)
- no resourceType/resourceAction set (granted)
- matching resources with extra scopes (granted)
2026-05-11 01:50:12 +00:00
29f0dd7af0 Initial package implementation: operations registry, call protocol, and adapters
Extracted from alkhub_ts packages/core/operations/ and packages/core/mcp/.
- Runtime-agnostic (injected fs/env deps, no Deno globals)
- Direct @logtape/logtape import instead of logger wrapper
- PendingRequestMap with pubsub-wired call protocol
- Peer-dep isolation for MCP adapter (sub-path export)
- Schema const naming convention (XSchema + X type alias)
- 68 tests passing, build + lint + test all green
2026-04-30 12:34:26 +00:00