@lunora/runtime 1.0.0-alpha.26 → 1.0.0-alpha.260
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/LICENSE.md +120 -0
- package/README.md +52 -10
- package/dist/index.d.mts +4555 -1618
- package/dist/index.d.ts +4555 -1618
- package/dist/index.mjs +1 -16
- package/dist/packem_shared/BACKUP_KEY_PREFIX-BOtSu-_3.mjs +1 -0
- package/dist/packem_shared/DEFAULT_LOG_COLUMNS-gYMhXLzO.mjs +1 -0
- package/dist/packem_shared/DEFAULT_REGISTRY_CACHE_TTL_MS-w_RLPiwj.mjs +2 -0
- package/dist/packem_shared/HEALTH_PATH-B8ndDG3s.mjs +1 -0
- package/dist/packem_shared/LOG_ARCHIVE_NOT_CONFIGURED-CDpi4yFD.mjs +1 -0
- package/dist/packem_shared/LOG_ARCHIVE_PATH-dTuCzfyj.mjs +1 -0
- package/dist/packem_shared/LunoraError-PkZWF-_g.mjs +1 -0
- package/dist/packem_shared/NOOP_EXECUTION_CONTEXT-YmXqH-jH.mjs +1 -0
- package/dist/packem_shared/STORAGE_UPLOAD_MAX_BODY_BYTES-DiZho96u.mjs +1 -0
- package/dist/packem_shared/analyticsEngineSink-s5j-3P1X.mjs +1 -0
- package/dist/packem_shared/applyJurisdiction-DKQE8kOA.mjs +1 -0
- package/dist/packem_shared/applyRestCache-CEcBz3qq.mjs +1 -0
- package/dist/packem_shared/argsFromQuery-C8Ox3sr1.mjs +1 -0
- package/dist/packem_shared/base64-Bl1_r2k1.mjs +1 -0
- package/dist/packem_shared/composeIdentityResolvers-CpdHuDyk.mjs +1 -0
- package/dist/packem_shared/composeWorker-DgrKHFdI.mjs +37 -0
- package/dist/packem_shared/createCrossShardRelationCapabilities-DRYvyR4Y.mjs +1 -0
- package/dist/packem_shared/createKvCursorStore-Bkn5pilz.mjs +1 -0
- package/dist/packem_shared/createQueryCoordinator-D3Pz-Jdr.mjs +1 -0
- package/dist/packem_shared/createShardClient-rKSKWKAG.mjs +1 -0
- package/dist/packem_shared/declareAppJurisdiction-DEba2p42.mjs +1 -0
- package/dist/packem_shared/decorateResponse-CdelJSUs.mjs +1 -0
- package/dist/packem_shared/emitLogEvent-CdybnWG8.mjs +1 -0
- package/dist/packem_shared/enrichSink-44NOapaE.mjs +1 -0
- package/dist/packem_shared/error-detail-C46mdOTW.mjs +1 -0
- package/dist/packem_shared/export-tap-C2B_SATf.mjs +3 -0
- package/dist/packem_shared/identity-header-ByHiZBcH.mjs +1 -0
- package/dist/packem_shared/memoize-identity-DFkwm3x6.mjs +1 -0
- package/dist/packem_shared/memoizeIdentity-C4BJchsg.mjs +1 -0
- package/dist/packem_shared/method-guard-8Jo4Q8uS.mjs +1 -0
- package/dist/packem_shared/observability-9slk__Gi.mjs +1 -0
- package/dist/packem_shared/observability-sinks-lLKqc_rV.mjs +4 -0
- package/dist/packem_shared/origin-paywall-B6eOO67m.mjs +1 -0
- package/dist/packem_shared/otlp-resource-Ch_8_U0e.mjs +1 -0
- package/dist/packem_shared/parseStackFrames-CZddjveh.mjs +2 -0
- package/dist/packem_shared/pipeline-log-reader-C-nuWG_e.mjs +1 -0
- package/dist/packem_shared/portable-json-CSq6T1AU.mjs +1 -0
- package/dist/packem_shared/rest-cache-CmHN871W.mjs +1 -0
- package/dist/packem_shared/rest-routes-CDQ1F7kI.mjs +1 -0
- package/dist/packem_shared/toAirbyteMessages-DY0vsuEn.mjs +1 -0
- package/package.json +10 -2
- package/dist/packem_shared/DEFAULT_REGISTRY_CACHE_TTL_MS-B3pA7aXp.mjs +0 -79
- package/dist/packem_shared/LunoraError-Bpb9EFJ3.mjs +0 -22
- package/dist/packem_shared/NOOP_EXECUTION_CONTEXT-CCTu0Bf1.mjs +0 -8
- package/dist/packem_shared/analyticsEngineSink-F-5ZAdUA.mjs +0 -200
- package/dist/packem_shared/applyJurisdiction-BkZtTkct.mjs +0 -20
- package/dist/packem_shared/composeIdentityResolvers-XGjO7V1J.mjs +0 -55
- package/dist/packem_shared/composeWorker-BMxMYwKq.mjs +0 -3175
- package/dist/packem_shared/createCrossShardRelationCapabilities-CbcWjkAn.mjs +0 -63
- package/dist/packem_shared/createQueryCoordinator-DNCJzOZE.mjs +0 -847
- package/dist/packem_shared/decorateResponse-DRWQFNhF.mjs +0 -273
- package/dist/packem_shared/emitLogEvent-pEdtqAK8.mjs +0 -20
- package/dist/packem_shared/otlp-D_YzGXu1.mjs +0 -81
- package/dist/packem_shared/toAirbyteMessages-DrHdplb4.mjs +0 -39
|
@@ -1,273 +0,0 @@
|
|
|
1
|
-
import { LunoraError } from './LunoraError-Bpb9EFJ3.mjs';
|
|
2
|
-
|
|
3
|
-
const DEFAULT_CSP = "default-src 'none'; frame-ancestors 'none'; base-uri 'none'; form-action 'none'";
|
|
4
|
-
const htmlCspFor = (frameOptions) => {
|
|
5
|
-
const parts = ["base-uri 'none'", "object-src 'none'"];
|
|
6
|
-
if (frameOptions === "DENY") {
|
|
7
|
-
parts.push("frame-ancestors 'none'");
|
|
8
|
-
} else if (frameOptions === "SAMEORIGIN") {
|
|
9
|
-
parts.push("frame-ancestors 'self'");
|
|
10
|
-
}
|
|
11
|
-
return parts.join("; ");
|
|
12
|
-
};
|
|
13
|
-
const DEFAULT_PERMISSIONS_POLICY = "accelerometer=(), autoplay=(), camera=(), display-capture=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()";
|
|
14
|
-
const DEFAULT_CORS_HEADERS = ["Authorization", "Content-Type", "X-D1-Bookmark", "X-Lunora-Mutation-Id"];
|
|
15
|
-
const DEFAULT_CORS_METHODS = ["DELETE", "GET", "HEAD", "PATCH", "POST", "PUT"];
|
|
16
|
-
const ONE_YEAR_SECONDS = 31536e3;
|
|
17
|
-
const SAFE_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD", "OPTIONS"]);
|
|
18
|
-
const resolveHstsHeader = (hsts) => {
|
|
19
|
-
if (hsts === false) {
|
|
20
|
-
return void 0;
|
|
21
|
-
}
|
|
22
|
-
const config = hsts === void 0 || hsts === true ? {} : hsts;
|
|
23
|
-
const maxAge = config.maxAge ?? ONE_YEAR_SECONDS;
|
|
24
|
-
const includeSubDomains = config.includeSubDomains ?? true;
|
|
25
|
-
return `max-age=${String(maxAge)}${includeSubDomains ? "; includeSubDomains" : ""}${config.preload ? "; preload" : ""}`;
|
|
26
|
-
};
|
|
27
|
-
const resolveCspHeader = (csp, htmlDefault) => {
|
|
28
|
-
if (csp === false) {
|
|
29
|
-
return void 0;
|
|
30
|
-
}
|
|
31
|
-
if (typeof csp === "string") {
|
|
32
|
-
return { htmlValue: csp, value: csp };
|
|
33
|
-
}
|
|
34
|
-
return { htmlValue: htmlDefault, value: DEFAULT_CSP };
|
|
35
|
-
};
|
|
36
|
-
const resolveHeaders = (input) => {
|
|
37
|
-
if (input === false) {
|
|
38
|
-
return {
|
|
39
|
-
coop: void 0,
|
|
40
|
-
csp: void 0,
|
|
41
|
-
enabled: false,
|
|
42
|
-
frameOptions: void 0,
|
|
43
|
-
hsts: void 0,
|
|
44
|
-
permissionsPolicy: void 0,
|
|
45
|
-
referrerPolicy: void 0
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
const options = input === void 0 || input === true ? {} : input;
|
|
49
|
-
const frameOptions = options.frameOptions === false ? void 0 : options.frameOptions ?? "SAMEORIGIN";
|
|
50
|
-
return {
|
|
51
|
-
coop: "same-origin",
|
|
52
|
-
csp: resolveCspHeader(options.csp, htmlCspFor(frameOptions)),
|
|
53
|
-
enabled: true,
|
|
54
|
-
frameOptions,
|
|
55
|
-
hsts: resolveHstsHeader(options.hsts),
|
|
56
|
-
permissionsPolicy: options.permissionsPolicy === false ? void 0 : options.permissionsPolicy ?? DEFAULT_PERMISSIONS_POLICY,
|
|
57
|
-
referrerPolicy: options.referrerPolicy === false ? void 0 : options.referrerPolicy ?? "strict-origin-when-cross-origin"
|
|
58
|
-
};
|
|
59
|
-
};
|
|
60
|
-
const resolveCors = (input) => {
|
|
61
|
-
const disabled = {
|
|
62
|
-
allowCredentials: false,
|
|
63
|
-
allowedHeaders: DEFAULT_CORS_HEADERS,
|
|
64
|
-
allowedMethods: DEFAULT_CORS_METHODS,
|
|
65
|
-
enabled: false,
|
|
66
|
-
isAllowed: () => false,
|
|
67
|
-
isExplicitlyAllowed: () => false,
|
|
68
|
-
maxAge: 600
|
|
69
|
-
};
|
|
70
|
-
if (input === void 0 || input === false) {
|
|
71
|
-
return disabled;
|
|
72
|
-
}
|
|
73
|
-
const allowCredentials = input.allowCredentials ?? false;
|
|
74
|
-
const origins = input.allowedOrigins;
|
|
75
|
-
let isAllowed;
|
|
76
|
-
let isExplicitlyAllowed;
|
|
77
|
-
if (typeof origins === "function") {
|
|
78
|
-
isAllowed = origins;
|
|
79
|
-
isExplicitlyAllowed = origins;
|
|
80
|
-
const credentialsNote = allowCredentials ? " AND reflects matching origins with credentials (`allowCredentials: true`)" : "";
|
|
81
|
-
console.warn(
|
|
82
|
-
`@lunora/runtime: security.cors uses a custom \`allowedOrigins\` predicate. It is trusted by the CSRF and WebSocket origin checks${credentialsNote} — ensure it matches ONLY trusted origins by exact equality; an over-broad predicate (e.g. \`() => true\`, or \`endsWith\`/\`includes\` checks) defeats the allowlist.`
|
|
83
|
-
);
|
|
84
|
-
} else {
|
|
85
|
-
const originsList = origins;
|
|
86
|
-
if (originsList.includes("*") && allowCredentials) {
|
|
87
|
-
throw new LunoraError(
|
|
88
|
-
'@lunora/runtime: security.cors cannot combine a wildcard origin ("*") with allowCredentials: true — browsers reject it and it defeats the allowlist.'
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
isAllowed = (origin) => originsList.includes("*") || originsList.includes(origin);
|
|
92
|
-
isExplicitlyAllowed = (origin) => originsList.includes(origin);
|
|
93
|
-
}
|
|
94
|
-
return {
|
|
95
|
-
allowCredentials,
|
|
96
|
-
allowedHeaders: input.allowedHeaders ?? DEFAULT_CORS_HEADERS,
|
|
97
|
-
allowedMethods: input.allowedMethods ?? DEFAULT_CORS_METHODS,
|
|
98
|
-
enabled: true,
|
|
99
|
-
isAllowed,
|
|
100
|
-
isExplicitlyAllowed,
|
|
101
|
-
maxAge: input.maxAge ?? 600
|
|
102
|
-
};
|
|
103
|
-
};
|
|
104
|
-
const resolveCsrf = (input) => {
|
|
105
|
-
if (input === false) {
|
|
106
|
-
return { enabled: false, trustedOrigins: [] };
|
|
107
|
-
}
|
|
108
|
-
const options = input === void 0 || input === true ? {} : input;
|
|
109
|
-
return { enabled: true, trustedOrigins: options.trustedOrigins ?? [] };
|
|
110
|
-
};
|
|
111
|
-
const DISABLED_ENV_VALUES = /* @__PURE__ */ new Set(["0", "disabled", "false", "no", "off"]);
|
|
112
|
-
const ENABLED_ENV_VALUES = /* @__PURE__ */ new Set(["1", "enabled", "on", "true", "yes"]);
|
|
113
|
-
const isEnvDisabled = (value) => typeof value === "string" && DISABLED_ENV_VALUES.has(value.trim().toLowerCase());
|
|
114
|
-
const isEnvEnabled = (value) => typeof value === "string" && ENABLED_ENV_VALUES.has(value.trim().toLowerCase());
|
|
115
|
-
const parseEnvCors = (env) => {
|
|
116
|
-
const raw = env?.["LUNORA_ALLOWED_ORIGINS"];
|
|
117
|
-
if (typeof raw !== "string") {
|
|
118
|
-
return void 0;
|
|
119
|
-
}
|
|
120
|
-
const allowedOrigins = raw.split(",").map((origin) => origin.trim()).filter((origin) => origin.length > 0);
|
|
121
|
-
if (allowedOrigins.length === 0) {
|
|
122
|
-
return void 0;
|
|
123
|
-
}
|
|
124
|
-
const wildcard = allowedOrigins.includes("*");
|
|
125
|
-
const allowCredentials = !wildcard && isEnvEnabled(env?.["LUNORA_CORS_ALLOW_CREDENTIALS"]);
|
|
126
|
-
return { allowCredentials, allowedOrigins };
|
|
127
|
-
};
|
|
128
|
-
const resolveSecurity = (security, env) => {
|
|
129
|
-
const headers = security?.headers ?? (isEnvDisabled(env?.["LUNORA_SECURITY_HEADERS"]) ? false : void 0);
|
|
130
|
-
const csrf = security?.csrf ?? (isEnvDisabled(env?.["LUNORA_SECURITY_CSRF"]) ? false : void 0);
|
|
131
|
-
const cors = security?.cors ?? parseEnvCors(env);
|
|
132
|
-
return {
|
|
133
|
-
cors: resolveCors(cors),
|
|
134
|
-
csrf: resolveCsrf(csrf),
|
|
135
|
-
headers: resolveHeaders(headers)
|
|
136
|
-
};
|
|
137
|
-
};
|
|
138
|
-
const originOf = (value) => {
|
|
139
|
-
if (!value) {
|
|
140
|
-
return void 0;
|
|
141
|
-
}
|
|
142
|
-
try {
|
|
143
|
-
return new URL(value).origin;
|
|
144
|
-
} catch {
|
|
145
|
-
return void 0;
|
|
146
|
-
}
|
|
147
|
-
};
|
|
148
|
-
const isTrustedOrigin = (origin, selfOrigin, resolved) => {
|
|
149
|
-
if (origin === selfOrigin) {
|
|
150
|
-
return true;
|
|
151
|
-
}
|
|
152
|
-
if (resolved.csrf.trustedOrigins.includes(origin)) {
|
|
153
|
-
return true;
|
|
154
|
-
}
|
|
155
|
-
return resolved.cors.enabled && resolved.cors.isExplicitlyAllowed(origin);
|
|
156
|
-
};
|
|
157
|
-
const enforceOrigin = (request, resolved) => {
|
|
158
|
-
if (!resolved.csrf.enabled || SAFE_METHODS.has(request.method) || !request.headers.get("cookie")) {
|
|
159
|
-
return void 0;
|
|
160
|
-
}
|
|
161
|
-
const selfOrigin = new URL(request.url).origin;
|
|
162
|
-
const source = originOf(request.headers.get("origin")) ?? originOf(request.headers.get("referer"));
|
|
163
|
-
if (source !== void 0 && isTrustedOrigin(source, selfOrigin, resolved)) {
|
|
164
|
-
return void 0;
|
|
165
|
-
}
|
|
166
|
-
return Response.json(
|
|
167
|
-
{ error: { code: "FORBIDDEN_ORIGIN", message: "cross-origin state-changing request rejected" } },
|
|
168
|
-
{ headers: { "content-type": "application/json" }, status: 403 }
|
|
169
|
-
);
|
|
170
|
-
};
|
|
171
|
-
const enforceWebSocketOrigin = (request, resolved) => {
|
|
172
|
-
if (!resolved.csrf.enabled || !request.headers.get("cookie")) {
|
|
173
|
-
return void 0;
|
|
174
|
-
}
|
|
175
|
-
const selfOrigin = new URL(request.url).origin;
|
|
176
|
-
const source = originOf(request.headers.get("origin"));
|
|
177
|
-
if (source !== void 0 && isTrustedOrigin(source, selfOrigin, resolved)) {
|
|
178
|
-
return void 0;
|
|
179
|
-
}
|
|
180
|
-
return Response.json(
|
|
181
|
-
{ error: { code: "FORBIDDEN_ORIGIN", message: "cross-origin websocket upgrade rejected" } },
|
|
182
|
-
{ headers: { "content-type": "application/json" }, status: 403 }
|
|
183
|
-
);
|
|
184
|
-
};
|
|
185
|
-
const corsResponseHeaders = (origin, cors) => {
|
|
186
|
-
const headers = new Headers();
|
|
187
|
-
headers.set("access-control-allow-origin", origin);
|
|
188
|
-
headers.append("vary", "Origin");
|
|
189
|
-
if (cors.allowCredentials) {
|
|
190
|
-
headers.set("access-control-allow-credentials", "true");
|
|
191
|
-
}
|
|
192
|
-
return headers;
|
|
193
|
-
};
|
|
194
|
-
const handleCorsPreflight = (request, resolved) => {
|
|
195
|
-
if (!resolved.cors.enabled || request.method !== "OPTIONS") {
|
|
196
|
-
return void 0;
|
|
197
|
-
}
|
|
198
|
-
const origin = request.headers.get("origin");
|
|
199
|
-
if (!origin || !request.headers.get("access-control-request-method") || !resolved.cors.isAllowed(origin)) {
|
|
200
|
-
return void 0;
|
|
201
|
-
}
|
|
202
|
-
const headers = corsResponseHeaders(origin, resolved.cors);
|
|
203
|
-
const requested = request.headers.get("access-control-request-headers");
|
|
204
|
-
headers.set("access-control-allow-methods", resolved.cors.allowedMethods.join(", "));
|
|
205
|
-
let allowedHeaders;
|
|
206
|
-
if (requested === null) {
|
|
207
|
-
allowedHeaders = resolved.cors.allowedHeaders.join(", ");
|
|
208
|
-
} else {
|
|
209
|
-
const permitted = new Set(resolved.cors.allowedHeaders.map((name) => name.toLowerCase()));
|
|
210
|
-
allowedHeaders = requested.split(",").map((name) => name.trim()).filter((name) => name.length > 0 && permitted.has(name.toLowerCase())).join(", ");
|
|
211
|
-
}
|
|
212
|
-
headers.set("access-control-allow-headers", allowedHeaders);
|
|
213
|
-
headers.set("access-control-max-age", String(resolved.cors.maxAge));
|
|
214
|
-
return new Response(null, { headers, status: 204 });
|
|
215
|
-
};
|
|
216
|
-
const isHtmlResponse = (response) => (response.headers.get("content-type") ?? "").toLowerCase().includes("text/html");
|
|
217
|
-
const setIfAbsent = (headers, name, value) => {
|
|
218
|
-
if (!headers.has(name)) {
|
|
219
|
-
headers.set(name, value);
|
|
220
|
-
}
|
|
221
|
-
};
|
|
222
|
-
const applyBaselineHeaders = (headers, request, response, config) => {
|
|
223
|
-
if (config.hsts !== void 0 && new URL(request.url).protocol === "https:") {
|
|
224
|
-
setIfAbsent(headers, "strict-transport-security", config.hsts);
|
|
225
|
-
}
|
|
226
|
-
setIfAbsent(headers, "x-content-type-options", "nosniff");
|
|
227
|
-
if (config.frameOptions !== void 0) {
|
|
228
|
-
setIfAbsent(headers, "x-frame-options", config.frameOptions);
|
|
229
|
-
}
|
|
230
|
-
if (config.referrerPolicy !== void 0) {
|
|
231
|
-
setIfAbsent(headers, "referrer-policy", config.referrerPolicy);
|
|
232
|
-
}
|
|
233
|
-
if (config.permissionsPolicy !== void 0) {
|
|
234
|
-
setIfAbsent(headers, "permissions-policy", config.permissionsPolicy);
|
|
235
|
-
}
|
|
236
|
-
if (config.coop !== void 0) {
|
|
237
|
-
setIfAbsent(headers, "cross-origin-opener-policy", config.coop);
|
|
238
|
-
}
|
|
239
|
-
if (config.csp !== void 0) {
|
|
240
|
-
const cspValue = isHtmlResponse(response) ? config.csp.htmlValue : config.csp.value;
|
|
241
|
-
if (cspValue !== void 0) {
|
|
242
|
-
setIfAbsent(headers, "content-security-policy", cspValue);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
};
|
|
246
|
-
const applyCorsHeaders = (headers, request, cors) => {
|
|
247
|
-
const origin = request.headers.get("origin");
|
|
248
|
-
if (!origin || !cors.isAllowed(origin)) {
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
for (const [name, value] of corsResponseHeaders(origin, cors).entries()) {
|
|
252
|
-
if (name === "vary") {
|
|
253
|
-
headers.append("vary", value);
|
|
254
|
-
} else {
|
|
255
|
-
setIfAbsent(headers, name, value);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
};
|
|
259
|
-
const decorateResponse = (response, request, resolved) => {
|
|
260
|
-
if (response.status === 101 || response.webSocket) {
|
|
261
|
-
return response;
|
|
262
|
-
}
|
|
263
|
-
const headers = new Headers(response.headers);
|
|
264
|
-
if (resolved.headers.enabled) {
|
|
265
|
-
applyBaselineHeaders(headers, request, response, resolved.headers);
|
|
266
|
-
}
|
|
267
|
-
if (resolved.cors.enabled) {
|
|
268
|
-
applyCorsHeaders(headers, request, resolved.cors);
|
|
269
|
-
}
|
|
270
|
-
return new Response(response.body, { headers, status: response.status, statusText: response.statusText });
|
|
271
|
-
};
|
|
272
|
-
|
|
273
|
-
export { decorateResponse, enforceOrigin, enforceWebSocketOrigin, handleCorsPreflight, resolveSecurity };
|
|
@@ -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,81 +0,0 @@
|
|
|
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 };
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
const DEFAULT_PRIMARY_KEY = "_id";
|
|
2
|
-
const toFivetranResponse = (page, primaryKey = DEFAULT_PRIMARY_KEY) => {
|
|
3
|
-
const insert = {};
|
|
4
|
-
const update = {};
|
|
5
|
-
const remove = {};
|
|
6
|
-
const schema = {};
|
|
7
|
-
const pkFor = (table) => typeof primaryKey === "string" ? primaryKey : primaryKey[table] ?? DEFAULT_PRIMARY_KEY;
|
|
8
|
-
const bucketFor = (target, table) => {
|
|
9
|
-
const existing = target[table];
|
|
10
|
-
if (existing) {
|
|
11
|
-
return existing;
|
|
12
|
-
}
|
|
13
|
-
const created = [];
|
|
14
|
-
target[table] = created;
|
|
15
|
-
return created;
|
|
16
|
-
};
|
|
17
|
-
for (const change of page.changes) {
|
|
18
|
-
schema[change.table] ??= { primary_key: [pkFor(change.table)] };
|
|
19
|
-
if (change.op === "delete") {
|
|
20
|
-
bucketFor(remove, change.table).push(change.doc);
|
|
21
|
-
} else if (change.op === "update") {
|
|
22
|
-
bucketFor(update, change.table).push(change.doc);
|
|
23
|
-
} else {
|
|
24
|
-
bucketFor(insert, change.table).push(change.doc);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
return { delete: remove, hasMore: page.hasMore, insert, schema, state: { cursor: page.nextCursor }, update };
|
|
28
|
-
};
|
|
29
|
-
const toAirbyteMessages = (page, emittedAt = Date.now()) => {
|
|
30
|
-
const messages = [];
|
|
31
|
-
for (const change of page.changes) {
|
|
32
|
-
const data = change.op === "delete" ? { ...change.doc, _lunora_deleted: true } : change.doc;
|
|
33
|
-
messages.push({ record: { data, emitted_at: emittedAt, stream: change.table }, type: "RECORD" });
|
|
34
|
-
}
|
|
35
|
-
messages.push({ state: { data: { cursor: page.nextCursor } }, type: "STATE" });
|
|
36
|
-
return messages;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export { toAirbyteMessages, toFivetranResponse };
|