@stepflowjs/trigger-stream 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.
@@ -0,0 +1,93 @@
1
+ import { Trigger, TriggerHandler } from '@stepflowjs/core';
2
+
3
+ interface StreamTriggerConfig<T = unknown> {
4
+ /** Identifier for the stream source */
5
+ source: string;
6
+ /** The async iterable to consume */
7
+ stream: AsyncIterable<T>;
8
+ /** Optional transform function to apply to each item */
9
+ transform?: (item: T) => unknown;
10
+ }
11
+ /**
12
+ * Generic async iterable stream trigger for Stepflow workflows
13
+ *
14
+ * Consumes items from an AsyncIterable and creates trigger events for each item.
15
+ * This is a base class for custom stream-based triggers (e.g., Kafka, NATS, message queues).
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * // Basic usage with async generator
20
+ * async function* numberStream() {
21
+ * for (let i = 0; i < 10; i++) {
22
+ * yield i;
23
+ * }
24
+ * }
25
+ *
26
+ * const trigger = new StreamTrigger({
27
+ * source: 'number-stream',
28
+ * stream: numberStream(),
29
+ * transform: (n) => ({ value: n, squared: n * n }),
30
+ * });
31
+ *
32
+ * await trigger.start(async (event) => {
33
+ * await stepflow.trigger('process-number', event.data);
34
+ * });
35
+ * ```
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * // Using the helper function
40
+ * const trigger = createStreamTrigger(
41
+ * 'events',
42
+ * eventStream,
43
+ * (event) => ({ ...event, processed: true })
44
+ * );
45
+ * ```
46
+ */
47
+ declare class StreamTrigger<T = unknown> implements Trigger<StreamTriggerConfig<T>> {
48
+ readonly config: StreamTriggerConfig<T>;
49
+ readonly type = "stream";
50
+ private handler?;
51
+ private abortController?;
52
+ private running;
53
+ private consumePromise?;
54
+ constructor(config: StreamTriggerConfig<T>);
55
+ /**
56
+ * Start the trigger with a handler function
57
+ * @param handler Function to call when stream items are received
58
+ */
59
+ start(handler: TriggerHandler): Promise<void>;
60
+ /**
61
+ * Consume items from the stream and create trigger events
62
+ * @private
63
+ */
64
+ private consumeStream;
65
+ /**
66
+ * Stop the trigger and cancel stream consumption
67
+ */
68
+ stop(): Promise<void>;
69
+ /**
70
+ * Health check - returns true if trigger is running
71
+ */
72
+ healthCheck(): Promise<boolean>;
73
+ }
74
+ /**
75
+ * Create a stream trigger from an async iterable
76
+ *
77
+ * @param source Identifier for the stream source
78
+ * @param stream The async iterable to consume
79
+ * @param transform Optional transform function to apply to each item
80
+ * @returns A new StreamTrigger instance
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * const trigger = createStreamTrigger(
85
+ * 'kafka-topic',
86
+ * kafkaConsumer,
87
+ * (msg) => JSON.parse(msg.value)
88
+ * );
89
+ * ```
90
+ */
91
+ declare function createStreamTrigger<T>(source: string, stream: AsyncIterable<T>, transform?: (item: T) => unknown): StreamTrigger<T>;
92
+
93
+ export { StreamTrigger, type StreamTriggerConfig, createStreamTrigger };
package/dist/index.js ADDED
@@ -0,0 +1,79 @@
1
+ // src/index.ts
2
+ var StreamTrigger = class {
3
+ constructor(config) {
4
+ this.config = config;
5
+ }
6
+ type = "stream";
7
+ handler;
8
+ abortController;
9
+ running = false;
10
+ consumePromise;
11
+ /**
12
+ * Start the trigger with a handler function
13
+ * @param handler Function to call when stream items are received
14
+ */
15
+ async start(handler) {
16
+ if (this.running) {
17
+ throw new Error("StreamTrigger is already running");
18
+ }
19
+ this.handler = handler;
20
+ this.abortController = new AbortController();
21
+ this.running = true;
22
+ this.consumePromise = this.consumeStream().catch((error) => {
23
+ if (error.name !== "AbortError") {
24
+ console.error("Stream error:", error);
25
+ }
26
+ });
27
+ }
28
+ /**
29
+ * Consume items from the stream and create trigger events
30
+ * @private
31
+ */
32
+ async consumeStream() {
33
+ try {
34
+ for await (const item of this.config.stream) {
35
+ if (!this.running) break;
36
+ const data = this.config.transform ? this.config.transform(item) : item;
37
+ const event = {
38
+ id: crypto.randomUUID(),
39
+ type: this.type,
40
+ source: this.config.source,
41
+ data,
42
+ metadata: {},
43
+ timestamp: /* @__PURE__ */ new Date()
44
+ };
45
+ await this.handler?.(event);
46
+ }
47
+ } catch (error) {
48
+ if (this.running) {
49
+ throw error;
50
+ }
51
+ }
52
+ }
53
+ /**
54
+ * Stop the trigger and cancel stream consumption
55
+ */
56
+ async stop() {
57
+ this.running = false;
58
+ this.abortController?.abort();
59
+ this.handler = void 0;
60
+ if (this.consumePromise) {
61
+ await this.consumePromise.catch(() => {
62
+ });
63
+ }
64
+ }
65
+ /**
66
+ * Health check - returns true if trigger is running
67
+ */
68
+ async healthCheck() {
69
+ return this.running;
70
+ }
71
+ };
72
+ function createStreamTrigger(source, stream, transform) {
73
+ return new StreamTrigger({ source, stream, transform });
74
+ }
75
+ export {
76
+ StreamTrigger,
77
+ createStreamTrigger
78
+ };
79
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Trigger, TriggerHandler, TriggerEvent } from \"@stepflowjs/core\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface StreamTriggerConfig<T = unknown> {\n /** Identifier for the stream source */\n source: string;\n /** The async iterable to consume */\n stream: AsyncIterable<T>;\n /** Optional transform function to apply to each item */\n transform?: (item: T) => unknown;\n}\n\n// ============================================================================\n// StreamTrigger Implementation\n// ============================================================================\n\n/**\n * Generic async iterable stream trigger for Stepflow workflows\n *\n * Consumes items from an AsyncIterable and creates trigger events for each item.\n * This is a base class for custom stream-based triggers (e.g., Kafka, NATS, message queues).\n *\n * @example\n * ```typescript\n * // Basic usage with async generator\n * async function* numberStream() {\n * for (let i = 0; i < 10; i++) {\n * yield i;\n * }\n * }\n *\n * const trigger = new StreamTrigger({\n * source: 'number-stream',\n * stream: numberStream(),\n * transform: (n) => ({ value: n, squared: n * n }),\n * });\n *\n * await trigger.start(async (event) => {\n * await stepflow.trigger('process-number', event.data);\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Using the helper function\n * const trigger = createStreamTrigger(\n * 'events',\n * eventStream,\n * (event) => ({ ...event, processed: true })\n * );\n * ```\n */\nexport class StreamTrigger<T = unknown> implements Trigger<\n StreamTriggerConfig<T>\n> {\n readonly type = \"stream\";\n private handler?: TriggerHandler;\n private abortController?: AbortController;\n private running = false;\n private consumePromise?: Promise<void>;\n\n constructor(readonly config: StreamTriggerConfig<T>) {}\n\n /**\n * Start the trigger with a handler function\n * @param handler Function to call when stream items are received\n */\n async start(handler: TriggerHandler): Promise<void> {\n if (this.running) {\n throw new Error(\"StreamTrigger is already running\");\n }\n\n this.handler = handler;\n this.abortController = new AbortController();\n this.running = true;\n\n // Start consuming the stream in the background\n this.consumePromise = this.consumeStream().catch((error) => {\n if (error.name !== \"AbortError\") {\n console.error(\"Stream error:\", error);\n }\n });\n }\n\n /**\n * Consume items from the stream and create trigger events\n * @private\n */\n private async consumeStream(): Promise<void> {\n try {\n for await (const item of this.config.stream) {\n if (!this.running) break;\n\n const data = this.config.transform ? this.config.transform(item) : item;\n\n const event: TriggerEvent = {\n id: crypto.randomUUID(),\n type: this.type,\n source: this.config.source,\n data,\n metadata: {},\n timestamp: new Date(),\n };\n\n await this.handler?.(event);\n }\n } catch (error) {\n if (this.running) {\n throw error;\n }\n }\n }\n\n /**\n * Stop the trigger and cancel stream consumption\n */\n async stop(): Promise<void> {\n this.running = false;\n this.abortController?.abort();\n this.handler = undefined;\n\n // Wait for stream consumption to complete\n if (this.consumePromise) {\n await this.consumePromise.catch(() => {\n // Ignore errors during shutdown\n });\n }\n }\n\n /**\n * Health check - returns true if trigger is running\n */\n async healthCheck(): Promise<boolean> {\n return this.running;\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Create a stream trigger from an async iterable\n *\n * @param source Identifier for the stream source\n * @param stream The async iterable to consume\n * @param transform Optional transform function to apply to each item\n * @returns A new StreamTrigger instance\n *\n * @example\n * ```typescript\n * const trigger = createStreamTrigger(\n * 'kafka-topic',\n * kafkaConsumer,\n * (msg) => JSON.parse(msg.value)\n * );\n * ```\n */\nexport function createStreamTrigger<T>(\n source: string,\n stream: AsyncIterable<T>,\n transform?: (item: T) => unknown,\n): StreamTrigger<T> {\n return new StreamTrigger({ source, stream, transform });\n}\n"],"mappings":";AAuDO,IAAM,gBAAN,MAEL;AAAA,EAOA,YAAqB,QAAgC;AAAhC;AAAA,EAAiC;AAAA,EAN7C,OAAO;AAAA,EACR;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AAAA;AAAA;AAAA;AAAA;AAAA,EAQR,MAAM,MAAM,SAAwC;AAClD,QAAI,KAAK,SAAS;AAChB,YAAM,IAAI,MAAM,kCAAkC;AAAA,IACpD;AAEA,SAAK,UAAU;AACf,SAAK,kBAAkB,IAAI,gBAAgB;AAC3C,SAAK,UAAU;AAGf,SAAK,iBAAiB,KAAK,cAAc,EAAE,MAAM,CAAC,UAAU;AAC1D,UAAI,MAAM,SAAS,cAAc;AAC/B,gBAAQ,MAAM,iBAAiB,KAAK;AAAA,MACtC;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,gBAA+B;AAC3C,QAAI;AACF,uBAAiB,QAAQ,KAAK,OAAO,QAAQ;AAC3C,YAAI,CAAC,KAAK,QAAS;AAEnB,cAAM,OAAO,KAAK,OAAO,YAAY,KAAK,OAAO,UAAU,IAAI,IAAI;AAEnE,cAAM,QAAsB;AAAA,UAC1B,IAAI,OAAO,WAAW;AAAA,UACtB,MAAM,KAAK;AAAA,UACX,QAAQ,KAAK,OAAO;AAAA,UACpB;AAAA,UACA,UAAU,CAAC;AAAA,UACX,WAAW,oBAAI,KAAK;AAAA,QACtB;AAEA,cAAM,KAAK,UAAU,KAAK;AAAA,MAC5B;AAAA,IACF,SAAS,OAAO;AACd,UAAI,KAAK,SAAS;AAChB,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAsB;AAC1B,SAAK,UAAU;AACf,SAAK,iBAAiB,MAAM;AAC5B,SAAK,UAAU;AAGf,QAAI,KAAK,gBAAgB;AACvB,YAAM,KAAK,eAAe,MAAM,MAAM;AAAA,MAEtC,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAgC;AACpC,WAAO,KAAK;AAAA,EACd;AACF;AAuBO,SAAS,oBACd,QACA,QACA,WACkB;AAClB,SAAO,IAAI,cAAc,EAAE,QAAQ,QAAQ,UAAU,CAAC;AACxD;","names":[]}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@stepflowjs/trigger-stream",
3
+ "version": "0.0.1",
4
+ "description": "Generic async iterable stream trigger for Stepflow",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "dependencies": {
19
+ "@stepflowjs/core": "0.0.1"
20
+ },
21
+ "devDependencies": {
22
+ "tsup": "^8.5.1",
23
+ "vitest": "^4.0.17"
24
+ },
25
+ "peerDependencies": {
26
+ "typescript": "^5.0.0"
27
+ },
28
+ "license": "MIT",
29
+ "author": "Stepflow Contributors",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "https://stepflow-production.up.railway.app",
33
+ "directory": "packages/triggers/stream"
34
+ },
35
+ "homepage": "https://stepflow-production.up.railway.app",
36
+ "bugs": {
37
+ "url": "https://stepflow-production.up.railway.app"
38
+ },
39
+ "keywords": [
40
+ "stepflow",
41
+ "trigger",
42
+ "stream",
43
+ "async-iterable",
44
+ "workflow",
45
+ "orchestration"
46
+ ],
47
+ "publishConfig": {
48
+ "access": "public"
49
+ },
50
+ "scripts": {
51
+ "build": "tsup",
52
+ "dev": "tsup --watch",
53
+ "typecheck": "tsc --noEmit",
54
+ "test": "vitest",
55
+ "clean": "rm -rf dist"
56
+ }
57
+ }