@tapi-dev/sdk 0.1.2 → 0.1.3

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.
Files changed (3) hide show
  1. package/README.md +189 -189
  2. package/dist/cli.js +24 -9
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,189 +1,189 @@
1
- # TAPI JavaScript SDK
2
-
3
- Official JavaScript and TypeScript client for TAPI developer APIs.
4
-
5
- ## Install
6
-
7
- ```bash
8
- npm install @tapi-dev/sdk
9
- ```
10
-
11
- This package is ESM-first and works in runtimes with `fetch`, including modern Node.js and browser-like server runtimes.
12
-
13
- ## Install Tapi Studio
14
-
15
- Tapi Studio is the desktop app used to author and test local Tapi integrations. Install the SDK first, then use the bundled CLI:
16
-
17
- ```bash
18
- npm install @tapi-dev/sdk
19
- npx tapi studio install --channel pilot
20
- npx tapi studio open
21
- ```
22
-
23
- You can also run the CLI directly from npm without adding the package first:
24
-
25
- ```bash
26
- npx @tapi-dev/sdk studio install --channel pilot
27
- ```
28
-
29
- The CLI reads the release manifest from:
30
-
31
- ```text
32
- https://downloads.tapi.dev/studio/channels/pilot/latest.json
33
- ```
34
-
35
- It downloads the Windows installer, verifies the manifest SHA256, caches the installer locally, and runs it. The installer cache defaults to:
36
-
37
- ```text
38
- %LOCALAPPDATA%\Tapi\Studio\downloads
39
- ```
40
-
41
- Useful commands:
42
-
43
- ```bash
44
- npx tapi studio install --channel pilot
45
- npx tapi studio install --channel pilot --download-only
46
- npx tapi studio install --manifest https://downloads.tapi.dev/studio/channels/pilot/latest.json
47
- npx tapi studio open
48
- npx tapi studio doctor
49
- ```
50
-
51
- Environment overrides:
52
-
53
- ```env
54
- TAPI_STUDIO_CHANNEL=pilot
55
- TAPI_STUDIO_MANIFEST_URL=https://downloads.tapi.dev/studio/channels/pilot/latest.json
56
- TAPI_DOWNLOADS_BASE_URL=https://downloads.tapi.dev
57
- TAPI_STUDIO_EXE=C:\Users\you\AppData\Local\Tapi Studio\Tapi Studio.exe
58
- ```
59
-
60
- Tapi Studio desktop releases are currently published for Windows x64.
61
-
62
- ## Quick Start
63
-
64
- Create one TAPI client in your app's server-side code:
65
-
66
- ```ts
67
- import { TapiClient } from "@tapi-dev/sdk";
68
-
69
- export const tapi = new TapiClient({
70
- baseUrl: process.env.TAPI_BASE_URL!,
71
- apiKey: process.env.TAPI_API_KEY!,
72
- appId: process.env.TAPI_APP_ID,
73
- });
74
- ```
75
-
76
- Then call a TAPI website API:
77
-
78
- ```ts
79
- const run = await tapi.websiteApis.run("brokerage.submitTrade", {
80
- inputs: {
81
- symbol: "AAPL",
82
- quantity: 1,
83
- side: "buy",
84
- },
85
- });
86
-
87
- const completedRun = await tapi.runs.wait(run.id);
88
- console.log(completedRun.status, completedRun.result);
89
- ```
90
-
91
- Do not expose `TAPI_API_KEY` in public browser bundles. Put the SDK behind your own backend route, server action, or job worker when using secret API keys.
92
-
93
- ## Configuration
94
-
95
- ```env
96
- TAPI_BASE_URL=https://your-tapi-api-host
97
- TAPI_API_KEY=tapi_your_api_key
98
- TAPI_APP_ID=your-app-id
99
- ```
100
-
101
- `appId` is optional. If provided, the SDK sends it as the `X-Tapi-App` header.
102
-
103
- ## Common Project Setup
104
-
105
- A typical application keeps the client in one small module:
106
-
107
- ```text
108
- src/
109
- lib/
110
- tapi.ts
111
- ```
112
-
113
- ```ts
114
- // src/lib/tapi.ts
115
- import { TapiClient } from "@tapi-dev/sdk";
116
-
117
- export const tapi = new TapiClient({
118
- baseUrl: process.env.TAPI_BASE_URL!,
119
- apiKey: process.env.TAPI_API_KEY!,
120
- appId: process.env.TAPI_APP_ID,
121
- });
122
- ```
123
-
124
- Application code should import this shared client instead of constructing a new client in every file.
125
-
126
- ## Available Resources
127
-
128
- ```ts
129
- await tapi.catalog.get();
130
- await tapi.runners.list();
131
- await tapi.runtime.requirements();
132
-
133
- const run = await tapi.websiteApis.run("apiName.requestKey", {
134
- inputs: { example: true },
135
- priority: 5,
136
- runnerId: "runner-id",
137
- idempotencyKey: "request-123",
138
- });
139
-
140
- await tapi.runs.get(run.id);
141
- await tapi.runs.wait(run.id, { intervalMs: 1000, timeoutMs: 300000 });
142
- await tapi.runs.cancel(run.id);
143
- ```
144
-
145
- Website API requests are addressed as `<apiName>.<requestKey>`.
146
-
147
- ## Errors
148
-
149
- Failed HTTP responses throw `TapiError`:
150
-
151
- ```ts
152
- import { TapiError } from "@tapi-dev/sdk";
153
-
154
- try {
155
- await tapi.catalog.get();
156
- } catch (error) {
157
- if (error instanceof TapiError) {
158
- console.error(error.status, error.code, error.details);
159
- }
160
- throw error;
161
- }
162
- ```
163
-
164
- ## TypeScript
165
-
166
- The package includes generated TypeScript declarations. Common exported types include:
167
-
168
- ```ts
169
- import type {
170
- RuntimeRequirements,
171
- SdkCatalog,
172
- TapiRun,
173
- TapiRunner,
174
- WebsiteApiRunRequest,
175
- } from "@tapi-dev/sdk";
176
- ```
177
-
178
- ## Local Development
179
-
180
- From this SDK directory:
181
-
182
- ```bash
183
- npm ci
184
- npm test
185
- npm run build
186
- npm pack --dry-run
187
- ```
188
-
189
- `npm pack --dry-run` shows the exact files that will be published.
1
+ # TAPI JavaScript SDK
2
+
3
+ Official JavaScript and TypeScript client for TAPI developer APIs.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @tapi-dev/sdk
9
+ ```
10
+
11
+ This package is ESM-first and works in runtimes with `fetch`, including modern Node.js and browser-like server runtimes.
12
+
13
+ ## Install Tapi Studio
14
+
15
+ Tapi Studio is the desktop app used to author and test local Tapi integrations. Install the SDK first, then use the bundled CLI:
16
+
17
+ ```bash
18
+ npm install @tapi-dev/sdk
19
+ npx tapi studio install --channel pilot
20
+ npx tapi studio open
21
+ ```
22
+
23
+ You can also run the CLI directly from npm without adding the package first:
24
+
25
+ ```bash
26
+ npx @tapi-dev/sdk studio install --channel pilot
27
+ ```
28
+
29
+ The CLI reads the release manifest from:
30
+
31
+ ```text
32
+ https://d4xaf52nfwiok.cloudfront.net/studio/channels/pilot/latest.json
33
+ ```
34
+
35
+ It downloads the Windows installer, verifies the manifest SHA256, caches the installer locally, and runs it. The installer cache defaults to:
36
+
37
+ ```text
38
+ %LOCALAPPDATA%\Tapi\Studio\downloads
39
+ ```
40
+
41
+ Useful commands:
42
+
43
+ ```bash
44
+ npx tapi studio install --channel pilot
45
+ npx tapi studio install --channel pilot --download-only
46
+ npx tapi studio install --manifest https://d4xaf52nfwiok.cloudfront.net/studio/channels/pilot/latest.json
47
+ npx tapi studio open
48
+ npx tapi studio doctor
49
+ ```
50
+
51
+ Environment overrides:
52
+
53
+ ```env
54
+ TAPI_STUDIO_CHANNEL=pilot
55
+ TAPI_STUDIO_MANIFEST_URL=https://d4xaf52nfwiok.cloudfront.net/studio/channels/pilot/latest.json
56
+ TAPI_DOWNLOADS_BASE_URL=https://d4xaf52nfwiok.cloudfront.net
57
+ TAPI_STUDIO_EXE=C:\Users\you\AppData\Local\Tapi Studio\Tapi Studio.exe
58
+ ```
59
+
60
+ Tapi Studio desktop releases are currently published for Windows x64.
61
+
62
+ ## Quick Start
63
+
64
+ Create one TAPI client in your app's server-side code:
65
+
66
+ ```ts
67
+ import { TapiClient } from "@tapi-dev/sdk";
68
+
69
+ export const tapi = new TapiClient({
70
+ baseUrl: process.env.TAPI_BASE_URL!,
71
+ apiKey: process.env.TAPI_API_KEY!,
72
+ appId: process.env.TAPI_APP_ID,
73
+ });
74
+ ```
75
+
76
+ Then call a TAPI website API:
77
+
78
+ ```ts
79
+ const run = await tapi.websiteApis.run("brokerage.submitTrade", {
80
+ inputs: {
81
+ symbol: "AAPL",
82
+ quantity: 1,
83
+ side: "buy",
84
+ },
85
+ });
86
+
87
+ const completedRun = await tapi.runs.wait(run.id);
88
+ console.log(completedRun.status, completedRun.result);
89
+ ```
90
+
91
+ Do not expose `TAPI_API_KEY` in public browser bundles. Put the SDK behind your own backend route, server action, or job worker when using secret API keys.
92
+
93
+ ## Configuration
94
+
95
+ ```env
96
+ TAPI_BASE_URL=https://your-tapi-api-host
97
+ TAPI_API_KEY=tapi_your_api_key
98
+ TAPI_APP_ID=your-app-id
99
+ ```
100
+
101
+ `appId` is optional. If provided, the SDK sends it as the `X-Tapi-App` header.
102
+
103
+ ## Common Project Setup
104
+
105
+ A typical application keeps the client in one small module:
106
+
107
+ ```text
108
+ src/
109
+ lib/
110
+ tapi.ts
111
+ ```
112
+
113
+ ```ts
114
+ // src/lib/tapi.ts
115
+ import { TapiClient } from "@tapi-dev/sdk";
116
+
117
+ export const tapi = new TapiClient({
118
+ baseUrl: process.env.TAPI_BASE_URL!,
119
+ apiKey: process.env.TAPI_API_KEY!,
120
+ appId: process.env.TAPI_APP_ID,
121
+ });
122
+ ```
123
+
124
+ Application code should import this shared client instead of constructing a new client in every file.
125
+
126
+ ## Available Resources
127
+
128
+ ```ts
129
+ await tapi.catalog.get();
130
+ await tapi.runners.list();
131
+ await tapi.runtime.requirements();
132
+
133
+ const run = await tapi.websiteApis.run("apiName.requestKey", {
134
+ inputs: { example: true },
135
+ priority: 5,
136
+ runnerId: "runner-id",
137
+ idempotencyKey: "request-123",
138
+ });
139
+
140
+ await tapi.runs.get(run.id);
141
+ await tapi.runs.wait(run.id, { intervalMs: 1000, timeoutMs: 300000 });
142
+ await tapi.runs.cancel(run.id);
143
+ ```
144
+
145
+ Website API requests are addressed as `<apiName>.<requestKey>`.
146
+
147
+ ## Errors
148
+
149
+ Failed HTTP responses throw `TapiError`:
150
+
151
+ ```ts
152
+ import { TapiError } from "@tapi-dev/sdk";
153
+
154
+ try {
155
+ await tapi.catalog.get();
156
+ } catch (error) {
157
+ if (error instanceof TapiError) {
158
+ console.error(error.status, error.code, error.details);
159
+ }
160
+ throw error;
161
+ }
162
+ ```
163
+
164
+ ## TypeScript
165
+
166
+ The package includes generated TypeScript declarations. Common exported types include:
167
+
168
+ ```ts
169
+ import type {
170
+ RuntimeRequirements,
171
+ SdkCatalog,
172
+ TapiRun,
173
+ TapiRunner,
174
+ WebsiteApiRunRequest,
175
+ } from "@tapi-dev/sdk";
176
+ ```
177
+
178
+ ## Local Development
179
+
180
+ From this SDK directory:
181
+
182
+ ```bash
183
+ npm ci
184
+ npm test
185
+ npm run build
186
+ npm pack --dry-run
187
+ ```
188
+
189
+ `npm pack --dry-run` shows the exact files that will be published.
package/dist/cli.js CHANGED
@@ -8,7 +8,7 @@ import { basename, join, resolve } from "node:path";
8
8
  import { Readable } from "node:stream";
9
9
  import { pipeline } from "node:stream/promises";
10
10
  import { fileURLToPath } from "node:url";
11
- const DEFAULT_DOWNLOADS_BASE_URL = "https://downloads.tapi.dev";
11
+ const DEFAULT_DOWNLOADS_BASE_URL = "https://d4xaf52nfwiok.cloudfront.net";
12
12
  const DEFAULT_CHANNEL = "pilot";
13
13
  const SUPPORTED_STUDIO_PLATFORM = "windows-x86_64";
14
14
  const sdkVersion = readSdkVersion();
@@ -109,10 +109,11 @@ export function parseStudioOptions(args) {
109
109
  throw new Error(`Unknown option: ${arg}`);
110
110
  }
111
111
  const channel = raw.channel ?? parseChannel(envString("TAPI_STUDIO_CHANNEL") ?? DEFAULT_CHANNEL);
112
- const downloadsBaseUrl = envString("TAPI_DOWNLOADS_BASE_URL") ?? DEFAULT_DOWNLOADS_BASE_URL;
113
- const manifestUrl = raw.manifestUrl ??
114
- envString("TAPI_STUDIO_MANIFEST_URL") ??
115
- `${downloadsBaseUrl.replace(/\/+$/, "")}/studio/channels/${channel}/latest.json`;
112
+ const downloadsBaseUrl = normalizeHttpUrl(envString("TAPI_DOWNLOADS_BASE_URL") ?? DEFAULT_DOWNLOADS_BASE_URL, "TAPI_DOWNLOADS_BASE_URL");
113
+ const explicitManifestUrl = raw.manifestUrl ?? envString("TAPI_STUDIO_MANIFEST_URL");
114
+ const manifestUrl = explicitManifestUrl
115
+ ? normalizeHttpUrl(explicitManifestUrl, "Studio manifest URL")
116
+ : `${downloadsBaseUrl.replace(/\/+$/, "")}/studio/channels/${channel}/latest.json`;
116
117
  return {
117
118
  channel,
118
119
  manifestUrl,
@@ -152,7 +153,7 @@ export function validateStudioManifest(input) {
152
153
  channel: requiredString(record, "channel"),
153
154
  platform: requiredString(record, "platform"),
154
155
  artifactName: requiredString(record, "artifactName"),
155
- url: requiredString(record, "url"),
156
+ url: normalizeHttpUrl(requiredString(record, "url"), "Studio manifest url"),
156
157
  sha256: requiredString(record, "sha256").toLowerCase(),
157
158
  sizeBytes: optionalNumber(record, "sizeBytes"),
158
159
  minSdkVersion: optionalString(record, "minSdkVersion"),
@@ -162,9 +163,6 @@ export function validateStudioManifest(input) {
162
163
  ref: optionalString(record, "ref"),
163
164
  installerKind: optionalString(record, "installerKind"),
164
165
  };
165
- if (!/^https?:\/\//i.test(manifest.url)) {
166
- throw new Error("Studio manifest url must be an absolute HTTP(S) URL.");
167
- }
168
166
  if (!/^[a-f0-9]{64}$/i.test(manifest.sha256)) {
169
167
  throw new Error("Studio manifest sha256 must be a 64-character hex digest.");
170
168
  }
@@ -363,6 +361,23 @@ function envString(name) {
363
361
  const value = process.env[name];
364
362
  return value && value.trim() ? value.trim() : undefined;
365
363
  }
364
+ function normalizeHttpUrl(value, label) {
365
+ const trimmed = value.trim();
366
+ const withScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`;
367
+ try {
368
+ const url = new URL(withScheme);
369
+ if (url.protocol !== "https:" && url.protocol !== "http:") {
370
+ throw new Error(`${label} must use HTTP or HTTPS.`);
371
+ }
372
+ return url.toString();
373
+ }
374
+ catch (error) {
375
+ if (error instanceof Error && error.message.includes("must use HTTP or HTTPS")) {
376
+ throw error;
377
+ }
378
+ throw new Error(`${label} must be a valid HTTP(S) URL.`);
379
+ }
380
+ }
366
381
  function hasHelpFlag(args) {
367
382
  return args.some((arg) => arg === "--help" || arg === "-h");
368
383
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tapi-dev/sdk",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",