modelfusion 0.53.2 → 0.54.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 (66) hide show
  1. package/README.md +2 -2
  2. package/browser/convertAudioChunksToBase64.cjs +8 -0
  3. package/browser/convertAudioChunksToBase64.d.ts +4 -0
  4. package/browser/convertAudioChunksToBase64.js +4 -0
  5. package/browser/convertBlobToBase64.cjs +23 -0
  6. package/browser/convertBlobToBase64.d.ts +1 -0
  7. package/browser/convertBlobToBase64.js +19 -0
  8. package/{ui → browser}/index.cjs +5 -0
  9. package/browser/index.d.ts +6 -0
  10. package/browser/index.js +6 -0
  11. package/browser/invokeFlow.cjs +23 -0
  12. package/browser/invokeFlow.d.ts +8 -0
  13. package/browser/invokeFlow.js +19 -0
  14. package/{event-source → browser}/readEventSource.cjs +8 -3
  15. package/{event-source → browser}/readEventSource.d.ts +3 -1
  16. package/{event-source → browser}/readEventSource.js +8 -3
  17. package/{event-source → browser}/readEventSourceStream.cjs +1 -1
  18. package/{event-source → browser}/readEventSourceStream.js +1 -1
  19. package/event-source/createEventSourceStream.cjs +7 -3
  20. package/event-source/createEventSourceStream.js +7 -3
  21. package/event-source/index.cjs +0 -2
  22. package/event-source/index.d.ts +0 -2
  23. package/event-source/index.js +0 -2
  24. package/index.cjs +0 -1
  25. package/index.d.ts +0 -1
  26. package/index.js +0 -1
  27. package/package.json +13 -4
  28. package/server/fastify/AssetStorage.cjs +2 -0
  29. package/server/fastify/AssetStorage.d.ts +17 -0
  30. package/server/fastify/AssetStorage.js +1 -0
  31. package/server/fastify/DefaultFlow.cjs +22 -0
  32. package/server/fastify/DefaultFlow.d.ts +16 -0
  33. package/server/fastify/DefaultFlow.js +18 -0
  34. package/server/fastify/FileSystemAssetStorage.cjs +60 -0
  35. package/server/fastify/FileSystemAssetStorage.d.ts +19 -0
  36. package/server/fastify/FileSystemAssetStorage.js +56 -0
  37. package/server/fastify/FileSystemLogger.cjs +48 -0
  38. package/server/fastify/FileSystemLogger.d.ts +18 -0
  39. package/server/fastify/FileSystemLogger.js +44 -0
  40. package/server/fastify/Flow.cjs +2 -0
  41. package/server/fastify/Flow.d.ts +9 -0
  42. package/server/fastify/Flow.js +1 -0
  43. package/server/fastify/FlowRun.cjs +71 -0
  44. package/server/fastify/FlowRun.d.ts +28 -0
  45. package/server/fastify/FlowRun.js +67 -0
  46. package/server/fastify/FlowSchema.cjs +2 -0
  47. package/server/fastify/FlowSchema.d.ts +5 -0
  48. package/server/fastify/FlowSchema.js +1 -0
  49. package/server/fastify/Logger.cjs +2 -0
  50. package/server/fastify/Logger.d.ts +13 -0
  51. package/server/fastify/Logger.js +1 -0
  52. package/server/fastify/PathProvider.cjs +34 -0
  53. package/server/fastify/PathProvider.d.ts +12 -0
  54. package/server/fastify/PathProvider.js +30 -0
  55. package/server/fastify/index.cjs +24 -0
  56. package/server/fastify/index.d.ts +8 -0
  57. package/server/fastify/index.js +8 -0
  58. package/server/fastify/modelFusionFlowPlugin.cjs +102 -0
  59. package/server/fastify/modelFusionFlowPlugin.d.ts +12 -0
  60. package/server/fastify/modelFusionFlowPlugin.js +98 -0
  61. package/ui/index.d.ts +0 -1
  62. package/ui/index.js +0 -1
  63. /package/{ui → browser}/MediaSourceAppender.cjs +0 -0
  64. /package/{ui → browser}/MediaSourceAppender.d.ts +0 -0
  65. /package/{ui → browser}/MediaSourceAppender.js +0 -0
  66. /package/{event-source → browser}/readEventSourceStream.d.ts +0 -0
package/README.md CHANGED
@@ -623,9 +623,9 @@ Create an 19th century painting image for your input.
623
623
 
624
624
  Record audio with push-to-talk and transcribe it using Whisper, implemented as a Next.js app. The app shows a list of the transcriptions.
625
625
 
626
- ### [Speech Streaming (Vite(React) + Fastify))](https://github.com/lgrammel/modelfusion/tree/main/examples/speech-streaming-vite-react-fastify)
626
+ ### [Duplex Speech Streaming (using Vite/React & ModelFusion Server/Fastify)](https://github.com/lgrammel/modelfusion/tree/main/examples/speech-streaming-vite-react-fastify)
627
627
 
628
- > _Speech Streaming_, _OpenAI_, _Elevenlabs_ _streaming_, _Vite_, _Fastify_
628
+ > _Speech Streaming_, _OpenAI_, _Elevenlabs_ _streaming_, _Vite_, _Fastify_, _ModelFusion Server_
629
629
 
630
630
  Given a prompt, the server returns both a text and a speech stream response.
631
631
 
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.convertAudioChunksToBase64 = void 0;
4
+ const convertBlobToBase64_js_1 = require("./convertBlobToBase64.cjs");
5
+ function convertAudioChunksToBase64({ audioChunks, mimeType, }) {
6
+ return (0, convertBlobToBase64_js_1.convertBlobToBase64)(new Blob(audioChunks, { type: mimeType }));
7
+ }
8
+ exports.convertAudioChunksToBase64 = convertAudioChunksToBase64;
@@ -0,0 +1,4 @@
1
+ export declare function convertAudioChunksToBase64({ audioChunks, mimeType, }: {
2
+ audioChunks: Blob[];
3
+ mimeType: string;
4
+ }): Promise<string>;
@@ -0,0 +1,4 @@
1
+ import { convertBlobToBase64 } from "./convertBlobToBase64.js";
2
+ export function convertAudioChunksToBase64({ audioChunks, mimeType, }) {
3
+ return convertBlobToBase64(new Blob(audioChunks, { type: mimeType }));
4
+ }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.convertBlobToBase64 = void 0;
4
+ async function convertBlobToBase64(blob) {
5
+ return new Promise((resolve, reject) => {
6
+ const reader = new FileReader();
7
+ reader.onloadend = () => {
8
+ if (reader.result) {
9
+ const base64String = btoa(new Uint8Array(reader.result).reduce((data, byte) => data + String.fromCharCode(byte), ""));
10
+ resolve(base64String);
11
+ }
12
+ else {
13
+ reject(new Error("Failed to read blob."));
14
+ }
15
+ };
16
+ reader.onerror = () => {
17
+ reader.abort();
18
+ reject(new DOMException("Problem parsing input blob."));
19
+ };
20
+ reader.readAsArrayBuffer(blob);
21
+ });
22
+ }
23
+ exports.convertBlobToBase64 = convertBlobToBase64;
@@ -0,0 +1 @@
1
+ export declare function convertBlobToBase64(blob: Blob): Promise<string>;
@@ -0,0 +1,19 @@
1
+ export async function convertBlobToBase64(blob) {
2
+ return new Promise((resolve, reject) => {
3
+ const reader = new FileReader();
4
+ reader.onloadend = () => {
5
+ if (reader.result) {
6
+ const base64String = btoa(new Uint8Array(reader.result).reduce((data, byte) => data + String.fromCharCode(byte), ""));
7
+ resolve(base64String);
8
+ }
9
+ else {
10
+ reject(new Error("Failed to read blob."));
11
+ }
12
+ };
13
+ reader.onerror = () => {
14
+ reader.abort();
15
+ reject(new DOMException("Problem parsing input blob."));
16
+ };
17
+ reader.readAsArrayBuffer(blob);
18
+ });
19
+ }
@@ -15,3 +15,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./MediaSourceAppender.cjs"), exports);
18
+ __exportStar(require("./convertAudioChunksToBase64.cjs"), exports);
19
+ __exportStar(require("./convertBlobToBase64.cjs"), exports);
20
+ __exportStar(require("./invokeFlow.cjs"), exports);
21
+ __exportStar(require("./readEventSource.cjs"), exports);
22
+ __exportStar(require("./readEventSourceStream.cjs"), exports);
@@ -0,0 +1,6 @@
1
+ export * from "./MediaSourceAppender.js";
2
+ export * from "./convertAudioChunksToBase64.js";
3
+ export * from "./convertBlobToBase64.js";
4
+ export * from "./invokeFlow.js";
5
+ export * from "./readEventSource.js";
6
+ export * from "./readEventSourceStream.js";
@@ -0,0 +1,6 @@
1
+ export * from "./MediaSourceAppender.js";
2
+ export * from "./convertAudioChunksToBase64.js";
3
+ export * from "./convertBlobToBase64.js";
4
+ export * from "./invokeFlow.js";
5
+ export * from "./readEventSource.js";
6
+ export * from "./readEventSourceStream.js";
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.invokeFlow = void 0;
4
+ const ZodSchema_1 = require("../core/structure/ZodSchema");
5
+ const readEventSource_1 = require("./readEventSource");
6
+ async function invokeFlow({ url, input, schema, onEvent, onStop, }) {
7
+ const response = await fetch(url, {
8
+ method: "POST",
9
+ headers: { "Content-Type": "application/json" },
10
+ body: JSON.stringify(input),
11
+ });
12
+ const eventSourceUrl = (await response.json()).url;
13
+ (0, readEventSource_1.readEventSource)({
14
+ url: eventSourceUrl,
15
+ schema: new ZodSchema_1.ZodSchema(schema.events),
16
+ isStopEvent(event) {
17
+ return event.data === "[DONE]";
18
+ },
19
+ onEvent,
20
+ onStop,
21
+ });
22
+ }
23
+ exports.invokeFlow = invokeFlow;
@@ -0,0 +1,8 @@
1
+ import { FlowSchema } from "../server/fastify/FlowSchema";
2
+ export declare function invokeFlow<INPUT, EVENT>({ url, input, schema, onEvent, onStop, }: {
3
+ url: string;
4
+ input: INPUT;
5
+ schema: FlowSchema<INPUT, EVENT>;
6
+ onEvent: (event: EVENT, eventSource: EventSource) => void;
7
+ onStop?: (eventSource: EventSource) => void;
8
+ }): Promise<void>;
@@ -0,0 +1,19 @@
1
+ import { ZodSchema } from "../core/structure/ZodSchema";
2
+ import { readEventSource } from "./readEventSource";
3
+ export async function invokeFlow({ url, input, schema, onEvent, onStop, }) {
4
+ const response = await fetch(url, {
5
+ method: "POST",
6
+ headers: { "Content-Type": "application/json" },
7
+ body: JSON.stringify(input),
8
+ });
9
+ const eventSourceUrl = (await response.json()).url;
10
+ readEventSource({
11
+ url: eventSourceUrl,
12
+ schema: new ZodSchema(schema.events),
13
+ isStopEvent(event) {
14
+ return event.data === "[DONE]";
15
+ },
16
+ onEvent,
17
+ onStop,
18
+ });
19
+ }
@@ -2,11 +2,16 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.readEventSource = void 0;
4
4
  const parseJSON_js_1 = require("../util/parseJSON.cjs");
5
- function readEventSource({ url, schema, onEvent, onError = console.error, }) {
5
+ function readEventSource({ url, schema, onEvent, onError = console.error, onStop, isStopEvent, }) {
6
6
  const eventSource = new EventSource(url);
7
- eventSource.onmessage = (e) => {
7
+ eventSource.onmessage = (event) => {
8
8
  try {
9
- const parseResult = (0, parseJSON_js_1.safeParseJsonWithSchema)(e.data, schema);
9
+ if (isStopEvent?.(event)) {
10
+ eventSource.close();
11
+ onStop?.(eventSource);
12
+ return;
13
+ }
14
+ const parseResult = (0, parseJSON_js_1.safeParseJsonWithSchema)(event.data, schema);
10
15
  if (!parseResult.success) {
11
16
  onError(parseResult.error, eventSource);
12
17
  return;
@@ -1,7 +1,9 @@
1
1
  import { Schema } from "../core/structure/Schema.js";
2
- export declare function readEventSource<T>({ url, schema, onEvent, onError, }: {
2
+ export declare function readEventSource<T>({ url, schema, onEvent, onError, onStop, isStopEvent, }: {
3
3
  url: string;
4
4
  schema: Schema<T>;
5
5
  onEvent: (event: T, eventSource: EventSource) => void;
6
6
  onError?: (error: unknown, eventSource: EventSource) => void;
7
+ onStop?: (eventSource: EventSource) => void;
8
+ isStopEvent?: (event: MessageEvent<unknown>) => boolean;
7
9
  }): void;
@@ -1,9 +1,14 @@
1
1
  import { safeParseJsonWithSchema } from "../util/parseJSON.js";
2
- export function readEventSource({ url, schema, onEvent, onError = console.error, }) {
2
+ export function readEventSource({ url, schema, onEvent, onError = console.error, onStop, isStopEvent, }) {
3
3
  const eventSource = new EventSource(url);
4
- eventSource.onmessage = (e) => {
4
+ eventSource.onmessage = (event) => {
5
5
  try {
6
- const parseResult = safeParseJsonWithSchema(e.data, schema);
6
+ if (isStopEvent?.(event)) {
7
+ eventSource.close();
8
+ onStop?.(eventSource);
9
+ return;
10
+ }
11
+ const parseResult = safeParseJsonWithSchema(event.data, schema);
7
12
  if (!parseResult.success) {
8
13
  onError(parseResult.error, eventSource);
9
14
  return;
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.readEventSourceStream = void 0;
4
4
  const parseJSON_js_1 = require("../util/parseJSON.cjs");
5
5
  const AsyncQueue_js_1 = require("../util/AsyncQueue.cjs");
6
- const parseEventSourceStream_js_1 = require("./parseEventSourceStream.cjs");
6
+ const parseEventSourceStream_js_1 = require("../event-source/parseEventSourceStream.cjs");
7
7
  function readEventSourceStream({ stream, schema, errorHandler, }) {
8
8
  const queue = new AsyncQueue_js_1.AsyncQueue();
9
9
  // run async (no await on purpose):
@@ -1,6 +1,6 @@
1
1
  import { safeParseJsonWithSchema } from "../util/parseJSON.js";
2
2
  import { AsyncQueue } from "../util/AsyncQueue.js";
3
- import { parseEventSourceStream } from "./parseEventSourceStream.js";
3
+ import { parseEventSourceStream } from "../event-source/parseEventSourceStream.js";
4
4
  export function readEventSourceStream({ stream, schema, errorHandler, }) {
5
5
  const queue = new AsyncQueue();
6
6
  // run async (no await on purpose):
@@ -5,10 +5,14 @@ const textEncoder = new TextEncoder();
5
5
  function createEventSourceStream(events) {
6
6
  return new ReadableStream({
7
7
  async start(controller) {
8
- for await (const event of events) {
9
- controller.enqueue(textEncoder.encode(`data: ${JSON.stringify(event)}\n\n`));
8
+ try {
9
+ for await (const event of events) {
10
+ controller.enqueue(textEncoder.encode(`data: ${JSON.stringify(event)}\n\n`));
11
+ }
12
+ }
13
+ finally {
14
+ controller.close();
10
15
  }
11
- controller.close();
12
16
  },
13
17
  });
14
18
  }
@@ -2,10 +2,14 @@ const textEncoder = new TextEncoder();
2
2
  export function createEventSourceStream(events) {
3
3
  return new ReadableStream({
4
4
  async start(controller) {
5
- for await (const event of events) {
6
- controller.enqueue(textEncoder.encode(`data: ${JSON.stringify(event)}\n\n`));
5
+ try {
6
+ for await (const event of events) {
7
+ controller.enqueue(textEncoder.encode(`data: ${JSON.stringify(event)}\n\n`));
8
+ }
9
+ }
10
+ finally {
11
+ controller.close();
7
12
  }
8
- controller.close();
9
13
  },
10
14
  });
11
15
  }
@@ -15,5 +15,3 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./createEventSourceStream.cjs"), exports);
18
- __exportStar(require("./readEventSource.cjs"), exports);
19
- __exportStar(require("./readEventSourceStream.cjs"), exports);
@@ -1,3 +1 @@
1
1
  export * from "./createEventSourceStream.js";
2
- export * from "./readEventSource.js";
3
- export * from "./readEventSourceStream.js";
@@ -1,3 +1 @@
1
1
  export * from "./createEventSourceStream.js";
2
- export * from "./readEventSource.js";
3
- export * from "./readEventSourceStream.js";
package/index.cjs CHANGED
@@ -25,6 +25,5 @@ __exportStar(require("./observability/index.cjs"), exports);
25
25
  __exportStar(require("./retriever/index.cjs"), exports);
26
26
  __exportStar(require("./text-chunk/index.cjs"), exports);
27
27
  __exportStar(require("./tool/index.cjs"), exports);
28
- __exportStar(require("./ui/index.cjs"), exports);
29
28
  __exportStar(require("./util/index.cjs"), exports);
30
29
  __exportStar(require("./vector-index/index.cjs"), exports);
package/index.d.ts CHANGED
@@ -9,6 +9,5 @@ export * from "./observability/index.js";
9
9
  export * from "./retriever/index.js";
10
10
  export * from "./text-chunk/index.js";
11
11
  export * from "./tool/index.js";
12
- export * from "./ui/index.js";
13
12
  export * from "./util/index.js";
14
13
  export * from "./vector-index/index.js";
package/index.js CHANGED
@@ -9,6 +9,5 @@ export * from "./observability/index.js";
9
9
  export * from "./retriever/index.js";
10
10
  export * from "./text-chunk/index.js";
11
11
  export * from "./tool/index.js";
12
- export * from "./ui/index.js";
13
12
  export * from "./util/index.js";
14
13
  export * from "./vector-index/index.js";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "modelfusion",
3
3
  "description": "Build multimodal applications, chatbots, and agents with JavaScript and TypeScript.",
4
- "version": "0.53.2",
4
+ "version": "0.54.0",
5
5
  "author": "Lars Grammel",
6
6
  "license": "MIT",
7
7
  "keywords": [
@@ -38,6 +38,16 @@
38
38
  "types": "./index.d.ts",
39
39
  "import": "./index.js",
40
40
  "require": "./index.cjs"
41
+ },
42
+ "./browser": {
43
+ "types": "./browser/index.d.ts",
44
+ "import": "./browser/index.js",
45
+ "require": "./browser/index.cjs"
46
+ },
47
+ "./fastify-server": {
48
+ "types": "./server/fastify/index.d.ts",
49
+ "import": "./server/fastify/index.js",
50
+ "require": "./server/fastify/index.cjs"
41
51
  }
42
52
  },
43
53
  "scripts": {
@@ -62,8 +72,6 @@
62
72
  "zod-to-json-schema": "3.21.4"
63
73
  },
64
74
  "devDependencies": {
65
- "@tsconfig/recommended": "1.0.3",
66
- "@types/deep-equal": "^1.0.2",
67
75
  "@types/node": "18.11.9",
68
76
  "@types/ws": "^8.5.7",
69
77
  "@typescript-eslint/eslint-plugin": "^6.1.0",
@@ -71,8 +79,9 @@
71
79
  "copyfiles": "2.4.1",
72
80
  "eslint": "^8.45.0",
73
81
  "eslint-config-prettier": "9.0.0",
82
+ "fastify": "^4.0.0",
74
83
  "husky": "^8.0.3",
75
- "lint-staged": "14.0.1",
84
+ "lint-staged": "15.0.2",
76
85
  "prettier": "3.0.3",
77
86
  "rimraf": "5.0.5",
78
87
  "typescript": "5.2.2",
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,17 @@
1
+ /// <reference types="node" />
2
+ import { FlowRun } from "./FlowRun.js";
3
+ export type Asset = {
4
+ data: Buffer;
5
+ contentType: string;
6
+ name: string;
7
+ };
8
+ export interface AssetStorage {
9
+ storeAsset(options: {
10
+ run: FlowRun<unknown>;
11
+ asset: Asset;
12
+ }): Promise<void>;
13
+ readAsset(options: {
14
+ run: FlowRun<unknown>;
15
+ assetName: string;
16
+ }): Promise<Asset | null>;
17
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DefaultFlow = void 0;
4
+ class DefaultFlow {
5
+ constructor({ schema, process, }) {
6
+ Object.defineProperty(this, "schema", {
7
+ enumerable: true,
8
+ configurable: true,
9
+ writable: true,
10
+ value: void 0
11
+ });
12
+ Object.defineProperty(this, "process", {
13
+ enumerable: true,
14
+ configurable: true,
15
+ writable: true,
16
+ value: void 0
17
+ });
18
+ this.schema = schema;
19
+ this.process = process;
20
+ }
21
+ }
22
+ exports.DefaultFlow = DefaultFlow;
@@ -0,0 +1,16 @@
1
+ import { FlowRun } from "./FlowRun.js";
2
+ import { FlowSchema } from "./FlowSchema.js";
3
+ export declare class DefaultFlow<INPUT, EVENT> {
4
+ readonly schema: FlowSchema<INPUT, EVENT>;
5
+ constructor({ schema, process, }: {
6
+ schema: FlowSchema<INPUT, EVENT>;
7
+ process: (options: {
8
+ input: INPUT;
9
+ run: FlowRun<EVENT>;
10
+ }) => Promise<void>;
11
+ });
12
+ process: (options: {
13
+ input: INPUT;
14
+ run: FlowRun<EVENT>;
15
+ }) => Promise<void>;
16
+ }
@@ -0,0 +1,18 @@
1
+ export class DefaultFlow {
2
+ constructor({ schema, process, }) {
3
+ Object.defineProperty(this, "schema", {
4
+ enumerable: true,
5
+ configurable: true,
6
+ writable: true,
7
+ value: void 0
8
+ });
9
+ Object.defineProperty(this, "process", {
10
+ enumerable: true,
11
+ configurable: true,
12
+ writable: true,
13
+ value: void 0
14
+ });
15
+ this.schema = schema;
16
+ this.process = process;
17
+ }
18
+ }
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FileSystemAssetStorage = void 0;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ class FileSystemAssetStorage {
7
+ constructor({ path, logger, }) {
8
+ Object.defineProperty(this, "path", {
9
+ enumerable: true,
10
+ configurable: true,
11
+ writable: true,
12
+ value: void 0
13
+ });
14
+ Object.defineProperty(this, "logger", {
15
+ enumerable: true,
16
+ configurable: true,
17
+ writable: true,
18
+ value: void 0
19
+ });
20
+ this.path = path;
21
+ this.logger = logger;
22
+ }
23
+ async storeAsset({ run, asset, }) {
24
+ try {
25
+ const assetPath = this.path(run);
26
+ await node_fs_1.promises.mkdir(assetPath, { recursive: true });
27
+ await node_fs_1.promises.writeFile((0, node_path_1.join)(assetPath, asset.name), asset.data);
28
+ await node_fs_1.promises.writeFile((0, node_path_1.join)(assetPath, `${asset.name}.meta.json`), JSON.stringify({
29
+ name: asset.name,
30
+ contentType: asset.contentType,
31
+ }));
32
+ }
33
+ catch (error) {
34
+ this.logger.logError({
35
+ run,
36
+ message: `Failed to store asset ${asset.name}`,
37
+ error,
38
+ });
39
+ throw error;
40
+ }
41
+ }
42
+ async readAsset(options) {
43
+ try {
44
+ const assetPath = this.path(options.run);
45
+ const data = await node_fs_1.promises.readFile((0, node_path_1.join)(assetPath, options.assetName));
46
+ const meta = await node_fs_1.promises.readFile((0, node_path_1.join)(assetPath, `${options.assetName}.meta.json`));
47
+ const { name, contentType } = JSON.parse(meta.toString());
48
+ return { data, name, contentType };
49
+ }
50
+ catch (error) {
51
+ this.logger.logError({
52
+ run: options.run,
53
+ message: `Failed to read asset ${options.assetName}`,
54
+ error,
55
+ });
56
+ throw error;
57
+ }
58
+ }
59
+ }
60
+ exports.FileSystemAssetStorage = FileSystemAssetStorage;
@@ -0,0 +1,19 @@
1
+ import type { Asset, AssetStorage } from "./AssetStorage.js";
2
+ import { FlowRun } from "./FlowRun.js";
3
+ import { Logger } from "./Logger.js";
4
+ export declare class FileSystemAssetStorage implements AssetStorage {
5
+ private readonly path;
6
+ private readonly logger;
7
+ constructor({ path, logger, }: {
8
+ path: (run: FlowRun<unknown>) => string;
9
+ logger: Logger;
10
+ });
11
+ storeAsset({ run, asset, }: {
12
+ run: FlowRun<unknown>;
13
+ asset: Asset;
14
+ }): Promise<void>;
15
+ readAsset(options: {
16
+ run: FlowRun<unknown>;
17
+ assetName: string;
18
+ }): Promise<Asset | null>;
19
+ }
@@ -0,0 +1,56 @@
1
+ import { promises as fs } from "node:fs";
2
+ import { join } from "node:path";
3
+ export class FileSystemAssetStorage {
4
+ constructor({ path, logger, }) {
5
+ Object.defineProperty(this, "path", {
6
+ enumerable: true,
7
+ configurable: true,
8
+ writable: true,
9
+ value: void 0
10
+ });
11
+ Object.defineProperty(this, "logger", {
12
+ enumerable: true,
13
+ configurable: true,
14
+ writable: true,
15
+ value: void 0
16
+ });
17
+ this.path = path;
18
+ this.logger = logger;
19
+ }
20
+ async storeAsset({ run, asset, }) {
21
+ try {
22
+ const assetPath = this.path(run);
23
+ await fs.mkdir(assetPath, { recursive: true });
24
+ await fs.writeFile(join(assetPath, asset.name), asset.data);
25
+ await fs.writeFile(join(assetPath, `${asset.name}.meta.json`), JSON.stringify({
26
+ name: asset.name,
27
+ contentType: asset.contentType,
28
+ }));
29
+ }
30
+ catch (error) {
31
+ this.logger.logError({
32
+ run,
33
+ message: `Failed to store asset ${asset.name}`,
34
+ error,
35
+ });
36
+ throw error;
37
+ }
38
+ }
39
+ async readAsset(options) {
40
+ try {
41
+ const assetPath = this.path(options.run);
42
+ const data = await fs.readFile(join(assetPath, options.assetName));
43
+ const meta = await fs.readFile(join(assetPath, `${options.assetName}.meta.json`));
44
+ const { name, contentType } = JSON.parse(meta.toString());
45
+ return { data, name, contentType };
46
+ }
47
+ catch (error) {
48
+ this.logger.logError({
49
+ run: options.run,
50
+ message: `Failed to read asset ${options.assetName}`,
51
+ error,
52
+ });
53
+ throw error;
54
+ }
55
+ }
56
+ }
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FileSystemLogger = void 0;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ class FileSystemLogger {
7
+ constructor({ path }) {
8
+ Object.defineProperty(this, "logPath", {
9
+ enumerable: true,
10
+ configurable: true,
11
+ writable: true,
12
+ value: void 0
13
+ });
14
+ this.logPath = path;
15
+ }
16
+ async logFunctionEvent({ run, event, }) {
17
+ const timestamp = event.startTimestamp.getTime();
18
+ try {
19
+ const logPath = this.logPath(run);
20
+ await node_fs_1.promises.mkdir(logPath, { recursive: true });
21
+ await node_fs_1.promises.writeFile((0, node_path_1.join)(logPath, `${timestamp}-${event.callId}-${event.functionId ?? event.functionType}-${event.eventType}.json`), JSON.stringify(event));
22
+ }
23
+ catch (error) {
24
+ this.logError({
25
+ run,
26
+ message: `Failed to write function event ${event.callId}`,
27
+ error,
28
+ });
29
+ }
30
+ }
31
+ async logError(options) {
32
+ const timestamp = Date.now();
33
+ try {
34
+ const logPath = this.logPath(options.run);
35
+ return node_fs_1.promises.writeFile((0, node_path_1.join)(logPath, `${timestamp}-error.json`), JSON.stringify({
36
+ timestamp: new Date(timestamp).toISOString(),
37
+ runId: options.run.runId,
38
+ message: options.message,
39
+ error: options.error,
40
+ }));
41
+ }
42
+ catch (error) {
43
+ console.error(`Failed to write error log`);
44
+ console.error(error);
45
+ }
46
+ }
47
+ }
48
+ exports.FileSystemLogger = FileSystemLogger;
@@ -0,0 +1,18 @@
1
+ import { FunctionEvent } from "../../core/FunctionEvent.js";
2
+ import { FlowRun } from "./FlowRun.js";
3
+ import { Logger } from "./Logger.js";
4
+ export declare class FileSystemLogger implements Logger {
5
+ private readonly logPath;
6
+ constructor({ path }: {
7
+ path: (run: FlowRun<unknown>) => string;
8
+ });
9
+ logFunctionEvent({ run, event, }: {
10
+ run: FlowRun<unknown>;
11
+ event: FunctionEvent;
12
+ }): Promise<void>;
13
+ logError(options: {
14
+ run: FlowRun<unknown>;
15
+ message: string;
16
+ error: unknown;
17
+ }): Promise<void>;
18
+ }