@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.js
CHANGED
|
@@ -87,6 +87,7 @@ __export(api_exports, {
|
|
|
87
87
|
TooManyRequestsError: () => TooManyRequestsError,
|
|
88
88
|
TruncationWarningEvent: () => TruncationWarningEvent,
|
|
89
89
|
UnauthorizedError: () => UnauthorizedError,
|
|
90
|
+
UserExistsResponse: () => UserExistsResponse,
|
|
90
91
|
UserRequest: () => UserRequest,
|
|
91
92
|
UserResponse: () => UserResponse,
|
|
92
93
|
auth: () => auth_exports,
|
|
@@ -763,6 +764,14 @@ var TruncationWarningEvent;
|
|
|
763
764
|
ContextWindowBudget: "context_window_budget"
|
|
764
765
|
};
|
|
765
766
|
})(TruncationWarningEvent || (TruncationWarningEvent = {}));
|
|
767
|
+
var UserExistsResponse;
|
|
768
|
+
((UserExistsResponse2) => {
|
|
769
|
+
UserExistsResponse2.Status = {
|
|
770
|
+
Active: "ACTIVE",
|
|
771
|
+
Suspended: "SUSPENDED",
|
|
772
|
+
Pending: "PENDING"
|
|
773
|
+
};
|
|
774
|
+
})(UserExistsResponse || (UserExistsResponse = {}));
|
|
766
775
|
var UserRequest;
|
|
767
776
|
((UserRequest2) => {
|
|
768
777
|
UserRequest2.Status = {
|
|
@@ -2455,7 +2464,7 @@ var AuthClient = class {
|
|
|
2455
2464
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/admin/access-log");
|
|
2456
2465
|
}
|
|
2457
2466
|
/**
|
|
2458
|
-
* Lists
|
|
2467
|
+
* 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.
|
|
2459
2468
|
*
|
|
2460
2469
|
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
2461
2470
|
*
|
|
@@ -2506,7 +2515,7 @@ var AuthClient = class {
|
|
|
2506
2515
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/admin/keys/scoped");
|
|
2507
2516
|
}
|
|
2508
2517
|
/**
|
|
2509
|
-
* 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.
|
|
2518
|
+
* 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.
|
|
2510
2519
|
*
|
|
2511
2520
|
* @param {Vectros.CreateScopedKeyRequest} request
|
|
2512
2521
|
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -2838,7 +2847,7 @@ var AuthClient = class {
|
|
|
2838
2847
|
);
|
|
2839
2848
|
}
|
|
2840
2849
|
/**
|
|
2841
|
-
* 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.
|
|
2850
|
+
* 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.
|
|
2842
2851
|
*
|
|
2843
2852
|
* @param {Vectros.CreateAccessProfileRequest} request
|
|
2844
2853
|
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -3256,11 +3265,12 @@ var AuthClient = class {
|
|
|
3256
3265
|
);
|
|
3257
3266
|
}
|
|
3258
3267
|
/**
|
|
3259
|
-
* 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
|
|
3268
|
+
* 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.
|
|
3260
3269
|
*
|
|
3261
3270
|
* @param {Vectros.UpdateAccessProfileRequest} request
|
|
3262
3271
|
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
3263
3272
|
*
|
|
3273
|
+
* @throws {@link Vectros.BadRequestError}
|
|
3264
3274
|
* @throws {@link Vectros.ForbiddenError}
|
|
3265
3275
|
* @throws {@link Vectros.NotFoundError}
|
|
3266
3276
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
@@ -3307,6 +3317,8 @@ var AuthClient = class {
|
|
|
3307
3317
|
}
|
|
3308
3318
|
if (_response.error.reason === "status-code") {
|
|
3309
3319
|
switch (_response.error.statusCode) {
|
|
3320
|
+
case 400:
|
|
3321
|
+
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
3310
3322
|
case 403:
|
|
3311
3323
|
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
3312
3324
|
case 404:
|
|
@@ -3329,7 +3341,7 @@ var AuthClient = class {
|
|
|
3329
3341
|
);
|
|
3330
3342
|
}
|
|
3331
3343
|
/**
|
|
3332
|
-
* 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.
|
|
3344
|
+
* 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.
|
|
3333
3345
|
*
|
|
3334
3346
|
* @param {Vectros.DeleteAccessProfileRequest} request
|
|
3335
3347
|
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -3998,6 +4010,254 @@ var AuthClient = class {
|
|
|
3998
4010
|
}
|
|
3999
4011
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/usage");
|
|
4000
4012
|
}
|
|
4013
|
+
/**
|
|
4014
|
+
* Retrieves a single registered issuer by issuerId. Requires a root API key or the bootstrap's provisioning capability.
|
|
4015
|
+
*
|
|
4016
|
+
* @param {Vectros.GetIssuerRequest} request
|
|
4017
|
+
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
4018
|
+
*
|
|
4019
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
4020
|
+
* @throws {@link Vectros.NotFoundError}
|
|
4021
|
+
*
|
|
4022
|
+
* @example
|
|
4023
|
+
* await client.auth.getIssuer({
|
|
4024
|
+
* issuerId: "auth0-prod"
|
|
4025
|
+
* })
|
|
4026
|
+
*/
|
|
4027
|
+
getIssuer(request, requestOptions) {
|
|
4028
|
+
return HttpResponsePromise.fromPromise(this.__getIssuer(request, requestOptions));
|
|
4029
|
+
}
|
|
4030
|
+
async __getIssuer(request, requestOptions) {
|
|
4031
|
+
const { issuerId } = request;
|
|
4032
|
+
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
4033
|
+
const _headers = mergeHeaders(
|
|
4034
|
+
_authRequest.headers,
|
|
4035
|
+
this._options?.headers,
|
|
4036
|
+
requestOptions?.headers
|
|
4037
|
+
);
|
|
4038
|
+
const _response = await fetcher({
|
|
4039
|
+
url: url_exports.join(
|
|
4040
|
+
await Supplier.get(this._options.baseUrl) ?? await Supplier.get(this._options.environment),
|
|
4041
|
+
`v1/auth/issuers/${url_exports.encodePathParam(issuerId)}`
|
|
4042
|
+
),
|
|
4043
|
+
method: "GET",
|
|
4044
|
+
headers: _headers,
|
|
4045
|
+
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
4046
|
+
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
4047
|
+
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
4048
|
+
abortSignal: requestOptions?.abortSignal,
|
|
4049
|
+
fetchFn: this._options?.fetch,
|
|
4050
|
+
logging: this._options.logging
|
|
4051
|
+
});
|
|
4052
|
+
if (_response.ok) {
|
|
4053
|
+
return { data: _response.body, rawResponse: _response.rawResponse };
|
|
4054
|
+
}
|
|
4055
|
+
if (_response.error.reason === "status-code") {
|
|
4056
|
+
switch (_response.error.statusCode) {
|
|
4057
|
+
case 403:
|
|
4058
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
4059
|
+
case 404:
|
|
4060
|
+
throw new NotFoundError(_response.error.body, _response.rawResponse);
|
|
4061
|
+
default:
|
|
4062
|
+
throw new VectrosError({
|
|
4063
|
+
statusCode: _response.error.statusCode,
|
|
4064
|
+
body: _response.error.body,
|
|
4065
|
+
rawResponse: _response.rawResponse
|
|
4066
|
+
});
|
|
4067
|
+
}
|
|
4068
|
+
}
|
|
4069
|
+
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/auth/issuers/{issuerId}");
|
|
4070
|
+
}
|
|
4071
|
+
/**
|
|
4072
|
+
* 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.
|
|
4073
|
+
*
|
|
4074
|
+
* @param {Vectros.DeleteIssuerRequest} request
|
|
4075
|
+
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
4076
|
+
*
|
|
4077
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
4078
|
+
* @throws {@link Vectros.NotFoundError}
|
|
4079
|
+
* @throws {@link Vectros.TooManyRequestsError}
|
|
4080
|
+
*
|
|
4081
|
+
* @example
|
|
4082
|
+
* await client.auth.deleteIssuer({
|
|
4083
|
+
* issuerId: "auth0-prod"
|
|
4084
|
+
* })
|
|
4085
|
+
*/
|
|
4086
|
+
deleteIssuer(request, requestOptions) {
|
|
4087
|
+
return HttpResponsePromise.fromPromise(this.__deleteIssuer(request, requestOptions));
|
|
4088
|
+
}
|
|
4089
|
+
async __deleteIssuer(request, requestOptions) {
|
|
4090
|
+
const { issuerId } = request;
|
|
4091
|
+
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
4092
|
+
const _headers = mergeHeaders(
|
|
4093
|
+
_authRequest.headers,
|
|
4094
|
+
this._options?.headers,
|
|
4095
|
+
requestOptions?.headers
|
|
4096
|
+
);
|
|
4097
|
+
const _response = await fetcher({
|
|
4098
|
+
url: url_exports.join(
|
|
4099
|
+
await Supplier.get(this._options.baseUrl) ?? await Supplier.get(this._options.environment),
|
|
4100
|
+
`v1/auth/issuers/${url_exports.encodePathParam(issuerId)}`
|
|
4101
|
+
),
|
|
4102
|
+
method: "DELETE",
|
|
4103
|
+
headers: _headers,
|
|
4104
|
+
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
4105
|
+
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
4106
|
+
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
4107
|
+
abortSignal: requestOptions?.abortSignal,
|
|
4108
|
+
fetchFn: this._options?.fetch,
|
|
4109
|
+
logging: this._options.logging
|
|
4110
|
+
});
|
|
4111
|
+
if (_response.ok) {
|
|
4112
|
+
return { data: void 0, rawResponse: _response.rawResponse };
|
|
4113
|
+
}
|
|
4114
|
+
if (_response.error.reason === "status-code") {
|
|
4115
|
+
switch (_response.error.statusCode) {
|
|
4116
|
+
case 403:
|
|
4117
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
4118
|
+
case 404:
|
|
4119
|
+
throw new NotFoundError(_response.error.body, _response.rawResponse);
|
|
4120
|
+
case 429:
|
|
4121
|
+
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
4122
|
+
default:
|
|
4123
|
+
throw new VectrosError({
|
|
4124
|
+
statusCode: _response.error.statusCode,
|
|
4125
|
+
body: _response.error.body,
|
|
4126
|
+
rawResponse: _response.rawResponse
|
|
4127
|
+
});
|
|
4128
|
+
}
|
|
4129
|
+
}
|
|
4130
|
+
return handleNonStatusCodeError(
|
|
4131
|
+
_response.error,
|
|
4132
|
+
_response.rawResponse,
|
|
4133
|
+
"DELETE",
|
|
4134
|
+
"/v1/auth/issuers/{issuerId}"
|
|
4135
|
+
);
|
|
4136
|
+
}
|
|
4137
|
+
/**
|
|
4138
|
+
* Returns the issuers registered in your tenant. Requires a root API key or the bootstrap's provisioning capability. Returns a `{data, nextCursor}` envelope.
|
|
4139
|
+
*
|
|
4140
|
+
* @param {Vectros.ListIssuersRequest} request
|
|
4141
|
+
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
4142
|
+
*
|
|
4143
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
4144
|
+
*
|
|
4145
|
+
* @example
|
|
4146
|
+
* await client.auth.listIssuers()
|
|
4147
|
+
*/
|
|
4148
|
+
listIssuers(request = {}, requestOptions) {
|
|
4149
|
+
return HttpResponsePromise.fromPromise(this.__listIssuers(request, requestOptions));
|
|
4150
|
+
}
|
|
4151
|
+
async __listIssuers(request = {}, requestOptions) {
|
|
4152
|
+
const { startFrom, limit } = request;
|
|
4153
|
+
const _queryParams = {
|
|
4154
|
+
startFrom,
|
|
4155
|
+
limit
|
|
4156
|
+
};
|
|
4157
|
+
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
4158
|
+
const _headers = mergeHeaders(
|
|
4159
|
+
_authRequest.headers,
|
|
4160
|
+
this._options?.headers,
|
|
4161
|
+
requestOptions?.headers
|
|
4162
|
+
);
|
|
4163
|
+
const _response = await fetcher({
|
|
4164
|
+
url: url_exports.join(
|
|
4165
|
+
await Supplier.get(this._options.baseUrl) ?? await Supplier.get(this._options.environment),
|
|
4166
|
+
"v1/auth/issuers"
|
|
4167
|
+
),
|
|
4168
|
+
method: "GET",
|
|
4169
|
+
headers: _headers,
|
|
4170
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
4171
|
+
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
4172
|
+
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
4173
|
+
abortSignal: requestOptions?.abortSignal,
|
|
4174
|
+
fetchFn: this._options?.fetch,
|
|
4175
|
+
logging: this._options.logging
|
|
4176
|
+
});
|
|
4177
|
+
if (_response.ok) {
|
|
4178
|
+
return { data: _response.body, rawResponse: _response.rawResponse };
|
|
4179
|
+
}
|
|
4180
|
+
if (_response.error.reason === "status-code") {
|
|
4181
|
+
switch (_response.error.statusCode) {
|
|
4182
|
+
case 403:
|
|
4183
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
4184
|
+
default:
|
|
4185
|
+
throw new VectrosError({
|
|
4186
|
+
statusCode: _response.error.statusCode,
|
|
4187
|
+
body: _response.error.body,
|
|
4188
|
+
rawResponse: _response.rawResponse
|
|
4189
|
+
});
|
|
4190
|
+
}
|
|
4191
|
+
}
|
|
4192
|
+
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/auth/issuers");
|
|
4193
|
+
}
|
|
4194
|
+
/**
|
|
4195
|
+
* 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.
|
|
4196
|
+
*
|
|
4197
|
+
* @param {Vectros.IssuerRequest} request
|
|
4198
|
+
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
4199
|
+
*
|
|
4200
|
+
* @throws {@link Vectros.BadRequestError}
|
|
4201
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
4202
|
+
* @throws {@link Vectros.TooManyRequestsError}
|
|
4203
|
+
*
|
|
4204
|
+
* @example
|
|
4205
|
+
* await client.auth.registerIssuer({
|
|
4206
|
+
* issuerId: "auth0-prod",
|
|
4207
|
+
* issuer: "https://your-tenant.us.auth0.com/",
|
|
4208
|
+
* jwksUri: "https://your-tenant.us.auth0.com/.well-known/jwks.json",
|
|
4209
|
+
* audience: "https://api.your-app.example.com",
|
|
4210
|
+
* contextId: "casework"
|
|
4211
|
+
* })
|
|
4212
|
+
*/
|
|
4213
|
+
registerIssuer(request, requestOptions) {
|
|
4214
|
+
return HttpResponsePromise.fromPromise(this.__registerIssuer(request, requestOptions));
|
|
4215
|
+
}
|
|
4216
|
+
async __registerIssuer(request, requestOptions) {
|
|
4217
|
+
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
4218
|
+
const _headers = mergeHeaders(
|
|
4219
|
+
_authRequest.headers,
|
|
4220
|
+
this._options?.headers,
|
|
4221
|
+
requestOptions?.headers
|
|
4222
|
+
);
|
|
4223
|
+
const _response = await fetcher({
|
|
4224
|
+
url: url_exports.join(
|
|
4225
|
+
await Supplier.get(this._options.baseUrl) ?? await Supplier.get(this._options.environment),
|
|
4226
|
+
"v1/auth/issuers"
|
|
4227
|
+
),
|
|
4228
|
+
method: "POST",
|
|
4229
|
+
headers: _headers,
|
|
4230
|
+
contentType: "application/json",
|
|
4231
|
+
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
4232
|
+
requestType: "json",
|
|
4233
|
+
body: request,
|
|
4234
|
+
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
4235
|
+
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
4236
|
+
abortSignal: requestOptions?.abortSignal,
|
|
4237
|
+
fetchFn: this._options?.fetch,
|
|
4238
|
+
logging: this._options.logging
|
|
4239
|
+
});
|
|
4240
|
+
if (_response.ok) {
|
|
4241
|
+
return { data: _response.body, rawResponse: _response.rawResponse };
|
|
4242
|
+
}
|
|
4243
|
+
if (_response.error.reason === "status-code") {
|
|
4244
|
+
switch (_response.error.statusCode) {
|
|
4245
|
+
case 400:
|
|
4246
|
+
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
4247
|
+
case 403:
|
|
4248
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
4249
|
+
case 429:
|
|
4250
|
+
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
4251
|
+
default:
|
|
4252
|
+
throw new VectrosError({
|
|
4253
|
+
statusCode: _response.error.statusCode,
|
|
4254
|
+
body: _response.error.body,
|
|
4255
|
+
rawResponse: _response.rawResponse
|
|
4256
|
+
});
|
|
4257
|
+
}
|
|
4258
|
+
}
|
|
4259
|
+
return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/v1/auth/issuers");
|
|
4260
|
+
}
|
|
4001
4261
|
/**
|
|
4002
4262
|
* 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.
|
|
4003
4263
|
*
|
|
@@ -4183,7 +4443,7 @@ var AuthClient = class {
|
|
|
4183
4443
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/v1/auth/token");
|
|
4184
4444
|
}
|
|
4185
4445
|
/**
|
|
4186
|
-
* 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 `
|
|
4446
|
+
* 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.
|
|
4187
4447
|
*
|
|
4188
4448
|
* @param {Vectros.CreateInviteRequest} request
|
|
4189
4449
|
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -4254,7 +4514,7 @@ var AuthClient = class {
|
|
|
4254
4514
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/v1/users/invite");
|
|
4255
4515
|
}
|
|
4256
4516
|
/**
|
|
4257
|
-
* 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.
|
|
4517
|
+
* 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.
|
|
4258
4518
|
*
|
|
4259
4519
|
* @param {Vectros.CreateInviteRequest} request
|
|
4260
4520
|
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -4321,6 +4581,72 @@ var AuthClient = class {
|
|
|
4321
4581
|
}
|
|
4322
4582
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/v1/users/invite/resend");
|
|
4323
4583
|
}
|
|
4584
|
+
/**
|
|
4585
|
+
* 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.
|
|
4586
|
+
*
|
|
4587
|
+
* @param {Vectros.TokenExchangeRequest} request
|
|
4588
|
+
* @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
4589
|
+
*
|
|
4590
|
+
* @throws {@link Vectros.BadRequestError}
|
|
4591
|
+
* @throws {@link Vectros.UnauthorizedError}
|
|
4592
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
4593
|
+
* @throws {@link Vectros.NotFoundError}
|
|
4594
|
+
* @throws {@link Vectros.TooManyRequestsError}
|
|
4595
|
+
*
|
|
4596
|
+
* @example
|
|
4597
|
+
* await client.auth.exchangeToken({
|
|
4598
|
+
* grant_type: "urn:ietf:params:oauth:grant-type:token-exchange",
|
|
4599
|
+
* subject_token: "subject_token",
|
|
4600
|
+
* subject_token_type: "urn:ietf:params:oauth:token-type:jwt"
|
|
4601
|
+
* })
|
|
4602
|
+
*/
|
|
4603
|
+
exchangeToken(request, requestOptions) {
|
|
4604
|
+
return HttpResponsePromise.fromPromise(this.__exchangeToken(request, requestOptions));
|
|
4605
|
+
}
|
|
4606
|
+
async __exchangeToken(request, requestOptions) {
|
|
4607
|
+
const _headers = mergeHeaders(this._options?.headers, requestOptions?.headers);
|
|
4608
|
+
const _response = await fetcher({
|
|
4609
|
+
url: url_exports.join(
|
|
4610
|
+
await Supplier.get(this._options.baseUrl) ?? await Supplier.get(this._options.environment),
|
|
4611
|
+
"v1/auth/token/exchange"
|
|
4612
|
+
),
|
|
4613
|
+
method: "POST",
|
|
4614
|
+
headers: _headers,
|
|
4615
|
+
contentType: "application/json",
|
|
4616
|
+
queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
|
|
4617
|
+
requestType: "json",
|
|
4618
|
+
body: request,
|
|
4619
|
+
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
4620
|
+
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
4621
|
+
abortSignal: requestOptions?.abortSignal,
|
|
4622
|
+
fetchFn: this._options?.fetch,
|
|
4623
|
+
logging: this._options.logging
|
|
4624
|
+
});
|
|
4625
|
+
if (_response.ok) {
|
|
4626
|
+
return { data: _response.body, rawResponse: _response.rawResponse };
|
|
4627
|
+
}
|
|
4628
|
+
if (_response.error.reason === "status-code") {
|
|
4629
|
+
switch (_response.error.statusCode) {
|
|
4630
|
+
case 400:
|
|
4631
|
+
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
4632
|
+
case 401:
|
|
4633
|
+
throw new UnauthorizedError(_response.error.body, _response.rawResponse);
|
|
4634
|
+
case 403:
|
|
4635
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
4636
|
+
case 404:
|
|
4637
|
+
throw new NotFoundError(_response.error.body, _response.rawResponse);
|
|
4638
|
+
case 429:
|
|
4639
|
+
throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
|
|
4640
|
+
default:
|
|
4641
|
+
throw new VectrosError({
|
|
4642
|
+
statusCode: _response.error.statusCode,
|
|
4643
|
+
body: _response.error.body,
|
|
4644
|
+
rawResponse: _response.rawResponse
|
|
4645
|
+
});
|
|
4646
|
+
}
|
|
4647
|
+
}
|
|
4648
|
+
return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/v1/auth/token/exchange");
|
|
4649
|
+
}
|
|
4324
4650
|
};
|
|
4325
4651
|
var ComplianceClient = class {
|
|
4326
4652
|
constructor(options) {
|
|
@@ -4588,7 +4914,7 @@ var DocumentsClient = class {
|
|
|
4588
4914
|
* userId: "550e8400-e29b-41d4-a716-446655440000",
|
|
4589
4915
|
* scope: "group:eng-team",
|
|
4590
4916
|
* folderId: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
|
|
4591
|
-
* startFrom: "
|
|
4917
|
+
* startFrom: "b3BhcXVlLWN1cnNvci1mcm9tLXRoZS1wcmV2aW91cy1wYWdl"
|
|
4592
4918
|
* })
|
|
4593
4919
|
*/
|
|
4594
4920
|
listDocuments(request = {}, requestOptions) {
|
|
@@ -4898,6 +5224,7 @@ var DocumentsClient = class {
|
|
|
4898
5224
|
* @param {DocumentsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
4899
5225
|
*
|
|
4900
5226
|
* @throws {@link Vectros.BadRequestError}
|
|
5227
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
4901
5228
|
* @throws {@link Vectros.NotFoundError}
|
|
4902
5229
|
* @throws {@link Vectros.ConflictError}
|
|
4903
5230
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
@@ -4945,6 +5272,8 @@ var DocumentsClient = class {
|
|
|
4945
5272
|
switch (_response.error.statusCode) {
|
|
4946
5273
|
case 400:
|
|
4947
5274
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
5275
|
+
case 403:
|
|
5276
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
4948
5277
|
case 404:
|
|
4949
5278
|
throw new NotFoundError(_response.error.body, _response.rawResponse);
|
|
4950
5279
|
case 409:
|
|
@@ -4975,7 +5304,7 @@ var DocumentsClient = class {
|
|
|
4975
5304
|
* field: "po_number",
|
|
4976
5305
|
* value: "PO-1001",
|
|
4977
5306
|
* prefix: "PO-2024",
|
|
4978
|
-
* startFrom: "
|
|
5307
|
+
* startFrom: "b3BhcXVlLWN1cnNvci1mcm9tLXRoZS1wcmV2aW91cy1wYWdl",
|
|
4979
5308
|
* userId: "550e8400-e29b-41d4-a716-446655440000",
|
|
4980
5309
|
* scope: "org:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
|
|
4981
5310
|
* })
|
|
@@ -5351,7 +5680,7 @@ var FoldersClient = class {
|
|
|
5351
5680
|
* parentFolderId: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
|
|
5352
5681
|
* userId: "550e8400-e29b-41d4-a716-446655440000",
|
|
5353
5682
|
* scope: "group:eng-team",
|
|
5354
|
-
* startFrom: "
|
|
5683
|
+
* startFrom: "b3BhcXVlLWN1cnNvci1mcm9tLXRoZS1wcmV2aW91cy1wYWdl"
|
|
5355
5684
|
* })
|
|
5356
5685
|
*/
|
|
5357
5686
|
listFolders(request = {}, requestOptions) {
|
|
@@ -5528,6 +5857,7 @@ var FoldersClient = class {
|
|
|
5528
5857
|
* @param {Vectros.UpdateFolderRequest} request
|
|
5529
5858
|
* @param {FoldersClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
5530
5859
|
*
|
|
5860
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
5531
5861
|
* @throws {@link Vectros.NotFoundError}
|
|
5532
5862
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
5533
5863
|
*
|
|
@@ -5572,6 +5902,8 @@ var FoldersClient = class {
|
|
|
5572
5902
|
}
|
|
5573
5903
|
if (_response.error.reason === "status-code") {
|
|
5574
5904
|
switch (_response.error.statusCode) {
|
|
5905
|
+
case 403:
|
|
5906
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
5575
5907
|
case 404:
|
|
5576
5908
|
throw new NotFoundError(_response.error.body, _response.rawResponse);
|
|
5577
5909
|
case 429:
|
|
@@ -5654,6 +5986,7 @@ var FoldersClient = class {
|
|
|
5654
5986
|
* @param {FoldersClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
5655
5987
|
*
|
|
5656
5988
|
* @throws {@link Vectros.BadRequestError}
|
|
5989
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
5657
5990
|
* @throws {@link Vectros.NotFoundError}
|
|
5658
5991
|
* @throws {@link Vectros.ConflictError}
|
|
5659
5992
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
@@ -5701,6 +6034,8 @@ var FoldersClient = class {
|
|
|
5701
6034
|
switch (_response.error.statusCode) {
|
|
5702
6035
|
case 400:
|
|
5703
6036
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
6037
|
+
case 403:
|
|
6038
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
5704
6039
|
case 404:
|
|
5705
6040
|
throw new NotFoundError(_response.error.body, _response.rawResponse);
|
|
5706
6041
|
case 409:
|
|
@@ -5788,7 +6123,8 @@ var IdentityClient = class {
|
|
|
5788
6123
|
*
|
|
5789
6124
|
* @example
|
|
5790
6125
|
* await client.identity.listEntities({
|
|
5791
|
-
* namespace: "team"
|
|
6126
|
+
* namespace: "team",
|
|
6127
|
+
* startFrom: "b3BhcXVlLWN1cnNvci1mcm9tLXRoZS1wcmV2aW91cy1wYWdl"
|
|
5792
6128
|
* })
|
|
5793
6129
|
*/
|
|
5794
6130
|
listEntities(request, requestOptions) {
|
|
@@ -6552,7 +6888,7 @@ var IdentityClient = class {
|
|
|
6552
6888
|
* @example
|
|
6553
6889
|
* await client.identity.listUsers({
|
|
6554
6890
|
* externalId: "usr_12345",
|
|
6555
|
-
* startFrom: "
|
|
6891
|
+
* startFrom: "b3BhcXVlLWN1cnNvci1mcm9tLXRoZS1wcmV2aW91cy1wYWdl",
|
|
6556
6892
|
* type: "person_v1",
|
|
6557
6893
|
* field: "team",
|
|
6558
6894
|
* value: "engineering",
|
|
@@ -6733,11 +7069,12 @@ var IdentityClient = class {
|
|
|
6733
7069
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/users/{id}");
|
|
6734
7070
|
}
|
|
6735
7071
|
/**
|
|
6736
|
-
* 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.
|
|
7072
|
+
* 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.
|
|
6737
7073
|
*
|
|
6738
7074
|
* @param {Vectros.UpdateUserRequest} request
|
|
6739
7075
|
* @param {IdentityClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
6740
7076
|
*
|
|
7077
|
+
* @throws {@link Vectros.BadRequestError}
|
|
6741
7078
|
* @throws {@link Vectros.NotFoundError}
|
|
6742
7079
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
6743
7080
|
*
|
|
@@ -6782,6 +7119,8 @@ var IdentityClient = class {
|
|
|
6782
7119
|
}
|
|
6783
7120
|
if (_response.error.reason === "status-code") {
|
|
6784
7121
|
switch (_response.error.statusCode) {
|
|
7122
|
+
case 400:
|
|
7123
|
+
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
6785
7124
|
case 404:
|
|
6786
7125
|
throw new NotFoundError(_response.error.body, _response.rawResponse);
|
|
6787
7126
|
case 429:
|
|
@@ -6915,6 +7254,69 @@ var IdentityClient = class {
|
|
|
6915
7254
|
}
|
|
6916
7255
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/v1/users/lookup");
|
|
6917
7256
|
}
|
|
7257
|
+
/**
|
|
7258
|
+
* 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.
|
|
7259
|
+
*
|
|
7260
|
+
* @param {Vectros.UserExistsByEmailRequest} request
|
|
7261
|
+
* @param {IdentityClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
7262
|
+
*
|
|
7263
|
+
* @throws {@link Vectros.BadRequestError}
|
|
7264
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
7265
|
+
*
|
|
7266
|
+
* @example
|
|
7267
|
+
* await client.identity.userExistsByEmail({
|
|
7268
|
+
* email: "user@example.com",
|
|
7269
|
+
* contextId: "myapp"
|
|
7270
|
+
* })
|
|
7271
|
+
*/
|
|
7272
|
+
userExistsByEmail(request = {}, requestOptions) {
|
|
7273
|
+
return HttpResponsePromise.fromPromise(this.__userExistsByEmail(request, requestOptions));
|
|
7274
|
+
}
|
|
7275
|
+
async __userExistsByEmail(request = {}, requestOptions) {
|
|
7276
|
+
const { email, contextId } = request;
|
|
7277
|
+
const _queryParams = {
|
|
7278
|
+
email,
|
|
7279
|
+
contextId
|
|
7280
|
+
};
|
|
7281
|
+
const _authRequest = await this._options.authProvider.getAuthRequest();
|
|
7282
|
+
const _headers = mergeHeaders(
|
|
7283
|
+
_authRequest.headers,
|
|
7284
|
+
this._options?.headers,
|
|
7285
|
+
requestOptions?.headers
|
|
7286
|
+
);
|
|
7287
|
+
const _response = await fetcher({
|
|
7288
|
+
url: url_exports.join(
|
|
7289
|
+
await Supplier.get(this._options.baseUrl) ?? await Supplier.get(this._options.environment),
|
|
7290
|
+
"v1/users/exists-by-email"
|
|
7291
|
+
),
|
|
7292
|
+
method: "GET",
|
|
7293
|
+
headers: _headers,
|
|
7294
|
+
queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
7295
|
+
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
7296
|
+
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
7297
|
+
abortSignal: requestOptions?.abortSignal,
|
|
7298
|
+
fetchFn: this._options?.fetch,
|
|
7299
|
+
logging: this._options.logging
|
|
7300
|
+
});
|
|
7301
|
+
if (_response.ok) {
|
|
7302
|
+
return { data: _response.body, rawResponse: _response.rawResponse };
|
|
7303
|
+
}
|
|
7304
|
+
if (_response.error.reason === "status-code") {
|
|
7305
|
+
switch (_response.error.statusCode) {
|
|
7306
|
+
case 400:
|
|
7307
|
+
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
7308
|
+
case 403:
|
|
7309
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
7310
|
+
default:
|
|
7311
|
+
throw new VectrosError({
|
|
7312
|
+
statusCode: _response.error.statusCode,
|
|
7313
|
+
body: _response.error.body,
|
|
7314
|
+
rawResponse: _response.rawResponse
|
|
7315
|
+
});
|
|
7316
|
+
}
|
|
7317
|
+
}
|
|
7318
|
+
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/users/exists-by-email");
|
|
7319
|
+
}
|
|
6918
7320
|
/**
|
|
6919
7321
|
* 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.
|
|
6920
7322
|
*
|
|
@@ -7429,7 +7831,7 @@ var RecordsClient = class {
|
|
|
7429
7831
|
* folderId: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
|
|
7430
7832
|
* userId: "550e8400-e29b-41d4-a716-446655440000",
|
|
7431
7833
|
* scope: "group:eng-team",
|
|
7432
|
-
* startFrom: "
|
|
7834
|
+
* startFrom: "b3BhcXVlLWN1cnNvci1mcm9tLXRoZS1wcmV2aW91cy1wYWdl"
|
|
7433
7835
|
* })
|
|
7434
7836
|
*/
|
|
7435
7837
|
listRecords(request = {}, requestOptions) {
|
|
@@ -7617,6 +8019,7 @@ var RecordsClient = class {
|
|
|
7617
8019
|
* @param {RecordsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
7618
8020
|
*
|
|
7619
8021
|
* @throws {@link Vectros.BadRequestError}
|
|
8022
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
7620
8023
|
* @throws {@link Vectros.NotFoundError}
|
|
7621
8024
|
* @throws {@link Vectros.ConflictError}
|
|
7622
8025
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
@@ -7665,6 +8068,8 @@ var RecordsClient = class {
|
|
|
7665
8068
|
switch (_response.error.statusCode) {
|
|
7666
8069
|
case 400:
|
|
7667
8070
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
8071
|
+
case 403:
|
|
8072
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
7668
8073
|
case 404:
|
|
7669
8074
|
throw new NotFoundError(_response.error.body, _response.rawResponse);
|
|
7670
8075
|
case 409:
|
|
@@ -7746,6 +8151,7 @@ var RecordsClient = class {
|
|
|
7746
8151
|
* @param {RecordsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
7747
8152
|
*
|
|
7748
8153
|
* @throws {@link Vectros.BadRequestError}
|
|
8154
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
7749
8155
|
* @throws {@link Vectros.NotFoundError}
|
|
7750
8156
|
* @throws {@link Vectros.ConflictError}
|
|
7751
8157
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
@@ -7796,6 +8202,8 @@ var RecordsClient = class {
|
|
|
7796
8202
|
switch (_response.error.statusCode) {
|
|
7797
8203
|
case 400:
|
|
7798
8204
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
8205
|
+
case 403:
|
|
8206
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
7799
8207
|
case 404:
|
|
7800
8208
|
throw new NotFoundError(_response.error.body, _response.rawResponse);
|
|
7801
8209
|
case 409:
|
|
@@ -7813,7 +8221,15 @@ var RecordsClient = class {
|
|
|
7813
8221
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "PATCH", "/v1/records/{id}");
|
|
7814
8222
|
}
|
|
7815
8223
|
/**
|
|
7816
|
-
* 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.
|
|
8224
|
+
* 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.
|
|
8225
|
+
*
|
|
8226
|
+
* 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`.
|
|
8227
|
+
*
|
|
8228
|
+
* 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.
|
|
8229
|
+
*
|
|
8230
|
+
* 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.
|
|
8231
|
+
*
|
|
8232
|
+
* 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.
|
|
7817
8233
|
*
|
|
7818
8234
|
* @param {Vectros.LookupRecordsRequest} request
|
|
7819
8235
|
* @param {RecordsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -7825,22 +8241,40 @@ var RecordsClient = class {
|
|
|
7825
8241
|
* type: "intake_form",
|
|
7826
8242
|
* field: "email",
|
|
7827
8243
|
* value: "jane@example.com",
|
|
8244
|
+
* values: ["open"],
|
|
7828
8245
|
* prefix: "jane",
|
|
7829
|
-
* startFrom: "
|
|
8246
|
+
* startFrom: "b3BhcXVlLWN1cnNvci1mcm9tLXRoZS1wcmV2aW91cy1wYWdl"
|
|
7830
8247
|
* })
|
|
7831
8248
|
*/
|
|
7832
8249
|
lookupRecords(request, requestOptions) {
|
|
7833
8250
|
return HttpResponsePromise.fromPromise(this.__lookupRecords(request, requestOptions));
|
|
7834
8251
|
}
|
|
7835
8252
|
async __lookupRecords(request, requestOptions) {
|
|
7836
|
-
const {
|
|
8253
|
+
const {
|
|
8254
|
+
type: type_,
|
|
8255
|
+
field,
|
|
8256
|
+
value,
|
|
8257
|
+
values,
|
|
8258
|
+
from: from_,
|
|
8259
|
+
to,
|
|
8260
|
+
prefix,
|
|
8261
|
+
sortFrom,
|
|
8262
|
+
sortTo,
|
|
8263
|
+
startFrom,
|
|
8264
|
+
limit,
|
|
8265
|
+
includePayload,
|
|
8266
|
+
order
|
|
8267
|
+
} = request;
|
|
7837
8268
|
const _queryParams = {
|
|
7838
8269
|
type: type_,
|
|
7839
8270
|
field,
|
|
7840
8271
|
value,
|
|
8272
|
+
values,
|
|
7841
8273
|
from: from_,
|
|
7842
8274
|
to,
|
|
7843
8275
|
prefix,
|
|
8276
|
+
sortFrom,
|
|
8277
|
+
sortTo,
|
|
7844
8278
|
startFrom,
|
|
7845
8279
|
limit,
|
|
7846
8280
|
includePayload,
|
|
@@ -7884,7 +8318,7 @@ var RecordsClient = class {
|
|
|
7884
8318
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/records/lookup");
|
|
7885
8319
|
}
|
|
7886
8320
|
/**
|
|
7887
|
-
* 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.
|
|
8321
|
+
* 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.
|
|
7888
8322
|
*
|
|
7889
8323
|
* @param {Vectros.RecordLookupRequest} request
|
|
7890
8324
|
* @param {RecordsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -8079,7 +8513,7 @@ var SchemasClient = class {
|
|
|
8079
8513
|
* scope: "org:6ba7b810-9dad-11d1-80b4-00c04fd430c8",
|
|
8080
8514
|
* surface: "document",
|
|
8081
8515
|
* recordType: "intake_form",
|
|
8082
|
-
* startFrom: "
|
|
8516
|
+
* startFrom: "b3BhcXVlLWN1cnNvci1mcm9tLXRoZS1wcmV2aW91cy1wYWdl"
|
|
8083
8517
|
* })
|
|
8084
8518
|
*/
|
|
8085
8519
|
listSchemas(request = {}, requestOptions) {
|
|
@@ -8283,6 +8717,7 @@ var SchemasClient = class {
|
|
|
8283
8717
|
* @param {SchemasClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
8284
8718
|
*
|
|
8285
8719
|
* @throws {@link Vectros.BadRequestError}
|
|
8720
|
+
* @throws {@link Vectros.ForbiddenError}
|
|
8286
8721
|
* @throws {@link Vectros.NotFoundError}
|
|
8287
8722
|
* @throws {@link Vectros.TooManyRequestsError}
|
|
8288
8723
|
*
|
|
@@ -8331,6 +8766,8 @@ var SchemasClient = class {
|
|
|
8331
8766
|
switch (_response.error.statusCode) {
|
|
8332
8767
|
case 400:
|
|
8333
8768
|
throw new BadRequestError(_response.error.body, _response.rawResponse);
|
|
8769
|
+
case 403:
|
|
8770
|
+
throw new ForbiddenError(_response.error.body, _response.rawResponse);
|
|
8334
8771
|
case 404:
|
|
8335
8772
|
throw new NotFoundError(_response.error.body, _response.rawResponse);
|
|
8336
8773
|
case 429:
|
|
@@ -8636,15 +9073,15 @@ function warnOnSuboptimalKey(key, log) {
|
|
|
8636
9073
|
} else if (key.prefix === "st") {
|
|
8637
9074
|
log.warn(
|
|
8638
9075
|
{ prefix: key.prefix, env: key.env },
|
|
8639
|
-
"short-lived token (st_*) will expire mid-session (1h
|
|
9076
|
+
"short-lived token (st_*) will expire mid-session (1h max). For long-running MCP installs, prefer a long-lived ssk_* key."
|
|
8640
9077
|
);
|
|
8641
9078
|
}
|
|
8642
9079
|
}
|
|
8643
9080
|
|
|
8644
9081
|
// src/build-info.ts
|
|
8645
9082
|
var BUILD_INFO = {
|
|
8646
|
-
mcpServer: true ? "0.
|
|
8647
|
-
sdk: true ? "0.
|
|
9083
|
+
mcpServer: true ? "0.14.0" : "dev",
|
|
9084
|
+
sdk: true ? "0.39.0" : "dev"
|
|
8648
9085
|
};
|
|
8649
9086
|
function formatBuildInfo() {
|
|
8650
9087
|
return `vectros-mcp-server ${BUILD_INFO.mcpServer} (sdk ${BUILD_INFO.sdk})`;
|
|
@@ -8687,7 +9124,9 @@ async function resolveIdentity({
|
|
|
8687
9124
|
const derived = {
|
|
8688
9125
|
status: "ok",
|
|
8689
9126
|
environment: deriveEnvironment(environment),
|
|
8690
|
-
principalType: derivePrincipalType(apiKey)
|
|
9127
|
+
principalType: derivePrincipalType(apiKey),
|
|
9128
|
+
mcpServerVersion: BUILD_INFO.mcpServer,
|
|
9129
|
+
sdkVersion: BUILD_INFO.sdk
|
|
8691
9130
|
};
|
|
8692
9131
|
if (!apiKey || !environment) {
|
|
8693
9132
|
log.debug({ component: "identity", mode: "derived-only" }, "identity derived (no fetch)");
|
|
@@ -8715,7 +9154,13 @@ async function resolveIdentity({
|
|
|
8715
9154
|
);
|
|
8716
9155
|
}
|
|
8717
9156
|
}
|
|
8718
|
-
const merged = {
|
|
9157
|
+
const merged = {
|
|
9158
|
+
...derived,
|
|
9159
|
+
...extended,
|
|
9160
|
+
status: "ok",
|
|
9161
|
+
mcpServerVersion: derived.mcpServerVersion,
|
|
9162
|
+
sdkVersion: derived.sdkVersion
|
|
9163
|
+
};
|
|
8719
9164
|
log.debug(
|
|
8720
9165
|
{
|
|
8721
9166
|
component: "identity",
|
|
@@ -9037,14 +9482,23 @@ var import_zod2 = require("zod");
|
|
|
9037
9482
|
function pageItems(page) {
|
|
9038
9483
|
return page.data ?? [];
|
|
9039
9484
|
}
|
|
9485
|
+
var MAX_PAGES = 100;
|
|
9486
|
+
var MAX_ROWS = 1e6;
|
|
9040
9487
|
async function drainPages(fetchPage) {
|
|
9041
9488
|
const all = [];
|
|
9042
9489
|
let startFrom;
|
|
9490
|
+
let pages = 0;
|
|
9043
9491
|
for (; ; ) {
|
|
9044
9492
|
const page = await fetchPage(startFrom);
|
|
9045
|
-
|
|
9493
|
+
pages++;
|
|
9494
|
+
if (page.data?.length) for (const item of page.data) all.push(item);
|
|
9046
9495
|
const next = page.nextCursor;
|
|
9047
9496
|
if (!next) break;
|
|
9497
|
+
if (pages > MAX_PAGES || all.length > MAX_ROWS) {
|
|
9498
|
+
throw new Error(
|
|
9499
|
+
`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.`
|
|
9500
|
+
);
|
|
9501
|
+
}
|
|
9048
9502
|
startFrom = next;
|
|
9049
9503
|
}
|
|
9050
9504
|
return all;
|
|
@@ -9055,14 +9509,23 @@ var MCP_DEFAULT_LIMIT2 = 3;
|
|
|
9055
9509
|
var MCP_MAX_LIMIT2 = 100;
|
|
9056
9510
|
var inputSchema2 = {
|
|
9057
9511
|
type: import_zod2.z.string().min(1, "type (record type) is required").describe('Record type / schema name (e.g. "patient", "clinical_note").'),
|
|
9058
|
-
// Lookup-mode args — provide `field` plus EXACTLY ONE of: value | from+to | prefix.
|
|
9512
|
+
// Lookup-mode args — provide `field` plus EXACTLY ONE of: value | values | from+to | prefix.
|
|
9059
9513
|
field: import_zod2.z.string().optional().describe(
|
|
9060
|
-
'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.)'
|
|
9514
|
+
'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.'
|
|
9515
|
+
),
|
|
9516
|
+
value: import_zod2.z.string().optional().describe(
|
|
9517
|
+
"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)."
|
|
9518
|
+
),
|
|
9519
|
+
values: import_zod2.z.array(import_zod2.z.string()).min(1).max(3).optional().describe(
|
|
9520
|
+
'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).'
|
|
9061
9521
|
),
|
|
9062
|
-
value: import_zod2.z.string().optional().describe("Lookup mode (equality): exact-match value for `field`."),
|
|
9063
9522
|
from: import_zod2.z.string().optional().describe("Lookup mode (range): inclusive lower bound; requires `to`. Non-sensitive fields only."),
|
|
9064
9523
|
to: import_zod2.z.string().optional().describe("Lookup mode (range): inclusive upper bound; requires `from`."),
|
|
9065
9524
|
prefix: import_zod2.z.string().optional().describe("Lookup mode (prefix): match values starting with this. String, non-sensitive fields only."),
|
|
9525
|
+
sortFrom: import_zod2.z.string().optional().describe(
|
|
9526
|
+
"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`."
|
|
9527
|
+
),
|
|
9528
|
+
sortTo: import_zod2.z.string().optional().describe("Lookup mode (equality/composite only): inclusive upper bound on the sort key; pairs with `sortFrom`."),
|
|
9066
9529
|
order: import_zod2.z.enum(["asc", "desc"]).optional().describe(
|
|
9067
9530
|
"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."
|
|
9068
9531
|
),
|
|
@@ -9079,54 +9542,106 @@ var inputSchema2 = {
|
|
|
9079
9542
|
var recordQuery = ({ client, log }) => ({
|
|
9080
9543
|
name: "record_query",
|
|
9081
9544
|
title: "Record query (list or lookup)",
|
|
9082
|
-
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
|
|
9545
|
+
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.",
|
|
9083
9546
|
inputSchema: inputSchema2,
|
|
9084
9547
|
handler: async (args) => {
|
|
9085
9548
|
const limit = args.limit ?? MCP_DEFAULT_LIMIT2;
|
|
9086
9549
|
const type = args.type;
|
|
9087
9550
|
const field = args.field;
|
|
9088
9551
|
const value = args.value;
|
|
9552
|
+
const values = args.values;
|
|
9089
9553
|
const from = args.from;
|
|
9090
9554
|
const to = args.to;
|
|
9091
9555
|
const prefix = args.prefix;
|
|
9556
|
+
const sortFrom = args.sortFrom;
|
|
9557
|
+
const sortTo = args.sortTo;
|
|
9092
9558
|
const startFrom = args.startFrom;
|
|
9559
|
+
if (!field && (value !== void 0 || values !== void 0 || from !== void 0 || to !== void 0 || prefix !== void 0 || sortFrom !== void 0 || sortTo !== void 0)) {
|
|
9560
|
+
return toolError(
|
|
9561
|
+
"record_query",
|
|
9562
|
+
new Error(
|
|
9563
|
+
"'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."
|
|
9564
|
+
)
|
|
9565
|
+
);
|
|
9566
|
+
}
|
|
9093
9567
|
try {
|
|
9094
9568
|
let page;
|
|
9095
9569
|
if (field) {
|
|
9570
|
+
const fieldNames = field.split(",").map((f) => f.trim()).filter(Boolean);
|
|
9571
|
+
const normalizedField = fieldNames.join(",");
|
|
9572
|
+
const isCompositeField = fieldNames.length > 1;
|
|
9096
9573
|
const hasEquality = value !== void 0;
|
|
9574
|
+
const hasComposite = values !== void 0;
|
|
9097
9575
|
const hasRange = from !== void 0 || to !== void 0;
|
|
9098
9576
|
const hasPrefix = prefix !== void 0;
|
|
9099
|
-
const modes = Number(hasEquality) + Number(hasRange) + Number(hasPrefix);
|
|
9577
|
+
const modes = Number(hasEquality) + Number(hasComposite) + Number(hasRange) + Number(hasPrefix);
|
|
9100
9578
|
if (modes === 0) {
|
|
9101
9579
|
return toolError(
|
|
9102
9580
|
"record_query",
|
|
9103
9581
|
new Error(
|
|
9104
|
-
`lookup on field '${field}' needs one of: 'value' (exact), 'from'+'to' (range), or 'prefix'.`
|
|
9582
|
+
`lookup on field '${field}' needs one of: 'value' (exact), 'values' (composite exact), 'from'+'to' (range), or 'prefix'.`
|
|
9105
9583
|
)
|
|
9106
9584
|
);
|
|
9107
9585
|
}
|
|
9108
9586
|
if (modes > 1) {
|
|
9109
9587
|
return toolError(
|
|
9110
9588
|
"record_query",
|
|
9111
|
-
new Error(
|
|
9589
|
+
new Error(
|
|
9590
|
+
"'value', 'values', 'from'/'to', and 'prefix' are mutually exclusive \u2014 provide exactly one."
|
|
9591
|
+
)
|
|
9112
9592
|
);
|
|
9113
9593
|
}
|
|
9114
9594
|
if (hasRange && !(from !== void 0 && to !== void 0)) {
|
|
9115
9595
|
return toolError("record_query", new Error("range lookup requires both 'from' and 'to'."));
|
|
9116
9596
|
}
|
|
9597
|
+
if (isCompositeField && (hasRange || hasPrefix)) {
|
|
9598
|
+
return toolError(
|
|
9599
|
+
"record_query",
|
|
9600
|
+
new Error(
|
|
9601
|
+
`'field' names ${fieldNames.length} fields ('${normalizedField}') \u2014 a composite lookup is exact-match only ('value' or 'values'), not 'from'/'to'/'prefix'.`
|
|
9602
|
+
)
|
|
9603
|
+
);
|
|
9604
|
+
}
|
|
9605
|
+
if (hasComposite && values.length > fieldNames.length) {
|
|
9606
|
+
return toolError(
|
|
9607
|
+
"record_query",
|
|
9608
|
+
new Error(
|
|
9609
|
+
`'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).`
|
|
9610
|
+
)
|
|
9611
|
+
);
|
|
9612
|
+
}
|
|
9613
|
+
if (sortFrom !== void 0 || sortTo !== void 0) {
|
|
9614
|
+
if (!(hasEquality || hasComposite)) {
|
|
9615
|
+
return toolError(
|
|
9616
|
+
"record_query",
|
|
9617
|
+
new Error("'sortFrom'/'sortTo' narrow a 'value' or 'values' match only \u2014 not 'from'/'to'/'prefix'.")
|
|
9618
|
+
);
|
|
9619
|
+
}
|
|
9620
|
+
if (hasComposite && values.length < fieldNames.length) {
|
|
9621
|
+
return toolError(
|
|
9622
|
+
"record_query",
|
|
9623
|
+
new Error(
|
|
9624
|
+
`'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.`
|
|
9625
|
+
)
|
|
9626
|
+
);
|
|
9627
|
+
}
|
|
9628
|
+
}
|
|
9117
9629
|
page = await client.records.lookupRecordsByBody({
|
|
9118
9630
|
type,
|
|
9119
|
-
field,
|
|
9631
|
+
field: normalizedField,
|
|
9120
9632
|
value,
|
|
9633
|
+
values,
|
|
9121
9634
|
from,
|
|
9122
9635
|
to,
|
|
9123
9636
|
prefix,
|
|
9637
|
+
sortFrom,
|
|
9638
|
+
sortTo,
|
|
9124
9639
|
order: args.order,
|
|
9125
9640
|
startFrom,
|
|
9126
9641
|
limit
|
|
9127
9642
|
});
|
|
9128
9643
|
log.debug(
|
|
9129
|
-
{ tool: "record_query", mode: "lookup", type, field, returned: pageItems(page).length },
|
|
9644
|
+
{ tool: "record_query", mode: "lookup", type, field: normalizedField, returned: pageItems(page).length },
|
|
9130
9645
|
"record_query lookup ok"
|
|
9131
9646
|
);
|
|
9132
9647
|
} else {
|
|
@@ -10065,7 +10580,7 @@ var inputSchema18 = {
|
|
|
10065
10580
|
var currentIdentity = ({ log, apiKey, environment }) => ({
|
|
10066
10581
|
name: "current_identity",
|
|
10067
10582
|
title: "Current identity (tenant + principal scope)",
|
|
10068
|
-
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?'
|
|
10583
|
+
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.",
|
|
10069
10584
|
inputSchema: inputSchema18,
|
|
10070
10585
|
handler: async () => {
|
|
10071
10586
|
try {
|
|
@@ -10543,7 +11058,7 @@ var identityResource = ({ log, apiKey, environment }) => ({
|
|
|
10543
11058
|
name: "identity",
|
|
10544
11059
|
uri: "vectros://identity",
|
|
10545
11060
|
title: "Current identity (tenant + principal scope)",
|
|
10546
|
-
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,
|
|
11061
|
+
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.",
|
|
10547
11062
|
mimeType: "application/json",
|
|
10548
11063
|
read: async () => {
|
|
10549
11064
|
const identity = await resolveIdentity({ log, apiKey, environment });
|