@plumix/core 0.4.0 → 0.6.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/dist/auth/authenticator.d.ts +8 -1
- package/dist/auth/authenticator.d.ts.map +1 -1
- package/dist/auth/authenticator.js +15 -0
- package/dist/auth/authenticator.js.map +1 -1
- package/dist/auth/bearer.js +2 -2
- package/dist/auth/bearer.js.map +1 -1
- package/dist/cache/decision.d.ts +7 -3
- package/dist/cache/decision.d.ts.map +1 -1
- package/dist/cache/decision.js +8 -6
- package/dist/cache/decision.js.map +1 -1
- package/dist/cache/read-through.d.ts +3 -0
- package/dist/cache/read-through.d.ts.map +1 -1
- package/dist/cache/read-through.js +14 -7
- package/dist/cache/read-through.js.map +1 -1
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/context/app.d.ts +50 -6
- package/dist/context/app.d.ts.map +1 -1
- package/dist/context/app.js +51 -12
- package/dist/context/app.js.map +1 -1
- package/dist/context/collector.d.ts +9 -0
- package/dist/context/collector.d.ts.map +1 -0
- package/dist/context/collector.js +130 -0
- package/dist/context/collector.js.map +1 -0
- package/dist/context/index.d.ts +1 -0
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js +1 -0
- package/dist/context/index.js.map +1 -1
- package/dist/context/memo.d.ts +22 -0
- package/dist/context/memo.d.ts.map +1 -0
- package/dist/context/memo.js +27 -0
- package/dist/context/memo.js.map +1 -0
- package/dist/context/stores.d.ts +2 -9
- package/dist/context/stores.d.ts.map +1 -1
- package/dist/context/stores.js.map +1 -1
- package/dist/context/telemetry.d.ts +148 -0
- package/dist/context/telemetry.d.ts.map +1 -0
- package/dist/context/telemetry.js +20 -0
- package/dist/context/telemetry.js.map +1 -0
- package/dist/context/traced-fetch.d.ts +14 -0
- package/dist/context/traced-fetch.d.ts.map +1 -0
- package/dist/context/traced-fetch.js +33 -0
- package/dist/context/traced-fetch.js.map +1 -0
- package/dist/context/traced-slots.d.ts +17 -0
- package/dist/context/traced-slots.d.ts.map +1 -0
- package/dist/context/traced-slots.js +57 -0
- package/dist/context/traced-slots.js.map +1 -0
- package/dist/db/libsql.d.ts.map +1 -1
- package/dist/db/libsql.js +6 -12
- package/dist/db/libsql.js.map +1 -1
- package/dist/db/query-kind.d.ts +8 -0
- package/dist/db/query-kind.d.ts.map +1 -0
- package/dist/db/query-kind.js +11 -0
- package/dist/db/query-kind.js.map +1 -0
- package/dist/db/trace-libsql.d.ts +15 -0
- package/dist/db/trace-libsql.d.ts.map +1 -0
- package/dist/db/trace-libsql.js +37 -0
- package/dist/db/trace-libsql.js.map +1 -0
- package/dist/db/trace.d.ts +21 -0
- package/dist/db/trace.d.ts.map +1 -0
- package/dist/db/trace.js +64 -0
- package/dist/db/trace.js.map +1 -0
- package/dist/debug-bar/consumer.d.ts +12 -0
- package/dist/debug-bar/consumer.d.ts.map +1 -0
- package/dist/debug-bar/consumer.js +13 -0
- package/dist/debug-bar/consumer.js.map +1 -0
- package/dist/debug-bar/format-param.d.ts +6 -4
- package/dist/debug-bar/format-param.d.ts.map +1 -1
- package/dist/debug-bar/format-param.js +6 -9
- package/dist/debug-bar/format-param.js.map +1 -1
- package/dist/debug-bar/highlight-sql.d.ts +0 -3
- package/dist/debug-bar/highlight-sql.d.ts.map +1 -1
- package/dist/debug-bar/highlight-sql.js +0 -6
- package/dist/debug-bar/highlight-sql.js.map +1 -1
- package/dist/debug-bar/panels/database.d.ts +6 -4
- package/dist/debug-bar/panels/database.d.ts.map +1 -1
- package/dist/debug-bar/panels/database.js +44 -8
- package/dist/debug-bar/panels/database.js.map +1 -1
- package/dist/debug-bar/panels/template.d.ts +1 -1
- package/dist/debug-bar/panels/template.d.ts.map +1 -1
- package/dist/debug-bar/panels/template.js +16 -2
- package/dist/debug-bar/panels/template.js.map +1 -1
- package/dist/debug-bar/panels/timeline.js +1 -1
- package/dist/debug-bar/panels/timeline.js.map +1 -1
- package/dist/debug-bar/styles.d.ts.map +1 -1
- package/dist/debug-bar/styles.js +5 -0
- package/dist/debug-bar/styles.js.map +1 -1
- package/dist/debug-bar/timeline-model.d.ts +3 -3
- package/dist/debug-bar/timeline-model.d.ts.map +1 -1
- package/dist/debug-bar/timeline-model.js +1 -1
- package/dist/debug-bar/timeline-model.js.map +1 -1
- package/dist/debug-bar/types.d.ts +1 -1
- package/dist/entries/read-service.d.ts +6 -0
- package/dist/entries/read-service.d.ts.map +1 -1
- package/dist/entries/read-service.js +14 -0
- package/dist/entries/read-service.js.map +1 -1
- package/dist/hooks/registry.d.ts.map +1 -1
- package/dist/hooks/registry.js +21 -3
- package/dist/hooks/registry.js.map +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +9 -3
- package/dist/mcp/server.js.map +1 -1
- package/dist/plugin/fields/entry.d.ts +8 -0
- package/dist/plugin/fields/entry.d.ts.map +1 -1
- package/dist/plugin/fields/entry.js.map +1 -1
- package/dist/plugin/lookup.d.ts +4 -9
- package/dist/plugin/lookup.d.ts.map +1 -1
- package/dist/plugin/manifest.d.ts +28 -32
- package/dist/plugin/manifest.d.ts.map +1 -1
- package/dist/plugin/manifest.js +7 -2
- package/dist/plugin/manifest.js.map +1 -1
- package/dist/plugin/provides-context.d.ts.map +1 -1
- package/dist/plugin/provides-context.js +5 -0
- package/dist/plugin/provides-context.js.map +1 -1
- package/dist/plugin/setup-context.d.ts +5 -0
- package/dist/plugin/setup-context.d.ts.map +1 -1
- package/dist/plugin/setup-context.js.map +1 -1
- package/dist/rest/build-handler.d.ts.map +1 -1
- package/dist/rest/build-handler.js +14 -1
- package/dist/rest/build-handler.js.map +1 -1
- package/dist/revisions/snapshot-envelope.d.ts +4 -2
- package/dist/revisions/snapshot-envelope.d.ts.map +1 -1
- package/dist/revisions/snapshot-envelope.js +6 -3
- package/dist/revisions/snapshot-envelope.js.map +1 -1
- package/dist/route/render/asset-manifest.d.ts +1 -1
- package/dist/route/render/asset-manifest.d.ts.map +1 -1
- package/dist/route/render/asset-manifest.js +7 -1
- package/dist/route/render/asset-manifest.js.map +1 -1
- package/dist/route/render/build-resolved-entries.d.ts.map +1 -1
- package/dist/route/render/build-resolved-entries.js +18 -10
- package/dist/route/render/build-resolved-entries.js.map +1 -1
- package/dist/route/render/render-template.d.ts +1 -1
- package/dist/route/render/render-template.d.ts.map +1 -1
- package/dist/route/render/render-template.js +61 -35
- package/dist/route/render/render-template.js.map +1 -1
- package/dist/route/render/template-builders.d.ts +12 -0
- package/dist/route/render/template-builders.d.ts.map +1 -1
- package/dist/route/render/template-builders.js +20 -0
- package/dist/route/render/template-builders.js.map +1 -1
- package/dist/route/resolve.d.ts.map +1 -1
- package/dist/route/resolve.js +4 -1
- package/dist/route/resolve.js.map +1 -1
- package/dist/rpc/authenticated.d.ts.map +1 -1
- package/dist/rpc/authenticated.js +2 -1
- package/dist/rpc/authenticated.js.map +1 -1
- package/dist/rpc/build-handler.d.ts.map +1 -1
- package/dist/rpc/build-handler.js +12 -0
- package/dist/rpc/build-handler.js.map +1 -1
- package/dist/rpc/meta/core.d.ts +3 -4
- package/dist/rpc/meta/core.d.ts.map +1 -1
- package/dist/rpc/meta/core.js +87 -152
- package/dist/rpc/meta/core.js.map +1 -1
- package/dist/rpc/procedures/auth/session.d.ts.map +1 -1
- package/dist/rpc/procedures/auth/session.js +2 -1
- package/dist/rpc/procedures/auth/session.js.map +1 -1
- package/dist/rpc/procedures/entry/helpers.d.ts +21 -0
- package/dist/rpc/procedures/entry/helpers.d.ts.map +1 -1
- package/dist/rpc/procedures/entry/helpers.js +44 -0
- package/dist/rpc/procedures/entry/helpers.js.map +1 -1
- package/dist/rpc/procedures/entry/index.d.ts +1 -0
- package/dist/rpc/procedures/entry/index.d.ts.map +1 -1
- package/dist/rpc/procedures/entry/lookup.js +14 -11
- package/dist/rpc/procedures/entry/lookup.js.map +1 -1
- package/dist/rpc/procedures/entry/schemas.d.ts +2 -0
- package/dist/rpc/procedures/entry/schemas.d.ts.map +1 -1
- package/dist/rpc/procedures/entry/schemas.js +7 -0
- package/dist/rpc/procedures/entry/schemas.js.map +1 -1
- package/dist/rpc/procedures/entry/update.d.ts +1 -0
- package/dist/rpc/procedures/entry/update.d.ts.map +1 -1
- package/dist/rpc/procedures/entry/update.js +10 -5
- package/dist/rpc/procedures/entry/update.js.map +1 -1
- package/dist/rpc/procedures/lookup.errors.d.ts +2 -1
- package/dist/rpc/procedures/lookup.errors.d.ts.map +1 -1
- package/dist/rpc/procedures/lookup.errors.js +3 -0
- package/dist/rpc/procedures/lookup.errors.js.map +1 -1
- package/dist/rpc/procedures/term/lookup.js +3 -8
- package/dist/rpc/procedures/term/lookup.js.map +1 -1
- package/dist/rpc/procedures/user/index.d.ts +1 -0
- package/dist/rpc/procedures/user/index.d.ts.map +1 -1
- package/dist/rpc/procedures/user/schemas.d.ts +1 -0
- package/dist/rpc/procedures/user/schemas.d.ts.map +1 -1
- package/dist/rpc/procedures/user/schemas.js +5 -0
- package/dist/rpc/procedures/user/schemas.js.map +1 -1
- package/dist/rpc/procedures/user/update.d.ts +1 -0
- package/dist/rpc/procedures/user/update.d.ts.map +1 -1
- package/dist/rpc/procedures/user/update.js +10 -1
- package/dist/rpc/procedures/user/update.js.map +1 -1
- package/dist/rpc/router.d.ts +2 -0
- package/dist/rpc/router.d.ts.map +1 -1
- package/dist/rpc/schemas.js +6 -6
- package/dist/rpc/schemas.js.map +1 -1
- package/dist/rpc/validation.d.ts +10 -0
- package/dist/rpc/validation.d.ts.map +1 -1
- package/dist/rpc/validation.js +10 -0
- package/dist/rpc/validation.js.map +1 -1
- package/dist/runtime/dispatcher.d.ts.map +1 -1
- package/dist/runtime/dispatcher.js +105 -37
- package/dist/runtime/dispatcher.js.map +1 -1
- package/dist/runtime/load-user-for-public-request.d.ts.map +1 -1
- package/dist/runtime/load-user-for-public-request.js +2 -2
- package/dist/runtime/load-user-for-public-request.js.map +1 -1
- package/dist/runtime/scheduled.d.ts +3 -1
- package/dist/runtime/scheduled.d.ts.map +1 -1
- package/dist/runtime/scheduled.js +16 -2
- package/dist/runtime/scheduled.js.map +1 -1
- package/dist/runtime/telemetry-delivery.d.ts +14 -0
- package/dist/runtime/telemetry-delivery.d.ts.map +1 -0
- package/dist/runtime/telemetry-delivery.js +39 -0
- package/dist/runtime/telemetry-delivery.js.map +1 -0
- package/dist/telemetry-otel.d.ts +29 -0
- package/dist/telemetry-otel.d.ts.map +1 -0
- package/dist/telemetry-otel.js +218 -0
- package/dist/telemetry-otel.js.map +1 -0
- package/dist/template-deps-core.d.ts.map +1 -1
- package/dist/template-deps-core.js +31 -14
- package/dist/template-deps-core.js.map +1 -1
- package/dist/template-deps.d.ts.map +1 -1
- package/dist/template-deps.js +12 -8
- package/dist/template-deps.js.map +1 -1
- package/dist/test/dispatcher.d.ts +13 -0
- package/dist/test/dispatcher.d.ts.map +1 -1
- package/dist/test/dispatcher.js +9 -3
- package/dist/test/dispatcher.js.map +1 -1
- package/dist/test/harness.d.ts.map +1 -1
- package/dist/test/harness.js +4 -12
- package/dist/test/harness.js.map +1 -1
- package/dist/test/index.d.ts +3 -0
- package/dist/test/index.d.ts.map +1 -1
- package/dist/test/index.js +4 -0
- package/dist/test/index.js.map +1 -1
- package/dist/test/traced-context.d.ts +17 -0
- package/dist/test/traced-context.d.ts.map +1 -0
- package/dist/test/traced-context.js +28 -0
- package/dist/test/traced-context.js.map +1 -0
- package/package.json +6 -2
- package/dist/context/debug.d.ts +0 -25
- package/dist/context/debug.d.ts.map +0 -1
- package/dist/context/debug.js +0 -13
- package/dist/context/debug.js.map +0 -1
- package/dist/debug-bar/collector.d.ts +0 -9
- package/dist/debug-bar/collector.d.ts.map +0 -1
- package/dist/debug-bar/collector.js +0 -80
- package/dist/debug-bar/collector.js.map +0 -1
- package/dist/debug-bar/db-query.d.ts +0 -21
- package/dist/debug-bar/db-query.d.ts.map +0 -1
- package/dist/debug-bar/db-query.js +0 -23
- package/dist/debug-bar/db-query.js.map +0 -1
- package/dist/debug-bar/trace-libsql.d.ts +0 -18
- package/dist/debug-bar/trace-libsql.d.ts.map +0 -1
- package/dist/debug-bar/trace-libsql.js +0 -42
- package/dist/debug-bar/trace-libsql.js.map +0 -1
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { traceStore } from "./stores.js";
|
|
2
|
+
import { NOOP_HANDLE } from "./telemetry.js";
|
|
3
|
+
function isThenable(value) {
|
|
4
|
+
return (value != null && typeof value.then === "function");
|
|
5
|
+
}
|
|
6
|
+
// `String(x)` itself throws for e.g. `Object.create(null)`; the serializer
|
|
7
|
+
// must never replace the original failure with its own.
|
|
8
|
+
function describeThrown(error) {
|
|
9
|
+
try {
|
|
10
|
+
return { name: "Error", message: String(error) };
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return { name: "Error", message: "<unserializable thrown value>" };
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
// Hard per-request caps so a pathological path (a runaway loop, an extreme
|
|
17
|
+
// N+1) can't accumulate unbounded memory. Overflow is never silent: it counts
|
|
18
|
+
// into getDropped(). Fixed on purpose — no config knob.
|
|
19
|
+
const MAX_SPANS = 2000;
|
|
20
|
+
const MAX_RECORDS_PER_NAMESPACE = 1000;
|
|
21
|
+
/**
|
|
22
|
+
* The real telemetry collector. Accumulates per-namespace entries and a span
|
|
23
|
+
* tree for the request. Always present in production bundles; created only
|
|
24
|
+
* when at least one registered consumer votes to sample the request, so a
|
|
25
|
+
* site with no consumers stays on the no-op and pays nothing.
|
|
26
|
+
*/
|
|
27
|
+
export function createTelemetryCollector() {
|
|
28
|
+
const entries = new Map();
|
|
29
|
+
const roots = [];
|
|
30
|
+
let spanCount = 0;
|
|
31
|
+
let droppedSpans = 0;
|
|
32
|
+
const droppedRecords = {};
|
|
33
|
+
return {
|
|
34
|
+
record(namespace, entry) {
|
|
35
|
+
const bucket = entries.get(namespace);
|
|
36
|
+
if (bucket && bucket.length >= MAX_RECORDS_PER_NAMESPACE) {
|
|
37
|
+
droppedRecords[namespace] = (droppedRecords[namespace] ?? 0) + 1;
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const record = {
|
|
41
|
+
at: Date.now(),
|
|
42
|
+
data: typeof entry === "function" ? entry() : entry,
|
|
43
|
+
};
|
|
44
|
+
if (bucket)
|
|
45
|
+
bucket.push(record);
|
|
46
|
+
else
|
|
47
|
+
entries.set(namespace, [record]);
|
|
48
|
+
},
|
|
49
|
+
span(name, fn) {
|
|
50
|
+
// Over the cap: the work still runs and returns unchanged, but no span
|
|
51
|
+
// is allocated and lazy attributes are never evaluated.
|
|
52
|
+
if (spanCount >= MAX_SPANS) {
|
|
53
|
+
droppedSpans += 1;
|
|
54
|
+
return fn(NOOP_HANDLE);
|
|
55
|
+
}
|
|
56
|
+
spanCount += 1;
|
|
57
|
+
const startedAt = Date.now();
|
|
58
|
+
const span = {
|
|
59
|
+
name,
|
|
60
|
+
startedAt,
|
|
61
|
+
durationMs: 0,
|
|
62
|
+
status: "ok",
|
|
63
|
+
attributes: {},
|
|
64
|
+
children: [],
|
|
65
|
+
};
|
|
66
|
+
const handle = {
|
|
67
|
+
set(key, value) {
|
|
68
|
+
span.attributes[key] = typeof value === "function" ? value() : value;
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
// Attach to the enclosing span (via AsyncLocalStorage) so nesting
|
|
72
|
+
// reflects call structure; top-level spans become roots.
|
|
73
|
+
const parent = traceStore.getStore();
|
|
74
|
+
if (parent)
|
|
75
|
+
parent.children.push(span);
|
|
76
|
+
else
|
|
77
|
+
roots.push(span);
|
|
78
|
+
const stamp = () => {
|
|
79
|
+
span.durationMs = Date.now() - startedAt;
|
|
80
|
+
};
|
|
81
|
+
// Serialized (never the live Error) so a finished span tree stays
|
|
82
|
+
// JSON-safe for any consumer; the failure itself propagates unchanged.
|
|
83
|
+
const fail = (error) => {
|
|
84
|
+
stamp();
|
|
85
|
+
span.status = "error";
|
|
86
|
+
span.error =
|
|
87
|
+
error instanceof Error
|
|
88
|
+
? { name: error.name, message: error.message, stack: error.stack }
|
|
89
|
+
: describeThrown(error);
|
|
90
|
+
};
|
|
91
|
+
let result;
|
|
92
|
+
try {
|
|
93
|
+
result = traceStore.run(span, () => fn(handle));
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
fail(error);
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
// Await async work before stamping so I/O time is measured, not just the
|
|
100
|
+
// synchronous prelude. Nesting already survives awaits via ALS.
|
|
101
|
+
if (isThenable(result)) {
|
|
102
|
+
return result.then((value) => {
|
|
103
|
+
stamp();
|
|
104
|
+
return value;
|
|
105
|
+
}, (error) => {
|
|
106
|
+
fail(error);
|
|
107
|
+
throw error;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
stamp();
|
|
111
|
+
return result;
|
|
112
|
+
},
|
|
113
|
+
get(namespace) {
|
|
114
|
+
return entries.get(namespace) ?? [];
|
|
115
|
+
},
|
|
116
|
+
getRecords() {
|
|
117
|
+
// Copies, not the live buckets — this is the snapshot read, and a
|
|
118
|
+
// captured snapshot must not grow under post-response recording.
|
|
119
|
+
return Object.fromEntries([...entries].map(([namespace, bucket]) => [namespace, [...bucket]]));
|
|
120
|
+
},
|
|
121
|
+
getSpans() {
|
|
122
|
+
return roots;
|
|
123
|
+
},
|
|
124
|
+
getDropped() {
|
|
125
|
+
// Snapshot, not the live counter map — a captured value must not mutate.
|
|
126
|
+
return { spans: droppedSpans, records: { ...droppedRecords } };
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=collector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collector.js","sourceRoot":"","sources":["../../src/context/collector.ts"],"names":[],"mappings":"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"}
|
package/dist/context/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/context/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/context/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC"}
|
package/dist/context/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/context/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/context/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request-scoped read-through memo — see `AppContextBase.memo`. Callers
|
|
3
|
+
* namespace keys (`core:settings-group:site`, `menu:data:primary`) since
|
|
4
|
+
* all consumers share one map per context.
|
|
5
|
+
*
|
|
6
|
+
* There is no invalidation: a write in the same execution is invisible to
|
|
7
|
+
* keys already loaded (cron runs share one memo across every task in the
|
|
8
|
+
* invocation). Loaders must also be principal-invariant — `withUser`
|
|
9
|
+
* derivations share the same memo, so anything user-dependent must embed
|
|
10
|
+
* the principal in the key.
|
|
11
|
+
*/
|
|
12
|
+
export type RequestMemo = <T>(key: string, load: () => Promise<T>) => Promise<T>;
|
|
13
|
+
export declare function createRequestMemo(): RequestMemo;
|
|
14
|
+
/**
|
|
15
|
+
* Per-id memo over a batched load: each id resolves through `memo`, and
|
|
16
|
+
* all misses share one lazy `loadAll` (single-flight, so the batch runs
|
|
17
|
+
* at most once per call). `loadAll` may fetch every requested id — hits
|
|
18
|
+
* keep their first-seen value regardless. Ids absent from the loaded map
|
|
19
|
+
* memoize as `null`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function memoBatch<K, T>(memo: RequestMemo, ids: readonly K[], keyFor: (id: K) => string, loadAll: () => Promise<ReadonlyMap<K, T>>): Promise<(T | null)[]>;
|
|
22
|
+
//# sourceMappingURL=memo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memo.d.ts","sourceRoot":"","sources":["../../src/context/memo.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,EAC1B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KACnB,OAAO,CAAC,CAAC,CAAC,CAAC;AAEhB,wBAAgB,iBAAiB,IAAI,WAAW,CAY/C;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,CAAC,EAC5B,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,SAAS,CAAC,EAAE,EACjB,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,MAAM,EACzB,OAAO,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GACxC,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAQvB"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export function createRequestMemo() {
|
|
2
|
+
const cache = new Map();
|
|
3
|
+
return (key, load) => {
|
|
4
|
+
const hit = cache.get(key);
|
|
5
|
+
if (hit !== undefined)
|
|
6
|
+
return hit;
|
|
7
|
+
const entry = load();
|
|
8
|
+
cache.set(key, entry);
|
|
9
|
+
// Rejections are not memoized — a transient DB error on one read
|
|
10
|
+
// shouldn't poison every later read of the same key in the request.
|
|
11
|
+
entry.catch(() => cache.delete(key));
|
|
12
|
+
return entry;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Per-id memo over a batched load: each id resolves through `memo`, and
|
|
17
|
+
* all misses share one lazy `loadAll` (single-flight, so the batch runs
|
|
18
|
+
* at most once per call). `loadAll` may fetch every requested id — hits
|
|
19
|
+
* keep their first-seen value regardless. Ids absent from the loaded map
|
|
20
|
+
* memoize as `null`.
|
|
21
|
+
*/
|
|
22
|
+
export function memoBatch(memo, ids, keyFor, loadAll) {
|
|
23
|
+
let batch;
|
|
24
|
+
const load = () => (batch ??= loadAll());
|
|
25
|
+
return Promise.all(ids.map((id) => memo(keyFor(id), async () => (await load()).get(id) ?? null)));
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=memo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memo.js","sourceRoot":"","sources":["../../src/context/memo.ts"],"names":[],"mappings":"AAgBA,MAAM,UAAU,iBAAiB;IAC/B,MAAM,KAAK,GAAG,IAAI,GAAG,EAA4B,CAAC;IAClD,OAAO,CAAI,GAAW,EAAE,IAAsB,EAAc,EAAE;QAC5D,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC3B,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,GAAiB,CAAC;QAChD,MAAM,KAAK,GAAG,IAAI,EAAE,CAAC;QACrB,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACtB,iEAAiE;QACjE,oEAAoE;QACpE,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACrC,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CACvB,IAAiB,EACjB,GAAiB,EACjB,MAAyB,EACzB,OAAyC;IAEzC,IAAI,KAA6C,CAAC;IAClD,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC,CAAC;IACzC,OAAO,OAAO,CAAC,GAAG,CAChB,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CACb,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,CAC7D,CACF,CAAC;AACJ,CAAC"}
|
package/dist/context/stores.d.ts
CHANGED
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
2
|
import type { AppContext } from "./app.js";
|
|
3
|
+
import type { TelemetrySpan } from "./telemetry.js";
|
|
3
4
|
export declare const requestStore: AsyncLocalStorage<AppContext>;
|
|
4
5
|
export interface HookFrame {
|
|
5
6
|
readonly hook: string;
|
|
6
7
|
readonly plugin: string | null;
|
|
7
8
|
}
|
|
8
9
|
export declare const hookStore: AsyncLocalStorage<HookFrame>;
|
|
9
|
-
export
|
|
10
|
-
readonly name: string;
|
|
11
|
-
readonly startedAt: number;
|
|
12
|
-
/** Wall-clock duration; set when the span's work completes. */
|
|
13
|
-
durationMs: number;
|
|
14
|
-
readonly children: TraceSpan[];
|
|
15
|
-
readonly annotations: Record<string, unknown>;
|
|
16
|
-
}
|
|
17
|
-
export declare const traceStore: AsyncLocalStorage<TraceSpan>;
|
|
10
|
+
export declare const traceStore: AsyncLocalStorage<TelemetrySpan>;
|
|
18
11
|
export declare const txStore: AsyncLocalStorage<unknown>;
|
|
19
12
|
export declare function getContext(): AppContext;
|
|
20
13
|
export declare function tryGetContext(): AppContext | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stores.d.ts","sourceRoot":"","sources":["../../src/context/stores.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"stores.d.ts","sourceRoot":"","sources":["../../src/context/stores.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGpD,eAAO,MAAM,YAAY,+BAAsC,CAAC;AAEhE,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,eAAO,MAAM,SAAS,8BAAqC,CAAC;AAE5D,eAAO,MAAM,UAAU,kCAAyC,CAAC;AAEjE,eAAO,MAAM,OAAO,4BAAmC,CAAC;AAExD,wBAAgB,UAAU,IAAI,UAAU,CAIvC;AAED,wBAAgB,aAAa,IAAI,UAAU,GAAG,IAAI,CAEjD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stores.js","sourceRoot":"","sources":["../../src/context/stores.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,0EAA0E;AAC1E,gFAAgF;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"stores.js","sourceRoot":"","sources":["../../src/context/stores.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,0EAA0E;AAC1E,gFAAgF;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAIrD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,iBAAiB,EAAc,CAAC;AAOhE,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,iBAAiB,EAAa,CAAC;AAE5D,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,iBAAiB,EAAiB,CAAC;AAEjE,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,iBAAiB,EAAW,CAAC;AAExD,MAAM,UAAU,UAAU;IACxB,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,CAAC;IACpC,IAAI,CAAC,GAAG;QAAE,MAAM,YAAY,CAAC,gBAAgB,EAAE,CAAC;IAChD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,YAAY,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import type { AppContext } from "./app.js";
|
|
2
|
+
/** Attribute and record values must be JSON-serializable — enforced by type only. */
|
|
3
|
+
export type JsonValue = string | number | boolean | null | readonly JsonValue[] | {
|
|
4
|
+
readonly [key: string]: JsonValue;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* A span's captured failure — the serialized form, never the live Error.
|
|
8
|
+
* @public consumer-facing (imported by exporters, not core)
|
|
9
|
+
*/
|
|
10
|
+
export interface TelemetrySpanError {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
readonly message: string;
|
|
13
|
+
readonly stack?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* One node in the request's span tree. Minimal and OTel-mappable: an exporter
|
|
17
|
+
* can project name/timing/attributes onto an OTel span ~1:1, minting ids at
|
|
18
|
+
* export time.
|
|
19
|
+
*/
|
|
20
|
+
export interface TelemetrySpan {
|
|
21
|
+
readonly name: string;
|
|
22
|
+
readonly startedAt: number;
|
|
23
|
+
/** Wall-clock duration; set when the span's work completes. */
|
|
24
|
+
durationMs: number;
|
|
25
|
+
/** "error" when the span's function threw or rejected; the error is captured
|
|
26
|
+
* before the failure propagates unchanged. */
|
|
27
|
+
status: "ok" | "error";
|
|
28
|
+
error?: TelemetrySpanError;
|
|
29
|
+
readonly attributes: Record<string, JsonValue>;
|
|
30
|
+
readonly children: TelemetrySpan[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Handed to a span's function for attaching attributes. A lazy (thunk) value is
|
|
34
|
+
* evaluated once by the active collector and never by the no-op — expensive
|
|
35
|
+
* payloads cost nothing when nobody collects.
|
|
36
|
+
*/
|
|
37
|
+
export interface TelemetrySpanHandle {
|
|
38
|
+
set(key: string, value: JsonValue | (() => JsonValue)): void;
|
|
39
|
+
}
|
|
40
|
+
/** A recorded durationless fact, stamped so consumers can order it against spans. */
|
|
41
|
+
export interface TelemetryRecord {
|
|
42
|
+
readonly at: number;
|
|
43
|
+
readonly data: unknown;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* What the hard per-request caps discarded — visible so a consumer never
|
|
47
|
+
* mistakes a truncated trace for a complete one.
|
|
48
|
+
* @public consumer-facing (imported by exporters, not core)
|
|
49
|
+
*/
|
|
50
|
+
export interface TelemetryDropped {
|
|
51
|
+
readonly spans: number;
|
|
52
|
+
readonly records: Readonly<Record<string, number>>;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Request-scoped telemetry collector — the single source of truth for what
|
|
56
|
+
* happened during a request. Core and plugins record spans (anything with a
|
|
57
|
+
* duration) and records (durationless facts) under a namespace; consumers such
|
|
58
|
+
* as the dev debug bar read them back. Two implementations:
|
|
59
|
+
* {@link NOOP_TELEMETRY} (used whenever no consumer sampled the request) and
|
|
60
|
+
* the real accumulating collector, activated by consumer vote.
|
|
61
|
+
*/
|
|
62
|
+
export interface TelemetryCollector {
|
|
63
|
+
/**
|
|
64
|
+
* Append an entry under `namespace` (for the debug bar: the panel's id).
|
|
65
|
+
* A function entry is a lazy payload: the active collector evaluates it once
|
|
66
|
+
* at record time; the no-op never does.
|
|
67
|
+
*/
|
|
68
|
+
record(namespace: string, entry: unknown): void;
|
|
69
|
+
/** Time `fn`, record a span, and return `fn`'s result unchanged. */
|
|
70
|
+
span<T>(name: string, fn: (s: TelemetrySpanHandle) => T): T;
|
|
71
|
+
/** Timestamped entries recorded under `namespace`, in record order. */
|
|
72
|
+
get(namespace: string): readonly TelemetryRecord[];
|
|
73
|
+
/** Every namespace's entries, keyed by namespace — the snapshot read. */
|
|
74
|
+
getRecords(): Readonly<Record<string, readonly TelemetryRecord[]>>;
|
|
75
|
+
/** The collected span tree (the Timeline panel consumes this). */
|
|
76
|
+
getSpans(): readonly TelemetrySpan[];
|
|
77
|
+
/** Counts of entries discarded by the per-request caps. */
|
|
78
|
+
getDropped(): TelemetryDropped;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The finished request's identity and outcome, as a consumer sees it.
|
|
82
|
+
* `requestId` is `ctx.requestId`, minted at context creation — mid-request
|
|
83
|
+
* reads (logs, error hooks) correlate with the snapshot on the same value.
|
|
84
|
+
* `startedAt`/`durationMs` span the dispatch of the request — context
|
|
85
|
+
* creation and the sampling vote happen just before the clock starts.
|
|
86
|
+
* @public consumer-facing (imported by exporters, not core)
|
|
87
|
+
*/
|
|
88
|
+
export interface TelemetryRequestEnvelope {
|
|
89
|
+
readonly requestId: string;
|
|
90
|
+
readonly method: string;
|
|
91
|
+
readonly url: string;
|
|
92
|
+
readonly status: number;
|
|
93
|
+
readonly startedAt: number;
|
|
94
|
+
readonly durationMs: number;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* The finished, JSON-serializable view of a collected request: envelope, root
|
|
98
|
+
* spans, timestamped records by namespace, and what the caps discarded.
|
|
99
|
+
* Serializability is enforced by type only — no runtime validation. The
|
|
100
|
+
* envelope `url` is the full request URL, query string included — an
|
|
101
|
+
* exporter shipping snapshots off-box owns scrubbing query-borne secrets.
|
|
102
|
+
* @public consumer-facing (imported by exporters, not core)
|
|
103
|
+
*/
|
|
104
|
+
export interface TelemetrySnapshot {
|
|
105
|
+
readonly request: TelemetryRequestEnvelope;
|
|
106
|
+
readonly spans: readonly TelemetrySpan[];
|
|
107
|
+
readonly records: Readonly<Record<string, readonly TelemetryRecord[]>>;
|
|
108
|
+
readonly dropped: TelemetryDropped;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* A telemetry export destination, registered once in app config
|
|
112
|
+
* (`telemetry.consumers`). A request collects iff at least one registered
|
|
113
|
+
* consumer votes yes; with no consumers the collector stays the no-op and
|
|
114
|
+
* production pays nothing.
|
|
115
|
+
*/
|
|
116
|
+
export interface TelemetryConsumer {
|
|
117
|
+
readonly id: string;
|
|
118
|
+
/**
|
|
119
|
+
* Head-sampling vote, called once at context creation (before any
|
|
120
|
+
* collection — `ctx.telemetry` is not yet active). Omitted = always yes.
|
|
121
|
+
* Runs pre-auth: on public requests `ctx.user` is null even when a
|
|
122
|
+
* session cookie is present. A throwing vote fails the request — decide
|
|
123
|
+
* from cheap request-shaped facts and don't throw.
|
|
124
|
+
*/
|
|
125
|
+
readonly sample?: (ctx: AppContext) => boolean;
|
|
126
|
+
/**
|
|
127
|
+
* Receives the finished snapshot after the response (via `waitUntil` on
|
|
128
|
+
* Workers), so export latency never adds to response time. Errors live in
|
|
129
|
+
* the span tree — there is no separate error callback; an error-hook
|
|
130
|
+
* consumer may read the live `ctx.telemetry` mid-request instead.
|
|
131
|
+
*/
|
|
132
|
+
readonly onRequestEnd?: (snapshot: TelemetrySnapshot, ctx: AppContext) => void | Promise<void>;
|
|
133
|
+
}
|
|
134
|
+
/** The `telemetry` app-config slot. */
|
|
135
|
+
export interface TelemetryConfig {
|
|
136
|
+
readonly consumers?: readonly TelemetryConsumer[];
|
|
137
|
+
}
|
|
138
|
+
/** Shared no-op span handle: attributes (lazy or not) are never evaluated. */
|
|
139
|
+
export declare const NOOP_HANDLE: TelemetrySpanHandle;
|
|
140
|
+
/**
|
|
141
|
+
* The permanent no-op collector. Lives in core proper so plugin `ctx.telemetry`
|
|
142
|
+
* call sites stay safe everywhere: `record` drops the entry, `span` calls
|
|
143
|
+
* through and returns the result, reads are empty. The real collector is
|
|
144
|
+
* swapped in only when at least one registered consumer votes to sample the
|
|
145
|
+
* request — a site with no consumers pays nothing, in dev or prod.
|
|
146
|
+
*/
|
|
147
|
+
export declare const NOOP_TELEMETRY: TelemetryCollector;
|
|
148
|
+
//# sourceMappingURL=telemetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../../src/context/telemetry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Shared no-op span handle: attributes (lazy or not) are never evaluated. */
|
|
2
|
+
export const NOOP_HANDLE = {
|
|
3
|
+
set: () => undefined,
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* The permanent no-op collector. Lives in core proper so plugin `ctx.telemetry`
|
|
7
|
+
* call sites stay safe everywhere: `record` drops the entry, `span` calls
|
|
8
|
+
* through and returns the result, reads are empty. The real collector is
|
|
9
|
+
* swapped in only when at least one registered consumer votes to sample the
|
|
10
|
+
* request — a site with no consumers pays nothing, in dev or prod.
|
|
11
|
+
*/
|
|
12
|
+
export const NOOP_TELEMETRY = {
|
|
13
|
+
record: () => undefined,
|
|
14
|
+
span: (_name, fn) => fn(NOOP_HANDLE),
|
|
15
|
+
get: () => [],
|
|
16
|
+
getRecords: () => ({}),
|
|
17
|
+
getSpans: () => [],
|
|
18
|
+
getDropped: () => ({ spans: 0, records: {} }),
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=telemetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../../src/context/telemetry.ts"],"names":[],"mappings":"AA4JA,8EAA8E;AAC9E,MAAM,CAAC,MAAM,WAAW,GAAwB;IAC9C,GAAG,EAAE,GAAG,EAAE,CAAC,SAAS;CACrB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,cAAc,GAAuB;IAChD,MAAM,EAAE,GAAG,EAAE,CAAC,SAAS;IACvB,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC;IACpC,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE;IACb,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;IACtB,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAE;IAClB,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;CAC9C,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { TelemetryCollector } from "./telemetry.js";
|
|
2
|
+
/**
|
|
3
|
+
* Traced outbound HTTP — the `ctx.fetch` implementation. Same call surface as
|
|
4
|
+
* global `fetch`; every call runs inside a telemetry span carrying method, URL,
|
|
5
|
+
* and response status (OTel-mappable attribute keys), with the span's own
|
|
6
|
+
* duration and error capture covering timing and failure. The collector is read
|
|
7
|
+
* per call so activation at context creation is always observed.
|
|
8
|
+
*
|
|
9
|
+
* W3C trace-context propagation (`traceparent` injection) is deliberately not
|
|
10
|
+
* here — trace ids don't exist during the request. The future OTel exporter
|
|
11
|
+
* will need a request-mutation seam at this choke point.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createTracedFetch(getTelemetry: () => TelemetryCollector): typeof globalThis.fetch;
|
|
14
|
+
//# sourceMappingURL=traced-fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traced-fetch.d.ts","sourceRoot":"","sources":["../../src/context/traced-fetch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AASzD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,kBAAkB,GACrC,OAAO,UAAU,CAAC,KAAK,CAgBzB"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// The span label carries the host (not the full URL) so a timeline groups
|
|
2
|
+
// calls per upstream; the full URL lives in the `url.full` attribute.
|
|
3
|
+
function spanName(method, url) {
|
|
4
|
+
const host = URL.parse(url)?.host;
|
|
5
|
+
return host ? `fetch: ${method} ${host}` : `fetch: ${method}`;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Traced outbound HTTP — the `ctx.fetch` implementation. Same call surface as
|
|
9
|
+
* global `fetch`; every call runs inside a telemetry span carrying method, URL,
|
|
10
|
+
* and response status (OTel-mappable attribute keys), with the span's own
|
|
11
|
+
* duration and error capture covering timing and failure. The collector is read
|
|
12
|
+
* per call so activation at context creation is always observed.
|
|
13
|
+
*
|
|
14
|
+
* W3C trace-context propagation (`traceparent` injection) is deliberately not
|
|
15
|
+
* here — trace ids don't exist during the request. The future OTel exporter
|
|
16
|
+
* will need a request-mutation seam at this choke point.
|
|
17
|
+
*/
|
|
18
|
+
export function createTracedFetch(getTelemetry) {
|
|
19
|
+
return (input, init) => {
|
|
20
|
+
// `init.method` wins over a Request input's method — the same precedence
|
|
21
|
+
// `new Request(input, init)` applies inside fetch itself.
|
|
22
|
+
const method = (init?.method ?? (input instanceof Request ? input.method : "GET")).toUpperCase();
|
|
23
|
+
const url = input instanceof Request ? input.url : String(input);
|
|
24
|
+
return getTelemetry().span(spanName(method, url), async (s) => {
|
|
25
|
+
s.set("http.request.method", method);
|
|
26
|
+
s.set("url.full", url);
|
|
27
|
+
const response = await globalThis.fetch(input, init);
|
|
28
|
+
s.set("http.response.status_code", response.status);
|
|
29
|
+
return response;
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=traced-fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traced-fetch.js","sourceRoot":"","sources":["../../src/context/traced-fetch.ts"],"names":[],"mappings":"AAEA,0EAA0E;AAC1E,sEAAsE;AACtE,SAAS,QAAQ,CAAC,MAAc,EAAE,GAAW;IAC3C,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;IAClC,OAAO,IAAI,CAAC,CAAC,CAAC,UAAU,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,UAAU,MAAM,EAAE,CAAC;AAChE,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB,CAC/B,YAAsC;IAEtC,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,yEAAyE;QACzE,0DAA0D;QAC1D,MAAM,MAAM,GAAG,CACb,IAAI,EAAE,MAAM,IAAI,CAAC,KAAK,YAAY,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAClE,CAAC,WAAW,EAAE,CAAC;QAChB,MAAM,GAAG,GAAG,KAAK,YAAY,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACjE,OAAO,YAAY,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;YAC5D,CAAC,CAAC,GAAG,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;YACrC,CAAC,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;YACvB,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YACrD,CAAC,CAAC,GAAG,CAAC,2BAA2B,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;YACpD,OAAO,QAAQ,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Mailer } from "../auth/mailer/types.js";
|
|
2
|
+
import type { AssetsBinding, ConnectedCache, ConnectedObjectStorage } from "../runtime/slots.js";
|
|
3
|
+
import type { TelemetryCollector } from "./telemetry.js";
|
|
4
|
+
/**
|
|
5
|
+
* Platform I/O slot tracing — the counterpart of `createTracedFetch` for the
|
|
6
|
+
* remaining context slots (#1494). Each wrapper is applied once at context
|
|
7
|
+
* assembly; the collector is read per call so the post-vote swap in
|
|
8
|
+
* `createAppContext` is always observed, and with no consumer sampled every
|
|
9
|
+
* span() is the no-op pass-through.
|
|
10
|
+
*/
|
|
11
|
+
type GetTelemetry = () => TelemetryCollector;
|
|
12
|
+
export declare function traceCache(cache: ConnectedCache, getTelemetry: GetTelemetry): ConnectedCache;
|
|
13
|
+
export declare function traceAssets(assets: AssetsBinding, getTelemetry: GetTelemetry): AssetsBinding;
|
|
14
|
+
export declare function traceStorage(storage: ConnectedObjectStorage, getTelemetry: GetTelemetry): ConnectedObjectStorage;
|
|
15
|
+
export declare function traceMailer(mailer: Mailer, getTelemetry: GetTelemetry): Mailer;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=traced-slots.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traced-slots.d.ts","sourceRoot":"","sources":["../../src/context/traced-slots.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EACV,aAAa,EACb,cAAc,EACd,sBAAsB,EACvB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEzD;;;;;;GAMG;AACH,KAAK,YAAY,GAAG,MAAM,kBAAkB,CAAC;AAE7C,wBAAgB,UAAU,CACxB,KAAK,EAAE,cAAc,EACrB,YAAY,EAAE,YAAY,GACzB,cAAc,CAiBhB;AAED,wBAAgB,WAAW,CACzB,MAAM,EAAE,aAAa,EACrB,YAAY,EAAE,YAAY,GACzB,aAAa,CAUf;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,sBAAsB,EAC/B,YAAY,EAAE,YAAY,GACzB,sBAAsB,CA2BxB;AAED,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,YAAY,GACzB,MAAM,CASR"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export function traceCache(cache, getTelemetry) {
|
|
2
|
+
return {
|
|
3
|
+
match: (request) => getTelemetry().span("cache: match", async (s) => {
|
|
4
|
+
const hit = await cache.match(request);
|
|
5
|
+
s.set("cache.hit", hit !== undefined);
|
|
6
|
+
return hit;
|
|
7
|
+
}),
|
|
8
|
+
put: (request, response, tags) => getTelemetry().span("cache: put", (s) => {
|
|
9
|
+
s.set("cache.tags", () => [...tags]);
|
|
10
|
+
return cache.put(request, response, tags);
|
|
11
|
+
}),
|
|
12
|
+
// Untraced on purpose: purges fire post-response (after the snapshot is
|
|
13
|
+
// delivered), so a span here would dangle as an unfinished root.
|
|
14
|
+
purgeTags: (tags) => cache.purgeTags(tags),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function traceAssets(assets, getTelemetry) {
|
|
18
|
+
return {
|
|
19
|
+
fetch: (request) => getTelemetry().span("assets: fetch", async (s) => {
|
|
20
|
+
s.set("url.full", request.url);
|
|
21
|
+
const response = await assets.fetch(request);
|
|
22
|
+
s.set("http.response.status_code", response.status);
|
|
23
|
+
return response;
|
|
24
|
+
}),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export function traceStorage(storage, getTelemetry) {
|
|
28
|
+
const spanned = (op, key, run) => getTelemetry().span(`storage: ${op}`, (s) => {
|
|
29
|
+
s.set("storage.key", key);
|
|
30
|
+
return run();
|
|
31
|
+
});
|
|
32
|
+
const presignPut = storage.presignPut?.bind(storage);
|
|
33
|
+
return {
|
|
34
|
+
put: (key, body, opts) => spanned("put", key, () => storage.put(key, body, opts)),
|
|
35
|
+
get: (key, opts) => spanned("get", key, () => storage.get(key, opts)),
|
|
36
|
+
head: (key) => spanned("head", key, () => storage.head(key)),
|
|
37
|
+
delete: (key) => spanned("delete", key, () => storage.delete(key)),
|
|
38
|
+
list: (prefix, opts) => getTelemetry().span("storage: list", (s) => {
|
|
39
|
+
s.set("storage.prefix", prefix ?? "");
|
|
40
|
+
return storage.list(prefix, opts);
|
|
41
|
+
}),
|
|
42
|
+
// URL minting (plain URL math / local signing), not object I/O — spanning
|
|
43
|
+
// it would put 0ms noise rows next to real bucket round-trips.
|
|
44
|
+
url: (key, opts) => storage.url(key, opts),
|
|
45
|
+
...(presignPut ? { presignPut } : {}),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export function traceMailer(mailer, getTelemetry) {
|
|
49
|
+
return {
|
|
50
|
+
send: (message) => getTelemetry().span("mailer: send", (s) => {
|
|
51
|
+
s.set("mail.to", message.to);
|
|
52
|
+
s.set("mail.subject", message.subject);
|
|
53
|
+
return mailer.send(message);
|
|
54
|
+
}),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=traced-slots.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traced-slots.js","sourceRoot":"","sources":["../../src/context/traced-slots.ts"],"names":[],"mappings":"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"}
|
package/dist/db/libsql.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"libsql.d.ts","sourceRoot":"","sources":["../../src/db/libsql.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"libsql.d.ts","sourceRoot":"","sources":["../../src/db/libsql.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAI3D,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC,YAAY,CAAC,CAAC;AAEvD,MAAM,WAAW,qBAAsB,SAAQ,eAAe;IAC5D,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;CACpC;AAED;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,qBAAqB,CAyBvE"}
|
package/dist/db/libsql.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { createClient } from "@libsql/client";
|
|
2
2
|
import { drizzle } from "drizzle-orm/libsql";
|
|
3
|
-
import { createDebugSqlLogger } from "../debug-bar/db-query.js";
|
|
4
|
-
import { traceSqlClient } from "../debug-bar/trace-libsql.js";
|
|
5
3
|
import { resolveEnvInput } from "../runtime/env-input.js";
|
|
4
|
+
import { traceSqlClient } from "./trace-libsql.js";
|
|
6
5
|
/**
|
|
7
6
|
* Database adapter for any libSQL-compatible SQLite endpoint. Lives behind
|
|
8
7
|
* the `@plumix/core/db/libsql` subpath so the driver only loads when this
|
|
@@ -23,20 +22,15 @@ export function libsql(config) {
|
|
|
23
22
|
connect: (env, _request, schema) => {
|
|
24
23
|
if (!client) {
|
|
25
24
|
const resolved = resolveEnvInput(config, env);
|
|
26
|
-
|
|
25
|
+
// Unconditional: spans are no-ops unless a telemetry consumer
|
|
26
|
+
// sampled the request, so production without consumers pays nothing.
|
|
27
|
+
client = traceSqlClient(createClient({
|
|
27
28
|
url: resolved.url,
|
|
28
29
|
authToken: resolved.authToken,
|
|
29
|
-
});
|
|
30
|
-
// Dev-only: time each query as a span for the Timeline panel.
|
|
31
|
-
client = process.env.PLUMIX_DEV ? traceSqlClient(raw) : raw;
|
|
30
|
+
}));
|
|
32
31
|
}
|
|
33
32
|
return {
|
|
34
|
-
db: drizzle(client, {
|
|
35
|
-
schema,
|
|
36
|
-
casing: "snake_case",
|
|
37
|
-
// Dev-only: feed the debug bar's Database panel. Tree-shaken in prod.
|
|
38
|
-
logger: process.env.PLUMIX_DEV ? createDebugSqlLogger() : undefined,
|
|
39
|
-
}),
|
|
33
|
+
db: drizzle(client, { schema, casing: "snake_case" }),
|
|
40
34
|
};
|
|
41
35
|
},
|
|
42
36
|
};
|
package/dist/db/libsql.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"libsql.js","sourceRoot":"","sources":["../../src/db/libsql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAK7C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"libsql.js","sourceRoot":"","sources":["../../src/db/libsql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAK7C,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAsBnD;;;;;;;;GAQG;AACH,MAAM,UAAU,MAAM,CAAC,MAAyB;IAC9C,2EAA2E;IAC3E,qEAAqE;IACrE,0EAA0E;IAC1E,IAAI,MAAmD,CAAC;IACxD,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,MAAM;QACN,OAAO,EAAE,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE;YACjC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,QAAQ,GAAG,eAAe,CAAC,MAAM,EAAE,GAAgB,CAAC,CAAC;gBAC3D,8DAA8D;gBAC9D,qEAAqE;gBACrE,MAAM,GAAG,cAAc,CACrB,YAAY,CAAC;oBACX,GAAG,EAAE,QAAQ,CAAC,GAAG;oBACjB,SAAS,EAAE,QAAQ,CAAC,SAAS;iBAC9B,CAAC,CACH,CAAC;YACJ,CAAC;YACD,OAAO;gBACL,EAAE,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;aACtD,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
|