@chainlink/cre-sdk 1.8.0 → 1.10.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 (51) hide show
  1. package/dist/generated/capabilities/blockchain/evm/v1alpha/client_pb.js +1 -1
  2. package/dist/generated/capabilities/blockchain/solana/v1alpha/client_pb.d.ts +268 -0
  3. package/dist/generated/capabilities/blockchain/solana/v1alpha/client_pb.js +90 -0
  4. package/dist/generated/chain-selectors/mainnet/evm/creditcoin-mainnet.d.ts +3 -0
  5. package/dist/generated/chain-selectors/mainnet/evm/creditcoin-mainnet.js +12 -0
  6. package/dist/generated/chain-selectors/mainnet/evm/robinhood-mainnet.d.ts +3 -0
  7. package/dist/generated/chain-selectors/mainnet/evm/robinhood-mainnet.js +12 -0
  8. package/dist/generated/chain-selectors/testnet/evm/creditcoin-testnet.d.ts +3 -0
  9. package/dist/generated/chain-selectors/testnet/evm/creditcoin-testnet.js +12 -0
  10. package/dist/generated/chain-selectors/testnet/evm/private-testnet-rhyolite.d.ts +3 -0
  11. package/dist/generated/chain-selectors/testnet/evm/private-testnet-rhyolite.js +12 -0
  12. package/dist/generated/networks.d.ts +2 -2
  13. package/dist/generated/networks.js +28 -0
  14. package/dist/generated-sdk/capabilities/blockchain/evm/v1alpha/client_sdk_gen.d.ts +10 -12
  15. package/dist/generated-sdk/capabilities/blockchain/evm/v1alpha/client_sdk_gen.js +0 -3
  16. package/dist/generated-sdk/capabilities/blockchain/solana/v1alpha/client_sdk_gen.d.ts +42 -0
  17. package/dist/generated-sdk/capabilities/blockchain/solana/v1alpha/client_sdk_gen.js +82 -0
  18. package/dist/generated-sdk/capabilities/internal/consensus/v1alpha/consensus_sdk_gen.d.ts +3 -2
  19. package/dist/generated-sdk/capabilities/networking/confidentialhttp/v1alpha/client_sdk_gen.d.ts +2 -1
  20. package/dist/generated-sdk/capabilities/networking/http/v1alpha/client_sdk_gen.d.ts +3 -2
  21. package/dist/generated-sdk/capabilities/networking/http/v1alpha/http_sdk_gen.d.ts +2 -1
  22. package/dist/generated-sdk/capabilities/scheduler/cron/v1/cron_sdk_gen.d.ts +2 -1
  23. package/dist/pb.d.ts +1 -0
  24. package/dist/pb.js +1 -0
  25. package/dist/sdk/cre/index.d.ts +4 -0
  26. package/dist/sdk/cre/index.js +5 -0
  27. package/dist/sdk/impl/runtime-impl.d.ts +3 -0
  28. package/dist/sdk/impl/runtime-impl.js +9 -4
  29. package/dist/sdk/index.d.ts +1 -0
  30. package/dist/sdk/index.js +1 -0
  31. package/dist/sdk/test/generated/capabilities/blockchain/solana/v1alpha/solana_mock_gen.d.ts +17 -0
  32. package/dist/sdk/test/generated/capabilities/blockchain/solana/v1alpha/solana_mock_gen.js +53 -0
  33. package/dist/sdk/test/generated/index.d.ts +1 -0
  34. package/dist/sdk/test/generated/index.js +1 -0
  35. package/dist/sdk/testutils/test-runtime.js +9 -1
  36. package/dist/sdk/types/global.d.ts +6 -0
  37. package/dist/sdk/utils/capabilities/blockchain/blockchain-helpers.js +3 -2
  38. package/dist/sdk/utils/capabilities/confidentialhttp/confidential-http-helpers.d.ts +43 -0
  39. package/dist/sdk/utils/capabilities/confidentialhttp/confidential-http-helpers.js +58 -0
  40. package/dist/sdk/utils/capabilities/http/http-helpers.d.ts +20 -6
  41. package/dist/sdk/utils/capabilities/http/http-helpers.js +23 -4
  42. package/dist/sdk/utils/safe-integer.d.ts +8 -0
  43. package/dist/sdk/utils/safe-integer.js +15 -0
  44. package/dist/sdk/utils/types/no-excess.d.ts +32 -0
  45. package/dist/sdk/utils/types/no-excess.js +1 -0
  46. package/dist/sdk/utils/values/value.js +3 -4
  47. package/dist/sdk/wasm/host-bindings.d.ts +39 -0
  48. package/dist/sdk/wasm/host-bindings.js +2 -1
  49. package/dist/sdk/wasm/runtime.js +3 -0
  50. package/package.json +5 -4
  51. package/scripts/src/generate-sdks.ts +6 -0
@@ -5,6 +5,7 @@ import { ConsensusCapability } from '../../generated-sdk/capabilities/internal/c
5
5
  import { Value, } from '../utils';
6
6
  import { CapabilityError } from '../utils/capabilities/capability-error';
7
7
  import { DonModeError, NodeModeError, SecretsError } from '../errors';
8
+ const DEFAULT_SECRET_NAMESPACE = 'main';
8
9
  /**
9
10
  * Base implementation shared by DON and Node runtimes.
10
11
  *
@@ -136,6 +137,9 @@ export class BaseRuntimeImpl {
136
137
  // date is already in milliseconds
137
138
  return new Date(this.helpers.now());
138
139
  }
140
+ sleep(ms) {
141
+ this.helpers.sleep(ms);
142
+ }
139
143
  log(message) {
140
144
  this.helpers.log(message);
141
145
  }
@@ -254,10 +258,10 @@ export class RuntimeImpl extends BaseRuntimeImpl {
254
258
  },
255
259
  };
256
260
  }
257
- // Normalize request (accept both protobuf and JSON formats)
258
- const secretRequest = request.$typeName
259
- ? request
260
- : create(SecretRequestSchema, request);
261
+ const secretRequest = create(SecretRequestSchema, {
262
+ id: request.id,
263
+ namespace: request.namespace || DEFAULT_SECRET_NAMESPACE,
264
+ });
261
265
  // Allocate callback ID and send request
262
266
  const id = this.nextCallId;
263
267
  this.nextCallId++;
@@ -314,6 +318,7 @@ export class RuntimeImpl extends BaseRuntimeImpl {
314
318
  */
315
319
  report(input) {
316
320
  const consensus = new ConsensusCapability();
321
+ // Cast to native overload signature - the impl dispatches on $typeName.
317
322
  const call = consensus.report(this, input);
318
323
  return {
319
324
  result: () => call.result(),
@@ -6,6 +6,7 @@ export type * from './runtime';
6
6
  export * from './runtime';
7
7
  export * from './types/bufbuild-types';
8
8
  export * from './utils';
9
+ export * from './utils/capabilities/confidentialhttp/confidential-http-helpers';
9
10
  export * from './utils/capabilities/http/http-helpers';
10
11
  export * from './wasm';
11
12
  export * from './workflow';
package/dist/sdk/index.js CHANGED
@@ -6,6 +6,7 @@ export * from './runtime';
6
6
  export * from './types/bufbuild-types';
7
7
  export * from './utils';
8
8
  // Export HTTP response helpers
9
+ export * from './utils/capabilities/confidentialhttp/confidential-http-helpers';
9
10
  export * from './utils/capabilities/http/http-helpers';
10
11
  export * from './wasm';
11
12
  export * from './workflow';
@@ -0,0 +1,17 @@
1
+ import { type WriteReportReply, type WriteReportReplyJson, type WriteReportRequest } from '../../../../../../../generated/capabilities/blockchain/solana/v1alpha/client_pb';
2
+ /**
3
+ * Mock for ClientCapability. Use testInstance() to obtain an instance; do not construct directly.
4
+ * Set per-method properties (e.g. performAction) to define return values. If a method is invoked without a handler set, an error is thrown.
5
+ */
6
+ export declare class SolanaMock {
7
+ static readonly CAPABILITY_ID = "solana@1.0.0";
8
+ /** Set to define the return value for WriteReport. May return a plain object (WriteReportReplyJson) or the message type. */
9
+ writeReport?: (input: WriteReportRequest) => WriteReportReply | WriteReportReplyJson;
10
+ private constructor();
11
+ /**
12
+ * Returns the mock instance for this capability and the specified tags.
13
+ * Multiple calls with the same tag values return the same instance.
14
+ * Must be called within the test framework's test() method.
15
+ */
16
+ static testInstance(chainSelector: bigint): SolanaMock;
17
+ }
@@ -0,0 +1,53 @@
1
+ import { fromJson } from '@bufbuild/protobuf';
2
+ import { anyPack, anyUnpack } from '@bufbuild/protobuf/wkt';
3
+ import { WriteReportReplySchema, WriteReportRequestSchema, } from '../../../../../../../generated/capabilities/blockchain/solana/v1alpha/client_pb';
4
+ import { __getTestMockInstance, __setTestMockInstance, registerTestCapability, } from '../../../../../../testutils/test-runtime';
5
+ /**
6
+ * Mock for ClientCapability. Use testInstance() to obtain an instance; do not construct directly.
7
+ * Set per-method properties (e.g. performAction) to define return values. If a method is invoked without a handler set, an error is thrown.
8
+ */
9
+ export class SolanaMock {
10
+ static CAPABILITY_ID = 'solana@1.0.0';
11
+ /** Set to define the return value for WriteReport. May return a plain object (WriteReportReplyJson) or the message type. */
12
+ writeReport;
13
+ constructor(chainSelector) {
14
+ const self = this;
15
+ const qualifiedId = `solana:ChainSelector:${chainSelector}@1.0.0`;
16
+ try {
17
+ registerTestCapability(qualifiedId, (req) => {
18
+ switch (req.method) {
19
+ case 'WriteReport': {
20
+ const input = anyUnpack(req.payload, WriteReportRequestSchema);
21
+ const handler = self.writeReport;
22
+ if (typeof handler !== 'function')
23
+ throw new Error("WriteReport: no implementation provided; set the mock's writeReport property to define the return value.");
24
+ const raw = handler(input);
25
+ const output = raw && typeof raw.$typeName === 'string'
26
+ ? raw
27
+ : fromJson(WriteReportReplySchema, raw);
28
+ return { response: { case: 'payload', value: anyPack(WriteReportReplySchema, output) } };
29
+ }
30
+ default:
31
+ return { response: { case: 'error', value: `unknown method ${req.method}` } };
32
+ }
33
+ });
34
+ }
35
+ catch {
36
+ throw new Error("Capability mocks must be used within the CRE test framework's test() method.");
37
+ }
38
+ }
39
+ /**
40
+ * Returns the mock instance for this capability and the specified tags.
41
+ * Multiple calls with the same tag values return the same instance.
42
+ * Must be called within the test framework's test() method.
43
+ */
44
+ static testInstance(chainSelector) {
45
+ const qualifiedId = `solana:ChainSelector:${chainSelector}@1.0.0`;
46
+ let instance = __getTestMockInstance(qualifiedId);
47
+ if (!instance) {
48
+ instance = new SolanaMock(chainSelector);
49
+ __setTestMockInstance(qualifiedId, instance);
50
+ }
51
+ return instance;
52
+ }
53
+ }
@@ -1,5 +1,6 @@
1
1
  /** Auto-generated barrel of capability mocks. Do not edit. */
2
2
  export { EvmMock } from './capabilities/blockchain/evm/v1alpha/evm_mock_gen';
3
+ export { SolanaMock } from './capabilities/blockchain/solana/v1alpha/solana_mock_gen';
3
4
  export { BasicTestActionTriggerMock } from './capabilities/internal/actionandtrigger/v1/basic_test_action_trigger_mock_gen';
4
5
  export { BasicTestActionMock } from './capabilities/internal/basicaction/v1/basic_test_action_mock_gen';
5
6
  export { ConsensusMock } from './capabilities/internal/consensus/v1alpha/consensus_mock_gen';
@@ -1,5 +1,6 @@
1
1
  /** Auto-generated barrel of capability mocks. Do not edit. */
2
2
  export { EvmMock } from './capabilities/blockchain/evm/v1alpha/evm_mock_gen';
3
+ export { SolanaMock } from './capabilities/blockchain/solana/v1alpha/solana_mock_gen';
3
4
  export { BasicTestActionTriggerMock } from './capabilities/internal/actionandtrigger/v1/basic_test_action_trigger_mock_gen';
4
5
  export { BasicTestActionMock } from './capabilities/internal/basicaction/v1/basic_test_action_mock_gen';
5
6
  export { ConsensusMock } from './capabilities/internal/consensus/v1alpha/consensus_mock_gen';
@@ -143,6 +143,9 @@ function createTestRuntimeHelpers(registry, secrets, testWriter, state, _maxResp
143
143
  function now() {
144
144
  return state.timeProvider ? state.timeProvider() : Date.now();
145
145
  }
146
+ function sleep(ms) {
147
+ return;
148
+ }
146
149
  return {
147
150
  call(request) {
148
151
  const handler = registry.get(request.id);
@@ -232,6 +235,7 @@ function createTestRuntimeHelpers(registry, secrets, testWriter, state, _maxResp
232
235
  },
233
236
  switchModes(_mode) { },
234
237
  now,
238
+ sleep,
235
239
  log(message) {
236
240
  testWriter.log(message);
237
241
  },
@@ -287,7 +291,11 @@ export function newTestRuntime(secrets, options = {}) {
287
291
  const state = {
288
292
  timeProvider: options.timeProvider,
289
293
  };
290
- const maxResponseSize = BigInt(options.maxResponseSize ?? DEFAULT_MAX_RESPONSE_SIZE_BYTES);
294
+ const configuredMaxResponseSize = options.maxResponseSize ?? DEFAULT_MAX_RESPONSE_SIZE_BYTES;
295
+ if (!Number.isSafeInteger(configuredMaxResponseSize) || configuredMaxResponseSize < 0) {
296
+ throw new Error('newTestRuntime maxResponseSize must be a non-negative safe integer number');
297
+ }
298
+ const maxResponseSize = BigInt(configuredMaxResponseSize);
291
299
  const helpers = createTestRuntimeHelpers(registry, secretsMap, testWriter, state, maxResponseSize);
292
300
  return new TestRuntime(helpers, maxResponseSize, testWriter, state);
293
301
  }
@@ -82,6 +82,12 @@ declare global {
82
82
  */
83
83
  function now(): number
84
84
 
85
+ /**
86
+ * Sleeps for the specified duration.
87
+ * @param ms - Duration in milliseconds
88
+ */
89
+ function sleep(ms: number): void
90
+
85
91
  /**
86
92
  * Console API available in the QuickJS runtime
87
93
  */
@@ -2,6 +2,7 @@ import { create, toJson } from '@bufbuild/protobuf';
2
2
  import { BigIntSchema } from '../../../../generated/values/v1/values_pb';
3
3
  import { EVMClient } from '../../../cre';
4
4
  import { bigintToBytes, bytesToBigint, hexToBase64, hexToBytes } from '../../hex-utils';
5
+ import { assertSafeIntegerNumber } from '../../safe-integer';
5
6
  /**
6
7
  * Converts a native JS bigint to a protobuf BigInt JSON representation.
7
8
  * Use this when passing bigint values to SDK methods.
@@ -16,8 +17,8 @@ import { bigintToBytes, bytesToBigint, hexToBase64, hexToBytes } from '../../hex
16
17
  * @returns The protobuf BigInt JSON representation.
17
18
  */
18
19
  export const bigintToProtoBigInt = (n) => {
19
- if (typeof n === 'number' && (!Number.isFinite(n) || !Number.isInteger(n))) {
20
- throw new Error(`bigintToProtoBigInt requires an integer number, received ${n}`);
20
+ if (typeof n === 'number') {
21
+ assertSafeIntegerNumber(n, 'bigintToProtoBigInt');
21
22
  }
22
23
  const val = BigInt(n);
23
24
  const abs = val < 0n ? -val : val;
@@ -0,0 +1,43 @@
1
+ import type { DurationJson } from '@bufbuild/protobuf/wkt';
2
+ import type { HTTPRequestJson as ConfidentialHTTPRequestJson, HeaderValuesJson } from '../../../../generated/capabilities/networking/confidentialhttp/v1alpha/client_pb';
3
+ /**
4
+ * Build an HTTPRequest JSON shape for the confidential-http capability.
5
+ *
6
+ * The proto defines `oneof body { string body_string = 3; bytes body_bytes = 8 }`,
7
+ * so the JSON wire keys are `bodyString` / `bodyBytes` — never plain `body`.
8
+ * Three mutually-exclusive ways to set the body, in order of preference:
9
+ *
10
+ * - `body` ergonomic; coerces by runtime type:
11
+ * - `string` -> bodyString (verbatim)
12
+ * - `Uint8Array` -> bodyBytes (base64)
13
+ * - object -> JSON.stringify -> bodyString
14
+ * (bigints as strings)
15
+ * - `bodyString` pass-through to the canonical proto field
16
+ * - `bodyBytes` `Uint8Array` is base64-encoded; a `string` is treated as
17
+ * already-encoded base64 and passed through verbatim
18
+ *
19
+ * Supplying more than one of these fields throws — the underlying proto is a
20
+ * oneof, so the call would otherwise be ambiguous.
21
+ *
22
+ * Headers can be passed in two ways:
23
+ * - `headers`: flat record with single or repeated values, mapped onto the
24
+ * `multiHeaders` shape under the hood.
25
+ * - `multiHeaders`: native proto shape `{ [name]: { values: string[] } }` —
26
+ * useful when forwarding headers already in canonical form.
27
+ *
28
+ * If both are supplied, `multiHeaders` is applied first and `headers` entries
29
+ * merge on top per-name (replacing the values list for that name).
30
+ */
31
+ export interface HttpRequestOptions {
32
+ url: string;
33
+ method?: string;
34
+ body?: string | Uint8Array | object;
35
+ bodyString?: string;
36
+ bodyBytes?: Uint8Array | string;
37
+ headers?: Record<string, string | string[]>;
38
+ multiHeaders?: Record<string, HeaderValuesJson>;
39
+ templateValues?: Record<string, string>;
40
+ timeout?: DurationJson;
41
+ encryptOutput?: boolean;
42
+ }
43
+ export declare function httpRequest(opts: HttpRequestOptions): ConfidentialHTTPRequestJson;
@@ -0,0 +1,58 @@
1
+ export function httpRequest(opts) {
2
+ const out = {
3
+ url: opts.url,
4
+ method: opts.method ?? 'GET',
5
+ };
6
+ const bodyFieldsSet = (opts.body !== undefined ? 1 : 0) +
7
+ (opts.bodyString !== undefined ? 1 : 0) +
8
+ (opts.bodyBytes !== undefined ? 1 : 0);
9
+ if (bodyFieldsSet > 1) {
10
+ throw new Error('httpRequest: specify the request body using only one of: body, bodyString or bodyBytes');
11
+ }
12
+ if (opts.bodyString !== undefined) {
13
+ out.bodyString = opts.bodyString;
14
+ }
15
+ else if (opts.bodyBytes !== undefined) {
16
+ out.bodyBytes =
17
+ typeof opts.bodyBytes === 'string'
18
+ ? opts.bodyBytes
19
+ : Buffer.from(opts.bodyBytes).toString('base64');
20
+ }
21
+ else if (typeof opts.body === 'string') {
22
+ out.bodyString = opts.body;
23
+ }
24
+ else if (opts.body instanceof Uint8Array) {
25
+ out.bodyBytes = Buffer.from(opts.body).toString('base64');
26
+ }
27
+ else if (opts.body !== undefined) {
28
+ // Compact JSON encoding; bigints serialise as strings.
29
+ try {
30
+ out.bodyString = JSON.stringify(opts.body, (_k, v) => typeof v === 'bigint' ? v.toString() : v);
31
+ }
32
+ catch (cause) {
33
+ throw new Error('httpRequest: failed to serialize body as JSON', {
34
+ cause,
35
+ });
36
+ }
37
+ }
38
+ if (opts.multiHeaders || opts.headers) {
39
+ const merged = {};
40
+ for (const [name, value] of Object.entries(opts.multiHeaders ?? {})) {
41
+ merged[name] = { values: value.values ?? [] };
42
+ }
43
+ for (const [name, value] of Object.entries(opts.headers ?? {})) {
44
+ merged[name] = { values: Array.isArray(value) ? value : [value] };
45
+ }
46
+ out.multiHeaders = merged;
47
+ }
48
+ if (opts.templateValues) {
49
+ out.templatePublicValues = { ...opts.templateValues };
50
+ }
51
+ if (opts.timeout) {
52
+ out.timeout = opts.timeout;
53
+ }
54
+ if (opts.encryptOutput) {
55
+ out.encryptOutput = true;
56
+ }
57
+ return out;
58
+ }
@@ -3,6 +3,7 @@ import type { Request, RequestJson, Response } from '../../../../generated/capab
3
3
  import type { ReportResponse } from '../../../../generated/sdk/v1alpha/sdk_pb';
4
4
  import type { NodeRuntime } from '../../..';
5
5
  import type { Report } from '../../../report';
6
+ type HeaderCapableResponse = Response | ConfidentialHTTPResponse;
6
7
  /**
7
8
  * HTTP Response Helper Functions
8
9
  *
@@ -81,20 +82,32 @@ export declare function json(responseFn: () => {
81
82
  result: () => unknown;
82
83
  };
83
84
  /**
84
- * Gets a specific header value
85
+ * Returns all values for a header (case-insensitive).
86
+ * Reads `multiHeaders` first; falls back to the deprecated single-value `headers` map.
85
87
  * @param response - The Response object
86
88
  * @param name - The header name (case-insensitive)
87
- * @returns The header value or undefined if not found
89
+ * @returns Array of header values; empty if not present
88
90
  */
89
- export declare function getHeader(response: Response, name: string): string | undefined;
91
+ export declare function getHeaders(response: HeaderCapableResponse, name: string): string[];
90
92
  /**
91
- * Gets a specific header value
93
+ * Returns all values for a header (case-insensitive).
94
+ * Reads `multiHeaders` first; falls back to the deprecated single-value `headers` map.
92
95
  * @param responseFn - Function that returns an object with result function that returns Response
93
96
  * @param name - The header name (case-insensitive)
94
- * @returns Object with result function that returns the header value or undefined if not found
97
+ * @returns Object with result function that returns array of header values; empty if not present
95
98
  */
99
+ export declare function getHeaders(responseFn: () => {
100
+ result: HeaderCapableResponse;
101
+ }, name: string): {
102
+ result: () => string[];
103
+ };
104
+ /**
105
+ * Returns a header value (case-insensitive). Multiple values are joined with `, `;
106
+ * use `getHeaders` when boundaries between values must be preserved.
107
+ */
108
+ export declare function getHeader(response: HeaderCapableResponse, name: string): string | undefined;
96
109
  export declare function getHeader(responseFn: () => {
97
- result: Response;
110
+ result: HeaderCapableResponse;
98
111
  }, name: string): {
99
112
  result: () => string | undefined;
100
113
  };
@@ -147,3 +160,4 @@ declare module '../../../../generated-sdk/capabilities/networking/http/v1alpha/c
147
160
  };
148
161
  }
149
162
  }
163
+ export {};
@@ -1,4 +1,10 @@
1
1
  import { decodeJson } from '../../decode-json';
2
+ function findCaseInsensitive(map, name) {
3
+ if (!map)
4
+ return undefined;
5
+ const lowerName = name.toLowerCase();
6
+ return Object.entries(map).find(([key]) => key.toLowerCase() === lowerName)?.[1];
7
+ }
2
8
  export function text(responseOrFn) {
3
9
  if (typeof responseOrFn === 'function') {
4
10
  return {
@@ -18,16 +24,27 @@ export function json(responseOrFn) {
18
24
  }
19
25
  return decodeJson(responseOrFn.body);
20
26
  }
27
+ export function getHeaders(responseOrFn, name) {
28
+ if (typeof responseOrFn === 'function') {
29
+ return {
30
+ result: () => getHeaders(responseOrFn().result, name),
31
+ };
32
+ }
33
+ const multiHeader = findCaseInsensitive(responseOrFn.multiHeaders, name);
34
+ if (multiHeader) {
35
+ return [...multiHeader.values];
36
+ }
37
+ const singleHeader = findCaseInsensitive('headers' in responseOrFn ? responseOrFn.headers : undefined, name);
38
+ return singleHeader === undefined ? [] : [singleHeader];
39
+ }
21
40
  export function getHeader(responseOrFn, name) {
22
41
  if (typeof responseOrFn === 'function') {
23
42
  return {
24
43
  result: () => getHeader(responseOrFn().result, name),
25
44
  };
26
45
  }
27
- else {
28
- const lowerName = name.toLowerCase();
29
- return Object.entries(responseOrFn.headers).find(([key]) => key.toLowerCase() === lowerName)?.[1];
30
- }
46
+ const values = getHeaders(responseOrFn, name);
47
+ return values.length === 0 ? undefined : values.join(', ');
31
48
  }
32
49
  export function ok(responseOrFn) {
33
50
  if (typeof responseOrFn === 'function') {
@@ -56,6 +73,7 @@ export function ok(responseOrFn) {
56
73
  function sendReport(runtime, report, fn) {
57
74
  const rawReport = report.x_generatedCodeOnly_unwrap();
58
75
  const request = fn(rawReport);
76
+ // Cast to native overload signature - the impl dispatches on $typeName.
59
77
  return this.sendRequest(runtime, request);
60
78
  }
61
79
  /**
@@ -71,6 +89,7 @@ function sendReport(runtime, report, fn) {
71
89
  function sendRequesterSendReport(report, fn) {
72
90
  const rawReport = report.x_generatedCodeOnly_unwrap();
73
91
  const request = fn(rawReport);
92
+ // Cast to native overload signature - the impl dispatches on $typeName.
74
93
  return this.sendRequest(request);
75
94
  }
76
95
  // ============================================================================
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Validates that a JS `number` represents a safe integer.
3
+ *
4
+ * The two failure modes are kept distinct so callers can tell apart
5
+ * "not an integer at all" (e.g. `1.5`, `NaN`) from "outside Number's safe
6
+ * integer range" (e.g. `2 ** 54`), which require different remediation.
7
+ */
8
+ export declare function assertSafeIntegerNumber(value: number, label: string): void;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Validates that a JS `number` represents a safe integer.
3
+ *
4
+ * The two failure modes are kept distinct so callers can tell apart
5
+ * "not an integer at all" (e.g. `1.5`, `NaN`) from "outside Number's safe
6
+ * integer range" (e.g. `2 ** 54`), which require different remediation.
7
+ */
8
+ export function assertSafeIntegerNumber(value, label) {
9
+ if (!Number.isFinite(value) || !Number.isInteger(value)) {
10
+ throw new Error(`${label} requires an integer number, received ${value}`);
11
+ }
12
+ if (!Number.isSafeInteger(value)) {
13
+ throw new Error(`${label} requires a safe integer number, received ${value}. Pass a bigint or string for larger values`);
14
+ }
15
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * NoExcess<T, Shape> rejects any property in T whose key is not present in
3
+ * Shape, while preserving the values of allowed properties.
4
+ *
5
+ * Native TS structural typing only triggers excess-property checks on object
6
+ * literals at the call site. Once a request object is bound to a variable
7
+ * its excess keys are tolerated. NoExcess closes that gap by mapping any
8
+ * unknown key to `never`, which fails to assign at the boundary.
9
+ *
10
+ * Recursion stops at:
11
+ * - primitives / Uint8Array / Date (`Shape[K]` not an indexable object), and
12
+ * - index-signature maps (every string key is "known"; nothing is excess).
13
+ *
14
+ * Depth bound is set to 6 to keep the tsc work bounded for nested protos.
15
+ */
16
+ export type NoExcess<T, Shape, Depth extends number = 6> = Depth extends 0 ? T : T extends object ? Shape extends object ? IsIndexed<Shape> extends true ? T : {
17
+ [K in keyof T]: K extends keyof Shape ? NoExcess<T[K], NonNullable<Shape[K]>, Prev<Depth>> : never;
18
+ } : T : T;
19
+ type IsIndexed<T> = string extends keyof T ? true : false;
20
+ type Prev<N extends number> = [-1, 0, 1, 2, 3, 4, 5, 6][N];
21
+ /**
22
+ * Pick the right shape for a capability input.
23
+ *
24
+ * Native protobuf messages carry a `$typeName` brand; JSON shapes do not.
25
+ * If the caller passes a native message we leave it untouched. Otherwise we
26
+ * apply NoExcess against the JSON shape so unknown keys (a stale `body`
27
+ * field, a typo, ...) fail at the call boundary.
28
+ */
29
+ export type CapabilityInput<TInput, Native, Json> = [TInput] extends [{
30
+ $typeName: string;
31
+ }] ? Native : NoExcess<TInput, Json>;
32
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,7 @@
1
1
  import { create } from '@bufbuild/protobuf';
2
2
  import { timestampDate, timestampFromDate } from '@bufbuild/protobuf/wkt';
3
3
  import { BigIntSchema, DecimalSchema, ListSchema, MapSchema, ValueSchema, } from '../../../generated/values/v1/values_pb';
4
+ import { assertSafeIntegerNumber } from '../safe-integer';
4
5
  export class Int64 {
5
6
  // int64 bounds
6
7
  static INT64_MIN = -(2n ** 63n);
@@ -18,8 +19,7 @@ export class Int64 {
18
19
  throw new Error('int64 underflow');
19
20
  return v;
20
21
  }
21
- if (!Number.isFinite(v) || !Number.isInteger(v))
22
- throw new Error('int64 requires an integer number');
22
+ assertSafeIntegerNumber(v, 'int64');
23
23
  const bi = BigInt(v);
24
24
  if (bi > Int64.INT64_MAX)
25
25
  throw new Error('int64 overflow');
@@ -66,8 +66,7 @@ export class UInt64 {
66
66
  throw new Error('uint64 underflow');
67
67
  return v;
68
68
  }
69
- if (!Number.isFinite(v) || !Number.isInteger(v))
70
- throw new Error('uint64 requires an integer number');
69
+ assertSafeIntegerNumber(v, 'uint64');
71
70
  const bi = BigInt(v);
72
71
  if (bi > UInt64.UINT64_MAX)
73
72
  throw new Error('uint64 overflow');
@@ -1,4 +1,42 @@
1
1
  import { Mode } from '../../generated/sdk/v1alpha/sdk_pb';
2
+ import { z } from 'zod';
3
+ export declare const globalHostBindingsSchema: z.ZodObject<{
4
+ switchModes: z.ZodFunction<z.ZodTuple<[z.ZodNativeEnum<typeof Mode>], z.ZodUnknown>, z.ZodVoid>;
5
+ log: z.ZodFunction<z.ZodTuple<[z.ZodString], z.ZodUnknown>, z.ZodVoid>;
6
+ sendResponse: z.ZodFunction<z.ZodTuple<[z.ZodUnion<[z.ZodType<Uint8Array<ArrayBuffer>, z.ZodTypeDef, Uint8Array<ArrayBuffer>>, z.ZodType<Uint8Array<ArrayBufferLike>, z.ZodTypeDef, Uint8Array<ArrayBufferLike>>]>], z.ZodUnknown>, z.ZodNumber>;
7
+ versionV2: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodVoid>;
8
+ callCapability: z.ZodFunction<z.ZodTuple<[z.ZodUnion<[z.ZodType<Uint8Array<ArrayBuffer>, z.ZodTypeDef, Uint8Array<ArrayBuffer>>, z.ZodType<Uint8Array<ArrayBufferLike>, z.ZodTypeDef, Uint8Array<ArrayBufferLike>>]>], z.ZodUnknown>, z.ZodNumber>;
9
+ awaitCapabilities: z.ZodFunction<z.ZodTuple<[z.ZodUnion<[z.ZodType<Uint8Array<ArrayBuffer>, z.ZodTypeDef, Uint8Array<ArrayBuffer>>, z.ZodType<Uint8Array<ArrayBufferLike>, z.ZodTypeDef, Uint8Array<ArrayBufferLike>>]>, z.ZodNumber], z.ZodUnknown>, z.ZodUnion<[z.ZodType<Uint8Array<ArrayBuffer>, z.ZodTypeDef, Uint8Array<ArrayBuffer>>, z.ZodType<Uint8Array<ArrayBufferLike>, z.ZodTypeDef, Uint8Array<ArrayBufferLike>>]>>;
10
+ getSecrets: z.ZodFunction<z.ZodTuple<[z.ZodUnion<[z.ZodType<Uint8Array<ArrayBuffer>, z.ZodTypeDef, Uint8Array<ArrayBuffer>>, z.ZodType<Uint8Array<ArrayBufferLike>, z.ZodTypeDef, Uint8Array<ArrayBufferLike>>]>, z.ZodNumber], z.ZodUnknown>, z.ZodAny>;
11
+ awaitSecrets: z.ZodFunction<z.ZodTuple<[z.ZodUnion<[z.ZodType<Uint8Array<ArrayBuffer>, z.ZodTypeDef, Uint8Array<ArrayBuffer>>, z.ZodType<Uint8Array<ArrayBufferLike>, z.ZodTypeDef, Uint8Array<ArrayBufferLike>>]>, z.ZodNumber], z.ZodUnknown>, z.ZodUnion<[z.ZodType<Uint8Array<ArrayBuffer>, z.ZodTypeDef, Uint8Array<ArrayBuffer>>, z.ZodType<Uint8Array<ArrayBufferLike>, z.ZodTypeDef, Uint8Array<ArrayBufferLike>>]>>;
12
+ getWasiArgs: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodString>;
13
+ now: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodNumber>;
14
+ sleep: z.ZodFunction<z.ZodTuple<[z.ZodNumber], z.ZodUnknown>, z.ZodVoid>;
15
+ }, "strip", z.ZodTypeAny, {
16
+ callCapability: (args_0: Uint8Array<ArrayBufferLike> | Uint8Array<ArrayBuffer>, ...args: unknown[]) => number;
17
+ awaitCapabilities: (args_0: Uint8Array<ArrayBufferLike> | Uint8Array<ArrayBuffer>, args_1: number, ...args: unknown[]) => Uint8Array<ArrayBufferLike> | Uint8Array<ArrayBuffer>;
18
+ getSecrets: (args_0: Uint8Array<ArrayBufferLike> | Uint8Array<ArrayBuffer>, args_1: number, ...args: unknown[]) => any;
19
+ awaitSecrets: (args_0: Uint8Array<ArrayBufferLike> | Uint8Array<ArrayBuffer>, args_1: number, ...args: unknown[]) => Uint8Array<ArrayBufferLike> | Uint8Array<ArrayBuffer>;
20
+ log: (args_0: string, ...args: unknown[]) => void;
21
+ sendResponse: (args_0: Uint8Array<ArrayBufferLike> | Uint8Array<ArrayBuffer>, ...args: unknown[]) => number;
22
+ switchModes: (args_0: Mode, ...args: unknown[]) => void;
23
+ versionV2: (...args: unknown[]) => void;
24
+ getWasiArgs: (...args: unknown[]) => string;
25
+ now: (...args: unknown[]) => number;
26
+ sleep: (args_0: number, ...args: unknown[]) => void;
27
+ }, {
28
+ callCapability: (args_0: Uint8Array<ArrayBufferLike> | Uint8Array<ArrayBuffer>, ...args: unknown[]) => number;
29
+ awaitCapabilities: (args_0: Uint8Array<ArrayBufferLike> | Uint8Array<ArrayBuffer>, args_1: number, ...args: unknown[]) => Uint8Array<ArrayBufferLike> | Uint8Array<ArrayBuffer>;
30
+ getSecrets: (args_0: Uint8Array<ArrayBufferLike> | Uint8Array<ArrayBuffer>, args_1: number, ...args: unknown[]) => any;
31
+ awaitSecrets: (args_0: Uint8Array<ArrayBufferLike> | Uint8Array<ArrayBuffer>, args_1: number, ...args: unknown[]) => Uint8Array<ArrayBufferLike> | Uint8Array<ArrayBuffer>;
32
+ log: (args_0: string, ...args: unknown[]) => void;
33
+ sendResponse: (args_0: Uint8Array<ArrayBufferLike> | Uint8Array<ArrayBuffer>, ...args: unknown[]) => number;
34
+ switchModes: (args_0: Mode, ...args: unknown[]) => void;
35
+ versionV2: (...args: unknown[]) => void;
36
+ getWasiArgs: (...args: unknown[]) => string;
37
+ now: (...args: unknown[]) => number;
38
+ sleep: (args_0: number, ...args: unknown[]) => void;
39
+ }>;
2
40
  export declare const hostBindings: {
3
41
  callCapability: (args_0: Uint8Array<ArrayBufferLike> | Uint8Array<ArrayBuffer>, ...args: unknown[]) => number;
4
42
  awaitCapabilities: (args_0: Uint8Array<ArrayBufferLike> | Uint8Array<ArrayBuffer>, args_1: number, ...args: unknown[]) => Uint8Array<ArrayBufferLike> | Uint8Array<ArrayBuffer>;
@@ -10,4 +48,5 @@ export declare const hostBindings: {
10
48
  versionV2: (...args: unknown[]) => void;
11
49
  getWasiArgs: (...args: unknown[]) => string;
12
50
  now: (...args: unknown[]) => number;
51
+ sleep: (args_0: number, ...args: unknown[]) => void;
13
52
  };
@@ -1,7 +1,7 @@
1
1
  import { Mode } from '../../generated/sdk/v1alpha/sdk_pb';
2
2
  import { z } from 'zod';
3
3
  // Zod schema for validating global host functions
4
- const globalHostBindingsSchema = z.object({
4
+ export const globalHostBindingsSchema = z.object({
5
5
  switchModes: z.function().args(z.nativeEnum(Mode)).returns(z.void()),
6
6
  log: z.function().args(z.string()).returns(z.void()),
7
7
  sendResponse: z
@@ -27,6 +27,7 @@ const globalHostBindingsSchema = z.object({
27
27
  .returns(z.union([z.instanceof(Uint8Array), z.custom()])),
28
28
  getWasiArgs: z.function().args().returns(z.string()),
29
29
  now: z.function().args().returns(z.number()),
30
+ sleep: z.function().args(z.number()).returns(z.void()),
30
31
  });
31
32
  // Validate global host functions at runtime
32
33
  const validateGlobalHostBindings = () => {
@@ -25,6 +25,9 @@ class WasmRuntimeHelpers {
25
25
  now() {
26
26
  return hostBindings.now();
27
27
  }
28
+ sleep(ms) {
29
+ hostBindings.sleep(ms);
30
+ }
28
31
  static getInstance() {
29
32
  if (!WasmRuntimeHelpers.instance) {
30
33
  WasmRuntimeHelpers.instance = new WasmRuntimeHelpers();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chainlink/cre-sdk",
3
- "version": "1.8.0",
3
+ "version": "1.10.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -55,12 +55,13 @@
55
55
  "prepublishOnly": "bun typecheck && bun check && bun test && bun test:standard",
56
56
  "test": "bun test",
57
57
  "test:standard": "./scripts/run-standard-tests.sh",
58
- "typecheck": "tsc -p tsconfig.json --noEmit"
58
+ "typecheck": "tsc -p tsconfig.json --noEmit",
59
+ "update-api-baseline": "bun run compile:build && cat dist/index.d.ts dist/pb.d.ts dist/sdk/index.d.ts dist/sdk/runtime.d.ts dist/sdk/workflow.d.ts dist/sdk/errors.d.ts dist/sdk/report.d.ts dist/sdk/test/index.d.ts > api-baseline.d.ts"
59
60
  },
60
61
  "dependencies": {
61
62
  "@bufbuild/protobuf": "2.6.3",
62
63
  "@bufbuild/protoc-gen-es": "2.6.3",
63
- "@chainlink/cre-sdk-javy-plugin": "1.6.0",
64
+ "@chainlink/cre-sdk-javy-plugin": "1.7.0",
64
65
  "@standard-schema/spec": "1.0.0",
65
66
  "viem": "2.34.0",
66
67
  "zod": "3.25.76"
@@ -69,7 +70,7 @@
69
70
  "@biomejs/biome": "2.3.14",
70
71
  "@bufbuild/buf": "1.56.0",
71
72
  "@types/bun": "1.3.8",
72
- "chain-selectors": "https://github.com/smartcontractkit/chain-selectors.git#a86ae261a09f805ea37165f58b017b4538e2e3bb",
73
+ "chain-selectors": "https://github.com/smartcontractkit/chain-selectors.git#116ebbce88b36d4e76a03c12b3437ed33a5f9860",
73
74
  "fast-glob": "3.3.3",
74
75
  "ts-proto": "2.7.5",
75
76
  "typescript": "5.9.3",