@codemation/node-example 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,23 @@
1
+ # `@codemation/node-example`
2
+
3
+ A **minimal example node package**: shows how to ship a custom node (config + implementation) that depends only on `@codemation/core`. The monorepo uses it in tests and as a template for **community or private node packages**.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pnpm add @codemation/node-example@^0.0.0
9
+ # or
10
+ npm install @codemation/node-example@^0.0.0
11
+ ```
12
+
13
+ ## When to use
14
+
15
+ Reference or copy this package when you author a new **`node-*`** package. Adding a real node package should not require changes inside `@codemation/core`.
16
+
17
+ ## Usage
18
+
19
+ ```ts
20
+ import { ExampleUppercase, ExampleUppercaseNode } from "@codemation/node-example";
21
+ ```
22
+
23
+ Inspect `src/` for the uppercase sample node pattern, then replace it with your own `NodeConfigBase` and `Node` classes and export them from your package’s public entry.
@@ -0,0 +1,25 @@
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
23
+
24
+ //#endregion
25
+ export { };
package/dist/index.cjs ADDED
@@ -0,0 +1,79 @@
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+
23
+ //#endregion
24
+ let __codemation_core = require("@codemation/core");
25
+ __codemation_core = __toESM(__codemation_core);
26
+
27
+ //#region \0@oxc-project+runtime@0.95.0/helpers/decorate.js
28
+ function __decorate(decorators, target, key, desc) {
29
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
30
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
31
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
32
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
33
+ }
34
+
35
+ //#endregion
36
+ //#region src/ExampleUppercaseNode.ts
37
+ let ExampleUppercaseNode = class ExampleUppercaseNode$1 {
38
+ kind = "node";
39
+ outputPorts = ["main"];
40
+ async execute(items, ctx) {
41
+ const out = [];
42
+ for (let i = 0; i < items.length; i++) {
43
+ const item = items[i];
44
+ const json = typeof item.json === "object" && item.json !== null ? item.json : {};
45
+ const value = String(json[ctx.config.cfg.field] ?? "");
46
+ out.push({
47
+ ...item,
48
+ json: {
49
+ ...json,
50
+ [ctx.config.cfg.field]: value.toUpperCase()
51
+ }
52
+ });
53
+ }
54
+ return { main: out };
55
+ }
56
+ };
57
+ ExampleUppercaseNode = __decorate([(0, __codemation_core.node)({ packageName: "@codemation/node-example" })], ExampleUppercaseNode);
58
+
59
+ //#endregion
60
+ //#region src/uppercase.ts
61
+ var ExampleUppercase = class {
62
+ kind = "node";
63
+ type = ExampleUppercaseNode;
64
+ constructor(name, cfg, id) {
65
+ this.name = name;
66
+ this.cfg = cfg;
67
+ this.id = id;
68
+ }
69
+ };
70
+
71
+ //#endregion
72
+ exports.ExampleUppercase = ExampleUppercase;
73
+ Object.defineProperty(exports, 'ExampleUppercaseNode', {
74
+ enumerable: true,
75
+ get: function () {
76
+ return ExampleUppercaseNode;
77
+ }
78
+ });
79
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["ExampleUppercaseNode","out: Item[]","name: string","cfg: { field: TField }","id?: string"],"sources":["../src/ExampleUppercaseNode.ts","../src/uppercase.ts"],"sourcesContent":["import type { Item, Items, Node, NodeExecutionContext, NodeOutputs } from \"@codemation/core\";\n\nimport { node } from \"@codemation/core\";\n\nimport { ExampleUppercase } from \"./uppercase\";\n\n@node({ packageName: \"@codemation/node-example\" })\nexport class ExampleUppercaseNode implements Node<ExampleUppercase<Record<string, unknown>, string>> {\n kind = \"node\" as const;\n outputPorts = [\"main\"] as const;\n\n async execute(\n items: Items,\n ctx: NodeExecutionContext<ExampleUppercase<Record<string, unknown>, string>>,\n ): Promise<NodeOutputs> {\n const out: Item[] = [];\n for (let i = 0; i < items.length; i++) {\n const item = items[i]!;\n const json = typeof item.json === \"object\" && item.json !== null ? (item.json as Record<string, unknown>) : {};\n const value = String(json[ctx.config.cfg.field] ?? \"\");\n out.push({ ...item, json: { ...json, [ctx.config.cfg.field]: value.toUpperCase() } });\n }\n return { main: out };\n }\n}\n","import type { RunnableNodeConfig, TypeToken } from \"@codemation/core\";\n\nimport { ExampleUppercaseNode } from \"./ExampleUppercaseNode\";\n\nexport class ExampleUppercase<\n TInputJson extends Record<string, unknown> = Record<string, unknown>,\n TField extends keyof TInputJson & string = keyof TInputJson & string,\n> implements RunnableNodeConfig<TInputJson, TInputJson> {\n readonly kind = \"node\" as const;\n readonly type: TypeToken<unknown> = ExampleUppercaseNode;\n constructor(\n public readonly name: string,\n public readonly cfg: { field: TField },\n public readonly id?: string,\n ) {}\n}\n\nexport { ExampleUppercaseNode } from \"./ExampleUppercaseNode\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAOO,iCAAMA,uBAAwF;CACnG,OAAO;CACP,cAAc,CAAC,OAAO;CAEtB,MAAM,QACJ,OACA,KACsB;EACtB,MAAMC,MAAc,EAAE;AACtB,OAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;GACrC,MAAM,OAAO,MAAM;GACnB,MAAM,OAAO,OAAO,KAAK,SAAS,YAAY,KAAK,SAAS,OAAQ,KAAK,OAAmC,EAAE;GAC9G,MAAM,QAAQ,OAAO,KAAK,IAAI,OAAO,IAAI,UAAU,GAAG;AACtD,OAAI,KAAK;IAAE,GAAG;IAAM,MAAM;KAAE,GAAG;MAAO,IAAI,OAAO,IAAI,QAAQ,MAAM,aAAa;KAAE;IAAE,CAAC;;AAEvF,SAAO,EAAE,MAAM,KAAK;;;+DAhBlB,EAAE,aAAa,4BAA4B,CAAC;;;;ACFlD,IAAa,mBAAb,MAGwD;CACtD,AAAS,OAAO;CAChB,AAAS,OAA2B;CACpC,YACE,AAAgBC,MAChB,AAAgBC,KAChB,AAAgBC,IAChB;EAHgB;EACA;EACA"}
@@ -0,0 +1,270 @@
1
+ import { ReadableStream } from "node:stream/web";
2
+ import { InjectionToken as TypeToken } from "tsyringe";
3
+
4
+ //#region ../core/src/contracts/retryPolicySpec.types.d.ts
5
+
6
+ /**
7
+ * In-process retry policy for runnable nodes. Serialized configs use the same
8
+ * `kind` discriminator (`JSON.stringify` / persisted workflows).
9
+ *
10
+ * `maxAttempts` is the total number of tries including the first (e.g. 3 means up to 2 delays after failures).
11
+ */
12
+ type RetryPolicySpec = NoneRetryPolicySpec | FixedRetryPolicySpec | ExponentialRetryPolicySpec;
13
+ interface NoneRetryPolicySpec {
14
+ readonly kind: "none";
15
+ }
16
+ interface FixedRetryPolicySpec {
17
+ readonly kind: "fixed";
18
+ /** Total attempts including the first execution. Must be >= 1. */
19
+ readonly maxAttempts: number;
20
+ readonly delayMs: number;
21
+ }
22
+ interface ExponentialRetryPolicySpec {
23
+ readonly kind: "exponential";
24
+ /** Total attempts including the first execution. Must be >= 1. */
25
+ readonly maxAttempts: number;
26
+ readonly initialDelayMs: number;
27
+ readonly multiplier: number;
28
+ readonly maxDelayMs?: number;
29
+ /** When true, each delay is multiplied by a random factor in [1, 1.2). */
30
+ readonly jitter?: boolean;
31
+ }
32
+ //#endregion
33
+ //#region ../core/src/contracts/runTypes.d.ts
34
+
35
+ type NodeInputsByPort = Readonly<Record<InputPortKey, Items>>;
36
+ type NodeExecutionStatus = "pending" | "queued" | "running" | "completed" | "failed" | "skipped";
37
+ interface NodeExecutionError {
38
+ message: string;
39
+ name?: string;
40
+ stack?: string;
41
+ }
42
+ /** Stable id for a single connection invocation row in {@link ConnectionInvocationRecord}. */
43
+ type ConnectionInvocationId = string;
44
+ /** Arguments for appending a {@link ConnectionInvocationRecord} (engine fills run/workflow ids and timestamps). */
45
+ type ConnectionInvocationAppendArgs = Readonly<{
46
+ invocationId: ConnectionInvocationId;
47
+ connectionNodeId: NodeId;
48
+ parentAgentNodeId: NodeId;
49
+ parentAgentActivationId: NodeActivationId;
50
+ status: NodeExecutionStatus;
51
+ managedInput?: JsonValue;
52
+ managedOutput?: JsonValue;
53
+ error?: NodeExecutionError;
54
+ queuedAt?: string;
55
+ startedAt?: string;
56
+ finishedAt?: string;
57
+ }>;
58
+ //#endregion
59
+ //#region ../core/src/contracts/runtimeTypes.d.ts
60
+ interface NodeExecutionStatePublisher {
61
+ markQueued(args: {
62
+ nodeId: NodeId;
63
+ activationId?: NodeActivationId;
64
+ inputsByPort?: NodeInputsByPort;
65
+ }): Promise<void>;
66
+ markRunning(args: {
67
+ nodeId: NodeId;
68
+ activationId?: NodeActivationId;
69
+ inputsByPort?: NodeInputsByPort;
70
+ }): Promise<void>;
71
+ markCompleted(args: {
72
+ nodeId: NodeId;
73
+ activationId?: NodeActivationId;
74
+ inputsByPort?: NodeInputsByPort;
75
+ outputs?: NodeOutputs;
76
+ }): Promise<void>;
77
+ markFailed(args: {
78
+ nodeId: NodeId;
79
+ activationId?: NodeActivationId;
80
+ inputsByPort?: NodeInputsByPort;
81
+ error: Error;
82
+ }): Promise<void>;
83
+ appendConnectionInvocation(args: ConnectionInvocationAppendArgs): Promise<void>;
84
+ }
85
+ type BinaryBody = ReadableStream<Uint8Array> | AsyncIterable<Uint8Array> | Uint8Array | ArrayBuffer;
86
+ interface BinaryStorageReadResult {
87
+ body: ReadableStream<Uint8Array>;
88
+ size?: number;
89
+ }
90
+ interface BinaryAttachmentCreateRequest {
91
+ name: string;
92
+ body: BinaryBody;
93
+ mimeType: string;
94
+ filename?: string;
95
+ previewKind?: BinaryAttachment["previewKind"];
96
+ }
97
+ interface NodeBinaryAttachmentService extends ExecutionBinaryService {
98
+ attach(args: BinaryAttachmentCreateRequest): Promise<BinaryAttachment>;
99
+ withAttachment<TJson>(item: Item<TJson>, name: string, attachment: BinaryAttachment): Item<TJson>;
100
+ }
101
+ interface ExecutionBinaryService {
102
+ forNode(args: {
103
+ nodeId: NodeId;
104
+ activationId: NodeActivationId;
105
+ }): NodeBinaryAttachmentService;
106
+ openReadStream(attachment: BinaryAttachment): Promise<BinaryStorageReadResult | undefined>;
107
+ }
108
+ interface ExecutionContext {
109
+ runId: RunId;
110
+ workflowId: WorkflowId;
111
+ parent?: ParentExecutionRef;
112
+ /** This run's subworkflow depth (0 = root). */
113
+ subworkflowDepth: number;
114
+ /** Effective activation budget cap for this run (after policy merge). */
115
+ engineMaxNodeActivations: number;
116
+ /** Effective subworkflow nesting cap for this run (after policy merge). */
117
+ engineMaxSubworkflowDepth: number;
118
+ now: () => Date;
119
+ data: RunDataSnapshot;
120
+ nodeState?: NodeExecutionStatePublisher;
121
+ binary: ExecutionBinaryService;
122
+ getCredential<TSession = unknown>(slotKey: string): Promise<TSession>;
123
+ }
124
+ interface NodeExecutionContext<TConfig extends NodeConfigBase = NodeConfigBase> extends ExecutionContext {
125
+ nodeId: NodeId;
126
+ activationId: NodeActivationId;
127
+ config: TConfig;
128
+ binary: NodeBinaryAttachmentService;
129
+ }
130
+ interface Node<TConfig extends NodeConfigBase = NodeConfigBase> {
131
+ kind: "node";
132
+ outputPorts: ReadonlyArray<OutputPortKey>;
133
+ execute(items: Items, ctx: NodeExecutionContext<TConfig>): Promise<NodeOutputs>;
134
+ }
135
+ //#endregion
136
+ //#region ../core/src/contracts/workflowTypes.d.ts
137
+ type WorkflowId = string;
138
+ type NodeId = string;
139
+ type OutputPortKey = string;
140
+ type InputPortKey = string;
141
+ type NodeKind = "trigger" | "node";
142
+ type JsonPrimitive = string | number | boolean | null;
143
+ interface JsonObject {
144
+ readonly [key: string]: JsonValue;
145
+ }
146
+ type JsonValue = JsonPrimitive | JsonObject | JsonArray;
147
+ type JsonArray = ReadonlyArray<JsonValue>;
148
+ interface NodeConfigBase {
149
+ readonly kind: NodeKind;
150
+ readonly type: TypeToken<unknown>;
151
+ readonly name?: string;
152
+ readonly id?: NodeId;
153
+ readonly icon?: string;
154
+ readonly execution?: Readonly<{
155
+ hint?: "local" | "worker";
156
+ queue?: string;
157
+ }>;
158
+ /** In-process execute retries (runnable nodes). Triggers typically omit this. */
159
+ readonly retryPolicy?: RetryPolicySpec;
160
+ /** Recover from execute failures; return outputs to continue, or rethrow to fail the node. */
161
+ readonly nodeErrorHandler?: NodeErrorHandlerSpec;
162
+ /**
163
+ * When true, edges carrying zero items on an output port still schedule single-input downstream nodes.
164
+ * Decided from the **source** node that produced the (empty) output. Default (false/undefined): empty
165
+ * main batches skip downstream execution and propagate the empty path.
166
+ */
167
+ readonly continueWhenEmptyOutput?: boolean;
168
+ getCredentialRequirements?(): ReadonlyArray<CredentialRequirement>;
169
+ }
170
+ declare const runnableNodeInputType: unique symbol;
171
+ declare const runnableNodeOutputType: unique symbol;
172
+ interface RunnableNodeConfig<TInputJson$1 = unknown, TOutputJson$1 = unknown> extends NodeConfigBase {
173
+ readonly kind: "node";
174
+ readonly [runnableNodeInputType]?: TInputJson$1;
175
+ readonly [runnableNodeOutputType]?: TOutputJson$1;
176
+ }
177
+ type PairedItemRef = Readonly<{
178
+ nodeId: NodeId;
179
+ output: OutputPortKey;
180
+ itemIndex: number;
181
+ }>;
182
+ type BinaryPreviewKind = "image" | "audio" | "video" | "download";
183
+ type BinaryAttachment = Readonly<{
184
+ id: string;
185
+ storageKey: string;
186
+ mimeType: string;
187
+ size: number;
188
+ storageDriver: string;
189
+ previewKind: BinaryPreviewKind;
190
+ createdAt: string;
191
+ runId: RunId;
192
+ workflowId: WorkflowId;
193
+ nodeId: NodeId;
194
+ activationId: NodeActivationId;
195
+ filename?: string;
196
+ sha256?: string;
197
+ }>;
198
+ type ItemBinary = Readonly<Record<string, BinaryAttachment>>;
199
+ type Item<TJson = unknown> = Readonly<{
200
+ json: TJson;
201
+ binary?: ItemBinary;
202
+ meta?: Readonly<Record<string, unknown>>;
203
+ paired?: ReadonlyArray<PairedItemRef>;
204
+ }>;
205
+ type Items<TJson = unknown> = ReadonlyArray<Item<TJson>>;
206
+ type NodeOutputs = Partial<Record<OutputPortKey, Items>>;
207
+ type RunId = string;
208
+ type NodeActivationId = string;
209
+ interface ParentExecutionRef {
210
+ runId: RunId;
211
+ workflowId: WorkflowId;
212
+ nodeId: NodeId;
213
+ /** Subworkflow depth of the **spawning** run (0 = root). Passed when starting a child run. */
214
+ subworkflowDepth?: number;
215
+ /** Effective max node activations from the parent run (propagated to child policy merge). */
216
+ engineMaxNodeActivations?: number;
217
+ /** Effective max subworkflow depth from the parent run (propagated to child policy merge). */
218
+ engineMaxSubworkflowDepth?: number;
219
+ }
220
+ interface RunDataSnapshot {
221
+ getOutputs(nodeId: NodeId): NodeOutputs | undefined;
222
+ getOutputItems(nodeId: NodeId, output?: OutputPortKey): Items;
223
+ getOutputItem(nodeId: NodeId, itemIndex: number, output?: OutputPortKey): Item | undefined;
224
+ }
225
+ interface NodeErrorHandlerArgs<TConfig extends NodeConfigBase = NodeConfigBase> {
226
+ readonly kind: "single" | "multi";
227
+ readonly items: Items;
228
+ readonly inputsByPort: Readonly<Record<InputPortKey, Items>> | undefined;
229
+ readonly ctx: NodeExecutionContext<TConfig>;
230
+ readonly error: Error;
231
+ }
232
+ interface NodeErrorHandler {
233
+ handle<TConfig extends NodeConfigBase>(args: NodeErrorHandlerArgs<TConfig>): Promise<NodeOutputs>;
234
+ }
235
+ type NodeErrorHandlerSpec = TypeToken<NodeErrorHandler> | NodeErrorHandler;
236
+ //#endregion
237
+ //#region ../core/src/contracts/credentialTypes.d.ts
238
+ type CredentialTypeId = string;
239
+ type CredentialRequirement = Readonly<{
240
+ slotKey: string;
241
+ label: string;
242
+ acceptedTypes: ReadonlyArray<CredentialTypeId>;
243
+ optional?: true;
244
+ helpText?: string;
245
+ helpUrl?: string;
246
+ }>;
247
+ //#endregion
248
+ //#region src/ExampleUppercaseNode.d.ts
249
+ declare class ExampleUppercaseNode implements Node<ExampleUppercase<Record<string, unknown>, string>> {
250
+ kind: "node";
251
+ outputPorts: readonly ["main"];
252
+ execute(items: Items, ctx: NodeExecutionContext<ExampleUppercase<Record<string, unknown>, string>>): Promise<NodeOutputs>;
253
+ }
254
+ //#endregion
255
+ //#region src/uppercase.d.ts
256
+ declare class ExampleUppercase<TInputJson$1 extends Record<string, unknown> = Record<string, unknown>, TField extends keyof TInputJson$1 & string = keyof TInputJson$1 & string> implements RunnableNodeConfig<TInputJson$1, TInputJson$1> {
257
+ readonly name: string;
258
+ readonly cfg: {
259
+ field: TField;
260
+ };
261
+ readonly id?: string | undefined;
262
+ readonly kind: "node";
263
+ readonly type: TypeToken<unknown>;
264
+ constructor(name: string, cfg: {
265
+ field: TField;
266
+ }, id?: string | undefined);
267
+ }
268
+ //#endregion
269
+ export { ExampleUppercase, ExampleUppercaseNode };
270
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1,270 @@
1
+ import { ReadableStream } from "node:stream/web";
2
+ import { InjectionToken as TypeToken } from "tsyringe";
3
+
4
+ //#region ../core/src/contracts/retryPolicySpec.types.d.ts
5
+
6
+ /**
7
+ * In-process retry policy for runnable nodes. Serialized configs use the same
8
+ * `kind` discriminator (`JSON.stringify` / persisted workflows).
9
+ *
10
+ * `maxAttempts` is the total number of tries including the first (e.g. 3 means up to 2 delays after failures).
11
+ */
12
+ type RetryPolicySpec = NoneRetryPolicySpec | FixedRetryPolicySpec | ExponentialRetryPolicySpec;
13
+ interface NoneRetryPolicySpec {
14
+ readonly kind: "none";
15
+ }
16
+ interface FixedRetryPolicySpec {
17
+ readonly kind: "fixed";
18
+ /** Total attempts including the first execution. Must be >= 1. */
19
+ readonly maxAttempts: number;
20
+ readonly delayMs: number;
21
+ }
22
+ interface ExponentialRetryPolicySpec {
23
+ readonly kind: "exponential";
24
+ /** Total attempts including the first execution. Must be >= 1. */
25
+ readonly maxAttempts: number;
26
+ readonly initialDelayMs: number;
27
+ readonly multiplier: number;
28
+ readonly maxDelayMs?: number;
29
+ /** When true, each delay is multiplied by a random factor in [1, 1.2). */
30
+ readonly jitter?: boolean;
31
+ }
32
+ //#endregion
33
+ //#region ../core/src/contracts/runTypes.d.ts
34
+
35
+ type NodeInputsByPort = Readonly<Record<InputPortKey, Items>>;
36
+ type NodeExecutionStatus = "pending" | "queued" | "running" | "completed" | "failed" | "skipped";
37
+ interface NodeExecutionError {
38
+ message: string;
39
+ name?: string;
40
+ stack?: string;
41
+ }
42
+ /** Stable id for a single connection invocation row in {@link ConnectionInvocationRecord}. */
43
+ type ConnectionInvocationId = string;
44
+ /** Arguments for appending a {@link ConnectionInvocationRecord} (engine fills run/workflow ids and timestamps). */
45
+ type ConnectionInvocationAppendArgs = Readonly<{
46
+ invocationId: ConnectionInvocationId;
47
+ connectionNodeId: NodeId;
48
+ parentAgentNodeId: NodeId;
49
+ parentAgentActivationId: NodeActivationId;
50
+ status: NodeExecutionStatus;
51
+ managedInput?: JsonValue;
52
+ managedOutput?: JsonValue;
53
+ error?: NodeExecutionError;
54
+ queuedAt?: string;
55
+ startedAt?: string;
56
+ finishedAt?: string;
57
+ }>;
58
+ //#endregion
59
+ //#region ../core/src/contracts/runtimeTypes.d.ts
60
+ interface NodeExecutionStatePublisher {
61
+ markQueued(args: {
62
+ nodeId: NodeId;
63
+ activationId?: NodeActivationId;
64
+ inputsByPort?: NodeInputsByPort;
65
+ }): Promise<void>;
66
+ markRunning(args: {
67
+ nodeId: NodeId;
68
+ activationId?: NodeActivationId;
69
+ inputsByPort?: NodeInputsByPort;
70
+ }): Promise<void>;
71
+ markCompleted(args: {
72
+ nodeId: NodeId;
73
+ activationId?: NodeActivationId;
74
+ inputsByPort?: NodeInputsByPort;
75
+ outputs?: NodeOutputs;
76
+ }): Promise<void>;
77
+ markFailed(args: {
78
+ nodeId: NodeId;
79
+ activationId?: NodeActivationId;
80
+ inputsByPort?: NodeInputsByPort;
81
+ error: Error;
82
+ }): Promise<void>;
83
+ appendConnectionInvocation(args: ConnectionInvocationAppendArgs): Promise<void>;
84
+ }
85
+ type BinaryBody = ReadableStream<Uint8Array> | AsyncIterable<Uint8Array> | Uint8Array | ArrayBuffer;
86
+ interface BinaryStorageReadResult {
87
+ body: ReadableStream<Uint8Array>;
88
+ size?: number;
89
+ }
90
+ interface BinaryAttachmentCreateRequest {
91
+ name: string;
92
+ body: BinaryBody;
93
+ mimeType: string;
94
+ filename?: string;
95
+ previewKind?: BinaryAttachment["previewKind"];
96
+ }
97
+ interface NodeBinaryAttachmentService extends ExecutionBinaryService {
98
+ attach(args: BinaryAttachmentCreateRequest): Promise<BinaryAttachment>;
99
+ withAttachment<TJson>(item: Item<TJson>, name: string, attachment: BinaryAttachment): Item<TJson>;
100
+ }
101
+ interface ExecutionBinaryService {
102
+ forNode(args: {
103
+ nodeId: NodeId;
104
+ activationId: NodeActivationId;
105
+ }): NodeBinaryAttachmentService;
106
+ openReadStream(attachment: BinaryAttachment): Promise<BinaryStorageReadResult | undefined>;
107
+ }
108
+ interface ExecutionContext {
109
+ runId: RunId;
110
+ workflowId: WorkflowId;
111
+ parent?: ParentExecutionRef;
112
+ /** This run's subworkflow depth (0 = root). */
113
+ subworkflowDepth: number;
114
+ /** Effective activation budget cap for this run (after policy merge). */
115
+ engineMaxNodeActivations: number;
116
+ /** Effective subworkflow nesting cap for this run (after policy merge). */
117
+ engineMaxSubworkflowDepth: number;
118
+ now: () => Date;
119
+ data: RunDataSnapshot;
120
+ nodeState?: NodeExecutionStatePublisher;
121
+ binary: ExecutionBinaryService;
122
+ getCredential<TSession = unknown>(slotKey: string): Promise<TSession>;
123
+ }
124
+ interface NodeExecutionContext<TConfig extends NodeConfigBase = NodeConfigBase> extends ExecutionContext {
125
+ nodeId: NodeId;
126
+ activationId: NodeActivationId;
127
+ config: TConfig;
128
+ binary: NodeBinaryAttachmentService;
129
+ }
130
+ interface Node<TConfig extends NodeConfigBase = NodeConfigBase> {
131
+ kind: "node";
132
+ outputPorts: ReadonlyArray<OutputPortKey>;
133
+ execute(items: Items, ctx: NodeExecutionContext<TConfig>): Promise<NodeOutputs>;
134
+ }
135
+ //#endregion
136
+ //#region ../core/src/contracts/workflowTypes.d.ts
137
+ type WorkflowId = string;
138
+ type NodeId = string;
139
+ type OutputPortKey = string;
140
+ type InputPortKey = string;
141
+ type NodeKind = "trigger" | "node";
142
+ type JsonPrimitive = string | number | boolean | null;
143
+ interface JsonObject {
144
+ readonly [key: string]: JsonValue;
145
+ }
146
+ type JsonValue = JsonPrimitive | JsonObject | JsonArray;
147
+ type JsonArray = ReadonlyArray<JsonValue>;
148
+ interface NodeConfigBase {
149
+ readonly kind: NodeKind;
150
+ readonly type: TypeToken<unknown>;
151
+ readonly name?: string;
152
+ readonly id?: NodeId;
153
+ readonly icon?: string;
154
+ readonly execution?: Readonly<{
155
+ hint?: "local" | "worker";
156
+ queue?: string;
157
+ }>;
158
+ /** In-process execute retries (runnable nodes). Triggers typically omit this. */
159
+ readonly retryPolicy?: RetryPolicySpec;
160
+ /** Recover from execute failures; return outputs to continue, or rethrow to fail the node. */
161
+ readonly nodeErrorHandler?: NodeErrorHandlerSpec;
162
+ /**
163
+ * When true, edges carrying zero items on an output port still schedule single-input downstream nodes.
164
+ * Decided from the **source** node that produced the (empty) output. Default (false/undefined): empty
165
+ * main batches skip downstream execution and propagate the empty path.
166
+ */
167
+ readonly continueWhenEmptyOutput?: boolean;
168
+ getCredentialRequirements?(): ReadonlyArray<CredentialRequirement>;
169
+ }
170
+ declare const runnableNodeInputType: unique symbol;
171
+ declare const runnableNodeOutputType: unique symbol;
172
+ interface RunnableNodeConfig<TInputJson$1 = unknown, TOutputJson$1 = unknown> extends NodeConfigBase {
173
+ readonly kind: "node";
174
+ readonly [runnableNodeInputType]?: TInputJson$1;
175
+ readonly [runnableNodeOutputType]?: TOutputJson$1;
176
+ }
177
+ type PairedItemRef = Readonly<{
178
+ nodeId: NodeId;
179
+ output: OutputPortKey;
180
+ itemIndex: number;
181
+ }>;
182
+ type BinaryPreviewKind = "image" | "audio" | "video" | "download";
183
+ type BinaryAttachment = Readonly<{
184
+ id: string;
185
+ storageKey: string;
186
+ mimeType: string;
187
+ size: number;
188
+ storageDriver: string;
189
+ previewKind: BinaryPreviewKind;
190
+ createdAt: string;
191
+ runId: RunId;
192
+ workflowId: WorkflowId;
193
+ nodeId: NodeId;
194
+ activationId: NodeActivationId;
195
+ filename?: string;
196
+ sha256?: string;
197
+ }>;
198
+ type ItemBinary = Readonly<Record<string, BinaryAttachment>>;
199
+ type Item<TJson = unknown> = Readonly<{
200
+ json: TJson;
201
+ binary?: ItemBinary;
202
+ meta?: Readonly<Record<string, unknown>>;
203
+ paired?: ReadonlyArray<PairedItemRef>;
204
+ }>;
205
+ type Items<TJson = unknown> = ReadonlyArray<Item<TJson>>;
206
+ type NodeOutputs = Partial<Record<OutputPortKey, Items>>;
207
+ type RunId = string;
208
+ type NodeActivationId = string;
209
+ interface ParentExecutionRef {
210
+ runId: RunId;
211
+ workflowId: WorkflowId;
212
+ nodeId: NodeId;
213
+ /** Subworkflow depth of the **spawning** run (0 = root). Passed when starting a child run. */
214
+ subworkflowDepth?: number;
215
+ /** Effective max node activations from the parent run (propagated to child policy merge). */
216
+ engineMaxNodeActivations?: number;
217
+ /** Effective max subworkflow depth from the parent run (propagated to child policy merge). */
218
+ engineMaxSubworkflowDepth?: number;
219
+ }
220
+ interface RunDataSnapshot {
221
+ getOutputs(nodeId: NodeId): NodeOutputs | undefined;
222
+ getOutputItems(nodeId: NodeId, output?: OutputPortKey): Items;
223
+ getOutputItem(nodeId: NodeId, itemIndex: number, output?: OutputPortKey): Item | undefined;
224
+ }
225
+ interface NodeErrorHandlerArgs<TConfig extends NodeConfigBase = NodeConfigBase> {
226
+ readonly kind: "single" | "multi";
227
+ readonly items: Items;
228
+ readonly inputsByPort: Readonly<Record<InputPortKey, Items>> | undefined;
229
+ readonly ctx: NodeExecutionContext<TConfig>;
230
+ readonly error: Error;
231
+ }
232
+ interface NodeErrorHandler {
233
+ handle<TConfig extends NodeConfigBase>(args: NodeErrorHandlerArgs<TConfig>): Promise<NodeOutputs>;
234
+ }
235
+ type NodeErrorHandlerSpec = TypeToken<NodeErrorHandler> | NodeErrorHandler;
236
+ //#endregion
237
+ //#region ../core/src/contracts/credentialTypes.d.ts
238
+ type CredentialTypeId = string;
239
+ type CredentialRequirement = Readonly<{
240
+ slotKey: string;
241
+ label: string;
242
+ acceptedTypes: ReadonlyArray<CredentialTypeId>;
243
+ optional?: true;
244
+ helpText?: string;
245
+ helpUrl?: string;
246
+ }>;
247
+ //#endregion
248
+ //#region src/ExampleUppercaseNode.d.ts
249
+ declare class ExampleUppercaseNode implements Node<ExampleUppercase<Record<string, unknown>, string>> {
250
+ kind: "node";
251
+ outputPorts: readonly ["main"];
252
+ execute(items: Items, ctx: NodeExecutionContext<ExampleUppercase<Record<string, unknown>, string>>): Promise<NodeOutputs>;
253
+ }
254
+ //#endregion
255
+ //#region src/uppercase.d.ts
256
+ declare class ExampleUppercase<TInputJson$1 extends Record<string, unknown> = Record<string, unknown>, TField extends keyof TInputJson$1 & string = keyof TInputJson$1 & string> implements RunnableNodeConfig<TInputJson$1, TInputJson$1> {
257
+ readonly name: string;
258
+ readonly cfg: {
259
+ field: TField;
260
+ };
261
+ readonly id?: string | undefined;
262
+ readonly kind: "node";
263
+ readonly type: TypeToken<unknown>;
264
+ constructor(name: string, cfg: {
265
+ field: TField;
266
+ }, id?: string | undefined);
267
+ }
268
+ //#endregion
269
+ export { ExampleUppercase, ExampleUppercaseNode };
270
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,49 @@
1
+ import { node } from "@codemation/core";
2
+
3
+ //#region \0@oxc-project+runtime@0.95.0/helpers/decorate.js
4
+ function __decorate(decorators, target, key, desc) {
5
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
6
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
7
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
8
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
9
+ }
10
+
11
+ //#endregion
12
+ //#region src/ExampleUppercaseNode.ts
13
+ let ExampleUppercaseNode = class ExampleUppercaseNode$1 {
14
+ kind = "node";
15
+ outputPorts = ["main"];
16
+ async execute(items, ctx) {
17
+ const out = [];
18
+ for (let i = 0; i < items.length; i++) {
19
+ const item = items[i];
20
+ const json = typeof item.json === "object" && item.json !== null ? item.json : {};
21
+ const value = String(json[ctx.config.cfg.field] ?? "");
22
+ out.push({
23
+ ...item,
24
+ json: {
25
+ ...json,
26
+ [ctx.config.cfg.field]: value.toUpperCase()
27
+ }
28
+ });
29
+ }
30
+ return { main: out };
31
+ }
32
+ };
33
+ ExampleUppercaseNode = __decorate([node({ packageName: "@codemation/node-example" })], ExampleUppercaseNode);
34
+
35
+ //#endregion
36
+ //#region src/uppercase.ts
37
+ var ExampleUppercase = class {
38
+ kind = "node";
39
+ type = ExampleUppercaseNode;
40
+ constructor(name, cfg, id) {
41
+ this.name = name;
42
+ this.cfg = cfg;
43
+ this.id = id;
44
+ }
45
+ };
46
+
47
+ //#endregion
48
+ export { ExampleUppercase, ExampleUppercaseNode };
49
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["ExampleUppercaseNode","out: Item[]","name: string","cfg: { field: TField }","id?: string"],"sources":["../src/ExampleUppercaseNode.ts","../src/uppercase.ts"],"sourcesContent":["import type { Item, Items, Node, NodeExecutionContext, NodeOutputs } from \"@codemation/core\";\n\nimport { node } from \"@codemation/core\";\n\nimport { ExampleUppercase } from \"./uppercase\";\n\n@node({ packageName: \"@codemation/node-example\" })\nexport class ExampleUppercaseNode implements Node<ExampleUppercase<Record<string, unknown>, string>> {\n kind = \"node\" as const;\n outputPorts = [\"main\"] as const;\n\n async execute(\n items: Items,\n ctx: NodeExecutionContext<ExampleUppercase<Record<string, unknown>, string>>,\n ): Promise<NodeOutputs> {\n const out: Item[] = [];\n for (let i = 0; i < items.length; i++) {\n const item = items[i]!;\n const json = typeof item.json === \"object\" && item.json !== null ? (item.json as Record<string, unknown>) : {};\n const value = String(json[ctx.config.cfg.field] ?? \"\");\n out.push({ ...item, json: { ...json, [ctx.config.cfg.field]: value.toUpperCase() } });\n }\n return { main: out };\n }\n}\n","import type { RunnableNodeConfig, TypeToken } from \"@codemation/core\";\n\nimport { ExampleUppercaseNode } from \"./ExampleUppercaseNode\";\n\nexport class ExampleUppercase<\n TInputJson extends Record<string, unknown> = Record<string, unknown>,\n TField extends keyof TInputJson & string = keyof TInputJson & string,\n> implements RunnableNodeConfig<TInputJson, TInputJson> {\n readonly kind = \"node\" as const;\n readonly type: TypeToken<unknown> = ExampleUppercaseNode;\n constructor(\n public readonly name: string,\n public readonly cfg: { field: TField },\n public readonly id?: string,\n ) {}\n}\n\nexport { ExampleUppercaseNode } from \"./ExampleUppercaseNode\";\n"],"mappings":";;;;;;;;;;;;AAOO,iCAAMA,uBAAwF;CACnG,OAAO;CACP,cAAc,CAAC,OAAO;CAEtB,MAAM,QACJ,OACA,KACsB;EACtB,MAAMC,MAAc,EAAE;AACtB,OAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;GACrC,MAAM,OAAO,MAAM;GACnB,MAAM,OAAO,OAAO,KAAK,SAAS,YAAY,KAAK,SAAS,OAAQ,KAAK,OAAmC,EAAE;GAC9G,MAAM,QAAQ,OAAO,KAAK,IAAI,OAAO,IAAI,UAAU,GAAG;AACtD,OAAI,KAAK;IAAE,GAAG;IAAM,MAAM;KAAE,GAAG;MAAO,IAAI,OAAO,IAAI,QAAQ,MAAM,aAAa;KAAE;IAAE,CAAC;;AAEvF,SAAO,EAAE,MAAM,KAAK;;;mCAhBvB,KAAK,EAAE,aAAa,4BAA4B,CAAC;;;;ACFlD,IAAa,mBAAb,MAGwD;CACtD,AAAS,OAAO;CAChB,AAAS,OAA2B;CACpC,YACE,AAAgBC,MAChB,AAAgBC,KAChB,AAAgBC,IAChB;EAHgB;EACA;EACA"}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@codemation/node-example",
3
+ "version": "0.0.1",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "author": "Made Relevant B.V.",
8
+ "homepage": "https://www.maderelevant.com",
9
+ "type": "module",
10
+ "main": "./dist/index.cjs",
11
+ "module": "./dist/index.js",
12
+ "types": "./dist/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "development": {
17
+ "import": "./src/index.ts",
18
+ "require": "./dist/index.cjs"
19
+ },
20
+ "import": "./dist/index.js",
21
+ "require": "./dist/index.cjs"
22
+ }
23
+ },
24
+ "dependencies": {
25
+ "@codemation/core": "0.0.1"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "^25.3.5",
29
+ "eslint": "^10.0.3",
30
+ "tsdown": "^0.15.5",
31
+ "typescript": "^5.9.3"
32
+ },
33
+ "scripts": {
34
+ "dev": "tsdown --watch",
35
+ "build": "tsdown",
36
+ "typecheck": "tsc -p tsconfig.json --noEmit",
37
+ "lint": "eslint .",
38
+ "test": "echo \"(test placeholder)\""
39
+ }
40
+ }
@@ -0,0 +1,25 @@
1
+ import type { Item, Items, Node, NodeExecutionContext, NodeOutputs } from "@codemation/core";
2
+
3
+ import { node } from "@codemation/core";
4
+
5
+ import { ExampleUppercase } from "./uppercase";
6
+
7
+ @node({ packageName: "@codemation/node-example" })
8
+ export class ExampleUppercaseNode implements Node<ExampleUppercase<Record<string, unknown>, string>> {
9
+ kind = "node" as const;
10
+ outputPorts = ["main"] as const;
11
+
12
+ async execute(
13
+ items: Items,
14
+ ctx: NodeExecutionContext<ExampleUppercase<Record<string, unknown>, string>>,
15
+ ): Promise<NodeOutputs> {
16
+ const out: Item[] = [];
17
+ for (let i = 0; i < items.length; i++) {
18
+ const item = items[i]!;
19
+ const json = typeof item.json === "object" && item.json !== null ? (item.json as Record<string, unknown>) : {};
20
+ const value = String(json[ctx.config.cfg.field] ?? "");
21
+ out.push({ ...item, json: { ...json, [ctx.config.cfg.field]: value.toUpperCase() } });
22
+ }
23
+ return { main: out };
24
+ }
25
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./uppercase";
@@ -0,0 +1,18 @@
1
+ import type { RunnableNodeConfig, TypeToken } from "@codemation/core";
2
+
3
+ import { ExampleUppercaseNode } from "./ExampleUppercaseNode";
4
+
5
+ export class ExampleUppercase<
6
+ TInputJson extends Record<string, unknown> = Record<string, unknown>,
7
+ TField extends keyof TInputJson & string = keyof TInputJson & string,
8
+ > implements RunnableNodeConfig<TInputJson, TInputJson> {
9
+ readonly kind = "node" as const;
10
+ readonly type: TypeToken<unknown> = ExampleUppercaseNode;
11
+ constructor(
12
+ public readonly name: string,
13
+ public readonly cfg: { field: TField },
14
+ public readonly id?: string,
15
+ ) {}
16
+ }
17
+
18
+ export { ExampleUppercaseNode } from "./ExampleUppercaseNode";
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "lib": ["ES2022"],
5
+ "types": ["node"],
6
+ "noEmit": true
7
+ },
8
+ "include": ["src/**/*.ts"]
9
+ }
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from "tsdown";
2
+
3
+ export default defineConfig({
4
+ entry: "src/index.ts",
5
+ outDir: "dist",
6
+ clean: false,
7
+ dts: true,
8
+ format: ["esm", "cjs"],
9
+ sourcemap: true,
10
+ });