@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.
Files changed (49) hide show
  1. package/dist/{BaseController-CgHomZ4d.mjs → BaseController-DPwe89qs.mjs} +1 -1
  2. package/dist/cli/commands/docs.mjs +1 -1
  3. package/dist/cli/commands/init.mjs +1 -1
  4. package/dist/cli/index.mjs +1 -1
  5. package/dist/context/index.d.mts +54 -1
  6. package/dist/context/index.mjs +65 -2
  7. package/dist/core/index.mjs +3 -3
  8. package/dist/{core-D8tpQ4ZL.mjs → core-B41eZxyM.mjs} +8 -5
  9. package/dist/{createActionRouter-BHUMb1-y.mjs → createActionRouter-CRaIwB5S.mjs} +2 -2
  10. package/dist/{createAggregationRouter-BYVvhfc5.mjs → createAggregationRouter-n3O6WdLO.mjs} +1 -1
  11. package/dist/{createApp-CzCEEsEm.mjs → createApp-D56t2Dsj.mjs} +7 -2
  12. package/dist/docs/index.mjs +1 -1
  13. package/dist/{eventPlugin-CnJCUyM0.mjs → eventPlugin-Dxp9JlKK.mjs} +1 -1
  14. package/dist/events/index.d.mts +48 -0
  15. package/dist/events/index.mjs +27 -5
  16. package/dist/factory/index.mjs +1 -1
  17. package/dist/index.mjs +4 -4
  18. package/dist/{init-DYzfniuX.mjs → init-DQ_rY1J7.mjs} +13 -13
  19. package/dist/integrations/event-gateway.d.mts +1 -1
  20. package/dist/integrations/index.d.mts +2 -2
  21. package/dist/integrations/mcp/index.d.mts +42 -2
  22. package/dist/integrations/mcp/index.mjs +102 -2
  23. package/dist/integrations/mcp/testing.d.mts +1 -1
  24. package/dist/integrations/mcp/testing.mjs +1 -1
  25. package/dist/integrations/websocket-pushref-redis.d.mts +71 -0
  26. package/dist/integrations/websocket-pushref-redis.mjs +205 -0
  27. package/dist/integrations/websocket-redis.d.mts +1 -1
  28. package/dist/integrations/websocket.d.mts +3 -2
  29. package/dist/integrations/websocket.mjs +1142 -23
  30. package/dist/{mcpPlugin-C6FViZXw.mjs → mcpPlugin-BrepZ0cV.mjs} +3 -3
  31. package/dist/{openapi-DKDs9NfD.mjs → openapi-CLZx9bwS.mjs} +1 -1
  32. package/dist/plugins/index.d.mts +15 -1
  33. package/dist/plugins/index.mjs +44 -3
  34. package/dist/plugins/tracing-entry.d.mts +1 -1
  35. package/dist/plugins/tracing-entry.mjs +1 -1
  36. package/dist/presets/filesUpload.d.mts +1 -1
  37. package/dist/pushref-registry-Bq_-EVsC.d.mts +435 -0
  38. package/dist/{requestContext-SSaaTgW8.mjs → requestContext-DDLS3NVU.mjs} +26 -1
  39. package/dist/{routerShared-nCyJGOKX.mjs → routerShared-Dl0A77Ba.mjs} +1 -1
  40. package/dist/{schemaIR-DAOvBWgT.mjs → schemaIR-Bk6Tns82.mjs} +17 -5
  41. package/dist/testing/index.mjs +1 -1
  42. package/dist/testing/storageContract.d.mts +1 -1
  43. package/dist/types/storage.d.mts +1 -1
  44. package/dist/websocket-BZMUP7Gr.d.mts +456 -0
  45. package/package.json +12 -1
  46. package/dist/websocket-BJ0w-3Dt.d.mts +0 -186
  47. /package/dist/{storage-HcAgP5Ni.d.mts → storage-BFmamN5m.d.mts} +0 -0
  48. /package/dist/{tracing-bRqqUxFO.d.mts → tracing-BYQ3hsbM.d.mts} +0 -0
  49. /package/dist/{types-CoMjNmkF.d.mts → types-D3HV0r5L.d.mts} +0 -0
@@ -1,4 +1,4 @@
1
- import { a as defaultCrudDescription, c as mcpHandlerAdapter, d as toCallToolResult, f as toCallToolSuccess, h as resolveToolCollisions, i as fieldRulesToZod, l as permissionDeniedResult, m as createMcpServer, n as mcpPlugin, o as resolveCrudDescription, p as buildRequestContext, r as resourceToTools, s as invokeController, t as filterResourcesForMcp, u as toCallToolError } from "../../mcpPlugin-C6FViZXw.mjs";
1
+ import { a as defaultCrudDescription, c as mcpHandlerAdapter, d as toCallToolResult, f as toCallToolSuccess, h as resolveToolCollisions, i as fieldRulesToZod, l as permissionDeniedResult, m as createMcpServer, n as mcpPlugin, o as resolveCrudDescription, p as buildRequestContext, r as resourceToTools, s as invokeController, t as filterResourcesForMcp, u as toCallToolError } from "../../mcpPlugin-BrepZ0cV.mjs";
2
2
  //#region src/integrations/mcp/defineTool.ts
3
3
  /**
4
4
  * Define a type-safe MCP tool.
@@ -275,4 +275,104 @@ function definePrompt(name, config) {
275
275
  };
276
276
  }
277
277
  //#endregion
278
- export { bridgeToMcp, buildMcpToolsFromBridges, buildRequestContext, createMcpAuthFromBetterAuthApiKey, createMcpServer, customGuard, defaultCrudDescription, definePrompt, defineTool, denied, fieldRulesToZod, filterResourcesForMcp, getOrgId, getUserId, guard, hasOrg, invokeController, isAuthenticated, isOrg, mcpHandlerAdapter, mcpPlugin, permissionDeniedResult, requireAuth, requireOrg, requireOrgId, requireRole, resolveCrudDescription, resolveToolCollisions, resourceToTools, toCallToolError, toCallToolResult, toCallToolSuccess };
278
+ //#region src/integrations/mcp/realtimeBridge.ts
279
+ /**
280
+ * Dispatch a batch of tool calls through the host's MCP tool registry.
281
+ *
282
+ * Returns the response array in the same order as the input. Each
283
+ * response carries either the tool's `content` (success path) or a
284
+ * `{isError:true, error:{message,...}}` shape (validation failure or
285
+ * handler throw). The realtime client uses the `id` to correlate
286
+ * responses to the original calls.
287
+ */
288
+ async function dispatchRealtimeToolCall(tools, calls, opts = {}) {
289
+ const byName = new Map(tools.map((t) => [t.name, t]));
290
+ const noopLog = async () => {};
291
+ const baseCtx = {
292
+ session: opts.session ?? null,
293
+ log: opts.log ?? noopLog,
294
+ extra: opts.extra ?? {}
295
+ };
296
+ return (await Promise.allSettled(calls.map((call) => dispatchOne(byName.get(call.name), call, baseCtx)))).map((s, i) => {
297
+ const call = calls[i];
298
+ if (!call) return {
299
+ id: "unknown",
300
+ name: "unknown",
301
+ isError: true,
302
+ response: { error: "missing call slot" }
303
+ };
304
+ if (s.status === "fulfilled") return s.value;
305
+ return {
306
+ id: call.id,
307
+ name: call.name,
308
+ isError: true,
309
+ response: { error: s.reason instanceof Error ? s.reason.message : String(s.reason) }
310
+ };
311
+ });
312
+ }
313
+ async function dispatchOne(def, call, ctx) {
314
+ if (!def) return {
315
+ id: call.id,
316
+ name: call.name,
317
+ isError: true,
318
+ response: { error: `unknown tool: ${call.name}` }
319
+ };
320
+ let parsedArgs = call.arguments ?? {};
321
+ if (!call.arguments && typeof call.arguments_json === "string") try {
322
+ parsedArgs = JSON.parse(call.arguments_json);
323
+ } catch {
324
+ return {
325
+ id: call.id,
326
+ name: call.name,
327
+ isError: true,
328
+ response: { error: "arguments_json is not valid JSON" }
329
+ };
330
+ }
331
+ if (def.inputSchema) {
332
+ const fieldErrors = [];
333
+ const validated = {};
334
+ for (const [key, schema] of Object.entries(def.inputSchema)) {
335
+ const result = schema.safeParse(parsedArgs[key]);
336
+ if (!result.success) fieldErrors.push(`${key}: ${result.error.message}`);
337
+ else validated[key] = result.data;
338
+ }
339
+ if (fieldErrors.length > 0) return {
340
+ id: call.id,
341
+ name: call.name,
342
+ isError: true,
343
+ response: {
344
+ error: "argument validation failed",
345
+ fields: fieldErrors
346
+ }
347
+ };
348
+ parsedArgs = validated;
349
+ }
350
+ const result = await def.handler(parsedArgs, ctx);
351
+ return {
352
+ id: call.id,
353
+ name: call.name,
354
+ isError: result.isError,
355
+ response: normalizeResult(result)
356
+ };
357
+ }
358
+ /**
359
+ * Normalize an MCP `CallToolResult` into a flat JSON object the realtime
360
+ * wire can carry. Prefers structuredContent; falls back to concatenated
361
+ * text content.
362
+ */
363
+ function normalizeResult(result) {
364
+ if (result.structuredContent) return result.structuredContent;
365
+ const texts = [];
366
+ for (const part of result.content) if (part.type === "text" && typeof part.text === "string") texts.push(part.text);
367
+ if (texts.length > 0) {
368
+ const joined = texts.join("");
369
+ try {
370
+ const parsed = JSON.parse(joined);
371
+ if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
372
+ } catch {}
373
+ return { text: joined };
374
+ }
375
+ return {};
376
+ }
377
+ //#endregion
378
+ export { bridgeToMcp, buildMcpToolsFromBridges, buildRequestContext, createMcpAuthFromBetterAuthApiKey, createMcpServer, customGuard, defaultCrudDescription, definePrompt, defineTool, denied, dispatchRealtimeToolCall, fieldRulesToZod, filterResourcesForMcp, getOrgId, getUserId, guard, hasOrg, invokeController, isAuthenticated, isOrg, mcpHandlerAdapter, mcpPlugin, permissionDeniedResult, requireAuth, requireOrg, requireOrgId, requireRole, resolveCrudDescription, resolveToolCollisions, resourceToTools, toCallToolError, toCallToolResult, toCallToolSuccess };
@@ -1,4 +1,4 @@
1
- import { c as McpAuthResult, l as McpPluginOptions } from "../../types-CoMjNmkF.mjs";
1
+ import { c as McpAuthResult, l as McpPluginOptions } from "../../types-D3HV0r5L.mjs";
2
2
 
3
3
  //#region src/integrations/mcp/testing.d.ts
4
4
  interface TestMcpClientOptions {
@@ -1,4 +1,4 @@
1
- import { m as createMcpServer, r as resourceToTools, t as filterResourcesForMcp } from "../../mcpPlugin-C6FViZXw.mjs";
1
+ import { m as createMcpServer, r as resourceToTools, t as filterResourcesForMcp } from "../../mcpPlugin-BrepZ0cV.mjs";
2
2
  //#region src/integrations/mcp/testing.ts
3
3
  /**
4
4
  * @classytic/arc/mcp/testing — MCP Test Utilities
@@ -0,0 +1,71 @@
1
+ import { c as SerializedEntry, i as Principal, n as FencedWriteOutcome, s as PushRefStore, t as EnvelopeSnapshot } from "../pushref-registry-Bq_-EVsC.mjs";
2
+
3
+ //#region src/integrations/websocket-pushref-redis.d.ts
4
+ /**
5
+ * Minimal `ioredis` shape — typed structurally so this file doesn't
6
+ * take a typecheck-time dep on `ioredis`. The peer dep is declared
7
+ * `optional: true` in package.json; hosts who don't use this subpath
8
+ * never need to install ioredis.
9
+ */
10
+ interface RedisLike {
11
+ get(key: string): Promise<string | null>;
12
+ set(key: string, value: string, mode?: string, duration?: number): Promise<unknown>;
13
+ del(key: string): Promise<number>;
14
+ pexpire(key: string, ttlMs: number): Promise<number>;
15
+ scan(cursor: string | number, matchKw: "MATCH", pattern: string, countKw: "COUNT", count: number): Promise<[string, string[]]>;
16
+ eval(script: string, numKeys: number, ...args: (string | number)[]): Promise<unknown>;
17
+ }
18
+ interface RedisPushRefStoreOptions {
19
+ /** Redis key namespace. Default `arc:pushref:`. */
20
+ keyPrefix?: string;
21
+ /**
22
+ * Grace ms added to the Redis-side TTL beyond the registry's logical
23
+ * TTL — protects against clock skew between application and broker.
24
+ * Default 5_000.
25
+ */
26
+ graceMs?: number;
27
+ }
28
+ declare class RedisPushRefStore implements PushRefStore {
29
+ private redis;
30
+ private prefix;
31
+ private graceMs;
32
+ constructor(redis: RedisLike, opts?: RedisPushRefStoreOptions);
33
+ get(pushRef: string): Promise<SerializedEntry | undefined>;
34
+ set(pushRef: string, entry: SerializedEntry): Promise<void>;
35
+ delete(pushRef: string): Promise<void>;
36
+ claim(args: {
37
+ pushRef: string;
38
+ principal: Principal;
39
+ now: number;
40
+ ttlMs: number;
41
+ mintFresh: () => SerializedEntry;
42
+ maxEntries: number;
43
+ countNonExpired: () => Promise<number>;
44
+ }): Promise<{
45
+ outcome: "new" | "resumed" | "rejected";
46
+ entry?: SerializedEntry;
47
+ supersededActive?: boolean;
48
+ }>;
49
+ releaseIfGen(args: {
50
+ pushRef: string;
51
+ expectedGeneration: number;
52
+ snapshot?: EnvelopeSnapshot;
53
+ expiresAt: number;
54
+ }): Promise<FencedWriteOutcome>;
55
+ persistIfGen(args: {
56
+ pushRef: string;
57
+ expectedGeneration: number;
58
+ snapshot: EnvelopeSnapshot;
59
+ expiresAt: number;
60
+ }): Promise<FencedWriteOutcome>;
61
+ stageIfInactive(args: {
62
+ pushRef: string;
63
+ payload: unknown;
64
+ timestamp: number;
65
+ expiresAt: number;
66
+ }): Promise<"ok" | "missing" | "active" | "raw">;
67
+ gc(_now: number): Promise<number>;
68
+ size(): Promise<number>;
69
+ }
70
+ //#endregion
71
+ export { RedisLike, RedisPushRefStore, RedisPushRefStoreOptions };
@@ -0,0 +1,205 @@
1
+ //#region src/integrations/websocket-pushref-redis.ts
2
+ /**
3
+ * Lua script for atomic claim. Runs server-side, single-roundtrip.
4
+ *
5
+ * KEYS[1] = key
6
+ * ARGV[1] = principal
7
+ * ARGV[2] = now (ms)
8
+ * ARGV[3] = ttlMs
9
+ * ARGV[4] = mintedJson (serialized SerializedEntry for new-claim path)
10
+ * ARGV[5] = graceMs (added to PEXPIRE so the broker GC's stale keys)
11
+ *
12
+ * Returns: { outcome, json, supersededActive } where
13
+ * outcome ∈ {"new","resumed","rejected"}
14
+ * json is the SerializedEntry (or empty string for reject)
15
+ * supersededActive is "1" when the previous entry was still active
16
+ *
17
+ * Generation handling: every resumed claim bumps `entry.generation` so
18
+ * the connection layer can fence the previous owner. The bump happens
19
+ * atomically inside the script — no read-modify-write race across nodes.
20
+ */
21
+ const CLAIM_SCRIPT = `
22
+ local existing = redis.call('GET', KEYS[1])
23
+ local now = tonumber(ARGV[2])
24
+ local ttl = tonumber(ARGV[3])
25
+ local pexpire = ttl + tonumber(ARGV[5])
26
+ if existing then
27
+ local entry = cjson.decode(existing)
28
+ if entry.active == false and entry.expiresAt <= now then
29
+ -- expired — fall through to new-claim path
30
+ else
31
+ if entry.principal ~= ARGV[1] then
32
+ return {'rejected', '', '0'}
33
+ end
34
+ local superseded = '0'
35
+ if entry.active == true then
36
+ superseded = '1'
37
+ end
38
+ entry.active = true
39
+ entry.expiresAt = now + ttl
40
+ entry.generation = (entry.generation or 0) + 1
41
+ local payload = cjson.encode(entry)
42
+ redis.call('SET', KEYS[1], payload, 'PX', pexpire)
43
+ return {'resumed', payload, superseded}
44
+ end
45
+ end
46
+ redis.call('SET', KEYS[1], ARGV[4], 'PX', pexpire)
47
+ return {'new', ARGV[4], '0'}
48
+ `;
49
+ /**
50
+ * Generation-fenced release. Single Lua roundtrip:
51
+ *
52
+ * KEYS[1] = key
53
+ * ARGV[1] = expectedGeneration
54
+ * ARGV[2] = expiresAt (ms epoch)
55
+ * ARGV[3] = pexpire ms (relative)
56
+ * ARGV[4] = snapshotJson or empty string (skip envelope flush when empty)
57
+ *
58
+ * Returns "ok" | "stale" | "missing".
59
+ *
60
+ * Stale outcome means another node has claimed a higher generation
61
+ * since the caller captured theirs — caller's release is dropped at
62
+ * the store level. This closes the 2.17.2 race where a fenced Node A's
63
+ * close handler could mutate Node B's freshly-claimed entry.
64
+ */
65
+ const RELEASE_IF_GEN_SCRIPT = `
66
+ local existing = redis.call('GET', KEYS[1])
67
+ if not existing then return 'missing' end
68
+ local entry = cjson.decode(existing)
69
+ local expected = tonumber(ARGV[1])
70
+ if entry.generation ~= expected then return 'stale' end
71
+ entry.active = false
72
+ entry.expiresAt = tonumber(ARGV[2])
73
+ if ARGV[4] ~= '' then
74
+ local snap = cjson.decode(ARGV[4])
75
+ entry.nextSeq = snap.nextSeq
76
+ entry.deadQueue = snap.deadQueue
77
+ end
78
+ redis.call('SET', KEYS[1], cjson.encode(entry), 'PX', tonumber(ARGV[3]))
79
+ return 'ok'
80
+ `;
81
+ /**
82
+ * Atomic offline-stage. Closes the read-modify-write race the 2.17.2
83
+ * review surfaced for `stageForResume` — a get-then-set could clobber
84
+ * a freshly-claimed higher-generation entry with the stale inactive
85
+ * snapshot. The whole sequence (test active + seq mode, assign seq,
86
+ * wrap payload, append, trim, extend TTL) runs in one EVAL.
87
+ *
88
+ * KEYS[1] = key
89
+ * ARGV[1] = payloadJson (raw payload, NOT pre-wrapped)
90
+ * ARGV[2] = timestamp (ms, server clock)
91
+ * ARGV[3] = expiresAt (ms epoch)
92
+ * ARGV[4] = pexpire ms
93
+ *
94
+ * Returns "ok" | "missing" | "active" | "raw".
95
+ *
96
+ * Note on JSON key order: cjson.encode and JSON.stringify may emit
97
+ * different orderings; consumers parse the envelope and read by key,
98
+ * so order is not part of the wire contract.
99
+ */
100
+ const STAGE_IF_INACTIVE_SCRIPT = `
101
+ local existing = redis.call('GET', KEYS[1])
102
+ if not existing then return 'missing' end
103
+ local entry = cjson.decode(existing)
104
+ if entry.active then return 'active' end
105
+ if entry.envelopeMode ~= 'seq' then return 'raw' end
106
+ local seq = entry.nextSeq
107
+ entry.nextSeq = seq + 1
108
+ local payload = cjson.decode(ARGV[1])
109
+ local envelope = { seq = seq, t = tonumber(ARGV[2]), msg = payload }
110
+ local serialized = cjson.encode(envelope)
111
+ if not entry.deadQueue then entry.deadQueue = {} end
112
+ table.insert(entry.deadQueue, { seq = seq, payload = serialized })
113
+ while #entry.deadQueue > entry.deadQueueSize do
114
+ table.remove(entry.deadQueue, 1)
115
+ end
116
+ entry.expiresAt = tonumber(ARGV[3])
117
+ redis.call('SET', KEYS[1], cjson.encode(entry), 'PX', tonumber(ARGV[4]))
118
+ return 'ok'
119
+ `;
120
+ /**
121
+ * Generation-fenced persist. Same atomicity contract as release.
122
+ *
123
+ * KEYS[1] = key
124
+ * ARGV[1] = expectedGeneration
125
+ * ARGV[2] = expiresAt
126
+ * ARGV[3] = pexpire ms
127
+ * ARGV[4] = snapshotJson (required for persist — non-empty)
128
+ */
129
+ const PERSIST_IF_GEN_SCRIPT = `
130
+ local existing = redis.call('GET', KEYS[1])
131
+ if not existing then return 'missing' end
132
+ local entry = cjson.decode(existing)
133
+ local expected = tonumber(ARGV[1])
134
+ if entry.generation ~= expected then return 'stale' end
135
+ local snap = cjson.decode(ARGV[4])
136
+ entry.nextSeq = snap.nextSeq
137
+ entry.deadQueue = snap.deadQueue
138
+ entry.expiresAt = tonumber(ARGV[2])
139
+ redis.call('SET', KEYS[1], cjson.encode(entry), 'PX', tonumber(ARGV[3]))
140
+ return 'ok'
141
+ `;
142
+ var RedisPushRefStore = class {
143
+ redis;
144
+ prefix;
145
+ graceMs;
146
+ constructor(redis, opts = {}) {
147
+ this.redis = redis;
148
+ this.prefix = opts.keyPrefix ?? "arc:pushref:";
149
+ this.graceMs = opts.graceMs ?? 5e3;
150
+ }
151
+ async get(pushRef) {
152
+ const raw = await this.redis.get(this.prefix + pushRef);
153
+ if (!raw) return void 0;
154
+ return JSON.parse(raw);
155
+ }
156
+ async set(pushRef, entry) {
157
+ const json = JSON.stringify(entry);
158
+ const pexpire = Math.max(1e3, entry.expiresAt - Date.now() + this.graceMs);
159
+ await this.redis.set(this.prefix + pushRef, json, "PX", pexpire);
160
+ }
161
+ async delete(pushRef) {
162
+ await this.redis.del(this.prefix + pushRef);
163
+ }
164
+ async claim(args) {
165
+ if (args.maxEntries > 0) {
166
+ if (await args.countNonExpired() >= args.maxEntries) {}
167
+ }
168
+ const minted = JSON.stringify(args.mintFresh());
169
+ const result = await this.redis.eval(CLAIM_SCRIPT, 1, this.prefix + args.pushRef, args.principal, args.now, args.ttlMs, minted, this.graceMs);
170
+ const outcome = result[0];
171
+ if (outcome === "rejected") return { outcome };
172
+ return {
173
+ outcome,
174
+ entry: JSON.parse(result[1]),
175
+ supersededActive: result[2] === "1"
176
+ };
177
+ }
178
+ async releaseIfGen(args) {
179
+ const pexpire = Math.max(1e3, args.expiresAt - Date.now() + this.graceMs);
180
+ return await this.redis.eval(RELEASE_IF_GEN_SCRIPT, 1, this.prefix + args.pushRef, args.expectedGeneration, args.expiresAt, pexpire, args.snapshot ? JSON.stringify(args.snapshot) : "");
181
+ }
182
+ async persistIfGen(args) {
183
+ const pexpire = Math.max(1e3, args.expiresAt - Date.now() + this.graceMs);
184
+ return await this.redis.eval(PERSIST_IF_GEN_SCRIPT, 1, this.prefix + args.pushRef, args.expectedGeneration, args.expiresAt, pexpire, JSON.stringify(args.snapshot));
185
+ }
186
+ async stageIfInactive(args) {
187
+ const pexpire = Math.max(1e3, args.expiresAt - Date.now() + this.graceMs);
188
+ return await this.redis.eval(STAGE_IF_INACTIVE_SCRIPT, 1, this.prefix + args.pushRef, JSON.stringify(args.payload), args.timestamp, args.expiresAt, pexpire);
189
+ }
190
+ async gc(_now) {
191
+ return 0;
192
+ }
193
+ async size() {
194
+ let cursor = "0";
195
+ let count = 0;
196
+ do {
197
+ const [next, keys] = await this.redis.scan(cursor, "MATCH", `${this.prefix}*`, "COUNT", 500);
198
+ count += keys.length;
199
+ cursor = next;
200
+ } while (cursor !== "0");
201
+ return count;
202
+ }
203
+ };
204
+ //#endregion
205
+ export { RedisPushRefStore };
@@ -1,4 +1,4 @@
1
- import { c as WebSocketAdapter } from "../websocket-BJ0w-3Dt.mjs";
1
+ import { f as WebSocketAdapter } from "../websocket-BZMUP7Gr.mjs";
2
2
 
3
3
  //#region src/integrations/websocket-redis.d.ts
4
4
  interface RedisLike {
@@ -1,2 +1,3 @@
1
- import { a as WebSocketMessage, c as WebSocketAdapter, i as WebSocketClient, n as websocketPlugin, o as WebSocketPluginOptions, r as AuthResult, s as LocalWebSocketAdapter, t as RoomManager } from "../websocket-BJ0w-3Dt.mjs";
2
- export { AuthResult, LocalWebSocketAdapter, RoomManager, WebSocketAdapter, WebSocketClient, WebSocketMessage, WebSocketPluginOptions, websocketPlugin };
1
+ import { a as GeoRoomOptions, c as WebSocketClient, d as LocalWebSocketAdapter, f as WebSocketAdapter, i as GeoRoom, l as WebSocketMessage, n as GeoPoint, o as RoomManager, r as GeoPublishOpts, s as AuthResult, t as websocketPlugin, u as WebSocketPluginOptions } from "../websocket-BZMUP7Gr.mjs";
2
+ import { a as PushRefRegistry, c as SerializedEntry, i as Principal, o as PushRefRegistryOptions, r as MemoryPushRefStore, s as PushRefStore } from "../pushref-registry-Bq_-EVsC.mjs";
3
+ export { AuthResult, GeoPoint, GeoPublishOpts, GeoRoom, GeoRoomOptions, LocalWebSocketAdapter, MemoryPushRefStore, Principal, PushRefRegistry, PushRefRegistryOptions, PushRefStore, RoomManager, SerializedEntry, WebSocketAdapter, WebSocketClient, WebSocketMessage, WebSocketPluginOptions, websocketPlugin };