@tapi-dev/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,7 @@
1
+ import type { HttpClient } from "./client";
2
+ import type { SdkCatalog } from "./types";
3
+ export declare class CatalogResource {
4
+ private readonly http;
5
+ constructor(http: HttpClient);
6
+ get(): Promise<SdkCatalog>;
7
+ }
@@ -0,0 +1,9 @@
1
+ export class CatalogResource {
2
+ http;
3
+ constructor(http) {
4
+ this.http = http;
5
+ }
6
+ get() {
7
+ return this.http.get("/api/sdk/v1/catalog");
8
+ }
9
+ }
@@ -0,0 +1,11 @@
1
+ import type { TapiClientOptions } from "./types";
2
+ export declare class HttpClient {
3
+ private readonly baseUrl;
4
+ private readonly apiKey;
5
+ private readonly appId?;
6
+ private readonly fetchImpl;
7
+ constructor(options: TapiClientOptions);
8
+ get<T>(path: string): Promise<T>;
9
+ post<T>(path: string, body?: unknown): Promise<T>;
10
+ private request;
11
+ }
package/dist/client.js ADDED
@@ -0,0 +1,50 @@
1
+ import { TapiError } from "./errors";
2
+ export class HttpClient {
3
+ baseUrl;
4
+ apiKey;
5
+ appId;
6
+ fetchImpl;
7
+ constructor(options) {
8
+ this.baseUrl = options.baseUrl.replace(/\/+$/, "");
9
+ this.apiKey = options.apiKey;
10
+ this.appId = options.appId;
11
+ this.fetchImpl = options.fetch ?? fetch;
12
+ }
13
+ async get(path) {
14
+ return this.request("GET", path);
15
+ }
16
+ async post(path, body) {
17
+ return this.request("POST", path, body);
18
+ }
19
+ async request(method, path, body) {
20
+ const response = await this.fetchImpl(`${this.baseUrl}${path}`, {
21
+ method,
22
+ headers: {
23
+ Authorization: `Bearer ${this.apiKey}`,
24
+ "Content-Type": "application/json",
25
+ ...(this.appId ? { "X-Tapi-App": this.appId } : {}),
26
+ },
27
+ body: body === undefined ? undefined : JSON.stringify(body),
28
+ });
29
+ const payload = await readJson(response);
30
+ if (!response.ok) {
31
+ const detail = isRecord(payload) ? payload.detail ?? payload.error ?? payload : payload;
32
+ throw new TapiError(`tapi request failed: ${response.status}`, {
33
+ status: response.status,
34
+ code: isRecord(detail) && typeof detail.code === "string" ? detail.code : "http_error",
35
+ details: detail,
36
+ });
37
+ }
38
+ return payload;
39
+ }
40
+ }
41
+ async function readJson(response) {
42
+ const text = await response.text();
43
+ if (!text) {
44
+ return {};
45
+ }
46
+ return JSON.parse(text);
47
+ }
48
+ function isRecord(value) {
49
+ return typeof value === "object" && value !== null && !Array.isArray(value);
50
+ }
@@ -0,0 +1,10 @@
1
+ export declare class TapiError extends Error {
2
+ readonly status: number;
3
+ readonly code: string;
4
+ readonly details: unknown;
5
+ constructor(message: string, options: {
6
+ status: number;
7
+ code?: string;
8
+ details?: unknown;
9
+ });
10
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,12 @@
1
+ export class TapiError extends Error {
2
+ status;
3
+ code;
4
+ details;
5
+ constructor(message, options) {
6
+ super(message);
7
+ this.name = "TapiError";
8
+ this.status = options.status;
9
+ this.code = options.code ?? "tapi_error";
10
+ this.details = options.details;
11
+ }
12
+ }
@@ -0,0 +1,16 @@
1
+ import { CatalogResource } from "./catalog";
2
+ import { RunnersResource } from "./runners";
3
+ import { RunsResource } from "./runs";
4
+ import { RuntimeResource } from "./runtime";
5
+ import type { TapiClientOptions } from "./types";
6
+ import { WebsiteApisResource } from "./website-apis";
7
+ export declare class TapiClient {
8
+ readonly catalog: CatalogResource;
9
+ readonly runners: RunnersResource;
10
+ readonly runs: RunsResource;
11
+ readonly runtime: RuntimeResource;
12
+ readonly websiteApis: WebsiteApisResource;
13
+ constructor(options: TapiClientOptions);
14
+ }
15
+ export * from "./errors";
16
+ export * from "./types";
package/dist/index.js ADDED
@@ -0,0 +1,23 @@
1
+ import { HttpClient } from "./client";
2
+ import { CatalogResource } from "./catalog";
3
+ import { RunnersResource } from "./runners";
4
+ import { RunsResource } from "./runs";
5
+ import { RuntimeResource } from "./runtime";
6
+ import { WebsiteApisResource } from "./website-apis";
7
+ export class TapiClient {
8
+ catalog;
9
+ runners;
10
+ runs;
11
+ runtime;
12
+ websiteApis;
13
+ constructor(options) {
14
+ const http = new HttpClient(options);
15
+ this.catalog = new CatalogResource(http);
16
+ this.runners = new RunnersResource(http);
17
+ this.runs = new RunsResource(http);
18
+ this.runtime = new RuntimeResource(http);
19
+ this.websiteApis = new WebsiteApisResource(http);
20
+ }
21
+ }
22
+ export * from "./errors";
23
+ export * from "./types";
@@ -0,0 +1,9 @@
1
+ import type { HttpClient } from "./client";
2
+ import type { TapiRunner } from "./types";
3
+ export declare class RunnersResource {
4
+ private readonly http;
5
+ constructor(http: HttpClient);
6
+ list(): Promise<{
7
+ runners: TapiRunner[];
8
+ }>;
9
+ }
@@ -0,0 +1,9 @@
1
+ export class RunnersResource {
2
+ http;
3
+ constructor(http) {
4
+ this.http = http;
5
+ }
6
+ list() {
7
+ return this.http.get("/api/sdk/v1/runners");
8
+ }
9
+ }
package/dist/runs.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ import type { HttpClient } from "./client";
2
+ import type { TapiRun } from "./types";
3
+ export declare class RunsResource {
4
+ private readonly http;
5
+ constructor(http: HttpClient);
6
+ get(runId: string): Promise<TapiRun>;
7
+ cancel(runId: string): Promise<TapiRun>;
8
+ wait(runId: string, options?: {
9
+ intervalMs?: number;
10
+ timeoutMs?: number;
11
+ }): Promise<TapiRun>;
12
+ }
package/dist/runs.js ADDED
@@ -0,0 +1,24 @@
1
+ export class RunsResource {
2
+ http;
3
+ constructor(http) {
4
+ this.http = http;
5
+ }
6
+ get(runId) {
7
+ return this.http.get(`/api/sdk/v1/runs/${encodeURIComponent(runId)}`);
8
+ }
9
+ cancel(runId) {
10
+ return this.http.post(`/api/sdk/v1/runs/${encodeURIComponent(runId)}/cancel`);
11
+ }
12
+ async wait(runId, options = {}) {
13
+ const intervalMs = options.intervalMs ?? 1000;
14
+ const deadline = Date.now() + (options.timeoutMs ?? 300000);
15
+ while (Date.now() <= deadline) {
16
+ const run = await this.get(runId);
17
+ if (["completed", "failed", "cancelled", "needs_developer_attention"].includes(run.status)) {
18
+ return run;
19
+ }
20
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
21
+ }
22
+ throw new Error(`timed out waiting for run ${runId}`);
23
+ }
24
+ }
@@ -0,0 +1,7 @@
1
+ import type { HttpClient } from "./client";
2
+ import type { RuntimeRequirements } from "./types";
3
+ export declare class RuntimeResource {
4
+ private readonly http;
5
+ constructor(http: HttpClient);
6
+ requirements(): Promise<RuntimeRequirements>;
7
+ }
@@ -0,0 +1,9 @@
1
+ export class RuntimeResource {
2
+ http;
3
+ constructor(http) {
4
+ this.http = http;
5
+ }
6
+ requirements() {
7
+ return this.http.get("/api/sdk/v1/runtime/requirements");
8
+ }
9
+ }
@@ -0,0 +1,55 @@
1
+ export type RunStatus = "queued" | "running" | "completed" | "failed" | "cancelled" | "needs_developer_attention";
2
+ export interface TapiClientOptions {
3
+ baseUrl: string;
4
+ apiKey: string;
5
+ appId?: string;
6
+ fetch?: typeof fetch;
7
+ }
8
+ export interface WebsiteApiRunRequest {
9
+ inputs?: Record<string, unknown>;
10
+ priority?: number;
11
+ runnerId?: string;
12
+ idempotencyKey?: string;
13
+ }
14
+ export interface TapiRun {
15
+ id: string;
16
+ status: RunStatus;
17
+ apiName?: string;
18
+ requestKey?: string;
19
+ result?: Record<string, unknown> | null;
20
+ error?: Record<string, unknown> | null;
21
+ createdAt?: string;
22
+ updatedAt?: string;
23
+ [key: string]: unknown;
24
+ }
25
+ export interface TapiRunner {
26
+ id: string;
27
+ status: string;
28
+ name?: string;
29
+ online?: boolean;
30
+ [key: string]: unknown;
31
+ }
32
+ export interface RuntimeRequirements {
33
+ daemonRequired: boolean;
34
+ localControlUrl?: string;
35
+ windowsServiceName?: string;
36
+ [key: string]: unknown;
37
+ }
38
+ export interface SdkCatalogRequest {
39
+ key: string;
40
+ status: string;
41
+ inputs?: unknown[];
42
+ responseSchema?: Record<string, unknown>;
43
+ [key: string]: unknown;
44
+ }
45
+ export interface SdkCatalogApi {
46
+ name: string;
47
+ version: string;
48
+ site?: string;
49
+ requests: SdkCatalogRequest[];
50
+ [key: string]: unknown;
51
+ }
52
+ export interface SdkCatalog {
53
+ apis: SdkCatalogApi[];
54
+ [key: string]: unknown;
55
+ }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ import type { HttpClient } from "./client";
2
+ import type { TapiRun, WebsiteApiRunRequest } from "./types";
3
+ export declare class WebsiteApisResource {
4
+ private readonly http;
5
+ constructor(http: HttpClient);
6
+ run(apiRequest: string, request?: WebsiteApiRunRequest): Promise<TapiRun>;
7
+ }
@@ -0,0 +1,21 @@
1
+ export class WebsiteApisResource {
2
+ http;
3
+ constructor(http) {
4
+ this.http = http;
5
+ }
6
+ run(apiRequest, request = {}) {
7
+ const { apiName, requestKey } = splitApiRequest(apiRequest);
8
+ return this.http.post(`/api/sdk/v1/website-apis/${encodeURIComponent(apiName)}/requests/${encodeURIComponent(requestKey)}/runs`, request);
9
+ }
10
+ }
11
+ function splitApiRequest(value) {
12
+ const text = value.trim();
13
+ const index = text.lastIndexOf(".");
14
+ if (index <= 0 || index === text.length - 1) {
15
+ throw new Error("api request must be formatted as '<apiName>.<requestKey>'");
16
+ }
17
+ return {
18
+ apiName: text.slice(0, index),
19
+ requestKey: text.slice(index + 1),
20
+ };
21
+ }
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@tapi-dev/sdk",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsc -p tsconfig.json",
18
+ "test": "vitest run",
19
+ "prepack": "npm run build",
20
+ "prepublishOnly": "npm test && npm run build"
21
+ },
22
+ "publishConfig": {
23
+ "access": "public"
24
+ },
25
+ "devDependencies": {
26
+ "typescript": "^5.5.0",
27
+ "vitest": "^2.0.0"
28
+ }
29
+ }