@chainlink/cre-sdk 0.0.1-alpha → 0.0.2-alpha

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 (114) hide show
  1. package/dist/generated/capabilities/internal/nodeaction/v1/node_action_pb.d.ts +69 -0
  2. package/dist/generated/capabilities/internal/nodeaction/v1/node_action_pb.js +29 -0
  3. package/dist/generated-sdk/capabilities/blockchain/evm/v1alpha/client_sdk_gen.d.ts +13 -18
  4. package/dist/generated-sdk/capabilities/blockchain/evm/v1alpha/client_sdk_gen.js +71 -260
  5. package/dist/generated-sdk/capabilities/internal/actionandtrigger/v1/basic_sdk_gen.d.ts +4 -9
  6. package/dist/generated-sdk/capabilities/internal/actionandtrigger/v1/basic_sdk_gen.js +14 -45
  7. package/dist/generated-sdk/capabilities/internal/basicaction/v1/basicaction_sdk_gen.d.ts +3 -7
  8. package/dist/generated-sdk/capabilities/internal/basicaction/v1/basicaction_sdk_gen.js +9 -36
  9. package/dist/generated-sdk/capabilities/internal/basictrigger/v1/basic_sdk_gen.d.ts +2 -8
  10. package/dist/generated-sdk/capabilities/internal/basictrigger/v1/basic_sdk_gen.js +8 -21
  11. package/dist/generated-sdk/capabilities/internal/consensus/v1alpha/consensus_sdk_gen.d.ts +5 -8
  12. package/dist/generated-sdk/capabilities/internal/consensus/v1alpha/consensus_sdk_gen.js +16 -60
  13. package/dist/generated-sdk/capabilities/internal/nodeaction/v1/basicaction_sdk_gen.d.ts +19 -0
  14. package/dist/generated-sdk/capabilities/internal/nodeaction/v1/basicaction_sdk_gen.js +36 -0
  15. package/dist/generated-sdk/capabilities/networking/http/v1alpha/client_sdk_gen.d.ts +3 -7
  16. package/dist/generated-sdk/capabilities/networking/http/v1alpha/client_sdk_gen.js +9 -36
  17. package/dist/generated-sdk/capabilities/networking/http/v1alpha/http_sdk_gen.d.ts +2 -8
  18. package/dist/generated-sdk/capabilities/networking/http/v1alpha/http_sdk_gen.js +8 -21
  19. package/dist/generated-sdk/capabilities/scheduler/cron/v1/cron_sdk_gen.d.ts +2 -8
  20. package/dist/generated-sdk/capabilities/scheduler/cron/v1/cron_sdk_gen.js +8 -21
  21. package/dist/index.d.ts +1 -0
  22. package/dist/index.js +1 -0
  23. package/dist/sdk/cre/index.d.ts +5 -19
  24. package/dist/sdk/cre/index.js +1 -17
  25. package/dist/sdk/errors.d.ts +12 -0
  26. package/dist/sdk/errors.js +21 -0
  27. package/dist/sdk/impl/runtime-impl.d.ts +38 -0
  28. package/dist/sdk/impl/runtime-impl.js +190 -0
  29. package/dist/sdk/impl/runtime-impl.test.js +334 -0
  30. package/dist/sdk/index.d.ts +3 -0
  31. package/dist/sdk/index.js +2 -0
  32. package/dist/sdk/runtime.d.ts +24 -0
  33. package/dist/sdk/utils/capabilities/capability-error.d.ts +0 -3
  34. package/dist/sdk/utils/capabilities/capability-error.js +0 -2
  35. package/dist/sdk/utils/config/configHandler.test.d.ts +1 -0
  36. package/dist/sdk/utils/config/configHandler.test.js +193 -0
  37. package/dist/sdk/utils/config/index.d.ts +4 -6
  38. package/dist/sdk/utils/config/index.js +10 -34
  39. package/dist/sdk/utils/index.d.ts +0 -3
  40. package/dist/sdk/utils/index.js +0 -3
  41. package/dist/sdk/utils/values/consensus_aggregators.d.ts +1 -1
  42. package/dist/sdk/{runtime → wasm}/host-bindings.d.ts +0 -1
  43. package/dist/sdk/{runtime → wasm}/host-bindings.js +0 -4
  44. package/dist/sdk/wasm/index.d.ts +1 -0
  45. package/dist/sdk/wasm/index.js +1 -0
  46. package/dist/sdk/wasm/runner.d.ts +14 -0
  47. package/dist/sdk/wasm/runner.js +114 -0
  48. package/dist/sdk/wasm/runner.test.d.ts +1 -0
  49. package/dist/sdk/wasm/runner.test.js +270 -0
  50. package/dist/sdk/wasm/runtime.d.ts +7 -0
  51. package/dist/sdk/wasm/runtime.js +55 -0
  52. package/dist/sdk/workflow.d.ts +13 -15
  53. package/dist/sdk/workflow.js +1 -21
  54. package/package.json +2 -2
  55. package/dist/sdk/engine/execute.d.ts +0 -4
  56. package/dist/sdk/engine/execute.js +0 -12
  57. package/dist/sdk/engine/execute.test.js +0 -129
  58. package/dist/sdk/engine/handleExecutionPhase.d.ts +0 -4
  59. package/dist/sdk/engine/handleExecutionPhase.js +0 -34
  60. package/dist/sdk/engine/handleSubscribePhase.d.ts +0 -3
  61. package/dist/sdk/engine/handleSubscribePhase.js +0 -23
  62. package/dist/sdk/logger.d.ts +0 -7
  63. package/dist/sdk/logger.js +0 -18
  64. package/dist/sdk/runtime/errors.d.ts +0 -23
  65. package/dist/sdk/runtime/errors.js +0 -30
  66. package/dist/sdk/runtime/index.d.ts +0 -3
  67. package/dist/sdk/runtime/index.js +0 -2
  68. package/dist/sdk/runtime/run-in-node-mode.d.ts +0 -12
  69. package/dist/sdk/runtime/run-in-node-mode.js +0 -47
  70. package/dist/sdk/runtime/run-in-node-mode.test.js +0 -116
  71. package/dist/sdk/runtime/runtime.d.ts +0 -36
  72. package/dist/sdk/runtime/runtime.js +0 -84
  73. package/dist/sdk/runtime/runtime.test.d.ts +0 -1
  74. package/dist/sdk/runtime/runtime.test.js +0 -58
  75. package/dist/sdk/testhelpers/dangerously-call-capability.d.ts +0 -10
  76. package/dist/sdk/testhelpers/dangerously-call-capability.js +0 -26
  77. package/dist/sdk/testhelpers/mock-host-bindings.d.ts +0 -15
  78. package/dist/sdk/testhelpers/mock-host-bindings.js +0 -25
  79. package/dist/sdk/testhelpers/mock-runtime.d.ts +0 -2
  80. package/dist/sdk/testhelpers/mock-runtime.js +0 -16
  81. package/dist/sdk/utils/await-async-request.d.ts +0 -9
  82. package/dist/sdk/utils/await-async-request.js +0 -27
  83. package/dist/sdk/utils/capabilities/call-capability.d.ts +0 -22
  84. package/dist/sdk/utils/capabilities/call-capability.js +0 -33
  85. package/dist/sdk/utils/capabilities/callback-id.d.ts +0 -3
  86. package/dist/sdk/utils/capabilities/callback-id.js +0 -22
  87. package/dist/sdk/utils/capabilities/http/fetch.d.ts +0 -44
  88. package/dist/sdk/utils/capabilities/http/fetch.js +0 -63
  89. package/dist/sdk/utils/do-request-async.d.ts +0 -12
  90. package/dist/sdk/utils/do-request-async.js +0 -17
  91. package/dist/sdk/utils/error-boundary.d.ts +0 -2
  92. package/dist/sdk/utils/error-boundary.js +0 -30
  93. package/dist/sdk/utils/get-request.d.ts +0 -1
  94. package/dist/sdk/utils/get-request.js +0 -15
  95. package/dist/sdk/utils/lazy-promise.d.ts +0 -59
  96. package/dist/sdk/utils/lazy-promise.js +0 -81
  97. package/dist/sdk/utils/random/get-rand.d.ts +0 -3
  98. package/dist/sdk/utils/random/get-rand.js +0 -6
  99. package/dist/sdk/utils/random/random.d.ts +0 -35
  100. package/dist/sdk/utils/random/random.js +0 -123
  101. package/dist/sdk/utils/secrets/await-async-secret.d.ts +0 -1
  102. package/dist/sdk/utils/secrets/await-async-secret.js +0 -29
  103. package/dist/sdk/utils/secrets/do-get-secret.d.ts +0 -1
  104. package/dist/sdk/utils/secrets/do-get-secret.js +0 -14
  105. package/dist/sdk/utils/secrets/get-secret.d.ts +0 -1
  106. package/dist/sdk/utils/secrets/get-secret.js +0 -10
  107. package/dist/sdk/utils/send-error.d.ts +0 -1
  108. package/dist/sdk/utils/send-error.js +0 -16
  109. package/dist/sdk/utils/send-response-value.d.ts +0 -2
  110. package/dist/sdk/utils/send-response-value.js +0 -15
  111. package/dist/sdk/utils/time/get-time.d.ts +0 -16
  112. package/dist/sdk/utils/time/get-time.js +0 -21
  113. /package/dist/sdk/{engine/execute.test.d.ts → impl/runtime-impl.test.d.ts} +0 -0
  114. /package/dist/sdk/{runtime/run-in-node-mode.test.d.ts → runtime.js} +0 -0
@@ -1,129 +0,0 @@
1
- import { describe, expect, mock, test } from 'bun:test';
2
- import { create, fromBinary, toBinary } from '@bufbuild/protobuf';
3
- import { EmptySchema } from '@bufbuild/protobuf/wkt';
4
- import { TriggerEventSchema as ActionTriggerEventSchema } from '../../generated/capabilities/internal/actionandtrigger/v1/action_and_trigger_pb';
5
- import { OutputsSchema as BasicTriggerOutputsSchema } from '../../generated/capabilities/internal/basictrigger/v1/basic_trigger_pb';
6
- import { ExecuteRequestSchema, ExecutionResultSchema, } from '../../generated/sdk/v1alpha/sdk_pb';
7
- import { BasicCapability as ActionAndTriggerCapability } from '../../generated-sdk/capabilities/internal/actionandtrigger/v1/basic_sdk_gen';
8
- import { BasicCapability as BasicTriggerCapability } from '../../generated-sdk/capabilities/internal/basictrigger/v1/basic_sdk_gen';
9
- import { handleExecuteRequest } from './execute';
10
- import { mockHostBindings } from '../testhelpers/mock-host-bindings';
11
- import { mockedRuntime } from '../testhelpers/mock-runtime';
12
- import { getTypeUrl } from '../utils/typeurl';
13
- import { handler } from '../workflow';
14
- const emptyConfig = {};
15
- const decodeExecutionResult = (result) => fromBinary(ExecutionResultSchema, result);
16
- describe('engine/execute', () => {
17
- test('subscribe returns TriggerSubscriptionRequest wrapped in ExecutionResult', async () => {
18
- const subs = [];
19
- // mock sendResponse to capture the payload
20
- mockHostBindings.sendResponse.mockImplementation((resp) => {
21
- const exec = decodeExecutionResult(resp);
22
- const ts = exec.result.case === 'triggerSubscriptions' ? exec.result.value : undefined;
23
- expect(ts).toBeDefined();
24
- expect(ts.subscriptions.length).toBe(3);
25
- ts.subscriptions.forEach((s) => subs.push(`${s.id}:${s.method}:${s.payload?.typeUrl}`));
26
- return 0;
27
- });
28
- const basic = new BasicTriggerCapability();
29
- const action = new ActionAndTriggerCapability();
30
- const workflow = [
31
- handler(basic.trigger({ name: 'first-trigger', number: 100 }), () => { }),
32
- handler(action.trigger({ name: 'second-trigger', number: 150 }), () => { }),
33
- handler(basic.trigger({ name: 'third-trigger', number: 200 }), () => { }),
34
- ];
35
- const req = create(ExecuteRequestSchema, {
36
- config: new Uint8Array(),
37
- request: { case: 'subscribe', value: create(EmptySchema) },
38
- maxResponseSize: 0n,
39
- });
40
- await handleExecuteRequest(req, workflow, emptyConfig, mockedRuntime);
41
- expect(subs[0]).toContain('basic-test-trigger@1.0.0:Trigger:type.googleapis.com/capabilities.internal.basictrigger.v1.Config');
42
- expect(subs[1]).toContain('basic-test-action-trigger@1.0.0:Trigger:type.googleapis.com/capabilities.internal.actionandtrigger.v1.Config');
43
- expect(subs[2]).toContain('basic-test-trigger@1.0.0:Trigger:type.googleapis.com/capabilities.internal.basictrigger.v1.Config');
44
- mockHostBindings.sendResponse.mockRestore();
45
- });
46
- test('trigger routes by id and decodes payload for correct handler', async () => {
47
- const calls = [];
48
- const basic = new BasicTriggerCapability();
49
- const action = new ActionAndTriggerCapability();
50
- const workflow = [
51
- handler(basic.trigger({ name: 'first-trigger', number: 100 }), (_e, _r, out) => {
52
- // @ts-ignore
53
- calls.push(`basic:${out.coolOutput}`);
54
- }),
55
- handler(action.trigger({ name: 'second-trigger', number: 150 }), (_e, _r, out) => {
56
- // @ts-ignore
57
- calls.push(`action:${out.coolOutput}`);
58
- }),
59
- handler(basic.trigger({ name: 'third-trigger', number: 200 }), (_e, _r, out) => {
60
- // @ts-ignore
61
- calls.push(`basic2:${out.coolOutput}`);
62
- }),
63
- ];
64
- // Build ExecuteRequest with id=1 (second handler) and payload of Action TriggerEvent
65
- const payloadAny = {
66
- typeUrl: getTypeUrl(ActionTriggerEventSchema),
67
- value: toBinary(ActionTriggerEventSchema, create(ActionTriggerEventSchema, { coolOutput: 'different' })),
68
- };
69
- const req = create(ExecuteRequestSchema, {
70
- config: new Uint8Array(),
71
- request: {
72
- case: 'trigger',
73
- value: { id: 1n, payload: payloadAny },
74
- },
75
- maxResponseSize: 0n,
76
- });
77
- await handleExecuteRequest(req, workflow, emptyConfig, mockedRuntime);
78
- expect(calls).toEqual(['action:different']);
79
- });
80
- test('trigger ignores out-of-range id (no handler invoked)', async () => {
81
- const calls = [];
82
- const basic = new BasicTriggerCapability();
83
- const action = new ActionAndTriggerCapability();
84
- const workflow = [
85
- handler(basic.trigger({ name: 'first-trigger', number: 100 }), () => {
86
- calls.push('basic');
87
- }),
88
- handler(action.trigger({ name: 'second-trigger', number: 150 }), () => {
89
- calls.push('action');
90
- }),
91
- ];
92
- const payloadAny = {
93
- typeUrl: getTypeUrl(ActionTriggerEventSchema),
94
- value: toBinary(ActionTriggerEventSchema, create(ActionTriggerEventSchema, { coolOutput: 'x' })),
95
- };
96
- const req = create(ExecuteRequestSchema, {
97
- config: new Uint8Array(),
98
- request: { case: 'trigger', value: { id: 999n, payload: payloadAny } },
99
- maxResponseSize: 0n,
100
- });
101
- await handleExecuteRequest(req, workflow, emptyConfig, mockedRuntime);
102
- expect(calls).toEqual([]);
103
- });
104
- test('trigger ignores typeUrl mismatch for targeted handler', async () => {
105
- const calls = [];
106
- const basic = new BasicTriggerCapability();
107
- const action = new ActionAndTriggerCapability();
108
- const workflow = [
109
- handler(basic.trigger({ name: 'first-trigger', number: 100 }), () => {
110
- calls.push('basic');
111
- }),
112
- handler(action.trigger({ name: 'second-trigger', number: 150 }), () => {
113
- calls.push('action');
114
- }),
115
- ];
116
- // Intentionally send BasicTriggerOutputs payload to the action trigger handler (index 1)
117
- const payloadAny = {
118
- typeUrl: `type.googleapis.com/${BasicTriggerOutputsSchema.typeName}`,
119
- value: toBinary(BasicTriggerOutputsSchema, create(BasicTriggerOutputsSchema, { coolOutput: 'mismatch' })),
120
- };
121
- const req = create(ExecuteRequestSchema, {
122
- config: new Uint8Array(),
123
- request: { case: 'trigger', value: { id: 1n, payload: payloadAny } },
124
- maxResponseSize: 0n,
125
- });
126
- await handleExecuteRequest(req, workflow, emptyConfig, mockedRuntime);
127
- expect(calls).toEqual([]);
128
- });
129
- });
@@ -1,4 +0,0 @@
1
- import type { CapabilityResponse, ExecuteRequest } from '../../generated/sdk/v1alpha/sdk_pb';
2
- import type { Runtime } from '../runtime/runtime';
3
- import type { Workflow } from '../workflow';
4
- export declare const handleExecutionPhase: <TConfig>(req: ExecuteRequest, workflow: Workflow<TConfig>, config: TConfig, runtime: Runtime) => Promise<CapabilityResponse | undefined>;
@@ -1,34 +0,0 @@
1
- import { fromBinary } from '@bufbuild/protobuf';
2
- import { getTypeUrl } from '../utils/typeurl';
3
- export const handleExecutionPhase = async (req, workflow, config, runtime) => {
4
- if (req.request.case !== 'trigger') {
5
- return;
6
- }
7
- const triggerMsg = req.request.value;
8
- const index = Number(triggerMsg.id);
9
- if (Number.isFinite(index) && index >= 0 && index < workflow.length) {
10
- const entry = workflow[index];
11
- const schema = entry.trigger.outputSchema();
12
- const payloadAny = triggerMsg.payload;
13
- if (!payloadAny) {
14
- return;
15
- }
16
- // Extra safety: verify payload typeUrl matches expected schema type
17
- const expectedTypeUrl = getTypeUrl(schema);
18
- if (payloadAny.typeUrl && payloadAny.typeUrl !== expectedTypeUrl) {
19
- return;
20
- }
21
- /**
22
- * Note: do not hardcode method name; routing by id is authoritative.
23
- *
24
- * This matches the GO SDK behavior, which also just checks for the id.
25
- *
26
- * @see https://github.com/smartcontractkit/cre-sdk-go/blob/5a41d81e3e072008484e85dc96d746401aafcba2/cre/wasm/runner.go#L81
27
- * */
28
- const decoded = fromBinary(schema, payloadAny.value);
29
- const adapted = await entry.trigger.adapt(decoded);
30
- // By default config is a JSON string, send as bytes
31
- const handlerEnv = config || JSON.parse(Buffer.from(req.config).toString());
32
- await entry.fn(handlerEnv, runtime, adapted);
33
- }
34
- };
@@ -1,3 +0,0 @@
1
- import type { ExecuteRequest } from '../../generated/sdk/v1alpha/sdk_pb';
2
- import type { Workflow } from '../workflow';
3
- export declare const handleSubscribePhase: <TConfig>(req: ExecuteRequest, workflow: Workflow<TConfig>) => undefined;
@@ -1,23 +0,0 @@
1
- import { create, toBinary } from '@bufbuild/protobuf';
2
- import { ExecutionResultSchema, TriggerSubscriptionRequestSchema, } from '../../generated/sdk/v1alpha/sdk_pb';
3
- import { hostBindings } from '../runtime/host-bindings';
4
- export const handleSubscribePhase = (req, workflow) => {
5
- if (req.request.case !== 'subscribe') {
6
- return;
7
- }
8
- // Build TriggerSubscriptionRequest from the workflow entries
9
- const subscriptions = workflow.map((entry) => ({
10
- id: entry.trigger.capabilityId(),
11
- method: entry.trigger.method(),
12
- payload: entry.trigger.configAsAny(),
13
- }));
14
- const subscriptionRequest = create(TriggerSubscriptionRequestSchema, {
15
- subscriptions,
16
- });
17
- // Wrap in ExecutionResult.triggerSubscriptions
18
- const execResult = create(ExecutionResultSchema, {
19
- result: { case: 'triggerSubscriptions', value: subscriptionRequest },
20
- });
21
- const encoded = toBinary(ExecutionResultSchema, execResult);
22
- hostBindings.sendResponse(encoded);
23
- };
@@ -1,7 +0,0 @@
1
- export type Logger = {
2
- log: (message: string) => void;
3
- info: (message: string) => void;
4
- error: (message: string) => void;
5
- warn: (message: string) => void;
6
- };
7
- export declare const logger: Logger;
@@ -1,18 +0,0 @@
1
- export const logger = {
2
- log: (message) => {
3
- console.log(message);
4
- log(message);
5
- },
6
- info: (message) => {
7
- console.info(message);
8
- log(message);
9
- },
10
- error: (message) => {
11
- console.error(message);
12
- log(message);
13
- },
14
- warn: (message) => {
15
- console.warn(message);
16
- log(message);
17
- },
18
- };
@@ -1,23 +0,0 @@
1
- import type { Mode } from '../../generated/sdk/v1alpha/sdk_pb';
2
- export declare class DonModeError extends Error {
3
- name: string;
4
- capabilityId?: string;
5
- method?: string;
6
- mode?: Mode;
7
- constructor(message?: string, options?: {
8
- capabilityId?: string;
9
- method?: string;
10
- mode?: Mode;
11
- });
12
- }
13
- export declare class NodeModeError extends Error {
14
- name: string;
15
- capabilityId?: string;
16
- method?: string;
17
- mode?: Mode;
18
- constructor(message?: string, options?: {
19
- capabilityId?: string;
20
- method?: string;
21
- mode?: Mode;
22
- });
23
- }
@@ -1,30 +0,0 @@
1
- export class DonModeError extends Error {
2
- name;
3
- capabilityId;
4
- method;
5
- mode;
6
- constructor(message = 'cannot use Runtime inside RunInNodeMode', options) {
7
- super(message);
8
- this.name = 'DonModeError';
9
- if (options) {
10
- this.capabilityId = options.capabilityId;
11
- this.method = options.method;
12
- this.mode = options.mode;
13
- }
14
- }
15
- }
16
- export class NodeModeError extends Error {
17
- name;
18
- capabilityId;
19
- method;
20
- mode;
21
- constructor(message = 'cannot use NodeRuntime outside RunInNodeMode', options) {
22
- super(message);
23
- this.name = 'NodeModeError';
24
- if (options) {
25
- this.capabilityId = options.capabilityId;
26
- this.method = options.method;
27
- this.mode = options.mode;
28
- }
29
- }
30
- }
@@ -1,3 +0,0 @@
1
- export { runInNodeMode } from './run-in-node-mode';
2
- export type * from './runtime';
3
- export * from './runtime';
@@ -1,2 +0,0 @@
1
- export { runInNodeMode } from './run-in-node-mode';
2
- export * from './runtime';
@@ -1,12 +0,0 @@
1
- import { type NodeRuntime } from './runtime';
2
- import type { ConsensusAggregation, PrimitiveTypes, UnwrapOptions } from '../utils';
3
- /**
4
- * Runs the provided builder inside Node mode and returns the consensus result Value.
5
- * Ensures mode is switched back to DON even if errors occur.
6
- */
7
- /**
8
- * Runs the provided builder inside Node mode and returns the consensus result Value.
9
- * For primitive types (number, bigint, Date, boolean, string), it will use unwrap()
10
- * For complex types, it will use unwrapToType() with the provided options
11
- */
12
- export declare function runInNodeMode<TArgs extends any[], TOutput>(fn: (nodeRuntime: NodeRuntime, ...args: TArgs) => Promise<TOutput> | TOutput, consesusAggretation: ConsensusAggregation<TOutput, true>, unwrapOptions?: TOutput extends PrimitiveTypes ? never : UnwrapOptions<TOutput>): (...args: TArgs) => Promise<TOutput>;
@@ -1,47 +0,0 @@
1
- import { create } from '@bufbuild/protobuf';
2
- import { Mode, SimpleConsensusInputsSchema } from '../../generated/sdk/v1alpha/sdk_pb';
3
- import { ConsensusCapability } from '../../generated-sdk/capabilities/internal/consensus/v1alpha/consensus_sdk_gen';
4
- import { runtime } from './runtime';
5
- import { Value } from '../utils';
6
- /**
7
- * Runs the provided builder inside Node mode and returns the consensus result Value.
8
- * Ensures mode is switched back to DON even if errors occur.
9
- */
10
- /**
11
- * Runs the provided builder inside Node mode and returns the consensus result Value.
12
- * For primitive types (number, bigint, Date, boolean, string), it will use unwrap()
13
- * For complex types, it will use unwrapToType() with the provided options
14
- */
15
- export function runInNodeMode(fn, consesusAggretation, unwrapOptions) {
16
- return async (...args) => {
17
- const nodeRuntime = runtime.switchModes(Mode.NODE);
18
- const consensusInput = create(SimpleConsensusInputsSchema, {
19
- descriptors: consesusAggretation.descriptor,
20
- });
21
- if (consesusAggretation.defaultValue) {
22
- // This cast is safe, since ConsensusAggregation can only have true its second argument if T extends CreSerializable<TOutput>
23
- consensusInput.default = Value.from(consesusAggretation.defaultValue).proto();
24
- }
25
- try {
26
- const observation = await fn(nodeRuntime, ...args);
27
- // This cast is safe, since ConsensusAggregation can only have true its second argument if T extends CreSerializable<TOutput>
28
- consensusInput.observation = {
29
- case: 'value',
30
- value: Value.from(observation).proto(),
31
- };
32
- }
33
- catch (e) {
34
- consensusInput.observation = { case: 'error', value: e.message || String(e) };
35
- }
36
- finally {
37
- // Always restore DON mode before invoking consensus
38
- runtime.switchModes(Mode.DON);
39
- }
40
- const consensus = new ConsensusCapability();
41
- const result = await consensus.simple(consensusInput).result();
42
- const wrappedValue = Value.wrap(result);
43
- return unwrapOptions
44
- ? wrappedValue.unwrapToType(unwrapOptions)
45
- : wrappedValue.unwrap();
46
- };
47
- }
@@ -1,116 +0,0 @@
1
- import { describe, expect, mock, test } from 'bun:test';
2
- import { create } from '@bufbuild/protobuf';
3
- import { AggregationType, ConsensusDescriptorSchema, } from '../../generated/sdk/v1alpha/sdk_pb';
4
- import { BasicActionCapability } from '../../generated-sdk/capabilities/internal/basicaction/v1/basicaction_sdk_gen';
5
- import { ConsensusCapability } from '../../generated-sdk/capabilities/internal/consensus/v1alpha/consensus_sdk_gen';
6
- import { runInNodeMode } from './run-in-node-mode';
7
- // Mock the host bindings before importing runtime
8
- import { calls } from '../testhelpers/mock-host-bindings';
9
- import { consensusIdenticalAggregation, consensusMedianAggregation, Value } from '../utils';
10
- function expectObservation(i) {
11
- expect(i.observation.case).toEqual('value');
12
- return Value.wrap(i.observation.value);
13
- }
14
- function expectError(i) {
15
- expect(i.observation.case).toEqual('error');
16
- return i.observation.value;
17
- }
18
- describe('runInNodeMode', () => {
19
- test('successful run', async () => {
20
- // Clear the calls array for this test
21
- calls.length = 0;
22
- const anyObservation = 120;
23
- const anyResult = 123;
24
- // spy on consensus.simple
25
- const origSimple = ConsensusCapability.prototype.simple;
26
- ConsensusCapability.prototype.simple = mock((inputs) => {
27
- calls.push('CONSENSUS_SIMPLE');
28
- // biome-ignore lint/suspicious/noExplicitAny: Needed for runtime type checking of protocol buffer messages
29
- expect(inputs.$typeName).toBeDefined();
30
- const castedInputs = inputs;
31
- expect(castedInputs.default).toBeUndefined();
32
- const actualObservation = expectObservation(castedInputs);
33
- expect(Value.from(anyObservation)).toEqual(actualObservation);
34
- const expectedDescriptor = create(ConsensusDescriptorSchema, {
35
- descriptor: {
36
- case: 'aggregation',
37
- value: AggregationType.MEDIAN,
38
- },
39
- });
40
- expect(castedInputs.descriptors).toEqual(expectedDescriptor);
41
- return { result: async () => Value.from(anyResult).proto() };
42
- });
43
- const res = await runInNodeMode((_) => anyObservation, consensusMedianAggregation())();
44
- expect(res).toEqual(anyResult);
45
- expect(calls).toEqual(['NODE', 'DON', 'CONSENSUS_SIMPLE']);
46
- // Restore the original method after the test
47
- ConsensusCapability.prototype.simple = origSimple;
48
- });
49
- test('local failure with consensus', async () => {
50
- // Clear the calls array for this test
51
- calls.length = 0;
52
- const anyError = Error('nope');
53
- const anyResult = 123;
54
- // spy on consensus.simple
55
- const origSimple = ConsensusCapability.prototype.simple;
56
- ConsensusCapability.prototype.simple = mock((inputs) => {
57
- calls.push('CONSENSUS_SIMPLE');
58
- // biome-ignore lint/suspicious/noExplicitAny: Needed for runtime type checking of protocol buffer messages
59
- expect(inputs.$typeName).toBeDefined();
60
- const castedInputs = inputs;
61
- expect(castedInputs.default).toBeUndefined();
62
- const actualError = expectError(castedInputs);
63
- expect(anyError.message).toEqual(actualError);
64
- const expectedDescriptor = create(ConsensusDescriptorSchema, {
65
- descriptor: {
66
- case: 'aggregation',
67
- value: AggregationType.MEDIAN,
68
- },
69
- });
70
- expect(castedInputs.descriptors).toEqual(expectedDescriptor);
71
- return { result: async () => Value.from(anyResult).proto() };
72
- });
73
- const errFn = (_) => {
74
- throw anyError;
75
- };
76
- const res = await runInNodeMode(errFn, consensusMedianAggregation())();
77
- expect(res).toEqual(anyResult);
78
- expect(calls).toEqual(['NODE', 'DON', 'CONSENSUS_SIMPLE']);
79
- // Restore the original method after the test
80
- ConsensusCapability.prototype.simple = origSimple;
81
- });
82
- test('guards DON calls while in node mode, also local and consensus failure', async () => {
83
- // Simulate switchModes by touching global function used by host
84
- const origSwitch = globalThis.switchModes;
85
- globalThis.switchModes = (_m) => { };
86
- // spy on consensus.simple
87
- const origSimple = ConsensusCapability.prototype.simple;
88
- ConsensusCapability.prototype.simple = mock((inputs) => {
89
- calls.push('CONSENSUS_SIMPLE');
90
- // biome-ignore lint/suspicious/noExplicitAny: Needed for runtime type checking of protocol buffer messages
91
- expect(inputs.$typeName).toBeDefined();
92
- const castedInputs = inputs;
93
- expect(castedInputs.default).toBeUndefined();
94
- const actualError = expectError(castedInputs);
95
- expect(actualError).toContain('cannot use Runtime inside RunInNodeMode.');
96
- const expectedDescriptor = create(ConsensusDescriptorSchema, {
97
- descriptor: {
98
- case: 'aggregation',
99
- value: AggregationType.IDENTICAL,
100
- },
101
- });
102
- expect(castedInputs.descriptors).toEqual(expectedDescriptor);
103
- throw Error(actualError);
104
- });
105
- expect(async () => {
106
- await runInNodeMode(async (_) => {
107
- const ba = new BasicActionCapability();
108
- const result = await ba.performAction({ inputThing: true }).result();
109
- return result.adaptedThing;
110
- }, consensusIdenticalAggregation())();
111
- }).toThrow(/.*cannot use Runtime inside RunInNodeMode.*/);
112
- // Restore the original method and global after the test
113
- ConsensusCapability.prototype.simple = origSimple;
114
- globalThis.switchModes = origSwitch;
115
- });
116
- });
@@ -1,36 +0,0 @@
1
- import { Mode } from '../../generated/sdk/v1alpha/sdk_pb';
2
- import { type Logger } from '../logger';
3
- import type { Rand } from '../utils/random/random';
4
- /**
5
- * Runtime guards are not actually causing / throwing errors.
6
- * They pre-set the errors, depending on the current mode and then
7
- * assert methods are used to check if feature can be called in given mode.
8
- * If not the prepared error will be thrown.
9
- */
10
- export declare const runtimeGuards: {
11
- setMode: (mode: Mode) => void;
12
- assertDonSafe: () => void;
13
- assertNodeSafe: () => void;
14
- getMode: () => Mode;
15
- };
16
- export type BaseRuntime<M extends Mode = Mode> = {
17
- logger: Logger;
18
- mode: M;
19
- assertDonSafe(): asserts this is Runtime;
20
- assertNodeSafe(): asserts this is NodeRuntime;
21
- getRand(): Rand;
22
- now(): Date;
23
- };
24
- export type Runtime = BaseRuntime<Mode.DON> & {
25
- isNodeRuntime: false;
26
- switchModes(mode: Mode.NODE): NodeRuntime;
27
- switchModes(mode: Mode.DON): Runtime;
28
- getSecret(id: string): Promise<any>;
29
- };
30
- export type NodeRuntime = BaseRuntime<Mode.NODE> & {
31
- isNodeRuntime: true;
32
- switchModes(mode: Mode.NODE): NodeRuntime;
33
- switchModes(mode: Mode.DON): Runtime;
34
- };
35
- export declare const runtime: Runtime;
36
- export declare const nodeRuntime: NodeRuntime;
@@ -1,84 +0,0 @@
1
- import { Mode } from '../../generated/sdk/v1alpha/sdk_pb';
2
- import { logger } from '../logger';
3
- import { DonModeError, NodeModeError } from './errors';
4
- import { hostBindings } from './host-bindings';
5
- import { getRand } from '../utils/random/get-rand';
6
- import { getSecret } from '../utils/secrets/get-secret';
7
- import { getTimeAsDate } from '../utils/time/get-time';
8
- /**
9
- * Runtime guards are not actually causing / throwing errors.
10
- * They pre-set the errors, depending on the current mode and then
11
- * assert methods are used to check if feature can be called in given mode.
12
- * If not the prepared error will be thrown.
13
- */
14
- export const runtimeGuards = (() => {
15
- let currentMode = Mode.UNSPECIFIED;
16
- let donModeGuardError = null;
17
- let nodeModeGuardError = new NodeModeError();
18
- const setMode = (mode) => {
19
- currentMode = mode;
20
- if (mode === Mode.NODE) {
21
- // In node mode, forbid DON runtime calls
22
- donModeGuardError = new DonModeError();
23
- nodeModeGuardError = null;
24
- }
25
- else if (mode === Mode.DON) {
26
- // Back in DON mode, forbid node runtime calls
27
- nodeModeGuardError = new NodeModeError();
28
- donModeGuardError = null;
29
- }
30
- else {
31
- donModeGuardError = null;
32
- nodeModeGuardError = null;
33
- }
34
- };
35
- const assertDonSafe = () => {
36
- if (donModeGuardError) {
37
- throw donModeGuardError;
38
- }
39
- };
40
- const assertNodeSafe = () => {
41
- if (nodeModeGuardError) {
42
- throw nodeModeGuardError;
43
- }
44
- };
45
- const getMode = () => currentMode;
46
- return { setMode, assertDonSafe, assertNodeSafe, getMode };
47
- })();
48
- function switchModes(mode) {
49
- // Changing to the same mode should be a noop, we make sure to actually call switching logic if it's different mode
50
- if (mode !== runtimeGuards.getMode()) {
51
- hostBindings.switchModes(mode);
52
- runtimeGuards.setMode(mode);
53
- }
54
- return mode === Mode.NODE ? nodeRuntime : runtime;
55
- }
56
- export const runtime = {
57
- mode: Mode.DON,
58
- isNodeRuntime: false,
59
- logger,
60
- switchModes,
61
- assertDonSafe: () => {
62
- runtimeGuards.assertDonSafe();
63
- },
64
- assertNodeSafe: () => {
65
- runtimeGuards.assertNodeSafe();
66
- },
67
- getSecret,
68
- getRand: () => getRand(Mode.DON),
69
- now: () => getTimeAsDate(),
70
- };
71
- export const nodeRuntime = {
72
- mode: Mode.NODE,
73
- isNodeRuntime: true,
74
- logger,
75
- switchModes,
76
- assertNodeSafe: () => {
77
- runtimeGuards.assertNodeSafe();
78
- },
79
- assertDonSafe: () => {
80
- runtimeGuards.assertDonSafe();
81
- },
82
- getRand: () => getRand(Mode.NODE),
83
- now: () => getTimeAsDate(),
84
- };
@@ -1 +0,0 @@
1
- import '../testhelpers/mock-host-bindings';
@@ -1,58 +0,0 @@
1
- import { beforeEach, describe, expect, test } from 'bun:test';
2
- import { Mode } from '../../generated/sdk/v1alpha/sdk_pb';
3
- // Mock the host bindings before importing runtime
4
- import '../testhelpers/mock-host-bindings';
5
- import { DonModeError, NodeModeError } from './errors';
6
- import { runtime, runtimeGuards } from './runtime';
7
- describe('Handling runtime in TS SDK', () => {
8
- beforeEach(() => {
9
- runtimeGuards.setMode(Mode.DON);
10
- });
11
- test('runtime should be DON by default', () => {
12
- expect(runtime.mode).toBe(Mode.DON);
13
- });
14
- test('switching modes should work', () => {
15
- // Start from DON mode
16
- expect(runtime.isNodeRuntime).toBe(false);
17
- // Switch to NODE mode and verify it works
18
- const nodeRt = runtime.switchModes(Mode.NODE);
19
- expect(nodeRt.isNodeRuntime).toBe(true);
20
- expect(nodeRt.mode).toBe(Mode.NODE);
21
- // Switch back to DON mode and verify it works
22
- const rt = nodeRt.switchModes(Mode.DON);
23
- expect(rt.mode).toBe(Mode.DON);
24
- expect(rt.isNodeRuntime).toBe(false);
25
- });
26
- test('switching modes should be noop when already in that mode', () => {
27
- // By default we are in DON mode, but we call switchModes to confirm that's a noop
28
- const rt = runtime.switchModes(Mode.DON);
29
- expect(rt.mode).toBe(Mode.DON);
30
- expect(rt.isNodeRuntime).toBe(false);
31
- // // Now actually switch to NODE mode
32
- let nodeRuntime = rt.switchModes(Mode.NODE);
33
- expect(nodeRuntime.mode).toBe(Mode.NODE);
34
- expect(nodeRuntime.isNodeRuntime).toBe(true);
35
- // And now switch to Node mode again, make sure it's a noop and the runtime is still in NODE mode.
36
- nodeRuntime = nodeRuntime.switchModes(Mode.NODE);
37
- expect(nodeRuntime.mode).toBe(Mode.NODE);
38
- expect(nodeRuntime.isNodeRuntime).toBe(true);
39
- });
40
- test('assertDonSafe should throw an error if called in NODE mode', () => {
41
- // DON mode is default so asserting DON safe should not throw an error
42
- runtime.assertDonSafe();
43
- // Switch to NODE mode and assert DON safe should throw an error
44
- const nodeRuntime = runtime.switchModes(Mode.NODE);
45
- expect(() => nodeRuntime.assertDonSafe()).toThrow(DonModeError);
46
- // Asserting node safe should not throw however
47
- nodeRuntime.assertNodeSafe();
48
- const rt = nodeRuntime.switchModes(Mode.DON);
49
- expect(() => rt.assertNodeSafe()).toThrow(NodeModeError);
50
- });
51
- test('getSecret is only available in DON mode', () => {
52
- // Casting to any because typescript itself is not letting us do this
53
- const nodeRuntime = runtime.switchModes(Mode.NODE);
54
- expect(nodeRuntime.getSecret).toBeUndefined();
55
- const rt = nodeRuntime.switchModes(Mode.DON);
56
- expect(rt.getSecret).toBeDefined();
57
- });
58
- });