@init.computer/sdk 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.
@@ -0,0 +1,77 @@
1
+ export type JsonValue =
2
+ | string
3
+ | number
4
+ | boolean
5
+ | null
6
+ | JsonValue[]
7
+ | { [key: string]: JsonValue };
8
+
9
+ export type JsonObject = { [key: string]: JsonValue | undefined };
10
+
11
+ export type InitClientOptions = {
12
+ apiKey?: string;
13
+ baseUrl?: string;
14
+ fetch?: typeof fetch;
15
+ };
16
+
17
+ export type RequestOptions = {
18
+ method?: string;
19
+ requestFormat?: "json" | "multipart/form-data";
20
+ headers?: HeadersInit;
21
+ };
22
+
23
+ export class InitApiError extends Error {
24
+ status?: number;
25
+ response?: unknown;
26
+ details?: unknown;
27
+ constructor(message: string, options?: { status?: number; response?: unknown; details?: unknown });
28
+ }
29
+
30
+ export type ResourceClient = {
31
+ list<T = unknown>(query?: JsonObject): Promise<T>;
32
+ get<T = unknown>(id: string): Promise<T>;
33
+ update<T = unknown>(id: string, patch: JsonObject): Promise<T>;
34
+ edit<T = unknown>(resourceId: string, request: JsonObject): Promise<T>;
35
+ versions<T = unknown>(id: string): Promise<T>;
36
+ activateVersion<T = unknown>(id: string, versionId: string): Promise<T>;
37
+ };
38
+
39
+ export type DirectoryClient = {
40
+ list<T = unknown>(query?: JsonObject): Promise<T>;
41
+ create<T = unknown>(input: JsonObject): Promise<T>;
42
+ get<T = unknown>(id: string): Promise<T>;
43
+ update<T = unknown>(id: string, patch: JsonObject): Promise<T>;
44
+ delete<T = unknown>(id: string): Promise<T>;
45
+ addResources<T = unknown>(id: string, resourceIds: string[]): Promise<T>;
46
+ removeResource<T = unknown>(id: string, resourceId: string): Promise<T>;
47
+ };
48
+
49
+ export type DaemonClient = {
50
+ list<T = unknown>(query?: JsonObject): Promise<T>;
51
+ create<T = unknown>(input: JsonObject): Promise<T>;
52
+ get<T = unknown>(id: string): Promise<T>;
53
+ pause<T = unknown>(id: string): Promise<T>;
54
+ resume<T = unknown>(id: string): Promise<T>;
55
+ stop<T = unknown>(id: string): Promise<T>;
56
+ run<T = unknown>(id: string): Promise<T>;
57
+ };
58
+
59
+ export type PackageClient = {
60
+ list<T = unknown>(query?: JsonObject): Promise<T>;
61
+ };
62
+
63
+ export class InitClient {
64
+ constructor(options?: InitClientOptions);
65
+ baseUrl: string;
66
+ apiKey?: string;
67
+ resource: ResourceClient;
68
+ directory: DirectoryClient;
69
+ daemon: DaemonClient;
70
+ pkg: PackageClient;
71
+ withApiKey(apiKey: string): InitClient;
72
+ generate<T = unknown>(request: JsonObject): Promise<T>;
73
+ run<T = unknown>(route: string, input?: JsonObject | FormData, options?: RequestOptions & { version?: number }): Promise<T>;
74
+ request<T = unknown>(path: string, options?: RequestOptions & { body?: unknown }): Promise<T>;
75
+ }
76
+
77
+ export function createClient(options?: InitClientOptions): InitClient;
package/dist/index.js ADDED
@@ -0,0 +1,196 @@
1
+ const DEFAULT_BASE_URL = "https://api.init.computer";
2
+
3
+ export class InitApiError extends Error {
4
+ constructor(message, { status, response, details } = {}) {
5
+ super(message);
6
+ this.name = "InitApiError";
7
+ this.status = status;
8
+ this.response = response;
9
+ this.details = details;
10
+ }
11
+ }
12
+
13
+ export class InitClient {
14
+ constructor(options = {}) {
15
+ const env = globalThis.process?.env || {};
16
+ this.baseUrl = stripTrailingSlash(options.baseUrl || env.INIT_API_BASE_URL || DEFAULT_BASE_URL);
17
+ this.apiKey = options.apiKey || env.INIT_API_KEY;
18
+ this.fetch = options.fetch || globalThis.fetch;
19
+ if (!this.fetch) {
20
+ throw new InitApiError("A fetch implementation is required.");
21
+ }
22
+ this.resource = {
23
+ list: (query = {}) => this.request(`/v1/resources${queryString(query)}`),
24
+ get: (id) => this.request(`/v1/resources/${encodeURIComponent(id)}`),
25
+ update: (id, patch) => this.request(`/v1/resources/${encodeURIComponent(id)}`, {
26
+ method: "PATCH",
27
+ body: patch,
28
+ }),
29
+ edit: (resourceId, request) => this.generate({ ...request, resource_id: resourceId }),
30
+ versions: (id) => this.request(`/v1/resources/${encodeURIComponent(id)}/versions`),
31
+ activateVersion: (id, versionId) => this.request(
32
+ `/v1/resources/${encodeURIComponent(id)}/versions/${encodeURIComponent(versionId)}/activate`,
33
+ { method: "POST" },
34
+ ),
35
+ };
36
+ this.directory = {
37
+ list: (query = {}) => this.request(`/v1/directories${queryString(query)}`),
38
+ create: (input) => this.request("/v1/directories", { method: "POST", body: input }),
39
+ get: (id) => this.request(`/v1/directories/${encodeURIComponent(id)}`),
40
+ update: (id, patch) => this.request(`/v1/directories/${encodeURIComponent(id)}`, {
41
+ method: "PATCH",
42
+ body: patch,
43
+ }),
44
+ delete: (id) => this.request(`/v1/directories/${encodeURIComponent(id)}`, {
45
+ method: "DELETE",
46
+ }),
47
+ addResources: (id, resourceIds) => this.request(`/v1/directories/${encodeURIComponent(id)}/resources`, {
48
+ method: "POST",
49
+ body: { resource_ids: resourceIds },
50
+ }),
51
+ removeResource: (id, resourceId) => this.request(
52
+ `/v1/directories/${encodeURIComponent(id)}/resources/${encodeURIComponent(resourceId)}`,
53
+ { method: "DELETE" },
54
+ ),
55
+ };
56
+ this.daemon = {
57
+ list: (query = {}) => this.request(`/v1/daemons${queryString(query)}`),
58
+ create: (input) => this.request("/v1/daemons", { method: "POST", body: input }),
59
+ get: (id) => this.request(`/v1/daemons/${encodeURIComponent(id)}`),
60
+ pause: (id) => this.request(`/v1/daemons/${encodeURIComponent(id)}/pause`, { method: "POST" }),
61
+ resume: (id) => this.request(`/v1/daemons/${encodeURIComponent(id)}/resume`, { method: "POST" }),
62
+ stop: (id) => this.request(`/v1/daemons/${encodeURIComponent(id)}/stop`, { method: "POST" }),
63
+ run: (id) => this.request(`/v1/daemons/${encodeURIComponent(id)}/run`, { method: "POST" }),
64
+ };
65
+ this.pkg = {
66
+ list: (query = {}) => this.request(`/v1/packages${queryString(query)}`),
67
+ };
68
+ }
69
+
70
+ withApiKey(apiKey) {
71
+ return new InitClient({ baseUrl: this.baseUrl, apiKey, fetch: this.fetch });
72
+ }
73
+
74
+ async generate(request) {
75
+ return this.request("/v1/generate", {
76
+ method: "POST",
77
+ body: request,
78
+ });
79
+ }
80
+
81
+ async run(route, input = {}, options = {}) {
82
+ const path = normalizeRunPath(route, options.version);
83
+ return this.request(path, {
84
+ method: options.method || "POST",
85
+ body: input,
86
+ requestFormat: options.requestFormat,
87
+ });
88
+ }
89
+
90
+ async request(path, options = {}) {
91
+ const headers = new Headers(options.headers || {});
92
+ if (this.apiKey && !headers.has("authorization")) {
93
+ headers.set("authorization", `Bearer ${this.apiKey}`);
94
+ }
95
+
96
+ let body;
97
+ const requestFormat = options.requestFormat || inferRequestFormat(options.body);
98
+ if (options.body !== undefined && options.method !== "GET") {
99
+ if (requestFormat === "multipart/form-data") {
100
+ body = toFormData(options.body);
101
+ } else {
102
+ headers.set("content-type", "application/json");
103
+ body = JSON.stringify(options.body);
104
+ }
105
+ }
106
+
107
+ const response = await this.fetch(`${this.baseUrl}${path}`, {
108
+ method: options.method || "GET",
109
+ headers,
110
+ body,
111
+ });
112
+ const text = await response.text();
113
+ const payload = parseJson(text);
114
+ if (!response.ok || payload?.success === false) {
115
+ const firstError = Array.isArray(payload?.errors) ? payload.errors[0] : undefined;
116
+ throw new InitApiError(firstError?.message || response.statusText || "Init API request failed", {
117
+ status: response.status,
118
+ response: payload ?? text,
119
+ details: firstError?.details,
120
+ });
121
+ }
122
+ return payload ?? text;
123
+ }
124
+ }
125
+
126
+ export function createClient(options) {
127
+ return new InitClient(options);
128
+ }
129
+
130
+ function normalizeRunPath(route, version = 1) {
131
+ if (!route) {
132
+ throw new InitApiError("route is required.");
133
+ }
134
+ const raw = String(route);
135
+ if (raw.startsWith("http://") || raw.startsWith("https://")) {
136
+ const url = new URL(raw);
137
+ return `${url.pathname}${url.search}`;
138
+ }
139
+ if (raw.startsWith("/")) {
140
+ return raw;
141
+ }
142
+ if (/^v\d+\//.test(raw)) {
143
+ return `/${raw}`;
144
+ }
145
+ return `/v${version}/${raw}`;
146
+ }
147
+
148
+ function queryString(query) {
149
+ const params = new URLSearchParams();
150
+ for (const [key, value] of Object.entries(query || {})) {
151
+ if (value === undefined || value === null || value === "") continue;
152
+ params.set(key, String(value));
153
+ }
154
+ const text = params.toString();
155
+ return text ? `?${text}` : "";
156
+ }
157
+
158
+ function inferRequestFormat(body) {
159
+ if (typeof FormData !== "undefined" && body instanceof FormData) {
160
+ return "multipart/form-data";
161
+ }
162
+ return "json";
163
+ }
164
+
165
+ function toFormData(input) {
166
+ if (typeof FormData !== "undefined" && input instanceof FormData) {
167
+ return input;
168
+ }
169
+ const form = new FormData();
170
+ for (const [key, value] of Object.entries(input || {})) {
171
+ if (Array.isArray(value)) {
172
+ for (const item of value) form.append(key, formValue(item));
173
+ } else {
174
+ form.append(key, formValue(value));
175
+ }
176
+ }
177
+ return form;
178
+ }
179
+
180
+ function formValue(value) {
181
+ if (typeof Blob !== "undefined" && value instanceof Blob) return value;
182
+ return typeof value === "string" ? value : JSON.stringify(value);
183
+ }
184
+
185
+ function parseJson(text) {
186
+ if (!text) return null;
187
+ try {
188
+ return JSON.parse(text);
189
+ } catch {
190
+ return null;
191
+ }
192
+ }
193
+
194
+ function stripTrailingSlash(value) {
195
+ return String(value).replace(/\/+$/, "");
196
+ }
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "@init.computer/sdk",
3
+ "version": "0.1.0",
4
+ "description": "Official JavaScript SDK for Init generated backend APIs.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "engines": {
18
+ "node": ">=18"
19
+ },
20
+ "license": "UNLICENSED"
21
+ }