@rlanz/socket 0.0.1-6 → 0.0.1-8
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/README.md +186 -147
- package/build/{types-DiYaFvgi.d.ts → base_channel-DPOnqned.d.ts} +185 -171
- package/build/chunk-6PJ4ALJD.js +115 -0
- package/build/chunk-6PJ4ALJD.js.map +1 -0
- package/build/chunk-E6ILCRL3.js +182 -0
- package/build/chunk-E6ILCRL3.js.map +1 -0
- package/build/{chunk-SHH6U4CI.js → chunk-G75J233Z.js} +1 -1
- package/build/chunk-G75J233Z.js.map +1 -0
- package/build/{chunk-B4Y3TNDI.js → chunk-IUQ3GYZZ.js} +5 -24
- package/build/chunk-IUQ3GYZZ.js.map +1 -0
- package/build/chunk-K243S3QP.js +131 -0
- package/build/chunk-K243S3QP.js.map +1 -0
- package/build/chunk-QNOOQXYY.js +899 -0
- package/build/chunk-QNOOQXYY.js.map +1 -0
- package/build/{chunk-FVPY6HZW.js → chunk-YVC7IMDN.js} +21 -5
- package/build/chunk-YVC7IMDN.js.map +1 -0
- package/build/framework-B8pJ4cCA.d.ts +13 -0
- package/build/index-DjBYUhFR.d.ts +150 -0
- package/build/index.d.ts +23 -12
- package/build/index.js +12 -14
- package/build/index.js.map +1 -1
- package/build/providers/socket_provider.d.ts +2 -2
- package/build/providers/socket_provider.js +478 -215
- package/build/providers/socket_provider.js.map +1 -1
- package/build/services/socket.d.ts +2 -2
- package/build/{socket_service-D3jKrleE.d.ts → socket_service-BcC9ASCE.d.ts} +8 -7
- package/build/src/assembler_hook.js +33 -59
- package/build/src/assembler_hook.js.map +1 -1
- package/build/src/client/index.d.ts +3 -147
- package/build/src/client/index.js +4 -837
- package/build/src/client/index.js.map +1 -1
- package/build/src/client/react.d.ts +13 -5
- package/build/src/client/react.js +27 -11
- package/build/src/client/react.js.map +1 -1
- package/build/src/client/types.d.ts +30 -36
- package/build/src/client/vue.d.ts +17 -6
- package/build/src/client/vue.js +31 -13
- package/build/src/client/vue.js.map +1 -1
- package/build/src/decorators.d.ts +3 -2
- package/build/src/decorators.js +1 -1
- package/build/src/health_check.d.ts +2 -2
- package/build/src/health_check.js +14 -3
- package/build/src/health_check.js.map +1 -1
- package/build/src/otel.js +0 -1
- package/build/src/otel.js.map +1 -1
- package/build/src/testing.d.ts +3 -12
- package/build/src/testing.js +1 -1
- package/build/src/types/tracing_channels.d.ts +1 -2
- package/build/src/types.d.ts +1 -1
- package/package.json +3 -9
- package/build/chunk-B4Y3TNDI.js.map +0 -1
- package/build/chunk-FVPY6HZW.js.map +0 -1
- package/build/chunk-HK7Z65DA.js +0 -19
- package/build/chunk-HK7Z65DA.js.map +0 -1
- package/build/chunk-SFAY2ZA4.js +0 -28
- package/build/chunk-SFAY2ZA4.js.map +0 -1
- package/build/chunk-SHH6U4CI.js.map +0 -1
- package/build/chunk-YAX5EHHB.js +0 -453
- package/build/chunk-YAX5EHHB.js.map +0 -1
- package/build/framework-DuW6zpPk.d.ts +0 -14
- package/build/src/client/svelte.d.ts +0 -23
- package/build/src/client/svelte.js +0 -82
- package/build/src/client/svelte.js.map +0 -1
package/build/chunk-YAX5EHHB.js
DELETED
|
@@ -1,453 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getDecoratedChannelHandlers
|
|
3
|
-
} from "./chunk-SHH6U4CI.js";
|
|
4
|
-
|
|
5
|
-
// src/base_channel.ts
|
|
6
|
-
var SocketResponseError = class extends Error {
|
|
7
|
-
};
|
|
8
|
-
var MissingPresenceInfoError = class extends SocketResponseError {
|
|
9
|
-
constructor() {
|
|
10
|
-
super("Presence channels must implement getPresenceInfo(socket)");
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
var BaseChannel = class {
|
|
14
|
-
/**
|
|
15
|
-
* URL-like channel pattern, for example: 'chat/:roomId'.
|
|
16
|
-
*/
|
|
17
|
-
static pattern;
|
|
18
|
-
/**
|
|
19
|
-
* Channel options.
|
|
20
|
-
*/
|
|
21
|
-
static options;
|
|
22
|
-
/**
|
|
23
|
-
* Middlewares to run before subscription.
|
|
24
|
-
*/
|
|
25
|
-
static middlewares;
|
|
26
|
-
/**
|
|
27
|
-
* Event handler map.
|
|
28
|
-
* Ex: { 'chat:send': 'handleSend' }
|
|
29
|
-
*/
|
|
30
|
-
handlers = {};
|
|
31
|
-
/**
|
|
32
|
-
* Injected socket service.
|
|
33
|
-
*/
|
|
34
|
-
socket;
|
|
35
|
-
/**
|
|
36
|
-
* Full channel name, for example: 'chat/general'.
|
|
37
|
-
*/
|
|
38
|
-
channelName;
|
|
39
|
-
/**
|
|
40
|
-
* Parameters extracted from the pattern, for example: { roomId: 'general' }.
|
|
41
|
-
*/
|
|
42
|
-
params;
|
|
43
|
-
/**
|
|
44
|
-
* Injected presence manager when presence is enabled.
|
|
45
|
-
*/
|
|
46
|
-
presence;
|
|
47
|
-
/**
|
|
48
|
-
* Injects dependencies.
|
|
49
|
-
*/
|
|
50
|
-
$setContext(socket, channelName, params, presence) {
|
|
51
|
-
this.socket = socket;
|
|
52
|
-
this.channelName = channelName;
|
|
53
|
-
this.params = params;
|
|
54
|
-
if (presence) {
|
|
55
|
-
this.presence = presence;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Emits to every channel member.
|
|
60
|
-
*/
|
|
61
|
-
broadcast(event, data) {
|
|
62
|
-
this.socket.to(this.channelName).emit(event, data);
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Emits to every channel member except one socket.
|
|
66
|
-
*/
|
|
67
|
-
broadcastExcept(socketId, event, data) {
|
|
68
|
-
this.socket.to(this.channelName).except(socketId).emit(event, data);
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Runs the middleware chain.
|
|
72
|
-
*
|
|
73
|
-
* middleware[0] -> middleware[1] -> ... -> subscribe
|
|
74
|
-
*/
|
|
75
|
-
async $runMiddlewares(ctx) {
|
|
76
|
-
const middlewares = this.constructor.middlewares || [];
|
|
77
|
-
let index = 0;
|
|
78
|
-
const next = async () => {
|
|
79
|
-
if (index >= middlewares.length) return;
|
|
80
|
-
const middleware = middlewares[index++];
|
|
81
|
-
if (typeof middleware === "function") {
|
|
82
|
-
await middleware(ctx, next);
|
|
83
|
-
} else {
|
|
84
|
-
await middleware.handle(ctx, next);
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
await next();
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Dispatches a message to the matching handler.
|
|
91
|
-
* Called by SocketService. Do not override.
|
|
92
|
-
*/
|
|
93
|
-
async $handleMessage(socket, event, data) {
|
|
94
|
-
const handlers = {
|
|
95
|
-
...this.handlers,
|
|
96
|
-
...getDecoratedChannelHandlers(this)
|
|
97
|
-
};
|
|
98
|
-
const handler = handlers[event];
|
|
99
|
-
if (typeof handler === "function") {
|
|
100
|
-
return Reflect.apply(handler, this, [socket, data]);
|
|
101
|
-
}
|
|
102
|
-
return this.onMessage?.(socket, event, data);
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Runs the generic join hook. ChannelSubscriptions owns subscription lifecycle.
|
|
106
|
-
*/
|
|
107
|
-
async $handleJoin(socket, ...params) {
|
|
108
|
-
await this.onJoin?.(socket, ...params);
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Runs the generic leave hook. ChannelSubscriptions owns subscription lifecycle.
|
|
112
|
-
*/
|
|
113
|
-
async $handleLeave(socket, ...params) {
|
|
114
|
-
await this.onLeave?.(socket, ...params);
|
|
115
|
-
}
|
|
116
|
-
$getPresenceInfo(socket) {
|
|
117
|
-
if (!this.getPresenceInfo) {
|
|
118
|
-
throw new MissingPresenceInfoError();
|
|
119
|
-
}
|
|
120
|
-
return this.getPresenceInfo(socket);
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
// src/channel_pattern.ts
|
|
125
|
-
import { exec, match, parse } from "@poppinss/matchit";
|
|
126
|
-
var ChannelPattern = class _ChannelPattern {
|
|
127
|
-
constructor(value) {
|
|
128
|
-
this.value = value;
|
|
129
|
-
this.route = parse(value);
|
|
130
|
-
this.score = this.route.map((segment) => {
|
|
131
|
-
switch (segment.type) {
|
|
132
|
-
case 0:
|
|
133
|
-
return 40;
|
|
134
|
-
case 1:
|
|
135
|
-
return 30;
|
|
136
|
-
case 3:
|
|
137
|
-
return 20;
|
|
138
|
-
case 2:
|
|
139
|
-
return 0;
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
route;
|
|
144
|
-
score;
|
|
145
|
-
static from(value) {
|
|
146
|
-
return new _ChannelPattern(value);
|
|
147
|
-
}
|
|
148
|
-
match(channelName) {
|
|
149
|
-
const matched = match(channelName, [this.route]);
|
|
150
|
-
if (matched.length === 0) {
|
|
151
|
-
return null;
|
|
152
|
-
}
|
|
153
|
-
return Object.fromEntries(
|
|
154
|
-
Object.entries(exec(channelName, matched, true)).map(([name, value]) => [
|
|
155
|
-
name,
|
|
156
|
-
Array.isArray(value) ? value.join("/") : value
|
|
157
|
-
])
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Returns the most specific matching candidate. Static segments outrank params,
|
|
162
|
-
* params outrank optional params, and optional params outrank wildcards.
|
|
163
|
-
* Insertion order is preserved for ties.
|
|
164
|
-
*/
|
|
165
|
-
static firstMatch(channelName, candidates) {
|
|
166
|
-
const sorted = [...candidates].sort((left, right) => {
|
|
167
|
-
return _ChannelPattern.#compareSpecificity(left.pattern, right.pattern);
|
|
168
|
-
});
|
|
169
|
-
const routes = sorted.map((candidate) => candidate.pattern.route);
|
|
170
|
-
const matched = match(channelName, routes);
|
|
171
|
-
if (matched.length === 0) {
|
|
172
|
-
return null;
|
|
173
|
-
}
|
|
174
|
-
for (const { pattern, channel } of sorted) {
|
|
175
|
-
if (pattern.route !== matched) {
|
|
176
|
-
continue;
|
|
177
|
-
}
|
|
178
|
-
const params = pattern.match(channelName);
|
|
179
|
-
if (params) {
|
|
180
|
-
return { pattern, channel, params };
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
return null;
|
|
184
|
-
}
|
|
185
|
-
static #compareSpecificity(left, right) {
|
|
186
|
-
const length = Math.max(left.score.length, right.score.length);
|
|
187
|
-
for (let index = 0; index < length; index++) {
|
|
188
|
-
const scoreDifference = (right.score[index] ?? -1) - (left.score[index] ?? -1);
|
|
189
|
-
if (scoreDifference !== 0) {
|
|
190
|
-
return scoreDifference;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
return right.score.length - left.score.length;
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
// src/channel_router.ts
|
|
198
|
-
var ChannelRouter = class {
|
|
199
|
-
/**
|
|
200
|
-
* Registered channels keyed by their pattern.
|
|
201
|
-
*/
|
|
202
|
-
#channels = /* @__PURE__ */ new Map();
|
|
203
|
-
/**
|
|
204
|
-
* Registers a channel.
|
|
205
|
-
*/
|
|
206
|
-
register(channel) {
|
|
207
|
-
const patternValue = channel.pattern;
|
|
208
|
-
if (!patternValue) {
|
|
209
|
-
throw new Error(`Channel ${channel.name} must define a static pattern`);
|
|
210
|
-
}
|
|
211
|
-
if (this.#channels.has(patternValue)) {
|
|
212
|
-
throw new Error(`Channel pattern "${patternValue}" is already registered`);
|
|
213
|
-
}
|
|
214
|
-
const pattern = ChannelPattern.from(patternValue);
|
|
215
|
-
this.#channels.set(pattern.value, { pattern, channel });
|
|
216
|
-
}
|
|
217
|
-
/**
|
|
218
|
-
* Matches a channel name against registered patterns.
|
|
219
|
-
*/
|
|
220
|
-
match(channelName) {
|
|
221
|
-
const matched = ChannelPattern.firstMatch(channelName, this.#channels.values());
|
|
222
|
-
if (!matched) {
|
|
223
|
-
return null;
|
|
224
|
-
}
|
|
225
|
-
return {
|
|
226
|
-
channel: matched.channel,
|
|
227
|
-
pattern: matched.pattern.value,
|
|
228
|
-
params: matched.params
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
/**
|
|
232
|
-
* Authorizes a socket before it joins a channel.
|
|
233
|
-
*/
|
|
234
|
-
async authorize(socket, channelName) {
|
|
235
|
-
const matched = this.match(channelName);
|
|
236
|
-
if (!matched) {
|
|
237
|
-
return {
|
|
238
|
-
success: false,
|
|
239
|
-
error: "Channel not found"
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
const instance = new matched.channel();
|
|
243
|
-
const paramValues = Object.values(matched.params);
|
|
244
|
-
const ctx = {
|
|
245
|
-
socket,
|
|
246
|
-
channel: channelName,
|
|
247
|
-
params: matched.params,
|
|
248
|
-
presenceData: void 0,
|
|
249
|
-
setPresenceData(data) {
|
|
250
|
-
ctx.presenceData = data;
|
|
251
|
-
}
|
|
252
|
-
};
|
|
253
|
-
try {
|
|
254
|
-
await instance.$runMiddlewares(ctx);
|
|
255
|
-
} catch (error) {
|
|
256
|
-
return {
|
|
257
|
-
success: false,
|
|
258
|
-
error: error instanceof SocketResponseError ? error.message : "Authorization failed",
|
|
259
|
-
cause: error
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
return {
|
|
263
|
-
success: true,
|
|
264
|
-
instance,
|
|
265
|
-
params: matched.params,
|
|
266
|
-
paramValues,
|
|
267
|
-
presenceData: ctx.presenceData ?? null
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
/**
|
|
271
|
-
* Lists all registered channels.
|
|
272
|
-
*/
|
|
273
|
-
list() {
|
|
274
|
-
return [...this.#channels.values()].map(({ pattern, channel }) => ({
|
|
275
|
-
pattern: pattern.value,
|
|
276
|
-
name: channel.name,
|
|
277
|
-
options: channel.options
|
|
278
|
-
}));
|
|
279
|
-
}
|
|
280
|
-
/**
|
|
281
|
-
* Number of registered channels.
|
|
282
|
-
*/
|
|
283
|
-
get size() {
|
|
284
|
-
return this.#channels.size;
|
|
285
|
-
}
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
// src/presence_manager.ts
|
|
289
|
-
var PRESENCE_DATA_KEY = "__rlanzSocketPresence";
|
|
290
|
-
var PresenceManager = class {
|
|
291
|
-
#presence = /* @__PURE__ */ new Map();
|
|
292
|
-
#fetchSockets = null;
|
|
293
|
-
/**
|
|
294
|
-
* Sets the socket fetcher used to build distributed snapshots.
|
|
295
|
-
*/
|
|
296
|
-
setSocketFetcher(fetchSockets) {
|
|
297
|
-
this.#fetchSockets = fetchSockets;
|
|
298
|
-
}
|
|
299
|
-
/**
|
|
300
|
-
* Adds a user to a channel.
|
|
301
|
-
*/
|
|
302
|
-
join(channel, socket, member) {
|
|
303
|
-
const user = {
|
|
304
|
-
...member.data,
|
|
305
|
-
id: member.id,
|
|
306
|
-
joinedAt: /* @__PURE__ */ new Date()
|
|
307
|
-
};
|
|
308
|
-
const users = this.#presence.get(channel) ?? /* @__PURE__ */ new Map();
|
|
309
|
-
users.set(socket.id, user);
|
|
310
|
-
this.#presence.set(channel, users);
|
|
311
|
-
this.#setSocketPresence(socket, channel, user);
|
|
312
|
-
return user;
|
|
313
|
-
}
|
|
314
|
-
/**
|
|
315
|
-
* Removes a user from a channel.
|
|
316
|
-
*/
|
|
317
|
-
leave(channel, socket) {
|
|
318
|
-
const channelPresence = this.#presence.get(channel);
|
|
319
|
-
if (channelPresence) {
|
|
320
|
-
channelPresence.delete(socket.id);
|
|
321
|
-
if (channelPresence.size === 0) {
|
|
322
|
-
this.#presence.delete(channel);
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
this.#deleteSocketPresence(socket, channel);
|
|
326
|
-
}
|
|
327
|
-
/**
|
|
328
|
-
* Removes a user from every channel.
|
|
329
|
-
* Returns the list of channels the user left.
|
|
330
|
-
*/
|
|
331
|
-
leaveAll(socket) {
|
|
332
|
-
const leftChannels = [];
|
|
333
|
-
for (const [channel, users] of this.#presence) {
|
|
334
|
-
if (users.has(socket.id)) {
|
|
335
|
-
users.delete(socket.id);
|
|
336
|
-
leftChannels.push(channel);
|
|
337
|
-
if (users.size === 0) {
|
|
338
|
-
this.#presence.delete(channel);
|
|
339
|
-
}
|
|
340
|
-
this.#deleteSocketPresence(socket, channel);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
return leftChannels;
|
|
344
|
-
}
|
|
345
|
-
/**
|
|
346
|
-
* Gets presence data for a channel.
|
|
347
|
-
*/
|
|
348
|
-
async snapshot(channel) {
|
|
349
|
-
if (this.#fetchSockets) {
|
|
350
|
-
return this.#getFromSockets(channel);
|
|
351
|
-
}
|
|
352
|
-
return this.#localSnapshot(channel);
|
|
353
|
-
}
|
|
354
|
-
/**
|
|
355
|
-
* Gets the number of users in a channel.
|
|
356
|
-
*/
|
|
357
|
-
async count(channel) {
|
|
358
|
-
return (await this.snapshot(channel)).count;
|
|
359
|
-
}
|
|
360
|
-
/**
|
|
361
|
-
* Checks whether a socket is locally present in a channel.
|
|
362
|
-
*/
|
|
363
|
-
hasLocal(channel, socketId) {
|
|
364
|
-
return this.#presence.get(channel)?.has(socketId) || false;
|
|
365
|
-
}
|
|
366
|
-
/**
|
|
367
|
-
* Gets the presence user retained for one local socket.
|
|
368
|
-
*/
|
|
369
|
-
getLocalUser(channel, socketId) {
|
|
370
|
-
return this.#presence.get(channel)?.get(socketId);
|
|
371
|
-
}
|
|
372
|
-
/**
|
|
373
|
-
* Lists every local channel where a socket is present.
|
|
374
|
-
*/
|
|
375
|
-
getLocalChannelsForSocket(socketId) {
|
|
376
|
-
const channels = [];
|
|
377
|
-
for (const [channel, users] of this.#presence) {
|
|
378
|
-
if (users.has(socketId)) {
|
|
379
|
-
channels.push(channel);
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
return channels;
|
|
383
|
-
}
|
|
384
|
-
/**
|
|
385
|
-
* Lists sockets that are locally present in a channel.
|
|
386
|
-
*/
|
|
387
|
-
getLocalSockets(channel) {
|
|
388
|
-
const users = this.#presence.get(channel);
|
|
389
|
-
if (!users) {
|
|
390
|
-
return [];
|
|
391
|
-
}
|
|
392
|
-
return Array.from(users.entries()).map(([socketId, user]) => ({
|
|
393
|
-
id: socketId,
|
|
394
|
-
data: {
|
|
395
|
-
[PRESENCE_DATA_KEY]: {
|
|
396
|
-
[channel]: user
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
}));
|
|
400
|
-
}
|
|
401
|
-
#localSnapshot(channel) {
|
|
402
|
-
return this.#createSnapshot(channel, Array.from(this.#presence.get(channel)?.entries() ?? []));
|
|
403
|
-
}
|
|
404
|
-
async #getFromSockets(channel) {
|
|
405
|
-
const sockets = await this.#fetchSockets(channel);
|
|
406
|
-
const users = sockets.flatMap((socket) => {
|
|
407
|
-
const user = socket.data?.[PRESENCE_DATA_KEY]?.[channel];
|
|
408
|
-
return user ? [[socket.id, user]] : [];
|
|
409
|
-
});
|
|
410
|
-
return this.#createSnapshot(channel, users);
|
|
411
|
-
}
|
|
412
|
-
#createSnapshot(channel, connections) {
|
|
413
|
-
const usersById = /* @__PURE__ */ new Map();
|
|
414
|
-
for (const connection of connections) {
|
|
415
|
-
const current = usersById.get(connection[1].id);
|
|
416
|
-
if (!current || this.#compareConnections(connection, current) < 0) {
|
|
417
|
-
usersById.set(connection[1].id, connection);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
const users = [...usersById.values()].sort((left, right) => this.#compareConnections(left, right)).map(([, user]) => user);
|
|
421
|
-
return {
|
|
422
|
-
channel,
|
|
423
|
-
users,
|
|
424
|
-
count: users.length
|
|
425
|
-
};
|
|
426
|
-
}
|
|
427
|
-
#compareConnections([leftSocketId, leftUser], [rightSocketId, rightUser]) {
|
|
428
|
-
const joinedAtDifference = leftUser.joinedAt.getTime() - rightUser.joinedAt.getTime();
|
|
429
|
-
return joinedAtDifference || leftSocketId.localeCompare(rightSocketId);
|
|
430
|
-
}
|
|
431
|
-
#setSocketPresence(socket, channel, user) {
|
|
432
|
-
socket.data[PRESENCE_DATA_KEY] ??= {};
|
|
433
|
-
socket.data[PRESENCE_DATA_KEY][channel] = user;
|
|
434
|
-
}
|
|
435
|
-
#deleteSocketPresence(socket, channel) {
|
|
436
|
-
if (!socket.data[PRESENCE_DATA_KEY]) {
|
|
437
|
-
return;
|
|
438
|
-
}
|
|
439
|
-
delete socket.data[PRESENCE_DATA_KEY][channel];
|
|
440
|
-
if (Object.keys(socket.data[PRESENCE_DATA_KEY]).length === 0) {
|
|
441
|
-
delete socket.data[PRESENCE_DATA_KEY];
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
};
|
|
445
|
-
|
|
446
|
-
export {
|
|
447
|
-
SocketResponseError,
|
|
448
|
-
BaseChannel,
|
|
449
|
-
ChannelRouter,
|
|
450
|
-
PRESENCE_DATA_KEY,
|
|
451
|
-
PresenceManager
|
|
452
|
-
};
|
|
453
|
-
//# sourceMappingURL=chunk-YAX5EHHB.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/base_channel.ts","../src/channel_pattern.ts","../src/channel_router.ts","../src/presence_manager.ts"],"sourcesContent":["import type {\n AuthenticatedSocket,\n ChannelOptions,\n PresenceInfo,\n PresenceMember,\n Middleware,\n MiddlewareContext,\n ChannelHandlerMap,\n} from './types.js'\nimport type { PresenceManager } from './presence_manager.js'\nimport { getDecoratedChannelHandlers } from './decorators.js'\n\ninterface ChannelBroadcaster {\n to(channel: string): {\n emit(event: string, data: unknown): void\n except(socketId: string): {\n emit(event: string, data: unknown): void\n }\n }\n}\n\n/**\n * Error whose message may intentionally be returned to a socket client.\n */\nexport class SocketResponseError extends Error {}\n\nexport class MissingPresenceInfoError extends SocketResponseError {\n constructor() {\n super('Presence channels must implement getPresenceInfo(socket)')\n }\n}\n\n/**\n * Abstract class used to define a channel.\n *\n * @example\n * ```ts\n * export default class ChatChannel extends BaseChannel {\n * static pattern = 'chat/:roomId'\n * static middlewares = [\n * async (ctx, next) => {\n * // Authorize access to the channel through middleware.\n * // if (!Room.isMember(ctx.params.roomId, ctx.socket.user.id)) throw new Error('Forbidden')\n * await next()\n * },\n * ]\n * }\n * ```\n *\n * @example With presence and decorated handlers\n * ```ts\n * import { onMessage } from '@rlanz/socket/decorators'\n *\n * export default class ChatChannel extends BaseChannel {\n * static pattern = 'chat/:roomId'\n * static options = { presence: true }\n *\n * static middlewares = [\n * async (ctx, next) => {\n * if (!ctx.socket.user.isVerified) throw new Error('Not verified')\n * await next()\n * }\n * ]\n *\n * @onMessage('chat:send')\n * async handleSend(socket: AuthenticatedSocket<User>, data: unknown) {\n * // Handle chat:send event\n * }\n *\n * @onMessage('chat:typing')\n * async handleTyping(socket: AuthenticatedSocket<User>, data: unknown) {\n * // Handle chat:typing event\n * }\n * }\n * ```\n */\nexport class BaseChannel<User = unknown, ServerEvents = unknown> {\n /** Type-only server event declarations consumed by generated browser client types. */\n declare readonly $serverEvents: ServerEvents\n /**\n * URL-like channel pattern, for example: 'chat/:roomId'.\n */\n static pattern: string\n\n /**\n * Channel options.\n */\n static options?: ChannelOptions\n\n /**\n * Middlewares to run before subscription.\n */\n static middlewares?: Middleware<any>[]\n\n /**\n * Event handler map.\n * Ex: { 'chat:send': 'handleSend' }\n */\n protected handlers: ChannelHandlerMap<User> = {}\n\n /**\n * Injected socket service.\n */\n protected socket!: ChannelBroadcaster\n\n /**\n * Full channel name, for example: 'chat/general'.\n */\n protected channelName!: string\n\n /**\n * Parameters extracted from the pattern, for example: { roomId: 'general' }.\n */\n protected params!: Record<string, string>\n\n /**\n * Injected presence manager when presence is enabled.\n */\n protected presence!: PresenceManager\n\n /**\n * Injects dependencies.\n */\n $setContext(\n socket: ChannelBroadcaster,\n channelName: string,\n params: Record<string, string>,\n presence?: PresenceManager\n ): void {\n this.socket = socket\n this.channelName = channelName\n this.params = params\n if (presence) {\n this.presence = presence\n }\n }\n\n /**\n * Emits to every channel member.\n */\n protected broadcast<\n K extends unknown extends ServerEvents ? string : keyof ServerEvents & string,\n >(\n event: K,\n data: unknown extends ServerEvents ? unknown : ServerEvents[K & keyof ServerEvents]\n ): void {\n this.socket.to(this.channelName).emit(event, data)\n }\n\n /**\n * Emits to every channel member except one socket.\n */\n protected broadcastExcept<\n K extends unknown extends ServerEvents ? string : keyof ServerEvents & string,\n >(\n socketId: string,\n event: K,\n data: unknown extends ServerEvents ? unknown : ServerEvents[K & keyof ServerEvents]\n ): void {\n this.socket.to(this.channelName).except(socketId).emit(event, data)\n }\n\n /**\n * Runs the middleware chain.\n *\n * middleware[0] -> middleware[1] -> ... -> subscribe\n */\n async $runMiddlewares(ctx: MiddlewareContext<User>): Promise<void> {\n const middlewares = (this.constructor as typeof BaseChannel).middlewares || []\n\n let index = 0\n\n const next = async (): Promise<void> => {\n if (index >= middlewares.length) return\n\n const middleware = middlewares[index++]\n\n if (typeof middleware === 'function') {\n await middleware(ctx, next)\n } else {\n await middleware.handle(ctx, next)\n }\n }\n\n await next()\n }\n\n /**\n * Returns member information for presence.\n * Implement when options.presence = true.\n */\n getPresenceInfo?(socket: AuthenticatedSocket<User>): PresenceInfo\n\n /**\n * Hook called when a socket joins the channel.\n */\n onJoin?(socket: AuthenticatedSocket<User>, ...params: string[]): Promise<void>\n\n /**\n * Hook called when a socket leaves the channel.\n */\n onLeave?(socket: AuthenticatedSocket<User>, ...params: string[]): Promise<void>\n\n /**\n * Hook called when a message is received on the channel.\n * Used as fallback when no event handler matches.\n */\n onMessage?(socket: AuthenticatedSocket<User>, event: string, data: unknown): Promise<void>\n\n /**\n * Hook called when a member joins a presence channel.\n */\n onMemberJoin?(\n socket: AuthenticatedSocket<User>,\n member: PresenceMember,\n ...params: string[]\n ): Promise<void>\n\n /**\n * Hook called when a member leaves a presence channel.\n */\n onMemberLeave?(\n socket: AuthenticatedSocket<User>,\n member: PresenceMember,\n ...params: string[]\n ): Promise<void>\n\n /**\n * Dispatches a message to the matching handler.\n * Called by SocketService. Do not override.\n */\n async $handleMessage(\n socket: AuthenticatedSocket<User>,\n event: string,\n data: unknown\n ): Promise<unknown> {\n const handlers: Record<string, unknown> = {\n ...this.handlers,\n ...getDecoratedChannelHandlers<User>(this),\n }\n const handler = handlers[event]\n\n if (typeof handler === 'function') {\n return Reflect.apply(handler, this, [socket, data])\n }\n\n // Fall back to onMessage when it is defined.\n return this.onMessage?.(socket, event, data)\n }\n\n /**\n * Runs the generic join hook. ChannelSubscriptions owns subscription lifecycle.\n */\n async $handleJoin(socket: AuthenticatedSocket<User>, ...params: string[]): Promise<void> {\n await this.onJoin?.(socket, ...params)\n }\n\n /**\n * Runs the generic leave hook. ChannelSubscriptions owns subscription lifecycle.\n */\n async $handleLeave(socket: AuthenticatedSocket<User>, ...params: string[]): Promise<void> {\n await this.onLeave?.(socket, ...params)\n }\n\n $getPresenceInfo(socket: AuthenticatedSocket<User>): PresenceInfo {\n if (!this.getPresenceInfo) {\n throw new MissingPresenceInfoError()\n }\n\n return this.getPresenceInfo(socket)\n }\n}\n\n/** Constructor for any BaseChannel specialization. */\nexport type BaseChannelConstructor = typeof BaseChannel<any, any>\n","import type { BaseChannelConstructor } from './base_channel.js'\nimport { exec, match, parse, type ParsedRoute } from '@poppinss/matchit'\n\ntype MatchParams = Record<string, string>\n\nexport interface ChannelPatternMatch {\n pattern: ChannelPattern\n channel: BaseChannelConstructor\n params: MatchParams\n}\n\ninterface MatchCandidate {\n pattern: ChannelPattern\n channel: BaseChannelConstructor\n}\n\nexport class ChannelPattern {\n readonly route: ParsedRoute\n readonly score: number[]\n\n private constructor(readonly value: string) {\n this.route = parse(value)\n this.score = this.route.map((segment) => {\n switch (segment.type) {\n case 0:\n return 40\n case 1:\n return 30\n case 3:\n return 20\n case 2:\n return 0\n }\n })\n }\n\n static from(value: string): ChannelPattern {\n return new ChannelPattern(value)\n }\n\n match(channelName: string): MatchParams | null {\n const matched = match(channelName, [this.route])\n if (matched.length === 0) {\n return null\n }\n\n return Object.fromEntries(\n Object.entries(exec(channelName, matched, true)).map(([name, value]) => [\n name,\n Array.isArray(value) ? value.join('/') : value,\n ])\n )\n }\n\n /**\n * Returns the most specific matching candidate. Static segments outrank params,\n * params outrank optional params, and optional params outrank wildcards.\n * Insertion order is preserved for ties.\n */\n static firstMatch(\n channelName: string,\n candidates: Iterable<MatchCandidate>\n ): ChannelPatternMatch | null {\n const sorted = [...candidates].sort((left, right) => {\n return ChannelPattern.#compareSpecificity(left.pattern, right.pattern)\n })\n const routes = sorted.map((candidate) => candidate.pattern.route)\n const matched = match(channelName, routes)\n\n if (matched.length === 0) {\n return null\n }\n\n for (const { pattern, channel } of sorted) {\n if (pattern.route !== matched) {\n continue\n }\n\n const params = pattern.match(channelName)\n if (params) {\n return { pattern, channel, params }\n }\n }\n\n return null\n }\n\n static #compareSpecificity(left: ChannelPattern, right: ChannelPattern): number {\n const length = Math.max(left.score.length, right.score.length)\n\n for (let index = 0; index < length; index++) {\n const scoreDifference = (right.score[index] ?? -1) - (left.score[index] ?? -1)\n if (scoreDifference !== 0) {\n return scoreDifference\n }\n }\n\n return right.score.length - left.score.length\n }\n}\n","import {\n SocketResponseError,\n type BaseChannel,\n type BaseChannelConstructor,\n} from './base_channel.js'\nimport { ChannelPattern } from './channel_pattern.js'\nimport type { AuthenticatedSocket, ChannelMatch, MiddlewareContext } from './types.js'\n\ninterface RegisteredChannel {\n pattern: ChannelPattern\n channel: BaseChannelConstructor\n}\n\n/**\n * Matches channel names against registered patterns.\n *\n * Pattern: chat/:roomId\n * Channel: chat/general\n *\n * chat / :roomId\n * | |\n * chat / general => { roomId: \"general\" }\n */\nexport class ChannelRouter {\n /**\n * Registered channels keyed by their pattern.\n */\n #channels = new Map<string, RegisteredChannel>()\n\n /**\n * Registers a channel.\n */\n register(channel: BaseChannelConstructor): void {\n const patternValue = channel.pattern\n\n if (!patternValue) {\n throw new Error(`Channel ${channel.name} must define a static pattern`)\n }\n\n if (this.#channels.has(patternValue)) {\n throw new Error(`Channel pattern \"${patternValue}\" is already registered`)\n }\n\n const pattern = ChannelPattern.from(patternValue)\n\n this.#channels.set(pattern.value, { pattern, channel })\n }\n\n /**\n * Matches a channel name against registered patterns.\n */\n match(channelName: string): ChannelMatch | null {\n const matched = ChannelPattern.firstMatch(channelName, this.#channels.values())\n\n if (!matched) {\n return null\n }\n\n return {\n channel: matched.channel,\n pattern: matched.pattern.value,\n params: matched.params,\n }\n }\n\n /**\n * Authorizes a socket before it joins a channel.\n */\n async authorize<User = unknown>(socket: AuthenticatedSocket<User>, channelName: string) {\n const matched = this.match(channelName)\n\n if (!matched) {\n return {\n success: false,\n error: 'Channel not found',\n } as const\n }\n\n const instance = new matched.channel() as BaseChannel<User>\n const paramValues = Object.values(matched.params)\n\n const ctx: MiddlewareContext<User> = {\n socket,\n channel: channelName,\n params: matched.params,\n presenceData: undefined,\n setPresenceData(data) {\n ctx.presenceData = data\n },\n }\n\n // Run authorization middlewares.\n try {\n await instance.$runMiddlewares(ctx)\n } catch (error) {\n return {\n success: false,\n error: error instanceof SocketResponseError ? error.message : 'Authorization failed',\n cause: error,\n } as const\n }\n\n return {\n success: true,\n instance,\n params: matched.params,\n paramValues,\n presenceData: ctx.presenceData ?? null,\n } as const\n }\n\n /**\n * Lists all registered channels.\n */\n list() {\n return [...this.#channels.values()].map(({ pattern, channel }) => ({\n pattern: pattern.value,\n name: channel.name,\n options: channel.options,\n }))\n }\n\n /**\n * Number of registered channels.\n */\n get size(): number {\n return this.#channels.size\n }\n}\n","import type { PresenceInfo } from './types.js'\n\nexport const PRESENCE_DATA_KEY = '__rlanzSocketPresence'\n\ntype PresenceSocketData = Record<string, unknown> & {\n [PRESENCE_DATA_KEY]?: Record<string, PresenceUser>\n}\n\nexport interface PresenceUser {\n id: string\n joinedAt: Date\n [key: string]: unknown\n}\n\nexport interface PresenceData {\n channel: string\n users: PresenceUser[]\n count: number\n}\n\nexport interface PresenceSocket {\n id: string\n data: PresenceSocketData\n}\n\n/**\n * Tracks user presence in channels.\n *\n * channel -> socketId -> PresenceUser\n */\nexport class PresenceManager {\n #presence = new Map<string, Map<string, PresenceUser>>()\n #fetchSockets: ((channel: string) => Promise<PresenceSocket[]>) | null = null\n\n /**\n * Sets the socket fetcher used to build distributed snapshots.\n */\n setSocketFetcher(fetchSockets: ((channel: string) => Promise<PresenceSocket[]>) | null): void {\n this.#fetchSockets = fetchSockets\n }\n\n /**\n * Adds a user to a channel.\n */\n join(channel: string, socket: PresenceSocket, member: PresenceInfo): PresenceUser {\n const user = {\n ...member.data,\n id: member.id,\n joinedAt: new Date(),\n }\n\n const users = this.#presence.get(channel) ?? new Map()\n users.set(socket.id, user)\n this.#presence.set(channel, users)\n this.#setSocketPresence(socket, channel, user)\n\n return user\n }\n\n /**\n * Removes a user from a channel.\n */\n leave(channel: string, socket: PresenceSocket): void {\n const channelPresence = this.#presence.get(channel)\n\n if (channelPresence) {\n channelPresence.delete(socket.id)\n\n if (channelPresence.size === 0) {\n this.#presence.delete(channel)\n }\n }\n\n this.#deleteSocketPresence(socket, channel)\n }\n\n /**\n * Removes a user from every channel.\n * Returns the list of channels the user left.\n */\n leaveAll(socket: PresenceSocket): string[] {\n const leftChannels: string[] = []\n\n for (const [channel, users] of this.#presence) {\n if (users.has(socket.id)) {\n users.delete(socket.id)\n leftChannels.push(channel)\n\n if (users.size === 0) {\n this.#presence.delete(channel)\n }\n\n this.#deleteSocketPresence(socket, channel)\n }\n }\n\n return leftChannels\n }\n\n /**\n * Gets presence data for a channel.\n */\n async snapshot(channel: string): Promise<PresenceData> {\n if (this.#fetchSockets) {\n return this.#getFromSockets(channel)\n }\n\n return this.#localSnapshot(channel)\n }\n\n /**\n * Gets the number of users in a channel.\n */\n async count(channel: string): Promise<number> {\n return (await this.snapshot(channel)).count\n }\n\n /**\n * Checks whether a socket is locally present in a channel.\n */\n hasLocal(channel: string, socketId: string): boolean {\n return this.#presence.get(channel)?.has(socketId) || false\n }\n\n /**\n * Gets the presence user retained for one local socket.\n */\n getLocalUser(channel: string, socketId: string): PresenceUser | undefined {\n return this.#presence.get(channel)?.get(socketId)\n }\n\n /**\n * Lists every local channel where a socket is present.\n */\n getLocalChannelsForSocket(socketId: string): string[] {\n const channels: string[] = []\n\n for (const [channel, users] of this.#presence) {\n if (users.has(socketId)) {\n channels.push(channel)\n }\n }\n\n return channels\n }\n\n /**\n * Lists sockets that are locally present in a channel.\n */\n getLocalSockets(channel: string): PresenceSocket[] {\n const users = this.#presence.get(channel)\n\n if (!users) {\n return []\n }\n\n return Array.from(users.entries()).map(([socketId, user]) => ({\n id: socketId,\n data: {\n [PRESENCE_DATA_KEY]: {\n [channel]: user,\n },\n },\n }))\n }\n\n #localSnapshot(channel: string): PresenceData {\n return this.#createSnapshot(channel, Array.from(this.#presence.get(channel)?.entries() ?? []))\n }\n\n async #getFromSockets(channel: string): Promise<PresenceData> {\n const sockets = await this.#fetchSockets!(channel)\n const users = sockets.flatMap((socket): Array<[string, PresenceUser]> => {\n const user = socket.data?.[PRESENCE_DATA_KEY]?.[channel]\n return user ? [[socket.id, user]] : []\n })\n\n return this.#createSnapshot(channel, users)\n }\n\n #createSnapshot(\n channel: string,\n connections: Array<[socketId: string, user: PresenceUser]>\n ): PresenceData {\n const usersById = new Map<string, [socketId: string, user: PresenceUser]>()\n\n for (const connection of connections) {\n const current = usersById.get(connection[1].id)\n if (!current || this.#compareConnections(connection, current) < 0) {\n usersById.set(connection[1].id, connection)\n }\n }\n\n const users = [...usersById.values()]\n .sort((left, right) => this.#compareConnections(left, right))\n .map(([, user]) => user)\n\n return {\n channel,\n users,\n count: users.length,\n }\n }\n\n #compareConnections(\n [leftSocketId, leftUser]: [string, PresenceUser],\n [rightSocketId, rightUser]: [string, PresenceUser]\n ): number {\n const joinedAtDifference = leftUser.joinedAt.getTime() - rightUser.joinedAt.getTime()\n return joinedAtDifference || leftSocketId.localeCompare(rightSocketId)\n }\n\n #setSocketPresence(socket: PresenceSocket, channel: string, user: PresenceUser): void {\n socket.data[PRESENCE_DATA_KEY] ??= {}\n socket.data[PRESENCE_DATA_KEY][channel] = user\n }\n\n #deleteSocketPresence(socket: PresenceSocket, channel: string): void {\n if (!socket.data[PRESENCE_DATA_KEY]) {\n return\n }\n\n delete socket.data[PRESENCE_DATA_KEY][channel]\n\n if (Object.keys(socket.data[PRESENCE_DATA_KEY]).length === 0) {\n delete socket.data[PRESENCE_DATA_KEY]\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { Channel } from './src/client/index.js';
|
|
2
|
-
import { ChannelContract, ChannelContractFor } from './src/client/types.js';
|
|
3
|
-
|
|
4
|
-
type UnknownContract = ChannelContract<unknown, unknown>;
|
|
5
|
-
type ServerEvents<Contract> = Contract extends ChannelContract<unknown, infer Events> ? Events : unknown;
|
|
6
|
-
type IsUnknown<Value> = unknown extends Value ? true : false;
|
|
7
|
-
type FrameworkChannelMember<Registry, Name extends string> = string extends Name ? Channel<UnknownContract> : [Registry] extends [never] ? Channel<UnknownContract> : ChannelContractFor<Registry, Name> extends infer Contract ? [Contract] extends [never] ? never : Channel<Contract> : never;
|
|
8
|
-
type FrameworkChannel<Registry, Name extends string> = Name extends unknown ? FrameworkChannelMember<Registry, Name> : never;
|
|
9
|
-
type FrameworkChannelNameValidity<Registry, Name extends string> = Name extends unknown ? FrameworkChannelMember<Registry, Name> extends never ? false : true : never;
|
|
10
|
-
type FrameworkChannelName<Registry, Name extends string> = Name & ([FrameworkChannelNameValidity<Registry, Name>] extends [true] ? unknown : never);
|
|
11
|
-
type FrameworkChannelEvent<Registry, Name extends string> = FrameworkChannel<Registry, Name> extends Channel<infer Contract> ? IsUnknown<ServerEvents<Contract>> extends true ? string : Extract<keyof ServerEvents<Contract>, string> : never;
|
|
12
|
-
type FrameworkChannelEventPayload<Registry, Name extends string, Event extends FrameworkChannelEvent<Registry, Name>> = FrameworkChannel<Registry, Name> extends Channel<infer Contract> ? IsUnknown<ServerEvents<Contract>> extends true ? unknown : Event extends keyof ServerEvents<Contract> ? ServerEvents<Contract>[Event] : never : never;
|
|
13
|
-
|
|
14
|
-
export type { FrameworkChannelName as F, FrameworkChannel as a, FrameworkChannelEvent as b, FrameworkChannelEventPayload as c };
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { Readable } from 'svelte/store';
|
|
2
|
-
import { Socket } from './index.js';
|
|
3
|
-
import { ConnectionState, EventHandler } from './types.js';
|
|
4
|
-
import { F as FrameworkChannelName, a as FrameworkChannel, b as FrameworkChannelEvent, c as FrameworkChannelEventPayload } from '../../framework-DuW6zpPk.js';
|
|
5
|
-
import '../../types-DiYaFvgi.js';
|
|
6
|
-
import 'ws';
|
|
7
|
-
import 'node:http';
|
|
8
|
-
import '@adonisjs/core/types/http';
|
|
9
|
-
import '@adonisjs/core/http';
|
|
10
|
-
import '@boringnode/bus/types/main';
|
|
11
|
-
|
|
12
|
-
type ChannelNameInput<Registry, Name extends string> = (Name & FrameworkChannelName<Registry, NoInfer<Name>>) | null | (Readable<Name | null> & Readable<FrameworkChannelName<Registry, NoInfer<Name>> | null>);
|
|
13
|
-
declare function createSocketContext<Registry = never>(): {
|
|
14
|
-
setSocket: (socket: Socket<Registry>, options?: {
|
|
15
|
-
owned?: boolean;
|
|
16
|
-
}) => void;
|
|
17
|
-
useSocket: () => Socket<Registry>;
|
|
18
|
-
useSocketState: () => Readable<ConnectionState>;
|
|
19
|
-
channel: <const Name extends string>(name: ChannelNameInput<Registry, Name>) => Readable<FrameworkChannel<Registry, Name> | null>;
|
|
20
|
-
onChannelEvent: <const Name extends string, Event extends FrameworkChannelEvent<Registry, Name>>(name: ChannelNameInput<Registry, Name>, event: Event, handler: EventHandler<FrameworkChannelEventPayload<Registry, Name, Event>>) => () => void;
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
export { createSocketContext };
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
acquireChannel,
|
|
3
|
-
acquireSocketOwnership
|
|
4
|
-
} from "../../chunk-FVPY6HZW.js";
|
|
5
|
-
import "../../chunk-SFAY2ZA4.js";
|
|
6
|
-
|
|
7
|
-
// src/client/svelte.ts
|
|
8
|
-
import { getContext, onDestroy, onMount, setContext } from "svelte";
|
|
9
|
-
import { readable } from "svelte/store";
|
|
10
|
-
function isReadable(value) {
|
|
11
|
-
return typeof value === "object" && value !== null && "subscribe" in value;
|
|
12
|
-
}
|
|
13
|
-
function createSocketContext() {
|
|
14
|
-
const key = /* @__PURE__ */ Symbol("socket");
|
|
15
|
-
function setSocket(socket, options = {}) {
|
|
16
|
-
const state = readable(socket.state, (set) => socket.onStateChange(set));
|
|
17
|
-
setContext(key, { socket, state });
|
|
18
|
-
if (options.owned) {
|
|
19
|
-
onMount(() => acquireSocketOwnership(socket));
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
function useContext() {
|
|
23
|
-
const context = getContext(key);
|
|
24
|
-
if (!context) throw new Error("setSocket must be called by an ancestor");
|
|
25
|
-
return context;
|
|
26
|
-
}
|
|
27
|
-
function useSocket() {
|
|
28
|
-
return useContext().socket;
|
|
29
|
-
}
|
|
30
|
-
function useSocketState() {
|
|
31
|
-
return useContext().state;
|
|
32
|
-
}
|
|
33
|
-
function channel(name) {
|
|
34
|
-
const socket = useSocket();
|
|
35
|
-
return readable(null, (set) => {
|
|
36
|
-
let release;
|
|
37
|
-
const acquire = (nextName) => {
|
|
38
|
-
release?.();
|
|
39
|
-
release = void 0;
|
|
40
|
-
if (nextName === null) {
|
|
41
|
-
set(null);
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
const acquired = acquireChannel(socket, nextName);
|
|
45
|
-
release = () => acquired.lease.release();
|
|
46
|
-
set(acquired.channel);
|
|
47
|
-
};
|
|
48
|
-
const stopName = isReadable(name) ? name.subscribe(acquire) : (acquire(name), void 0);
|
|
49
|
-
return () => {
|
|
50
|
-
stopName?.();
|
|
51
|
-
release?.();
|
|
52
|
-
};
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
function onChannelEvent(name, event, handler) {
|
|
56
|
-
const socket = useSocket();
|
|
57
|
-
let release;
|
|
58
|
-
const acquire = (nextName) => {
|
|
59
|
-
release?.();
|
|
60
|
-
release = void 0;
|
|
61
|
-
if (nextName === null) return;
|
|
62
|
-
const { lease } = acquireChannel(socket, nextName);
|
|
63
|
-
lease.listen(event, handler);
|
|
64
|
-
release = () => lease.release();
|
|
65
|
-
};
|
|
66
|
-
const stopName = isReadable(name) ? name.subscribe(acquire) : (acquire(name), void 0);
|
|
67
|
-
let disposed = false;
|
|
68
|
-
const dispose = () => {
|
|
69
|
-
if (disposed) return;
|
|
70
|
-
disposed = true;
|
|
71
|
-
stopName?.();
|
|
72
|
-
release?.();
|
|
73
|
-
};
|
|
74
|
-
onDestroy(dispose);
|
|
75
|
-
return dispose;
|
|
76
|
-
}
|
|
77
|
-
return { setSocket, useSocket, useSocketState, channel, onChannelEvent };
|
|
78
|
-
}
|
|
79
|
-
export {
|
|
80
|
-
createSocketContext
|
|
81
|
-
};
|
|
82
|
-
//# sourceMappingURL=svelte.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/client/svelte.ts"],"sourcesContent":["import { getContext, onDestroy, onMount, setContext } from 'svelte'\nimport { readable, type Readable } from 'svelte/store'\nimport type { Socket } from './socket.js'\nimport type { ConnectionState, EventHandler } from './types.js'\nimport {\n acquireChannel,\n acquireSocketOwnership,\n type FrameworkChannel,\n type FrameworkChannelEvent,\n type FrameworkChannelEventPayload,\n type FrameworkChannelName,\n} from './framework.js'\n\ninterface SvelteSocketContext<Registry> {\n socket: Socket<Registry>\n state: Readable<ConnectionState>\n}\n\ntype ChannelNameInput<Registry, Name extends string> =\n | (Name & FrameworkChannelName<Registry, NoInfer<Name>>)\n | null\n | (Readable<Name | null> & Readable<FrameworkChannelName<Registry, NoInfer<Name>> | null>)\n\nfunction isReadable<Value>(value: Value | Readable<Value>): value is Readable<Value> {\n return typeof value === 'object' && value !== null && 'subscribe' in value\n}\n\nexport function createSocketContext<Registry = never>() {\n const key = Symbol('socket')\n\n function setSocket(socket: Socket<Registry>, options: { owned?: boolean } = {}): void {\n const state = readable(socket.state, (set) => socket.onStateChange(set))\n setContext<SvelteSocketContext<Registry>>(key, { socket, state })\n\n if (options.owned) {\n onMount(() => acquireSocketOwnership(socket))\n }\n }\n\n function useContext(): SvelteSocketContext<Registry> {\n const context = getContext<SvelteSocketContext<Registry>>(key)\n if (!context) throw new Error('setSocket must be called by an ancestor')\n return context\n }\n\n function useSocket(): Socket<Registry> {\n return useContext().socket\n }\n\n function useSocketState(): Readable<ConnectionState> {\n return useContext().state\n }\n\n function channel<const Name extends string>(\n name: ChannelNameInput<Registry, Name>\n ): Readable<FrameworkChannel<Registry, Name> | null> {\n const socket = useSocket()\n return readable<FrameworkChannel<Registry, Name> | null>(null, (set) => {\n let release: (() => void) | undefined\n const acquire = (nextName: FrameworkChannelName<Registry, Name> | null) => {\n release?.()\n release = undefined\n if (nextName === null) {\n set(null)\n return\n }\n const acquired = acquireChannel(socket, nextName)\n release = () => acquired.lease.release()\n set(acquired.channel)\n }\n\n const stopName = isReadable(name) ? name.subscribe(acquire) : (acquire(name), undefined)\n return () => {\n stopName?.()\n release?.()\n }\n })\n }\n\n function onChannelEvent<\n const Name extends string,\n Event extends FrameworkChannelEvent<Registry, Name>,\n >(\n name: ChannelNameInput<Registry, Name>,\n event: Event,\n handler: EventHandler<FrameworkChannelEventPayload<Registry, Name, Event>>\n ): () => void {\n const socket = useSocket()\n let release: (() => void) | undefined\n const acquire = (nextName: FrameworkChannelName<Registry, Name> | null) => {\n release?.()\n release = undefined\n if (nextName === null) return\n const { lease } = acquireChannel(socket, nextName)\n lease.listen(event, handler)\n release = () => lease.release()\n }\n const stopName = isReadable(name) ? name.subscribe(acquire) : (acquire(name), undefined)\n let disposed = false\n const dispose = () => {\n if (disposed) return\n disposed = true\n stopName?.()\n release?.()\n }\n onDestroy(dispose)\n return dispose\n }\n\n return { setSocket, useSocket, useSocketState, channel, onChannelEvent }\n}\n"],"mappings":";;;;;;;AAAA,SAAS,YAAY,WAAW,SAAS,kBAAkB;AAC3D,SAAS,gBAA+B;AAsBxC,SAAS,WAAkB,OAA0D;AACnF,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,eAAe;AACvE;AAEO,SAAS,sBAAwC;AACtD,QAAM,MAAM,uBAAO,QAAQ;AAE3B,WAAS,UAAU,QAA0B,UAA+B,CAAC,GAAS;AACpF,UAAM,QAAQ,SAAS,OAAO,OAAO,CAAC,QAAQ,OAAO,cAAc,GAAG,CAAC;AACvE,eAA0C,KAAK,EAAE,QAAQ,MAAM,CAAC;AAEhE,QAAI,QAAQ,OAAO;AACjB,cAAQ,MAAM,uBAAuB,MAAM,CAAC;AAAA,IAC9C;AAAA,EACF;AAEA,WAAS,aAA4C;AACnD,UAAM,UAAU,WAA0C,GAAG;AAC7D,QAAI,CAAC,QAAS,OAAM,IAAI,MAAM,yCAAyC;AACvE,WAAO;AAAA,EACT;AAEA,WAAS,YAA8B;AACrC,WAAO,WAAW,EAAE;AAAA,EACtB;AAEA,WAAS,iBAA4C;AACnD,WAAO,WAAW,EAAE;AAAA,EACtB;AAEA,WAAS,QACP,MACmD;AACnD,UAAM,SAAS,UAAU;AACzB,WAAO,SAAkD,MAAM,CAAC,QAAQ;AACtE,UAAI;AACJ,YAAM,UAAU,CAAC,aAA0D;AACzE,kBAAU;AACV,kBAAU;AACV,YAAI,aAAa,MAAM;AACrB,cAAI,IAAI;AACR;AAAA,QACF;AACA,cAAM,WAAW,eAAe,QAAQ,QAAQ;AAChD,kBAAU,MAAM,SAAS,MAAM,QAAQ;AACvC,YAAI,SAAS,OAAO;AAAA,MACtB;AAEA,YAAM,WAAW,WAAW,IAAI,IAAI,KAAK,UAAU,OAAO,KAAK,QAAQ,IAAI,GAAG;AAC9E,aAAO,MAAM;AACX,mBAAW;AACX,kBAAU;AAAA,MACZ;AAAA,IACF,CAAC;AAAA,EACH;AAEA,WAAS,eAIP,MACA,OACA,SACY;AACZ,UAAM,SAAS,UAAU;AACzB,QAAI;AACJ,UAAM,UAAU,CAAC,aAA0D;AACzE,gBAAU;AACV,gBAAU;AACV,UAAI,aAAa,KAAM;AACvB,YAAM,EAAE,MAAM,IAAI,eAAe,QAAQ,QAAQ;AACjD,YAAM,OAAO,OAAO,OAAO;AAC3B,gBAAU,MAAM,MAAM,QAAQ;AAAA,IAChC;AACA,UAAM,WAAW,WAAW,IAAI,IAAI,KAAK,UAAU,OAAO,KAAK,QAAQ,IAAI,GAAG;AAC9E,QAAI,WAAW;AACf,UAAM,UAAU,MAAM;AACpB,UAAI,SAAU;AACd,iBAAW;AACX,iBAAW;AACX,gBAAU;AAAA,IACZ;AACA,cAAU,OAAO;AACjB,WAAO;AAAA,EACT;AAEA,SAAO,EAAE,WAAW,WAAW,gBAAgB,SAAS,eAAe;AACzE;","names":[]}
|