@glasstrace/sdk 1.1.3 → 1.2.1
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/README.md +54 -1
- package/dist/{chunk-6RNBUUBR.js → chunk-2GCN27SI.js} +2 -2
- package/dist/{chunk-4EZ6JTDG.js → chunk-47B2G3FE.js} +2 -2
- package/dist/{chunk-FGDS33I2.js → chunk-CTJO7PUZ.js} +71 -17
- package/dist/chunk-CTJO7PUZ.js.map +1 -0
- package/dist/{chunk-X5MAXP5T.js → chunk-EBYISKQP.js} +5 -3
- package/dist/{chunk-X5MAXP5T.js.map → chunk-EBYISKQP.js.map} +1 -1
- package/dist/{chunk-JKI4OCFV.js → chunk-HV5ID2WJ.js} +3 -3
- package/dist/{chunk-TWTWRJ25.js → chunk-MD5XPCTQ.js} +2 -2
- package/dist/{chunk-TWHCJKRS.js → chunk-NFPDYME5.js} +3 -3
- package/dist/{chunk-DST4UBXU.js → chunk-YMLMZCPR.js} +2 -2
- package/dist/cli/init.cjs +5 -3
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.js +6 -6
- package/dist/cli/mcp-add.cjs +4 -2
- package/dist/cli/mcp-add.cjs.map +1 -1
- package/dist/cli/mcp-add.js +2 -2
- package/dist/cli/uninit.js +3 -3
- package/dist/cli/validate.cjs +4 -2
- package/dist/cli/validate.cjs.map +1 -1
- package/dist/cli/validate.js +2 -2
- package/dist/edge-entry.cjs +4 -2
- package/dist/edge-entry.cjs.map +1 -1
- package/dist/edge-entry.js +2 -2
- package/dist/index.cjs +70 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +5 -5
- package/dist/node-entry.cjs +70 -14
- package/dist/node-entry.cjs.map +1 -1
- package/dist/node-entry.js +7 -7
- package/dist/node-subpath.cjs +4 -2
- package/dist/node-subpath.cjs.map +1 -1
- package/dist/node-subpath.js +3 -3
- package/dist/{source-map-uploader-DPUUCLNW.js → source-map-uploader-RA4Z7TWA.js} +3 -3
- package/dist/trpc/index.cjs +809 -0
- package/dist/trpc/index.cjs.map +1 -0
- package/dist/trpc/index.d.cts +165 -0
- package/dist/trpc/index.d.ts +165 -0
- package/dist/trpc/index.js +65 -0
- package/dist/trpc/index.js.map +1 -0
- package/package.json +12 -1
- package/dist/chunk-FGDS33I2.js.map +0 -1
- /package/dist/{chunk-6RNBUUBR.js.map → chunk-2GCN27SI.js.map} +0 -0
- /package/dist/{chunk-4EZ6JTDG.js.map → chunk-47B2G3FE.js.map} +0 -0
- /package/dist/{chunk-JKI4OCFV.js.map → chunk-HV5ID2WJ.js.map} +0 -0
- /package/dist/{chunk-TWTWRJ25.js.map → chunk-MD5XPCTQ.js.map} +0 -0
- /package/dist/{chunk-TWHCJKRS.js.map → chunk-NFPDYME5.js.map} +0 -0
- /package/dist/{chunk-DST4UBXU.js.map → chunk-YMLMZCPR.js.map} +0 -0
- /package/dist/{source-map-uploader-DPUUCLNW.js.map → source-map-uploader-RA4Z7TWA.js.map} +0 -0
package/README.md
CHANGED
|
@@ -280,7 +280,7 @@ file directly and no longer needs the runtime handler.
|
|
|
280
280
|
|
|
281
281
|
## Subpath exports
|
|
282
282
|
|
|
283
|
-
`@glasstrace/sdk` ships
|
|
283
|
+
`@glasstrace/sdk` ships four public entries:
|
|
284
284
|
|
|
285
285
|
- **`@glasstrace/sdk`** — primary import site. Use from
|
|
286
286
|
`instrumentation.ts` (runtime instrumentation) and `next.config.ts`
|
|
@@ -298,6 +298,8 @@ file directly and no longer needs the runtime handler.
|
|
|
298
298
|
condition; non-Node runtimes (workerd, edge-light) fail cleanly at
|
|
299
299
|
module resolution rather than at evaluation.
|
|
300
300
|
- **`@glasstrace/sdk/drizzle`** — Drizzle ORM adapter.
|
|
301
|
+
- **`@glasstrace/sdk/trpc`** — tRPC middleware-chain instrumentation.
|
|
302
|
+
See "tRPC middleware instrumentation" below.
|
|
301
303
|
|
|
302
304
|
The source-map and import-graph helpers previously reachable from the
|
|
303
305
|
`@glasstrace/sdk` root specifier have moved to `@glasstrace/sdk/node`
|
|
@@ -383,6 +385,57 @@ on the Node-only side to become edge-safe, the right move is to remove
|
|
|
383
385
|
the `process` and Node built-in reaches from the symbol's transitive
|
|
384
386
|
closure, not to add a runtime guard.
|
|
385
387
|
|
|
388
|
+
## tRPC middleware instrumentation
|
|
389
|
+
|
|
390
|
+
The `@glasstrace/sdk/trpc` subpath exposes `tracedMiddleware`, a thin
|
|
391
|
+
wrapper that turns a user-supplied tRPC middleware function into a
|
|
392
|
+
span-emitting middleware function. Each invocation opens a child span
|
|
393
|
+
named `options.name` under the active OTel context (typically the HTTP
|
|
394
|
+
server span), so middleware steps land as children of the HTTP span
|
|
395
|
+
without manual context plumbing. Errors thrown from the middleware
|
|
396
|
+
body are recorded via `span.recordException` and propagate unchanged;
|
|
397
|
+
short-circuit `{ ok: false, error }` results mark the span `ERROR`
|
|
398
|
+
without recording an exception.
|
|
399
|
+
|
|
400
|
+
`@trpc/server` is declared as an optional peer dependency
|
|
401
|
+
(`^10.0.0 || ^11.0.0`); projects that do not use tRPC pay no runtime
|
|
402
|
+
cost because the subpath is excluded from the root barrel and is
|
|
403
|
+
tree-shakeable.
|
|
404
|
+
|
|
405
|
+
```ts
|
|
406
|
+
// trpc.ts — your project
|
|
407
|
+
import { initTRPC, TRPCError } from "@trpc/server";
|
|
408
|
+
import { tracedMiddleware } from "@glasstrace/sdk/trpc";
|
|
409
|
+
|
|
410
|
+
interface MyContext { session?: { userId: string }; tier?: string }
|
|
411
|
+
const t = initTRPC.context<MyContext>().create();
|
|
412
|
+
|
|
413
|
+
const isAuthed = t.middleware(
|
|
414
|
+
tracedMiddleware({ name: "isAuthed" }, async ({ ctx, next }) => {
|
|
415
|
+
if (!ctx.session) throw new TRPCError({ code: "UNAUTHORIZED" });
|
|
416
|
+
return next({ ctx: { ...ctx, session: ctx.session } });
|
|
417
|
+
}),
|
|
418
|
+
);
|
|
419
|
+
|
|
420
|
+
const isPro = t.middleware(
|
|
421
|
+
tracedMiddleware({ name: "isPro" }, async ({ ctx, next }) => {
|
|
422
|
+
if (ctx.tier !== "pro") throw new TRPCError({ code: "FORBIDDEN" });
|
|
423
|
+
return next();
|
|
424
|
+
}),
|
|
425
|
+
);
|
|
426
|
+
|
|
427
|
+
export const proProcedure = t.procedure.use(isAuthed).use(isPro);
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
The wrapped function preserves the original middleware's call-site type,
|
|
431
|
+
so tRPC's procedure-builder context narrowing flows through unchanged.
|
|
432
|
+
The existing `glasstrace.trpc.procedure` attribute (set on the parent
|
|
433
|
+
HTTP span) is not duplicated on the middleware child spans — middleware
|
|
434
|
+
spans carry only `trpc.path`, `trpc.type`, and any caller-supplied
|
|
435
|
+
`options.attributes`. Caller-supplied attributes are forwarded as-is;
|
|
436
|
+
the SDK does not redact them, so callers must avoid placing tokens or
|
|
437
|
+
credentials in `options.attributes`.
|
|
438
|
+
|
|
386
439
|
## Security
|
|
387
440
|
|
|
388
441
|
The SDK transmits your API key exclusively via the `Authorization: Bearer`
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-DQ25VOKK.js";
|
|
4
4
|
import {
|
|
5
5
|
GLASSTRACE_ATTRIBUTE_NAMES
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-EBYISKQP.js";
|
|
7
7
|
|
|
8
8
|
// src/errors.ts
|
|
9
9
|
var SdkError = class extends Error {
|
|
@@ -102,4 +102,4 @@ export {
|
|
|
102
102
|
GlasstraceSpanProcessor,
|
|
103
103
|
captureCorrelationId
|
|
104
104
|
};
|
|
105
|
-
//# sourceMappingURL=chunk-
|
|
105
|
+
//# sourceMappingURL=chunk-2GCN27SI.js.map
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
PresignedUploadResponseSchema,
|
|
6
6
|
SourceMapManifestResponseSchema,
|
|
7
7
|
SourceMapUploadResponseSchema
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-EBYISKQP.js";
|
|
9
9
|
|
|
10
10
|
// src/source-map-uploader.ts
|
|
11
11
|
import * as fs from "node:fs/promises";
|
|
@@ -331,4 +331,4 @@ export {
|
|
|
331
331
|
uploadSourceMapsPresigned,
|
|
332
332
|
uploadSourceMapsAuto
|
|
333
333
|
};
|
|
334
|
-
//# sourceMappingURL=chunk-
|
|
334
|
+
//# sourceMappingURL=chunk-47B2G3FE.js.map
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
performInit,
|
|
34
34
|
recordSpansDropped,
|
|
35
35
|
recordSpansExported
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-HV5ID2WJ.js";
|
|
37
37
|
import {
|
|
38
38
|
isAnonymousMode,
|
|
39
39
|
isProductionDisabled,
|
|
@@ -43,11 +43,11 @@ import {
|
|
|
43
43
|
atomicWriteFileSync,
|
|
44
44
|
getOrCreateAnonKey,
|
|
45
45
|
readAnonKey
|
|
46
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-MD5XPCTQ.js";
|
|
47
47
|
import {
|
|
48
48
|
GLASSTRACE_ATTRIBUTE_NAMES,
|
|
49
49
|
deriveSessionId
|
|
50
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-EBYISKQP.js";
|
|
51
51
|
import {
|
|
52
52
|
__require
|
|
53
53
|
} from "./chunk-NSBPE2FW.js";
|
|
@@ -144,16 +144,22 @@ var ERROR_RESPONSE_BODY_TRUNCATION_MARKER = "...[truncated]";
|
|
|
144
144
|
var REDACTED = "[REDACTED]";
|
|
145
145
|
var ERROR_STATUS_MIN = 400;
|
|
146
146
|
var ERROR_STATUS_MAX = 599;
|
|
147
|
-
function
|
|
147
|
+
function coerceHttpStatus(value) {
|
|
148
148
|
let numeric;
|
|
149
|
-
if (typeof
|
|
150
|
-
numeric =
|
|
151
|
-
} else if (typeof
|
|
152
|
-
|
|
149
|
+
if (typeof value === "number") {
|
|
150
|
+
numeric = value;
|
|
151
|
+
} else if (typeof value === "string") {
|
|
152
|
+
const trimmed = value.trim();
|
|
153
|
+
if (trimmed.length === 0) return void 0;
|
|
154
|
+
numeric = Number(trimmed);
|
|
153
155
|
} else {
|
|
154
|
-
return
|
|
156
|
+
return void 0;
|
|
155
157
|
}
|
|
156
|
-
|
|
158
|
+
return Number.isFinite(numeric) ? numeric : void 0;
|
|
159
|
+
}
|
|
160
|
+
function isHttpErrorStatus(status) {
|
|
161
|
+
const numeric = coerceHttpStatus(status);
|
|
162
|
+
if (numeric === void 0) return false;
|
|
157
163
|
return numeric >= ERROR_STATUS_MIN && numeric <= ERROR_STATUS_MAX;
|
|
158
164
|
}
|
|
159
165
|
var REDACTION_PATTERNS = [
|
|
@@ -413,7 +419,7 @@ var GlasstraceExporter = class {
|
|
|
413
419
|
}
|
|
414
420
|
}
|
|
415
421
|
}
|
|
416
|
-
const statusCode = attrs["http.status_code"] ?? attrs["http.response.status_code"];
|
|
422
|
+
const statusCode = coerceHttpStatus(attrs["http.status_code"]) ?? coerceHttpStatus(attrs["http.response.status_code"]);
|
|
417
423
|
if (statusCode !== void 0) {
|
|
418
424
|
extra[ATTR.HTTP_STATUS_CODE] = statusCode;
|
|
419
425
|
}
|
|
@@ -3906,8 +3912,51 @@ function createDiscoveryHandler(getAnonKey, getSessionId, getClaimState) {
|
|
|
3906
3912
|
|
|
3907
3913
|
// src/context-manager.ts
|
|
3908
3914
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3915
|
+
var GLASSTRACE_BRAND = 1;
|
|
3916
|
+
var GUARD = /* @__PURE__ */ Symbol.for("glasstrace.context-manager.installed");
|
|
3917
|
+
var OTEL_API_KEY = /* @__PURE__ */ Symbol.for("opentelemetry.js.api.1");
|
|
3918
|
+
function isOtelContextManager(value) {
|
|
3919
|
+
if (typeof value !== "object" || value === null) return false;
|
|
3920
|
+
const candidate = value;
|
|
3921
|
+
return typeof candidate.active === "function" && typeof candidate.with === "function" && typeof candidate.bind === "function" && typeof candidate.enable === "function" && typeof candidate.disable === "function";
|
|
3922
|
+
}
|
|
3923
|
+
function isInstallationRecord(value) {
|
|
3924
|
+
if (typeof value !== "object" || value === null) return false;
|
|
3925
|
+
const candidate = value;
|
|
3926
|
+
if (candidate.glasstraceContextManagerBrand !== GLASSTRACE_BRAND) return false;
|
|
3927
|
+
return candidate.manager === null || isOtelContextManager(candidate.manager);
|
|
3928
|
+
}
|
|
3929
|
+
function getOtelRegisteredContextManager() {
|
|
3930
|
+
const otelSlot = globalThis[OTEL_API_KEY];
|
|
3931
|
+
if (typeof otelSlot !== "object" || otelSlot === null) return void 0;
|
|
3932
|
+
const ctx = otelSlot.context;
|
|
3933
|
+
return isOtelContextManager(ctx) ? ctx : void 0;
|
|
3934
|
+
}
|
|
3909
3935
|
function installContextManager() {
|
|
3910
3936
|
try {
|
|
3937
|
+
const slot = globalThis;
|
|
3938
|
+
const existing = slot[GUARD];
|
|
3939
|
+
const otelCurrent = getOtelRegisteredContextManager();
|
|
3940
|
+
if (isInstallationRecord(existing) && existing.manager !== null && existing.manager === otelCurrent) {
|
|
3941
|
+
return true;
|
|
3942
|
+
}
|
|
3943
|
+
if (isInstallationRecord(existing) && existing.manager === null && otelCurrent !== void 0) {
|
|
3944
|
+
return false;
|
|
3945
|
+
}
|
|
3946
|
+
if (isInstallationRecord(existing) && existing.manager !== null) {
|
|
3947
|
+
const reSuccess = context.setGlobalContextManager(existing.manager);
|
|
3948
|
+
if (!reSuccess) {
|
|
3949
|
+
console.warn(
|
|
3950
|
+
"[glasstrace] Another context manager is already registered. Trace context propagation may not work as expected."
|
|
3951
|
+
);
|
|
3952
|
+
}
|
|
3953
|
+
const reRecord = {
|
|
3954
|
+
glasstraceContextManagerBrand: GLASSTRACE_BRAND,
|
|
3955
|
+
manager: reSuccess ? existing.manager : null
|
|
3956
|
+
};
|
|
3957
|
+
slot[GUARD] = reRecord;
|
|
3958
|
+
return reSuccess;
|
|
3959
|
+
}
|
|
3911
3960
|
const als = new AsyncLocalStorage();
|
|
3912
3961
|
const contextManager = {
|
|
3913
3962
|
active: () => als.getStore() ?? ROOT_CONTEXT,
|
|
@@ -3928,6 +3977,11 @@ function installContextManager() {
|
|
|
3928
3977
|
"[glasstrace] Another context manager is already registered. Trace context propagation may not work as expected."
|
|
3929
3978
|
);
|
|
3930
3979
|
}
|
|
3980
|
+
const record = {
|
|
3981
|
+
glasstraceContextManagerBrand: GLASSTRACE_BRAND,
|
|
3982
|
+
manager: success ? contextManager : null
|
|
3983
|
+
};
|
|
3984
|
+
slot[GUARD] = record;
|
|
3931
3985
|
return success;
|
|
3932
3986
|
} catch {
|
|
3933
3987
|
return false;
|
|
@@ -4153,7 +4207,7 @@ function registerGlasstrace(options) {
|
|
|
4153
4207
|
setCoreState(CoreState.REGISTERING);
|
|
4154
4208
|
startRuntimeStateWriter({
|
|
4155
4209
|
projectRoot: process.cwd(),
|
|
4156
|
-
sdkVersion: "1.1
|
|
4210
|
+
sdkVersion: "1.2.1"
|
|
4157
4211
|
});
|
|
4158
4212
|
const config = resolveConfig(options);
|
|
4159
4213
|
if (config.verbose) {
|
|
@@ -4319,8 +4373,8 @@ async function backgroundInit(config, anonKeyForInit, generation) {
|
|
|
4319
4373
|
if (config.verbose) {
|
|
4320
4374
|
console.info("[glasstrace] Background init firing.");
|
|
4321
4375
|
}
|
|
4322
|
-
const healthReport = collectHealthReport("1.1
|
|
4323
|
-
const initResult = await performInit(config, anonKeyForInit, "1.1
|
|
4376
|
+
const healthReport = collectHealthReport("1.2.1");
|
|
4377
|
+
const initResult = await performInit(config, anonKeyForInit, "1.2.1", healthReport);
|
|
4324
4378
|
if (generation !== registrationGeneration) return;
|
|
4325
4379
|
const currentState = getCoreState();
|
|
4326
4380
|
if (currentState === CoreState.SHUTTING_DOWN || currentState === CoreState.SHUTDOWN) {
|
|
@@ -4343,7 +4397,7 @@ async function backgroundInit(config, anonKeyForInit, generation) {
|
|
|
4343
4397
|
}
|
|
4344
4398
|
maybeInstallConsoleCapture();
|
|
4345
4399
|
if (didLastInitSucceed()) {
|
|
4346
|
-
startHeartbeat(config, anonKeyForInit, "1.1
|
|
4400
|
+
startHeartbeat(config, anonKeyForInit, "1.2.1", generation, (newApiKey, accountId) => {
|
|
4347
4401
|
setAuthState(AuthState.CLAIMING);
|
|
4348
4402
|
emitLifecycleEvent("auth:claim_started", { accountId });
|
|
4349
4403
|
setResolvedApiKey(newApiKey);
|
|
@@ -4638,7 +4692,7 @@ async function handleSourceMapUpload(distDir) {
|
|
|
4638
4692
|
);
|
|
4639
4693
|
return;
|
|
4640
4694
|
}
|
|
4641
|
-
const { discoverSourceMapFiles, computeBuildHash, uploadSourceMaps } = await import("./source-map-uploader-
|
|
4695
|
+
const { discoverSourceMapFiles, computeBuildHash, uploadSourceMaps } = await import("./source-map-uploader-RA4Z7TWA.js");
|
|
4642
4696
|
const files = await discoverSourceMapFiles(distDir);
|
|
4643
4697
|
if (files.length === 0) {
|
|
4644
4698
|
console.info("[glasstrace] No source map files found. Skipping upload.");
|
|
@@ -4692,4 +4746,4 @@ export {
|
|
|
4692
4746
|
withGlasstraceConfig,
|
|
4693
4747
|
captureError
|
|
4694
4748
|
};
|
|
4695
|
-
//# sourceMappingURL=chunk-
|
|
4749
|
+
//# sourceMappingURL=chunk-CTJO7PUZ.js.map
|