@plumix/core 0.5.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.
Files changed (76) hide show
  1. package/dist/context/app.d.ts +12 -0
  2. package/dist/context/app.d.ts.map +1 -1
  3. package/dist/context/app.js +10 -4
  4. package/dist/context/app.js.map +1 -1
  5. package/dist/context/memo.d.ts +22 -0
  6. package/dist/context/memo.d.ts.map +1 -0
  7. package/dist/context/memo.js +27 -0
  8. package/dist/context/memo.js.map +1 -0
  9. package/dist/context/traced-slots.d.ts +17 -0
  10. package/dist/context/traced-slots.d.ts.map +1 -0
  11. package/dist/context/traced-slots.js +57 -0
  12. package/dist/context/traced-slots.js.map +1 -0
  13. package/dist/entries/read-service.d.ts +6 -0
  14. package/dist/entries/read-service.d.ts.map +1 -1
  15. package/dist/entries/read-service.js +14 -0
  16. package/dist/entries/read-service.js.map +1 -1
  17. package/dist/index.d.ts +3 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +2 -0
  20. package/dist/index.js.map +1 -1
  21. package/dist/plugin/fields/entry.d.ts +8 -0
  22. package/dist/plugin/fields/entry.d.ts.map +1 -1
  23. package/dist/plugin/fields/entry.js.map +1 -1
  24. package/dist/plugin/lookup.d.ts +4 -9
  25. package/dist/plugin/lookup.d.ts.map +1 -1
  26. package/dist/plugin/manifest.d.ts +11 -32
  27. package/dist/plugin/manifest.d.ts.map +1 -1
  28. package/dist/plugin/manifest.js.map +1 -1
  29. package/dist/plugin/setup-context.d.ts +5 -0
  30. package/dist/plugin/setup-context.d.ts.map +1 -1
  31. package/dist/plugin/setup-context.js.map +1 -1
  32. package/dist/route/render/asset-manifest.d.ts +1 -1
  33. package/dist/route/render/asset-manifest.d.ts.map +1 -1
  34. package/dist/route/render/asset-manifest.js +7 -1
  35. package/dist/route/render/asset-manifest.js.map +1 -1
  36. package/dist/route/render/build-resolved-entries.d.ts.map +1 -1
  37. package/dist/route/render/build-resolved-entries.js +18 -10
  38. package/dist/route/render/build-resolved-entries.js.map +1 -1
  39. package/dist/route/render/render-template.d.ts +1 -1
  40. package/dist/route/render/render-template.d.ts.map +1 -1
  41. package/dist/route/render/render-template.js +38 -21
  42. package/dist/route/render/render-template.js.map +1 -1
  43. package/dist/rpc/meta/core.d.ts +3 -4
  44. package/dist/rpc/meta/core.d.ts.map +1 -1
  45. package/dist/rpc/meta/core.js +87 -152
  46. package/dist/rpc/meta/core.js.map +1 -1
  47. package/dist/rpc/procedures/entry/lookup.js +14 -11
  48. package/dist/rpc/procedures/entry/lookup.js.map +1 -1
  49. package/dist/rpc/procedures/lookup.errors.d.ts +2 -1
  50. package/dist/rpc/procedures/lookup.errors.d.ts.map +1 -1
  51. package/dist/rpc/procedures/lookup.errors.js +3 -0
  52. package/dist/rpc/procedures/lookup.errors.js.map +1 -1
  53. package/dist/rpc/procedures/term/lookup.js +3 -8
  54. package/dist/rpc/procedures/term/lookup.js.map +1 -1
  55. package/dist/runtime/dispatcher.d.ts.map +1 -1
  56. package/dist/runtime/dispatcher.js +70 -29
  57. package/dist/runtime/dispatcher.js.map +1 -1
  58. package/dist/telemetry-otel.d.ts +29 -0
  59. package/dist/telemetry-otel.d.ts.map +1 -0
  60. package/dist/telemetry-otel.js +218 -0
  61. package/dist/telemetry-otel.js.map +1 -0
  62. package/dist/template-deps-core.d.ts.map +1 -1
  63. package/dist/template-deps-core.js +31 -14
  64. package/dist/template-deps-core.js.map +1 -1
  65. package/dist/template-deps.d.ts.map +1 -1
  66. package/dist/template-deps.js +12 -8
  67. package/dist/template-deps.js.map +1 -1
  68. package/dist/test/index.d.ts +3 -0
  69. package/dist/test/index.d.ts.map +1 -1
  70. package/dist/test/index.js +4 -0
  71. package/dist/test/index.js.map +1 -1
  72. package/dist/test/traced-context.d.ts +17 -0
  73. package/dist/test/traced-context.d.ts.map +1 -0
  74. package/dist/test/traced-context.js +28 -0
  75. package/dist/test/traced-context.js.map +1 -0
  76. package/package.json +6 -2
@@ -0,0 +1,218 @@
1
+ const SPAN_KIND_INTERNAL = 1;
2
+ const SPAN_KIND_SERVER = 2;
3
+ const STATUS_CODE_ERROR = 2;
4
+ function randomHex(byteLength) {
5
+ const bytes = crypto.getRandomValues(new Uint8Array(byteLength));
6
+ return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
7
+ }
8
+ /** Epoch milliseconds → OTLP nanosecond string (exceeds Number range). */
9
+ function unixNano(ms) {
10
+ return (BigInt(Math.round(ms)) * 1000000n).toString();
11
+ }
12
+ /**
13
+ * OTLP attribute values are primitives or arrays of primitives; nested
14
+ * structures are JSON-stringified rather than projected onto `kvlistValue`.
15
+ */
16
+ function toAnyValue(value) {
17
+ if (typeof value === "string")
18
+ return { stringValue: value };
19
+ if (typeof value === "boolean")
20
+ return { boolValue: value };
21
+ if (typeof value === "number") {
22
+ // Beyond the safe range `String(n)` isn't a parseable int64 ("1e+21");
23
+ // a strict collector rejects the whole batch over one bad attribute.
24
+ return Number.isSafeInteger(value)
25
+ ? { intValue: String(value) }
26
+ : { doubleValue: value };
27
+ }
28
+ if (Array.isArray(value) && value.every((v) => typeof v !== "object")) {
29
+ return { arrayValue: { values: value.map(toAnyValue) } };
30
+ }
31
+ return { stringValue: JSON.stringify(value) };
32
+ }
33
+ // `Array.isArray` alone won't exclude `readonly JsonValue[]` from the union.
34
+ function isJsonObject(value) {
35
+ return typeof value === "object" && value !== null && !Array.isArray(value);
36
+ }
37
+ function toAttributes(record) {
38
+ return Object.entries(record).map(([key, value]) => ({
39
+ key,
40
+ value: toAnyValue(value),
41
+ }));
42
+ }
43
+ /** Depth-first projection of the collected tree, minting span ids on the way. */
44
+ function addTreeSpans(spans, traceId, parentSpanId, out) {
45
+ for (const span of spans) {
46
+ const spanId = randomHex(8);
47
+ const endTimeUnixNano = unixNano(span.startedAt + span.durationMs);
48
+ out.push({
49
+ traceId,
50
+ spanId,
51
+ parentSpanId,
52
+ name: span.name,
53
+ kind: SPAN_KIND_INTERNAL,
54
+ startTimeUnixNano: unixNano(span.startedAt),
55
+ endTimeUnixNano,
56
+ attributes: toAttributes(span.attributes),
57
+ ...(span.error && {
58
+ events: [
59
+ {
60
+ timeUnixNano: endTimeUnixNano,
61
+ name: "exception",
62
+ attributes: toAttributes({
63
+ "exception.type": span.error.name,
64
+ "exception.message": span.error.message,
65
+ ...(span.error.stack && {
66
+ "exception.stacktrace": span.error.stack,
67
+ }),
68
+ }),
69
+ },
70
+ ],
71
+ }),
72
+ status: span.status === "error"
73
+ ? { code: STATUS_CODE_ERROR, message: span.error?.message }
74
+ : {},
75
+ });
76
+ addTreeSpans(span.children, traceId, spanId, out);
77
+ }
78
+ }
79
+ /** Timestamped records → root-span events, the namespace as event name. */
80
+ function recordEvents(records) {
81
+ return Object.entries(records).flatMap(([namespace, entries]) => entries.map((record) => {
82
+ const data = record.data;
83
+ return {
84
+ timeUnixNano: unixNano(record.at),
85
+ name: namespace,
86
+ // Object payloads flatten into event attributes; anything else
87
+ // rides a single `data` attribute.
88
+ attributes: isJsonObject(data)
89
+ ? toAttributes(data)
90
+ : toAttributes({ data }),
91
+ };
92
+ }));
93
+ }
94
+ /**
95
+ * W3C trace-context `traceparent`: version-traceId-parentSpanId-flags. A
96
+ * valid inbound header joins this request's spans to the caller's trace;
97
+ * anything else (absent, malformed, all-zero ids, reserved version) is
98
+ * ignored and a fresh trace id is minted.
99
+ */
100
+ const TRACEPARENT_PATTERN = /^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/;
101
+ function parseTraceparent(header) {
102
+ const match = header ? TRACEPARENT_PATTERN.exec(header) : null;
103
+ if (!match)
104
+ return null;
105
+ const [, version = "", traceId = "", parentSpanId = ""] = match;
106
+ if (version === "ff")
107
+ return null;
108
+ if (/^0+$/.test(traceId) || /^0+$/.test(parentSpanId))
109
+ return null;
110
+ return { traceId, parentSpanId };
111
+ }
112
+ // No route abstraction reaches the snapshot; the raw path is the best label
113
+ // a CMS has. Deliberate semconv deviation (`{method} {route}` is preferred).
114
+ function rootSpanName(method, url) {
115
+ try {
116
+ return `${method} ${new URL(url).pathname}`;
117
+ }
118
+ catch {
119
+ return method;
120
+ }
121
+ }
122
+ // The envelope url keeps its query string and the exporter owns scrubbing
123
+ // query-borne secrets (see TelemetrySnapshot) — drop the query wholesale.
124
+ function scrubUrl(url) {
125
+ try {
126
+ const parsed = new URL(url);
127
+ return parsed.origin + parsed.pathname;
128
+ }
129
+ catch {
130
+ return url;
131
+ }
132
+ }
133
+ /**
134
+ * OTel trace exporter as a telemetry consumer: projects each collected
135
+ * snapshot onto an OTLP/HTTP JSON `ExportTraceServiceRequest` and POSTs it
136
+ * per request (from `waitUntil`, so export latency never blocks a response).
137
+ * Core spans carry no ids — trace/span ids are minted here at export time.
138
+ */
139
+ export function otelConsumer(options) {
140
+ const { sample, tailSample } = options;
141
+ return {
142
+ id: "otel",
143
+ ...(sample !== undefined && { sample: () => Math.random() < sample }),
144
+ onRequestEnd: async (snapshot, ctx) => {
145
+ if (tailSample && !tailSample(snapshot))
146
+ return;
147
+ // A failed export is an observability gap, never a request failure:
148
+ // the mapping too (records are `unknown` at runtime and can defeat
149
+ // JSON.stringify) — log and swallow so this promise cannot reject
150
+ // into `waitUntil`.
151
+ try {
152
+ const { request, spans: tree, records, dropped } = snapshot;
153
+ const inbound = parseTraceparent(ctx.request.headers.get("traceparent"));
154
+ const traceId = inbound?.traceId ?? randomHex(16);
155
+ const rootSpanId = randomHex(8);
156
+ const droppedRecords = Object.values(dropped.records).reduce((sum, count) => sum + count, 0);
157
+ const spans = [
158
+ {
159
+ traceId,
160
+ spanId: rootSpanId,
161
+ ...(inbound && { parentSpanId: inbound.parentSpanId }),
162
+ name: rootSpanName(request.method, request.url),
163
+ kind: SPAN_KIND_SERVER,
164
+ startTimeUnixNano: unixNano(request.startedAt),
165
+ endTimeUnixNano: unixNano(request.startedAt + request.durationMs),
166
+ attributes: toAttributes({
167
+ "http.request.method": request.method,
168
+ "url.full": scrubUrl(request.url),
169
+ "http.response.status_code": request.status,
170
+ "plumix.request_id": request.requestId,
171
+ // OTLP spans carry no dropped-child-span field; the cap
172
+ // overflow rides an attribute so truncation stays visible
173
+ // downstream.
174
+ ...(dropped.spans > 0 && {
175
+ "plumix.dropped_spans": dropped.spans,
176
+ }),
177
+ }),
178
+ events: recordEvents(records),
179
+ ...(droppedRecords > 0 && { droppedEventsCount: droppedRecords }),
180
+ // HTTP server semconv: only 5xx marks the server span failed.
181
+ status: request.status >= 500 ? { code: STATUS_CODE_ERROR } : {},
182
+ },
183
+ ];
184
+ addTreeSpans(tree, traceId, rootSpanId, spans);
185
+ const body = {
186
+ resourceSpans: [
187
+ {
188
+ resource: {
189
+ attributes: toAttributes({
190
+ "service.name": options.serviceName ?? "plumix",
191
+ }),
192
+ },
193
+ scopeSpans: [{ scope: { name: "plumix" }, spans }],
194
+ },
195
+ ],
196
+ };
197
+ const headers = new Headers(options.headers);
198
+ headers.set("content-type", "application/json");
199
+ const response = await (options.fetch ?? fetch)(options.endpoint, {
200
+ method: "POST",
201
+ headers,
202
+ body: JSON.stringify(body),
203
+ });
204
+ if (response.ok) {
205
+ // An unread body holds the connection open on Workers.
206
+ void response.body?.cancel();
207
+ }
208
+ else {
209
+ ctx.logger.error(`[plumix] otel export failed: ${String(response.status)} ${response.statusText} ${await response.text()}`);
210
+ }
211
+ }
212
+ catch (error) {
213
+ ctx.logger.error(`[plumix] otel export failed: ${error instanceof Error ? error.message : String(error)}`);
214
+ }
215
+ },
216
+ };
217
+ }
218
+ //# sourceMappingURL=telemetry-otel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry-otel.js","sourceRoot":"","sources":["../src/telemetry-otel.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"template-deps-core.d.ts","sourceRoot":"","sources":["../src/template-deps-core.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAMlE,OAAO,QAAQ,eAAe,CAAC;IAC7B,UAAU,mBAAmB;QAC3B,QAAQ,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;SAAE,CAAC;KAC7D;CACF;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,qBAAqB,GAC9B,IAAI,CAMN;AAED,wBAAsB,cAAc,CAClC,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,GAAG,EAAE,UAAU,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAiBlD"}
1
+ {"version":3,"file":"template-deps-core.d.ts","sourceRoot":"","sources":["../src/template-deps-core.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAOlE,OAAO,QAAQ,eAAe,CAAC;IAC7B,UAAU,mBAAmB;QAC3B,QAAQ,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;SAAE,CAAC;KAC7D;CACF;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,qBAAqB,GAC9B,IAAI,CAMN;AAED,wBAAsB,cAAc,CAClC,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,GAAG,EAAE,UAAU,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAqClD"}
@@ -1,4 +1,5 @@
1
1
  import { inArray } from "drizzle-orm";
2
+ import { memoBatch } from "./context/memo.js";
2
3
  import { settings } from "./db/schema/settings.js";
3
4
  /**
4
5
  * Seed the plugin registry with built-in template deps before plugin
@@ -14,22 +15,38 @@ export function registerCoreTemplateDeps(registry) {
14
15
  });
15
16
  }
16
17
  export async function settingsLoader(groups, ctx) {
17
- if (groups.length === 0)
18
+ const unique = [...new Set(groups)];
19
+ if (unique.length === 0)
18
20
  return {};
19
- const rows = await ctx.db
20
- .select({ group: settings.group, key: settings.key, value: settings.value })
21
- .from(settings)
22
- .where(inArray(settings.group, [...groups]));
23
- // Build a `Record<group, Record<key, value>>` so each declared
24
- // group maps to its full key/value bag. Groups that have no rows
25
- // surface as undefined in the per-group record but the caller's
26
- // `loadTemplateDeps` fills missing slugs with `null`.
21
+ // Per-group memo (#1493): head defaults, SEO surfaces, and the template
22
+ // dep all read `group='site'` in one request only the first pays a
23
+ // query. The lazy batch queries every requested group in one `IN(...)`;
24
+ // a group with no rows memoizes as `null` and stays absent from the
25
+ // result so the caller's `loadTemplateDeps` still fills missing slugs
26
+ // with `null`.
27
+ const bags = await memoBatch(ctx.memo, unique, (group) => `core:settings-group:${group}`, async () => {
28
+ const rows = await ctx.db
29
+ .select({
30
+ group: settings.group,
31
+ key: settings.key,
32
+ value: settings.value,
33
+ })
34
+ .from(settings)
35
+ .where(inArray(settings.group, unique));
36
+ const byGroup = new Map();
37
+ for (const row of rows) {
38
+ const bag = byGroup.get(row.group) ?? {};
39
+ bag[row.key] = row.value;
40
+ byGroup.set(row.group, bag);
41
+ }
42
+ return byGroup;
43
+ });
27
44
  const grouped = {};
28
- for (const row of rows) {
29
- const bag = grouped[row.group] ?? {};
30
- bag[row.key] = row.value;
31
- grouped[row.group] = bag;
32
- }
45
+ unique.forEach((group, i) => {
46
+ const bag = bags[i];
47
+ if (bag)
48
+ grouped[group] = bag;
49
+ });
33
50
  return grouped;
34
51
  }
35
52
  //# sourceMappingURL=template-deps-core.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"template-deps-core.js","sourceRoot":"","sources":["../src/template-deps-core.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAItC,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAWnD;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CACtC,QAA+B;IAE/B,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,EAAE;QACpC,IAAI,EAAE,UAAU;QAChB,YAAY,EAAE,IAAI;QAClB,IAAI,EAAE,cAAc;KACrB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAyB,EACzB,GAAe;IAEf,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACnC,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,EAAE;SACtB,MAAM,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC;SAC3E,IAAI,CAAC,QAAQ,CAAC;SACd,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IAC/C,+DAA+D;IAC/D,iEAAiE;IACjE,gEAAgE;IAChE,sDAAsD;IACtD,MAAM,OAAO,GAA4C,EAAE,CAAC;IAC5D,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACrC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC;IAC3B,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"template-deps-core.js","sourceRoot":"","sources":["../src/template-deps-core.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAItC,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAWnD;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CACtC,QAA+B;IAE/B,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,EAAE;QACpC,IAAI,EAAE,UAAU;QAChB,YAAY,EAAE,IAAI;QAClB,IAAI,EAAE,cAAc;KACrB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAyB,EACzB,GAAe;IAEf,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IACpC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACnC,wEAAwE;IACxE,qEAAqE;IACrE,wEAAwE;IACxE,oEAAoE;IACpE,sEAAsE;IACtE,eAAe;IACf,MAAM,IAAI,GAAG,MAAM,SAAS,CAC1B,GAAG,CAAC,IAAI,EACR,MAAM,EACN,CAAC,KAAK,EAAE,EAAE,CAAC,uBAAuB,KAAK,EAAE,EACzC,KAAK,IAAI,EAAE;QACT,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,EAAE;aACtB,MAAM,CAAC;YACN,KAAK,EAAE,QAAQ,CAAC,KAAK;YACrB,GAAG,EAAE,QAAQ,CAAC,GAAG;YACjB,KAAK,EAAE,QAAQ,CAAC,KAAK;SACtB,CAAC;aACD,IAAI,CAAC,QAAQ,CAAC;aACd,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;QAC1C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAmC,CAAC;QAC3D,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;YACzC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC9B,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC,CACF,CAAC;IACF,MAAM,OAAO,GAA4C,EAAE,CAAC;IAC5D,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,GAAG;YAAE,OAAO,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC;IAChC,CAAC,CAAC,CAAC;IACH,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"template-deps.d.ts","sourceRoot":"","sources":["../src/template-deps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EACV,uBAAuB,EACvB,mBAAmB,EACpB,MAAM,eAAe,CAAC;AAEvB;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,CAAC,KAAK,SAAS,MAAM,mBAAmB,IAAI,CACvE,KAAK,EAAE,SAAS,mBAAmB,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,EACpD,GAAG,EAAE,UAAU,KACZ,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;AAQ1E,KAAK,wBAAwB,GAAG,CAC9B,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,GAAG,EAAE,UAAU,KACZ,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEtC,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;IACxC,uEAAuE;IACvE,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;AAaD,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,MAAM,CAGtD,CAAC;AAEH;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,uBAAuB,GAAG,SAAS,EAC9C,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC1C,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,CAqB7C;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAC3C,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,qBAAqB,CAAC,EACpD,GAAG,EAAE,UAAU,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAUlD"}
1
+ {"version":3,"file":"template-deps.d.ts","sourceRoot":"","sources":["../src/template-deps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EACV,uBAAuB,EACvB,mBAAmB,EACpB,MAAM,eAAe,CAAC;AAEvB;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,CAAC,KAAK,SAAS,MAAM,mBAAmB,IAAI,CACvE,KAAK,EAAE,SAAS,mBAAmB,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,EACpD,GAAG,EAAE,UAAU,KACZ,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;AAQ1E,KAAK,wBAAwB,GAAG,CAC9B,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,GAAG,EAAE,UAAU,KACZ,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEtC,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;IACxC,uEAAuE;IACvE,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;AAaD,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,MAAM,CAGtD,CAAC;AAEH;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,uBAAuB,GAAG,SAAS,EAC9C,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC1C,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,CAqB7C;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAC3C,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,qBAAqB,CAAC,EACpD,GAAG,EAAE,UAAU,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAsBlD"}
@@ -58,17 +58,21 @@ export function mergeTemplateDepDeclarations(themeDeps, template) {
58
58
  * the deps map — themes use optional chaining (`settings?.["site"]`).
59
59
  */
60
60
  export async function loadTemplateDeps(template, registry, ctx) {
61
- const pending = [];
62
- for (const [kind, loader] of registry) {
63
- const declared = template[kind];
64
- if (!Array.isArray(declared) || declared.length === 0)
61
+ const declared = [];
62
+ for (const [kind, dep] of registry) {
63
+ const slugs = template[kind];
64
+ if (!Array.isArray(slugs) || slugs.length === 0)
65
65
  continue;
66
- const slugs = declared;
67
- pending.push(loadOne(kind, slugs, loader, ctx));
66
+ declared.push({ kind, slugs: slugs, dep });
68
67
  }
69
- if (pending.length === 0)
68
+ if (declared.length === 0)
70
69
  return {};
71
- return Object.fromEntries(await Promise.all(pending));
70
+ // Spanned only when there's work: an undeclared template skips the span so
71
+ // ordinary requests don't carry a 0ms `render: deps` row.
72
+ return ctx.telemetry.span("render: deps", async (s) => {
73
+ s.set("deps.kinds", () => declared.map((d) => d.kind));
74
+ return Object.fromEntries(await Promise.all(declared.map((d) => loadOne(d.kind, d.slugs, d.dep, ctx))));
75
+ });
72
76
  }
73
77
  async function loadOne(kind, slugs, loader, ctx) {
74
78
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"template-deps.js","sourceRoot":"","sources":["../src/template-deps.ts"],"names":[],"mappings":"AAoCA,wEAAwE;AACxE,wEAAwE;AACxE,iEAAiE;AACjE,sEAAsE;AACtE,oEAAoE;AACpE,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;AAChF,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC;IACrC,QAAQ;IACR,UAAU;IACV,wBAAwB;CACzB,CAAC,CAAC;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAwB,IAAI,GAAG,CAAC;IAClE,GAAG,mBAAmB;IACtB,GAAG,sBAAsB;CAC1B,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,UAAU,4BAA4B,CAC1C,SAA8C,EAC9C,QAA2C;IAE3C,MAAM,MAAM,GAAsC,EAAE,CAAC;IACrD,IAAI,SAAS,EAAE,CAAC;QACd,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YACtD,IAAI,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,SAAS;YAC5C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;gBAAE,MAAM,CAAC,IAAI,CAAC,GAAG,KAA0B,CAAC;QACtE,CAAC;IACH,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrD,IAAI,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS;QAC/C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,CAAC,IAAI,CAAC,GAAG,KAA0B,CAAC;QAC5C,CAAC;aAAM,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;YACvC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YAChC,MAAM,IAAI,GAAI,KAAwD,CACpE,IAAI,CACL,CAAC;YACF,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;gBAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;QAC/C,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,QAA2C,EAC3C,QAAoD,EACpD,GAAe;IAEf,MAAM,OAAO,GAA0D,EAAE,CAAC;IAC1E,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACtC,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QAChE,MAAM,KAAK,GAAG,QAA6B,CAAC;QAC5C,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IAClD,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACpC,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,KAAK,UAAU,OAAO,CACpB,IAAY,EACZ,KAAwB,EACxB,MAA6B,EAC7B,GAAe;IAEf,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC1C,4DAA4D;QAC5D,kCAAkC;QAClC,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;QACzE,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACxB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,EAAE;YAC3C,IAAI;YACJ,KAAK;YACL,GAAG,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;SACtD,CAAC,CAAC;QACH,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACpB,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"template-deps.js","sourceRoot":"","sources":["../src/template-deps.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,9 @@ export type { Factories } from "./factories.js";
3
3
  export { createTestDb } from "./harness.js";
4
4
  export { createDispatcherHarness, plumixRequest } from "./dispatcher.js";
5
5
  export type { DispatcherHarness, CreateDispatcherHarnessOptions, } from "./dispatcher.js";
6
+ export { createTracedContext } from "./traced-context.js";
7
+ export type { TracedContext } from "./traced-context.js";
8
+ export { createRequestMemo } from "../context/memo.js";
6
9
  export { createDeferQueue } from "./defer.js";
7
10
  export type { DeferQueue } from "./defer.js";
8
11
  export { createRpcHarness } from "./rpc.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,WAAW,EACX,SAAS,EACT,UAAU,EACV,UAAU,EACV,eAAe,EACf,cAAc,EACd,YAAY,EACZ,UAAU,EACV,cAAc,EACd,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,OAAO,EACP,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EACjB,YAAY,GACb,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACzE,YAAY,EACV,iBAAiB,EACjB,8BAA8B,GAC/B,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,YAAY,EACV,UAAU,EACV,uBAAuB,EACvB,cAAc,EACd,qBAAqB,EACrB,2BAA2B,GAC5B,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC1D,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC/D,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE/E,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAKrD,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,WAAW,EACX,SAAS,EACT,UAAU,EACV,UAAU,EACV,eAAe,EACf,cAAc,EACd,YAAY,EACZ,UAAU,EACV,cAAc,EACd,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,OAAO,EACP,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EACjB,YAAY,GACb,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACzE,YAAY,EACV,iBAAiB,EACjB,8BAA8B,GAC/B,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,YAAY,EACV,UAAU,EACV,uBAAuB,EACvB,cAAc,EACd,qBAAqB,EACrB,2BAA2B,GAC5B,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC1D,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC/D,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE/E,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAKrD,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC"}
@@ -4,6 +4,10 @@
4
4
  export { userFactory, adminUser, editorUser, authorUser, contributorUser, subscriberUser, entryFactory, draftEntry, publishedEntry, trashedEntry, termFactory, categoryTerm, tagTerm, inviteFactory, credentialFactory, sessionFactory, settingFactory, entryTermFactory, allowedDomainFactory, apiTokenFactory, authTokenFactory, oauthAccountFactory, deviceCodeFactory, factoriesFor, } from "./factories.js";
5
5
  export { createTestDb } from "./harness.js";
6
6
  export { createDispatcherHarness, plumixRequest } from "./dispatcher.js";
7
+ export { createTracedContext } from "./traced-context.js";
8
+ // Real request-memo implementation for hand-rolled AppContext stand-ins —
9
+ // service functions read through `ctx.memo`, so a stand-in needs one.
10
+ export { createRequestMemo } from "../context/memo.js";
7
11
  export { createDeferQueue } from "./defer.js";
8
12
  export { createRpcHarness } from "./rpc.js";
9
13
  export { buildRequest, TestResponse } from "./request.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/test/index.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,4EAA4E;AAC5E,wDAAwD;AAExD,OAAO,EACL,WAAW,EACX,SAAS,EACT,UAAU,EACV,UAAU,EACV,eAAe,EACf,cAAc,EACd,YAAY,EACZ,UAAU,EACV,cAAc,EACd,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,OAAO,EACP,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EACjB,YAAY,GACb,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAMzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAG9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAS5C,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG1D,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG/D,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAErD,2EAA2E;AAC3E,0EAA0E;AAC1E,2DAA2D;AAC3D,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/test/index.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,4EAA4E;AAC5E,wDAAwD;AAExD,OAAO,EACL,WAAW,EACX,SAAS,EACT,UAAU,EACV,UAAU,EACV,eAAe,EACf,cAAc,EACd,YAAY,EACZ,UAAU,EACV,cAAc,EACd,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,OAAO,EACP,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EACjB,YAAY,GACb,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAMzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAG1D,0EAA0E;AAC1E,sEAAsE;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAG9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAS5C,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG1D,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG/D,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAErD,2EAA2E;AAC3E,0EAA0E;AAC1E,2DAA2D;AAC3D,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { AppContext } from "../context/app.js";
2
+ import { createDispatcherHarness } from "./dispatcher.js";
3
+ export interface TracedContext {
4
+ readonly harness: Awaited<ReturnType<typeof createDispatcherHarness>>;
5
+ readonly ctx: AppContext;
6
+ /** Run `fn` with `ctx` in the ambient request store so DB spans attribute to it. */
7
+ readonly run: <T>(fn: () => Promise<T>) => Promise<T>;
8
+ /** Number of `db:` spans collected so far — one per query. */
9
+ readonly dbQueryCount: () => number;
10
+ }
11
+ /**
12
+ * A dispatcher harness plus a standalone request context with telemetry
13
+ * sampled on — for unit tests that assert how many queries a service
14
+ * function issues (request-memo coverage, N+1 guards).
15
+ */
16
+ export declare function createTracedContext(): Promise<TracedContext>;
17
+ //# sourceMappingURL=traced-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traced-context.d.ts","sourceRoot":"","sources":["../../src/test/traced-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC,CAAC;IACtE,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;IACzB,oFAAoF;IACpF,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IACtD,8DAA8D;IAC9D,QAAQ,CAAC,YAAY,EAAE,MAAM,MAAM,CAAC;CACrC;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,aAAa,CAAC,CAmBlE"}
@@ -0,0 +1,28 @@
1
+ import { createAppContext } from "../context/app.js";
2
+ import { requestStore } from "../context/stores.js";
3
+ import { createDispatcherHarness } from "./dispatcher.js";
4
+ /**
5
+ * A dispatcher harness plus a standalone request context with telemetry
6
+ * sampled on — for unit tests that assert how many queries a service
7
+ * function issues (request-memo coverage, N+1 guards).
8
+ */
9
+ export async function createTracedContext() {
10
+ const harness = await createDispatcherHarness();
11
+ const ctx = createAppContext({
12
+ db: harness.db,
13
+ env: harness.env,
14
+ request: new Request("https://cms.example/"),
15
+ hooks: harness.app.hooks,
16
+ plugins: harness.app.plugins,
17
+ telemetry: {
18
+ consumers: [{ id: "traced-context", onRequestEnd: () => undefined }],
19
+ },
20
+ });
21
+ return {
22
+ harness,
23
+ ctx,
24
+ run: (fn) => requestStore.run(ctx, fn),
25
+ dbQueryCount: () => ctx.telemetry.getSpans().filter((s) => s.name.startsWith("db:")).length,
26
+ };
27
+ }
28
+ //# sourceMappingURL=traced-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traced-context.js","sourceRoot":"","sources":["../../src/test/traced-context.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAW1D;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,MAAM,OAAO,GAAG,MAAM,uBAAuB,EAAE,CAAC;IAChD,MAAM,GAAG,GAAG,gBAAgB,CAAC;QAC3B,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,OAAO,EAAE,IAAI,OAAO,CAAC,sBAAsB,CAAC;QAC5C,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK;QACxB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO;QAC5B,SAAS,EAAE;YACT,SAAS,EAAE,CAAC,EAAE,EAAE,EAAE,gBAAgB,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC;SACrE;KACF,CAAC,CAAC;IACH,OAAO;QACL,OAAO;QACP,GAAG;QACH,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC;QACtC,YAAY,EAAE,GAAG,EAAE,CACjB,GAAG,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM;KAC1E,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plumix/core",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "description": "Plumix core: runtime, auth, data model, and plugin system",
6
6
  "license": "MIT",
@@ -68,6 +68,10 @@
68
68
  "./slugify": {
69
69
  "types": "./dist/slugify.d.ts",
70
70
  "default": "./dist/slugify.js"
71
+ },
72
+ "./telemetry-otel": {
73
+ "types": "./dist/telemetry-otel.d.ts",
74
+ "default": "./dist/telemetry-otel.js"
71
75
  }
72
76
  },
73
77
  "files": [
@@ -97,7 +101,7 @@
97
101
  "drizzle-valibot": "^0.4.2",
98
102
  "fishery": "^2.4.0",
99
103
  "valibot": "^1.4.2",
100
- "@plumix/blocks": "0.5.0"
104
+ "@plumix/blocks": "0.6.0"
101
105
  },
102
106
  "peerDependencies": {
103
107
  "@playwright/test": "^1.61.1",