opinionated-machine 6.14.0 → 6.16.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 (51) hide show
  1. package/README.md +196 -0
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.js +1 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/DIContext.d.ts +2 -0
  6. package/dist/lib/DIContext.js +34 -20
  7. package/dist/lib/DIContext.js.map +1 -1
  8. package/dist/lib/api-contracts/AbstractApiController.d.ts +19 -0
  9. package/dist/lib/api-contracts/AbstractApiController.js +18 -0
  10. package/dist/lib/api-contracts/AbstractApiController.js.map +1 -0
  11. package/dist/lib/api-contracts/apiHandlerTypes.d.ts +116 -0
  12. package/dist/lib/api-contracts/apiHandlerTypes.js +2 -0
  13. package/dist/lib/api-contracts/apiHandlerTypes.js.map +1 -0
  14. package/dist/lib/api-contracts/apiRouteBuilder.d.ts +9 -0
  15. package/dist/lib/api-contracts/apiRouteBuilder.js +344 -0
  16. package/dist/lib/api-contracts/apiRouteBuilder.js.map +1 -0
  17. package/dist/lib/api-contracts/asApiControllerClass.d.ts +24 -0
  18. package/dist/lib/api-contracts/asApiControllerClass.js +27 -0
  19. package/dist/lib/api-contracts/asApiControllerClass.js.map +1 -0
  20. package/dist/lib/api-contracts/index.d.ts +4 -0
  21. package/dist/lib/api-contracts/index.js +4 -0
  22. package/dist/lib/api-contracts/index.js.map +1 -0
  23. package/dist/lib/sse/AbstractSSEController.js +4 -3
  24. package/dist/lib/sse/AbstractSSEController.js.map +1 -1
  25. package/dist/lib/sse/index.d.ts +2 -1
  26. package/dist/lib/sse/index.js +2 -0
  27. package/dist/lib/sse/index.js.map +1 -1
  28. package/dist/lib/sse/rooms/SSERoomBroadcaster.d.ts +20 -4
  29. package/dist/lib/sse/rooms/SSERoomBroadcaster.js +44 -12
  30. package/dist/lib/sse/rooms/SSERoomBroadcaster.js.map +1 -1
  31. package/dist/lib/sse/rooms/SSERoomManager.d.ts +5 -2
  32. package/dist/lib/sse/rooms/SSERoomManager.js +8 -5
  33. package/dist/lib/sse/rooms/SSERoomManager.js.map +1 -1
  34. package/dist/lib/sse/rooms/adapters/InMemoryAdapter.d.ts +1 -1
  35. package/dist/lib/sse/rooms/adapters/InMemoryAdapter.js +1 -1
  36. package/dist/lib/sse/rooms/adapters/InMemoryAdapter.js.map +1 -1
  37. package/dist/lib/sse/rooms/index.d.ts +1 -1
  38. package/dist/lib/sse/rooms/types.d.ts +34 -2
  39. package/dist/lib/sse/subscriptions/SSESubscriptionManager.d.ts +47 -0
  40. package/dist/lib/sse/subscriptions/SSESubscriptionManager.js +298 -0
  41. package/dist/lib/sse/subscriptions/SSESubscriptionManager.js.map +1 -0
  42. package/dist/lib/sse/subscriptions/defineEventMetadata.d.ts +50 -0
  43. package/dist/lib/sse/subscriptions/defineEventMetadata.js +44 -0
  44. package/dist/lib/sse/subscriptions/defineEventMetadata.js.map +1 -0
  45. package/dist/lib/sse/subscriptions/index.d.ts +3 -0
  46. package/dist/lib/sse/subscriptions/index.js +3 -0
  47. package/dist/lib/sse/subscriptions/index.js.map +1 -0
  48. package/dist/lib/sse/subscriptions/types.d.ts +141 -0
  49. package/dist/lib/sse/subscriptions/types.js +2 -0
  50. package/dist/lib/sse/subscriptions/types.js.map +1 -0
  51. package/package.json +1 -1
package/README.md CHANGED
@@ -58,6 +58,17 @@ Very opinionated DI framework for fastify, built on top of awilix
58
58
  - [Room Query Methods](#room-query-methods)
59
59
  - [Auto-Leave on Disconnect](#auto-leave-on-disconnect)
60
60
  - [Multi-Node Deployments with Redis](#multi-node-deployments-with-redis)
61
+ - [SSE Subscriptions](#sse-subscriptions)
62
+ - [Defining Event Metadata](#defining-event-metadata)
63
+ - [Defining Resolvers](#defining-resolvers)
64
+ - [Configuring the Manager](#configuring-the-manager)
65
+ - [Integrating with a Controller](#integrating-with-a-controller)
66
+ - [Publishing Events](#publishing-events)
67
+ - [Refreshing Preferences Mid-Connection](#refreshing-preferences-mid-connection)
68
+ - [Pipeline Semantics](#pipeline-semantics)
69
+ - [Multi-Node Support](#multi-node-support)
70
+ - [Data Loading with layered-loader](#data-loading-with-layered-loader)
71
+ - [Testing](#testing)
61
72
  - [SSE Test Utilities](#sse-test-utilities)
62
73
  - [Quick Reference](#quick-reference)
63
74
  - [Inject vs HTTP Comparison](#inject-vs-http-comparison)
@@ -1803,6 +1814,191 @@ The Redis adapter uses Pub/Sub for cross-node message propagation. When you call
1803
1814
 
1804
1815
  See the [@opinionated-machine/sse-rooms-redis](./packages/sse-rooms-redis/README.md) package for detailed documentation on Redis adapter configuration and usage.
1805
1816
 
1817
+ ### SSE Subscriptions
1818
+
1819
+ SSE Subscriptions add user-centered event filtering on top of SSE Rooms. Users connect once to a universal stream, and a **resolver pipeline** determines which events reach them based on membership, preferences, and arbitrary business rules.
1820
+
1821
+ #### Defining Event Metadata
1822
+
1823
+ Define a discriminated union describing all event scopes, then create type-safe guards with `defineEventMetadata()`:
1824
+
1825
+ ```typescript
1826
+ import { defineEventMetadata } from 'opinionated-machine'
1827
+
1828
+ type EventMetadata =
1829
+ | { scope: 'project'; projectId: string }
1830
+ | { scope: 'team'; teamId: string }
1831
+ | { scope: 'global' }
1832
+
1833
+ const meta = defineEventMetadata<EventMetadata>()('scope', ['project', 'team', 'global'])
1834
+
1835
+ // In resolvers, guards narrow the type:
1836
+ if (meta.project(event.metadata)) {
1837
+ event.metadata.projectId // TypeScript knows this is string
1838
+ }
1839
+ ```
1840
+
1841
+ #### Defining Resolvers
1842
+
1843
+ Resolvers are stateless filters evaluated in pipeline order. Each resolver can `allow`, `deny`, or `defer`:
1844
+
1845
+ ```typescript
1846
+ import type { SubscriptionResolver, SubscriptionContext, FilterVerdict } from 'opinionated-machine'
1847
+
1848
+ class ProjectMembershipResolver {
1849
+ readonly name = 'project-membership'
1850
+
1851
+ async onConnect(ctx: SubscriptionContext<UserCtx>) {
1852
+ const memberships = await this.membershipLoader.get(ctx.userContext.userId)
1853
+ const projectIds = new Set(memberships.map(m => m.projectId))
1854
+ return {
1855
+ userContext: { ...ctx.userContext, projectIds },
1856
+ rooms: Array.from(projectIds).map(id => `project:${id}`),
1857
+ }
1858
+ }
1859
+
1860
+ evaluate(ctx: SubscriptionContext<UserCtx>, event: IncomingEvent<EventMetadata>): FilterVerdict {
1861
+ if (meta.project(event.metadata)) {
1862
+ return ctx.userContext.projectIds.has(event.metadata.projectId)
1863
+ ? { action: 'allow' }
1864
+ : { action: 'deny', reason: 'not a project member' }
1865
+ }
1866
+ return { action: 'defer' }
1867
+ }
1868
+
1869
+ async refresh(ctx: SubscriptionContext<UserCtx>) {
1870
+ // Re-fetch memberships on demand
1871
+ const memberships = await this.membershipLoader.get(ctx.userContext.userId)
1872
+ const projectIds = new Set(memberships.map(m => m.projectId))
1873
+ return {
1874
+ userContext: { ...ctx.userContext, projectIds },
1875
+ rooms: Array.from(projectIds).map(id => `project:${id}`),
1876
+ }
1877
+ }
1878
+ }
1879
+ ```
1880
+
1881
+ #### Configuring the Manager
1882
+
1883
+ ```typescript
1884
+ import { SSESubscriptionManager } from 'opinionated-machine'
1885
+
1886
+ const subscriptionManager = new SSESubscriptionManager<UserCtx, EventMetadata>(
1887
+ {
1888
+ resolveUserContext: async (request) => ({
1889
+ userId: request.user.id,
1890
+ projectIds: new Set(),
1891
+ mutedEventTypes: new Set(),
1892
+ }),
1893
+ resolvers: [
1894
+ new ProjectMembershipResolver(membershipLoader),
1895
+ new MutePreferencesResolver(prefsLoader),
1896
+ ],
1897
+ defaultPolicy: 'deny',
1898
+ resolveUserId: (ctx) => ctx.userId,
1899
+ },
1900
+ { sseRoomManager, sseRoomBroadcaster },
1901
+ )
1902
+ ```
1903
+
1904
+ #### Integrating with a Controller
1905
+
1906
+ Wire `handleConnect` and `handleDisconnect` into the SSE session lifecycle:
1907
+
1908
+ ```typescript
1909
+ class NotificationController extends AbstractSSEController<Contracts> {
1910
+ private handleStream = buildHandler(contract, {
1911
+ sse: (request, sse) => {
1912
+ const session = sse.start('keepAlive')
1913
+ this.subscriptionManager.handleConnect(session).catch(() => {
1914
+ // Handle connection setup failure (e.g., resolver threw)
1915
+ })
1916
+ },
1917
+ }, {
1918
+ onClose: (session) => {
1919
+ this.subscriptionManager.handleDisconnect(session)
1920
+ },
1921
+ })
1922
+ }
1923
+ ```
1924
+
1925
+ #### Publishing Events
1926
+
1927
+ ```typescript
1928
+ const result = await subscriptionManager.publish({
1929
+ eventName: 'announcement',
1930
+ data: { message: 'New feature released!' },
1931
+ targetRooms: ['project:123'],
1932
+ metadata: { scope: 'project', projectId: '123' },
1933
+ })
1934
+ // result: { delivered: 5, filtered: 2 }
1935
+ ```
1936
+
1937
+ `targetRooms` controls routing:
1938
+ - **Specific rooms** (`['project:123']`) — broadcast to those rooms, filter via resolver pipeline
1939
+ - **`undefined`** (omitted) — broadcast to all rooms of all managed connections
1940
+ - **Empty array** (`[]`) — no-op, returns `{ delivered: 0, filtered: 0 }`
1941
+
1942
+ #### Refreshing Preferences Mid-Connection
1943
+
1944
+ When a user updates preferences (e.g., mutes an event type), refresh their active connections:
1945
+
1946
+ ```typescript
1947
+ // In your REST endpoint handler:
1948
+ await prefsLoader.invalidateCacheFor(userId)
1949
+ await subscriptionManager.refreshUser(userId)
1950
+ ```
1951
+
1952
+ The manager diffs rooms and joins/leaves as needed — no reconnection required.
1953
+
1954
+ #### Pipeline Semantics
1955
+
1956
+ - Resolvers are evaluated in array order
1957
+ - First `deny` short-circuits — event is not delivered
1958
+ - `allow` does not short-circuit — subsequent resolvers can still deny
1959
+ - If all resolvers return `defer`, `defaultPolicy` applies (default: `deny`)
1960
+ - Resolver `evaluate()` errors are treated as `deny`
1961
+ - Resolver `refresh()` errors are caught per-resolver — the failed resolver keeps its previous state while remaining resolvers continue refreshing
1962
+ - Later resolvers in the array receive the accumulated `userContext` from earlier resolvers — use spread (`{ ...ctx.userContext, ...newFields }`) to preserve prior resolver data
1963
+ - `defaultPolicy` defaults to `'deny'` when not specified
1964
+
1965
+ #### Multi-Node Support
1966
+
1967
+ - Metadata flows through the adapter chain (Redis pub/sub) alongside the SSE message
1968
+ - Resolver pipeline runs locally on each node for its own connections
1969
+ - Wire format is a single v1 schema with optional `meta` — older nodes simply have no metadata
1970
+ - Use `layered-loader` for distributed cache invalidation across nodes
1971
+
1972
+ #### Data Loading with layered-loader
1973
+
1974
+ `layered-loader` is recommended (not required) for resolver data loading. It provides in-memory → Redis → DB caching with TTL, refresh-ahead, and distributed invalidation:
1975
+
1976
+ ```typescript
1977
+ import { Loader } from 'layered-loader'
1978
+
1979
+ const membershipLoader = new Loader<ProjectMembership[]>({
1980
+ inMemoryCache: { cacheType: 'lru-map', ttlInMsecs: 120_000, maxItems: 500 },
1981
+ asyncCache: new RedisCache(redis, { json: true, ttlInMsecs: 900_000 }),
1982
+ dataSources: [membershipDataSource],
1983
+ })
1984
+ ```
1985
+
1986
+ #### Testing
1987
+
1988
+ Create mock resolvers for unit tests:
1989
+
1990
+ ```typescript
1991
+ const mockResolver = {
1992
+ name: 'mock',
1993
+ evaluate: vi.fn().mockReturnValue({ action: 'allow' }),
1994
+ }
1995
+
1996
+ const manager = new SSESubscriptionManager(
1997
+ { resolveUserContext: async () => mockContext, resolvers: [mockResolver] },
1998
+ { sseRoomManager, sseRoomBroadcaster },
1999
+ )
2000
+ ```
2001
+
1806
2002
  ### SSE Test Utilities
1807
2003
 
1808
2004
  The library provides utilities for testing SSE endpoints.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { AbstractController, type BuildRoutesReturnType } from './lib/AbstractController.js';
2
2
  export { AbstractModule, type InferModuleDependencies, type InferPublicModuleDependencies, type MandatoryNameAndRegistrationPair, type PublicDependencies, } from './lib/AbstractModule.js';
3
3
  export { AbstractTestContextFactory, type CreateTestContextParams, } from './lib/AbstractTestContextFactory.js';
4
+ export * from './lib/api-contracts/index.js';
4
5
  export type { NestedPartial } from './lib/configUtils.js';
5
6
  export { type DependencyInjectionOptions, DIContext, type RegisterDependenciesParams, } from './lib/DIContext.js';
6
7
  export { ENABLE_ALL, isAnyMessageQueueConsumerEnabled, isEnqueuedJobWorkersEnabled, isJobQueueEnabled, isMessageQueueConsumerEnabled, isPeriodicJobEnabled, resolveJobQueuesEnabled, } from './lib/diConfigUtils.js';
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export { AbstractController } from './lib/AbstractController.js';
2
2
  export { AbstractModule, } from './lib/AbstractModule.js';
3
3
  export { AbstractTestContextFactory, } from './lib/AbstractTestContextFactory.js';
4
+ export * from './lib/api-contracts/index.js';
4
5
  export { DIContext, } from './lib/DIContext.js';
5
6
  export { ENABLE_ALL, isAnyMessageQueueConsumerEnabled, isEnqueuedJobWorkersEnabled, isJobQueueEnabled, isMessageQueueConsumerEnabled, isPeriodicJobEnabled, resolveJobQueuesEnabled, } from './lib/diConfigUtils.js';
6
7
  // Dual-mode (SSE + JSON)
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAA8B,MAAM,6BAA6B,CAAA;AAC5F,OAAO,EACL,cAAc,GAKf,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACL,0BAA0B,GAE3B,MAAM,qCAAqC,CAAA;AAE5C,OAAO,EAEL,SAAS,GAEV,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACL,UAAU,EACV,gCAAgC,EAChC,2BAA2B,EAC3B,iBAAiB,EACjB,6BAA6B,EAC7B,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,wBAAwB,CAAA;AAC/B,yBAAyB;AACzB,cAAc,yBAAyB,CAAA;AACvC,cAAc,4BAA4B,CAAA;AAC1C,iCAAiC;AACjC,cAAc,uBAAuB,CAAA;AACrC,MAAM;AACN,cAAc,oBAAoB,CAAA;AAClC,wBAAwB;AACxB,cAAc,wBAAwB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAA8B,MAAM,6BAA6B,CAAA;AAC5F,OAAO,EACL,cAAc,GAKf,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACL,0BAA0B,GAE3B,MAAM,qCAAqC,CAAA;AAC5C,cAAc,8BAA8B,CAAA;AAE5C,OAAO,EAEL,SAAS,GAEV,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACL,UAAU,EACV,gCAAgC,EAChC,2BAA2B,EAC3B,iBAAiB,EACjB,6BAA6B,EAC7B,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,wBAAwB,CAAA;AAC/B,yBAAyB;AACzB,cAAc,yBAAyB,CAAA;AACvC,cAAc,4BAA4B,CAAA;AAC1C,iCAAiC;AACjC,cAAc,uBAAuB,CAAA;AACrC,MAAM;AACN,cAAc,oBAAoB,CAAA;AAClC,wBAAwB;AACxB,cAAc,wBAAwB,CAAA"}
@@ -31,8 +31,10 @@ export declare class DIContext<Dependencies extends object, Config extends objec
31
31
  private readonly controllerResolvers;
32
32
  private readonly sseControllerNames;
33
33
  private readonly dualModeControllerNames;
34
+ private readonly apiControllerNames;
34
35
  private readonly appConfig;
35
36
  constructor(diContainer: AwilixContainer<Dependencies>, options: DependencyInjectionOptions, appConfig: Config, awilixManager?: AwilixManager);
37
+ private registerControllers;
36
38
  private registerModule;
37
39
  registerDependencies(params: RegisterDependenciesParams<Dependencies, Config, ExternalDependencies>, externalDependencies: ExternalDependencies, resolveControllers?: boolean): void;
38
40
  registerRoutes(app: FastifyInstance<any, any, any, any>): void;
@@ -12,6 +12,8 @@ export class DIContext {
12
12
  sseControllerNames;
13
13
  // Dual-mode controller dependency names (resolved from container to preserve singletons)
14
14
  dualModeControllerNames;
15
+ // ApiContract controller dependency names (resolved from container to preserve singletons)
16
+ apiControllerNames;
15
17
  appConfig;
16
18
  constructor(diContainer, options, appConfig, awilixManager) {
17
19
  this.options = options;
@@ -29,6 +31,31 @@ export class DIContext {
29
31
  this.controllerResolvers = [];
30
32
  this.sseControllerNames = [];
31
33
  this.dualModeControllerNames = [];
34
+ this.apiControllerNames = [];
35
+ }
36
+ registerControllers(
37
+ // biome-ignore lint/suspicious/noExplicitAny: controller resolver properties are duck-typed
38
+ controllers, targetDiConfig) {
39
+ for (const [name, resolver] of Object.entries(controllers)) {
40
+ if (resolver.isDualModeController) {
41
+ this.dualModeControllerNames.push(name);
42
+ // @ts-expect-error we can't really ensure type-safety here
43
+ targetDiConfig[name] = resolver;
44
+ }
45
+ else if (resolver.isSSEController) {
46
+ this.sseControllerNames.push(name);
47
+ // @ts-expect-error we can't really ensure type-safety here
48
+ targetDiConfig[name] = resolver;
49
+ }
50
+ else if (resolver.isApiController) {
51
+ this.apiControllerNames.push(name);
52
+ // @ts-expect-error we can't really ensure type-safety here
53
+ targetDiConfig[name] = resolver;
54
+ }
55
+ else {
56
+ this.controllerResolvers.push(resolver);
57
+ }
58
+ }
32
59
  }
33
60
  registerModule(module, targetDiConfig, externalDependencies, resolveControllers, isPrimaryModule) {
34
61
  const resolvedDIConfig = module.resolveDependencies(this.options, externalDependencies);
@@ -41,26 +68,7 @@ export class DIContext {
41
68
  }
42
69
  if (isPrimaryModule && resolveControllers) {
43
70
  const controllers = module.resolveControllers(this.options);
44
- for (const [name, resolver] of Object.entries(controllers)) {
45
- // @ts-expect-error isDualModeController is a custom property on the resolver
46
- if (resolver.isDualModeController) {
47
- // Dual-mode controller: register in DI container and track name for route registration
48
- this.dualModeControllerNames.push(name);
49
- // @ts-expect-error we can't really ensure type-safety here
50
- targetDiConfig[name] = resolver;
51
- // @ts-expect-error isSSEController is a custom property on the resolver
52
- }
53
- else if (resolver.isSSEController) {
54
- // SSE controller: register in DI container and track name for route registration
55
- this.sseControllerNames.push(name);
56
- // @ts-expect-error we can't really ensure type-safety here
57
- targetDiConfig[name] = resolver;
58
- }
59
- else {
60
- // REST controller: add resolver for route registration
61
- this.controllerResolvers.push(resolver);
62
- }
63
- }
71
+ this.registerControllers(controllers, targetDiConfig);
64
72
  }
65
73
  }
66
74
  registerDependencies(params, externalDependencies, resolveControllers = true) {
@@ -101,6 +109,12 @@ export class DIContext {
101
109
  app.route(route);
102
110
  }
103
111
  }
112
+ for (const controllerName of this.apiControllerNames) {
113
+ const controller = this.diContainer.resolve(controllerName);
114
+ for (const route of controller.routes) {
115
+ app.route(route);
116
+ }
117
+ }
104
118
  }
105
119
  /**
106
120
  * Check if any SSE controllers are registered.
@@ -1 +1 @@
1
- {"version":3,"file":"DIContext.js","sourceRoot":"","sources":["../../lib/DIContext.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DIContext.js","sourceRoot":"","sources":["../../lib/DIContext.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { RouteOptions } from 'fastify';
2
+ /**
3
+ * Abstract base class for controllers that use the `ApiContract` API.
4
+ *
5
+ * Concrete controllers declare a `routes` property built with `buildApiRoute()`.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * class UserController extends AbstractApiController {
10
+ * readonly routes = [
11
+ * buildApiRoute(getUser, async (req) => ({ status: 200, body: { id: req.params.id } })),
12
+ * buildApiRoute(streamUpdates, async (_req, sse) => { sse.start('keepAlive') }),
13
+ * ]
14
+ * }
15
+ * ```
16
+ */
17
+ export declare abstract class AbstractApiController {
18
+ abstract readonly routes: RouteOptions[];
19
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Abstract base class for controllers that use the `ApiContract` API.
3
+ *
4
+ * Concrete controllers declare a `routes` property built with `buildApiRoute()`.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * class UserController extends AbstractApiController {
9
+ * readonly routes = [
10
+ * buildApiRoute(getUser, async (req) => ({ status: 200, body: { id: req.params.id } })),
11
+ * buildApiRoute(streamUpdates, async (_req, sse) => { sse.start('keepAlive') }),
12
+ * ]
13
+ * }
14
+ * ```
15
+ */
16
+ export class AbstractApiController {
17
+ }
18
+ //# sourceMappingURL=AbstractApiController.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AbstractApiController.js","sourceRoot":"","sources":["../../../lib/api-contracts/AbstractApiController.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAgB,qBAAqB;CAE1C"}
@@ -0,0 +1,116 @@
1
+ import type { ApiContract, ContractNoBody, ContractResponseMode, InferSseSuccessResponses, PayloadApiContract } from '@lokalise/api-contracts';
2
+ import type { FastifyRequest, RouteOptions } from 'fastify';
3
+ import type { z } from 'zod/v4';
4
+ import type { DualModeType } from '../dualmode/dualModeTypes.ts';
5
+ import type { FastifySSERouteOptions, SSEContext, SSEHandlerResult, SyncModeReply } from '../routes/fastifyRouteTypes.ts';
6
+ type NonSseBodyEntry<T> = T extends undefined ? never : T extends {
7
+ _tag: 'SseResponse';
8
+ } ? never : T extends {
9
+ _tag: 'BlobResponse';
10
+ } ? Blob : T extends {
11
+ _tag: 'TextResponse';
12
+ } ? string : T extends {
13
+ _tag: 'AnyOfResponses';
14
+ responses: Array<infer R>;
15
+ } ? NonSseBodyEntry<R> : T extends z.ZodType ? z.output<T> : undefined;
16
+ /**
17
+ * Discriminated union of `{ status, body }` pairs for all non-SSE responses in a contract.
18
+ *
19
+ * Allows non-SSE handlers to return a specific status code and body together without
20
+ * calling `reply.code()` separately.
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * async (request) => {
25
+ * if (!valid) return { status: 400, body: { error: 'Bad Request' } }
26
+ * return { id: request.params.id }
27
+ * }
28
+ * ```
29
+ */
30
+ export type InferApiStatusResponse<Contract extends ApiContract> = {
31
+ [K in keyof Contract['responsesByStatusCode']]: NonSseBodyEntry<Contract['responsesByStatusCode'][K]> extends never ? never : {
32
+ status: K;
33
+ body: NonSseBodyEntry<Contract['responsesByStatusCode'][K]>;
34
+ };
35
+ }[keyof Contract['responsesByStatusCode']];
36
+ type InferOptSchema<T, Fallback = unknown> = NonNullable<T> extends z.ZodType ? z.output<NonNullable<T>> : Fallback;
37
+ type InferApiBodyType<Contract extends ApiContract> = Contract extends PayloadApiContract ? Contract['requestBodySchema'] extends typeof ContractNoBody ? undefined : NonNullable<Contract['requestBodySchema']> extends z.ZodType ? z.output<NonNullable<Contract['requestBodySchema']>> : undefined : undefined;
38
+ /**
39
+ * Infer the FastifyRequest type from an ApiContract.
40
+ *
41
+ * Provides properly typed params, querystring, headers, and body.
42
+ *
43
+ * @example
44
+ * ```typescript
45
+ * const handler = async (request: InferApiRequest<typeof myContract>) => {
46
+ * request.params.userId // typed
47
+ * request.body.name // typed
48
+ * }
49
+ * ```
50
+ */
51
+ export type InferApiRequest<Contract extends ApiContract> = FastifyRequest<{
52
+ Params: InferOptSchema<Contract['requestPathParamsSchema']>;
53
+ Querystring: InferOptSchema<Contract['requestQuerySchema']>;
54
+ Headers: InferOptSchema<Contract['requestHeaderSchema']>;
55
+ Body: InferApiBodyType<Contract>;
56
+ }>;
57
+ /**
58
+ * Handler for non-SSE responses from an ApiContract.
59
+ *
60
+ * Always return `{ status, body }` — the framework validates the body against the
61
+ * contract's schema for that status code and sends it.
62
+ *
63
+ * Use `reply.header()` to set response headers when needed.
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * async (request) => ({ status: 200, body: { id: request.params.userId } })
68
+ * ```
69
+ *
70
+ * @example With multiple status codes
71
+ * ```typescript
72
+ * async (request) => {
73
+ * if (!valid) return { status: 400, body: { error: 'Bad Request' } }
74
+ * return { status: 200, body: { id: request.params.userId } }
75
+ * }
76
+ * ```
77
+ */
78
+ export type ApiNonSseHandler<Contract extends ApiContract> = (request: InferApiRequest<Contract>, reply: SyncModeReply) => InferApiStatusResponse<Contract> | Promise<InferApiStatusResponse<Contract>>;
79
+ /**
80
+ * Handler for SSE responses from an ApiContract.
81
+ *
82
+ * Call `sse.start(mode)` to begin streaming or `sse.respond(code, body)` for
83
+ * early HTTP returns before streaming starts.
84
+ */
85
+ export type ApiSseHandler<Contract extends ApiContract> = (request: InferApiRequest<Contract>, sse: SSEContext<InferSseSuccessResponses<Contract['responsesByStatusCode']>>) => SSEHandlerResult | Promise<SSEHandlerResult>;
86
+ /**
87
+ * Infer the handler shape based on the contract's response mode:
88
+ * - `'non-sse'` — bare `ApiNonSseHandler` function
89
+ * - `'sse'` — bare `ApiSseHandler` function
90
+ * - `'dual'` — `{ nonSse, sse }` object, branched by `Accept` header
91
+ */
92
+ export type InferApiHandler<Contract extends ApiContract> = [
93
+ ContractResponseMode<Contract['responsesByStatusCode']>
94
+ ] extends ['dual'] ? {
95
+ nonSse: ApiNonSseHandler<Contract>;
96
+ sse: ApiSseHandler<Contract>;
97
+ } : [ContractResponseMode<Contract['responsesByStatusCode']>] extends ['sse'] ? ApiSseHandler<Contract> : ApiNonSseHandler<Contract>;
98
+ /**
99
+ * Options for configuring an ApiContract route.
100
+ *
101
+ * Extends Fastify's `RouteOptions` minus the fields the contract provides
102
+ * (`method`, `url`, `schema`, `handler`, `sse`), so any Fastify hook or config
103
+ * (`preHandler`, `onRequest`, `config`, `bodyLimit`, etc.) can be passed directly.
104
+ *
105
+ * SSE lifecycle options (`onConnect`, `onClose`, `onReconnect`) are only
106
+ * relevant for SSE and dual-mode contracts and are ignored for non-SSE routes.
107
+ */
108
+ export type ApiRouteOptions = Omit<RouteOptions, 'method' | 'url' | 'schema' | 'handler' | 'sse'> & Omit<FastifySSERouteOptions, 'preHandler'> & {
109
+ /**
110
+ * Default response mode for dual-mode routes when the `Accept` header
111
+ * does not express a preference.
112
+ * @default 'json'
113
+ */
114
+ defaultMode?: DualModeType;
115
+ };
116
+ export {};
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=apiHandlerTypes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiHandlerTypes.js","sourceRoot":"","sources":["../../../lib/api-contracts/apiHandlerTypes.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ import { type ApiContract } from '@lokalise/api-contracts';
2
+ import type { RouteOptions } from 'fastify';
3
+ import type { ApiRouteOptions, InferApiHandler } from './apiHandlerTypes.ts';
4
+ /**
5
+ * Build a Fastify `RouteOptions` object from an `ApiContract` + handler.
6
+ *
7
+ * @returns Fastify `RouteOptions` ready to pass to `app.route()`
8
+ */
9
+ export declare function buildApiRoute<Contract extends ApiContract>(contract: Contract, handler: InferApiHandler<Contract>, options?: ApiRouteOptions): RouteOptions;