@telorun/sdk 0.49.0 → 0.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dispatch-invoke-ref.d.ts.map +1 -1
- package/dist/dispatch-invoke-ref.js +12 -17
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/json-value.d.ts +20 -0
- package/dist/json-value.d.ts.map +1 -0
- package/dist/json-value.js +31 -0
- package/dist/log-record.d.ts +72 -0
- package/dist/log-record.d.ts.map +1 -0
- package/dist/log-record.js +34 -0
- package/dist/log-severity.d.ts +55 -0
- package/dist/log-severity.d.ts.map +1 -0
- package/dist/log-severity.js +110 -0
- package/dist/log-sink.d.ts +91 -0
- package/dist/log-sink.d.ts.map +1 -0
- package/dist/log-sink.js +16 -0
- package/dist/logger.d.ts +85 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +30 -0
- package/dist/resolve-ref-instance.d.ts +39 -0
- package/dist/resolve-ref-instance.d.ts.map +1 -0
- package/dist/resolve-ref-instance.js +57 -0
- package/dist/resource-context.d.ts +48 -0
- package/dist/resource-context.d.ts.map +1 -1
- package/dist/resource-instance.d.ts +17 -0
- package/dist/resource-instance.d.ts.map +1 -1
- package/dist/resource-instance.js +4 -0
- package/package.json +1 -1
- package/src/dispatch-invoke-ref.ts +20 -20
- package/src/index.ts +6 -0
- package/src/json-value.ts +43 -0
- package/src/log-record.ts +113 -0
- package/src/log-severity.ts +128 -0
- package/src/log-sink.ts +115 -0
- package/src/logger.ts +125 -0
- package/src/resolve-ref-instance.ts +81 -0
- package/src/resource-context.ts +53 -0
- package/src/resource-instance.ts +18 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch-invoke-ref.d.ts","sourceRoot":"","sources":["../src/dispatch-invoke-ref.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"dispatch-invoke-ref.d.ts","sourceRoot":"","sources":["../src/dispatch-invoke-ref.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGzD,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/E,4EAA4E;AAC5E,MAAM,WAAW,eAAe;IAC9B,cAAc,CAAC,OAAO,EACpB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,gBAAgB,EAC1B,MAAM,EAAE,OAAO,EACf,GAAG,CAAC,EAAE,aAAa,GAClB,OAAO,CAAC,OAAO,CAAC,CAAC;IACpB,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;CACvC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,OAAO,EACd,GAAG,EAAE,eAAe,EACpB,QAAQ,EAAE,MAAM,MAAM,GACrB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAgBlF"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveRefInstance } from "./resolve-ref-instance.js";
|
|
1
2
|
import { getRefIdentity } from "./resource-instance.js";
|
|
2
3
|
/**
|
|
3
4
|
* Resolve a decorator's `invoke:` field to a live invocable and return a thunk
|
|
@@ -11,22 +12,16 @@ import { getRefIdentity } from "./resource-instance.js";
|
|
|
11
12
|
* invocation context applies unchanged.
|
|
12
13
|
*/
|
|
13
14
|
export function resolveInvocableDispatcher(field, ctx, describe) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
const target = resolveRefInstance(field, ctx, isInvocableInstance, () => `${describe()}: 'invoke'`, "telo#Invocable");
|
|
16
|
+
// Dispatch through the traced chokepoint needs the target's kind+name: from
|
|
17
|
+
// the `!ref` identity the kernel stamped at injection, else from the raw ref.
|
|
18
|
+
const id = getRefIdentity(target) ?? field;
|
|
19
|
+
if (!id || typeof id.kind !== "string" || typeof id.name !== "string") {
|
|
20
|
+
return (inputs, invokeCtx) => target.invoke(inputs, invokeCtx);
|
|
20
21
|
}
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
? ctx.moduleContext.resolveImportedInstance(ref.alias, ref.name)
|
|
27
|
-
: ctx.moduleContext.getInstance(ref.name));
|
|
28
|
-
if (!resolved || typeof resolved.invoke !== "function") {
|
|
29
|
-
throw new Error(`${describe()}: 'invoke' reference '${ref.name}' did not resolve to an invocable.`);
|
|
30
|
-
}
|
|
31
|
-
return (inputs, invokeCtx) => ctx.invokeResolved(ref.kind, ref.name, resolved, inputs, invokeCtx);
|
|
22
|
+
const { kind, name } = id;
|
|
23
|
+
return (inputs, invokeCtx) => ctx.invokeResolved(kind, name, target, inputs, invokeCtx);
|
|
24
|
+
}
|
|
25
|
+
function isInvocableInstance(value) {
|
|
26
|
+
return typeof value?.invoke === "function";
|
|
32
27
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ export * from "./capabilities/provider.js";
|
|
|
9
9
|
export * from "./capabilities/runnable.js";
|
|
10
10
|
export * from "./context-provider.js";
|
|
11
11
|
export * from "./duration.js";
|
|
12
|
+
export * from "./json-value.js";
|
|
13
|
+
export * from "./resolve-ref-instance.js";
|
|
12
14
|
export * from "./controller-context.js";
|
|
13
15
|
export * from "./controller-policy.js";
|
|
14
16
|
export * from "./evaluation-context.js";
|
|
@@ -17,6 +19,10 @@ export * from "./resource-context.js";
|
|
|
17
19
|
export * from "./resource-instance.js";
|
|
18
20
|
export * from "./resource-manifest.js";
|
|
19
21
|
export * from "./invoke-error.js";
|
|
22
|
+
export * from "./log-record.js";
|
|
23
|
+
export * from "./log-sink.js";
|
|
24
|
+
export * from "./log-severity.js";
|
|
25
|
+
export * from "./logger.js";
|
|
20
26
|
export * from "./network-fetch.js";
|
|
21
27
|
export * from "./runtime-error.js";
|
|
22
28
|
export * from "./runtime-event.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,UAAU,CAAC;AACzB,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,UAAU,CAAC;AACzB,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,8 @@ export * from "./capabilities/provider.js";
|
|
|
9
9
|
export * from "./capabilities/runnable.js";
|
|
10
10
|
export * from "./context-provider.js";
|
|
11
11
|
export * from "./duration.js";
|
|
12
|
+
export * from "./json-value.js";
|
|
13
|
+
export * from "./resolve-ref-instance.js";
|
|
12
14
|
export * from "./controller-context.js";
|
|
13
15
|
export * from "./controller-policy.js";
|
|
14
16
|
export * from "./evaluation-context.js";
|
|
@@ -17,6 +19,10 @@ export * from "./resource-context.js";
|
|
|
17
19
|
export * from "./resource-instance.js";
|
|
18
20
|
export * from "./resource-manifest.js";
|
|
19
21
|
export * from "./invoke-error.js";
|
|
22
|
+
export * from "./log-record.js";
|
|
23
|
+
export * from "./log-sink.js";
|
|
24
|
+
export * from "./log-severity.js";
|
|
25
|
+
export * from "./logger.js";
|
|
20
26
|
export * from "./network-fetch.js";
|
|
21
27
|
export * from "./runtime-error.js";
|
|
22
28
|
export * from "./runtime-event.js";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON encoding for values that cross a persistence boundary.
|
|
3
|
+
*
|
|
4
|
+
* `JSON.stringify` THROWS on a BigInt, and CEL integers surface as BigInt in
|
|
5
|
+
* this runtime — so any controller that persists a result computed in CEL
|
|
6
|
+
* (`{ charged: 500 }` from a `Run.Sequence` output) hits it. A store that lets
|
|
7
|
+
* that throw escape is worse than one that never persisted: the caller sees an
|
|
8
|
+
* opaque TypeError, and a decorator built on the store can mistake it for the
|
|
9
|
+
* body having failed.
|
|
10
|
+
*
|
|
11
|
+
* BigInt is encoded as a tagged object rather than a plain string or a Number:
|
|
12
|
+
* a string would come back a different type than went in, and Number is lossy
|
|
13
|
+
* past 2^53. A replayed value must equal the freshly-produced one, or
|
|
14
|
+
* at-most-once execution silently changes its answer on the second call.
|
|
15
|
+
*/
|
|
16
|
+
/** Serialize a value to JSON text, preserving BigInt exactly. */
|
|
17
|
+
export declare function encodeJsonValue(value: unknown): string;
|
|
18
|
+
/** Inverse of {@link encodeJsonValue}; BigInt values are restored as BigInt. */
|
|
19
|
+
export declare function decodeJsonValue(text: string): unknown;
|
|
20
|
+
//# sourceMappingURL=json-value.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-value.d.ts","sourceRoot":"","sources":["../src/json-value.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAkBH,iEAAiE;AACjE,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAItD;AAED,gFAAgF;AAChF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON encoding for values that cross a persistence boundary.
|
|
3
|
+
*
|
|
4
|
+
* `JSON.stringify` THROWS on a BigInt, and CEL integers surface as BigInt in
|
|
5
|
+
* this runtime — so any controller that persists a result computed in CEL
|
|
6
|
+
* (`{ charged: 500 }` from a `Run.Sequence` output) hits it. A store that lets
|
|
7
|
+
* that throw escape is worse than one that never persisted: the caller sees an
|
|
8
|
+
* opaque TypeError, and a decorator built on the store can mistake it for the
|
|
9
|
+
* body having failed.
|
|
10
|
+
*
|
|
11
|
+
* BigInt is encoded as a tagged object rather than a plain string or a Number:
|
|
12
|
+
* a string would come back a different type than went in, and Number is lossy
|
|
13
|
+
* past 2^53. A replayed value must equal the freshly-produced one, or
|
|
14
|
+
* at-most-once execution silently changes its answer on the second call.
|
|
15
|
+
*/
|
|
16
|
+
const BIGINT_TAG = "$bigint";
|
|
17
|
+
function isTaggedBigInt(value) {
|
|
18
|
+
return (typeof value === "object" &&
|
|
19
|
+
value !== null &&
|
|
20
|
+
!Array.isArray(value) &&
|
|
21
|
+
typeof value[BIGINT_TAG] === "string" &&
|
|
22
|
+
Object.keys(value).length === 1);
|
|
23
|
+
}
|
|
24
|
+
/** Serialize a value to JSON text, preserving BigInt exactly. */
|
|
25
|
+
export function encodeJsonValue(value) {
|
|
26
|
+
return JSON.stringify(value ?? null, (_k, v) => typeof v === "bigint" ? { [BIGINT_TAG]: v.toString() } : v);
|
|
27
|
+
}
|
|
28
|
+
/** Inverse of {@link encodeJsonValue}; BigInt values are restored as BigInt. */
|
|
29
|
+
export function decodeJsonValue(text) {
|
|
30
|
+
return JSON.parse(text, (_k, v) => (isTaggedBigInt(v) ? BigInt(v[BIGINT_TAG]) : v));
|
|
31
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { SeverityNumber } from "./log-severity.js";
|
|
2
|
+
/**
|
|
3
|
+
* The Telo log record model — `kernel/specs/logging.md` §4. Maps 1:1 onto an
|
|
4
|
+
* OpenTelemetry `LogRecord`; encodings (§11) determine spelling and MUST NOT add
|
|
5
|
+
* or remove semantics.
|
|
6
|
+
*
|
|
7
|
+
* The one deliberate deviation from OTel is {@link LogRecord.message}: OTel's
|
|
8
|
+
* `Body` is an `AnyValue` and may be structured, while Telo requires a string and
|
|
9
|
+
* routes structured data to `attributes`. That keeps the console encoding total —
|
|
10
|
+
* every record has a renderable headline — and matches slog, pino, and zap.
|
|
11
|
+
*/
|
|
12
|
+
/** The attribute value type (§6.1). `null` is a valid value and is preserved. */
|
|
13
|
+
export type AnyValue = string | boolean | number | bigint | Uint8Array | null | AnyValue[] | {
|
|
14
|
+
[key: string]: AnyValue;
|
|
15
|
+
};
|
|
16
|
+
export type LogAttributes = Record<string, AnyValue>;
|
|
17
|
+
/** Structured error (§4.2). The `cause` chain is bounded per §6.3. */
|
|
18
|
+
export interface ErrorValue {
|
|
19
|
+
/** Error class or code, e.g. `ERR_INVOKE_CANCELLED`. */
|
|
20
|
+
type: string;
|
|
21
|
+
message: string;
|
|
22
|
+
/** Multi-line, unmodified. */
|
|
23
|
+
stack?: string;
|
|
24
|
+
cause?: ErrorValue;
|
|
25
|
+
}
|
|
26
|
+
/** The emitting Telo resource (§7.3). `id` is the full hierarchical id, which is
|
|
27
|
+
* what distinguishes two instances of the same templated kind. */
|
|
28
|
+
export interface ResourceRef {
|
|
29
|
+
kind: string;
|
|
30
|
+
name: string;
|
|
31
|
+
id?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface LogRecord {
|
|
34
|
+
/** Nanoseconds since the Unix epoch, by the origin clock. */
|
|
35
|
+
timestamp: bigint;
|
|
36
|
+
/** When the runtime observed the event, when that differs from `timestamp`
|
|
37
|
+
* (a bridged third-party logger, §13.3). */
|
|
38
|
+
observedTimestamp?: bigint;
|
|
39
|
+
severityNumber: SeverityNumber;
|
|
40
|
+
/** Canonical short name, or the original source spelling when bridging. */
|
|
41
|
+
severityText: string;
|
|
42
|
+
/** May be empty; never absent. */
|
|
43
|
+
message: string;
|
|
44
|
+
attributes?: LogAttributes;
|
|
45
|
+
/** 32 lowercase hex chars. */
|
|
46
|
+
traceId?: string;
|
|
47
|
+
/** 16 lowercase hex chars. Never present without `traceId`. */
|
|
48
|
+
spanId?: string;
|
|
49
|
+
/** Bit 0 = sampled, bit 1 reserved (§7.5), bits 2–7 zero. */
|
|
50
|
+
traceFlags?: number;
|
|
51
|
+
resource?: ResourceRef;
|
|
52
|
+
/** Module name of the emitter. Not unique — see `scope`. */
|
|
53
|
+
module?: string;
|
|
54
|
+
/** Dotted import-alias path identifying which *instance* emitted the record
|
|
55
|
+
* (`Api.Domain.Db`). Absent for the root Application's own resources. */
|
|
56
|
+
scope?: string;
|
|
57
|
+
/** Identifies a class of event; max 256 chars. */
|
|
58
|
+
eventName?: string;
|
|
59
|
+
error?: ErrorValue;
|
|
60
|
+
/** Non-zero when §6.3 limits truncated attributes. */
|
|
61
|
+
droppedAttributesCount?: number;
|
|
62
|
+
}
|
|
63
|
+
export declare function nowUnixNano(): bigint;
|
|
64
|
+
/** Epoch nanoseconds for a millisecond-resolution instant — used when bridging a
|
|
65
|
+
* third-party record that carries a `Date` or epoch-millis timestamp. */
|
|
66
|
+
export declare function unixNanoFromMillis(epochMillis: number): bigint;
|
|
67
|
+
/**
|
|
68
|
+
* RFC 3339, UTC, nanosecond precision, `Z` suffix — the `time` key of the `json`
|
|
69
|
+
* encoding (§11.1).
|
|
70
|
+
*/
|
|
71
|
+
export declare function formatUnixNano(timestamp: bigint): string;
|
|
72
|
+
//# sourceMappingURL=log-record.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-record.d.ts","sourceRoot":"","sources":["../src/log-record.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD;;;;;;;;;GASG;AAEH,iFAAiF;AACjF,MAAM,MAAM,QAAQ,GAChB,MAAM,GACN,OAAO,GACP,MAAM,GACN,MAAM,GACN,UAAU,GACV,IAAI,GACJ,QAAQ,EAAE,GACV;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAAA;CAAE,CAAC;AAEhC,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAErD,sEAAsE;AACtE,MAAM,WAAW,UAAU;IACzB,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,UAAU,CAAC;CACpB;AAED;mEACmE;AACnE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,SAAS;IACxB,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;IAClB;iDAC6C;IAC7C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,cAAc,CAAC;IAC/B,2EAA2E;IAC3E,YAAY,EAAE,MAAM,CAAC;IACrB,kCAAkC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;8EAC0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,sDAAsD;IACtD,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAoBD,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED;0EAC0E;AAC1E,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAKxD"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Written as `BigInt(...)` rather than as `1_000_000n` literals: this module is
|
|
2
|
+
// consumed from source by the browser-targeted editor, whose tsconfig targets
|
|
3
|
+
// below ES2020 and cannot parse the literal syntax.
|
|
4
|
+
const NANOS_PER_MS = BigInt(1_000_000);
|
|
5
|
+
const NANOS_PER_SECOND = BigInt(1_000_000_000);
|
|
6
|
+
/**
|
|
7
|
+
* Node has no true nanosecond wall clock: `Date` is millisecond-resolution and
|
|
8
|
+
* `hrtime.bigint()` is monotonic rather than epoch-anchored. The best available
|
|
9
|
+
* is the performance origin plus the monotonic offset, which yields microsecond
|
|
10
|
+
* resolution zero-padded to nine digits. Format-conformant with §11.1; the extra
|
|
11
|
+
* three digits are always zero.
|
|
12
|
+
*
|
|
13
|
+
* The origin is captured once as a bigint so the addition never routes a
|
|
14
|
+
* 16-significant-digit value through a float64 and loses the low microseconds.
|
|
15
|
+
*/
|
|
16
|
+
const ORIGIN_NANOS = BigInt(Math.round(performance.timeOrigin * 1e6));
|
|
17
|
+
export function nowUnixNano() {
|
|
18
|
+
return ORIGIN_NANOS + BigInt(Math.round(performance.now() * 1e6));
|
|
19
|
+
}
|
|
20
|
+
/** Epoch nanoseconds for a millisecond-resolution instant — used when bridging a
|
|
21
|
+
* third-party record that carries a `Date` or epoch-millis timestamp. */
|
|
22
|
+
export function unixNanoFromMillis(epochMillis) {
|
|
23
|
+
return BigInt(Math.round(epochMillis)) * NANOS_PER_MS;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* RFC 3339, UTC, nanosecond precision, `Z` suffix — the `time` key of the `json`
|
|
27
|
+
* encoding (§11.1).
|
|
28
|
+
*/
|
|
29
|
+
export function formatUnixNano(timestamp) {
|
|
30
|
+
const seconds = timestamp / NANOS_PER_SECOND;
|
|
31
|
+
const nanos = timestamp - seconds * NANOS_PER_SECOND;
|
|
32
|
+
const isoSeconds = new Date(Number(seconds) * 1000).toISOString().slice(0, 19);
|
|
33
|
+
return `${isoSeconds}.${nanos.toString().padStart(9, "0")}Z`;
|
|
34
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The OpenTelemetry `SeverityNumber` scale (1–24, stable), which Telo adopts
|
|
3
|
+
* verbatim — see `kernel/specs/logging.md` §5.
|
|
4
|
+
*
|
|
5
|
+
* Higher is more severe. All comparison, filtering, and threshold logic uses the
|
|
6
|
+
* number; severity *text* is presentation only and MUST NOT be compared. The
|
|
7
|
+
* full 24-value range stays valid on the wire so records bridged from a
|
|
8
|
+
* third-party logger survive a round-trip with their original spelling intact.
|
|
9
|
+
*/
|
|
10
|
+
/** An OTel SeverityNumber. `0` (UNSPECIFIED) is never emitted by a Telo runtime. */
|
|
11
|
+
export type SeverityNumber = number;
|
|
12
|
+
/** The six levels Telo names. Each is the floor of its four-value OTel range. */
|
|
13
|
+
export declare const SEVERITY: {
|
|
14
|
+
readonly trace: 1;
|
|
15
|
+
readonly debug: 5;
|
|
16
|
+
readonly info: 9;
|
|
17
|
+
readonly warn: 13;
|
|
18
|
+
readonly error: 17;
|
|
19
|
+
readonly fatal: 21;
|
|
20
|
+
};
|
|
21
|
+
export type LevelName = keyof typeof SEVERITY;
|
|
22
|
+
export declare const LEVEL_NAMES: readonly LevelName[];
|
|
23
|
+
/** The severity at or above which a record describes an error (§5.1). This is
|
|
24
|
+
* the portable error predicate; runtimes expose it rather than re-deriving it. */
|
|
25
|
+
export declare const ERROR_SEVERITY_FLOOR = 17;
|
|
26
|
+
/**
|
|
27
|
+
* The range floor for a severity number — the canonical level a value maps onto.
|
|
28
|
+
* Out-of-range values clamp into 1–24 rather than producing `0`, which §5.1
|
|
29
|
+
* forbids emitting.
|
|
30
|
+
*/
|
|
31
|
+
export declare function severityFloor(severity: SeverityNumber): number;
|
|
32
|
+
/** Canonical short name (`TRACE`…`FATAL`) for a severity number. */
|
|
33
|
+
export declare function severityText(severity: SeverityNumber): string;
|
|
34
|
+
/** `true` when the record describes an error (§5.1). */
|
|
35
|
+
export declare function isErrorSeverity(severity: SeverityNumber): boolean;
|
|
36
|
+
/** Resolve a manifest `level:` name to its severity number. */
|
|
37
|
+
export declare function severityForLevel(level: LevelName): number;
|
|
38
|
+
/**
|
|
39
|
+
* Map a level name of unknown provenance onto the scale. A name Telo does not
|
|
40
|
+
* recognize yields `undefined` so the caller can preserve the original spelling
|
|
41
|
+
* in `severity_text` while landing the number on a range floor (§5.1).
|
|
42
|
+
*/
|
|
43
|
+
export declare function parseLevelName(name: string): number | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Go's `log/slog` documents that subtracting 9 from an OTel severity converts it
|
|
46
|
+
* to the slog range — an exact, officially sanctioned relation, so a Go runtime
|
|
47
|
+
* uses arithmetic rather than a table (§5.2). Exposed here so the conformance
|
|
48
|
+
* vectors can assert the relation from the Node side too.
|
|
49
|
+
*/
|
|
50
|
+
export declare const SLOG_OFFSET = 9;
|
|
51
|
+
export declare function pinoLevelForSeverity(severity: SeverityNumber): number;
|
|
52
|
+
/** `undefined` for a pino level Telo does not name, so the caller preserves the
|
|
53
|
+
* source spelling and falls back to the nearest floor. */
|
|
54
|
+
export declare function severityForPinoLevel(level: number): number | undefined;
|
|
55
|
+
//# sourceMappingURL=log-severity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-severity.d.ts","sourceRoot":"","sources":["../src/log-severity.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,oFAAoF;AACpF,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AAEpC,iFAAiF;AACjF,eAAO,MAAM,QAAQ;;;;;;;CAOX,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,QAAQ,CAAC;AAE9C,eAAO,MAAM,WAAW,EAAE,SAAS,SAAS,EAAyD,CAAC;AAEtG;mFACmF;AACnF,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAavC;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,CAQ9D;AAED,oEAAoE;AACpE,wBAAgB,YAAY,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,CAE7D;AAED,wDAAwD;AACxD,wBAAgB,eAAe,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAEjE;AAED,+DAA+D;AAC/D,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAEzD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAU/D;AAED;;;;;GAKG;AACH,eAAO,MAAM,WAAW,IAAI,CAAC;AAwB7B,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,CAErE;AAED;2DAC2D;AAC3D,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEtE"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The OpenTelemetry `SeverityNumber` scale (1–24, stable), which Telo adopts
|
|
3
|
+
* verbatim — see `kernel/specs/logging.md` §5.
|
|
4
|
+
*
|
|
5
|
+
* Higher is more severe. All comparison, filtering, and threshold logic uses the
|
|
6
|
+
* number; severity *text* is presentation only and MUST NOT be compared. The
|
|
7
|
+
* full 24-value range stays valid on the wire so records bridged from a
|
|
8
|
+
* third-party logger survive a round-trip with their original spelling intact.
|
|
9
|
+
*/
|
|
10
|
+
/** The six levels Telo names. Each is the floor of its four-value OTel range. */
|
|
11
|
+
export const SEVERITY = {
|
|
12
|
+
trace: 1,
|
|
13
|
+
debug: 5,
|
|
14
|
+
info: 9,
|
|
15
|
+
warn: 13,
|
|
16
|
+
error: 17,
|
|
17
|
+
fatal: 21,
|
|
18
|
+
};
|
|
19
|
+
export const LEVEL_NAMES = ["trace", "debug", "info", "warn", "error", "fatal"];
|
|
20
|
+
/** The severity at or above which a record describes an error (§5.1). This is
|
|
21
|
+
* the portable error predicate; runtimes expose it rather than re-deriving it. */
|
|
22
|
+
export const ERROR_SEVERITY_FLOOR = 17;
|
|
23
|
+
const FLOORS = [1, 5, 9, 13, 17, 21];
|
|
24
|
+
const TEXT_BY_FLOOR = {
|
|
25
|
+
1: "TRACE",
|
|
26
|
+
5: "DEBUG",
|
|
27
|
+
9: "INFO",
|
|
28
|
+
13: "WARN",
|
|
29
|
+
17: "ERROR",
|
|
30
|
+
21: "FATAL",
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* The range floor for a severity number — the canonical level a value maps onto.
|
|
34
|
+
* Out-of-range values clamp into 1–24 rather than producing `0`, which §5.1
|
|
35
|
+
* forbids emitting.
|
|
36
|
+
*/
|
|
37
|
+
export function severityFloor(severity) {
|
|
38
|
+
const clamped = severity < 1 ? 1 : severity > 24 ? 24 : Math.trunc(severity);
|
|
39
|
+
let floor = FLOORS[0];
|
|
40
|
+
for (const candidate of FLOORS) {
|
|
41
|
+
if (candidate <= clamped)
|
|
42
|
+
floor = candidate;
|
|
43
|
+
else
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
return floor;
|
|
47
|
+
}
|
|
48
|
+
/** Canonical short name (`TRACE`…`FATAL`) for a severity number. */
|
|
49
|
+
export function severityText(severity) {
|
|
50
|
+
return TEXT_BY_FLOOR[severityFloor(severity)];
|
|
51
|
+
}
|
|
52
|
+
/** `true` when the record describes an error (§5.1). */
|
|
53
|
+
export function isErrorSeverity(severity) {
|
|
54
|
+
return severity >= ERROR_SEVERITY_FLOOR;
|
|
55
|
+
}
|
|
56
|
+
/** Resolve a manifest `level:` name to its severity number. */
|
|
57
|
+
export function severityForLevel(level) {
|
|
58
|
+
return SEVERITY[level];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Map a level name of unknown provenance onto the scale. A name Telo does not
|
|
62
|
+
* recognize yields `undefined` so the caller can preserve the original spelling
|
|
63
|
+
* in `severity_text` while landing the number on a range floor (§5.1).
|
|
64
|
+
*/
|
|
65
|
+
export function parseLevelName(name) {
|
|
66
|
+
const key = name.trim().toLowerCase();
|
|
67
|
+
// Own-property check, not `in`: `in` also matches inherited members, so
|
|
68
|
+
// `parseLevelName("toString")` would otherwise return a Function and defeat
|
|
69
|
+
// the `?? fallback` at every call site. Written as `hasOwnProperty.call`
|
|
70
|
+
// rather than `Object.hasOwn` because this module is consumed from source by
|
|
71
|
+
// the browser-targeted editor, whose tsconfig targets below ES2022.
|
|
72
|
+
return Object.prototype.hasOwnProperty.call(SEVERITY, key)
|
|
73
|
+
? SEVERITY[key]
|
|
74
|
+
: undefined;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Go's `log/slog` documents that subtracting 9 from an OTel severity converts it
|
|
78
|
+
* to the slog range — an exact, officially sanctioned relation, so a Go runtime
|
|
79
|
+
* uses arithmetic rather than a table (§5.2). Exposed here so the conformance
|
|
80
|
+
* vectors can assert the relation from the Node side too.
|
|
81
|
+
*/
|
|
82
|
+
export const SLOG_OFFSET = 9;
|
|
83
|
+
/**
|
|
84
|
+
* pino's scale is 10× and offset, with no arithmetic relation to OTel, so §5.2
|
|
85
|
+
* requires a table. Used by the Fastify logger replacement (§13.3).
|
|
86
|
+
*/
|
|
87
|
+
const PINO_BY_SEVERITY = {
|
|
88
|
+
1: 10,
|
|
89
|
+
5: 20,
|
|
90
|
+
9: 30,
|
|
91
|
+
13: 40,
|
|
92
|
+
17: 50,
|
|
93
|
+
21: 60,
|
|
94
|
+
};
|
|
95
|
+
const SEVERITY_BY_PINO = {
|
|
96
|
+
10: 1,
|
|
97
|
+
20: 5,
|
|
98
|
+
30: 9,
|
|
99
|
+
40: 13,
|
|
100
|
+
50: 17,
|
|
101
|
+
60: 21,
|
|
102
|
+
};
|
|
103
|
+
export function pinoLevelForSeverity(severity) {
|
|
104
|
+
return PINO_BY_SEVERITY[severityFloor(severity)];
|
|
105
|
+
}
|
|
106
|
+
/** `undefined` for a pino level Telo does not name, so the caller preserves the
|
|
107
|
+
* source spelling and falls back to the nearest floor. */
|
|
108
|
+
export function severityForPinoLevel(level) {
|
|
109
|
+
return SEVERITY_BY_PINO[level];
|
|
110
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { LogRecord } from "./log-record.js";
|
|
2
|
+
/**
|
|
3
|
+
* The `Telo.Sink` capability contract — `kernel/specs/logging.md` §10.
|
|
4
|
+
*
|
|
5
|
+
* This lives in the SDK rather than the kernel because §10.2 makes the sink set
|
|
6
|
+
* **open to the ecosystem**: a third party ships a sink by publishing a module
|
|
7
|
+
* whose kind extends `Telo.LogSink`. That module is an ordinary module author's
|
|
8
|
+
* artifact, so the contract it implements belongs on the module-author surface,
|
|
9
|
+
* not behind a kernel-internal import.
|
|
10
|
+
*
|
|
11
|
+
* The logger writes to a sink through this contract directly and **never**
|
|
12
|
+
* through `ctx.invoke`: per-record dispatch is far too slow for a logging hot
|
|
13
|
+
* path, and the dispatch chokepoint emits trace events, so logging through it
|
|
14
|
+
* would generate telemetry from inside the telemetry path.
|
|
15
|
+
*
|
|
16
|
+
* The contract is deliberately payload-opaque — no filtering, no encoding —
|
|
17
|
+
* which is what lets a future `Telo.TraceSink` reuse the capability with a
|
|
18
|
+
* different record type. Log-specific configuration lives on the
|
|
19
|
+
* `Telo.LogSink` abstract instead.
|
|
20
|
+
*/
|
|
21
|
+
export type DropCause = "buffer_full" | "sampled" | "encode_failure" | "sink_error";
|
|
22
|
+
/** Policy for a saturated buffer (§10.3). A runtime that cannot honour `block`
|
|
23
|
+
* rejects the manifest at load rather than silently substituting a dropping
|
|
24
|
+
* policy. */
|
|
25
|
+
export type OnFull = "block" | "drop_new" | "drop_old";
|
|
26
|
+
export interface SinkBufferPolicy {
|
|
27
|
+
/** Bounded. Never unbounded. */
|
|
28
|
+
buffer: number;
|
|
29
|
+
onFull: OnFull;
|
|
30
|
+
/** Max time a record may sit buffered, in milliseconds. */
|
|
31
|
+
flushIntervalMs: number;
|
|
32
|
+
}
|
|
33
|
+
export declare const DEFAULT_BUFFER_POLICY: SinkBufferPolicy;
|
|
34
|
+
export interface LogSinkInstance {
|
|
35
|
+
/** Identity for drop accounting (§10.4): the resource name for a `!ref`, or
|
|
36
|
+
* kind plus position for an inline definition. */
|
|
37
|
+
readonly sinkId: string;
|
|
38
|
+
/** This sink's own fan-out filter, applied *after* the record is created. It
|
|
39
|
+
* never decides whether a record is created at all — that is the pipeline's
|
|
40
|
+
* minimum-level gate. */
|
|
41
|
+
readonly level: number;
|
|
42
|
+
/**
|
|
43
|
+
* Whether the sink can be drained to its destination from inside a
|
|
44
|
+
* synchronous call, with no scheduler turn. A file descriptor write can; a
|
|
45
|
+
* network round-trip cannot, and neither can a transport living on another
|
|
46
|
+
* thread — the producer cannot drain a queue it does not own.
|
|
47
|
+
*
|
|
48
|
+
* A capability tier, not a language carve-out: the same rule makes an OTLP
|
|
49
|
+
* sink best-effort in Rust and Go, where blocking a producer thread is
|
|
50
|
+
* possible but still would not make a round-trip synchronous.
|
|
51
|
+
*/
|
|
52
|
+
readonly syncFlushable: boolean;
|
|
53
|
+
/** Accept a record. MUST NOT throw — a sink failure is reported out-of-band
|
|
54
|
+
* and counted, never propagated to the caller (§8.4). */
|
|
55
|
+
write(record: LogRecord): void;
|
|
56
|
+
/** Drain asynchronously. */
|
|
57
|
+
flush(): Promise<void>;
|
|
58
|
+
/** Drain to completion before returning. A no-op when {@link syncFlushable}
|
|
59
|
+
* is `false`; the `fatal` path initiates those sinks' flushes without
|
|
60
|
+
* waiting, because blocking on a sink it cannot synchronously drain is a
|
|
61
|
+
* deadlock on an event loop, not durability. */
|
|
62
|
+
flushSync(): void;
|
|
63
|
+
/** Release the destination. Called during teardown, after the final flush. */
|
|
64
|
+
close(): Promise<void>;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The pipeline surface a sink controller reaches for — attach, detach, resolve a
|
|
68
|
+
* level, count a drop. Deliberately narrow: everything else about the pipeline
|
|
69
|
+
* stays private to the runtime, so a third-party sink depends on this and
|
|
70
|
+
* nothing deeper.
|
|
71
|
+
*/
|
|
72
|
+
export interface LoggingHost {
|
|
73
|
+
attach(sink: LogSinkInstance): void;
|
|
74
|
+
detach(sink: LogSinkInstance): void;
|
|
75
|
+
/** Resolve a sink's declared `level:` to a severity number, falling back to
|
|
76
|
+
* the effective scope threshold when the sink declares none (§12.1). */
|
|
77
|
+
levelFor(level: string | undefined): number;
|
|
78
|
+
/** Count `count` dropped records against this sink so §10.4's accounting stays
|
|
79
|
+
* complete. `count` defaults to 1; a sink that loses a whole batch at once
|
|
80
|
+
* (an OTLP export failure) passes the batch size so the total is not
|
|
81
|
+
* undercounted to one-per-failure. */
|
|
82
|
+
recordDrop(sinkId: string, cause: DropCause, count?: number): void;
|
|
83
|
+
}
|
|
84
|
+
/** The diagnostic §10.3 requires when a runtime cannot honour `on_full: block`.
|
|
85
|
+
* Rejecting is deliberate: `on_full` exists so an operator can state durability
|
|
86
|
+
* intent, and silently substituting a dropping policy hands back the opposite
|
|
87
|
+
* guarantee — discovered from a gap in an audit trail rather than from an
|
|
88
|
+
* error. */
|
|
89
|
+
export declare function blockUnsupportedMessage(sinkId: string): string;
|
|
90
|
+
export declare const BLOCK_UNSUPPORTED = "ERR_LOG_SINK_ON_FULL_UNSUPPORTED";
|
|
91
|
+
//# sourceMappingURL=log-sink.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-sink.d.ts","sourceRoot":"","sources":["../src/log-sink.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,MAAM,SAAS,GAAG,aAAa,GAAG,SAAS,GAAG,gBAAgB,GAAG,YAAY,CAAC;AAEpF;;cAEc;AACd,MAAM,MAAM,MAAM,GAAG,OAAO,GAAG,UAAU,GAAG,UAAU,CAAC;AAEvD,MAAM,WAAW,gBAAgB;IAC/B,gCAAgC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,eAAO,MAAM,qBAAqB,EAAE,gBAInC,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B;uDACmD;IACnD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB;;8BAE0B;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB;;;;;;;;;OASG;IACH,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAEhC;8DAC0D;IAC1D,KAAK,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;IAE/B,4BAA4B;IAC5B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;qDAGiD;IACjD,SAAS,IAAI,IAAI,CAAC;IAElB,8EAA8E;IAC9E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAAC;IACpC,MAAM,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAAC;IACpC;6EACyE;IACzE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;IAC5C;;;2CAGuC;IACvC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACpE;AAED;;;;aAIa;AACb,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAM9D;AAED,eAAO,MAAM,iBAAiB,qCAAqC,CAAC"}
|
package/dist/log-sink.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const DEFAULT_BUFFER_POLICY = {
|
|
2
|
+
buffer: 8192,
|
|
3
|
+
onFull: "drop_new",
|
|
4
|
+
flushIntervalMs: 1000,
|
|
5
|
+
};
|
|
6
|
+
/** The diagnostic §10.3 requires when a runtime cannot honour `on_full: block`.
|
|
7
|
+
* Rejecting is deliberate: `on_full` exists so an operator can state durability
|
|
8
|
+
* intent, and silently substituting a dropping policy hands back the opposite
|
|
9
|
+
* guarantee — discovered from a gap in an audit trail rather than from an
|
|
10
|
+
* error. */
|
|
11
|
+
export function blockUnsupportedMessage(sinkId) {
|
|
12
|
+
return (`Sink "${sinkId}": on_full: block is not supported by this runtime ` +
|
|
13
|
+
`(single-threaded event loop — blocking the producer would stall the writer). ` +
|
|
14
|
+
`Use \`drop_new\` or \`drop_old\`, or move this sink to a worker thread.`);
|
|
15
|
+
}
|
|
16
|
+
export const BLOCK_UNSUPPORTED = "ERR_LOG_SINK_ON_FULL_UNSUPPORTED";
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { AnyValue, LogAttributes } from "./log-record.js";
|
|
2
|
+
import type { SeverityNumber } from "./log-severity.js";
|
|
3
|
+
/**
|
|
4
|
+
* The logger surface every Telo runtime exposes — `kernel/specs/logging.md` §8.
|
|
5
|
+
*
|
|
6
|
+
* Reached ambiently as `ctx.log`. The logger is ambient rather than a resource
|
|
7
|
+
* because it must work before any resource initializes; its *sinks* are
|
|
8
|
+
* resources, which is what keeps the destination set open to the ecosystem.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* A value resolved only on the emit path (§8.2) — slog's `LogValuer`, zap's
|
|
12
|
+
* `ObjectMarshaler`, `tracing`'s `Value`. A deferred value attached to a
|
|
13
|
+
* suppressed record is never resolved, so an expensive rendering costs nothing
|
|
14
|
+
* below the threshold. This is RECOMMENDED sugar and does **not** substitute for
|
|
15
|
+
* {@link Logger.enabled}, which is the only mechanism that avoids evaluating a
|
|
16
|
+
* call's *arguments*.
|
|
17
|
+
*/
|
|
18
|
+
export interface LogValuer {
|
|
19
|
+
toLogValue(): AnyValue;
|
|
20
|
+
}
|
|
21
|
+
export type LogAttributeInput = AnyValue | LogValuer;
|
|
22
|
+
export type LogAttributesInput = Record<string, LogAttributeInput>;
|
|
23
|
+
/** Per-record extras that are top-level record fields rather than attributes.
|
|
24
|
+
* Kept out of the attribute map so they cannot collide with a reserved key. */
|
|
25
|
+
export interface LogOptions {
|
|
26
|
+
/** Any thrown value. Normalized to the record's `error` (§4.2), with the
|
|
27
|
+
* `cause` chain bounded per §6.3. */
|
|
28
|
+
error?: unknown;
|
|
29
|
+
/** Identifies a class of event; max 256 chars. Bridges to the event bus. */
|
|
30
|
+
eventName?: string;
|
|
31
|
+
/** When the event occurred, if earlier than the moment `log()` was called —
|
|
32
|
+
* set by a bridge, which also stamps `observedTimestamp` (§13.3). */
|
|
33
|
+
timestamp?: bigint;
|
|
34
|
+
/** The original source spelling of the level, preserved when bridging a level
|
|
35
|
+
* Telo does not name (§5.1). Defaults to the canonical short name. */
|
|
36
|
+
severityText?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface Logger {
|
|
39
|
+
/**
|
|
40
|
+
* Whether a record at this severity would reach any sink. The load-bearing
|
|
41
|
+
* performance primitive: guard an expensive call with it so the *arguments*
|
|
42
|
+
* are never evaluated.
|
|
43
|
+
*
|
|
44
|
+
* Never blocks, never throws. The result is **not static** — it changes when
|
|
45
|
+
* configuration changes or a sink attaches or detaches (§12.4), so callers
|
|
46
|
+
* re-check per emission rather than caching a boolean.
|
|
47
|
+
*/
|
|
48
|
+
enabled(severity: SeverityNumber): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Emit a record. Never throws, under any condition, including sink failure —
|
|
51
|
+
* a sink failure is reported on the fallback diagnostic stream and counted,
|
|
52
|
+
* never propagated and never swallowed (§8.4).
|
|
53
|
+
*/
|
|
54
|
+
log(severity: SeverityNumber, message: string, attributes?: LogAttributesInput, options?: LogOptions): void;
|
|
55
|
+
/**
|
|
56
|
+
* A child logger whose bound attributes are merged into every record it emits.
|
|
57
|
+
* Record attributes override bound attributes. Binding is O(1) amortized: the
|
|
58
|
+
* merge happens once here, never per record.
|
|
59
|
+
*/
|
|
60
|
+
with(attributes: LogAttributesInput): Logger;
|
|
61
|
+
/** Drain every attached sink. Bounded by the caller; see §10.5. */
|
|
62
|
+
flush(): Promise<void>;
|
|
63
|
+
trace(message: string, attributes?: LogAttributesInput, options?: LogOptions): void;
|
|
64
|
+
debug(message: string, attributes?: LogAttributesInput, options?: LogOptions): void;
|
|
65
|
+
info(message: string, attributes?: LogAttributesInput, options?: LogOptions): void;
|
|
66
|
+
warn(message: string, attributes?: LogAttributesInput, options?: LogOptions): void;
|
|
67
|
+
error(message: string, attributes?: LogAttributesInput, options?: LogOptions): void;
|
|
68
|
+
/**
|
|
69
|
+
* Emits at severity 21. Severity never implies control flow (§5, D5): `fatal`
|
|
70
|
+
* does **not** terminate the process, exit, or panic — it triggers an
|
|
71
|
+
* immediate flush, synchronous on every sink that supports it and best-effort
|
|
72
|
+
* on the rest (§10.5).
|
|
73
|
+
*/
|
|
74
|
+
fatal(message: string, attributes?: LogAttributesInput, options?: LogOptions): void;
|
|
75
|
+
}
|
|
76
|
+
/** Resolve a {@link LogValuer} if the value is one, else pass it through. */
|
|
77
|
+
export declare function isLogValuer(value: unknown): value is LogValuer;
|
|
78
|
+
/** A logger that discards everything. Used where a logger is structurally
|
|
79
|
+
* required before one is available, and by tests that assert silence. */
|
|
80
|
+
export declare const NOOP_LOGGER: Logger;
|
|
81
|
+
/** The bound-attribute merge of {@link Logger.with}, exposed so a runtime's
|
|
82
|
+
* child-logger implementation and its conformance vectors share one definition
|
|
83
|
+
* of "record attributes win". */
|
|
84
|
+
export declare function mergeBoundAttributes(bound: LogAttributes | undefined, record: LogAttributes | undefined): LogAttributes | undefined;
|
|
85
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD;;;;;;GAMG;AAEH;;;;;;;GAOG;AACH,MAAM,WAAW,SAAS;IACxB,UAAU,IAAI,QAAQ,CAAC;CACxB;AAED,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,SAAS,CAAC;AACrD,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;AAEnE;gFACgF;AAChF,MAAM,WAAW,UAAU;IACzB;0CACsC;IACtC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;0EACsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;2EACuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,MAAM;IACrB;;;;;;;;OAQG;IACH,OAAO,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC;IAE3C;;;;OAIG;IACH,GAAG,CACD,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,kBAAkB,EAC/B,OAAO,CAAC,EAAE,UAAU,GACnB,IAAI,CAAC;IAER;;;;OAIG;IACH,IAAI,CAAC,UAAU,EAAE,kBAAkB,GAAG,MAAM,CAAC;IAE7C,mEAAmE;IACnE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IACpF,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IACpF,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IACnF,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IACnF,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IACpF;;;;;OAKG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;CACrF;AAED,6EAA6E;AAC7E,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAM9D;AAED;0EAC0E;AAC1E,eAAO,MAAM,WAAW,EAAE,MAWzB,CAAC;AAEF;;kCAEkC;AAClC,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,aAAa,GAAG,SAAS,EAChC,MAAM,EAAE,aAAa,GAAG,SAAS,GAChC,aAAa,GAAG,SAAS,CAI3B"}
|