@rootcat/node 0.0.0-stage → 0.2.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.
- package/CHANGELOG.md +83 -0
- package/LICENSE +202 -0
- package/README.md +294 -2
- package/dist/attach.d.ts +1 -0
- package/dist/attach.js +24 -0
- package/dist/attach.js.map +1 -0
- package/dist/callsite.d.ts +109 -0
- package/dist/callsite.js +565 -0
- package/dist/callsite.js.map +1 -0
- package/dist/coexist.d.ts +183 -0
- package/dist/coexist.js +587 -0
- package/dist/coexist.js.map +1 -0
- package/dist/config.d.ts +75 -0
- package/dist/config.js +182 -0
- package/dist/config.js.map +1 -0
- package/dist/drizzle.d.ts +21 -0
- package/dist/drizzle.js +127 -0
- package/dist/drizzle.js.map +1 -0
- package/dist/esm.mjs +57 -0
- package/dist/esmhook.d.ts +52 -0
- package/dist/esmhook.js +158 -0
- package/dist/esmhook.js.map +1 -0
- package/dist/iitm-hook.mjs +83 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +52 -0
- package/dist/index.js.map +1 -0
- package/dist/intake.d.ts +40 -0
- package/dist/intake.js +164 -0
- package/dist/intake.js.map +1 -0
- package/dist/keys.d.ts +20 -0
- package/dist/keys.js +33 -0
- package/dist/keys.js.map +1 -0
- package/dist/notices.d.ts +2 -0
- package/dist/notices.js +21 -0
- package/dist/notices.js.map +1 -0
- package/dist/otlp.d.ts +75 -0
- package/dist/otlp.js +449 -0
- package/dist/otlp.js.map +1 -0
- package/dist/pg.d.ts +16 -0
- package/dist/pg.js +170 -0
- package/dist/pg.js.map +1 -0
- package/dist/pgpool.d.ts +20 -0
- package/dist/pgpool.js +99 -0
- package/dist/pgpool.js.map +1 -0
- package/dist/postgresjs.d.ts +60 -0
- package/dist/postgresjs.js +400 -0
- package/dist/postgresjs.js.map +1 -0
- package/dist/privacy.d.ts +38 -0
- package/dist/privacy.js +161 -0
- package/dist/privacy.js.map +1 -0
- package/dist/processor.d.ts +197 -0
- package/dist/processor.js +494 -0
- package/dist/processor.js.map +1 -0
- package/dist/register.d.ts +1 -0
- package/dist/register.js +12 -0
- package/dist/register.js.map +1 -0
- package/dist/sampler.d.ts +30 -0
- package/dist/sampler.js +101 -0
- package/dist/sampler.js.map +1 -0
- package/dist/sdk.d.ts +129 -0
- package/dist/sdk.js +606 -0
- package/dist/sdk.js.map +1 -0
- package/package.json +72 -4
package/dist/pg.js
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PgInstrumentation = void 0;
|
|
4
|
+
// pg (node-postgres): one span per query, nothing else. The upstream
|
|
5
|
+
// instrumentation starts a span for every pool acquire beside the query,
|
|
6
|
+
// another per connection, records metrics and a dozen attributes, and
|
|
7
|
+
// costs about three times what the query span itself does (see the
|
|
8
|
+
// benchmark); the agent counts operations and keeps error events, so
|
|
9
|
+
// one client span with the statement, the database and the server is
|
|
10
|
+
// what it needs. Client.prototype.query is patched (pool.query goes
|
|
11
|
+
// through it); a submittable (a cursor or a stream) passes through
|
|
12
|
+
// untraced; parameter values are never read.
|
|
13
|
+
const api_1 = require("@opentelemetry/api");
|
|
14
|
+
const instrumentation_1 = require("@opentelemetry/instrumentation");
|
|
15
|
+
const callsite_js_1 = require("./callsite.js");
|
|
16
|
+
const keys_js_1 = require("./keys.js");
|
|
17
|
+
const privacy_js_1 = require("./privacy.js");
|
|
18
|
+
const processor_js_1 = require("./processor.js");
|
|
19
|
+
const maxStatementBytes = 4096;
|
|
20
|
+
const supportedVersions = ['>=8.0.0 <9'];
|
|
21
|
+
class PgInstrumentation extends instrumentation_1.InstrumentationBase {
|
|
22
|
+
constructor(options) {
|
|
23
|
+
super('@rootcat/node/pg', '0.2.0', options);
|
|
24
|
+
}
|
|
25
|
+
init() {
|
|
26
|
+
return new instrumentation_1.InstrumentationNodeModuleDefinition('pg', supportedVersions, (moduleExports) => {
|
|
27
|
+
const proto = clientPrototype(moduleExports);
|
|
28
|
+
if (proto) {
|
|
29
|
+
if ((0, instrumentation_1.isWrapped)(proto.query) && (0, keys_js_1.mine)(proto.query)) {
|
|
30
|
+
this._unwrap(proto, 'query');
|
|
31
|
+
}
|
|
32
|
+
const before = proto.query;
|
|
33
|
+
this._wrap(proto, 'query', this.wrapQuery);
|
|
34
|
+
if (proto.query !== before) {
|
|
35
|
+
(0, keys_js_1.marked)(proto.query); // not when a guard kept another SDK's wrapper
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return moduleExports;
|
|
39
|
+
}, (moduleExports) => {
|
|
40
|
+
const proto = clientPrototype(moduleExports);
|
|
41
|
+
if (proto && (0, instrumentation_1.isWrapped)(proto.query) && (0, keys_js_1.mine)(proto.query)) {
|
|
42
|
+
this._unwrap(proto, 'query');
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
wrapQuery = (original) => {
|
|
47
|
+
const instrumentation = this;
|
|
48
|
+
return function query(...args) {
|
|
49
|
+
const [config, values, callback] = args;
|
|
50
|
+
if (config && typeof config.submit === 'function') {
|
|
51
|
+
return original.apply(this, args); // a cursor or a stream: not a query with an end
|
|
52
|
+
}
|
|
53
|
+
const outer = api_1.context.active();
|
|
54
|
+
let span;
|
|
55
|
+
let parent = outer;
|
|
56
|
+
try {
|
|
57
|
+
const options = instrumentation.getConfig();
|
|
58
|
+
parent = options.sampling.carry(() => (0, callsite_js_1.captureCallSite)(options.depth, options.isApp, query)) ?? outer;
|
|
59
|
+
if ((0, processor_js_1.unsampled)(parent)) {
|
|
60
|
+
return original.apply(this, args); // not recorded: nothing to start or carry
|
|
61
|
+
}
|
|
62
|
+
span = instrumentation.startQuerySpan(this, config, parent);
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
span = undefined;
|
|
66
|
+
}
|
|
67
|
+
if (!span) {
|
|
68
|
+
return original.apply(this, args);
|
|
69
|
+
}
|
|
70
|
+
const end = instrumentation.endQuerySpan.bind(instrumentation, span);
|
|
71
|
+
// The callback may be the second or third argument, or on the config.
|
|
72
|
+
// It continues in the caller's context, not the query's.
|
|
73
|
+
let callArgs = args;
|
|
74
|
+
const userCallback = typeof values === 'function' ? values : typeof callback === 'function' ? callback : config?.callback;
|
|
75
|
+
if (typeof userCallback === 'function') {
|
|
76
|
+
const wrapped = api_1.context.bind(outer, function (error, result) {
|
|
77
|
+
end(error);
|
|
78
|
+
return userCallback.call(this, error, result);
|
|
79
|
+
});
|
|
80
|
+
if (typeof values === 'function') {
|
|
81
|
+
callArgs = [config, wrapped];
|
|
82
|
+
}
|
|
83
|
+
else if (typeof callback === 'function') {
|
|
84
|
+
callArgs = [config, values, wrapped];
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
// A config may be a class instance whose text or values are
|
|
88
|
+
// getters on its prototype: the callback goes on an object that
|
|
89
|
+
// inherits from it, not on a copy of its own fields.
|
|
90
|
+
const withCallback = Object.create(config);
|
|
91
|
+
withCallback.callback = wrapped;
|
|
92
|
+
callArgs = [withCallback, values, callback];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const active = api_1.trace.setSpan(parent, span);
|
|
96
|
+
let result;
|
|
97
|
+
try {
|
|
98
|
+
result = api_1.context.with(active, () => original.apply(this, callArgs));
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
end(error);
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
if (typeof userCallback !== 'function') {
|
|
105
|
+
if (result && typeof result.then === 'function') {
|
|
106
|
+
result.then(() => end(undefined), (error) => end(error ?? new Error('query failed')));
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
end(undefined);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return result;
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
startQuerySpan(client, config, parent) {
|
|
116
|
+
const text = typeof config === 'string' ? config : typeof config?.text === 'string' ? config.text : '';
|
|
117
|
+
const keyword = (0, privacy_js_1.statementKeyword)(text);
|
|
118
|
+
const attributes = { 'db.system.name': 'postgresql' };
|
|
119
|
+
if (keyword !== '') {
|
|
120
|
+
attributes['db.operation.name'] = keyword;
|
|
121
|
+
}
|
|
122
|
+
if (text !== '') {
|
|
123
|
+
// Literals are masked (or the text reduced to its keyword) by the
|
|
124
|
+
// processor's statement rule as the span starts.
|
|
125
|
+
attributes['db.query.text'] = text.slice(0, maxStatementBytes);
|
|
126
|
+
}
|
|
127
|
+
if (typeof client.database === 'string') {
|
|
128
|
+
attributes['db.namespace'] = client.database;
|
|
129
|
+
}
|
|
130
|
+
if (typeof client.host === 'string') {
|
|
131
|
+
attributes['server.address'] = client.host;
|
|
132
|
+
}
|
|
133
|
+
if (typeof client.port === 'number') {
|
|
134
|
+
attributes['server.port'] = client.port;
|
|
135
|
+
}
|
|
136
|
+
return this.tracer.startSpan(keyword === '' ? 'pg.query' : `pg.query:${keyword}`, { kind: api_1.SpanKind.CLIENT, attributes }, parent);
|
|
137
|
+
}
|
|
138
|
+
endQuerySpan(span, error) {
|
|
139
|
+
try {
|
|
140
|
+
if (error !== undefined && error !== null) {
|
|
141
|
+
// The server's message can quote the input that failed; only the
|
|
142
|
+
// error's class and SQLSTATE travel.
|
|
143
|
+
const e = error;
|
|
144
|
+
const generic = typeof e.name !== 'string' || e.name === '' || e.name === 'Error' || e.name === 'error';
|
|
145
|
+
const name = (generic ? e.constructor?.name : e.name) || 'Error';
|
|
146
|
+
const code = typeof e.code === 'string' ? e.code.slice(0, 16) : '';
|
|
147
|
+
const message = code === '' ? `${name} from pg` : `${name} from pg (code: ${code})`;
|
|
148
|
+
span.setStatus({ code: api_1.SpanStatusCode.ERROR, message });
|
|
149
|
+
span.addEvent('exception', { 'exception.type': name.slice(0, 64), 'exception.message': message });
|
|
150
|
+
span.setAttribute('error.type', name.slice(0, 64));
|
|
151
|
+
if (code !== '') {
|
|
152
|
+
span.setAttribute('db.response.status_code', code);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// the span still ends
|
|
158
|
+
}
|
|
159
|
+
finally {
|
|
160
|
+
span.end();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
exports.PgInstrumentation = PgInstrumentation;
|
|
165
|
+
function clientPrototype(moduleExports) {
|
|
166
|
+
const mod = moduleExports;
|
|
167
|
+
const proto = mod?.Client?.prototype;
|
|
168
|
+
return proto && typeof proto.query === 'function' ? proto : undefined;
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=pg.js.map
|
package/dist/pg.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pg.js","sourceRoot":"","sources":["../src/pg.ts"],"names":[],"mappings":"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"}
|
package/dist/pgpool.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
* connect false leaves Pool.prototype.connect alone: inside a tracing
|
|
10
|
+
* Sentry, whose pg instrumentation spans the pool's connect under the
|
|
11
|
+
* caller's span (and drops it without one), the root context the
|
|
12
|
+
* package runs connect in would change Sentry's spans.
|
|
13
|
+
*/
|
|
14
|
+
connect?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare class PgPoolEntryInstrumentation extends InstrumentationBase<PgPoolEntryOptions> {
|
|
17
|
+
constructor(options: PgPoolEntryOptions);
|
|
18
|
+
protected init(): InstrumentationNodeModuleDefinition;
|
|
19
|
+
private readonly wrapQuery;
|
|
20
|
+
}
|
package/dist/pgpool.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
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 keys_js_1 = require("./keys.js");
|
|
18
|
+
const processor_js_1 = require("./processor.js");
|
|
19
|
+
function poolPrototype(moduleExports) {
|
|
20
|
+
const proto = moduleExports?.prototype;
|
|
21
|
+
return proto && typeof proto.query === 'function' && typeof proto.connect === 'function' ? proto : undefined;
|
|
22
|
+
}
|
|
23
|
+
class PgPoolEntryInstrumentation extends instrumentation_1.InstrumentationBase {
|
|
24
|
+
constructor(options) {
|
|
25
|
+
super('@rootcat/node/pg-pool-entry', '0.2.0', options);
|
|
26
|
+
}
|
|
27
|
+
init() {
|
|
28
|
+
return new instrumentation_1.InstrumentationNodeModuleDefinition('pg-pool', ['>=2.0.0 <4'], (moduleExports) => {
|
|
29
|
+
const proto = poolPrototype(moduleExports);
|
|
30
|
+
if (proto) {
|
|
31
|
+
for (const name of ['query', 'connect']) {
|
|
32
|
+
if ((0, instrumentation_1.isWrapped)(proto[name]) && (0, keys_js_1.mine)(proto[name])) {
|
|
33
|
+
this._unwrap(proto, name);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const beforeQuery = proto.query;
|
|
37
|
+
this._wrap(proto, 'query', this.wrapQuery);
|
|
38
|
+
if (proto.query !== beforeQuery) {
|
|
39
|
+
(0, keys_js_1.marked)(proto.query); // not when a guard kept another SDK's wrapper
|
|
40
|
+
}
|
|
41
|
+
if (this.getConfig().connect !== false) {
|
|
42
|
+
const beforeConnect = proto.connect;
|
|
43
|
+
this._wrap(proto, 'connect', wrapConnect);
|
|
44
|
+
if (proto.connect !== beforeConnect) {
|
|
45
|
+
(0, keys_js_1.marked)(proto.connect);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return moduleExports;
|
|
50
|
+
}, (moduleExports) => {
|
|
51
|
+
const proto = poolPrototype(moduleExports);
|
|
52
|
+
if (proto) {
|
|
53
|
+
for (const name of ['query', 'connect']) {
|
|
54
|
+
if ((0, instrumentation_1.isWrapped)(proto[name]) && (0, keys_js_1.mine)(proto[name])) {
|
|
55
|
+
this._unwrap(proto, name);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
wrapQuery = (original) => {
|
|
62
|
+
const instrumentation = this;
|
|
63
|
+
return function query(...args) {
|
|
64
|
+
let carried;
|
|
65
|
+
try {
|
|
66
|
+
// A callback continues in the caller's context, never in the
|
|
67
|
+
// query's: a query issued from it captures its own site.
|
|
68
|
+
const last = args.length - 1;
|
|
69
|
+
if (last >= 0 && typeof args[last] === 'function') {
|
|
70
|
+
args[last] = api_1.context.bind(api_1.context.active(), args[last]);
|
|
71
|
+
}
|
|
72
|
+
const config = instrumentation.getConfig();
|
|
73
|
+
carried = config.sampling.carry(() => (0, callsite_js_1.captureCallSite)(config.depth, config.isApp, query));
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
carried = undefined;
|
|
77
|
+
}
|
|
78
|
+
return (0, processor_js_1.runCarried)(carried, () => original.apply(this, args));
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
exports.PgPoolEntryInstrumentation = PgPoolEntryInstrumentation;
|
|
83
|
+
/**
|
|
84
|
+
* wrapConnect binds a connect callback to the context of the call, and
|
|
85
|
+
* runs the pool's own work (opening a client and its socket) in the root
|
|
86
|
+
* context: a connection outlives the query that opened it, and the events
|
|
87
|
+
* it emits later (a LISTEN notification, an error) must not run in that
|
|
88
|
+
* query's context, with its span and call site.
|
|
89
|
+
*/
|
|
90
|
+
function wrapConnect(original) {
|
|
91
|
+
return function connect(...args) {
|
|
92
|
+
const callback = args[0];
|
|
93
|
+
if (typeof callback === 'function') {
|
|
94
|
+
args[0] = api_1.context.bind(api_1.context.active(), callback);
|
|
95
|
+
}
|
|
96
|
+
return api_1.context.with(api_1.ROOT_CONTEXT, () => original.apply(this, args));
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
//# 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,60 @@
|
|
|
1
|
+
import { InstrumentationBase, type InstrumentationConfig, InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation';
|
|
2
|
+
import { type CallSiteLocation } from './callsite.js';
|
|
3
|
+
import { type CallSiteSampling } from './processor.js';
|
|
4
|
+
/** PostgresJsOptions configures the instrumentation. */
|
|
5
|
+
export interface PostgresJsOptions extends InstrumentationConfig {
|
|
6
|
+
/** sampling gates the origin parsing, like any capture. */
|
|
7
|
+
sampling: CallSiteSampling;
|
|
8
|
+
/**
|
|
9
|
+
* spans false starts no span: another SDK (Sentry, tracing on) has
|
|
10
|
+
* already started one for the query when handle() runs, and onSite is
|
|
11
|
+
* handed the query's origin to give that span its call site.
|
|
12
|
+
*/
|
|
13
|
+
spans?: boolean;
|
|
14
|
+
/** onSite receives a query's call site when spans is false. */
|
|
15
|
+
onSite?: (site: CallSiteLocation) => void;
|
|
16
|
+
}
|
|
17
|
+
export declare class PostgresJsInstrumentation extends InstrumentationBase<PostgresJsOptions> {
|
|
18
|
+
private readonly patched;
|
|
19
|
+
/** origins remembers the parsed call site per template, null for none. */
|
|
20
|
+
private readonly origins;
|
|
21
|
+
/** recording maps a sql function to its site-recording proxy (spans false). */
|
|
22
|
+
private readonly recording;
|
|
23
|
+
/** templateSites remembers the captured call site per template (spans false). */
|
|
24
|
+
private readonly templateSites;
|
|
25
|
+
/** querySites holds the call site captured for a query until it is handled (spans false). */
|
|
26
|
+
private readonly querySites;
|
|
27
|
+
constructor(options: PostgresJsOptions);
|
|
28
|
+
protected init(): InstrumentationNodeModuleDefinition;
|
|
29
|
+
/**
|
|
30
|
+
* patchModule wraps the factory. CommonJS exports the function itself
|
|
31
|
+
* (the wrapper is returned in its place); an ES module namespace has it
|
|
32
|
+
* as default (replaced in place).
|
|
33
|
+
*/
|
|
34
|
+
private patchModule;
|
|
35
|
+
private unpatchModule;
|
|
36
|
+
private wrapFactory;
|
|
37
|
+
/**
|
|
38
|
+
* siteRecording is the sql function as the application gets it when
|
|
39
|
+
* another SDK (Sentry) spans the queries: the driver's own origin then
|
|
40
|
+
* cannot name the application, as it keeps four frames and Sentry's
|
|
41
|
+
* wrapper of the sql function takes the last one. The call site is
|
|
42
|
+
* captured here instead, where the application calls: once per tagged
|
|
43
|
+
* template (a template is one place in the source, as the driver's own
|
|
44
|
+
* origin cache assumes), and per unsafe() call unless an outer layer
|
|
45
|
+
* (Drizzle) already carries one; queries inside sql.begin() get the
|
|
46
|
+
* same treatment through the transaction's sql function.
|
|
47
|
+
*/
|
|
48
|
+
private siteRecording;
|
|
49
|
+
/** patchQueryClass finds Query.prototype through an unexecuted query. */
|
|
50
|
+
private patchQueryClass;
|
|
51
|
+
private readonly wrapHandle;
|
|
52
|
+
/**
|
|
53
|
+
* originSite is the application frame of the driver's own origin stack
|
|
54
|
+
* for a tagged query, parsed once per template; undefined for unsafe()
|
|
55
|
+
* and file() queries, which hold no origin.
|
|
56
|
+
*/
|
|
57
|
+
private originSite;
|
|
58
|
+
private startQuerySpan;
|
|
59
|
+
private endQuerySpan;
|
|
60
|
+
}
|