@bubblebridge/sdk 0.1.1 → 0.1.2

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 CHANGED
@@ -16,17 +16,14 @@ You need a client ID and a client secret. Register your agent at `https://bubble
16
16
 
17
17
  ## Send a user to the consent page
18
18
 
19
- Create a `state` value and a PKCE verifier. Store both for at most ten minutes. Then send the browser to the consent page.
19
+ Call `pkce` for a `state` value, a PKCE verifier, and its S256 challenge. Store the first two for at most ten minutes. Then send the browser to the consent page.
20
20
 
21
21
  ```ts
22
- import { createHash, randomBytes } from 'node:crypto';
23
- import { BubbleBridge } from '@bubblebridge/sdk';
22
+ import { BubbleBridge, pkce } from '@bubblebridge/sdk';
24
23
 
25
24
  const bb = new BubbleBridge({ clientId, clientSecret });
26
25
 
27
- const state = randomBytes(16).toString('base64url');
28
- const codeVerifier = randomBytes(32).toString('base64url');
29
- const codeChallenge = createHash('sha256').update(codeVerifier).digest('base64url');
26
+ const { state, codeVerifier, codeChallenge } = await pkce();
30
27
 
31
28
  const location = bb.oauth.authorizeUrl({
32
29
  scopes: ['google.gmail.readonly', 'google.calendar.events'],
@@ -0,0 +1 @@
1
+ export declare function base64Url(bytes: Uint8Array): string;
@@ -0,0 +1,6 @@
1
+ export function base64Url(bytes) {
2
+ let binary = '';
3
+ for (const byte of bytes)
4
+ binary += String.fromCharCode(byte);
5
+ return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
6
+ }
@@ -115,6 +115,54 @@ export interface paths {
115
115
  patch?: never;
116
116
  trace?: never;
117
117
  };
118
+ "/v1/admin/builder-requests": {
119
+ parameters: {
120
+ query?: never;
121
+ header?: never;
122
+ path?: never;
123
+ cookie?: never;
124
+ };
125
+ get: operations["list_requests"];
126
+ put?: never;
127
+ post?: never;
128
+ delete?: never;
129
+ options?: never;
130
+ head?: never;
131
+ patch?: never;
132
+ trace?: never;
133
+ };
134
+ "/v1/admin/builder-requests/{user_id}/accept": {
135
+ parameters: {
136
+ query?: never;
137
+ header?: never;
138
+ path?: never;
139
+ cookie?: never;
140
+ };
141
+ get?: never;
142
+ put?: never;
143
+ post: operations["accept"];
144
+ delete?: never;
145
+ options?: never;
146
+ head?: never;
147
+ patch?: never;
148
+ trace?: never;
149
+ };
150
+ "/v1/admin/builder-requests/{user_id}/reject": {
151
+ parameters: {
152
+ query?: never;
153
+ header?: never;
154
+ path?: never;
155
+ cookie?: never;
156
+ };
157
+ get?: never;
158
+ put?: never;
159
+ post: operations["reject"];
160
+ delete?: never;
161
+ options?: never;
162
+ head?: never;
163
+ patch?: never;
164
+ trace?: never;
165
+ };
118
166
  "/v1/agents": {
119
167
  parameters: {
120
168
  query?: never;
@@ -147,6 +195,22 @@ export interface paths {
147
195
  patch?: never;
148
196
  trace?: never;
149
197
  };
198
+ "/v1/billing": {
199
+ parameters: {
200
+ query?: never;
201
+ header?: never;
202
+ path?: never;
203
+ cookie?: never;
204
+ };
205
+ get: operations["status"];
206
+ put?: never;
207
+ post?: never;
208
+ delete?: never;
209
+ options?: never;
210
+ head?: never;
211
+ patch?: never;
212
+ trace?: never;
213
+ };
150
214
  "/v1/billing/checkout": {
151
215
  parameters: {
152
216
  query?: never;
@@ -179,6 +243,102 @@ export interface paths {
179
243
  patch?: never;
180
244
  trace?: never;
181
245
  };
246
+ "/v1/builder/agents": {
247
+ parameters: {
248
+ query?: never;
249
+ header?: never;
250
+ path?: never;
251
+ cookie?: never;
252
+ };
253
+ get: operations["list_builder_agents"];
254
+ put?: never;
255
+ post: operations["create_builder_agent"];
256
+ delete?: never;
257
+ options?: never;
258
+ head?: never;
259
+ patch?: never;
260
+ trace?: never;
261
+ };
262
+ "/v1/builder/agents/{agent_id}": {
263
+ parameters: {
264
+ query?: never;
265
+ header?: never;
266
+ path?: never;
267
+ cookie?: never;
268
+ };
269
+ get?: never;
270
+ put?: never;
271
+ post?: never;
272
+ delete?: never;
273
+ options?: never;
274
+ head?: never;
275
+ patch: operations["update_builder_agent"];
276
+ trace?: never;
277
+ };
278
+ "/v1/builder/agents/{agent_id}/rotate-secret": {
279
+ parameters: {
280
+ query?: never;
281
+ header?: never;
282
+ path?: never;
283
+ cookie?: never;
284
+ };
285
+ get?: never;
286
+ put?: never;
287
+ post: operations["rotate_builder_agent_secret"];
288
+ delete?: never;
289
+ options?: never;
290
+ head?: never;
291
+ patch?: never;
292
+ trace?: never;
293
+ };
294
+ "/v1/builder/invites/redeem": {
295
+ parameters: {
296
+ query?: never;
297
+ header?: never;
298
+ path?: never;
299
+ cookie?: never;
300
+ };
301
+ get?: never;
302
+ put?: never;
303
+ post: operations["redeem_invite"];
304
+ delete?: never;
305
+ options?: never;
306
+ head?: never;
307
+ patch?: never;
308
+ trace?: never;
309
+ };
310
+ "/v1/builder/requests": {
311
+ parameters: {
312
+ query?: never;
313
+ header?: never;
314
+ path?: never;
315
+ cookie?: never;
316
+ };
317
+ get?: never;
318
+ put?: never;
319
+ post: operations["create_request"];
320
+ delete?: never;
321
+ options?: never;
322
+ head?: never;
323
+ patch?: never;
324
+ trace?: never;
325
+ };
326
+ "/v1/builder/requests/me": {
327
+ parameters: {
328
+ query?: never;
329
+ header?: never;
330
+ path?: never;
331
+ cookie?: never;
332
+ };
333
+ get: operations["my_request"];
334
+ put?: never;
335
+ post?: never;
336
+ delete?: never;
337
+ options?: never;
338
+ head?: never;
339
+ patch?: never;
340
+ trace?: never;
341
+ };
182
342
  "/v1/connections": {
183
343
  parameters: {
184
344
  query?: never;
@@ -368,6 +528,11 @@ export interface components {
368
528
  AgentList: {
369
529
  agents: components["schemas"]["Agent"][];
370
530
  };
531
+ /**
532
+ * @description `listed` agents appear in the catalog. `unlisted` agents keep working but are hidden.
533
+ * @enum {string}
534
+ */
535
+ AgentStatus: "listed" | "unlisted";
371
536
  /** @description Query of `GET /oauth/authorize`. `scope` is a space-separated list of scope names. */
372
537
  AuthorizeQuery: {
373
538
  client_id: string;
@@ -376,6 +541,34 @@ export interface components {
376
541
  scope: string;
377
542
  state: string;
378
543
  };
544
+ /** @description Response of `GET /v1/billing`. `status` is the Stripe status or `none`. */
545
+ BillingStatus: {
546
+ cancel_at_period_end: boolean;
547
+ /** Format: int64 */
548
+ current_period_end?: number | null;
549
+ status: string;
550
+ };
551
+ /** @description One agent as its builder sees it. Element of `GET /v1/builder/agents`. */
552
+ BuilderAgent: {
553
+ client_id: string;
554
+ description: string;
555
+ homepage_url?: string | null;
556
+ id: string;
557
+ logo_url?: string | null;
558
+ name: string;
559
+ redirect_uris: string[];
560
+ requested_scopes: components["schemas"]["Scope"][];
561
+ slug: string;
562
+ status: components["schemas"]["AgentStatus"];
563
+ };
564
+ /** @description Response of `GET /v1/builder/agents`. */
565
+ BuilderAgentList: {
566
+ agents: components["schemas"]["BuilderAgent"][];
567
+ };
568
+ /** @description Response of `POST /v1/builder/agents/:agentId/rotate-secret`. The secret appears here one time. */
569
+ ClientSecret: {
570
+ client_secret: string;
571
+ };
379
572
  /** @description One connection without its credentials. */
380
573
  Connection: {
381
574
  account_email: string;
@@ -404,6 +597,22 @@ export interface components {
404
597
  ConsentResponse: {
405
598
  redirect_url: string;
406
599
  };
600
+ /** @description Body of `POST /v1/builder/agents`. */
601
+ CreateAgentBody: {
602
+ description: string;
603
+ homepage_url?: string | null;
604
+ logo_url?: string | null;
605
+ name: string;
606
+ redirect_uris: string[];
607
+ requested_scopes: components["schemas"]["Scope"][];
608
+ slug: string;
609
+ status: components["schemas"]["AgentStatus"];
610
+ };
611
+ /** @description Response of `POST /v1/builder/agents`. The client secret appears here one time. */
612
+ CreatedAgent: {
613
+ agent: components["schemas"]["BuilderAgent"];
614
+ client_secret: string;
615
+ };
407
616
  ErrorBody: {
408
617
  code: components["schemas"]["ErrorCode"];
409
618
  message: string;
@@ -413,7 +622,7 @@ export interface components {
413
622
  * @description The error codes that the API returns. See the proxy page, section 6.
414
623
  * @enum {string}
415
624
  */
416
- ErrorCode: "invalid_request" | "unauthorized" | "subscription_required" | "endpoint_not_allowed" | "scope_missing" | "agent_not_enabled" | "not_found" | "connection_not_found" | "connection_required" | "connection_reauth_required" | "payload_too_large" | "rate_limited" | "internal_error" | "upstream_timeout";
625
+ ErrorCode: "invalid_request" | "unauthorized" | "subscription_required" | "endpoint_not_allowed" | "scope_missing" | "agent_not_enabled" | "forbidden" | "not_found" | "connection_not_found" | "connection_required" | "connection_reauth_required" | "conflict" | "payload_too_large" | "rate_limited" | "internal_error" | "upstream_timeout";
417
626
  /** @description The JSON shape of every API error: `{ "error": { ... } }`. */
418
627
  ErrorResponse: {
419
628
  error: components["schemas"]["ErrorBody"];
@@ -436,6 +645,16 @@ export interface components {
436
645
  };
437
646
  /** @enum {string} */
438
647
  GrantStatus: "active" | "revoked";
648
+ /** @description Response of `POST /v1/admin/builder-requests/:userId/accept`. The code appears here one time. */
649
+ InviteCodeResponse: {
650
+ code: string;
651
+ /** Format: int64 */
652
+ expires_at: number;
653
+ };
654
+ /** @description Body of `POST /v1/builder/invites/redeem`. */
655
+ InviteRedeemBody: {
656
+ code: string;
657
+ };
439
658
  /** @description One RSA public key in `GET /.well-known/jwks.json`. */
440
659
  Jwk: {
441
660
  alg: string;
@@ -449,12 +668,43 @@ export interface components {
449
668
  Jwks: {
450
669
  keys: components["schemas"]["Jwk"][];
451
670
  };
671
+ /** @description Response of `POST /v1/builder/requests` and `GET /v1/builder/requests/me`. */
672
+ OnboardingRequest: {
673
+ agent_description: string;
674
+ company_name: string;
675
+ /** Format: int64 */
676
+ created_at: number;
677
+ email: string;
678
+ status: components["schemas"]["RequestStatus"];
679
+ user_id: string;
680
+ website: string;
681
+ };
682
+ /** @description Body of `POST /v1/builder/requests`. */
683
+ OnboardingRequestBody: {
684
+ agent_description: string;
685
+ company_name: string;
686
+ website: string;
687
+ };
688
+ /** @description Response of `GET /v1/admin/builder-requests`. */
689
+ OnboardingRequestList: {
690
+ requests: components["schemas"]["OnboardingRequest"][];
691
+ };
692
+ /**
693
+ * @description The status of an onboarding request. See the builder platform page, section 3.
694
+ * @enum {string}
695
+ */
696
+ RequestStatus: "pending" | "accepted" | "rejected";
452
697
  /** @description Body of `POST /oauth/revoke`. `token` is a refresh token. */
453
698
  RevokeRequest: {
454
699
  client_id: string;
455
700
  client_secret: string;
456
701
  token: string;
457
702
  };
703
+ /**
704
+ * @description The roles from the builder platform page, section 2. A later variant includes the earlier ones.
705
+ * @enum {string}
706
+ */
707
+ Role: "user" | "builder" | "admin";
458
708
  /**
459
709
  * @description A BubbleBridge scope. Each variant maps to one Google OAuth scope URL.
460
710
  * @enum {string}
@@ -493,12 +743,23 @@ export interface components {
493
743
  scope: string;
494
744
  user_id: string;
495
745
  };
746
+ /** @description Body of `PATCH /v1/builder/agents/:agentId`. A missing field keeps its value. */
747
+ UpdateAgentBody: {
748
+ description?: string | null;
749
+ homepage_url?: string | null;
750
+ logo_url?: string | null;
751
+ name?: string | null;
752
+ redirect_uris?: string[] | null;
753
+ requested_scopes?: components["schemas"]["Scope"][] | null;
754
+ status?: components["schemas"]["AgentStatus"] | null;
755
+ };
496
756
  /** @description Response of `POST /auth/google` and `GET /auth/me`. */
497
757
  User: {
498
758
  avatar_url?: string | null;
499
759
  email: string;
500
760
  id: string;
501
761
  name: string;
762
+ role: components["schemas"]["Role"];
502
763
  };
503
764
  };
504
765
  responses: never;
@@ -709,6 +970,7 @@ export interface operations {
709
970
  requestBody: {
710
971
  content: {
711
972
  "application/json": components["schemas"]["RevokeRequest"];
973
+ "application/x-www-form-urlencoded": components["schemas"]["RevokeRequest"];
712
974
  };
713
975
  };
714
976
  responses: {
@@ -738,6 +1000,7 @@ export interface operations {
738
1000
  requestBody: {
739
1001
  content: {
740
1002
  "application/json": components["schemas"]["TokenRequest"];
1003
+ "application/x-www-form-urlencoded": components["schemas"]["TokenRequest"];
741
1004
  };
742
1005
  };
743
1006
  responses: {
@@ -767,9 +1030,11 @@ export interface operations {
767
1030
  };
768
1031
  };
769
1032
  };
770
- list_catalog: {
1033
+ list_requests: {
771
1034
  parameters: {
772
- query?: never;
1035
+ query: {
1036
+ status: components["schemas"]["RequestStatus"];
1037
+ };
773
1038
  header?: never;
774
1039
  path?: never;
775
1040
  cookie?: never;
@@ -781,7 +1046,7 @@ export interface operations {
781
1046
  [name: string]: unknown;
782
1047
  };
783
1048
  content: {
784
- "application/json": components["schemas"]["AgentList"];
1049
+ "application/json": components["schemas"]["OnboardingRequestList"];
785
1050
  };
786
1051
  };
787
1052
  401: {
@@ -792,15 +1057,22 @@ export interface operations {
792
1057
  "application/json": components["schemas"]["ErrorResponse"];
793
1058
  };
794
1059
  };
1060
+ 403: {
1061
+ headers: {
1062
+ [name: string]: unknown;
1063
+ };
1064
+ content: {
1065
+ "application/json": components["schemas"]["ErrorResponse"];
1066
+ };
1067
+ };
795
1068
  };
796
1069
  };
797
- get: {
1070
+ accept: {
798
1071
  parameters: {
799
1072
  query?: never;
800
1073
  header?: never;
801
1074
  path: {
802
- /** @description The agent slug */
803
- slug: string;
1075
+ user_id: string;
804
1076
  };
805
1077
  cookie?: never;
806
1078
  };
@@ -811,7 +1083,7 @@ export interface operations {
811
1083
  [name: string]: unknown;
812
1084
  };
813
1085
  content: {
814
- "application/json": components["schemas"]["Agent"];
1086
+ "application/json": components["schemas"]["InviteCodeResponse"];
815
1087
  };
816
1088
  };
817
1089
  401: {
@@ -822,6 +1094,14 @@ export interface operations {
822
1094
  "application/json": components["schemas"]["ErrorResponse"];
823
1095
  };
824
1096
  };
1097
+ 403: {
1098
+ headers: {
1099
+ [name: string]: unknown;
1100
+ };
1101
+ content: {
1102
+ "application/json": components["schemas"]["ErrorResponse"];
1103
+ };
1104
+ };
825
1105
  404: {
826
1106
  headers: {
827
1107
  [name: string]: unknown;
@@ -830,13 +1110,23 @@ export interface operations {
830
1110
  "application/json": components["schemas"]["ErrorResponse"];
831
1111
  };
832
1112
  };
1113
+ 409: {
1114
+ headers: {
1115
+ [name: string]: unknown;
1116
+ };
1117
+ content: {
1118
+ "application/json": components["schemas"]["ErrorResponse"];
1119
+ };
1120
+ };
833
1121
  };
834
1122
  };
835
- checkout: {
1123
+ reject: {
836
1124
  parameters: {
837
1125
  query?: never;
838
1126
  header?: never;
839
- path?: never;
1127
+ path: {
1128
+ user_id: string;
1129
+ };
840
1130
  cookie?: never;
841
1131
  };
842
1132
  requestBody?: never;
@@ -846,7 +1136,7 @@ export interface operations {
846
1136
  [name: string]: unknown;
847
1137
  };
848
1138
  content: {
849
- "application/json": components["schemas"]["StripeUrl"];
1139
+ "application/json": components["schemas"]["OnboardingRequest"];
850
1140
  };
851
1141
  };
852
1142
  401: {
@@ -857,9 +1147,33 @@ export interface operations {
857
1147
  "application/json": components["schemas"]["ErrorResponse"];
858
1148
  };
859
1149
  };
1150
+ 403: {
1151
+ headers: {
1152
+ [name: string]: unknown;
1153
+ };
1154
+ content: {
1155
+ "application/json": components["schemas"]["ErrorResponse"];
1156
+ };
1157
+ };
1158
+ 404: {
1159
+ headers: {
1160
+ [name: string]: unknown;
1161
+ };
1162
+ content: {
1163
+ "application/json": components["schemas"]["ErrorResponse"];
1164
+ };
1165
+ };
1166
+ 409: {
1167
+ headers: {
1168
+ [name: string]: unknown;
1169
+ };
1170
+ content: {
1171
+ "application/json": components["schemas"]["ErrorResponse"];
1172
+ };
1173
+ };
860
1174
  };
861
1175
  };
862
- portal: {
1176
+ list_catalog: {
863
1177
  parameters: {
864
1178
  query?: never;
865
1179
  header?: never;
@@ -873,7 +1187,431 @@ export interface operations {
873
1187
  [name: string]: unknown;
874
1188
  };
875
1189
  content: {
876
- "application/json": components["schemas"]["StripeUrl"];
1190
+ "application/json": components["schemas"]["AgentList"];
1191
+ };
1192
+ };
1193
+ };
1194
+ };
1195
+ get: {
1196
+ parameters: {
1197
+ query?: never;
1198
+ header?: never;
1199
+ path: {
1200
+ /** @description The agent slug */
1201
+ slug: string;
1202
+ };
1203
+ cookie?: never;
1204
+ };
1205
+ requestBody?: never;
1206
+ responses: {
1207
+ 200: {
1208
+ headers: {
1209
+ [name: string]: unknown;
1210
+ };
1211
+ content: {
1212
+ "application/json": components["schemas"]["Agent"];
1213
+ };
1214
+ };
1215
+ 404: {
1216
+ headers: {
1217
+ [name: string]: unknown;
1218
+ };
1219
+ content: {
1220
+ "application/json": components["schemas"]["ErrorResponse"];
1221
+ };
1222
+ };
1223
+ };
1224
+ };
1225
+ status: {
1226
+ parameters: {
1227
+ query?: never;
1228
+ header?: never;
1229
+ path?: never;
1230
+ cookie?: never;
1231
+ };
1232
+ requestBody?: never;
1233
+ responses: {
1234
+ 200: {
1235
+ headers: {
1236
+ [name: string]: unknown;
1237
+ };
1238
+ content: {
1239
+ "application/json": components["schemas"]["BillingStatus"];
1240
+ };
1241
+ };
1242
+ 401: {
1243
+ headers: {
1244
+ [name: string]: unknown;
1245
+ };
1246
+ content: {
1247
+ "application/json": components["schemas"]["ErrorResponse"];
1248
+ };
1249
+ };
1250
+ };
1251
+ };
1252
+ checkout: {
1253
+ parameters: {
1254
+ query?: never;
1255
+ header?: never;
1256
+ path?: never;
1257
+ cookie?: never;
1258
+ };
1259
+ requestBody?: never;
1260
+ responses: {
1261
+ 200: {
1262
+ headers: {
1263
+ [name: string]: unknown;
1264
+ };
1265
+ content: {
1266
+ "application/json": components["schemas"]["StripeUrl"];
1267
+ };
1268
+ };
1269
+ 401: {
1270
+ headers: {
1271
+ [name: string]: unknown;
1272
+ };
1273
+ content: {
1274
+ "application/json": components["schemas"]["ErrorResponse"];
1275
+ };
1276
+ };
1277
+ };
1278
+ };
1279
+ portal: {
1280
+ parameters: {
1281
+ query?: never;
1282
+ header?: never;
1283
+ path?: never;
1284
+ cookie?: never;
1285
+ };
1286
+ requestBody?: never;
1287
+ responses: {
1288
+ 200: {
1289
+ headers: {
1290
+ [name: string]: unknown;
1291
+ };
1292
+ content: {
1293
+ "application/json": components["schemas"]["StripeUrl"];
1294
+ };
1295
+ };
1296
+ 401: {
1297
+ headers: {
1298
+ [name: string]: unknown;
1299
+ };
1300
+ content: {
1301
+ "application/json": components["schemas"]["ErrorResponse"];
1302
+ };
1303
+ };
1304
+ 404: {
1305
+ headers: {
1306
+ [name: string]: unknown;
1307
+ };
1308
+ content: {
1309
+ "application/json": components["schemas"]["ErrorResponse"];
1310
+ };
1311
+ };
1312
+ };
1313
+ };
1314
+ list_builder_agents: {
1315
+ parameters: {
1316
+ query?: never;
1317
+ header?: never;
1318
+ path?: never;
1319
+ cookie?: never;
1320
+ };
1321
+ requestBody?: never;
1322
+ responses: {
1323
+ 200: {
1324
+ headers: {
1325
+ [name: string]: unknown;
1326
+ };
1327
+ content: {
1328
+ "application/json": components["schemas"]["BuilderAgentList"];
1329
+ };
1330
+ };
1331
+ 401: {
1332
+ headers: {
1333
+ [name: string]: unknown;
1334
+ };
1335
+ content: {
1336
+ "application/json": components["schemas"]["ErrorResponse"];
1337
+ };
1338
+ };
1339
+ 403: {
1340
+ headers: {
1341
+ [name: string]: unknown;
1342
+ };
1343
+ content: {
1344
+ "application/json": components["schemas"]["ErrorResponse"];
1345
+ };
1346
+ };
1347
+ };
1348
+ };
1349
+ create_builder_agent: {
1350
+ parameters: {
1351
+ query?: never;
1352
+ header?: never;
1353
+ path?: never;
1354
+ cookie?: never;
1355
+ };
1356
+ requestBody: {
1357
+ content: {
1358
+ "application/json": components["schemas"]["CreateAgentBody"];
1359
+ };
1360
+ };
1361
+ responses: {
1362
+ 200: {
1363
+ headers: {
1364
+ [name: string]: unknown;
1365
+ };
1366
+ content: {
1367
+ "application/json": components["schemas"]["CreatedAgent"];
1368
+ };
1369
+ };
1370
+ 400: {
1371
+ headers: {
1372
+ [name: string]: unknown;
1373
+ };
1374
+ content: {
1375
+ "application/json": components["schemas"]["ErrorResponse"];
1376
+ };
1377
+ };
1378
+ 401: {
1379
+ headers: {
1380
+ [name: string]: unknown;
1381
+ };
1382
+ content: {
1383
+ "application/json": components["schemas"]["ErrorResponse"];
1384
+ };
1385
+ };
1386
+ 403: {
1387
+ headers: {
1388
+ [name: string]: unknown;
1389
+ };
1390
+ content: {
1391
+ "application/json": components["schemas"]["ErrorResponse"];
1392
+ };
1393
+ };
1394
+ 409: {
1395
+ headers: {
1396
+ [name: string]: unknown;
1397
+ };
1398
+ content: {
1399
+ "application/json": components["schemas"]["ErrorResponse"];
1400
+ };
1401
+ };
1402
+ };
1403
+ };
1404
+ update_builder_agent: {
1405
+ parameters: {
1406
+ query?: never;
1407
+ header?: never;
1408
+ path: {
1409
+ agent_id: string;
1410
+ };
1411
+ cookie?: never;
1412
+ };
1413
+ requestBody: {
1414
+ content: {
1415
+ "application/json": components["schemas"]["UpdateAgentBody"];
1416
+ };
1417
+ };
1418
+ responses: {
1419
+ 200: {
1420
+ headers: {
1421
+ [name: string]: unknown;
1422
+ };
1423
+ content: {
1424
+ "application/json": components["schemas"]["BuilderAgent"];
1425
+ };
1426
+ };
1427
+ 400: {
1428
+ headers: {
1429
+ [name: string]: unknown;
1430
+ };
1431
+ content: {
1432
+ "application/json": components["schemas"]["ErrorResponse"];
1433
+ };
1434
+ };
1435
+ 401: {
1436
+ headers: {
1437
+ [name: string]: unknown;
1438
+ };
1439
+ content: {
1440
+ "application/json": components["schemas"]["ErrorResponse"];
1441
+ };
1442
+ };
1443
+ 403: {
1444
+ headers: {
1445
+ [name: string]: unknown;
1446
+ };
1447
+ content: {
1448
+ "application/json": components["schemas"]["ErrorResponse"];
1449
+ };
1450
+ };
1451
+ 404: {
1452
+ headers: {
1453
+ [name: string]: unknown;
1454
+ };
1455
+ content: {
1456
+ "application/json": components["schemas"]["ErrorResponse"];
1457
+ };
1458
+ };
1459
+ };
1460
+ };
1461
+ rotate_builder_agent_secret: {
1462
+ parameters: {
1463
+ query?: never;
1464
+ header?: never;
1465
+ path: {
1466
+ agent_id: string;
1467
+ };
1468
+ cookie?: never;
1469
+ };
1470
+ requestBody?: never;
1471
+ responses: {
1472
+ 200: {
1473
+ headers: {
1474
+ [name: string]: unknown;
1475
+ };
1476
+ content: {
1477
+ "application/json": components["schemas"]["ClientSecret"];
1478
+ };
1479
+ };
1480
+ 401: {
1481
+ headers: {
1482
+ [name: string]: unknown;
1483
+ };
1484
+ content: {
1485
+ "application/json": components["schemas"]["ErrorResponse"];
1486
+ };
1487
+ };
1488
+ 403: {
1489
+ headers: {
1490
+ [name: string]: unknown;
1491
+ };
1492
+ content: {
1493
+ "application/json": components["schemas"]["ErrorResponse"];
1494
+ };
1495
+ };
1496
+ 404: {
1497
+ headers: {
1498
+ [name: string]: unknown;
1499
+ };
1500
+ content: {
1501
+ "application/json": components["schemas"]["ErrorResponse"];
1502
+ };
1503
+ };
1504
+ };
1505
+ };
1506
+ redeem_invite: {
1507
+ parameters: {
1508
+ query?: never;
1509
+ header?: never;
1510
+ path?: never;
1511
+ cookie?: never;
1512
+ };
1513
+ requestBody: {
1514
+ content: {
1515
+ "application/json": components["schemas"]["InviteRedeemBody"];
1516
+ };
1517
+ };
1518
+ responses: {
1519
+ 200: {
1520
+ headers: {
1521
+ [name: string]: unknown;
1522
+ };
1523
+ content: {
1524
+ "application/json": components["schemas"]["User"];
1525
+ };
1526
+ };
1527
+ 400: {
1528
+ headers: {
1529
+ [name: string]: unknown;
1530
+ };
1531
+ content: {
1532
+ "application/json": components["schemas"]["ErrorResponse"];
1533
+ };
1534
+ };
1535
+ 401: {
1536
+ headers: {
1537
+ [name: string]: unknown;
1538
+ };
1539
+ content: {
1540
+ "application/json": components["schemas"]["ErrorResponse"];
1541
+ };
1542
+ };
1543
+ 409: {
1544
+ headers: {
1545
+ [name: string]: unknown;
1546
+ };
1547
+ content: {
1548
+ "application/json": components["schemas"]["ErrorResponse"];
1549
+ };
1550
+ };
1551
+ };
1552
+ };
1553
+ create_request: {
1554
+ parameters: {
1555
+ query?: never;
1556
+ header?: never;
1557
+ path?: never;
1558
+ cookie?: never;
1559
+ };
1560
+ requestBody: {
1561
+ content: {
1562
+ "application/json": components["schemas"]["OnboardingRequestBody"];
1563
+ };
1564
+ };
1565
+ responses: {
1566
+ 200: {
1567
+ headers: {
1568
+ [name: string]: unknown;
1569
+ };
1570
+ content: {
1571
+ "application/json": components["schemas"]["OnboardingRequest"];
1572
+ };
1573
+ };
1574
+ 400: {
1575
+ headers: {
1576
+ [name: string]: unknown;
1577
+ };
1578
+ content: {
1579
+ "application/json": components["schemas"]["ErrorResponse"];
1580
+ };
1581
+ };
1582
+ 401: {
1583
+ headers: {
1584
+ [name: string]: unknown;
1585
+ };
1586
+ content: {
1587
+ "application/json": components["schemas"]["ErrorResponse"];
1588
+ };
1589
+ };
1590
+ 409: {
1591
+ headers: {
1592
+ [name: string]: unknown;
1593
+ };
1594
+ content: {
1595
+ "application/json": components["schemas"]["ErrorResponse"];
1596
+ };
1597
+ };
1598
+ };
1599
+ };
1600
+ my_request: {
1601
+ parameters: {
1602
+ query?: never;
1603
+ header?: never;
1604
+ path?: never;
1605
+ cookie?: never;
1606
+ };
1607
+ requestBody?: never;
1608
+ responses: {
1609
+ 200: {
1610
+ headers: {
1611
+ [name: string]: unknown;
1612
+ };
1613
+ content: {
1614
+ "application/json": components["schemas"]["OnboardingRequest"];
877
1615
  };
878
1616
  };
879
1617
  401: {
@@ -933,7 +1671,7 @@ export interface operations {
933
1671
  };
934
1672
  requestBody?: never;
935
1673
  responses: {
936
- /** @description Redirect to the connections page */
1674
+ /** @description Redirect to return_to from the start request, or to the connections page */
937
1675
  303: {
938
1676
  headers: {
939
1677
  [name: string]: unknown;
@@ -962,6 +1700,7 @@ export interface operations {
962
1700
  parameters: {
963
1701
  query: {
964
1702
  scopes: string;
1703
+ return_to?: string;
965
1704
  };
966
1705
  header?: never;
967
1706
  path?: never;
package/dist/gmail.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { base64Url } from './base64url.js';
1
2
  /** The Gmail helpers. `Google.gmail` holds it. */
2
3
  export class Gmail {
3
4
  google;
@@ -8,7 +9,7 @@ export class Gmail {
8
9
  send(email) {
9
10
  const message = `To: ${email.to}\r\nSubject: ${email.subject}\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n${email.text}`;
10
11
  return this.google.request('POST', '/gmail/v1/users/me/messages/send', {
11
- raw: base64Url(message),
12
+ raw: base64Url(new TextEncoder().encode(message)),
12
13
  });
13
14
  }
14
15
  /** Lists the message IDs that match a Gmail search query. */
@@ -17,10 +18,3 @@ export class Gmail {
17
18
  return this.google.request('GET', `/gmail/v1/users/me/messages?${params}`);
18
19
  }
19
20
  }
20
- function base64Url(text) {
21
- const bytes = new TextEncoder().encode(text);
22
- let binary = '';
23
- for (const byte of bytes)
24
- binary += String.fromCharCode(byte);
25
- return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
26
- }
package/dist/index.d.ts CHANGED
@@ -5,6 +5,7 @@ export type { components, operations, paths } from './generated.js';
5
5
  export type { Connection, ConnectionList, ConnectionStatus, Method, Scope, TokenResponse, } from './types.js';
6
6
  export { ApiError, UpstreamError } from './error.js';
7
7
  export { Oauth, type AuthorizeUrlInput, type ExchangeCodeInput } from './oauth.js';
8
+ export { pkce, type Pkce } from './pkce.js';
8
9
  export { UserClient, type ForUserOptions, type OnTokensUpdated } from './user.js';
9
10
  export { Google } from './google.js';
10
11
  export { Gmail, type SendEmail } from './gmail.js';
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ import { Oauth } from './oauth.js';
2
2
  import { UserClient } from './user.js';
3
3
  export { ApiError, UpstreamError } from './error.js';
4
4
  export { Oauth } from './oauth.js';
5
+ export { pkce } from './pkce.js';
5
6
  export { UserClient } from './user.js';
6
7
  export { Google } from './google.js';
7
8
  export { Gmail } from './gmail.js';
package/dist/pkce.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ /** The values for one consent flow. The agent site stores `state` and `codeVerifier` and sends `codeChallenge` to the consent page. */
2
+ export interface Pkce {
3
+ state: string;
4
+ codeVerifier: string;
5
+ codeChallenge: string;
6
+ }
7
+ /** A random `state` value, a random PKCE verifier, and its S256 challenge. */
8
+ export declare function pkce(): Promise<Pkce>;
package/dist/pkce.js ADDED
@@ -0,0 +1,8 @@
1
+ import { base64Url } from './base64url.js';
2
+ /** A random `state` value, a random PKCE verifier, and its S256 challenge. */
3
+ export async function pkce() {
4
+ const state = base64Url(crypto.getRandomValues(new Uint8Array(16)));
5
+ const codeVerifier = base64Url(crypto.getRandomValues(new Uint8Array(32)));
6
+ const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(codeVerifier));
7
+ return { state, codeVerifier, codeChallenge: base64Url(new Uint8Array(digest)) };
8
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bubblebridge/sdk",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "The BubbleBridge SDK for agent builders",
5
5
  "keywords": ["bubblebridge", "oauth", "gmail", "google-calendar", "agent"],
6
6
  "homepage": "https://bubblebridge.io",