@motiadev/core 0.15.5-beta.174-069425 → 0.15.5-beta.174-384621

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.
@@ -22,6 +22,7 @@ declare class Logger {
22
22
  warn(message: string, args?: unknown): void;
23
23
  log(args: any): void;
24
24
  addListener(listener: LogListener): void;
25
+ removeListener(listener: LogListener): void;
25
26
  }
26
27
  //#endregion
27
28
  export { Logger };
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.mts","names":[],"sources":["../../src/logger.ts"],"sourcesContent":[],"mappings":";KA6BY,WAAA;AAAA,cAEC,MAAA,CAFU;EAEV,SAAM,SAAA,EAAA,OAAA;EAaQ,iBAAA,IAAA;EACS,iBAAA,aAAA;EAGtB;;;;;;;;;0CAJa,yCACS;cAGtB,0BAA0B;;;;;;;wBA8ChB"}
1
+ {"version":3,"file":"logger.d.mts","names":[],"sources":["../../src/logger.ts"],"sourcesContent":[],"mappings":";KA6BY,WAAA;AAAA,cAEC,MAAA,CAFU;EAEV,SAAM,SAAA,EAAA,OAAA;EAaQ,iBAAA,IAAA;EACS,iBAAA,aAAA;EAGtB;;;;;;;;;0CAJa,yCACS;cAGtB,0BAA0B;;;;;;;wBA8ChB;2BAIG"}
@@ -71,6 +71,10 @@ var Logger = class Logger {
71
71
  addListener(listener) {
72
72
  this.listeners.push(listener);
73
73
  }
74
+ removeListener(listener) {
75
+ const index = this.listeners.indexOf(listener);
76
+ if (index > -1) this.listeners.splice(index, 1);
77
+ }
74
78
  };
75
79
  const globalLogger = new Logger();
76
80
 
@@ -1 +1 @@
1
- {"version":3,"file":"logger.mjs","names":["levelMap: Record<string, number>","isVerbose: boolean","meta: Record<string, unknown>","coreListeners: LogListener[]"],"sources":["../../src/logger.ts"],"sourcesContent":["import { prettyPrint } from './pretty-print'\n\nconst LEVELS = {\n NOTSET: 0,\n DEBUG: 10,\n INFO: 20,\n WARNING: 30,\n ERROR: 40,\n CRITICAL: 50,\n} as const\n\nconst levelMap: Record<string, number> = {\n debug: LEVELS.DEBUG,\n info: LEVELS.INFO,\n warn: LEVELS.WARNING,\n warning: LEVELS.WARNING,\n error: LEVELS.ERROR,\n critical: LEVELS.CRITICAL,\n}\n\nconst getLogLevel = (): number => {\n const level = process.env.LOG_LEVEL ?? 'info'\n return levelMap[level] ?? LEVELS.INFO\n}\n\nconst shouldLog = (messageLevel: number): boolean => {\n return messageLevel >= getLogLevel()\n}\n\nexport type LogListener = (level: string, msg: string, args?: unknown) => void\n\nexport class Logger {\n /**\n * Why do we need two level of listeners?\n *\n * Core listeners pass along to children loggers.\n *\n * However, base listeners do not pass along to children loggers.\n * Those are specific to each logger in the hierarchy.\n */\n private readonly listeners: LogListener[] = []\n\n constructor(\n readonly isVerbose: boolean = false,\n private readonly meta: Record<string, unknown> = {},\n private readonly coreListeners: LogListener[] = [],\n ) {}\n\n child(meta: Record<string, unknown>): Logger {\n return new Logger(this.isVerbose, { ...this.meta, ...meta }, this.coreListeners)\n }\n\n private _log(level: string, msg: string, args?: any) {\n const time = Date.now()\n const meta = { ...this.meta, ...(args ?? {}) }\n prettyPrint({ level, time, msg, ...meta }, !this.isVerbose)\n\n this.coreListeners.forEach((listener) => listener(level, msg, meta))\n this.listeners.forEach((listener) => listener(level, msg, meta))\n }\n\n info(message: string, args?: unknown) {\n if (shouldLog(LEVELS.INFO)) {\n this._log('info', message, args)\n }\n }\n\n error(message: string, args?: unknown) {\n if (shouldLog(LEVELS.ERROR)) {\n this._log('error', message, args)\n }\n }\n\n debug(message: string, args?: unknown) {\n if (shouldLog(LEVELS.DEBUG)) {\n this._log('debug', message, args)\n }\n }\n\n warn(message: string, args?: unknown) {\n if (shouldLog(LEVELS.WARNING)) {\n this._log('warn', message, args)\n }\n }\n\n log(args: any) {\n const level = args.level ?? 'info'\n const messageLevel = levelMap[level] ?? LEVELS.INFO\n\n if (!shouldLog(messageLevel)) return\n\n this._log(level, args.msg, args)\n }\n\n addListener(listener: LogListener) {\n this.listeners.push(listener)\n }\n}\n\nexport const globalLogger = new Logger()\n"],"mappings":";;;AAEA,MAAM,SAAS;CACb,QAAQ;CACR,OAAO;CACP,MAAM;CACN,SAAS;CACT,OAAO;CACP,UAAU;CACX;AAED,MAAMA,WAAmC;CACvC,OAAO,OAAO;CACd,MAAM,OAAO;CACb,MAAM,OAAO;CACb,SAAS,OAAO;CAChB,OAAO,OAAO;CACd,UAAU,OAAO;CAClB;AAED,MAAM,oBAA4B;AAEhC,QAAO,SADO,QAAQ,IAAI,aAAa,WACb,OAAO;;AAGnC,MAAM,aAAa,iBAAkC;AACnD,QAAO,gBAAgB,aAAa;;AAKtC,IAAa,SAAb,MAAa,OAAO;CAWlB,YACE,AAASC,YAAqB,OAC9B,AAAiBC,OAAgC,EAAE,EACnD,AAAiBC,gBAA+B,EAAE,EAClD;EAHS;EACQ;EACA;mBALyB,EAAE;;CAQ9C,MAAM,MAAuC;AAC3C,SAAO,IAAI,OAAO,KAAK,WAAW;GAAE,GAAG,KAAK;GAAM,GAAG;GAAM,EAAE,KAAK,cAAc;;CAGlF,AAAQ,KAAK,OAAe,KAAa,MAAY;EACnD,MAAM,OAAO,KAAK,KAAK;EACvB,MAAM,OAAO;GAAE,GAAG,KAAK;GAAM,GAAI,QAAQ,EAAE;GAAG;AAC9C,cAAY;GAAE;GAAO;GAAM;GAAK,GAAG;GAAM,EAAE,CAAC,KAAK,UAAU;AAE3D,OAAK,cAAc,SAAS,aAAa,SAAS,OAAO,KAAK,KAAK,CAAC;AACpE,OAAK,UAAU,SAAS,aAAa,SAAS,OAAO,KAAK,KAAK,CAAC;;CAGlE,KAAK,SAAiB,MAAgB;AACpC,MAAI,UAAU,OAAO,KAAK,CACxB,MAAK,KAAK,QAAQ,SAAS,KAAK;;CAIpC,MAAM,SAAiB,MAAgB;AACrC,MAAI,UAAU,OAAO,MAAM,CACzB,MAAK,KAAK,SAAS,SAAS,KAAK;;CAIrC,MAAM,SAAiB,MAAgB;AACrC,MAAI,UAAU,OAAO,MAAM,CACzB,MAAK,KAAK,SAAS,SAAS,KAAK;;CAIrC,KAAK,SAAiB,MAAgB;AACpC,MAAI,UAAU,OAAO,QAAQ,CAC3B,MAAK,KAAK,QAAQ,SAAS,KAAK;;CAIpC,IAAI,MAAW;EACb,MAAM,QAAQ,KAAK,SAAS;AAG5B,MAAI,CAAC,UAFgB,SAAS,UAAU,OAAO,KAEnB,CAAE;AAE9B,OAAK,KAAK,OAAO,KAAK,KAAK,KAAK;;CAGlC,YAAY,UAAuB;AACjC,OAAK,UAAU,KAAK,SAAS;;;AAIjC,MAAa,eAAe,IAAI,QAAQ"}
1
+ {"version":3,"file":"logger.mjs","names":["levelMap: Record<string, number>","isVerbose: boolean","meta: Record<string, unknown>","coreListeners: LogListener[]"],"sources":["../../src/logger.ts"],"sourcesContent":["import { prettyPrint } from './pretty-print'\n\nconst LEVELS = {\n NOTSET: 0,\n DEBUG: 10,\n INFO: 20,\n WARNING: 30,\n ERROR: 40,\n CRITICAL: 50,\n} as const\n\nconst levelMap: Record<string, number> = {\n debug: LEVELS.DEBUG,\n info: LEVELS.INFO,\n warn: LEVELS.WARNING,\n warning: LEVELS.WARNING,\n error: LEVELS.ERROR,\n critical: LEVELS.CRITICAL,\n}\n\nconst getLogLevel = (): number => {\n const level = process.env.LOG_LEVEL ?? 'info'\n return levelMap[level] ?? LEVELS.INFO\n}\n\nconst shouldLog = (messageLevel: number): boolean => {\n return messageLevel >= getLogLevel()\n}\n\nexport type LogListener = (level: string, msg: string, args?: unknown) => void\n\nexport class Logger {\n /**\n * Why do we need two level of listeners?\n *\n * Core listeners pass along to children loggers.\n *\n * However, base listeners do not pass along to children loggers.\n * Those are specific to each logger in the hierarchy.\n */\n private readonly listeners: LogListener[] = []\n\n constructor(\n readonly isVerbose: boolean = false,\n private readonly meta: Record<string, unknown> = {},\n private readonly coreListeners: LogListener[] = [],\n ) {}\n\n child(meta: Record<string, unknown>): Logger {\n return new Logger(this.isVerbose, { ...this.meta, ...meta }, this.coreListeners)\n }\n\n private _log(level: string, msg: string, args?: any) {\n const time = Date.now()\n const meta = { ...this.meta, ...(args ?? {}) }\n prettyPrint({ level, time, msg, ...meta }, !this.isVerbose)\n\n this.coreListeners.forEach((listener) => listener(level, msg, meta))\n this.listeners.forEach((listener) => listener(level, msg, meta))\n }\n\n info(message: string, args?: unknown) {\n if (shouldLog(LEVELS.INFO)) {\n this._log('info', message, args)\n }\n }\n\n error(message: string, args?: unknown) {\n if (shouldLog(LEVELS.ERROR)) {\n this._log('error', message, args)\n }\n }\n\n debug(message: string, args?: unknown) {\n if (shouldLog(LEVELS.DEBUG)) {\n this._log('debug', message, args)\n }\n }\n\n warn(message: string, args?: unknown) {\n if (shouldLog(LEVELS.WARNING)) {\n this._log('warn', message, args)\n }\n }\n\n log(args: any) {\n const level = args.level ?? 'info'\n const messageLevel = levelMap[level] ?? LEVELS.INFO\n\n if (!shouldLog(messageLevel)) return\n\n this._log(level, args.msg, args)\n }\n\n addListener(listener: LogListener) {\n this.listeners.push(listener)\n }\n\n removeListener(listener: LogListener) {\n const index = this.listeners.indexOf(listener)\n if (index > -1) {\n this.listeners.splice(index, 1)\n }\n }\n}\n\nexport const globalLogger = new Logger()\n"],"mappings":";;;AAEA,MAAM,SAAS;CACb,QAAQ;CACR,OAAO;CACP,MAAM;CACN,SAAS;CACT,OAAO;CACP,UAAU;CACX;AAED,MAAMA,WAAmC;CACvC,OAAO,OAAO;CACd,MAAM,OAAO;CACb,MAAM,OAAO;CACb,SAAS,OAAO;CAChB,OAAO,OAAO;CACd,UAAU,OAAO;CAClB;AAED,MAAM,oBAA4B;AAEhC,QAAO,SADO,QAAQ,IAAI,aAAa,WACb,OAAO;;AAGnC,MAAM,aAAa,iBAAkC;AACnD,QAAO,gBAAgB,aAAa;;AAKtC,IAAa,SAAb,MAAa,OAAO;CAWlB,YACE,AAASC,YAAqB,OAC9B,AAAiBC,OAAgC,EAAE,EACnD,AAAiBC,gBAA+B,EAAE,EAClD;EAHS;EACQ;EACA;mBALyB,EAAE;;CAQ9C,MAAM,MAAuC;AAC3C,SAAO,IAAI,OAAO,KAAK,WAAW;GAAE,GAAG,KAAK;GAAM,GAAG;GAAM,EAAE,KAAK,cAAc;;CAGlF,AAAQ,KAAK,OAAe,KAAa,MAAY;EACnD,MAAM,OAAO,KAAK,KAAK;EACvB,MAAM,OAAO;GAAE,GAAG,KAAK;GAAM,GAAI,QAAQ,EAAE;GAAG;AAC9C,cAAY;GAAE;GAAO;GAAM;GAAK,GAAG;GAAM,EAAE,CAAC,KAAK,UAAU;AAE3D,OAAK,cAAc,SAAS,aAAa,SAAS,OAAO,KAAK,KAAK,CAAC;AACpE,OAAK,UAAU,SAAS,aAAa,SAAS,OAAO,KAAK,KAAK,CAAC;;CAGlE,KAAK,SAAiB,MAAgB;AACpC,MAAI,UAAU,OAAO,KAAK,CACxB,MAAK,KAAK,QAAQ,SAAS,KAAK;;CAIpC,MAAM,SAAiB,MAAgB;AACrC,MAAI,UAAU,OAAO,MAAM,CACzB,MAAK,KAAK,SAAS,SAAS,KAAK;;CAIrC,MAAM,SAAiB,MAAgB;AACrC,MAAI,UAAU,OAAO,MAAM,CACzB,MAAK,KAAK,SAAS,SAAS,KAAK;;CAIrC,KAAK,SAAiB,MAAgB;AACpC,MAAI,UAAU,OAAO,QAAQ,CAC3B,MAAK,KAAK,QAAQ,SAAS,KAAK;;CAIpC,IAAI,MAAW;EACb,MAAM,QAAQ,KAAK,SAAS;AAG5B,MAAI,CAAC,UAFgB,SAAS,UAAU,OAAO,KAEnB,CAAE;AAE9B,OAAK,KAAK,OAAO,KAAK,KAAK,KAAK;;CAGlC,YAAY,UAAuB;AACjC,OAAK,UAAU,KAAK,SAAS;;CAG/B,eAAe,UAAuB;EACpC,MAAM,QAAQ,KAAK,UAAU,QAAQ,SAAS;AAC9C,MAAI,QAAQ,GACV,MAAK,UAAU,OAAO,OAAO,EAAE;;;AAKrC,MAAa,eAAe,IAAI,QAAQ"}
@@ -1 +1 @@
1
- {"version":3,"file":"tracer.mjs","names":["traceStream: MotiaStream<Trace>","traceGroupStream: MotiaStream<TraceGroup>","traceGroup: TraceGroup","traceStreamAdapter: MotiaStream<Trace>","traceGroupStreamAdapter: MotiaStream<TraceGroup>"],"sources":["../../../src/observability/tracer.ts"],"sourcesContent":["import { FileStreamAdapterManager } from '../adapters/defaults/stream/file-stream-adapter-manager'\nimport type { LockedData } from '../locked-data'\nimport type { Logger } from '../logger'\nimport type { Step } from '../types'\nimport type { MotiaStream } from '../types-stream'\nimport { createTrace } from './create-trace'\nimport type { TracerFactory } from './index'\nimport { RedisTraceStreamAdapter } from './redis-trace-stream-adapter'\nimport { StreamTracer } from './stream-tracer'\nimport { TraceManager } from './trace-manager'\nimport type { Trace, TraceGroup } from './types'\n\nexport class BaseTracerFactory implements TracerFactory {\n constructor(\n private readonly traceStream: MotiaStream<Trace>,\n private readonly traceGroupStream: MotiaStream<TraceGroup>,\n ) {}\n\n private async getAllGroups() {\n return await this.traceGroupStream.getGroup('default')\n }\n\n private async deleteGroup(group: TraceGroup) {\n const traces = await this.traceStream.getGroup(group.id)\n\n for (const trace of traces) {\n await this.traceStream.delete(group.id, trace.id)\n }\n await this.traceGroupStream.delete('default', group.id)\n }\n\n async clear() {\n const groups = await this.getAllGroups()\n\n for (const group of groups) {\n await this.deleteGroup(group)\n }\n }\n\n async createTracer(traceId: string, step: Step, logger: Logger) {\n const traceGroup: TraceGroup = {\n id: traceId,\n name: step.config.name,\n lastActivity: Date.now(),\n metadata: {\n completedSteps: 0,\n activeSteps: 0,\n totalSteps: 0,\n },\n correlationId: undefined,\n status: 'running',\n startTime: Date.now(),\n }\n\n const trace = createTrace(traceGroup, step)\n const manager = new TraceManager(this.traceStream, this.traceGroupStream, traceGroup, trace)\n\n return new StreamTracer(manager, traceGroup, trace, logger)\n }\n\n async attachToTrace(traceId: string, step: Step, logger: Logger) {\n const existingGroup = await this.traceGroupStream.get('default', traceId)\n\n if (!existingGroup) {\n return this.createTracer(traceId, step, logger)\n }\n\n const trace = createTrace(existingGroup, step)\n const manager = new TraceManager(this.traceStream, this.traceGroupStream, existingGroup, trace)\n\n return new StreamTracer(manager, existingGroup, trace, logger)\n }\n}\n\nexport const createTracerFactory = (lockedData: LockedData): TracerFactory => {\n if (!lockedData.redisClient) {\n throw new Error(\n 'Redis client is required for tracer factory. Please provide a redisClient when creating LockedData.',\n )\n }\n\n const traceStreamName = 'motia-trace'\n const traceStreamAdapter: MotiaStream<Trace> = new RedisTraceStreamAdapter(traceStreamName, lockedData.redisClient)\n\n const traceStream = lockedData.createStream<Trace>({\n filePath: traceStreamName,\n hidden: true,\n config: {\n name: traceStreamName,\n baseConfig: { storageType: 'custom', factory: () => traceStreamAdapter },\n schema: null as never,\n },\n })()\n\n const traceGroupName = 'motia-trace-group'\n const traceGroupStreamAdapter: MotiaStream<TraceGroup> = new RedisTraceStreamAdapter(\n traceGroupName,\n lockedData.redisClient,\n )\n\n const traceGroupStream = lockedData.createStream<TraceGroup>({\n filePath: traceGroupName,\n hidden: true,\n config: {\n name: traceGroupName,\n baseConfig: { storageType: 'custom', factory: () => traceGroupStreamAdapter },\n schema: null as never,\n },\n })()\n\n return new BaseTracerFactory(traceStream, traceGroupStream)\n}\n"],"mappings":";;;;;;AAYA,IAAa,oBAAb,MAAwD;CACtD,YACE,AAAiBA,aACjB,AAAiBC,kBACjB;EAFiB;EACA;;CAGnB,MAAc,eAAe;AAC3B,SAAO,MAAM,KAAK,iBAAiB,SAAS,UAAU;;CAGxD,MAAc,YAAY,OAAmB;EAC3C,MAAM,SAAS,MAAM,KAAK,YAAY,SAAS,MAAM,GAAG;AAExD,OAAK,MAAM,SAAS,OAClB,OAAM,KAAK,YAAY,OAAO,MAAM,IAAI,MAAM,GAAG;AAEnD,QAAM,KAAK,iBAAiB,OAAO,WAAW,MAAM,GAAG;;CAGzD,MAAM,QAAQ;EACZ,MAAM,SAAS,MAAM,KAAK,cAAc;AAExC,OAAK,MAAM,SAAS,OAClB,OAAM,KAAK,YAAY,MAAM;;CAIjC,MAAM,aAAa,SAAiB,MAAY,QAAgB;EAC9D,MAAMC,aAAyB;GAC7B,IAAI;GACJ,MAAM,KAAK,OAAO;GAClB,cAAc,KAAK,KAAK;GACxB,UAAU;IACR,gBAAgB;IAChB,aAAa;IACb,YAAY;IACb;GACD,eAAe;GACf,QAAQ;GACR,WAAW,KAAK,KAAK;GACtB;EAED,MAAM,QAAQ,YAAY,YAAY,KAAK;AAG3C,SAAO,IAAI,aAFK,IAAI,aAAa,KAAK,aAAa,KAAK,kBAAkB,YAAY,MAAM,EAE3D,YAAY,OAAO,OAAO;;CAG7D,MAAM,cAAc,SAAiB,MAAY,QAAgB;EAC/D,MAAM,gBAAgB,MAAM,KAAK,iBAAiB,IAAI,WAAW,QAAQ;AAEzE,MAAI,CAAC,cACH,QAAO,KAAK,aAAa,SAAS,MAAM,OAAO;EAGjD,MAAM,QAAQ,YAAY,eAAe,KAAK;AAG9C,SAAO,IAAI,aAFK,IAAI,aAAa,KAAK,aAAa,KAAK,kBAAkB,eAAe,MAAM,EAE9D,eAAe,OAAO,OAAO;;;AAIlE,MAAa,uBAAuB,eAA0C;AAC5E,KAAI,CAAC,WAAW,YACd,OAAM,IAAI,MACR,sGACD;CAGH,MAAM,kBAAkB;CACxB,MAAMC,qBAAyC,IAAI,wBAAwB,iBAAiB,WAAW,YAAY;CAEnH,MAAM,cAAc,WAAW,aAAoB;EACjD,UAAU;EACV,QAAQ;EACR,QAAQ;GACN,MAAM;GACN,YAAY;IAAE,aAAa;IAAU,eAAe;IAAoB;GACxE,QAAQ;GACT;EACF,CAAC,EAAE;CAEJ,MAAM,iBAAiB;CACvB,MAAMC,0BAAmD,IAAI,wBAC3D,gBACA,WAAW,YACZ;AAYD,QAAO,IAAI,kBAAkB,aAVJ,WAAW,aAAyB;EAC3D,UAAU;EACV,QAAQ;EACR,QAAQ;GACN,MAAM;GACN,YAAY;IAAE,aAAa;IAAU,eAAe;IAAyB;GAC7E,QAAQ;GACT;EACF,CAAC,EAAE,CAEuD"}
1
+ {"version":3,"file":"tracer.mjs","names":["traceStream: MotiaStream<Trace>","traceGroupStream: MotiaStream<TraceGroup>","traceGroup: TraceGroup","traceStreamAdapter: MotiaStream<Trace>","traceGroupStreamAdapter: MotiaStream<TraceGroup>"],"sources":["../../../src/observability/tracer.ts"],"sourcesContent":["import type { LockedData } from '../locked-data'\nimport type { Logger } from '../logger'\nimport type { Step } from '../types'\nimport type { MotiaStream } from '../types-stream'\nimport { createTrace } from './create-trace'\nimport type { TracerFactory } from './index'\nimport { RedisTraceStreamAdapter } from './redis-trace-stream-adapter'\nimport { StreamTracer } from './stream-tracer'\nimport { TraceManager } from './trace-manager'\nimport type { Trace, TraceGroup } from './types'\n\nexport class BaseTracerFactory implements TracerFactory {\n constructor(\n private readonly traceStream: MotiaStream<Trace>,\n private readonly traceGroupStream: MotiaStream<TraceGroup>,\n ) {}\n\n private async getAllGroups() {\n return await this.traceGroupStream.getGroup('default')\n }\n\n private async deleteGroup(group: TraceGroup) {\n const traces = await this.traceStream.getGroup(group.id)\n\n for (const trace of traces) {\n await this.traceStream.delete(group.id, trace.id)\n }\n await this.traceGroupStream.delete('default', group.id)\n }\n\n async clear() {\n const groups = await this.getAllGroups()\n\n for (const group of groups) {\n await this.deleteGroup(group)\n }\n }\n\n async createTracer(traceId: string, step: Step, logger: Logger) {\n const traceGroup: TraceGroup = {\n id: traceId,\n name: step.config.name,\n lastActivity: Date.now(),\n metadata: {\n completedSteps: 0,\n activeSteps: 0,\n totalSteps: 0,\n },\n correlationId: undefined,\n status: 'running',\n startTime: Date.now(),\n }\n\n const trace = createTrace(traceGroup, step)\n const manager = new TraceManager(this.traceStream, this.traceGroupStream, traceGroup, trace)\n\n return new StreamTracer(manager, traceGroup, trace, logger)\n }\n\n async attachToTrace(traceId: string, step: Step, logger: Logger) {\n const existingGroup = await this.traceGroupStream.get('default', traceId)\n\n if (!existingGroup) {\n return this.createTracer(traceId, step, logger)\n }\n\n const trace = createTrace(existingGroup, step)\n const manager = new TraceManager(this.traceStream, this.traceGroupStream, existingGroup, trace)\n\n return new StreamTracer(manager, existingGroup, trace, logger)\n }\n}\n\nexport const createTracerFactory = (lockedData: LockedData): TracerFactory => {\n if (!lockedData.redisClient) {\n throw new Error(\n 'Redis client is required for tracer factory. Please provide a redisClient when creating LockedData.',\n )\n }\n\n const traceStreamName = 'motia-trace'\n const traceStreamAdapter: MotiaStream<Trace> = new RedisTraceStreamAdapter(traceStreamName, lockedData.redisClient)\n\n const traceStream = lockedData.createStream<Trace>({\n filePath: traceStreamName,\n hidden: true,\n config: {\n name: traceStreamName,\n baseConfig: { storageType: 'custom', factory: () => traceStreamAdapter },\n schema: null as never,\n },\n })()\n\n const traceGroupName = 'motia-trace-group'\n const traceGroupStreamAdapter: MotiaStream<TraceGroup> = new RedisTraceStreamAdapter(\n traceGroupName,\n lockedData.redisClient,\n )\n\n const traceGroupStream = lockedData.createStream<TraceGroup>({\n filePath: traceGroupName,\n hidden: true,\n config: {\n name: traceGroupName,\n baseConfig: { storageType: 'custom', factory: () => traceGroupStreamAdapter },\n schema: null as never,\n },\n })()\n\n return new BaseTracerFactory(traceStream, traceGroupStream)\n}\n"],"mappings":";;;;;;AAWA,IAAa,oBAAb,MAAwD;CACtD,YACE,AAAiBA,aACjB,AAAiBC,kBACjB;EAFiB;EACA;;CAGnB,MAAc,eAAe;AAC3B,SAAO,MAAM,KAAK,iBAAiB,SAAS,UAAU;;CAGxD,MAAc,YAAY,OAAmB;EAC3C,MAAM,SAAS,MAAM,KAAK,YAAY,SAAS,MAAM,GAAG;AAExD,OAAK,MAAM,SAAS,OAClB,OAAM,KAAK,YAAY,OAAO,MAAM,IAAI,MAAM,GAAG;AAEnD,QAAM,KAAK,iBAAiB,OAAO,WAAW,MAAM,GAAG;;CAGzD,MAAM,QAAQ;EACZ,MAAM,SAAS,MAAM,KAAK,cAAc;AAExC,OAAK,MAAM,SAAS,OAClB,OAAM,KAAK,YAAY,MAAM;;CAIjC,MAAM,aAAa,SAAiB,MAAY,QAAgB;EAC9D,MAAMC,aAAyB;GAC7B,IAAI;GACJ,MAAM,KAAK,OAAO;GAClB,cAAc,KAAK,KAAK;GACxB,UAAU;IACR,gBAAgB;IAChB,aAAa;IACb,YAAY;IACb;GACD,eAAe;GACf,QAAQ;GACR,WAAW,KAAK,KAAK;GACtB;EAED,MAAM,QAAQ,YAAY,YAAY,KAAK;AAG3C,SAAO,IAAI,aAFK,IAAI,aAAa,KAAK,aAAa,KAAK,kBAAkB,YAAY,MAAM,EAE3D,YAAY,OAAO,OAAO;;CAG7D,MAAM,cAAc,SAAiB,MAAY,QAAgB;EAC/D,MAAM,gBAAgB,MAAM,KAAK,iBAAiB,IAAI,WAAW,QAAQ;AAEzE,MAAI,CAAC,cACH,QAAO,KAAK,aAAa,SAAS,MAAM,OAAO;EAGjD,MAAM,QAAQ,YAAY,eAAe,KAAK;AAG9C,SAAO,IAAI,aAFK,IAAI,aAAa,KAAK,aAAa,KAAK,kBAAkB,eAAe,MAAM,EAE9D,eAAe,OAAO,OAAO;;;AAIlE,MAAa,uBAAuB,eAA0C;AAC5E,KAAI,CAAC,WAAW,YACd,OAAM,IAAI,MACR,sGACD;CAGH,MAAM,kBAAkB;CACxB,MAAMC,qBAAyC,IAAI,wBAAwB,iBAAiB,WAAW,YAAY;CAEnH,MAAM,cAAc,WAAW,aAAoB;EACjD,UAAU;EACV,QAAQ;EACR,QAAQ;GACN,MAAM;GACN,YAAY;IAAE,aAAa;IAAU,eAAe;IAAoB;GACxE,QAAQ;GACT;EACF,CAAC,EAAE;CAEJ,MAAM,iBAAiB;CACvB,MAAMC,0BAAmD,IAAI,wBAC3D,gBACA,WAAW,YACZ;AAYD,QAAO,IAAI,kBAAkB,aAVJ,WAAW,aAAyB;EAC3D,UAAU;EACV,QAAQ;EACR,QAAQ;GACN,MAAM;GACN,YAAY;IAAE,aAAa;IAAU,eAAe;IAAyB;GAC7E,QAAQ;GACT;EACF,CAAC,EAAE,CAEuD"}
@@ -48,11 +48,17 @@ var ProcessManager = class {
48
48
  }
49
49
  kill() {
50
50
  if (this.child) this.child.kill("SIGKILL");
51
- this.child = void 0;
52
51
  }
53
52
  close() {
54
- if (this.processor) this.processor.close();
55
- this.processor = void 0;
53
+ if (this.child) {
54
+ this.child.removeAllListeners();
55
+ this.child.stdout?.removeAllListeners();
56
+ this.child.stderr?.removeAllListeners();
57
+ }
58
+ if (this.processor) {
59
+ this.processor.close();
60
+ this.processor = void 0;
61
+ }
56
62
  }
57
63
  get process() {
58
64
  return this.child;
@@ -1 +1 @@
1
- {"version":3,"file":"process-manager.mjs","names":["options: ProcessManagerOptions"],"sources":["../../../src/process-communication/process-manager.ts"],"sourcesContent":["import { type ChildProcess, spawn } from 'child_process'\nimport type { Logger } from '../logger'\nimport { RpcProcessor } from '../step-handler-rpc-processor'\nimport { RpcStdinProcessor } from '../step-handler-rpc-stdin-processor'\nimport { type CommunicationType, createCommunicationConfig } from './communication-config'\nimport type { MessageCallback, RpcHandler, RpcProcessorInterface } from './rpc-processor-interface'\n\nexport interface ProcessManagerOptions {\n command: string\n args: string[]\n logger: Logger\n context?: string\n projectRoot?: string\n}\n\nexport class ProcessManager {\n private child?: ChildProcess\n private processor?: RpcProcessorInterface\n private communicationType?: CommunicationType\n\n constructor(private options: ProcessManagerOptions) {}\n\n async spawn(): Promise<ChildProcess> {\n const { command, args, logger, context = 'Process', projectRoot } = this.options\n\n // Get communication configuration\n const commConfig = createCommunicationConfig(command, projectRoot)\n this.communicationType = commConfig.type\n\n logger.debug(`[${context}] Spawning process`, {\n command,\n args,\n communicationType: this.communicationType,\n })\n\n // Spawn the process\n this.child = spawn(command, args, commConfig.spawnOptions)\n\n // Create appropriate processor based on communication type\n this.processor = this.communicationType === 'rpc' ? new RpcStdinProcessor(this.child) : new RpcProcessor(this.child)\n\n // Initialize the processor\n await this.processor.init()\n\n return this.child\n }\n\n handler<TInput, TOutput = unknown>(method: string, handler: RpcHandler<TInput, TOutput>): void {\n if (!this.processor) {\n throw new Error('Process not spawned yet. Call spawn() first.')\n }\n this.processor.handler(method, handler)\n }\n\n onMessage<T = unknown>(callback: MessageCallback<T>): void {\n if (!this.processor) {\n throw new Error('Process not spawned yet. Call spawn() first.')\n }\n this.processor.onMessage(callback)\n }\n\n onProcessClose(callback: (code: number | null) => void): void {\n if (!this.child) {\n throw new Error('Process not spawned yet. Call spawn() first.')\n }\n this.child.on('close', callback)\n }\n\n onProcessError(callback: (error: Error & { code?: string }) => void): void {\n if (!this.child) {\n throw new Error('Process not spawned yet. Call spawn() first.')\n }\n this.child.on('error', callback)\n }\n\n onStderr(callback: (data: Buffer) => void): void {\n if (!this.child) {\n throw new Error('Process not spawned yet. Call spawn() first.')\n }\n this.child.stderr?.on('data', callback)\n }\n\n onStdout(callback: (data: Buffer) => void): void {\n if (!this.child) {\n throw new Error('Process not spawned yet. Call spawn() first.')\n }\n // Only for non-RPC mode (in RPC mode, stdout is used for communication)\n if (this.communicationType !== 'rpc') {\n this.child.stdout?.on('data', callback)\n }\n }\n\n kill(): void {\n if (this.child) {\n this.child.kill('SIGKILL')\n }\n this.child = undefined\n }\n\n close(): void {\n if (this.processor) {\n this.processor.close()\n }\n this.processor = undefined\n }\n\n get process(): ChildProcess | undefined {\n return this.child\n }\n\n get commType(): CommunicationType | undefined {\n return this.communicationType\n }\n}\n"],"mappings":";;;;;;AAeA,IAAa,iBAAb,MAA4B;CAK1B,YAAY,AAAQA,SAAgC;EAAhC;;CAEpB,MAAM,QAA+B;EACnC,MAAM,EAAE,SAAS,MAAM,QAAQ,UAAU,WAAW,gBAAgB,KAAK;EAGzE,MAAM,aAAa,0BAA0B,SAAS,YAAY;AAClE,OAAK,oBAAoB,WAAW;AAEpC,SAAO,MAAM,IAAI,QAAQ,qBAAqB;GAC5C;GACA;GACA,mBAAmB,KAAK;GACzB,CAAC;AAGF,OAAK,QAAQ,MAAM,SAAS,MAAM,WAAW,aAAa;AAG1D,OAAK,YAAY,KAAK,sBAAsB,QAAQ,IAAI,kBAAkB,KAAK,MAAM,GAAG,IAAI,aAAa,KAAK,MAAM;AAGpH,QAAM,KAAK,UAAU,MAAM;AAE3B,SAAO,KAAK;;CAGd,QAAmC,QAAgB,SAA4C;AAC7F,MAAI,CAAC,KAAK,UACR,OAAM,IAAI,MAAM,+CAA+C;AAEjE,OAAK,UAAU,QAAQ,QAAQ,QAAQ;;CAGzC,UAAuB,UAAoC;AACzD,MAAI,CAAC,KAAK,UACR,OAAM,IAAI,MAAM,+CAA+C;AAEjE,OAAK,UAAU,UAAU,SAAS;;CAGpC,eAAe,UAA+C;AAC5D,MAAI,CAAC,KAAK,MACR,OAAM,IAAI,MAAM,+CAA+C;AAEjE,OAAK,MAAM,GAAG,SAAS,SAAS;;CAGlC,eAAe,UAA4D;AACzE,MAAI,CAAC,KAAK,MACR,OAAM,IAAI,MAAM,+CAA+C;AAEjE,OAAK,MAAM,GAAG,SAAS,SAAS;;CAGlC,SAAS,UAAwC;AAC/C,MAAI,CAAC,KAAK,MACR,OAAM,IAAI,MAAM,+CAA+C;AAEjE,OAAK,MAAM,QAAQ,GAAG,QAAQ,SAAS;;CAGzC,SAAS,UAAwC;AAC/C,MAAI,CAAC,KAAK,MACR,OAAM,IAAI,MAAM,+CAA+C;AAGjE,MAAI,KAAK,sBAAsB,MAC7B,MAAK,MAAM,QAAQ,GAAG,QAAQ,SAAS;;CAI3C,OAAa;AACX,MAAI,KAAK,MACP,MAAK,MAAM,KAAK,UAAU;AAE5B,OAAK,QAAQ;;CAGf,QAAc;AACZ,MAAI,KAAK,UACP,MAAK,UAAU,OAAO;AAExB,OAAK,YAAY;;CAGnB,IAAI,UAAoC;AACtC,SAAO,KAAK;;CAGd,IAAI,WAA0C;AAC5C,SAAO,KAAK"}
1
+ {"version":3,"file":"process-manager.mjs","names":["options: ProcessManagerOptions"],"sources":["../../../src/process-communication/process-manager.ts"],"sourcesContent":["import { type ChildProcess, spawn } from 'child_process'\nimport type { Logger } from '../logger'\nimport { RpcProcessor } from '../step-handler-rpc-processor'\nimport { RpcStdinProcessor } from '../step-handler-rpc-stdin-processor'\nimport { type CommunicationType, createCommunicationConfig } from './communication-config'\nimport type { MessageCallback, RpcHandler, RpcProcessorInterface } from './rpc-processor-interface'\n\nexport interface ProcessManagerOptions {\n command: string\n args: string[]\n logger: Logger\n context?: string\n projectRoot?: string\n}\n\nexport class ProcessManager {\n private child?: ChildProcess\n private processor?: RpcProcessorInterface\n private communicationType?: CommunicationType\n\n constructor(private options: ProcessManagerOptions) {}\n\n async spawn(): Promise<ChildProcess> {\n const { command, args, logger, context = 'Process', projectRoot } = this.options\n\n // Get communication configuration\n const commConfig = createCommunicationConfig(command, projectRoot)\n this.communicationType = commConfig.type\n\n logger.debug(`[${context}] Spawning process`, {\n command,\n args,\n communicationType: this.communicationType,\n })\n\n // Spawn the process\n this.child = spawn(command, args, commConfig.spawnOptions)\n\n // Create appropriate processor based on communication type\n this.processor = this.communicationType === 'rpc' ? new RpcStdinProcessor(this.child) : new RpcProcessor(this.child)\n\n // Initialize the processor\n await this.processor.init()\n\n return this.child\n }\n\n handler<TInput, TOutput = unknown>(method: string, handler: RpcHandler<TInput, TOutput>): void {\n if (!this.processor) {\n throw new Error('Process not spawned yet. Call spawn() first.')\n }\n this.processor.handler(method, handler)\n }\n\n onMessage<T = unknown>(callback: MessageCallback<T>): void {\n if (!this.processor) {\n throw new Error('Process not spawned yet. Call spawn() first.')\n }\n this.processor.onMessage(callback)\n }\n\n onProcessClose(callback: (code: number | null) => void): void {\n if (!this.child) {\n throw new Error('Process not spawned yet. Call spawn() first.')\n }\n this.child.on('close', callback)\n }\n\n onProcessError(callback: (error: Error & { code?: string }) => void): void {\n if (!this.child) {\n throw new Error('Process not spawned yet. Call spawn() first.')\n }\n this.child.on('error', callback)\n }\n\n onStderr(callback: (data: Buffer) => void): void {\n if (!this.child) {\n throw new Error('Process not spawned yet. Call spawn() first.')\n }\n this.child.stderr?.on('data', callback)\n }\n\n onStdout(callback: (data: Buffer) => void): void {\n if (!this.child) {\n throw new Error('Process not spawned yet. Call spawn() first.')\n }\n // Only for non-RPC mode (in RPC mode, stdout is used for communication)\n if (this.communicationType !== 'rpc') {\n this.child.stdout?.on('data', callback)\n }\n }\n\n kill(): void {\n if (this.child) {\n this.child.kill('SIGKILL')\n }\n }\n\n close(): void {\n if (this.child) {\n this.child.removeAllListeners()\n this.child.stdout?.removeAllListeners()\n this.child.stderr?.removeAllListeners()\n }\n if (this.processor) {\n this.processor.close()\n this.processor = undefined\n }\n }\n\n get process(): ChildProcess | undefined {\n return this.child\n }\n\n get commType(): CommunicationType | undefined {\n return this.communicationType\n }\n}\n"],"mappings":";;;;;;AAeA,IAAa,iBAAb,MAA4B;CAK1B,YAAY,AAAQA,SAAgC;EAAhC;;CAEpB,MAAM,QAA+B;EACnC,MAAM,EAAE,SAAS,MAAM,QAAQ,UAAU,WAAW,gBAAgB,KAAK;EAGzE,MAAM,aAAa,0BAA0B,SAAS,YAAY;AAClE,OAAK,oBAAoB,WAAW;AAEpC,SAAO,MAAM,IAAI,QAAQ,qBAAqB;GAC5C;GACA;GACA,mBAAmB,KAAK;GACzB,CAAC;AAGF,OAAK,QAAQ,MAAM,SAAS,MAAM,WAAW,aAAa;AAG1D,OAAK,YAAY,KAAK,sBAAsB,QAAQ,IAAI,kBAAkB,KAAK,MAAM,GAAG,IAAI,aAAa,KAAK,MAAM;AAGpH,QAAM,KAAK,UAAU,MAAM;AAE3B,SAAO,KAAK;;CAGd,QAAmC,QAAgB,SAA4C;AAC7F,MAAI,CAAC,KAAK,UACR,OAAM,IAAI,MAAM,+CAA+C;AAEjE,OAAK,UAAU,QAAQ,QAAQ,QAAQ;;CAGzC,UAAuB,UAAoC;AACzD,MAAI,CAAC,KAAK,UACR,OAAM,IAAI,MAAM,+CAA+C;AAEjE,OAAK,UAAU,UAAU,SAAS;;CAGpC,eAAe,UAA+C;AAC5D,MAAI,CAAC,KAAK,MACR,OAAM,IAAI,MAAM,+CAA+C;AAEjE,OAAK,MAAM,GAAG,SAAS,SAAS;;CAGlC,eAAe,UAA4D;AACzE,MAAI,CAAC,KAAK,MACR,OAAM,IAAI,MAAM,+CAA+C;AAEjE,OAAK,MAAM,GAAG,SAAS,SAAS;;CAGlC,SAAS,UAAwC;AAC/C,MAAI,CAAC,KAAK,MACR,OAAM,IAAI,MAAM,+CAA+C;AAEjE,OAAK,MAAM,QAAQ,GAAG,QAAQ,SAAS;;CAGzC,SAAS,UAAwC;AAC/C,MAAI,CAAC,KAAK,MACR,OAAM,IAAI,MAAM,+CAA+C;AAGjE,MAAI,KAAK,sBAAsB,MAC7B,MAAK,MAAM,QAAQ,GAAG,QAAQ,SAAS;;CAI3C,OAAa;AACX,MAAI,KAAK,MACP,MAAK,MAAM,KAAK,UAAU;;CAI9B,QAAc;AACZ,MAAI,KAAK,OAAO;AACd,QAAK,MAAM,oBAAoB;AAC/B,QAAK,MAAM,QAAQ,oBAAoB;AACvC,QAAK,MAAM,QAAQ,oBAAoB;;AAEzC,MAAI,KAAK,WAAW;AAClB,QAAK,UAAU,OAAO;AACtB,QAAK,YAAY;;;CAIrB,IAAI,UAAoC;AACtC,SAAO,KAAK;;CAGd,IAAI,WAA0C;AAC5C,SAAO,KAAK"}
@@ -24,9 +24,9 @@ def get_can_access(config):
24
24
  async def run_python_module(file_path: str, payload: dict) -> None:
25
25
  try:
26
26
  path = Path(file_path).resolve()
27
- steps_dir = next((p for p in path.parents if p.name == "steps"), None)
27
+ steps_dir = next((p for p in path.parents if p.name in ("src", "steps")), None)
28
28
  if steps_dir is None:
29
- raise RuntimeError("Could not find 'steps' directory in path")
29
+ raise RuntimeError("Could not find 'src' or 'steps' directory in path")
30
30
 
31
31
  project_root = steps_dir.parent
32
32
  project_parent = project_root.parent
@@ -23,9 +23,9 @@ def sendMessage(text):
23
23
  async def run_python_module(file_path: str) -> None:
24
24
  try:
25
25
  path = Path(file_path).resolve()
26
- steps_dir = next((p for p in path.parents if p.name == "steps"), None)
26
+ steps_dir = next((p for p in path.parents if p.name in ("src", "steps")), None)
27
27
  if steps_dir is None:
28
- raise RuntimeError("Could not find 'steps' directory in path")
28
+ raise RuntimeError("Could not find 'src' or 'steps' directory in path")
29
29
 
30
30
  project_root = steps_dir.parent
31
31
  project_parent = project_root.parent
@@ -24,9 +24,9 @@ async def run_python_module(file_path: str, rpc: RpcSender, args: Dict) -> None:
24
24
  """Execute a Python module with the given arguments"""
25
25
  try:
26
26
  path = Path(file_path).resolve()
27
- steps_dir = next((p for p in path.parents if p.name == "steps"), None)
27
+ steps_dir = next((p for p in path.parents if p.name in ("src", "steps")), None)
28
28
  if steps_dir is None:
29
- raise RuntimeError("Could not find 'steps' directory in path")
29
+ raise RuntimeError("Could not find 'src' or 'steps' directory in path")
30
30
 
31
31
  project_root = steps_dir.parent
32
32
  project_parent = project_root.parent
@@ -1,6 +1,6 @@
1
1
  import { globalLogger } from "./logger.mjs";
2
2
  import { getRoom, sendAccessDenied, sendError } from "./socket-server/helpers.mjs";
3
- import { WebSocketServer } from "ws";
3
+ import { WebSocket, WebSocketServer } from "ws";
4
4
 
5
5
  //#region src/socket-server.ts
6
6
  const AUTH_ERROR_CODE = 401;
@@ -37,9 +37,9 @@ const createSocketServer = ({ server, onJoin, onJoinGroup, authenticate, authori
37
37
  };
38
38
  socketServer.on("connection", async (socket, request) => {
39
39
  authContexts.set(socket, request.authContext);
40
- subscriptions.set(socket, /* @__PURE__ */ new Set());
41
- socket.on("message", async (payload) => {
42
- const message = JSON.parse(payload.toString());
40
+ subscriptions.set(socket, /* @__PURE__ */ new Map());
41
+ let messageQueue = Promise.resolve();
42
+ const processMessage = async (message) => {
43
43
  if (message.type === "join") {
44
44
  if (!await isAuthorized(socket, message.data)) {
45
45
  sendAccessDenied(socket, message.data);
@@ -78,15 +78,30 @@ const createSocketServer = ({ server, onJoin, onJoinGroup, authenticate, authori
78
78
  }
79
79
  }
80
80
  rooms[room].set(message.data.subscriptionId, socket);
81
- subscriptions.get(socket)?.add([room, message.data.subscriptionId]);
81
+ subscriptions.get(socket)?.set(message.data.subscriptionId, room);
82
82
  } else if (message.type === "leave") {
83
+ if (!message.data.subscriptionId) {
84
+ globalLogger.error("[Socket Server] Subscription ID is required for leave message");
85
+ return;
86
+ }
83
87
  const room = getRoom(message.data);
84
- if (rooms[room]) rooms[room].delete(message.data.subscriptionId);
88
+ if (rooms[room]) {
89
+ rooms[room].delete(message.data.subscriptionId);
90
+ if (rooms[room].size === 0) delete rooms[room];
91
+ }
92
+ subscriptions.get(socket)?.delete(message.data.subscriptionId);
85
93
  }
94
+ };
95
+ socket.on("message", (payload) => {
96
+ const message = JSON.parse(payload.toString());
97
+ messageQueue = messageQueue.then(() => processMessage(message)).catch((error) => {
98
+ globalLogger.error("[Socket Server] Error processing message", error);
99
+ });
86
100
  });
87
101
  socket.on("close", () => {
88
- subscriptions.get(socket)?.forEach(([room, subscriptionId]) => {
102
+ subscriptions.get(socket)?.forEach((room, subscriptionId) => {
89
103
  rooms[room]?.delete(subscriptionId);
104
+ if (rooms[room]?.size === 0) delete rooms[room];
90
105
  });
91
106
  subscriptions.delete(socket);
92
107
  authContexts.delete(socket);
@@ -102,18 +117,21 @@ const createSocketServer = ({ server, onJoin, onJoinGroup, authenticate, authori
102
117
  timestamp: Date.now(),
103
118
  ...message
104
119
  });
105
- if (rooms[groupRoom]) rooms[groupRoom].forEach((socket) => {
106
- socket.send(eventMessage);
107
- });
120
+ const safeSend = (socket) => {
121
+ if (socket.readyState === WebSocket.OPEN) try {
122
+ socket.send(eventMessage);
123
+ } catch (error) {
124
+ globalLogger.debug("[Socket Server] Failed to send message to socket", error);
125
+ }
126
+ };
127
+ if (rooms[groupRoom]) rooms[groupRoom].forEach(safeSend);
108
128
  if (id) {
109
129
  const itemRoom = getRoom({
110
130
  groupId,
111
131
  streamName,
112
132
  id
113
133
  });
114
- if (rooms[itemRoom]) rooms[itemRoom].forEach((socket) => {
115
- socket.send(eventMessage);
116
- });
134
+ if (rooms[itemRoom]) rooms[itemRoom].forEach(safeSend);
117
135
  }
118
136
  };
119
137
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"socket-server.mjs","names":["authRequest: StreamAuthRequest","rooms: Record<string, Map<string, WebSocket>>","subscriptions: Map<WebSocket, Set<[string, string]>>","authContexts: Map<WebSocket, unknown>","message: Message","resultMessage: EventMessage<typeof item>","resultMessage: EventMessage<typeof items>"],"sources":["../../src/socket-server.ts"],"sourcesContent":["import type { Server } from 'http'\nimport { type WebSocket, WebSocketServer } from 'ws'\nimport { globalLogger } from './logger'\nimport {\n type BaseMessage,\n type EventMessage,\n getRoom,\n type JoinMessage,\n sendAccessDenied,\n sendError,\n} from './socket-server/helpers'\nimport type { StreamAuthRequest } from './types/app-config-types'\n\ntype Message = { type: 'join' | 'leave'; data: JoinMessage }\n\ntype Props = {\n server: Server\n onJoin: <TData>(streamName: string, groupId: string, id: string) => Promise<TData>\n onJoinGroup: <TData>(streamName: string, groupId: string) => Promise<TData[] | undefined>\n authenticate?: (request: StreamAuthRequest) => Promise<unknown | null> | unknown | null\n authorize?: (\n subscription: { streamName: string; groupId: string; id?: string },\n authContext?: unknown,\n ) => Promise<boolean> | boolean\n}\n\nconst AUTH_ERROR_CODE = 401\nexport const createSocketServer = ({ server, onJoin, onJoinGroup, authenticate, authorize }: Props) => {\n const socketServer = new WebSocketServer({\n server,\n verifyClient: async (info, callback) => {\n if (authenticate) {\n try {\n const authRequest: StreamAuthRequest = {\n headers: info.req.headers,\n url: info.req.url,\n }\n info.req.authContext = await authenticate(authRequest)\n callback(true)\n } catch {\n globalLogger.debug('[Socket Server] Authentication failed')\n callback(false, AUTH_ERROR_CODE, 'Authentication failed')\n }\n } else {\n callback(true)\n }\n },\n })\n const rooms: Record<string, Map<string, WebSocket>> = {}\n const subscriptions: Map<WebSocket, Set<[string, string]>> = new Map()\n const authContexts: Map<WebSocket, unknown> = new Map()\n\n const isAuthorized = async (socket: WebSocket, data: BaseMessage): Promise<boolean> => {\n if (!authorize) {\n return true\n }\n\n try {\n const authContext = authContexts.get(socket)\n const result = await authorize(data, authContext)\n return result !== false\n } catch (error) {\n sendError(socket, data, error as Error)\n globalLogger.error('[Socket Server] Failed to authorize stream subscription')\n return false\n }\n }\n\n socketServer.on('connection', async (socket, request) => {\n authContexts.set(socket, request.authContext)\n\n subscriptions.set(socket, new Set())\n\n socket.on('message', async (payload: Buffer) => {\n const message: Message = JSON.parse(payload.toString())\n\n if (message.type === 'join') {\n const authorized = await isAuthorized(socket, message.data)\n\n if (!authorized) {\n sendAccessDenied(socket, message.data)\n return\n }\n\n const room = getRoom(message.data)\n\n if (!rooms[room]) {\n rooms[room] = new Map()\n }\n\n if (message.data.id) {\n const item = await onJoin(message.data.streamName, message.data.groupId, message.data.id)\n\n if (item) {\n const resultMessage: EventMessage<typeof item> = {\n timestamp: Date.now(),\n streamName: message.data.streamName,\n groupId: message.data.groupId,\n id: message.data.id,\n event: { type: 'sync', data: item },\n }\n\n socket.send(JSON.stringify(resultMessage))\n }\n } else {\n const items = await onJoinGroup(message.data.streamName, message.data.groupId)\n\n if (items) {\n const resultMessage: EventMessage<typeof items> = {\n timestamp: Date.now(),\n streamName: message.data.streamName,\n groupId: message.data.groupId,\n event: { type: 'sync', data: items },\n }\n\n socket.send(JSON.stringify(resultMessage))\n }\n }\n\n rooms[room].set(message.data.subscriptionId, socket)\n subscriptions.get(socket)?.add([room, message.data.subscriptionId])\n } else if (message.type === 'leave') {\n const room = getRoom(message.data)\n\n if (rooms[room]) {\n rooms[room].delete(message.data.subscriptionId)\n }\n }\n })\n\n socket.on('close', () => {\n subscriptions.get(socket)?.forEach(([room, subscriptionId]) => {\n rooms[room]?.delete(subscriptionId)\n })\n subscriptions.delete(socket)\n authContexts.delete(socket)\n })\n })\n\n const pushEvent = <TData>(message: Omit<EventMessage<TData>, 'timestamp'>) => {\n const { groupId, streamName, id } = message\n const groupRoom = getRoom({ streamName, groupId })\n const eventMessage = JSON.stringify({ timestamp: Date.now(), ...message })\n\n if (rooms[groupRoom]) {\n rooms[groupRoom].forEach((socket) => {\n socket.send(eventMessage)\n })\n }\n\n if (id) {\n const itemRoom = getRoom({ groupId, streamName, id })\n\n if (rooms[itemRoom]) {\n rooms[itemRoom].forEach((socket) => {\n socket.send(eventMessage)\n })\n }\n }\n }\n\n return { pushEvent, socketServer }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"socket-server.mjs","names":["authRequest: StreamAuthRequest","rooms: Record<string, Map<string, WebSocket>>","subscriptions: Map<WebSocket, Map<string, string>>","authContexts: Map<WebSocket, unknown>","messageQueue: Promise<void>","resultMessage: EventMessage<typeof item>","resultMessage: EventMessage<typeof items>","message: Message"],"sources":["../../src/socket-server.ts"],"sourcesContent":["import type { Server } from 'http'\nimport { WebSocket, WebSocketServer } from 'ws'\nimport { globalLogger } from './logger'\nimport {\n type BaseMessage,\n type EventMessage,\n getRoom,\n type JoinMessage,\n sendAccessDenied,\n sendError,\n} from './socket-server/helpers'\nimport type { StreamAuthRequest } from './types/app-config-types'\n\ntype Message = { type: 'join' | 'leave'; data: JoinMessage }\n\ntype Props = {\n server: Server\n onJoin: <TData>(streamName: string, groupId: string, id: string) => Promise<TData>\n onJoinGroup: <TData>(streamName: string, groupId: string) => Promise<TData[] | undefined>\n authenticate?: (request: StreamAuthRequest) => Promise<unknown | null> | unknown | null\n authorize?: (\n subscription: { streamName: string; groupId: string; id?: string },\n authContext?: unknown,\n ) => Promise<boolean> | boolean\n}\n\nconst AUTH_ERROR_CODE = 401\nexport const createSocketServer = ({ server, onJoin, onJoinGroup, authenticate, authorize }: Props) => {\n const socketServer = new WebSocketServer({\n server,\n verifyClient: async (info, callback) => {\n if (authenticate) {\n try {\n const authRequest: StreamAuthRequest = {\n headers: info.req.headers,\n url: info.req.url,\n }\n info.req.authContext = await authenticate(authRequest)\n callback(true)\n } catch {\n globalLogger.debug('[Socket Server] Authentication failed')\n callback(false, AUTH_ERROR_CODE, 'Authentication failed')\n }\n } else {\n callback(true)\n }\n },\n })\n const rooms: Record<string, Map<string, WebSocket>> = {}\n const subscriptions: Map<WebSocket, Map<string, string>> = new Map()\n const authContexts: Map<WebSocket, unknown> = new Map()\n\n const isAuthorized = async (socket: WebSocket, data: BaseMessage): Promise<boolean> => {\n if (!authorize) {\n return true\n }\n\n try {\n const authContext = authContexts.get(socket)\n const result = await authorize(data, authContext)\n return result !== false\n } catch (error) {\n sendError(socket, data, error as Error)\n globalLogger.error('[Socket Server] Failed to authorize stream subscription')\n return false\n }\n }\n\n socketServer.on('connection', async (socket, request) => {\n authContexts.set(socket, request.authContext)\n\n subscriptions.set(socket, new Map())\n\n // Message queue to ensure messages are processed in order\n // This prevents race conditions where async join handlers allow leave to overtake join\n let messageQueue: Promise<void> = Promise.resolve()\n\n const processMessage = async (message: Message) => {\n if (message.type === 'join') {\n const authorized = await isAuthorized(socket, message.data)\n\n if (!authorized) {\n sendAccessDenied(socket, message.data)\n return\n }\n\n const room = getRoom(message.data)\n\n if (!rooms[room]) {\n rooms[room] = new Map()\n }\n\n if (message.data.id) {\n const item = await onJoin(message.data.streamName, message.data.groupId, message.data.id)\n\n if (item) {\n const resultMessage: EventMessage<typeof item> = {\n timestamp: Date.now(),\n streamName: message.data.streamName,\n groupId: message.data.groupId,\n id: message.data.id,\n event: { type: 'sync', data: item },\n }\n\n socket.send(JSON.stringify(resultMessage))\n }\n } else {\n const items = await onJoinGroup(message.data.streamName, message.data.groupId)\n\n if (items) {\n const resultMessage: EventMessage<typeof items> = {\n timestamp: Date.now(),\n streamName: message.data.streamName,\n groupId: message.data.groupId,\n event: { type: 'sync', data: items },\n }\n\n socket.send(JSON.stringify(resultMessage))\n }\n }\n\n rooms[room].set(message.data.subscriptionId, socket)\n subscriptions.get(socket)?.set(message.data.subscriptionId, room)\n } else if (message.type === 'leave') {\n if (!message.data.subscriptionId) {\n globalLogger.error('[Socket Server] Subscription ID is required for leave message')\n return\n }\n\n const room = getRoom(message.data)\n if (rooms[room]) {\n rooms[room].delete(message.data.subscriptionId)\n if (rooms[room].size === 0) {\n delete rooms[room]\n }\n }\n\n subscriptions.get(socket)?.delete(message.data.subscriptionId)\n }\n }\n\n socket.on('message', (payload: Buffer) => {\n const message: Message = JSON.parse(payload.toString())\n // Chain messages to ensure they are processed in order\n messageQueue = messageQueue\n .then(() => processMessage(message))\n .catch((error) => {\n globalLogger.error('[Socket Server] Error processing message', error)\n })\n })\n\n socket.on('close', () => {\n subscriptions.get(socket)?.forEach((room, subscriptionId) => {\n rooms[room]?.delete(subscriptionId)\n\n if (rooms[room]?.size === 0) {\n delete rooms[room]\n }\n })\n subscriptions.delete(socket)\n authContexts.delete(socket)\n })\n })\n\n const pushEvent = <TData>(message: Omit<EventMessage<TData>, 'timestamp'>) => {\n const { groupId, streamName, id } = message\n const groupRoom = getRoom({ streamName, groupId })\n const eventMessage = JSON.stringify({ timestamp: Date.now(), ...message })\n\n const safeSend = (socket: WebSocket) => {\n if (socket.readyState === WebSocket.OPEN) {\n try {\n socket.send(eventMessage)\n } catch (error) {\n globalLogger.debug('[Socket Server] Failed to send message to socket', error)\n }\n }\n }\n\n if (rooms[groupRoom]) {\n rooms[groupRoom].forEach(safeSend)\n }\n\n if (id) {\n const itemRoom = getRoom({ groupId, streamName, id })\n\n if (rooms[itemRoom]) {\n rooms[itemRoom].forEach(safeSend)\n }\n }\n }\n\n return { pushEvent, socketServer }\n}\n"],"mappings":"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"}
@@ -48,6 +48,7 @@ var RpcProcessor = class {
48
48
  close() {
49
49
  this.isClosed = true;
50
50
  this.messageCallback = void 0;
51
+ this.handlers = {};
51
52
  }
52
53
  };
53
54
 
@@ -1 +1 @@
1
- {"version":3,"file":"step-handler-rpc-processor.mjs","names":["child: ChildProcess"],"sources":["../../src/step-handler-rpc-processor.ts"],"sourcesContent":["import type { ChildProcess } from 'child_process'\nimport type {\n MessageCallback,\n RpcHandler,\n RpcProcessorInterface,\n} from './process-communication/rpc-processor-interface'\n\nexport type RpcMessage = {\n type: 'rpc_request'\n id: string | undefined\n method: string\n args: unknown\n}\n\nexport class RpcProcessor implements RpcProcessorInterface {\n private handlers: Record<string, RpcHandler<any, any>> = {}\n\n private messageCallback?: MessageCallback<any>\n private isClosed = false\n\n constructor(private child: ChildProcess) {}\n\n handler<TInput, TOutput = unknown>(method: string, handler: RpcHandler<TInput, TOutput>) {\n this.handlers[method] = handler\n }\n\n onMessage<T = unknown>(callback: MessageCallback<T>): void {\n this.messageCallback = callback\n }\n\n async handle(method: string, input: unknown) {\n const handler = this.handlers[method]\n if (!handler) {\n throw new Error(`Handler for method ${method} not found`)\n }\n return handler(input)\n }\n\n private response(id: string | undefined, result: unknown, error: unknown) {\n if (id && !this.isClosed && this.child.send && this.child.connected) {\n const responseMessage = {\n type: 'rpc_response',\n id,\n result: error ? undefined : result,\n error: error ? String(error) : undefined,\n }\n this.child.send(responseMessage)\n }\n }\n\n async init() {\n this.child.on('message', (msg: any) => {\n // Call generic message callback if registered\n if (this.messageCallback) {\n this.messageCallback(msg)\n }\n\n // Handle RPC requests specifically\n if (msg && msg.type === 'rpc_request') {\n const { id, method, args } = msg as RpcMessage\n this.handle(method, args)\n .then((result) => this.response(id, result, null))\n .catch((error) => this.response(id, null, error))\n }\n })\n\n this.child.on('exit', () => {\n this.isClosed = true\n })\n this.child.on('close', () => {\n this.isClosed = true\n })\n this.child.on('disconnect', () => {\n this.isClosed = true\n })\n }\n\n close() {\n this.isClosed = true\n this.messageCallback = undefined\n }\n}\n"],"mappings":";AAcA,IAAa,eAAb,MAA2D;CAMzD,YAAY,AAAQA,OAAqB;EAArB;kBALqC,EAAE;kBAGxC;;CAInB,QAAmC,QAAgB,SAAsC;AACvF,OAAK,SAAS,UAAU;;CAG1B,UAAuB,UAAoC;AACzD,OAAK,kBAAkB;;CAGzB,MAAM,OAAO,QAAgB,OAAgB;EAC3C,MAAM,UAAU,KAAK,SAAS;AAC9B,MAAI,CAAC,QACH,OAAM,IAAI,MAAM,sBAAsB,OAAO,YAAY;AAE3D,SAAO,QAAQ,MAAM;;CAGvB,AAAQ,SAAS,IAAwB,QAAiB,OAAgB;AACxE,MAAI,MAAM,CAAC,KAAK,YAAY,KAAK,MAAM,QAAQ,KAAK,MAAM,WAAW;GACnE,MAAM,kBAAkB;IACtB,MAAM;IACN;IACA,QAAQ,QAAQ,SAAY;IAC5B,OAAO,QAAQ,OAAO,MAAM,GAAG;IAChC;AACD,QAAK,MAAM,KAAK,gBAAgB;;;CAIpC,MAAM,OAAO;AACX,OAAK,MAAM,GAAG,YAAY,QAAa;AAErC,OAAI,KAAK,gBACP,MAAK,gBAAgB,IAAI;AAI3B,OAAI,OAAO,IAAI,SAAS,eAAe;IACrC,MAAM,EAAE,IAAI,QAAQ,SAAS;AAC7B,SAAK,OAAO,QAAQ,KAAK,CACtB,MAAM,WAAW,KAAK,SAAS,IAAI,QAAQ,KAAK,CAAC,CACjD,OAAO,UAAU,KAAK,SAAS,IAAI,MAAM,MAAM,CAAC;;IAErD;AAEF,OAAK,MAAM,GAAG,cAAc;AAC1B,QAAK,WAAW;IAChB;AACF,OAAK,MAAM,GAAG,eAAe;AAC3B,QAAK,WAAW;IAChB;AACF,OAAK,MAAM,GAAG,oBAAoB;AAChC,QAAK,WAAW;IAChB;;CAGJ,QAAQ;AACN,OAAK,WAAW;AAChB,OAAK,kBAAkB"}
1
+ {"version":3,"file":"step-handler-rpc-processor.mjs","names":["child: ChildProcess"],"sources":["../../src/step-handler-rpc-processor.ts"],"sourcesContent":["import type { ChildProcess } from 'child_process'\nimport type {\n MessageCallback,\n RpcHandler,\n RpcProcessorInterface,\n} from './process-communication/rpc-processor-interface'\n\nexport type RpcMessage = {\n type: 'rpc_request'\n id: string | undefined\n method: string\n args: unknown\n}\n\nexport class RpcProcessor implements RpcProcessorInterface {\n private handlers: Record<string, RpcHandler<any, any>> = {}\n\n private messageCallback?: MessageCallback<any>\n private isClosed = false\n\n constructor(private child: ChildProcess) {}\n\n handler<TInput, TOutput = unknown>(method: string, handler: RpcHandler<TInput, TOutput>) {\n this.handlers[method] = handler\n }\n\n onMessage<T = unknown>(callback: MessageCallback<T>): void {\n this.messageCallback = callback\n }\n\n async handle(method: string, input: unknown) {\n const handler = this.handlers[method]\n if (!handler) {\n throw new Error(`Handler for method ${method} not found`)\n }\n return handler(input)\n }\n\n private response(id: string | undefined, result: unknown, error: unknown) {\n if (id && !this.isClosed && this.child.send && this.child.connected) {\n const responseMessage = {\n type: 'rpc_response',\n id,\n result: error ? undefined : result,\n error: error ? String(error) : undefined,\n }\n this.child.send(responseMessage)\n }\n }\n\n async init() {\n this.child.on('message', (msg: any) => {\n // Call generic message callback if registered\n if (this.messageCallback) {\n this.messageCallback(msg)\n }\n\n // Handle RPC requests specifically\n if (msg && msg.type === 'rpc_request') {\n const { id, method, args } = msg as RpcMessage\n this.handle(method, args)\n .then((result) => this.response(id, result, null))\n .catch((error) => this.response(id, null, error))\n }\n })\n\n this.child.on('exit', () => {\n this.isClosed = true\n })\n this.child.on('close', () => {\n this.isClosed = true\n })\n this.child.on('disconnect', () => {\n this.isClosed = true\n })\n }\n\n close() {\n this.isClosed = true\n this.messageCallback = undefined\n this.handlers = {}\n }\n}\n"],"mappings":";AAcA,IAAa,eAAb,MAA2D;CAMzD,YAAY,AAAQA,OAAqB;EAArB;kBALqC,EAAE;kBAGxC;;CAInB,QAAmC,QAAgB,SAAsC;AACvF,OAAK,SAAS,UAAU;;CAG1B,UAAuB,UAAoC;AACzD,OAAK,kBAAkB;;CAGzB,MAAM,OAAO,QAAgB,OAAgB;EAC3C,MAAM,UAAU,KAAK,SAAS;AAC9B,MAAI,CAAC,QACH,OAAM,IAAI,MAAM,sBAAsB,OAAO,YAAY;AAE3D,SAAO,QAAQ,MAAM;;CAGvB,AAAQ,SAAS,IAAwB,QAAiB,OAAgB;AACxE,MAAI,MAAM,CAAC,KAAK,YAAY,KAAK,MAAM,QAAQ,KAAK,MAAM,WAAW;GACnE,MAAM,kBAAkB;IACtB,MAAM;IACN;IACA,QAAQ,QAAQ,SAAY;IAC5B,OAAO,QAAQ,OAAO,MAAM,GAAG;IAChC;AACD,QAAK,MAAM,KAAK,gBAAgB;;;CAIpC,MAAM,OAAO;AACX,OAAK,MAAM,GAAG,YAAY,QAAa;AAErC,OAAI,KAAK,gBACP,MAAK,gBAAgB,IAAI;AAI3B,OAAI,OAAO,IAAI,SAAS,eAAe;IACrC,MAAM,EAAE,IAAI,QAAQ,SAAS;AAC7B,SAAK,OAAO,QAAQ,KAAK,CACtB,MAAM,WAAW,KAAK,SAAS,IAAI,QAAQ,KAAK,CAAC,CACjD,OAAO,UAAU,KAAK,SAAS,IAAI,MAAM,MAAM,CAAC;;IAErD;AAEF,OAAK,MAAM,GAAG,cAAc;AAC1B,QAAK,WAAW;IAChB;AACF,OAAK,MAAM,GAAG,eAAe;AAC3B,QAAK,WAAW;IAChB;AACF,OAAK,MAAM,GAAG,oBAAoB;AAChC,QAAK,WAAW;IAChB;;CAGJ,QAAQ;AACN,OAAK,WAAW;AAChB,OAAK,kBAAkB;AACvB,OAAK,WAAW,EAAE"}
@@ -62,6 +62,7 @@ var RpcStdinProcessor = class {
62
62
  close() {
63
63
  this.isClosed = true;
64
64
  this.messageCallback = void 0;
65
+ this.handlers = {};
65
66
  if (this.rl) {
66
67
  this.rl.removeAllListeners();
67
68
  this.rl.close();
@@ -1 +1 @@
1
- {"version":3,"file":"step-handler-rpc-stdin-processor.mjs","names":["child: ChildProcess"],"sources":["../../src/step-handler-rpc-stdin-processor.ts"],"sourcesContent":["import type { ChildProcess } from 'child_process'\nimport readline from 'readline'\nimport type {\n MessageCallback,\n RpcHandler,\n RpcProcessorInterface,\n} from './process-communication/rpc-processor-interface'\n\nexport type RpcMessage = {\n type: 'rpc_request'\n id: string | undefined\n method: string\n args: unknown\n}\n\nexport class RpcStdinProcessor implements RpcProcessorInterface {\n private handlers: Record<string, RpcHandler<any, any>> = {}\n\n private messageCallback?: MessageCallback<any>\n private isClosed = false\n private rl?: readline.Interface\n\n constructor(private child: ChildProcess) {}\n\n handler<TInput, TOutput = unknown>(method: string, handler: RpcHandler<TInput, TOutput>) {\n this.handlers[method] = handler\n }\n\n onMessage<T = unknown>(callback: MessageCallback<T>): void {\n this.messageCallback = callback\n }\n\n async handle(method: string, input: unknown) {\n const handler = this.handlers[method]\n if (!handler) {\n throw new Error(`Handler for method ${method} not found`)\n }\n return handler(input)\n }\n\n private response(id: string | undefined, result: unknown, error: unknown) {\n if (id && !this.isClosed && this.child.stdin && !this.child.killed) {\n const responseMessage = {\n type: 'rpc_response',\n id,\n result: error ? undefined : result,\n error: error ? String(error) : undefined,\n }\n const messageStr = JSON.stringify(responseMessage)\n this.child.stdin.write(messageStr + '\\n')\n }\n }\n\n async init() {\n if (this.child.stdout) {\n this.rl = readline.createInterface({\n input: this.child.stdout,\n crlfDelay: Infinity,\n })\n\n this.rl.on('line', (line) => {\n try {\n const msg = JSON.parse(line.trim())\n\n // Call generic message callback if registered\n if (this.messageCallback) {\n this.messageCallback(msg)\n }\n\n // Handle RPC requests specifically\n if (msg && msg.type === 'rpc_request') {\n const { id, method, args } = msg as RpcMessage\n this.handle(method, args)\n .then((result) => this.response(id, result, null))\n .catch((error) => this.response(id, null, error))\n }\n } catch (error) {\n console.error('Failed to parse RPC message:', error, 'Raw line:', line)\n }\n })\n\n this.rl.on('close', () => {\n this.isClosed = true\n })\n }\n\n this.child.on('exit', () => {\n this.isClosed = true\n })\n this.child.on('close', () => {\n this.isClosed = true\n })\n }\n\n close() {\n this.isClosed = true\n this.messageCallback = undefined\n if (this.rl) {\n this.rl.removeAllListeners()\n this.rl.close()\n }\n }\n}\n"],"mappings":";;;AAeA,IAAa,oBAAb,MAAgE;CAO9D,YAAY,AAAQA,OAAqB;EAArB;kBANqC,EAAE;kBAGxC;;CAKnB,QAAmC,QAAgB,SAAsC;AACvF,OAAK,SAAS,UAAU;;CAG1B,UAAuB,UAAoC;AACzD,OAAK,kBAAkB;;CAGzB,MAAM,OAAO,QAAgB,OAAgB;EAC3C,MAAM,UAAU,KAAK,SAAS;AAC9B,MAAI,CAAC,QACH,OAAM,IAAI,MAAM,sBAAsB,OAAO,YAAY;AAE3D,SAAO,QAAQ,MAAM;;CAGvB,AAAQ,SAAS,IAAwB,QAAiB,OAAgB;AACxE,MAAI,MAAM,CAAC,KAAK,YAAY,KAAK,MAAM,SAAS,CAAC,KAAK,MAAM,QAAQ;GAClE,MAAM,kBAAkB;IACtB,MAAM;IACN;IACA,QAAQ,QAAQ,SAAY;IAC5B,OAAO,QAAQ,OAAO,MAAM,GAAG;IAChC;GACD,MAAM,aAAa,KAAK,UAAU,gBAAgB;AAClD,QAAK,MAAM,MAAM,MAAM,aAAa,KAAK;;;CAI7C,MAAM,OAAO;AACX,MAAI,KAAK,MAAM,QAAQ;AACrB,QAAK,KAAK,SAAS,gBAAgB;IACjC,OAAO,KAAK,MAAM;IAClB,WAAW;IACZ,CAAC;AAEF,QAAK,GAAG,GAAG,SAAS,SAAS;AAC3B,QAAI;KACF,MAAM,MAAM,KAAK,MAAM,KAAK,MAAM,CAAC;AAGnC,SAAI,KAAK,gBACP,MAAK,gBAAgB,IAAI;AAI3B,SAAI,OAAO,IAAI,SAAS,eAAe;MACrC,MAAM,EAAE,IAAI,QAAQ,SAAS;AAC7B,WAAK,OAAO,QAAQ,KAAK,CACtB,MAAM,WAAW,KAAK,SAAS,IAAI,QAAQ,KAAK,CAAC,CACjD,OAAO,UAAU,KAAK,SAAS,IAAI,MAAM,MAAM,CAAC;;aAE9C,OAAO;AACd,aAAQ,MAAM,gCAAgC,OAAO,aAAa,KAAK;;KAEzE;AAEF,QAAK,GAAG,GAAG,eAAe;AACxB,SAAK,WAAW;KAChB;;AAGJ,OAAK,MAAM,GAAG,cAAc;AAC1B,QAAK,WAAW;IAChB;AACF,OAAK,MAAM,GAAG,eAAe;AAC3B,QAAK,WAAW;IAChB;;CAGJ,QAAQ;AACN,OAAK,WAAW;AAChB,OAAK,kBAAkB;AACvB,MAAI,KAAK,IAAI;AACX,QAAK,GAAG,oBAAoB;AAC5B,QAAK,GAAG,OAAO"}
1
+ {"version":3,"file":"step-handler-rpc-stdin-processor.mjs","names":["child: ChildProcess"],"sources":["../../src/step-handler-rpc-stdin-processor.ts"],"sourcesContent":["import type { ChildProcess } from 'child_process'\nimport readline from 'readline'\nimport type {\n MessageCallback,\n RpcHandler,\n RpcProcessorInterface,\n} from './process-communication/rpc-processor-interface'\n\nexport type RpcMessage = {\n type: 'rpc_request'\n id: string | undefined\n method: string\n args: unknown\n}\n\nexport class RpcStdinProcessor implements RpcProcessorInterface {\n private handlers: Record<string, RpcHandler<any, any>> = {}\n\n private messageCallback?: MessageCallback<any>\n private isClosed = false\n private rl?: readline.Interface\n\n constructor(private child: ChildProcess) {}\n\n handler<TInput, TOutput = unknown>(method: string, handler: RpcHandler<TInput, TOutput>) {\n this.handlers[method] = handler\n }\n\n onMessage<T = unknown>(callback: MessageCallback<T>): void {\n this.messageCallback = callback\n }\n\n async handle(method: string, input: unknown) {\n const handler = this.handlers[method]\n if (!handler) {\n throw new Error(`Handler for method ${method} not found`)\n }\n return handler(input)\n }\n\n private response(id: string | undefined, result: unknown, error: unknown) {\n if (id && !this.isClosed && this.child.stdin && !this.child.killed) {\n const responseMessage = {\n type: 'rpc_response',\n id,\n result: error ? undefined : result,\n error: error ? String(error) : undefined,\n }\n const messageStr = JSON.stringify(responseMessage)\n this.child.stdin.write(messageStr + '\\n')\n }\n }\n\n async init() {\n if (this.child.stdout) {\n this.rl = readline.createInterface({\n input: this.child.stdout,\n crlfDelay: Infinity,\n })\n\n this.rl.on('line', (line) => {\n try {\n const msg = JSON.parse(line.trim())\n\n // Call generic message callback if registered\n if (this.messageCallback) {\n this.messageCallback(msg)\n }\n\n // Handle RPC requests specifically\n if (msg && msg.type === 'rpc_request') {\n const { id, method, args } = msg as RpcMessage\n this.handle(method, args)\n .then((result) => this.response(id, result, null))\n .catch((error) => this.response(id, null, error))\n }\n } catch (error) {\n console.error('Failed to parse RPC message:', error, 'Raw line:', line)\n }\n })\n\n this.rl.on('close', () => {\n this.isClosed = true\n })\n }\n\n this.child.on('exit', () => {\n this.isClosed = true\n })\n this.child.on('close', () => {\n this.isClosed = true\n })\n }\n\n close() {\n this.isClosed = true\n this.messageCallback = undefined\n this.handlers = {}\n if (this.rl) {\n this.rl.removeAllListeners()\n this.rl.close()\n }\n }\n}\n"],"mappings":";;;AAeA,IAAa,oBAAb,MAAgE;CAO9D,YAAY,AAAQA,OAAqB;EAArB;kBANqC,EAAE;kBAGxC;;CAKnB,QAAmC,QAAgB,SAAsC;AACvF,OAAK,SAAS,UAAU;;CAG1B,UAAuB,UAAoC;AACzD,OAAK,kBAAkB;;CAGzB,MAAM,OAAO,QAAgB,OAAgB;EAC3C,MAAM,UAAU,KAAK,SAAS;AAC9B,MAAI,CAAC,QACH,OAAM,IAAI,MAAM,sBAAsB,OAAO,YAAY;AAE3D,SAAO,QAAQ,MAAM;;CAGvB,AAAQ,SAAS,IAAwB,QAAiB,OAAgB;AACxE,MAAI,MAAM,CAAC,KAAK,YAAY,KAAK,MAAM,SAAS,CAAC,KAAK,MAAM,QAAQ;GAClE,MAAM,kBAAkB;IACtB,MAAM;IACN;IACA,QAAQ,QAAQ,SAAY;IAC5B,OAAO,QAAQ,OAAO,MAAM,GAAG;IAChC;GACD,MAAM,aAAa,KAAK,UAAU,gBAAgB;AAClD,QAAK,MAAM,MAAM,MAAM,aAAa,KAAK;;;CAI7C,MAAM,OAAO;AACX,MAAI,KAAK,MAAM,QAAQ;AACrB,QAAK,KAAK,SAAS,gBAAgB;IACjC,OAAO,KAAK,MAAM;IAClB,WAAW;IACZ,CAAC;AAEF,QAAK,GAAG,GAAG,SAAS,SAAS;AAC3B,QAAI;KACF,MAAM,MAAM,KAAK,MAAM,KAAK,MAAM,CAAC;AAGnC,SAAI,KAAK,gBACP,MAAK,gBAAgB,IAAI;AAI3B,SAAI,OAAO,IAAI,SAAS,eAAe;MACrC,MAAM,EAAE,IAAI,QAAQ,SAAS;AAC7B,WAAK,OAAO,QAAQ,KAAK,CACtB,MAAM,WAAW,KAAK,SAAS,IAAI,QAAQ,KAAK,CAAC,CACjD,OAAO,UAAU,KAAK,SAAS,IAAI,MAAM,MAAM,CAAC;;aAE9C,OAAO;AACd,aAAQ,MAAM,gCAAgC,OAAO,aAAa,KAAK;;KAEzE;AAEF,QAAK,GAAG,GAAG,eAAe;AACxB,SAAK,WAAW;KAChB;;AAGJ,OAAK,MAAM,GAAG,cAAc;AAC1B,QAAK,WAAW;IAChB;AACF,OAAK,MAAM,GAAG,eAAe;AAC3B,QAAK,WAAW;IAChB;;CAGJ,QAAQ;AACN,OAAK,WAAW;AAChB,OAAK,kBAAkB;AACvB,OAAK,WAAW,EAAE;AAClB,MAAI,KAAK,IAAI;AACX,QAAK,GAAG,oBAAoB;AAC5B,QAAK,GAAG,OAAO"}
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "import": "./dist/index.mjs"
12
12
  }
13
13
  },
14
- "version": "0.15.5-beta.174-069425",
14
+ "version": "0.15.5-beta.174-384621",
15
15
  "dependencies": {
16
16
  "@amplitude/analytics-node": "^1.5.26",
17
17
  "@standard-schema/spec": "^1.0.0",