@seenn/node 0.1.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Seenn
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,188 @@
1
+ # @seenn/node
2
+
3
+ > **Open Source Backend SDK for Job State Transport**
4
+
5
+ [![npm version](https://badge.fury.io/js/@seenn%2Fnode.svg)](https://www.npmjs.com/package/@seenn/node)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ Real-time job progress tracking for AI video generation, image processing, and long-running async tasks.
9
+
10
+ ## Features
11
+
12
+ - **Fluent API** - Chain job updates naturally
13
+ - **Auto-retry** - Exponential backoff with jitter
14
+ - **TypeScript** - Full type definitions
15
+ - **Self-hosted** - Use with your own backend
16
+ - **Open Source** - MIT License
17
+
18
+ ---
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ npm install @seenn/node
24
+ # or
25
+ yarn add @seenn/node
26
+ # or
27
+ pnpm add @seenn/node
28
+ ```
29
+
30
+ ---
31
+
32
+ ## Quick Start
33
+
34
+ ### Seenn Cloud
35
+
36
+ ```typescript
37
+ import { SeennClient } from '@seenn/node';
38
+
39
+ const seenn = new SeennClient({
40
+ apiKey: 'sk_live_your_api_key',
41
+ });
42
+ ```
43
+
44
+ ### Self-Hosted (Your Own Backend)
45
+
46
+ ```typescript
47
+ import { SeennClient } from '@seenn/node';
48
+
49
+ const seenn = new SeennClient({
50
+ apiKey: 'sk_live_your_api_key',
51
+ baseUrl: 'https://api.yourapp.com', // Your backend URL
52
+ });
53
+ ```
54
+
55
+ ---
56
+
57
+ ## Usage
58
+
59
+ ### Start a Job
60
+
61
+ ```typescript
62
+ const job = await seenn.jobs.start({
63
+ jobType: 'video-generation',
64
+ userId: 'user_123',
65
+ title: 'Generating video...',
66
+ metadata: { prompt: 'A cat playing piano' },
67
+ queue: { position: 5, total: 20 },
68
+ stage: { name: 'queued', current: 1, total: 4 },
69
+ });
70
+
71
+ console.log(`Job started: ${job.id}`);
72
+ ```
73
+
74
+ ### Update Progress
75
+
76
+ ```typescript
77
+ await job.setProgress(50, {
78
+ message: 'Rendering frames...',
79
+ stage: { name: 'render', current: 2, total: 4 },
80
+ });
81
+ ```
82
+
83
+ ### Complete Job
84
+
85
+ ```typescript
86
+ await job.complete({
87
+ result: {
88
+ type: 'video',
89
+ url: 'https://cdn.example.com/video.mp4',
90
+ data: { duration: 30, resolution: '1080p' },
91
+ },
92
+ message: 'Video ready!',
93
+ });
94
+ ```
95
+
96
+ ### Fail Job
97
+
98
+ ```typescript
99
+ await job.fail({
100
+ error: {
101
+ code: 'RENDER_FAILED',
102
+ message: 'GPU memory exceeded',
103
+ details: { gpuMemory: '16GB', required: '24GB' },
104
+ },
105
+ retryable: true,
106
+ });
107
+ ```
108
+
109
+ ### Get / List Jobs
110
+
111
+ ```typescript
112
+ // Get single job
113
+ const job = await seenn.jobs.get('job_01ABC123');
114
+ console.log(job.status, job.progress);
115
+
116
+ // List user's jobs
117
+ const { jobs, nextCursor } = await seenn.jobs.list('user_123', {
118
+ limit: 20,
119
+ });
120
+ ```
121
+
122
+ ---
123
+
124
+ ## Configuration
125
+
126
+ ```typescript
127
+ const seenn = new SeennClient({
128
+ apiKey: string; // Required: sk_live_xxx or sk_test_xxx
129
+ baseUrl?: string; // Default: https://api.seenn.io
130
+ timeout?: number; // Default: 30000 (30s)
131
+ maxRetries?: number; // Default: 3
132
+ debug?: boolean; // Default: false
133
+ });
134
+ ```
135
+
136
+ ---
137
+
138
+ ## Error Handling
139
+
140
+ ```typescript
141
+ import { SeennError, RateLimitError, ValidationError, NotFoundError } from '@seenn/node';
142
+
143
+ try {
144
+ await seenn.jobs.start({ ... });
145
+ } catch (error) {
146
+ if (error instanceof RateLimitError) {
147
+ console.log(`Rate limited. Retry after ${error.retryAfter}s`);
148
+ } else if (error instanceof ValidationError) {
149
+ console.log('Invalid input:', error.details);
150
+ } else if (error instanceof NotFoundError) {
151
+ console.log('Job not found');
152
+ } else if (error instanceof SeennError) {
153
+ console.log(`Error ${error.code}: ${error.message}`);
154
+ }
155
+ }
156
+ ```
157
+
158
+ ---
159
+
160
+ ## Self-Hosted Requirements
161
+
162
+ To use this SDK with your own backend, implement these endpoints:
163
+
164
+ | Method | Endpoint | Description |
165
+ |--------|----------|-------------|
166
+ | POST | `/v1/jobs` | Create a new job |
167
+ | GET | `/v1/jobs/:id` | Get job by ID |
168
+ | GET | `/v1/jobs?userId=xxx` | List user's jobs |
169
+ | POST | `/v1/jobs/:id/progress` | Update job progress |
170
+ | POST | `/v1/jobs/:id/complete` | Mark job as completed |
171
+ | POST | `/v1/jobs/:id/fail` | Mark job as failed |
172
+
173
+ See [Self-Hosted Guide](https://docs.seenn.io/self-hosted) for full API specification.
174
+
175
+ ---
176
+
177
+ ## Links
178
+
179
+ - [Documentation](https://docs.seenn.io)
180
+ - [Website](https://seenn.io)
181
+ - [GitHub](https://github.com/seenn-io/node)
182
+ - [npm](https://www.npmjs.com/package/@seenn/node)
183
+
184
+ ---
185
+
186
+ ## License
187
+
188
+ MIT © [Seenn](https://seenn.io)
@@ -0,0 +1,43 @@
1
+ import { Job } from './job.js';
2
+ import type { StartJobParams } from './types.js';
3
+ export interface SeennConfig {
4
+ /** API key (sk_live_xxx or sk_test_xxx) */
5
+ apiKey: string;
6
+ /** Base URL (default: https://api.seenn.io) */
7
+ baseUrl?: string;
8
+ /** Request timeout in ms (default: 30000) */
9
+ timeout?: number;
10
+ /** Max retry attempts (default: 3) */
11
+ maxRetries?: number;
12
+ /** Enable debug logging */
13
+ debug?: boolean;
14
+ }
15
+ export declare class SeennClient {
16
+ private readonly http;
17
+ private readonly config;
18
+ constructor(config: SeennConfig);
19
+ /**
20
+ * Jobs resource
21
+ */
22
+ get jobs(): {
23
+ /**
24
+ * Start a new job
25
+ */
26
+ start: (params: StartJobParams) => Promise<Job>;
27
+ /**
28
+ * Get a job by ID
29
+ */
30
+ get: (jobId: string) => Promise<Job>;
31
+ /**
32
+ * List jobs for a user
33
+ */
34
+ list: (userId: string, options?: {
35
+ limit?: number;
36
+ cursor?: string;
37
+ }) => Promise<{
38
+ jobs: Job[];
39
+ nextCursor: string | undefined;
40
+ }>;
41
+ };
42
+ }
43
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,OAAO,KAAK,EAAE,cAAc,EAAe,MAAM,YAAY,CAAC;AAE9D,MAAM,WAAW,WAAW;IAC1B,2CAA2C;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sCAAsC;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwB;gBAEnC,MAAM,EAAE,WAAW;IAoB/B;;OAEG;IACH,IAAI,IAAI;QAEJ;;WAEG;wBACmB,cAAc,KAAG,OAAO,CAAC,GAAG,CAAC;QAKnD;;WAEG;qBACgB,MAAM,KAAG,OAAO,CAAC,GAAG,CAAC;QAKxC;;WAEG;uBACkB,MAAM,YAAY;YAAE,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAA;SAAE;;;;MAgB7E;CACF"}
package/dist/client.js ADDED
@@ -0,0 +1,59 @@
1
+ import { Job } from './job.js';
2
+ import { HttpClient } from './http.js';
3
+ export class SeennClient {
4
+ http;
5
+ config;
6
+ constructor(config) {
7
+ if (!config.apiKey) {
8
+ throw new Error('apiKey is required');
9
+ }
10
+ if (!config.apiKey.startsWith('sk_')) {
11
+ throw new Error('apiKey must start with sk_live_ or sk_test_');
12
+ }
13
+ this.config = {
14
+ apiKey: config.apiKey,
15
+ baseUrl: config.baseUrl || 'https://api.seenn.io',
16
+ timeout: config.timeout || 30000,
17
+ maxRetries: config.maxRetries || 3,
18
+ debug: config.debug || false,
19
+ };
20
+ this.http = new HttpClient(this.config);
21
+ }
22
+ /**
23
+ * Jobs resource
24
+ */
25
+ get jobs() {
26
+ return {
27
+ /**
28
+ * Start a new job
29
+ */
30
+ start: async (params) => {
31
+ const response = await this.http.post('/v1/jobs', params);
32
+ return new Job(response, this.http);
33
+ },
34
+ /**
35
+ * Get a job by ID
36
+ */
37
+ get: async (jobId) => {
38
+ const response = await this.http.get(`/v1/jobs/${jobId}`);
39
+ return new Job(response, this.http);
40
+ },
41
+ /**
42
+ * List jobs for a user
43
+ */
44
+ list: async (userId, options) => {
45
+ const params = new URLSearchParams({ userId });
46
+ if (options?.limit)
47
+ params.set('limit', String(options.limit));
48
+ if (options?.cursor)
49
+ params.set('cursor', options.cursor);
50
+ const response = await this.http.get(`/v1/jobs?${params}`);
51
+ return {
52
+ jobs: response.jobs.map((j) => new Job(j, this.http)),
53
+ nextCursor: response.nextCursor,
54
+ };
55
+ },
56
+ };
57
+ }
58
+ }
59
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAgBvC,MAAM,OAAO,WAAW;IACL,IAAI,CAAa;IACjB,MAAM,CAAwB;IAE/C,YAAY,MAAmB;QAC7B,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACxC,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QACjE,CAAC;QAED,IAAI,CAAC,MAAM,GAAG;YACZ,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,sBAAsB;YACjD,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,KAAK;YAChC,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,CAAC;YAClC,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,KAAK;SAC7B,CAAC;QAEF,IAAI,CAAC,IAAI,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1C,CAAC;IAED;;OAEG;IACH,IAAI,IAAI;QACN,OAAO;YACL;;eAEG;YACH,KAAK,EAAE,KAAK,EAAE,MAAsB,EAAgB,EAAE;gBACpD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAc,UAAU,EAAE,MAAM,CAAC,CAAC;gBACvE,OAAO,IAAI,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;YACtC,CAAC;YAED;;eAEG;YACH,GAAG,EAAE,KAAK,EAAE,KAAa,EAAgB,EAAE;gBACzC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAc,YAAY,KAAK,EAAE,CAAC,CAAC;gBACvE,OAAO,IAAI,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;YACtC,CAAC;YAED;;eAEG;YACH,IAAI,EAAE,KAAK,EAAE,MAAc,EAAE,OAA6C,EAAE,EAAE;gBAC5E,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;gBAC/C,IAAI,OAAO,EAAE,KAAK;oBAAE,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;gBAC/D,IAAI,OAAO,EAAE,MAAM;oBAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;gBAE1D,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAGjC,YAAY,MAAM,EAAE,CAAC,CAAC;gBAEzB,OAAO;oBACL,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;oBACrD,UAAU,EAAE,QAAQ,CAAC,UAAU;iBAChC,CAAC;YACJ,CAAC;SACF,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,32 @@
1
+ export declare class SeennError extends Error {
2
+ readonly code: string;
3
+ readonly statusCode: number;
4
+ readonly details?: Record<string, unknown> | undefined;
5
+ constructor(message: string, code: string, statusCode?: number, details?: Record<string, unknown> | undefined);
6
+ toJSON(): {
7
+ name: string;
8
+ code: string;
9
+ message: string;
10
+ statusCode: number;
11
+ details: Record<string, unknown> | undefined;
12
+ };
13
+ }
14
+ export declare class ValidationError extends SeennError {
15
+ constructor(message: string, details?: Record<string, unknown>);
16
+ }
17
+ export declare class NotFoundError extends SeennError {
18
+ constructor(resource: string, id: string);
19
+ }
20
+ export declare class RateLimitError extends SeennError {
21
+ readonly retryAfter: number;
22
+ readonly limit: number;
23
+ readonly remaining: number;
24
+ constructor(retryAfter: number, limit: number, remaining: number);
25
+ }
26
+ export declare class AuthenticationError extends SeennError {
27
+ constructor(message?: string);
28
+ }
29
+ export declare class ConflictError extends SeennError {
30
+ constructor(message: string, details?: Record<string, unknown>);
31
+ }
32
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,UAAW,SAAQ,KAAK;aAGjB,IAAI,EAAE,MAAM;aACZ,UAAU,EAAE,MAAM;aAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBAHjD,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM,EACZ,UAAU,GAAE,MAAY,EACxB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,YAAA;IAMnD,MAAM;;;;;;;CASP;AAED,qBAAa,eAAgB,SAAQ,UAAU;gBACjC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAI/D;AAED,qBAAa,aAAc,SAAQ,UAAU;gBAC/B,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;CAIzC;AAED,qBAAa,cAAe,SAAQ,UAAU;aAE1B,UAAU,EAAE,MAAM;aAClB,KAAK,EAAE,MAAM;aACb,SAAS,EAAE,MAAM;gBAFjB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM;CASpC;AAED,qBAAa,mBAAoB,SAAQ,UAAU;gBACrC,OAAO,GAAE,MAAqC;CAI3D;AAED,qBAAa,aAAc,SAAQ,UAAU;gBAC/B,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAI/D"}
package/dist/errors.js ADDED
@@ -0,0 +1,62 @@
1
+ export class SeennError extends Error {
2
+ code;
3
+ statusCode;
4
+ details;
5
+ constructor(message, code, statusCode = 500, details) {
6
+ super(message);
7
+ this.code = code;
8
+ this.statusCode = statusCode;
9
+ this.details = details;
10
+ this.name = 'SeennError';
11
+ }
12
+ toJSON() {
13
+ return {
14
+ name: this.name,
15
+ code: this.code,
16
+ message: this.message,
17
+ statusCode: this.statusCode,
18
+ details: this.details,
19
+ };
20
+ }
21
+ }
22
+ export class ValidationError extends SeennError {
23
+ constructor(message, details) {
24
+ super(message, 'VALIDATION_ERROR', 400, details);
25
+ this.name = 'ValidationError';
26
+ }
27
+ }
28
+ export class NotFoundError extends SeennError {
29
+ constructor(resource, id) {
30
+ super(`${resource} not found: ${id}`, 'NOT_FOUND', 404, { resource, id });
31
+ this.name = 'NotFoundError';
32
+ }
33
+ }
34
+ export class RateLimitError extends SeennError {
35
+ retryAfter;
36
+ limit;
37
+ remaining;
38
+ constructor(retryAfter, limit, remaining) {
39
+ super(`Rate limit exceeded. Retry after ${retryAfter} seconds`, 'RATE_LIMIT_EXCEEDED', 429, {
40
+ retryAfter,
41
+ limit,
42
+ remaining,
43
+ });
44
+ this.retryAfter = retryAfter;
45
+ this.limit = limit;
46
+ this.remaining = remaining;
47
+ this.name = 'RateLimitError';
48
+ }
49
+ }
50
+ export class AuthenticationError extends SeennError {
51
+ constructor(message = 'Invalid or missing API key') {
52
+ super(message, 'AUTHENTICATION_ERROR', 401);
53
+ this.name = 'AuthenticationError';
54
+ }
55
+ }
56
+ export class ConflictError extends SeennError {
57
+ constructor(message, details) {
58
+ super(message, 'CONFLICT', 409, details);
59
+ this.name = 'ConflictError';
60
+ }
61
+ }
62
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,UAAW,SAAQ,KAAK;IAGjB;IACA;IACA;IAJlB,YACE,OAAe,EACC,IAAY,EACZ,aAAqB,GAAG,EACxB,OAAiC;QAEjD,KAAK,CAAC,OAAO,CAAC,CAAC;QAJC,SAAI,GAAJ,IAAI,CAAQ;QACZ,eAAU,GAAV,UAAU,CAAc;QACxB,YAAO,GAAP,OAAO,CAA0B;QAGjD,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;IAC3B,CAAC;IAED,MAAM;QACJ,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC;IACJ,CAAC;CACF;AAED,MAAM,OAAO,eAAgB,SAAQ,UAAU;IAC7C,YAAY,OAAe,EAAE,OAAiC;QAC5D,KAAK,CAAC,OAAO,EAAE,kBAAkB,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;QACjD,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AAED,MAAM,OAAO,aAAc,SAAQ,UAAU;IAC3C,YAAY,QAAgB,EAAE,EAAU;QACtC,KAAK,CAAC,GAAG,QAAQ,eAAe,EAAE,EAAE,EAAE,WAAW,EAAE,GAAG,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;QAC1E,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AAED,MAAM,OAAO,cAAe,SAAQ,UAAU;IAE1B;IACA;IACA;IAHlB,YACkB,UAAkB,EAClB,KAAa,EACb,SAAiB;QAEjC,KAAK,CAAC,oCAAoC,UAAU,UAAU,EAAE,qBAAqB,EAAE,GAAG,EAAE;YAC1F,UAAU;YACV,KAAK;YACL,SAAS;SACV,CAAC,CAAC;QARa,eAAU,GAAV,UAAU,CAAQ;QAClB,UAAK,GAAL,KAAK,CAAQ;QACb,cAAS,GAAT,SAAS,CAAQ;QAOjC,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED,MAAM,OAAO,mBAAoB,SAAQ,UAAU;IACjD,YAAY,UAAkB,4BAA4B;QACxD,KAAK,CAAC,OAAO,EAAE,sBAAsB,EAAE,GAAG,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED,MAAM,OAAO,aAAc,SAAQ,UAAU;IAC3C,YAAY,OAAe,EAAE,OAAiC;QAC5D,KAAK,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;QACzC,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF"}
package/dist/http.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ import type { SeennConfig } from './client.js';
2
+ export declare class HttpClient {
3
+ private readonly config;
4
+ constructor(config: Required<SeennConfig>);
5
+ get<T>(path: string): Promise<T>;
6
+ post<T>(path: string, body?: unknown): Promise<T>;
7
+ put<T>(path: string, body?: unknown): Promise<T>;
8
+ delete<T>(path: string): Promise<T>;
9
+ private request;
10
+ private executeWithRetry;
11
+ private handleErrorResponse;
12
+ private sleep;
13
+ }
14
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAiB/C,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwB;gBAEnC,MAAM,EAAE,QAAQ,CAAC,WAAW,CAAC;IAInC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAIhC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAIjD,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAIhD,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;YAI3B,OAAO;YAoDP,gBAAgB;YAyChB,mBAAmB;IAmCjC,OAAO,CAAC,KAAK;CAGd"}
package/dist/http.js ADDED
@@ -0,0 +1,125 @@
1
+ import { SeennError, RateLimitError, ValidationError, NotFoundError, AuthenticationError, } from './errors.js';
2
+ export class HttpClient {
3
+ config;
4
+ constructor(config) {
5
+ this.config = config;
6
+ }
7
+ async get(path) {
8
+ return this.request({ method: 'GET', path });
9
+ }
10
+ async post(path, body) {
11
+ return this.request({ method: 'POST', path, body });
12
+ }
13
+ async put(path, body) {
14
+ return this.request({ method: 'PUT', path, body });
15
+ }
16
+ async delete(path) {
17
+ return this.request({ method: 'DELETE', path });
18
+ }
19
+ async request(options) {
20
+ const { method, path, body } = options;
21
+ const url = `${this.config.baseUrl}${path}`;
22
+ const headers = {
23
+ 'Authorization': `Bearer ${this.config.apiKey}`,
24
+ 'Content-Type': 'application/json',
25
+ 'User-Agent': '@seenn/node',
26
+ };
27
+ if (options.idempotencyKey) {
28
+ headers['Idempotency-Key'] = options.idempotencyKey;
29
+ }
30
+ return this.executeWithRetry(async () => {
31
+ const controller = new AbortController();
32
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
33
+ try {
34
+ const response = await fetch(url, {
35
+ method,
36
+ headers,
37
+ body: body ? JSON.stringify(body) : undefined,
38
+ signal: controller.signal,
39
+ });
40
+ clearTimeout(timeoutId);
41
+ if (!response.ok) {
42
+ await this.handleErrorResponse(response);
43
+ }
44
+ return (await response.json());
45
+ }
46
+ catch (error) {
47
+ clearTimeout(timeoutId);
48
+ if (error instanceof SeennError) {
49
+ throw error;
50
+ }
51
+ if (error instanceof Error) {
52
+ if (error.name === 'AbortError') {
53
+ throw new SeennError('Request timeout', 'TIMEOUT', 408);
54
+ }
55
+ throw new SeennError(error.message, 'NETWORK_ERROR', 0);
56
+ }
57
+ throw new SeennError('Unknown error', 'UNKNOWN', 0);
58
+ }
59
+ }, method === 'GET' || !!options.idempotencyKey);
60
+ }
61
+ async executeWithRetry(fn, idempotent) {
62
+ let lastError;
63
+ const maxRetries = idempotent ? this.config.maxRetries : 1;
64
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
65
+ try {
66
+ return await fn();
67
+ }
68
+ catch (error) {
69
+ lastError = error;
70
+ // Don't retry on client errors (4xx) except rate limits
71
+ if (error instanceof SeennError) {
72
+ if (error.statusCode >= 400 && error.statusCode < 500) {
73
+ if (!(error instanceof RateLimitError)) {
74
+ throw error;
75
+ }
76
+ }
77
+ }
78
+ // Calculate delay with exponential backoff + jitter
79
+ if (attempt < maxRetries - 1) {
80
+ const baseDelay = 1000; // 1 second
81
+ const exponentialDelay = baseDelay * Math.pow(2, attempt);
82
+ const jitter = Math.random() * 0.2 * exponentialDelay;
83
+ const delay = Math.min(exponentialDelay + jitter, 30000); // Max 30s
84
+ if (this.config.debug) {
85
+ console.log(`[seenn] Retry attempt ${attempt + 1}/${maxRetries} after ${delay}ms`);
86
+ }
87
+ await this.sleep(delay);
88
+ }
89
+ }
90
+ }
91
+ throw lastError;
92
+ }
93
+ async handleErrorResponse(response) {
94
+ let errorData;
95
+ try {
96
+ errorData = (await response.json());
97
+ }
98
+ catch {
99
+ // Response might not be JSON
100
+ }
101
+ const message = errorData?.error?.message || response.statusText;
102
+ const code = errorData?.error?.code || 'UNKNOWN';
103
+ const details = errorData?.error?.details;
104
+ switch (response.status) {
105
+ case 400:
106
+ throw new ValidationError(message, details);
107
+ case 401:
108
+ throw new AuthenticationError(message);
109
+ case 404:
110
+ throw new NotFoundError('Resource', details?.id || 'unknown');
111
+ case 429: {
112
+ const retryAfter = parseInt(response.headers.get('Retry-After') || '60', 10);
113
+ const limit = parseInt(response.headers.get('X-RateLimit-Limit') || '0', 10);
114
+ const remaining = parseInt(response.headers.get('X-RateLimit-Remaining') || '0', 10);
115
+ throw new RateLimitError(retryAfter, limit, remaining);
116
+ }
117
+ default:
118
+ throw new SeennError(message, code, response.status, details);
119
+ }
120
+ }
121
+ sleep(ms) {
122
+ return new Promise((resolve) => setTimeout(resolve, ms));
123
+ }
124
+ }
125
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export { SeennClient } from './client.js';
2
+ export type { SeennConfig } from './client.js';
3
+ export { Job } from './job.js';
4
+ export type { JobStatus, JobData, ProgressOptions, CompleteOptions, FailOptions } from './job.js';
5
+ export type { StartJobParams, ProgressParams, CompleteParams, FailParams, QueueInfo, StageInfo, JobResult, JobError, } from './types.js';
6
+ export { SeennError, RateLimitError, ValidationError, NotFoundError } from './errors.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAElG,YAAY,EACV,cAAc,EACd,cAAc,EACd,cAAc,EACd,UAAU,EACV,SAAS,EACT,SAAS,EACT,SAAS,EACT,QAAQ,GACT,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ // @seenn/node - Job State Transport SDK
2
+ export { SeennClient } from './client.js';
3
+ export { Job } from './job.js';
4
+ export { SeennError, RateLimitError, ValidationError, NotFoundError } from './errors.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,wCAAwC;AAExC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG1C,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAc/B,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}