@classytic/arc 2.17.1 → 2.18.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.
- package/dist/{BaseController-CgHomZ4d.mjs → BaseController-DPwe89qs.mjs} +1 -1
- package/dist/cli/commands/docs.mjs +1 -1
- package/dist/cli/commands/init.mjs +1 -1
- package/dist/cli/index.mjs +1 -1
- package/dist/context/index.d.mts +54 -1
- package/dist/context/index.mjs +65 -2
- package/dist/core/index.mjs +3 -3
- package/dist/{core-D8tpQ4ZL.mjs → core-B41eZxyM.mjs} +8 -5
- package/dist/{createActionRouter-BHUMb1-y.mjs → createActionRouter-CRaIwB5S.mjs} +2 -2
- package/dist/{createAggregationRouter-BYVvhfc5.mjs → createAggregationRouter-n3O6WdLO.mjs} +1 -1
- package/dist/{createApp-CzCEEsEm.mjs → createApp-D56t2Dsj.mjs} +7 -2
- package/dist/docs/index.mjs +1 -1
- package/dist/{eventPlugin-CnJCUyM0.mjs → eventPlugin-Dxp9JlKK.mjs} +1 -1
- package/dist/events/index.d.mts +48 -0
- package/dist/events/index.mjs +27 -5
- package/dist/factory/index.mjs +1 -1
- package/dist/index.mjs +4 -4
- package/dist/{init-DYzfniuX.mjs → init-DQ_rY1J7.mjs} +13 -13
- package/dist/integrations/event-gateway.d.mts +1 -1
- package/dist/integrations/index.d.mts +2 -2
- package/dist/integrations/mcp/index.d.mts +42 -2
- package/dist/integrations/mcp/index.mjs +102 -2
- package/dist/integrations/mcp/testing.d.mts +1 -1
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/integrations/websocket-pushref-redis.d.mts +71 -0
- package/dist/integrations/websocket-pushref-redis.mjs +205 -0
- package/dist/integrations/websocket-redis.d.mts +1 -1
- package/dist/integrations/websocket.d.mts +3 -2
- package/dist/integrations/websocket.mjs +1142 -23
- package/dist/{mcpPlugin-C6FViZXw.mjs → mcpPlugin-BrepZ0cV.mjs} +3 -3
- package/dist/{openapi-DKDs9NfD.mjs → openapi-CLZx9bwS.mjs} +1 -1
- package/dist/plugins/index.d.mts +15 -1
- package/dist/plugins/index.mjs +44 -3
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/presets/filesUpload.d.mts +1 -1
- package/dist/pushref-registry-Bq_-EVsC.d.mts +435 -0
- package/dist/{requestContext-SSaaTgW8.mjs → requestContext-DDLS3NVU.mjs} +26 -1
- package/dist/{routerShared-nCyJGOKX.mjs → routerShared-Dl0A77Ba.mjs} +1 -1
- package/dist/{schemaIR-DAOvBWgT.mjs → schemaIR-Bk6Tns82.mjs} +17 -5
- package/dist/testing/index.mjs +1 -1
- package/dist/testing/storageContract.d.mts +1 -1
- package/dist/types/storage.d.mts +1 -1
- package/dist/websocket-BZMUP7Gr.d.mts +456 -0
- package/package.json +12 -1
- package/dist/websocket-BJ0w-3Dt.d.mts +0 -186
- /package/dist/{storage-HcAgP5Ni.d.mts → storage-BFmamN5m.d.mts} +0 -0
- /package/dist/{tracing-bRqqUxFO.d.mts → tracing-BYQ3hsbM.d.mts} +0 -0
- /package/dist/{types-CoMjNmkF.d.mts → types-D3HV0r5L.d.mts} +0 -0
|
@@ -1,186 +0,0 @@
|
|
|
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 };
|
|
File without changes
|
|
File without changes
|
|
File without changes
|