@smthrs/gateway 0.33.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/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@smthrs/gateway",
3
+ "version": "0.33.0",
4
+ "description": "Stable Smithers Gateway RPC contracts, auth scopes, and deployment metadata",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "exports": {
8
+ ".": {
9
+ "types": "./src/index.d.ts",
10
+ "import": "./src/index.js",
11
+ "default": "./src/index.js"
12
+ },
13
+ "./rpc": {
14
+ "types": "./src/rpc/index.d.ts",
15
+ "import": "./src/rpc/index.js",
16
+ "default": "./src/rpc/index.js"
17
+ },
18
+ "./auth/scopes": {
19
+ "types": "./src/auth/scopes.d.ts",
20
+ "import": "./src/auth/scopes.js",
21
+ "default": "./src/auth/scopes.js"
22
+ },
23
+ "./api": {
24
+ "types": "./src/api/index.d.ts",
25
+ "import": "./src/api/index.js",
26
+ "default": "./src/api/index.js"
27
+ }
28
+ },
29
+ "files": [
30
+ "src/",
31
+ "openapi.yaml"
32
+ ],
33
+ "dependencies": {
34
+ "@smthrs/protocol": "0.33.0"
35
+ },
36
+ "devDependencies": {
37
+ "@types/bun": "latest",
38
+ "typescript": "~6.0.3"
39
+ },
40
+ "scripts": {
41
+ "generate:openapi": "bun run scripts/generate-openapi.ts",
42
+ "check:openapi": "bun run scripts/generate-openapi.ts --check",
43
+ "build": "bun run check:openapi && node ../../scripts/clean-dts.mjs src && tsup --dts-only",
44
+ "typecheck": "tsc -p tsconfig.json --noEmit",
45
+ "test": "bun test tests"
46
+ }
47
+ }
package/src/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # @smthrs/gateway — src
2
+
3
+ The stable Gateway runtime contract package: pure data plus tiny pure
4
+ functions. `@smthrs/protocol/gateway-rpc` owns the canonical
5
+ wire types; this package owns the runtime RPC catalog and JSON schemas, auth
6
+ scopes, compatibility aliases, and API row serializers. Its only runtime
7
+ dependency is `@smthrs/protocol`, and it deliberately has no
8
+ `effect` dependency.
9
+
10
+ Layout:
11
+
12
+ - `rpc/index.js` — the frozen v1 runtime catalog: JSON schemas,
13
+ `GATEWAY_RPC_DEFINITIONS`, the error table, legacy method aliases, and the
14
+ required-scope lookup (including HTTP-only routes).
15
+ - `rpc/gatewayRpcTypes.ts` — types for the gateway-owned runtime catalog plus
16
+ compatibility re-exports of the protocol-owned wire types.
17
+ - `auth/scopes.js` — the scope catalog, per-family scope hierarchy, and
18
+ `hasGatewayScope` enforcement (including legacy `read`/`execute`/`approve`/
19
+ `admin` grants and per-method name/prefix grants).
20
+ - `api/` — pure DB-row → wire-row serializers for the collection endpoints
21
+ (see `api/README.md`).
22
+ - `index.js` — re-exports all three; `package.json` also exposes each subpath
23
+ (`./rpc`, `./auth/scopes`, `./api`) directly.
24
+
25
+ `@smthrs/gateway/rpc` remains a supported compatibility surface:
26
+ it re-exports the protocol wire types alongside the gateway-owned runtime
27
+ catalog values. The server consumes that runtime catalog. Client code uses
28
+ `@smthrs/gateway-client`, and `gateway-react` consumes
29
+ `gateway-client` instead of importing this package directly.
30
+
31
+ Gotchas:
32
+
33
+ - `openapi.yaml` at the package root is generated from
34
+ `GATEWAY_RPC_DEFINITIONS` by `scripts/generate-openapi.ts` and gated by
35
+ `check:openapi` — any change to serialized schema content requires
36
+ regenerating it.
37
+ - Every RPC here is maturity `stable`; adding or renaming a method or scope is
38
+ a contract change pinned by `tests/rpc-contract.test.ts` (exact method list
39
+ and per-method required scopes).
@@ -0,0 +1,23 @@
1
+ # api/
2
+
3
+ Pure serializers that turn raw DB rows (snake_case keys, driver-typed values)
4
+ into the stable camelCase wire rows served by the Gateway HTTP/Electric
5
+ collection endpoints. `apiCollectionNames.ts` lists the served collection
6
+ names.
7
+
8
+ How it fits together:
9
+
10
+ - `normalizeApiRow.ts` (internal — not re-exported from `index.ts`) does the
11
+ shared work: snake→camel keys, and bigint→number (or a decimal string when
12
+ the value is not a safe integer).
13
+ - Each `serializeXRow.ts` then pins the exact wire shape for one collection —
14
+ picking fields, defaulting missing ones, and parsing embedded JSON columns
15
+ (e.g. approval `request_json`, run-event `payload_json`).
16
+ - One `serializeXRow` exists per collection even when it is a bare
17
+ `normalizeApiRow` pass-through (account/prompt/workflow): a deliberate
18
+ family, so every collection has a named seam to pin its shape later.
19
+
20
+ Consumers: `packages/server/src/gateway.js` and `packages/gateway-client`
21
+ (whose `mapSmithersElectricRow` plus the electric-row-parity and
22
+ local-import-boundary tests assert parity), so the output shapes are contract,
23
+ not implementation detail.
@@ -0,0 +1,10 @@
1
+ export const apiCollectionNames = /** @type {const} */ ([
2
+ "runs",
3
+ "run_events",
4
+ "nodes",
5
+ "node_outputs",
6
+ "approvals",
7
+ "crons",
8
+ "tickets",
9
+ "docs",
10
+ ]);
@@ -0,0 +1,126 @@
1
+ import { GatewayComparisonScoreRow as GatewayComparisonScoreRow$1, GatewayScoreDetail as GatewayScoreDetail$1 } from '@smthrs/protocol/gateway-rpc';
2
+
3
+ /**
4
+ * @template {Record<string, unknown>} Row
5
+ * @param {Row} row
6
+ * @returns {Row}
7
+ */
8
+ declare function serializeAccountRow<Row extends Record<string, unknown>>(row: Row): Row;
9
+
10
+ declare const apiCollectionNames: readonly ["runs", "run_events", "nodes", "node_outputs", "approvals", "crons", "tickets", "docs"];
11
+
12
+ /**
13
+ * @param {Record<string, unknown>} row
14
+ * @returns {{
15
+ * runId: unknown,
16
+ * workflowKey?: unknown,
17
+ * nodeId: unknown,
18
+ * iteration: unknown,
19
+ * requestTitle: unknown,
20
+ * requestSummary: unknown,
21
+ * requestedAtMs: unknown,
22
+ * approvalMode: unknown,
23
+ * options: unknown,
24
+ * allowedScopes: unknown,
25
+ * allowedUsers: unknown,
26
+ * autoApprove: unknown,
27
+ * }}
28
+ */
29
+ declare function serializeApprovalRow(row: Record<string, unknown>): {
30
+ runId: unknown;
31
+ workflowKey?: unknown;
32
+ nodeId: unknown;
33
+ iteration: unknown;
34
+ requestTitle: unknown;
35
+ requestSummary: unknown;
36
+ requestedAtMs: unknown;
37
+ approvalMode: unknown;
38
+ options: unknown;
39
+ allowedScopes: unknown;
40
+ allowedUsers: unknown;
41
+ autoApprove: unknown;
42
+ };
43
+
44
+ /**
45
+ * @template {Record<string, unknown>} Row
46
+ * @param {Row} row
47
+ * @returns {Row}
48
+ */
49
+ declare function serializeCronRow<Row extends Record<string, unknown>>(row: Row): Row;
50
+
51
+ /**
52
+ * @template {Record<string, unknown>} Row
53
+ * @param {Row} row
54
+ * @returns {Row}
55
+ */
56
+ declare function serializeDocRow<Row extends Record<string, unknown>>(row: Row): Row;
57
+
58
+ /**
59
+ * @template {Record<string, unknown>} Row
60
+ * @param {Row} row
61
+ * @returns {Row}
62
+ */
63
+ declare function serializeMemoryFactRow<Row extends Record<string, unknown>>(row: Row): Row;
64
+
65
+ /**
66
+ * @template {Record<string, unknown>} Row
67
+ * @param {Row} row
68
+ * @returns {Row}
69
+ */
70
+ declare function serializePromptRow<Row extends Record<string, unknown>>(row: Row): Row;
71
+
72
+ /**
73
+ * @template {Record<string, unknown>} Row
74
+ * @param {Row} row
75
+ * @returns {Row}
76
+ */
77
+ declare function serializeRunEventRow<Row extends Record<string, unknown>>(row: Row): Row;
78
+
79
+ /**
80
+ * @template {Record<string, unknown>} Row
81
+ * @param {Row} row
82
+ * @returns {Row}
83
+ */
84
+ declare function serializeRunRow<Row extends Record<string, unknown>>(row: Row): Row;
85
+
86
+ /** @typedef {import("../rpc/gatewayRpcTypes.ts").GatewayComparisonScoreRow} GatewayComparisonScoreRow */
87
+ /**
88
+ * @param {Record<string, unknown>} row
89
+ * @returns {GatewayComparisonScoreRow}
90
+ */
91
+ declare function serializeComparisonScoreRow(row: Record<string, unknown>): GatewayComparisonScoreRow;
92
+ type GatewayComparisonScoreRow = GatewayComparisonScoreRow$1;
93
+
94
+ /** @typedef {import("../rpc/gatewayRpcTypes.ts").GatewayScoreDetail} GatewayScoreDetail */
95
+ /**
96
+ * Serialize an already-decoded score detail row. JSON parsing deliberately
97
+ * stays in the server so malformed persistence can fail explicitly instead of
98
+ * being hidden by a wire serializer.
99
+ * @param {Record<string, unknown>} row
100
+ * @returns {GatewayScoreDetail}
101
+ */
102
+ declare function serializeScoreDetailRow(row: Record<string, unknown>): GatewayScoreDetail;
103
+ type GatewayScoreDetail = GatewayScoreDetail$1;
104
+
105
+ /**
106
+ * @template {Record<string, unknown>} Row
107
+ * @param {Row} row
108
+ * @returns {Row}
109
+ */
110
+ declare function serializeScoreRow<Row extends Record<string, unknown>>(row: Row): Row;
111
+
112
+ /**
113
+ * @template {Record<string, unknown>} Row
114
+ * @param {Row} row
115
+ * @returns {Row}
116
+ */
117
+ declare function serializeTicketRow<Row extends Record<string, unknown>>(row: Row): Row;
118
+
119
+ /**
120
+ * @template {Record<string, unknown>} Row
121
+ * @param {Row} row
122
+ * @returns {Row}
123
+ */
124
+ declare function serializeWorkflowRow<Row extends Record<string, unknown>>(row: Row): Row;
125
+
126
+ export { apiCollectionNames, serializeAccountRow, serializeApprovalRow, serializeComparisonScoreRow, serializeCronRow, serializeDocRow, serializeMemoryFactRow, serializePromptRow, serializeRunEventRow, serializeRunRow, serializeScoreDetailRow, serializeScoreRow, serializeTicketRow, serializeWorkflowRow };
@@ -0,0 +1,14 @@
1
+ export { serializeAccountRow } from "./serializeAccountRow.js";
2
+ export { apiCollectionNames } from "./apiCollectionNames.js";
3
+ export { serializeApprovalRow } from "./serializeApprovalRow.js";
4
+ export { serializeCronRow } from "./serializeCronRow.js";
5
+ export { serializeDocRow } from "./serializeDocRow.js";
6
+ export { serializeMemoryFactRow } from "./serializeMemoryFactRow.js";
7
+ export { serializePromptRow } from "./serializePromptRow.js";
8
+ export { serializeRunEventRow } from "./serializeRunEventRow.js";
9
+ export { serializeRunRow } from "./serializeRunRow.js";
10
+ export { serializeComparisonScoreRow } from "./serializeComparisonScoreRow.js";
11
+ export { serializeScoreDetailRow } from "./serializeScoreDetailRow.js";
12
+ export { serializeScoreRow } from "./serializeScoreRow.js";
13
+ export { serializeTicketRow } from "./serializeTicketRow.js";
14
+ export { serializeWorkflowRow } from "./serializeWorkflowRow.js";
@@ -0,0 +1,36 @@
1
+ const SNAKE_SEGMENT = /_([a-z0-9])/g;
2
+
3
+ /**
4
+ * @param {string} key
5
+ * @returns {string}
6
+ */
7
+ function toCamelKey(key) {
8
+ return key.replace(SNAKE_SEGMENT, (_, /** @type {string} */ char) => char.toUpperCase());
9
+ }
10
+
11
+ /**
12
+ * @param {unknown} value
13
+ * @returns {unknown}
14
+ */
15
+ function normalizeValue(value) {
16
+ if (typeof value === "bigint") {
17
+ const number = Number(value);
18
+ return Number.isSafeInteger(number) ? number : value.toString();
19
+ }
20
+ return value;
21
+ }
22
+
23
+ /**
24
+ * @template {Record<string, unknown>} Row
25
+ * @param {Row} row
26
+ * @returns {Record<string, unknown>}
27
+ */
28
+ export function normalizeApiRow(row) {
29
+ /** @type {Record<string, unknown>} */
30
+ const normalized = {};
31
+ for (const [key, value] of Object.entries(row)) {
32
+ const camelKey = toCamelKey(key);
33
+ normalized[camelKey] = normalizeValue(value);
34
+ }
35
+ return normalized;
36
+ }
@@ -0,0 +1,10 @@
1
+ import { normalizeApiRow } from "./normalizeApiRow.js";
2
+
3
+ /**
4
+ * @template {Record<string, unknown>} Row
5
+ * @param {Row} row
6
+ * @returns {Row}
7
+ */
8
+ export function serializeAccountRow(row) {
9
+ return /** @type {Row} */ (normalizeApiRow(row));
10
+ }
@@ -0,0 +1,53 @@
1
+ import { normalizeApiRow } from "./normalizeApiRow.js";
2
+
3
+ /**
4
+ * @param {unknown} value
5
+ * @returns {Record<string, unknown>}
6
+ */
7
+ function parseJson(value) {
8
+ if (!value || typeof value !== "string") return {};
9
+ try {
10
+ const parsed = JSON.parse(value);
11
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed)
12
+ ? /** @type {Record<string, unknown>} */ (parsed)
13
+ : {};
14
+ } catch {
15
+ return {};
16
+ }
17
+ }
18
+
19
+ /**
20
+ * @param {Record<string, unknown>} row
21
+ * @returns {{
22
+ * runId: unknown,
23
+ * workflowKey?: unknown,
24
+ * nodeId: unknown,
25
+ * iteration: unknown,
26
+ * requestTitle: unknown,
27
+ * requestSummary: unknown,
28
+ * requestedAtMs: unknown,
29
+ * approvalMode: unknown,
30
+ * options: unknown,
31
+ * allowedScopes: unknown,
32
+ * allowedUsers: unknown,
33
+ * autoApprove: unknown,
34
+ * }}
35
+ */
36
+ export function serializeApprovalRow(row) {
37
+ const normalized = normalizeApiRow(row);
38
+ const request = parseJson(normalized.requestJson);
39
+ return {
40
+ runId: normalized.runId,
41
+ ...(normalized.workflowKey === undefined ? {} : { workflowKey: normalized.workflowKey }),
42
+ nodeId: normalized.nodeId,
43
+ iteration: normalized.iteration ?? 0,
44
+ requestTitle: normalized.requestTitle ?? request.title,
45
+ requestSummary: normalized.requestSummary ?? request.summary,
46
+ requestedAtMs: normalized.requestedAtMs ?? null,
47
+ approvalMode: normalized.approvalMode ?? request.mode,
48
+ options: normalized.options ?? request.options,
49
+ allowedScopes: normalized.allowedScopes ?? request.allowedScopes,
50
+ allowedUsers: normalized.allowedUsers ?? request.allowedUsers,
51
+ autoApprove: normalized.autoApprove ?? request.autoApprove,
52
+ };
53
+ }
@@ -0,0 +1,18 @@
1
+ import { normalizeApiRow } from "./normalizeApiRow.js";
2
+ import { serializeScoreRow } from "./serializeScoreRow.js";
3
+
4
+ /** @typedef {import("../rpc/gatewayRpcTypes.ts").GatewayComparisonScoreRow} GatewayComparisonScoreRow */
5
+
6
+ /**
7
+ * @param {Record<string, unknown>} row
8
+ * @returns {GatewayComparisonScoreRow}
9
+ */
10
+ export function serializeComparisonScoreRow(row) {
11
+ const normalized = normalizeApiRow(row);
12
+ return /** @type {GatewayComparisonScoreRow} */ (
13
+ /** @type {unknown} */ ({
14
+ scoreId: normalized.scoreId ?? normalized.id,
15
+ ...serializeScoreRow(row),
16
+ })
17
+ );
18
+ }
@@ -0,0 +1,30 @@
1
+ import { normalizeApiRow } from "./normalizeApiRow.js";
2
+
3
+ /**
4
+ * @template {Record<string, unknown>} Row
5
+ * @param {Row} row
6
+ * @returns {Row}
7
+ */
8
+ export function serializeCronRow(row) {
9
+ const normalized = normalizeApiRow(row);
10
+ const workflowPath = typeof normalized.workflowPath === "string" ? normalized.workflowPath : "";
11
+ const workflow =
12
+ typeof normalized.workflow === "string"
13
+ ? normalized.workflow
14
+ : workflowPath.startsWith("gateway:")
15
+ ? workflowPath.slice("gateway:".length)
16
+ : workflowPath;
17
+ return /** @type {Row} */ (
18
+ /** @type {unknown} */ ({
19
+ cronId: normalized.cronId,
20
+ pattern: normalized.pattern,
21
+ workflowPath,
22
+ workflow,
23
+ enabled: normalized.enabled === true || normalized.enabled === 1,
24
+ createdAtMs: normalized.createdAtMs,
25
+ lastRunAtMs: normalized.lastRunAtMs ?? null,
26
+ nextRunAtMs: normalized.nextRunAtMs ?? null,
27
+ errorJson: normalized.errorJson ?? null,
28
+ })
29
+ );
30
+ }
@@ -0,0 +1,20 @@
1
+ import { normalizeApiRow } from "./normalizeApiRow.js";
2
+
3
+ /**
4
+ * @template {Record<string, unknown>} Row
5
+ * @param {Row} row
6
+ * @returns {Row}
7
+ */
8
+ export function serializeDocRow(row) {
9
+ const normalized = normalizeApiRow(row);
10
+ return /** @type {Row} */ (
11
+ /** @type {unknown} */ ({
12
+ path: normalized.path,
13
+ kind: normalized.kind,
14
+ content: normalized.content,
15
+ contentHash: normalized.contentHash,
16
+ updatedAtMs: normalized.updatedAtMs,
17
+ deletedAtMs: normalized.deletedAtMs ?? null,
18
+ })
19
+ );
20
+ }
@@ -0,0 +1,21 @@
1
+ import { normalizeApiRow } from "./normalizeApiRow.js";
2
+
3
+ /**
4
+ * @template {Record<string, unknown>} Row
5
+ * @param {Row} row
6
+ * @returns {Row}
7
+ */
8
+ export function serializeMemoryFactRow(row) {
9
+ const normalized = normalizeApiRow(row);
10
+ return /** @type {Row} */ (
11
+ /** @type {unknown} */ ({
12
+ namespace: normalized.namespace,
13
+ key: normalized.key,
14
+ valueJson: normalized.valueJson,
15
+ schemaSig: normalized.schemaSig ?? null,
16
+ createdAtMs: normalized.createdAtMs,
17
+ updatedAtMs: normalized.updatedAtMs,
18
+ ttlMs: normalized.ttlMs ?? null,
19
+ })
20
+ );
21
+ }
@@ -0,0 +1,10 @@
1
+ import { normalizeApiRow } from "./normalizeApiRow.js";
2
+
3
+ /**
4
+ * @template {Record<string, unknown>} Row
5
+ * @param {Row} row
6
+ * @returns {Row}
7
+ */
8
+ export function serializePromptRow(row) {
9
+ return /** @type {Row} */ (normalizeApiRow(row));
10
+ }
@@ -0,0 +1,28 @@
1
+ import { normalizeApiRow } from "./normalizeApiRow.js";
2
+
3
+ /**
4
+ * @template {Record<string, unknown>} Row
5
+ * @param {Row} row
6
+ * @returns {Row}
7
+ */
8
+ export function serializeRunEventRow(row) {
9
+ const normalized = normalizeApiRow(row);
10
+ const payloadJson = normalized.payloadJson;
11
+ let payload = normalized.payload;
12
+ if (payload === undefined && typeof payloadJson === "string") {
13
+ try {
14
+ payload = JSON.parse(payloadJson);
15
+ } catch {
16
+ payload = payloadJson;
17
+ }
18
+ }
19
+ return /** @type {Row} */ (
20
+ /** @type {unknown} */ ({
21
+ runId: normalized.runId,
22
+ seq: normalized.seq,
23
+ event: normalized.event ?? normalized.type,
24
+ payload,
25
+ ...(normalized.timestampMs === undefined ? {} : { timestampMs: normalized.timestampMs }),
26
+ })
27
+ );
28
+ }
@@ -0,0 +1,61 @@
1
+ import { normalizeApiRow } from "./normalizeApiRow.js";
2
+
3
+ /** @param {unknown} value */
4
+ function validStartedBy(value) {
5
+ if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
6
+ const source = /** @type {Record<string, unknown>} */ (value);
7
+ const known = ["harness", "sessionId", "prompt", "detected"];
8
+ if (Object.keys(source).some((key) => !known.includes(key))) return undefined;
9
+ if (["harness", "sessionId", "prompt"].some((key) => source[key] !== undefined && typeof source[key] !== "string"))
10
+ return undefined;
11
+ if (source.detected !== undefined && source.detected !== true) return undefined;
12
+ const harness = typeof source.harness === "string" ? source.harness : undefined;
13
+ const sessionId = typeof source.sessionId === "string" ? source.sessionId : undefined;
14
+ const prompt = typeof source.prompt === "string" ? source.prompt : undefined;
15
+ if (!harness && !sessionId && prompt === undefined) return undefined;
16
+ if (source.detected === true && !harness && !sessionId) return undefined;
17
+ return {
18
+ ...(harness ? { harness } : {}),
19
+ ...(sessionId ? { sessionId } : {}),
20
+ ...(prompt !== undefined ? { prompt } : {}),
21
+ ...(source.detected === true ? { detected: true } : {}),
22
+ };
23
+ }
24
+
25
+ /**
26
+ * @template {Record<string, unknown>} Row
27
+ * @param {Row} row
28
+ * @returns {Row}
29
+ */
30
+ export function serializeRunRow(row) {
31
+ const normalized = normalizeApiRow(row);
32
+ let config;
33
+ if (typeof normalized.configJson === "string") {
34
+ try {
35
+ config = /** @type {{ gatewayWorkflowKey?: unknown; gatewaySystem?: unknown; startedBy?: unknown }} */ (
36
+ JSON.parse(normalized.configJson)
37
+ );
38
+ } catch {
39
+ // Malformed run config stays opaque on the wire.
40
+ }
41
+ }
42
+ if (normalized.workflowKey === undefined && typeof config?.gatewayWorkflowKey === "string") {
43
+ normalized.workflowKey = config.gatewayWorkflowKey;
44
+ }
45
+ const startedBy = validStartedBy(config?.startedBy);
46
+ if (startedBy) normalized.startedBy = startedBy;
47
+ // Visibility is fail-closed. New gateway runs persist a boolean stamp;
48
+ // historical or malformed rows are internal until an explicit debug list
49
+ // opts into them. Preserve an already-projected trusted server response
50
+ // (launch/get/list) which carries no configJson.
51
+ normalized.system =
52
+ typeof config?.gatewaySystem === "boolean"
53
+ ? config.gatewaySystem
54
+ : typeof normalized.system === "boolean"
55
+ ? normalized.system
56
+ : true;
57
+ if (normalized.workflowKey === undefined && typeof normalized.workflowName === "string") {
58
+ normalized.workflowKey = normalized.workflowName;
59
+ }
60
+ return /** @type {Row} */ (normalized);
61
+ }
@@ -0,0 +1,25 @@
1
+ import { normalizeApiRow } from "./normalizeApiRow.js";
2
+ import { serializeComparisonScoreRow } from "./serializeComparisonScoreRow.js";
3
+
4
+ /** @typedef {import("../rpc/gatewayRpcTypes.ts").GatewayScoreDetail} GatewayScoreDetail */
5
+
6
+ /**
7
+ * Serialize an already-decoded score detail row. JSON parsing deliberately
8
+ * stays in the server so malformed persistence can fail explicitly instead of
9
+ * being hidden by a wire serializer.
10
+ * @param {Record<string, unknown>} row
11
+ * @returns {GatewayScoreDetail}
12
+ */
13
+ export function serializeScoreDetailRow(row) {
14
+ const normalized = normalizeApiRow(row);
15
+ return /** @type {GatewayScoreDetail} */ (
16
+ /** @type {unknown} */ ({
17
+ ...serializeComparisonScoreRow(row),
18
+ meta: normalized.meta ?? null,
19
+ input: normalized.input ?? null,
20
+ output: normalized.output ?? null,
21
+ groundTruth: normalized.groundTruth ?? null,
22
+ context: normalized.context ?? null,
23
+ })
24
+ );
25
+ }
@@ -0,0 +1,26 @@
1
+ import { normalizeApiRow } from "./normalizeApiRow.js";
2
+
3
+ /**
4
+ * @template {Record<string, unknown>} Row
5
+ * @param {Row} row
6
+ * @returns {Row}
7
+ */
8
+ export function serializeScoreRow(row) {
9
+ const normalized = normalizeApiRow(row);
10
+ return /** @type {Row} */ (
11
+ /** @type {unknown} */ ({
12
+ runId: normalized.runId,
13
+ nodeId: normalized.nodeId,
14
+ iteration: normalized.iteration ?? 0,
15
+ attempt: normalized.attempt ?? 0,
16
+ scorerId: normalized.scorerId,
17
+ scorerName: normalized.scorerName,
18
+ source: normalized.source,
19
+ score: normalized.score,
20
+ reason: normalized.reason ?? null,
21
+ scoredAtMs: normalized.scoredAtMs,
22
+ latencyMs: normalized.latencyMs ?? null,
23
+ durationMs: normalized.durationMs ?? null,
24
+ })
25
+ );
26
+ }
@@ -0,0 +1,20 @@
1
+ import { normalizeApiRow } from "./normalizeApiRow.js";
2
+
3
+ /**
4
+ * @template {Record<string, unknown>} Row
5
+ * @param {Row} row
6
+ * @returns {Row}
7
+ */
8
+ export function serializeTicketRow(row) {
9
+ const normalized = normalizeApiRow(row);
10
+ return /** @type {Row} */ (
11
+ /** @type {unknown} */ ({
12
+ path: normalized.path,
13
+ kind: normalized.kind,
14
+ content: normalized.content,
15
+ contentHash: normalized.contentHash,
16
+ status: normalized.status ?? null,
17
+ updatedAtMs: normalized.updatedAtMs,
18
+ })
19
+ );
20
+ }
@@ -0,0 +1,10 @@
1
+ import { normalizeApiRow } from "./normalizeApiRow.js";
2
+
3
+ /**
4
+ * @template {Record<string, unknown>} Row
5
+ * @param {Row} row
6
+ * @returns {Row}
7
+ */
8
+ export function serializeWorkflowRow(row) {
9
+ return /** @type {Row} */ (normalizeApiRow(row));
10
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @param {string} scope
3
+ * @returns {scope is GatewayScope}
4
+ */
5
+ declare function isGatewayScope(scope: string): scope is GatewayScope;
6
+ /**
7
+ * @param {readonly string[]} grantedScopes
8
+ * @param {GatewayScope} requiredScope
9
+ * @param {string} [methodName]
10
+ * @returns {boolean}
11
+ */
12
+ declare function hasGatewayScope(grantedScopes: readonly string[], requiredScope: GatewayScope, methodName?: string): boolean;
13
+ /** @typedef {(typeof GATEWAY_SCOPE_VALUES)[number]} GatewayScope */
14
+ declare const GATEWAY_SCOPE_VALUES: readonly ["run:read", "run:write", "run:admin", "approval:submit", "signal:submit", "cron:read", "cron:write", "account:read", "memory:read", "prompt:read", "score:read", "ticket:read", "ticket:write", "observability:read"];
15
+ /** @type {Record<GatewayScope, string>} */
16
+ declare const GATEWAY_SCOPE_DESCRIPTIONS: Record<GatewayScope, string>;
17
+ type GatewayScope = (typeof GATEWAY_SCOPE_VALUES)[number];
18
+
19
+ export { GATEWAY_SCOPE_DESCRIPTIONS, GATEWAY_SCOPE_VALUES, type GatewayScope, hasGatewayScope, isGatewayScope };