@lunora/runtime 1.0.0-alpha.34 → 1.0.0-alpha.36
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 +1853 -1012
- package/dist/index.d.ts +1853 -1012
- package/dist/index.mjs +6 -3
- package/dist/packem_shared/HEALTH_PATH-e5J_NHBx.mjs +150 -0
- package/dist/packem_shared/{analyticsEngineSink-DE48mQA9.mjs → analyticsEngineSink-yLFNjHDt.mjs} +74 -17
- package/dist/packem_shared/argsFromQuery-c-U1WRy-.mjs +121 -0
- package/dist/packem_shared/{composeWorker-DAwO9LLs.mjs → composeWorker-DiWwOXXt.mjs} +475 -94
- package/dist/packem_shared/createKvCursorStore-g8aA6B4L.mjs +165 -0
- package/dist/packem_shared/emitLogEvent-BlGMnKZK.mjs +1 -0
- package/dist/packem_shared/method-guard-Qzw99aCj.mjs +3 -0
- package/dist/packem_shared/observability--NOFYBFc.mjs +47 -0
- package/dist/packem_shared/otlp-resource-Dow6-F_u.mjs +163 -0
- package/package.json +3 -3
- package/dist/packem_shared/emitLogEvent-pEdtqAK8.mjs +0 -20
- package/dist/packem_shared/otlp-DOLuy1Aj.mjs +0 -95
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
const defaultSleep = (ms) => new Promise((resolve) => {
|
|
2
|
+
setTimeout(resolve, ms);
|
|
3
|
+
});
|
|
4
|
+
const sanitizeChange = (raw) => {
|
|
5
|
+
const table = typeof raw["table"] === "string" ? raw["table"] : "";
|
|
6
|
+
const rawOp = typeof raw["op"] === "string" ? raw["op"] : "";
|
|
7
|
+
const op = rawOp === "delete" || rawOp === "insert" || rawOp === "update" ? rawOp : "upsert";
|
|
8
|
+
const id = typeof raw["id"] === "string" ? raw["id"] : void 0;
|
|
9
|
+
const documentRow = raw["doc"] && typeof raw["doc"] === "object" ? raw["doc"] : void 0;
|
|
10
|
+
const seq = typeof raw["seq"] === "number" && Number.isFinite(raw["seq"]) ? raw["seq"] : void 0;
|
|
11
|
+
const ts = typeof raw["ts"] === "number" && Number.isFinite(raw["ts"]) ? raw["ts"] : void 0;
|
|
12
|
+
return {
|
|
13
|
+
op,
|
|
14
|
+
table,
|
|
15
|
+
...documentRow === void 0 ? {} : { doc: documentRow },
|
|
16
|
+
...id === void 0 ? {} : { id },
|
|
17
|
+
...seq === void 0 ? {} : { seq },
|
|
18
|
+
...ts === void 0 ? {} : { ts }
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
const deliverWithRetry = async (sink, batch, maxRetries, initialBackoffMs, maxBackoffMs, sleep) => {
|
|
22
|
+
let attempt = 0;
|
|
23
|
+
while (true) {
|
|
24
|
+
try {
|
|
25
|
+
await sink.deliver(batch);
|
|
26
|
+
return;
|
|
27
|
+
} catch (error) {
|
|
28
|
+
if (attempt >= maxRetries) {
|
|
29
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
30
|
+
}
|
|
31
|
+
const delay = Math.min(initialBackoffMs * 2 ** attempt, maxBackoffMs);
|
|
32
|
+
await sleep(delay);
|
|
33
|
+
attempt += 1;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const runExportTap = async (options) => {
|
|
38
|
+
const {
|
|
39
|
+
coordinator,
|
|
40
|
+
cursorStore,
|
|
41
|
+
headers,
|
|
42
|
+
initialBackoffMs = 100,
|
|
43
|
+
limit,
|
|
44
|
+
maxBackoffMs = 5e3,
|
|
45
|
+
maxRetries = 3,
|
|
46
|
+
shardDO,
|
|
47
|
+
sink,
|
|
48
|
+
sleep = defaultSleep,
|
|
49
|
+
tables
|
|
50
|
+
} = options;
|
|
51
|
+
const priorCursors = await cursorStore.read(sink.name);
|
|
52
|
+
const feed = await coordinator.orchestrateCdcSync(shardDO, { cursors: priorCursors, headers, limit, tables });
|
|
53
|
+
const nextCursors = { ...priorCursors };
|
|
54
|
+
const failures = [];
|
|
55
|
+
let delivered = 0;
|
|
56
|
+
let hasMore = false;
|
|
57
|
+
for (const shard of feed.shards) {
|
|
58
|
+
if (shard.error) {
|
|
59
|
+
failures.push({ error: shard.error.message, shardKey: shard.shardKey });
|
|
60
|
+
hasMore = true;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const rawChanges = shard.changes ?? [];
|
|
64
|
+
if (rawChanges.length === 0) {
|
|
65
|
+
nextCursors[shard.shardKey] = shard.cursor;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const changes = rawChanges.map((change) => sanitizeChange(change));
|
|
69
|
+
const batch = { changes, cursor: shard.cursor, shardKey: shard.shardKey, sink: sink.name };
|
|
70
|
+
try {
|
|
71
|
+
await deliverWithRetry(sink, batch, maxRetries, initialBackoffMs, maxBackoffMs, sleep);
|
|
72
|
+
nextCursors[shard.shardKey] = shard.cursor;
|
|
73
|
+
delivered += changes.length;
|
|
74
|
+
if (limit !== void 0 && rawChanges.length >= limit) {
|
|
75
|
+
hasMore = true;
|
|
76
|
+
}
|
|
77
|
+
} catch (error) {
|
|
78
|
+
failures.push({ error: error instanceof Error ? error.message : String(error), shardKey: shard.shardKey });
|
|
79
|
+
hasMore = true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
await cursorStore.write(sink.name, nextCursors);
|
|
83
|
+
return { cursors: nextCursors, delivered, failures, hasMore, shards: feed.shards.length };
|
|
84
|
+
};
|
|
85
|
+
const defineExportSink = (config) => {
|
|
86
|
+
if (typeof config.name !== "string" || config.name.length === 0) {
|
|
87
|
+
throw new Error("defineExportSink: `name` must be a non-empty string");
|
|
88
|
+
}
|
|
89
|
+
if (typeof config.deliver !== "function") {
|
|
90
|
+
throw new TypeError("defineExportSink: `deliver` must be a function");
|
|
91
|
+
}
|
|
92
|
+
return { deliver: config.deliver, name: config.name };
|
|
93
|
+
};
|
|
94
|
+
const encodeNdjson = (changes) => `${changes.map((change) => JSON.stringify(change)).join("\n")}
|
|
95
|
+
`;
|
|
96
|
+
const webhookExportSink = (config) => {
|
|
97
|
+
const fetchImpl = config.fetchImpl ?? ((input, init) => fetch(input, init));
|
|
98
|
+
return defineExportSink({
|
|
99
|
+
deliver: async (batch) => {
|
|
100
|
+
const response = await fetchImpl(config.url, {
|
|
101
|
+
body: encodeNdjson(batch.changes),
|
|
102
|
+
headers: {
|
|
103
|
+
"content-type": "application/x-ndjson",
|
|
104
|
+
"x-lunora-cursor": String(batch.cursor),
|
|
105
|
+
"x-lunora-shard": batch.shardKey,
|
|
106
|
+
"x-lunora-sink": batch.sink,
|
|
107
|
+
...config.headers
|
|
108
|
+
},
|
|
109
|
+
method: "POST"
|
|
110
|
+
});
|
|
111
|
+
if (!response.ok) {
|
|
112
|
+
throw new Error(`webhook export sink "${config.name}" returned ${String(response.status)}`);
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
name: config.name
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
const r2Sink = (config) => {
|
|
119
|
+
let prefix = config.prefix ?? "cdc";
|
|
120
|
+
while (prefix.endsWith("/")) {
|
|
121
|
+
prefix = prefix.slice(0, -1);
|
|
122
|
+
}
|
|
123
|
+
return defineExportSink({
|
|
124
|
+
deliver: async (batch) => {
|
|
125
|
+
const key = `${prefix}/${batch.shardKey}/${String(batch.cursor)}.ndjson`;
|
|
126
|
+
await config.bucket.put(key, encodeNdjson(batch.changes), { httpMetadata: { contentType: "application/x-ndjson" } });
|
|
127
|
+
},
|
|
128
|
+
name: config.name
|
|
129
|
+
});
|
|
130
|
+
};
|
|
131
|
+
const createMemoryCursorStore = () => {
|
|
132
|
+
const state = {};
|
|
133
|
+
return {
|
|
134
|
+
read: (sink) => Promise.resolve({ ...state[sink] }),
|
|
135
|
+
snapshot: () => structuredClone(state),
|
|
136
|
+
write: (sink, cursors) => {
|
|
137
|
+
state[sink] = { ...cursors };
|
|
138
|
+
return Promise.resolve();
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
const createKvCursorStore = (kv, options) => {
|
|
143
|
+
const keyPrefix = options?.keyPrefix ?? "__lunora_source_cursor:export";
|
|
144
|
+
const keyFor = (sink) => `${keyPrefix}:${sink}`;
|
|
145
|
+
return {
|
|
146
|
+
read: async (sink) => {
|
|
147
|
+
const raw = await kv.get(keyFor(sink), "json");
|
|
148
|
+
if (raw === null || typeof raw !== "object") {
|
|
149
|
+
return {};
|
|
150
|
+
}
|
|
151
|
+
const cursors = {};
|
|
152
|
+
for (const [shardKey, value] of Object.entries(raw)) {
|
|
153
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
154
|
+
cursors[shardKey] = value;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return cursors;
|
|
158
|
+
},
|
|
159
|
+
write: async (sink, cursors) => {
|
|
160
|
+
await kv.put(keyFor(sink), JSON.stringify(cursors));
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
export { createKvCursorStore, createMemoryCursorStore, defineExportSink, r2Sink, runExportTap, sanitizeChange, webhookExportSink };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { e as emitLogEvent, a as emitRpcEvent } from './observability--NOFYBFc.mjs';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const DEFAULT_TRACE_HEAD_RATE = 1;
|
|
2
|
+
const traceIdToUnitInterval = (traceId) => {
|
|
3
|
+
const int = Number.parseInt(traceId.slice(0, 8), 16);
|
|
4
|
+
return Number.isFinite(int) ? int / 4294967296 : 0;
|
|
5
|
+
};
|
|
6
|
+
const isTraceHeadSampled = (traceId, headRate = DEFAULT_TRACE_HEAD_RATE) => {
|
|
7
|
+
if (headRate >= 1) {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
if (headRate <= 0) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
return traceIdToUnitInterval(traceId) < headRate;
|
|
14
|
+
};
|
|
15
|
+
const resolveTraceSampling = (config, traceId) => {
|
|
16
|
+
return {
|
|
17
|
+
isTraced: isTraceHeadSampled(traceId, config?.headRate ?? DEFAULT_TRACE_HEAD_RATE),
|
|
18
|
+
keepErrors: config?.alwaysSampleErrors ?? true
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
const shouldExportTrace = (decision, traceHasError) => {
|
|
22
|
+
return decision.isTraced || decision.keepErrors && traceHasError;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const emitRpcEvent = (sink, event, context, sampling) => {
|
|
26
|
+
if (!sink?.onRpc) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (sampling !== void 0 && event.traceId !== void 0 && !shouldExportTrace(resolveTraceSampling(sampling, event.traceId), !event.ok)) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
sink.onRpc(event, context);
|
|
34
|
+
} catch {
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const emitLogEvent = (sink, event, context) => {
|
|
38
|
+
if (!sink?.onLog) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
sink.onLog(event, context);
|
|
43
|
+
} catch {
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export { emitRpcEvent as a, emitLogEvent as e, resolveTraceSampling as r };
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
const OTLP_SEVERITY = {
|
|
2
|
+
debug: 5,
|
|
3
|
+
// DEBUG
|
|
4
|
+
error: 17,
|
|
5
|
+
// ERROR
|
|
6
|
+
fatal: 21,
|
|
7
|
+
// FATAL
|
|
8
|
+
info: 9,
|
|
9
|
+
// INFO
|
|
10
|
+
log: 9,
|
|
11
|
+
// INFO
|
|
12
|
+
trace: 1,
|
|
13
|
+
// TRACE
|
|
14
|
+
warn: 13
|
|
15
|
+
// WARN
|
|
16
|
+
};
|
|
17
|
+
const otlpUnixNano = (ms) => `${String(Math.round(ms))}000000`;
|
|
18
|
+
const otlpRandomHex = (bytes) => {
|
|
19
|
+
const buffer = new Uint8Array(bytes);
|
|
20
|
+
crypto.getRandomValues(buffer);
|
|
21
|
+
let hex = "";
|
|
22
|
+
for (const byte of buffer) {
|
|
23
|
+
hex += byte.toString(16).padStart(2, "0");
|
|
24
|
+
}
|
|
25
|
+
return hex;
|
|
26
|
+
};
|
|
27
|
+
const HEX_ONLY = /^[0-9a-f]+$/;
|
|
28
|
+
const buildTraceparent = (traceId, spanId, sampled = true) => `00-${traceId}-${spanId}-${sampled ? "01" : "00"}`;
|
|
29
|
+
const parseTraceparent = (header) => {
|
|
30
|
+
if (header === null || header === void 0) {
|
|
31
|
+
return void 0;
|
|
32
|
+
}
|
|
33
|
+
const parts = header.trim().toLowerCase().split("-");
|
|
34
|
+
const [version, traceId, parentSpanId, flags] = parts;
|
|
35
|
+
if (parts.length < 4 || version === void 0 || version.length !== 2 || !HEX_ONLY.test(version) || version === "ff" || // Version 00 forbids trailing fields; only a future version may carry them.
|
|
36
|
+
version === "00" && parts.length !== 4 || traceId === void 0 || parentSpanId === void 0 || flags === void 0 || flags.length !== 2 || !HEX_ONLY.test(flags) || traceId.length !== 32 || parentSpanId.length !== 16 || !HEX_ONLY.test(traceId) || !HEX_ONLY.test(parentSpanId) || traceId === "00000000000000000000000000000000" || parentSpanId === "0000000000000000") {
|
|
37
|
+
return void 0;
|
|
38
|
+
}
|
|
39
|
+
return { parentSpanId, sampled: (Number.parseInt(flags, 16) & 1) === 1, traceId };
|
|
40
|
+
};
|
|
41
|
+
const encodeAttribute = (key, value) => {
|
|
42
|
+
if (typeof value === "boolean") {
|
|
43
|
+
return { key, value: { boolValue: value } };
|
|
44
|
+
}
|
|
45
|
+
if (typeof value === "number") {
|
|
46
|
+
if (!Number.isFinite(value)) {
|
|
47
|
+
return { key, value: { stringValue: String(value) } };
|
|
48
|
+
}
|
|
49
|
+
return Number.isSafeInteger(value) ? { key, value: { intValue: String(value) } } : { key, value: { doubleValue: value } };
|
|
50
|
+
}
|
|
51
|
+
return { key, value: { stringValue: value } };
|
|
52
|
+
};
|
|
53
|
+
const mergeHeaders = (defaults, overrides, token) => {
|
|
54
|
+
const merged = {};
|
|
55
|
+
const seen = /* @__PURE__ */ new Map();
|
|
56
|
+
const put = (name, value) => {
|
|
57
|
+
const lower = name.toLowerCase();
|
|
58
|
+
const existing = seen.get(lower);
|
|
59
|
+
if (existing === void 0) {
|
|
60
|
+
seen.set(lower, name);
|
|
61
|
+
merged[name] = value;
|
|
62
|
+
} else {
|
|
63
|
+
merged[existing] = value;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
for (const [name, value] of Object.entries(defaults)) {
|
|
67
|
+
put(name, value);
|
|
68
|
+
}
|
|
69
|
+
for (const [name, value] of Object.entries(overrides ?? {})) {
|
|
70
|
+
put(name, value);
|
|
71
|
+
}
|
|
72
|
+
if (token !== void 0 && token.length > 0) {
|
|
73
|
+
put("authorization", `Bearer ${token}`);
|
|
74
|
+
}
|
|
75
|
+
return merged;
|
|
76
|
+
};
|
|
77
|
+
const buildResourceAttributes = (serviceName, extra) => {
|
|
78
|
+
const merged = { "service.name": serviceName };
|
|
79
|
+
for (const [key, value] of Object.entries(extra ?? {})) {
|
|
80
|
+
merged[key] = value;
|
|
81
|
+
}
|
|
82
|
+
return Object.entries(merged).map(([key, value]) => encodeAttribute(key, value));
|
|
83
|
+
};
|
|
84
|
+
const wrapResourceSpans = (span, scopeName, serviceName, resourceAttributes) => {
|
|
85
|
+
return {
|
|
86
|
+
resourceSpans: [
|
|
87
|
+
{
|
|
88
|
+
resource: { attributes: buildResourceAttributes(serviceName, resourceAttributes) },
|
|
89
|
+
scopeSpans: [{ scope: { name: scopeName }, spans: [span] }]
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
const wrapResourceLogs = (logRecord, scopeName, serviceName, resourceAttributes) => {
|
|
95
|
+
return {
|
|
96
|
+
resourceLogs: [
|
|
97
|
+
{
|
|
98
|
+
resource: { attributes: buildResourceAttributes(serviceName, resourceAttributes) },
|
|
99
|
+
scopeLogs: [{ logRecords: [logRecord], scope: { name: scopeName } }]
|
|
100
|
+
}
|
|
101
|
+
]
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
const wrapResourceMetrics = (metric, scopeName, serviceName, resourceAttributes) => {
|
|
105
|
+
return {
|
|
106
|
+
resourceMetrics: [
|
|
107
|
+
{
|
|
108
|
+
resource: { attributes: buildResourceAttributes(serviceName, resourceAttributes) },
|
|
109
|
+
scopeMetrics: [{ metrics: [metric], scope: { name: scopeName } }]
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const readerFromRecord = (environment) => (key) => {
|
|
116
|
+
const value = environment?.[key];
|
|
117
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
118
|
+
};
|
|
119
|
+
const stringProperty = (object, key) => {
|
|
120
|
+
if (typeof object !== "object" || object === null) {
|
|
121
|
+
return void 0;
|
|
122
|
+
}
|
|
123
|
+
const value = object[key];
|
|
124
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
125
|
+
};
|
|
126
|
+
const detectServiceResource = (read) => {
|
|
127
|
+
const detected = {};
|
|
128
|
+
const serviceVersion = read("SERVICE_VERSION") ?? read("CF_VERSION_METADATA") ?? read("VERCEL_GIT_COMMIT_SHA") ?? read("GITHUB_SHA") ?? read("COMMIT_SHA");
|
|
129
|
+
if (serviceVersion !== void 0) {
|
|
130
|
+
detected["service.version"] = serviceVersion;
|
|
131
|
+
}
|
|
132
|
+
const deploymentEnvironment = read("DEPLOYMENT_ENVIRONMENT") ?? read("ENVIRONMENT") ?? read("NODE_ENV");
|
|
133
|
+
if (deploymentEnvironment !== void 0) {
|
|
134
|
+
detected["deployment.environment"] = deploymentEnvironment;
|
|
135
|
+
}
|
|
136
|
+
return detected;
|
|
137
|
+
};
|
|
138
|
+
const detectCloudflareResource = (read, cf) => {
|
|
139
|
+
const isCloudflare = cf !== void 0 || read("CLOUDFLARE") !== void 0 || read("CF_ACCOUNT_ID") !== void 0;
|
|
140
|
+
if (!isCloudflare) {
|
|
141
|
+
return {};
|
|
142
|
+
}
|
|
143
|
+
const detected = { "cloud.provider": "cloudflare" };
|
|
144
|
+
const colo = stringProperty(cf, "colo") ?? read("CF_COLO") ?? read("CLOUDFLARE_COLO");
|
|
145
|
+
if (colo !== void 0) {
|
|
146
|
+
detected["cloud.region"] = colo;
|
|
147
|
+
}
|
|
148
|
+
return detected;
|
|
149
|
+
};
|
|
150
|
+
const mergeResourceAttributes = (...bags) => {
|
|
151
|
+
const merged = {};
|
|
152
|
+
for (const bag of bags) {
|
|
153
|
+
if (bag === void 0) {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
for (const [key, value] of Object.entries(bag)) {
|
|
157
|
+
merged[key] = value;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return merged;
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
export { OTLP_SEVERITY as O, detectServiceResource as a, buildTraceparent as b, wrapResourceMetrics as c, detectCloudflareResource as d, wrapResourceLogs as e, encodeAttribute as f, otlpUnixNano as g, mergeHeaders as h, mergeResourceAttributes as m, otlpRandomHex as o, parseTraceparent as p, readerFromRecord as r, wrapResourceSpans as w };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/runtime",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.36",
|
|
4
4
|
"description": "Lunora Worker runtime: the RPC router, shard resolver, and query coordinator",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"access": "public"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@lunora/bindings": "1.0.0-alpha.
|
|
50
|
-
"@lunora/errors": "1.0.0-alpha.
|
|
49
|
+
"@lunora/bindings": "1.0.0-alpha.10",
|
|
50
|
+
"@lunora/errors": "1.0.0-alpha.7"
|
|
51
51
|
},
|
|
52
52
|
"engines": {
|
|
53
53
|
"node": "^22.15.0 || >=24.11.0"
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
const emitRpcEvent = (sink, event, context) => {
|
|
2
|
-
if (!sink?.onRpc) {
|
|
3
|
-
return;
|
|
4
|
-
}
|
|
5
|
-
try {
|
|
6
|
-
sink.onRpc(event, context);
|
|
7
|
-
} catch {
|
|
8
|
-
}
|
|
9
|
-
};
|
|
10
|
-
const emitLogEvent = (sink, event, context) => {
|
|
11
|
-
if (!sink?.onLog) {
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
try {
|
|
15
|
-
sink.onLog(event, context);
|
|
16
|
-
} catch {
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export { emitLogEvent, emitRpcEvent };
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
const OTLP_SEVERITY = {
|
|
2
|
-
debug: 5,
|
|
3
|
-
// DEBUG
|
|
4
|
-
error: 17,
|
|
5
|
-
// ERROR
|
|
6
|
-
fatal: 21,
|
|
7
|
-
// FATAL
|
|
8
|
-
info: 9,
|
|
9
|
-
// INFO
|
|
10
|
-
log: 9,
|
|
11
|
-
// INFO
|
|
12
|
-
trace: 1,
|
|
13
|
-
// TRACE
|
|
14
|
-
warn: 13
|
|
15
|
-
// WARN
|
|
16
|
-
};
|
|
17
|
-
const otlpUnixNano = (ms) => `${String(Math.round(ms))}000000`;
|
|
18
|
-
const otlpRandomHex = (bytes) => {
|
|
19
|
-
const buffer = new Uint8Array(bytes);
|
|
20
|
-
crypto.getRandomValues(buffer);
|
|
21
|
-
let hex = "";
|
|
22
|
-
for (const byte of buffer) {
|
|
23
|
-
hex += byte.toString(16).padStart(2, "0");
|
|
24
|
-
}
|
|
25
|
-
return hex;
|
|
26
|
-
};
|
|
27
|
-
const buildTraceparent = (traceId, spanId) => `00-${traceId}-${spanId}-01`;
|
|
28
|
-
const encodeAttribute = (key, value) => {
|
|
29
|
-
if (typeof value === "boolean") {
|
|
30
|
-
return { key, value: { boolValue: value } };
|
|
31
|
-
}
|
|
32
|
-
if (typeof value === "number") {
|
|
33
|
-
if (!Number.isFinite(value)) {
|
|
34
|
-
return { key, value: { stringValue: String(value) } };
|
|
35
|
-
}
|
|
36
|
-
return Number.isSafeInteger(value) ? { key, value: { intValue: String(value) } } : { key, value: { doubleValue: value } };
|
|
37
|
-
}
|
|
38
|
-
return { key, value: { stringValue: value } };
|
|
39
|
-
};
|
|
40
|
-
const mergeHeaders = (defaults, overrides, token) => {
|
|
41
|
-
const merged = {};
|
|
42
|
-
const seen = /* @__PURE__ */ new Map();
|
|
43
|
-
const put = (name, value) => {
|
|
44
|
-
const lower = name.toLowerCase();
|
|
45
|
-
const existing = seen.get(lower);
|
|
46
|
-
if (existing === void 0) {
|
|
47
|
-
seen.set(lower, name);
|
|
48
|
-
merged[name] = value;
|
|
49
|
-
} else {
|
|
50
|
-
merged[existing] = value;
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
for (const [name, value] of Object.entries(defaults)) {
|
|
54
|
-
put(name, value);
|
|
55
|
-
}
|
|
56
|
-
for (const [name, value] of Object.entries(overrides ?? {})) {
|
|
57
|
-
put(name, value);
|
|
58
|
-
}
|
|
59
|
-
if (token !== void 0 && token.length > 0) {
|
|
60
|
-
put("authorization", `Bearer ${token}`);
|
|
61
|
-
}
|
|
62
|
-
return merged;
|
|
63
|
-
};
|
|
64
|
-
const wrapResourceSpans = (span, scopeName, serviceName) => {
|
|
65
|
-
return {
|
|
66
|
-
resourceSpans: [
|
|
67
|
-
{
|
|
68
|
-
resource: { attributes: [encodeAttribute("service.name", serviceName)] },
|
|
69
|
-
scopeSpans: [{ scope: { name: scopeName }, spans: [span] }]
|
|
70
|
-
}
|
|
71
|
-
]
|
|
72
|
-
};
|
|
73
|
-
};
|
|
74
|
-
const wrapResourceLogs = (logRecord, scopeName, serviceName) => {
|
|
75
|
-
return {
|
|
76
|
-
resourceLogs: [
|
|
77
|
-
{
|
|
78
|
-
resource: { attributes: [encodeAttribute("service.name", serviceName)] },
|
|
79
|
-
scopeLogs: [{ logRecords: [logRecord], scope: { name: scopeName } }]
|
|
80
|
-
}
|
|
81
|
-
]
|
|
82
|
-
};
|
|
83
|
-
};
|
|
84
|
-
const wrapResourceMetrics = (metric, scopeName, serviceName) => {
|
|
85
|
-
return {
|
|
86
|
-
resourceMetrics: [
|
|
87
|
-
{
|
|
88
|
-
resource: { attributes: [encodeAttribute("service.name", serviceName)] },
|
|
89
|
-
scopeMetrics: [{ metrics: [metric], scope: { name: scopeName } }]
|
|
90
|
-
}
|
|
91
|
-
]
|
|
92
|
-
};
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
export { OTLP_SEVERITY as O, wrapResourceMetrics as a, buildTraceparent as b, wrapResourceLogs as c, otlpUnixNano as d, encodeAttribute as e, mergeHeaders as m, otlpRandomHex as o, wrapResourceSpans as w };
|