@rlanz/socket 0.0.1-7 → 0.0.1-9

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.
@@ -1,9 +1,9 @@
1
- import { S as SocketService } from '../socket_service-BYEB8LIN.js';
1
+ import { S as SocketService } from '../socket_service-BcC9ASCE.js';
2
2
  import 'node:http';
3
3
  import '@adonisjs/logger';
4
4
  import 'emittery';
5
5
  import 'ws';
6
- import '../base_channel-Dr40l7CW.js';
6
+ import '../base_channel-DPOnqned.js';
7
7
  import '@adonisjs/core/types/http';
8
8
  import '@adonisjs/core/http';
9
9
  import '@boringnode/bus/types/main';
@@ -2,7 +2,7 @@ import { IncomingMessage, Server } from 'node:http';
2
2
  import { Logger } from '@adonisjs/logger';
3
3
  import Emittery from 'emittery';
4
4
  import { WebSocketServer } from 'ws';
5
- import { u as BaseChannelConstructor, B as BaseChannel, v as ChannelMatch, A as AuthenticatedSocket, w as PresenceData, d as ChannelOptions, k as SocketEvents, P as PresenceManager, c as SocketConfig, r as SocketServiceStatus, l as SocketHealthSnapshot } from './base_channel-Dr40l7CW.js';
5
+ import { v as BaseChannelConstructor, B as BaseChannel, w as ChannelMiddlewareRunnerFactory, x as ChannelMatch, A as AuthenticatedSocket, y as PresenceData, d as ChannelOptions, l as SocketEvents, P as PresenceManager, c as SocketConfig, s as SocketServiceStatus, m as SocketHealthSnapshot } from './base_channel-DPOnqned.js';
6
6
  import { HttpContext } from '@adonisjs/core/http';
7
7
  import { SocketFake } from './src/testing.js';
8
8
 
@@ -22,7 +22,8 @@ type ChannelFactory = (channel: BaseChannelConstructor) => BaseChannel<any> | Pr
22
22
  declare class ChannelRouter {
23
23
  #private;
24
24
  private makeChannel;
25
- constructor(makeChannel?: ChannelFactory);
25
+ private createMiddlewareRunner?;
26
+ constructor(makeChannel?: ChannelFactory, createMiddlewareRunner?: ChannelMiddlewareRunnerFactory | undefined);
26
27
  /**
27
28
  * Registers a channel.
28
29
  */
@@ -5,7 +5,9 @@ import "../chunk-E6ILCRL3.js";
5
5
 
6
6
  // src/assembler_hook.ts
7
7
  import fs from "fs";
8
- import ts from "typescript";
8
+ import { createRequire } from "module";
9
+ var require2 = createRequire(import.meta.url);
10
+ var ts;
9
11
  function quote(value) {
10
12
  return `'${value.replaceAll("\\", "\\\\").replaceAll("'", "\\'")}'`;
11
13
  }
@@ -144,6 +146,7 @@ function inspectChannel(filePath, importPath) {
144
146
  function generateSocketRegistry(options = {}) {
145
147
  return {
146
148
  run(_parent, hooks, indexGenerator) {
149
+ ts ??= require2("typescript");
147
150
  const source = options.source ?? "./app/channels";
148
151
  const glob = options.glob ?? ["**/*_channel.{ts,js}"];
149
152
  const importAlias = appImportAlias(source);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/assembler_hook.ts"],"sourcesContent":["import fs from 'node:fs'\nimport ts from 'typescript'\nimport type { CommonHooks } from '@adonisjs/assembler/types'\nimport type { IndexGeneratorSourceConfig } from '@adonisjs/assembler/types'\nimport { BindableChannelPattern } from './bindable_channel_pattern.js'\n\nexport interface SocketAssemblerHookOptions {\n source?: string\n glob?: string[]\n output?: string\n}\n\ntype Handler = { event: string; method: string }\ntype Channel = {\n pattern: string\n bindablePattern: BindableChannelPattern\n importPath: string\n handlers: Handler[]\n}\ntype SocketAssemblerHook = Extract<CommonHooks['init'][number], { run: (...args: any[]) => any }>\n\nfunction quote(value: string) {\n return `'${value.replaceAll('\\\\', '\\\\\\\\').replaceAll(\"'\", \"\\\\'\")}'`\n}\n\nfunction generatedImportPath(importPath: string): string {\n return importPath.replace(/\\.ts$/, '')\n}\n\nfunction appImportAlias(source: string): string {\n const normalized = source.replace(/^\\.\\//, '')\n if (normalized === 'app') return '#app'\n if (normalized.startsWith('app/')) return `#app/${normalized.slice('app/'.length)}`\n throw new Error('[socket] Channel source must be inside the app directory')\n}\n\nfunction fail(filePath: string, message: string): never {\n throw new Error(`[socket] Cannot generate client types for ${filePath}: ${message}`)\n}\n\nfunction propertyName(node: ts.PropertyName | undefined): string | undefined {\n if (node && (ts.isIdentifier(node) || ts.isStringLiteral(node))) return node.text\n}\n\nfunction isPublic(method: ts.MethodDeclaration) {\n return !method.modifiers?.some(\n (modifier) =>\n modifier.kind === ts.SyntaxKind.PrivateKeyword ||\n modifier.kind === ts.SyntaxKind.ProtectedKeyword\n )\n}\n\nfunction isStatic(member: ts.ClassElement): boolean {\n return (\n ts.canHaveModifiers(member) &&\n !!ts.getModifiers(member)?.some((modifier) => modifier.kind === ts.SyntaxKind.StaticKeyword)\n )\n}\n\nfunction validateHandlerMethod(filePath: string, method: ts.MethodDeclaration, name: string): void {\n const parameters = method.parameters.filter(\n (parameter) => !(ts.isIdentifier(parameter.name) && parameter.name.text === 'this')\n )\n if (parameters.some((parameter) => parameter.dotDotDotToken)) {\n fail(filePath, `handler method ${name} must not use rest parameters`)\n }\n if (parameters.slice(2).some((parameter) => !parameter.questionToken && !parameter.initializer)) {\n fail(filePath, `handler method ${name} must not require parameters after the payload`)\n }\n}\n\nfunction inspectChannel(filePath: string, importPath: string): Channel | string {\n const source = ts.createSourceFile(\n filePath,\n fs.readFileSync(filePath, 'utf8'),\n ts.ScriptTarget.Latest,\n true,\n filePath.endsWith('.js') ? ts.ScriptKind.JS : ts.ScriptKind.TS\n )\n const decoratorImports = new Set<string>()\n const decoratorNamespaces = new Set<string>()\n const baseChannelImports = new Set<string>()\n const socketNamespaces = new Set<string>()\n\n for (const statement of source.statements) {\n if (\n !ts.isImportDeclaration(statement) ||\n !ts.isStringLiteral(statement.moduleSpecifier) ||\n (statement.moduleSpecifier.text !== '@rlanz/socket/decorators' &&\n statement.moduleSpecifier.text !== '@rlanz/socket')\n ) {\n continue\n }\n\n const bindings = statement.importClause?.namedBindings\n if (bindings && ts.isNamedImports(bindings)) {\n for (const binding of bindings.elements) {\n const importedName = (binding.propertyName ?? binding.name).text\n if (\n statement.moduleSpecifier.text === '@rlanz/socket/decorators' &&\n importedName === 'onMessage'\n ) {\n decoratorImports.add(binding.name.text)\n }\n if (statement.moduleSpecifier.text === '@rlanz/socket' && importedName === 'BaseChannel') {\n baseChannelImports.add(binding.name.text)\n }\n }\n } else if (bindings && ts.isNamespaceImport(bindings)) {\n if (statement.moduleSpecifier.text === '@rlanz/socket/decorators') {\n decoratorNamespaces.add(bindings.name.text)\n } else {\n socketNamespaces.add(bindings.name.text)\n }\n }\n }\n\n const classes = source.statements.filter(ts.isClassDeclaration)\n let channelClass = classes.find((node) =>\n node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.DefaultKeyword)\n )\n\n if (!channelClass) {\n const defaultExport = source.statements.find(\n (node): node is ts.ExportAssignment => ts.isExportAssignment(node) && !node.isExportEquals\n )\n if (defaultExport && ts.isIdentifier(defaultExport.expression)) {\n const defaultClassName = defaultExport.expression.text\n channelClass = classes.find((node) => node.name?.text === defaultClassName)\n }\n }\n if (!channelClass) fail(filePath, 'a default-exported channel class was not found')\n if (channelClass.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AbstractKeyword)) {\n fail(filePath, 'the default-exported channel class must not be abstract')\n }\n\n const extendsType = channelClass.heritageClauses\n ?.find((clause) => clause.token === ts.SyntaxKind.ExtendsKeyword)\n ?.types.at(0)\n const extendsExpression = extendsType?.expression\n const directlyExtendsBaseChannel =\n (extendsExpression &&\n ts.isIdentifier(extendsExpression) &&\n baseChannelImports.has(extendsExpression.text)) ||\n (extendsExpression &&\n ts.isPropertyAccessExpression(extendsExpression) &&\n ts.isIdentifier(extendsExpression.expression) &&\n socketNamespaces.has(extendsExpression.expression.text) &&\n extendsExpression.name.text === 'BaseChannel')\n\n if (!directlyExtendsBaseChannel) {\n return (\n `Omitted ${importPath}: generated contracts do not support channel inheritance; ` +\n 'the default export must directly extend BaseChannel imported from @rlanz/socket.'\n )\n }\n\n const patternMember = channelClass.members.find(\n (member): member is ts.PropertyDeclaration =>\n ts.isPropertyDeclaration(member) &&\n propertyName(member.name) === 'pattern' &&\n !!member.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.StaticKeyword)\n )\n if (\n !patternMember ||\n !patternMember.initializer ||\n !ts.isStringLiteral(patternMember.initializer)\n ) {\n return `Omitted ${importPath}: static pattern must be a direct string literal.`\n }\n\n const bindablePattern = BindableChannelPattern.parse(patternMember.initializer.text)\n if (!bindablePattern) {\n return (\n `Omitted ${importPath}: pattern ${quote(patternMember.initializer.text)} is not supported by ` +\n 'generated typing; use literals, required params, a final optional param, or a final wildcard.'\n )\n }\n\n const handlers: Handler[] = []\n for (const method of channelClass.members.filter(ts.isMethodDeclaration)) {\n for (const decorator of ts.getDecorators(method) ?? []) {\n const expression = decorator.expression\n const isImportedDecorator =\n ts.isCallExpression(expression) &&\n ((ts.isIdentifier(expression.expression) &&\n decoratorImports.has(expression.expression.text)) ||\n (ts.isPropertyAccessExpression(expression.expression) &&\n ts.isIdentifier(expression.expression.expression) &&\n decoratorNamespaces.has(expression.expression.expression.text) &&\n expression.expression.name.text === 'onMessage'))\n\n if (!isImportedDecorator || !ts.isCallExpression(expression)) {\n continue\n }\n\n if (isStatic(method)) {\n fail(filePath, '@onMessage cannot generate a contract for a static method')\n }\n\n if (expression.arguments.length !== 1 || !ts.isStringLiteral(expression.arguments[0])) {\n fail(\n filePath,\n `@onMessage on ${propertyName(method.name) ?? '<computed>'} needs a literal event`\n )\n }\n const event = expression.arguments[0].text\n const name = propertyName(method.name)\n if (!name || !ts.isIdentifier(method.name)) fail(filePath, '@onMessage methods must be named')\n if (!isPublic(method)) fail(filePath, `decorated handler method ${name} must be public`)\n validateHandlerMethod(filePath, method, name)\n if (handlers.some((handler) => handler.event === event)) {\n fail(filePath, `event \"${event}\" is mapped more than once`)\n }\n handlers.push({ event, method: name })\n }\n }\n\n return { pattern: patternMember.initializer.text, bindablePattern, importPath, handlers }\n}\n\n/** Registers generation of the application socket registry with AdonisJS Assembler. */\nexport function generateSocketRegistry(\n options: SocketAssemblerHookOptions = {}\n): SocketAssemblerHook {\n return {\n run(_parent, hooks, indexGenerator) {\n const source = options.source ?? './app/channels'\n const glob = options.glob ?? ['**/*_channel.{ts,js}']\n const importAlias = appImportAlias(source)\n\n indexGenerator.add('socketChannels', {\n source,\n glob,\n importAlias,\n output: options.output ?? './.adonisjs/client/socket.ts',\n as(vfs, buffer, _config, helpers) {\n const channels: Channel[] = []\n const diagnostics: string[] = []\n for (const filePath of Object.values(vfs.asList())) {\n const importPath = generatedImportPath(helpers.toImportPath(filePath))\n const inspected = inspectChannel(filePath, importPath)\n if (typeof inspected === 'string') diagnostics.push(inspected)\n else channels.push(inspected)\n }\n\n const patterns = new Set<string>()\n for (const channel of channels) {\n if (patterns.has(channel.bindablePattern.canonicalPattern)) {\n fail(\n channel.importPath,\n `pattern ${quote(channel.pattern)} is declared more than once`\n )\n }\n patterns.add(channel.bindablePattern.canonicalPattern)\n }\n\n for (const diagnostic of diagnostics) buffer.writeLine(`// [socket] ${diagnostic}`)\n if (diagnostics.length) buffer.writeLine('')\n buffer.writeLine('export interface AppSocket {').indent()\n buffer.writeLine('readonly channels: {').indent()\n for (const channel of channels) {\n buffer.writeLine(`readonly ${quote(channel.pattern)}: {`).indent()\n if (channel.bindablePattern.parameters.length === 0) {\n buffer.writeLine('readonly params: undefined')\n } else {\n buffer.writeLine('readonly params: {').indent()\n for (const parameter of channel.bindablePattern.parameters) {\n buffer.writeLine(\n `readonly ${quote(parameter.name)}${parameter.optional ? '?' : ''}: string | number`\n )\n }\n buffer.dedent().writeLine('}')\n }\n buffer.writeLine(\n `readonly channel: typeof import(${quote(channel.importPath)}).default`\n )\n buffer.writeLine('readonly handlers: {').indent()\n for (const handler of channel.handlers) {\n buffer.writeLine(`readonly ${quote(handler.event)}: ${quote(handler.method)}`)\n }\n buffer.dedent().writeLine('}')\n buffer.dedent().writeLine('}')\n }\n buffer.dedent().writeLine('}')\n buffer.dedent().writeLine('}')\n },\n } satisfies IndexGeneratorSourceConfig)\n\n indexGenerator.add('socketServerChannels', {\n source,\n glob,\n importAlias,\n output: './.adonisjs/server/socket_channels.ts',\n as(vfs, buffer, _config, helpers) {\n const filePaths = Object.values(vfs.asList())\n filePaths.forEach((filePath, index) => {\n const importPath = generatedImportPath(helpers.toImportPath(filePath))\n buffer.writeLine(`import Channel${index} from ${quote(importPath)}`)\n })\n if (filePaths.length) buffer.writeLine('')\n buffer.writeLine(\n `export const socketChannels = [${filePaths.map((_filePath, index) => `Channel${index}`).join(', ')}] as const`\n )\n },\n } satisfies IndexGeneratorSourceConfig)\n\n hooks.add('fileChanged', (_relativePath, absolutePath) => {\n return indexGenerator.addFile(absolutePath)\n })\n },\n }\n}\n\nconst socketRegistryHook = generateSocketRegistry()\nconst lazySocketRegistryHook: SocketAssemblerHook['run'] = socketRegistryHook.run\n\nexport default lazySocketRegistryHook\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/assembler_hook.ts"],"sourcesContent":["import fs from 'node:fs'\nimport { createRequire } from 'node:module'\nimport type TypeScript from 'typescript'\nimport type { CommonHooks } from '@adonisjs/assembler/types'\nimport type { IndexGeneratorSourceConfig } from '@adonisjs/assembler/types'\nimport { BindableChannelPattern } from './bindable_channel_pattern.js'\n\nconst require = createRequire(import.meta.url)\nlet ts: typeof TypeScript\n\nexport interface SocketAssemblerHookOptions {\n source?: string\n glob?: string[]\n output?: string\n}\n\ntype Handler = { event: string; method: string }\ntype Channel = {\n pattern: string\n bindablePattern: BindableChannelPattern\n importPath: string\n handlers: Handler[]\n}\ntype SocketAssemblerHook = Extract<CommonHooks['init'][number], { run: (...args: any[]) => any }>\n\nfunction quote(value: string) {\n return `'${value.replaceAll('\\\\', '\\\\\\\\').replaceAll(\"'\", \"\\\\'\")}'`\n}\n\nfunction generatedImportPath(importPath: string): string {\n return importPath.replace(/\\.ts$/, '')\n}\n\nfunction appImportAlias(source: string): string {\n const normalized = source.replace(/^\\.\\//, '')\n if (normalized === 'app') return '#app'\n if (normalized.startsWith('app/')) return `#app/${normalized.slice('app/'.length)}`\n throw new Error('[socket] Channel source must be inside the app directory')\n}\n\nfunction fail(filePath: string, message: string): never {\n throw new Error(`[socket] Cannot generate client types for ${filePath}: ${message}`)\n}\n\nfunction propertyName(node: TypeScript.PropertyName | undefined): string | undefined {\n if (node && (ts.isIdentifier(node) || ts.isStringLiteral(node))) return node.text\n}\n\nfunction isPublic(method: TypeScript.MethodDeclaration) {\n return !method.modifiers?.some(\n (modifier) =>\n modifier.kind === ts.SyntaxKind.PrivateKeyword ||\n modifier.kind === ts.SyntaxKind.ProtectedKeyword\n )\n}\n\nfunction isStatic(member: TypeScript.ClassElement): boolean {\n return (\n ts.canHaveModifiers(member) &&\n !!ts.getModifiers(member)?.some((modifier) => modifier.kind === ts.SyntaxKind.StaticKeyword)\n )\n}\n\nfunction validateHandlerMethod(\n filePath: string,\n method: TypeScript.MethodDeclaration,\n name: string\n): void {\n const parameters = method.parameters.filter(\n (parameter) => !(ts.isIdentifier(parameter.name) && parameter.name.text === 'this')\n )\n if (parameters.some((parameter) => parameter.dotDotDotToken)) {\n fail(filePath, `handler method ${name} must not use rest parameters`)\n }\n if (parameters.slice(2).some((parameter) => !parameter.questionToken && !parameter.initializer)) {\n fail(filePath, `handler method ${name} must not require parameters after the payload`)\n }\n}\n\nfunction inspectChannel(filePath: string, importPath: string): Channel | string {\n const source = ts.createSourceFile(\n filePath,\n fs.readFileSync(filePath, 'utf8'),\n ts.ScriptTarget.Latest,\n true,\n filePath.endsWith('.js') ? ts.ScriptKind.JS : ts.ScriptKind.TS\n )\n const decoratorImports = new Set<string>()\n const decoratorNamespaces = new Set<string>()\n const baseChannelImports = new Set<string>()\n const socketNamespaces = new Set<string>()\n\n for (const statement of source.statements) {\n if (\n !ts.isImportDeclaration(statement) ||\n !ts.isStringLiteral(statement.moduleSpecifier) ||\n (statement.moduleSpecifier.text !== '@rlanz/socket/decorators' &&\n statement.moduleSpecifier.text !== '@rlanz/socket')\n ) {\n continue\n }\n\n const bindings = statement.importClause?.namedBindings\n if (bindings && ts.isNamedImports(bindings)) {\n for (const binding of bindings.elements) {\n const importedName = (binding.propertyName ?? binding.name).text\n if (\n statement.moduleSpecifier.text === '@rlanz/socket/decorators' &&\n importedName === 'onMessage'\n ) {\n decoratorImports.add(binding.name.text)\n }\n if (statement.moduleSpecifier.text === '@rlanz/socket' && importedName === 'BaseChannel') {\n baseChannelImports.add(binding.name.text)\n }\n }\n } else if (bindings && ts.isNamespaceImport(bindings)) {\n if (statement.moduleSpecifier.text === '@rlanz/socket/decorators') {\n decoratorNamespaces.add(bindings.name.text)\n } else {\n socketNamespaces.add(bindings.name.text)\n }\n }\n }\n\n const classes = source.statements.filter(ts.isClassDeclaration)\n let channelClass = classes.find((node) =>\n node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.DefaultKeyword)\n )\n\n if (!channelClass) {\n const defaultExport = source.statements.find(\n (node): node is TypeScript.ExportAssignment =>\n ts.isExportAssignment(node) && !node.isExportEquals\n )\n if (defaultExport && ts.isIdentifier(defaultExport.expression)) {\n const defaultClassName = defaultExport.expression.text\n channelClass = classes.find((node) => node.name?.text === defaultClassName)\n }\n }\n if (!channelClass) fail(filePath, 'a default-exported channel class was not found')\n if (channelClass.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AbstractKeyword)) {\n fail(filePath, 'the default-exported channel class must not be abstract')\n }\n\n const extendsType = channelClass.heritageClauses\n ?.find((clause) => clause.token === ts.SyntaxKind.ExtendsKeyword)\n ?.types.at(0)\n const extendsExpression = extendsType?.expression\n const directlyExtendsBaseChannel =\n (extendsExpression &&\n ts.isIdentifier(extendsExpression) &&\n baseChannelImports.has(extendsExpression.text)) ||\n (extendsExpression &&\n ts.isPropertyAccessExpression(extendsExpression) &&\n ts.isIdentifier(extendsExpression.expression) &&\n socketNamespaces.has(extendsExpression.expression.text) &&\n extendsExpression.name.text === 'BaseChannel')\n\n if (!directlyExtendsBaseChannel) {\n return (\n `Omitted ${importPath}: generated contracts do not support channel inheritance; ` +\n 'the default export must directly extend BaseChannel imported from @rlanz/socket.'\n )\n }\n\n const patternMember = channelClass.members.find(\n (member): member is TypeScript.PropertyDeclaration =>\n ts.isPropertyDeclaration(member) &&\n propertyName(member.name) === 'pattern' &&\n !!member.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.StaticKeyword)\n )\n if (\n !patternMember ||\n !patternMember.initializer ||\n !ts.isStringLiteral(patternMember.initializer)\n ) {\n return `Omitted ${importPath}: static pattern must be a direct string literal.`\n }\n\n const bindablePattern = BindableChannelPattern.parse(patternMember.initializer.text)\n if (!bindablePattern) {\n return (\n `Omitted ${importPath}: pattern ${quote(patternMember.initializer.text)} is not supported by ` +\n 'generated typing; use literals, required params, a final optional param, or a final wildcard.'\n )\n }\n\n const handlers: Handler[] = []\n for (const method of channelClass.members.filter(ts.isMethodDeclaration)) {\n for (const decorator of ts.getDecorators(method) ?? []) {\n const expression = decorator.expression\n const isImportedDecorator =\n ts.isCallExpression(expression) &&\n ((ts.isIdentifier(expression.expression) &&\n decoratorImports.has(expression.expression.text)) ||\n (ts.isPropertyAccessExpression(expression.expression) &&\n ts.isIdentifier(expression.expression.expression) &&\n decoratorNamespaces.has(expression.expression.expression.text) &&\n expression.expression.name.text === 'onMessage'))\n\n if (!isImportedDecorator || !ts.isCallExpression(expression)) {\n continue\n }\n\n if (isStatic(method)) {\n fail(filePath, '@onMessage cannot generate a contract for a static method')\n }\n\n if (expression.arguments.length !== 1 || !ts.isStringLiteral(expression.arguments[0])) {\n fail(\n filePath,\n `@onMessage on ${propertyName(method.name) ?? '<computed>'} needs a literal event`\n )\n }\n const event = expression.arguments[0].text\n const name = propertyName(method.name)\n if (!name || !ts.isIdentifier(method.name)) fail(filePath, '@onMessage methods must be named')\n if (!isPublic(method)) fail(filePath, `decorated handler method ${name} must be public`)\n validateHandlerMethod(filePath, method, name)\n if (handlers.some((handler) => handler.event === event)) {\n fail(filePath, `event \"${event}\" is mapped more than once`)\n }\n handlers.push({ event, method: name })\n }\n }\n\n return { pattern: patternMember.initializer.text, bindablePattern, importPath, handlers }\n}\n\n/** Registers generation of the application socket registry with AdonisJS Assembler. */\nexport function generateSocketRegistry(\n options: SocketAssemblerHookOptions = {}\n): SocketAssemblerHook {\n return {\n run(_parent, hooks, indexGenerator) {\n ts ??= require('typescript') as typeof TypeScript\n\n const source = options.source ?? './app/channels'\n const glob = options.glob ?? ['**/*_channel.{ts,js}']\n const importAlias = appImportAlias(source)\n\n indexGenerator.add('socketChannels', {\n source,\n glob,\n importAlias,\n output: options.output ?? './.adonisjs/client/socket.ts',\n as(vfs, buffer, _config, helpers) {\n const channels: Channel[] = []\n const diagnostics: string[] = []\n for (const filePath of Object.values(vfs.asList())) {\n const importPath = generatedImportPath(helpers.toImportPath(filePath))\n const inspected = inspectChannel(filePath, importPath)\n if (typeof inspected === 'string') diagnostics.push(inspected)\n else channels.push(inspected)\n }\n\n const patterns = new Set<string>()\n for (const channel of channels) {\n if (patterns.has(channel.bindablePattern.canonicalPattern)) {\n fail(\n channel.importPath,\n `pattern ${quote(channel.pattern)} is declared more than once`\n )\n }\n patterns.add(channel.bindablePattern.canonicalPattern)\n }\n\n for (const diagnostic of diagnostics) buffer.writeLine(`// [socket] ${diagnostic}`)\n if (diagnostics.length) buffer.writeLine('')\n buffer.writeLine('export interface AppSocket {').indent()\n buffer.writeLine('readonly channels: {').indent()\n for (const channel of channels) {\n buffer.writeLine(`readonly ${quote(channel.pattern)}: {`).indent()\n if (channel.bindablePattern.parameters.length === 0) {\n buffer.writeLine('readonly params: undefined')\n } else {\n buffer.writeLine('readonly params: {').indent()\n for (const parameter of channel.bindablePattern.parameters) {\n buffer.writeLine(\n `readonly ${quote(parameter.name)}${parameter.optional ? '?' : ''}: string | number`\n )\n }\n buffer.dedent().writeLine('}')\n }\n buffer.writeLine(\n `readonly channel: typeof import(${quote(channel.importPath)}).default`\n )\n buffer.writeLine('readonly handlers: {').indent()\n for (const handler of channel.handlers) {\n buffer.writeLine(`readonly ${quote(handler.event)}: ${quote(handler.method)}`)\n }\n buffer.dedent().writeLine('}')\n buffer.dedent().writeLine('}')\n }\n buffer.dedent().writeLine('}')\n buffer.dedent().writeLine('}')\n },\n } satisfies IndexGeneratorSourceConfig)\n\n indexGenerator.add('socketServerChannels', {\n source,\n glob,\n importAlias,\n output: './.adonisjs/server/socket_channels.ts',\n as(vfs, buffer, _config, helpers) {\n const filePaths = Object.values(vfs.asList())\n filePaths.forEach((filePath, index) => {\n const importPath = generatedImportPath(helpers.toImportPath(filePath))\n buffer.writeLine(`import Channel${index} from ${quote(importPath)}`)\n })\n if (filePaths.length) buffer.writeLine('')\n buffer.writeLine(\n `export const socketChannels = [${filePaths.map((_filePath, index) => `Channel${index}`).join(', ')}] as const`\n )\n },\n } satisfies IndexGeneratorSourceConfig)\n\n hooks.add('fileChanged', (_relativePath, absolutePath) => {\n return indexGenerator.addFile(absolutePath)\n })\n },\n }\n}\n\nconst socketRegistryHook = generateSocketRegistry()\nconst lazySocketRegistryHook: SocketAssemblerHook['run'] = socketRegistryHook.run\n\nexport default lazySocketRegistryHook\n"],"mappings":"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","names":["require"]}
@@ -1,6 +1,6 @@
1
- export { S as Socket } from '../../index-Fg-tkHhP.js';
1
+ export { S as Socket } from '../../index-DjBYUhFR.js';
2
2
  export { ChannelBroadcastEvent, ChannelBroadcastPayload, ChannelCallArgs, ChannelClientEvent, ChannelClientEventPayload, ChannelParameters, ChannelPattern, ConnectionState, EventHandler, PresenceData, PresenceUser, SocketOptions, SubscribeAckData, SubscribeOptions, SubscribeResult, UnsubscribeOptions } from './types.js';
3
- export { a as ChannelAck, b as ChannelMessage } from '../../base_channel-Dr40l7CW.js';
3
+ export { a as ChannelAck, b as ChannelMessage } from '../../base_channel-DPOnqned.js';
4
4
  import 'ws';
5
5
  import 'node:http';
6
6
  import '@adonisjs/core/types/http';
@@ -1,9 +1,9 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
- import { S as Socket } from '../../index-Fg-tkHhP.js';
3
+ import { S as Socket } from '../../index-DjBYUhFR.js';
4
4
  import { ConnectionState, EventHandler } from './types.js';
5
- import { F as FrameworkChannelCallArgs, a as FrameworkChannel, b as FrameworkChannelPattern, c as FrameworkChannelEvent, d as FrameworkChannelParameters, e as FrameworkChannelEventPayload } from '../../framework-B-4kGmAw.js';
6
- import '../../base_channel-Dr40l7CW.js';
5
+ import { F as FrameworkChannelCallArgs, a as FrameworkChannel, b as FrameworkChannelPattern, c as FrameworkChannelEvent, d as FrameworkChannelParameters, e as FrameworkChannelEventPayload } from '../../framework-B8pJ4cCA.js';
6
+ import '../../base_channel-DPOnqned.js';
7
7
  import 'ws';
8
8
  import 'node:http';
9
9
  import '@adonisjs/core/types/http';
@@ -1,5 +1,5 @@
1
- import { C as ChannelServerEventsOf } from '../../base_channel-Dr40l7CW.js';
2
- export { a as ChannelAck, b as ChannelMessage } from '../../base_channel-Dr40l7CW.js';
1
+ import { C as ChannelServerEventsOf } from '../../base_channel-DPOnqned.js';
2
+ export { a as ChannelAck, b as ChannelMessage } from '../../base_channel-DPOnqned.js';
3
3
  import 'ws';
4
4
  import 'node:http';
5
5
  import '@adonisjs/core/types/http';
@@ -1,8 +1,8 @@
1
1
  import { ShallowRef, ComputedRef, MaybeRefOrGetter } from 'vue';
2
- import { S as Socket } from '../../index-Fg-tkHhP.js';
2
+ import { S as Socket } from '../../index-DjBYUhFR.js';
3
3
  import { ConnectionState, EventHandler } from './types.js';
4
- import { b as FrameworkChannelPattern, d as FrameworkChannelParameters, a as FrameworkChannel, c as FrameworkChannelEvent, e as FrameworkChannelEventPayload } from '../../framework-B-4kGmAw.js';
5
- import '../../base_channel-Dr40l7CW.js';
4
+ import { b as FrameworkChannelPattern, d as FrameworkChannelParameters, a as FrameworkChannel, c as FrameworkChannelEvent, e as FrameworkChannelEventPayload } from '../../framework-B8pJ4cCA.js';
5
+ import '../../base_channel-DPOnqned.js';
6
6
  import 'ws';
7
7
  import 'node:http';
8
8
  import '@adonisjs/core/types/http';
@@ -1,4 +1,4 @@
1
- import { A as AuthenticatedSocket } from '../base_channel-Dr40l7CW.js';
1
+ import { A as AuthenticatedSocket } from '../base_channel-DPOnqned.js';
2
2
  import 'ws';
3
3
  import 'node:http';
4
4
  import '@adonisjs/core/types/http';
@@ -1,10 +1,10 @@
1
1
  import { BaseCheck, Result } from '@adonisjs/core/health';
2
- import { S as SocketService } from '../socket_service-BYEB8LIN.js';
2
+ import { S as SocketService } from '../socket_service-BcC9ASCE.js';
3
3
  import 'node:http';
4
4
  import '@adonisjs/logger';
5
5
  import 'emittery';
6
6
  import 'ws';
7
- import '../base_channel-Dr40l7CW.js';
7
+ import '../base_channel-DPOnqned.js';
8
8
  import '@adonisjs/core/types/http';
9
9
  import '@adonisjs/core/http';
10
10
  import '@boringnode/bus/types/main';
@@ -1,4 +1,4 @@
1
- export { A as AuthenticatedSocket, a as ChannelAck, v as ChannelMatch, b as ChannelMessage, d as ChannelOptions, C as ChannelServerEventsOf, D as Duration, M as Middleware, e as MiddlewareClass, f as MiddlewareContext, g as MiddlewareFn, h as PresenceInfo, i as PresenceMember, R as RawSocket, S as SocketAuthenticationHandler, j as SocketAuthenticationResult, c as SocketConfig, k as SocketEvents, l as SocketHealthSnapshot, m as SocketHttpMiddleware, n as SocketOriginResolver, o as SocketOriginValues, q as SocketRetryQueueConfig, r as SocketServiceStatus, s as SocketTransportConfig, t as SocketUpgradeContext } from '../base_channel-Dr40l7CW.js';
1
+ export { A as AuthenticatedSocket, a as ChannelAck, x as ChannelMatch, b as ChannelMessage, d as ChannelOptions, C as ChannelServerEventsOf, D as Duration, M as Middleware, e as MiddlewareClass, f as MiddlewareConstructor, g as MiddlewareContext, h as MiddlewareFn, i as PresenceInfo, j as PresenceMember, R as RawSocket, S as SocketAuthenticationHandler, k as SocketAuthenticationResult, c as SocketConfig, l as SocketEvents, m as SocketHealthSnapshot, n as SocketHttpMiddleware, o as SocketOriginResolver, p as SocketOriginValues, r as SocketRetryQueueConfig, s as SocketServiceStatus, t as SocketTransportConfig, u as SocketUpgradeContext } from '../base_channel-DPOnqned.js';
2
2
  import 'ws';
3
3
  import 'node:http';
4
4
  import '@adonisjs/core/types/http';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rlanz/socket",
3
- "version": "0.0.1-7",
3
+ "version": "0.0.1-9",
4
4
  "description": "WebSocket integration for AdonisJS",
5
5
  "type": "module",
6
6
  "main": "./build/index.js",
@@ -32,12 +32,11 @@
32
32
  "build": "npm run compile",
33
33
  "clean": "del-cli build",
34
34
  "compile": "npm run clean && tsup-node",
35
- "check:package": "node --import=@poppinss/ts-exec bin/check_package.ts",
36
35
  "lint": "oxlint",
37
36
  "lint:fix": "oxlint --fix",
38
37
  "format": "oxfmt --check .",
39
38
  "format:fix": "oxfmt --write .",
40
- "prepublishOnly": "npm run build && npm run check:package",
39
+ "prepublishOnly": "npm run build",
41
40
  "release": "release-it",
42
41
  "test": "node --import=@poppinss/ts-exec --enable-source-maps bin/test.ts",
43
42
  "typecheck": "tsc --noEmit",
@@ -72,6 +71,7 @@
72
71
  "oxlint": "^1.53.0",
73
72
  "react": "^19.1.1",
74
73
  "react-test-renderer": "^19.1.1",
74
+ "reflect-metadata": "^0.2.2",
75
75
  "release-it": "^19.2.4",
76
76
  "scheduler": "^0.27.0",
77
77
  "tsup": "^8.5.1",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/base_channel.ts"],"sourcesContent":["import type {\n AuthenticatedSocket,\n ChannelOptions,\n PresenceInfo,\n PresenceMember,\n Middleware,\n MiddlewareContext,\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 = Record<never, never>> {\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 * 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<K extends keyof ServerEvents & string>(\n event: K,\n data: ServerEvents[K]\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<K extends keyof ServerEvents & string>(\n socketId: string,\n event: K,\n data: ServerEvents[K]\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 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 = getDecoratedChannelHandlers<User>(this)\n const handler = handlers[event]\n\n if (typeof handler === 'function') {\n return Reflect.apply(handler, this, [socket, data])\n }\n\n throw new SocketResponseError(`Unknown channel event: ${event}`)\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, including container-injected dependencies. */\nexport interface BaseChannelConstructor {\n new (...args: any[]): BaseChannel<any, any>\n readonly name: string\n pattern: string\n options?: ChannelOptions\n middlewares?: Middleware<any>[]\n}\n"],"mappings":";;;;;AAuBO,IAAM,sBAAN,cAAkC,MAAM;AAAC;AAEzC,IAAM,2BAAN,cAAuC,oBAAoB;AAAA,EAChE,cAAc;AACZ,UAAM,0DAA0D;AAAA,EAClE;AACF;AA8CO,IAAM,cAAN,MAAuE;AAAA;AAAA;AAAA;AAAA,EAM5E,OAAO;AAAA;AAAA;AAAA;AAAA,EAKP,OAAO;AAAA;AAAA;AAAA;AAAA,EAKP,OAAO;AAAA;AAAA;AAAA;AAAA,EAKG;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA,EAKV,YACE,QACA,aACA,QACA,UACM;AACN,SAAK,SAAS;AACd,SAAK,cAAc;AACnB,SAAK,SAAS;AACd,QAAI,UAAU;AACZ,WAAK,WAAW;AAAA,IAClB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKU,UACR,OACA,MACM;AACN,SAAK,OAAO,GAAG,KAAK,WAAW,EAAE,KAAK,OAAO,IAAI;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA,EAKU,gBACR,UACA,OACA,MACM;AACN,SAAK,OAAO,GAAG,KAAK,WAAW,EAAE,OAAO,QAAQ,EAAE,KAAK,OAAO,IAAI;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,gBAAgB,KAA6C;AACjE,UAAM,cAAe,KAAK,YAAmC,eAAe,CAAC;AAE7E,QAAI,QAAQ;AAEZ,UAAM,OAAO,YAA2B;AACtC,UAAI,SAAS,YAAY,OAAQ;AAEjC,YAAM,aAAa,YAAY,OAAO;AAEtC,UAAI,OAAO,eAAe,YAAY;AACpC,cAAM,WAAW,KAAK,IAAI;AAAA,MAC5B,OAAO;AACL,cAAM,WAAW,OAAO,KAAK,IAAI;AAAA,MACnC;AAAA,IACF;AAEA,UAAM,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA,EAwCA,MAAM,eACJ,QACA,OACA,MACkB;AAClB,UAAM,WAAW,4BAAkC,IAAI;AACvD,UAAM,UAAU,SAAS,KAAK;AAE9B,QAAI,OAAO,YAAY,YAAY;AACjC,aAAO,QAAQ,MAAM,SAAS,MAAM,CAAC,QAAQ,IAAI,CAAC;AAAA,IACpD;AAEA,UAAM,IAAI,oBAAoB,0BAA0B,KAAK,EAAE;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAY,WAAsC,QAAiC;AACvF,UAAM,KAAK,SAAS,QAAQ,GAAG,MAAM;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa,WAAsC,QAAiC;AACxF,UAAM,KAAK,UAAU,QAAQ,GAAG,MAAM;AAAA,EACxC;AAAA,EAEA,iBAAiB,QAAiD;AAChE,QAAI,CAAC,KAAK,iBAAiB;AACzB,YAAM,IAAI,yBAAyB;AAAA,IACrC;AAEA,WAAO,KAAK,gBAAgB,MAAM;AAAA,EACpC;AACF;","names":[]}