@rootcat/node 0.0.0-stage → 0.1.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 (55) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +213 -2
  3. package/dist/callsite.d.ts +109 -0
  4. package/dist/callsite.js +565 -0
  5. package/dist/callsite.js.map +1 -0
  6. package/dist/config.d.ts +75 -0
  7. package/dist/config.js +182 -0
  8. package/dist/config.js.map +1 -0
  9. package/dist/drizzle.d.ts +21 -0
  10. package/dist/drizzle.js +124 -0
  11. package/dist/drizzle.js.map +1 -0
  12. package/dist/esm.mjs +41 -0
  13. package/dist/esmhook.d.ts +12 -0
  14. package/dist/esmhook.js +84 -0
  15. package/dist/esmhook.js.map +1 -0
  16. package/dist/index.d.ts +12 -0
  17. package/dist/index.js +50 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/intake.d.ts +40 -0
  20. package/dist/intake.js +164 -0
  21. package/dist/intake.js.map +1 -0
  22. package/dist/keys.d.ts +9 -0
  23. package/dist/keys.js +15 -0
  24. package/dist/keys.js.map +1 -0
  25. package/dist/notices.d.ts +2 -0
  26. package/dist/notices.js +21 -0
  27. package/dist/notices.js.map +1 -0
  28. package/dist/otlp.d.ts +75 -0
  29. package/dist/otlp.js +449 -0
  30. package/dist/otlp.js.map +1 -0
  31. package/dist/pg.d.ts +16 -0
  32. package/dist/pg.js +165 -0
  33. package/dist/pg.js.map +1 -0
  34. package/dist/pgpool.d.ts +13 -0
  35. package/dist/pgpool.js +85 -0
  36. package/dist/pgpool.js.map +1 -0
  37. package/dist/postgresjs.d.ts +33 -0
  38. package/dist/postgresjs.js +272 -0
  39. package/dist/postgresjs.js.map +1 -0
  40. package/dist/privacy.d.ts +38 -0
  41. package/dist/privacy.js +147 -0
  42. package/dist/privacy.js.map +1 -0
  43. package/dist/processor.d.ts +94 -0
  44. package/dist/processor.js +252 -0
  45. package/dist/processor.js.map +1 -0
  46. package/dist/register.d.ts +1 -0
  47. package/dist/register.js +12 -0
  48. package/dist/register.js.map +1 -0
  49. package/dist/sampler.d.ts +12 -0
  50. package/dist/sampler.js +52 -0
  51. package/dist/sampler.js.map +1 -0
  52. package/dist/sdk.d.ts +88 -0
  53. package/dist/sdk.js +305 -0
  54. package/dist/sdk.js.map +1 -0
  55. package/package.json +65 -4
@@ -0,0 +1,13 @@
1
+ import { InstrumentationBase, type InstrumentationConfig, InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation';
2
+ import { type CallSiteSampling } from './processor.js';
3
+ /** PgPoolEntryOptions bounds and gates the capture. */
4
+ export interface PgPoolEntryOptions extends InstrumentationConfig {
5
+ depth: number;
6
+ sampling: CallSiteSampling;
7
+ isApp?: (file: string) => boolean;
8
+ }
9
+ export declare class PgPoolEntryInstrumentation extends InstrumentationBase<PgPoolEntryOptions> {
10
+ constructor(options: PgPoolEntryOptions);
11
+ protected init(): InstrumentationNodeModuleDefinition;
12
+ private readonly wrapQuery;
13
+ }
package/dist/pgpool.js ADDED
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PgPoolEntryInstrumentation = void 0;
4
+ // pg-pool entry. Pool.prototype.query hands the query to a client on a
5
+ // later tick, so the pg query span's stack never shows the caller: this
6
+ // wrapper captures the call site where the application calls pool.query
7
+ // and carries it in the active context to the span that starts later.
8
+ //
9
+ // Pool.prototype.connect queues its callback when every client is busy
10
+ // and runs it from the release of another client, in that client's
11
+ // query's context. Its callback is bound to the context of the connect
12
+ // call, so a queued query keeps its own call site and its own parent
13
+ // instead of borrowing the query that freed the client.
14
+ const api_1 = require("@opentelemetry/api");
15
+ const instrumentation_1 = require("@opentelemetry/instrumentation");
16
+ const callsite_js_1 = require("./callsite.js");
17
+ const processor_js_1 = require("./processor.js");
18
+ function poolPrototype(moduleExports) {
19
+ const proto = moduleExports?.prototype;
20
+ return proto && typeof proto.query === 'function' && typeof proto.connect === 'function' ? proto : undefined;
21
+ }
22
+ class PgPoolEntryInstrumentation extends instrumentation_1.InstrumentationBase {
23
+ constructor(options) {
24
+ super('@rootcat/node/pg-pool-entry', '0.1.0', options);
25
+ }
26
+ init() {
27
+ return new instrumentation_1.InstrumentationNodeModuleDefinition('pg-pool', ['>=2.0.0 <4'], (moduleExports) => {
28
+ const proto = poolPrototype(moduleExports);
29
+ if (proto) {
30
+ for (const name of ['query', 'connect']) {
31
+ if ((0, instrumentation_1.isWrapped)(proto[name])) {
32
+ this._unwrap(proto, name);
33
+ }
34
+ }
35
+ this._wrap(proto, 'query', this.wrapQuery);
36
+ this._wrap(proto, 'connect', wrapConnect);
37
+ }
38
+ return moduleExports;
39
+ }, (moduleExports) => {
40
+ const proto = poolPrototype(moduleExports);
41
+ if (proto) {
42
+ this._unwrap(proto, 'query');
43
+ this._unwrap(proto, 'connect');
44
+ }
45
+ });
46
+ }
47
+ wrapQuery = (original) => {
48
+ const instrumentation = this;
49
+ return function query(...args) {
50
+ let carried;
51
+ try {
52
+ // A callback continues in the caller's context, never in the
53
+ // query's: a query issued from it captures its own site.
54
+ const last = args.length - 1;
55
+ if (last >= 0 && typeof args[last] === 'function') {
56
+ args[last] = api_1.context.bind(api_1.context.active(), args[last]);
57
+ }
58
+ const config = instrumentation.getConfig();
59
+ carried = config.sampling.carry(() => (0, callsite_js_1.captureCallSite)(config.depth, config.isApp, query));
60
+ }
61
+ catch {
62
+ carried = undefined;
63
+ }
64
+ return (0, processor_js_1.runCarried)(carried, () => original.apply(this, args));
65
+ };
66
+ };
67
+ }
68
+ exports.PgPoolEntryInstrumentation = PgPoolEntryInstrumentation;
69
+ /**
70
+ * wrapConnect binds a connect callback to the context of the call, and
71
+ * runs the pool's own work (opening a client and its socket) in the root
72
+ * context: a connection outlives the query that opened it, and the events
73
+ * it emits later (a LISTEN notification, an error) must not run in that
74
+ * query's context, with its span and call site.
75
+ */
76
+ function wrapConnect(original) {
77
+ return function connect(...args) {
78
+ const callback = args[0];
79
+ if (typeof callback === 'function') {
80
+ args[0] = api_1.context.bind(api_1.context.active(), callback);
81
+ }
82
+ return api_1.context.with(api_1.ROOT_CONTEXT, () => original.apply(this, args));
83
+ };
84
+ }
85
+ //# sourceMappingURL=pgpool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pgpool.js","sourceRoot":"","sources":["../src/pgpool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { InstrumentationBase, type InstrumentationConfig, InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation';
2
+ import { type CallSiteSampling } from './processor.js';
3
+ /** PostgresJsOptions configures the instrumentation. */
4
+ export interface PostgresJsOptions extends InstrumentationConfig {
5
+ /** sampling gates the origin parsing, like any capture. */
6
+ sampling: CallSiteSampling;
7
+ }
8
+ export declare class PostgresJsInstrumentation extends InstrumentationBase<PostgresJsOptions> {
9
+ private readonly patched;
10
+ /** origins remembers the parsed call site per template, null for none. */
11
+ private readonly origins;
12
+ constructor(options: PostgresJsOptions);
13
+ protected init(): InstrumentationNodeModuleDefinition;
14
+ /**
15
+ * patchModule wraps the factory. CommonJS exports the function itself
16
+ * (the wrapper is returned in its place); an ES module namespace has it
17
+ * as default (replaced in place).
18
+ */
19
+ private patchModule;
20
+ private unpatchModule;
21
+ private wrapFactory;
22
+ /** patchQueryClass finds Query.prototype through an unexecuted query. */
23
+ private patchQueryClass;
24
+ private readonly wrapHandle;
25
+ /**
26
+ * originSite is the application frame of the driver's own origin stack
27
+ * for a tagged query, parsed once per template; undefined for unsafe()
28
+ * and file() queries, which hold no origin.
29
+ */
30
+ private originSite;
31
+ private startQuerySpan;
32
+ private endQuerySpan;
33
+ }
@@ -0,0 +1,272 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PostgresJsInstrumentation = void 0;
4
+ // postgres.js (the `postgres` package) has no upstream instrumentation.
5
+ // Its Query is a lazy promise: nothing runs until .then, .execute or
6
+ // .forEach calls handle(). An awaited Query is a Promise subclass, so the
7
+ // await calls then() from a job of its own, where no application frame
8
+ // is on the stack. The driver itself keeps a short stack per tagged
9
+ // template (query.origin, four frames, cached per template), which is
10
+ // where the span's call site comes from: parsed once per template.
11
+ // The span starts in handle() on the first execution and ends when the
12
+ // query resolves or rejects. The statement text is what the driver built
13
+ // (query.statement.string, with $1 placeholders); the span never touches
14
+ // query.args.
15
+ //
16
+ // The Query class is internal to the module, so the module's default
17
+ // export (the postgres() factory) is wrapped: the first sql function it
18
+ // returns yields the class through an unexecuted query, and handle() is
19
+ // patched on that prototype once. The same wrapper serves the CommonJS
20
+ // and the ES module builds.
21
+ const api_1 = require("@opentelemetry/api");
22
+ const instrumentation_1 = require("@opentelemetry/instrumentation");
23
+ const callsite_js_1 = require("./callsite.js");
24
+ const privacy_js_1 = require("./privacy.js");
25
+ const processor_js_1 = require("./processor.js");
26
+ /** Bounds. */
27
+ const maxStatementBytes = 4096;
28
+ const supportedVersions = ['>=3.0.0 <4'];
29
+ const rootcatSpan = Symbol('rootcat.span');
30
+ const rootcatWrapped = Symbol('rootcat.wrapped');
31
+ const rootcatOptions = Symbol('rootcat.options');
32
+ /** probe is a template that is never executed; it only yields the class. */
33
+ const probe = Object.freeze(Object.assign(['select 1'], { raw: Object.freeze(['select 1']) }));
34
+ class PostgresJsInstrumentation extends instrumentation_1.InstrumentationBase {
35
+ patched = new WeakSet();
36
+ /** origins remembers the parsed call site per template, null for none. */
37
+ origins = new WeakMap();
38
+ constructor(options) {
39
+ super('@rootcat/node/postgres-js', '0.1.0', options);
40
+ }
41
+ init() {
42
+ return new instrumentation_1.InstrumentationNodeModuleDefinition('postgres', supportedVersions, (moduleExports) => this.patchModule(moduleExports), (moduleExports) => this.unpatchModule(moduleExports));
43
+ }
44
+ /**
45
+ * patchModule wraps the factory. CommonJS exports the function itself
46
+ * (the wrapper is returned in its place); an ES module namespace has it
47
+ * as default (replaced in place).
48
+ */
49
+ patchModule(moduleExports) {
50
+ const ns = moduleExports;
51
+ if (typeof ns === 'function') {
52
+ return this.wrapFactory(ns);
53
+ }
54
+ if (ns && typeof ns.default === 'function') {
55
+ try {
56
+ ns.default = this.wrapFactory(ns.default);
57
+ }
58
+ catch {
59
+ // a frozen namespace: no postgres.js spans
60
+ }
61
+ }
62
+ return moduleExports;
63
+ }
64
+ unpatchModule(moduleExports) {
65
+ const ns = moduleExports;
66
+ const wrapped = typeof ns === 'function' ? ns : ns?.default;
67
+ const original = wrapped?.[rootcatWrapped];
68
+ if (original && typeof ns !== 'function' && ns) {
69
+ ns.default = original;
70
+ }
71
+ }
72
+ wrapFactory(original) {
73
+ const marked = original;
74
+ if (marked[rootcatWrapped]) {
75
+ return original;
76
+ }
77
+ const instrumentation = this;
78
+ const wrapper = function postgres(...args) {
79
+ const sql = original.apply(this, args);
80
+ try {
81
+ instrumentation.patchQueryClass(sql);
82
+ }
83
+ catch {
84
+ // the driver works untraced
85
+ }
86
+ return sql;
87
+ };
88
+ Object.assign(wrapper, original);
89
+ Object.setPrototypeOf(wrapper, Object.getPrototypeOf(original));
90
+ wrapper[rootcatWrapped] = original;
91
+ return wrapper;
92
+ }
93
+ /** patchQueryClass finds Query.prototype through an unexecuted query. */
94
+ patchQueryClass(sql) {
95
+ if (typeof sql !== 'function') {
96
+ return;
97
+ }
98
+ const query = sql(probe);
99
+ if (!query || typeof query !== 'object') {
100
+ return;
101
+ }
102
+ const proto = Object.getPrototypeOf(query);
103
+ if (!proto || typeof proto.handle !== 'function') {
104
+ return;
105
+ }
106
+ // The connection options live on the sql function; the queries of
107
+ // this instance reach them through their handler.
108
+ if (typeof query.handler === 'function' && sql.options && typeof sql.options === 'object') {
109
+ query.handler[rootcatOptions] = sql.options;
110
+ }
111
+ if (this.patched.has(proto)) {
112
+ return;
113
+ }
114
+ this.patched.add(proto);
115
+ if ((0, instrumentation_1.isWrapped)(proto.handle)) {
116
+ this._unwrap(proto, 'handle');
117
+ }
118
+ this._wrap(proto, 'handle', this.wrapHandle);
119
+ }
120
+ wrapHandle = (original) => {
121
+ const instrumentation = this;
122
+ return function handle(...args) {
123
+ if (this.executed || this[rootcatSpan]) {
124
+ return original.apply(this, args);
125
+ }
126
+ let span;
127
+ try {
128
+ span = instrumentation.startQuerySpan(this);
129
+ }
130
+ catch {
131
+ span = undefined;
132
+ }
133
+ if (!span) {
134
+ return original.apply(this, args);
135
+ }
136
+ this[rootcatSpan] = span;
137
+ const resolve = this.resolve;
138
+ const reject = this.reject;
139
+ const query = this;
140
+ if (typeof resolve === 'function') {
141
+ this.resolve = function (value) {
142
+ instrumentation.endQuerySpan(query, span, undefined);
143
+ return resolve.call(this, value);
144
+ };
145
+ }
146
+ if (typeof reject === 'function') {
147
+ this.reject = function (reason) {
148
+ instrumentation.endQuerySpan(query, span, reason);
149
+ return reject.call(this, reason);
150
+ };
151
+ }
152
+ return original.apply(this, args);
153
+ };
154
+ };
155
+ /**
156
+ * originSite is the application frame of the driver's own origin stack
157
+ * for a tagged query, parsed once per template; undefined for unsafe()
158
+ * and file() queries, which hold no origin.
159
+ */
160
+ originSite(query) {
161
+ const strings = query.strings;
162
+ if (!query.tagged || !strings || typeof strings !== 'object') {
163
+ return undefined;
164
+ }
165
+ const known = this.origins.get(strings);
166
+ if (known !== undefined) {
167
+ return known ?? undefined;
168
+ }
169
+ let site;
170
+ try {
171
+ const origin = query.origin;
172
+ site = typeof origin === 'string' ? (0, callsite_js_1.parseStack)(origin) : undefined;
173
+ }
174
+ catch {
175
+ site = undefined;
176
+ }
177
+ this.origins.set(strings, site ?? null);
178
+ return site;
179
+ }
180
+ startQuerySpan(query) {
181
+ // The template's own origin (free: parsed once per template) wins over
182
+ // a site carried from outside, as a query written in the continuation
183
+ // of another is its own; unsafe() queries keep what an ORM carried.
184
+ const ctx = this.getConfig().sampling.carry(() => this.originSite(query), true) ?? api_1.context.active();
185
+ if ((0, processor_js_1.unsampled)(ctx)) {
186
+ return undefined; // not recorded: the query runs untouched
187
+ }
188
+ const options = query.handler?.[rootcatOptions];
189
+ const keyword = (0, privacy_js_1.statementKeyword)(leadingText(query));
190
+ const attributes = { 'db.system.name': 'postgresql' };
191
+ if (keyword !== '') {
192
+ attributes['db.operation.name'] = keyword;
193
+ }
194
+ if (options) {
195
+ if (typeof options.database === 'string') {
196
+ attributes['db.namespace'] = options.database;
197
+ }
198
+ const host = Array.isArray(options.host) ? options.host[0] : options.host;
199
+ if (typeof host === 'string') {
200
+ attributes['server.address'] = host;
201
+ }
202
+ const port = Array.isArray(options.port) ? options.port[0] : options.port;
203
+ if (typeof port === 'number') {
204
+ attributes['server.port'] = port;
205
+ }
206
+ }
207
+ const name = keyword === '' ? 'postgres.query' : `postgres.query:${keyword}`;
208
+ return this.tracer.startSpan(name, { kind: api_1.SpanKind.CLIENT, attributes }, ctx);
209
+ }
210
+ endQuerySpan(query, span, reason) {
211
+ try {
212
+ // Literals are masked (or the text reduced to its keyword) by the
213
+ // processor's statement rule as the span ends.
214
+ const statement = finalStatement(query);
215
+ if (statement !== '') {
216
+ span.setAttribute('db.query.text', statement);
217
+ }
218
+ if (reason !== undefined) {
219
+ // The server's message can quote the input that failed ("invalid
220
+ // input syntax for type integer: ..."), so, as the pg
221
+ // instrumentation does, only the error's class and SQLSTATE travel.
222
+ const error = reason;
223
+ const name = typeof error?.name === 'string' ? error.name.slice(0, 64) : 'Error';
224
+ const code = typeof error?.code === 'string' ? error.code.slice(0, 16) : '';
225
+ const message = code === '' ? `${name} from postgres.js` : `${name} from postgres.js (code: ${code})`;
226
+ span.setStatus({ code: api_1.SpanStatusCode.ERROR, message });
227
+ span.addEvent('exception', { 'exception.type': name, 'exception.message': message });
228
+ span.setAttribute('error.type', name);
229
+ if (code !== '') {
230
+ span.setAttribute('db.response.status_code', code);
231
+ }
232
+ }
233
+ }
234
+ catch {
235
+ // the span still ends
236
+ }
237
+ finally {
238
+ span.end();
239
+ delete query[rootcatSpan];
240
+ }
241
+ }
242
+ }
243
+ exports.PostgresJsInstrumentation = PostgresJsInstrumentation;
244
+ /** leadingText is the first template part, before any parameter. */
245
+ function leadingText(query) {
246
+ const strings = query.strings;
247
+ if (Array.isArray(strings) && typeof strings[0] === 'string') {
248
+ return strings[0].slice(0, 256);
249
+ }
250
+ return '';
251
+ }
252
+ /**
253
+ * finalStatement is the statement the driver sent: query.statement.string
254
+ * once built, else the template joined with placeholders for a query the
255
+ * driver answered without building (an error before the build).
256
+ */
257
+ function finalStatement(query) {
258
+ const built = query.statement?.string;
259
+ if (typeof built === 'string') {
260
+ return built.slice(0, maxStatementBytes);
261
+ }
262
+ const strings = query.strings;
263
+ if (Array.isArray(strings) && strings.every((part) => typeof part === 'string')) {
264
+ let text = strings[0] ?? '';
265
+ for (let i = 1; i < strings.length; i++) {
266
+ text += '$' + i + strings[i];
267
+ }
268
+ return text.slice(0, maxStatementBytes);
269
+ }
270
+ return '';
271
+ }
272
+ //# sourceMappingURL=postgresjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgresjs.js","sourceRoot":"","sources":["../src/postgresjs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import type { Attributes } from '@opentelemetry/api';
2
+ /** StatementMode is what query text keeps: its shape with literals masked, or its first keyword. */
3
+ export type StatementMode = 'masked' | 'off';
4
+ /** urlKeys hold a URL or path whose query, fragment and opaque segments are cut. */
5
+ export declare const urlKeys: readonly ["http.url", "url.full", "http.target", "url.path"];
6
+ /** clearedKeys hold a query string, a client's address or a user agent; they are emptied. */
7
+ export declare const clearedKeys: readonly ["url.query", "http.client_ip", "client.address", "net.peer.ip", "net.sock.peer.addr", "network.peer.address", "user_agent.original", "http.user_agent"];
8
+ /** maxStatementLength bounds the text the masker reads. */
9
+ export declare const maxStatementLength = 4096;
10
+ /** statementKeys hold query text. */
11
+ export declare const statementKeys: readonly ["db.statement", "db.query.text"];
12
+ /**
13
+ * framesOnly keeps the frame lines of a stack trace (" at ...") and
14
+ * drops the message line(s) before them, which can quote input.
15
+ */
16
+ export declare function framesOnly(stack: string): string;
17
+ /** stripQuery cuts a URL at its query or fragment. */
18
+ export declare function stripQuery(url: string): string;
19
+ /**
20
+ * maskPath cuts the query and fragment and replaces every segment that
21
+ * could hold an identifier or a token (numbers, UUIDs, JWTs, reset
22
+ * tokens, emails, file names) with {id}; the scheme and host of a full
23
+ * URL are kept.
24
+ */
25
+ export declare function maskPath(url: string): string;
26
+ /** statementKeyword keeps the first word of a statement, upper-cased. */
27
+ export declare function statementKeyword(statement: string): string;
28
+ /**
29
+ * maskLiterals replaces every literal in a SQL statement with ?, keeps
30
+ * identifiers, keywords and placeholders, and drops comments (which
31
+ * sqlcommenter fills with values).
32
+ */
33
+ export declare function maskLiterals(statement: string): string;
34
+ /**
35
+ * scrubbed returns the attribute changes privacy requires for the given
36
+ * attributes, or undefined when nothing needs changing.
37
+ */
38
+ export declare function scrubbed(attributes: Attributes, statement: StatementMode): Attributes | undefined;
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.statementKeys = exports.maxStatementLength = exports.clearedKeys = exports.urlKeys = void 0;
4
+ exports.framesOnly = framesOnly;
5
+ exports.stripQuery = stripQuery;
6
+ exports.maskPath = maskPath;
7
+ exports.statementKeyword = statementKeyword;
8
+ exports.maskLiterals = maskLiterals;
9
+ exports.scrubbed = scrubbed;
10
+ /** urlKeys hold a URL or path whose query, fragment and opaque segments are cut. */
11
+ exports.urlKeys = ['http.url', 'url.full', 'http.target', 'url.path'];
12
+ /** clearedKeys hold a query string, a client's address or a user agent; they are emptied. */
13
+ exports.clearedKeys = [
14
+ 'url.query',
15
+ 'http.client_ip',
16
+ 'client.address',
17
+ 'net.peer.ip',
18
+ 'net.sock.peer.addr',
19
+ 'network.peer.address',
20
+ 'user_agent.original',
21
+ 'http.user_agent',
22
+ ];
23
+ /** maxStatementLength bounds the text the masker reads. */
24
+ exports.maxStatementLength = 4096;
25
+ /** statementKeys hold query text. */
26
+ exports.statementKeys = ['db.statement', 'db.query.text'];
27
+ /**
28
+ * framesOnly keeps the frame lines of a stack trace (" at ...") and
29
+ * drops the message line(s) before them, which can quote input.
30
+ */
31
+ function framesOnly(stack) {
32
+ const lines = stack.split('\n');
33
+ const first = lines.findIndex((line) => /^\s+at\s/.test(line));
34
+ if (first <= 0) {
35
+ return first === 0 ? stack : '';
36
+ }
37
+ return lines.slice(first).join('\n');
38
+ }
39
+ /** stripQuery cuts a URL at its query or fragment. */
40
+ function stripQuery(url) {
41
+ const cut = url.search(/[?#]/);
42
+ return cut < 0 ? url : url.slice(0, cut);
43
+ }
44
+ /**
45
+ * keptSegment reports whether a path segment can hold no secret: a name
46
+ * of letters, hyphens and underscores up to 32 bytes that is not a
47
+ * mixed-case run of twelve or more (a base62 token without digits), or a
48
+ * version (v1, api2). The agent's request capture keeps the same.
49
+ */
50
+ function keptSegment(segment) {
51
+ if (/^[A-Za-z]{1,4}\d{1,3}$/.test(segment)) {
52
+ return true;
53
+ }
54
+ if (!/^[A-Za-z_-]{1,32}$/.test(segment)) {
55
+ return false;
56
+ }
57
+ return !(segment.length >= 12 && /[a-z]/.test(segment) && /[A-Z]/.test(segment));
58
+ }
59
+ /**
60
+ * maskPath cuts the query and fragment and replaces every segment that
61
+ * could hold an identifier or a token (numbers, UUIDs, JWTs, reset
62
+ * tokens, emails, file names) with {id}; the scheme and host of a full
63
+ * URL are kept.
64
+ */
65
+ function maskPath(url) {
66
+ const bare = stripQuery(url);
67
+ const origin = /^[a-z][a-z0-9+.-]*:\/\/[^/]*/i.exec(bare);
68
+ const prefix = origin ? origin[0] : '';
69
+ const rest = bare.slice(prefix.length);
70
+ const masked = rest
71
+ .split('/')
72
+ .map((segment) => (segment === '' || keptSegment(segment) ? segment : '{id}'))
73
+ .join('/');
74
+ return prefix + masked;
75
+ }
76
+ /** statementKeyword keeps the first word of a statement, upper-cased. */
77
+ function statementKeyword(statement) {
78
+ const match = /^\s*(?:\/\*.*?\*\/\s*)*([A-Za-z]+)/.exec(statement);
79
+ return match ? match[1].toUpperCase() : '';
80
+ }
81
+ // One pass over the text: quoted identifiers are kept, comments dropped,
82
+ // string, dollar-quoted and numeric literals masked. $1-style
83
+ // placeholders are kept (a dollar quote's tag cannot start with a digit,
84
+ // and a number right after $ is not a literal).
85
+ // A string or dollar quote left open (a statement cut at its bound) is
86
+ // masked to the end.
87
+ // An E'' string's E must start a word (in LIKE'%x%' the E ends a keyword).
88
+ // Numbers: decimal with or without digits on either side of the point
89
+ // (1, 1.5, 1., .5), with an exponent, or hexadecimal (0xDEAD).
90
+ const sqlTokens = /("(?:[^"]|"")*"|`(?:[^`]|``)*`)|(--[^\n]*|\/\*[\s\S]*?\*\/)|((?<!\w)[Ee]'(?:[^'\\]|\\.|'')*'|'(?:[^']|'')*'|\$([A-Za-z_][A-Za-z0-9_]*)?\$[\s\S]*?\$\4\$|(?<!\w)[Ee]'[\s\S]*$|'[\s\S]*$|\$(?:[A-Za-z_][A-Za-z0-9_]*)?\$[\s\S]*$)|((?<![\w$.])(?:0[xX][0-9a-fA-F]+|(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?)(?![\w.]))/g;
91
+ /**
92
+ * maskLiterals replaces every literal in a SQL statement with ?, keeps
93
+ * identifiers, keywords and placeholders, and drops comments (which
94
+ * sqlcommenter fills with values).
95
+ */
96
+ function maskLiterals(statement) {
97
+ return statement
98
+ .replace(sqlTokens, (_match, identifier, comment) => {
99
+ if (identifier !== undefined) {
100
+ return identifier;
101
+ }
102
+ if (comment !== undefined) {
103
+ return '';
104
+ }
105
+ return '?';
106
+ })
107
+ .trim();
108
+ }
109
+ /**
110
+ * scrubbed returns the attribute changes privacy requires for the given
111
+ * attributes, or undefined when nothing needs changing.
112
+ */
113
+ function scrubbed(attributes, statement) {
114
+ let changes;
115
+ const set = (key, value) => {
116
+ (changes ??= {})[key] = value;
117
+ };
118
+ for (const key of exports.urlKeys) {
119
+ const value = attributes[key];
120
+ if (typeof value === 'string' && value !== '') {
121
+ const masked = maskPath(value);
122
+ if (masked !== value) {
123
+ set(key, masked);
124
+ }
125
+ }
126
+ }
127
+ for (const key of exports.clearedKeys) {
128
+ const value = attributes[key];
129
+ if (typeof value === 'string' && value !== '') {
130
+ set(key, '');
131
+ }
132
+ }
133
+ for (const key of exports.statementKeys) {
134
+ const value = attributes[key];
135
+ if (typeof value === 'string' && value !== '') {
136
+ // The span limits bound attribute values; the masker never runs over
137
+ // more than that, whatever set the attribute.
138
+ const bounded = value.length > exports.maxStatementLength ? value.slice(0, exports.maxStatementLength) : value;
139
+ const kept = statement === 'off' ? statementKeyword(bounded) : maskLiterals(bounded);
140
+ if (kept !== value) {
141
+ set(key, kept);
142
+ }
143
+ }
144
+ }
145
+ return changes;
146
+ }
147
+ //# sourceMappingURL=privacy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"privacy.js","sourceRoot":"","sources":["../src/privacy.ts"],"names":[],"mappings":"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"}