@inferencesh/app 0.1.2 → 0.1.4
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/dist/file.d.ts +1 -0
- package/dist/file.js +85 -2
- package/dist/index.d.ts +1 -2
- package/dist/index.js +2 -1
- package/dist/output-meta.d.ts +14 -36
- package/dist/output-meta.js +4 -3
- package/dist/types.d.ts +68 -0
- package/dist/types.js +11 -0
- package/package.json +2 -1
- package/dist/test/file.test.d.ts +0 -1
- package/dist/test/file.test.js +0 -70
- package/dist/test/output-meta.test.d.ts +0 -1
- package/dist/test/output-meta.test.js +0 -48
- package/dist/test/storage.test.d.ts +0 -1
- package/dist/test/storage.test.js +0 -10
package/dist/file.d.ts
CHANGED
package/dist/file.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { createWriteStream, existsSync, mkdirSync, statSync, renameSync, unlinkSync } from "node:fs";
|
|
2
|
+
import { createWriteStream, existsSync, mkdirSync, statSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { basename, resolve, join } from "node:path";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
import { get as httpsGet } from "node:https";
|
|
@@ -74,7 +74,10 @@ export class File {
|
|
|
74
74
|
const file = new File(options);
|
|
75
75
|
// Resolve URI
|
|
76
76
|
if (file.uri) {
|
|
77
|
-
if (
|
|
77
|
+
if (isDataUri(file.uri)) {
|
|
78
|
+
file._decodeDataUri(file.uri);
|
|
79
|
+
}
|
|
80
|
+
else if (isUrl(file.uri)) {
|
|
78
81
|
await file._downloadUrl(file.uri);
|
|
79
82
|
}
|
|
80
83
|
else {
|
|
@@ -148,6 +151,32 @@ export class File {
|
|
|
148
151
|
mkdirSync(hashDir, { recursive: true });
|
|
149
152
|
return join(hashDir, fname);
|
|
150
153
|
}
|
|
154
|
+
// --- Data URI ---
|
|
155
|
+
_decodeDataUri(uri) {
|
|
156
|
+
const parsed = parseDataUri(uri);
|
|
157
|
+
// Create cache path based on hash
|
|
158
|
+
const hash = createHash("sha256").update(uri).digest("hex").slice(0, 16);
|
|
159
|
+
const cacheDir = join(File.getCacheDir(), "data_uri", hash);
|
|
160
|
+
// Check for existing cached file
|
|
161
|
+
if (existsSync(cacheDir)) {
|
|
162
|
+
const files = require("node:fs").readdirSync(cacheDir);
|
|
163
|
+
if (files.length > 0) {
|
|
164
|
+
this.path = join(cacheDir, files[0]);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// Set content type from data URI
|
|
169
|
+
if (!this.contentType) {
|
|
170
|
+
this.contentType = parsed.mediaType;
|
|
171
|
+
}
|
|
172
|
+
// Write to cache
|
|
173
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
174
|
+
const ext = getExtensionForMimeType(parsed.mediaType);
|
|
175
|
+
const filename = `file${ext}`;
|
|
176
|
+
const cachePath = join(cacheDir, filename);
|
|
177
|
+
writeFileSync(cachePath, parsed.data);
|
|
178
|
+
this.path = cachePath;
|
|
179
|
+
}
|
|
151
180
|
// --- Download ---
|
|
152
181
|
async _downloadUrl(url) {
|
|
153
182
|
const cachePath = this._getCachePath(url);
|
|
@@ -191,6 +220,60 @@ export class File {
|
|
|
191
220
|
function isUrl(s) {
|
|
192
221
|
return s.startsWith("http://") || s.startsWith("https://");
|
|
193
222
|
}
|
|
223
|
+
function isDataUri(s) {
|
|
224
|
+
return s.startsWith("data:");
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Parse a data URI and return the media type and decoded data.
|
|
228
|
+
*
|
|
229
|
+
* Supports formats:
|
|
230
|
+
* - data:image/jpeg;base64,/9j/4AAQ...
|
|
231
|
+
* - data:text/plain,Hello%20World
|
|
232
|
+
* - data:;base64,SGVsbG8= (defaults to text/plain)
|
|
233
|
+
*/
|
|
234
|
+
function parseDataUri(uri) {
|
|
235
|
+
const match = uri.match(/^data:([^;,]*)?(?:;(base64))?,(.*)$/s);
|
|
236
|
+
if (!match) {
|
|
237
|
+
throw new Error("Invalid data URI format");
|
|
238
|
+
}
|
|
239
|
+
const mediaType = match[1] || "text/plain";
|
|
240
|
+
const isBase64 = match[2] === "base64";
|
|
241
|
+
let dataStr = match[3];
|
|
242
|
+
if (isBase64) {
|
|
243
|
+
// Handle URL-safe base64 (- and _ instead of + and /)
|
|
244
|
+
dataStr = dataStr.replace(/-/g, "+").replace(/_/g, "/");
|
|
245
|
+
// Add padding if needed
|
|
246
|
+
const padding = 4 - (dataStr.length % 4);
|
|
247
|
+
if (padding !== 4) {
|
|
248
|
+
dataStr += "=".repeat(padding);
|
|
249
|
+
}
|
|
250
|
+
return { mediaType, data: Buffer.from(dataStr, "base64") };
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
// URL-encoded data
|
|
254
|
+
return { mediaType, data: Buffer.from(decodeURIComponent(dataStr), "utf-8") };
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
const EXTENSION_MAP = {
|
|
258
|
+
"image/jpeg": ".jpg",
|
|
259
|
+
"image/png": ".png",
|
|
260
|
+
"image/gif": ".gif",
|
|
261
|
+
"image/webp": ".webp",
|
|
262
|
+
"image/svg+xml": ".svg",
|
|
263
|
+
"video/mp4": ".mp4",
|
|
264
|
+
"video/webm": ".webm",
|
|
265
|
+
"audio/mpeg": ".mp3",
|
|
266
|
+
"audio/wav": ".wav",
|
|
267
|
+
"audio/ogg": ".ogg",
|
|
268
|
+
"application/pdf": ".pdf",
|
|
269
|
+
"application/json": ".json",
|
|
270
|
+
"text/plain": ".txt",
|
|
271
|
+
"text/html": ".html",
|
|
272
|
+
"text/csv": ".csv",
|
|
273
|
+
};
|
|
274
|
+
function getExtensionForMimeType(mimeType) {
|
|
275
|
+
return EXTENSION_MAP[mimeType] || "";
|
|
276
|
+
}
|
|
194
277
|
function downloadToFile(url, destPath) {
|
|
195
278
|
return new Promise((resolve, reject) => {
|
|
196
279
|
const parsed = new URL(url);
|
package/dist/index.d.ts
CHANGED
|
@@ -3,5 +3,4 @@ export type { FileOptions, FileData } from "./file.js";
|
|
|
3
3
|
export { StorageDir, ensureDir } from "./storage.js";
|
|
4
4
|
export type { StorageDirValue } from "./storage.js";
|
|
5
5
|
export { download } from "./download.js";
|
|
6
|
-
export
|
|
7
|
-
export type { OutputMeta, MetaItem, MetaItemBase, TextMeta, ImageMeta, VideoMeta, AudioMeta, RawMeta, } from "./output-meta.js";
|
|
6
|
+
export * from "./output-meta.js";
|
package/dist/index.js
CHANGED
|
@@ -5,4 +5,5 @@ export { StorageDir, ensureDir } from "./storage.js";
|
|
|
5
5
|
// Download utility
|
|
6
6
|
export { download } from "./download.js";
|
|
7
7
|
// Output metadata for usage-based pricing
|
|
8
|
-
|
|
8
|
+
// (includes generated types + factory functions)
|
|
9
|
+
export * from "./output-meta.js";
|
package/dist/output-meta.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Output metadata types for usage-based pricing.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* pricing calculation.
|
|
4
|
+
* Types are generated from Go source of truth (common-go/pkg/models/usage.go)
|
|
5
|
+
* via `make types`. Factory functions provide type-safe constructors.
|
|
7
6
|
*
|
|
8
7
|
* @example
|
|
9
8
|
* ```js
|
|
@@ -18,45 +17,24 @@
|
|
|
18
17
|
* };
|
|
19
18
|
* ```
|
|
20
19
|
*/
|
|
21
|
-
export
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
export interface TextMeta extends MetaItemBase {
|
|
20
|
+
export * from "./types.js";
|
|
21
|
+
import type { MetaItem } from "./types.js";
|
|
22
|
+
export type TextMeta = MetaItem & {
|
|
26
23
|
type: "text";
|
|
27
24
|
tokens: number;
|
|
28
|
-
}
|
|
29
|
-
export
|
|
25
|
+
};
|
|
26
|
+
export type ImageMeta = MetaItem & {
|
|
30
27
|
type: "image";
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
resolution_mp?: number;
|
|
34
|
-
steps?: number;
|
|
35
|
-
count?: number;
|
|
36
|
-
}
|
|
37
|
-
export interface VideoMeta extends MetaItemBase {
|
|
28
|
+
};
|
|
29
|
+
export type VideoMeta = MetaItem & {
|
|
38
30
|
type: "video";
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
resolution_mp?: number;
|
|
42
|
-
resolution?: "480p" | "720p" | "1080p" | "1440p" | "4k";
|
|
43
|
-
seconds?: number;
|
|
44
|
-
fps?: number;
|
|
45
|
-
}
|
|
46
|
-
export interface AudioMeta extends MetaItemBase {
|
|
31
|
+
};
|
|
32
|
+
export type AudioMeta = MetaItem & {
|
|
47
33
|
type: "audio";
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
export interface RawMeta extends MetaItemBase {
|
|
34
|
+
};
|
|
35
|
+
export type RawMeta = MetaItem & {
|
|
52
36
|
type: "raw";
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
export type MetaItem = TextMeta | ImageMeta | VideoMeta | AudioMeta | RawMeta;
|
|
56
|
-
export interface OutputMeta {
|
|
57
|
-
inputs?: MetaItem[];
|
|
58
|
-
outputs?: MetaItem[];
|
|
59
|
-
}
|
|
37
|
+
};
|
|
60
38
|
/** Create a text metadata item. */
|
|
61
39
|
export declare function textMeta(opts: Omit<TextMeta, "type">): TextMeta;
|
|
62
40
|
/** Create an image metadata item. */
|
package/dist/output-meta.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Output metadata types for usage-based pricing.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* pricing calculation.
|
|
4
|
+
* Types are generated from Go source of truth (common-go/pkg/models/usage.go)
|
|
5
|
+
* via `make types`. Factory functions provide type-safe constructors.
|
|
7
6
|
*
|
|
8
7
|
* @example
|
|
9
8
|
* ```js
|
|
@@ -18,6 +17,8 @@
|
|
|
18
17
|
* };
|
|
19
18
|
* ```
|
|
20
19
|
*/
|
|
20
|
+
// Re-export all generated types (MetaItem, MetaItemType, OutputMeta, VideoResolution, constants)
|
|
21
|
+
export * from "./types.js";
|
|
21
22
|
// --- Factories ---
|
|
22
23
|
/** Create a text metadata item. */
|
|
23
24
|
export function textMeta(opts) {
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export interface AppSDKTypes {
|
|
2
|
+
}
|
|
3
|
+
/**
|
|
4
|
+
* MetaItemType is the type discriminator for MetaItem
|
|
5
|
+
*/
|
|
6
|
+
export type MetaItemType = string;
|
|
7
|
+
export declare const MetaItemTypeText: MetaItemType;
|
|
8
|
+
export declare const MetaItemTypeImage: MetaItemType;
|
|
9
|
+
export declare const MetaItemTypeVideo: MetaItemType;
|
|
10
|
+
export declare const MetaItemTypeAudio: MetaItemType;
|
|
11
|
+
export declare const MetaItemTypeRaw: MetaItemType;
|
|
12
|
+
/**
|
|
13
|
+
* VideoResolution represents standard video resolution presets
|
|
14
|
+
*/
|
|
15
|
+
export type VideoResolution = string;
|
|
16
|
+
export declare const VideoRes480P: VideoResolution;
|
|
17
|
+
export declare const VideoRes720P: VideoResolution;
|
|
18
|
+
export declare const VideoRes1080P: VideoResolution;
|
|
19
|
+
export declare const VideoRes1440P: VideoResolution;
|
|
20
|
+
export declare const VideoRes4K: VideoResolution;
|
|
21
|
+
/**
|
|
22
|
+
* MetaItem represents metadata about an input or output item
|
|
23
|
+
*/
|
|
24
|
+
export interface MetaItem {
|
|
25
|
+
type: MetaItemType;
|
|
26
|
+
/**
|
|
27
|
+
* Text fields
|
|
28
|
+
*/
|
|
29
|
+
tokens?: number;
|
|
30
|
+
/**
|
|
31
|
+
* Image/Video shared fields
|
|
32
|
+
*/
|
|
33
|
+
width?: number;
|
|
34
|
+
height?: number;
|
|
35
|
+
resolution_mp?: number;
|
|
36
|
+
/**
|
|
37
|
+
* Image specific fields
|
|
38
|
+
*/
|
|
39
|
+
steps?: number;
|
|
40
|
+
count?: number;
|
|
41
|
+
/**
|
|
42
|
+
* Video specific fields
|
|
43
|
+
*/
|
|
44
|
+
resolution?: VideoResolution;
|
|
45
|
+
seconds?: number;
|
|
46
|
+
fps?: number;
|
|
47
|
+
/**
|
|
48
|
+
* Audio specific fields
|
|
49
|
+
*/
|
|
50
|
+
sample_rate?: number;
|
|
51
|
+
/**
|
|
52
|
+
* Raw specific fields
|
|
53
|
+
*/
|
|
54
|
+
cost?: number;
|
|
55
|
+
/**
|
|
56
|
+
* App-specific key-value pairs for custom pricing factors
|
|
57
|
+
*/
|
|
58
|
+
extra?: {
|
|
59
|
+
[key: string]: any;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* OutputMeta contains structured metadata about task inputs and outputs for pricing calculation
|
|
64
|
+
*/
|
|
65
|
+
export interface OutputMeta {
|
|
66
|
+
inputs: MetaItem[];
|
|
67
|
+
outputs: MetaItem[];
|
|
68
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Code generated by tygo. DO NOT EDIT.
|
|
2
|
+
export const MetaItemTypeText = "text";
|
|
3
|
+
export const MetaItemTypeImage = "image";
|
|
4
|
+
export const MetaItemTypeVideo = "video";
|
|
5
|
+
export const MetaItemTypeAudio = "audio";
|
|
6
|
+
export const MetaItemTypeRaw = "raw";
|
|
7
|
+
export const VideoRes480P = "480p";
|
|
8
|
+
export const VideoRes720P = "720p";
|
|
9
|
+
export const VideoRes1080P = "1080p";
|
|
10
|
+
export const VideoRes1440P = "1440p";
|
|
11
|
+
export const VideoRes4K = "4k";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inferencesh/app",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "App framework for building inference.sh apps — File handling, output metadata, storage utilities",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
},
|
|
47
47
|
"files": [
|
|
48
48
|
"dist",
|
|
49
|
+
"!dist/test",
|
|
49
50
|
"README.md",
|
|
50
51
|
"LICENSE"
|
|
51
52
|
]
|
package/dist/test/file.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/test/file.test.js
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { describe, it, before, after } from "node:test";
|
|
2
|
-
import assert from "node:assert";
|
|
3
|
-
import { writeFileSync, mkdirSync, rmSync } from "node:fs";
|
|
4
|
-
import { join } from "node:path";
|
|
5
|
-
import { tmpdir } from "node:os";
|
|
6
|
-
import { File } from "../file.js";
|
|
7
|
-
const TEST_DIR = join(tmpdir(), "inferencesh-app-test-" + Date.now());
|
|
8
|
-
let testFile;
|
|
9
|
-
describe("File", () => {
|
|
10
|
-
before(() => {
|
|
11
|
-
mkdirSync(TEST_DIR, { recursive: true });
|
|
12
|
-
testFile = join(TEST_DIR, "hello.txt");
|
|
13
|
-
writeFileSync(testFile, "hello world");
|
|
14
|
-
});
|
|
15
|
-
after(() => {
|
|
16
|
-
rmSync(TEST_DIR, { recursive: true, force: true });
|
|
17
|
-
});
|
|
18
|
-
it("creates from local path", () => {
|
|
19
|
-
const file = File.fromPath(testFile);
|
|
20
|
-
assert.ok(file.path);
|
|
21
|
-
assert.ok(file.exists());
|
|
22
|
-
assert.strictEqual(file.filename, "hello.txt");
|
|
23
|
-
assert.strictEqual(file.contentType, "text/plain");
|
|
24
|
-
assert.strictEqual(file.size, 11);
|
|
25
|
-
});
|
|
26
|
-
it("creates from path via async from()", async () => {
|
|
27
|
-
const file = await File.from(testFile);
|
|
28
|
-
assert.ok(file.path);
|
|
29
|
-
assert.ok(file.exists());
|
|
30
|
-
assert.strictEqual(file.filename, "hello.txt");
|
|
31
|
-
});
|
|
32
|
-
it("creates from options object", async () => {
|
|
33
|
-
const file = await File.from({ path: testFile, contentType: "text/plain" });
|
|
34
|
-
assert.ok(file.exists());
|
|
35
|
-
assert.strictEqual(file.contentType, "text/plain");
|
|
36
|
-
});
|
|
37
|
-
it("creates from FileData with content_type (snake_case)", async () => {
|
|
38
|
-
const file = await File.from({ path: testFile, content_type: "application/octet-stream" });
|
|
39
|
-
assert.strictEqual(file.contentType, "application/octet-stream");
|
|
40
|
-
});
|
|
41
|
-
it("creates from another File", async () => {
|
|
42
|
-
const original = File.fromPath(testFile);
|
|
43
|
-
const copy = await File.from(original);
|
|
44
|
-
assert.strictEqual(copy.path, original.path);
|
|
45
|
-
assert.strictEqual(copy.filename, original.filename);
|
|
46
|
-
});
|
|
47
|
-
it("serializes to JSON with snake_case", () => {
|
|
48
|
-
const file = File.fromPath(testFile);
|
|
49
|
-
const json = file.toJSON();
|
|
50
|
-
assert.ok(json.path);
|
|
51
|
-
assert.strictEqual(json.content_type, "text/plain");
|
|
52
|
-
assert.strictEqual(json.size, 11);
|
|
53
|
-
assert.strictEqual(json.filename, "hello.txt");
|
|
54
|
-
assert.strictEqual(json.uri, undefined);
|
|
55
|
-
});
|
|
56
|
-
it("works with JSON.stringify", () => {
|
|
57
|
-
const file = File.fromPath(testFile);
|
|
58
|
-
const str = JSON.stringify({ image: file });
|
|
59
|
-
const parsed = JSON.parse(str);
|
|
60
|
-
assert.ok(parsed.image.path);
|
|
61
|
-
assert.strictEqual(parsed.image.content_type, "text/plain");
|
|
62
|
-
});
|
|
63
|
-
it("resolves relative paths to absolute", () => {
|
|
64
|
-
const file = File.fromPath("./package.json");
|
|
65
|
-
assert.ok(file.path.startsWith("/"));
|
|
66
|
-
});
|
|
67
|
-
it("throws on missing path and uri", async () => {
|
|
68
|
-
await assert.rejects(() => File.from({}), /Either 'uri' or 'path' must be provided/);
|
|
69
|
-
});
|
|
70
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { describe, it } from "node:test";
|
|
2
|
-
import assert from "node:assert";
|
|
3
|
-
import { textMeta, imageMeta, videoMeta, audioMeta, rawMeta } from "../output-meta.js";
|
|
4
|
-
describe("OutputMeta", () => {
|
|
5
|
-
it("creates text meta", () => {
|
|
6
|
-
const meta = textMeta({ tokens: 150 });
|
|
7
|
-
assert.strictEqual(meta.type, "text");
|
|
8
|
-
assert.strictEqual(meta.tokens, 150);
|
|
9
|
-
});
|
|
10
|
-
it("creates image meta", () => {
|
|
11
|
-
const meta = imageMeta({ width: 1024, height: 1024, steps: 20, count: 1 });
|
|
12
|
-
assert.strictEqual(meta.type, "image");
|
|
13
|
-
assert.strictEqual(meta.width, 1024);
|
|
14
|
-
assert.strictEqual(meta.steps, 20);
|
|
15
|
-
});
|
|
16
|
-
it("creates video meta", () => {
|
|
17
|
-
const meta = videoMeta({ resolution: "1080p", seconds: 5.0 });
|
|
18
|
-
assert.strictEqual(meta.type, "video");
|
|
19
|
-
assert.strictEqual(meta.resolution, "1080p");
|
|
20
|
-
});
|
|
21
|
-
it("creates audio meta", () => {
|
|
22
|
-
const meta = audioMeta({ seconds: 30.0 });
|
|
23
|
-
assert.strictEqual(meta.type, "audio");
|
|
24
|
-
assert.strictEqual(meta.seconds, 30.0);
|
|
25
|
-
});
|
|
26
|
-
it("creates raw meta", () => {
|
|
27
|
-
const meta = rawMeta({ cost: 0.5 });
|
|
28
|
-
assert.strictEqual(meta.type, "raw");
|
|
29
|
-
assert.strictEqual(meta.cost, 0.5);
|
|
30
|
-
});
|
|
31
|
-
it("supports extra data", () => {
|
|
32
|
-
const meta = imageMeta({ width: 512, height: 512, extra: { model: "sdxl" } });
|
|
33
|
-
assert.strictEqual(meta.extra?.model, "sdxl");
|
|
34
|
-
});
|
|
35
|
-
it("composes into OutputMeta", () => {
|
|
36
|
-
const output = {
|
|
37
|
-
inputs: [textMeta({ tokens: 100 })],
|
|
38
|
-
outputs: [textMeta({ tokens: 500 }), imageMeta({ width: 1024, height: 1024 })],
|
|
39
|
-
};
|
|
40
|
-
assert.strictEqual(output.inputs.length, 1);
|
|
41
|
-
assert.strictEqual(output.outputs.length, 2);
|
|
42
|
-
// Serializes cleanly
|
|
43
|
-
const json = JSON.stringify(output);
|
|
44
|
-
const parsed = JSON.parse(json);
|
|
45
|
-
assert.strictEqual(parsed.inputs[0].type, "text");
|
|
46
|
-
assert.strictEqual(parsed.outputs[1].type, "image");
|
|
47
|
-
});
|
|
48
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { describe, it } from "node:test";
|
|
2
|
-
import assert from "node:assert";
|
|
3
|
-
import { StorageDir } from "../storage.js";
|
|
4
|
-
describe("StorageDir", () => {
|
|
5
|
-
it("has correct paths", () => {
|
|
6
|
-
assert.strictEqual(StorageDir.DATA, "/app/data");
|
|
7
|
-
assert.strictEqual(StorageDir.TEMP, "/app/tmp");
|
|
8
|
-
assert.strictEqual(StorageDir.CACHE, "/app/cache");
|
|
9
|
-
});
|
|
10
|
-
});
|