@classytic/arc 2.10.3 → 2.11.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 (153) hide show
  1. package/README.md +1 -1
  2. package/dist/{BaseController-CbKKIflT.mjs → BaseController-JNV08qOT.mjs} +595 -537
  3. package/dist/{queryCachePlugin-BKbWjgDG.d.mts → QueryCache-DOBNHBE0.d.mts} +2 -32
  4. package/dist/actionPermissions-C8YYU92K.mjs +22 -0
  5. package/dist/adapters/index.d.mts +2 -2
  6. package/dist/adapters/index.mjs +1 -1
  7. package/dist/{adapters-BXY4i-hw.mjs → adapters-D0tT2Tyo.mjs} +54 -0
  8. package/dist/audit/index.d.mts +2 -2
  9. package/dist/audit/index.mjs +15 -17
  10. package/dist/auth/index.d.mts +4 -4
  11. package/dist/auth/index.mjs +3 -3
  12. package/dist/auth/redis-session.d.mts +1 -1
  13. package/dist/{betterAuthOpenApi-BBRVhjQN.mjs → betterAuthOpenApi-DwxtK3uG.mjs} +1 -1
  14. package/dist/cache/index.d.mts +3 -2
  15. package/dist/cache/index.mjs +3 -3
  16. package/dist/cli/commands/docs.mjs +2 -2
  17. package/dist/cli/commands/generate.mjs +37 -27
  18. package/dist/cli/commands/init.mjs +47 -34
  19. package/dist/cli/commands/introspect.mjs +1 -1
  20. package/dist/context/index.d.mts +58 -0
  21. package/dist/context/index.mjs +2 -0
  22. package/dist/core/index.d.mts +3 -3
  23. package/dist/core/index.mjs +4 -3
  24. package/dist/core-DXdSSFW-.mjs +1037 -0
  25. package/dist/createActionRouter-BwaSM0No.mjs +166 -0
  26. package/dist/{createApp-BuvPma24.mjs → createApp-DvNYEhpb.mjs} +118 -36
  27. package/dist/docs/index.d.mts +2 -2
  28. package/dist/docs/index.mjs +1 -1
  29. package/dist/{elevation-C7hgL_aI.mjs → elevation-DOFoxoDs.mjs} +1 -1
  30. package/dist/errorHandler-Co3lnVmJ.d.mts +114 -0
  31. package/dist/{eventPlugin-DCUjuiQT.mjs → eventPlugin--5HIkdPU.mjs} +1 -1
  32. package/dist/{eventPlugin-CxWgpd6K.d.mts → eventPlugin-CUNjYYRY.d.mts} +1 -1
  33. package/dist/events/index.d.mts +4 -4
  34. package/dist/events/index.mjs +69 -51
  35. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  36. package/dist/events/transports/redis.d.mts +1 -1
  37. package/dist/factory/index.d.mts +1 -1
  38. package/dist/factory/index.mjs +2 -2
  39. package/dist/{fields-Lo1VUDpt.d.mts → fields-C8Y0XLAu.d.mts} +1 -1
  40. package/dist/hooks/index.d.mts +1 -1
  41. package/dist/hooks/index.mjs +1 -1
  42. package/dist/idempotency/index.d.mts +3 -3
  43. package/dist/idempotency/index.mjs +38 -27
  44. package/dist/idempotency/redis.d.mts +1 -1
  45. package/dist/{index-ChIw3776.d.mts → index-BYCqHCVu.d.mts} +4 -4
  46. package/dist/{index-Cl0uoKd5.d.mts → index-Cm0vUrr_.d.mts} +2100 -1688
  47. package/dist/{index-DStwgFUK.d.mts → index-DAushRTt.d.mts} +29 -10
  48. package/dist/index-DsJ1MNfC.d.mts +1179 -0
  49. package/dist/{index-8qw4y6ff.d.mts → index-t8pLpPFW.d.mts} +13 -10
  50. package/dist/index.d.mts +7 -251
  51. package/dist/index.mjs +8 -128
  52. package/dist/integrations/event-gateway.d.mts +2 -2
  53. package/dist/integrations/event-gateway.mjs +1 -1
  54. package/dist/integrations/index.d.mts +2 -2
  55. package/dist/integrations/mcp/index.d.mts +2 -2
  56. package/dist/integrations/mcp/index.mjs +1 -1
  57. package/dist/integrations/mcp/testing.d.mts +1 -1
  58. package/dist/integrations/mcp/testing.mjs +1 -1
  59. package/dist/integrations/streamline.d.mts +46 -5
  60. package/dist/integrations/streamline.mjs +50 -21
  61. package/dist/integrations/websocket-redis.d.mts +1 -1
  62. package/dist/integrations/websocket.d.mts +2 -154
  63. package/dist/integrations/websocket.mjs +292 -224
  64. package/dist/{keys-qcD-TVJl.mjs → keys-CARyUjiR.mjs} +2 -0
  65. package/dist/{loadResources-BAzJItAJ.mjs → loadResources-YNwKHvRA.mjs} +3 -1
  66. package/dist/logger/index.d.mts +81 -0
  67. package/dist/{logger-DLg8-Ueg.mjs → logger/index.mjs} +1 -6
  68. package/dist/middleware/index.d.mts +109 -0
  69. package/dist/middleware/index.mjs +70 -0
  70. package/dist/multipartBody-CvTR1Un6.mjs +123 -0
  71. package/dist/{openapi-B5F8AddX.mjs → openapi-C0L9ar7m.mjs} +9 -7
  72. package/dist/org/index.d.mts +2 -2
  73. package/dist/permissions/index.d.mts +2 -2
  74. package/dist/permissions/index.mjs +1 -3
  75. package/dist/{permissions-Dk6mshja.mjs → permissions-B4vU9L0Q.mjs} +220 -2
  76. package/dist/pipe-DVoIheVC.mjs +62 -0
  77. package/dist/pipeline/index.d.mts +62 -0
  78. package/dist/pipeline/index.mjs +53 -0
  79. package/dist/plugins/index.d.mts +25 -5
  80. package/dist/plugins/index.mjs +10 -10
  81. package/dist/plugins/response-cache.mjs +1 -1
  82. package/dist/plugins/tracing-entry.d.mts +1 -1
  83. package/dist/plugins/tracing-entry.mjs +42 -24
  84. package/dist/presets/filesUpload.d.mts +4 -4
  85. package/dist/presets/filesUpload.mjs +255 -1
  86. package/dist/presets/index.d.mts +1 -1
  87. package/dist/presets/index.mjs +2 -2
  88. package/dist/presets/multiTenant.d.mts +1 -1
  89. package/dist/presets/multiTenant.mjs +48 -8
  90. package/dist/presets/search.d.mts +2 -2
  91. package/dist/presets/search.mjs +1 -1
  92. package/dist/{presets-fLJVXdVn.mjs → presets-k604Lj99.mjs} +1 -1
  93. package/dist/queryCachePlugin-BUXBSm4F.d.mts +34 -0
  94. package/dist/{queryCachePlugin-DQCEfJis.mjs → queryCachePlugin-Bq6bO6vc.mjs} +3 -3
  95. package/dist/{redis-DqyeggCa.d.mts → redis-Cm1gnRDf.d.mts} +1 -1
  96. package/dist/{redis-stream-CakIQmwR.d.mts → redis-stream-CM8TXTix.d.mts} +1 -1
  97. package/dist/registry/index.d.mts +1 -1
  98. package/dist/registry/index.mjs +2 -2
  99. package/dist/{requestContext-xHIKedG6.mjs → requestContext-CfRkaxwf.mjs} +1 -1
  100. package/dist/{resourceToTools-BElv3xPT.mjs → resourceToTools--okX6QBr.mjs} +534 -415
  101. package/dist/routerShared-DeESFp4a.mjs +515 -0
  102. package/dist/schemaIR-BlG9bY7v.mjs +137 -0
  103. package/dist/scope/index.d.mts +2 -2
  104. package/dist/scope/index.mjs +1 -1
  105. package/dist/{sse-yBCgOLGu.mjs → sse-V7aXc3bW.mjs} +1 -1
  106. package/dist/{store-helpers-ZCSMJJAX.mjs → store-helpers-BhrzxvyQ.mjs} +4 -0
  107. package/dist/testing/index.d.mts +367 -711
  108. package/dist/testing/index.mjs +646 -1434
  109. package/dist/testing/storageContract.d.mts +1 -1
  110. package/dist/{tracing-65B51Dw3.d.mts → tracing-DokiEsuz.d.mts} +9 -4
  111. package/dist/types/index.d.mts +5 -5
  112. package/dist/types/index.mjs +1 -3
  113. package/dist/types/storage.d.mts +1 -1
  114. package/dist/{types-Co8k3NyS.d.mts → types-CgikqKAj.d.mts} +133 -21
  115. package/dist/{types-Btdda02s.d.mts → types-D9NqiYIw.d.mts} +1 -1
  116. package/dist/utils/index.d.mts +2 -898
  117. package/dist/utils/index.mjs +4 -5
  118. package/dist/utils-D3Yxnrwr.mjs +1639 -0
  119. package/dist/versioning-M9lNLhO8.d.mts +117 -0
  120. package/dist/websocket-CyJ1VIFI.d.mts +186 -0
  121. package/package.json +26 -8
  122. package/skills/arc/SKILL.md +124 -39
  123. package/skills/arc/references/testing.md +212 -183
  124. package/dist/applyPermissionResult-QhV1Pa-g.mjs +0 -37
  125. package/dist/core-CcR01lup.mjs +0 -1411
  126. package/dist/createActionRouter-Bp_5c_2b.mjs +0 -249
  127. package/dist/errorHandler-DRQ3EqfL.d.mts +0 -218
  128. package/dist/errors-CCSsMpXE.d.mts +0 -140
  129. package/dist/fields-bxkeltzz.mjs +0 -126
  130. package/dist/filesUpload-t21LS-py.mjs +0 -377
  131. package/dist/queryParser-DBqBB6AC.mjs +0 -352
  132. package/dist/types-Csi3FLfq.mjs +0 -27
  133. package/dist/utils-B2fNOD_i.mjs +0 -929
  134. /package/dist/{EventTransport-CUw5NNWe.d.mts → EventTransport-CfVEGaEl.d.mts} +0 -0
  135. /package/dist/{HookSystem-BNYKnrXF.mjs → HookSystem-CGsMd6oK.mjs} +0 -0
  136. /package/dist/{ResourceRegistry-BPd6NQDm.mjs → ResourceRegistry-DkAeAuTX.mjs} +0 -0
  137. /package/dist/{caching-CBpK_SCM.mjs → caching-CheW3m-S.mjs} +0 -0
  138. /package/dist/{elevation-C5SwtkAn.d.mts → elevation-s5ykdNHr.d.mts} +0 -0
  139. /package/dist/{errorHandler-Bb49BvPD.mjs → errorHandler-BQm8ZxTK.mjs} +0 -0
  140. /package/dist/{externalPaths-BQ8QijNH.d.mts → externalPaths-Bapitwvd.d.mts} +0 -0
  141. /package/dist/{interface-CSbZdv_3.d.mts → interface-CkkWm5uR.d.mts} +0 -0
  142. /package/dist/{interface-D218ikEo.d.mts → interface-Da0r7Lna.d.mts} +0 -0
  143. /package/dist/{memory-B5Amv9A1.mjs → memory-DikHSvWa.mjs} +0 -0
  144. /package/dist/{metrics-DuhiSEZI.mjs → metrics-Csh4nsvv.mjs} +0 -0
  145. /package/dist/{pluralize-A0tWEl1K.mjs → pluralize-BneOJkpi.mjs} +0 -0
  146. /package/dist/{registry-B3lRFBWo.mjs → registry-D63ee7fl.mjs} +0 -0
  147. /package/dist/{replyHelpers-CXtJDAZ0.mjs → replyHelpers-ByllIXXV.mjs} +0 -0
  148. /package/dist/{schemaConverter-BxFDdtXu.mjs → schemaConverter-B0oKLuqI.mjs} +0 -0
  149. /package/dist/{sessionManager-BkzVU8h2.d.mts → sessionManager-D-oNWHz3.d.mts} +0 -0
  150. /package/dist/{storage-CVk_SEn2.d.mts → storage-BwGQXUpd.d.mts} +0 -0
  151. /package/dist/{typeGuards-Cj5Rgvlg.mjs → typeGuards-CcFZXgU7.mjs} +0 -0
  152. /package/dist/{types-BD85MlEK.d.mts → types-tgR4Pt8F.d.mts} +0 -0
  153. /package/dist/{versioning-C2U_bLY0.mjs → versioning-CGPjkqAg.mjs} +0 -0
@@ -0,0 +1,117 @@
1
+ import { n as DomainEvent } from "./EventTransport-CfVEGaEl.mjs";
2
+ import { FastifyPluginAsync, FastifyRequest } from "fastify";
3
+
4
+ //#region src/plugins/caching.d.ts
5
+ interface CachingRule {
6
+ /** Path prefix to match (e.g., '/api/products') */
7
+ match: string;
8
+ /** Cache-Control max-age in seconds */
9
+ maxAge: number;
10
+ /** Cache-Control: private vs public (default: public) */
11
+ private?: boolean;
12
+ /** stale-while-revalidate directive in seconds */
13
+ staleWhileRevalidate?: number;
14
+ }
15
+ interface CachingOptions {
16
+ /** Default max-age in seconds for Cache-Control (default: 0 = no-cache) */
17
+ maxAge?: number;
18
+ /** Enable ETag generation (default: true) */
19
+ etag?: boolean;
20
+ /** Enable conditional requests — 304 Not Modified (default: true) */
21
+ conditional?: boolean;
22
+ /** HTTP methods to cache (default: ['GET', 'HEAD']) */
23
+ methods?: string[];
24
+ /** Paths to exclude from caching (prefix match) */
25
+ exclude?: string[];
26
+ /** Custom cache rules per path prefix */
27
+ rules?: CachingRule[];
28
+ }
29
+ declare const cachingPlugin: FastifyPluginAsync<CachingOptions>;
30
+ declare const _default$3: FastifyPluginAsync<CachingOptions>;
31
+ //#endregion
32
+ //#region src/plugins/sse.d.ts
33
+ interface SSEOptions {
34
+ /** SSE endpoint path (default: '/events/stream') */
35
+ path?: string;
36
+ /** Require authentication (default: true) */
37
+ requireAuth?: boolean;
38
+ /** Event patterns to stream (default: ['*'] = all) */
39
+ patterns?: string[];
40
+ /** Heartbeat interval in ms (default: 30000) */
41
+ heartbeat?: number;
42
+ /** Filter events by organizationId from request.scope (default: false) */
43
+ orgScoped?: boolean;
44
+ /** Custom event filter function */
45
+ filter?: (event: DomainEvent<unknown>, request: FastifyRequest) => boolean;
46
+ }
47
+ declare const ssePlugin: FastifyPluginAsync<SSEOptions>;
48
+ declare const _default$2: FastifyPluginAsync<SSEOptions>;
49
+ //#endregion
50
+ //#region src/plugins/metrics.d.ts
51
+ interface MetricsOptions {
52
+ /** Endpoint path (default: '/_metrics') */
53
+ path?: string;
54
+ /** Prefix for all metric names (default: 'arc') */
55
+ prefix?: string;
56
+ /** Called after metrics are collected (for OTLP push, etc.) */
57
+ onCollect?: (metrics: MetricEntry[]) => void;
58
+ }
59
+ interface MetricEntry {
60
+ name: string;
61
+ type: "counter" | "histogram" | "gauge";
62
+ help: string;
63
+ values: Array<{
64
+ labels: Record<string, string>;
65
+ value: number;
66
+ }>;
67
+ }
68
+ interface MetricsCollector {
69
+ /** Get all metrics as structured data */
70
+ collect(): MetricEntry[];
71
+ /** Reset all metrics */
72
+ reset(): void;
73
+ /** Record a CRUD operation */
74
+ recordOperation(resource: string, operation: string, status: number, durationMs: number): void;
75
+ /** Record a cache hit */
76
+ recordCacheHit(resource: string): void;
77
+ /** Record a cache miss */
78
+ recordCacheMiss(resource: string): void;
79
+ /** Record an event publish */
80
+ recordEventPublish(eventType: string): void;
81
+ /** Record an event consume */
82
+ recordEventConsume(eventType: string): void;
83
+ /** Record a circuit breaker state change */
84
+ recordCircuitBreakerState(service: string, state: string): void;
85
+ }
86
+ declare module "fastify" {
87
+ interface FastifyInstance {
88
+ metrics: MetricsCollector;
89
+ }
90
+ }
91
+ declare const metricsPlugin: FastifyPluginAsync<MetricsOptions>;
92
+ declare const _default$1: FastifyPluginAsync<MetricsOptions>;
93
+ //#endregion
94
+ //#region src/plugins/versioning.d.ts
95
+ interface VersioningOptions {
96
+ /** Versioning strategy */
97
+ type: "header" | "prefix";
98
+ /** Default version when none specified (default: '1') */
99
+ defaultVersion?: string;
100
+ /** Header name to read (default: 'accept-version') */
101
+ headerName?: string;
102
+ /** Response header name (default: 'x-api-version') */
103
+ responseHeader?: string;
104
+ /** Deprecated versions — adds Deprecation + Sunset headers */
105
+ deprecated?: string[];
106
+ /** Sunset date for deprecated versions (ISO 8601) */
107
+ sunset?: string;
108
+ }
109
+ declare module "fastify" {
110
+ interface FastifyRequest {
111
+ apiVersion: string;
112
+ }
113
+ }
114
+ declare const versioningPlugin: FastifyPluginAsync<VersioningOptions>;
115
+ declare const _default: FastifyPluginAsync<VersioningOptions>;
116
+ //#endregion
117
+ export { MetricsCollector as a, metricsPlugin as c, ssePlugin as d, CachingOptions as f, cachingPlugin as h, MetricEntry as i, SSEOptions as l, _default$3 as m, _default as n, MetricsOptions as o, CachingRule as p, versioningPlugin as r, _default$1 as s, VersioningOptions as t, _default$2 as u };
@@ -0,0 +1,186 @@
1
+ import { FastifyPluginAsync } from "fastify";
2
+
3
+ //#region src/integrations/websocket/adapter.d.ts
4
+ /**
5
+ * WebSocket cross-instance adapter contract.
6
+ *
7
+ * The adapter is NOT used for local broadcasts — `RoomManager` handles those.
8
+ * The adapter only handles the cross-instance relay (Redis pub/sub, NATS, etc.)
9
+ * so a message broadcast on instance A is also delivered to clients connected
10
+ * to instance B.
11
+ *
12
+ * Implementations:
13
+ * - `LocalWebSocketAdapter` (here) — no-op, single-instance only
14
+ * - `RedisWebSocketAdapter` (@classytic/arc/integrations/websocket-redis)
15
+ *
16
+ * Custom adapters just need to satisfy the interface.
17
+ */
18
+ /**
19
+ * Adapter interface for cross-instance WebSocket broadcast.
20
+ *
21
+ * - `publish()`: Send a message to all instances (via Redis, NATS, etc.)
22
+ * - `subscribe()`: Receive messages from other instances
23
+ * - `close()`: Clean up connections
24
+ */
25
+ interface WebSocketAdapter {
26
+ /** Adapter name for logging */
27
+ readonly name: string;
28
+ /** Publish a room broadcast to all other instances */
29
+ publish(room: string, message: string): Promise<void>;
30
+ /** Subscribe to broadcasts from other instances */
31
+ subscribe(callback: (room: string, message: string) => void): Promise<void>;
32
+ /** Close adapter connections */
33
+ close(): Promise<void>;
34
+ }
35
+ /**
36
+ * Default adapter — no cross-instance broadcast (single-instance only).
37
+ * All methods are no-ops. Used when no adapter is configured.
38
+ */
39
+ declare class LocalWebSocketAdapter implements WebSocketAdapter {
40
+ readonly name = "local";
41
+ publish(): Promise<void>;
42
+ subscribe(): Promise<void>;
43
+ close(): Promise<void>;
44
+ }
45
+ //#endregion
46
+ //#region src/integrations/websocket/types.d.ts
47
+ /**
48
+ * A connected WebSocket client — one entry per TCP socket.
49
+ *
50
+ * `subscriptions` is mutated by `RoomManager`; other fields are set once at
51
+ * handshake time and treated as effectively immutable for the lifetime of
52
+ * the connection.
53
+ */
54
+ interface WebSocketClient {
55
+ id: string;
56
+ socket: {
57
+ send(data: string): void;
58
+ close(): void;
59
+ readyState: number;
60
+ };
61
+ subscriptions: Set<string>;
62
+ userId?: string;
63
+ organizationId?: string;
64
+ /** OAuth client ID — present for service/machine-to-machine connections */
65
+ clientId?: string;
66
+ /** OAuth scopes — present for service/machine-to-machine connections */
67
+ scopes?: readonly string[];
68
+ metadata?: Record<string, unknown>;
69
+ }
70
+ interface WebSocketMessage {
71
+ type: string;
72
+ resource?: string;
73
+ channel?: string;
74
+ data?: unknown;
75
+ }
76
+ /**
77
+ * Result of a successful authentication. The plugin's handshake and the
78
+ * optional re-auth loop both return this shape so the downstream code
79
+ * doesn't branch on auth mode. `null` means rejected.
80
+ */
81
+ interface AuthResult {
82
+ userId?: string;
83
+ organizationId?: string;
84
+ /** Set for machine-to-machine / service account auth */
85
+ clientId?: string;
86
+ /** OAuth scopes for service accounts */
87
+ scopes?: readonly string[];
88
+ }
89
+ interface WebSocketPluginOptions {
90
+ /** WebSocket endpoint path (default: '/ws') */
91
+ path?: string;
92
+ /** Require authentication for WebSocket connections (default: true) */
93
+ auth?: boolean;
94
+ /** Resources to auto-broadcast CRUD events for */
95
+ resources?: string[];
96
+ /** Heartbeat interval in ms (default: 30000). Set 0 to disable. */
97
+ heartbeatInterval?: number;
98
+ /** Custom authentication function for WebSocket upgrade */
99
+ authenticate?: (request: unknown) => Promise<AuthResult | null>;
100
+ /** Max clients per resource subscription (default: 10000) */
101
+ maxClientsPerRoom?: number;
102
+ /**
103
+ * Expose a stats endpoint at `{path}/stats`.
104
+ * - `false` (default): stats endpoint is not registered
105
+ * - `true`: registered without auth
106
+ * - `'authenticated'`: guarded by `fastify.authenticate` if available
107
+ */
108
+ exposeStats?: boolean | "authenticated";
109
+ /**
110
+ * Authorize room subscriptions. Return true to allow, false to deny.
111
+ * Called before every subscribe. If not provided, all rooms are allowed.
112
+ */
113
+ roomPolicy?: (client: WebSocketClient, room: string) => boolean | Promise<boolean>;
114
+ /** Maximum message size in bytes from client (default: 16384 = 16KB). Messages exceeding this are dropped. */
115
+ maxMessageBytes?: number;
116
+ /** Maximum subscriptions per client (default: 100). Prevents resource exhaustion. */
117
+ maxSubscriptionsPerClient?: number;
118
+ /**
119
+ * Periodic re-authentication interval in ms (default: 0 = disabled).
120
+ * When set, the server periodically re-validates the client's auth token.
121
+ * If the token is expired/revoked, the client is disconnected with code 4003.
122
+ *
123
+ * Recommended: 300000 (5 minutes) for production.
124
+ *
125
+ * @example
126
+ * ```typescript
127
+ * websocketPlugin({ reauthInterval: 5 * 60 * 1000 }) // re-check every 5 min
128
+ * ```
129
+ */
130
+ reauthInterval?: number;
131
+ /** Custom message handler */
132
+ onMessage?: (client: WebSocketClient, message: WebSocketMessage) => void | Promise<void>;
133
+ /** Called when a client connects */
134
+ onConnect?: (client: WebSocketClient) => void | Promise<void>;
135
+ /** Called when a client disconnects */
136
+ onDisconnect?: (client: WebSocketClient) => void | Promise<void>;
137
+ /**
138
+ * Cross-instance broadcast adapter (default: LocalWebSocketAdapter — single-instance only).
139
+ * Provide a RedisWebSocketAdapter for multi-instance deployments.
140
+ *
141
+ * @example
142
+ * ```typescript
143
+ * import { RedisWebSocketAdapter } from '@classytic/arc/integrations/websocket-redis';
144
+ * adapter: new RedisWebSocketAdapter(redis, { channel: 'arc-ws' })
145
+ * ```
146
+ */
147
+ adapter?: WebSocketAdapter;
148
+ }
149
+ //#endregion
150
+ //#region src/integrations/websocket/plugin.d.ts
151
+ /** Pluggable WebSocket integration for Arc */
152
+ declare const websocketPlugin: FastifyPluginAsync<WebSocketPluginOptions>;
153
+ //#endregion
154
+ //#region src/integrations/websocket/room-manager.d.ts
155
+ declare class RoomManager {
156
+ private rooms;
157
+ private clients;
158
+ private maxPerRoom;
159
+ private adapter?;
160
+ constructor(maxPerRoom?: number, adapter?: WebSocketAdapter);
161
+ addClient(client: WebSocketClient): void;
162
+ removeClient(clientId: string): void;
163
+ subscribe(clientId: string, room: string): boolean;
164
+ unsubscribe(clientId: string, room: string): void;
165
+ broadcast(room: string, message: string, excludeClientId?: string): void;
166
+ broadcastToOrg(organizationId: string, room: string, message: string): void;
167
+ /**
168
+ * Broadcast locally AND through adapter (for cross-instance delivery).
169
+ * Use this instead of broadcast() when multi-instance is possible.
170
+ */
171
+ broadcastWithAdapter(room: string, message: string, excludeClientId?: string): Promise<void>;
172
+ /**
173
+ * Org-scoped broadcast locally AND through adapter.
174
+ * Uses a namespaced room key for the adapter so other instances
175
+ * can filter by org when delivering locally.
176
+ */
177
+ broadcastToOrgWithAdapter(organizationId: string, room: string, message: string): Promise<void>;
178
+ getClient(clientId: string): WebSocketClient | undefined;
179
+ getStats(): {
180
+ clients: number;
181
+ rooms: number;
182
+ subscriptions: Record<string, number>;
183
+ };
184
+ }
185
+ //#endregion
186
+ export { WebSocketMessage as a, WebSocketAdapter as c, WebSocketClient as i, websocketPlugin as n, WebSocketPluginOptions as o, AuthResult as r, LocalWebSocketAdapter as s, RoomManager as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classytic/arc",
3
- "version": "2.10.3",
3
+ "version": "2.11.0",
4
4
  "description": "Resource-oriented backend framework for Fastify — clean, minimal, powerful, tree-shakable",
5
5
  "type": "module",
6
6
  "exports": {
@@ -64,6 +64,22 @@
64
64
  "types": "./dist/hooks/index.d.mts",
65
65
  "default": "./dist/hooks/index.mjs"
66
66
  },
67
+ "./middleware": {
68
+ "types": "./dist/middleware/index.d.mts",
69
+ "default": "./dist/middleware/index.mjs"
70
+ },
71
+ "./pipeline": {
72
+ "types": "./dist/pipeline/index.d.mts",
73
+ "default": "./dist/pipeline/index.mjs"
74
+ },
75
+ "./context": {
76
+ "types": "./dist/context/index.d.mts",
77
+ "default": "./dist/context/index.mjs"
78
+ },
79
+ "./logger": {
80
+ "types": "./dist/logger/index.d.mts",
81
+ "default": "./dist/logger/index.mjs"
82
+ },
67
83
  "./registry": {
68
84
  "types": "./dist/registry/index.d.mts",
69
85
  "default": "./dist/registry/index.mjs"
@@ -217,15 +233,16 @@
217
233
  "test:e2e": "vitest run tests/e2e",
218
234
  "test:unit": "vitest run tests/core tests/hooks tests/utils tests/plugins",
219
235
  "smoke": "node scripts/smoke-test.mjs",
236
+ "push": "classytic-push",
220
237
  "prepublishOnly": "npm run typecheck && npm run lint && npm run build && npm run test:ci && npm run smoke"
221
238
  },
222
239
  "engines": {
223
240
  "node": ">=22"
224
241
  },
225
242
  "peerDependencies": {
226
- "@classytic/mongokit": ">=3.10.2",
227
- "@classytic/repo-core": ">=0.1.0",
228
- "@classytic/streamline": ">=2.1.0",
243
+ "@classytic/mongokit": ">=3.11.1",
244
+ "@classytic/repo-core": ">=0.2.0",
245
+ "@classytic/streamline": ">=2.2.0",
229
246
  "@fastify/cors": ">=11.0.0",
230
247
  "@fastify/helmet": ">=13.0.0",
231
248
  "@fastify/jwt": ">=10.0.0",
@@ -347,10 +364,11 @@
347
364
  "@better-auth/drizzle-adapter": "^1.6.2",
348
365
  "@better-auth/mongo-adapter": "^1.6.2",
349
366
  "@biomejs/biome": "^2.4.11",
350
- "@classytic/mongokit": "^3.10.2",
351
- "@classytic/repo-core": "^0.1.0",
352
- "@classytic/sqlitekit": "^0.1.0",
353
- "@classytic/streamline": "^2.1.0",
367
+ "@classytic/dev-tools": "^0.2.0",
368
+ "@classytic/mongokit": "^3.11.1",
369
+ "@classytic/repo-core": "^0.2.0",
370
+ "@classytic/sqlitekit": "^0.2.0",
371
+ "@classytic/streamline": "^2.2.0",
354
372
  "@fastify/cors": "^11.2.0",
355
373
  "@fastify/helmet": "^13.0.2",
356
374
  "@fastify/jwt": "^10.0.0",