@lunora/runtime 1.0.0-alpha.25 → 1.0.0-alpha.27

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/index.d.mts CHANGED
@@ -682,6 +682,16 @@ interface ObservabilityEvent {
682
682
  ok: boolean;
683
683
  /** Shard key for single-shard calls; absent for fan-outs. */
684
684
  shardKey?: string;
685
+ /**
686
+ * W3C trace context for this dispatch, generated once at dispatch entry (32-
687
+ * and 16-hex). A sink (e.g. `otlpSink`) reuses these for the dispatch's span
688
+ * instead of minting fresh ids, and the runtime propagates them to the shard
689
+ * as a `traceparent` so a container the handler calls can stitch its spans
690
+ * under the same trace. Absent on paths that don't originate a trace (a sink
691
+ * falls back to random ids).
692
+ */
693
+ spanId?: string;
694
+ traceId?: string;
685
695
  }
686
696
  /** Severity of a {@link LogEvent}, mirroring the usual console levels. */
687
697
  type LogLevel = "debug" | "error" | "info" | "log" | "warn";
@@ -2338,6 +2348,17 @@ interface WorkerOptions {
2338
2348
  */
2339
2349
  vectorIntrospector?: VectorIntrospector;
2340
2350
  /**
2351
+ * Voice-session Durable Object namespaces, keyed by the agent's
2352
+ * `lunora/agents.ts` export name (e.g. `{ support: env.VOICE_SUPPORT }`).
2353
+ * Codegen wires this for every voice-enabled agent. When set, the worker
2354
+ * exposes `/_lunora/voice/<agentExportName>` — a WebSocket upgrade that
2355
+ * resolves the caller's identity, forwards it on the server-minted
2356
+ * `x-lunora-userid` / `x-lunora-identity` headers, and hands the socket to
2357
+ * the agent's `VoiceSessionDO`. Omit it (voice-free apps) and the route does
2358
+ * not exist.
2359
+ */
2360
+ voiceAgents?: Record<string, ShardNamespaceLike>;
2361
+ /**
2341
2362
  * Resolver for the Cloudflare Workflows REST client, built from the
2342
2363
  * deployment `env` (its `CLOUDFLARE_ACCOUNT_ID` / `CLOUDFLARE_API_TOKEN`).
2343
2364
  * Set by the codegen-emitted worker entry (which depends on
package/dist/index.d.ts CHANGED
@@ -682,6 +682,16 @@ interface ObservabilityEvent {
682
682
  ok: boolean;
683
683
  /** Shard key for single-shard calls; absent for fan-outs. */
684
684
  shardKey?: string;
685
+ /**
686
+ * W3C trace context for this dispatch, generated once at dispatch entry (32-
687
+ * and 16-hex). A sink (e.g. `otlpSink`) reuses these for the dispatch's span
688
+ * instead of minting fresh ids, and the runtime propagates them to the shard
689
+ * as a `traceparent` so a container the handler calls can stitch its spans
690
+ * under the same trace. Absent on paths that don't originate a trace (a sink
691
+ * falls back to random ids).
692
+ */
693
+ spanId?: string;
694
+ traceId?: string;
685
695
  }
686
696
  /** Severity of a {@link LogEvent}, mirroring the usual console levels. */
687
697
  type LogLevel = "debug" | "error" | "info" | "log" | "warn";
@@ -2338,6 +2348,17 @@ interface WorkerOptions {
2338
2348
  */
2339
2349
  vectorIntrospector?: VectorIntrospector;
2340
2350
  /**
2351
+ * Voice-session Durable Object namespaces, keyed by the agent's
2352
+ * `lunora/agents.ts` export name (e.g. `{ support: env.VOICE_SUPPORT }`).
2353
+ * Codegen wires this for every voice-enabled agent. When set, the worker
2354
+ * exposes `/_lunora/voice/&lt;agentExportName>` — a WebSocket upgrade that
2355
+ * resolves the caller's identity, forwards it on the server-minted
2356
+ * `x-lunora-userid` / `x-lunora-identity` headers, and hands the socket to
2357
+ * the agent's `VoiceSessionDO`. Omit it (voice-free apps) and the route does
2358
+ * not exist.
2359
+ */
2360
+ voiceAgents?: Record<string, ShardNamespaceLike>;
2361
+ /**
2341
2362
  * Resolver for the Cloudflare Workflows REST client, built from the
2342
2363
  * deployment `env` (its `CLOUDFLARE_ACCOUNT_ID` / `CLOUDFLARE_API_TOKEN`).
2343
2364
  * Set by the codegen-emitted worker entry (which depends on
package/dist/index.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  export { toAirbyteMessages, toFivetranResponse } from './packem_shared/toAirbyteMessages-DrHdplb4.mjs';
2
- export { composeWorker, createLunoraHandler, createWorker, defineRpcEnvelope, resolveLunoraOptions, withFrameworkWorker } from './packem_shared/composeWorker-CxwkPZUl.mjs';
2
+ export { composeWorker, createLunoraHandler, createWorker, defineRpcEnvelope, resolveLunoraOptions, withFrameworkWorker } from './packem_shared/composeWorker-UZKPkF3Q.mjs';
3
3
  export { createCrossShardRelationCapabilities } from './packem_shared/createCrossShardRelationCapabilities-CbcWjkAn.mjs';
4
4
  export { DEFAULT_REGISTRY_CACHE_TTL_MS, SHARD_REGISTRY_DO_NAME, createDynamicShardRegistry } from './packem_shared/DEFAULT_REGISTRY_CACHE_TTL_MS-B3pA7aXp.mjs';
5
5
  export { LunoraError, toErrorResponse } from './packem_shared/LunoraError-Bpb9EFJ3.mjs';
6
6
  export { emitLogEvent, emitRpcEvent } from './packem_shared/emitLogEvent-pEdtqAK8.mjs';
7
- export { analyticsEngineSink, combineSinks, consoleSink, otlpSink, sentrySink, webhookSink } from './packem_shared/analyticsEngineSink-BpJlA7e9.mjs';
7
+ export { analyticsEngineSink, combineSinks, consoleSink, otlpSink, sentrySink, webhookSink } from './packem_shared/analyticsEngineSink-F-5ZAdUA.mjs';
8
8
  export { createQueryCoordinator, createStaticShardRegistry, mergeStrategyForAggregate } from './packem_shared/createQueryCoordinator-DNCJzOZE.mjs';
9
9
  export { applyJurisdiction, resolveShard } from './packem_shared/applyJurisdiction-BkZtTkct.mjs';
10
10
  export { decorateResponse, enforceOrigin, handleCorsPreflight, resolveSecurity } from './packem_shared/decorateResponse-DRWQFNhF.mjs';
@@ -1,81 +1,4 @@
1
- const OTLP_SEVERITY = {
2
- debug: 5,
3
- // DEBUG
4
- error: 17,
5
- // ERROR
6
- info: 9,
7
- // INFO
8
- log: 9,
9
- // INFO
10
- warn: 13
11
- // WARN
12
- };
13
- const otlpUnixNano = (ms) => `${String(Math.round(ms))}000000`;
14
- const otlpRandomHex = (bytes) => {
15
- const buffer = new Uint8Array(bytes);
16
- crypto.getRandomValues(buffer);
17
- let hex = "";
18
- for (const byte of buffer) {
19
- hex += byte.toString(16).padStart(2, "0");
20
- }
21
- return hex;
22
- };
23
- const encodeAttribute = (key, value) => {
24
- if (typeof value === "boolean") {
25
- return { key, value: { boolValue: value } };
26
- }
27
- if (typeof value === "number") {
28
- if (!Number.isFinite(value)) {
29
- return { key, value: { stringValue: String(value) } };
30
- }
31
- return Number.isSafeInteger(value) ? { key, value: { intValue: String(value) } } : { key, value: { doubleValue: value } };
32
- }
33
- return { key, value: { stringValue: value } };
34
- };
35
- const mergeHeaders = (defaults, overrides, token) => {
36
- const merged = {};
37
- const seen = /* @__PURE__ */ new Map();
38
- const put = (name, value) => {
39
- const lower = name.toLowerCase();
40
- const existing = seen.get(lower);
41
- if (existing === void 0) {
42
- seen.set(lower, name);
43
- merged[name] = value;
44
- } else {
45
- merged[existing] = value;
46
- }
47
- };
48
- for (const [name, value] of Object.entries(defaults)) {
49
- put(name, value);
50
- }
51
- for (const [name, value] of Object.entries(overrides ?? {})) {
52
- put(name, value);
53
- }
54
- if (token !== void 0 && token.length > 0) {
55
- put("authorization", `Bearer ${token}`);
56
- }
57
- return merged;
58
- };
59
- const wrapResourceSpans = (span, scopeName, serviceName) => {
60
- return {
61
- resourceSpans: [
62
- {
63
- resource: { attributes: [encodeAttribute("service.name", serviceName)] },
64
- scopeSpans: [{ scope: { name: scopeName }, spans: [span] }]
65
- }
66
- ]
67
- };
68
- };
69
- const wrapResourceLogs = (logRecord, scopeName, serviceName) => {
70
- return {
71
- resourceLogs: [
72
- {
73
- resource: { attributes: [encodeAttribute("service.name", serviceName)] },
74
- scopeLogs: [{ logRecords: [logRecord], scope: { name: scopeName } }]
75
- }
76
- ]
77
- };
78
- };
1
+ import { m as mergeHeaders, o as otlpRandomHex, w as wrapResourceSpans, a as wrapResourceLogs, e as encodeAttribute, O as OTLP_SEVERITY, c as otlpUnixNano } from './otlp-D_YzGXu1.mjs';
79
2
 
80
3
  const shouldSkip = (event, onlyErrors) => onlyErrors === true && event.ok;
81
4
  const otlpTraceBody = (event, serviceName, endMs) => {
@@ -99,11 +22,13 @@ const otlpTraceBody = (event, serviceName, endMs) => {
99
22
  // SPAN_KIND_SERVER — a dispatched RPC is server-side request handling.
100
23
  kind: 2,
101
24
  name: event.functionPath,
102
- spanId: otlpRandomHex(8),
25
+ // Reuse the dispatch's trace context when the runtime set it (so this span
26
+ // shares the id it propagated as `traceparent`); else mint fresh ids.
27
+ spanId: event.spanId ?? otlpRandomHex(8),
103
28
  startTimeUnixNano: otlpUnixNano(endMs - event.durationMs),
104
29
  // STATUS_CODE_OK (1) / STATUS_CODE_ERROR (2).
105
30
  status: event.ok ? { code: 1 } : { code: 2, message: event.error?.message ?? "" },
106
- traceId: otlpRandomHex(16)
31
+ traceId: event.traceId ?? otlpRandomHex(16)
107
32
  };
108
33
  return wrapResourceSpans(span, "@lunora/runtime", serviceName);
109
34
  };
@@ -1,5 +1,6 @@
1
1
  import { isLunoraError, toErrorBody } from '@lunora/errors';
2
2
  import { NOOP_EXECUTION_CONTEXT } from './NOOP_EXECUTION_CONTEXT-CCTu0Bf1.mjs';
3
+ import { o as otlpRandomHex, b as buildTraceparent } from './otlp-D_YzGXu1.mjs';
3
4
  import { LunoraError, toErrorResponse } from './LunoraError-Bpb9EFJ3.mjs';
4
5
  import { wrapResolverWithContract } from './composeIdentityResolvers-XGjO7V1J.mjs';
5
6
  export { composeIdentityResolvers, routeIdentityResolvers } from './composeIdentityResolvers-XGjO7V1J.mjs';
@@ -1916,12 +1917,24 @@ const NDJSON_ENCODER = new TextEncoder();
1916
1917
  const RPC_PATH = "/_lunora/rpc";
1917
1918
  const RPC_BATCH_PATH = "/_lunora/rpc-batch";
1918
1919
  const WS_PATH = "/_lunora/ws";
1920
+ const VOICE_PATH_PREFIX = "/_lunora/voice/";
1919
1921
  const SCHEDULER_DISPATCH_PATH = "/_lunora/scheduler/dispatch";
1920
1922
  const CRON_JOBS_RUN_PATH = "/_lunora/admin/cron-jobs/run";
1921
1923
  const ADMIN_PATH_PREFIX = "/_lunora/admin/";
1922
1924
  const MIGRATE_PATH = "/_lunora/migrate";
1923
1925
  const STATUS_PATH = "/_lunora/status";
1924
1926
  const isAdminPath = (pathname) => pathname.startsWith(ADMIN_PATH_PREFIX) || pathname === MIGRATE_PATH;
1927
+ const readForwardedIdentity = (request) => {
1928
+ const forwardedUserId = request.headers.get("x-lunora-userid");
1929
+ const forwardedIdentity = request.headers.get("x-lunora-identity");
1930
+ if (forwardedUserId === null && forwardedIdentity === null) {
1931
+ return void 0;
1932
+ }
1933
+ return {
1934
+ ...forwardedIdentity === null ? {} : { identity: forwardedIdentity },
1935
+ ...forwardedUserId === null ? {} : { userId: forwardedUserId }
1936
+ };
1937
+ };
1925
1938
  const DEFAULT_AUTH_BASE_PATH = "/api/auth";
1926
1939
  const RECORD_AUTH_EVENT_OP = "__lunora_admin__:recordAuthEvent";
1927
1940
  const AUTH_ATTEMPT_SEGMENTS = ["/sign-in", "/sign-up", "/callback"];
@@ -2239,7 +2252,7 @@ const createWorker = (options) => {
2239
2252
  resolveForwardContext: resolveAdminForwardContext,
2240
2253
  shardDO
2241
2254
  });
2242
- const dispatchToShard = async (functionPath, args, shardKey, mutationId) => {
2255
+ const dispatchToShard = async (functionPath, args, shardKey, mutationId, forwardedIdentity) => {
2243
2256
  if (options.authorizeShard) {
2244
2257
  const allowed = await options.authorizeShard(null, shardKey);
2245
2258
  if (!allowed) {
@@ -2247,6 +2260,12 @@ const createWorker = (options) => {
2247
2260
  }
2248
2261
  }
2249
2262
  const headers = { "content-type": "application/json", "x-lunora-system": "1" };
2263
+ if (forwardedIdentity?.userId !== void 0 && forwardedIdentity.userId.length > 0) {
2264
+ headers["x-lunora-userid"] = forwardedIdentity.userId;
2265
+ }
2266
+ if (forwardedIdentity?.identity !== void 0 && forwardedIdentity.identity.length > 0) {
2267
+ headers["x-lunora-identity"] = forwardedIdentity.identity;
2268
+ }
2250
2269
  if (mutationId !== void 0 && mutationId.length > 0) {
2251
2270
  headers["x-lunora-mutation-id"] = mutationId;
2252
2271
  }
@@ -2257,16 +2276,17 @@ const createWorker = (options) => {
2257
2276
  });
2258
2277
  return forwardToShard(shardDO, shardKey, forwarded);
2259
2278
  };
2260
- const startCronWorkflow = async (binding, job, env) => {
2279
+ const startWorkflowInstance = async (binding, args, env, label) => {
2261
2280
  const candidate = env?.[binding];
2262
2281
  if (!candidate || typeof candidate.create !== "function") {
2263
- throw new LunoraError(`cron job "${job.name}" targets workflow binding "${binding}", which is not bound on env`, {
2282
+ throw new LunoraError(`${label} targets workflow binding "${binding}", which is not bound on env`, {
2264
2283
  code: "CRON_JOB_FAILED",
2265
2284
  status: 500
2266
2285
  });
2267
2286
  }
2268
- await candidate.create({ params: job.args ?? {} });
2287
+ await candidate.create({ params: args });
2269
2288
  };
2289
+ const startCronWorkflow = async (binding, job, env) => startWorkflowInstance(binding, job.args ?? {}, env, `cron job "${job.name}"`);
2270
2290
  const runOneCronJob = async (job, env) => {
2271
2291
  if (job.workflow) {
2272
2292
  await startCronWorkflow(job.workflow, job, env);
@@ -2363,13 +2383,18 @@ const createWorker = (options) => {
2363
2383
  throw new LunoraError("Scheduler dispatch body must be valid JSON", { code: "BAD_REQUEST", status: 400 });
2364
2384
  }
2365
2385
  const candidate = body ?? {};
2386
+ const args = candidate.args ?? {};
2387
+ if (typeof candidate.workflow === "string" && candidate.workflow.length > 0) {
2388
+ await startWorkflowInstance(candidate.workflow, args, env, "scheduled workflow");
2389
+ return Response.json({ ok: true }, { status: 200 });
2390
+ }
2366
2391
  if (typeof candidate.functionPath !== "string" || candidate.functionPath.length === 0) {
2367
2392
  throw new LunoraError("Scheduler dispatch is missing `functionPath`", { code: "BAD_REQUEST", status: 400 });
2368
2393
  }
2369
- const args = candidate.args ?? {};
2370
2394
  const shardKey = typeof candidate.shardKey === "string" && candidate.shardKey.length > 0 ? candidate.shardKey : defaultShard;
2371
2395
  const mutationId = typeof candidate.id === "string" && candidate.id.length > 0 ? candidate.id : void 0;
2372
- const response = await dispatchToShard(candidate.functionPath, args, shardKey, mutationId);
2396
+ const identity = readForwardedIdentity(request);
2397
+ const response = await dispatchToShard(candidate.functionPath, args, shardKey, mutationId, identity);
2373
2398
  await releasePoolSlot(candidate);
2374
2399
  return response;
2375
2400
  };
@@ -2562,6 +2587,59 @@ const createWorker = (options) => {
2562
2587
  }
2563
2588
  return forwardToShard(shardDO, shardKey, new Request(request, { headers: upgradeHeaders }));
2564
2589
  };
2590
+ const handleVoiceUpgrade = async (request, env, url) => {
2591
+ const { voiceAgents } = options;
2592
+ if (voiceAgents === void 0) {
2593
+ return new Response("Not found", { status: 404 });
2594
+ }
2595
+ if (request.headers.get("Upgrade") !== "websocket") {
2596
+ return new Response("Expected a WebSocket upgrade", { headers: { allow: "GET" }, status: 426 });
2597
+ }
2598
+ const blockedUpgrade = enforceWebSocketOrigin(request, resolvedSecurity);
2599
+ if (blockedUpgrade) {
2600
+ return blockedUpgrade;
2601
+ }
2602
+ let agentName;
2603
+ try {
2604
+ agentName = decodeURIComponent(url.pathname.slice(VOICE_PATH_PREFIX.length));
2605
+ } catch {
2606
+ return new Response("Unknown voice agent", { status: 404 });
2607
+ }
2608
+ const namespace = Object.hasOwn(voiceAgents, agentName) ? voiceAgents[agentName] : void 0;
2609
+ if (namespace === void 0) {
2610
+ return new Response("Unknown voice agent", { status: 404 });
2611
+ }
2612
+ const threadKey = url.searchParams.get("threadKey");
2613
+ if (threadKey === null || threadKey.length === 0) {
2614
+ return new Response("Missing threadKey", { status: 400 });
2615
+ }
2616
+ const { headers: forwardedHeaders, identity } = await resolveForwardContext(request, env, publicResolveIdentity);
2617
+ if (options.authorizeShard) {
2618
+ const allowed = await options.authorizeShard(identity, threadKey);
2619
+ if (!allowed) {
2620
+ return new Response("Forbidden", { status: 403 });
2621
+ }
2622
+ } else {
2623
+ guardUnauthenticatedShardAccess("shard");
2624
+ }
2625
+ const upgradeHeaders = new Headers(request.headers);
2626
+ upgradeHeaders.delete("x-lunora-userid");
2627
+ upgradeHeaders.delete("x-lunora-identity");
2628
+ upgradeHeaders.delete("x-lunora-identity-exp");
2629
+ const forwardedUserId = forwardedHeaders["x-lunora-userid"];
2630
+ const forwardedIdentity = forwardedHeaders["x-lunora-identity"];
2631
+ const forwardedExp = forwardedHeaders["x-lunora-identity-exp"];
2632
+ if (forwardedUserId !== void 0) {
2633
+ upgradeHeaders.set("x-lunora-userid", forwardedUserId);
2634
+ }
2635
+ if (forwardedIdentity !== void 0) {
2636
+ upgradeHeaders.set("x-lunora-identity", forwardedIdentity);
2637
+ }
2638
+ if (forwardedExp !== void 0) {
2639
+ upgradeHeaders.set("x-lunora-identity-exp", forwardedExp);
2640
+ }
2641
+ return forwardToShard(namespace, threadKey, new Request(request, { headers: upgradeHeaders }));
2642
+ };
2565
2643
  const authorizeFanOutEnvelope = async (fanOut, functionPath, identity) => {
2566
2644
  if (options.authorizeFanOut) {
2567
2645
  const allowed = await options.authorizeFanOut(identity, fanOut.table, functionPath);
@@ -2605,9 +2683,11 @@ const createWorker = (options) => {
2605
2683
  const dispatchSingleShard = async (functionPath, args, shardKey, forwardedHeaders, sinkContext) => {
2606
2684
  const rpcStartedAt = Date.now();
2607
2685
  const { observability } = options;
2686
+ const traceId = otlpRandomHex(16);
2687
+ const spanId = otlpRandomHex(8);
2608
2688
  const forwarded = new Request(`https://shard.internal/rpc`, {
2609
2689
  body: JSON.stringify({ args, functionPath }),
2610
- headers: forwardedHeaders,
2690
+ headers: { ...forwardedHeaders, traceparent: buildTraceparent(traceId, spanId) },
2611
2691
  method: "POST"
2612
2692
  });
2613
2693
  try {
@@ -2619,13 +2699,15 @@ const createWorker = (options) => {
2619
2699
  functionPath,
2620
2700
  ok: response.ok,
2621
2701
  shardKey,
2702
+ spanId,
2703
+ traceId,
2622
2704
  ...response.ok ? {} : { error: { code: "SHARD_ERROR", message: `shard returned ${String(response.status)}`, status: response.status } }
2623
2705
  },
2624
2706
  sinkContext
2625
2707
  );
2626
2708
  return response;
2627
2709
  } catch (error) {
2628
- emitRpcEvent(observability, buildErrorEvent(functionPath, Date.now() - rpcStartedAt, error, { shardKey }), sinkContext);
2710
+ emitRpcEvent(observability, { ...buildErrorEvent(functionPath, Date.now() - rpcStartedAt, error, { shardKey }), spanId, traceId }, sinkContext);
2629
2711
  throw error;
2630
2712
  }
2631
2713
  };
@@ -3086,6 +3168,9 @@ const createWorker = (options) => {
3086
3168
  await applyAdminGate(request, url.pathname);
3087
3169
  return internalRoute(request, env, url, context);
3088
3170
  }
3171
+ if (options.voiceAgents !== void 0 && url.pathname.startsWith(VOICE_PATH_PREFIX)) {
3172
+ return handleVoiceUpgrade(request, env, url);
3173
+ }
3089
3174
  const httpRouteResponse = await dispatchHttpRoute(request, env, context);
3090
3175
  if (httpRouteResponse) {
3091
3176
  return httpRouteResponse;
@@ -0,0 +1,81 @@
1
+ const OTLP_SEVERITY = {
2
+ debug: 5,
3
+ // DEBUG
4
+ error: 17,
5
+ // ERROR
6
+ info: 9,
7
+ // INFO
8
+ log: 9,
9
+ // INFO
10
+ warn: 13
11
+ // WARN
12
+ };
13
+ const otlpUnixNano = (ms) => `${String(Math.round(ms))}000000`;
14
+ const otlpRandomHex = (bytes) => {
15
+ const buffer = new Uint8Array(bytes);
16
+ crypto.getRandomValues(buffer);
17
+ let hex = "";
18
+ for (const byte of buffer) {
19
+ hex += byte.toString(16).padStart(2, "0");
20
+ }
21
+ return hex;
22
+ };
23
+ const buildTraceparent = (traceId, spanId) => `00-${traceId}-${spanId}-01`;
24
+ const encodeAttribute = (key, value) => {
25
+ if (typeof value === "boolean") {
26
+ return { key, value: { boolValue: value } };
27
+ }
28
+ if (typeof value === "number") {
29
+ if (!Number.isFinite(value)) {
30
+ return { key, value: { stringValue: String(value) } };
31
+ }
32
+ return Number.isSafeInteger(value) ? { key, value: { intValue: String(value) } } : { key, value: { doubleValue: value } };
33
+ }
34
+ return { key, value: { stringValue: value } };
35
+ };
36
+ const mergeHeaders = (defaults, overrides, token) => {
37
+ const merged = {};
38
+ const seen = /* @__PURE__ */ new Map();
39
+ const put = (name, value) => {
40
+ const lower = name.toLowerCase();
41
+ const existing = seen.get(lower);
42
+ if (existing === void 0) {
43
+ seen.set(lower, name);
44
+ merged[name] = value;
45
+ } else {
46
+ merged[existing] = value;
47
+ }
48
+ };
49
+ for (const [name, value] of Object.entries(defaults)) {
50
+ put(name, value);
51
+ }
52
+ for (const [name, value] of Object.entries(overrides ?? {})) {
53
+ put(name, value);
54
+ }
55
+ if (token !== void 0 && token.length > 0) {
56
+ put("authorization", `Bearer ${token}`);
57
+ }
58
+ return merged;
59
+ };
60
+ const wrapResourceSpans = (span, scopeName, serviceName) => {
61
+ return {
62
+ resourceSpans: [
63
+ {
64
+ resource: { attributes: [encodeAttribute("service.name", serviceName)] },
65
+ scopeSpans: [{ scope: { name: scopeName }, spans: [span] }]
66
+ }
67
+ ]
68
+ };
69
+ };
70
+ const wrapResourceLogs = (logRecord, scopeName, serviceName) => {
71
+ return {
72
+ resourceLogs: [
73
+ {
74
+ resource: { attributes: [encodeAttribute("service.name", serviceName)] },
75
+ scopeLogs: [{ logRecords: [logRecord], scope: { name: scopeName } }]
76
+ }
77
+ ]
78
+ };
79
+ };
80
+
81
+ export { OTLP_SEVERITY as O, wrapResourceLogs as a, buildTraceparent as b, otlpUnixNano as c, encodeAttribute as e, mergeHeaders as m, otlpRandomHex as o, wrapResourceSpans as w };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/runtime",
3
- "version": "1.0.0-alpha.25",
3
+ "version": "1.0.0-alpha.27",
4
4
  "description": "Lunora Worker runtime: the RPC router, shard resolver, and query coordinator",
5
5
  "keywords": [
6
6
  "cloudflare",