@vellumai/credential-executor 0.6.5 → 0.7.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.
Files changed (46) hide show
  1. package/Dockerfile +5 -5
  2. package/bun.lock +15 -7
  3. package/node_modules/@vellumai/credential-storage/src/__tests__/package-boundary.test.ts +32 -6
  4. package/node_modules/@vellumai/egress-proxy/src/__tests__/package-boundary.test.ts +32 -1
  5. package/node_modules/@vellumai/egress-proxy/src/types.ts +19 -0
  6. package/node_modules/@vellumai/{ces-contracts → service-contracts}/bun.lock +1 -1
  7. package/node_modules/@vellumai/{ces-contracts → service-contracts}/package.json +4 -2
  8. package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/contracts.test.ts +5 -1
  9. package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +155 -0
  10. package/node_modules/@vellumai/service-contracts/src/credential-rpc.ts +23 -0
  11. package/node_modules/@vellumai/service-contracts/src/index.ts +25 -0
  12. package/node_modules/@vellumai/{ces-contracts/src/index.ts → service-contracts/src/transport.ts} +6 -28
  13. package/node_modules/@vellumai/service-contracts/src/trust-rules.ts +116 -0
  14. package/package.json +3 -3
  15. package/src/__tests__/bulk-set-credentials.test.ts +1 -1
  16. package/src/__tests__/command-executor.test.ts +2 -2
  17. package/src/__tests__/http-executor.test.ts +1 -1
  18. package/src/__tests__/local-materializers.test.ts +1 -1
  19. package/src/__tests__/managed-integration.test.ts +1 -1
  20. package/src/__tests__/managed-lazy-getters.test.ts +1 -1
  21. package/src/__tests__/managed-materializers.test.ts +1 -1
  22. package/src/__tests__/managed-rejection.test.ts +1 -1
  23. package/src/__tests__/transport.test.ts +1 -1
  24. package/src/audit/store.ts +2 -2
  25. package/src/commands/executor.ts +2 -2
  26. package/src/grants/rpc-handlers.ts +1 -1
  27. package/src/http/audit.ts +1 -1
  28. package/src/http/executor.ts +2 -2
  29. package/src/http/policy.ts +1 -1
  30. package/src/main.ts +1 -1
  31. package/src/managed-errors.ts +2 -2
  32. package/src/managed-lazy-getters.ts +4 -4
  33. package/src/managed-main.ts +3 -3
  34. package/src/materializers/local.ts +1 -1
  35. package/src/server.ts +2 -2
  36. package/src/subjects/local.ts +2 -2
  37. package/src/subjects/managed.ts +1 -1
  38. package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +0 -471
  39. package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +0 -436
  40. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/grants.test.ts +0 -0
  41. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/error.ts +0 -0
  42. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/grants.ts +0 -0
  43. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/handles.ts +0 -0
  44. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rendering.ts +0 -0
  45. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rpc.ts +0 -0
  46. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/tsconfig.json +0 -0
package/Dockerfile CHANGED
@@ -14,7 +14,7 @@ RUN curl -fsSL https://bun.sh/install | bash -s "bun-v1.3.11"
14
14
  ENV PATH="/root/.bun/bin:${PATH}"
15
15
 
16
16
  # Copy shared packages first (needed for repo-local dependencies)
17
- COPY packages/ces-contracts ./packages/ces-contracts
17
+ COPY packages/service-contracts ./packages/service-contracts
18
18
  COPY packages/credential-storage ./packages/credential-storage
19
19
  COPY packages/egress-proxy ./packages/egress-proxy
20
20
 
@@ -22,9 +22,6 @@ COPY packages/egress-proxy ./packages/egress-proxy
22
22
  COPY credential-executor/package.json credential-executor/bun.lock* ./credential-executor/
23
23
  RUN cd /app/credential-executor && bun install --frozen-lockfile
24
24
 
25
- # Copy credential-executor source
26
- COPY credential-executor ./credential-executor
27
-
28
25
  # Runtime stage
29
26
  FROM debian:trixie-slim@sha256:1d3c811171a08a5adaa4a163fbafd96b61b87aa871bbc7aa15431ac275d3d430 AS runner
30
27
 
@@ -42,9 +39,12 @@ RUN ln -sf /usr/local/bin/bun /usr/local/bin/bunx
42
39
  RUN groupadd --system --gid 1001 ces && \
43
40
  useradd --system --uid 1001 --gid ces --create-home ces
44
41
 
45
- # Copy built app from builder
42
+ # Copy installed deps + shared packages from builder.
46
43
  COPY --from=builder --chown=ces:ces /app /app
47
44
 
45
+ # Copy source separately to avoid invalidating builder layer.
46
+ COPY --chown=ces:ces credential-executor ./
47
+
48
48
  # Pre-create /ces-data so the non-root ces user can write to it
49
49
  # when no PVC volume is mounted (e.g., direct docker run)
50
50
  RUN mkdir -p /ces-data && chown ces:ces /ces-data
package/bun.lock CHANGED
@@ -5,9 +5,9 @@
5
5
  "": {
6
6
  "name": "@vellumai/credential-executor",
7
7
  "dependencies": {
8
- "@vellumai/ces-contracts": "file:../packages/ces-contracts",
9
8
  "@vellumai/credential-storage": "file:../packages/credential-storage",
10
9
  "@vellumai/egress-proxy": "file:../packages/egress-proxy",
10
+ "@vellumai/service-contracts": "file:../packages/service-contracts",
11
11
  "pino": "9.14.0",
12
12
  "pino-pretty": "13.1.3",
13
13
  },
@@ -22,13 +22,15 @@
22
22
 
23
23
  "@types/bun": ["@types/bun@1.3.10", "", { "dependencies": { "bun-types": "1.3.10" } }, "sha512-0+rlrUrOrTSskibryHbvQkDOWRJwJZqZlxrUs1u4oOoTln8+WIXBPmAuCF35SWB2z4Zl3E84Nl/D0P7803nigQ=="],
24
24
 
25
- "@types/node": ["@types/node@25.5.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw=="],
25
+ "@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
26
26
 
27
- "@vellumai/ces-contracts": ["@vellumai/ces-contracts@file:../packages/ces-contracts", { "dependencies": { "zod": "^4.3.6" }, "devDependencies": { "@types/bun": "^1.2.4", "typescript": "^5.7.3" } }],
27
+ "@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="],
28
28
 
29
- "@vellumai/credential-storage": ["@vellumai/credential-storage@file:../packages/credential-storage", { "devDependencies": { "@types/bun": "^1.2.4", "typescript": "^5.7.3" } }],
29
+ "@vellumai/credential-storage": ["@vellumai/credential-storage@file:../packages/credential-storage", { "devDependencies": { "@types/bun": "1.3.10", "typescript": "5.9.3" } }],
30
30
 
31
- "@vellumai/egress-proxy": ["@vellumai/egress-proxy@file:../packages/egress-proxy", { "devDependencies": { "@types/bun": "^1.2.4", "typescript": "^5.7.3" } }],
31
+ "@vellumai/egress-proxy": ["@vellumai/egress-proxy@file:../packages/egress-proxy", { "devDependencies": { "@types/bun": "1.3.10", "typescript": "5.9.3" } }],
32
+
33
+ "@vellumai/service-contracts": ["@vellumai/service-contracts@file:../packages/service-contracts", { "dependencies": { "zod": "4.3.6" }, "devDependencies": { "@types/bun": "1.2.4", "typescript": "5.7.3" } }],
32
34
 
33
35
  "atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="],
34
36
 
@@ -40,7 +42,7 @@
40
42
 
41
43
  "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="],
42
44
 
43
- "fast-copy": ["fast-copy@4.0.2", "", {}, "sha512-ybA6PDXIXOXivLJK/z9e+Otk7ve13I4ckBvGO5I2RRmBU1gMHLVDJYEuJYhGwez7YNlYji2M2DvVU+a9mSFDlw=="],
45
+ "fast-copy": ["fast-copy@4.0.3", "", {}, "sha512-58apWr0GUiDFM8+3afrO6eYwJBn9ZAhDOzG3L+/9llab/haCARS2UIfffmOurYLwbgDRs8n0rfr6qAAPEAuAQw=="],
44
46
 
45
47
  "fast-safe-stringify": ["fast-safe-stringify@2.1.1", "", {}, "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="],
46
48
 
@@ -84,12 +86,18 @@
84
86
 
85
87
  "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
86
88
 
87
- "undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="],
89
+ "undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
88
90
 
89
91
  "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
90
92
 
91
93
  "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
92
94
 
95
+ "@vellumai/service-contracts/@types/bun": ["@types/bun@1.2.4", "", { "dependencies": { "bun-types": "1.2.4" } }, "sha512-QtuV5OMR8/rdKJs213iwXDpfVvnskPXY/S0ZiFbsTjQZycuqPbMW8Gf/XhLfwE5njW8sxI2WjISURXPlHypMFA=="],
96
+
97
+ "@vellumai/service-contracts/typescript": ["typescript@5.7.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw=="],
98
+
93
99
  "pino-pretty/pino-abstract-transport": ["pino-abstract-transport@3.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg=="],
100
+
101
+ "@vellumai/service-contracts/@types/bun/bun-types": ["bun-types@1.2.4", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-nDPymR207ZZEoWD4AavvEaa/KZe/qlrbMSchqpQwovPZCKc7pwMoENjEtHgMKaAjJhy+x6vfqSBA1QU3bJgs0Q=="],
94
102
  }
95
103
  }
@@ -3,8 +3,13 @@
3
3
  *
4
4
  * Ensures the package:
5
5
  * 1. Does NOT import from the assistant daemon or CES modules.
6
- * 2. Exposes only local storage/runtime abstractions.
7
- * 3. Remains portable and self-contained.
6
+ * 2. Does NOT import from x-client packages (@vellumai/assistant-client,
7
+ * @vellumai/ces-client, @vellumai/gateway-client).
8
+ * 3. Does NOT import from @vellumai/service-contracts runtime/internal modules
9
+ * (the aggregate root or any subpath beyond what credential-storage needs
10
+ * for pure type definitions is not required at all).
11
+ * 4. Exposes only local storage/runtime abstractions.
12
+ * 5. Remains portable and self-contained.
8
13
  */
9
14
 
10
15
  import { describe, expect, test } from "bun:test";
@@ -59,6 +64,21 @@ const FORBIDDEN_IMPORT_PATTERNS = [
59
64
  /from\s+["'].*\/tools\//,
60
65
  /from\s+["'].*\/oauth\/oauth-store/,
61
66
  /from\s+["'].*\/security\/secure-keys/,
67
+
68
+ // x-client packages (must not depend on any typed service client)
69
+ /from\s+["']@vellumai\/assistant-client(?:\/|["'])/,
70
+ /require\s*\(\s*["']@vellumai\/assistant-client(?:\/|["'])/,
71
+ /from\s+["']@vellumai\/ces-client(?:\/|["'])/,
72
+ /require\s*\(\s*["']@vellumai\/ces-client(?:\/|["'])/,
73
+ /from\s+["']@vellumai\/gateway-client(?:\/|["'])/,
74
+ /require\s*\(\s*["']@vellumai\/gateway-client(?:\/|["'])/,
75
+
76
+ // service-contracts aggregate root or internal subpaths
77
+ // credential-storage is a lower-layer package and must not depend on
78
+ // service-contracts (which sits at the same layer but deals with RPC
79
+ // protocol types, not storage abstractions).
80
+ /from\s+["']@vellumai\/service-contracts(?:\/|["'])/,
81
+ /require\s*\(\s*["']@vellumai\/service-contracts(?:\/|["'])/,
62
82
  ];
63
83
 
64
84
  describe("package boundary", () => {
@@ -68,7 +88,7 @@ describe("package boundary", () => {
68
88
  expect(sourceFiles.length).toBeGreaterThan(0);
69
89
  });
70
90
 
71
- test("does not import from assistant or CES modules", () => {
91
+ test("does not import from assistant, CES, x-client, or service-contracts modules", () => {
72
92
  const violations: string[] = [];
73
93
 
74
94
  for (const file of sourceFiles) {
@@ -101,7 +121,7 @@ describe("package boundary", () => {
101
121
  expect(pkg.private).toBe(true);
102
122
  });
103
123
 
104
- test("package.json does not depend on assistant or CES packages", () => {
124
+ test("package.json does not depend on assistant, CES, x-client, or service-contracts packages", () => {
105
125
  const pkg = JSON.parse(
106
126
  readFileSync(join(PACKAGE_ROOT, "package.json"), "utf-8"),
107
127
  );
@@ -113,8 +133,14 @@ describe("package boundary", () => {
113
133
  const forbidden = Object.keys(allDeps).filter(
114
134
  (dep) =>
115
135
  dep.includes("assistant") ||
116
- dep.includes("ces") ||
117
- dep.includes("daemon"),
136
+ dep.includes("daemon") ||
137
+ [
138
+ "@vellumai/ces-client",
139
+ "@vellumai/ces-contracts",
140
+ "@vellumai/service-contracts",
141
+ "@vellumai/assistant-client",
142
+ "@vellumai/gateway-client",
143
+ ].includes(dep),
118
144
  );
119
145
  expect(forbidden).toEqual([]);
120
146
  });
@@ -4,6 +4,13 @@
4
4
  * These tests ensure the egress-proxy package remains isolated from
5
5
  * assistant runtime and CES server implementation modules. If a direct
6
6
  * import of those modules is introduced, these tests will fail.
7
+ *
8
+ * Tightened boundaries (added):
9
+ * - Does NOT import from x-client packages (@vellumai/assistant-client,
10
+ * @vellumai/ces-client, @vellumai/gateway-client).
11
+ * - Does NOT import from @vellumai/service-contracts (the egress-proxy
12
+ * package deals only with proxy session lifecycle and must not depend on
13
+ * CES wire-protocol types).
7
14
  */
8
15
 
9
16
  import { describe, expect, test } from "bun:test";
@@ -66,6 +73,25 @@ const FORBIDDEN_PATTERNS = [
66
73
  /require\s*\(.*\/gateway\/src\//,
67
74
  /import\s+['"].*\/gateway\/src\//,
68
75
  /import\s+['"]@vellumai\/vellum-gateway/,
76
+
77
+ // x-client packages (must not depend on any typed service client)
78
+ /from\s+['"]@vellumai\/assistant-client(?:\/|['"])/,
79
+ /import\s+['"]@vellumai\/assistant-client(?:\/|['"])/,
80
+ /require\s*\(['"]@vellumai\/assistant-client(?:\/|['"])/,
81
+ /from\s+['"]@vellumai\/ces-client(?:\/|['"])/,
82
+ /import\s+['"]@vellumai\/ces-client(?:\/|['"])/,
83
+ /require\s*\(['"]@vellumai\/ces-client(?:\/|['"])/,
84
+ /from\s+['"]@vellumai\/gateway-client(?:\/|['"])/,
85
+ /import\s+['"]@vellumai\/gateway-client(?:\/|['"])/,
86
+ /require\s*\(['"]@vellumai\/gateway-client(?:\/|['"])/,
87
+
88
+ // service-contracts (RPC protocol types — egress-proxy must not depend on CES wire types)
89
+ /from\s+['"]@vellumai\/service-contracts(?:\/|['"])/,
90
+ /import\s+['"]@vellumai\/service-contracts(?:\/|['"])/,
91
+ /require\s*\(['"]@vellumai\/service-contracts(?:\/|['"])/,
92
+ /from\s+['"]@vellumai\/ces-contracts(?:\/|['"])/,
93
+ /import\s+['"]@vellumai\/ces-contracts(?:\/|['"])/,
94
+ /require\s*\(['"]@vellumai\/ces-contracts(?:\/|['"])/,
69
95
  ];
70
96
 
71
97
  describe("package boundary", () => {
@@ -94,7 +120,7 @@ describe("package boundary", () => {
94
120
  }
95
121
  });
96
122
 
97
- test("package.json has no dependencies on assistant, CES, or gateway", async () => {
123
+ test("package.json has no dependencies on assistant, CES, gateway, x-client, or service-contracts", async () => {
98
124
  const pkgJsonPath = resolve(PKG_SRC, "..", "package.json");
99
125
  const pkgJson = JSON.parse(await Bun.file(pkgJsonPath).text());
100
126
 
@@ -109,6 +135,11 @@ describe("package boundary", () => {
109
135
  "@vellumai/assistant",
110
136
  "@vellumai/ces",
111
137
  "@vellumai/vellum-gateway",
138
+ "@vellumai/assistant-client",
139
+ "@vellumai/ces-client",
140
+ "@vellumai/ces-contracts",
141
+ "@vellumai/gateway-client",
142
+ "@vellumai/service-contracts",
112
143
  ];
113
144
 
114
145
  for (const dep of forbidden) {
@@ -197,12 +197,19 @@ export type PolicyDecision =
197
197
  /**
198
198
  * Callback invoked by the proxy HTTP forwarder for each outbound request.
199
199
  * Returns injected headers on allow, or `null` to block the request.
200
+ *
201
+ * `method` and `requestHeaders` are populated for plain-HTTP proxied
202
+ * requests (absolute-URL form). For HTTPS CONNECT tunnels the proxy has
203
+ * not yet terminated TLS and cannot see HTTP-level details, so these are
204
+ * left undefined.
200
205
  */
201
206
  export type PolicyCallback = (
202
207
  hostname: string,
203
208
  port: number | null,
204
209
  path: string,
205
210
  scheme: "http" | "https",
211
+ method?: string,
212
+ requestHeaders?: Record<string, string | string[] | undefined>,
206
213
  ) => Promise<Record<string, string> | null>;
207
214
 
208
215
  /**
@@ -216,6 +223,18 @@ export interface ProxyApprovalRequest {
216
223
  | PolicyDecisionAskUnauthenticated;
217
224
  /** The proxy session ID that originated the request. */
218
225
  sessionId: ProxySessionId;
226
+ /**
227
+ * HTTP method of the incoming request, when available. Undefined for HTTPS
228
+ * CONNECT tunnels — at CONNECT time the proxy has not terminated TLS so
229
+ * no HTTP-level information is visible.
230
+ */
231
+ method?: string;
232
+ /**
233
+ * Curated subset of request headers, when available. Only non-sensitive
234
+ * headers are surfaced (content-type, content-length, user-agent, accept).
235
+ * Undefined for HTTPS CONNECT tunnels.
236
+ */
237
+ requestHeaders?: Record<string, string>;
219
238
  }
220
239
 
221
240
  /**
@@ -3,7 +3,7 @@
3
3
  "configVersion": 1,
4
4
  "workspaces": {
5
5
  "": {
6
- "name": "@vellumai/ces-contracts",
6
+ "name": "@vellumai/service-contracts",
7
7
  "dependencies": {
8
8
  "zod": "4.3.6",
9
9
  },
@@ -1,16 +1,18 @@
1
1
  {
2
- "name": "@vellumai/ces-contracts",
2
+ "name": "@vellumai/service-contracts",
3
3
  "version": "0.0.1",
4
4
  "private": true,
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "exports": {
8
8
  ".": "./src/index.ts",
9
+ "./credential-rpc": "./src/credential-rpc.ts",
10
+ "./trust-rules": "./src/trust-rules.ts",
9
11
  "./handles": "./src/handles.ts",
10
12
  "./grants": "./src/grants.ts",
11
13
  "./rpc": "./src/rpc.ts",
12
14
  "./rendering": "./src/rendering.ts",
13
- "./trust-rules": "./src/trust-rules.ts"
15
+ "./error": "./src/error.ts"
14
16
  },
15
17
  "scripts": {
16
18
  "typecheck": "bunx tsc --noEmit",
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Tests for @vellumai/ces-contracts
2
+ * Tests for @vellumai/service-contracts
3
3
  *
4
4
  * These tests verify:
5
5
  * 1. The package can be consumed independently (no assistant/ or CES imports).
@@ -30,6 +30,10 @@ describe("package independence", () => {
30
30
  "../grants.ts",
31
31
  "../rpc.ts",
32
32
  "../rendering.ts",
33
+ "../transport.ts",
34
+ "../credential-rpc.ts",
35
+ "../trust-rules.ts",
36
+ "../error.ts",
33
37
  ];
34
38
 
35
39
  for (const file of sourceFiles) {
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Package boundary tests for @vellumai/service-contracts.
3
+ *
4
+ * Ensures the package:
5
+ * 1. Does NOT import from assistant, gateway, credential-executor, or other
6
+ * service runtime modules.
7
+ * 2. Does NOT import from runtime shared packages that sit above it in the
8
+ * dependency hierarchy (@vellumai/credential-storage, @vellumai/egress-proxy,
9
+ * @vellumai/skill-host-contracts).
10
+ * 3. Does NOT import from x-client packages (@vellumai/assistant-client,
11
+ * @vellumai/ces-client, @vellumai/gateway-client).
12
+ * 4. Remains a pure schema/type package — no runtime dependencies beyond zod.
13
+ *
14
+ * @vellumai/service-contracts is the lowest layer of the shared packages
15
+ * hierarchy and must not depend on any higher-layer package.
16
+ */
17
+
18
+ import { describe, expect, test } from "bun:test";
19
+ import { readFileSync, readdirSync, statSync } from "node:fs";
20
+ import { join, resolve } from "node:path";
21
+
22
+ const PACKAGE_ROOT = resolve(import.meta.dirname, "../..");
23
+ const SRC_DIR = join(PACKAGE_ROOT, "src");
24
+
25
+ /**
26
+ * Recursively collect all .ts source files, excluding test and declaration files.
27
+ */
28
+ function collectSourceFiles(dir: string): string[] {
29
+ const files: string[] = [];
30
+ for (const entry of readdirSync(dir)) {
31
+ const full = join(dir, entry);
32
+ const stat = statSync(full);
33
+ if (stat.isDirectory()) {
34
+ if (entry === "node_modules" || entry === "__tests__") continue;
35
+ files.push(...collectSourceFiles(full));
36
+ } else if (
37
+ entry.endsWith(".ts") &&
38
+ !entry.endsWith(".test.ts") &&
39
+ !entry.endsWith(".d.ts")
40
+ ) {
41
+ files.push(full);
42
+ }
43
+ }
44
+ return files;
45
+ }
46
+
47
+ /**
48
+ * Patterns that must NOT appear in any import/require statement within
49
+ * source files. These catch imports from higher-layer packages that would
50
+ * create a forbidden upward dependency.
51
+ */
52
+ const FORBIDDEN_IMPORT_PATTERNS = [
53
+ // Assistant runtime
54
+ /from\s+["'](?:\.\.\/)*assistant(?:\/|["'])/,
55
+ /require\s*\(\s*["'](?:\.\.\/)*assistant(?:\/|["'])/,
56
+ /from\s+["']@vellumai\/assistant(?:\/|["'])/,
57
+ /require\s*\(\s*["']@vellumai\/assistant(?:\/|["'])/,
58
+
59
+ // Gateway
60
+ /from\s+["'](?:\.\.\/)*gateway(?:\/|["'])/,
61
+ /require\s*\(\s*["'](?:\.\.\/)*gateway(?:\/|["'])/,
62
+ /from\s+["']@vellumai\/(?:vellum-)?gateway(?:\/|["'])/,
63
+ /require\s*\(\s*["']@vellumai\/(?:vellum-)?gateway(?:\/|["'])/,
64
+
65
+ // Credential executor
66
+ /from\s+["'](?:\.\.\/)*credential-executor(?:\/|["'])/,
67
+ /require\s*\(\s*["'](?:\.\.\/)*credential-executor(?:\/|["'])/,
68
+ /from\s+["']@vellumai\/credential-executor(?:\/|["'])/,
69
+ /require\s*\(\s*["']@vellumai\/credential-executor(?:\/|["'])/,
70
+
71
+ // Runtime shared packages (higher layer)
72
+ /from\s+["']@vellumai\/credential-storage(?:\/|["'])/,
73
+ /require\s*\(\s*["']@vellumai\/credential-storage(?:\/|["'])/,
74
+ /from\s+["']@vellumai\/egress-proxy(?:\/|["'])/,
75
+ /require\s*\(\s*["']@vellumai\/egress-proxy(?:\/|["'])/,
76
+ /from\s+["']@vellumai\/skill-host-contracts(?:\/|["'])/,
77
+ /require\s*\(\s*["']@vellumai\/skill-host-contracts(?:\/|["'])/,
78
+
79
+ // x-client packages (higher layer)
80
+ /from\s+["']@vellumai\/assistant-client(?:\/|["'])/,
81
+ /require\s*\(\s*["']@vellumai\/assistant-client(?:\/|["'])/,
82
+ /from\s+["']@vellumai\/ces-client(?:\/|["'])/,
83
+ /require\s*\(\s*["']@vellumai\/ces-client(?:\/|["'])/,
84
+ /from\s+["']@vellumai\/gateway-client(?:\/|["'])/,
85
+ /require\s*\(\s*["']@vellumai\/gateway-client(?:\/|["'])/,
86
+ ];
87
+
88
+ describe("package boundary", () => {
89
+ const sourceFiles = collectSourceFiles(SRC_DIR);
90
+
91
+ test("has source files to validate", () => {
92
+ expect(sourceFiles.length).toBeGreaterThan(0);
93
+ });
94
+
95
+ test("does not import from runtime or higher-layer packages", () => {
96
+ const violations: string[] = [];
97
+
98
+ for (const file of sourceFiles) {
99
+ const content = readFileSync(file, "utf-8");
100
+ const lines = content.split("\n");
101
+
102
+ for (let i = 0; i < lines.length; i++) {
103
+ const line = lines[i];
104
+ for (const pattern of FORBIDDEN_IMPORT_PATTERNS) {
105
+ if (pattern.test(line)) {
106
+ const relative = file.replace(PACKAGE_ROOT + "/", "");
107
+ violations.push(`${relative}:${i + 1}: ${line.trim()}`);
108
+ }
109
+ }
110
+ }
111
+ }
112
+
113
+ if (violations.length > 0) {
114
+ throw new Error(
115
+ `Found ${violations.length} forbidden import(s) in service-contracts package:\n` +
116
+ violations.map((v) => ` - ${v}`).join("\n") +
117
+ "\n\n" +
118
+ "@vellumai/service-contracts is a pure schema/type package and must not\n" +
119
+ "import from runtime services or higher-layer packages.",
120
+ );
121
+ }
122
+ });
123
+
124
+ test("package.json declares it as private", () => {
125
+ const pkg = JSON.parse(
126
+ readFileSync(join(PACKAGE_ROOT, "package.json"), "utf-8"),
127
+ );
128
+ expect(pkg.private).toBe(true);
129
+ });
130
+
131
+ test("package.json does not depend on runtime or higher-layer packages", () => {
132
+ const pkg = JSON.parse(
133
+ readFileSync(join(PACKAGE_ROOT, "package.json"), "utf-8"),
134
+ );
135
+ const allDeps = {
136
+ ...pkg.dependencies,
137
+ ...pkg.devDependencies,
138
+ ...pkg.peerDependencies,
139
+ };
140
+
141
+ const forbidden = Object.keys(allDeps).filter((dep) =>
142
+ [
143
+ "@vellumai/assistant",
144
+ "@vellumai/credential-storage",
145
+ "@vellumai/egress-proxy",
146
+ "@vellumai/skill-host-contracts",
147
+ "@vellumai/assistant-client",
148
+ "@vellumai/ces-client",
149
+ "@vellumai/gateway-client",
150
+ ].includes(dep),
151
+ );
152
+
153
+ expect(forbidden).toEqual([]);
154
+ });
155
+ });
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @vellumai/service-contracts/credential-rpc
3
+ *
4
+ * Domain entrypoint for the CES (Credential Execution Service) transport and
5
+ * RPC surface. Re-exports the transport/RPC/handles/grants/rendering/error
6
+ * contracts without the trust-rule helpers.
7
+ *
8
+ * Prefer this subpath over the root `.` import when you only need the
9
+ * credential RPC surface:
10
+ *
11
+ * import { CesRpcMethod, MakeAuthenticatedRequestSchema } from "@vellumai/service-contracts/credential-rpc";
12
+ *
13
+ * For trust-rule types use the dedicated subpath:
14
+ *
15
+ * import { TrustRule, parseTrustRule } from "@vellumai/service-contracts/trust-rules";
16
+ */
17
+
18
+ export * from "./transport.js";
19
+ export * from "./error.js";
20
+ export * from "./handles.js";
21
+ export * from "./grants.js";
22
+ export * from "./rendering.js";
23
+ export * from "./rpc.js";
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @vellumai/service-contracts — aggregate export (compat entry point)
3
+ *
4
+ * This is a compatibility aggregate that re-exports everything from all
5
+ * submodules. Prefer the explicit domain subpaths for new code:
6
+ *
7
+ * - `@vellumai/service-contracts/credential-rpc` — transport, RPC, handles, grants, rendering, error
8
+ * - `@vellumai/service-contracts/trust-rules` — trust-rule types and parsing helpers
9
+ *
10
+ * Fine-grained subpaths are also available for low-friction migration:
11
+ * `./rpc`, `./handles`, `./grants`, `./rendering`, `./error`, `./trust-rules`
12
+ *
13
+ * Neutral wire-protocol contracts for communication between the assistant
14
+ * daemon and the Credential Execution Service (CES). This package is
15
+ * intentionally free of imports from `assistant/` or any CES implementation
16
+ * module so that both sides can depend on it without circular references.
17
+ */
18
+
19
+ export * from "./transport.js";
20
+ export * from "./error.js";
21
+ export * from "./handles.js";
22
+ export * from "./grants.js";
23
+ export * from "./rpc.js";
24
+ export * from "./rendering.js";
25
+ export * from "./trust-rules.js";
@@ -1,10 +1,9 @@
1
1
  /**
2
- * @vellumai/ces-contracts
2
+ * Transport-level handshake and envelope schemas.
3
3
  *
4
- * Neutral wire-protocol contracts for communication between the assistant
5
- * daemon and the Credential Execution Service (CES). This package is
6
- * intentionally free of imports from `assistant/` or any CES implementation
7
- * module so that both sides can depend on it without circular references.
4
+ * Extracted from the aggregate index to allow credential-rpc.ts to import
5
+ * the full transport surface without creating a circular dependency through
6
+ * index.ts.
8
7
  */
9
8
 
10
9
  import { z } from "zod";
@@ -35,9 +34,8 @@ export const HandshakeRequestSchema = z.object({
35
34
  assistantApiKey: z.string().optional(),
36
35
  /**
37
36
  * Optional platform assistant ID passed from the assistant runtime.
38
- * In managed (sidecar) mode with warm pools, the PLATFORM_ASSISTANT_ID
39
- * env var may not be set at CES startup. The assistant forwards it here
40
- * so CES can use it for platform credential materialisation.
37
+ * The assistant ID is not available at CES startup (warm-pool pods),
38
+ * so the assistant forwards it here for platform credential materialisation.
41
39
  */
42
40
  assistantId: z.string().optional(),
43
41
  });
@@ -75,16 +73,6 @@ export const RpcEnvelopeSchema = z.object({
75
73
  });
76
74
  export type RpcEnvelope = z.infer<typeof RpcEnvelopeSchema>;
77
75
 
78
- // ---------------------------------------------------------------------------
79
- // RPC error (defined in error.ts to avoid circular deps with rpc.ts)
80
- // ---------------------------------------------------------------------------
81
-
82
- export {
83
- RpcErrorSchema,
84
- type RpcError,
85
- MANAGED_LOCAL_STATIC_REJECTION_ERROR,
86
- } from "./error.js";
87
-
88
76
  // ---------------------------------------------------------------------------
89
77
  // Tool request / response base shapes
90
78
  // ---------------------------------------------------------------------------
@@ -143,13 +131,3 @@ export const TransportMessageSchema = z.discriminatedUnion("type", [
143
131
  RpcEnvelopeSchema.extend({ type: z.literal("rpc") }),
144
132
  ]);
145
133
  export type TransportMessage = z.infer<typeof TransportMessageSchema>;
146
-
147
- // ---------------------------------------------------------------------------
148
- // Re-exports from sub-modules
149
- // ---------------------------------------------------------------------------
150
-
151
- export * from "./handles.js";
152
- export * from "./grants.js";
153
- export * from "./rpc.js";
154
- export * from "./rendering.js";
155
- export * from "./trust-rules.js";