@blokjs/runner 0.2.0 → 0.2.2

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.
Files changed (80) hide show
  1. package/dist/Blok.js +11 -11
  2. package/dist/Blok.js.map +1 -1
  3. package/dist/Configuration.d.ts +21 -2
  4. package/dist/Configuration.js +188 -26
  5. package/dist/Configuration.js.map +1 -1
  6. package/dist/ConfigurationResolver.d.ts +9 -0
  7. package/dist/ConfigurationResolver.js +17 -1
  8. package/dist/ConfigurationResolver.js.map +1 -1
  9. package/dist/RunnerSteps.js +52 -9
  10. package/dist/RunnerSteps.js.map +1 -1
  11. package/dist/RuntimeAdapterNode.d.ts +32 -2
  12. package/dist/RuntimeAdapterNode.js +122 -27
  13. package/dist/RuntimeAdapterNode.js.map +1 -1
  14. package/dist/TriggerBase.js +35 -2
  15. package/dist/TriggerBase.js.map +1 -1
  16. package/dist/adapters/BunRuntimeAdapter.d.ts +1 -0
  17. package/dist/adapters/BunRuntimeAdapter.js +1 -0
  18. package/dist/adapters/BunRuntimeAdapter.js.map +1 -1
  19. package/dist/adapters/DockerRuntimeAdapter.d.ts +2 -1
  20. package/dist/adapters/DockerRuntimeAdapter.js +10 -1
  21. package/dist/adapters/DockerRuntimeAdapter.js.map +1 -1
  22. package/dist/adapters/HttpRuntimeAdapter.d.ts +26 -5
  23. package/dist/adapters/HttpRuntimeAdapter.js +97 -16
  24. package/dist/adapters/HttpRuntimeAdapter.js.map +1 -1
  25. package/dist/adapters/NodeJsRuntimeAdapter.d.ts +1 -0
  26. package/dist/adapters/NodeJsRuntimeAdapter.js +1 -0
  27. package/dist/adapters/NodeJsRuntimeAdapter.js.map +1 -1
  28. package/dist/adapters/RuntimeAdapter.d.ts +17 -0
  29. package/dist/adapters/WasmRuntimeAdapter.d.ts +1 -0
  30. package/dist/adapters/WasmRuntimeAdapter.js +1 -0
  31. package/dist/adapters/WasmRuntimeAdapter.js.map +1 -1
  32. package/dist/adapters/grpc/GrpcChannelOptions.d.ts +31 -0
  33. package/dist/adapters/grpc/GrpcChannelOptions.js +68 -0
  34. package/dist/adapters/grpc/GrpcChannelOptions.js.map +1 -0
  35. package/dist/adapters/grpc/GrpcClientPool.d.ts +43 -0
  36. package/dist/adapters/grpc/GrpcClientPool.js +89 -0
  37. package/dist/adapters/grpc/GrpcClientPool.js.map +1 -0
  38. package/dist/adapters/grpc/GrpcCodec.d.ts +226 -0
  39. package/dist/adapters/grpc/GrpcCodec.js +275 -0
  40. package/dist/adapters/grpc/GrpcCodec.js.map +1 -0
  41. package/dist/adapters/grpc/GrpcErrors.d.ts +59 -0
  42. package/dist/adapters/grpc/GrpcErrors.js +190 -0
  43. package/dist/adapters/grpc/GrpcErrors.js.map +1 -0
  44. package/dist/adapters/grpc/GrpcHealthChecker.d.ts +69 -0
  45. package/dist/adapters/grpc/GrpcHealthChecker.js +96 -0
  46. package/dist/adapters/grpc/GrpcHealthChecker.js.map +1 -0
  47. package/dist/adapters/grpc/GrpcRuntimeAdapter.d.ts +98 -0
  48. package/dist/adapters/grpc/GrpcRuntimeAdapter.js +478 -0
  49. package/dist/adapters/grpc/GrpcRuntimeAdapter.js.map +1 -0
  50. package/dist/adapters/grpc/index.d.ts +13 -0
  51. package/dist/adapters/grpc/index.js +14 -0
  52. package/dist/adapters/grpc/index.js.map +1 -0
  53. package/dist/adapters/grpc/proto/blok/runtime/v1/runtime.proto +302 -0
  54. package/dist/adapters/grpc/types.d.ts +97 -0
  55. package/dist/adapters/grpc/types.js +41 -0
  56. package/dist/adapters/grpc/types.js.map +1 -0
  57. package/dist/adapters/transport.d.ts +108 -0
  58. package/dist/adapters/transport.js +196 -0
  59. package/dist/adapters/transport.js.map +1 -0
  60. package/dist/index.d.ts +13 -1
  61. package/dist/index.js +14 -0
  62. package/dist/index.js.map +1 -1
  63. package/dist/testing/WorkflowTestRunner.js +12 -0
  64. package/dist/testing/WorkflowTestRunner.js.map +1 -1
  65. package/dist/tracing/RunTracker.d.ts +23 -2
  66. package/dist/tracing/RunTracker.js +120 -10
  67. package/dist/tracing/RunTracker.js.map +1 -1
  68. package/dist/tracing/SqliteRunStore.js +19 -3
  69. package/dist/tracing/SqliteRunStore.js.map +1 -1
  70. package/dist/tracing/TraceRouter.js +245 -4
  71. package/dist/tracing/TraceRouter.js.map +1 -1
  72. package/dist/tracing/types.d.ts +82 -10
  73. package/dist/types/GlobalOptions.d.ts +9 -2
  74. package/dist/workflow/PersistenceHelper.d.ts +46 -0
  75. package/dist/workflow/PersistenceHelper.js +57 -0
  76. package/dist/workflow/PersistenceHelper.js.map +1 -0
  77. package/dist/workflow/WorkflowNormalizer.d.ts +91 -0
  78. package/dist/workflow/WorkflowNormalizer.js +304 -0
  79. package/dist/workflow/WorkflowNormalizer.js.map +1 -0
  80. package/package.json +10 -7
@@ -0,0 +1,226 @@
1
+ import type { Context } from "@blokjs/shared";
2
+ import { type ServiceClientConstructor } from "@grpc/grpc-js";
3
+ import type RunnerNode from "../../RunnerNode";
4
+ /**
5
+ * The {@link NodeRuntime} service client constructor — used by
6
+ * {@link GrpcClientPool} to instantiate clients.
7
+ */
8
+ export declare const NodeRuntimeService: ServiceClientConstructor;
9
+ export interface ExecuteRequestProto {
10
+ node: NodeRefProto;
11
+ inputs: Buffer;
12
+ step: StepInfoProto;
13
+ trigger: TriggerInfoProto;
14
+ state: RuntimeStateProto;
15
+ workflow: WorkflowInfoProto;
16
+ options: ExecuteOptionsProto;
17
+ }
18
+ export interface NodeRefProto {
19
+ name: string;
20
+ type: string;
21
+ version: string;
22
+ }
23
+ export interface StepInfoProto {
24
+ name: string;
25
+ index: number;
26
+ total: number;
27
+ depth: number;
28
+ }
29
+ export interface TriggerInfoProto {
30
+ body: Buffer;
31
+ headers: Record<string, string>;
32
+ params: Record<string, string>;
33
+ query: Record<string, string>;
34
+ cookies: Record<string, string>;
35
+ method: string;
36
+ url: string;
37
+ baseUrl: string;
38
+ triggerKind: string;
39
+ }
40
+ export interface RuntimeStateProto {
41
+ previousOutput: Buffer;
42
+ vars: Buffer;
43
+ env: Record<string, string>;
44
+ }
45
+ export interface WorkflowInfoProto {
46
+ runId: string;
47
+ name: string;
48
+ path: string;
49
+ version: string;
50
+ startedAt: {
51
+ seconds: string;
52
+ nanos: number;
53
+ } | null;
54
+ }
55
+ export interface ExecuteOptionsProto {
56
+ deadlineMs: string;
57
+ streamLogs: boolean;
58
+ captureMetrics: boolean;
59
+ hints: Record<string, string>;
60
+ }
61
+ export interface ExecuteResponseProto {
62
+ success: boolean;
63
+ data: Buffer;
64
+ contentType: string;
65
+ error: NodeErrorProto | null;
66
+ varsDelta: Buffer;
67
+ logs: LogLineProto[];
68
+ metrics: MetricsProto | null;
69
+ }
70
+ export interface NodeErrorProto {
71
+ code: string;
72
+ category: string;
73
+ severity: string;
74
+ node: string;
75
+ sdk: string;
76
+ sdkVersion: string;
77
+ runtimeKind: string;
78
+ at: {
79
+ seconds: string;
80
+ nanos: number;
81
+ } | null;
82
+ message: string;
83
+ description: string;
84
+ remediation: string;
85
+ docUrl: string;
86
+ causes: NodeErrorProto[];
87
+ stack: string;
88
+ contextSnapshotJson: Buffer;
89
+ httpStatus: number;
90
+ retryable: boolean;
91
+ retryAfterMs: string;
92
+ detailsJson: Buffer;
93
+ }
94
+ export interface LogLineProto {
95
+ timestamp: {
96
+ seconds: string;
97
+ nanos: number;
98
+ } | null;
99
+ level: string;
100
+ message: string;
101
+ attributes: Record<string, string>;
102
+ }
103
+ export interface MetricsProto {
104
+ durationMs: number;
105
+ cpuMs: number;
106
+ memoryBytes: string;
107
+ requestBytes: string;
108
+ responseBytes: string;
109
+ }
110
+ export interface DecodedExecuteResponse {
111
+ readonly success: boolean;
112
+ readonly data: unknown;
113
+ readonly contentType: string;
114
+ readonly varsDelta: Record<string, unknown>;
115
+ readonly logs: ReadonlyArray<DecodedLogLine>;
116
+ readonly error: DecodedNodeError | null;
117
+ readonly metrics: DecodedMetrics;
118
+ }
119
+ export interface DecodedLogLine {
120
+ readonly timestamp: number;
121
+ readonly level: string;
122
+ readonly message: string;
123
+ readonly attributes: Record<string, string>;
124
+ }
125
+ export interface DecodedNodeError {
126
+ readonly code: string;
127
+ readonly category: string;
128
+ readonly severity: string;
129
+ readonly node: string;
130
+ readonly sdk: string;
131
+ readonly sdkVersion: string;
132
+ readonly runtimeKind: string;
133
+ readonly at: number;
134
+ readonly message: string;
135
+ readonly description: string;
136
+ readonly remediation: string;
137
+ readonly docUrl: string;
138
+ readonly causes: ReadonlyArray<DecodedNodeError>;
139
+ readonly stack: string;
140
+ readonly contextSnapshot: unknown;
141
+ readonly httpStatus: number;
142
+ readonly retryable: boolean;
143
+ readonly retryAfterMs: number;
144
+ readonly details: unknown;
145
+ }
146
+ export interface DecodedMetrics {
147
+ readonly durationMs: number;
148
+ readonly cpuMs: number;
149
+ readonly memoryBytes: number;
150
+ readonly requestBytes: number;
151
+ readonly responseBytes: number;
152
+ }
153
+ /**
154
+ * Encode a workflow {@link Context} and a {@link RunnerNode} into a
155
+ * {@link ExecuteRequestProto} ready for the gRPC wire.
156
+ *
157
+ * Pure function — no I/O. The opaque JSON-shaped fields (`inputs`,
158
+ * `previous_output`, `vars`, body) are serialized to UTF-8 bytes here so the
159
+ * SDK side can JSON-decode lazily.
160
+ *
161
+ * Critically, `inputs` is the resolved node config (from the Blueprint
162
+ * Mapper) sent UNWRAPPED — no `{inputs:{...}}` envelope. This closes the
163
+ * `BLOK_FRAMEWORK_FIXES.md` #3 unwrap-hack family of bugs at the wire format
164
+ * layer.
165
+ */
166
+ export declare function encodeExecuteRequest(node: RunnerNode, ctx: Context, stepIndex: number, stepTotal: number, stepDepth: number, deadlineMs: number): ExecuteRequestProto;
167
+ /**
168
+ * Proto envelope for a streamed event. proto-loader with `oneofs: true`
169
+ * exposes the active oneof case via the `event` property AND mirrors the
170
+ * matching field at the top level. We discriminate on `event`.
171
+ */
172
+ export interface ExecuteEventProto {
173
+ event: "started" | "log" | "progress" | "partial" | "final" | undefined;
174
+ started?: {
175
+ at: {
176
+ seconds: string;
177
+ nanos: number;
178
+ } | null;
179
+ };
180
+ log?: LogLineProto;
181
+ progress?: {
182
+ percent: number;
183
+ phase: string;
184
+ };
185
+ partial?: {
186
+ snapshotJson: Buffer;
187
+ };
188
+ final?: ExecuteResponseProto;
189
+ }
190
+ /**
191
+ * Adapter-facing discriminated union — keeps callers free of proto-loader
192
+ * shape concerns and lets TypeScript narrow on the `type` field.
193
+ */
194
+ export type DecodedExecuteEvent = {
195
+ readonly type: "started";
196
+ readonly at: number;
197
+ } | {
198
+ readonly type: "log";
199
+ readonly log: DecodedLogLine;
200
+ } | {
201
+ readonly type: "progress";
202
+ readonly percent: number;
203
+ readonly phase: string;
204
+ } | {
205
+ readonly type: "partial";
206
+ readonly snapshot: unknown;
207
+ } | {
208
+ readonly type: "final";
209
+ readonly response: DecodedExecuteResponse;
210
+ };
211
+ /**
212
+ * Decode a single streamed `ExecuteEvent` proto into the discriminated union
213
+ * the adapter exposes. Returns `null` when the proto envelope is empty (no
214
+ * oneof field set) — the caller skips such frames.
215
+ */
216
+ export declare function decodeExecuteEvent(event: ExecuteEventProto): DecodedExecuteEvent | null;
217
+ /**
218
+ * Decode a {@link ExecuteResponseProto} from the wire into the shape the
219
+ * adapter consumes. Defensive against missing fields (proto-loader fills in
220
+ * defaults, but we guard against malformed responses too).
221
+ */
222
+ export declare function decodeExecuteResponse(response: ExecuteResponseProto): DecodedExecuteResponse;
223
+ /** Encode a value as UTF-8 JSON bytes. `null`/`undefined` → empty buffer. */
224
+ export declare function jsonToBuffer(value: unknown): Buffer;
225
+ /** Decode a buffer as UTF-8 JSON. Empty/missing buffer → `null`. */
226
+ export declare function bufferToJson(buf: Buffer | undefined): unknown;
@@ -0,0 +1,275 @@
1
+ import path from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ import { loadPackageDefinition } from "@grpc/grpc-js";
4
+ import { loadSync } from "@grpc/proto-loader";
5
+ // =============================================================================
6
+ // Proto loading — single point of I/O in this module
7
+ // =============================================================================
8
+ /**
9
+ * Resolve the path to `runtime.proto`. Prefers the dist-bundled copy at
10
+ * runtime; falls back to the src copy when running from source.
11
+ */
12
+ function resolveProtoPath() {
13
+ // `import.meta.url` works under both Node ESM and Bun. The dist copy
14
+ // sits next to the compiled JS; src copy sits next to TS source.
15
+ const here = path.dirname(fileURLToPath(import.meta.url));
16
+ return path.resolve(here, "proto/blok/runtime/v1/runtime.proto");
17
+ }
18
+ /** Options for `@grpc/proto-loader` — chosen for fidelity with our schema. */
19
+ const PROTO_LOADER_OPTIONS = {
20
+ keepCase: false, // snake_case in proto -> camelCase in JS for ergonomic field access
21
+ longs: String,
22
+ enums: String,
23
+ defaults: true,
24
+ oneofs: true,
25
+ includeDirs: [],
26
+ };
27
+ /** Loaded once at module init; reused for every encode/decode. */
28
+ const PROTO_PATH = resolveProtoPath();
29
+ const PACKAGE_DEFINITION = loadSync(PROTO_PATH, PROTO_LOADER_OPTIONS);
30
+ const PROTO_DESCRIPTOR = loadPackageDefinition(PACKAGE_DEFINITION);
31
+ /** Path to the `NodeRuntime` service constructor inside the loaded proto. */
32
+ const NODE_RUNTIME_NAMESPACE = PROTO_DESCRIPTOR.blok.runtime.v1;
33
+ /**
34
+ * The {@link NodeRuntime} service client constructor — used by
35
+ * {@link GrpcClientPool} to instantiate clients.
36
+ */
37
+ export const NodeRuntimeService = NODE_RUNTIME_NAMESPACE.NodeRuntime;
38
+ // =============================================================================
39
+ // Encoder — Context + RunnerNode → proto ExecuteRequest
40
+ // =============================================================================
41
+ /**
42
+ * Encode a workflow {@link Context} and a {@link RunnerNode} into a
43
+ * {@link ExecuteRequestProto} ready for the gRPC wire.
44
+ *
45
+ * Pure function — no I/O. The opaque JSON-shaped fields (`inputs`,
46
+ * `previous_output`, `vars`, body) are serialized to UTF-8 bytes here so the
47
+ * SDK side can JSON-decode lazily.
48
+ *
49
+ * Critically, `inputs` is the resolved node config (from the Blueprint
50
+ * Mapper) sent UNWRAPPED — no `{inputs:{...}}` envelope. This closes the
51
+ * `BLOK_FRAMEWORK_FIXES.md` #3 unwrap-hack family of bugs at the wire format
52
+ * layer.
53
+ */
54
+ export function encodeExecuteRequest(node, ctx, stepIndex, stepTotal, stepDepth, deadlineMs) {
55
+ const resolvedInputs = extractResolvedInputs(ctx, node.name);
56
+ const previousOutput = ctx.response?.data ?? null;
57
+ const vars = ctx.vars ?? {};
58
+ const env = stringEnv(ctx.env);
59
+ const request = ctx.request ?? {};
60
+ const requestBody = request.body;
61
+ return {
62
+ node: {
63
+ name: node.node,
64
+ type: node.type ?? "",
65
+ version: "",
66
+ },
67
+ inputs: jsonToBuffer(resolvedInputs),
68
+ step: {
69
+ name: node.name,
70
+ index: stepIndex,
71
+ total: stepTotal,
72
+ depth: stepDepth,
73
+ },
74
+ trigger: {
75
+ body: bodyToBuffer(requestBody),
76
+ headers: stringMap(request.headers),
77
+ params: stringMap(request.params),
78
+ query: stringMap(request.query),
79
+ cookies: stringMap(request.cookies),
80
+ method: stringField(request.method),
81
+ url: stringField(request.url),
82
+ baseUrl: stringField(request.baseUrl),
83
+ triggerKind: "",
84
+ },
85
+ state: {
86
+ previousOutput: jsonToBuffer(previousOutput),
87
+ vars: jsonToBuffer(vars),
88
+ env,
89
+ },
90
+ workflow: {
91
+ runId: ctx.id,
92
+ name: ctx.workflow_name ?? "",
93
+ path: ctx.workflow_path ?? "",
94
+ version: "",
95
+ startedAt: null,
96
+ },
97
+ options: {
98
+ deadlineMs: String(deadlineMs),
99
+ streamLogs: false,
100
+ captureMetrics: true,
101
+ hints: {},
102
+ },
103
+ };
104
+ }
105
+ /**
106
+ * Decode a single streamed `ExecuteEvent` proto into the discriminated union
107
+ * the adapter exposes. Returns `null` when the proto envelope is empty (no
108
+ * oneof field set) — the caller skips such frames.
109
+ */
110
+ export function decodeExecuteEvent(event) {
111
+ switch (event.event) {
112
+ case "started":
113
+ return { type: "started", at: timestampToMs(event.started?.at ?? null) };
114
+ case "log":
115
+ return event.log ? { type: "log", log: decodeLogLine(event.log) } : null;
116
+ case "progress":
117
+ return {
118
+ type: "progress",
119
+ percent: event.progress?.percent ?? 0,
120
+ phase: event.progress?.phase ?? "",
121
+ };
122
+ case "partial":
123
+ return { type: "partial", snapshot: bufferToJson(event.partial?.snapshotJson) };
124
+ case "final":
125
+ return event.final ? { type: "final", response: decodeExecuteResponse(event.final) } : null;
126
+ default:
127
+ return null;
128
+ }
129
+ }
130
+ // =============================================================================
131
+ // Decoder — proto ExecuteResponse → DecodedExecuteResponse
132
+ // =============================================================================
133
+ /**
134
+ * Decode a {@link ExecuteResponseProto} from the wire into the shape the
135
+ * adapter consumes. Defensive against missing fields (proto-loader fills in
136
+ * defaults, but we guard against malformed responses too).
137
+ */
138
+ export function decodeExecuteResponse(response) {
139
+ return {
140
+ success: response.success ?? false,
141
+ data: bufferToJson(response.data),
142
+ contentType: response.contentType || "application/json",
143
+ varsDelta: bufferToJson(response.varsDelta) ?? {},
144
+ logs: (response.logs ?? []).map(decodeLogLine),
145
+ error: response.error ? decodeNodeError(response.error) : null,
146
+ metrics: decodeMetrics(response.metrics),
147
+ };
148
+ }
149
+ function decodeLogLine(line) {
150
+ return {
151
+ timestamp: timestampToMs(line.timestamp),
152
+ level: line.level,
153
+ message: line.message,
154
+ attributes: line.attributes ?? {},
155
+ };
156
+ }
157
+ function decodeNodeError(err) {
158
+ return {
159
+ code: err.code,
160
+ category: err.category,
161
+ severity: err.severity,
162
+ node: err.node,
163
+ sdk: err.sdk,
164
+ sdkVersion: err.sdkVersion,
165
+ runtimeKind: err.runtimeKind,
166
+ at: timestampToMs(err.at),
167
+ message: err.message,
168
+ description: err.description,
169
+ remediation: err.remediation,
170
+ docUrl: err.docUrl,
171
+ causes: (err.causes ?? []).map(decodeNodeError),
172
+ stack: err.stack,
173
+ contextSnapshot: bufferToJson(err.contextSnapshotJson),
174
+ httpStatus: err.httpStatus,
175
+ retryable: err.retryable,
176
+ retryAfterMs: Number(err.retryAfterMs ?? 0),
177
+ details: bufferToJson(err.detailsJson),
178
+ };
179
+ }
180
+ function decodeMetrics(metrics) {
181
+ return {
182
+ durationMs: metrics?.durationMs ?? 0,
183
+ cpuMs: metrics?.cpuMs ?? 0,
184
+ memoryBytes: Number(metrics?.memoryBytes ?? 0),
185
+ requestBytes: Number(metrics?.requestBytes ?? 0),
186
+ responseBytes: Number(metrics?.responseBytes ?? 0),
187
+ };
188
+ }
189
+ // =============================================================================
190
+ // Internal serialization helpers
191
+ // =============================================================================
192
+ /**
193
+ * Pull resolved node inputs from `ctx.config[nodeName].inputs` (the shape
194
+ * established by the Blueprint Mapper) and return them as a plain object.
195
+ *
196
+ * Falls back to `ctx.response.data` when no resolved inputs exist (matches
197
+ * the legacy zero-config-chaining behavior of `HttpRuntimeAdapter`).
198
+ */
199
+ function extractResolvedInputs(ctx, nodeName) {
200
+ const nodeConfig = ctx.config
201
+ ? ctx.config[nodeName]
202
+ : undefined;
203
+ const resolved = nodeConfig?.inputs;
204
+ if (resolved !== undefined)
205
+ return resolved;
206
+ return ctx.response?.data ?? {};
207
+ }
208
+ /** Encode a value as UTF-8 JSON bytes. `null`/`undefined` → empty buffer. */
209
+ export function jsonToBuffer(value) {
210
+ if (value === null || value === undefined)
211
+ return Buffer.alloc(0);
212
+ return Buffer.from(JSON.stringify(value), "utf-8");
213
+ }
214
+ /** Decode a buffer as UTF-8 JSON. Empty/missing buffer → `null`. */
215
+ export function bufferToJson(buf) {
216
+ if (!buf || buf.length === 0)
217
+ return null;
218
+ try {
219
+ return JSON.parse(buf.toString("utf-8"));
220
+ }
221
+ catch {
222
+ // Malformed JSON — return raw string so callers can salvage what they can.
223
+ return buf.toString("utf-8");
224
+ }
225
+ }
226
+ /**
227
+ * Encode a request body. Strings stay UTF-8; objects become JSON; Buffers
228
+ * pass through. Anything else stringifies via JSON.
229
+ */
230
+ function bodyToBuffer(body) {
231
+ if (body === null || body === undefined)
232
+ return Buffer.alloc(0);
233
+ if (Buffer.isBuffer(body))
234
+ return body;
235
+ if (typeof body === "string")
236
+ return Buffer.from(body, "utf-8");
237
+ return Buffer.from(JSON.stringify(body), "utf-8");
238
+ }
239
+ /** Coerce an unknown record-like value into `Record<string, string>`. */
240
+ function stringMap(value) {
241
+ if (!value || typeof value !== "object")
242
+ return {};
243
+ const out = {};
244
+ for (const [key, val] of Object.entries(value)) {
245
+ if (typeof val === "string")
246
+ out[key] = val;
247
+ else if (val !== null && val !== undefined)
248
+ out[key] = String(val);
249
+ }
250
+ return out;
251
+ }
252
+ /** Coerce an unknown value into a string field; default empty. */
253
+ function stringField(value) {
254
+ return typeof value === "string" ? value : "";
255
+ }
256
+ /** Filter env to string-valued entries (process.env can carry undefined). */
257
+ function stringEnv(env) {
258
+ if (!env)
259
+ return {};
260
+ const out = {};
261
+ for (const [key, val] of Object.entries(env)) {
262
+ if (typeof val === "string")
263
+ out[key] = val;
264
+ }
265
+ return out;
266
+ }
267
+ /** Convert a proto Timestamp to ms-since-epoch. */
268
+ function timestampToMs(ts) {
269
+ if (!ts)
270
+ return 0;
271
+ const seconds = Number(ts.seconds ?? 0);
272
+ const nanos = ts.nanos ?? 0;
273
+ return seconds * 1000 + Math.floor(nanos / 1_000_000);
274
+ }
275
+ //# sourceMappingURL=GrpcCodec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GrpcCodec.js","sourceRoot":"","sources":["../../../src/adapters/grpc/GrpcCodec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ import { BlokError, ErrorCategory } from "@blokjs/shared";
2
+ import { status as GrpcStatus, type ServiceError } from "@grpc/grpc-js";
3
+ /**
4
+ * Mapping table from `@grpc/grpc-js` `status` codes to canonical
5
+ * `(ErrorCategory, defaultHttpStatus)` pairs.
6
+ *
7
+ * Single source of truth for gRPC-side error classification. Adapters never
8
+ * branch on status codes inline; they call {@link toBlokError} which uses
9
+ * this table.
10
+ *
11
+ * The table is exhaustive — every gRPC status defined in
12
+ * `@grpc/grpc-js#status` has an entry. CI verifies coverage in the unit test.
13
+ */
14
+ export declare const GRPC_STATUS_MAP: Readonly<Record<GrpcStatus, {
15
+ category: ErrorCategory;
16
+ httpStatus: number;
17
+ codePrefix: string;
18
+ }>>;
19
+ /**
20
+ * Context passed alongside a gRPC error so the resulting {@link BlokError}
21
+ * carries origin information (which SDK, which kind, which step) without
22
+ * the adapter having to know the proto layout.
23
+ */
24
+ export interface GrpcErrorContext {
25
+ readonly node: string;
26
+ readonly sdk: string;
27
+ readonly sdkVersion: string;
28
+ readonly runtimeKind: string;
29
+ }
30
+ /**
31
+ * Convert a gRPC `ServiceError` (or any thrown value from a gRPC call) into a
32
+ * canonical {@link BlokError}. Lossless when the SDK populates structured
33
+ * details: gRPC `status.details` carrying a serialized {@link NodeErrorPayload}
34
+ * is decoded and merged into the resulting error.
35
+ *
36
+ * Behavior:
37
+ * - `ServiceError` with a known `code`: looked up in {@link GRPC_STATUS_MAP}.
38
+ * If `metadata` carries `blok-error-bin` (a serialized NodeErrorPayload),
39
+ * the payload is reconstructed via {@link BlokError.fromJSON} and the
40
+ * gRPC status only refines the http_status / category fallback.
41
+ * - Plain `Error`: wrapped via {@link BlokError.fromUnknown}.
42
+ * - Anything else: stringified and wrapped as `INTERNAL`.
43
+ */
44
+ export declare function toBlokError(err: unknown, ctx: GrpcErrorContext): BlokError;
45
+ /**
46
+ * Type guard for {@link ServiceError}. Duck-typed because `instanceof` checks
47
+ * across `@grpc/grpc-js` module boundaries are unreliable when the dep is
48
+ * deduped at multiple versions.
49
+ */
50
+ export declare function isServiceError(err: unknown): err is ServiceError;
51
+ /**
52
+ * Translate a `BlokError` produced by the runner side back into a gRPC status
53
+ * code, for cases where the runner needs to report failure to a downstream
54
+ * caller using gRPC. Inverse of {@link GRPC_STATUS_MAP}.
55
+ *
56
+ * Currently used only by tests; will be used by Phase 5 streaming when the
57
+ * runner re-emits node errors as `ExecuteStream` `final` frames.
58
+ */
59
+ export declare function categoryToGrpcStatus(category: ErrorCategory): GrpcStatus;