@yetter/client 0.0.11 → 0.0.13

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/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export { YetterImageClient } from "./api.js";
2
2
  export * from "./types.js";
3
- export { yetter } from "./client.js";
3
+ export { yetter, YetterClient } from "./client.js";
4
+ export type { UploadOptions, GetUploadUrlRequest, GetUploadUrlResponse, UploadCompleteRequest, UploadCompleteResponse, } from "./types.js";
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  export { YetterImageClient } from "./api.js";
2
2
  export * from "./types.js";
3
- export { yetter } from "./client.js";
3
+ export { yetter, YetterClient } from "./client.js";
package/dist/types.d.ts CHANGED
@@ -58,6 +58,7 @@ export interface SubscribeOptions {
58
58
  input: Omit<GenerateRequest, 'model'>;
59
59
  logs?: boolean;
60
60
  onQueueUpdate?: (update: GetStatusResponse) => void;
61
+ pollIntervalMs?: number;
61
62
  }
62
63
  export interface SubmitQueueOptions {
63
64
  input: Omit<GenerateRequest, 'model'>;
@@ -90,3 +91,65 @@ export interface YetterStream extends AsyncIterable<StreamEvent> {
90
91
  cancel(): Promise<void>;
91
92
  getRequestId(): string;
92
93
  }
94
+ /**
95
+ * Options for yetter.uploadFile() and yetter.uploadBlob()
96
+ */
97
+ export interface UploadOptions {
98
+ /** Optional callback for upload progress (0-100) */
99
+ onProgress?: (progress: number) => void;
100
+ /** Optional upload timeout in milliseconds (default: 5 minutes) */
101
+ timeout?: number;
102
+ /** Optional custom filename (browser File uploads) */
103
+ filename?: string;
104
+ }
105
+ /**
106
+ * Request to get presigned upload URL(s)
107
+ */
108
+ export interface GetUploadUrlRequest {
109
+ /** Original filename with extension */
110
+ file_name: string;
111
+ /** MIME type (e.g., "image/jpeg") */
112
+ content_type: string;
113
+ /** File size in bytes */
114
+ size: number;
115
+ }
116
+ /**
117
+ * Response containing presigned URL(s) for upload
118
+ */
119
+ export interface GetUploadUrlResponse {
120
+ /** Upload mode: "single" for small files, "multipart" for large files */
121
+ mode: "single" | "multipart";
122
+ /** S3 object key for tracking */
123
+ key: string;
124
+ /** Presigned PUT URL (single mode only) */
125
+ put_url?: string;
126
+ /** Size of each part in bytes (multipart mode only) */
127
+ part_size?: number;
128
+ /** Array of part URLs with part numbers (multipart mode only) */
129
+ part_urls?: Array<{
130
+ part_number: number;
131
+ url: string;
132
+ }>;
133
+ }
134
+ /**
135
+ * Request to notify upload completion
136
+ */
137
+ export interface UploadCompleteRequest {
138
+ /** S3 object key from GetUploadUrlResponse */
139
+ key: string;
140
+ }
141
+ /**
142
+ * Response after successful upload completion
143
+ */
144
+ export interface UploadCompleteResponse {
145
+ /** Public URL to access the uploaded file */
146
+ url: string;
147
+ /** S3 object key */
148
+ key: string;
149
+ /** Optional metadata */
150
+ metadata?: {
151
+ size: number;
152
+ content_type: string;
153
+ uploaded_at?: string;
154
+ };
155
+ }
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@yetter/client",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "build": "tsc",
7
+ "test": "npm run build && node --test tests/*.test.mjs",
7
8
  "test:submit": "node --loader ts-node/esm examples/submit.ts",
8
9
  "test:subscribe": "node --loader ts-node/esm examples/subscribe.ts",
9
10
  "test:stream": "node --loader ts-node/esm examples/stream.ts",
@@ -11,6 +12,10 @@
11
12
  },
12
13
  "main": "dist/index.js",
13
14
  "types": "dist/index.d.ts",
15
+ "files": [
16
+ "dist",
17
+ "README.md"
18
+ ],
14
19
  "exports": {
15
20
  ".": {
16
21
  "import": "./dist/index.js",
@@ -23,9 +28,11 @@
23
28
  "description": "",
24
29
  "dependencies": {
25
30
  "@types/eventsource": "^1.1.15",
31
+ "@types/mime-types": "^3.0.1",
26
32
  "cross-fetch": "^4.1.0",
27
33
  "event-source-polyfill": "^1.0.31",
28
- "eventsource": "^4.0.0"
34
+ "eventsource": "^4.0.0",
35
+ "mime-types": "^3.0.2"
29
36
  },
30
37
  "devDependencies": {
31
38
  "@types/event-source-polyfill": "^1.0.5",
@@ -1,54 +0,0 @@
1
- import { yetter } from "../src/client.js";
2
-
3
- async function main() {
4
- const model = "ytr-ai/flux/dev";
5
- console.log("\n--- Starting Stream Test ---");
6
- console.time("Stream Test");
7
- let streamRequestId = "";
8
-
9
- try {
10
- const streamInstance = await yetter.stream(model, {
11
- input: {
12
- prompt: "a bioluminescent forest at night, fantasy art",
13
- num_inference_steps: 28,
14
- },
15
- });
16
- streamRequestId = streamInstance.getRequestId();
17
- console.log(`[${new Date().toLocaleTimeString()}] Stream initiated for Request ID: ${streamRequestId}`);
18
-
19
- // Iterate over stream events
20
- for await (const event of streamInstance) {
21
- console.log(`[${new Date().toLocaleTimeString()}][STREAM EVENT - ${streamRequestId}] Status: ${event.status}, QPos: ${event.queue_position}`);
22
- if (event.logs && event.logs.length > 0) {
23
- console.log(` Logs for ${streamRequestId}:`);
24
- event.logs.forEach(log => console.log(` - ${log.message}`));
25
- }
26
- }
27
- console.log(`[${new Date().toLocaleTimeString()}] Stream for ${streamRequestId} finished iterating events.`);
28
-
29
- // Wait for the final result from the done() method
30
- console.log(`[${new Date().toLocaleTimeString()}] Waiting for done() on stream for ${streamRequestId}...`);
31
- const result = await streamInstance.done();
32
- console.log("\n--- Stream Test Final Result ---");
33
- console.log(`Request ID: ${streamRequestId}`);
34
- if (result.images && result.images.length > 0) {
35
- console.log("Generated Images:", result.images);
36
- } else {
37
- console.log("No images in final result.");
38
- }''
39
- console.log("Original Prompt:", result.prompt);
40
- console.timeEnd("Stream Test");
41
- } catch (err: any) {
42
- console.error(`\n--- Stream Test Failed (Request ID: ${streamRequestId || 'UNKNOWN'}) ---`);
43
- console.error("Error during stream test:", err.message || err);
44
- if (err.stack) {
45
- console.error(err.stack);
46
- }
47
- process.exit(1);
48
- }
49
- }
50
-
51
- main().catch(err => {
52
- console.error("Unhandled error in main:", err);
53
- process.exit(1);
54
- });
@@ -1,80 +0,0 @@
1
- import { yetter } from "../src/client.js";
2
-
3
- async function main() {
4
- const model = "ytr-ai/flux/dev";
5
- // Queue Submit test
6
- try {
7
- console.log("\n--- Starting Queue Submit Test ---");
8
- const { request_id, status, queue_position } = await yetter.queue.submit(model, {
9
- input: {
10
- prompt: "a fluffy white kitten playing with a yarn ball",
11
- num_inference_steps: 28,
12
- },
13
- });
14
-
15
- console.log("\n--- Queue Submit Test Result ---");
16
- console.log("Request ID:", request_id);
17
- console.log("Status:", status);
18
- console.log("Queue Position:", queue_position);
19
-
20
- if (request_id) {
21
- console.log(`\n--- Polling for status of Request ID: ${request_id} (3-minute timeout) ---`);
22
-
23
- const startTime = Date.now();
24
- const timeoutMilliseconds = 3 * 60 * 1000; // 3 minutes
25
- const pollIntervalMilliseconds = 10 * 1000; // Poll every 10 seconds
26
- let success = false;
27
-
28
- while (Date.now() - startTime < timeoutMilliseconds) {
29
- try {
30
- const statusResult = await yetter.queue.status(model, {
31
- requestId: request_id,
32
- });
33
- const currentStatus = statusResult.data.status;
34
- console.log(`[${new Date().toLocaleTimeString()}] Request ${request_id} status: ${currentStatus}, Queue Position: ${statusResult.data.queue_position}`);
35
-
36
- if (currentStatus === "COMPLETED") {
37
- console.log("Status is COMPLETED. Fetching final result...");
38
- const finalResult = await yetter.queue.result(model, {
39
- requestId: request_id,
40
- });
41
- console.log("\n--- Get Result Test Succeeded ---");
42
- console.log("Request ID:", finalResult.requestId);
43
- console.log("Image Data:", finalResult.data.images);
44
- console.log("Prompt:", finalResult.data.prompt);
45
- success = true;
46
- break; // Exit loop on success
47
- } else if (currentStatus === "FAILED") {
48
- console.error(`Request ${request_id} FAILED. Logs:`, statusResult.data.logs);
49
- break; // Exit loop on failure
50
- }
51
- // For other statuses (e.g., IN_QUEUE, IN_PROGRESS), continue polling
52
-
53
- } catch (pollError: any) {
54
- console.error(`Error during status polling for ${request_id} (will retry):`, pollError.message || pollError);
55
- }
56
-
57
- if (Date.now() - startTime + pollIntervalMilliseconds >= timeoutMilliseconds) {
58
- if (!success) console.error("Timeout approaching, last poll cycle completed or error occurred.");
59
- break; // Don't wait if the next interval exceeds timeout
60
- }
61
- await new Promise(resolve => setTimeout(resolve, pollIntervalMilliseconds));
62
- }
63
-
64
- if (!success) {
65
- console.error(`\n--- Polling Timed Out or Failed for Request ID: ${request_id} ---`);
66
- console.error(`Failed to get a COMPLETED status for ${request_id} within 3 minutes.`);
67
- }
68
- }
69
-
70
- } catch (err: any) {
71
- console.error("\n--- Queue Submit Test Failed ---");
72
- console.error("Error during queue submit:", err.message || err);
73
- if (err.stack) {
74
- console.error(err.stack);
75
- }
76
- process.exit(1);
77
- }
78
- }
79
-
80
- main();
@@ -1,41 +0,0 @@
1
- import { yetter } from "../dist/index.js";
2
-
3
- async function main() {
4
- const model = "ytr-ai/flux/dev";
5
- // Subscribe test
6
- try {
7
- console.log("\n--- Starting Subscribe Test ---");
8
- console.time("Subscribe Test");
9
- const result = await yetter.subscribe(model, {
10
- input: {
11
- prompt: "a vibrant coral reef, underwater photography",
12
- num_inference_steps: 28,
13
- },
14
- logs: true,
15
- onQueueUpdate: (update) => {
16
- console.log(`[Queue Update] Status: ${update.status}, Position: ${update.queue_position}`);
17
- if (update.status === "IN_PROGRESS" && update.logs) {
18
- console.log("Logs:");
19
- update.logs.map((log) => log.message).forEach(logMessage => console.log(` - ${logMessage}`));
20
- } else if (update.status === "COMPLETED") {
21
- console.log("Processing completed!");
22
- } else if (update.status === "FAILED") {
23
- console.error("Processing failed. Logs:", update.logs);
24
- }
25
- },
26
- });
27
-
28
- console.log("\n--- Subscribe Test Result ---");
29
- console.log("Results:", result);
30
- console.timeEnd("Subscribe Test");
31
- } catch (err: any) {
32
- console.error("\n--- Subscribe Test Failed ---");
33
- console.error("Error during subscribe:", err.message || err);
34
- if (err.stack) {
35
- console.error(err.stack);
36
- }
37
- process.exit(1);
38
- }
39
- }
40
-
41
- main();
package/src/api.ts DELETED
@@ -1,105 +0,0 @@
1
- import fetch from "cross-fetch";
2
- import {
3
- ClientOptions,
4
- GenerateRequest,
5
- GenerateResponse,
6
- GetStatusRequest,
7
- GetStatusResponse,
8
- CancelRequest,
9
- CancelResponse,
10
- GetResponseRequest,
11
- GetResponseResponse,
12
- } from "./types";
13
-
14
- export class YetterImageClient {
15
- private apiKey: string;
16
- private endpoint: string;
17
-
18
- constructor(options: ClientOptions) {
19
- if (!options.apiKey) {
20
- throw new Error("`apiKey` is required");
21
- }
22
- this.apiKey = options.apiKey;
23
- this.endpoint = options.endpoint || "https://api.yetter.ai";
24
- }
25
-
26
- public getApiEndpoint(): string {
27
- return this.endpoint;
28
- }
29
-
30
- public async generate(
31
- body: GenerateRequest
32
- ): Promise<GenerateResponse> {
33
- const url = `${this.endpoint}/${body.model}`;
34
- const res = await fetch(url, {
35
- method: "POST",
36
- headers: {
37
- "Content-Type": "application/json",
38
- Authorization: this.apiKey,
39
- },
40
- body: JSON.stringify(body),
41
- });
42
-
43
- if (!res.ok) {
44
- const errorText = await res.text();
45
- throw new Error(`API error (${res.status}): ${errorText}`);
46
- }
47
-
48
- return (await res.json()) as GenerateResponse;
49
- }
50
-
51
- public async getStatus(body: GetStatusRequest): Promise<GetStatusResponse> {
52
- const url = new URL(body.url);
53
- if (body.logs) {
54
- url.searchParams.append('logs', '1');
55
- }
56
-
57
- const res = await fetch(url.toString(), {
58
- method: "GET",
59
- headers: {
60
- "Content-Type": "application/json",
61
- Authorization: this.apiKey,
62
- },
63
- });
64
-
65
- if (!res.ok) {
66
- const errorText = await res.text();
67
- throw new Error(`API error (${res.status}): ${errorText}`);
68
- }
69
-
70
- return (await res.json()) as GetStatusResponse;
71
- }
72
-
73
- public async cancel(body: CancelRequest): Promise<CancelResponse> {
74
- const res = await fetch(body.url, {
75
- method: "PUT",
76
- headers: {
77
- "Content-Type": "application/json",
78
- Authorization: this.apiKey,
79
- },
80
- });
81
-
82
- if (!res.ok) {
83
- const errorText = await res.text();
84
- throw new Error(`API error (${res.status}): ${errorText}`);
85
- }
86
-
87
- return (await res.json()) as CancelResponse;
88
- }
89
-
90
- public async getResponse(body: GetResponseRequest): Promise<GetResponseResponse> {
91
- const res = await fetch(body.url, {
92
- method: "GET",
93
- headers: {
94
- "Content-Type": "application/json",
95
- Authorization: this.apiKey,
96
- },
97
- });
98
-
99
- if (!res.ok) {
100
- const errorText = await res.text();
101
- throw new Error(`API error (${res.status}): ${errorText}`);
102
- }
103
- return (await res.json()) as GetResponseResponse;
104
- }
105
- }