hyperclip 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/README.md +58 -0
- package/dist/index.d.mts +149 -0
- package/dist/index.d.ts +149 -0
- package/dist/index.js +157 -0
- package/dist/index.mjs +128 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# hyperclip
|
|
2
|
+
|
|
3
|
+
Official Node SDK for the [Hyperclip](https://hyperclip.co) API. Trigger flow runs, poll for completion, and pull the final video URL — without writing fetch boilerplate.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install hyperclip
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires Node 18+ (uses native `fetch`).
|
|
12
|
+
|
|
13
|
+
## Quickstart
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { Hyperclip } from "hyperclip";
|
|
17
|
+
|
|
18
|
+
const hc = new Hyperclip({
|
|
19
|
+
apiKey: process.env.HYPERCLIP_API_KEY,
|
|
20
|
+
baseUrl: "https://YOUR-PROJECT.supabase.co/functions/v1/api-v1",
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const { id } = await hc.runs.create({
|
|
24
|
+
flow_id: "a3c7f1ea-1234-4abc-bb11-5faed63c7e90",
|
|
25
|
+
inputs: { prompts: { 0: "a lighthouse at dawn" } },
|
|
26
|
+
idempotency_key: crypto.randomUUID(),
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const run = await hc.runs.wait(id, {
|
|
30
|
+
onUpdate: (r) => console.log(r.status, r.current_step),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
if (run.status === "completed") {
|
|
34
|
+
console.log("Video:", run.video_url);
|
|
35
|
+
} else {
|
|
36
|
+
console.error(run.error_code, run.error_message);
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Configuration
|
|
41
|
+
|
|
42
|
+
| Option | Env var | Required |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| `apiKey` | `HYPERCLIP_API_KEY` | yes |
|
|
45
|
+
| `baseUrl` | `HYPERCLIP_BASE_URL` | yes |
|
|
46
|
+
| `fetch` | — | no (defaults to global) |
|
|
47
|
+
|
|
48
|
+
## API
|
|
49
|
+
|
|
50
|
+
- `hc.runs.create(params)` — `POST /runs`
|
|
51
|
+
- `hc.runs.get(id)` — `GET /runs/:id`
|
|
52
|
+
- `hc.runs.list({ limit?, status? })` — `GET /runs`
|
|
53
|
+
- `hc.runs.cancel(id)` — `POST /runs/:id/cancel`
|
|
54
|
+
- `hc.runs.wait(id, { timeoutMs?, pollIntervalMs?, onUpdate?, signal? })` — polls until terminal
|
|
55
|
+
- `hc.flows.list()` — `GET /flows`
|
|
56
|
+
- `hc.flows.get(id)` — `GET /flows/:id`
|
|
57
|
+
|
|
58
|
+
Errors throw `HyperclipError` with `.status` and `.code`. Timeouts throw `HyperclipTimeoutError`.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
type RunStatus = "queued" | "running" | "completed" | "failed" | "cancelled";
|
|
2
|
+
interface FlowSchemaNode {
|
|
3
|
+
id: string;
|
|
4
|
+
type: string;
|
|
5
|
+
label: string;
|
|
6
|
+
position: {
|
|
7
|
+
x: number;
|
|
8
|
+
y: number;
|
|
9
|
+
};
|
|
10
|
+
config: Record<string, unknown>;
|
|
11
|
+
}
|
|
12
|
+
interface FlowSchemaEdge {
|
|
13
|
+
id: string;
|
|
14
|
+
source: string;
|
|
15
|
+
sourceHandle: string;
|
|
16
|
+
target: string;
|
|
17
|
+
targetHandle: string;
|
|
18
|
+
}
|
|
19
|
+
interface FlowSchema {
|
|
20
|
+
version: 1;
|
|
21
|
+
metadata?: {
|
|
22
|
+
title?: string;
|
|
23
|
+
category?: string;
|
|
24
|
+
description?: string;
|
|
25
|
+
};
|
|
26
|
+
nodes: FlowSchemaNode[];
|
|
27
|
+
edges: FlowSchemaEdge[];
|
|
28
|
+
}
|
|
29
|
+
interface MediaInput {
|
|
30
|
+
url: string;
|
|
31
|
+
type: "image" | "video" | "audio";
|
|
32
|
+
}
|
|
33
|
+
interface RunInputs {
|
|
34
|
+
prompts?: Record<number, string>;
|
|
35
|
+
media?: Record<number, MediaInput>;
|
|
36
|
+
model_overrides?: Record<number, Record<string, unknown>>;
|
|
37
|
+
}
|
|
38
|
+
interface CreateRunParams {
|
|
39
|
+
flow_id?: string;
|
|
40
|
+
flow_schema?: FlowSchema;
|
|
41
|
+
inputs?: RunInputs;
|
|
42
|
+
idempotency_key?: string;
|
|
43
|
+
}
|
|
44
|
+
interface RunRef {
|
|
45
|
+
id: string;
|
|
46
|
+
status: RunStatus;
|
|
47
|
+
created_at: string;
|
|
48
|
+
}
|
|
49
|
+
interface Run {
|
|
50
|
+
id: string;
|
|
51
|
+
status: RunStatus;
|
|
52
|
+
current_step: number | null;
|
|
53
|
+
video_url: string | null;
|
|
54
|
+
error_code: string | null;
|
|
55
|
+
error_message: string | null;
|
|
56
|
+
credits_charged: number;
|
|
57
|
+
api_markup_multiplier: string;
|
|
58
|
+
created_at: string;
|
|
59
|
+
started_at: string | null;
|
|
60
|
+
completed_at: string | null;
|
|
61
|
+
}
|
|
62
|
+
interface RunListItem {
|
|
63
|
+
id: string;
|
|
64
|
+
status: RunStatus;
|
|
65
|
+
current_step: number | null;
|
|
66
|
+
video_url: string | null;
|
|
67
|
+
error_code: string | null;
|
|
68
|
+
credits_charged: number;
|
|
69
|
+
created_at: string;
|
|
70
|
+
completed_at: string | null;
|
|
71
|
+
}
|
|
72
|
+
interface FlowListItem {
|
|
73
|
+
id: string;
|
|
74
|
+
title: string;
|
|
75
|
+
description: string | null;
|
|
76
|
+
updated_at: string;
|
|
77
|
+
}
|
|
78
|
+
interface FlowDetail {
|
|
79
|
+
id: string;
|
|
80
|
+
title: string;
|
|
81
|
+
description: string | null;
|
|
82
|
+
flow_schema: FlowSchema;
|
|
83
|
+
required_inputs: Array<{
|
|
84
|
+
step_order: number;
|
|
85
|
+
node_type: string;
|
|
86
|
+
field: "prompt" | "media";
|
|
87
|
+
}>;
|
|
88
|
+
}
|
|
89
|
+
interface ListRunsParams {
|
|
90
|
+
limit?: number;
|
|
91
|
+
status?: RunStatus;
|
|
92
|
+
}
|
|
93
|
+
interface WaitOptions {
|
|
94
|
+
/** Total wait timeout in milliseconds. Default: 10 minutes. */
|
|
95
|
+
timeoutMs?: number;
|
|
96
|
+
/** Initial poll interval in milliseconds. Default: 4000. */
|
|
97
|
+
pollIntervalMs?: number;
|
|
98
|
+
/** Called on every poll with the latest run state. */
|
|
99
|
+
onUpdate?: (run: Run) => void;
|
|
100
|
+
/** AbortSignal to cancel the wait early. */
|
|
101
|
+
signal?: AbortSignal;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
interface HyperclipOptions {
|
|
105
|
+
/** API key (`hck_live_<prefix>.<secret>`). Falls back to `HYPERCLIP_API_KEY`. */
|
|
106
|
+
apiKey?: string;
|
|
107
|
+
/**
|
|
108
|
+
* Full base URL — e.g. `https://your-project.supabase.co/functions/v1/api-v1`.
|
|
109
|
+
* Falls back to `HYPERCLIP_BASE_URL`.
|
|
110
|
+
*/
|
|
111
|
+
baseUrl?: string;
|
|
112
|
+
/** Override the global fetch (e.g. for testing). */
|
|
113
|
+
fetch?: typeof fetch;
|
|
114
|
+
}
|
|
115
|
+
declare class Hyperclip {
|
|
116
|
+
private readonly apiKey;
|
|
117
|
+
private readonly baseUrl;
|
|
118
|
+
private readonly fetchImpl;
|
|
119
|
+
constructor(options?: HyperclipOptions);
|
|
120
|
+
readonly runs: {
|
|
121
|
+
create: (params: CreateRunParams) => Promise<RunRef>;
|
|
122
|
+
get: (id: string) => Promise<Run>;
|
|
123
|
+
list: (params?: ListRunsParams) => Promise<RunListItem[]>;
|
|
124
|
+
cancel: (id: string) => Promise<{
|
|
125
|
+
id: string;
|
|
126
|
+
status: "cancelled";
|
|
127
|
+
}>;
|
|
128
|
+
wait: (id: string, options?: WaitOptions) => Promise<Run>;
|
|
129
|
+
};
|
|
130
|
+
readonly flows: {
|
|
131
|
+
list: () => Promise<FlowListItem[]>;
|
|
132
|
+
get: (id: string) => Promise<FlowDetail>;
|
|
133
|
+
};
|
|
134
|
+
private createRun;
|
|
135
|
+
private listRuns;
|
|
136
|
+
private waitForRun;
|
|
137
|
+
private request;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
declare class HyperclipError extends Error {
|
|
141
|
+
readonly status: number;
|
|
142
|
+
readonly code: string;
|
|
143
|
+
constructor(status: number, code: string, message: string);
|
|
144
|
+
}
|
|
145
|
+
declare class HyperclipTimeoutError extends Error {
|
|
146
|
+
constructor(message?: string);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export { type CreateRunParams, type FlowDetail, type FlowListItem, type FlowSchema, type FlowSchemaEdge, type FlowSchemaNode, Hyperclip, HyperclipError, type HyperclipOptions, HyperclipTimeoutError, type ListRunsParams, type MediaInput, type Run, type RunInputs, type RunListItem, type RunRef, type RunStatus, type WaitOptions };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
type RunStatus = "queued" | "running" | "completed" | "failed" | "cancelled";
|
|
2
|
+
interface FlowSchemaNode {
|
|
3
|
+
id: string;
|
|
4
|
+
type: string;
|
|
5
|
+
label: string;
|
|
6
|
+
position: {
|
|
7
|
+
x: number;
|
|
8
|
+
y: number;
|
|
9
|
+
};
|
|
10
|
+
config: Record<string, unknown>;
|
|
11
|
+
}
|
|
12
|
+
interface FlowSchemaEdge {
|
|
13
|
+
id: string;
|
|
14
|
+
source: string;
|
|
15
|
+
sourceHandle: string;
|
|
16
|
+
target: string;
|
|
17
|
+
targetHandle: string;
|
|
18
|
+
}
|
|
19
|
+
interface FlowSchema {
|
|
20
|
+
version: 1;
|
|
21
|
+
metadata?: {
|
|
22
|
+
title?: string;
|
|
23
|
+
category?: string;
|
|
24
|
+
description?: string;
|
|
25
|
+
};
|
|
26
|
+
nodes: FlowSchemaNode[];
|
|
27
|
+
edges: FlowSchemaEdge[];
|
|
28
|
+
}
|
|
29
|
+
interface MediaInput {
|
|
30
|
+
url: string;
|
|
31
|
+
type: "image" | "video" | "audio";
|
|
32
|
+
}
|
|
33
|
+
interface RunInputs {
|
|
34
|
+
prompts?: Record<number, string>;
|
|
35
|
+
media?: Record<number, MediaInput>;
|
|
36
|
+
model_overrides?: Record<number, Record<string, unknown>>;
|
|
37
|
+
}
|
|
38
|
+
interface CreateRunParams {
|
|
39
|
+
flow_id?: string;
|
|
40
|
+
flow_schema?: FlowSchema;
|
|
41
|
+
inputs?: RunInputs;
|
|
42
|
+
idempotency_key?: string;
|
|
43
|
+
}
|
|
44
|
+
interface RunRef {
|
|
45
|
+
id: string;
|
|
46
|
+
status: RunStatus;
|
|
47
|
+
created_at: string;
|
|
48
|
+
}
|
|
49
|
+
interface Run {
|
|
50
|
+
id: string;
|
|
51
|
+
status: RunStatus;
|
|
52
|
+
current_step: number | null;
|
|
53
|
+
video_url: string | null;
|
|
54
|
+
error_code: string | null;
|
|
55
|
+
error_message: string | null;
|
|
56
|
+
credits_charged: number;
|
|
57
|
+
api_markup_multiplier: string;
|
|
58
|
+
created_at: string;
|
|
59
|
+
started_at: string | null;
|
|
60
|
+
completed_at: string | null;
|
|
61
|
+
}
|
|
62
|
+
interface RunListItem {
|
|
63
|
+
id: string;
|
|
64
|
+
status: RunStatus;
|
|
65
|
+
current_step: number | null;
|
|
66
|
+
video_url: string | null;
|
|
67
|
+
error_code: string | null;
|
|
68
|
+
credits_charged: number;
|
|
69
|
+
created_at: string;
|
|
70
|
+
completed_at: string | null;
|
|
71
|
+
}
|
|
72
|
+
interface FlowListItem {
|
|
73
|
+
id: string;
|
|
74
|
+
title: string;
|
|
75
|
+
description: string | null;
|
|
76
|
+
updated_at: string;
|
|
77
|
+
}
|
|
78
|
+
interface FlowDetail {
|
|
79
|
+
id: string;
|
|
80
|
+
title: string;
|
|
81
|
+
description: string | null;
|
|
82
|
+
flow_schema: FlowSchema;
|
|
83
|
+
required_inputs: Array<{
|
|
84
|
+
step_order: number;
|
|
85
|
+
node_type: string;
|
|
86
|
+
field: "prompt" | "media";
|
|
87
|
+
}>;
|
|
88
|
+
}
|
|
89
|
+
interface ListRunsParams {
|
|
90
|
+
limit?: number;
|
|
91
|
+
status?: RunStatus;
|
|
92
|
+
}
|
|
93
|
+
interface WaitOptions {
|
|
94
|
+
/** Total wait timeout in milliseconds. Default: 10 minutes. */
|
|
95
|
+
timeoutMs?: number;
|
|
96
|
+
/** Initial poll interval in milliseconds. Default: 4000. */
|
|
97
|
+
pollIntervalMs?: number;
|
|
98
|
+
/** Called on every poll with the latest run state. */
|
|
99
|
+
onUpdate?: (run: Run) => void;
|
|
100
|
+
/** AbortSignal to cancel the wait early. */
|
|
101
|
+
signal?: AbortSignal;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
interface HyperclipOptions {
|
|
105
|
+
/** API key (`hck_live_<prefix>.<secret>`). Falls back to `HYPERCLIP_API_KEY`. */
|
|
106
|
+
apiKey?: string;
|
|
107
|
+
/**
|
|
108
|
+
* Full base URL — e.g. `https://your-project.supabase.co/functions/v1/api-v1`.
|
|
109
|
+
* Falls back to `HYPERCLIP_BASE_URL`.
|
|
110
|
+
*/
|
|
111
|
+
baseUrl?: string;
|
|
112
|
+
/** Override the global fetch (e.g. for testing). */
|
|
113
|
+
fetch?: typeof fetch;
|
|
114
|
+
}
|
|
115
|
+
declare class Hyperclip {
|
|
116
|
+
private readonly apiKey;
|
|
117
|
+
private readonly baseUrl;
|
|
118
|
+
private readonly fetchImpl;
|
|
119
|
+
constructor(options?: HyperclipOptions);
|
|
120
|
+
readonly runs: {
|
|
121
|
+
create: (params: CreateRunParams) => Promise<RunRef>;
|
|
122
|
+
get: (id: string) => Promise<Run>;
|
|
123
|
+
list: (params?: ListRunsParams) => Promise<RunListItem[]>;
|
|
124
|
+
cancel: (id: string) => Promise<{
|
|
125
|
+
id: string;
|
|
126
|
+
status: "cancelled";
|
|
127
|
+
}>;
|
|
128
|
+
wait: (id: string, options?: WaitOptions) => Promise<Run>;
|
|
129
|
+
};
|
|
130
|
+
readonly flows: {
|
|
131
|
+
list: () => Promise<FlowListItem[]>;
|
|
132
|
+
get: (id: string) => Promise<FlowDetail>;
|
|
133
|
+
};
|
|
134
|
+
private createRun;
|
|
135
|
+
private listRuns;
|
|
136
|
+
private waitForRun;
|
|
137
|
+
private request;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
declare class HyperclipError extends Error {
|
|
141
|
+
readonly status: number;
|
|
142
|
+
readonly code: string;
|
|
143
|
+
constructor(status: number, code: string, message: string);
|
|
144
|
+
}
|
|
145
|
+
declare class HyperclipTimeoutError extends Error {
|
|
146
|
+
constructor(message?: string);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export { type CreateRunParams, type FlowDetail, type FlowListItem, type FlowSchema, type FlowSchemaEdge, type FlowSchemaNode, Hyperclip, HyperclipError, type HyperclipOptions, HyperclipTimeoutError, type ListRunsParams, type MediaInput, type Run, type RunInputs, type RunListItem, type RunRef, type RunStatus, type WaitOptions };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
Hyperclip: () => Hyperclip,
|
|
24
|
+
HyperclipError: () => HyperclipError,
|
|
25
|
+
HyperclipTimeoutError: () => HyperclipTimeoutError
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(index_exports);
|
|
28
|
+
|
|
29
|
+
// src/errors.ts
|
|
30
|
+
var HyperclipError = class extends Error {
|
|
31
|
+
constructor(status, code, message) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.name = "HyperclipError";
|
|
34
|
+
this.status = status;
|
|
35
|
+
this.code = code;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var HyperclipTimeoutError = class extends Error {
|
|
39
|
+
constructor(message = "Run polling timed out") {
|
|
40
|
+
super(message);
|
|
41
|
+
this.name = "HyperclipTimeoutError";
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// src/client.ts
|
|
46
|
+
var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
|
|
47
|
+
var Hyperclip = class {
|
|
48
|
+
constructor(options = {}) {
|
|
49
|
+
this.runs = {
|
|
50
|
+
create: (params) => this.createRun(params),
|
|
51
|
+
get: (id) => this.request("GET", `/runs/${encodeURIComponent(id)}`),
|
|
52
|
+
list: (params = {}) => this.listRuns(params),
|
|
53
|
+
cancel: (id) => this.request("POST", `/runs/${encodeURIComponent(id)}/cancel`),
|
|
54
|
+
wait: (id, options) => this.waitForRun(id, options)
|
|
55
|
+
};
|
|
56
|
+
this.flows = {
|
|
57
|
+
list: async () => {
|
|
58
|
+
const res = await this.request("GET", "/flows");
|
|
59
|
+
return res.flows;
|
|
60
|
+
},
|
|
61
|
+
get: (id) => this.request("GET", `/flows/${encodeURIComponent(id)}`)
|
|
62
|
+
};
|
|
63
|
+
const apiKey = options.apiKey ?? process.env.HYPERCLIP_API_KEY;
|
|
64
|
+
const baseUrl = options.baseUrl ?? process.env.HYPERCLIP_BASE_URL;
|
|
65
|
+
if (!apiKey) {
|
|
66
|
+
throw new Error(
|
|
67
|
+
"Hyperclip: missing apiKey. Pass `apiKey` or set HYPERCLIP_API_KEY."
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
if (!baseUrl) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
"Hyperclip: missing baseUrl. Pass `baseUrl` or set HYPERCLIP_BASE_URL (e.g. https://your-project.supabase.co/functions/v1/api-v1)."
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
this.apiKey = apiKey;
|
|
76
|
+
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
77
|
+
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
78
|
+
if (!this.fetchImpl) {
|
|
79
|
+
throw new Error("Hyperclip: no fetch implementation available. Use Node 18+ or pass `fetch`.");
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async createRun(params) {
|
|
83
|
+
const headers = {};
|
|
84
|
+
if (params.idempotency_key) headers["Idempotency-Key"] = params.idempotency_key;
|
|
85
|
+
return this.request("POST", "/runs", params, headers);
|
|
86
|
+
}
|
|
87
|
+
async listRuns(params) {
|
|
88
|
+
const qs = new URLSearchParams();
|
|
89
|
+
if (params.limit !== void 0) qs.set("limit", String(params.limit));
|
|
90
|
+
if (params.status) qs.set("status", params.status);
|
|
91
|
+
const path = qs.toString() ? `/runs?${qs}` : "/runs";
|
|
92
|
+
const res = await this.request("GET", path);
|
|
93
|
+
return res.runs;
|
|
94
|
+
}
|
|
95
|
+
async waitForRun(id, options = {}) {
|
|
96
|
+
const { timeoutMs = 10 * 6e4, pollIntervalMs = 4e3, onUpdate, signal } = options;
|
|
97
|
+
const deadline = Date.now() + timeoutMs;
|
|
98
|
+
while (Date.now() < deadline) {
|
|
99
|
+
if (signal?.aborted) throw new HyperclipTimeoutError("Wait aborted");
|
|
100
|
+
const run = await this.runs.get(id);
|
|
101
|
+
onUpdate?.(run);
|
|
102
|
+
if (TERMINAL_STATUSES.has(run.status)) return run;
|
|
103
|
+
await sleep(pollIntervalMs, signal);
|
|
104
|
+
}
|
|
105
|
+
throw new HyperclipTimeoutError();
|
|
106
|
+
}
|
|
107
|
+
async request(method, path, body, extraHeaders = {}) {
|
|
108
|
+
const headers = {
|
|
109
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
110
|
+
...extraHeaders
|
|
111
|
+
};
|
|
112
|
+
if (body !== void 0) headers["Content-Type"] = "application/json";
|
|
113
|
+
const res = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
114
|
+
method,
|
|
115
|
+
headers,
|
|
116
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
117
|
+
});
|
|
118
|
+
const text = await res.text();
|
|
119
|
+
const data = text ? safeJson(text) : void 0;
|
|
120
|
+
if (!res.ok) {
|
|
121
|
+
const err = data?.error;
|
|
122
|
+
throw new HyperclipError(
|
|
123
|
+
res.status,
|
|
124
|
+
err?.code ?? "unknown_error",
|
|
125
|
+
err?.message ?? `HTTP ${res.status}`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
return data;
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
function safeJson(text) {
|
|
132
|
+
try {
|
|
133
|
+
return JSON.parse(text);
|
|
134
|
+
} catch {
|
|
135
|
+
return void 0;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function sleep(ms, signal) {
|
|
139
|
+
return new Promise((resolve, reject) => {
|
|
140
|
+
if (signal?.aborted) return reject(new HyperclipTimeoutError("Wait aborted"));
|
|
141
|
+
const t = setTimeout(() => {
|
|
142
|
+
signal?.removeEventListener("abort", onAbort);
|
|
143
|
+
resolve();
|
|
144
|
+
}, ms);
|
|
145
|
+
const onAbort = () => {
|
|
146
|
+
clearTimeout(t);
|
|
147
|
+
reject(new HyperclipTimeoutError("Wait aborted"));
|
|
148
|
+
};
|
|
149
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
153
|
+
0 && (module.exports = {
|
|
154
|
+
Hyperclip,
|
|
155
|
+
HyperclipError,
|
|
156
|
+
HyperclipTimeoutError
|
|
157
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var HyperclipError = class extends Error {
|
|
3
|
+
constructor(status, code, message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "HyperclipError";
|
|
6
|
+
this.status = status;
|
|
7
|
+
this.code = code;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var HyperclipTimeoutError = class extends Error {
|
|
11
|
+
constructor(message = "Run polling timed out") {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = "HyperclipTimeoutError";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// src/client.ts
|
|
18
|
+
var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
|
|
19
|
+
var Hyperclip = class {
|
|
20
|
+
constructor(options = {}) {
|
|
21
|
+
this.runs = {
|
|
22
|
+
create: (params) => this.createRun(params),
|
|
23
|
+
get: (id) => this.request("GET", `/runs/${encodeURIComponent(id)}`),
|
|
24
|
+
list: (params = {}) => this.listRuns(params),
|
|
25
|
+
cancel: (id) => this.request("POST", `/runs/${encodeURIComponent(id)}/cancel`),
|
|
26
|
+
wait: (id, options) => this.waitForRun(id, options)
|
|
27
|
+
};
|
|
28
|
+
this.flows = {
|
|
29
|
+
list: async () => {
|
|
30
|
+
const res = await this.request("GET", "/flows");
|
|
31
|
+
return res.flows;
|
|
32
|
+
},
|
|
33
|
+
get: (id) => this.request("GET", `/flows/${encodeURIComponent(id)}`)
|
|
34
|
+
};
|
|
35
|
+
const apiKey = options.apiKey ?? process.env.HYPERCLIP_API_KEY;
|
|
36
|
+
const baseUrl = options.baseUrl ?? process.env.HYPERCLIP_BASE_URL;
|
|
37
|
+
if (!apiKey) {
|
|
38
|
+
throw new Error(
|
|
39
|
+
"Hyperclip: missing apiKey. Pass `apiKey` or set HYPERCLIP_API_KEY."
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
if (!baseUrl) {
|
|
43
|
+
throw new Error(
|
|
44
|
+
"Hyperclip: missing baseUrl. Pass `baseUrl` or set HYPERCLIP_BASE_URL (e.g. https://your-project.supabase.co/functions/v1/api-v1)."
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
this.apiKey = apiKey;
|
|
48
|
+
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
49
|
+
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
50
|
+
if (!this.fetchImpl) {
|
|
51
|
+
throw new Error("Hyperclip: no fetch implementation available. Use Node 18+ or pass `fetch`.");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async createRun(params) {
|
|
55
|
+
const headers = {};
|
|
56
|
+
if (params.idempotency_key) headers["Idempotency-Key"] = params.idempotency_key;
|
|
57
|
+
return this.request("POST", "/runs", params, headers);
|
|
58
|
+
}
|
|
59
|
+
async listRuns(params) {
|
|
60
|
+
const qs = new URLSearchParams();
|
|
61
|
+
if (params.limit !== void 0) qs.set("limit", String(params.limit));
|
|
62
|
+
if (params.status) qs.set("status", params.status);
|
|
63
|
+
const path = qs.toString() ? `/runs?${qs}` : "/runs";
|
|
64
|
+
const res = await this.request("GET", path);
|
|
65
|
+
return res.runs;
|
|
66
|
+
}
|
|
67
|
+
async waitForRun(id, options = {}) {
|
|
68
|
+
const { timeoutMs = 10 * 6e4, pollIntervalMs = 4e3, onUpdate, signal } = options;
|
|
69
|
+
const deadline = Date.now() + timeoutMs;
|
|
70
|
+
while (Date.now() < deadline) {
|
|
71
|
+
if (signal?.aborted) throw new HyperclipTimeoutError("Wait aborted");
|
|
72
|
+
const run = await this.runs.get(id);
|
|
73
|
+
onUpdate?.(run);
|
|
74
|
+
if (TERMINAL_STATUSES.has(run.status)) return run;
|
|
75
|
+
await sleep(pollIntervalMs, signal);
|
|
76
|
+
}
|
|
77
|
+
throw new HyperclipTimeoutError();
|
|
78
|
+
}
|
|
79
|
+
async request(method, path, body, extraHeaders = {}) {
|
|
80
|
+
const headers = {
|
|
81
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
82
|
+
...extraHeaders
|
|
83
|
+
};
|
|
84
|
+
if (body !== void 0) headers["Content-Type"] = "application/json";
|
|
85
|
+
const res = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
86
|
+
method,
|
|
87
|
+
headers,
|
|
88
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
89
|
+
});
|
|
90
|
+
const text = await res.text();
|
|
91
|
+
const data = text ? safeJson(text) : void 0;
|
|
92
|
+
if (!res.ok) {
|
|
93
|
+
const err = data?.error;
|
|
94
|
+
throw new HyperclipError(
|
|
95
|
+
res.status,
|
|
96
|
+
err?.code ?? "unknown_error",
|
|
97
|
+
err?.message ?? `HTTP ${res.status}`
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
return data;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
function safeJson(text) {
|
|
104
|
+
try {
|
|
105
|
+
return JSON.parse(text);
|
|
106
|
+
} catch {
|
|
107
|
+
return void 0;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function sleep(ms, signal) {
|
|
111
|
+
return new Promise((resolve, reject) => {
|
|
112
|
+
if (signal?.aborted) return reject(new HyperclipTimeoutError("Wait aborted"));
|
|
113
|
+
const t = setTimeout(() => {
|
|
114
|
+
signal?.removeEventListener("abort", onAbort);
|
|
115
|
+
resolve();
|
|
116
|
+
}, ms);
|
|
117
|
+
const onAbort = () => {
|
|
118
|
+
clearTimeout(t);
|
|
119
|
+
reject(new HyperclipTimeoutError("Wait aborted"));
|
|
120
|
+
};
|
|
121
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
export {
|
|
125
|
+
Hyperclip,
|
|
126
|
+
HyperclipError,
|
|
127
|
+
HyperclipTimeoutError
|
|
128
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "hyperclip",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official Node SDK for the Hyperclip API — create, poll, and manage flow runs.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://hyperclip.co",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/hyperclip/hyperclip-sdks.git",
|
|
10
|
+
"directory": "node"
|
|
11
|
+
},
|
|
12
|
+
"bugs": "https://github.com/hyperclip/hyperclip-sdks/issues",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"hyperclip",
|
|
15
|
+
"video",
|
|
16
|
+
"ai-video",
|
|
17
|
+
"sdk",
|
|
18
|
+
"api"
|
|
19
|
+
],
|
|
20
|
+
"main": "./dist/index.cjs",
|
|
21
|
+
"module": "./dist/index.mjs",
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"import": "./dist/index.mjs",
|
|
27
|
+
"require": "./dist/index.cjs"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"README.md",
|
|
33
|
+
"LICENSE"
|
|
34
|
+
],
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=18"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
40
|
+
"lint": "tsc --noEmit",
|
|
41
|
+
"prepublishOnly": "npm run build"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"tsup": "^8.0.0",
|
|
45
|
+
"typescript": "^5.4.0"
|
|
46
|
+
},
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public"
|
|
49
|
+
}
|
|
50
|
+
}
|