@tapi-dev/sdk 0.1.36 → 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 +33 -34
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +149 -227
- package/dist/client.d.ts +1 -1
- package/dist/client.js +10 -3
- package/dist/types.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -52,9 +52,10 @@ The current artifact and current release are kept.
|
|
|
52
52
|
|
|
53
53
|
Useful commands:
|
|
54
54
|
|
|
55
|
-
```bash
|
|
56
|
-
tapi
|
|
57
|
-
tapi
|
|
55
|
+
```bash
|
|
56
|
+
tapi login
|
|
57
|
+
tapi init --project brokerage
|
|
58
|
+
tapi link --project brokerage
|
|
58
59
|
tapi studio
|
|
59
60
|
tapi service install --channel pilot
|
|
60
61
|
tapi service status
|
|
@@ -80,8 +81,8 @@ ServiceMaps and service-run contracts are saved in the bound Tapi server
|
|
|
80
81
|
project. Runtime SDK calls read the service catalog from that project.
|
|
81
82
|
|
|
82
83
|
```bash
|
|
83
|
-
|
|
84
|
-
|
|
84
|
+
tapi tapp create brokerage --name "Brokerage"
|
|
85
|
+
tapi tapp service add brokerage schwab.place_order \
|
|
85
86
|
--service-map sm_123 \
|
|
86
87
|
--entry place_order
|
|
87
88
|
```
|
|
@@ -102,23 +103,23 @@ page that can create or accept a queue id, attach that queue to the Tapp, and
|
|
|
102
103
|
assign one or more slots on the runner:
|
|
103
104
|
|
|
104
105
|
```bash
|
|
105
|
-
|
|
106
|
+
tapi runner setup \
|
|
106
107
|
--runner-id john-laptop \
|
|
107
108
|
--project brokerage
|
|
108
109
|
```
|
|
109
110
|
|
|
110
111
|
## Quick Start
|
|
111
112
|
|
|
112
|
-
Create one TAPI client in server-side app code. Use a
|
|
113
|
-
|
|
114
|
-
`.tapi/project.json`.
|
|
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`.
|
|
115
116
|
|
|
116
117
|
```ts
|
|
117
118
|
import { TapiClient } from "@tapi-dev/sdk";
|
|
118
119
|
|
|
119
120
|
export const tapi = new TapiClient({
|
|
120
121
|
baseUrl: process.env.TAPI_BASE_URL!,
|
|
121
|
-
|
|
122
|
+
authToken: process.env.TAPI_FIREBASE_ID_TOKEN!,
|
|
122
123
|
tappId: process.env.TAPI_TAPP_ID!,
|
|
123
124
|
projectId: process.env.TAPI_PROJECT_ID!,
|
|
124
125
|
});
|
|
@@ -130,7 +131,7 @@ holding a browser open:
|
|
|
130
131
|
```ts
|
|
131
132
|
const tapi = new TapiClient({
|
|
132
133
|
baseUrl: process.env.TAPI_BASE_URL!,
|
|
133
|
-
|
|
134
|
+
authToken: process.env.TAPI_FIREBASE_ID_TOKEN!,
|
|
134
135
|
tappId: process.env.TAPI_TAPP_ID!,
|
|
135
136
|
projectId: process.env.TAPI_PROJECT_ID!,
|
|
136
137
|
dev: false,
|
|
@@ -144,7 +145,7 @@ production failure:
|
|
|
144
145
|
```ts
|
|
145
146
|
const tapi = new TapiClient({
|
|
146
147
|
baseUrl: process.env.TAPI_BASE_URL!,
|
|
147
|
-
|
|
148
|
+
authToken: process.env.TAPI_FIREBASE_ID_TOKEN!,
|
|
148
149
|
tappId: process.env.TAPI_TAPP_ID!,
|
|
149
150
|
projectId: process.env.TAPI_PROJECT_ID!,
|
|
150
151
|
dev: true,
|
|
@@ -269,8 +270,8 @@ export default {
|
|
|
269
270
|
};
|
|
270
271
|
```
|
|
271
272
|
|
|
272
|
-
```bash
|
|
273
|
-
|
|
273
|
+
```bash
|
|
274
|
+
tapi triggers sync
|
|
274
275
|
```
|
|
275
276
|
|
|
276
277
|
`triggers sync` upserts by trigger name for the current `.tapi/project.json`
|
|
@@ -295,14 +296,13 @@ await tapi.triggers.disable("act_123");
|
|
|
295
296
|
You can inspect the same input/output contract from the CLI:
|
|
296
297
|
|
|
297
298
|
```bash
|
|
298
|
-
tapi services describe schwab.place_order \
|
|
299
|
-
--api-base-url "$TAPI_BASE_URL" \
|
|
300
|
-
--
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
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.
|
|
306
306
|
|
|
307
307
|
## Runtime Profiles and Proxies
|
|
308
308
|
|
|
@@ -370,7 +370,7 @@ If your JavaScript runtime does not provide `WebSocket`, pass one:
|
|
|
370
370
|
```ts
|
|
371
371
|
const tapi = new TapiClient({
|
|
372
372
|
baseUrl: process.env.TAPI_BASE_URL!,
|
|
373
|
-
|
|
373
|
+
authToken: process.env.TAPI_FIREBASE_ID_TOKEN!,
|
|
374
374
|
tappId: process.env.TAPI_TAPP_ID!,
|
|
375
375
|
webSocket: MyWebSocketImplementation,
|
|
376
376
|
});
|
|
@@ -378,17 +378,16 @@ const tapi = new TapiClient({
|
|
|
378
378
|
|
|
379
379
|
## Configuration
|
|
380
380
|
|
|
381
|
-
```env
|
|
381
|
+
```env
|
|
382
382
|
TAPI_BASE_URL=https://your-tapi-api-host
|
|
383
|
-
|
|
383
|
+
TAPI_FIREBASE_ID_TOKEN=firebase_id_token_for_the_tapp_owner
|
|
384
384
|
TAPI_TAPP_ID=brokerage
|
|
385
385
|
TAPI_PROJECT_ID=brokerage
|
|
386
386
|
```
|
|
387
387
|
|
|
388
388
|
`tappId` is required. Service calls are made for that Tapp, and the developer
|
|
389
|
-
who owns the Tapp pays for the service delivery. `projectId` is
|
|
390
|
-
|
|
391
|
-
`X-Tapi-Project` header and the server rejects mismatches.
|
|
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.
|
|
392
391
|
|
|
393
392
|
## Common Project Setup
|
|
394
393
|
|
|
@@ -406,7 +405,7 @@ import { TapiClient } from "@tapi-dev/sdk";
|
|
|
406
405
|
|
|
407
406
|
export const tapi = new TapiClient({
|
|
408
407
|
baseUrl: process.env.TAPI_BASE_URL!,
|
|
409
|
-
|
|
408
|
+
authToken: process.env.TAPI_FIREBASE_ID_TOKEN!,
|
|
410
409
|
tappId: process.env.TAPI_TAPP_ID!,
|
|
411
410
|
projectId: process.env.TAPI_PROJECT_ID!,
|
|
412
411
|
});
|
|
@@ -446,10 +445,10 @@ Cloud runs are requested from the SDK, but VM provisioning, service
|
|
|
446
445
|
installation, worker leases, browser internals, and AWS cleanup stay on the
|
|
447
446
|
Tapi server. The SDK is only the front door.
|
|
448
447
|
|
|
449
|
-
Keep this code server-side. Do not put
|
|
450
|
-
do not wire AWS or Stripe from the developer's app. The app
|
|
451
|
-
identity to Tapi, and Tapi handles prepaid Stripe checkout,
|
|
452
|
-
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.
|
|
453
452
|
|
|
454
453
|
The minimum developer flow is:
|
|
455
454
|
|
|
@@ -523,7 +522,7 @@ low, `runCloudBatch` converts the server's HTTP `402` into a normal
|
|
|
523
522
|
`availableBalanceCents`, and `requiredBalanceCents`. That keeps the button
|
|
524
523
|
handler simple.
|
|
525
524
|
|
|
526
|
-
Credits are scoped under the
|
|
525
|
+
Credits are scoped under the authenticated Firebase owner, Tapp id, and
|
|
527
526
|
`user.externalUserId`. Use the same `externalUserId` for quote, balance,
|
|
528
527
|
checkout, and run calls. If you omit `externalUserId` but provide `email`, Tapi
|
|
529
528
|
uses the normalized email as the external user id.
|
package/dist/cli.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -117,6 +117,50 @@ async function withCliSpinner(message, work) {
|
|
|
117
117
|
throw error;
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
|
+
async function withSdkAuth(options) {
|
|
121
|
+
if (options.authToken?.trim()) {
|
|
122
|
+
return { ...options, authToken: options.authToken.trim() };
|
|
123
|
+
}
|
|
124
|
+
const envAuthToken = envString("TAPI_FIREBASE_ID_TOKEN");
|
|
125
|
+
if (envAuthToken) {
|
|
126
|
+
return { ...options, authToken: envAuthToken };
|
|
127
|
+
}
|
|
128
|
+
const credentials = await requireSdkFirebaseCredentials();
|
|
129
|
+
return { ...options, authToken: credentials.idToken };
|
|
130
|
+
}
|
|
131
|
+
async function requireSdkFirebaseCredentials() {
|
|
132
|
+
const credentials = await refreshCachedFirebaseCredentials();
|
|
133
|
+
if (!credentials) {
|
|
134
|
+
throw new Error(`Tapi sign-in is required. Run \`tapi login\`, then retry.`);
|
|
135
|
+
}
|
|
136
|
+
await writeStudioAuthCache(credentials);
|
|
137
|
+
return credentials;
|
|
138
|
+
}
|
|
139
|
+
async function runLogin() {
|
|
140
|
+
try {
|
|
141
|
+
const credentials = await withCliSpinner("Signing in to Tapi", () => authenticateSdkUser());
|
|
142
|
+
console.log(`Signed in to Tapi as ${credentials.uid}.`);
|
|
143
|
+
return 0;
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
console.error(formatError(error));
|
|
147
|
+
return 1;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async function authenticateSdkUser() {
|
|
151
|
+
const cached = await refreshCachedFirebaseCredentials();
|
|
152
|
+
if (cached) {
|
|
153
|
+
await writeStudioAuthCache(cached);
|
|
154
|
+
return cached;
|
|
155
|
+
}
|
|
156
|
+
const browserAuth = await browserGoogleSignIn();
|
|
157
|
+
if (!browserAuth.idToken) {
|
|
158
|
+
throw new Error(browserAuth.error || browserAuth.detail || "Browser sign-in did not return a Google ID token.");
|
|
159
|
+
}
|
|
160
|
+
const credentials = await exchangeGoogleToFirebase(browserAuth.idToken, browserAuth.accessToken);
|
|
161
|
+
await writeStudioAuthCache(credentials);
|
|
162
|
+
return credentials;
|
|
163
|
+
}
|
|
120
164
|
export async function runCli(argv = process.argv.slice(2)) {
|
|
121
165
|
const [command, subcommand, ...rest] = argv;
|
|
122
166
|
if (!command || command === "help" || command === "--help" || command === "-h") {
|
|
@@ -127,6 +171,18 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
127
171
|
console.log(sdkVersion);
|
|
128
172
|
return 0;
|
|
129
173
|
}
|
|
174
|
+
if (command === "login") {
|
|
175
|
+
if (hasHelpFlag([subcommand, ...rest])) {
|
|
176
|
+
printLoginHelp();
|
|
177
|
+
return 0;
|
|
178
|
+
}
|
|
179
|
+
if (subcommand) {
|
|
180
|
+
console.error(`Unexpected login argument: ${subcommand}`);
|
|
181
|
+
printLoginHelp();
|
|
182
|
+
return 1;
|
|
183
|
+
}
|
|
184
|
+
return runLogin();
|
|
185
|
+
}
|
|
130
186
|
if (command === "doctor") {
|
|
131
187
|
if (hasHelpFlag([subcommand, ...rest])) {
|
|
132
188
|
printStudioHelp();
|
|
@@ -430,7 +486,6 @@ function parseServiceOptions(args) {
|
|
|
430
486
|
let operation = "";
|
|
431
487
|
const workspace = loadWorkspace();
|
|
432
488
|
let apiBaseUrl = envString("TAPI_BASE_URL") || workspace?.apiBaseUrl || DEFAULT_STUDIO_API_BASE_URL;
|
|
433
|
-
let apiKey = envString("TAPI_API_KEY") || "";
|
|
434
489
|
let projectId = envString("TAPI_PROJECT_ID") || workspace?.projectId || "";
|
|
435
490
|
for (let index = 0; index < args.length; index += 1) {
|
|
436
491
|
const arg = args[index];
|
|
@@ -448,14 +503,6 @@ function parseServiceOptions(args) {
|
|
|
448
503
|
apiBaseUrl = arg.slice("--server=".length);
|
|
449
504
|
continue;
|
|
450
505
|
}
|
|
451
|
-
if (arg === "--api-key") {
|
|
452
|
-
apiKey = requireOptionValue(args, ++index, "--api-key");
|
|
453
|
-
continue;
|
|
454
|
-
}
|
|
455
|
-
if (arg.startsWith("--api-key=")) {
|
|
456
|
-
apiKey = arg.slice("--api-key=".length);
|
|
457
|
-
continue;
|
|
458
|
-
}
|
|
459
506
|
if (arg === "--project") {
|
|
460
507
|
projectId = normalizeProjectValue(requireOptionValue(args, ++index, "--project"), "project");
|
|
461
508
|
continue;
|
|
@@ -476,9 +523,6 @@ function parseServiceOptions(args) {
|
|
|
476
523
|
if (!operation) {
|
|
477
524
|
throw new Error("services describe requires a service run like schwab.place_order.");
|
|
478
525
|
}
|
|
479
|
-
if (!apiKey) {
|
|
480
|
-
throw new Error("services describe requires --api-key or TAPI_API_KEY.");
|
|
481
|
-
}
|
|
482
526
|
if (!projectId) {
|
|
483
527
|
throw new Error("services describe requires --project, TAPI_PROJECT_ID, or .tapi/project.json.");
|
|
484
528
|
}
|
|
@@ -486,7 +530,6 @@ function parseServiceOptions(args) {
|
|
|
486
530
|
operation,
|
|
487
531
|
options: {
|
|
488
532
|
apiBaseUrl: normalizeHttpUrl(apiBaseUrl, "Tapi API base URL"),
|
|
489
|
-
apiKey,
|
|
490
533
|
projectId,
|
|
491
534
|
},
|
|
492
535
|
};
|
|
@@ -494,11 +537,12 @@ function parseServiceOptions(args) {
|
|
|
494
537
|
async function describeServiceOperation(args) {
|
|
495
538
|
try {
|
|
496
539
|
const { operation, options } = parseServiceOptions(args);
|
|
540
|
+
const authenticated = await withSdkAuth(options);
|
|
497
541
|
const client = new TapiClient({
|
|
498
|
-
baseUrl:
|
|
499
|
-
|
|
500
|
-
tappId:
|
|
501
|
-
projectId:
|
|
542
|
+
baseUrl: authenticated.apiBaseUrl,
|
|
543
|
+
authToken: authenticated.authToken,
|
|
544
|
+
tappId: authenticated.projectId,
|
|
545
|
+
projectId: authenticated.projectId,
|
|
502
546
|
});
|
|
503
547
|
const description = await withCliSpinner(`Fetching Tapi service-run contract for ${operation}`, () => client.services.describe(operation));
|
|
504
548
|
console.log(JSON.stringify(description, null, 2));
|
|
@@ -512,7 +556,6 @@ async function describeServiceOperation(args) {
|
|
|
512
556
|
function parseApiWorkspaceOptions(args) {
|
|
513
557
|
const workspace = loadWorkspace();
|
|
514
558
|
let apiBaseUrl = envString("TAPI_BASE_URL") || workspace?.apiBaseUrl || DEFAULT_STUDIO_API_BASE_URL;
|
|
515
|
-
let apiKey = envString("TAPI_API_KEY") || "";
|
|
516
559
|
let projectId = envString("TAPI_PROJECT_ID") || workspace?.projectId || "";
|
|
517
560
|
let catalogPath = workspace?.config.services?.catalog || ".tapi/services/catalog.json";
|
|
518
561
|
for (let index = 0; index < args.length; index += 1) {
|
|
@@ -531,14 +574,6 @@ function parseApiWorkspaceOptions(args) {
|
|
|
531
574
|
apiBaseUrl = arg.slice("--server=".length);
|
|
532
575
|
continue;
|
|
533
576
|
}
|
|
534
|
-
if (arg === "--api-key") {
|
|
535
|
-
apiKey = requireOptionValue(args, ++index, "--api-key");
|
|
536
|
-
continue;
|
|
537
|
-
}
|
|
538
|
-
if (arg.startsWith("--api-key=")) {
|
|
539
|
-
apiKey = arg.slice("--api-key=".length);
|
|
540
|
-
continue;
|
|
541
|
-
}
|
|
542
577
|
if (arg === "--project") {
|
|
543
578
|
projectId = normalizeProjectValue(requireOptionValue(args, ++index, "--project"), "project");
|
|
544
579
|
continue;
|
|
@@ -557,23 +592,19 @@ function parseApiWorkspaceOptions(args) {
|
|
|
557
592
|
}
|
|
558
593
|
throw new Error(`Unknown services option: ${arg}`);
|
|
559
594
|
}
|
|
560
|
-
if (!apiKey) {
|
|
561
|
-
throw new Error("services command requires --api-key or TAPI_API_KEY.");
|
|
562
|
-
}
|
|
563
595
|
if (!projectId) {
|
|
564
596
|
throw new Error("services command requires --project, TAPI_PROJECT_ID, or .tapi/project.json.");
|
|
565
597
|
}
|
|
566
598
|
const root = workspace?.root || process.cwd();
|
|
567
599
|
return {
|
|
568
600
|
apiBaseUrl: normalizeHttpUrl(apiBaseUrl, "Tapi API base URL"),
|
|
569
|
-
apiKey,
|
|
570
601
|
projectId,
|
|
571
602
|
catalogPath: resolve(root, catalogPath),
|
|
572
603
|
};
|
|
573
604
|
}
|
|
574
605
|
async function syncServiceCatalog(args) {
|
|
575
606
|
try {
|
|
576
|
-
const options = parseApiWorkspaceOptions(args);
|
|
607
|
+
const options = await withSdkAuth(parseApiWorkspaceOptions(args));
|
|
577
608
|
const catalog = await withCliSpinner("Fetching Tapi service-run catalog", () => fetchApiCatalog(options));
|
|
578
609
|
await writeJsonFile(options.catalogPath, catalog);
|
|
579
610
|
console.log(`Synced Tapi service-run catalog: ${options.catalogPath}`);
|
|
@@ -587,7 +618,6 @@ async function syncServiceCatalog(args) {
|
|
|
587
618
|
function parseTappServiceAddOptions(args) {
|
|
588
619
|
const workspace = loadWorkspace();
|
|
589
620
|
let apiBaseUrl = envString("TAPI_BASE_URL") || workspace?.apiBaseUrl || DEFAULT_STUDIO_API_BASE_URL;
|
|
590
|
-
let apiKey = envString("TAPI_API_KEY") || "";
|
|
591
621
|
let tappId = "";
|
|
592
622
|
let serviceCall = "";
|
|
593
623
|
let serviceMapId = "";
|
|
@@ -609,14 +639,6 @@ function parseTappServiceAddOptions(args) {
|
|
|
609
639
|
apiBaseUrl = arg.slice("--server=".length);
|
|
610
640
|
continue;
|
|
611
641
|
}
|
|
612
|
-
if (arg === "--api-key") {
|
|
613
|
-
apiKey = requireOptionValue(args, ++index, "--api-key");
|
|
614
|
-
continue;
|
|
615
|
-
}
|
|
616
|
-
if (arg.startsWith("--api-key=")) {
|
|
617
|
-
apiKey = arg.slice("--api-key=".length);
|
|
618
|
-
continue;
|
|
619
|
-
}
|
|
620
642
|
if (arg === "--service-map") {
|
|
621
643
|
serviceMapId = requireOptionValue(args, ++index, "--service-map");
|
|
622
644
|
continue;
|
|
@@ -654,9 +676,6 @@ function parseTappServiceAddOptions(args) {
|
|
|
654
676
|
}
|
|
655
677
|
throw new Error(`Unexpected tapp service add argument: ${arg}`);
|
|
656
678
|
}
|
|
657
|
-
if (!apiKey) {
|
|
658
|
-
throw new Error("tapp service add requires --api-key or TAPI_API_KEY.");
|
|
659
|
-
}
|
|
660
679
|
if (!tappId) {
|
|
661
680
|
throw new Error("tapp service add requires a Tapp id.");
|
|
662
681
|
}
|
|
@@ -671,7 +690,6 @@ function parseTappServiceAddOptions(args) {
|
|
|
671
690
|
}
|
|
672
691
|
return {
|
|
673
692
|
apiBaseUrl: normalizeHttpUrl(apiBaseUrl, "Tapi API base URL"),
|
|
674
|
-
apiKey,
|
|
675
693
|
tappId,
|
|
676
694
|
serviceCall,
|
|
677
695
|
serviceMapId,
|
|
@@ -682,7 +700,6 @@ function parseTappServiceAddOptions(args) {
|
|
|
682
700
|
function parseTappCreateOptions(args) {
|
|
683
701
|
const workspace = loadWorkspace();
|
|
684
702
|
let apiBaseUrl = envString("TAPI_BASE_URL") || workspace?.apiBaseUrl || DEFAULT_STUDIO_API_BASE_URL;
|
|
685
|
-
let apiKey = envString("TAPI_API_KEY") || "";
|
|
686
703
|
let tappId = envString("TAPI_PROJECT_ID") || workspace?.projectId || "";
|
|
687
704
|
let name = "";
|
|
688
705
|
for (let index = 0; index < args.length; index += 1) {
|
|
@@ -701,14 +718,6 @@ function parseTappCreateOptions(args) {
|
|
|
701
718
|
apiBaseUrl = arg.slice("--server=".length);
|
|
702
719
|
continue;
|
|
703
720
|
}
|
|
704
|
-
if (arg === "--api-key") {
|
|
705
|
-
apiKey = requireOptionValue(args, ++index, "--api-key");
|
|
706
|
-
continue;
|
|
707
|
-
}
|
|
708
|
-
if (arg.startsWith("--api-key=")) {
|
|
709
|
-
apiKey = arg.slice("--api-key=".length);
|
|
710
|
-
continue;
|
|
711
|
-
}
|
|
712
721
|
if (arg === "--tapp-id" || arg === "--project") {
|
|
713
722
|
tappId = normalizeProjectValue(requireOptionValue(args, ++index, arg), "tapp");
|
|
714
723
|
continue;
|
|
@@ -741,9 +750,6 @@ function parseTappCreateOptions(args) {
|
|
|
741
750
|
}
|
|
742
751
|
throw new Error(`Unexpected tapp create argument: ${arg}`);
|
|
743
752
|
}
|
|
744
|
-
if (!apiKey) {
|
|
745
|
-
throw new Error("tapp create requires --api-key or TAPI_API_KEY.");
|
|
746
|
-
}
|
|
747
753
|
if (!tappId) {
|
|
748
754
|
throw new Error("tapp create requires a Tapp id or name.");
|
|
749
755
|
}
|
|
@@ -752,14 +758,13 @@ function parseTappCreateOptions(args) {
|
|
|
752
758
|
}
|
|
753
759
|
return {
|
|
754
760
|
apiBaseUrl: normalizeHttpUrl(apiBaseUrl, "Tapi API base URL"),
|
|
755
|
-
apiKey,
|
|
756
761
|
tappId,
|
|
757
762
|
name,
|
|
758
763
|
};
|
|
759
764
|
}
|
|
760
765
|
async function createTapp(args) {
|
|
761
766
|
try {
|
|
762
|
-
const options = parseTappCreateOptions(args);
|
|
767
|
+
const options = await withSdkAuth(parseTappCreateOptions(args));
|
|
763
768
|
const tapp = await withCliSpinner(`Creating Tapi Tapp ${options.tappId}`, () => postTappCreate(options));
|
|
764
769
|
console.log(JSON.stringify(tapp, null, 2));
|
|
765
770
|
return 0;
|
|
@@ -772,11 +777,7 @@ async function createTapp(args) {
|
|
|
772
777
|
async function postTappCreate(options, fetchImpl = fetch) {
|
|
773
778
|
const response = await fetchImpl(`${options.apiBaseUrl.replace(/\/+$/, "")}/api/sdk/v1/tapps`, {
|
|
774
779
|
method: "POST",
|
|
775
|
-
headers:
|
|
776
|
-
"Content-Type": "application/json",
|
|
777
|
-
"X-API-Key": options.apiKey,
|
|
778
|
-
"X-Tapi-Project": options.tappId,
|
|
779
|
-
},
|
|
780
|
+
headers: sdkJsonHeaders(options.authToken, options.tappId),
|
|
780
781
|
body: JSON.stringify({
|
|
781
782
|
tappId: options.tappId,
|
|
782
783
|
name: options.name,
|
|
@@ -791,7 +792,7 @@ async function postTappCreate(options, fetchImpl = fetch) {
|
|
|
791
792
|
}
|
|
792
793
|
async function addTappService(args) {
|
|
793
794
|
try {
|
|
794
|
-
const options = parseTappServiceAddOptions(args);
|
|
795
|
+
const options = await withSdkAuth(parseTappServiceAddOptions(args));
|
|
795
796
|
const operation = await withCliSpinner(`Adding Tapi service ${options.serviceCall} to ${options.tappId}`, () => postTappServiceAdd(options));
|
|
796
797
|
console.log(JSON.stringify(operation, null, 2));
|
|
797
798
|
return 0;
|
|
@@ -804,11 +805,7 @@ async function addTappService(args) {
|
|
|
804
805
|
async function postTappServiceAdd(options) {
|
|
805
806
|
const response = await fetch(`${options.apiBaseUrl.replace(/\/+$/, "")}/api/sdk/v1/tapps/${encodeURIComponent(options.tappId)}/services/${encodeURIComponent(options.serviceCall)}`, {
|
|
806
807
|
method: "POST",
|
|
807
|
-
headers:
|
|
808
|
-
"Content-Type": "application/json",
|
|
809
|
-
"X-API-Key": options.apiKey,
|
|
810
|
-
"X-Tapi-Project": options.tappId,
|
|
811
|
-
},
|
|
808
|
+
headers: sdkJsonHeaders(options.authToken, options.tappId),
|
|
812
809
|
body: JSON.stringify({
|
|
813
810
|
serviceMapId: options.serviceMapId,
|
|
814
811
|
entry: options.entry,
|
|
@@ -825,7 +822,6 @@ async function postTappServiceAdd(options) {
|
|
|
825
822
|
function parseQueueCreateOptions(args) {
|
|
826
823
|
const workspace = loadWorkspace();
|
|
827
824
|
let apiBaseUrl = envString("TAPI_BASE_URL") || workspace?.apiBaseUrl || DEFAULT_STUDIO_API_BASE_URL;
|
|
828
|
-
let apiKey = envString("TAPI_API_KEY") || "";
|
|
829
825
|
let projectId = envString("TAPI_PROJECT_ID") || workspace?.projectId || "";
|
|
830
826
|
let displayName = "";
|
|
831
827
|
let maxSlots = 8;
|
|
@@ -845,14 +841,6 @@ function parseQueueCreateOptions(args) {
|
|
|
845
841
|
apiBaseUrl = arg.slice("--server=".length);
|
|
846
842
|
continue;
|
|
847
843
|
}
|
|
848
|
-
if (arg === "--api-key") {
|
|
849
|
-
apiKey = requireOptionValue(args, ++index, "--api-key");
|
|
850
|
-
continue;
|
|
851
|
-
}
|
|
852
|
-
if (arg.startsWith("--api-key=")) {
|
|
853
|
-
apiKey = arg.slice("--api-key=".length);
|
|
854
|
-
continue;
|
|
855
|
-
}
|
|
856
844
|
if (arg === "--project") {
|
|
857
845
|
projectId = normalizeProjectValue(requireOptionValue(args, ++index, "--project"), "project");
|
|
858
846
|
continue;
|
|
@@ -878,12 +866,8 @@ function parseQueueCreateOptions(args) {
|
|
|
878
866
|
}
|
|
879
867
|
throw new Error(`Unexpected queue create argument: ${arg}`);
|
|
880
868
|
}
|
|
881
|
-
if (!apiKey) {
|
|
882
|
-
throw new Error("queue create requires --api-key or TAPI_API_KEY.");
|
|
883
|
-
}
|
|
884
869
|
return {
|
|
885
870
|
apiBaseUrl: normalizeHttpUrl(apiBaseUrl, "Tapi API base URL"),
|
|
886
|
-
apiKey,
|
|
887
871
|
projectId,
|
|
888
872
|
displayName,
|
|
889
873
|
maxSlots,
|
|
@@ -892,7 +876,6 @@ function parseQueueCreateOptions(args) {
|
|
|
892
876
|
function parseTappQueueAddOptions(args) {
|
|
893
877
|
const workspace = loadWorkspace();
|
|
894
878
|
let apiBaseUrl = envString("TAPI_BASE_URL") || workspace?.apiBaseUrl || DEFAULT_STUDIO_API_BASE_URL;
|
|
895
|
-
let apiKey = envString("TAPI_API_KEY") || "";
|
|
896
879
|
let tappId = "";
|
|
897
880
|
let queueId = "";
|
|
898
881
|
for (let index = 0; index < args.length; index += 1) {
|
|
@@ -911,14 +894,6 @@ function parseTappQueueAddOptions(args) {
|
|
|
911
894
|
apiBaseUrl = arg.slice("--server=".length);
|
|
912
895
|
continue;
|
|
913
896
|
}
|
|
914
|
-
if (arg === "--api-key") {
|
|
915
|
-
apiKey = requireOptionValue(args, ++index, "--api-key");
|
|
916
|
-
continue;
|
|
917
|
-
}
|
|
918
|
-
if (arg.startsWith("--api-key=")) {
|
|
919
|
-
apiKey = arg.slice("--api-key=".length);
|
|
920
|
-
continue;
|
|
921
|
-
}
|
|
922
897
|
if (arg.startsWith("--")) {
|
|
923
898
|
throw new Error(`Unknown tapp queue add option: ${arg}`);
|
|
924
899
|
}
|
|
@@ -932,9 +907,6 @@ function parseTappQueueAddOptions(args) {
|
|
|
932
907
|
}
|
|
933
908
|
throw new Error(`Unexpected tapp queue add argument: ${arg}`);
|
|
934
909
|
}
|
|
935
|
-
if (!apiKey) {
|
|
936
|
-
throw new Error("tapp queue add requires --api-key or TAPI_API_KEY.");
|
|
937
|
-
}
|
|
938
910
|
if (!tappId) {
|
|
939
911
|
throw new Error("tapp queue add requires a Tapp id.");
|
|
940
912
|
}
|
|
@@ -943,7 +915,6 @@ function parseTappQueueAddOptions(args) {
|
|
|
943
915
|
}
|
|
944
916
|
return {
|
|
945
917
|
apiBaseUrl: normalizeHttpUrl(apiBaseUrl, "Tapi API base URL"),
|
|
946
|
-
apiKey,
|
|
947
918
|
tappId,
|
|
948
919
|
queueId,
|
|
949
920
|
};
|
|
@@ -951,7 +922,6 @@ function parseTappQueueAddOptions(args) {
|
|
|
951
922
|
function parseRunnerSlotSetOptions(args) {
|
|
952
923
|
const workspace = loadWorkspace();
|
|
953
924
|
let apiBaseUrl = envString("TAPI_BASE_URL") || workspace?.apiBaseUrl || DEFAULT_STUDIO_API_BASE_URL;
|
|
954
|
-
let apiKey = envString("TAPI_API_KEY") || "";
|
|
955
925
|
let projectId = envString("TAPI_PROJECT_ID") || workspace?.projectId || "";
|
|
956
926
|
let runnerId = "";
|
|
957
927
|
let slotIndex = 0;
|
|
@@ -972,14 +942,6 @@ function parseRunnerSlotSetOptions(args) {
|
|
|
972
942
|
apiBaseUrl = arg.slice("--server=".length);
|
|
973
943
|
continue;
|
|
974
944
|
}
|
|
975
|
-
if (arg === "--api-key") {
|
|
976
|
-
apiKey = requireOptionValue(args, ++index, "--api-key");
|
|
977
|
-
continue;
|
|
978
|
-
}
|
|
979
|
-
if (arg.startsWith("--api-key=")) {
|
|
980
|
-
apiKey = arg.slice("--api-key=".length);
|
|
981
|
-
continue;
|
|
982
|
-
}
|
|
983
945
|
if (arg === "--project") {
|
|
984
946
|
projectId = normalizeProjectValue(requireOptionValue(args, ++index, "--project"), "project");
|
|
985
947
|
continue;
|
|
@@ -1005,9 +967,6 @@ function parseRunnerSlotSetOptions(args) {
|
|
|
1005
967
|
}
|
|
1006
968
|
throw new Error(`Unexpected runner slot set argument: ${arg}`);
|
|
1007
969
|
}
|
|
1008
|
-
if (!apiKey) {
|
|
1009
|
-
throw new Error("runner slot set requires --api-key or TAPI_API_KEY.");
|
|
1010
|
-
}
|
|
1011
970
|
if (!projectId) {
|
|
1012
971
|
throw new Error("runner slot set requires --project or TAPI_PROJECT_ID.");
|
|
1013
972
|
}
|
|
@@ -1022,7 +981,6 @@ function parseRunnerSlotSetOptions(args) {
|
|
|
1022
981
|
}
|
|
1023
982
|
return {
|
|
1024
983
|
apiBaseUrl: normalizeHttpUrl(apiBaseUrl, "Tapi API base URL"),
|
|
1025
|
-
apiKey,
|
|
1026
984
|
projectId,
|
|
1027
985
|
runnerId,
|
|
1028
986
|
slotIndex,
|
|
@@ -1031,7 +989,7 @@ function parseRunnerSlotSetOptions(args) {
|
|
|
1031
989
|
}
|
|
1032
990
|
async function createQueue(args) {
|
|
1033
991
|
try {
|
|
1034
|
-
const options = parseQueueCreateOptions(args);
|
|
992
|
+
const options = await withSdkAuth(parseQueueCreateOptions(args));
|
|
1035
993
|
const queue = await withCliSpinner(`Creating Tapi queue`, () => postQueueCreate(options));
|
|
1036
994
|
console.log(JSON.stringify(queue, null, 2));
|
|
1037
995
|
return 0;
|
|
@@ -1043,7 +1001,7 @@ async function createQueue(args) {
|
|
|
1043
1001
|
}
|
|
1044
1002
|
async function addTappQueue(args) {
|
|
1045
1003
|
try {
|
|
1046
|
-
const options = parseTappQueueAddOptions(args);
|
|
1004
|
+
const options = await withSdkAuth(parseTappQueueAddOptions(args));
|
|
1047
1005
|
const result = await withCliSpinner(`Attaching Tapi queue ${options.queueId} to ${options.tappId}`, () => postTappQueueAdd(options));
|
|
1048
1006
|
console.log(JSON.stringify(result, null, 2));
|
|
1049
1007
|
return 0;
|
|
@@ -1055,7 +1013,7 @@ async function addTappQueue(args) {
|
|
|
1055
1013
|
}
|
|
1056
1014
|
async function setRunnerSlot(args) {
|
|
1057
1015
|
try {
|
|
1058
|
-
const options = parseRunnerSlotSetOptions(args);
|
|
1016
|
+
const options = await withSdkAuth(parseRunnerSlotSetOptions(args));
|
|
1059
1017
|
const result = await withCliSpinner(`Assigning runner slot ${options.runnerId}/${options.slotIndex} to queue ${options.queueId}`, () => putRunnerSlot(options));
|
|
1060
1018
|
console.log(JSON.stringify(result, null, 2));
|
|
1061
1019
|
return 0;
|
|
@@ -1066,13 +1024,7 @@ async function setRunnerSlot(args) {
|
|
|
1066
1024
|
}
|
|
1067
1025
|
}
|
|
1068
1026
|
async function postQueueCreate(options) {
|
|
1069
|
-
const headers =
|
|
1070
|
-
"Content-Type": "application/json",
|
|
1071
|
-
"X-API-Key": options.apiKey,
|
|
1072
|
-
};
|
|
1073
|
-
if (options.projectId) {
|
|
1074
|
-
headers["X-Tapi-Project"] = options.projectId;
|
|
1075
|
-
}
|
|
1027
|
+
const headers = sdkJsonHeaders(options.authToken, options.projectId);
|
|
1076
1028
|
const response = await fetch(`${options.apiBaseUrl.replace(/\/+$/, "")}/api/sdk/v1/queues`, {
|
|
1077
1029
|
method: "POST",
|
|
1078
1030
|
headers,
|
|
@@ -1091,11 +1043,7 @@ async function postQueueCreate(options) {
|
|
|
1091
1043
|
async function postTappQueueAdd(options) {
|
|
1092
1044
|
const response = await fetch(`${options.apiBaseUrl.replace(/\/+$/, "")}/api/sdk/v1/tapps/${encodeURIComponent(options.tappId)}/queues`, {
|
|
1093
1045
|
method: "POST",
|
|
1094
|
-
headers:
|
|
1095
|
-
"Content-Type": "application/json",
|
|
1096
|
-
"X-API-Key": options.apiKey,
|
|
1097
|
-
"X-Tapi-Project": options.tappId,
|
|
1098
|
-
},
|
|
1046
|
+
headers: sdkJsonHeaders(options.authToken, options.tappId),
|
|
1099
1047
|
body: JSON.stringify({ queueId: options.queueId }),
|
|
1100
1048
|
});
|
|
1101
1049
|
const body = await readJsonBody(response);
|
|
@@ -1108,11 +1056,7 @@ async function postTappQueueAdd(options) {
|
|
|
1108
1056
|
async function putRunnerSlot(options) {
|
|
1109
1057
|
const response = await fetch(`${options.apiBaseUrl.replace(/\/+$/, "")}/api/sdk/v1/runners/${encodeURIComponent(options.runnerId)}/slots/${encodeURIComponent(String(options.slotIndex))}`, {
|
|
1110
1058
|
method: "PUT",
|
|
1111
|
-
headers:
|
|
1112
|
-
"Content-Type": "application/json",
|
|
1113
|
-
"X-API-Key": options.apiKey,
|
|
1114
|
-
"X-Tapi-Project": options.projectId,
|
|
1115
|
-
},
|
|
1059
|
+
headers: sdkJsonHeaders(options.authToken, options.projectId),
|
|
1116
1060
|
body: JSON.stringify({ queueId: options.queueId }),
|
|
1117
1061
|
});
|
|
1118
1062
|
const body = await readJsonBody(response);
|
|
@@ -1125,7 +1069,6 @@ async function putRunnerSlot(options) {
|
|
|
1125
1069
|
export function parseRunnerSetupOptions(args) {
|
|
1126
1070
|
const workspace = loadWorkspace();
|
|
1127
1071
|
let apiBaseUrl = envString("TAPI_BASE_URL") || workspace?.apiBaseUrl || DEFAULT_STUDIO_API_BASE_URL;
|
|
1128
|
-
let apiKey = envString("TAPI_API_KEY") || "";
|
|
1129
1072
|
let projectId = envString("TAPI_PROJECT_ID") || workspace?.projectId || "";
|
|
1130
1073
|
let runnerId = envString("TAPI_RUNNER_ID") || "";
|
|
1131
1074
|
let port = Number(envString("TAPI_RUNNER_SETUP_PORT") || "17687");
|
|
@@ -1146,14 +1089,6 @@ export function parseRunnerSetupOptions(args) {
|
|
|
1146
1089
|
apiBaseUrl = arg.slice("--server=".length);
|
|
1147
1090
|
continue;
|
|
1148
1091
|
}
|
|
1149
|
-
if (arg === "--api-key") {
|
|
1150
|
-
apiKey = requireOptionValue(args, ++index, "--api-key");
|
|
1151
|
-
continue;
|
|
1152
|
-
}
|
|
1153
|
-
if (arg.startsWith("--api-key=")) {
|
|
1154
|
-
apiKey = arg.slice("--api-key=".length);
|
|
1155
|
-
continue;
|
|
1156
|
-
}
|
|
1157
1092
|
if (arg === "--project") {
|
|
1158
1093
|
projectId = normalizeProjectValue(requireOptionValue(args, ++index, "--project"), "project");
|
|
1159
1094
|
continue;
|
|
@@ -1191,9 +1126,6 @@ export function parseRunnerSetupOptions(args) {
|
|
|
1191
1126
|
}
|
|
1192
1127
|
throw new Error(`Unexpected runner setup argument: ${arg}`);
|
|
1193
1128
|
}
|
|
1194
|
-
if (!apiKey) {
|
|
1195
|
-
throw new Error("runner setup requires --api-key or TAPI_API_KEY.");
|
|
1196
|
-
}
|
|
1197
1129
|
if (!projectId) {
|
|
1198
1130
|
throw new Error("runner setup requires --project or TAPI_PROJECT_ID.");
|
|
1199
1131
|
}
|
|
@@ -1205,7 +1137,6 @@ export function parseRunnerSetupOptions(args) {
|
|
|
1205
1137
|
}
|
|
1206
1138
|
return {
|
|
1207
1139
|
apiBaseUrl: normalizeHttpUrl(apiBaseUrl, "Tapi API base URL"),
|
|
1208
|
-
apiKey,
|
|
1209
1140
|
projectId,
|
|
1210
1141
|
runnerId,
|
|
1211
1142
|
port,
|
|
@@ -1214,7 +1145,7 @@ export function parseRunnerSetupOptions(args) {
|
|
|
1214
1145
|
}
|
|
1215
1146
|
async function runRunnerSetup(args) {
|
|
1216
1147
|
try {
|
|
1217
|
-
const options = parseRunnerSetupOptions(args);
|
|
1148
|
+
const options = await withSdkAuth(parseRunnerSetupOptions(args));
|
|
1218
1149
|
const handle = await startRunnerSetupServer(options);
|
|
1219
1150
|
if (options.openBrowser) {
|
|
1220
1151
|
openUrlInBrowser(handle.url);
|
|
@@ -1252,7 +1183,7 @@ export async function executeRunnerSetupAction(options, action, fetchImpl = fetc
|
|
|
1252
1183
|
if (!queueId) {
|
|
1253
1184
|
queue = await sdkJsonRequest(fetchImpl, `${options.apiBaseUrl.replace(/\/+$/, "")}/api/sdk/v1/queues`, {
|
|
1254
1185
|
method: "POST",
|
|
1255
|
-
headers: sdkJsonHeaders(options.
|
|
1186
|
+
headers: sdkJsonHeaders(options.authToken, options.projectId),
|
|
1256
1187
|
body: JSON.stringify({
|
|
1257
1188
|
displayName: String(action.displayName || `${options.projectId} queue`).trim(),
|
|
1258
1189
|
maxSlots,
|
|
@@ -1265,7 +1196,7 @@ export async function executeRunnerSetupAction(options, action, fetchImpl = fetc
|
|
|
1265
1196
|
}
|
|
1266
1197
|
const attachment = await sdkJsonRequest(fetchImpl, `${options.apiBaseUrl.replace(/\/+$/, "")}/api/sdk/v1/tapps/${encodeURIComponent(options.projectId)}/queues`, {
|
|
1267
1198
|
method: "POST",
|
|
1268
|
-
headers: sdkJsonHeaders(options.
|
|
1199
|
+
headers: sdkJsonHeaders(options.authToken, options.projectId),
|
|
1269
1200
|
body: JSON.stringify({ queueId }),
|
|
1270
1201
|
});
|
|
1271
1202
|
const slots = [];
|
|
@@ -1273,7 +1204,7 @@ export async function executeRunnerSetupAction(options, action, fetchImpl = fetc
|
|
|
1273
1204
|
const slotIndex = slotStart + offset;
|
|
1274
1205
|
slots.push(await sdkJsonRequest(fetchImpl, `${options.apiBaseUrl.replace(/\/+$/, "")}/api/sdk/v1/runners/${encodeURIComponent(options.runnerId)}/slots/${encodeURIComponent(String(slotIndex))}`, {
|
|
1275
1206
|
method: "PUT",
|
|
1276
|
-
headers: sdkJsonHeaders(options.
|
|
1207
|
+
headers: sdkJsonHeaders(options.authToken, options.projectId),
|
|
1277
1208
|
body: JSON.stringify({ queueId }),
|
|
1278
1209
|
}));
|
|
1279
1210
|
}
|
|
@@ -1416,12 +1347,22 @@ async function sdkJsonRequest(fetchImpl, url, init) {
|
|
|
1416
1347
|
}
|
|
1417
1348
|
return body ?? {};
|
|
1418
1349
|
}
|
|
1419
|
-
function sdkJsonHeaders(
|
|
1420
|
-
|
|
1350
|
+
function sdkJsonHeaders(authToken, projectId) {
|
|
1351
|
+
const headers = {
|
|
1421
1352
|
"Content-Type": "application/json",
|
|
1422
|
-
|
|
1423
|
-
"X-Tapi-Project": projectId,
|
|
1353
|
+
Authorization: `Bearer ${requireSdkAuthToken(authToken)}`,
|
|
1424
1354
|
};
|
|
1355
|
+
if (projectId) {
|
|
1356
|
+
headers["X-Tapi-Project"] = projectId;
|
|
1357
|
+
}
|
|
1358
|
+
return headers;
|
|
1359
|
+
}
|
|
1360
|
+
function requireSdkAuthToken(authToken) {
|
|
1361
|
+
const normalized = String(authToken || "").trim();
|
|
1362
|
+
if (!normalized) {
|
|
1363
|
+
throw new Error("Tapi sign-in is required. Run `tapi login`, then retry.");
|
|
1364
|
+
}
|
|
1365
|
+
return normalized;
|
|
1425
1366
|
}
|
|
1426
1367
|
function coercePositiveInteger(value, fallback, label) {
|
|
1427
1368
|
const text = value === undefined || value === null || value === "" ? String(fallback) : String(value);
|
|
@@ -1444,7 +1385,6 @@ function parseNonNegativeInteger(value, label) {
|
|
|
1444
1385
|
function parseTriggerSyncOptions(args) {
|
|
1445
1386
|
const workspace = loadWorkspace();
|
|
1446
1387
|
let apiBaseUrl = envString("TAPI_BASE_URL") || workspace?.apiBaseUrl || DEFAULT_STUDIO_API_BASE_URL;
|
|
1447
|
-
let apiKey = envString("TAPI_API_KEY") || "";
|
|
1448
1388
|
let projectId = envString("TAPI_PROJECT_ID") || workspace?.projectId || "";
|
|
1449
1389
|
let configPath = "";
|
|
1450
1390
|
const root = workspace?.root || process.cwd();
|
|
@@ -1464,14 +1404,6 @@ function parseTriggerSyncOptions(args) {
|
|
|
1464
1404
|
apiBaseUrl = arg.slice("--server=".length);
|
|
1465
1405
|
continue;
|
|
1466
1406
|
}
|
|
1467
|
-
if (arg === "--api-key") {
|
|
1468
|
-
apiKey = requireOptionValue(args, ++index, "--api-key");
|
|
1469
|
-
continue;
|
|
1470
|
-
}
|
|
1471
|
-
if (arg.startsWith("--api-key=")) {
|
|
1472
|
-
apiKey = arg.slice("--api-key=".length);
|
|
1473
|
-
continue;
|
|
1474
|
-
}
|
|
1475
1407
|
if (arg === "--project") {
|
|
1476
1408
|
projectId = normalizeProjectValue(requireOptionValue(args, ++index, "--project"), "project");
|
|
1477
1409
|
continue;
|
|
@@ -1490,29 +1422,25 @@ function parseTriggerSyncOptions(args) {
|
|
|
1490
1422
|
}
|
|
1491
1423
|
throw new Error(`Unknown triggers option: ${arg}`);
|
|
1492
1424
|
}
|
|
1493
|
-
if (!apiKey) {
|
|
1494
|
-
throw new Error("triggers sync requires --api-key or TAPI_API_KEY.");
|
|
1495
|
-
}
|
|
1496
1425
|
if (!projectId) {
|
|
1497
1426
|
throw new Error("triggers sync requires --project, TAPI_PROJECT_ID, or .tapi/project.json.");
|
|
1498
1427
|
}
|
|
1499
1428
|
return {
|
|
1500
1429
|
apiBaseUrl: normalizeHttpUrl(apiBaseUrl, "Tapi API base URL"),
|
|
1501
|
-
apiKey,
|
|
1502
1430
|
projectId,
|
|
1503
1431
|
configPath: configPath ? resolve(root, configPath) : defaultTriggerConfigPath(root),
|
|
1504
1432
|
};
|
|
1505
1433
|
}
|
|
1506
1434
|
async function syncServiceTriggers(args) {
|
|
1507
1435
|
try {
|
|
1508
|
-
const options = parseTriggerSyncOptions(args);
|
|
1436
|
+
const options = await withSdkAuth(parseTriggerSyncOptions(args));
|
|
1509
1437
|
const triggers = await readServiceTriggerConfig(options.configPath);
|
|
1510
1438
|
if (triggers.length === 0) {
|
|
1511
1439
|
throw new Error(`No Tapi service triggers found in ${options.configPath}.`);
|
|
1512
1440
|
}
|
|
1513
1441
|
const client = new TapiClient({
|
|
1514
1442
|
baseUrl: options.apiBaseUrl,
|
|
1515
|
-
|
|
1443
|
+
authToken: options.authToken,
|
|
1516
1444
|
tappId: options.projectId,
|
|
1517
1445
|
projectId: options.projectId,
|
|
1518
1446
|
});
|
|
@@ -1532,7 +1460,6 @@ async function syncServiceTriggers(args) {
|
|
|
1532
1460
|
function parseSessionsOptions(args) {
|
|
1533
1461
|
const workspace = loadWorkspace();
|
|
1534
1462
|
let apiBaseUrl = envString("TAPI_BASE_URL") || workspace?.apiBaseUrl || DEFAULT_STUDIO_API_BASE_URL;
|
|
1535
|
-
let apiKey = envString("TAPI_API_KEY") || "";
|
|
1536
1463
|
let projectId = envString("TAPI_PROJECT_ID") || workspace?.projectId || "";
|
|
1537
1464
|
let site = "";
|
|
1538
1465
|
let sessionId = "";
|
|
@@ -1554,14 +1481,6 @@ function parseSessionsOptions(args) {
|
|
|
1554
1481
|
apiBaseUrl = arg.slice("--server=".length);
|
|
1555
1482
|
continue;
|
|
1556
1483
|
}
|
|
1557
|
-
if (arg === "--api-key") {
|
|
1558
|
-
apiKey = requireOptionValue(args, ++index, "--api-key");
|
|
1559
|
-
continue;
|
|
1560
|
-
}
|
|
1561
|
-
if (arg.startsWith("--api-key=")) {
|
|
1562
|
-
apiKey = arg.slice("--api-key=".length);
|
|
1563
|
-
continue;
|
|
1564
|
-
}
|
|
1565
1484
|
if (arg === "--project") {
|
|
1566
1485
|
projectId = normalizeProjectValue(requireOptionValue(args, ++index, "--project"), "project");
|
|
1567
1486
|
continue;
|
|
@@ -1596,9 +1515,6 @@ function parseSessionsOptions(args) {
|
|
|
1596
1515
|
}
|
|
1597
1516
|
throw new Error(`Unexpected sessions argument: ${arg}`);
|
|
1598
1517
|
}
|
|
1599
|
-
if (!apiKey) {
|
|
1600
|
-
throw new Error("sessions command requires --api-key or TAPI_API_KEY.");
|
|
1601
|
-
}
|
|
1602
1518
|
if (!projectId) {
|
|
1603
1519
|
throw new Error("sessions command requires --project, TAPI_PROJECT_ID, or .tapi/project.json.");
|
|
1604
1520
|
}
|
|
@@ -1606,7 +1522,6 @@ function parseSessionsOptions(args) {
|
|
|
1606
1522
|
sessionId,
|
|
1607
1523
|
options: {
|
|
1608
1524
|
apiBaseUrl: normalizeHttpUrl(apiBaseUrl, "Tapi API base URL"),
|
|
1609
|
-
apiKey,
|
|
1610
1525
|
projectId,
|
|
1611
1526
|
site: site || undefined,
|
|
1612
1527
|
json,
|
|
@@ -1617,18 +1532,19 @@ function parseSessionsOptions(args) {
|
|
|
1617
1532
|
async function listDevSessions(args) {
|
|
1618
1533
|
try {
|
|
1619
1534
|
const { options } = parseSessionsOptions(args);
|
|
1620
|
-
const
|
|
1621
|
-
|
|
1535
|
+
const authenticated = await withSdkAuth(options);
|
|
1536
|
+
const sessions = await fetchDevSessions(authenticated);
|
|
1537
|
+
if (authenticated.json) {
|
|
1622
1538
|
console.log(JSON.stringify(sessions, null, 2));
|
|
1623
1539
|
return 0;
|
|
1624
1540
|
}
|
|
1625
1541
|
const rows = flattenDevSessions(sessions);
|
|
1626
1542
|
if (rows.length === 0) {
|
|
1627
|
-
console.log(`No Tapi dev sessions found for project ${sessions.projectId ||
|
|
1543
|
+
console.log(`No Tapi dev sessions found for project ${sessions.projectId || authenticated.projectId}.`);
|
|
1628
1544
|
return 0;
|
|
1629
1545
|
}
|
|
1630
|
-
if (!
|
|
1631
|
-
return await runSessionsPicker(sessions,
|
|
1546
|
+
if (!authenticated.noInteractive && process.stdin.isTTY && process.stdout.isTTY && rows.some((session) => session.openable)) {
|
|
1547
|
+
return await runSessionsPicker(sessions, authenticated);
|
|
1632
1548
|
}
|
|
1633
1549
|
console.log(renderDevSessions(sessions));
|
|
1634
1550
|
const openable = rows.find((session) => session.openable);
|
|
@@ -1645,15 +1561,16 @@ async function listDevSessions(args) {
|
|
|
1645
1561
|
async function openDevSession(args) {
|
|
1646
1562
|
try {
|
|
1647
1563
|
const { sessionId, options } = parseSessionsOptions(args);
|
|
1564
|
+
const authenticated = await withSdkAuth(options);
|
|
1648
1565
|
if (!sessionId) {
|
|
1649
1566
|
throw new Error("sessions open requires a session id.");
|
|
1650
1567
|
}
|
|
1651
|
-
const sessions = await fetchDevSessions(
|
|
1568
|
+
const sessions = await fetchDevSessions(authenticated);
|
|
1652
1569
|
const session = findDevSession(sessions, sessionId);
|
|
1653
1570
|
if (!session) {
|
|
1654
1571
|
throw new Error(`Tapi session not found: ${sessionId}`);
|
|
1655
1572
|
}
|
|
1656
|
-
return await openDevSessionInStudio(session,
|
|
1573
|
+
return await openDevSessionInStudio(session, authenticated);
|
|
1657
1574
|
}
|
|
1658
1575
|
catch (error) {
|
|
1659
1576
|
console.error(formatError(error));
|
|
@@ -1663,7 +1580,7 @@ async function openDevSession(args) {
|
|
|
1663
1580
|
async function fetchDevSessions(options) {
|
|
1664
1581
|
const client = new TapiClient({
|
|
1665
1582
|
baseUrl: options.apiBaseUrl,
|
|
1666
|
-
|
|
1583
|
+
authToken: options.authToken,
|
|
1667
1584
|
tappId: options.projectId,
|
|
1668
1585
|
projectId: options.projectId,
|
|
1669
1586
|
});
|
|
@@ -2103,7 +2020,7 @@ function rejectNonPolicyTriggerRuntimeOwner(runtime, fieldName) {
|
|
|
2103
2020
|
async function fetchApiCatalog(options) {
|
|
2104
2021
|
const client = new TapiClient({
|
|
2105
2022
|
baseUrl: options.apiBaseUrl,
|
|
2106
|
-
|
|
2023
|
+
authToken: options.authToken,
|
|
2107
2024
|
tappId: options.projectId,
|
|
2108
2025
|
projectId: options.projectId,
|
|
2109
2026
|
});
|
|
@@ -4508,8 +4425,9 @@ function readSdkVersion() {
|
|
|
4508
4425
|
function printHelp() {
|
|
4509
4426
|
console.log(`Tapi CLI
|
|
4510
4427
|
|
|
4511
|
-
Usage:
|
|
4512
|
-
tapi
|
|
4428
|
+
Usage:
|
|
4429
|
+
tapi login
|
|
4430
|
+
tapi init --project PROJECT
|
|
4513
4431
|
tapi link --project PROJECT
|
|
4514
4432
|
tapi studio install [--channel pilot] [--api-base-url URL]
|
|
4515
4433
|
tapi studio
|
|
@@ -4528,8 +4446,9 @@ Usage:
|
|
|
4528
4446
|
tapi service status
|
|
4529
4447
|
tapi doctor
|
|
4530
4448
|
|
|
4531
|
-
Commands:
|
|
4532
|
-
|
|
4449
|
+
Commands:
|
|
4450
|
+
login Sign in with Firebase credentials for SDK commands
|
|
4451
|
+
init Create .tapi/project.json for this repo
|
|
4533
4452
|
link Rebind this repo to an existing Tapi project
|
|
4534
4453
|
studio install Download, verify, and run the Tapi Studio installer
|
|
4535
4454
|
studio Open Tapi Studio for this repo
|
|
@@ -4551,18 +4470,26 @@ Commands:
|
|
|
4551
4470
|
doctor Alias for studio doctor
|
|
4552
4471
|
`);
|
|
4553
4472
|
}
|
|
4473
|
+
function printLoginHelp() {
|
|
4474
|
+
console.log(`Tapi login
|
|
4475
|
+
|
|
4476
|
+
Usage:
|
|
4477
|
+
tapi login
|
|
4478
|
+
|
|
4479
|
+
Signs in with the browser and caches Firebase credentials for SDK commands.
|
|
4480
|
+
`);
|
|
4481
|
+
}
|
|
4554
4482
|
function printTappHelp() {
|
|
4555
4483
|
console.log(`Tapi Tapp commands
|
|
4556
4484
|
|
|
4557
4485
|
Usage:
|
|
4558
|
-
tapi tapp create <tapp> [--name NAME] [--api-base-url URL]
|
|
4559
|
-
tapi tapp service add <tapp> <service.call> --service-map ID --entry ENTRY [--api-base-url URL]
|
|
4560
|
-
tapi tapp queue add <tapp> <queue-id> [--api-base-url URL]
|
|
4486
|
+
tapi tapp create <tapp> [--name NAME] [--api-base-url URL]
|
|
4487
|
+
tapi tapp service add <tapp> <service.call> --service-map ID --entry ENTRY [--api-base-url URL]
|
|
4488
|
+
tapi tapp queue add <tapp> <queue-id> [--api-base-url URL]
|
|
4561
4489
|
|
|
4562
4490
|
Options:
|
|
4563
4491
|
--api-base-url <url> Tapi API base URL
|
|
4564
4492
|
--server <url> Alias for --api-base-url
|
|
4565
|
-
--api-key <key> Tapi API key; defaults to TAPI_API_KEY
|
|
4566
4493
|
--tapp-id <id> Explicit Tapp id for tapp create
|
|
4567
4494
|
--name <name> Display name for tapp create
|
|
4568
4495
|
--service-map <id> Backing ServiceMap id
|
|
@@ -4574,12 +4501,11 @@ function printQueueHelp() {
|
|
|
4574
4501
|
console.log(`Tapi queue commands
|
|
4575
4502
|
|
|
4576
4503
|
Usage:
|
|
4577
|
-
tapi queue create [display-name] [--max-slots N] [--project TAPP] [--api-base-url URL]
|
|
4504
|
+
tapi queue create [display-name] [--max-slots N] [--project TAPP] [--api-base-url URL]
|
|
4578
4505
|
|
|
4579
4506
|
Options:
|
|
4580
4507
|
--api-base-url <url> Tapi API base URL
|
|
4581
4508
|
--server <url> Alias for --api-base-url
|
|
4582
|
-
--api-key <key> Tapi API key; defaults to TAPI_API_KEY
|
|
4583
4509
|
--project <id> Optional project scope for the queue request
|
|
4584
4510
|
--max-slots <n> Maximum runner slots this queue may use
|
|
4585
4511
|
`);
|
|
@@ -4588,13 +4514,12 @@ function printRunnerHelp() {
|
|
|
4588
4514
|
console.log(`Tapi runner commands
|
|
4589
4515
|
|
|
4590
4516
|
Usage:
|
|
4591
|
-
tapi runner setup --runner-id RUNNER --project TAPP [--port PORT] [--no-open] [--api-base-url URL]
|
|
4592
|
-
tapi runner slot set <runner-id> <slot-index> <queue-id> [--project TAPP] [--api-base-url URL]
|
|
4517
|
+
tapi runner setup --runner-id RUNNER --project TAPP [--port PORT] [--no-open] [--api-base-url URL]
|
|
4518
|
+
tapi runner slot set <runner-id> <slot-index> <queue-id> [--project TAPP] [--api-base-url URL]
|
|
4593
4519
|
|
|
4594
4520
|
Options:
|
|
4595
4521
|
--api-base-url <url> Tapi API base URL
|
|
4596
4522
|
--server <url> Alias for --api-base-url
|
|
4597
|
-
--api-key <key> Tapi API key; defaults to TAPI_API_KEY
|
|
4598
4523
|
--project <id> Tapi project id; defaults to TAPI_PROJECT_ID or .tapi/project.json
|
|
4599
4524
|
--runner-id <id> Runner id for setup; defaults to TAPI_RUNNER_ID
|
|
4600
4525
|
--port <n> Local setup UI port; defaults to 17687
|
|
@@ -4604,16 +4529,15 @@ Options:
|
|
|
4604
4529
|
function printSessionsHelp() {
|
|
4605
4530
|
console.log(`Tapi dev session commands
|
|
4606
4531
|
|
|
4607
|
-
Usage:
|
|
4608
|
-
tapi sessions [--api-base-url URL] [--
|
|
4609
|
-
tapi sessions list [--json] [--site SITE]
|
|
4610
|
-
tapi sessions open <session-id> [--api-base-url URL] [--
|
|
4611
|
-
|
|
4612
|
-
Options:
|
|
4613
|
-
--api-base-url <url> Tapi API base URL
|
|
4614
|
-
--server <url> Alias for --api-base-url
|
|
4615
|
-
--
|
|
4616
|
-
--project <id> Tapi project id; defaults to TAPI_PROJECT_ID or .tapi/project.json
|
|
4532
|
+
Usage:
|
|
4533
|
+
tapi sessions [--api-base-url URL] [--project PROJECT]
|
|
4534
|
+
tapi sessions list [--json] [--site SITE]
|
|
4535
|
+
tapi sessions open <session-id> [--api-base-url URL] [--project PROJECT]
|
|
4536
|
+
|
|
4537
|
+
Options:
|
|
4538
|
+
--api-base-url <url> Tapi API base URL
|
|
4539
|
+
--server <url> Alias for --api-base-url
|
|
4540
|
+
--project <id> Tapi project id; defaults to TAPI_PROJECT_ID or .tapi/project.json
|
|
4617
4541
|
--site <name> Limit sessions to one sitemap/site
|
|
4618
4542
|
--json Print raw grouped session JSON
|
|
4619
4543
|
--no-interactive Print the grouped list without the arrow-key picker
|
|
@@ -4622,30 +4546,28 @@ Options:
|
|
|
4622
4546
|
function printServicesHelp() {
|
|
4623
4547
|
console.log(`Tapi ServiceMap service-run commands
|
|
4624
4548
|
|
|
4625
|
-
Usage:
|
|
4626
|
-
tapi services describe <servicemap.run> [--api-base-url URL] [--
|
|
4627
|
-
tapi services sync [--api-base-url URL] [--
|
|
4628
|
-
|
|
4629
|
-
Options:
|
|
4630
|
-
--api-base-url <url> Tapi API base URL
|
|
4631
|
-
--server <url> Alias for --api-base-url
|
|
4632
|
-
--
|
|
4633
|
-
--project <id> Tapi project id; defaults to TAPI_PROJECT_ID or .tapi/project.json
|
|
4549
|
+
Usage:
|
|
4550
|
+
tapi services describe <servicemap.run> [--api-base-url URL] [--project PROJECT]
|
|
4551
|
+
tapi services sync [--api-base-url URL] [--project PROJECT]
|
|
4552
|
+
|
|
4553
|
+
Options:
|
|
4554
|
+
--api-base-url <url> Tapi API base URL
|
|
4555
|
+
--server <url> Alias for --api-base-url
|
|
4556
|
+
--project <id> Tapi project id; defaults to TAPI_PROJECT_ID or .tapi/project.json
|
|
4634
4557
|
--catalog <path> Catalog JSON output path
|
|
4635
4558
|
`);
|
|
4636
4559
|
}
|
|
4637
4560
|
function printTriggersHelp() {
|
|
4638
4561
|
console.log(`Tapi service trigger commands
|
|
4639
4562
|
|
|
4640
|
-
Usage:
|
|
4641
|
-
tapi triggers sync [--config FILE] [--api-base-url URL] [--
|
|
4642
|
-
|
|
4643
|
-
Options:
|
|
4644
|
-
--config <path> Trigger config path; defaults to tapi.config.ts/js/json in the workspace root
|
|
4645
|
-
--api-base-url <url> Tapi API base URL
|
|
4646
|
-
--server <url> Alias for --api-base-url
|
|
4647
|
-
--
|
|
4648
|
-
--project <id> Tapi project id; defaults to TAPI_PROJECT_ID or .tapi/project.json
|
|
4563
|
+
Usage:
|
|
4564
|
+
tapi triggers sync [--config FILE] [--api-base-url URL] [--project PROJECT]
|
|
4565
|
+
|
|
4566
|
+
Options:
|
|
4567
|
+
--config <path> Trigger config path; defaults to tapi.config.ts/js/json in the workspace root
|
|
4568
|
+
--api-base-url <url> Tapi API base URL
|
|
4569
|
+
--server <url> Alias for --api-base-url
|
|
4570
|
+
--project <id> Tapi project id; defaults to TAPI_PROJECT_ID or .tapi/project.json
|
|
4649
4571
|
|
|
4650
4572
|
Config:
|
|
4651
4573
|
export default {
|
package/dist/client.d.ts
CHANGED
package/dist/client.js
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import { TapiError } from "./errors.js";
|
|
2
2
|
export class HttpClient {
|
|
3
3
|
baseUrl;
|
|
4
|
-
|
|
4
|
+
authToken;
|
|
5
5
|
tappId;
|
|
6
6
|
projectId;
|
|
7
7
|
fetchImpl;
|
|
8
8
|
constructor(options) {
|
|
9
9
|
this.baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
10
|
-
this.
|
|
10
|
+
this.authToken = options.authToken.trim();
|
|
11
|
+
if (!this.authToken) {
|
|
12
|
+
throw new TapiError("authToken is required", {
|
|
13
|
+
status: 0,
|
|
14
|
+
code: "invalid_client_config",
|
|
15
|
+
details: { field: "authToken" },
|
|
16
|
+
});
|
|
17
|
+
}
|
|
11
18
|
this.tappId = options.tappId.trim();
|
|
12
19
|
if (!this.tappId) {
|
|
13
20
|
throw new TapiError("tappId is required", {
|
|
@@ -35,7 +42,7 @@ export class HttpClient {
|
|
|
35
42
|
const response = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
36
43
|
method,
|
|
37
44
|
headers: {
|
|
38
|
-
|
|
45
|
+
Authorization: `Bearer ${this.authToken}`,
|
|
39
46
|
"Content-Type": "application/json",
|
|
40
47
|
"X-Tapi-Tapp": this.tappId,
|
|
41
48
|
...(this.projectId ? { "X-Tapi-Project": this.projectId } : {}),
|
package/dist/types.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { LateInput } from "./late-input.js";
|
|
|
2
2
|
export type RunStatus = "queued" | "running" | "waiting_for_input" | "completed" | "failed" | "cancelled" | "needs_developer_attention";
|
|
3
3
|
export interface TapiClientOptions {
|
|
4
4
|
baseUrl: string;
|
|
5
|
-
|
|
5
|
+
authToken: string;
|
|
6
6
|
tappId: string;
|
|
7
7
|
projectId?: string;
|
|
8
8
|
dev?: boolean;
|