@tapi-dev/sdk 0.1.7 → 0.1.8

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/client.d.ts CHANGED
@@ -2,7 +2,7 @@ import type { TapiClientOptions } from "./types.js";
2
2
  export declare class HttpClient {
3
3
  private readonly baseUrl;
4
4
  private readonly apiKey;
5
- private readonly appId?;
5
+ private readonly projectId?;
6
6
  private readonly fetchImpl;
7
7
  constructor(options: TapiClientOptions);
8
8
  get<T>(path: string): Promise<T>;
package/dist/client.js CHANGED
@@ -2,12 +2,12 @@ import { TapiError } from "./errors.js";
2
2
  export class HttpClient {
3
3
  baseUrl;
4
4
  apiKey;
5
- appId;
5
+ projectId;
6
6
  fetchImpl;
7
7
  constructor(options) {
8
8
  this.baseUrl = options.baseUrl.replace(/\/+$/, "");
9
9
  this.apiKey = options.apiKey;
10
- this.appId = options.appId;
10
+ this.projectId = options.projectId;
11
11
  this.fetchImpl = options.fetch ?? fetch;
12
12
  }
13
13
  async get(path) {
@@ -22,7 +22,7 @@ export class HttpClient {
22
22
  headers: {
23
23
  Authorization: `Bearer ${this.apiKey}`,
24
24
  "Content-Type": "application/json",
25
- ...(this.appId ? { "X-Tapi-App": this.appId } : {}),
25
+ ...(this.projectId ? { "X-Tapi-Project": this.projectId } : {}),
26
26
  },
27
27
  body: body === undefined ? undefined : JSON.stringify(body),
28
28
  });
package/dist/index.d.ts CHANGED
@@ -16,3 +16,4 @@ export declare class TapiClient {
16
16
  }
17
17
  export * from "./errors.js";
18
18
  export * from "./types.js";
19
+ export * from "./workspace.js";
package/dist/index.js CHANGED
@@ -24,3 +24,4 @@ export class TapiClient {
24
24
  }
25
25
  export * from "./errors.js";
26
26
  export * from "./types.js";
27
+ export * from "./workspace.js";
package/dist/types.d.ts CHANGED
@@ -2,7 +2,7 @@ export type RunStatus = "queued" | "running" | "completed" | "failed" | "cancell
2
2
  export interface TapiClientOptions {
3
3
  baseUrl: string;
4
4
  apiKey: string;
5
- appId?: string;
5
+ projectId?: string;
6
6
  fetch?: typeof fetch;
7
7
  localControlUrl?: string;
8
8
  webSocket?: LocalWebSocketConstructor;
@@ -0,0 +1,35 @@
1
+ export declare const TAPI_WORKSPACE_DIR = ".tapi";
2
+ export declare const TAPI_WORKSPACE_CONFIG = "project.json";
3
+ export interface TapiGeneratedConfig {
4
+ catalog?: string;
5
+ typescript?: string;
6
+ [key: string]: unknown;
7
+ }
8
+ export interface TapiWorkspaceConfig {
9
+ version: 1;
10
+ projectId: string;
11
+ projectSlug?: string;
12
+ apiBaseUrl?: string;
13
+ generated?: TapiGeneratedConfig;
14
+ [key: string]: unknown;
15
+ }
16
+ export interface TapiWorkspace {
17
+ root: string;
18
+ configPath: string;
19
+ config: TapiWorkspaceConfig;
20
+ projectId: string;
21
+ projectSlug?: string;
22
+ apiBaseUrl?: string;
23
+ }
24
+ export interface WriteWorkspaceConfigOptions {
25
+ root?: string;
26
+ projectId: string;
27
+ projectSlug?: string;
28
+ apiBaseUrl?: string;
29
+ force?: boolean;
30
+ }
31
+ export declare function findWorkspaceConfigPath(startDir?: string): string | undefined;
32
+ export declare function loadWorkspace(startDir?: string): TapiWorkspace | undefined;
33
+ export declare function readWorkspaceConfig(configPath: string): TapiWorkspaceConfig;
34
+ export declare function writeWorkspaceConfig(options: WriteWorkspaceConfigOptions): Promise<TapiWorkspace>;
35
+ export declare function normalizeProjectValue(value: unknown, fieldName?: string): string;
@@ -0,0 +1,117 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { mkdir, writeFile } from "node:fs/promises";
3
+ import { dirname, join, resolve } from "node:path";
4
+ export const TAPI_WORKSPACE_DIR = ".tapi";
5
+ export const TAPI_WORKSPACE_CONFIG = "project.json";
6
+ export function findWorkspaceConfigPath(startDir = process.cwd()) {
7
+ let current = resolve(startDir);
8
+ while (true) {
9
+ const candidate = join(current, TAPI_WORKSPACE_DIR, TAPI_WORKSPACE_CONFIG);
10
+ if (existsSync(candidate)) {
11
+ return candidate;
12
+ }
13
+ const parent = dirname(current);
14
+ if (parent === current) {
15
+ return undefined;
16
+ }
17
+ current = parent;
18
+ }
19
+ }
20
+ export function loadWorkspace(startDir = process.cwd()) {
21
+ const configPath = findWorkspaceConfigPath(startDir);
22
+ if (!configPath) {
23
+ return undefined;
24
+ }
25
+ const config = readWorkspaceConfig(configPath);
26
+ const root = dirname(dirname(configPath));
27
+ return {
28
+ root,
29
+ configPath,
30
+ config,
31
+ projectId: config.projectId,
32
+ projectSlug: config.projectSlug,
33
+ apiBaseUrl: config.apiBaseUrl,
34
+ };
35
+ }
36
+ export function readWorkspaceConfig(configPath) {
37
+ let parsed;
38
+ try {
39
+ parsed = JSON.parse(readFileSync(configPath, "utf8"));
40
+ }
41
+ catch (error) {
42
+ throw new Error(`Could not read Tapi workspace config at ${configPath}: ${formatError(error)}`);
43
+ }
44
+ if (!isRecord(parsed)) {
45
+ throw new Error(`Tapi workspace config at ${configPath} must be a JSON object.`);
46
+ }
47
+ const version = parsed.version;
48
+ if (version !== 1) {
49
+ throw new Error(`Tapi workspace config at ${configPath} has unsupported version '${String(version)}'.`);
50
+ }
51
+ const projectId = normalizeProjectValue(parsed.projectId, "projectId");
52
+ const projectSlug = optionalProjectValue(parsed.projectSlug, "projectSlug");
53
+ const apiBaseUrl = typeof parsed.apiBaseUrl === "string" && parsed.apiBaseUrl.trim() ? parsed.apiBaseUrl.trim() : undefined;
54
+ const generated = isRecord(parsed.generated) ? { ...parsed.generated } : undefined;
55
+ return {
56
+ ...parsed,
57
+ version: 1,
58
+ projectId,
59
+ ...(projectSlug ? { projectSlug } : {}),
60
+ ...(apiBaseUrl ? { apiBaseUrl } : {}),
61
+ ...(generated ? { generated } : {}),
62
+ };
63
+ }
64
+ export async function writeWorkspaceConfig(options) {
65
+ const root = resolve(options.root ?? process.cwd());
66
+ const projectId = normalizeProjectValue(options.projectId, "projectId");
67
+ const projectSlug = optionalProjectValue(options.projectSlug, "projectSlug") ?? projectId;
68
+ const configPath = join(root, TAPI_WORKSPACE_DIR, TAPI_WORKSPACE_CONFIG);
69
+ if (!options.force && existsSync(configPath)) {
70
+ throw new Error(`Tapi workspace config already exists at ${configPath}. Use --force to overwrite.`);
71
+ }
72
+ const config = {
73
+ version: 1,
74
+ projectId,
75
+ projectSlug,
76
+ ...(options.apiBaseUrl ? { apiBaseUrl: options.apiBaseUrl } : {}),
77
+ generated: {
78
+ catalog: ".tapi/generated/catalog.json",
79
+ typescript: "src/tapi.generated.ts",
80
+ },
81
+ };
82
+ await mkdir(dirname(configPath), { recursive: true });
83
+ await writeFile(configPath, `${JSON.stringify(config, null, 2)}\n`, "utf8");
84
+ return {
85
+ root,
86
+ configPath,
87
+ config,
88
+ projectId,
89
+ projectSlug,
90
+ apiBaseUrl: config.apiBaseUrl,
91
+ };
92
+ }
93
+ export function normalizeProjectValue(value, fieldName = "project") {
94
+ if (typeof value !== "string") {
95
+ throw new Error(`Tapi ${fieldName} must be a string.`);
96
+ }
97
+ const project = value.trim();
98
+ if (!project) {
99
+ throw new Error(`Tapi ${fieldName} is required.`);
100
+ }
101
+ if (project.includes("/") || project.includes("\\") || project.includes("..")) {
102
+ throw new Error(`Tapi ${fieldName} is invalid.`);
103
+ }
104
+ return project;
105
+ }
106
+ function optionalProjectValue(value, fieldName) {
107
+ if (value === undefined || value === null || value === "") {
108
+ return undefined;
109
+ }
110
+ return normalizeProjectValue(value, fieldName);
111
+ }
112
+ function isRecord(value) {
113
+ return typeof value === "object" && value !== null && !Array.isArray(value);
114
+ }
115
+ function formatError(error) {
116
+ return error instanceof Error ? error.message : String(error);
117
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tapi-dev/sdk",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -21,7 +21,7 @@
21
21
  ],
22
22
  "scripts": {
23
23
  "build": "tsc -p tsconfig.json",
24
- "test": "vitest run",
24
+ "test": "vitest run --no-file-parallelism --testTimeout=30000",
25
25
  "prepack": "npm run build",
26
26
  "prepublishOnly": "npm test && npm run build"
27
27
  },
@@ -31,6 +31,7 @@
31
31
  "devDependencies": {
32
32
  "@types/node": "^20.0.0",
33
33
  "typescript": "^5.5.0",
34
- "vitest": "^2.0.0"
34
+ "vite": "6.4.3",
35
+ "vitest": "^4.1.8"
35
36
  }
36
37
  }