@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,305 @@
1
+ // Copyright (c) 2026 Mike Warriner. All rights reserved. Proprietary — see LICENSE.
2
+ 'use strict'
3
+
4
+ // PostgreSQL-backed job queues (82 §11): pg-boss (ITG-222) and graphile-worker (ITG-223), with the
5
+ // opt-in payload carrier of ITG-220 (`messaging.payloadCarrier`): the producer adds
6
+ // `__pmx_trace__` = { traceparent, tracestate?, baggage? } to a copy of a job payload that is a
7
+ // plain object (never to arrays or scalars) and lacks the key; the consumer wrapper removes the key
8
+ // before the handler/task sees the payload, whatever the setting. Without the option producer and
9
+ // consumer spans are still created and share `messaging.message.id` (the job id). The SQL these
10
+ // libraries run inside a PRODUCER span is its children (the span is current during the call).
11
+
12
+ const c = require('./common')
13
+
14
+ const KEY = c.TRACE_KEY
15
+
16
+ function isPlain (v) {
17
+ if (!v || typeof v !== 'object' || Array.isArray(v)) return false
18
+ const p = Object.getPrototypeOf(v)
19
+ return p === Object.prototype || p === null
20
+ }
21
+
22
+ /** A payload copy carrying the span's context (ITG-220), or the payload unchanged. */
23
+ function carry (payload, span) {
24
+ const t = c.msgTracer()
25
+ if (!span || !t || !t.messaging.payloadCarrier || !isPlain(payload) || Object.prototype.hasOwnProperty.call(payload, KEY)) return payload
26
+ return Object.assign({}, payload, { [KEY]: c.traceCarrier(span) })
27
+ }
28
+
29
+ /** The context in a payload's carrier, removing the key in place (the object is the library's). */
30
+ function take (payload) {
31
+ if (!isPlain(payload) || !Object.prototype.hasOwnProperty.call(payload, KEY)) return null
32
+ const carrier = payload[KEY]
33
+ try {
34
+ delete payload[KEY]
35
+ } catch (_) {}
36
+ return carrier && typeof carrier === 'object' ? c.extract(carrier) : null
37
+ }
38
+
39
+ /** Run fn with the PRODUCER span current; `args(span)` builds the arguments (carrier). */
40
+ function produce (system, destination, tags, fn, thisArg, args, idOf, origArgs) {
41
+ const span = c.producer(system, destination, tags)
42
+ if (!span) return { span: null, result: fn.apply(thisArg, origArgs) }
43
+ const a = args(span)
44
+ let r
45
+ try {
46
+ const store = require('../tracing/context').current()
47
+ r = require('../tracing/context').run({ span, bag: span.bag, server: store && store.server, itg: system }, fn, thisArg, a)
48
+ } catch (err) {
49
+ c.end(span, err)
50
+ throw err
51
+ }
52
+ if (!c.isThenable(r)) {
53
+ c.end(span)
54
+ return { span, result: r }
55
+ }
56
+ return { span, result: c.settle(r, span, (v) => {
57
+ const id = idOf ? idOf(v) : undefined
58
+ if (id !== undefined && id !== null) span.setAttribute('messaging.message.id', String(id))
59
+ }) }
60
+ }
61
+
62
+ function nestedIn (system) {
63
+ const s = require('../tracing/context').current()
64
+ return Boolean(s && s.itg === system)
65
+ }
66
+
67
+ // -- pg-boss ----------------------------------------------------------------------------------
68
+
69
+ const PGBOSS = 'pg-boss'
70
+
71
+ /** send(name, data, options) | send({ name, data, options }) → [name, data, rebuild(data')]. */
72
+ function sendArgs (args) {
73
+ if (typeof args[0] === 'string') {
74
+ return { name: args[0], data: args[1], rebuild: (d) => { const a = args.slice(); a[1] = d; return a } }
75
+ }
76
+ if (args[0] && typeof args[0] === 'object') {
77
+ const req = args[0]
78
+ return { name: req.name, data: req.data, rebuild: (d) => { const a = args.slice(); a[0] = Object.assign({}, req, { data: d }); return a } }
79
+ }
80
+ return null
81
+ }
82
+
83
+ function wrapBossSend (orig) {
84
+ return function send () {
85
+ const args = Array.prototype.slice.call(arguments)
86
+ if (!c.msgTracer() || nestedIn(PGBOSS)) return orig.apply(this, args)
87
+ const s = sendArgs(args)
88
+ if (!s || internalQueue(s.name)) return orig.apply(this, args)
89
+ return produce(PGBOSS, s.name, {}, orig, this, (span) => s.rebuild(carry(s.data, span)), (id) => (typeof id === 'string' ? id : undefined), args).result
90
+ }
91
+ }
92
+
93
+ function wrapBossPublish (orig) {
94
+ return function publish (event, data) {
95
+ if (!c.msgTracer() || nestedIn(PGBOSS)) return orig.apply(this, arguments)
96
+ const args = Array.prototype.slice.call(arguments)
97
+ return produce(PGBOSS, event, {}, orig, this, (span) => { const a = args.slice(); a[1] = carry(data, span); return a }, undefined, args).result
98
+ }
99
+ }
100
+
101
+ function wrapBossInsert (orig) {
102
+ return function insert () {
103
+ const args = Array.prototype.slice.call(arguments)
104
+ if (!c.msgTracer() || nestedIn(PGBOSS)) return orig.apply(this, args)
105
+ // 9.x/10.x: insert(jobs); 11+: insert(name, jobs, options)
106
+ const named = typeof args[0] === 'string'
107
+ const jobs = named ? args[1] : args[0]
108
+ if (!Array.isArray(jobs)) return orig.apply(this, args)
109
+ const names = new Set(named ? [args[0]] : jobs.map((j) => j && j.name))
110
+ const tags = {}
111
+ if (jobs.length > 1) tags['messaging.batch.message_count'] = String(jobs.length)
112
+ return produce(PGBOSS, names.size === 1 ? Array.from(names)[0] : undefined, tags, orig, this, (span) => {
113
+ const copy = jobs.map((j) => (j && typeof j === 'object' ? Object.assign({}, j, { data: carry(j.data, span) }) : j))
114
+ const a = args.slice()
115
+ a[named ? 1 : 0] = copy
116
+ return a
117
+ }, undefined, args).result
118
+ }
119
+ }
120
+
121
+ function jobTags (job) {
122
+ const tags = {}
123
+ if (job && job.id !== undefined) tags['messaging.message.id'] = String(job.id)
124
+ const rc = job && (job.retryCount !== undefined ? job.retryCount : job.retrycount)
125
+ if (typeof rc === 'number') tags['messaging.pmx.attempt'] = String(rc + 1)
126
+ return tags
127
+ }
128
+
129
+ function wrapBossHandler (queue, handler) {
130
+ const w = function (arg) {
131
+ if (!c.msgTracer()) {
132
+ if (Array.isArray(arg)) arg.forEach((j) => take(j && j.data))
133
+ else take(arg && arg.data)
134
+ return handler.apply(this, arguments)
135
+ }
136
+ let span
137
+ if (Array.isArray(arg) && arg.length !== 1) {
138
+ const ctxs = arg.map((j) => take(j && j.data))
139
+ const tags = {}
140
+ if (arg.length > 1) tags['messaging.batch.message_count'] = String(arg.length)
141
+ span = c.batchConsumer(PGBOSS, queue, ctxs, tags, 'process')
142
+ } else {
143
+ const job = Array.isArray(arg) ? arg[0] : arg
144
+ span = c.consumer(PGBOSS, queue, take(job && job.data), jobTags(job))
145
+ }
146
+ return c.runConsumer(span, handler, this, arguments)
147
+ }
148
+ return c.copyMeta(w, handler)
149
+ }
150
+
151
+ const internalQueue = (name) => typeof name === 'string' && name.startsWith('__pgboss__')
152
+
153
+ function wrapBossWork (orig) {
154
+ return function work (name) {
155
+ const args = Array.prototype.slice.call(arguments)
156
+ const i = args.length - 1
157
+ if (!c.tracer() || i < 1 || typeof args[i] !== 'function' || internalQueue(name)) return orig.apply(this, args)
158
+ args[i] = wrapBossHandler(typeof name === 'string' ? name : (name && name.name), args[i])
159
+ // the worker's own polling (fetch) runs in this context: marked, it makes no receive spans
160
+ const ctx = require('../tracing/context')
161
+ const store = ctx.current()
162
+ return ctx.run({ span: store && store.span, bag: store ? store.bag : [], server: store && store.server, itg: PGBOSS }, orig, this, args)
163
+ }
164
+ }
165
+
166
+ function wrapBossFetch (orig) {
167
+ return function fetch (name) {
168
+ if (!c.msgTracer() || nestedIn(PGBOSS) || internalQueue(name)) return orig.apply(this, arguments)
169
+ const span = c.batchConsumer(PGBOSS, typeof name === 'string' ? name : undefined, null, {}, 'receive')
170
+ let r
171
+ try {
172
+ r = orig.apply(this, arguments)
173
+ } catch (err) {
174
+ c.end(span, err)
175
+ throw err
176
+ }
177
+ if (!c.isThenable(r)) return r
178
+ return r.then((res) => {
179
+ try {
180
+ const jobs = Array.isArray(res) ? res : (res ? [res] : [])
181
+ for (const j of jobs) c.addLink(span, take(j && j.data))
182
+ if (jobs.length >= 2) span.setAttribute('messaging.batch.message_count', String(jobs.length))
183
+ if (jobs.length > 0) c.end(span)
184
+ } catch (_) {}
185
+ return res
186
+ }, (err) => {
187
+ c.end(span, err)
188
+ throw err
189
+ })
190
+ }
191
+ }
192
+
193
+ /** pg-boss manager (9.x/10.x `src/manager.js` CommonJS; 11+ `dist/manager.js` ES module). */
194
+ function patchBoss (exports, info) {
195
+ const Manager = info && info.esm ? exports.default : (exports && (exports.default || exports))
196
+ const proto = Manager && Manager.prototype
197
+ if (!proto || typeof proto.send !== 'function' || typeof proto.work !== 'function') {
198
+ c.disabled('pg-boss', 'Manager.send/work not found')
199
+ return
200
+ }
201
+ for (const m of ['send', 'sendAfter', 'sendThrottled', 'sendDebounced']) {
202
+ if (typeof proto[m] === 'function') c.wrap(proto, m, wrapBossSend)
203
+ }
204
+ if (typeof proto.publish === 'function') c.wrap(proto, 'publish', wrapBossPublish)
205
+ if (typeof proto.insert === 'function') c.wrap(proto, 'insert', wrapBossInsert)
206
+ c.wrap(proto, 'work', wrapBossWork)
207
+ if (typeof proto.fetch === 'function') c.wrap(proto, 'fetch', wrapBossFetch)
208
+ }
209
+
210
+ // -- graphile-worker --------------------------------------------------------------------------
211
+
212
+ const GRAPHILE = 'graphile-worker'
213
+
214
+ function wrapAddJob (orig) {
215
+ if (typeof orig !== 'function' || orig[c.WRAPPED]) return orig
216
+ const w = function addJob (identifier, payload, spec) {
217
+ if (!c.msgTracer()) return orig.apply(this, arguments)
218
+ const tags = {}
219
+ if (spec && spec.queueName) tags['messaging.graphile_worker.queue_name'] = String(spec.queueName)
220
+ const args = Array.prototype.slice.call(arguments)
221
+ return produce(GRAPHILE, identifier, tags, orig, this, (span) => { const a = args.slice(); a[1] = carry(payload, span); return a }, (job) => job && job.id, args).result
222
+ }
223
+ return c.copyMeta(w, orig)
224
+ }
225
+
226
+ function wrapTask (identifier, task) {
227
+ const w = function (payload, helpers) {
228
+ const job = helpers && helpers.job
229
+ if (!c.msgTracer()) {
230
+ take(payload)
231
+ return task.apply(this, arguments)
232
+ }
233
+ const ctx = take(payload)
234
+ const tags = {}
235
+ if (job && job.id !== undefined) tags['messaging.message.id'] = String(job.id)
236
+ if (job && typeof job.attempts === 'number') tags['messaging.pmx.attempt'] = String(job.attempts)
237
+ if (job && job.queue_name) tags['messaging.graphile_worker.queue_name'] = String(job.queue_name)
238
+ const span = c.consumer(GRAPHILE, identifier, ctx, tags)
239
+ return c.runConsumer(span, task, this, arguments)
240
+ }
241
+ return c.copyMeta(w, task)
242
+ }
243
+
244
+ const taskCache = new WeakMap()
245
+
246
+ function tasksProxy (tasks) {
247
+ if (!tasks || typeof tasks !== 'object') return tasks
248
+ return new Proxy(tasks, {
249
+ get (target, key, receiver) {
250
+ const v = Reflect.get(target, key, receiver)
251
+ if (typeof v !== 'function' || typeof key !== 'string') return v
252
+ let w = taskCache.get(v)
253
+ if (!w) {
254
+ w = wrapTask(key, v)
255
+ taskCache.set(v, w)
256
+ }
257
+ return w
258
+ }
259
+ })
260
+ }
261
+
262
+ /** helpers.js: makeAddJob(compiledSharedOptions, withPgClient) returns addJob. */
263
+ function patchHelpers (exports) {
264
+ const make = exports && exports.makeAddJob
265
+ if (typeof make !== 'function') {
266
+ c.disabled('graphile-worker', 'makeAddJob not found')
267
+ return
268
+ }
269
+ const w = c.copyMeta(function makeAddJob () {
270
+ return wrapAddJob(make.apply(this, arguments))
271
+ }, make)
272
+ return replace(exports, 'makeAddJob', w)
273
+ }
274
+
275
+ /** worker.js: makeNewWorker(workerShared, params) with params.tasks. */
276
+ function patchWorker (exports) {
277
+ const make = exports && exports.makeNewWorker
278
+ if (typeof make !== 'function') {
279
+ c.disabled('graphile-worker', 'makeNewWorker not found')
280
+ return
281
+ }
282
+ const w = c.copyMeta(function makeNewWorker (shared, params) {
283
+ if (!params || typeof params !== 'object' || !params.tasks || !c.tracer()) return make.apply(this, arguments)
284
+ const args = Array.prototype.slice.call(arguments)
285
+ args[1] = Object.assign({}, params, { tasks: tasksProxy(params.tasks) })
286
+ return make.apply(this, args)
287
+ }, make)
288
+ return replace(exports, 'makeNewWorker', w)
289
+ }
290
+
291
+ function replace (exports, name, value) {
292
+ const d = Object.getOwnPropertyDescriptor(exports, name)
293
+ if (d && d.writable) {
294
+ exports[name] = value
295
+ return
296
+ }
297
+ if (d && d.configurable) {
298
+ Object.defineProperty(exports, name, { value, writable: true, enumerable: d.enumerable, configurable: true })
299
+ return
300
+ }
301
+ // a getter-only (non-configurable) binding: return a copy with the replaced export
302
+ return require('../integrations').replaceExport(exports, name, value)
303
+ }
304
+
305
+ module.exports = { patchBoss, patchHelpers, patchWorker, carry, take }
@@ -0,0 +1,252 @@
1
+ // Copyright (c) 2026 Mike Warriner. All rights reserved. Proprietary — see LICENSE.
2
+ 'use strict'
3
+
4
+ // postgres.js (82 §5.4, ITG-115–118). Every way a postgres.js query runs — awaiting it (`then`,
5
+ // `catch`, `finally`), `execute()`, `forEach()`, `cursor()` iteration, `describe()`, `simple()`,
6
+ // `values()`, `raw()`, `sql.unsafe`, `sql.file`, transactions and reserved connections — goes
7
+ // through `Query.prototype.handle`, called once when execution starts. Wrapping that one method
8
+ // (instead of the `sql` function) keeps every query object lazy and every property of `sql`
9
+ // untouched: a query object that is never awaited never calls it and creates no span. The span
10
+ // ends when the query's `resolve`/`reject` runs (also when postgres.js replaces them for cursor
11
+ // iteration). The BEGIN/COMMIT/ROLLBACK/SAVEPOINT statements that `sql.begin` issues itself make no
12
+ // span (ITG-117: the transaction has no span of its own); queries inside it do.
13
+
14
+ const c = require('./common')
15
+ const sql = require('./sql')
16
+ const dbc = require('./dbcomment')
17
+
18
+ const SPAN = Symbol('pmx-pgjs-span')
19
+ const PREFIX = Symbol('pmx-pgjs-comment')
20
+ const TX_OPS = new Set(['BEGIN', 'COMMIT', 'ROLLBACK', 'SAVEPOINT'])
21
+
22
+ function optionTags (options) {
23
+ const tags = { 'db.system': 'postgresql' }
24
+ if (!options || typeof options !== 'object') return tags
25
+ if (options.database) tags['db.name'] = String(options.database)
26
+ if (options.user) tags['db.user'] = String(options.user)
27
+ const host = Array.isArray(options.host) ? options.host[0] : options.host
28
+ const port = Array.isArray(options.port) ? options.port[0] : options.port
29
+ if (options.path) {
30
+ tags['net.peer.name'] = String(options.path)
31
+ } else {
32
+ if (host) tags['net.peer.name'] = String(host)
33
+ if (port) tags['net.peer.port'] = String(port)
34
+ }
35
+ return tags
36
+ }
37
+
38
+ function templateText (q) {
39
+ const strings = q.strings
40
+ if (!Array.isArray(strings)) return ''
41
+ let s = String(strings[0] === undefined ? '' : strings[0])
42
+ for (let i = 1; i < strings.length; i++) s += '$' + i + strings[i]
43
+ return s
44
+ }
45
+
46
+ /** Keep `prop` of `q` wrapped by `make(current)` even when postgres.js assigns a new value. */
47
+ function intercept (q, prop, make) {
48
+ let current = q[prop]
49
+ let wrapped = typeof current === 'function' ? make(current) : current
50
+ Object.defineProperty(q, prop, {
51
+ configurable: true,
52
+ enumerable: Object.prototype.propertyIsEnumerable.call(q, prop),
53
+ get () {
54
+ return wrapped
55
+ },
56
+ set (v) {
57
+ current = v
58
+ wrapped = typeof v === 'function' ? make(v) : v
59
+ }
60
+ })
61
+ }
62
+
63
+ function instrument (q, span, t) {
64
+ let delivered = 0
65
+ let streaming = false
66
+ const finish = (err, result) => {
67
+ if (span.ended) return
68
+ try {
69
+ let st = q.statement && typeof q.statement.string === 'string' ? q.statement.string : null
70
+ // the trace comment is never part of db.statement (96 SVM-504)
71
+ const prefix = q[PREFIX]
72
+ if (st !== null && prefix && st.startsWith(prefix)) st = st.slice(prefix.length)
73
+ if (st !== null) {
74
+ const tag = sql.statementTag(st, t.db.statement, false)
75
+ if (tag !== undefined) span.setAttribute('db.statement', tag)
76
+ if (!span.attributes['db.operation']) {
77
+ // sql.file(): the text was read after execution started
78
+ const op = sql.operation(st)
79
+ if (op) {
80
+ span.setAttribute('db.operation', op)
81
+ const db = span.attributes['db.name']
82
+ span.updateName(db ? op + ' ' + db : op)
83
+ }
84
+ }
85
+ }
86
+ if (!err) {
87
+ if (streaming) span.setAttribute('db.rows', String(delivered))
88
+ else if (result && typeof result.count === 'number') span.setAttribute('db.rows', String(result.count))
89
+ }
90
+ } catch (_) {}
91
+ c.end(span, err, err && typeof err.code === 'string' ? err.code : undefined)
92
+ }
93
+ const onResolve = (fn) => function (x) {
94
+ finish(undefined, x)
95
+ return fn.apply(this, arguments)
96
+ }
97
+ const onReject = (fn) => function (err) {
98
+ finish(err || new Error('query failed'))
99
+ return fn.apply(this, arguments)
100
+ }
101
+ const count = (fn) => function (v) {
102
+ delivered += Array.isArray(v) ? v.length : 1
103
+ return fn.apply(this, arguments)
104
+ }
105
+ if (q.cursorRows || typeof q.cursorFn === 'function') {
106
+ // cursor iteration assigns new resolve/reject/cursorFn at every next(): keep them wrapped
107
+ streaming = true
108
+ intercept(q, 'resolve', onResolve)
109
+ intercept(q, 'reject', onReject)
110
+ intercept(q, 'cursorFn', count)
111
+ return
112
+ }
113
+ // every other path: the functions present now are the ones postgres.js calls (cheaper)
114
+ if (typeof q.resolve === 'function') q.resolve = onResolve(q.resolve)
115
+ if (typeof q.reject === 'function') q.reject = onReject(q.reject)
116
+ if (typeof q.forEachFn === 'function') {
117
+ streaming = true
118
+ q.forEachFn = count(q.forEachFn)
119
+ }
120
+ }
121
+
122
+ /**
123
+ * 96 SVM-501/502: prepend the trace comment to the query's first string. postgres.js prepares
124
+ * (and caches by text) every non-simple query unless `prepare: false` (instance or query option):
125
+ * those are skipped with `on`; with `force` the query is sent unprepared.
126
+ */
127
+ function comment (q, t, span, text) {
128
+ try {
129
+ const strings = q.strings
130
+ if (!Array.isArray(strings) || typeof strings[0] !== 'string') return
131
+ const qo = q.options && typeof q.options === 'object' ? q.options : {}
132
+ const io = optionsOf(q) || {}
133
+ const prepared = !qo.simple && io.prepare !== false && !('prepare' in qo && !qo.prepare)
134
+ if (!dbc.wants(t, span, text, prepared)) return
135
+ const prefix = dbc.sqlPrefix(t, span)
136
+ const next = Array.prototype.slice.call(strings)
137
+ next[0] = prefix + next[0]
138
+ q.strings = next
139
+ q[PREFIX] = prefix
140
+ if (prepared) q.options = Object.assign({}, qo, { prepare: false })
141
+ } catch (_) {}
142
+ }
143
+
144
+ function wrapHandle (orig) {
145
+ return function handle () {
146
+ if (this.executed || this[SPAN] !== undefined) return orig.apply(this, arguments)
147
+ const t = c.dbTracer()
148
+ if (t && !c.nested()) {
149
+ try {
150
+ const text = templateText(this)
151
+ const op = sql.operation(text)
152
+ const isTx = TX_OPS.has(op) || (op === 'PREPARE' && /^\s*prepare\s+transaction\b/i.test(text))
153
+ if (!isTx) {
154
+ const base = optionTags(optionsOf(this))
155
+ const tags = Object.assign({}, base)
156
+ if (op) tags['db.operation'] = op
157
+ const st = sql.statementTag(text, t.db.statement, false)
158
+ if (st !== undefined) tags['db.statement'] = st
159
+ const name = op ? (base['db.name'] ? op + ' ' + base['db.name'] : op) : (base['db.name'] || 'postgresql')
160
+ const span = c.clientSpan(t, name, tags)
161
+ this[SPAN] = span
162
+ if (span) {
163
+ instrument(this, span, t)
164
+ comment(this, t, span, text)
165
+ }
166
+ }
167
+ } catch (_) {}
168
+ }
169
+ return orig.apply(this, arguments)
170
+ }
171
+ }
172
+
173
+ // The instance options (database, user, host, port) are not reachable from a query object, only
174
+ // its `handler` is. The wrapped factory learns the handler of each instance by creating (never
175
+ // executing) one query object, and maps it to the instance's options; queries of transactions and
176
+ // reserved connections have their own handlers and use the options of the instance created last.
177
+ const OPTIONS = new WeakMap()
178
+ let lastOptions = null
179
+
180
+ function remember (sqlFn) {
181
+ if (typeof sqlFn !== 'function' || !sqlFn.options) return
182
+ lastOptions = sqlFn.options
183
+ const probe = sqlFn`select 1`
184
+ if (probe && typeof probe.handler === 'function') OPTIONS.set(probe.handler, sqlFn.options)
185
+ }
186
+
187
+ function optionsOf (q) {
188
+ return (q.handler && OPTIONS.get(q.handler)) || lastOptions
189
+ }
190
+
191
+ /**
192
+ * 96 SVM-505: `connection.application_name` = the pmx app name unless the app set one (options,
193
+ * URL query or PGAPPNAME); postgres.js's own default ('postgres.js') counts as not set.
194
+ */
195
+ function withAppName (argsIn) {
196
+ const t = c.dbTracer()
197
+ const name = t && dbc.connectionAppName(t)
198
+ if (!name || process.env.PGAPPNAME) return argsIn
199
+ const args = Array.prototype.slice.call(argsIn)
200
+ const url = typeof args[0] === 'string' ? args[0] : ''
201
+ if (/[?&]application_name=/i.test(url)) return argsIn
202
+ const i = url || args[0] === undefined ? 1 : 0
203
+ const opts = args[i]
204
+ if (opts !== undefined && (opts === null || typeof opts !== 'object')) return argsIn
205
+ const conn = opts && opts.connection
206
+ if (conn && typeof conn === 'object' && conn.application_name) return argsIn
207
+ args[i] = Object.assign({}, opts || {}, { connection: Object.assign({}, conn || {}, { application_name: name }) })
208
+ return args
209
+ }
210
+
211
+ function wrapFactory (Postgres) {
212
+ if (typeof Postgres !== 'function' || Postgres[c.WRAPPED]) return Postgres
213
+ const wrapped = function postgres () {
214
+ let args = arguments
215
+ try {
216
+ args = withAppName(arguments)
217
+ } catch (_) {}
218
+ const sqlFn = Postgres.apply(this, args)
219
+ try {
220
+ remember(sqlFn)
221
+ } catch (_) {}
222
+ return sqlFn
223
+ }
224
+ return c.copyMeta(wrapped, Postgres)
225
+ }
226
+
227
+ /** Patch query.js (CommonJS `cjs/src/query.js`, ESM `src/query.js`): Query.prototype.handle. */
228
+ function patchQuery (exports) {
229
+ const Query = exports && exports.Query
230
+ if (!Query || !Query.prototype || typeof Query.prototype.handle !== 'function') {
231
+ c.disabled('postgres', 'Query.prototype.handle not found')
232
+ return
233
+ }
234
+ c.wrap(Query.prototype, 'handle', wrapHandle)
235
+ }
236
+
237
+ /** Wrap the default export (the factory) so instance options can be found for tags. */
238
+ function patchIndex (exports, info) {
239
+ const fn = info && info.esm ? exports.default : exports
240
+ if (typeof fn !== 'function') {
241
+ c.disabled('postgres', 'default export is not a function')
242
+ return
243
+ }
244
+ const w = wrapFactory(fn)
245
+ if (info && info.esm) {
246
+ exports.default = w
247
+ return
248
+ }
249
+ return w
250
+ }
251
+
252
+ module.exports = { patchQuery, patchIndex, optionTags, templateText }