@tapi-dev/sdk 0.1.34 → 0.1.38
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 +176 -137
- package/dist/catalog.js +3 -2
- package/dist/cli.d.ts +30 -0
- package/dist/cli.js +1178 -237
- package/dist/client.d.ts +2 -1
- package/dist/client.js +20 -3
- package/dist/cloud-runs.js +5 -4
- package/dist/runs.js +7 -6
- package/dist/service-contract.d.ts +6 -0
- package/dist/service-contract.js +84 -0
- package/dist/services.d.ts +6 -5
- package/dist/services.js +119 -20
- package/dist/sessions.js +3 -2
- package/dist/triggers.d.ts +8 -8
- package/dist/triggers.js +54 -5
- package/dist/types.d.ts +56 -55
- package/dist/workspace.d.ts +0 -6
- package/dist/workspace.js +6 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -52,60 +52,90 @@ The current artifact and current release are kept.
|
|
|
52
52
|
|
|
53
53
|
Useful commands:
|
|
54
54
|
|
|
55
|
-
```bash
|
|
56
|
-
tapi
|
|
57
|
-
tapi
|
|
58
|
-
tapi
|
|
59
|
-
tapi
|
|
60
|
-
tapi service
|
|
61
|
-
tapi
|
|
62
|
-
tapi
|
|
63
|
-
tapi
|
|
55
|
+
```bash
|
|
56
|
+
tapi login
|
|
57
|
+
tapi init --project brokerage
|
|
58
|
+
tapi link --project brokerage
|
|
59
|
+
tapi studio
|
|
60
|
+
tapi service install --channel pilot
|
|
61
|
+
tapi service status
|
|
62
|
+
tapi services describe schwab.place_order
|
|
63
|
+
tapi tapp create brokerage
|
|
64
|
+
tapi queue create "John"
|
|
65
|
+
tapi tapp queue add brokerage queue_abc123
|
|
66
|
+
tapi runner setup --runner-id john-laptop --project brokerage
|
|
67
|
+
tapi runner slot set john-laptop 1 queue_abc123 --project brokerage
|
|
68
|
+
tapi tapp service add brokerage schwab.place_order --service-map sm_123 --entry place_order
|
|
69
|
+
tapi triggers sync
|
|
70
|
+
tapi sessions
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Local project identity lives in the app repo:
|
|
74
|
+
|
|
75
|
+
```text
|
|
76
|
+
.tapi/project.json
|
|
77
|
+
.tapi/services/catalog.json
|
|
64
78
|
```
|
|
65
79
|
|
|
66
|
-
|
|
80
|
+
ServiceMaps and service-run contracts are saved in the bound Tapi server
|
|
81
|
+
project. Runtime SDK calls read the service catalog from that project.
|
|
67
82
|
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
83
|
+
```bash
|
|
84
|
+
tapi tapp create brokerage --name "Brokerage"
|
|
85
|
+
tapi tapp service add brokerage schwab.place_order \
|
|
86
|
+
--service-map sm_123 \
|
|
87
|
+
--entry place_order
|
|
72
88
|
```
|
|
73
89
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
90
|
+
Create a queue, attach it to the Tapp, and point one or more runner slots at
|
|
91
|
+
that queue:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
tapi queue create "John" --project brokerage
|
|
95
|
+
tapi tapp queue add brokerage queue_abc123
|
|
96
|
+
|
|
97
|
+
tapi runner slot set john-laptop 1 queue_abc123 \
|
|
98
|
+
--project brokerage
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
For users setting up a local runner, `tapi runner setup` opens a localhost setup
|
|
102
|
+
page that can create or accept a queue id, attach that queue to the Tapp, and
|
|
103
|
+
assign one or more slots on the runner:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
tapi runner setup \
|
|
107
|
+
--runner-id john-laptop \
|
|
108
|
+
--project brokerage
|
|
109
|
+
```
|
|
83
110
|
|
|
84
111
|
## Quick Start
|
|
85
112
|
|
|
86
|
-
Create one TAPI client in server-side app code. Use a
|
|
87
|
-
the
|
|
113
|
+
Create one TAPI client in server-side app code. Use a Firebase ID token for the
|
|
114
|
+
developer identity that owns and pays for the Tapp, the Tapp id that owns the
|
|
115
|
+
service call, and optionally the same project id from `.tapi/project.json`.
|
|
88
116
|
|
|
89
117
|
```ts
|
|
90
118
|
import { TapiClient } from "@tapi-dev/sdk";
|
|
91
119
|
|
|
92
|
-
export const tapi = new TapiClient({
|
|
93
|
-
baseUrl: process.env.TAPI_BASE_URL!,
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
120
|
+
export const tapi = new TapiClient({
|
|
121
|
+
baseUrl: process.env.TAPI_BASE_URL!,
|
|
122
|
+
authToken: process.env.TAPI_FIREBASE_ID_TOKEN!,
|
|
123
|
+
tappId: process.env.TAPI_TAPP_ID!,
|
|
124
|
+
projectId: process.env.TAPI_PROJECT_ID!,
|
|
125
|
+
});
|
|
126
|
+
```
|
|
98
127
|
|
|
99
128
|
Production is the default mode. Unknown website states fail the run instead of
|
|
100
129
|
holding a browser open:
|
|
101
130
|
|
|
102
131
|
```ts
|
|
103
|
-
const tapi = new TapiClient({
|
|
104
|
-
baseUrl: process.env.TAPI_BASE_URL!,
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
132
|
+
const tapi = new TapiClient({
|
|
133
|
+
baseUrl: process.env.TAPI_BASE_URL!,
|
|
134
|
+
authToken: process.env.TAPI_FIREBASE_ID_TOKEN!,
|
|
135
|
+
tappId: process.env.TAPI_TAPP_ID!,
|
|
136
|
+
projectId: process.env.TAPI_PROJECT_ID!,
|
|
137
|
+
dev: false,
|
|
138
|
+
});
|
|
109
139
|
```
|
|
110
140
|
|
|
111
141
|
During development, set `dev: true`. If a website reaches an unknown state,
|
|
@@ -113,41 +143,46 @@ Tapi preserves the browser session for takeover instead of turning it into a
|
|
|
113
143
|
production failure:
|
|
114
144
|
|
|
115
145
|
```ts
|
|
116
|
-
const tapi = new TapiClient({
|
|
117
|
-
baseUrl: process.env.TAPI_BASE_URL!,
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
146
|
+
const tapi = new TapiClient({
|
|
147
|
+
baseUrl: process.env.TAPI_BASE_URL!,
|
|
148
|
+
authToken: process.env.TAPI_FIREBASE_ID_TOKEN!,
|
|
149
|
+
tappId: process.env.TAPI_TAPP_ID!,
|
|
150
|
+
projectId: process.env.TAPI_PROJECT_ID!,
|
|
151
|
+
dev: true,
|
|
152
|
+
});
|
|
122
153
|
```
|
|
123
154
|
|
|
124
155
|
Inspect preserved sessions from the repo:
|
|
125
156
|
|
|
126
157
|
```bash
|
|
127
158
|
tapi sessions
|
|
128
|
-
tapi sessions --json
|
|
129
|
-
tapi sessions open <session-id>
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
`tapi sessions open` reuses the matching Studio window for the current repo when
|
|
133
|
-
one is already running; otherwise it installs/starts Studio and opens directly
|
|
134
|
-
to that session.
|
|
135
|
-
|
|
136
|
-
Generated website APIs are authored visually in Tapi Studio by setting workflow
|
|
137
|
-
bounds, selecting inputs/outputs, and publishing an API. The SDK sees the public
|
|
138
|
-
operation name:
|
|
139
|
-
|
|
140
|
-
```text
|
|
141
|
-
<namespace>.<operation>
|
|
159
|
+
tapi sessions --json
|
|
160
|
+
tapi sessions open <session-id>
|
|
142
161
|
```
|
|
143
162
|
|
|
144
|
-
|
|
145
|
-
|
|
163
|
+
`tapi sessions open` reuses the matching Studio window for the current repo when
|
|
164
|
+
one is already running; otherwise it installs/starts Studio and opens directly
|
|
165
|
+
to that session.
|
|
146
166
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
167
|
+
Service runs are authored visually in Tapi Studio by setting ServiceMap bounds
|
|
168
|
+
and selecting inputs/outputs. The SDK sees the public service-run name:
|
|
169
|
+
|
|
170
|
+
```text
|
|
171
|
+
<namespace>.<operation>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
A service run is routed through a queue. The queue id is the only routing handle:
|
|
175
|
+
the Tapp must attach the queue, and one or more runner slots must be configured
|
|
176
|
+
with the same queue id.
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
const operation = await tapi.services.describe("schwab.place_order");
|
|
180
|
+
|
|
181
|
+
const run = await tapi.services.run("schwab.place_order", {
|
|
182
|
+
queueId: "queue_abc123",
|
|
183
|
+
inputs: {
|
|
184
|
+
symbol: "AAPL",
|
|
185
|
+
side: "buy",
|
|
151
186
|
quantity: 10,
|
|
152
187
|
orderType: "limit",
|
|
153
188
|
limitPrice: 190,
|
|
@@ -160,13 +195,13 @@ console.log(completedRun.status, completedRun.result);
|
|
|
160
195
|
|
|
161
196
|
## Late Inputs
|
|
162
197
|
|
|
163
|
-
Most
|
|
198
|
+
Most service inputs are known before the run starts. Use `lateInput()` when the
|
|
164
199
|
workflow needs a value later, after earlier browser steps have triggered work
|
|
165
200
|
somewhere else.
|
|
166
201
|
|
|
167
202
|
For example, state 4 might submit a login form and trigger a one-time code by
|
|
168
203
|
email or SMS. State 5 needs that code, but your app can only retrieve it after
|
|
169
|
-
state 4 runs. Declare the input up front with the
|
|
204
|
+
state 4 runs. Declare the input up front with the service run, then resolve it
|
|
170
205
|
from your own code:
|
|
171
206
|
|
|
172
207
|
```ts
|
|
@@ -179,7 +214,7 @@ const verificationCode = lateInput<string>({
|
|
|
179
214
|
timeoutMs: 180_000,
|
|
180
215
|
});
|
|
181
216
|
|
|
182
|
-
const run = await tapi.
|
|
217
|
+
const run = await tapi.services.run("walmart.login", {
|
|
183
218
|
inputs: {
|
|
184
219
|
email: "buyer@example.com",
|
|
185
220
|
password: process.env.WALMART_PASSWORD!,
|
|
@@ -198,7 +233,7 @@ worker, webhook, or polling loop finds the value:
|
|
|
198
233
|
```ts
|
|
199
234
|
const verificationCode = lateInput<string>({ timeoutMs: 180_000 });
|
|
200
235
|
|
|
201
|
-
const run = await tapi.
|
|
236
|
+
const run = await tapi.services.run("walmart.login", {
|
|
202
237
|
inputs: { email: "buyer@example.com", verificationCode },
|
|
203
238
|
});
|
|
204
239
|
|
|
@@ -214,19 +249,19 @@ not provided before `timeoutMs`, the run fails instead of guessing or using the
|
|
|
214
249
|
recorded default.
|
|
215
250
|
|
|
216
251
|
Late inputs are for values produced outside the website flow. Values read from
|
|
217
|
-
the website itself should stay as normal
|
|
252
|
+
the website itself should stay as normal service outputs.
|
|
218
253
|
|
|
219
|
-
##
|
|
254
|
+
## Service Triggers
|
|
220
255
|
|
|
221
|
-
Triggers are scheduled
|
|
222
|
-
|
|
256
|
+
Triggers are scheduled service runs. Keep trigger definitions in the app repo
|
|
257
|
+
and sync them with the service catalog from that repo:
|
|
223
258
|
|
|
224
259
|
```ts
|
|
225
260
|
// tapi.config.ts
|
|
226
261
|
export default {
|
|
227
262
|
triggers: {
|
|
228
263
|
nightlyBalance: {
|
|
229
|
-
|
|
264
|
+
serviceRun: "schwab.get_balance",
|
|
230
265
|
schedule: { cron: "0 9 * * MON-FRI" },
|
|
231
266
|
inputs: { accountId: "main" },
|
|
232
267
|
runtime: { profileRef: "perm_default" },
|
|
@@ -235,8 +270,8 @@ export default {
|
|
|
235
270
|
};
|
|
236
271
|
```
|
|
237
272
|
|
|
238
|
-
```bash
|
|
239
|
-
|
|
273
|
+
```bash
|
|
274
|
+
tapi triggers sync
|
|
240
275
|
```
|
|
241
276
|
|
|
242
277
|
`triggers sync` upserts by trigger name for the current `.tapi/project.json`
|
|
@@ -248,7 +283,7 @@ You can also manage triggers directly:
|
|
|
248
283
|
```ts
|
|
249
284
|
await tapi.triggers.create({
|
|
250
285
|
name: "nightlyBalance",
|
|
251
|
-
|
|
286
|
+
serviceRun: "schwab.get_balance",
|
|
252
287
|
schedule: { cron: "0 9 * * MON-FRI" },
|
|
253
288
|
inputs: { accountId: "main" },
|
|
254
289
|
runtime: { profileRef: "perm_default" },
|
|
@@ -261,19 +296,18 @@ await tapi.triggers.disable("act_123");
|
|
|
261
296
|
You can inspect the same input/output contract from the CLI:
|
|
262
297
|
|
|
263
298
|
```bash
|
|
264
|
-
tapi
|
|
265
|
-
--api-base-url "$TAPI_BASE_URL" \
|
|
266
|
-
--
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
own backend route, server action, or job worker when using secret API keys.
|
|
299
|
+
tapi services describe schwab.place_order \
|
|
300
|
+
--api-base-url "$TAPI_BASE_URL" \
|
|
301
|
+
--project "$TAPI_PROJECT_ID"
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Do not expose developer Firebase ID tokens in public browser bundles. Put the
|
|
305
|
+
SDK behind your own backend route, server action, or job worker.
|
|
272
306
|
|
|
273
307
|
## Runtime Profiles and Proxies
|
|
274
308
|
|
|
275
309
|
Browser identity is selected with a runner-local `profileRef`, not by passing
|
|
276
|
-
Chrome folder paths through the cloud
|
|
310
|
+
Chrome folder paths through the cloud service-run request.
|
|
277
311
|
|
|
278
312
|
Use `PermProfile` for a long-lived account identity. It owns a persistent
|
|
279
313
|
Chrome user-data directory and should usually use the runner's normal home IP:
|
|
@@ -284,13 +318,14 @@ const perm = await tapi.runtime.permProfiles.create({
|
|
|
284
318
|
originPolicy: { type: "home" },
|
|
285
319
|
});
|
|
286
320
|
|
|
287
|
-
await tapi.runtime.permProfiles.launchSetup(perm.profile.profileRef);
|
|
288
|
-
// The user logs in, adds passkeys, then closes setup Chrome.
|
|
289
|
-
|
|
290
|
-
await tapi.
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
}
|
|
321
|
+
await tapi.runtime.permProfiles.launchSetup(perm.profile.profileRef);
|
|
322
|
+
// The user logs in, adds passkeys, then closes setup Chrome.
|
|
323
|
+
|
|
324
|
+
await tapi.services.run("walmart.reorder", {
|
|
325
|
+
queueId: "queue_abc123",
|
|
326
|
+
inputs: { item: "paper towels" },
|
|
327
|
+
runtime: { profileRef: perm.profile.profileRef },
|
|
328
|
+
});
|
|
294
329
|
```
|
|
295
330
|
|
|
296
331
|
Use `TempProfile` for throwaway work. Temp profiles can be cloned from a
|
|
@@ -310,8 +345,9 @@ const temp = await tapi.runtime.tempProfiles.provisionMany({
|
|
|
310
345
|
|
|
311
346
|
await Promise.all(
|
|
312
347
|
temp.profiles.map((profile) =>
|
|
313
|
-
tapi.
|
|
314
|
-
|
|
348
|
+
tapi.services.run("walmart.lookupItem", {
|
|
349
|
+
queueId: "queue_abc123",
|
|
350
|
+
inputs: { sku: "123" },
|
|
315
351
|
runtime: {
|
|
316
352
|
profileRef: profile.profileRef,
|
|
317
353
|
destroyOnRelease: profile.destroyOnRelease,
|
|
@@ -321,7 +357,7 @@ await Promise.all(
|
|
|
321
357
|
);
|
|
322
358
|
```
|
|
323
359
|
|
|
324
|
-
`runtime.profileRef` is the only value sent to the TAPI cloud run
|
|
360
|
+
`runtime.profileRef` is the only value sent to the TAPI cloud run request. Proxy
|
|
325
361
|
URLs, proxy credentials, and Chrome profile folders stay on the local runner
|
|
326
362
|
and are handled through the local control WebSocket at `ws://127.0.0.1:8765`.
|
|
327
363
|
When the same `PermProfile` is used concurrently for multiple different sites,
|
|
@@ -332,24 +368,26 @@ the base `profileRef` and let the runner decide.
|
|
|
332
368
|
If your JavaScript runtime does not provide `WebSocket`, pass one:
|
|
333
369
|
|
|
334
370
|
```ts
|
|
335
|
-
const tapi = new TapiClient({
|
|
336
|
-
baseUrl: process.env.TAPI_BASE_URL!,
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
371
|
+
const tapi = new TapiClient({
|
|
372
|
+
baseUrl: process.env.TAPI_BASE_URL!,
|
|
373
|
+
authToken: process.env.TAPI_FIREBASE_ID_TOKEN!,
|
|
374
|
+
tappId: process.env.TAPI_TAPP_ID!,
|
|
375
|
+
webSocket: MyWebSocketImplementation,
|
|
376
|
+
});
|
|
377
|
+
```
|
|
341
378
|
|
|
342
379
|
## Configuration
|
|
343
380
|
|
|
344
|
-
```env
|
|
345
|
-
TAPI_BASE_URL=https://your-tapi-api-host
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
381
|
+
```env
|
|
382
|
+
TAPI_BASE_URL=https://your-tapi-api-host
|
|
383
|
+
TAPI_FIREBASE_ID_TOKEN=firebase_id_token_for_the_tapp_owner
|
|
384
|
+
TAPI_TAPP_ID=brokerage
|
|
385
|
+
TAPI_PROJECT_ID=brokerage
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
`tappId` is required. Service calls are made for that Tapp, and the developer
|
|
389
|
+
who owns the Tapp pays for the service delivery. If provided, `projectId` is
|
|
390
|
+
sent as the `X-Tapi-Project` header and the server rejects mismatches.
|
|
353
391
|
|
|
354
392
|
## Common Project Setup
|
|
355
393
|
|
|
@@ -365,11 +403,12 @@ src/
|
|
|
365
403
|
// src/lib/tapi.ts
|
|
366
404
|
import { TapiClient } from "@tapi-dev/sdk";
|
|
367
405
|
|
|
368
|
-
export const tapi = new TapiClient({
|
|
369
|
-
baseUrl: process.env.TAPI_BASE_URL!,
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
406
|
+
export const tapi = new TapiClient({
|
|
407
|
+
baseUrl: process.env.TAPI_BASE_URL!,
|
|
408
|
+
authToken: process.env.TAPI_FIREBASE_ID_TOKEN!,
|
|
409
|
+
tappId: process.env.TAPI_TAPP_ID!,
|
|
410
|
+
projectId: process.env.TAPI_PROJECT_ID!,
|
|
411
|
+
});
|
|
373
412
|
```
|
|
374
413
|
|
|
375
414
|
Application code should import this shared client instead of constructing a new client in every file.
|
|
@@ -384,15 +423,15 @@ await tapi.runtime.profiles.list();
|
|
|
384
423
|
await tapi.runtime.profiles.clone({ profileRef: "perm_default", site: "walmart" });
|
|
385
424
|
await tapi.runtime.permProfiles.create({ displayName: "Default", originPolicy: { type: "home" } });
|
|
386
425
|
await tapi.runtime.tempProfiles.provisionMany({ proxies: ["http://user:pass@host:8080"] });
|
|
387
|
-
await tapi.
|
|
426
|
+
await tapi.services.describe("schwab.place_order");
|
|
388
427
|
|
|
389
|
-
const run = await tapi.
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
idempotencyKey: "request-123",
|
|
395
|
-
});
|
|
428
|
+
const run = await tapi.services.run("serviceName.serviceKey", {
|
|
429
|
+
queueId: "queue_abc123",
|
|
430
|
+
inputs: { example: true },
|
|
431
|
+
runtime: { profileRef: "perm_default" },
|
|
432
|
+
priority: 5,
|
|
433
|
+
idempotencyKey: "request-123",
|
|
434
|
+
});
|
|
396
435
|
|
|
397
436
|
await tapi.runs.get(run.id);
|
|
398
437
|
await tapi.runs.wait(run.id, { intervalMs: 1000, timeoutMs: 300000 });
|
|
@@ -406,10 +445,10 @@ Cloud runs are requested from the SDK, but VM provisioning, service
|
|
|
406
445
|
installation, worker leases, browser internals, and AWS cleanup stay on the
|
|
407
446
|
Tapi server. The SDK is only the front door.
|
|
408
447
|
|
|
409
|
-
Keep this code server-side. Do not put
|
|
410
|
-
do not wire AWS or Stripe from the developer's app. The app
|
|
411
|
-
identity to Tapi, and Tapi handles prepaid Stripe checkout,
|
|
412
|
-
AWS worker provisioning, and cleanup.
|
|
448
|
+
Keep this code server-side. Do not put developer Firebase ID tokens in a
|
|
449
|
+
browser bundle and do not wire AWS or Stripe from the developer's app. The app
|
|
450
|
+
sends its own user identity to Tapi, and Tapi handles prepaid Stripe checkout,
|
|
451
|
+
credit accounting, AWS worker provisioning, and cleanup.
|
|
413
452
|
|
|
414
453
|
The minimum developer flow is:
|
|
415
454
|
|
|
@@ -423,7 +462,7 @@ The minimum developer flow is:
|
|
|
423
462
|
|
|
424
463
|
```ts
|
|
425
464
|
// backend route or server action
|
|
426
|
-
const quote = await tapi.
|
|
465
|
+
const quote = await tapi.services.quoteCloud("schwab.place_order", {
|
|
427
466
|
inputs: [
|
|
428
467
|
{ symbol: "AAPL", quantity: 1 },
|
|
429
468
|
{ symbol: "MSFT", quantity: 2 },
|
|
@@ -444,7 +483,7 @@ if (!quote.withinMaxCost) {
|
|
|
444
483
|
throw new Error("Cloud batch exceeds the configured cost cap");
|
|
445
484
|
}
|
|
446
485
|
|
|
447
|
-
const run = await tapi.
|
|
486
|
+
const run = await tapi.services.runCloudBatch("schwab.place_order", {
|
|
448
487
|
inputs: [
|
|
449
488
|
{ symbol: "AAPL", quantity: 1 },
|
|
450
489
|
{ symbol: "MSFT", quantity: 2 },
|
|
@@ -483,10 +522,10 @@ low, `runCloudBatch` converts the server's HTTP `402` into a normal
|
|
|
483
522
|
`availableBalanceCents`, and `requiredBalanceCents`. That keeps the button
|
|
484
523
|
handler simple.
|
|
485
524
|
|
|
486
|
-
Credits are scoped under the
|
|
487
|
-
`user.externalUserId`. Use the same `externalUserId` for quote, balance,
|
|
488
|
-
checkout, and run calls. If you omit `externalUserId` but provide `email`, Tapi
|
|
489
|
-
uses the normalized email as the external user id.
|
|
525
|
+
Credits are scoped under the authenticated Firebase owner, Tapp id, and
|
|
526
|
+
`user.externalUserId`. Use the same `externalUserId` for quote, balance,
|
|
527
|
+
checkout, and run calls. If you omit `externalUserId` but provide `email`, Tapi
|
|
528
|
+
uses the normalized email as the external user id.
|
|
490
529
|
|
|
491
530
|
Applications can also create a top-up checkout explicitly:
|
|
492
531
|
|
|
@@ -513,9 +552,9 @@ The developer application does not need VM provisioning logic, installer
|
|
|
513
552
|
deployment logic, worker command interpretation, browser runner internals, or
|
|
514
553
|
builder logic. Those stay behind the Tapi server API.
|
|
515
554
|
|
|
516
|
-
|
|
517
|
-
comes from the
|
|
518
|
-
developer types into the SDK name textbox at the
|
|
555
|
+
Service runs are addressed as `<serviceName>.<serviceKey>`. The service name
|
|
556
|
+
comes from the ServiceMap name in Studio. The service key is the name the
|
|
557
|
+
developer types into the SDK name textbox at the service boundary.
|
|
519
558
|
|
|
520
559
|
`describe()` returns the public SDK contract: input controls such as
|
|
521
560
|
`textbox`, `radio`, `select`, `checkbox`, conditional requirements such as
|
|
@@ -550,10 +589,10 @@ import type {
|
|
|
550
589
|
RuntimeProfile,
|
|
551
590
|
RuntimeRunOptions,
|
|
552
591
|
SdkCatalog,
|
|
592
|
+
ServiceOperation,
|
|
593
|
+
ServiceRunRequest,
|
|
553
594
|
TapiRun,
|
|
554
595
|
TapiRunner,
|
|
555
|
-
WebsiteApiOperation,
|
|
556
|
-
WebsiteApiRunRequest,
|
|
557
596
|
} from "@tapi-dev/sdk";
|
|
558
597
|
```
|
|
559
598
|
|
package/dist/catalog.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { normalizeSdkCatalog } from "./service-contract.js";
|
|
1
2
|
export class CatalogResource {
|
|
2
3
|
http;
|
|
3
4
|
constructor(http) {
|
|
4
5
|
this.http = http;
|
|
5
6
|
}
|
|
6
|
-
get() {
|
|
7
|
-
return this.http.get("/api/sdk/v1/catalog");
|
|
7
|
+
async get() {
|
|
8
|
+
return normalizeSdkCatalog(await this.http.get("/api/sdk/v1/catalog"));
|
|
8
9
|
}
|
|
9
10
|
}
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import type { TapiDevSession } from "./types.js";
|
|
3
3
|
import { type TapiWorkspace } from "./workspace.js";
|
|
4
|
+
export declare const PORTABLE_STUDIO_SERVER_READY_TIMEOUT_MS = 120000;
|
|
4
5
|
export type StudioChannel = "pilot" | "stable" | "nightly";
|
|
5
6
|
export interface StudioReleaseManifest {
|
|
6
7
|
product?: string;
|
|
@@ -68,6 +69,32 @@ export interface StudioCliOptions {
|
|
|
68
69
|
workspaceMode: boolean;
|
|
69
70
|
launchUrlQuery?: string;
|
|
70
71
|
}
|
|
72
|
+
export interface RunnerSetupCliOptions {
|
|
73
|
+
apiBaseUrl: string;
|
|
74
|
+
authToken?: string;
|
|
75
|
+
projectId: string;
|
|
76
|
+
runnerId: string;
|
|
77
|
+
port: number;
|
|
78
|
+
openBrowser: boolean;
|
|
79
|
+
}
|
|
80
|
+
export interface RunnerSetupAction {
|
|
81
|
+
queueId?: string;
|
|
82
|
+
displayName?: string;
|
|
83
|
+
maxSlots?: number;
|
|
84
|
+
slotStart?: number;
|
|
85
|
+
slotCount?: number;
|
|
86
|
+
}
|
|
87
|
+
export interface RunnerSetupActionResult {
|
|
88
|
+
queueId: string;
|
|
89
|
+
queue: Record<string, unknown>;
|
|
90
|
+
attachment: Record<string, unknown>;
|
|
91
|
+
slots: Record<string, unknown>[];
|
|
92
|
+
}
|
|
93
|
+
export interface RunnerSetupServerHandle {
|
|
94
|
+
url: string;
|
|
95
|
+
port: number;
|
|
96
|
+
close: () => Promise<void>;
|
|
97
|
+
}
|
|
71
98
|
export interface ServiceStatus {
|
|
72
99
|
installed: boolean;
|
|
73
100
|
name?: string;
|
|
@@ -80,6 +107,9 @@ type StudioPortAvailable = (port: number) => Promise<boolean>;
|
|
|
80
107
|
type StudioPortReaper = (preferred: number, count: number) => Promise<number>;
|
|
81
108
|
export declare function runCli(argv?: string[]): Promise<number>;
|
|
82
109
|
export declare function parseStudioOptions(args: string[]): StudioCliOptions;
|
|
110
|
+
export declare function parseRunnerSetupOptions(args: string[]): RunnerSetupCliOptions;
|
|
111
|
+
export declare function startRunnerSetupServer(options: RunnerSetupCliOptions, fetchImpl?: FetchLike): Promise<RunnerSetupServerHandle>;
|
|
112
|
+
export declare function executeRunnerSetupAction(options: RunnerSetupCliOptions, action: RunnerSetupAction, fetchImpl?: FetchLike): Promise<RunnerSetupActionResult>;
|
|
83
113
|
export declare function trySelectDevSessionInOpenStudio(session: TapiDevSession, options: StudioCliOptions, fetchImpl?: FetchLike): Promise<{
|
|
84
114
|
selected: boolean;
|
|
85
115
|
baseUrl?: string;
|