@terrascale/sdk 0.0.2 → 0.0.4
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/CHANGELOG.md +43 -0
- package/README.md +193 -56
- package/package.json +14 -5
- package/sdk-public-v1-route-manifest.json +81 -0
- package/sdk-v1-route-manifest.json +8996 -1697
- package/src/database-codec.js +21 -26
- package/src/database-types.js +11 -11
- package/src/database-view.js +6 -6
- package/src/http.js +13 -48
- package/src/ids.js +22 -0
- package/src/index.js +77 -2
- package/src/local/better-auth.js +17 -6
- package/src/local/environment.js +0 -1
- package/src/local/index.js +2 -2
- package/src/local/legacy-client.js +5 -5
- package/src/local/router.js +12 -12
- package/src/local/store.js +29 -28
- package/src/local/test-environment.js +3 -2
- package/src/postgres.js +5 -4
- package/src/react/core.js +2 -2
- package/src/ts-auth-ids.js +122 -0
- package/src/ts-auth.js +75 -77
- package/src/v1/backups.js +111 -0
- package/src/v1/catalog.js +210 -0
- package/src/v1/changes.js +225 -0
- package/src/v1/database-schema.js +45 -0
- package/src/v1/decode.js +20 -8
- package/src/v1/errors.js +23 -3
- package/src/v1/ids.js +9 -59
- package/src/v1/imports.js +72 -0
- package/src/v1/indexes.js +76 -0
- package/src/v1/json.js +4 -3
- package/src/v1/management-decode.js +24 -0
- package/src/v1/management-routes.js +67 -0
- package/src/v1/management-validation.js +25 -0
- package/src/v1/routes.js +36 -11
- package/src/v1/saved-queries.js +58 -0
- package/src/v1/shape-crypto.js +125 -0
- package/src/v1/shape-manifest.js +31 -0
- package/src/v1/shape-reader.js +212 -0
- package/src/v1/shape-subscription.js +208 -0
- package/src/v1/shapes.js +15 -10
- package/src/v1/sql.js +98 -0
- package/src/v1/system.js +80 -0
- package/src/v1/terrabase-v1.js +192 -33
- package/src/v1/transport.js +80 -34
- package/src/v1/usage.js +101 -0
- package/types/database-codec.d.ts +1 -6
- package/types/database-types.d.ts +11 -11
- package/types/http.d.ts +2 -8
- package/types/ids.d.ts +10 -0
- package/types/index.d.ts +70 -1
- package/types/local/environment.d.ts +1 -1
- package/types/local/store.d.ts +10 -0
- package/types/local/test-environment.d.ts +2 -2
- package/types/postgres.d.ts +4 -4
- package/types/ts-auth-ids.d.ts +14 -0
- package/types/ts-auth.d.ts +99 -101
- package/types/v1/backups.d.ts +128 -0
- package/types/v1/catalog.d.ts +92 -0
- package/types/v1/changes.d.ts +53 -0
- package/types/v1/database-schema.d.ts +82 -0
- package/types/v1/decode.d.ts +17 -4
- package/types/v1/errors.d.ts +16 -1
- package/types/v1/ids.d.ts +4 -16
- package/types/v1/imports.d.ts +132 -0
- package/types/v1/indexes.d.ts +75 -0
- package/types/v1/management-decode.d.ts +15 -0
- package/types/v1/management-routes.d.ts +3 -0
- package/types/v1/management-validation.d.ts +8 -0
- package/types/v1/routes.d.ts +5 -2
- package/types/v1/saved-queries.d.ts +33 -0
- package/types/v1/shape-crypto.d.ts +39 -0
- package/types/v1/shape-manifest.d.ts +28 -0
- package/types/v1/shape-reader.d.ts +45 -0
- package/types/v1/shape-subscription.d.ts +35 -0
- package/types/v1/shapes.d.ts +14 -0
- package/types/v1/sql.d.ts +47 -0
- package/types/v1/system.d.ts +85 -0
- package/types/v1/terrabase-v1.d.ts +116 -7
- package/types/v1/transport.d.ts +27 -10
- package/types/v1/usage.d.ts +171 -0
- package/src/ts-auth-discovery.js +0 -207
- package/types/ts-auth-discovery.d.ts +0 -19
package/src/ts-auth.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { TsAuthHttp } from "./http.js";
|
|
2
2
|
import { err } from "./result.js";
|
|
3
|
+
import { isValidId, requireId } from "./ids.js";
|
|
4
|
+
import { requireDeadLetterId } from "./ts-auth-ids.js";
|
|
3
5
|
/** @import { TerraScaleResult } from "./result.js" */
|
|
4
6
|
|
|
5
7
|
/** @typedef {import("./config.js").TsAuthRuntimeConfig} TsAuthRuntimeConfig */
|
|
@@ -13,7 +15,6 @@ import { err } from "./result.js";
|
|
|
13
15
|
* @typedef {Omit<TsAuthRuntimeConfig, "apiBaseUrl"> & {
|
|
14
16
|
* readonly apiBaseUrl: string; // The ts-auth deployment's public origin; there is no default.
|
|
15
17
|
* readonly instanceSlug: string; // The instance the `sk_` key belongs to; it prefixes every route.
|
|
16
|
-
* readonly useReverseProxy?: boolean; // Route public auth calls through the reverse proxy instead of regional discovery.
|
|
17
18
|
* }} TsAuthClientConfig
|
|
18
19
|
*/
|
|
19
20
|
|
|
@@ -27,7 +28,7 @@ import { err } from "./result.js";
|
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* @typedef {{
|
|
30
|
-
* readonly id:
|
|
31
|
+
* readonly id: import("./ids.js").EntityId;
|
|
31
32
|
* readonly email: string | null;
|
|
32
33
|
* readonly email_verified: boolean;
|
|
33
34
|
* readonly username: string | null;
|
|
@@ -43,7 +44,7 @@ import { err } from "./result.js";
|
|
|
43
44
|
|
|
44
45
|
/**
|
|
45
46
|
* @typedef {{
|
|
46
|
-
* readonly id:
|
|
47
|
+
* readonly id: import("./ids.js").EntityId;
|
|
47
48
|
* readonly status: string;
|
|
48
49
|
* readonly created_at: number; // Unix seconds.
|
|
49
50
|
* readonly expires_at: number; // Unix seconds.
|
|
@@ -55,7 +56,7 @@ import { err } from "./result.js";
|
|
|
55
56
|
|
|
56
57
|
/**
|
|
57
58
|
* @typedef {{
|
|
58
|
-
* readonly id:
|
|
59
|
+
* readonly id: import("./ids.js").EntityId;
|
|
59
60
|
* readonly type: string;
|
|
60
61
|
* readonly confirmed: boolean;
|
|
61
62
|
* readonly createdAt: number; // Unix seconds.
|
|
@@ -64,7 +65,7 @@ import { err } from "./result.js";
|
|
|
64
65
|
|
|
65
66
|
/**
|
|
66
67
|
* @typedef {{
|
|
67
|
-
* readonly id:
|
|
68
|
+
* readonly id: import("./ids.js").EntityId;
|
|
68
69
|
* readonly nickname: string | null;
|
|
69
70
|
* readonly algorithm: string;
|
|
70
71
|
* readonly createdAt: number; // Unix seconds.
|
|
@@ -74,7 +75,7 @@ import { err } from "./result.js";
|
|
|
74
75
|
|
|
75
76
|
/**
|
|
76
77
|
* @typedef {{
|
|
77
|
-
* readonly id:
|
|
78
|
+
* readonly id: import("./ids.js").EntityId;
|
|
78
79
|
* readonly name: string;
|
|
79
80
|
* readonly slug: string;
|
|
80
81
|
* readonly created_at: number; // Unix seconds.
|
|
@@ -83,7 +84,7 @@ import { err } from "./result.js";
|
|
|
83
84
|
|
|
84
85
|
/**
|
|
85
86
|
* @typedef {{
|
|
86
|
-
* readonly id:
|
|
87
|
+
* readonly id: import("./ids.js").EntityId;
|
|
87
88
|
* readonly role: string;
|
|
88
89
|
* readonly created_at: number; // Unix seconds.
|
|
89
90
|
* readonly organization: TsAuthOrganization | null;
|
|
@@ -320,7 +321,7 @@ export class TsAuthUsersClient {
|
|
|
320
321
|
...(options.limit === undefined ? {} : { limit: options.limit }),
|
|
321
322
|
...(options.startingAfter === undefined
|
|
322
323
|
? {}
|
|
323
|
-
: { starting_after: options.startingAfter }),
|
|
324
|
+
: { starting_after: requireId(options.startingAfter, "startingAfter") }),
|
|
324
325
|
},
|
|
325
326
|
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
326
327
|
});
|
|
@@ -586,7 +587,7 @@ export class TsAuthSessionsClient {
|
|
|
586
587
|
|
|
587
588
|
/**
|
|
588
589
|
* @typedef {{
|
|
589
|
-
* readonly id:
|
|
590
|
+
* readonly id: import("./ids.js").EntityId;
|
|
590
591
|
* readonly name: string;
|
|
591
592
|
* readonly api_key: string; // One-time full sk_ bearer; only the creating call returns it.
|
|
592
593
|
* readonly scopes: readonly string[];
|
|
@@ -595,7 +596,7 @@ export class TsAuthSessionsClient {
|
|
|
595
596
|
|
|
596
597
|
/**
|
|
597
598
|
* @typedef {{
|
|
598
|
-
* readonly id:
|
|
599
|
+
* readonly id: import("./ids.js").EntityId;
|
|
599
600
|
* readonly name: string;
|
|
600
601
|
* readonly scopes: readonly string[];
|
|
601
602
|
* readonly created_at: number; // Unix seconds.
|
|
@@ -674,9 +675,9 @@ export class TsAuthApiKeysClient {
|
|
|
674
675
|
|
|
675
676
|
/**
|
|
676
677
|
* @typedef {{
|
|
677
|
-
* readonly id:
|
|
678
|
-
* readonly organization_id:
|
|
679
|
-
* readonly user_id:
|
|
678
|
+
* readonly id: import("./ids.js").EntityId;
|
|
679
|
+
* readonly organization_id: import("./ids.js").EntityId;
|
|
680
|
+
* readonly user_id: import("./ids.js").EntityId;
|
|
680
681
|
* readonly role: string;
|
|
681
682
|
* readonly created_at: number; // Unix seconds.
|
|
682
683
|
* }} TsAuthMembership
|
|
@@ -685,7 +686,7 @@ export class TsAuthApiKeysClient {
|
|
|
685
686
|
/**
|
|
686
687
|
* @typedef {TsAuthMembership & {
|
|
687
688
|
* readonly user: {
|
|
688
|
-
* readonly id:
|
|
689
|
+
* readonly id: import("./ids.js").EntityId;
|
|
689
690
|
* readonly email: string;
|
|
690
691
|
* readonly name: string;
|
|
691
692
|
* } | null;
|
|
@@ -694,8 +695,8 @@ export class TsAuthApiKeysClient {
|
|
|
694
695
|
|
|
695
696
|
/**
|
|
696
697
|
* @typedef {{
|
|
697
|
-
* readonly id:
|
|
698
|
-
* readonly organization_id:
|
|
698
|
+
* readonly id: import("./ids.js").EntityId;
|
|
699
|
+
* readonly organization_id: import("./ids.js").EntityId;
|
|
699
700
|
* readonly email: string;
|
|
700
701
|
* readonly role: string;
|
|
701
702
|
* readonly status: string;
|
|
@@ -706,14 +707,14 @@ export class TsAuthApiKeysClient {
|
|
|
706
707
|
|
|
707
708
|
/**
|
|
708
709
|
* @typedef {{
|
|
709
|
-
* readonly id:
|
|
710
|
-
* readonly organization_id:
|
|
710
|
+
* readonly id: import("./ids.js").EntityId;
|
|
711
|
+
* readonly organization_id: import("./ids.js").EntityId;
|
|
711
712
|
* readonly domain: string;
|
|
712
713
|
* readonly created_at: number; // Unix seconds.
|
|
713
714
|
* }} TsAuthOrganizationDomain
|
|
714
715
|
*/
|
|
715
716
|
|
|
716
|
-
/** @typedef {{ readonly org_id:
|
|
717
|
+
/** @typedef {{ readonly org_id: import("./ids.js").EntityId }} TsAuthDomainEnrollment */
|
|
717
718
|
|
|
718
719
|
/**
|
|
719
720
|
* @typedef {{
|
|
@@ -730,7 +731,7 @@ export class TsAuthApiKeysClient {
|
|
|
730
731
|
|
|
731
732
|
/**
|
|
732
733
|
* @typedef {{
|
|
733
|
-
* readonly user_id:
|
|
734
|
+
* readonly user_id: import("./ids.js").EntityId;
|
|
734
735
|
* readonly role: string;
|
|
735
736
|
* }} TsAuthCreateMembershipRequest
|
|
736
737
|
*/
|
|
@@ -750,7 +751,7 @@ export class TsAuthApiKeysClient {
|
|
|
750
751
|
|
|
751
752
|
/**
|
|
752
753
|
* @typedef {{
|
|
753
|
-
* readonly user_id:
|
|
754
|
+
* readonly user_id: import("./ids.js").EntityId;
|
|
754
755
|
* }} TsAuthEnrollRequest
|
|
755
756
|
*/
|
|
756
757
|
|
|
@@ -844,7 +845,7 @@ export class TsAuthOrganizationsClient {
|
|
|
844
845
|
* @returns {Promise<TerraScaleResult<TsAuthMembership>>}
|
|
845
846
|
*/
|
|
846
847
|
createMembership(organizationId, request) {
|
|
847
|
-
|
|
848
|
+
requireId(request?.user_id, "user_id");
|
|
848
849
|
requireText(request?.role, "role");
|
|
849
850
|
return this.#http.request({
|
|
850
851
|
method: "POST",
|
|
@@ -982,7 +983,7 @@ export class TsAuthOrganizationsClient {
|
|
|
982
983
|
* @returns {Promise<TerraScaleResult<TsAuthDomainEnrollment>>}
|
|
983
984
|
*/
|
|
984
985
|
enrollDomain(domain, request) {
|
|
985
|
-
|
|
986
|
+
requireId(request?.user_id, "user_id");
|
|
986
987
|
return this.#http.request({
|
|
987
988
|
method: "POST",
|
|
988
989
|
path: `v1/${this.#slug}/domains/${segment(domain, "domain")}/enroll`,
|
|
@@ -1028,8 +1029,8 @@ export class TsAuthOrganizationsClient {
|
|
|
1028
1029
|
*/
|
|
1029
1030
|
/**
|
|
1030
1031
|
* @typedef {{
|
|
1031
|
-
* readonly id:
|
|
1032
|
-
* readonly client_id:
|
|
1032
|
+
* readonly id: import("./ids.js").EntityId;
|
|
1033
|
+
* readonly client_id: import("./ids.js").EntityId;
|
|
1033
1034
|
* readonly name: string;
|
|
1034
1035
|
* readonly redirect_uris: readonly string[];
|
|
1035
1036
|
* readonly post_logout_redirect_uris: readonly string[];
|
|
@@ -1146,7 +1147,7 @@ export class TsAuthOauthClientsClient {
|
|
|
1146
1147
|
/**
|
|
1147
1148
|
* @typedef {{
|
|
1148
1149
|
* readonly audience: string;
|
|
1149
|
-
* readonly allowed_client_ids: readonly
|
|
1150
|
+
* readonly allowed_client_ids: readonly import("./ids.js").EntityId[];
|
|
1150
1151
|
* readonly allowed_grant_types: readonly TsAuthOauthGrantType[];
|
|
1151
1152
|
* readonly allowed_scopes: readonly string[];
|
|
1152
1153
|
* }} TsAuthCreateOauthResourceRequest
|
|
@@ -1154,7 +1155,7 @@ export class TsAuthOauthClientsClient {
|
|
|
1154
1155
|
/**
|
|
1155
1156
|
* @typedef {{
|
|
1156
1157
|
* readonly expected_auth_epoch: number;
|
|
1157
|
-
* readonly allowed_client_ids?: readonly
|
|
1158
|
+
* readonly allowed_client_ids?: readonly import("./ids.js").EntityId[] | undefined;
|
|
1158
1159
|
* readonly allowed_grant_types?: readonly TsAuthOauthGrantType[] | undefined;
|
|
1159
1160
|
* readonly allowed_scopes?: readonly string[] | undefined;
|
|
1160
1161
|
* readonly enabled?: boolean | undefined;
|
|
@@ -1163,8 +1164,8 @@ export class TsAuthOauthClientsClient {
|
|
|
1163
1164
|
*/
|
|
1164
1165
|
/**
|
|
1165
1166
|
* @typedef {TsAuthCreateOauthResourceRequest & {
|
|
1166
|
-
* readonly id:
|
|
1167
|
-
* readonly introspection_client_id:
|
|
1167
|
+
* readonly id: import("./ids.js").EntityId;
|
|
1168
|
+
* readonly introspection_client_id: import("./ids.js").EntityId;
|
|
1168
1169
|
* readonly token_endpoint_auth_method: "client_secret_basic";
|
|
1169
1170
|
* readonly auth_epoch: number;
|
|
1170
1171
|
* readonly enabled: boolean;
|
|
@@ -1265,11 +1266,11 @@ export class TsAuthOauthResourcesClient {
|
|
|
1265
1266
|
|
|
1266
1267
|
/**
|
|
1267
1268
|
* @typedef {{
|
|
1268
|
-
* readonly id:
|
|
1269
|
+
* readonly id: import("./ids.js").EntityId;
|
|
1269
1270
|
* readonly type: "oidc" | "saml";
|
|
1270
1271
|
* readonly name: string;
|
|
1271
1272
|
* readonly enabled: boolean;
|
|
1272
|
-
* readonly org_id:
|
|
1273
|
+
* readonly org_id: import("./ids.js").EntityId | null;
|
|
1273
1274
|
* readonly issuer_url: string | null;
|
|
1274
1275
|
* readonly client_id: string | null;
|
|
1275
1276
|
* readonly authorization_endpoint: string | null;
|
|
@@ -1342,7 +1343,7 @@ export class TsAuthConnectionsClient {
|
|
|
1342
1343
|
requireText(request?.name, "name");
|
|
1343
1344
|
if (request.type === "oidc") {
|
|
1344
1345
|
requireAbsoluteHttpUrl(request.issuer_url, "issuer_url");
|
|
1345
|
-
requireText(request.client_id, "client_id");
|
|
1346
|
+
requireText(request.client_id, "client_id"); // This client belongs to the external IdP.
|
|
1346
1347
|
requireText(request.client_secret, "client_secret");
|
|
1347
1348
|
} else {
|
|
1348
1349
|
requireText(request.idp_entity_id, "idp_entity_id");
|
|
@@ -1399,16 +1400,16 @@ export class TsAuthConnectionsClient {
|
|
|
1399
1400
|
|
|
1400
1401
|
/**
|
|
1401
1402
|
* @typedef {{
|
|
1402
|
-
* readonly id:
|
|
1403
|
-
* readonly org_id:
|
|
1403
|
+
* readonly id: import("./ids.js").EntityId;
|
|
1404
|
+
* readonly org_id: import("./ids.js").EntityId | null;
|
|
1404
1405
|
* readonly token: string; // One-time SCIM bearer; only create and rotate return it.
|
|
1405
1406
|
* }} TsAuthDirectoryWithToken
|
|
1406
1407
|
*/
|
|
1407
1408
|
|
|
1408
1409
|
/**
|
|
1409
1410
|
* @typedef {{
|
|
1410
|
-
* readonly id:
|
|
1411
|
-
* readonly org_id:
|
|
1411
|
+
* readonly id: import("./ids.js").EntityId;
|
|
1412
|
+
* readonly org_id: import("./ids.js").EntityId | null;
|
|
1412
1413
|
* readonly created_at: number; // Unix seconds.
|
|
1413
1414
|
* }} TsAuthDirectory
|
|
1414
1415
|
*/
|
|
@@ -1439,7 +1440,7 @@ export class TsAuthDirectoriesClient {
|
|
|
1439
1440
|
* @returns {Promise<TerraScaleResult<TsAuthDirectoryWithToken>>}
|
|
1440
1441
|
*/
|
|
1441
1442
|
create(request = {}) {
|
|
1442
|
-
if (request.org_id !== undefined)
|
|
1443
|
+
if (request.org_id !== undefined) requireId(request.org_id, "org_id");
|
|
1443
1444
|
return this.#http.request({
|
|
1444
1445
|
method: "POST",
|
|
1445
1446
|
path: `v1/${this.#slug}/directories`,
|
|
@@ -1488,7 +1489,7 @@ export class TsAuthDirectoriesClient {
|
|
|
1488
1489
|
|
|
1489
1490
|
/**
|
|
1490
1491
|
* @typedef {{
|
|
1491
|
-
* readonly id:
|
|
1492
|
+
* readonly id: import("./ids.js").EntityId;
|
|
1492
1493
|
* readonly name: string;
|
|
1493
1494
|
* readonly claims: Record<string, string>;
|
|
1494
1495
|
* readonly lifetime_seconds: number;
|
|
@@ -1600,12 +1601,12 @@ export class TsAuthJwtTemplatesClient {
|
|
|
1600
1601
|
|
|
1601
1602
|
/**
|
|
1602
1603
|
* @param {string} name
|
|
1603
|
-
* @param {{ readonly user_id:
|
|
1604
|
+
* @param {{ readonly user_id: import("./ids.js").EntityId }} request
|
|
1604
1605
|
* @returns {Promise<TerraScaleResult<TsAuthJwtTokenResponse>>}
|
|
1605
1606
|
*/
|
|
1606
1607
|
issueToken(name, request) {
|
|
1607
1608
|
validateJwtTemplateName(name);
|
|
1608
|
-
|
|
1609
|
+
requireId(request?.user_id, "user_id");
|
|
1609
1610
|
return this.#http.request({
|
|
1610
1611
|
method: "POST",
|
|
1611
1612
|
path: `v1/${this.#slug}/jwt-templates/${segment(name, "template name")}/tokens`,
|
|
@@ -1619,7 +1620,7 @@ export class TsAuthJwtTemplatesClient {
|
|
|
1619
1620
|
|
|
1620
1621
|
/**
|
|
1621
1622
|
* @typedef {{
|
|
1622
|
-
* readonly id:
|
|
1623
|
+
* readonly id: import("./ids.js").EntityId;
|
|
1623
1624
|
* readonly url: string;
|
|
1624
1625
|
* readonly events: readonly string[];
|
|
1625
1626
|
* readonly signing_secret: string; // One-time HMAC key for verifying deliveries; only create returns it.
|
|
@@ -1628,7 +1629,7 @@ export class TsAuthJwtTemplatesClient {
|
|
|
1628
1629
|
|
|
1629
1630
|
/**
|
|
1630
1631
|
* @typedef {{
|
|
1631
|
-
* readonly id:
|
|
1632
|
+
* readonly id: import("./ids.js").EntityId;
|
|
1632
1633
|
* readonly url: string;
|
|
1633
1634
|
* readonly events: readonly string[];
|
|
1634
1635
|
* readonly enabled: boolean;
|
|
@@ -1638,9 +1639,9 @@ export class TsAuthJwtTemplatesClient {
|
|
|
1638
1639
|
|
|
1639
1640
|
/**
|
|
1640
1641
|
* @typedef {{
|
|
1641
|
-
* readonly id:
|
|
1642
|
-
* readonly endpoint_id:
|
|
1643
|
-
* readonly event_id:
|
|
1642
|
+
* readonly id: `${import("./ids.js").EntityId}:${import("./ids.js").EntityId}`; // endpointId:eventId delivery selector.
|
|
1643
|
+
* readonly endpoint_id: import("./ids.js").EntityId;
|
|
1644
|
+
* readonly event_id: import("./ids.js").EntityId;
|
|
1644
1645
|
* readonly attempts: number;
|
|
1645
1646
|
* readonly last_error?: string | undefined;
|
|
1646
1647
|
* readonly updated_at: number; // Unix seconds.
|
|
@@ -1741,7 +1742,7 @@ export class TsAuthWebhooksClient {
|
|
|
1741
1742
|
replayDeadLetter(entryId) {
|
|
1742
1743
|
return this.#http.request({
|
|
1743
1744
|
method: "POST",
|
|
1744
|
-
path: `v1/${this.#slug}/webhooks/dead-letter/${
|
|
1745
|
+
path: `v1/${this.#slug}/webhooks/dead-letter/${encodeURIComponent(requireDeadLetterId(entryId))}/replay`,
|
|
1745
1746
|
routeName: "tsauth.webhooks.replayDeadLetter",
|
|
1746
1747
|
});
|
|
1747
1748
|
}
|
|
@@ -1751,10 +1752,10 @@ export class TsAuthWebhooksClient {
|
|
|
1751
1752
|
|
|
1752
1753
|
/**
|
|
1753
1754
|
* @typedef {{
|
|
1754
|
-
* readonly id:
|
|
1755
|
-
* readonly instance_id:
|
|
1755
|
+
* readonly id: import("./ids.js").EntityId;
|
|
1756
|
+
* readonly instance_id: import("./ids.js").EntityId;
|
|
1756
1757
|
* readonly type: string;
|
|
1757
|
-
* readonly actor_id?:
|
|
1758
|
+
* readonly actor_id?: import("./ids.js").EntityId | undefined; // Omitted from the wire when null.
|
|
1758
1759
|
* readonly data: Record<string, unknown>;
|
|
1759
1760
|
* readonly created_at: number; // Unix seconds.
|
|
1760
1761
|
* readonly integrity_version: number;
|
|
@@ -1918,7 +1919,7 @@ export class TsAuthBillingClient {
|
|
|
1918
1919
|
|
|
1919
1920
|
/**
|
|
1920
1921
|
* @typedef {{
|
|
1921
|
-
* readonly id:
|
|
1922
|
+
* readonly id: import("./ids.js").EntityId;
|
|
1922
1923
|
* readonly slug: string;
|
|
1923
1924
|
* readonly name: string;
|
|
1924
1925
|
* readonly logo_url?: string | null | undefined;
|
|
@@ -2033,7 +2034,7 @@ export class TsAuthInstanceClient {
|
|
|
2033
2034
|
|
|
2034
2035
|
/**
|
|
2035
2036
|
* @typedef {{
|
|
2036
|
-
* readonly client_id:
|
|
2037
|
+
* readonly client_id: import("./ids.js").EntityId;
|
|
2037
2038
|
* readonly redirect_uri: string;
|
|
2038
2039
|
* readonly response_type: "code";
|
|
2039
2040
|
* readonly scope?: string | undefined;
|
|
@@ -2108,20 +2109,20 @@ export class TsAuthInstanceClient {
|
|
|
2108
2109
|
* readonly active: true;
|
|
2109
2110
|
* readonly token_type: "Bearer";
|
|
2110
2111
|
* readonly iss: string;
|
|
2111
|
-
* readonly sub:
|
|
2112
|
+
* readonly sub: import("./ids.js").EntityId;
|
|
2112
2113
|
* readonly aud: string;
|
|
2113
|
-
* readonly client_id:
|
|
2114
|
+
* readonly client_id: import("./ids.js").EntityId;
|
|
2114
2115
|
* readonly scope: string;
|
|
2115
2116
|
* readonly exp: number;
|
|
2116
2117
|
* readonly iat: number;
|
|
2117
|
-
* readonly sid:
|
|
2118
|
+
* readonly sid: import("./ids.js").EntityId | null;
|
|
2118
2119
|
* readonly principal_kind: "user" | "service";
|
|
2119
2120
|
* }} TsAuthOidcAccessIntrospection
|
|
2120
2121
|
*/
|
|
2121
2122
|
/**
|
|
2122
2123
|
* @typedef {Omit<TsAuthOidcAccessIntrospection, "token_type" | "principal_kind"> & {
|
|
2123
2124
|
* readonly token_type: "refresh_token";
|
|
2124
|
-
* readonly family_id:
|
|
2125
|
+
* readonly family_id: import("./ids.js").EntityId;
|
|
2125
2126
|
* }} TsAuthOidcRefreshIntrospection
|
|
2126
2127
|
*/
|
|
2127
2128
|
/**
|
|
@@ -2132,7 +2133,7 @@ export class TsAuthInstanceClient {
|
|
|
2132
2133
|
/**
|
|
2133
2134
|
* @typedef {Omit<TsAuthOidcAccessIntrospection, "sid" | "principal_kind"> &
|
|
2134
2135
|
* (
|
|
2135
|
-
* | { readonly principal_kind: "user"; readonly sid:
|
|
2136
|
+
* | { readonly principal_kind: "user"; readonly sid: import("./ids.js").EntityId }
|
|
2136
2137
|
* | { readonly principal_kind: "service"; readonly sid: null }
|
|
2137
2138
|
* )} TsAuthOidcResourceAccessIntrospection
|
|
2138
2139
|
*/
|
|
@@ -2144,14 +2145,14 @@ export class TsAuthInstanceClient {
|
|
|
2144
2145
|
* @typedef {{
|
|
2145
2146
|
* readonly issuer: string; // Configured canonical provider issuer, independently trusted by the caller.
|
|
2146
2147
|
* readonly audience: string; // Exact registered resource URI; never derived from the response.
|
|
2147
|
-
* readonly introspection_client_id:
|
|
2148
|
+
* readonly introspection_client_id: import("./ids.js").EntityId;
|
|
2148
2149
|
* readonly introspection_secret: string;
|
|
2149
2150
|
* }} TsAuthOidcResourceCredentials
|
|
2150
2151
|
*/
|
|
2151
2152
|
|
|
2152
2153
|
/**
|
|
2153
2154
|
* @typedef {{
|
|
2154
|
-
* readonly sub:
|
|
2155
|
+
* readonly sub: import("./ids.js").EntityId;
|
|
2155
2156
|
* readonly email?: string | undefined;
|
|
2156
2157
|
* readonly email_verified?: boolean | undefined;
|
|
2157
2158
|
* readonly name?: string | undefined;
|
|
@@ -2358,7 +2359,6 @@ export class TsAuthOidcClient {
|
|
|
2358
2359
|
routeName: "tsauth.oidc.resourceIntrospect",
|
|
2359
2360
|
formBody: form,
|
|
2360
2361
|
resourceIntrospectionBasic: basic,
|
|
2361
|
-
issuer: expectedIssuer,
|
|
2362
2362
|
}),
|
|
2363
2363
|
/** @returns {value is TsAuthOidcResourceIntrospection} */
|
|
2364
2364
|
(value) => {
|
|
@@ -2518,9 +2518,7 @@ export class TsAuthClient {
|
|
|
2518
2518
|
);
|
|
2519
2519
|
}
|
|
2520
2520
|
const slug = validateInstanceSlug(config?.instanceSlug);
|
|
2521
|
-
this.#http = new TsAuthHttp(config
|
|
2522
|
-
authReverseProxy: config.useReverseProxy === true,
|
|
2523
|
-
});
|
|
2521
|
+
this.#http = new TsAuthHttp(config);
|
|
2524
2522
|
requireBareOrigin(this.#http.config.apiBaseUrl);
|
|
2525
2523
|
this.users = new TsAuthUsersClient(this.#http, slug);
|
|
2526
2524
|
this.sessions = new TsAuthSessionsClient(this.#http, slug);
|
|
@@ -2726,6 +2724,7 @@ const utf8Encoder = new TextEncoder();
|
|
|
2726
2724
|
* @returns {string}
|
|
2727
2725
|
*/
|
|
2728
2726
|
function segment(value, name) {
|
|
2727
|
+
if (name.endsWith(" id")) return requireId(value, name);
|
|
2729
2728
|
if (
|
|
2730
2729
|
typeof value !== "string" ||
|
|
2731
2730
|
value.length === 0 ||
|
|
@@ -2840,7 +2839,7 @@ function validateJwtTemplateClaims(claims) {
|
|
|
2840
2839
|
*/
|
|
2841
2840
|
function clientCredentialForm(clientId, clientSecret) {
|
|
2842
2841
|
return new URLSearchParams({
|
|
2843
|
-
client_id:
|
|
2842
|
+
client_id: requireId(clientId, "clientId"),
|
|
2844
2843
|
client_secret: requireText(clientSecret, "clientSecret"),
|
|
2845
2844
|
});
|
|
2846
2845
|
}
|
|
@@ -3166,7 +3165,7 @@ function validateOauthResourceRequest(request, update) {
|
|
|
3166
3165
|
]);
|
|
3167
3166
|
if (!update) requireResourceAudience(request.audience);
|
|
3168
3167
|
for (const [field, accepts] of /** @type {const} */ ([
|
|
3169
|
-
["allowed_client_ids",
|
|
3168
|
+
["allowed_client_ids", isValidId],
|
|
3170
3169
|
["allowed_grant_types", oauthGrant],
|
|
3171
3170
|
["allowed_scopes", oauthScopeToken],
|
|
3172
3171
|
])) {
|
|
@@ -3198,7 +3197,7 @@ function validateAuthorizationRequest(request) {
|
|
|
3198
3197
|
"code_challenge_method",
|
|
3199
3198
|
"prompt",
|
|
3200
3199
|
]);
|
|
3201
|
-
|
|
3200
|
+
requireId(request.client_id, "client_id");
|
|
3202
3201
|
requireText(request.redirect_uri, "redirect_uri");
|
|
3203
3202
|
if (request.response_type !== "code")
|
|
3204
3203
|
throw new TypeError("response_type must be code.");
|
|
@@ -3227,7 +3226,8 @@ function validateAuthorizationRequest(request) {
|
|
|
3227
3226
|
* @returns {string}
|
|
3228
3227
|
*/
|
|
3229
3228
|
function resourceBasic(clientId, secret) {
|
|
3230
|
-
|
|
3229
|
+
requireId(clientId, "introspection_client_id");
|
|
3230
|
+
if (!oauthText(secret))
|
|
3231
3231
|
throw new TypeError(
|
|
3232
3232
|
"Resource introspection credentials must be nonempty well-formed text.",
|
|
3233
3233
|
);
|
|
@@ -3264,7 +3264,7 @@ const clientViewFields = [
|
|
|
3264
3264
|
function isOauthClientView(value) {
|
|
3265
3265
|
return (
|
|
3266
3266
|
exactOauthFields(value, clientViewFields) &&
|
|
3267
|
-
|
|
3267
|
+
isValidId(value.id) && isValidId(value.client_id) && oauthText(value.name) &&
|
|
3268
3268
|
[
|
|
3269
3269
|
value.redirect_uris,
|
|
3270
3270
|
value.post_logout_redirect_uris,
|
|
@@ -3324,12 +3324,12 @@ const resourceViewFields = [
|
|
|
3324
3324
|
function isOauthResourceView(value) {
|
|
3325
3325
|
return (
|
|
3326
3326
|
exactOauthFields(value, resourceViewFields) &&
|
|
3327
|
-
|
|
3327
|
+
isValidId(value.id) &&
|
|
3328
3328
|
validResourceAudience(value.audience) &&
|
|
3329
|
-
|
|
3329
|
+
Array.isArray(value.allowed_client_ids) && value.allowed_client_ids.every(isValidId) &&
|
|
3330
3330
|
oauthGrantsList(value.allowed_grant_types) &&
|
|
3331
3331
|
oauthStrings(value.allowed_scopes) &&
|
|
3332
|
-
|
|
3332
|
+
isValidId(value.introspection_client_id) &&
|
|
3333
3333
|
value.token_endpoint_auth_method === "client_secret_basic" &&
|
|
3334
3334
|
exactUnsignedInteger(value.auth_epoch) &&
|
|
3335
3335
|
typeof value.enabled === "boolean" &&
|
|
@@ -3442,13 +3442,13 @@ function isAccessIntrospection(value) {
|
|
|
3442
3442
|
exactOauthFields(value, [...introspectionFields, "principal_kind"]) &&
|
|
3443
3443
|
value.active === true &&
|
|
3444
3444
|
value.token_type === "Bearer" &&
|
|
3445
|
-
[value.iss, value.
|
|
3445
|
+
[value.iss, value.aud].every(oauthText) && [value.sub, value.client_id].every(isValidId) &&
|
|
3446
3446
|
typeof value.scope === "string" &&
|
|
3447
3447
|
exactUnsignedInteger(value.exp) &&
|
|
3448
3448
|
exactUnsignedInteger(value.iat) &&
|
|
3449
3449
|
value.exp > value.iat &&
|
|
3450
3450
|
((value.principal_kind === "user" &&
|
|
3451
|
-
(value.sid === null ||
|
|
3451
|
+
(value.sid === null || isValidId(value.sid))) ||
|
|
3452
3452
|
(value.principal_kind === "service" &&
|
|
3453
3453
|
value.sid === null &&
|
|
3454
3454
|
value.sub === value.client_id))
|
|
@@ -3462,7 +3462,7 @@ function isResourceAccessIntrospection(value) {
|
|
|
3462
3462
|
return (
|
|
3463
3463
|
isAccessIntrospection(value) &&
|
|
3464
3464
|
(value.principal_kind === "user"
|
|
3465
|
-
?
|
|
3465
|
+
? isValidId(value.sid)
|
|
3466
3466
|
: value.sid === null && value.sub === value.client_id)
|
|
3467
3467
|
);
|
|
3468
3468
|
}
|
|
@@ -3475,14 +3475,12 @@ function isRefreshIntrospection(value) {
|
|
|
3475
3475
|
exactOauthFields(value, [...introspectionFields, "family_id"]) &&
|
|
3476
3476
|
value.active === true &&
|
|
3477
3477
|
value.token_type === "refresh_token" &&
|
|
3478
|
-
[value.iss, value.
|
|
3479
|
-
oauthText,
|
|
3480
|
-
) &&
|
|
3478
|
+
[value.iss, value.aud].every(oauthText) && [value.sub, value.client_id, value.family_id].every(isValidId) &&
|
|
3481
3479
|
typeof value.scope === "string" &&
|
|
3482
3480
|
exactUnsignedInteger(value.exp) &&
|
|
3483
3481
|
exactUnsignedInteger(value.iat) &&
|
|
3484
3482
|
value.exp > value.iat &&
|
|
3485
|
-
(value.sid === null ||
|
|
3483
|
+
(value.sid === null || isValidId(value.sid))
|
|
3486
3484
|
);
|
|
3487
3485
|
}
|
|
3488
3486
|
/**
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { requireId } from "../ids.js";
|
|
2
|
+
import { requireName } from "./ids.js";
|
|
3
|
+
import { flag, list, nullable, numeric, optional, record, text } from "./management-decode.js";
|
|
4
|
+
import { members, mutationOptions, pageQuery } from "./management-validation.js";
|
|
5
|
+
import { malformed, object } from "./decode.js";
|
|
6
|
+
import { stringifyExactJson } from "./json.js";
|
|
7
|
+
/** @import { V1Transport } from "./transport.js" */
|
|
8
|
+
/** @import { V1RequestOptions } from "./terrabase-v1.js" */
|
|
9
|
+
const backup = record({ id: requireId, databaseId: requireId, status: text, trigger: text, sizeBytes: numeric, createdAt: text });
|
|
10
|
+
const backupPage = record({ items: list(backup), next: nullable(text) });
|
|
11
|
+
const policy = record({ fullBackupCron: nullable(text), retentionDays: numeric, disabled: flag, updatedAt: nullable(text) });
|
|
12
|
+
const window = record({ earliest: text, latest: text });
|
|
13
|
+
const plan = record({ window, pointInTime: text, snapshotAt: text, latestSegmentAt: nullable(text), segmentCount: numeric, historyCheck: text });
|
|
14
|
+
const restored = record({ id: requireId, projectId: requireId, name: text, branchedFrom: nullable(requireId), createdAt: text,
|
|
15
|
+
homeRegion: optional(nullable(text)), replicaRegions: optional(nullable(list(text))), placementVersion: optional(numeric), replicas: list(text) });
|
|
16
|
+
const destination = record({ endpoint: text, region: text, bucket: text, mode: text, updatedAt: text });
|
|
17
|
+
/** @typedef {ReturnType<typeof backup>} V1Backup */
|
|
18
|
+
/** @typedef {ReturnType<typeof backupPage>} V1BackupPage */
|
|
19
|
+
/** @typedef {ReturnType<typeof policy>} V1BackupPolicy */
|
|
20
|
+
/** @typedef {ReturnType<typeof window>} V1RestoreWindow */
|
|
21
|
+
/** @typedef {ReturnType<typeof plan>} V1PointInTimePlan */
|
|
22
|
+
/** @typedef {ReturnType<typeof restored>} V1RestoredDatabase */
|
|
23
|
+
/** @typedef {ReturnType<typeof destination>} V1BackupDestination */
|
|
24
|
+
/** @typedef {{ readonly fullBackupCron?: string | null; readonly retentionDays?: number | null; readonly disabled?: boolean | null }} V1BackupPolicyRequest */
|
|
25
|
+
/** @typedef {{ readonly pointInTime: string; readonly destination?: "platform" | "customer" | null }} V1PointInTimeRequest */
|
|
26
|
+
/** @typedef {V1PointInTimeRequest & { readonly name?: string | null }} V1PointInTimeRestoreRequest */
|
|
27
|
+
/** @typedef {{ readonly endpoint: string; readonly region: string; readonly bucket: string; readonly accessKeyId: string; readonly secretKey: string; readonly mode: "both" | "customer" }} V1BackupDestinationRequest */
|
|
28
|
+
/** @param {unknown} value @returns {"platform" | "customer"} */
|
|
29
|
+
function source(value) {
|
|
30
|
+
if (value !== "platform" && value !== "customer") throw new TypeError("destination must be platform or customer.");
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
/** @param {V1PointInTimeRequest} request */
|
|
34
|
+
function pointInTime(request) {
|
|
35
|
+
if (typeof request.pointInTime !== "string" || !Number.isFinite(Date.parse(request.pointInTime))) throw new TypeError("pointInTime must be an RFC 3339 instant.");
|
|
36
|
+
if (request.destination !== undefined && request.destination !== null) source(request.destination);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Backups and explicit point-in-time restore sources for one database. */
|
|
40
|
+
export class V1Backups {
|
|
41
|
+
/** @type {V1Transport} */
|
|
42
|
+
#transport;
|
|
43
|
+
/** @type {{database: string}} */
|
|
44
|
+
#params;
|
|
45
|
+
/** @param {V1Transport} transport @param {string} database */
|
|
46
|
+
constructor(transport, database) { this.#transport = transport; this.#params = { database: requireName("database", database) }; Object.freeze(this); }
|
|
47
|
+
/** @param {V1RequestOptions} [options] @returns {Promise<V1Backup>} */
|
|
48
|
+
async create(options = {}) {
|
|
49
|
+
mutationOptions(options);
|
|
50
|
+
return backup((await this.#transport.call("createBackup", this.#params, { signal: options.signal })).value);
|
|
51
|
+
}
|
|
52
|
+
/** @param {import("./catalog.js").V1DatabaseListRequest} [request] @param {V1RequestOptions} [options] @returns {Promise<V1BackupPage>} */
|
|
53
|
+
async list(request = {}, options = {}) { return backupPage((await this.#transport.call("listBackups", this.#params, { query: pageQuery(request), signal: options.signal })).value); }
|
|
54
|
+
/** @param {string} id @param {{readonly name?: string | null}} [request] @param {V1RequestOptions} [options] @returns {Promise<V1RestoredDatabase>} */
|
|
55
|
+
async restore(id, request = {}, options = {}) {
|
|
56
|
+
members(request, ["name"]);
|
|
57
|
+
if (request.name !== undefined && request.name !== null) requireName("database", request.name);
|
|
58
|
+
mutationOptions(options);
|
|
59
|
+
return restored((await this.#transport.call("restoreBackup", { ...this.#params, backup: requireId(id) }, {
|
|
60
|
+
body: stringifyExactJson(request, "restore"), signal: options.signal,
|
|
61
|
+
})).value);
|
|
62
|
+
}
|
|
63
|
+
/** @param {V1RequestOptions} [options] @returns {Promise<V1BackupPolicy>} */
|
|
64
|
+
async getPolicy(options = {}) { return policy((await this.#transport.call("getBackupPolicy", this.#params, { signal: options.signal })).value); }
|
|
65
|
+
/** @param {V1BackupPolicyRequest} request @param {V1RequestOptions} [options] @returns {Promise<V1BackupPolicy>} */
|
|
66
|
+
async setPolicy(request, options = {}) {
|
|
67
|
+
members(request, ["fullBackupCron", "retentionDays", "disabled"]);
|
|
68
|
+
mutationOptions(options);
|
|
69
|
+
return policy((await this.#transport.call("setBackupPolicy", this.#params, { body: stringifyExactJson(request, "backup policy"), signal: options.signal })).value);
|
|
70
|
+
}
|
|
71
|
+
/** @param {{readonly destination?: "platform" | "customer"}} [request] @param {V1RequestOptions} [options] @returns {Promise<V1RestoreWindow>} */
|
|
72
|
+
async window(request = {}, options = {}) {
|
|
73
|
+
members(request, ["destination"]);
|
|
74
|
+
const query = new URLSearchParams();
|
|
75
|
+
if (request.destination !== undefined) query.set("destination", source(request.destination));
|
|
76
|
+
return window((await this.#transport.call("getRestoreWindow", this.#params, { query, signal: options.signal })).value);
|
|
77
|
+
}
|
|
78
|
+
/** @param {V1PointInTimeRequest} request @param {V1RequestOptions} [options] @returns {Promise<V1PointInTimePlan>} */
|
|
79
|
+
async plan(request, options = {}) {
|
|
80
|
+
members(request, ["pointInTime", "destination"]);
|
|
81
|
+
pointInTime(request);
|
|
82
|
+
return plan((await this.#transport.call("planPointInTime", this.#params, { body: stringifyExactJson(request, "restore plan"), signal: options.signal })).value);
|
|
83
|
+
}
|
|
84
|
+
/** @param {V1PointInTimeRestoreRequest} request @param {V1RequestOptions} [options] @returns {Promise<V1RestoredDatabase>} */
|
|
85
|
+
async restorePointInTime(request, options = {}) {
|
|
86
|
+
members(request, ["pointInTime", "destination", "name"]);
|
|
87
|
+
pointInTime(request);
|
|
88
|
+
if (request.name !== undefined && request.name !== null) requireName("database", request.name);
|
|
89
|
+
mutationOptions(options);
|
|
90
|
+
return restored((await this.#transport.call("restorePointInTime", this.#params, { body: stringifyExactJson(request, "point-in-time restore"), signal: options.signal })).value);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/** Write-only destination credentials are sent only to the configured API, never retained in the client. */
|
|
94
|
+
export class V1BackupDestinationClient {
|
|
95
|
+
/** @type {V1Transport} */
|
|
96
|
+
#transport;
|
|
97
|
+
/** @param {V1Transport} transport */
|
|
98
|
+
constructor(transport) { this.#transport = transport; Object.freeze(this); }
|
|
99
|
+
/** @param {V1RequestOptions} [options] @returns {Promise<V1BackupDestination>} */
|
|
100
|
+
async get(options = {}) { return destination((await this.#transport.call("getBackupDestination", {}, { signal: options.signal })).value); }
|
|
101
|
+
/** @param {V1BackupDestinationRequest} request @param {V1RequestOptions} [options] @returns {Promise<V1BackupDestination>} */
|
|
102
|
+
async set(request, options = {}) {
|
|
103
|
+
members(request, ["endpoint", "region", "bucket", "accessKeyId", "secretKey", "mode"]);
|
|
104
|
+
mutationOptions(options);
|
|
105
|
+
const raw = object((await this.#transport.call("setBackupDestination", {}, { body: stringifyExactJson(request, "backup destination"), signal: options.signal })).value, "backup destination");
|
|
106
|
+
if (raw.accessKeyId !== undefined || raw.secretKey !== undefined) malformed("write-only destination credentials");
|
|
107
|
+
return destination(raw);
|
|
108
|
+
}
|
|
109
|
+
/** @param {V1RequestOptions} [options] @returns {Promise<void>} */
|
|
110
|
+
async delete(options = {}) { mutationOptions(options); await this.#transport.call("deleteBackupDestination", {}, { signal: options.signal }); }
|
|
111
|
+
}
|