@vectros-ai/mcp-server 0.12.0 → 0.14.0
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 +46 -0
- package/README.md +2 -2
- package/dist/cli-http.js +551 -36
- package/dist/cli-http.js.map +1 -1
- package/dist/cli-http.mjs +551 -36
- package/dist/cli-http.mjs.map +1 -1
- package/dist/cli.js +551 -36
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +551 -36
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +551 -36
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +551 -36
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/cli-http.mjs
CHANGED
|
@@ -64,6 +64,7 @@ __export(api_exports, {
|
|
|
64
64
|
TooManyRequestsError: () => TooManyRequestsError,
|
|
65
65
|
TruncationWarningEvent: () => TruncationWarningEvent,
|
|
66
66
|
UnauthorizedError: () => UnauthorizedError,
|
|
67
|
+
UserExistsResponse: () => UserExistsResponse,
|
|
67
68
|
UserRequest: () => UserRequest,
|
|
68
69
|
UserResponse: () => UserResponse,
|
|
69
70
|
auth: () => auth_exports,
|
|
@@ -740,6 +741,14 @@ var TruncationWarningEvent;
|
|
|
740
741
|
ContextWindowBudget: "context_window_budget"
|
|
741
742
|
};
|
|
742
743
|
})(TruncationWarningEvent || (TruncationWarningEvent = {}));
|
|
744
|
+
var UserExistsResponse;
|
|
745
|
+
((UserExistsResponse2) => {
|
|
746
|
+
UserExistsResponse2.Status = {
|
|
747
|
+
Active: "ACTIVE",
|
|
748
|
+
Suspended: "SUSPENDED",
|
|
749
|
+
Pending: "PENDING"
|
|
750
|
+
};
|
|
751
|
+
})(UserExistsResponse || (UserExistsResponse = {}));
|
|
743
752
|
var UserRequest;
|
|
744
753
|
((UserRequest2) => {
|
|
745
754
|
UserRequest2.Status = {
|
|
@@ -2432,7 +2441,7 @@ var AuthClient = class {
|
|
|
2432
2441
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/admin/access-log");
|
|
2433
2442
|
}
|
|
2434
2443
|
/**
|
|
2435
|
-
* Lists
|
|
2444
|
+
* Lists your scoped API keys (`ssk_*`) in your credential's own environment — a live key lists live keys, a test key lists test keys. Revoked keys are excluded. Requires the `keys:r` scope.
|
|
2436
2445
|
*
|
|
2437
2446
|
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
2438
2447
|
*
|
|
@@ -2483,7 +2492,7 @@ var AuthClient = class {
|
|
|
2483
2492
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/admin/keys/scoped");
|
|
2484
2493
|
}
|
|
2485
2494
|
/**
|
|
2486
|
-
* Creates a scoped API key (an `ssk_*` secret) that inherits its permissions from an existing access profile in your account. The call is idempotent on the combination of tenant, context, user, and key name: re-issuing the same request returns the existing key WITHOUT re-disclosing its raw secret. The raw key is returned ONLY in this response — store it securely, as it cannot be retrieved again. Requires the `keys:c` scope.
|
|
2495
|
+
* Creates a scoped API key (an `ssk_*` secret) that inherits its permissions from an existing access profile in your account. The call is idempotent on the combination of tenant, context, user, and key name: re-issuing the same request returns the existing key WITHOUT re-disclosing its raw secret. The raw key is returned ONLY in this response — store it securely, as it cannot be retrieved again. Requires the `keys:c` scope. If you use a scoped credential, `keys:c` alone is not sufficient: because the minted key is durably bound to the profile you name, the profile's effective scopes may not exceed your own, and you may only mint against a profile whose `identityOverrides` values your own identity holds. A root API key (`sk_`) is exempt from both bounds.
|
|
2487
2496
|
*
|
|
2488
2497
|
* @param {Vectros.CreateScopedKeyRequest} request
|
|
2489
2498
|
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -2815,7 +2824,7 @@ var AuthClient = class {
|
|
|
2815
2824
|
);
|
|
2816
2825
|
}
|
|
2817
2826
|
/**
|
|
2818
|
-
* Creates a new access profile under the given app context. This call is idempotent by `principalId`: if a profile with the same `principalId` already exists, the existing profile is returned (with status 200) instead of creating a duplicate. The response's `created` field (and the HTTP status — 201 when created, 200 when an existing profile was returned) tells the two apart. To overwrite an existing profile's `scopes`/`roleId`, `identityOverrides`, and `status` instead of returning it unchanged, set `?upsert=true` (this also requires the `profiles:u` scope). You must provide exactly one of `scopes` (an inline list of scopes) or `roleId` (a reference to a role); supplying both, or neither, is rejected. `identityOverrides` is keyed by ownership namespace in `scope:<namespace>` form — `scope:org` and `scope:client` for the reserved namespaces, or any namespace you have registered — and may name at most two; any other key (including the account identifier or `userId`) is rejected. If you use a scoped credential, the profile's effective scopes may not exceed your own; a root API key (`sk_`) is exempt. Requires the `profiles:c` scope.
|
|
2827
|
+
* Creates a new access profile under the given app context. This call is idempotent by `principalId`: if a profile with the same `principalId` already exists, the existing profile is returned (with status 200) instead of creating a duplicate. The response's `created` field (and the HTTP status — 201 when created, 200 when an existing profile was returned) tells the two apart. To overwrite an existing profile's `scopes`/`roleId`, `identityOverrides`, and `status` instead of returning it unchanged, set `?upsert=true` (this also requires the `profiles:u` scope, and applies the same `identityOverrides` bounds the update endpoint documents — a scoped credential may not repoint or clear an identity value it does not itself hold). You must provide exactly one of `scopes` (an inline list of scopes) or `roleId` (a reference to a role); supplying both, or neither, is rejected. `identityOverrides` is keyed by ownership namespace in `scope:<namespace>` form — `scope:org` and `scope:client` for the reserved namespaces, or any namespace you have registered — and may name at most two; any other key (including the account identifier or `userId`) is rejected. If you use a scoped credential, the profile's effective scopes may not exceed your own; a root API key (`sk_`) is exempt. Requires the `profiles:c` scope.
|
|
2819
2828
|
*
|
|
2820
2829
|
* @param {Vectros.CreateAccessProfileRequest} request
|
|
2821
2830
|
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -3233,11 +3242,12 @@ var AuthClient = class {
|
|
|
3233
3242
|
);
|
|
3234
3243
|
}
|
|
3235
3244
|
/**
|
|
3236
|
-
* Updates an access profile. This is a partial update: any field you omit (or send as null) keeps its existing value. A profile must reference either inline `scopes` or a `roleId`, never both — so setting `scopes` clears any `roleId`, and setting `roleId` clears any inline `scopes`. The `contextId` and `principalId` are immutable. Status changes (for example active to suspended) take effect within about five minutes. If you use a scoped credential, the profile's effective scopes may not exceed your own
|
|
3245
|
+
* Updates an access profile. This is a partial update: any field you omit (or send as null) keeps its existing value. A profile must reference either inline `scopes` or a `roleId`, never both — so setting `scopes` clears any `roleId`, and setting `roleId` clears any inline `scopes`. The `contextId` and `principalId` are immutable. Status changes (for example active to suspended) take effect within about five minutes. If you use a scoped credential, the profile's effective scopes may not exceed your own, and its `identityOverrides` are bounded twice: you may only set a value your own identity holds, and you may only change or clear a value the profile already holds if that value is yours as well. Repointing or clearing another principal's established identity therefore returns 403. A root API key (`sk_`) is exempt. If you set `roleId`, it must reference a role that already exists in this context. Requires the `profiles:u` scope.
|
|
3237
3246
|
*
|
|
3238
3247
|
* @param {Vectros.UpdateAccessProfileRequest} request
|
|
3239
3248
|
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
3240
3249
|
*
|
|
3250
|
+
* @throws {@link Vectros.BadRequestError}
|
|
3241
3251
|
* @throws {@link Vectros.ForbiddenError}
|
|
3242
3252
|
* @throws {@link Vectros.NotFoundError}
|
|
3243
3253
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
@@ -3284,6 +3294,8 @@ var AuthClient = class {
|
|
|
3284
3294
|
}
|
|
3285
3295
|
if (_response.error.reason === "status-code") {
|
|
3286
3296
|
switch (_response.error.statusCode) {
|
|
3297
|
+
case 400:
|
|
3298
|
+
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
3287
3299
|
case 403:
|
|
3288
3300
|
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
3289
3301
|
case 404:
|
|
@@ -3306,7 +3318,7 @@ var AuthClient = class {
|
|
|
3306
3318
|
);
|
|
3307
3319
|
}
|
|
3308
3320
|
/**
|
|
3309
|
-
* Deletes an access profile. Within about five minutes (the access-profile cache lifetime), token minting for this principal in this context will be denied. Requires the `profiles:d` scope.
|
|
3321
|
+
* Deletes an access profile. Within about five minutes (the access-profile cache lifetime), token minting for this principal in this context will be denied. If you use a scoped credential and the profile carries `identityOverrides`, you may only delete it when you hold those values yourself — deleting a profile removes its identity, so the same bound applies as when clearing it. A profile with no `identityOverrides` is unaffected, and a root API key (`sk_`) is exempt. Requires the `profiles:d` scope.
|
|
3310
3322
|
*
|
|
3311
3323
|
* @param {Vectros.DeleteAccessProfileRequest} request
|
|
3312
3324
|
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -3975,6 +3987,254 @@ var AuthClient = class {
|
|
|
3975
3987
|
}
|
|
3976
3988
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/usage");
|
|
3977
3989
|
}
|
|
3990
|
+
/**
|
|
3991
|
+
* Retrieves a single registered issuer by issuerId. Requires a root API key or the bootstrap's provisioning capability.
|
|
3992
|
+
*
|
|
3993
|
+
* @param {Vectros.GetIssuerRequest} request
|
|
3994
|
+
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
3995
|
+
*
|
|
3996
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
3997
|
+
* @throws {@link Vectros.NotFoundError}
|
|
3998
|
+
*
|
|
3999
|
+
* @example
|
|
4000
|
+
* await client.auth.getIssuer({
|
|
4001
|
+
* issuerId: "auth0-prod"
|
|
4002
|
+
* })
|
|
4003
|
+
*/
|
|
4004
|
+
getIssuer(request, requestOptions) {
|
|
4005
|
+
return HttpResponsePromise.fromPromise(this.__getIssuer(request, requestOptions));
|
|
4006
|
+
}
|
|
4007
|
+
async __getIssuer(request, requestOptions) {
|
|
4008
|
+
const { issuerId } = request;
|
|
4009
|
+
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
4010
|
+
const _headers = mergeHeaders(
|
|
4011
|
+
_authRequest.headers,
|
|
4012
|
+
this._options?.headers,
|
|
4013
|
+
requestOptions?.headers
|
|
4014
|
+
);
|
|
4015
|
+
const _response = await fetcher({
|
|
4016
|
+
url: url_exports.join(
|
|
4017
|
+
await Supplier.get(this._options.baseUrl) ?? await Supplier.get(this._options.environment),
|
|
4018
|
+
`v1/auth/issuers/${url_exports.encodePathParam(issuerId)}`
|
|
4019
|
+
),
|
|
4020
|
+
method: "GET",
|
|
4021
|
+
headers: _headers,
|
|
4022
|
+
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
4023
|
+
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
4024
|
+
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
4025
|
+
abortSignal: requestOptions?.abortSignal,
|
|
4026
|
+
fetchFn: this._options?.fetch,
|
|
4027
|
+
logging: this._options.logging
|
|
4028
|
+
});
|
|
4029
|
+
if (_response.ok) {
|
|
4030
|
+
return { data: _response.body, rawResponse: _response.rawResponse };
|
|
4031
|
+
}
|
|
4032
|
+
if (_response.error.reason === "status-code") {
|
|
4033
|
+
switch (_response.error.statusCode) {
|
|
4034
|
+
case 403:
|
|
4035
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
4036
|
+
case 404:
|
|
4037
|
+
throw new NotFoundError(_response.error.body, _response.rawResponse);
|
|
4038
|
+
default:
|
|
4039
|
+
throw new VectrosError({
|
|
4040
|
+
statusCode: _response.error.statusCode,
|
|
4041
|
+
body: _response.error.body,
|
|
4042
|
+
rawResponse: _response.rawResponse
|
|
4043
|
+
});
|
|
4044
|
+
}
|
|
4045
|
+
}
|
|
4046
|
+
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/auth/issuers/{issuerId}");
|
|
4047
|
+
}
|
|
4048
|
+
/**
|
|
4049
|
+
* Deregisters a trusted third-party IdP issuer. Requires a root API key or the bootstrap's provisioning capability. Unconditional — unlike some other registry deletes on this API, this does not check for or block on any downstream reference. Any user account already created via this issuer (by a prior self-signup or accepted invite) is NOT deleted or modified, but that user can no longer obtain a NEW token this way once you deregister the issuer — every `POST /v1/auth/token/exchange` call against it will 404, with no distinction between an unknown issuer and one you just deregistered. Register a replacement issuer, or restore this one, before your users' current tokens expire if you want their access to continue uninterrupted.
|
|
4050
|
+
*
|
|
4051
|
+
* @param {Vectros.DeleteIssuerRequest} request
|
|
4052
|
+
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
4053
|
+
*
|
|
4054
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
4055
|
+
* @throws {@link Vectros.NotFoundError}
|
|
4056
|
+
* @throws {@link Vectros.TooManyRequestsError}
|
|
4057
|
+
*
|
|
4058
|
+
* @example
|
|
4059
|
+
* await client.auth.deleteIssuer({
|
|
4060
|
+
* issuerId: "auth0-prod"
|
|
4061
|
+
* })
|
|
4062
|
+
*/
|
|
4063
|
+
deleteIssuer(request, requestOptions) {
|
|
4064
|
+
return HttpResponsePromise.fromPromise(this.__deleteIssuer(request, requestOptions));
|
|
4065
|
+
}
|
|
4066
|
+
async __deleteIssuer(request, requestOptions) {
|
|
4067
|
+
const { issuerId } = request;
|
|
4068
|
+
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
4069
|
+
const _headers = mergeHeaders(
|
|
4070
|
+
_authRequest.headers,
|
|
4071
|
+
this._options?.headers,
|
|
4072
|
+
requestOptions?.headers
|
|
4073
|
+
);
|
|
4074
|
+
const _response = await fetcher({
|
|
4075
|
+
url: url_exports.join(
|
|
4076
|
+
await Supplier.get(this._options.baseUrl) ?? await Supplier.get(this._options.environment),
|
|
4077
|
+
`v1/auth/issuers/${url_exports.encodePathParam(issuerId)}`
|
|
4078
|
+
),
|
|
4079
|
+
method: "DELETE",
|
|
4080
|
+
headers: _headers,
|
|
4081
|
+
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
4082
|
+
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
4083
|
+
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
4084
|
+
abortSignal: requestOptions?.abortSignal,
|
|
4085
|
+
fetchFn: this._options?.fetch,
|
|
4086
|
+
logging: this._options.logging
|
|
4087
|
+
});
|
|
4088
|
+
if (_response.ok) {
|
|
4089
|
+
return { data: void 0, rawResponse: _response.rawResponse };
|
|
4090
|
+
}
|
|
4091
|
+
if (_response.error.reason === "status-code") {
|
|
4092
|
+
switch (_response.error.statusCode) {
|
|
4093
|
+
case 403:
|
|
4094
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
4095
|
+
case 404:
|
|
4096
|
+
throw new NotFoundError(_response.error.body, _response.rawResponse);
|
|
4097
|
+
case 429:
|
|
4098
|
+
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
4099
|
+
default:
|
|
4100
|
+
throw new VectrosError({
|
|
4101
|
+
statusCode: _response.error.statusCode,
|
|
4102
|
+
body: _response.error.body,
|
|
4103
|
+
rawResponse: _response.rawResponse
|
|
4104
|
+
});
|
|
4105
|
+
}
|
|
4106
|
+
}
|
|
4107
|
+
return handleNonStatusCodeError(
|
|
4108
|
+
_response.error,
|
|
4109
|
+
_response.rawResponse,
|
|
4110
|
+
"DELETE",
|
|
4111
|
+
"/v1/auth/issuers/{issuerId}"
|
|
4112
|
+
);
|
|
4113
|
+
}
|
|
4114
|
+
/**
|
|
4115
|
+
* Returns the issuers registered in your tenant. Requires a root API key or the bootstrap's provisioning capability. Returns a `{data, nextCursor}` envelope.
|
|
4116
|
+
*
|
|
4117
|
+
* @param {Vectros.ListIssuersRequest} request
|
|
4118
|
+
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
4119
|
+
*
|
|
4120
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
4121
|
+
*
|
|
4122
|
+
* @example
|
|
4123
|
+
* await client.auth.listIssuers()
|
|
4124
|
+
*/
|
|
4125
|
+
listIssuers(request = {}, requestOptions) {
|
|
4126
|
+
return HttpResponsePromise.fromPromise(this.__listIssuers(request, requestOptions));
|
|
4127
|
+
}
|
|
4128
|
+
async __listIssuers(request = {}, requestOptions) {
|
|
4129
|
+
const { startFrom, limit } = request;
|
|
4130
|
+
const _queryParams = {
|
|
4131
|
+
startFrom,
|
|
4132
|
+
limit
|
|
4133
|
+
};
|
|
4134
|
+
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
4135
|
+
const _headers = mergeHeaders(
|
|
4136
|
+
_authRequest.headers,
|
|
4137
|
+
this._options?.headers,
|
|
4138
|
+
requestOptions?.headers
|
|
4139
|
+
);
|
|
4140
|
+
const _response = await fetcher({
|
|
4141
|
+
url: url_exports.join(
|
|
4142
|
+
await Supplier.get(this._options.baseUrl) ?? await Supplier.get(this._options.environment),
|
|
4143
|
+
"v1/auth/issuers"
|
|
4144
|
+
),
|
|
4145
|
+
method: "GET",
|
|
4146
|
+
headers: _headers,
|
|
4147
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
4148
|
+
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
4149
|
+
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
4150
|
+
abortSignal: requestOptions?.abortSignal,
|
|
4151
|
+
fetchFn: this._options?.fetch,
|
|
4152
|
+
logging: this._options.logging
|
|
4153
|
+
});
|
|
4154
|
+
if (_response.ok) {
|
|
4155
|
+
return { data: _response.body, rawResponse: _response.rawResponse };
|
|
4156
|
+
}
|
|
4157
|
+
if (_response.error.reason === "status-code") {
|
|
4158
|
+
switch (_response.error.statusCode) {
|
|
4159
|
+
case 403:
|
|
4160
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
4161
|
+
default:
|
|
4162
|
+
throw new VectrosError({
|
|
4163
|
+
statusCode: _response.error.statusCode,
|
|
4164
|
+
body: _response.error.body,
|
|
4165
|
+
rawResponse: _response.rawResponse
|
|
4166
|
+
});
|
|
4167
|
+
}
|
|
4168
|
+
}
|
|
4169
|
+
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/auth/issuers");
|
|
4170
|
+
}
|
|
4171
|
+
/**
|
|
4172
|
+
* Registers a trusted third-party IdP issuer that BYO-IdP token exchange (`POST /v1/auth/token/exchange`) may accept a `subject_token` from. Requires a root API key or the CLI bootstrap's provisioning capability — never an ordinary partner-grantable scope. Idempotent by `issuerId` within your tenant; the `(issuer, audience)` pair must not already be registered by a different issuerId/tenant.
|
|
4173
|
+
*
|
|
4174
|
+
* @param {Vectros.IssuerRequest} request
|
|
4175
|
+
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
4176
|
+
*
|
|
4177
|
+
* @throws {@link Vectros.BadRequestError}
|
|
4178
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
4179
|
+
* @throws {@link Vectros.TooManyRequestsError}
|
|
4180
|
+
*
|
|
4181
|
+
* @example
|
|
4182
|
+
* await client.auth.registerIssuer({
|
|
4183
|
+
* issuerId: "auth0-prod",
|
|
4184
|
+
* issuer: "https://your-tenant.us.auth0.com/",
|
|
4185
|
+
* jwksUri: "https://your-tenant.us.auth0.com/.well-known/jwks.json",
|
|
4186
|
+
* audience: "https://api.your-app.example.com",
|
|
4187
|
+
* contextId: "casework"
|
|
4188
|
+
* })
|
|
4189
|
+
*/
|
|
4190
|
+
registerIssuer(request, requestOptions) {
|
|
4191
|
+
return HttpResponsePromise.fromPromise(this.__registerIssuer(request, requestOptions));
|
|
4192
|
+
}
|
|
4193
|
+
async __registerIssuer(request, requestOptions) {
|
|
4194
|
+
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
4195
|
+
const _headers = mergeHeaders(
|
|
4196
|
+
_authRequest.headers,
|
|
4197
|
+
this._options?.headers,
|
|
4198
|
+
requestOptions?.headers
|
|
4199
|
+
);
|
|
4200
|
+
const _response = await fetcher({
|
|
4201
|
+
url: url_exports.join(
|
|
4202
|
+
await Supplier.get(this._options.baseUrl) ?? await Supplier.get(this._options.environment),
|
|
4203
|
+
"v1/auth/issuers"
|
|
4204
|
+
),
|
|
4205
|
+
method: "POST",
|
|
4206
|
+
headers: _headers,
|
|
4207
|
+
contentType: "application/json",
|
|
4208
|
+
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
4209
|
+
requestType: "json",
|
|
4210
|
+
body: request,
|
|
4211
|
+
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
4212
|
+
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
4213
|
+
abortSignal: requestOptions?.abortSignal,
|
|
4214
|
+
fetchFn: this._options?.fetch,
|
|
4215
|
+
logging: this._options.logging
|
|
4216
|
+
});
|
|
4217
|
+
if (_response.ok) {
|
|
4218
|
+
return { data: _response.body, rawResponse: _response.rawResponse };
|
|
4219
|
+
}
|
|
4220
|
+
if (_response.error.reason === "status-code") {
|
|
4221
|
+
switch (_response.error.statusCode) {
|
|
4222
|
+
case 400:
|
|
4223
|
+
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
4224
|
+
case 403:
|
|
4225
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
4226
|
+
case 429:
|
|
4227
|
+
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
4228
|
+
default:
|
|
4229
|
+
throw new VectrosError({
|
|
4230
|
+
statusCode: _response.error.statusCode,
|
|
4231
|
+
body: _response.error.body,
|
|
4232
|
+
rawResponse: _response.rawResponse
|
|
4233
|
+
});
|
|
4234
|
+
}
|
|
4235
|
+
}
|
|
4236
|
+
return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/v1/auth/issuers");
|
|
4237
|
+
}
|
|
3978
4238
|
/**
|
|
3979
4239
|
* Returns the identity bound to your credential — your account, principal type, key id, and scope details — so you can confirm who you are authenticated as and that the credential is valid. MCP clients use this to render "signed in as ..." in a chat UI without a separate identity endpoint.
|
|
3980
4240
|
*
|
|
@@ -4160,7 +4420,7 @@ var AuthClient = class {
|
|
|
4160
4420
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/v1/auth/token");
|
|
4161
4421
|
}
|
|
4162
4422
|
/**
|
|
4163
|
-
* Invite a new member to one of your app contexts by email. Creates a pending user with a pre-resolved access profile (their permissions on accept) and signs an invitation token. This call is idempotent on the combination of context and email: re-inviting the same email in the same context rotates the token and resends the invitation rather than creating a duplicate. Returns HTTP 201 on a new invite or a successful resend. Returns 409 if that email already belongs to an active or suspended member of the app context, or already has an identity elsewhere in your account (an email can currently belong to only one tenant per account, i.e. your test and live environments cannot share an email). When `sendEmail` is false, the response includes the raw token and a ready-to-use accept link so you can deliver the invitation through your own email provider. Requires the `
|
|
4423
|
+
* Invite a new member to one of your app contexts by email. Creates a pending user with a pre-resolved access profile (their permissions on accept) and signs an invitation token. This call is idempotent on the combination of context and email: re-inviting the same email in the same context rotates the token and resends the invitation rather than creating a duplicate — this requires the `users:r` and `users:u` scopes in addition to `users:c`, because resending rotates a credential on an existing invitation and invalidates any link already sent. Without them the collision returns 409 instead, with no invitation details and no change to the outstanding invitation. Returns HTTP 201 on a new invite or a successful resend. Returns 409 if that email already belongs to an active or suspended member of the app context, or already has an identity elsewhere in your account (an email can currently belong to only one tenant per account, i.e. your test and live environments cannot share an email). When `sendEmail` is false, the response includes the raw token and a ready-to-use accept link so you can deliver the invitation through your own email provider. Requires the `users:c` scope.
|
|
4164
4424
|
*
|
|
4165
4425
|
* @param {Vectros.CreateInviteRequest} request
|
|
4166
4426
|
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -4231,7 +4491,7 @@ var AuthClient = class {
|
|
|
4231
4491
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/v1/users/invite");
|
|
4232
4492
|
}
|
|
4233
4493
|
/**
|
|
4234
|
-
* Resend an outstanding invitation, identified by its email and app context. Rotates the invitation token and extends its expiry, then (when `sendEmail` is true) re-delivers the email. Rotating the token invalidates any previously issued link for this invitation, so only the newest link works. The invitee's pending permissions are left unchanged.
|
|
4494
|
+
* Resend an outstanding invitation, identified by its email and app context. Rotates the invitation token and extends its expiry, then (when `sendEmail` is true) re-delivers the email. Rotating the token invalidates any previously issued link for this invitation, so only the newest link works. The invitee's pending permissions are left unchanged. Because this rotates a credential on an existing invitation, it requires the `users:c`, `users:r` and `users:u` scopes.
|
|
4235
4495
|
*
|
|
4236
4496
|
* @param {Vectros.CreateInviteRequest} request
|
|
4237
4497
|
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -4298,6 +4558,72 @@ var AuthClient = class {
|
|
|
4298
4558
|
}
|
|
4299
4559
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/v1/users/invite/resend");
|
|
4300
4560
|
}
|
|
4561
|
+
/**
|
|
4562
|
+
* RFC 8693 OAuth 2.0 Token Exchange. Trades a JWT issued by a third-party identity provider you've registered (`POST /v1/auth/issuers`) for a Vectros `st_*` scoped bearer token — no Vectros credential required to call this endpoint. The exchanged token's scope is resolved entirely server-side from the matched user's access profile; this endpoint accepts no caller-supplied scope, resource, or audience parameter (RFC 8693 §2.1's `resource`/`audience`/`scope` are not used in v1 — the registered `(issuer, audience)` pair alone pins the target tenant and app context). On a first-time login (no existing Vectros identity for this subject), two opt-in binding paths exist: `invite_token` (a `PENDING` sub-user invitation), and — if the registration declares one or more self-signup policies — `signup_type` (a brand-new user is created and bound to the policy's configured role). If `invite_token` is present at all, it is the ONLY path tried — a failed invite never falls through to self-signup. Neither field is required for a subject with an existing identity. Uses the OAuth-standard error envelope (`{"error":..., "error_description":...}`, RFC 6749 §5.2), NOT this API's usual `{"message":...}` shape — its client is generic OAuth tooling, not the Vectros SDK.
|
|
4563
|
+
*
|
|
4564
|
+
* @param {Vectros.TokenExchangeRequest} request
|
|
4565
|
+
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
4566
|
+
*
|
|
4567
|
+
* @throws {@link Vectros.BadRequestError}
|
|
4568
|
+
* @throws {@link Vectros.UnauthorizedError}
|
|
4569
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
4570
|
+
* @throws {@link Vectros.NotFoundError}
|
|
4571
|
+
* @throws {@link Vectros.TooManyRequestsError}
|
|
4572
|
+
*
|
|
4573
|
+
* @example
|
|
4574
|
+
* await client.auth.exchangeToken({
|
|
4575
|
+
* grant_type: "urn:ietf:params:oauth:grant-type:token-exchange",
|
|
4576
|
+
* subject_token: "subject_token",
|
|
4577
|
+
* subject_token_type: "urn:ietf:params:oauth:token-type:jwt"
|
|
4578
|
+
* })
|
|
4579
|
+
*/
|
|
4580
|
+
exchangeToken(request, requestOptions) {
|
|
4581
|
+
return HttpResponsePromise.fromPromise(this.__exchangeToken(request, requestOptions));
|
|
4582
|
+
}
|
|
4583
|
+
async __exchangeToken(request, requestOptions) {
|
|
4584
|
+
const _headers = mergeHeaders(this._options?.headers, requestOptions?.headers);
|
|
4585
|
+
const _response = await fetcher({
|
|
4586
|
+
url: url_exports.join(
|
|
4587
|
+
await Supplier.get(this._options.baseUrl) ?? await Supplier.get(this._options.environment),
|
|
4588
|
+
"v1/auth/token/exchange"
|
|
4589
|
+
),
|
|
4590
|
+
method: "POST",
|
|
4591
|
+
headers: _headers,
|
|
4592
|
+
contentType: "application/json",
|
|
4593
|
+
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
4594
|
+
requestType: "json",
|
|
4595
|
+
body: request,
|
|
4596
|
+
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
4597
|
+
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
4598
|
+
abortSignal: requestOptions?.abortSignal,
|
|
4599
|
+
fetchFn: this._options?.fetch,
|
|
4600
|
+
logging: this._options.logging
|
|
4601
|
+
});
|
|
4602
|
+
if (_response.ok) {
|
|
4603
|
+
return { data: _response.body, rawResponse: _response.rawResponse };
|
|
4604
|
+
}
|
|
4605
|
+
if (_response.error.reason === "status-code") {
|
|
4606
|
+
switch (_response.error.statusCode) {
|
|
4607
|
+
case 400:
|
|
4608
|
+
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
4609
|
+
case 401:
|
|
4610
|
+
throw new UnauthorizedError(_response.error.body, _response.rawResponse);
|
|
4611
|
+
case 403:
|
|
4612
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
4613
|
+
case 404:
|
|
4614
|
+
throw new NotFoundError(_response.error.body, _response.rawResponse);
|
|
4615
|
+
case 429:
|
|
4616
|
+
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
4617
|
+
default:
|
|
4618
|
+
throw new VectrosError({
|
|
4619
|
+
statusCode: _response.error.statusCode,
|
|
4620
|
+
body: _response.error.body,
|
|
4621
|
+
rawResponse: _response.rawResponse
|
|
4622
|
+
});
|
|
4623
|
+
}
|
|
4624
|
+
}
|
|
4625
|
+
return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/v1/auth/token/exchange");
|
|
4626
|
+
}
|
|
4301
4627
|
};
|
|
4302
4628
|
var ComplianceClient = class {
|
|
4303
4629
|
constructor(options) {
|
|
@@ -4565,7 +4891,7 @@ var DocumentsClient = class {
|
|
|
4565
4891
|
* userId: "550e8400-e29b-41d4-a716-446655440000",
|
|
4566
4892
|
* scope: "group:eng-team",
|
|
4567
4893
|
* folderId: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
|
|
4568
|
-
* startFrom: "
|
|
4894
|
+
* startFrom: "b3BhcXVlLWN1cnNvci1mcm9tLXRoZS1wcmV2aW91cy1wYWdl"
|
|
4569
4895
|
* })
|
|
4570
4896
|
*/
|
|
4571
4897
|
listDocuments(request = {}, requestOptions) {
|
|
@@ -4875,6 +5201,7 @@ var DocumentsClient = class {
|
|
|
4875
5201
|
* @param {DocumentsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
4876
5202
|
*
|
|
4877
5203
|
* @throws {@link Vectros.BadRequestError}
|
|
5204
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
4878
5205
|
* @throws {@link Vectros.NotFoundError}
|
|
4879
5206
|
* @throws {@link Vectros.ConflictError}
|
|
4880
5207
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
@@ -4922,6 +5249,8 @@ var DocumentsClient = class {
|
|
|
4922
5249
|
switch (_response.error.statusCode) {
|
|
4923
5250
|
case 400:
|
|
4924
5251
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
5252
|
+
case 403:
|
|
5253
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
4925
5254
|
case 404:
|
|
4926
5255
|
throw new NotFoundError(_response.error.body, _response.rawResponse);
|
|
4927
5256
|
case 409:
|
|
@@ -4952,7 +5281,7 @@ var DocumentsClient = class {
|
|
|
4952
5281
|
* field: "po_number",
|
|
4953
5282
|
* value: "PO-1001",
|
|
4954
5283
|
* prefix: "PO-2024",
|
|
4955
|
-
* startFrom: "
|
|
5284
|
+
* startFrom: "b3BhcXVlLWN1cnNvci1mcm9tLXRoZS1wcmV2aW91cy1wYWdl",
|
|
4956
5285
|
* userId: "550e8400-e29b-41d4-a716-446655440000",
|
|
4957
5286
|
* scope: "org:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
|
|
4958
5287
|
* })
|
|
@@ -5328,7 +5657,7 @@ var FoldersClient = class {
|
|
|
5328
5657
|
* parentFolderId: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
|
|
5329
5658
|
* userId: "550e8400-e29b-41d4-a716-446655440000",
|
|
5330
5659
|
* scope: "group:eng-team",
|
|
5331
|
-
* startFrom: "
|
|
5660
|
+
* startFrom: "b3BhcXVlLWN1cnNvci1mcm9tLXRoZS1wcmV2aW91cy1wYWdl"
|
|
5332
5661
|
* })
|
|
5333
5662
|
*/
|
|
5334
5663
|
listFolders(request = {}, requestOptions) {
|
|
@@ -5505,6 +5834,7 @@ var FoldersClient = class {
|
|
|
5505
5834
|
* @param {Vectros.UpdateFolderRequest} request
|
|
5506
5835
|
* @param {FoldersClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
5507
5836
|
*
|
|
5837
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
5508
5838
|
* @throws {@link Vectros.NotFoundError}
|
|
5509
5839
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
5510
5840
|
*
|
|
@@ -5549,6 +5879,8 @@ var FoldersClient = class {
|
|
|
5549
5879
|
}
|
|
5550
5880
|
if (_response.error.reason === "status-code") {
|
|
5551
5881
|
switch (_response.error.statusCode) {
|
|
5882
|
+
case 403:
|
|
5883
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
5552
5884
|
case 404:
|
|
5553
5885
|
throw new NotFoundError(_response.error.body, _response.rawResponse);
|
|
5554
5886
|
case 429:
|
|
@@ -5631,6 +5963,7 @@ var FoldersClient = class {
|
|
|
5631
5963
|
* @param {FoldersClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
5632
5964
|
*
|
|
5633
5965
|
* @throws {@link Vectros.BadRequestError}
|
|
5966
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
5634
5967
|
* @throws {@link Vectros.NotFoundError}
|
|
5635
5968
|
* @throws {@link Vectros.ConflictError}
|
|
5636
5969
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
@@ -5678,6 +6011,8 @@ var FoldersClient = class {
|
|
|
5678
6011
|
switch (_response.error.statusCode) {
|
|
5679
6012
|
case 400:
|
|
5680
6013
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
6014
|
+
case 403:
|
|
6015
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
5681
6016
|
case 404:
|
|
5682
6017
|
throw new NotFoundError(_response.error.body, _response.rawResponse);
|
|
5683
6018
|
case 409:
|
|
@@ -5765,7 +6100,8 @@ var IdentityClient = class {
|
|
|
5765
6100
|
*
|
|
5766
6101
|
* @example
|
|
5767
6102
|
* await client.identity.listEntities({
|
|
5768
|
-
* namespace: "team"
|
|
6103
|
+
* namespace: "team",
|
|
6104
|
+
* startFrom: "b3BhcXVlLWN1cnNvci1mcm9tLXRoZS1wcmV2aW91cy1wYWdl"
|
|
5769
6105
|
* })
|
|
5770
6106
|
*/
|
|
5771
6107
|
listEntities(request, requestOptions) {
|
|
@@ -6529,7 +6865,7 @@ var IdentityClient = class {
|
|
|
6529
6865
|
* @example
|
|
6530
6866
|
* await client.identity.listUsers({
|
|
6531
6867
|
* externalId: "usr_12345",
|
|
6532
|
-
* startFrom: "
|
|
6868
|
+
* startFrom: "b3BhcXVlLWN1cnNvci1mcm9tLXRoZS1wcmV2aW91cy1wYWdl",
|
|
6533
6869
|
* type: "person_v1",
|
|
6534
6870
|
* field: "team",
|
|
6535
6871
|
* value: "engineering",
|
|
@@ -6710,11 +7046,12 @@ var IdentityClient = class {
|
|
|
6710
7046
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/users/{id}");
|
|
6711
7047
|
}
|
|
6712
7048
|
/**
|
|
6713
|
-
* Updates mutable fields on an existing user (such as email, status, payload, or schema binding). The `type` field is immutable after creation. This endpoint also activates an invited user: a PUT that moves a PENDING user to ACTIVE and carries `inviteToken`, `externalSubject`, and `emailVerifiedAttestation=true` completes the invitation. Requires the `users:u` scope.
|
|
7049
|
+
* Updates mutable fields on an existing user (such as email, status, payload, or schema binding). The `type` field is immutable after creation, and `email` cannot be changed while an invitation to that user is still outstanding — revoke the invitation, or invite the new address instead. This endpoint also activates an invited user: a PUT that moves a PENDING user to ACTIVE and carries `inviteToken`, `externalSubject`, and `emailVerifiedAttestation=true` completes the invitation. Requires the `users:u` scope.
|
|
6714
7050
|
*
|
|
6715
7051
|
* @param {Vectros.UpdateUserRequest} request
|
|
6716
7052
|
* @param {IdentityClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
6717
7053
|
*
|
|
7054
|
+
* @throws {@link Vectros.BadRequestError}
|
|
6718
7055
|
* @throws {@link Vectros.NotFoundError}
|
|
6719
7056
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
6720
7057
|
*
|
|
@@ -6759,6 +7096,8 @@ var IdentityClient = class {
|
|
|
6759
7096
|
}
|
|
6760
7097
|
if (_response.error.reason === "status-code") {
|
|
6761
7098
|
switch (_response.error.statusCode) {
|
|
7099
|
+
case 400:
|
|
7100
|
+
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
6762
7101
|
case 404:
|
|
6763
7102
|
throw new NotFoundError(_response.error.body, _response.rawResponse);
|
|
6764
7103
|
case 429:
|
|
@@ -6892,6 +7231,69 @@ var IdentityClient = class {
|
|
|
6892
7231
|
}
|
|
6893
7232
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/v1/users/lookup");
|
|
6894
7233
|
}
|
|
7234
|
+
/**
|
|
7235
|
+
* Answers "does a user with this email hold an ACTIVE access profile in this app context" — a narrow existence check, not a general lookup. `exists` is false for a member whose access to this context has been suspended, not only for a member who was never granted it. The answer is scoped to the `contextId` you supply: it does not reveal whether the email exists elsewhere in your tenant or account, only whether it belongs to an active member of the named context. Returns `{exists, userId, status}` — never the full user record — so a caller asking "does X exist" cannot receive that user's payload/schema binding/etc. as a side effect. Useful for resolving an email you were handed (for example, by an org-admin adding an existing member to another org) to a `userId`, without paging through the full context membership. Requires the `users:r` scope.
|
|
7236
|
+
*
|
|
7237
|
+
* @param {Vectros.UserExistsByEmailRequest} request
|
|
7238
|
+
* @param {IdentityClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
7239
|
+
*
|
|
7240
|
+
* @throws {@link Vectros.BadRequestError}
|
|
7241
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
7242
|
+
*
|
|
7243
|
+
* @example
|
|
7244
|
+
* await client.identity.userExistsByEmail({
|
|
7245
|
+
* email: "user@example.com",
|
|
7246
|
+
* contextId: "myapp"
|
|
7247
|
+
* })
|
|
7248
|
+
*/
|
|
7249
|
+
userExistsByEmail(request = {}, requestOptions) {
|
|
7250
|
+
return HttpResponsePromise.fromPromise(this.__userExistsByEmail(request, requestOptions));
|
|
7251
|
+
}
|
|
7252
|
+
async __userExistsByEmail(request = {}, requestOptions) {
|
|
7253
|
+
const { email, contextId } = request;
|
|
7254
|
+
const _queryParams = {
|
|
7255
|
+
email,
|
|
7256
|
+
contextId
|
|
7257
|
+
};
|
|
7258
|
+
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
7259
|
+
const _headers = mergeHeaders(
|
|
7260
|
+
_authRequest.headers,
|
|
7261
|
+
this._options?.headers,
|
|
7262
|
+
requestOptions?.headers
|
|
7263
|
+
);
|
|
7264
|
+
const _response = await fetcher({
|
|
7265
|
+
url: url_exports.join(
|
|
7266
|
+
await Supplier.get(this._options.baseUrl) ?? await Supplier.get(this._options.environment),
|
|
7267
|
+
"v1/users/exists-by-email"
|
|
7268
|
+
),
|
|
7269
|
+
method: "GET",
|
|
7270
|
+
headers: _headers,
|
|
7271
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
7272
|
+
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
7273
|
+
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
7274
|
+
abortSignal: requestOptions?.abortSignal,
|
|
7275
|
+
fetchFn: this._options?.fetch,
|
|
7276
|
+
logging: this._options.logging
|
|
7277
|
+
});
|
|
7278
|
+
if (_response.ok) {
|
|
7279
|
+
return { data: _response.body, rawResponse: _response.rawResponse };
|
|
7280
|
+
}
|
|
7281
|
+
if (_response.error.reason === "status-code") {
|
|
7282
|
+
switch (_response.error.statusCode) {
|
|
7283
|
+
case 400:
|
|
7284
|
+
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
7285
|
+
case 403:
|
|
7286
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
7287
|
+
default:
|
|
7288
|
+
throw new VectrosError({
|
|
7289
|
+
statusCode: _response.error.statusCode,
|
|
7290
|
+
body: _response.error.body,
|
|
7291
|
+
rawResponse: _response.rawResponse
|
|
7292
|
+
});
|
|
7293
|
+
}
|
|
7294
|
+
}
|
|
7295
|
+
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/users/exists-by-email");
|
|
7296
|
+
}
|
|
6895
7297
|
/**
|
|
6896
7298
|
* Returns the audit trail of changes to a user, most recent first. Identity history is always recorded and always available. Sensitive field values are redacted in every historical version. Returns a page in the `{data, nextCursor}` envelope. Requires the `users:r` scope.
|
|
6897
7299
|
*
|
|
@@ -7406,7 +7808,7 @@ var RecordsClient = class {
|
|
|
7406
7808
|
* folderId: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
|
|
7407
7809
|
* userId: "550e8400-e29b-41d4-a716-446655440000",
|
|
7408
7810
|
* scope: "group:eng-team",
|
|
7409
|
-
* startFrom: "
|
|
7811
|
+
* startFrom: "b3BhcXVlLWN1cnNvci1mcm9tLXRoZS1wcmV2aW91cy1wYWdl"
|
|
7410
7812
|
* })
|
|
7411
7813
|
*/
|
|
7412
7814
|
listRecords(request = {}, requestOptions) {
|
|
@@ -7594,6 +7996,7 @@ var RecordsClient = class {
|
|
|
7594
7996
|
* @param {RecordsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
7595
7997
|
*
|
|
7596
7998
|
* @throws {@link Vectros.BadRequestError}
|
|
7999
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
7597
8000
|
* @throws {@link Vectros.NotFoundError}
|
|
7598
8001
|
* @throws {@link Vectros.ConflictError}
|
|
7599
8002
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
@@ -7642,6 +8045,8 @@ var RecordsClient = class {
|
|
|
7642
8045
|
switch (_response.error.statusCode) {
|
|
7643
8046
|
case 400:
|
|
7644
8047
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
8048
|
+
case 403:
|
|
8049
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
7645
8050
|
case 404:
|
|
7646
8051
|
throw new NotFoundError(_response.error.body, _response.rawResponse);
|
|
7647
8052
|
case 409:
|
|
@@ -7723,6 +8128,7 @@ var RecordsClient = class {
|
|
|
7723
8128
|
* @param {RecordsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
7724
8129
|
*
|
|
7725
8130
|
* @throws {@link Vectros.BadRequestError}
|
|
8131
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
7726
8132
|
* @throws {@link Vectros.NotFoundError}
|
|
7727
8133
|
* @throws {@link Vectros.ConflictError}
|
|
7728
8134
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
@@ -7773,6 +8179,8 @@ var RecordsClient = class {
|
|
|
7773
8179
|
switch (_response.error.statusCode) {
|
|
7774
8180
|
case 400:
|
|
7775
8181
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
8182
|
+
case 403:
|
|
8183
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
7776
8184
|
case 404:
|
|
7777
8185
|
throw new NotFoundError(_response.error.body, _response.rawResponse);
|
|
7778
8186
|
case 409:
|
|
@@ -7790,7 +8198,15 @@ var RecordsClient = class {
|
|
|
7790
8198
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "PATCH", "/v1/records/{id}");
|
|
7791
8199
|
}
|
|
7792
8200
|
/**
|
|
7793
|
-
* Finds records by the value of a lookup field declared on the type's schema. Provide exactly one lookup mode: `value` (exact match), `from`+`to` (inclusive range, ascending by value), or `prefix` (string fields only, ascending). Range and prefix lookups are not supported on a sensitive field, because its value is stored as a blind index and has no sortable order. An exact-`value` lookup on a sensitive field is also rejected on this GET endpoint — the value must not appear in the URL — so use the `POST /v1/records/lookup` body variant for sensitive fields.
|
|
8201
|
+
* Finds records by the value of a lookup field declared on the type's schema. Provide exactly one lookup mode: `value` (exact match), `from`+`to` (inclusive range, ascending by value), or `prefix` (string fields only, ascending). Range and prefix lookups are not supported on a sensitive field, because its value is stored as a blind index and has no sortable order. An exact-`value` lookup on a sensitive field is also rejected on this GET endpoint — the value must not appear in the URL — so use the `POST /v1/records/lookup` body variant for sensitive fields.
|
|
8202
|
+
*
|
|
8203
|
+
* A `value` lookup can additionally be narrowed to a window of the lookup field's **sort key** using `sortFrom` and/or `sortTo` (inclusive) — for example, one session's records created since a timestamp. The sort key is whatever the schema declares as that lookup's `sortBy` (`createdAt` by default, `lastUpdated`, or another field), and bounds are given in that field's own units — epoch milliseconds for the two timestamp options. **Records that have no value for the sorted field are never included in a bounded window** — they are ordered ahead of every record that does have one, and a `sortFrom`/`sortTo` window only ever selects from records carrying a value. The sorted field does not have to be `required`.
|
|
8204
|
+
*
|
|
8205
|
+
* Narrowing is available on any lookup field your schema declares for fast equality lookup, and on `externalId` — which is always ordered by creation time, so its bounds are epoch milliseconds whatever the schema says. It is rejected (`400`) for a field declared with `rangeEnabled`, for a field declared beyond the schema's fast-lookup budget, for a lookup whose `sortBy` names a sensitive field (a sensitive value is stored as a blind index and has no order), and for a window whose start is after its end. Ownership fields are not lookup fields on this endpoint at all — see the `field` parameter.
|
|
8206
|
+
*
|
|
8207
|
+
* While paging a narrowed lookup, keep every other parameter identical. The cursor is valid only for the exact query that returned it — changing `order`, `sortFrom`, `sortTo`, or dropping them altogether, is rejected rather than silently resumed at a position that means something different in the new query.
|
|
8208
|
+
*
|
|
8209
|
+
* Results are paginated: set `limit` for the page size and pass the returned `nextCursor` back as `startFrom` for the next page. **Keep paging until `nextCursor` is null** — a page can come back empty or shorter than `limit` while more results remain, so an empty page is not the end of the results. Requires the `records:r:<type>` scope.
|
|
7794
8210
|
*
|
|
7795
8211
|
* @param {Vectros.LookupRecordsRequest} request
|
|
7796
8212
|
* @param {RecordsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -7802,22 +8218,40 @@ var RecordsClient = class {
|
|
|
7802
8218
|
* type: "intake_form",
|
|
7803
8219
|
* field: "email",
|
|
7804
8220
|
* value: "jane@example.com",
|
|
8221
|
+
* values: ["open"],
|
|
7805
8222
|
* prefix: "jane",
|
|
7806
|
-
* startFrom: "
|
|
8223
|
+
* startFrom: "b3BhcXVlLWN1cnNvci1mcm9tLXRoZS1wcmV2aW91cy1wYWdl"
|
|
7807
8224
|
* })
|
|
7808
8225
|
*/
|
|
7809
8226
|
lookupRecords(request, requestOptions) {
|
|
7810
8227
|
return HttpResponsePromise.fromPromise(this.__lookupRecords(request, requestOptions));
|
|
7811
8228
|
}
|
|
7812
8229
|
async __lookupRecords(request, requestOptions) {
|
|
7813
|
-
const {
|
|
8230
|
+
const {
|
|
8231
|
+
type: type_,
|
|
8232
|
+
field,
|
|
8233
|
+
value,
|
|
8234
|
+
values,
|
|
8235
|
+
from: from_,
|
|
8236
|
+
to,
|
|
8237
|
+
prefix,
|
|
8238
|
+
sortFrom,
|
|
8239
|
+
sortTo,
|
|
8240
|
+
startFrom,
|
|
8241
|
+
limit,
|
|
8242
|
+
includePayload,
|
|
8243
|
+
order
|
|
8244
|
+
} = request;
|
|
7814
8245
|
const _queryParams = {
|
|
7815
8246
|
type: type_,
|
|
7816
8247
|
field,
|
|
7817
8248
|
value,
|
|
8249
|
+
values,
|
|
7818
8250
|
from: from_,
|
|
7819
8251
|
to,
|
|
7820
8252
|
prefix,
|
|
8253
|
+
sortFrom,
|
|
8254
|
+
sortTo,
|
|
7821
8255
|
startFrom,
|
|
7822
8256
|
limit,
|
|
7823
8257
|
includePayload,
|
|
@@ -7861,7 +8295,7 @@ var RecordsClient = class {
|
|
|
7861
8295
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/records/lookup");
|
|
7862
8296
|
}
|
|
7863
8297
|
/**
|
|
7864
|
-
* Body-based equivalent of `GET /v1/records/lookup`. Use this when looking up by a sensitive field: the value travels in the request body (and is blind-indexed server-side) instead of in the URL query string, so it never lands in access, CDN, or proxy logs. The GET variant rejects an exact-value lookup on a sensitive field and directs you here. Non-sensitive exact-value, range (`from`+`to`), and prefix lookups also work here. Returns the same `{data, nextCursor}` envelope and uses the same pagination as the GET variant. Requires the `records:r:<type>` scope.
|
|
8298
|
+
* Body-based equivalent of `GET /v1/records/lookup`. Use this when looking up by a sensitive field: the value travels in the request body (and is blind-indexed server-side) instead of in the URL query string, so it never lands in access, CDN, or proxy logs. The GET variant rejects an exact-value lookup on a sensitive field and directs you here. Non-sensitive exact-value, range (`from`+`to`), and prefix lookups also work here, as does narrowing a `value` lookup by the field's sort key with `sortFrom`/`sortTo` — see the GET variant for what the sort key is and when narrowing by it is available. Returns the same `{data, nextCursor}` envelope and uses the same pagination as the GET variant; keep paging until `nextCursor` is null rather than stopping on an empty page. Requires the `records:r:<type>` scope.
|
|
7865
8299
|
*
|
|
7866
8300
|
* @param {Vectros.RecordLookupRequest} request
|
|
7867
8301
|
* @param {RecordsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -8056,7 +8490,7 @@ var SchemasClient = class {
|
|
|
8056
8490
|
* scope: "org:6ba7b810-9dad-11d1-80b4-00c04fd430c8",
|
|
8057
8491
|
* surface: "document",
|
|
8058
8492
|
* recordType: "intake_form",
|
|
8059
|
-
* startFrom: "
|
|
8493
|
+
* startFrom: "b3BhcXVlLWN1cnNvci1mcm9tLXRoZS1wcmV2aW91cy1wYWdl"
|
|
8060
8494
|
* })
|
|
8061
8495
|
*/
|
|
8062
8496
|
listSchemas(request = {}, requestOptions) {
|
|
@@ -8260,6 +8694,7 @@ var SchemasClient = class {
|
|
|
8260
8694
|
* @param {SchemasClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
8261
8695
|
*
|
|
8262
8696
|
* @throws {@link Vectros.BadRequestError}
|
|
8697
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
8263
8698
|
* @throws {@link Vectros.NotFoundError}
|
|
8264
8699
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
8265
8700
|
*
|
|
@@ -8308,6 +8743,8 @@ var SchemasClient = class {
|
|
|
8308
8743
|
switch (_response.error.statusCode) {
|
|
8309
8744
|
case 400:
|
|
8310
8745
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
8746
|
+
case 403:
|
|
8747
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
8311
8748
|
case 404:
|
|
8312
8749
|
throw new NotFoundError(_response.error.body, _response.rawResponse);
|
|
8313
8750
|
case 429:
|
|
@@ -8618,15 +9055,15 @@ function warnOnSuboptimalKey(key, log) {
|
|
|
8618
9055
|
} else if (key.prefix === "st") {
|
|
8619
9056
|
log.warn(
|
|
8620
9057
|
{ prefix: key.prefix, env: key.env },
|
|
8621
|
-
"short-lived token (st_*) will expire mid-session (1h
|
|
9058
|
+
"short-lived token (st_*) will expire mid-session (1h max). For long-running MCP installs, prefer a long-lived ssk_* key."
|
|
8622
9059
|
);
|
|
8623
9060
|
}
|
|
8624
9061
|
}
|
|
8625
9062
|
|
|
8626
9063
|
// src/build-info.ts
|
|
8627
9064
|
var BUILD_INFO = {
|
|
8628
|
-
mcpServer: true ? "0.
|
|
8629
|
-
sdk: true ? "0.
|
|
9065
|
+
mcpServer: true ? "0.14.0" : "dev",
|
|
9066
|
+
sdk: true ? "0.39.0" : "dev"
|
|
8630
9067
|
};
|
|
8631
9068
|
|
|
8632
9069
|
// src/log.ts
|
|
@@ -8666,7 +9103,9 @@ async function resolveIdentity({
|
|
|
8666
9103
|
const derived = {
|
|
8667
9104
|
status: "ok",
|
|
8668
9105
|
environment: deriveEnvironment(environment),
|
|
8669
|
-
principalType: derivePrincipalType(apiKey)
|
|
9106
|
+
principalType: derivePrincipalType(apiKey),
|
|
9107
|
+
mcpServerVersion: BUILD_INFO.mcpServer,
|
|
9108
|
+
sdkVersion: BUILD_INFO.sdk
|
|
8670
9109
|
};
|
|
8671
9110
|
if (!apiKey || !environment) {
|
|
8672
9111
|
log.debug({ component: "identity", mode: "derived-only" }, "identity derived (no fetch)");
|
|
@@ -8694,7 +9133,13 @@ async function resolveIdentity({
|
|
|
8694
9133
|
);
|
|
8695
9134
|
}
|
|
8696
9135
|
}
|
|
8697
|
-
const merged = {
|
|
9136
|
+
const merged = {
|
|
9137
|
+
...derived,
|
|
9138
|
+
...extended,
|
|
9139
|
+
status: "ok",
|
|
9140
|
+
mcpServerVersion: derived.mcpServerVersion,
|
|
9141
|
+
sdkVersion: derived.sdkVersion
|
|
9142
|
+
};
|
|
8698
9143
|
log.debug(
|
|
8699
9144
|
{
|
|
8700
9145
|
component: "identity",
|
|
@@ -9016,14 +9461,23 @@ import { z as z2 } from "zod";
|
|
|
9016
9461
|
function pageItems(page) {
|
|
9017
9462
|
return page.data ?? [];
|
|
9018
9463
|
}
|
|
9464
|
+
var MAX_PAGES = 100;
|
|
9465
|
+
var MAX_ROWS = 1e6;
|
|
9019
9466
|
async function drainPages(fetchPage) {
|
|
9020
9467
|
const all = [];
|
|
9021
9468
|
let startFrom;
|
|
9469
|
+
let pages = 0;
|
|
9022
9470
|
for (; ; ) {
|
|
9023
9471
|
const page = await fetchPage(startFrom);
|
|
9024
|
-
|
|
9472
|
+
pages++;
|
|
9473
|
+
if (page.data?.length) for (const item of page.data) all.push(item);
|
|
9025
9474
|
const next = page.nextCursor;
|
|
9026
9475
|
if (!next) break;
|
|
9476
|
+
if (pages > MAX_PAGES || all.length > MAX_ROWS) {
|
|
9477
|
+
throw new Error(
|
|
9478
|
+
`drainPages: exceeded the runaway guard (${all.length} rows over ${pages} pages, limits ${MAX_ROWS}/${MAX_PAGES}) without the cursor going null. Refusing to return a partial result \u2014 the backend may be returning empty pages with a live cursor.`
|
|
9479
|
+
);
|
|
9480
|
+
}
|
|
9027
9481
|
startFrom = next;
|
|
9028
9482
|
}
|
|
9029
9483
|
return all;
|
|
@@ -9034,14 +9488,23 @@ var MCP_DEFAULT_LIMIT2 = 3;
|
|
|
9034
9488
|
var MCP_MAX_LIMIT2 = 100;
|
|
9035
9489
|
var inputSchema2 = {
|
|
9036
9490
|
type: z2.string().min(1, "type (record type) is required").describe('Record type / schema name (e.g. "patient", "clinical_note").'),
|
|
9037
|
-
// Lookup-mode args — provide `field` plus EXACTLY ONE of: value | from+to | prefix.
|
|
9491
|
+
// Lookup-mode args — provide `field` plus EXACTLY ONE of: value | values | from+to | prefix.
|
|
9038
9492
|
field: z2.string().optional().describe(
|
|
9039
|
-
'Lookup mode: name of the lookup-indexed field to query by. `externalId` is always queryable \u2014 e.g. `{type:"control", field:"externalId", value:"ctrl-scoped-key"}` finds the record you created under that externalId. (record_get / record_update also accept externalId directly.)'
|
|
9493
|
+
'Lookup mode: name of the lookup-indexed field to query by. `externalId` is always queryable \u2014 e.g. `{type:"control", field:"externalId", value:"ctrl-scoped-key"}` finds the record you created under that externalId. (record_get / record_update also accept externalId directly.) For a SCHEMA-declared composite lookup \u2014 check list_schemas\' lookupFields for a fieldNames entry, not any two fields you pick \u2014 give those field names comma-joined in the declared order (e.g. "status,area"). Use `values` to match on several of those fields at once, or `value` to match on just the FIRST field named (equivalent to a one-element `values`); range/prefix are not valid on a composite field.'
|
|
9494
|
+
),
|
|
9495
|
+
value: z2.string().optional().describe(
|
|
9496
|
+
"Lookup mode (equality): exact-match value for `field`. Also valid when `field` names a SCHEMA-declared composite lookup \u2014 matches just the first named field, grouping by the rest (equivalent to `values` with one entry)."
|
|
9497
|
+
),
|
|
9498
|
+
values: z2.array(z2.string()).min(1).max(3).optional().describe(
|
|
9499
|
+
'Lookup mode (composite equality): only valid against a lookup the SCHEMA declares over several fields together (a fieldNames entry in list_schemas \u2014 you cannot combine two ordinary single-field lookups this way). One value per field, in the order the schema declares them (e.g. field="status,area", values=["open","billing"]). Mutually exclusive with `value`; a single-element array is exactly `value` written uniformly. Supplying FEWER values than the lookup declares is allowed \u2014 as long as they\'re a leading run of its fields \u2014 and returns records grouped by the fields left unspecified; `order` then sorts within each group, not across them. Record lookups only (not documents/users/entities).'
|
|
9040
9500
|
),
|
|
9041
|
-
value: z2.string().optional().describe("Lookup mode (equality): exact-match value for `field`."),
|
|
9042
9501
|
from: z2.string().optional().describe("Lookup mode (range): inclusive lower bound; requires `to`. Non-sensitive fields only."),
|
|
9043
9502
|
to: z2.string().optional().describe("Lookup mode (range): inclusive upper bound; requires `from`."),
|
|
9044
9503
|
prefix: z2.string().optional().describe("Lookup mode (prefix): match values starting with this. String, non-sensitive fields only."),
|
|
9504
|
+
sortFrom: z2.string().optional().describe(
|
|
9505
|
+
"Lookup mode (equality/composite only): inclusive lower bound on the lookup field's sort key, narrowing a `value`/`values` match to a window instead of paging the whole match. Give the bound in the sort field's own units (epoch milliseconds for `createdAt`/`lastUpdated`). With `values`, requires every value be supplied (no grouping) for one continuous ordering. Not valid with `from`/`to`/`prefix`."
|
|
9506
|
+
),
|
|
9507
|
+
sortTo: z2.string().optional().describe("Lookup mode (equality/composite only): inclusive upper bound on the sort key; pairs with `sortFrom`."),
|
|
9045
9508
|
order: z2.enum(["asc", "desc"]).optional().describe(
|
|
9046
9509
|
"Lookup mode: sort direction by the looked-up field. `asc` (default) or `desc` \u2014 use `desc` with a range/prefix lookup to get the most-recent / highest values first (e.g. latest-N). Ignored in list mode."
|
|
9047
9510
|
),
|
|
@@ -9058,54 +9521,106 @@ var inputSchema2 = {
|
|
|
9058
9521
|
var recordQuery = ({ client, log }) => ({
|
|
9059
9522
|
name: "record_query",
|
|
9060
9523
|
title: "Record query (list or lookup)",
|
|
9061
|
-
description: "Query structured records of a given type. Two modes:\n \u2022 Lookup on a lookup-indexed field: pass `field` plus exactly one of `value` (exact), `from`+`to` (range), or `prefix`. Works on sensitive fields too
|
|
9524
|
+
description: "Query structured records of a given type. Two modes:\n \u2022 Lookup on a lookup-indexed field: pass `field` plus exactly one of `value` (exact), `values` (exact, composite \u2014 one value per field; a single-element array is the same as `value`), `from`+`to` (range), or `prefix`. `values` with more than one entry, or a comma-joined `field`, ONLY works for a lookup the schema itself declared over several fields together \u2014 check list_schemas' lookupFields for a fieldNames entry, then pass those field names comma-joined as `field`; `from`/`to`/`prefix` are not valid there. Works on sensitive fields too. Optionally narrow an exact match to a window with `sortFrom`/`sortTo`.\n \u2022 List by type: omit `field`; optionally filter by `userId` or `scope` (`namespace:value`).\nReturns a `{ data, nextCursor }` page: `data` holds up to `limit` records (default 3, max 100 \u2014 raise it in one call when you can accept the payload), and a non-null `nextCursor` means more remain \u2014 pass it back as `startFrom` to page. A composite lookup given fewer than its full field count returns records grouped by the unspecified fields, ordered within each group. Mode is auto-detected from the arguments present.",
|
|
9062
9525
|
inputSchema: inputSchema2,
|
|
9063
9526
|
handler: async (args) => {
|
|
9064
9527
|
const limit = args.limit ?? MCP_DEFAULT_LIMIT2;
|
|
9065
9528
|
const type = args.type;
|
|
9066
9529
|
const field = args.field;
|
|
9067
9530
|
const value = args.value;
|
|
9531
|
+
const values = args.values;
|
|
9068
9532
|
const from = args.from;
|
|
9069
9533
|
const to = args.to;
|
|
9070
9534
|
const prefix = args.prefix;
|
|
9535
|
+
const sortFrom = args.sortFrom;
|
|
9536
|
+
const sortTo = args.sortTo;
|
|
9071
9537
|
const startFrom = args.startFrom;
|
|
9538
|
+
if (!field && (value !== void 0 || values !== void 0 || from !== void 0 || to !== void 0 || prefix !== void 0 || sortFrom !== void 0 || sortTo !== void 0)) {
|
|
9539
|
+
return toolError(
|
|
9540
|
+
"record_query",
|
|
9541
|
+
new Error(
|
|
9542
|
+
"'value'/'values'/'from'/'to'/'prefix'/'sortFrom'/'sortTo' require 'field' \u2014 without it, list mode runs and silently ignores them. Pass 'field' to run a lookup, or drop these to list by type."
|
|
9543
|
+
)
|
|
9544
|
+
);
|
|
9545
|
+
}
|
|
9072
9546
|
try {
|
|
9073
9547
|
let page;
|
|
9074
9548
|
if (field) {
|
|
9549
|
+
const fieldNames = field.split(",").map((f) => f.trim()).filter(Boolean);
|
|
9550
|
+
const normalizedField = fieldNames.join(",");
|
|
9551
|
+
const isCompositeField = fieldNames.length > 1;
|
|
9075
9552
|
const hasEquality = value !== void 0;
|
|
9553
|
+
const hasComposite = values !== void 0;
|
|
9076
9554
|
const hasRange = from !== void 0 || to !== void 0;
|
|
9077
9555
|
const hasPrefix = prefix !== void 0;
|
|
9078
|
-
const modes = Number(hasEquality) + Number(hasRange) + Number(hasPrefix);
|
|
9556
|
+
const modes = Number(hasEquality) + Number(hasComposite) + Number(hasRange) + Number(hasPrefix);
|
|
9079
9557
|
if (modes === 0) {
|
|
9080
9558
|
return toolError(
|
|
9081
9559
|
"record_query",
|
|
9082
9560
|
new Error(
|
|
9083
|
-
`lookup on field '${field}' needs one of: 'value' (exact), 'from'+'to' (range), or 'prefix'.`
|
|
9561
|
+
`lookup on field '${field}' needs one of: 'value' (exact), 'values' (composite exact), 'from'+'to' (range), or 'prefix'.`
|
|
9084
9562
|
)
|
|
9085
9563
|
);
|
|
9086
9564
|
}
|
|
9087
9565
|
if (modes > 1) {
|
|
9088
9566
|
return toolError(
|
|
9089
9567
|
"record_query",
|
|
9090
|
-
new Error(
|
|
9568
|
+
new Error(
|
|
9569
|
+
"'value', 'values', 'from'/'to', and 'prefix' are mutually exclusive \u2014 provide exactly one."
|
|
9570
|
+
)
|
|
9091
9571
|
);
|
|
9092
9572
|
}
|
|
9093
9573
|
if (hasRange && !(from !== void 0 && to !== void 0)) {
|
|
9094
9574
|
return toolError("record_query", new Error("range lookup requires both 'from' and 'to'."));
|
|
9095
9575
|
}
|
|
9576
|
+
if (isCompositeField && (hasRange || hasPrefix)) {
|
|
9577
|
+
return toolError(
|
|
9578
|
+
"record_query",
|
|
9579
|
+
new Error(
|
|
9580
|
+
`'field' names ${fieldNames.length} fields ('${normalizedField}') \u2014 a composite lookup is exact-match only ('value' or 'values'), not 'from'/'to'/'prefix'.`
|
|
9581
|
+
)
|
|
9582
|
+
);
|
|
9583
|
+
}
|
|
9584
|
+
if (hasComposite && values.length > fieldNames.length) {
|
|
9585
|
+
return toolError(
|
|
9586
|
+
"record_query",
|
|
9587
|
+
new Error(
|
|
9588
|
+
`'values' has ${values.length} entries but 'field' names only ${fieldNames.length} field(s) ('${normalizedField}') \u2014 supply at most one value per field, in order (fewer only as a leading run).`
|
|
9589
|
+
)
|
|
9590
|
+
);
|
|
9591
|
+
}
|
|
9592
|
+
if (sortFrom !== void 0 || sortTo !== void 0) {
|
|
9593
|
+
if (!(hasEquality || hasComposite)) {
|
|
9594
|
+
return toolError(
|
|
9595
|
+
"record_query",
|
|
9596
|
+
new Error("'sortFrom'/'sortTo' narrow a 'value' or 'values' match only \u2014 not 'from'/'to'/'prefix'.")
|
|
9597
|
+
);
|
|
9598
|
+
}
|
|
9599
|
+
if (hasComposite && values.length < fieldNames.length) {
|
|
9600
|
+
return toolError(
|
|
9601
|
+
"record_query",
|
|
9602
|
+
new Error(
|
|
9603
|
+
`'sortFrom'/'sortTo' with 'values' requires a value for every field named in 'field' (got ${values.length} of ${fieldNames.length}) \u2014 a partial/grouped match has no single continuous ordering to window.`
|
|
9604
|
+
)
|
|
9605
|
+
);
|
|
9606
|
+
}
|
|
9607
|
+
}
|
|
9096
9608
|
page = await client.records.lookupRecordsByBody({
|
|
9097
9609
|
type,
|
|
9098
|
-
field,
|
|
9610
|
+
field: normalizedField,
|
|
9099
9611
|
value,
|
|
9612
|
+
values,
|
|
9100
9613
|
from,
|
|
9101
9614
|
to,
|
|
9102
9615
|
prefix,
|
|
9616
|
+
sortFrom,
|
|
9617
|
+
sortTo,
|
|
9103
9618
|
order: args.order,
|
|
9104
9619
|
startFrom,
|
|
9105
9620
|
limit
|
|
9106
9621
|
});
|
|
9107
9622
|
log.debug(
|
|
9108
|
-
{ tool: "record_query", mode: "lookup", type, field, returned: pageItems(page).length },
|
|
9623
|
+
{ tool: "record_query", mode: "lookup", type, field: normalizedField, returned: pageItems(page).length },
|
|
9109
9624
|
"record_query lookup ok"
|
|
9110
9625
|
);
|
|
9111
9626
|
} else {
|
|
@@ -10044,7 +10559,7 @@ var inputSchema18 = {
|
|
|
10044
10559
|
var currentIdentity = ({ log, apiKey, environment }) => ({
|
|
10045
10560
|
name: "current_identity",
|
|
10046
10561
|
title: "Current identity (tenant + principal scope)",
|
|
10047
|
-
description: "Describe the credential the MCP server is operating under. Returns tenantId, environment (staging|production), principalType (root_key|scoped_key|token), principalKeyId, principalLabel, and (for scoped credentials) allowedActions plus dataScope \u2014 the credential's reach as { userId, scopes[] }, where each scope is a `namespace:value` string (e.g. \"org:<uuid>\"). Use this when the user asks 'what can you do here?'
|
|
10562
|
+
description: "Describe the credential the MCP server is operating under. Returns tenantId, environment (staging|production), principalType (root_key|scoped_key|token), principalKeyId, principalLabel, and (for scoped credentials) allowedActions plus dataScope \u2014 the credential's reach as { userId, scopes[] }, where each scope is a `namespace:value` string (e.g. \"org:<uuid>\"). Also reports mcpServerVersion (this server's own package version) and sdkVersion (the bundled @vectros-ai/sdk version) so a caller can tell what build it's talking to. Use this when the user asks 'what can you do here?', 'what tenant am I in?', or 'what version is this?'. Calls GET /v1/ping under the hood.",
|
|
10048
10563
|
inputSchema: inputSchema18,
|
|
10049
10564
|
handler: async () => {
|
|
10050
10565
|
try {
|
|
@@ -10522,7 +11037,7 @@ var identityResource = ({ log, apiKey, environment }) => ({
|
|
|
10522
11037
|
name: "identity",
|
|
10523
11038
|
uri: "vectros://identity",
|
|
10524
11039
|
title: "Current identity (tenant + principal scope)",
|
|
10525
|
-
description: "The tenant + principal scope the MCP server is authenticated as. Returns the same payload as the `current_identity` tool: status, tenantId, environment, principalType, principalKeyId, principalLabel,
|
|
11040
|
+
description: "The tenant + principal scope the MCP server is authenticated as. Returns the same payload as the `current_identity` tool: status, tenantId, environment, principalType, principalKeyId, principalLabel, (for scoped credentials) allowedActions + dataScope ({ userId, scopes[] }), plus mcpServerVersion and sdkVersion (this build's own version and the bundled @vectros-ai/sdk version). The /v1/ping backing call ships the extended shape today; the version fields are always client-derived.",
|
|
10526
11041
|
mimeType: "application/json",
|
|
10527
11042
|
read: async () => {
|
|
10528
11043
|
const identity = await resolveIdentity({ log, apiKey, environment });
|