@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/LICENSE +21 -0
- package/openapi.yaml +29179 -0
- package/package.json +47 -0
- package/src/README.md +39 -0
- package/src/api/README.md +23 -0
- package/src/api/apiCollectionNames.js +10 -0
- package/src/api/index.d.ts +126 -0
- package/src/api/index.js +14 -0
- package/src/api/normalizeApiRow.js +36 -0
- package/src/api/serializeAccountRow.js +10 -0
- package/src/api/serializeApprovalRow.js +53 -0
- package/src/api/serializeComparisonScoreRow.js +18 -0
- package/src/api/serializeCronRow.js +30 -0
- package/src/api/serializeDocRow.js +20 -0
- package/src/api/serializeMemoryFactRow.js +21 -0
- package/src/api/serializePromptRow.js +10 -0
- package/src/api/serializeRunEventRow.js +28 -0
- package/src/api/serializeRunRow.js +61 -0
- package/src/api/serializeScoreDetailRow.js +25 -0
- package/src/api/serializeScoreRow.js +26 -0
- package/src/api/serializeTicketRow.js +20 -0
- package/src/api/serializeWorkflowRow.js +10 -0
- package/src/auth/scopes.d.ts +19 -0
- package/src/auth/scopes.js +164 -0
- package/src/index.d.ts +316 -0
- package/src/index.js +108 -0
- package/src/rpc/gatewayRpcTypes.ts +183 -0
- package/src/rpc/index.d.ts +221 -0
- package/src/rpc/index.js +2426 -0
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,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 };
|
package/src/api/index.js
ADDED
|
@@ -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,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,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,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 };
|