@heddleagent/execution-host-client 6.7.0 → 8.0.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 (116) hide show
  1. package/README.md +54 -35
  2. package/dist/agentcore/agentcore-execution-host.d.ts +1 -1
  3. package/dist/agentcore/agentcore-execution-host.d.ts.map +1 -1
  4. package/dist/agentcore/agentcore-execution-host.js +6 -3
  5. package/dist/agentcore/agentcore-execution-host.js.map +1 -1
  6. package/dist/cli/hostctl.d.ts +11 -0
  7. package/dist/cli/hostctl.d.ts.map +1 -0
  8. package/dist/cli/hostctl.js +49 -0
  9. package/dist/cli/hostctl.js.map +1 -0
  10. package/dist/contracts/index.d.ts +18 -1
  11. package/dist/contracts/index.d.ts.map +1 -1
  12. package/dist/contracts/index.js +28 -1
  13. package/dist/contracts/index.js.map +1 -1
  14. package/dist/conversation/hosted-conversation-turn-service.js +2 -2
  15. package/dist/conversation/hosted-conversation-turn-service.js.map +1 -1
  16. package/dist/conversation/types.d.ts +2 -2
  17. package/dist/conversation/types.d.ts.map +1 -1
  18. package/dist/conversation/types.js.map +1 -1
  19. package/dist/coordinator/contracts.d.ts +148 -5
  20. package/dist/coordinator/contracts.d.ts.map +1 -1
  21. package/dist/coordinator/contracts.js +74 -3
  22. package/dist/coordinator/contracts.js.map +1 -1
  23. package/dist/coordinator/hosted-heartbeat-execution-client.d.ts +30 -0
  24. package/dist/coordinator/hosted-heartbeat-execution-client.d.ts.map +1 -0
  25. package/dist/coordinator/hosted-heartbeat-execution-client.js +240 -0
  26. package/dist/coordinator/hosted-heartbeat-execution-client.js.map +1 -0
  27. package/dist/coordinator/hosted-heartbeat-execution-service.d.ts +14 -0
  28. package/dist/coordinator/hosted-heartbeat-execution-service.d.ts.map +1 -0
  29. package/dist/coordinator/hosted-heartbeat-execution-service.js +100 -0
  30. package/dist/coordinator/hosted-heartbeat-execution-service.js.map +1 -0
  31. package/dist/coordinator/index.d.ts +5 -5
  32. package/dist/coordinator/index.d.ts.map +1 -1
  33. package/dist/coordinator/index.js +3 -3
  34. package/dist/coordinator/index.js.map +1 -1
  35. package/dist/coordinator/node/execution-http-service.d.ts +11 -0
  36. package/dist/coordinator/node/execution-http-service.d.ts.map +1 -0
  37. package/dist/coordinator/node/{delegation-http-service.js → execution-http-service.js} +52 -39
  38. package/dist/coordinator/node/execution-http-service.js.map +1 -0
  39. package/dist/coordinator/node/index.d.ts +2 -2
  40. package/dist/coordinator/node/index.d.ts.map +1 -1
  41. package/dist/coordinator/node/index.js +1 -1
  42. package/dist/coordinator/node/index.js.map +1 -1
  43. package/dist/coordinator/node/types.d.ts +10 -9
  44. package/dist/coordinator/node/types.d.ts.map +1 -1
  45. package/dist/coordinator/node/types.js.map +1 -1
  46. package/dist/coordinator/types.d.ts +51 -13
  47. package/dist/coordinator/types.d.ts.map +1 -1
  48. package/dist/coordinator/types.js.map +1 -1
  49. package/dist/heartbeat/hosted-heartbeat-task-service.js +2 -2
  50. package/dist/heartbeat/hosted-heartbeat-task-service.js.map +1 -1
  51. package/dist/host/jwt-execution-host-mcp-capability-verifier.d.ts.map +1 -1
  52. package/dist/host/jwt-execution-host-mcp-capability-verifier.js +4 -2
  53. package/dist/host/jwt-execution-host-mcp-capability-verifier.js.map +1 -1
  54. package/dist/host/jwt-execution-identity-verifier.d.ts.map +1 -1
  55. package/dist/host/jwt-execution-identity-verifier.js +4 -2
  56. package/dist/host/jwt-execution-identity-verifier.js.map +1 -1
  57. package/dist/host/runtime-session/service.d.ts +2 -2
  58. package/dist/host/runtime-session/service.d.ts.map +1 -1
  59. package/dist/host/runtime-session/service.js +1 -1
  60. package/dist/host/runtime-session/service.js.map +1 -1
  61. package/dist/host/runtime-session/types.d.ts +2 -2
  62. package/dist/host/runtime-session/types.d.ts.map +1 -1
  63. package/dist/host/runtime-session/types.js.map +1 -1
  64. package/dist/host/schemas.d.ts +6 -0
  65. package/dist/host/schemas.d.ts.map +1 -1
  66. package/dist/host/schemas.js +18 -1
  67. package/dist/host/schemas.js.map +1 -1
  68. package/dist/host/types.d.ts +2 -0
  69. package/dist/host/types.d.ts.map +1 -1
  70. package/dist/host/types.js.map +1 -1
  71. package/dist/http-sse/direct-http-execution-host.d.ts.map +1 -1
  72. package/dist/http-sse/direct-http-execution-host.js +8 -7
  73. package/dist/http-sse/direct-http-execution-host.js.map +1 -1
  74. package/dist/http-sse/types.d.ts +5 -3
  75. package/dist/http-sse/types.d.ts.map +1 -1
  76. package/dist/http-sse/types.js.map +1 -1
  77. package/dist/node/authority-key.d.ts.map +1 -1
  78. package/dist/node/authority-key.js +24 -49
  79. package/dist/node/authority-key.js.map +1 -1
  80. package/dist/node/direct-credentials.d.ts +3 -7
  81. package/dist/node/direct-credentials.d.ts.map +1 -1
  82. package/dist/node/direct-credentials.js +3 -15
  83. package/dist/node/direct-credentials.js.map +1 -1
  84. package/dist/node/environment-value.d.ts +17 -0
  85. package/dist/node/environment-value.d.ts.map +1 -0
  86. package/dist/node/environment-value.js +78 -0
  87. package/dist/node/environment-value.js.map +1 -0
  88. package/dist/node/index.d.ts +4 -0
  89. package/dist/node/index.d.ts.map +1 -1
  90. package/dist/node/index.js +2 -0
  91. package/dist/node/index.js.map +1 -1
  92. package/dist/node/local-credential-bundle.d.ts +33 -0
  93. package/dist/node/local-credential-bundle.d.ts.map +1 -0
  94. package/dist/node/local-credential-bundle.js +196 -0
  95. package/dist/node/local-credential-bundle.js.map +1 -0
  96. package/dist/node/owner-only-file.d.ts +17 -0
  97. package/dist/node/owner-only-file.d.ts.map +1 -0
  98. package/dist/node/owner-only-file.js +59 -0
  99. package/dist/node/owner-only-file.js.map +1 -0
  100. package/dist/testing/request.d.ts.map +1 -1
  101. package/dist/testing/request.js +14 -4
  102. package/dist/testing/request.js.map +1 -1
  103. package/package.json +5 -1
  104. package/spec/v1/openapi.json +62 -4
  105. package/spec/v1/schema-bundle.json +58 -0
  106. package/dist/coordinator/hosted-heartbeat-delegation-client.d.ts +0 -21
  107. package/dist/coordinator/hosted-heartbeat-delegation-client.d.ts.map +0 -1
  108. package/dist/coordinator/hosted-heartbeat-delegation-client.js +0 -117
  109. package/dist/coordinator/hosted-heartbeat-delegation-client.js.map +0 -1
  110. package/dist/coordinator/hosted-heartbeat-delegation-service.d.ts +0 -15
  111. package/dist/coordinator/hosted-heartbeat-delegation-service.d.ts.map +0 -1
  112. package/dist/coordinator/hosted-heartbeat-delegation-service.js +0 -81
  113. package/dist/coordinator/hosted-heartbeat-delegation-service.js.map +0 -1
  114. package/dist/coordinator/node/delegation-http-service.d.ts +0 -11
  115. package/dist/coordinator/node/delegation-http-service.d.ts.map +0 -1
  116. package/dist/coordinator/node/delegation-http-service.js.map +0 -1
@@ -1,35 +1,60 @@
1
1
  import { createHash, timingSafeEqual } from 'node:crypto';
2
2
  import { z, ZodError } from 'zod';
3
- import { HOSTED_HEARTBEAT_DELEGATIONS_PATH, HostedHeartbeatDelegationRequestSchema, } from '../contracts.js';
4
- import { HostedHeartbeatDelegationRejectedError, } from '../hosted-heartbeat-delegation-service.js';
3
+ import { HOSTED_HEARTBEAT_EXECUTION_PATHS, HostedHeartbeatExecutionPreparationRequestSchema, HostedHeartbeatExecutionSettlementRequestSchema, } from '../contracts.js';
5
4
  import { HostedHeartbeatServiceTokenSchema } from '../service-token.js';
6
5
  import { NodeHttpPathSchema, NodeHttpRequestError, errorType, readJsonBody, readPathname, takeAuthorization, writeJson, writeJsonError, } from '../../node/http-utils.js';
7
6
  const DEFAULT_MAX_BODY_BYTES = 16 * 1_024;
8
- /** Standard authenticated Node HTTP edge for product-owned run authority. */
9
- export class NodeHostedHeartbeatDelegationHttpService {
10
- #delegations;
7
+ /** Standard authenticated Node HTTP edge for product-owned work lifecycle. */
8
+ export class NodeHostedHeartbeatExecutionHttpService {
9
+ #executions;
11
10
  #tokenDigest;
12
- #path;
11
+ #paths;
13
12
  #maxBodyBytes;
14
13
  #reportFailure;
15
14
  #active = new Set();
16
15
  #closed = false;
17
16
  #closePromise;
18
17
  constructor(config) {
19
- this.#delegations = config.delegations;
18
+ this.#executions = config.executions;
20
19
  this.#tokenDigest = digest(HostedHeartbeatServiceTokenSchema.parse(config.apiToken));
21
- this.#path = NodeHttpPathSchema.parse(config.path ?? HOSTED_HEARTBEAT_DELEGATIONS_PATH);
20
+ this.#paths = {
21
+ prepare: NodeHttpPathSchema.parse(config.preparePath ?? HOSTED_HEARTBEAT_EXECUTION_PATHS.prepare),
22
+ settle: NodeHttpPathSchema.parse(config.settlePath ?? HOSTED_HEARTBEAT_EXECUTION_PATHS.settle),
23
+ };
22
24
  this.#maxBodyBytes = z.number().int().min(1).max(1_048_576).parse(config.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES);
23
25
  this.#reportFailure = config.reportFailure;
24
26
  }
25
27
  handle(request, response) {
26
- if (readPathname(request.url) !== this.#path) {
28
+ const operation = this.#operation(readPathname(request.url));
29
+ if (!operation) {
27
30
  return false;
28
31
  }
29
- this.handleDelegation(request, response);
32
+ this.#start(operation, request, response);
30
33
  return true;
31
34
  }
32
- handleDelegation(request, response) {
35
+ handleExecution(request, response) {
36
+ const operation = this.#operation(readPathname(request.url));
37
+ if (!operation) {
38
+ request.resume();
39
+ writeJsonError(response, 404, 'Heartbeat execution route not found.');
40
+ return;
41
+ }
42
+ this.#start(operation, request, response);
43
+ }
44
+ close() {
45
+ if (!this.#closePromise) {
46
+ this.#closed = true;
47
+ const active = [...this.#active];
48
+ active.forEach(({ abortController, request, response }) => {
49
+ abortController.abort(new Error('The heartbeat execution service is stopping.'));
50
+ request.destroy();
51
+ response.destroy();
52
+ });
53
+ this.#closePromise = Promise.allSettled(active.map(({ pending }) => pending)).then(() => undefined);
54
+ }
55
+ return this.#closePromise;
56
+ }
57
+ #start(operation, request, response) {
33
58
  if (this.#closed) {
34
59
  request.resume();
35
60
  writeJsonError(response, 503, 'Hosted execution is unavailable.');
@@ -48,7 +73,7 @@ export class NodeHostedHeartbeatDelegationHttpService {
48
73
  }
49
74
  catch (error) {
50
75
  request.resume();
51
- writeJsonError(response, error instanceof NodeHttpRequestError ? error.statusCode : 400, 'Invalid heartbeat delegation request.');
76
+ writeJsonError(response, error instanceof NodeHttpRequestError ? error.statusCode : 400, 'Invalid heartbeat execution request.');
52
77
  return;
53
78
  }
54
79
  if (!this.#authenticates(authorization)) {
@@ -59,7 +84,7 @@ export class NodeHostedHeartbeatDelegationHttpService {
59
84
  return;
60
85
  }
61
86
  const abortController = new AbortController();
62
- const abort = () => abortController.abort(new Error('The heartbeat delegation request closed.'));
87
+ const abort = () => abortController.abort(new Error('The heartbeat execution request closed.'));
63
88
  request.once('aborted', abort);
64
89
  response.once('close', abort);
65
90
  const active = {
@@ -68,48 +93,36 @@ export class NodeHostedHeartbeatDelegationHttpService {
68
93
  response,
69
94
  pending: Promise.resolve(),
70
95
  };
71
- active.pending = this.#serve(request, response, abortController.signal).finally(() => {
96
+ active.pending = this.#serve(operation, request, response, abortController.signal).finally(() => {
72
97
  request.removeListener('aborted', abort);
73
98
  response.removeListener('close', abort);
74
99
  this.#active.delete(active);
75
100
  });
76
101
  this.#active.add(active);
77
102
  }
78
- close() {
79
- if (!this.#closePromise) {
80
- this.#closed = true;
81
- const active = [...this.#active];
82
- active.forEach(({ abortController, request, response }) => {
83
- abortController.abort(new Error('The heartbeat delegation service is stopping.'));
84
- request.destroy();
85
- response.destroy();
86
- });
87
- this.#closePromise = Promise.allSettled(active.map(({ pending }) => pending)).then(() => undefined);
88
- }
89
- return this.#closePromise;
90
- }
91
- async #serve(request, response, signal) {
103
+ async #serve(operation, request, response, signal) {
92
104
  try {
93
- const input = HostedHeartbeatDelegationRequestSchema.parse(await readJsonBody(request, this.#maxBodyBytes, signal));
94
- const delegation = await this.#delegations.issue(input, signal);
95
- writeJson(response, 200, delegation);
105
+ const body = await readJsonBody(request, this.#maxBodyBytes, signal);
106
+ const result = operation === 'prepare'
107
+ ? await this.#executions.prepare(HostedHeartbeatExecutionPreparationRequestSchema.parse(body), signal)
108
+ : await this.#executions.settle(HostedHeartbeatExecutionSettlementRequestSchema.parse(body), signal);
109
+ writeJson(response, 200, result);
96
110
  }
97
111
  catch (error) {
98
112
  if (signal.aborted) {
99
113
  return;
100
114
  }
101
- if (error instanceof HostedHeartbeatDelegationRejectedError) {
102
- writeJsonError(response, 403, error.message);
103
- return;
104
- }
105
115
  if (error instanceof NodeHttpRequestError || error instanceof ZodError) {
106
- writeJsonError(response, error instanceof NodeHttpRequestError ? error.statusCode : 400, 'Invalid heartbeat delegation request.');
116
+ writeJsonError(response, error instanceof NodeHttpRequestError ? error.statusCode : 400, 'Invalid heartbeat execution request.');
107
117
  return;
108
118
  }
109
- this.#report({ phase: 'delegation', errorType: errorType(error) });
110
- writeJsonError(response, 500, 'Heartbeat delegation failed.');
119
+ this.#report({ phase: operation, errorType: errorType(error) });
120
+ writeJsonError(response, 500, `Heartbeat execution ${operation} failed.`);
111
121
  }
112
122
  }
123
+ #operation(pathname) {
124
+ return Object.entries(this.#paths).find(([, path]) => path === pathname)?.[0];
125
+ }
113
126
  #authenticates(authorization) {
114
127
  const token = /^Bearer ([^\s]+)$/i.exec(authorization?.trim() ?? '')?.[1];
115
128
  return token
@@ -128,4 +141,4 @@ export class NodeHostedHeartbeatDelegationHttpService {
128
141
  function digest(value) {
129
142
  return createHash('sha256').update(value, 'utf8').digest();
130
143
  }
131
- //# sourceMappingURL=delegation-http-service.js.map
144
+ //# sourceMappingURL=execution-http-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execution-http-service.js","sourceRoot":"","sources":["../../../src/coordinator/node/execution-http-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, timingSafeEqual } from 'node:crypto';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport { z, ZodError } from 'zod';\nimport {\n HOSTED_HEARTBEAT_EXECUTION_PATHS,\n HostedHeartbeatExecutionPreparationRequestSchema,\n HostedHeartbeatExecutionSettlementRequestSchema,\n} from '../contracts.js';\nimport { HostedHeartbeatServiceTokenSchema } from '../service-token.js';\nimport {\n NodeHttpPathSchema,\n NodeHttpRequestError,\n errorType,\n readJsonBody,\n readPathname,\n takeAuthorization,\n writeJson,\n writeJsonError,\n} from '../../node/http-utils.js';\nimport type {\n NodeHostedHeartbeatExecutionFailure,\n NodeHostedHeartbeatExecutionHttpHandler,\n NodeHostedHeartbeatExecutionHttpServiceConfig,\n} from './types.js';\n\nconst DEFAULT_MAX_BODY_BYTES = 16 * 1_024;\n\ntype ExecutionOperation = 'prepare' | 'settle';\ntype ActiveRequest = {\n abortController: AbortController;\n request: IncomingMessage;\n response: ServerResponse;\n pending: Promise<void>;\n};\n\n/** Standard authenticated Node HTTP edge for product-owned work lifecycle. */\nexport class NodeHostedHeartbeatExecutionHttpService\nimplements NodeHostedHeartbeatExecutionHttpHandler {\n readonly #executions: NodeHostedHeartbeatExecutionHttpServiceConfig[\n 'executions'\n ];\n readonly #tokenDigest: Buffer;\n readonly #paths: Record<ExecutionOperation, string>;\n readonly #maxBodyBytes: number;\n readonly #reportFailure: NodeHostedHeartbeatExecutionHttpServiceConfig[\n 'reportFailure'\n ];\n readonly #active = new Set<ActiveRequest>();\n #closed = false;\n #closePromise: Promise<void> | undefined;\n\n constructor(config: NodeHostedHeartbeatExecutionHttpServiceConfig) {\n this.#executions = config.executions;\n this.#tokenDigest = digest(\n HostedHeartbeatServiceTokenSchema.parse(config.apiToken),\n );\n this.#paths = {\n prepare: NodeHttpPathSchema.parse(\n config.preparePath ?? HOSTED_HEARTBEAT_EXECUTION_PATHS.prepare,\n ),\n settle: NodeHttpPathSchema.parse(\n config.settlePath ?? HOSTED_HEARTBEAT_EXECUTION_PATHS.settle,\n ),\n };\n this.#maxBodyBytes = z.number().int().min(1).max(1_048_576).parse(\n config.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES,\n );\n this.#reportFailure = config.reportFailure;\n }\n\n handle(request: IncomingMessage, response: ServerResponse): boolean {\n const operation = this.#operation(readPathname(request.url));\n if (!operation) {\n return false;\n }\n this.#start(operation, request, response);\n return true;\n }\n\n handleExecution(\n request: IncomingMessage,\n response: ServerResponse,\n ): void {\n const operation = this.#operation(readPathname(request.url));\n if (!operation) {\n request.resume();\n writeJsonError(response, 404, 'Heartbeat execution route not found.');\n return;\n }\n this.#start(operation, request, response);\n }\n\n close(): Promise<void> {\n if (!this.#closePromise) {\n this.#closed = true;\n const active = [...this.#active];\n active.forEach(({ abortController, request, response }) => {\n abortController.abort(\n new Error('The heartbeat execution service is stopping.'),\n );\n request.destroy();\n response.destroy();\n });\n this.#closePromise = Promise.allSettled(\n active.map(({ pending }) => pending),\n ).then(() => undefined);\n }\n return this.#closePromise;\n }\n\n #start(\n operation: ExecutionOperation,\n request: IncomingMessage,\n response: ServerResponse,\n ): void {\n if (this.#closed) {\n request.resume();\n writeJsonError(response, 503, 'Hosted execution is unavailable.');\n return;\n }\n\n let authorization: string | undefined;\n try {\n authorization = takeAuthorization(request);\n if (request.method !== 'POST') {\n request.resume();\n writeJsonError(response, 405, 'Method not allowed.', {\n Allow: 'POST',\n });\n return;\n }\n } catch (error) {\n request.resume();\n writeJsonError(\n response,\n error instanceof NodeHttpRequestError ? error.statusCode : 400,\n 'Invalid heartbeat execution request.',\n );\n return;\n }\n if (!this.#authenticates(authorization)) {\n request.resume();\n writeJsonError(response, 401, 'Authentication is required.', {\n 'WWW-Authenticate': 'Bearer',\n });\n return;\n }\n\n const abortController = new AbortController();\n const abort = () => abortController.abort(\n new Error('The heartbeat execution request closed.'),\n );\n request.once('aborted', abort);\n response.once('close', abort);\n const active: ActiveRequest = {\n abortController,\n request,\n response,\n pending: Promise.resolve(),\n };\n active.pending = this.#serve(\n operation,\n request,\n response,\n abortController.signal,\n ).finally(() => {\n request.removeListener('aborted', abort);\n response.removeListener('close', abort);\n this.#active.delete(active);\n });\n this.#active.add(active);\n }\n\n async #serve(\n operation: ExecutionOperation,\n request: IncomingMessage,\n response: ServerResponse,\n signal: AbortSignal,\n ): Promise<void> {\n try {\n const body = await readJsonBody(request, this.#maxBodyBytes, signal);\n const result = operation === 'prepare'\n ? await this.#executions.prepare(\n HostedHeartbeatExecutionPreparationRequestSchema.parse(body),\n signal,\n )\n : await this.#executions.settle(\n HostedHeartbeatExecutionSettlementRequestSchema.parse(body),\n signal,\n );\n writeJson(response, 200, result);\n } catch (error) {\n if (signal.aborted) {\n return;\n }\n if (error instanceof NodeHttpRequestError || error instanceof ZodError) {\n writeJsonError(\n response,\n error instanceof NodeHttpRequestError ? error.statusCode : 400,\n 'Invalid heartbeat execution request.',\n );\n return;\n }\n this.#report({ phase: operation, errorType: errorType(error) });\n writeJsonError(response, 500, `Heartbeat execution ${operation} failed.`);\n }\n }\n\n #operation(pathname: string | undefined): ExecutionOperation | undefined {\n return (Object.entries(this.#paths) as Array<[\n ExecutionOperation,\n string,\n ]>).find(([, path]) => path === pathname)?.[0];\n }\n\n #authenticates(authorization: string | undefined): boolean {\n const token = /^Bearer ([^\\s]+)$/i.exec(\n authorization?.trim() ?? '',\n )?.[1];\n return token\n ? timingSafeEqual(digest(token), this.#tokenDigest)\n : false;\n }\n\n #report(failure: NodeHostedHeartbeatExecutionFailure): void {\n try {\n this.#reportFailure?.(Object.freeze({ ...failure }));\n } catch {\n // Observability must not change request settlement.\n }\n }\n}\n\nfunction digest(value: string): Buffer {\n return createHash('sha256').update(value, 'utf8').digest();\n}\n"]}
@@ -1,4 +1,4 @@
1
- export { NodeHostedHeartbeatDelegationHttpService } from './delegation-http-service.js';
1
+ export { NodeHostedHeartbeatExecutionHttpService } from './execution-http-service.js';
2
2
  export { takeHostedHeartbeatServiceToken } from './environment.js';
3
- export type { NodeHostedHeartbeatDelegationFailure, NodeHostedHeartbeatDelegationHttpHandler, NodeHostedHeartbeatDelegationHttpServiceConfig, } from './types.js';
3
+ export type { NodeHostedHeartbeatExecutionFailure, NodeHostedHeartbeatExecutionHttpHandler, NodeHostedHeartbeatExecutionHttpServiceConfig, } from './types.js';
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/coordinator/node/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wCAAwC,EAAE,MAAM,8BAA8B,CAAC;AACxF,OAAO,EAAE,+BAA+B,EAAE,MAAM,kBAAkB,CAAC;AACnE,YAAY,EACV,oCAAoC,EACpC,wCAAwC,EACxC,8CAA8C,GAC/C,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/coordinator/node/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uCAAuC,EAAE,MAAM,6BAA6B,CAAC;AACtF,OAAO,EAAE,+BAA+B,EAAE,MAAM,kBAAkB,CAAC;AACnE,YAAY,EACV,mCAAmC,EACnC,uCAAuC,EACvC,6CAA6C,GAC9C,MAAM,YAAY,CAAC"}
@@ -1,3 +1,3 @@
1
- export { NodeHostedHeartbeatDelegationHttpService } from './delegation-http-service.js';
1
+ export { NodeHostedHeartbeatExecutionHttpService } from './execution-http-service.js';
2
2
  export { takeHostedHeartbeatServiceToken } from './environment.js';
3
3
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/coordinator/node/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wCAAwC,EAAE,MAAM,8BAA8B,CAAC;AACxF,OAAO,EAAE,+BAA+B,EAAE,MAAM,kBAAkB,CAAC","sourcesContent":["export { NodeHostedHeartbeatDelegationHttpService } from './delegation-http-service.js';\nexport { takeHostedHeartbeatServiceToken } from './environment.js';\nexport type {\n NodeHostedHeartbeatDelegationFailure,\n NodeHostedHeartbeatDelegationHttpHandler,\n NodeHostedHeartbeatDelegationHttpServiceConfig,\n} from './types.js';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/coordinator/node/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uCAAuC,EAAE,MAAM,6BAA6B,CAAC;AACtF,OAAO,EAAE,+BAA+B,EAAE,MAAM,kBAAkB,CAAC","sourcesContent":["export { NodeHostedHeartbeatExecutionHttpService } from './execution-http-service.js';\nexport { takeHostedHeartbeatServiceToken } from './environment.js';\nexport type {\n NodeHostedHeartbeatExecutionFailure,\n NodeHostedHeartbeatExecutionHttpHandler,\n NodeHostedHeartbeatExecutionHttpServiceConfig,\n} from './types.js';\n"]}
@@ -1,20 +1,21 @@
1
1
  import type { IncomingMessage, ServerResponse } from 'node:http';
2
- import type { HostedHeartbeatDelegationIssuer } from '../types.js';
3
- export type NodeHostedHeartbeatDelegationFailure = {
4
- phase: 'delegation';
2
+ import type { HostedHeartbeatExecutionApi } from '../types.js';
3
+ export type NodeHostedHeartbeatExecutionFailure = {
4
+ phase: 'prepare' | 'settle';
5
5
  errorType: string;
6
6
  };
7
- export type NodeHostedHeartbeatDelegationHttpServiceConfig = {
8
- delegations: HostedHeartbeatDelegationIssuer;
7
+ export type NodeHostedHeartbeatExecutionHttpServiceConfig = {
8
+ executions: HostedHeartbeatExecutionApi;
9
9
  apiToken: string;
10
- path?: string;
10
+ preparePath?: string;
11
+ settlePath?: string;
11
12
  maxBodyBytes?: number;
12
13
  /** Receives credential-free operational metadata, never the raw error. */
13
- reportFailure?: (failure: NodeHostedHeartbeatDelegationFailure) => void;
14
+ reportFailure?: (failure: NodeHostedHeartbeatExecutionFailure) => void;
14
15
  };
15
- export interface NodeHostedHeartbeatDelegationHttpHandler {
16
+ export interface NodeHostedHeartbeatExecutionHttpHandler {
16
17
  handle(request: IncomingMessage, response: ServerResponse): boolean;
17
- handleDelegation(request: IncomingMessage, response: ServerResponse): void;
18
+ handleExecution(request: IncomingMessage, response: ServerResponse): void;
18
19
  close(): Promise<void>;
19
20
  }
20
21
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/coordinator/node/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,aAAa,CAAC;AAEnE,MAAM,MAAM,oCAAoC,GAAG;IACjD,KAAK,EAAE,YAAY,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,8CAA8C,GAAG;IAC3D,WAAW,EAAE,+BAA+B,CAAC;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,oCAAoC,KAAK,IAAI,CAAC;CACzE,CAAC;AAEF,MAAM,WAAW,wCAAwC;IACvD,MAAM,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC;IACpE,gBAAgB,CACd,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,cAAc,GACvB,IAAI,CAAC;IACR,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/coordinator/node/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AAE/D,MAAM,MAAM,mCAAmC,GAAG;IAChD,KAAK,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,6CAA6C,GAAG;IAC1D,UAAU,EAAE,2BAA2B,CAAC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,mCAAmC,KAAK,IAAI,CAAC;CACxE,CAAC;AAEF,MAAM,WAAW,uCAAuC;IACtD,MAAM,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC;IACpE,eAAe,CACb,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,cAAc,GACvB,IAAI,CAAC;IACR,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/coordinator/node/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { HostedHeartbeatDelegationIssuer } from '../types.js';\n\nexport type NodeHostedHeartbeatDelegationFailure = {\n phase: 'delegation';\n errorType: string;\n};\n\nexport type NodeHostedHeartbeatDelegationHttpServiceConfig = {\n delegations: HostedHeartbeatDelegationIssuer;\n apiToken: string;\n path?: string;\n maxBodyBytes?: number;\n /** Receives credential-free operational metadata, never the raw error. */\n reportFailure?: (failure: NodeHostedHeartbeatDelegationFailure) => void;\n};\n\nexport interface NodeHostedHeartbeatDelegationHttpHandler {\n handle(request: IncomingMessage, response: ServerResponse): boolean;\n handleDelegation(\n request: IncomingMessage,\n response: ServerResponse,\n ): void;\n close(): Promise<void>;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/coordinator/node/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { HostedHeartbeatExecutionApi } from '../types.js';\n\nexport type NodeHostedHeartbeatExecutionFailure = {\n phase: 'prepare' | 'settle';\n errorType: string;\n};\n\nexport type NodeHostedHeartbeatExecutionHttpServiceConfig = {\n executions: HostedHeartbeatExecutionApi;\n apiToken: string;\n preparePath?: string;\n settlePath?: string;\n maxBodyBytes?: number;\n /** Receives credential-free operational metadata, never the raw error. */\n reportFailure?: (failure: NodeHostedHeartbeatExecutionFailure) => void;\n};\n\nexport interface NodeHostedHeartbeatExecutionHttpHandler {\n handle(request: IncomingMessage, response: ServerResponse): boolean;\n handleExecution(\n request: IncomingMessage,\n response: ServerResponse,\n ): void;\n close(): Promise<void>;\n}\n"]}
@@ -2,7 +2,7 @@ import type { ExecutionAuthorityIssuer } from '../authority/index.js';
2
2
  import type { HostedModelCredentialProvider } from '../conversation/index.js';
3
3
  import type { HostedHeartbeatAgentExecutionTransportInput } from '../heartbeat/index.js';
4
4
  import type { HeartbeatExecutionHost } from '../http-sse/index.js';
5
- import type { HostedHeartbeatCoordinatorTaskInput, HostedHeartbeatCoordinatorState, HostedHeartbeatCoordinatorTaskDetail, HostedHeartbeatCoordinatorTaskView, HostedHeartbeatDelegation, HostedHeartbeatDelegationAuthorization, HostedHeartbeatDelegationRequest, HostedHeartbeatDesiredTask } from './contracts.js';
5
+ import type { HostedHeartbeatCoordinatorTaskInput, HostedHeartbeatCoordinatorState, HostedHeartbeatCoordinatorTaskDetail, HostedHeartbeatCoordinatorTaskView, HostedHeartbeatExecutionPreparation, HostedHeartbeatExecutionPreparationDecision, HostedHeartbeatExecutionPreparationRequest, HostedHeartbeatExecutionSettlement, HostedHeartbeatExecutionSettlementRequest, HostedHeartbeatDesiredTask } from './contracts.js';
6
6
  export type HostedHeartbeatCoordinatorClientConfig = {
7
7
  baseUrl: URL;
8
8
  apiToken: string;
@@ -32,36 +32,74 @@ export type HostedHeartbeatTaskReconciliation = {
32
32
  export type HostedHeartbeatTaskReconcilerConfig = {
33
33
  coordinator: Pick<HostedHeartbeatCoordinatorTaskApi, 'listTasks' | 'upsertTask' | 'deleteTask' | 'pause' | 'resume'>;
34
34
  };
35
- export type HostedHeartbeatDelegationAuthorizationInput = {
35
+ export type HostedHeartbeatExecutionPreparationInput = {
36
36
  taskId: string;
37
37
  executionId: string;
38
+ interruptedExecutionId?: string;
38
39
  signal: AbortSignal;
39
40
  };
40
- export interface HostedHeartbeatDelegationAuthorizer {
41
- authorize(input: HostedHeartbeatDelegationAuthorizationInput): HostedHeartbeatDelegationAuthorization | undefined | Promise<HostedHeartbeatDelegationAuthorization | undefined>;
41
+ export type HostedHeartbeatExecutionSettlementInput = HostedHeartbeatExecutionSettlementRequest & {
42
+ signal: AbortSignal;
43
+ };
44
+ /** Product-owned lifecycle around one Coordinator-owned execution attempt. */
45
+ export interface HostedHeartbeatProductExecutionLifecycle {
46
+ prepare(input: HostedHeartbeatExecutionPreparationInput): HostedHeartbeatExecutionPreparationDecision | Promise<HostedHeartbeatExecutionPreparationDecision>;
47
+ settle(input: HostedHeartbeatExecutionSettlementInput): HostedHeartbeatExecutionSettlement['disposition'] | Promise<HostedHeartbeatExecutionSettlement['disposition']>;
42
48
  }
43
- export type HostedHeartbeatDelegationServiceConfig = {
49
+ export type HostedHeartbeatExecutionServiceConfig = {
44
50
  authority: ExecutionAuthorityIssuer;
45
- authorizer: HostedHeartbeatDelegationAuthorizer;
51
+ lifecycle: HostedHeartbeatProductExecutionLifecycle;
46
52
  runtimeSessionNamespace: string;
47
53
  maxExecutionMs: number;
48
54
  now?: () => Date;
49
55
  };
50
- export interface HostedHeartbeatDelegationIssuer {
51
- issue(input: HostedHeartbeatDelegationRequest, signal?: AbortSignal): Promise<HostedHeartbeatDelegation>;
56
+ export interface HostedHeartbeatExecutionApi {
57
+ prepare(input: HostedHeartbeatExecutionPreparationRequest, signal?: AbortSignal): Promise<HostedHeartbeatExecutionPreparation>;
58
+ settle(input: HostedHeartbeatExecutionSettlementRequest, signal?: AbortSignal): Promise<HostedHeartbeatExecutionSettlement>;
52
59
  }
53
- export type HostedHeartbeatDelegationClientConfig = {
60
+ export type HostedHeartbeatExecutionClientConfig = {
54
61
  baseUrl: URL;
55
62
  apiToken: string;
63
+ /** Allows only Docker's explicit local-host alias over HTTP. */
64
+ allowDockerLocalHost?: boolean;
56
65
  fetch?: typeof globalThis.fetch;
57
- path?: string;
66
+ preparePath?: string;
67
+ settlePath?: string;
68
+ requestTimeoutMs?: number;
58
69
  };
59
- export type HostedHeartbeatDelegatedExecutionTransportConfig = {
60
- delegations: HostedHeartbeatDelegationIssuer;
70
+ export type HostedHeartbeatDelegatedExecutionConfig = {
71
+ executions: HostedHeartbeatExecutionApi;
61
72
  executionHost: HeartbeatExecutionHost;
62
73
  modelCredentials: HostedModelCredentialProvider;
63
74
  };
64
- export interface HostedHeartbeatDelegatedExecutionTransportPort {
75
+ export interface HostedHeartbeatExecutionTransportPort {
65
76
  execute(input: HostedHeartbeatAgentExecutionTransportInput): Promise<unknown>;
66
77
  }
78
+ /**
79
+ * Structural subset of Heddle's heartbeat handler context. Keeping this port
80
+ * local avoids making the adopter client depend on the full Runtime package.
81
+ */
82
+ export type HostedHeartbeatCoordinatorExecutionContext<TResult = unknown, TOutcome = unknown> = {
83
+ task: {
84
+ id: string;
85
+ state?: {
86
+ recovery?: {
87
+ interruptedExecutionId: string;
88
+ };
89
+ };
90
+ };
91
+ executionId: string;
92
+ signal: AbortSignal;
93
+ runAgent(): Promise<TResult>;
94
+ skip(input: {
95
+ summary: string;
96
+ }): TOutcome;
97
+ retry(input: {
98
+ summary: string;
99
+ delayMs?: number;
100
+ }): TOutcome;
101
+ block(input: {
102
+ summary: string;
103
+ }): TOutcome;
104
+ };
67
105
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/coordinator/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/coordinator/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/coordinator/types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n ExecutionAuthorityIssuer,\n} from '../authority/index.js';\nimport type {\n HostedModelCredentialProvider,\n} from '../conversation/index.js';\nimport type {\n HostedHeartbeatAgentExecutionTransportInput,\n} from '../heartbeat/index.js';\nimport type { HeartbeatExecutionHost } from '../http-sse/index.js';\nimport type {\n HostedHeartbeatCoordinatorTaskInput,\n HostedHeartbeatCoordinatorState,\n HostedHeartbeatCoordinatorTaskDetail,\n HostedHeartbeatCoordinatorTaskView,\n HostedHeartbeatDelegation,\n HostedHeartbeatDelegationAuthorization,\n HostedHeartbeatDelegationRequest,\n HostedHeartbeatDesiredTask,\n} from './contracts.js';\n\nexport type HostedHeartbeatCoordinatorClientConfig = {\n baseUrl: URL;\n apiToken: string;\n fetch?: typeof globalThis.fetch;\n};\n\nexport interface HostedHeartbeatCoordinatorTaskApi {\n readState(signal?: AbortSignal): Promise<HostedHeartbeatCoordinatorState>;\n listTasks(\n signal?: AbortSignal,\n ): Promise<HostedHeartbeatCoordinatorTaskView[]>;\n readTask(\n taskId: string,\n signal?: AbortSignal,\n ): Promise<HostedHeartbeatCoordinatorTaskDetail>;\n upsertTask(\n taskId: string,\n task: HostedHeartbeatCoordinatorTaskInput,\n signal?: AbortSignal,\n ): Promise<void>;\n triggerTask(\n taskId: string,\n signal?: AbortSignal,\n ): Promise<HostedHeartbeatCoordinatorTaskView>;\n deleteTask(taskId: string, signal?: AbortSignal): Promise<void>;\n pause(signal?: AbortSignal): Promise<void>;\n resume(signal?: AbortSignal): Promise<void>;\n drain(signal?: AbortSignal): Promise<void>;\n}\n\nexport type HostedHeartbeatTaskReconciliationInput = {\n desiredTasks: readonly HostedHeartbeatDesiredTask[];\n resume: boolean;\n signal?: AbortSignal;\n};\n\nexport type HostedHeartbeatTaskReconciliation = {\n deleted: number;\n upserted: number;\n resumed: boolean;\n};\n\nexport type HostedHeartbeatTaskReconcilerConfig = {\n coordinator: Pick<\n HostedHeartbeatCoordinatorTaskApi,\n 'listTasks' | 'upsertTask' | 'deleteTask' | 'pause' | 'resume'\n >;\n};\n\nexport type HostedHeartbeatDelegationAuthorizationInput = {\n taskId: string;\n executionId: string;\n signal: AbortSignal;\n};\n\nexport interface HostedHeartbeatDelegationAuthorizer {\n authorize(\n input: HostedHeartbeatDelegationAuthorizationInput,\n ): HostedHeartbeatDelegationAuthorization\n | undefined\n | Promise<HostedHeartbeatDelegationAuthorization | undefined>;\n}\n\nexport type HostedHeartbeatDelegationServiceConfig = {\n authority: ExecutionAuthorityIssuer;\n authorizer: HostedHeartbeatDelegationAuthorizer;\n runtimeSessionNamespace: string;\n maxExecutionMs: number;\n now?: () => Date;\n};\n\nexport interface HostedHeartbeatDelegationIssuer {\n issue(\n input: HostedHeartbeatDelegationRequest,\n signal?: AbortSignal,\n ): Promise<HostedHeartbeatDelegation>;\n}\n\nexport type HostedHeartbeatDelegationClientConfig = {\n baseUrl: URL;\n apiToken: string;\n fetch?: typeof globalThis.fetch;\n path?: string;\n};\n\nexport type HostedHeartbeatDelegatedExecutionTransportConfig = {\n delegations: HostedHeartbeatDelegationIssuer;\n executionHost: HeartbeatExecutionHost;\n modelCredentials: HostedModelCredentialProvider;\n};\n\nexport interface HostedHeartbeatDelegatedExecutionTransportPort {\n execute(\n input: HostedHeartbeatAgentExecutionTransportInput,\n ): Promise<unknown>;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/coordinator/types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n ExecutionAuthorityIssuer,\n} from '../authority/index.js';\nimport type {\n HostedModelCredentialProvider,\n} from '../conversation/index.js';\nimport type {\n HostedHeartbeatAgentExecutionTransportInput,\n} from '../heartbeat/index.js';\nimport type { HeartbeatExecutionHost } from '../http-sse/index.js';\nimport type {\n HostedHeartbeatCoordinatorTaskInput,\n HostedHeartbeatCoordinatorState,\n HostedHeartbeatCoordinatorTaskDetail,\n HostedHeartbeatCoordinatorTaskView,\n HostedHeartbeatExecutionPreparation,\n HostedHeartbeatExecutionPreparationDecision,\n HostedHeartbeatExecutionPreparationRequest,\n HostedHeartbeatExecutionSettlement,\n HostedHeartbeatExecutionSettlementRequest,\n HostedHeartbeatDesiredTask,\n} from './contracts.js';\n\nexport type HostedHeartbeatCoordinatorClientConfig = {\n baseUrl: URL;\n apiToken: string;\n fetch?: typeof globalThis.fetch;\n};\n\nexport interface HostedHeartbeatCoordinatorTaskApi {\n readState(signal?: AbortSignal): Promise<HostedHeartbeatCoordinatorState>;\n listTasks(\n signal?: AbortSignal,\n ): Promise<HostedHeartbeatCoordinatorTaskView[]>;\n readTask(\n taskId: string,\n signal?: AbortSignal,\n ): Promise<HostedHeartbeatCoordinatorTaskDetail>;\n upsertTask(\n taskId: string,\n task: HostedHeartbeatCoordinatorTaskInput,\n signal?: AbortSignal,\n ): Promise<void>;\n triggerTask(\n taskId: string,\n signal?: AbortSignal,\n ): Promise<HostedHeartbeatCoordinatorTaskView>;\n deleteTask(taskId: string, signal?: AbortSignal): Promise<void>;\n pause(signal?: AbortSignal): Promise<void>;\n resume(signal?: AbortSignal): Promise<void>;\n drain(signal?: AbortSignal): Promise<void>;\n}\n\nexport type HostedHeartbeatTaskReconciliationInput = {\n desiredTasks: readonly HostedHeartbeatDesiredTask[];\n resume: boolean;\n signal?: AbortSignal;\n};\n\nexport type HostedHeartbeatTaskReconciliation = {\n deleted: number;\n upserted: number;\n resumed: boolean;\n};\n\nexport type HostedHeartbeatTaskReconcilerConfig = {\n coordinator: Pick<\n HostedHeartbeatCoordinatorTaskApi,\n 'listTasks' | 'upsertTask' | 'deleteTask' | 'pause' | 'resume'\n >;\n};\n\nexport type HostedHeartbeatExecutionPreparationInput = {\n taskId: string;\n executionId: string;\n interruptedExecutionId?: string;\n signal: AbortSignal;\n};\n\nexport type HostedHeartbeatExecutionSettlementInput =\n HostedHeartbeatExecutionSettlementRequest & {\n signal: AbortSignal;\n };\n\n/** Product-owned lifecycle around one Coordinator-owned execution attempt. */\nexport interface HostedHeartbeatProductExecutionLifecycle {\n prepare(\n input: HostedHeartbeatExecutionPreparationInput,\n ): HostedHeartbeatExecutionPreparationDecision\n | Promise<HostedHeartbeatExecutionPreparationDecision>;\n settle(\n input: HostedHeartbeatExecutionSettlementInput,\n ): HostedHeartbeatExecutionSettlement['disposition']\n | Promise<HostedHeartbeatExecutionSettlement['disposition']>;\n}\n\nexport type HostedHeartbeatExecutionServiceConfig = {\n authority: ExecutionAuthorityIssuer;\n lifecycle: HostedHeartbeatProductExecutionLifecycle;\n runtimeSessionNamespace: string;\n maxExecutionMs: number;\n now?: () => Date;\n};\n\nexport interface HostedHeartbeatExecutionApi {\n prepare(\n input: HostedHeartbeatExecutionPreparationRequest,\n signal?: AbortSignal,\n ): Promise<HostedHeartbeatExecutionPreparation>;\n settle(\n input: HostedHeartbeatExecutionSettlementRequest,\n signal?: AbortSignal,\n ): Promise<HostedHeartbeatExecutionSettlement>;\n}\n\nexport type HostedHeartbeatExecutionClientConfig = {\n baseUrl: URL;\n apiToken: string;\n /** Allows only Docker's explicit local-host alias over HTTP. */\n allowDockerLocalHost?: boolean;\n fetch?: typeof globalThis.fetch;\n preparePath?: string;\n settlePath?: string;\n requestTimeoutMs?: number;\n};\n\nexport type HostedHeartbeatDelegatedExecutionConfig = {\n executions: HostedHeartbeatExecutionApi;\n executionHost: HeartbeatExecutionHost;\n modelCredentials: HostedModelCredentialProvider;\n};\n\nexport interface HostedHeartbeatExecutionTransportPort {\n execute(\n input: HostedHeartbeatAgentExecutionTransportInput,\n ): Promise<unknown>;\n}\n\n/**\n * Structural subset of Heddle's heartbeat handler context. Keeping this port\n * local avoids making the adopter client depend on the full Runtime package.\n */\nexport type HostedHeartbeatCoordinatorExecutionContext<\n TResult = unknown,\n TOutcome = unknown,\n> = {\n task: {\n id: string;\n state?: {\n recovery?: { interruptedExecutionId: string };\n };\n };\n executionId: string;\n signal: AbortSignal;\n runAgent(): Promise<TResult>;\n skip(input: { summary: string }): TOutcome;\n retry(input: { summary: string; delayMs?: number }): TOutcome;\n block(input: { summary: string }): TOutcome;\n};\n"]}
@@ -48,7 +48,7 @@ export class HostedHeartbeatTaskService {
48
48
  if (this.#allowedTools && !mcpCapability) {
49
49
  throw new HostedHeartbeatConfigurationError('Hosted heartbeat tool policy requires an MCP-capable execution authority.');
50
50
  }
51
- const modelApiKey = await this.#modelCredentials.resolveModelApiKey({
51
+ const modelCredential = await this.#modelCredentials.resolveModelCredential({
52
52
  scope: input.scope,
53
53
  invocationId: input.invocationId,
54
54
  signal: input.signal,
@@ -74,7 +74,7 @@ export class HostedHeartbeatTaskService {
74
74
  ...(input.signal ? { signal: input.signal } : {}),
75
75
  executionAssertion: issued.executionAssertion(),
76
76
  ...(mcpCapability ? { mcpCapability } : {}),
77
- modelApiKey,
77
+ modelCredential,
78
78
  })) {
79
79
  if (event.kind === 'activity') {
80
80
  input.publishActivity?.(event.activity);
@@ -1 +1 @@
1
- {"version":3,"file":"hosted-heartbeat-task-service.js","sourceRoot":"","sources":["../../src/heartbeat/hosted-heartbeat-task-service.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n HEARTBEAT_TASK_WORKFLOW,\n McpAllowedToolsSchema,\n} from '../contracts/index.js';\nimport { ExecutionHostInvocationCancelledError } from '../http-sse/index.js';\nimport {\n HostedHeartbeatTaskInputSchema,\n type HostedHeartbeatTaskInput,\n type HostedHeartbeatTaskRunner,\n type HostedHeartbeatTaskServiceConfig,\n} from './types.js';\n\nexport class HostedHeartbeatConfigurationError extends Error {\n readonly name = 'HostedHeartbeatConfigurationError';\n}\n\nexport class HostedHeartbeatExecutionError extends Error {\n readonly name = 'HostedHeartbeatExecutionError';\n\n constructor(readonly code: string) {\n super('Execution Host heartbeat task failed.');\n }\n}\n\n/**\n * Provider-neutral application service for one remotely executed heartbeat.\n *\n * It owns authority issuance, optional product-tool policy, model credentials,\n * ordered stream consumption, cancellation, and terminal classification. The\n * caller owns product scope/session mapping and the durable heartbeat store.\n */\nexport class HostedHeartbeatTaskService\nimplements HostedHeartbeatTaskRunner {\n readonly #authority: HostedHeartbeatTaskServiceConfig['authority'];\n readonly #executionHost: HostedHeartbeatTaskServiceConfig['executionHost'];\n readonly #modelCredentials: HostedHeartbeatTaskServiceConfig[\n 'modelCredentials'\n ];\n readonly #allowedTools: readonly string[] | undefined;\n\n constructor(config: HostedHeartbeatTaskServiceConfig) {\n this.#authority = config.authority;\n this.#executionHost = config.executionHost;\n this.#modelCredentials = config.modelCredentials;\n this.#allowedTools = config.mcp\n ? Object.freeze(McpAllowedToolsSchema.parse(config.mcp.allowedTools))\n : undefined;\n }\n\n async execute(\n rawInput: HostedHeartbeatTaskInput,\n ): Promise<unknown> {\n const input = HostedHeartbeatTaskInputSchema.parse(rawInput);\n input.signal?.throwIfAborted();\n const issued = await this.#authority.issue({\n scope: input.scope,\n runtimeSessionId: input.runtimeSessionId,\n invocationId: input.invocationId,\n workflow: HEARTBEAT_TASK_WORKFLOW,\n ...(this.#allowedTools\n ? { mcp: { allowedTools: this.#allowedTools } }\n : {}),\n });\n const mcpCapability = issued.mcpCapability();\n if (this.#allowedTools && !mcpCapability) {\n throw new HostedHeartbeatConfigurationError(\n 'Hosted heartbeat tool policy requires an MCP-capable execution authority.',\n );\n }\n const modelApiKey = await this.#modelCredentials.resolveModelApiKey({\n scope: input.scope,\n invocationId: input.invocationId,\n signal: input.signal,\n });\n input.signal?.throwIfAborted();\n\n for await (const event of this.#executionHost.streamHeartbeatTask({\n invocationId: input.invocationId,\n runtimeSessionId: input.runtimeSessionId,\n taskId: input.taskId,\n task: input.task,\n ...(input.checkpoint ? { checkpoint: input.checkpoint } : {}),\n runContext: input.runContext,\n ...(input.model ? { model: input.model } : {}),\n ...(input.reasoningEffort\n ? { reasoningEffort: input.reasoningEffort }\n : {}),\n ...(input.maxSteps !== undefined ? { maxSteps: input.maxSteps } : {}),\n ...(input.searchIgnoreDirs\n ? { searchIgnoreDirs: input.searchIgnoreDirs }\n : {}),\n ...(input.systemContext ? { systemContext: input.systemContext } : {}),\n ...(input.deadlineAt ? { deadlineAt: input.deadlineAt } : {}),\n ...(input.signal ? { signal: input.signal } : {}),\n executionAssertion: issued.executionAssertion(),\n ...(mcpCapability ? { mcpCapability } : {}),\n modelApiKey,\n })) {\n if (event.kind === 'activity') {\n input.publishActivity?.(event.activity);\n continue;\n }\n if (event.kind === 'result') {\n return event.result;\n }\n if (event.kind === 'cancelled') {\n throw new ExecutionHostInvocationCancelledError();\n }\n if (event.kind === 'error') {\n throw new HostedHeartbeatExecutionError(event.error.code);\n }\n }\n throw new HostedHeartbeatExecutionError('missing_terminal_result');\n }\n}\n"]}
1
+ {"version":3,"file":"hosted-heartbeat-task-service.js","sourceRoot":"","sources":["../../src/heartbeat/hosted-heartbeat-task-service.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n HEARTBEAT_TASK_WORKFLOW,\n McpAllowedToolsSchema,\n} from '../contracts/index.js';\nimport { ExecutionHostInvocationCancelledError } from '../http-sse/index.js';\nimport {\n HostedHeartbeatTaskInputSchema,\n type HostedHeartbeatTaskInput,\n type HostedHeartbeatTaskRunner,\n type HostedHeartbeatTaskServiceConfig,\n} from './types.js';\n\nexport class HostedHeartbeatConfigurationError extends Error {\n readonly name = 'HostedHeartbeatConfigurationError';\n}\n\nexport class HostedHeartbeatExecutionError extends Error {\n readonly name = 'HostedHeartbeatExecutionError';\n\n constructor(readonly code: string) {\n super('Execution Host heartbeat task failed.');\n }\n}\n\n/**\n * Provider-neutral application service for one remotely executed heartbeat.\n *\n * It owns authority issuance, optional product-tool policy, model credentials,\n * ordered stream consumption, cancellation, and terminal classification. The\n * caller owns product scope/session mapping and the durable heartbeat store.\n */\nexport class HostedHeartbeatTaskService\nimplements HostedHeartbeatTaskRunner {\n readonly #authority: HostedHeartbeatTaskServiceConfig['authority'];\n readonly #executionHost: HostedHeartbeatTaskServiceConfig['executionHost'];\n readonly #modelCredentials: HostedHeartbeatTaskServiceConfig[\n 'modelCredentials'\n ];\n readonly #allowedTools: readonly string[] | undefined;\n\n constructor(config: HostedHeartbeatTaskServiceConfig) {\n this.#authority = config.authority;\n this.#executionHost = config.executionHost;\n this.#modelCredentials = config.modelCredentials;\n this.#allowedTools = config.mcp\n ? Object.freeze(McpAllowedToolsSchema.parse(config.mcp.allowedTools))\n : undefined;\n }\n\n async execute(\n rawInput: HostedHeartbeatTaskInput,\n ): Promise<unknown> {\n const input = HostedHeartbeatTaskInputSchema.parse(rawInput);\n input.signal?.throwIfAborted();\n const issued = await this.#authority.issue({\n scope: input.scope,\n runtimeSessionId: input.runtimeSessionId,\n invocationId: input.invocationId,\n workflow: HEARTBEAT_TASK_WORKFLOW,\n ...(this.#allowedTools\n ? { mcp: { allowedTools: this.#allowedTools } }\n : {}),\n });\n const mcpCapability = issued.mcpCapability();\n if (this.#allowedTools && !mcpCapability) {\n throw new HostedHeartbeatConfigurationError(\n 'Hosted heartbeat tool policy requires an MCP-capable execution authority.',\n );\n }\n const modelCredential = await this.#modelCredentials.resolveModelCredential({\n scope: input.scope,\n invocationId: input.invocationId,\n signal: input.signal,\n });\n input.signal?.throwIfAborted();\n\n for await (const event of this.#executionHost.streamHeartbeatTask({\n invocationId: input.invocationId,\n runtimeSessionId: input.runtimeSessionId,\n taskId: input.taskId,\n task: input.task,\n ...(input.checkpoint ? { checkpoint: input.checkpoint } : {}),\n runContext: input.runContext,\n ...(input.model ? { model: input.model } : {}),\n ...(input.reasoningEffort\n ? { reasoningEffort: input.reasoningEffort }\n : {}),\n ...(input.maxSteps !== undefined ? { maxSteps: input.maxSteps } : {}),\n ...(input.searchIgnoreDirs\n ? { searchIgnoreDirs: input.searchIgnoreDirs }\n : {}),\n ...(input.systemContext ? { systemContext: input.systemContext } : {}),\n ...(input.deadlineAt ? { deadlineAt: input.deadlineAt } : {}),\n ...(input.signal ? { signal: input.signal } : {}),\n executionAssertion: issued.executionAssertion(),\n ...(mcpCapability ? { mcpCapability } : {}),\n modelCredential,\n })) {\n if (event.kind === 'activity') {\n input.publishActivity?.(event.activity);\n continue;\n }\n if (event.kind === 'result') {\n return event.result;\n }\n if (event.kind === 'cancelled') {\n throw new ExecutionHostInvocationCancelledError();\n }\n if (event.kind === 'error') {\n throw new HostedHeartbeatExecutionError(event.error.code);\n }\n }\n throw new HostedHeartbeatExecutionError('missing_terminal_result');\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"jwt-execution-host-mcp-capability-verifier.d.ts","sourceRoot":"","sources":["../../src/host/jwt-execution-host-mcp-capability-verifier.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACV,+BAA+B,EAC/B,6CAA6C,EAC7C,kCAAkC,EAClC,2CAA2C,EAC3C,kCAAkC,EACnC,MAAM,YAAY,CAAC;AAOpB,gFAAgF;AAChF,qBAAa,qCACb,YAAW,kCAAkC;;gBAMzC,MAAM,EAAE,2CAA2C,EACnD,OAAO,GAAE,+BAAoC;IAczC,MAAM,CACV,UAAU,EAAE,6CAA6C,GACxD,OAAO,CAAC,kCAAkC,CAAC;CAkF/C"}
1
+ {"version":3,"file":"jwt-execution-host-mcp-capability-verifier.d.ts","sourceRoot":"","sources":["../../src/host/jwt-execution-host-mcp-capability-verifier.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EACV,+BAA+B,EAC/B,6CAA6C,EAC7C,kCAAkC,EAClC,2CAA2C,EAC3C,kCAAkC,EACnC,MAAM,YAAY,CAAC;AAOpB,gFAAgF;AAChF,qBAAa,qCACb,YAAW,kCAAkC;;gBAMzC,MAAM,EAAE,2CAA2C,EACnD,OAAO,GAAE,+BAAoC;IAczC,MAAM,CACV,UAAU,EAAE,6CAA6C,GACxD,OAAO,CAAC,kCAAkC,CAAC;CAkF/C"}
@@ -3,7 +3,7 @@ import { z } from 'zod';
3
3
  import { MCP_CAPABILITY_TYPE, McpCapabilityClaimsSchema, } from '../contracts/index.js';
4
4
  import { createJwtKeyResolver, resolveJwtVerificationUnavailableCategory, } from '../internal/jwt-verification.js';
5
5
  import { ExecutionHostMcpCapabilityUnavailableError, ExecutionHostMcpCapabilityVerificationError, } from './errors.js';
6
- import { JwtExecutionHostMcpCapabilityVerifierConfigSchema } from './schemas.js';
6
+ import { parseJwtExecutionHostMcpCapabilityVerifierConfig, } from './schemas.js';
7
7
  const AssertionSchema = z.string().trim().min(32).max(4_096);
8
8
  /** Verifies MCP authority against an independently verified host invocation. */
9
9
  export class JwtExecutionHostMcpCapabilityVerifier {
@@ -11,7 +11,9 @@ export class JwtExecutionHostMcpCapabilityVerifier {
11
11
  #keyResolver;
12
12
  #now;
13
13
  constructor(config, options = {}) {
14
- const parsed = JwtExecutionHostMcpCapabilityVerifierConfigSchema.parse(config);
14
+ const parsed = parseJwtExecutionHostMcpCapabilityVerifierConfig(config, {
15
+ allowDockerLocalHost: options.allowDockerLocalHost === true,
16
+ });
15
17
  this.#config = Object.freeze({
16
18
  ...parsed,
17
19
  jwksUrl: new URL(parsed.jwksUrl),
@@ -1 +1 @@
1
- {"version":3,"file":"jwt-execution-host-mcp-capability-verifier.js","sourceRoot":"","sources":["../../src/host/jwt-execution-host-mcp-capability-verifier.ts"],"names":[],"mappings":"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","sourcesContent":["import { jwtVerify } from 'jose';\nimport { z } from 'zod';\nimport {\n MCP_CAPABILITY_TYPE,\n McpCapabilityClaimsSchema,\n} from '../contracts/index.js';\nimport {\n createJwtKeyResolver,\n resolveJwtVerificationUnavailableCategory,\n} from '../internal/jwt-verification.js';\nimport {\n ExecutionHostMcpCapabilityUnavailableError,\n ExecutionHostMcpCapabilityVerificationError,\n} from './errors.js';\nimport { JwtExecutionHostMcpCapabilityVerifierConfigSchema } from './schemas.js';\nimport type {\n ExecutionHostJwtVerifierOptions,\n ExecutionHostMcpCapabilityVerificationRequest,\n ExecutionHostMcpCapabilityVerifier,\n JwtExecutionHostMcpCapabilityVerifierConfig,\n VerifiedExecutionHostMcpCapability,\n} from './types.js';\n\nconst AssertionSchema = z.string().trim().min(32).max(4_096);\ntype ParsedConfig = z.infer<\n typeof JwtExecutionHostMcpCapabilityVerifierConfigSchema\n>;\n\n/** Verifies MCP authority against an independently verified host invocation. */\nexport class JwtExecutionHostMcpCapabilityVerifier\nimplements ExecutionHostMcpCapabilityVerifier {\n readonly #config: Readonly<ParsedConfig>;\n readonly #keyResolver: NonNullable<ExecutionHostJwtVerifierOptions['keyResolver']>;\n readonly #now: () => Date;\n\n constructor(\n config: JwtExecutionHostMcpCapabilityVerifierConfig,\n options: ExecutionHostJwtVerifierOptions = {},\n ) {\n const parsed = JwtExecutionHostMcpCapabilityVerifierConfigSchema.parse(\n config,\n );\n this.#config = Object.freeze({\n ...parsed,\n jwksUrl: new URL(parsed.jwksUrl),\n });\n this.#keyResolver = options.keyResolver\n ?? createJwtKeyResolver(this.#config.jwksUrl);\n this.#now = options.now ?? (() => new Date());\n }\n\n async verify(\n rawRequest: ExecutionHostMcpCapabilityVerificationRequest,\n ): Promise<VerifiedExecutionHostMcpCapability> {\n try {\n const request = Object.freeze({\n ...rawRequest,\n assertion: AssertionSchema.parse(rawRequest.assertion),\n });\n const { payload } = await jwtVerify(\n request.assertion,\n this.#keyResolver,\n {\n algorithms: [...this.#config.jwtAlgorithms],\n audience: this.#config.audience,\n clockTolerance: this.#config.clockToleranceSeconds,\n currentDate: this.#now(),\n issuer: this.#config.issuer,\n maxTokenAge: this.#config.maxCapabilityAgeSeconds,\n requiredClaims: ['exp', 'iat', 'jti', 'sub'],\n typ: MCP_CAPABILITY_TYPE,\n },\n );\n const claims = McpCapabilityClaimsSchema.parse(payload);\n this.#assertInvocationBinding(claims, request);\n this.#assertBoundedLifetime(claims);\n\n return Object.freeze({\n assertion: request.assertion,\n capabilityId: claims.jti,\n serverId: claims.serverId,\n allowedTools: Object.freeze([...claims.allowedTools]),\n issuedAt: new Date(claims.iat * 1_000).toISOString(),\n expiresAt: new Date(claims.exp * 1_000).toISOString(),\n });\n } catch (error) {\n if (\n error instanceof ExecutionHostMcpCapabilityVerificationError\n || error instanceof ExecutionHostMcpCapabilityUnavailableError\n ) {\n throw error;\n }\n const category = resolveJwtVerificationUnavailableCategory(error);\n if (category) {\n throw new ExecutionHostMcpCapabilityUnavailableError(\n category,\n { cause: error },\n );\n }\n throw new ExecutionHostMcpCapabilityVerificationError({ cause: error });\n }\n }\n\n #assertInvocationBinding(\n claims: z.infer<typeof McpCapabilityClaimsSchema>,\n request: ExecutionHostMcpCapabilityVerificationRequest,\n ): void {\n const { identity } = request;\n if (\n claims.adopterId !== this.#config.trustedAdopterId\n || claims.adopterId !== identity.scope.adopterId\n || claims.tenantId !== identity.scope.tenantId\n || claims.sub !== identity.scope.subjectId\n || claims.productSessionId !== identity.scope.productSessionId\n || claims.runtimeSessionId !== identity.runtimeSessionId\n || claims.invocationId !== identity.invocationId\n || claims.workflow !== identity.workflow\n || claims.serverId !== this.#config.serverId\n || claims.jti === identity.invocationId\n ) {\n throw new ExecutionHostMcpCapabilityVerificationError();\n }\n }\n\n #assertBoundedLifetime(\n claims: z.infer<typeof McpCapabilityClaimsSchema>,\n ): void {\n const lifetimeSeconds = claims.exp - claims.iat;\n if (\n lifetimeSeconds <= 0\n || lifetimeSeconds > this.#config.maxCapabilityAgeSeconds\n ) {\n throw new ExecutionHostMcpCapabilityVerificationError();\n }\n }\n}\n"]}
1
+ {"version":3,"file":"jwt-execution-host-mcp-capability-verifier.js","sourceRoot":"","sources":["../../src/host/jwt-execution-host-mcp-capability-verifier.ts"],"names":[],"mappings":"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","sourcesContent":["import { jwtVerify } from 'jose';\nimport { z } from 'zod';\nimport {\n MCP_CAPABILITY_TYPE,\n McpCapabilityClaimsSchema,\n} from '../contracts/index.js';\nimport {\n createJwtKeyResolver,\n resolveJwtVerificationUnavailableCategory,\n} from '../internal/jwt-verification.js';\nimport {\n ExecutionHostMcpCapabilityUnavailableError,\n ExecutionHostMcpCapabilityVerificationError,\n} from './errors.js';\nimport {\n JwtExecutionHostMcpCapabilityVerifierConfigSchema,\n parseJwtExecutionHostMcpCapabilityVerifierConfig,\n} from './schemas.js';\nimport type {\n ExecutionHostJwtVerifierOptions,\n ExecutionHostMcpCapabilityVerificationRequest,\n ExecutionHostMcpCapabilityVerifier,\n JwtExecutionHostMcpCapabilityVerifierConfig,\n VerifiedExecutionHostMcpCapability,\n} from './types.js';\n\nconst AssertionSchema = z.string().trim().min(32).max(4_096);\ntype ParsedConfig = z.infer<\n typeof JwtExecutionHostMcpCapabilityVerifierConfigSchema\n>;\n\n/** Verifies MCP authority against an independently verified host invocation. */\nexport class JwtExecutionHostMcpCapabilityVerifier\nimplements ExecutionHostMcpCapabilityVerifier {\n readonly #config: Readonly<ParsedConfig>;\n readonly #keyResolver: NonNullable<ExecutionHostJwtVerifierOptions['keyResolver']>;\n readonly #now: () => Date;\n\n constructor(\n config: JwtExecutionHostMcpCapabilityVerifierConfig,\n options: ExecutionHostJwtVerifierOptions = {},\n ) {\n const parsed = parseJwtExecutionHostMcpCapabilityVerifierConfig(config, {\n allowDockerLocalHost: options.allowDockerLocalHost === true,\n });\n this.#config = Object.freeze({\n ...parsed,\n jwksUrl: new URL(parsed.jwksUrl),\n });\n this.#keyResolver = options.keyResolver\n ?? createJwtKeyResolver(this.#config.jwksUrl);\n this.#now = options.now ?? (() => new Date());\n }\n\n async verify(\n rawRequest: ExecutionHostMcpCapabilityVerificationRequest,\n ): Promise<VerifiedExecutionHostMcpCapability> {\n try {\n const request = Object.freeze({\n ...rawRequest,\n assertion: AssertionSchema.parse(rawRequest.assertion),\n });\n const { payload } = await jwtVerify(\n request.assertion,\n this.#keyResolver,\n {\n algorithms: [...this.#config.jwtAlgorithms],\n audience: this.#config.audience,\n clockTolerance: this.#config.clockToleranceSeconds,\n currentDate: this.#now(),\n issuer: this.#config.issuer,\n maxTokenAge: this.#config.maxCapabilityAgeSeconds,\n requiredClaims: ['exp', 'iat', 'jti', 'sub'],\n typ: MCP_CAPABILITY_TYPE,\n },\n );\n const claims = McpCapabilityClaimsSchema.parse(payload);\n this.#assertInvocationBinding(claims, request);\n this.#assertBoundedLifetime(claims);\n\n return Object.freeze({\n assertion: request.assertion,\n capabilityId: claims.jti,\n serverId: claims.serverId,\n allowedTools: Object.freeze([...claims.allowedTools]),\n issuedAt: new Date(claims.iat * 1_000).toISOString(),\n expiresAt: new Date(claims.exp * 1_000).toISOString(),\n });\n } catch (error) {\n if (\n error instanceof ExecutionHostMcpCapabilityVerificationError\n || error instanceof ExecutionHostMcpCapabilityUnavailableError\n ) {\n throw error;\n }\n const category = resolveJwtVerificationUnavailableCategory(error);\n if (category) {\n throw new ExecutionHostMcpCapabilityUnavailableError(\n category,\n { cause: error },\n );\n }\n throw new ExecutionHostMcpCapabilityVerificationError({ cause: error });\n }\n }\n\n #assertInvocationBinding(\n claims: z.infer<typeof McpCapabilityClaimsSchema>,\n request: ExecutionHostMcpCapabilityVerificationRequest,\n ): void {\n const { identity } = request;\n if (\n claims.adopterId !== this.#config.trustedAdopterId\n || claims.adopterId !== identity.scope.adopterId\n || claims.tenantId !== identity.scope.tenantId\n || claims.sub !== identity.scope.subjectId\n || claims.productSessionId !== identity.scope.productSessionId\n || claims.runtimeSessionId !== identity.runtimeSessionId\n || claims.invocationId !== identity.invocationId\n || claims.workflow !== identity.workflow\n || claims.serverId !== this.#config.serverId\n || claims.jti === identity.invocationId\n ) {\n throw new ExecutionHostMcpCapabilityVerificationError();\n }\n }\n\n #assertBoundedLifetime(\n claims: z.infer<typeof McpCapabilityClaimsSchema>,\n ): void {\n const lifetimeSeconds = claims.exp - claims.iat;\n if (\n lifetimeSeconds <= 0\n || lifetimeSeconds > this.#config.maxCapabilityAgeSeconds\n ) {\n throw new ExecutionHostMcpCapabilityVerificationError();\n }\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"jwt-execution-identity-verifier.d.ts","sourceRoot":"","sources":["../../src/host/jwt-execution-identity-verifier.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACV,oCAAoC,EACpC,yBAAyB,EACzB,+BAA+B,EAC/B,kCAAkC,EAClC,yBAAyB,EAC1B,MAAM,YAAY,CAAC;AAKpB,4EAA4E;AAC5E,qBAAa,4BAA6B,YAAW,yBAAyB;;gBAM1E,MAAM,EAAE,kCAAkC,EAC1C,OAAO,GAAE,+BAAoC;IAYzC,MAAM,CACV,UAAU,EAAE,oCAAoC,GAC/C,OAAO,CAAC,yBAAyB,CAAC;CAgEtC"}
1
+ {"version":3,"file":"jwt-execution-identity-verifier.d.ts","sourceRoot":"","sources":["../../src/host/jwt-execution-identity-verifier.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EACV,oCAAoC,EACpC,yBAAyB,EACzB,+BAA+B,EAC/B,kCAAkC,EAClC,yBAAyB,EAC1B,MAAM,YAAY,CAAC;AAKpB,4EAA4E;AAC5E,qBAAa,4BAA6B,YAAW,yBAAyB;;gBAM1E,MAAM,EAAE,kCAAkC,EAC1C,OAAO,GAAE,+BAAoC;IAczC,MAAM,CACV,UAAU,EAAE,oCAAoC,GAC/C,OAAO,CAAC,yBAAyB,CAAC;CAgEtC"}
@@ -3,7 +3,7 @@ import { z } from 'zod';
3
3
  import { EXECUTION_ASSERTION_TYPE, ExecutionAssertionClaimsSchema, } from '../contracts/index.js';
4
4
  import { createJwtKeyResolver, resolveJwtVerificationUnavailableCategory, } from '../internal/jwt-verification.js';
5
5
  import { ExecutionIdentityUnavailableError, ExecutionIdentityVerificationError, } from './errors.js';
6
- import { JwtExecutionIdentityVerifierConfigSchema } from './schemas.js';
6
+ import { parseJwtExecutionIdentityVerifierConfig, } from './schemas.js';
7
7
  const AssertionSchema = z.string().trim().min(32).max(4_096);
8
8
  /** Verifies adopter authority and binds it to one exact host invocation. */
9
9
  export class JwtExecutionIdentityVerifier {
@@ -11,7 +11,9 @@ export class JwtExecutionIdentityVerifier {
11
11
  #keyResolver;
12
12
  #now;
13
13
  constructor(config, options = {}) {
14
- const parsed = JwtExecutionIdentityVerifierConfigSchema.parse(config);
14
+ const parsed = parseJwtExecutionIdentityVerifierConfig(config, {
15
+ allowDockerLocalHost: options.allowDockerLocalHost === true,
16
+ });
15
17
  this.#config = Object.freeze({
16
18
  ...parsed,
17
19
  executionJwksUrl: new URL(parsed.executionJwksUrl),
@@ -1 +1 @@
1
- {"version":3,"file":"jwt-execution-identity-verifier.js","sourceRoot":"","sources":["../../src/host/jwt-execution-identity-verifier.ts"],"names":[],"mappings":"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","sourcesContent":["import { jwtVerify } from 'jose';\nimport { z } from 'zod';\nimport {\n EXECUTION_ASSERTION_TYPE,\n ExecutionAssertionClaimsSchema,\n} from '../contracts/index.js';\nimport {\n createJwtKeyResolver,\n resolveJwtVerificationUnavailableCategory,\n} from '../internal/jwt-verification.js';\nimport {\n ExecutionIdentityUnavailableError,\n ExecutionIdentityVerificationError,\n} from './errors.js';\nimport { JwtExecutionIdentityVerifierConfigSchema } from './schemas.js';\nimport type {\n ExecutionIdentityVerificationRequest,\n ExecutionIdentityVerifier,\n ExecutionHostJwtVerifierOptions,\n JwtExecutionIdentityVerifierConfig,\n VerifiedExecutionIdentity,\n} from './types.js';\n\nconst AssertionSchema = z.string().trim().min(32).max(4_096);\ntype ParsedConfig = z.infer<typeof JwtExecutionIdentityVerifierConfigSchema>;\n\n/** Verifies adopter authority and binds it to one exact host invocation. */\nexport class JwtExecutionIdentityVerifier implements ExecutionIdentityVerifier {\n readonly #config: Readonly<ParsedConfig>;\n readonly #keyResolver: NonNullable<ExecutionHostJwtVerifierOptions['keyResolver']>;\n readonly #now: () => Date;\n\n constructor(\n config: JwtExecutionIdentityVerifierConfig,\n options: ExecutionHostJwtVerifierOptions = {},\n ) {\n const parsed = JwtExecutionIdentityVerifierConfigSchema.parse(config);\n this.#config = Object.freeze({\n ...parsed,\n executionJwksUrl: new URL(parsed.executionJwksUrl),\n });\n this.#keyResolver = options.keyResolver\n ?? createJwtKeyResolver(this.#config.executionJwksUrl);\n this.#now = options.now ?? (() => new Date());\n }\n\n async verify(\n rawRequest: ExecutionIdentityVerificationRequest,\n ): Promise<VerifiedExecutionIdentity> {\n try {\n const request = Object.freeze({\n ...rawRequest,\n assertion: AssertionSchema.parse(rawRequest.assertion),\n });\n const { payload } = await jwtVerify(\n request.assertion,\n this.#keyResolver,\n {\n algorithms: [...this.#config.executionJwtAlgorithms],\n audience: this.#config.executionAudience,\n clockTolerance: this.#config.assertionClockToleranceSeconds,\n currentDate: this.#now(),\n issuer: this.#config.executionIssuer,\n maxTokenAge: this.#config.maxAssertionAgeSeconds,\n requiredClaims: ['exp', 'iat', 'jti', 'sub'],\n typ: EXECUTION_ASSERTION_TYPE,\n },\n );\n const claims = ExecutionAssertionClaimsSchema.parse(payload);\n this.#assertRequestBinding(claims, request);\n\n return Object.freeze({\n scope: Object.freeze({\n adopterId: claims.adopterId,\n tenantId: claims.tenantId,\n subjectId: claims.sub,\n productSessionId: claims.productSessionId,\n }),\n runtimeSessionId: claims.runtimeSessionId,\n invocationId: claims.jti,\n workflow: claims.workflow,\n issuedAt: new Date(claims.iat * 1_000).toISOString(),\n expiresAt: new Date(claims.exp * 1_000).toISOString(),\n });\n } catch (error) {\n if (\n error instanceof ExecutionIdentityVerificationError\n || error instanceof ExecutionIdentityUnavailableError\n ) {\n throw error;\n }\n const category = resolveJwtVerificationUnavailableCategory(error);\n if (category) {\n throw new ExecutionIdentityUnavailableError(category, { cause: error });\n }\n throw new ExecutionIdentityVerificationError({ cause: error });\n }\n }\n\n #assertRequestBinding(\n claims: z.infer<typeof ExecutionAssertionClaimsSchema>,\n request: ExecutionIdentityVerificationRequest,\n ): void {\n if (\n claims.adopterId !== this.#config.trustedAdopterId\n || claims.runtimeSessionId !== request.runtimeSessionId\n || claims.jti !== request.invocationId\n || claims.workflow !== request.workflow\n ) {\n throw new ExecutionIdentityVerificationError();\n }\n }\n}\n"]}
1
+ {"version":3,"file":"jwt-execution-identity-verifier.js","sourceRoot":"","sources":["../../src/host/jwt-execution-identity-verifier.ts"],"names":[],"mappings":"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","sourcesContent":["import { jwtVerify } from 'jose';\nimport { z } from 'zod';\nimport {\n EXECUTION_ASSERTION_TYPE,\n ExecutionAssertionClaimsSchema,\n} from '../contracts/index.js';\nimport {\n createJwtKeyResolver,\n resolveJwtVerificationUnavailableCategory,\n} from '../internal/jwt-verification.js';\nimport {\n ExecutionIdentityUnavailableError,\n ExecutionIdentityVerificationError,\n} from './errors.js';\nimport {\n JwtExecutionIdentityVerifierConfigSchema,\n parseJwtExecutionIdentityVerifierConfig,\n} from './schemas.js';\nimport type {\n ExecutionIdentityVerificationRequest,\n ExecutionIdentityVerifier,\n ExecutionHostJwtVerifierOptions,\n JwtExecutionIdentityVerifierConfig,\n VerifiedExecutionIdentity,\n} from './types.js';\n\nconst AssertionSchema = z.string().trim().min(32).max(4_096);\ntype ParsedConfig = z.infer<typeof JwtExecutionIdentityVerifierConfigSchema>;\n\n/** Verifies adopter authority and binds it to one exact host invocation. */\nexport class JwtExecutionIdentityVerifier implements ExecutionIdentityVerifier {\n readonly #config: Readonly<ParsedConfig>;\n readonly #keyResolver: NonNullable<ExecutionHostJwtVerifierOptions['keyResolver']>;\n readonly #now: () => Date;\n\n constructor(\n config: JwtExecutionIdentityVerifierConfig,\n options: ExecutionHostJwtVerifierOptions = {},\n ) {\n const parsed = parseJwtExecutionIdentityVerifierConfig(config, {\n allowDockerLocalHost: options.allowDockerLocalHost === true,\n });\n this.#config = Object.freeze({\n ...parsed,\n executionJwksUrl: new URL(parsed.executionJwksUrl),\n });\n this.#keyResolver = options.keyResolver\n ?? createJwtKeyResolver(this.#config.executionJwksUrl);\n this.#now = options.now ?? (() => new Date());\n }\n\n async verify(\n rawRequest: ExecutionIdentityVerificationRequest,\n ): Promise<VerifiedExecutionIdentity> {\n try {\n const request = Object.freeze({\n ...rawRequest,\n assertion: AssertionSchema.parse(rawRequest.assertion),\n });\n const { payload } = await jwtVerify(\n request.assertion,\n this.#keyResolver,\n {\n algorithms: [...this.#config.executionJwtAlgorithms],\n audience: this.#config.executionAudience,\n clockTolerance: this.#config.assertionClockToleranceSeconds,\n currentDate: this.#now(),\n issuer: this.#config.executionIssuer,\n maxTokenAge: this.#config.maxAssertionAgeSeconds,\n requiredClaims: ['exp', 'iat', 'jti', 'sub'],\n typ: EXECUTION_ASSERTION_TYPE,\n },\n );\n const claims = ExecutionAssertionClaimsSchema.parse(payload);\n this.#assertRequestBinding(claims, request);\n\n return Object.freeze({\n scope: Object.freeze({\n adopterId: claims.adopterId,\n tenantId: claims.tenantId,\n subjectId: claims.sub,\n productSessionId: claims.productSessionId,\n }),\n runtimeSessionId: claims.runtimeSessionId,\n invocationId: claims.jti,\n workflow: claims.workflow,\n issuedAt: new Date(claims.iat * 1_000).toISOString(),\n expiresAt: new Date(claims.exp * 1_000).toISOString(),\n });\n } catch (error) {\n if (\n error instanceof ExecutionIdentityVerificationError\n || error instanceof ExecutionIdentityUnavailableError\n ) {\n throw error;\n }\n const category = resolveJwtVerificationUnavailableCategory(error);\n if (category) {\n throw new ExecutionIdentityUnavailableError(category, { cause: error });\n }\n throw new ExecutionIdentityVerificationError({ cause: error });\n }\n }\n\n #assertRequestBinding(\n claims: z.infer<typeof ExecutionAssertionClaimsSchema>,\n request: ExecutionIdentityVerificationRequest,\n ): void {\n if (\n claims.adopterId !== this.#config.trustedAdopterId\n || claims.runtimeSessionId !== request.runtimeSessionId\n || claims.jti !== request.invocationId\n || claims.workflow !== request.workflow\n ) {\n throw new ExecutionIdentityVerificationError();\n }\n }\n}\n"]}