@rlanz/socket 0.0.1-5 → 0.0.1-7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +174 -160
  2. package/build/{types-C7Q36ryo.d.ts → base_channel-Dr40l7CW.d.ts} +178 -169
  3. package/build/chunk-2X6WGCH5.js +120 -0
  4. package/build/chunk-2X6WGCH5.js.map +1 -0
  5. package/build/chunk-6PJ4ALJD.js +115 -0
  6. package/build/chunk-6PJ4ALJD.js.map +1 -0
  7. package/build/chunk-E6ILCRL3.js +182 -0
  8. package/build/chunk-E6ILCRL3.js.map +1 -0
  9. package/build/{chunk-SHH6U4CI.js → chunk-G75J233Z.js} +1 -1
  10. package/build/chunk-G75J233Z.js.map +1 -0
  11. package/build/{chunk-B4Y3TNDI.js → chunk-IUQ3GYZZ.js} +5 -24
  12. package/build/chunk-IUQ3GYZZ.js.map +1 -0
  13. package/build/chunk-QNOOQXYY.js +899 -0
  14. package/build/chunk-QNOOQXYY.js.map +1 -0
  15. package/build/{chunk-ANT2E3LT.js → chunk-YVC7IMDN.js} +21 -5
  16. package/build/chunk-YVC7IMDN.js.map +1 -0
  17. package/build/framework-B-4kGmAw.d.ts +13 -0
  18. package/build/index-Fg-tkHhP.d.ts +150 -0
  19. package/build/index.d.ts +23 -12
  20. package/build/index.js +12 -14
  21. package/build/index.js.map +1 -1
  22. package/build/providers/socket_provider.d.ts +2 -2
  23. package/build/providers/socket_provider.js +474 -215
  24. package/build/providers/socket_provider.js.map +1 -1
  25. package/build/services/socket.d.ts +2 -2
  26. package/build/{socket_service-mybqv1hj.d.ts → socket_service-BYEB8LIN.d.ts} +7 -7
  27. package/build/src/assembler_hook.d.ts +6 -4
  28. package/build/src/assembler_hook.js +49 -63
  29. package/build/src/assembler_hook.js.map +1 -1
  30. package/build/src/client/index.d.ts +3 -147
  31. package/build/src/client/index.js +4 -837
  32. package/build/src/client/index.js.map +1 -1
  33. package/build/src/client/react.d.ts +13 -5
  34. package/build/src/client/react.js +27 -11
  35. package/build/src/client/react.js.map +1 -1
  36. package/build/src/client/types.d.ts +30 -35
  37. package/build/src/client/vue.d.ts +17 -5
  38. package/build/src/client/vue.js +31 -13
  39. package/build/src/client/vue.js.map +1 -1
  40. package/build/src/decorators.d.ts +3 -2
  41. package/build/src/decorators.js +1 -1
  42. package/build/src/health_check.d.ts +2 -2
  43. package/build/src/health_check.js +14 -3
  44. package/build/src/health_check.js.map +1 -1
  45. package/build/src/otel.js +0 -1
  46. package/build/src/otel.js.map +1 -1
  47. package/build/src/testing.d.ts +3 -12
  48. package/build/src/testing.js +1 -1
  49. package/build/src/types/tracing_channels.d.ts +1 -2
  50. package/build/src/types.d.ts +1 -1
  51. package/package.json +2 -9
  52. package/build/chunk-ANT2E3LT.js.map +0 -1
  53. package/build/chunk-B4Y3TNDI.js.map +0 -1
  54. package/build/chunk-HK7Z65DA.js +0 -19
  55. package/build/chunk-HK7Z65DA.js.map +0 -1
  56. package/build/chunk-SFAY2ZA4.js +0 -28
  57. package/build/chunk-SFAY2ZA4.js.map +0 -1
  58. package/build/chunk-SHH6U4CI.js.map +0 -1
  59. package/build/chunk-YAX5EHHB.js +0 -453
  60. package/build/chunk-YAX5EHHB.js.map +0 -1
  61. package/build/framework-CvxgHwbv.d.ts +0 -12
  62. package/build/src/client/svelte.d.ts +0 -22
  63. package/build/src/client/svelte.js +0 -82
  64. package/build/src/client/svelte.js.map +0 -1
@@ -0,0 +1,182 @@
1
+ // src/channel_pattern_syntax.ts
2
+ var SEPARATOR = "/";
3
+ var SLASH_CODE = 47;
4
+ var COLON_CODE = 58;
5
+ var ASTERISK_CODE = 42;
6
+ var QUESTION_MARK_CODE = 63;
7
+ var ChannelPatternSyntax = class _ChannelPatternSyntax {
8
+ canonicalPattern;
9
+ segments;
10
+ #specificity;
11
+ constructor(value) {
12
+ const canonicalPattern = _ChannelPatternSyntax.#normalize(value);
13
+ if (canonicalPattern === SEPARATOR) {
14
+ this.canonicalPattern = canonicalPattern;
15
+ this.segments = Object.freeze([Object.freeze({ kind: "static", value: SEPARATOR })]);
16
+ } else {
17
+ const segments = [];
18
+ let remaining = canonicalPattern;
19
+ let index = -1;
20
+ let start = 0;
21
+ let length = remaining.length;
22
+ while (++index < length) {
23
+ const character = remaining.charCodeAt(index);
24
+ if (character === COLON_CODE) {
25
+ start = index + 1;
26
+ let optional = false;
27
+ let marker = 0;
28
+ let suffix = "";
29
+ while (index < length && remaining.charCodeAt(index) !== SLASH_CODE) {
30
+ const parameterCharacter = remaining.charCodeAt(index);
31
+ if (parameterCharacter === QUESTION_MARK_CODE) {
32
+ marker = index;
33
+ optional = true;
34
+ } else if (parameterCharacter === 46 && suffix.length === 0) {
35
+ marker = index;
36
+ suffix = remaining.slice(index);
37
+ }
38
+ index++;
39
+ }
40
+ segments.push({
41
+ kind: "parameter",
42
+ name: remaining.slice(start, marker || index),
43
+ optional,
44
+ suffix
45
+ });
46
+ remaining = remaining.slice(index);
47
+ length -= index;
48
+ index = 0;
49
+ continue;
50
+ }
51
+ if (character === ASTERISK_CODE) {
52
+ segments.push({ kind: "wildcard", name: remaining.slice(index) });
53
+ continue;
54
+ }
55
+ start = index;
56
+ while (index < length && remaining.charCodeAt(index) !== SLASH_CODE) {
57
+ index++;
58
+ }
59
+ segments.push({ kind: "static", value: remaining.slice(start, index) });
60
+ remaining = remaining.slice(index);
61
+ length -= index;
62
+ index = 0;
63
+ start = 0;
64
+ }
65
+ this.canonicalPattern = canonicalPattern;
66
+ this.segments = Object.freeze(segments.map((segment) => Object.freeze(segment)));
67
+ }
68
+ this.#specificity = Object.freeze(
69
+ this.segments.map((segment) => {
70
+ if (segment.kind === "static") return 40;
71
+ if (segment.kind === "wildcard") return 0;
72
+ return segment.optional ? 20 : 30;
73
+ })
74
+ );
75
+ }
76
+ /**
77
+ * Parse one pattern and return its immutable syntax.
78
+ */
79
+ static from(value) {
80
+ const syntax = new _ChannelPatternSyntax(value);
81
+ Object.freeze(syntax);
82
+ return syntax;
83
+ }
84
+ /**
85
+ * Match one channel name and return its decoded parameters.
86
+ */
87
+ match(channelName) {
88
+ return this.#matchValues(_ChannelPatternSyntax.#split(channelName));
89
+ }
90
+ /**
91
+ * Compare this syntax with another syntax for runtime routing.
92
+ * Return a negative value when this syntax is more specific.
93
+ */
94
+ compareSpecificity(other) {
95
+ const length = Math.max(this.#specificity.length, other.#specificity.length);
96
+ for (let index = 0; index < length; index++) {
97
+ const difference = (other.#specificity[index] ?? -1) - (this.#specificity[index] ?? -1);
98
+ if (difference !== 0) {
99
+ return difference;
100
+ }
101
+ }
102
+ return other.#specificity.length - this.#specificity.length;
103
+ }
104
+ /**
105
+ * Return the first matching syntax without splitting the channel name again.
106
+ */
107
+ static firstMatch(patterns, channelName) {
108
+ const values = _ChannelPatternSyntax.#split(channelName);
109
+ for (const [index, pattern] of patterns.entries()) {
110
+ const params = pattern.#matchValues(values);
111
+ if (params) return { index, params };
112
+ }
113
+ return null;
114
+ }
115
+ #matchValues(values) {
116
+ const finalSegment = this.segments.at(-1);
117
+ const compatibleLength = this.segments.length === values.length || this.segments.length < values.length && finalSegment?.kind === "wildcard" || this.segments.length > values.length && finalSegment?.kind === "parameter" && finalSegment.optional;
118
+ if (!compatibleLength || !this.segments.every(
119
+ (segment, index) => _ChannelPatternSyntax.#segmentMatches(segment, values[index])
120
+ )) {
121
+ return null;
122
+ }
123
+ const parameters = {};
124
+ for (const [index, segment] of this.segments.entries()) {
125
+ if (values[index] === SEPARATOR) continue;
126
+ if (segment.kind === "wildcard") {
127
+ if (segment.name === "*") {
128
+ parameters[segment.name] = values.slice(index).map(_ChannelPatternSyntax.#decode).join(SEPARATOR);
129
+ }
130
+ break;
131
+ }
132
+ if (segment.kind === "parameter" && values[index] !== void 0) {
133
+ parameters[segment.name] = _ChannelPatternSyntax.#decode(
134
+ values[index].replace(segment.suffix, "")
135
+ );
136
+ }
137
+ }
138
+ return parameters;
139
+ }
140
+ static #normalize(value) {
141
+ if (value === SEPARATOR) return value;
142
+ let normalized = value;
143
+ if (normalized.charCodeAt(0) === SLASH_CODE) {
144
+ normalized = normalized.slice(1);
145
+ }
146
+ if (normalized.charCodeAt(normalized.length - 1) === SLASH_CODE) {
147
+ normalized = normalized.slice(0, -1);
148
+ }
149
+ return normalized;
150
+ }
151
+ static #split(value) {
152
+ const normalized = _ChannelPatternSyntax.#normalize(value);
153
+ return normalized === SEPARATOR ? [SEPARATOR] : normalized.split(SEPARATOR);
154
+ }
155
+ static #decode(value) {
156
+ try {
157
+ return decodeURIComponent(value);
158
+ } catch {
159
+ return value;
160
+ }
161
+ }
162
+ static #segmentMatches(segment, value) {
163
+ if (segment.kind === "static") {
164
+ return segment.value === value;
165
+ }
166
+ if (value === SEPARATOR) {
167
+ return segment.kind === "wildcard" || segment.optional;
168
+ }
169
+ if (value === "") {
170
+ return segment.kind === "wildcard" || segment.suffix === "";
171
+ }
172
+ if (value === void 0) {
173
+ return segment.kind === "wildcard" || segment.suffix === "";
174
+ }
175
+ return segment.kind === "wildcard" || value.endsWith(segment.suffix);
176
+ }
177
+ };
178
+
179
+ export {
180
+ ChannelPatternSyntax
181
+ };
182
+ //# sourceMappingURL=chunk-E6ILCRL3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/channel_pattern_syntax.ts"],"sourcesContent":["/**\n * Pattern parsing and matching semantics are adapted from @poppinss/matchit.\n * Copyright 2020 Harminder Virk and contributors, used under the MIT license.\n * See the repository LICENSE.md for the license text.\n */\n\nconst SEPARATOR = '/'\nconst SLASH_CODE = 47\nconst COLON_CODE = 58\nconst ASTERISK_CODE = 42\nconst QUESTION_MARK_CODE = 63\n\ntype ChannelPatternSegment =\n | { readonly kind: 'static'; readonly value: string }\n | {\n readonly kind: 'parameter'\n readonly name: string\n readonly optional: boolean\n readonly suffix: string\n }\n | { readonly kind: 'wildcard'; readonly name: string }\n\nexport interface ChannelPatternSyntaxMatch {\n readonly index: number\n readonly params: Record<string, string>\n}\n\n/**\n * Immutable parsed syntax shared by runtime matching and generated binding.\n */\nexport class ChannelPatternSyntax {\n readonly canonicalPattern: string\n protected readonly segments: readonly ChannelPatternSegment[]\n readonly #specificity: readonly number[]\n\n protected constructor(value: string) {\n const canonicalPattern = ChannelPatternSyntax.#normalize(value)\n if (canonicalPattern === SEPARATOR) {\n this.canonicalPattern = canonicalPattern\n this.segments = Object.freeze([Object.freeze({ kind: 'static', value: SEPARATOR })])\n } else {\n const segments: ChannelPatternSegment[] = []\n let remaining = canonicalPattern\n let index = -1\n let start = 0\n let length = remaining.length\n\n while (++index < length) {\n const character = remaining.charCodeAt(index)\n\n if (character === COLON_CODE) {\n // Read the parameter name, its optional marker, and its suffix.\n start = index + 1\n let optional = false\n let marker = 0\n let suffix = ''\n\n while (index < length && remaining.charCodeAt(index) !== SLASH_CODE) {\n const parameterCharacter = remaining.charCodeAt(index)\n if (parameterCharacter === QUESTION_MARK_CODE) {\n marker = index\n optional = true\n } else if (parameterCharacter === 46 && suffix.length === 0) {\n marker = index\n suffix = remaining.slice(index)\n }\n index++\n }\n\n segments.push({\n kind: 'parameter',\n name: remaining.slice(start, marker || index),\n optional,\n suffix,\n })\n remaining = remaining.slice(index)\n length -= index\n index = 0\n continue\n }\n\n if (character === ASTERISK_CODE) {\n // A wildcard consumes the rest of the pattern.\n segments.push({ kind: 'wildcard', name: remaining.slice(index) })\n continue\n }\n\n start = index\n while (index < length && remaining.charCodeAt(index) !== SLASH_CODE) {\n index++\n }\n segments.push({ kind: 'static', value: remaining.slice(start, index) })\n remaining = remaining.slice(index)\n length -= index\n index = 0\n start = 0\n }\n\n this.canonicalPattern = canonicalPattern\n this.segments = Object.freeze(segments.map((segment) => Object.freeze(segment)))\n }\n\n this.#specificity = Object.freeze(\n this.segments.map((segment) => {\n if (segment.kind === 'static') return 40\n if (segment.kind === 'wildcard') return 0\n return segment.optional ? 20 : 30\n })\n )\n }\n\n /**\n * Parse one pattern and return its immutable syntax.\n */\n static from(value: string): ChannelPatternSyntax {\n const syntax = new ChannelPatternSyntax(value)\n Object.freeze(syntax)\n return syntax\n }\n\n /**\n * Match one channel name and return its decoded parameters.\n */\n match(channelName: string): Record<string, string> | null {\n return this.#matchValues(ChannelPatternSyntax.#split(channelName))\n }\n\n /**\n * Compare this syntax with another syntax for runtime routing.\n * Return a negative value when this syntax is more specific.\n */\n compareSpecificity(other: ChannelPatternSyntax): number {\n const length = Math.max(this.#specificity.length, other.#specificity.length)\n\n for (let index = 0; index < length; index++) {\n const difference = (other.#specificity[index] ?? -1) - (this.#specificity[index] ?? -1)\n if (difference !== 0) {\n return difference\n }\n }\n\n return other.#specificity.length - this.#specificity.length\n }\n\n /**\n * Return the first matching syntax without splitting the channel name again.\n */\n static firstMatch(\n patterns: readonly ChannelPatternSyntax[],\n channelName: string\n ): ChannelPatternSyntaxMatch | null {\n const values = ChannelPatternSyntax.#split(channelName)\n for (const [index, pattern] of patterns.entries()) {\n const params = pattern.#matchValues(values)\n if (params) return { index, params }\n }\n return null\n }\n\n #matchValues(values: string[]): Record<string, string> | null {\n const finalSegment = this.segments.at(-1)\n\n // A wildcard can consume extra values. A final optional parameter can be absent.\n const compatibleLength =\n this.segments.length === values.length ||\n (this.segments.length < values.length && finalSegment?.kind === 'wildcard') ||\n (this.segments.length > values.length &&\n finalSegment?.kind === 'parameter' &&\n finalSegment.optional)\n\n if (\n !compatibleLength ||\n !this.segments.every((segment, index) =>\n ChannelPatternSyntax.#segmentMatches(segment, values[index])\n )\n ) {\n return null\n }\n\n const parameters: Record<string, string> = {}\n for (const [index, segment] of this.segments.entries()) {\n // The root separator does not produce a parameter.\n if (values[index] === SEPARATOR) continue\n\n if (segment.kind === 'wildcard') {\n // Decode each wildcard value before the values are joined again.\n if (segment.name === '*') {\n parameters[segment.name] = values\n .slice(index)\n .map(ChannelPatternSyntax.#decode)\n .join(SEPARATOR)\n }\n break\n }\n\n if (segment.kind === 'parameter' && values[index] !== undefined) {\n // Remove the static suffix before the parameter is decoded.\n parameters[segment.name] = ChannelPatternSyntax.#decode(\n values[index].replace(segment.suffix, '')\n )\n }\n }\n return parameters\n }\n\n static #normalize(value: string): string {\n if (value === SEPARATOR) return value\n\n // Remove one leading slash and one trailing slash. This keeps Matchit behavior.\n let normalized = value\n if (normalized.charCodeAt(0) === SLASH_CODE) {\n normalized = normalized.slice(1)\n }\n if (normalized.charCodeAt(normalized.length - 1) === SLASH_CODE) {\n normalized = normalized.slice(0, -1)\n }\n return normalized\n }\n\n static #split(value: string): string[] {\n const normalized = ChannelPatternSyntax.#normalize(value)\n return normalized === SEPARATOR ? [SEPARATOR] : normalized.split(SEPARATOR)\n }\n\n static #decode(value: string): string {\n try {\n return decodeURIComponent(value)\n } catch {\n // Keep invalid encoded input unchanged. Matchit uses the same fallback.\n return value\n }\n }\n\n static #segmentMatches(segment: ChannelPatternSegment, value: string | undefined): boolean {\n if (segment.kind === 'static') {\n return segment.value === value\n }\n if (value === SEPARATOR) {\n return segment.kind === 'wildcard' || segment.optional\n }\n if (value === '') {\n return segment.kind === 'wildcard' || segment.suffix === ''\n }\n if (value === undefined) {\n return segment.kind === 'wildcard' || segment.suffix === ''\n }\n return segment.kind === 'wildcard' || value.endsWith(segment.suffix)\n }\n}\n"],"mappings":"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","names":[]}
@@ -42,4 +42,4 @@ export {
42
42
  onMessage,
43
43
  getDecoratedChannelHandlers
44
44
  };
45
- //# sourceMappingURL=chunk-SHH6U4CI.js.map
45
+ //# sourceMappingURL=chunk-G75J233Z.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/decorators.ts"],"sourcesContent":["import type { AuthenticatedSocket } from './types.js'\n\ntype DecoratedChannelHandler<User> = (socket: AuthenticatedSocket<User>, data: unknown) => unknown\n\ntype ChannelMessageHandlerDefinition = {\n event: string\n methodName: string | symbol\n}\n\nconst decoratedHandlers = new WeakMap<object, ChannelMessageHandlerDefinition[]>()\n\n/**\n * Method decorator used to bind an incoming channel event to a method.\n */\nexport function onMessage<EventName extends string>(event: EventName): MethodDecorator {\n return (target, propertyKey, descriptor) => {\n if (typeof descriptor?.value !== 'function') {\n throw new Error(`@onMessage(\"${event}\") can only be used on methods`)\n }\n\n const constructor = target.constructor\n const handlers = [...(decoratedHandlers.get(constructor) ?? [])]\n\n handlers.push({\n event,\n methodName: propertyKey,\n })\n\n decoratedHandlers.set(constructor, handlers)\n }\n}\n\n/**\n * Resolve decorated handlers for a channel instance, including inherited ones.\n * Child classes override parent handlers when the event name is the same.\n */\nexport function getDecoratedChannelHandlers<User = unknown>(\n instance: object\n): Record<string, DecoratedChannelHandler<User>> {\n const constructors: object[] = []\n\n let proto = Object.getPrototypeOf(instance)\n while (proto && proto !== Object.prototype) {\n const constructor = Reflect.get(proto, 'constructor')\n if (typeof constructor === 'function') {\n constructors.unshift(constructor)\n }\n proto = Object.getPrototypeOf(proto)\n }\n\n const handlers: Record<string, unknown> = {}\n\n for (const constructor of constructors) {\n const definitions = decoratedHandlers.get(constructor) ?? []\n\n for (const definition of definitions) {\n const handler = Reflect.get(instance, definition.methodName)\n if (typeof handler !== 'function') {\n continue\n }\n\n handlers[definition.event] = handler.bind(instance)\n }\n }\n\n return handlers as Record<string, DecoratedChannelHandler<User>>\n}\n"],"mappings":";AASA,IAAM,oBAAoB,oBAAI,QAAmD;AAK1E,SAAS,UAAoC,OAAmC;AACrF,SAAO,CAAC,QAAQ,aAAa,eAAe;AAC1C,QAAI,OAAO,YAAY,UAAU,YAAY;AAC3C,YAAM,IAAI,MAAM,eAAe,KAAK,gCAAgC;AAAA,IACtE;AAEA,UAAM,cAAc,OAAO;AAC3B,UAAM,WAAW,CAAC,GAAI,kBAAkB,IAAI,WAAW,KAAK,CAAC,CAAE;AAE/D,aAAS,KAAK;AAAA,MACZ;AAAA,MACA,YAAY;AAAA,IACd,CAAC;AAED,sBAAkB,IAAI,aAAa,QAAQ;AAAA,EAC7C;AACF;AAMO,SAAS,4BACd,UAC+C;AAC/C,QAAM,eAAyB,CAAC;AAEhC,MAAI,QAAQ,OAAO,eAAe,QAAQ;AAC1C,SAAO,SAAS,UAAU,OAAO,WAAW;AAC1C,UAAM,cAAc,QAAQ,IAAI,OAAO,aAAa;AACpD,QAAI,OAAO,gBAAgB,YAAY;AACrC,mBAAa,QAAQ,WAAW;AAAA,IAClC;AACA,YAAQ,OAAO,eAAe,KAAK;AAAA,EACrC;AAEA,QAAM,WAAoC,CAAC;AAE3C,aAAW,eAAe,cAAc;AACtC,UAAM,cAAc,kBAAkB,IAAI,WAAW,KAAK,CAAC;AAE3D,eAAW,cAAc,aAAa;AACpC,YAAM,UAAU,QAAQ,IAAI,UAAU,WAAW,UAAU;AAC3D,UAAI,OAAO,YAAY,YAAY;AACjC;AAAA,MACF;AAEA,eAAS,WAAW,KAAK,IAAI,QAAQ,KAAK,QAAQ;AAAA,IACpD;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
@@ -56,21 +56,7 @@ var SocketFake = class {
56
56
  `Expected socket event "${event}" not to have been emitted to channel "${channel}"`
57
57
  );
58
58
  }
59
- assertEmittedToUser(userId, event, query) {
60
- this.#assertEmitted(
61
- (emission) => emission.target === "user" && emission.userId === userId && emission.event === event,
62
- query,
63
- `Expected socket event "${event}" to have been emitted to user "${String(userId)}"`
64
- );
65
- }
66
- assertNotEmittedToUser(userId, event, query) {
67
- this.#assertNotEmitted(
68
- (emission) => emission.target === "user" && emission.userId === userId && emission.event === event,
69
- query,
70
- `Expected socket event "${event}" not to have been emitted to user "${String(userId)}"`
71
- );
72
- }
73
- assertEmittedCount(count, query) {
59
+ assertCount(count, query) {
74
60
  const actual = this.#matching(query).length;
75
61
  if (actual !== count) {
76
62
  throw new AssertionError({
@@ -81,9 +67,6 @@ var SocketFake = class {
81
67
  });
82
68
  }
83
69
  }
84
- assertNothingEmitted() {
85
- this.assertEmittedCount(0);
86
- }
87
70
  #assertEmitted(predicate, query, message) {
88
71
  const matching = this.#emissions.filter((emission) => {
89
72
  return predicate(emission) && this.#matchesQuery(emission, query);
@@ -112,16 +95,14 @@ var SocketFake = class {
112
95
  }
113
96
  #matching(query) {
114
97
  return this.#emissions.filter((emission) => {
115
- if (query?.target && emission.target !== query.target) {
98
+ if (!query) return true;
99
+ if (query.target && emission.target !== query.target) {
116
100
  return false;
117
101
  }
118
102
  if (query?.event && emission.event !== query.event) {
119
103
  return false;
120
104
  }
121
- if (query?.channel && (!("channel" in emission) || emission.channel !== query.channel)) {
122
- return false;
123
- }
124
- if (query?.userId !== void 0 && (!("userId" in emission) || emission.userId !== query.userId)) {
105
+ if (query.channel && (!("channel" in emission) || emission.channel !== query.channel)) {
125
106
  return false;
126
107
  }
127
108
  return this.#matchesQuery(emission, query);
@@ -156,4 +137,4 @@ var SocketFake = class {
156
137
  export {
157
138
  SocketFake
158
139
  };
159
- //# sourceMappingURL=chunk-B4Y3TNDI.js.map
140
+ //# sourceMappingURL=chunk-IUQ3GYZZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/fake_socket.ts"],"sourcesContent":["import { AssertionError } from 'node:assert'\nimport { isDeepStrictEqual } from 'node:util'\nimport type { SocketEmission, SocketEmissionSink, SocketEmissionTarget } from './broadcasting.js'\n\nexport type SocketFakeTarget = SocketEmissionTarget\nexport type SocketFakeEmission = SocketEmission\n\ntype SocketFakeMatcher<Value> = Value | ((value: Value) => boolean)\n\nexport interface SocketFakeEmissionQuery {\n data?: unknown | ((data: unknown) => boolean)\n except?: SocketFakeMatcher<string[] | undefined>\n}\n\nexport interface SocketFakeCountQuery extends SocketFakeEmissionQuery {\n target?: SocketFakeTarget\n event?: string\n channel?: string\n}\n\nexport class SocketFake implements SocketEmissionSink {\n #emissions: SocketFakeEmission[] = []\n #restore: () => void\n\n constructor(restore: () => void) {\n this.#restore = restore\n }\n\n get emissions(): SocketFakeEmission[] {\n return [...this.#emissions]\n }\n\n record(emission: SocketFakeEmission): void {\n this.#emissions.push({\n ...emission,\n ...('except' in emission && emission.except ? { except: [...emission.except] } : {}),\n })\n }\n\n dispatch(emission: SocketFakeEmission): void {\n this.record(emission)\n }\n\n clear(): void {\n this.#emissions = []\n }\n\n restore(): void {\n this.#restore()\n }\n\n [Symbol.dispose](): void {\n this.restore()\n }\n\n assertBroadcasted(event: string, query?: SocketFakeEmissionQuery): void {\n this.#assertEmitted(\n (emission) => emission.target === 'global' && emission.event === event,\n query,\n `Expected socket event \"${event}\" to have been broadcasted`\n )\n }\n\n assertNotBroadcasted(event: string, query?: SocketFakeEmissionQuery): void {\n this.#assertNotEmitted(\n (emission) => emission.target === 'global' && emission.event === event,\n query,\n `Expected socket event \"${event}\" not to have been broadcasted`\n )\n }\n\n assertEmittedTo(channel: string, event: string, query?: SocketFakeEmissionQuery): void {\n this.#assertEmitted(\n (emission) =>\n emission.target === 'channel' && emission.channel === channel && emission.event === event,\n query,\n `Expected socket event \"${event}\" to have been emitted to channel \"${channel}\"`\n )\n }\n\n assertNotEmittedTo(channel: string, event: string, query?: SocketFakeEmissionQuery): void {\n this.#assertNotEmitted(\n (emission) =>\n emission.target === 'channel' && emission.channel === channel && emission.event === event,\n query,\n `Expected socket event \"${event}\" not to have been emitted to channel \"${channel}\"`\n )\n }\n\n assertCount(count: number, query?: SocketFakeCountQuery): void {\n const actual = this.#matching(query).length\n\n if (actual !== count) {\n throw new AssertionError({\n message: `Expected ${count} socket event(s) to have been emitted, but found ${actual}`,\n actual,\n expected: count,\n operator: 'strictEqual',\n })\n }\n }\n\n #assertEmitted(\n predicate: (emission: SocketFakeEmission) => boolean,\n query: SocketFakeEmissionQuery | undefined,\n message: string\n ): void {\n const matching = this.#emissions.filter((emission) => {\n return predicate(emission) && this.#matchesQuery(emission, query)\n })\n\n if (matching.length === 0) {\n throw new AssertionError({\n message,\n actual: this.#emissions,\n expected: query,\n operator: 'includes',\n })\n }\n }\n\n #assertNotEmitted(\n predicate: (emission: SocketFakeEmission) => boolean,\n query: SocketFakeEmissionQuery | undefined,\n message: string\n ): void {\n const matching = this.#emissions.filter((emission) => {\n return predicate(emission) && this.#matchesQuery(emission, query)\n })\n\n if (matching.length > 0) {\n throw new AssertionError({\n message,\n actual: matching,\n expected: [],\n operator: 'doesNotInclude',\n })\n }\n }\n\n #matching(query: SocketFakeCountQuery | undefined): SocketFakeEmission[] {\n return this.#emissions.filter((emission) => {\n if (!query) return true\n\n if (query.target && emission.target !== query.target) {\n return false\n }\n\n if (query?.event && emission.event !== query.event) {\n return false\n }\n\n if (query.channel && (!('channel' in emission) || emission.channel !== query.channel)) {\n return false\n }\n\n return this.#matchesQuery(emission, query)\n })\n }\n\n #matchesQuery(emission: SocketFakeEmission, query: SocketFakeEmissionQuery | undefined): boolean {\n if (!query) {\n return true\n }\n\n if ('data' in query) {\n if (typeof query.data === 'function') {\n if (!query.data(emission.data)) {\n return false\n }\n } else if (!isDeepStrictEqual(emission.data, query.data)) {\n return false\n }\n }\n\n if ('except' in query) {\n if (typeof query.except === 'function') {\n if (!query.except('except' in emission ? emission.except : undefined)) {\n return false\n }\n } else if (\n !isDeepStrictEqual(('except' in emission ? emission.except : undefined) ?? [], query.except)\n ) {\n return false\n }\n }\n\n return true\n }\n}\n"],"mappings":"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","names":[]}