@unifyplane/logsdk 0.1.4 → 0.1.6
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/core/clock.d.ts +3 -0
- package/dist/core/clock.d.ts.map +1 -0
- package/dist/core/clock.js +21 -0
- package/dist/core/clock.js.map +1 -0
- package/dist/core/context.d.ts +10 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +100 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/fanout.d.ts +6 -0
- package/dist/core/fanout.d.ts.map +1 -0
- package/dist/core/fanout.js +35 -0
- package/dist/core/fanout.js.map +1 -0
- package/dist/core/ids.d.ts +6 -0
- package/dist/core/ids.d.ts.map +1 -0
- package/dist/core/ids.js +27 -0
- package/dist/core/ids.js.map +1 -0
- package/dist/core/message_constraints.d.ts +4 -0
- package/dist/core/message_constraints.d.ts.map +1 -0
- package/dist/core/message_constraints.js +53 -0
- package/dist/core/message_constraints.js.map +1 -0
- package/dist/core/outcomes.d.ts +5 -0
- package/dist/core/outcomes.d.ts.map +1 -0
- package/dist/core/outcomes.js +4 -0
- package/dist/core/outcomes.js.map +1 -0
- package/dist/core/record_builder.d.ts +34 -0
- package/dist/core/record_builder.d.ts.map +1 -0
- package/dist/core/record_builder.js +188 -0
- package/dist/core/record_builder.js.map +1 -0
- package/dist/core/spool.d.ts +4 -0
- package/dist/core/spool.d.ts.map +1 -0
- package/dist/core/spool.js +31 -0
- package/dist/core/spool.js.map +1 -0
- package/dist/core/types.d.ts +33 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +4 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/index.js.map +1 -0
- package/dist/sinks/file_ndjson.d.ts +18 -0
- package/dist/sinks/file_ndjson.d.ts.map +1 -0
- package/dist/sinks/file_ndjson.js +29 -0
- package/dist/sinks/file_ndjson.js.map +1 -0
- package/dist/sinks/file_ndjson_sink.d.ts +7 -0
- package/dist/sinks/file_ndjson_sink.d.ts.map +1 -0
- package/dist/sinks/file_ndjson_sink.js +36 -0
- package/dist/sinks/file_ndjson_sink.js.map +1 -0
- package/dist/sinks/index.d.ts +12 -0
- package/dist/sinks/index.d.ts.map +1 -0
- package/dist/sinks/index.js +11 -0
- package/dist/sinks/index.js.map +1 -0
- package/dist/sinks/sink_types.d.ts +12 -0
- package/dist/sinks/sink_types.d.ts.map +1 -0
- package/dist/sinks/sink_types.js +2 -0
- package/dist/sinks/sink_types.js.map +1 -0
- package/dist/sinks/stdout_sink.d.ts +6 -0
- package/dist/sinks/stdout_sink.d.ts.map +1 -0
- package/dist/sinks/stdout_sink.js +15 -0
- package/dist/sinks/stdout_sink.js.map +1 -0
- package/dist/validate/api_surface_guard.d.ts +2 -0
- package/dist/validate/api_surface_guard.d.ts.map +1 -0
- package/dist/validate/api_surface_guard.js +63 -0
- package/dist/validate/api_surface_guard.js.map +1 -0
- package/dist/validate/noncompliance.d.ts +15 -0
- package/dist/validate/noncompliance.d.ts.map +1 -0
- package/dist/validate/noncompliance.js +17 -0
- package/dist/validate/noncompliance.js.map +1 -0
- package/dist/validate/schema_guard.d.ts +5 -0
- package/dist/validate/schema_guard.d.ts.map +1 -0
- package/dist/validate/schema_guard.js +151 -0
- package/dist/validate/schema_guard.js.map +1 -0
- package/package.json +1 -1
- package/src/core/fanout.ts +8 -3
- package/src/index.ts +9 -1
- package/src/sinks/index.ts +9 -5
- package/src.zip +0 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { assertValidMessage } from "../core/message_constraints.js";
|
|
2
|
+
import { CANONICAL_SCHEMA_VIOLATION, CONTEXT_INJECTION_VIOLATION, NO_AUTHORITATIVE_SINK, PAYLOAD_EMBEDDING_VIOLATION, NonComplianceError, } from "./noncompliance.js";
|
|
3
|
+
const REQUIRED_FIELDS = [
|
|
4
|
+
"record_version",
|
|
5
|
+
"record_id",
|
|
6
|
+
"sequence",
|
|
7
|
+
"timestamp_utc",
|
|
8
|
+
"monotonic_time",
|
|
9
|
+
"institution",
|
|
10
|
+
"system_name",
|
|
11
|
+
"system_type",
|
|
12
|
+
"environment",
|
|
13
|
+
"system_version",
|
|
14
|
+
"message",
|
|
15
|
+
"context_hash",
|
|
16
|
+
"context_version",
|
|
17
|
+
"record_hash",
|
|
18
|
+
"hash_algorithm",
|
|
19
|
+
];
|
|
20
|
+
const OPTIONAL_FIELDS = [
|
|
21
|
+
"instance_id",
|
|
22
|
+
"trace_id",
|
|
23
|
+
"span_id",
|
|
24
|
+
"parent_step_id",
|
|
25
|
+
"surface_type",
|
|
26
|
+
"surface_name",
|
|
27
|
+
"surface_instance",
|
|
28
|
+
"source_file",
|
|
29
|
+
"source_module",
|
|
30
|
+
"source_function",
|
|
31
|
+
"source_line",
|
|
32
|
+
"message_code",
|
|
33
|
+
"evidence_refs",
|
|
34
|
+
];
|
|
35
|
+
const ALLOWED_FIELDS = new Set([...REQUIRED_FIELDS, ...OPTIONAL_FIELDS]);
|
|
36
|
+
const CONTEXT_FIELDS = ["context", "context_blob", "context_data", "context_value"];
|
|
37
|
+
// Explicit type assertion for string keys from Object.keys(schema.properties)
|
|
38
|
+
function asRecord(value) {
|
|
39
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
40
|
+
throw new NonComplianceError(CANONICAL_SCHEMA_VIOLATION, "Step record must be a plain object.");
|
|
41
|
+
}
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
export function assertStepRecord(record) {
|
|
45
|
+
const candidate = asRecord(record);
|
|
46
|
+
if (!Object.isFrozen(candidate)) {
|
|
47
|
+
throw new NonComplianceError(CANONICAL_SCHEMA_VIOLATION, "Step record must be immutable at emission time.");
|
|
48
|
+
}
|
|
49
|
+
for (const forbidden of CONTEXT_FIELDS) {
|
|
50
|
+
if (forbidden in candidate) {
|
|
51
|
+
throw new NonComplianceError(CONTEXT_INJECTION_VIOLATION, "Context must not be embedded in the step record.");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
for (const key of Object.keys(candidate)) {
|
|
55
|
+
if (!ALLOWED_FIELDS.has(key)) {
|
|
56
|
+
throw new NonComplianceError(CANONICAL_SCHEMA_VIOLATION, `Unexpected field in step record: ${key}.`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
for (const field of REQUIRED_FIELDS) {
|
|
60
|
+
if (!(field in candidate)) {
|
|
61
|
+
throw new NonComplianceError(CANONICAL_SCHEMA_VIOLATION, `Missing required field: ${field}.`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
assertStringField(candidate, "record_version");
|
|
65
|
+
assertStringField(candidate, "record_id");
|
|
66
|
+
assertIntegerField(candidate, "sequence");
|
|
67
|
+
assertStringField(candidate, "timestamp_utc");
|
|
68
|
+
assertNumberField(candidate, "monotonic_time");
|
|
69
|
+
assertStringField(candidate, "institution");
|
|
70
|
+
assertStringField(candidate, "system_name");
|
|
71
|
+
assertStringField(candidate, "system_type");
|
|
72
|
+
assertStringField(candidate, "environment");
|
|
73
|
+
assertStringField(candidate, "system_version");
|
|
74
|
+
assertStringField(candidate, "context_hash");
|
|
75
|
+
assertStringField(candidate, "context_version");
|
|
76
|
+
assertStringField(candidate, "record_hash");
|
|
77
|
+
assertStringField(candidate, "hash_algorithm");
|
|
78
|
+
if (candidate.record_version !== "log.step.v1") {
|
|
79
|
+
throw new NonComplianceError(CANONICAL_SCHEMA_VIOLATION, "record_version must be log.step.v1.");
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
assertValidMessage(candidate.message);
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
throw new NonComplianceError(PAYLOAD_EMBEDDING_VIOLATION, error instanceof Error ? error.message : "Invalid message content.");
|
|
86
|
+
}
|
|
87
|
+
if (typeof candidate.timestamp_utc === "string") {
|
|
88
|
+
const parsed = Date.parse(candidate.timestamp_utc);
|
|
89
|
+
if (Number.isNaN(parsed)) {
|
|
90
|
+
throw new NonComplianceError(CANONICAL_SCHEMA_VIOLATION, "timestamp_utc must be a valid ISO-8601 string.");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
assertOptionalStringField(candidate, "instance_id");
|
|
94
|
+
assertOptionalStringField(candidate, "trace_id");
|
|
95
|
+
assertOptionalStringField(candidate, "span_id");
|
|
96
|
+
assertOptionalStringField(candidate, "parent_step_id");
|
|
97
|
+
assertOptionalStringField(candidate, "surface_type");
|
|
98
|
+
assertOptionalStringField(candidate, "surface_name");
|
|
99
|
+
assertOptionalStringField(candidate, "surface_instance");
|
|
100
|
+
assertOptionalStringField(candidate, "source_file");
|
|
101
|
+
assertOptionalStringField(candidate, "source_module");
|
|
102
|
+
assertOptionalStringField(candidate, "source_function");
|
|
103
|
+
assertOptionalStringField(candidate, "message_code");
|
|
104
|
+
if ("source_line" in candidate && candidate.source_line !== undefined) {
|
|
105
|
+
assertNumberField(candidate, "source_line");
|
|
106
|
+
}
|
|
107
|
+
if ("evidence_refs" in candidate && candidate.evidence_refs !== undefined) {
|
|
108
|
+
if (!Array.isArray(candidate.evidence_refs)) {
|
|
109
|
+
throw new NonComplianceError(CANONICAL_SCHEMA_VIOLATION, "evidence_refs must be an array of strings.");
|
|
110
|
+
}
|
|
111
|
+
for (const ref of candidate.evidence_refs) {
|
|
112
|
+
if (typeof ref !== "string" || ref.length === 0) {
|
|
113
|
+
throw new NonComplianceError(CANONICAL_SCHEMA_VIOLATION, "evidence_refs must contain non-empty strings.");
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Explicit type assertion for string keys from Object.keys(schema.properties)
|
|
119
|
+
export function assertHasAuthoritativeSink(sinks) {
|
|
120
|
+
const hasAuthoritative = sinks.some((entry) => entry.sinkClass === "authoritative");
|
|
121
|
+
if (!hasAuthoritative) {
|
|
122
|
+
throw new NonComplianceError(NO_AUTHORITATIVE_SINK, "At least one authoritative sink is required.");
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function assertStringField(record, field) {
|
|
126
|
+
const value = record[field];
|
|
127
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
128
|
+
throw new NonComplianceError(CANONICAL_SCHEMA_VIOLATION, `${field} must be a non-empty string.`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function assertOptionalStringField(record, field) {
|
|
132
|
+
if (field in record && record[field] !== undefined) {
|
|
133
|
+
const value = record[field];
|
|
134
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
135
|
+
throw new NonComplianceError(CANONICAL_SCHEMA_VIOLATION, `${field} must be a non-empty string when provided.`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function assertNumberField(record, field) {
|
|
140
|
+
const value = record[field];
|
|
141
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
142
|
+
throw new NonComplianceError(CANONICAL_SCHEMA_VIOLATION, `${field} must be a finite number.`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function assertIntegerField(record, field) {
|
|
146
|
+
const value = record[field];
|
|
147
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
|
|
148
|
+
throw new NonComplianceError(CANONICAL_SCHEMA_VIOLATION, `${field} must be a non-negative integer.`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=schema_guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema_guard.js","sourceRoot":"","sources":["../../src/validate/schema_guard.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/core/fanout.ts
CHANGED
|
@@ -6,9 +6,14 @@ export type FanoutOutcome = "OK" | "DEGRADED" | "FAILED";
|
|
|
6
6
|
|
|
7
7
|
export async function fanout(
|
|
8
8
|
record: StepRecord,
|
|
9
|
-
sinks: ReadonlyArray<SinkEntry
|
|
9
|
+
sinks: ReadonlyArray<SinkEntry>,
|
|
10
|
+
options?: { mode?: "authoritative" | "non-authoritative" }
|
|
10
11
|
): Promise<FanoutOutcome> {
|
|
11
|
-
|
|
12
|
+
const mode = options?.mode ?? "authoritative";
|
|
13
|
+
|
|
14
|
+
if (mode === "authoritative") {
|
|
15
|
+
assertHasAuthoritativeSink(sinks);
|
|
16
|
+
}
|
|
12
17
|
const frozenRecord = Object.isFrozen(record) ? record : Object.freeze(record);
|
|
13
18
|
let outcome: FanoutOutcome = "OK";
|
|
14
19
|
let spooled = false;
|
|
@@ -17,7 +22,7 @@ export async function fanout(
|
|
|
17
22
|
try {
|
|
18
23
|
await entry.sink.emit(frozenRecord);
|
|
19
24
|
} catch {
|
|
20
|
-
if (entry.sinkClass === "authoritative") {
|
|
25
|
+
if (mode === "authoritative" && entry.sinkClass === "authoritative") {
|
|
21
26
|
if (!spooled) {
|
|
22
27
|
try {
|
|
23
28
|
await writeEmergencySpool(frozenRecord);
|
package/src/index.ts
CHANGED
|
@@ -29,6 +29,12 @@ export type LogSDKConfig = {
|
|
|
29
29
|
context: unknown;
|
|
30
30
|
system: SystemOwnership;
|
|
31
31
|
sinks: ReadonlyArray<SinkEntry>;
|
|
32
|
+
/**
|
|
33
|
+
* Execution mode of the logger.
|
|
34
|
+
* - "authoritative" (default): requires at least one authoritative sink
|
|
35
|
+
* - "non-authoritative": allows orchestration-only runtimes (CLI, planners)
|
|
36
|
+
*/
|
|
37
|
+
mode?: "authoritative" | "non-authoritative";
|
|
32
38
|
};
|
|
33
39
|
|
|
34
40
|
export type LogApi = {
|
|
@@ -75,7 +81,9 @@ export function initLogSDK(config: LogSDKConfig): LogApi {
|
|
|
75
81
|
|
|
76
82
|
assertStepRecord(record);
|
|
77
83
|
|
|
78
|
-
const outcome = await fanout(record, sinks
|
|
84
|
+
const outcome = await fanout(record, sinks, {
|
|
85
|
+
mode: config.mode ?? "authoritative",
|
|
86
|
+
});
|
|
79
87
|
if (outcome === "FAILED") {
|
|
80
88
|
throw new NonComplianceError(
|
|
81
89
|
AUTHORITATIVE_FAILURE_SWALLOWED,
|
package/src/sinks/index.ts
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
+
|
|
3
4
|
import { createStdoutSink } from "./stdout_sink.js";
|
|
4
5
|
import { createFileNdjsonSink } from "./file_ndjson_sink.js";
|
|
5
|
-
|
|
6
|
-
export {
|
|
6
|
+
// ---- Sink factories (authoritative API) ----
|
|
7
|
+
export { createStdoutSink } from "./stdout_sink.js";
|
|
8
|
+
export { createFileNdjsonSink } from "./file_ndjson_sink.js";
|
|
9
|
+
|
|
10
|
+
// ---- Optional class exports (ESM only) ----
|
|
11
|
+
export { StdoutSink } from "./stdout_sink.js";
|
|
12
|
+
export { FileNdjsonSink } from "./file_ndjson_sink.js";
|
|
7
13
|
|
|
8
|
-
// CJS interop
|
|
14
|
+
// ---- CJS interop (single, stable surface) ----
|
|
9
15
|
export default {
|
|
10
16
|
createStdoutSink,
|
|
11
17
|
createFileNdjsonSink
|
|
12
18
|
};
|
|
13
|
-
// Public sink exports
|
|
14
|
-
// These are execution substrates and part of LogSDK's supported API.
|
package/src.zip
CHANGED
|
Binary file
|