@rlanz/socket 0.0.1-4 → 0.0.1-6
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 +430 -26
- package/build/chunk-B4Y3TNDI.js +159 -0
- package/build/chunk-B4Y3TNDI.js.map +1 -0
- package/build/{chunk-GKAD2UOA.js → chunk-D3HUBCBW.js} +1 -1
- package/build/chunk-D3HUBCBW.js.map +1 -0
- package/build/chunk-FVPY6HZW.js +136 -0
- package/build/chunk-FVPY6HZW.js.map +1 -0
- package/build/chunk-SFAY2ZA4.js +28 -0
- package/build/chunk-SFAY2ZA4.js.map +1 -0
- package/build/{chunk-XUDFDJME.js → chunk-SHH6U4CI.js} +12 -9
- package/build/chunk-SHH6U4CI.js.map +1 -0
- package/build/chunk-YAX5EHHB.js +453 -0
- package/build/chunk-YAX5EHHB.js.map +1 -0
- package/build/framework-DuW6zpPk.d.ts +14 -0
- package/build/index.d.ts +7 -13
- package/build/index.js +18 -10
- package/build/index.js.map +1 -1
- package/build/providers/socket_provider.d.ts +4 -3
- package/build/providers/socket_provider.js +1780 -57
- package/build/providers/socket_provider.js.map +1 -1
- package/build/services/socket.d.ts +4 -3
- package/build/socket_service-D3jKrleE.d.ts +105 -0
- package/build/src/assembler_hook.d.ts +15 -0
- package/build/src/assembler_hook.js +261 -0
- package/build/src/assembler_hook.js.map +1 -0
- package/build/src/client/index.d.ts +46 -12
- package/build/src/client/index.js +223 -76
- package/build/src/client/index.js.map +1 -1
- package/build/src/client/react.d.ts +27 -0
- package/build/src/client/react.js +69 -0
- package/build/src/client/react.js.map +1 -0
- package/build/src/client/svelte.d.ts +23 -0
- package/build/src/client/svelte.js +82 -0
- package/build/src/client/svelte.js.map +1 -0
- package/build/src/client/types.d.ts +69 -5
- package/build/src/client/vue.d.ts +26 -0
- package/build/src/client/vue.js +81 -0
- package/build/src/client/vue.js.map +1 -0
- package/build/src/decorators.d.ts +4 -4
- package/build/src/decorators.js +1 -1
- package/build/src/health_check.d.ts +4 -3
- package/build/src/otel.js +4 -5
- package/build/src/otel.js.map +1 -1
- package/build/src/testing.d.ts +54 -0
- package/build/src/testing.js +7 -0
- package/build/src/testing.js.map +1 -0
- package/build/src/types.d.ts +2 -2
- package/build/{types-BBLNfcWk.d.ts → types-DiYaFvgi.d.ts} +112 -63
- package/package.json +41 -6
- package/build/chunk-GKAD2UOA.js.map +0 -1
- package/build/chunk-ILDK672E.js +0 -1921
- package/build/chunk-ILDK672E.js.map +0 -1
- package/build/chunk-XUDFDJME.js.map +0 -1
- package/build/shared_types-Dw9AphfO.d.ts +0 -21
- package/build/socket_service-CRmPa74K.d.ts +0 -144
|
@@ -0,0 +1,453 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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":[]}
|
|
@@ -0,0 +1,14 @@
|
|
|
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 };
|
package/build/index.d.ts
CHANGED
|
@@ -1,25 +1,19 @@
|
|
|
1
|
-
export { C as ChannelRouter
|
|
2
|
-
import { S as SocketConfig,
|
|
3
|
-
export { A as AuthenticatedSocket, B as BaseChannel,
|
|
1
|
+
export { C as ChannelRouter } from './socket_service-D3jKrleE.js';
|
|
2
|
+
import { S as SocketConfig, d as SocketAuthenticationHandler } from './types-DiYaFvgi.js';
|
|
3
|
+
export { A as AuthenticatedSocket, B as BaseChannel, e as BaseChannelConstructor, b as ChannelAck, f as ChannelHandlerFn, C as ChannelHandlerMap, g as ChannelMatch, c as ChannelMessage, h as ChannelOptions, a as ChannelServerEventsOf, D as Duration, M as Middleware, i as MiddlewareClass, j as MiddlewareContext, k as MiddlewareFn, l as PresenceInfo, P as PresenceManager, m as PresenceMember, R as RawSocket, n as SocketAuthenticationResult, o as SocketEvents, p as SocketHealthSnapshot, q as SocketHttpMiddleware, r as SocketResponseError, s as SocketServiceStatus, t as SocketUpgradeContext } from './types-DiYaFvgi.js';
|
|
4
4
|
export { SocketHealthCheck } from './src/health_check.js';
|
|
5
|
-
export {
|
|
5
|
+
export { SocketFake, SocketFakeCountQuery, SocketFakeEmission, SocketFakeEmissionQuery, SocketFakeTarget } from './src/testing.js';
|
|
6
6
|
import 'node:http';
|
|
7
7
|
import '@adonisjs/logger';
|
|
8
8
|
import 'emittery';
|
|
9
9
|
import 'ws';
|
|
10
|
+
import '@adonisjs/core/http';
|
|
10
11
|
import '@adonisjs/core/types/http';
|
|
11
12
|
import '@boringnode/bus/types/main';
|
|
12
13
|
import '@adonisjs/core/health';
|
|
13
14
|
|
|
14
|
-
declare function defineConfig<User = unknown,
|
|
15
|
+
declare function defineConfig<User = unknown, Config extends SocketConfig<User> = SocketConfig<User>>(config: Config): Config;
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
authenticateUsing(): void | Promise<void>;
|
|
18
|
-
getUserOrFail(): User;
|
|
19
|
-
}
|
|
20
|
-
interface AdonisAuthHttpContext<User> {
|
|
21
|
-
auth: AdonisAuthenticator<User>;
|
|
22
|
-
}
|
|
23
|
-
declare function authenticateWithAdonisAuth<User = unknown, HttpContext extends AdonisAuthHttpContext<User> = AdonisAuthHttpContext<User>>(): SocketAuthenticationHandler<User, HttpContext>;
|
|
17
|
+
declare function authenticateWithAdonisAuth<User = unknown>(): SocketAuthenticationHandler<User>;
|
|
24
18
|
|
|
25
19
|
export { SocketAuthenticationHandler, SocketConfig, authenticateWithAdonisAuth, defineConfig };
|
package/build/index.js
CHANGED
|
@@ -2,14 +2,15 @@ import {
|
|
|
2
2
|
BaseChannel,
|
|
3
3
|
ChannelRouter,
|
|
4
4
|
PresenceManager,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import "./chunk-XUDFDJME.js";
|
|
5
|
+
SocketResponseError
|
|
6
|
+
} from "./chunk-YAX5EHHB.js";
|
|
7
|
+
import "./chunk-SHH6U4CI.js";
|
|
9
8
|
import {
|
|
10
9
|
SocketHealthCheck
|
|
11
10
|
} from "./chunk-HK7Z65DA.js";
|
|
12
|
-
import
|
|
11
|
+
import {
|
|
12
|
+
SocketFake
|
|
13
|
+
} from "./chunk-B4Y3TNDI.js";
|
|
13
14
|
|
|
14
15
|
// src/define_config.ts
|
|
15
16
|
function defineConfig(config) {
|
|
@@ -19,11 +20,18 @@ function defineConfig(config) {
|
|
|
19
20
|
// src/adonis_auth.ts
|
|
20
21
|
function authenticateWithAdonisAuth() {
|
|
21
22
|
return async (ctx) => {
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
const auth = Reflect.get(ctx.httpContext, "auth");
|
|
24
|
+
if (typeof auth !== "object" || auth === null || typeof Reflect.get(auth, "authenticateUsing") !== "function" || typeof Reflect.get(auth, "getUserOrFail") !== "function") {
|
|
25
|
+
throw new Error(
|
|
26
|
+
"AdonisJS Auth must be initialized by websocket middleware before authenticating sockets"
|
|
27
|
+
);
|
|
24
28
|
}
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
const authenticator = {
|
|
30
|
+
authenticateUsing: Reflect.get(auth, "authenticateUsing").bind(auth),
|
|
31
|
+
getUserOrFail: Reflect.get(auth, "getUserOrFail").bind(auth)
|
|
32
|
+
};
|
|
33
|
+
await authenticator.authenticateUsing();
|
|
34
|
+
return authenticator.getUserOrFail();
|
|
27
35
|
};
|
|
28
36
|
}
|
|
29
37
|
export {
|
|
@@ -32,7 +40,7 @@ export {
|
|
|
32
40
|
PresenceManager,
|
|
33
41
|
SocketFake,
|
|
34
42
|
SocketHealthCheck,
|
|
35
|
-
|
|
43
|
+
SocketResponseError,
|
|
36
44
|
authenticateWithAdonisAuth,
|
|
37
45
|
defineConfig
|
|
38
46
|
};
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/define_config.ts","../src/adonis_auth.ts"],"sourcesContent":["import type { SocketConfig } from './types.js'\n\nexport function defineConfig<\n User = unknown,\n
|
|
1
|
+
{"version":3,"sources":["../src/define_config.ts","../src/adonis_auth.ts"],"sourcesContent":["import type { SocketConfig } from './types.js'\n\nexport function defineConfig<\n User = unknown,\n Config extends SocketConfig<User> = SocketConfig<User>,\n>(config: Config): Config {\n return config\n}\n","import type { SocketAuthenticationHandler } from './types.js'\n\ninterface AdonisAuthenticator {\n authenticateUsing: () => unknown\n getUserOrFail: () => unknown\n}\n\nexport function authenticateWithAdonisAuth<User = unknown>(): SocketAuthenticationHandler<User> {\n return async (ctx) => {\n const auth: unknown = Reflect.get(ctx.httpContext, 'auth')\n if (\n typeof auth !== 'object' ||\n auth === null ||\n typeof Reflect.get(auth, 'authenticateUsing') !== 'function' ||\n typeof Reflect.get(auth, 'getUserOrFail') !== 'function'\n ) {\n throw new Error(\n 'AdonisJS Auth must be initialized by websocket middleware before authenticating sockets'\n )\n }\n\n const authenticator: AdonisAuthenticator = {\n authenticateUsing: Reflect.get(auth, 'authenticateUsing').bind(auth),\n getUserOrFail: Reflect.get(auth, 'getUserOrFail').bind(auth),\n }\n await authenticator.authenticateUsing()\n\n // The configured Adonis authenticator owns the application's User type.\n return authenticator.getUserOrFail() as User\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAEO,SAAS,aAGd,QAAwB;AACxB,SAAO;AACT;;;ACAO,SAAS,6BAAgF;AAC9F,SAAO,OAAO,QAAQ;AACpB,UAAM,OAAgB,QAAQ,IAAI,IAAI,aAAa,MAAM;AACzD,QACE,OAAO,SAAS,YAChB,SAAS,QACT,OAAO,QAAQ,IAAI,MAAM,mBAAmB,MAAM,cAClD,OAAO,QAAQ,IAAI,MAAM,eAAe,MAAM,YAC9C;AACA,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,UAAM,gBAAqC;AAAA,MACzC,mBAAmB,QAAQ,IAAI,MAAM,mBAAmB,EAAE,KAAK,IAAI;AAAA,MACnE,eAAe,QAAQ,IAAI,MAAM,eAAe,EAAE,KAAK,IAAI;AAAA,IAC7D;AACA,UAAM,cAAc,kBAAkB;AAGtC,WAAO,cAAc,cAAc;AAAA,EACrC;AACF;","names":[]}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { ApplicationService } from '@adonisjs/core/types';
|
|
2
|
-
import {
|
|
3
|
-
import { P as PresenceManager } from '../types-
|
|
2
|
+
import { S as SocketService, C as ChannelRouter } from '../socket_service-D3jKrleE.js';
|
|
3
|
+
import { P as PresenceManager } from '../types-DiYaFvgi.js';
|
|
4
4
|
import 'node:http';
|
|
5
5
|
import '@adonisjs/logger';
|
|
6
6
|
import 'emittery';
|
|
7
7
|
import 'ws';
|
|
8
|
+
import '@adonisjs/core/http';
|
|
9
|
+
import '../src/testing.js';
|
|
8
10
|
import '@adonisjs/core/types/http';
|
|
9
11
|
import '@boringnode/bus/types/main';
|
|
10
|
-
import '../shared_types-Dw9AphfO.js';
|
|
11
12
|
|
|
12
13
|
declare module '@adonisjs/core/types' {
|
|
13
14
|
interface ContainerBindings {
|