@aidra/pmx-io 0.0.0-stage → 9.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +69 -2
  2. package/bin/pmx-io-node.js +143 -0
  3. package/index.d.ts +381 -0
  4. package/index.js +27 -0
  5. package/index.mjs +47 -0
  6. package/lib/actions.js +120 -0
  7. package/lib/activate.js +402 -0
  8. package/lib/application.js +106 -0
  9. package/lib/bun.js +155 -0
  10. package/lib/config.js +67 -0
  11. package/lib/constants.js +17 -0
  12. package/lib/debug.js +48 -0
  13. package/lib/esm-hooks.mjs +111 -0
  14. package/lib/exit.js +79 -0
  15. package/lib/features/metrics.js +409 -0
  16. package/lib/features/notify.js +358 -0
  17. package/lib/features/profiling.js +208 -0
  18. package/lib/hooks.js +151 -0
  19. package/lib/inbound.js +174 -0
  20. package/lib/integrations.js +372 -0
  21. package/lib/itg/amqplib.js +169 -0
  22. package/lib/itg/bullmq.js +141 -0
  23. package/lib/itg/common.js +657 -0
  24. package/lib/itg/dbcomment.js +114 -0
  25. package/lib/itg/index.js +103 -0
  26. package/lib/itg/ioredis.js +212 -0
  27. package/lib/itg/kafkajs.js +205 -0
  28. package/lib/itg/mongodb.js +322 -0
  29. package/lib/itg/mysql2.js +205 -0
  30. package/lib/itg/nats.js +531 -0
  31. package/lib/itg/noderedis.js +236 -0
  32. package/lib/itg/pg.js +253 -0
  33. package/lib/itg/pgqueue.js +305 -0
  34. package/lib/itg/postgres.js +252 -0
  35. package/lib/itg/redis-common.js +265 -0
  36. package/lib/itg/sql.js +302 -0
  37. package/lib/metrics/service.js +286 -0
  38. package/lib/metrics/types.js +342 -0
  39. package/lib/modules.js +260 -0
  40. package/lib/node-options.js +62 -0
  41. package/lib/otel/bridge.js +797 -0
  42. package/lib/otel/env.js +114 -0
  43. package/lib/outbound.js +362 -0
  44. package/lib/pmx.js +757 -0
  45. package/lib/relay/hub.js +279 -0
  46. package/lib/relay/transport.js +253 -0
  47. package/lib/standalone/activate.js +307 -0
  48. package/lib/standalone/capture.js +55 -0
  49. package/lib/standalone/container.js +909 -0
  50. package/lib/standalone/transport.js +1023 -0
  51. package/lib/tracing/context.js +90 -0
  52. package/lib/tracing/control.js +124 -0
  53. package/lib/tracing/exporter.js +115 -0
  54. package/lib/tracing/index.js +242 -0
  55. package/lib/tracing/logs.js +176 -0
  56. package/lib/tracing/options.js +105 -0
  57. package/lib/tracing/paths.js +34 -0
  58. package/lib/tracing/tracer.js +850 -0
  59. package/lib/tracing/w3c.js +415 -0
  60. package/lib/transport/ipc.js +97 -0
  61. package/lib/transport/ws.js +511 -0
  62. package/lib/util.js +109 -0
  63. package/package.json +48 -4
  64. package/preload.cjs +26 -0
  65. package/preload.mjs +25 -0
  66. package/standalone.cjs +16 -0
  67. package/standalone.mjs +17 -0
@@ -0,0 +1,169 @@
1
+ // Copyright (c) 2026 Mike Warriner. All rights reserved. Proprietary — see LICENSE.
2
+ 'use strict'
3
+
4
+ // amqplib (RabbitMQ, AMQP 0-9-1; 82 §13 ITG-242, ITG-243), promise API (lib/channel_model.js) and
5
+ // callback API (lib/callback_model.js), normal and confirm channels:
6
+ // * publish(exchange, routingKey, content, options) and sendToQueue(queue, content, options) →
7
+ // PRODUCER `publish <exchange>` (the routing key / queue for the default exchange), trace headers
8
+ // in a copy of `options.headers`; the span ends when the call returns (also on confirm
9
+ // channels, not at the broker confirm);
10
+ // * consume(queue, onMessage, options) → callback style per delivery (a `null` delivery, the
11
+ // consumer being cancelled, makes none), parent extracted from `properties.headers`;
12
+ // * get(queue) → batch pull of one (`receive <queue>`, one link), only when a message came back.
13
+
14
+ const c = require('./common')
15
+
16
+ const SYSTEM = 'rabbitmq'
17
+
18
+ function peer (ch) {
19
+ const tags = {}
20
+ try {
21
+ const s = ch && ch.connection && ch.connection.stream
22
+ if (s && s.remoteAddress) {
23
+ tags['net.peer.name'] = String(s.remoteAddress)
24
+ if (s.remotePort) tags['net.peer.port'] = String(s.remotePort)
25
+ }
26
+ } catch (_) {}
27
+ return tags
28
+ }
29
+
30
+ function publishSpan (ch, exchange, routingKey, content, options) {
31
+ const tags = peer(ch)
32
+ if (routingKey !== undefined && routingKey !== null) tags['messaging.rabbitmq.destination.routing_key'] = String(routingKey)
33
+ if (options && options.messageId !== undefined) tags['messaging.message.id'] = String(options.messageId)
34
+ const size = c.bodySize(content)
35
+ if (size !== undefined) tags['messaging.message.body.size'] = String(size)
36
+ const dest = exchange ? String(exchange) : (routingKey !== undefined && routingKey !== null ? String(routingKey) : undefined)
37
+ return c.producer(SYSTEM, dest, tags)
38
+ }
39
+
40
+ function withHeaders (options, span) {
41
+ const o = Object.assign({}, options || {})
42
+ o.headers = c.headersObject(span, options && options.headers)
43
+ return o
44
+ }
45
+
46
+ function wrapPublish (orig) {
47
+ return function publish (exchange, routingKey, content, options) {
48
+ if (!c.msgTracer() || c.nested()) return orig.apply(this, arguments)
49
+ const span = publishSpan(this, exchange, routingKey, content, options)
50
+ if (!span) return c.outer(orig, this, arguments)
51
+ const args = Array.prototype.slice.call(arguments)
52
+ while (args.length < 4) args.push(undefined)
53
+ args[3] = withHeaders(options, span)
54
+ try {
55
+ const r = c.outer(orig, this, args)
56
+ c.end(span)
57
+ return r
58
+ } catch (err) {
59
+ c.end(span, err)
60
+ throw err
61
+ }
62
+ }
63
+ }
64
+
65
+ function wrapSendToQueue (orig) {
66
+ return function sendToQueue (queue, content, options) {
67
+ if (!c.msgTracer() || c.nested()) return orig.apply(this, arguments)
68
+ const span = publishSpan(this, '', queue, content, options)
69
+ if (!span) return c.outer(orig, this, arguments)
70
+ const args = Array.prototype.slice.call(arguments)
71
+ while (args.length < 3) args.push(undefined)
72
+ args[2] = withHeaders(options, span)
73
+ try {
74
+ const r = c.outer(orig, this, args)
75
+ c.end(span)
76
+ return r
77
+ } catch (err) {
78
+ c.end(span, err)
79
+ throw err
80
+ }
81
+ }
82
+ }
83
+
84
+ function msgTags (ch, msg, queue) {
85
+ const tags = peer(ch)
86
+ const f = msg.fields || {}
87
+ const p = msg.properties || {}
88
+ if (f.routingKey !== undefined) tags['messaging.rabbitmq.destination.routing_key'] = String(f.routingKey)
89
+ if (p.messageId !== undefined && p.messageId !== null) tags['messaging.message.id'] = String(p.messageId)
90
+ const size = c.bodySize(msg.content)
91
+ if (size !== undefined) tags['messaging.message.body.size'] = String(size)
92
+ return tags
93
+ }
94
+
95
+ function wrapConsume (orig) {
96
+ return function consume (queue, onMessage) {
97
+ if (!c.msgTracer() || typeof onMessage !== 'function') return orig.apply(this, arguments)
98
+ const ch = this
99
+ const args = Array.prototype.slice.call(arguments)
100
+ args[1] = function (msg) {
101
+ if (msg === null || msg === undefined || !c.msgTracer()) return onMessage.apply(this, arguments)
102
+ const headers = msg.properties && msg.properties.headers
103
+ const span = c.consumer(SYSTEM, String(queue), c.extract(headers), msgTags(ch, msg, queue))
104
+ return c.runConsumer(span, onMessage, this, arguments)
105
+ }
106
+ return orig.apply(this, args)
107
+ }
108
+ }
109
+
110
+ function receiveDone (span, msg) {
111
+ if (!span) return
112
+ if (!msg) return // nothing returned: no span (ITG-023)
113
+ try {
114
+ c.addLink(span, c.extract(msg.properties && msg.properties.headers))
115
+ } catch (_) {}
116
+ c.end(span)
117
+ }
118
+
119
+ function wrapGet (orig) {
120
+ return function get (queue, options, cb) {
121
+ if (!c.msgTracer()) return orig.apply(this, arguments)
122
+ const span = c.batchConsumer(SYSTEM, String(queue), null, peer(this), 'receive')
123
+ if (!span) return orig.apply(this, arguments)
124
+ const args = Array.prototype.slice.call(arguments)
125
+ const cbIndex = typeof options === 'function' ? 1 : (typeof cb === 'function' ? 2 : -1)
126
+ if (cbIndex !== -1) {
127
+ const fn = c.bind(args[cbIndex])
128
+ args[cbIndex] = function (err, msg) {
129
+ if (err) c.end(span, err)
130
+ else receiveDone(span, msg)
131
+ return fn.apply(this, arguments)
132
+ }
133
+ return orig.apply(this, args)
134
+ }
135
+ let r
136
+ try {
137
+ r = orig.apply(this, args)
138
+ } catch (err) {
139
+ c.end(span, err)
140
+ throw err
141
+ }
142
+ if (!c.isThenable(r)) return r
143
+ return r.then((msg) => {
144
+ receiveDone(span, msg)
145
+ return msg
146
+ }, (err) => {
147
+ c.end(span, err)
148
+ throw err
149
+ })
150
+ }
151
+ }
152
+
153
+ function patchModel (exports, info) {
154
+ let any = false
155
+ for (const name of ['Channel', 'ConfirmChannel']) {
156
+ const K = exports && exports[name]
157
+ const proto = K && K.prototype
158
+ if (!proto) continue
159
+ for (const [m, w] of [['publish', wrapPublish], ['sendToQueue', wrapSendToQueue], ['consume', wrapConsume], ['get', wrapGet]]) {
160
+ if (Object.prototype.hasOwnProperty.call(proto, m) && typeof proto[m] === 'function') {
161
+ c.wrap(proto, m, w)
162
+ any = true
163
+ }
164
+ }
165
+ }
166
+ if (!any) c.disabled('amqplib', 'Channel.publish not found in ' + info.file)
167
+ }
168
+
169
+ module.exports = { patchModel }
@@ -0,0 +1,141 @@
1
+ // Copyright (c) 2026 Mike Warriner. All rights reserved. Proprietary — see LICENSE.
2
+ 'use strict'
3
+
4
+ // BullMQ (82 §10 ITG-212). Producer: `Queue.prototype.add(name, data, opts)` → PRODUCER
5
+ // `publish <queue name>` (current during the call, so BullMQ's Redis commands are its children,
6
+ // ITG-005), the carrier `pmxTrace` = { traceparent, tracestate?, baggage? } in a copy of `opts`
7
+ // (BullMQ stores job options with the job); `addBulk(jobs)` → one PRODUCER span with
8
+ // `messaging.batch.message_count`, every job carrying that span's context. Worker: the export
9
+ // `Worker` is replaced by a Proxy whose construct trap wraps a processor function (CONSUMER
10
+ // `process <queue name>`, callback style until its promise settles, parent from
11
+ // `job.opts.pmxTrace`, `messaging.pmx.attempt` = attemptsMade + 1 on BullMQ ≥ 5, attemptsMade on
12
+ // 4.x). Sandboxed processors (a file
13
+ // path) are covered when the child that runs them is instrumented (80 NIO-290–296). BullMQ's own
14
+ // `telemetry` option is left untouched.
15
+
16
+ const c = require('./common')
17
+
18
+ const SYSTEM = 'bullmq'
19
+ const KEY = 'pmxTrace'
20
+
21
+ function withCarrier (opts, span) {
22
+ // a repeatable job (`repeat`) is a schedule: BullMQ copies its options into every job it creates
23
+ // from it, which would make each run (for days) a child of this one call. Its runs start new
24
+ // traces, as jobs from `upsertJobScheduler` do.
25
+ if (opts && typeof opts === 'object' && opts.repeat) return opts
26
+ const o = Object.assign({}, opts || {})
27
+ if (o[KEY] === undefined) o[KEY] = c.traceCarrier(span)
28
+ return o
29
+ }
30
+
31
+ function wrapAdd (orig) {
32
+ return function add (name, data, opts) {
33
+ if (!c.msgTracer()) return orig.apply(this, arguments)
34
+ const tags = {}
35
+ if (name !== undefined) tags['messaging.bullmq.job.name'] = String(name)
36
+ const span = c.producer(SYSTEM, this.name, tags)
37
+ if (!span) return orig.apply(this, arguments)
38
+ const args = Array.prototype.slice.call(arguments)
39
+ while (args.length < 3) args.push(undefined)
40
+ args[2] = withCarrier(opts, span)
41
+ let p
42
+ try {
43
+ p = c.withSpan(span, orig, this, args)
44
+ } catch (err) {
45
+ c.end(span, err)
46
+ throw err
47
+ }
48
+ if (!c.isThenable(p)) {
49
+ c.end(span)
50
+ return p
51
+ }
52
+ return c.settle(p, span, (job) => {
53
+ if (job && job.id !== undefined) span.setAttribute('messaging.message.id', String(job.id))
54
+ })
55
+ }
56
+ }
57
+
58
+ function wrapAddBulk (orig) {
59
+ return function addBulk (jobs) {
60
+ if (!c.msgTracer() || !Array.isArray(jobs)) return orig.apply(this, arguments)
61
+ const tags = {}
62
+ if (jobs.length > 1) tags['messaging.batch.message_count'] = String(jobs.length)
63
+ const span = c.producer(SYSTEM, this.name, tags)
64
+ if (!span) return orig.apply(this, arguments)
65
+ const copy = jobs.map((j) => (j && typeof j === 'object' ? Object.assign({}, j, { opts: withCarrier(j.opts, span) }) : j))
66
+ let p
67
+ try {
68
+ p = c.withSpan(span, orig, this, [copy])
69
+ } catch (err) {
70
+ c.end(span, err)
71
+ throw err
72
+ }
73
+ if (!c.isThenable(p)) {
74
+ c.end(span)
75
+ return p
76
+ }
77
+ return c.settle(p, span)
78
+ }
79
+ }
80
+
81
+ function wrapProcessor (queueName, processor) {
82
+ const w = function (job) {
83
+ if (!c.msgTracer() || !job) return processor.apply(this, arguments)
84
+ const tags = {}
85
+ if (job.id !== undefined) tags['messaging.message.id'] = String(job.id)
86
+ if (job.name !== undefined) tags['messaging.bullmq.job.name'] = String(job.name)
87
+ // BullMQ ≥ 5 counts failed attempts in attemptsMade (and has attemptsStarted); 4.x increments
88
+ // attemptsMade when the job starts, so it already is the 1-based attempt number
89
+ if (typeof job.attemptsMade === 'number') {
90
+ tags['messaging.pmx.attempt'] = String(typeof job.attemptsStarted === 'number' ? job.attemptsMade + 1 : Math.max(1, job.attemptsMade))
91
+ }
92
+ const carrier = job.opts && job.opts[KEY]
93
+ const span = c.consumer(SYSTEM, queueName, carrier ? c.extract(carrier) : null, tags)
94
+ return c.runConsumer(span, processor, this, arguments)
95
+ }
96
+ return c.copyMeta(w, processor)
97
+ }
98
+
99
+ function proxyWorker (Worker) {
100
+ return new Proxy(Worker, {
101
+ construct (target, args, newTarget) {
102
+ let a = args
103
+ try {
104
+ if (typeof args[1] === 'function' && c.tracer()) {
105
+ a = args.slice()
106
+ a[1] = wrapProcessor(String(args[0]), args[1])
107
+ }
108
+ } catch (_) {
109
+ a = args
110
+ }
111
+ return Reflect.construct(target, a, newTarget)
112
+ }
113
+ })
114
+ }
115
+
116
+ /** classes/queue.js: Queue.prototype.add / addBulk. */
117
+ function patchQueue (exports) {
118
+ const Queue = exports && exports.Queue
119
+ const proto = Queue && Queue.prototype
120
+ if (!proto || typeof proto.add !== 'function') {
121
+ c.disabled('bullmq', 'Queue.prototype.add not found')
122
+ return
123
+ }
124
+ c.wrap(proto, 'add', wrapAdd)
125
+ if (typeof proto.addBulk === 'function') c.wrap(proto, 'addBulk', wrapAddBulk)
126
+ }
127
+
128
+ /** classes/worker.js: the Worker export. */
129
+ function patchWorker (exports) {
130
+ const Worker = exports && exports.Worker
131
+ if (typeof Worker !== 'function') {
132
+ c.disabled('bullmq', 'Worker not found')
133
+ return
134
+ }
135
+ const P = proxyWorker(Worker)
136
+ const d = Object.getOwnPropertyDescriptor(exports, 'Worker')
137
+ if (d && d.writable) exports.Worker = P
138
+ else Object.defineProperty(exports, 'Worker', { value: P, writable: true, enumerable: true, configurable: true })
139
+ }
140
+
141
+ module.exports = { patchQueue, patchWorker }