@layervai/qurl 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +153 -16
- package/dist/cjs/client.d.ts +164 -4
- package/dist/cjs/client.js +483 -6
- package/dist/cjs/errors.d.ts +4 -0
- package/dist/cjs/errors.js +5 -1
- package/dist/cjs/index.d.ts +3 -3
- package/dist/cjs/index.js +4 -1
- package/dist/cjs/types.d.ts +83 -0
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/client.d.ts +164 -4
- package/dist/esm/client.d.ts.map +1 -1
- package/dist/esm/client.js +482 -6
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/errors.d.ts +4 -0
- package/dist/esm/errors.d.ts.map +1 -1
- package/dist/esm/errors.js +4 -0
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/index.d.ts +3 -3
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +2 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types.d.ts +83 -0
- package/dist/esm/types.d.ts.map +1 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/package.json +1 -1
package/dist/cjs/client.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.QURLClient = void 0;
|
|
3
|
+
exports.ProtectedResource = exports.QURLClient = void 0;
|
|
4
4
|
const errors_js_1 = require("./errors.js");
|
|
5
5
|
const version_js_1 = require("./version.js");
|
|
6
6
|
const DEFAULT_BASE_URL = "https://api.layerv.ai";
|
|
@@ -130,6 +130,27 @@ const CREATE_QURL_FOR_RESOURCE_FIELD_KEYS = [
|
|
|
130
130
|
"target_path",
|
|
131
131
|
];
|
|
132
132
|
assertExhaustive(true);
|
|
133
|
+
/**
|
|
134
|
+
* Options accepted by the portal-verb `protectUrl` / `createPortal`
|
|
135
|
+
* surface. These are camelCase caller-facing options (the portal verbs are
|
|
136
|
+
* the idiomatic layer); the build helpers map them onto the same wire
|
|
137
|
+
* fields the REST-shaped methods send.
|
|
138
|
+
*/
|
|
139
|
+
const PROTECT_URL_OPTION_KEYS = [
|
|
140
|
+
"description",
|
|
141
|
+
"tags",
|
|
142
|
+
"customDomain",
|
|
143
|
+
"alias",
|
|
144
|
+
];
|
|
145
|
+
assertExhaustive(true);
|
|
146
|
+
const CREATE_PORTAL_OPTION_KEYS = [
|
|
147
|
+
"validFor",
|
|
148
|
+
"label",
|
|
149
|
+
"oneTimeUse",
|
|
150
|
+
"maxSessions",
|
|
151
|
+
"sessionDuration",
|
|
152
|
+
];
|
|
153
|
+
assertExhaustive(true);
|
|
133
154
|
const UPDATE_RESOURCE_QURL_FIELD_KEYS = [
|
|
134
155
|
"extend_by",
|
|
135
156
|
"expires_at",
|
|
@@ -379,11 +400,11 @@ function requireNonEmptyIfPresent(value, field) {
|
|
|
379
400
|
throw clientValidationError(`${field}: must not be an empty string`);
|
|
380
401
|
}
|
|
381
402
|
}
|
|
382
|
-
function requireMaxSessionsInRange(value) {
|
|
403
|
+
function requireMaxSessionsInRange(value, field = "max_sessions") {
|
|
383
404
|
if (value === undefined)
|
|
384
405
|
return;
|
|
385
406
|
if (!Number.isInteger(value) || value < 0 || value > MAX_MAX_SESSIONS) {
|
|
386
|
-
throw clientValidationError(
|
|
407
|
+
throw clientValidationError(`${field}: must be an integer between 0 and ${MAX_MAX_SESSIONS} (got ${value})`);
|
|
387
408
|
}
|
|
388
409
|
}
|
|
389
410
|
function requireBooleanIfPresent(value, field) {
|
|
@@ -890,6 +911,195 @@ function batchItemResultValidationReason(entry) {
|
|
|
890
911
|
}
|
|
891
912
|
return "missing/invalid 'success' discriminant (expected boolean)";
|
|
892
913
|
}
|
|
914
|
+
// ---- Portal-verb helpers (mirrors qurl-go) -------------------------------
|
|
915
|
+
// Client-side guardrails for the portal flow (protectUrl → createPortal →
|
|
916
|
+
// enterPortal), kept in lockstep with qurl-go's option validation and
|
|
917
|
+
// qurl-python's port of it.
|
|
918
|
+
/**
|
|
919
|
+
* Client-side floor for portal lifetimes, mirroring qurl-go's `ValidFor`.
|
|
920
|
+
* The LayerV API remains the source of truth for account limits; there is
|
|
921
|
+
* intentionally no SDK-side maximum because an account may allow
|
|
922
|
+
* longer-lived portals.
|
|
923
|
+
*/
|
|
924
|
+
const MIN_PORTAL_VALID_FOR_SECONDS = 60;
|
|
925
|
+
/**
|
|
926
|
+
* Client-side floor for session durations, mirroring qurl-go's
|
|
927
|
+
* `WithSessionDuration` (at least one second; zero is rejected rather than
|
|
928
|
+
* treated as the server default).
|
|
929
|
+
*/
|
|
930
|
+
const MIN_SESSION_DURATION_SECONDS = 1;
|
|
931
|
+
// Shape of qurl-go's offline signed-fragment links: three or more
|
|
932
|
+
// dot-separated base64url parts (<version>.<claims>.<secret>.<sig>).
|
|
933
|
+
// Detected only to give those links a precise error in extractAccessToken.
|
|
934
|
+
const SIGNED_FRAGMENT_RE = /^[A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+){2,}$/;
|
|
935
|
+
// Access-token grammar accepted by enterPortal (base64url charset).
|
|
936
|
+
const ACCESS_TOKEN_RE = /^[A-Za-z0-9_-]+$/;
|
|
937
|
+
/**
|
|
938
|
+
* Serialize a duration option to the API's h/m/s duration grammar.
|
|
939
|
+
*
|
|
940
|
+
* Strings pass through unvalidated — the server is authoritative, same as
|
|
941
|
+
* the REST-shaped `expires_in` fields. Numbers are milliseconds and get
|
|
942
|
+
* qurl-go's client-side guardrails: whole seconds only and at least
|
|
943
|
+
* `minimumSeconds` (checked in that order so e.g. 30.5s reports "at least
|
|
944
|
+
* 60s" in every SDK). Serialized with hours as the largest unit so all API
|
|
945
|
+
* duration fields use the same grammar across SDKs.
|
|
946
|
+
*/
|
|
947
|
+
function serializeApiDuration(value, field, minimumSeconds) {
|
|
948
|
+
if (value === undefined)
|
|
949
|
+
return undefined;
|
|
950
|
+
if (typeof value === "string") {
|
|
951
|
+
if (value.trim() === "") {
|
|
952
|
+
throw clientValidationError(`${field}: must be a non-empty duration string`);
|
|
953
|
+
}
|
|
954
|
+
return value;
|
|
955
|
+
}
|
|
956
|
+
if (typeof value === "number") {
|
|
957
|
+
// NaN fails no comparison, so an explicit finite check keeps the
|
|
958
|
+
// error actionable instead of a misleading "whole seconds" report.
|
|
959
|
+
if (!Number.isFinite(value)) {
|
|
960
|
+
throw clientValidationError(`${field}: must be a finite number of milliseconds`);
|
|
961
|
+
}
|
|
962
|
+
if (value < minimumSeconds * 1000) {
|
|
963
|
+
throw clientValidationError(`${field}: must be at least ${minimumSeconds}s`);
|
|
964
|
+
}
|
|
965
|
+
if (value % 1000 !== 0) {
|
|
966
|
+
throw clientValidationError(`${field}: must be whole seconds`);
|
|
967
|
+
}
|
|
968
|
+
const seconds = value / 1000;
|
|
969
|
+
if (seconds % 3600 === 0)
|
|
970
|
+
return `${seconds / 3600}h`;
|
|
971
|
+
if (seconds % 60 === 0)
|
|
972
|
+
return `${seconds / 60}m`;
|
|
973
|
+
return `${seconds}s`;
|
|
974
|
+
}
|
|
975
|
+
throw clientValidationError(`${field}: must be a duration string (e.g. "5m") or a number of milliseconds`);
|
|
976
|
+
}
|
|
977
|
+
/**
|
|
978
|
+
* Portal-verb target URL validation (qurl-go `ProtectURL` parity). On top of
|
|
979
|
+
* the shared scheme/length check, the URL must carry a host and must parse,
|
|
980
|
+
* and embedded credentials (userinfo) are rejected. The added checks never
|
|
981
|
+
* echo the URL — a userinfo URL contains credentials that must stay out of
|
|
982
|
+
* logs and error messages. The REST-shaped compatibility layer keeps its
|
|
983
|
+
* original prefix-only check so its accepted inputs don't change.
|
|
984
|
+
*/
|
|
985
|
+
function requirePortalTargetUrl(targetUrl) {
|
|
986
|
+
requireValidTargetUrl(targetUrl);
|
|
987
|
+
const url = targetUrl; // requireValidTargetUrl only returns for http(s) strings
|
|
988
|
+
// WHATWG URL normalizes away an empty authority ("https:///x" parses
|
|
989
|
+
// with host "x"), so the host-presence check runs on the raw string,
|
|
990
|
+
// mirroring qurl-go's url.Parse which rejects authority-less URLs.
|
|
991
|
+
const afterScheme = url.slice(url.indexOf("://") + 3);
|
|
992
|
+
if (afterScheme === "" || "/?#".includes(afterScheme[0])) {
|
|
993
|
+
throw clientValidationError("target_url: must include a host");
|
|
994
|
+
}
|
|
995
|
+
let parsed;
|
|
996
|
+
try {
|
|
997
|
+
parsed = new URL(url);
|
|
998
|
+
}
|
|
999
|
+
catch {
|
|
1000
|
+
throw clientValidationError("target_url: malformed URL");
|
|
1001
|
+
}
|
|
1002
|
+
if (parsed.username !== "" || parsed.password !== "") {
|
|
1003
|
+
throw clientValidationError("target_url: must not include embedded credentials (userinfo)");
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
/**
|
|
1007
|
+
* Extract the access token from a qURL link, or pass a bare token through.
|
|
1008
|
+
*
|
|
1009
|
+
* Platform-issued links carry the access token in the URL fragment
|
|
1010
|
+
* (`https://qurl.link/#at_...`). Error messages deliberately never echo the
|
|
1011
|
+
* input — qURL links are credentials and must stay out of logs.
|
|
1012
|
+
*/
|
|
1013
|
+
function extractAccessToken(qurlLink) {
|
|
1014
|
+
if (typeof qurlLink !== "string" || qurlLink.trim() === "") {
|
|
1015
|
+
throw clientValidationError("qurlLink: must be a non-empty string");
|
|
1016
|
+
}
|
|
1017
|
+
const hashIndex = qurlLink.indexOf("#");
|
|
1018
|
+
const token = hashIndex >= 0 ? qurlLink.slice(hashIndex + 1) : qurlLink;
|
|
1019
|
+
if (SIGNED_FRAGMENT_RE.test(token)) {
|
|
1020
|
+
throw clientValidationError("qurlLink: this is a signed qURL link (offline fragment format), which cannot be " +
|
|
1021
|
+
"opened through the API resolver — enterPortal only accepts platform links " +
|
|
1022
|
+
"(https://qurl.link/#at_...) or bare access tokens");
|
|
1023
|
+
}
|
|
1024
|
+
if (token === "" || !ACCESS_TOKEN_RE.test(token)) {
|
|
1025
|
+
throw clientValidationError("qurlLink: no access token found — pass a platform qURL link " +
|
|
1026
|
+
"(https://qurl.link/#at_...) or a bare access token");
|
|
1027
|
+
}
|
|
1028
|
+
return token;
|
|
1029
|
+
}
|
|
1030
|
+
/**
|
|
1031
|
+
* Parse an RFC 3339 timestamp from the API into a `Date`, or `undefined`
|
|
1032
|
+
* when absent or unparseable. The portal surface exposes `Date` (matching
|
|
1033
|
+
* qurl-go's `time.Time` and qurl-python's `datetime`); the REST-shaped
|
|
1034
|
+
* layer keeps raw wire strings.
|
|
1035
|
+
*/
|
|
1036
|
+
function parseApiDate(value) {
|
|
1037
|
+
if (typeof value !== "string" || value === "")
|
|
1038
|
+
return undefined;
|
|
1039
|
+
const parsed = new Date(value);
|
|
1040
|
+
return Number.isNaN(parsed.getTime()) ? undefined : parsed;
|
|
1041
|
+
}
|
|
1042
|
+
/**
|
|
1043
|
+
* Parse a {@link Portal} from a create-portal API response. `resource_id`
|
|
1044
|
+
* and `qurl_link` are required, mirroring qurl-go's fail-closed response
|
|
1045
|
+
* check; everything else is optional because the two mint endpoints differ
|
|
1046
|
+
* in which ancillary fields they return.
|
|
1047
|
+
*/
|
|
1048
|
+
function parsePortal(data, method) {
|
|
1049
|
+
if (typeof data?.resource_id !== "string" || data.resource_id.trim() === "") {
|
|
1050
|
+
throw unexpectedResponseError(`${method}: response is missing resource_id`);
|
|
1051
|
+
}
|
|
1052
|
+
if (typeof data.qurl_link !== "string" || data.qurl_link.trim() === "") {
|
|
1053
|
+
throw unexpectedResponseError(`${method}: response is missing qurl_link`);
|
|
1054
|
+
}
|
|
1055
|
+
return {
|
|
1056
|
+
resourceId: data.resource_id,
|
|
1057
|
+
link: data.qurl_link,
|
|
1058
|
+
site: data.qurl_site,
|
|
1059
|
+
expiresAt: parseApiDate(data.expires_at),
|
|
1060
|
+
// Same empty-string → absent normalization the REST-shaped layer's
|
|
1061
|
+
// consumers apply to qurl_id.
|
|
1062
|
+
qurlId: data.qurl_id || undefined,
|
|
1063
|
+
label: data.label,
|
|
1064
|
+
};
|
|
1065
|
+
}
|
|
1066
|
+
/**
|
|
1067
|
+
* Validate portal options and build the create-portal wire body, or
|
|
1068
|
+
* `undefined` when every option is omitted so no request body is sent and
|
|
1069
|
+
* the server applies its default lifetime (matching mintLink /
|
|
1070
|
+
* createQurlForResource).
|
|
1071
|
+
*/
|
|
1072
|
+
function buildCreatePortalBody(opts, method) {
|
|
1073
|
+
requireObjectInput(opts, method);
|
|
1074
|
+
requireNoUnknownFields(opts, CREATE_PORTAL_OPTION_KEYS, method);
|
|
1075
|
+
// null → omitted, via the SDK-wide normalizePatchFields convention.
|
|
1076
|
+
const { validFor, label, oneTimeUse, maxSessions, sessionDuration } = normalizePatchFields(opts, CREATE_PORTAL_OPTION_KEYS);
|
|
1077
|
+
if (label !== undefined) {
|
|
1078
|
+
requireMaxLength(label, "label", MAX_LABEL);
|
|
1079
|
+
// qurl-go's WithLabel rejects blank labels; the REST-shaped mintLink
|
|
1080
|
+
// keeps its permissive whitespace behavior, so the check lives here.
|
|
1081
|
+
if (label.trim() === "") {
|
|
1082
|
+
throw clientValidationError("label: must not be empty");
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
requireBooleanIfPresent(oneTimeUse, "oneTimeUse");
|
|
1086
|
+
requireMaxSessionsInRange(maxSessions, "maxSessions");
|
|
1087
|
+
const body = {};
|
|
1088
|
+
const expiresIn = serializeApiDuration(validFor, "validFor", MIN_PORTAL_VALID_FOR_SECONDS);
|
|
1089
|
+
if (expiresIn !== undefined)
|
|
1090
|
+
body.expires_in = expiresIn;
|
|
1091
|
+
if (label !== undefined)
|
|
1092
|
+
body.label = label;
|
|
1093
|
+
if (oneTimeUse !== undefined)
|
|
1094
|
+
body.one_time_use = oneTimeUse;
|
|
1095
|
+
// Explicit 0 means unlimited and must survive body construction.
|
|
1096
|
+
if (maxSessions !== undefined)
|
|
1097
|
+
body.max_sessions = maxSessions;
|
|
1098
|
+
const wireSessionDuration = serializeApiDuration(sessionDuration, "sessionDuration", MIN_SESSION_DURATION_SECONDS);
|
|
1099
|
+
if (wireSessionDuration !== undefined)
|
|
1100
|
+
body.session_duration = wireSessionDuration;
|
|
1101
|
+
return Object.keys(body).length > 0 ? body : undefined;
|
|
1102
|
+
}
|
|
893
1103
|
/** qURL API client. */
|
|
894
1104
|
class QURLClient {
|
|
895
1105
|
baseUrl;
|
|
@@ -1147,8 +1357,214 @@ class QURLClient {
|
|
|
1147
1357
|
}
|
|
1148
1358
|
} while (cursor);
|
|
1149
1359
|
}
|
|
1360
|
+
// --- Portal API (mirrors qurl-go: ProtectURL → CreatePortal → EnterPortal) ---
|
|
1361
|
+
/**
|
|
1362
|
+
* Protect a private URL — create or reuse its LayerV resource.
|
|
1363
|
+
*
|
|
1364
|
+
* The first step of the portal flow (qurl-go: `Client.ProtectURL`).
|
|
1365
|
+
* Protect the URL once, then mint short-lived links for it with
|
|
1366
|
+
* {@link ProtectedResource.createPortal}:
|
|
1367
|
+
*
|
|
1368
|
+
* ```ts
|
|
1369
|
+
* const resource = await client.protectUrl("https://internal.example.com/dashboard");
|
|
1370
|
+
* const portal = await resource.createPortal({ validFor: "5m" });
|
|
1371
|
+
* share(portal.link);
|
|
1372
|
+
* ```
|
|
1373
|
+
*
|
|
1374
|
+
* Protecting the same target URL again returns the existing resource.
|
|
1375
|
+
* Malformed URLs and URLs with embedded credentials (userinfo) are
|
|
1376
|
+
* rejected before any request, mirroring qurl-go. REST-shaped equivalent:
|
|
1377
|
+
* {@link createResource}.
|
|
1378
|
+
*/
|
|
1379
|
+
async protectUrl(targetUrl, opts = {}, requestOptions) {
|
|
1380
|
+
requirePortalTargetUrl(targetUrl);
|
|
1381
|
+
requireObjectInput(opts, "protectUrl");
|
|
1382
|
+
requireNoUnknownFields(opts, PROTECT_URL_OPTION_KEYS, "protectUrl");
|
|
1383
|
+
// camelCase options → wire fields; null is treated as omitted, via the
|
|
1384
|
+
// SDK-wide normalizePatchFields convention.
|
|
1385
|
+
const normalized = normalizePatchFields(opts, PROTECT_URL_OPTION_KEYS);
|
|
1386
|
+
const body = { target_url: targetUrl };
|
|
1387
|
+
if (normalized.description !== undefined)
|
|
1388
|
+
body.description = normalized.description;
|
|
1389
|
+
if (normalized.tags !== undefined)
|
|
1390
|
+
body.tags = normalized.tags;
|
|
1391
|
+
if (normalized.customDomain !== undefined)
|
|
1392
|
+
body.custom_domain = normalized.customDomain;
|
|
1393
|
+
if (normalized.alias !== undefined)
|
|
1394
|
+
body.alias = normalized.alias;
|
|
1395
|
+
validateResourceWriteFields(body);
|
|
1396
|
+
const resource = await this.request("POST", "/v1/resources", body, requestOptions);
|
|
1397
|
+
if (typeof resource?.resource_id !== "string" || resource.resource_id.trim() === "") {
|
|
1398
|
+
throw unexpectedResponseError("protectUrl: response is missing resource_id");
|
|
1399
|
+
}
|
|
1400
|
+
return new ProtectedResource(this, resource.resource_id,
|
|
1401
|
+
// Some resource types redact target_url in responses; fall back to
|
|
1402
|
+
// the caller-supplied URL so the handle stays useful.
|
|
1403
|
+
resource.target_url || targetUrl, resource);
|
|
1404
|
+
}
|
|
1405
|
+
/**
|
|
1406
|
+
* Return a portal-minting handle for a stored resource id, without an API
|
|
1407
|
+
* call.
|
|
1408
|
+
*
|
|
1409
|
+
* Use when you persisted a LayerV resource id and want to mint more
|
|
1410
|
+
* portals for it (qurl-go: `Client.ResourceByID`):
|
|
1411
|
+
*
|
|
1412
|
+
* ```ts
|
|
1413
|
+
* const resource = client.resourceById("r_demo1234567");
|
|
1414
|
+
* const portal = await resource.createPortal({ validFor: "1h" });
|
|
1415
|
+
* ```
|
|
1416
|
+
*
|
|
1417
|
+
* The handle carries no server metadata; use {@link getResource} when you
|
|
1418
|
+
* need the full resource details.
|
|
1419
|
+
*/
|
|
1420
|
+
resourceById(id) {
|
|
1421
|
+
requireNonEmptyId(id, "resourceById");
|
|
1422
|
+
return new ProtectedResource(this, id);
|
|
1423
|
+
}
|
|
1424
|
+
/**
|
|
1425
|
+
* Return the resource qURL Connector created for `connectorId`.
|
|
1426
|
+
*
|
|
1427
|
+
* Use when qURL Connector already protects the service — do not call
|
|
1428
|
+
* {@link protectUrl} again for the same service. The connector id is the
|
|
1429
|
+
* resource slug LayerV stores for that connector; the LayerV API performs
|
|
1430
|
+
* the slug lookup, and the SDK confirms the returned alias matches
|
|
1431
|
+
* `connectorId` before binding the handle (qurl-go:
|
|
1432
|
+
* `Client.ConnectorResource`).
|
|
1433
|
+
*
|
|
1434
|
+
* Throws {@link NotFoundError} (`status: 0`, `code: "resource_not_found"`)
|
|
1435
|
+
* when no resource exists for the connector id, {@link QURLError}
|
|
1436
|
+
* (`code: "ambiguous_resource"`) when the lookup returns more than one
|
|
1437
|
+
* resource, and {@link ValidationError} (`code: "unexpected_response"`)
|
|
1438
|
+
* when the returned resource's alias is missing or does not match.
|
|
1439
|
+
*/
|
|
1440
|
+
async connectorResource(connectorId) {
|
|
1441
|
+
requireNonEmptyId(connectorId, "connectorResource", "connector id");
|
|
1442
|
+
const { resources } = await this.listResources({ slug: connectorId });
|
|
1443
|
+
if (resources.length === 0) {
|
|
1444
|
+
throw new errors_js_1.NotFoundError({
|
|
1445
|
+
status: 0,
|
|
1446
|
+
code: errors_js_1.ERROR_CODE_RESOURCE_NOT_FOUND,
|
|
1447
|
+
title: "Resource Not Found",
|
|
1448
|
+
detail: `connectorResource: no resource found for connector "${connectorId}"`,
|
|
1449
|
+
});
|
|
1450
|
+
}
|
|
1451
|
+
if (resources.length > 1) {
|
|
1452
|
+
throw new errors_js_1.QURLError({
|
|
1453
|
+
status: 0,
|
|
1454
|
+
code: errors_js_1.ERROR_CODE_AMBIGUOUS_RESOURCE,
|
|
1455
|
+
title: "Ambiguous Resource",
|
|
1456
|
+
detail: `connectorResource: connector "${connectorId}" returned ${resources.length} resources`,
|
|
1457
|
+
});
|
|
1458
|
+
}
|
|
1459
|
+
const resource = resources[0];
|
|
1460
|
+
if (resource.alias !== connectorId) {
|
|
1461
|
+
throw unexpectedResponseError(`connectorResource: connector "${connectorId}" returned a resource with a missing or different alias`);
|
|
1462
|
+
}
|
|
1463
|
+
if (typeof resource.resource_id !== "string" || resource.resource_id.trim() === "") {
|
|
1464
|
+
throw unexpectedResponseError("connectorResource: response is missing resource_id");
|
|
1465
|
+
}
|
|
1466
|
+
return new ProtectedResource(this, resource.resource_id, resource.target_url, resource);
|
|
1467
|
+
}
|
|
1468
|
+
/**
|
|
1469
|
+
* Mint a short-lived qURL link (a portal) for a protected resource.
|
|
1470
|
+
*
|
|
1471
|
+
* A portal is cryptographic, just-in-time permission for one actor to
|
|
1472
|
+
* reach one private resource. Recipients open `portal.link` directly and
|
|
1473
|
+
* need no LayerV credentials. Prefer short lifetimes such as
|
|
1474
|
+
* `{ validFor: "5m" }`. Accepts a {@link ProtectedResource} handle or a
|
|
1475
|
+
* resource id (`r_` prefix). REST-shaped equivalents: {@link mintLink} /
|
|
1476
|
+
* {@link createQurlForResource}.
|
|
1477
|
+
*
|
|
1478
|
+
* Duration options take a string (`"5m"`, `"24h"`; server-validated) or a
|
|
1479
|
+
* number of milliseconds with qurl-go's client-side guardrails: whole
|
|
1480
|
+
* seconds only, at least one minute for `validFor` and one second for
|
|
1481
|
+
* `sessionDuration`. `maxSessions: 0` is sent explicitly and means
|
|
1482
|
+
* unlimited; blank labels are rejected.
|
|
1483
|
+
*/
|
|
1484
|
+
async createPortal(resource, opts = {}, requestOptions) {
|
|
1485
|
+
let resourceId;
|
|
1486
|
+
if (typeof resource === "string") {
|
|
1487
|
+
resourceId = resource;
|
|
1488
|
+
}
|
|
1489
|
+
else if (resource instanceof ProtectedResource) {
|
|
1490
|
+
if (!ProtectedResource.isBoundTo(resource, this)) {
|
|
1491
|
+
throw clientValidationError("createPortal: resource is bound to a different client");
|
|
1492
|
+
}
|
|
1493
|
+
resourceId = resource.id;
|
|
1494
|
+
}
|
|
1495
|
+
else {
|
|
1496
|
+
throw clientValidationError(`createPortal: resource must be a ProtectedResource handle or a resource id string (got ${describeShape(resource)})`);
|
|
1497
|
+
}
|
|
1498
|
+
requireNonEmptyId(resourceId, "createPortal", "resource id");
|
|
1499
|
+
const body = buildCreatePortalBody(opts, "createPortal");
|
|
1500
|
+
const data = await this.request("POST", `/v1/resources/${encodeURIComponent(resourceId)}/qurls`, body, requestOptions);
|
|
1501
|
+
return parsePortal(data, "createPortal");
|
|
1502
|
+
}
|
|
1503
|
+
/**
|
|
1504
|
+
* Protect `targetUrl` and mint a portal in one API call.
|
|
1505
|
+
*
|
|
1506
|
+
* Convenience for one-off scripts (qurl-go: `Client.CreatePortalForURL`).
|
|
1507
|
+
* The returned resource handle is reusable for minting more portals but
|
|
1508
|
+
* carries only the resource id and the caller-supplied target URL; use
|
|
1509
|
+
* {@link protectUrl} when you need the full server-populated resource
|
|
1510
|
+
* metadata. Portal options match {@link createPortal}; `targetUrl` gets
|
|
1511
|
+
* the same malformed-URL and embedded-credentials rejection as
|
|
1512
|
+
* {@link protectUrl}. REST-shaped equivalent: {@link create}.
|
|
1513
|
+
*/
|
|
1514
|
+
async createPortalForUrl(targetUrl, opts = {}, requestOptions) {
|
|
1515
|
+
requirePortalTargetUrl(targetUrl);
|
|
1516
|
+
const body = {
|
|
1517
|
+
target_url: targetUrl,
|
|
1518
|
+
...buildCreatePortalBody(opts, "createPortalForUrl"),
|
|
1519
|
+
};
|
|
1520
|
+
const data = await this.request("POST", "/v1/qurls", body, requestOptions);
|
|
1521
|
+
const portal = parsePortal(data, "createPortalForUrl");
|
|
1522
|
+
return {
|
|
1523
|
+
portal,
|
|
1524
|
+
resource: new ProtectedResource(this, portal.resourceId, targetUrl),
|
|
1525
|
+
};
|
|
1526
|
+
}
|
|
1527
|
+
/**
|
|
1528
|
+
* Open a qURL link programmatically and return the reachable resource.
|
|
1529
|
+
*
|
|
1530
|
+
* For services and agents that open received qURL links in code — human
|
|
1531
|
+
* recipients just open the link. Accepts a full platform link
|
|
1532
|
+
* (`https://qurl.link/#at_...`) or a bare access token. Triggers an NHP
|
|
1533
|
+
* knock that grants network access for the caller's IP and returns a
|
|
1534
|
+
* {@link ResourceHandle} with the reachable resource URL and access
|
|
1535
|
+
* lifetime.
|
|
1536
|
+
*
|
|
1537
|
+
* Unlike qurl-go's `EnterPortal` (which verifies links locally and needs
|
|
1538
|
+
* no LayerV credentials), this SDK opens links through the LayerV API:
|
|
1539
|
+
* the client needs an API key with the `qurl:resolve` scope. REST-shaped
|
|
1540
|
+
* equivalent: {@link resolve}.
|
|
1541
|
+
*
|
|
1542
|
+
* Throws {@link ValidationError} (`code: "client_validation"`) when no
|
|
1543
|
+
* access token can be extracted from `qurlLink`, and
|
|
1544
|
+
* (`code: "unexpected_response"`) when access is granted but the API
|
|
1545
|
+
* reports no resource URL — it fails closed rather than returning an
|
|
1546
|
+
* empty handle. Error messages never echo the link; qURL links are
|
|
1547
|
+
* credentials.
|
|
1548
|
+
*/
|
|
1549
|
+
async enterPortal(qurlLink, requestOptions) {
|
|
1550
|
+
const token = extractAccessToken(qurlLink);
|
|
1551
|
+
const resolved = await this.resolve(token, requestOptions);
|
|
1552
|
+
if (typeof resolved?.target_url !== "string" || resolved.target_url === "") {
|
|
1553
|
+
throw unexpectedResponseError("enterPortal: access was granted but the API returned no resource URL");
|
|
1554
|
+
}
|
|
1555
|
+
return {
|
|
1556
|
+
resourceUrl: resolved.target_url,
|
|
1557
|
+
openSeconds: resolved.access_grant?.expires_in ?? 0,
|
|
1558
|
+
resourceId: resolved.resource_id,
|
|
1559
|
+
};
|
|
1560
|
+
}
|
|
1150
1561
|
// --- Public API ---
|
|
1151
|
-
/**
|
|
1562
|
+
/**
|
|
1563
|
+
* Create a new qURL.
|
|
1564
|
+
*
|
|
1565
|
+
* Portal-flow equivalent: {@link createPortalForUrl} (same endpoint,
|
|
1566
|
+
* returns a {@link Portal} plus a reusable resource handle).
|
|
1567
|
+
*/
|
|
1152
1568
|
async create(input, options) {
|
|
1153
1569
|
validateCreateInput(input);
|
|
1154
1570
|
return this.request("POST", "/v1/qurls", input, options);
|
|
@@ -1445,6 +1861,8 @@ class QURLClient {
|
|
|
1445
1861
|
/**
|
|
1446
1862
|
* Mint a new access link for a qURL.
|
|
1447
1863
|
*
|
|
1864
|
+
* Portal-flow equivalent: {@link createPortal}.
|
|
1865
|
+
*
|
|
1448
1866
|
* Accepts either a resource ID (`r_` prefix) or a qURL display ID (`q_`
|
|
1449
1867
|
* prefix); the API resolves `q_` IDs to the parent resource automatically.
|
|
1450
1868
|
*
|
|
@@ -1501,6 +1919,9 @@ class QURLClient {
|
|
|
1501
1919
|
/**
|
|
1502
1920
|
* Resolve a qURL access token (headless).
|
|
1503
1921
|
*
|
|
1922
|
+
* Portal-flow equivalent: {@link enterPortal} (also accepts full qURL
|
|
1923
|
+
* links and fails closed when no resource URL is returned).
|
|
1924
|
+
*
|
|
1504
1925
|
* Triggers an NHP knock to grant network access for the caller's IP.
|
|
1505
1926
|
* Requires `qurl:resolve` scope on the API key.
|
|
1506
1927
|
*
|
|
@@ -1555,7 +1976,12 @@ class QURLClient {
|
|
|
1555
1976
|
validateListAllInput(input, RESOURCE_LIST_PARAM_KEYS, "listAllResources");
|
|
1556
1977
|
return this.paginateAll("listAllResources", input, (pageInput) => this.listResources(pageInput), (page) => page.resources);
|
|
1557
1978
|
}
|
|
1558
|
-
/**
|
|
1979
|
+
/**
|
|
1980
|
+
* Create a resource directly.
|
|
1981
|
+
*
|
|
1982
|
+
* Portal-flow equivalent for URL resources: {@link protectUrl} (returns
|
|
1983
|
+
* a portal-minting handle).
|
|
1984
|
+
*/
|
|
1559
1985
|
async createResource(input, options) {
|
|
1560
1986
|
requireObjectInput(input, "createResource");
|
|
1561
1987
|
requireNoUnknownFields(input, CREATE_RESOURCE_FIELD_KEYS, "createResource");
|
|
@@ -1590,7 +2016,11 @@ class QURLClient {
|
|
|
1590
2016
|
requireNonEmptyId(id, "deleteResource");
|
|
1591
2017
|
await this.rawRequest("DELETE", `/v1/resources/${encodeURIComponent(id)}`);
|
|
1592
2018
|
}
|
|
1593
|
-
/**
|
|
2019
|
+
/**
|
|
2020
|
+
* Mint a qURL against an existing resource.
|
|
2021
|
+
*
|
|
2022
|
+
* Portal-flow equivalent: {@link createPortal} (same endpoint).
|
|
2023
|
+
*/
|
|
1594
2024
|
async createQurlForResource(id, input, options) {
|
|
1595
2025
|
requireNonEmptyId(id, "createQurlForResource");
|
|
1596
2026
|
let normalized = input;
|
|
@@ -2211,3 +2641,50 @@ class QURLClient {
|
|
|
2211
2641
|
}
|
|
2212
2642
|
}
|
|
2213
2643
|
exports.QURLClient = QURLClient;
|
|
2644
|
+
/**
|
|
2645
|
+
* A LayerV-protected resource, bound to the client that produced it.
|
|
2646
|
+
*
|
|
2647
|
+
* Obtained from {@link QURLClient.protectUrl},
|
|
2648
|
+
* {@link QURLClient.connectorResource}, or {@link QURLClient.resourceById} —
|
|
2649
|
+
* not constructed directly. Mint short-lived access links for the resource
|
|
2650
|
+
* with {@link createPortal} (qurl-go: `qurl.Resource`).
|
|
2651
|
+
*/
|
|
2652
|
+
class ProtectedResource {
|
|
2653
|
+
// A true private field (not a module-scope WeakMap registry, which
|
|
2654
|
+
// CONTRIBUTING.md's dual-build rule bars) so the binding stays on the
|
|
2655
|
+
// instance and out of Object.keys/JSON.stringify output.
|
|
2656
|
+
#client;
|
|
2657
|
+
/** The LayerV resource id (`r_` prefix). */
|
|
2658
|
+
id;
|
|
2659
|
+
/** The private URL protected by this resource, when known. */
|
|
2660
|
+
targetUrl;
|
|
2661
|
+
/**
|
|
2662
|
+
* Full server-populated {@link Resource} metadata when the handle came
|
|
2663
|
+
* from an API response; `undefined` for {@link QURLClient.resourceById}
|
|
2664
|
+
* handles and for the one-call {@link QURLClient.createPortalForUrl} path.
|
|
2665
|
+
*/
|
|
2666
|
+
details;
|
|
2667
|
+
constructor(client, id, targetUrl, details) {
|
|
2668
|
+
this.#client = client;
|
|
2669
|
+
this.id = id;
|
|
2670
|
+
this.targetUrl = targetUrl;
|
|
2671
|
+
this.details = details;
|
|
2672
|
+
}
|
|
2673
|
+
/**
|
|
2674
|
+
* Whether `resource` was produced by `client`. A static because the
|
|
2675
|
+
* binding lives in a private field that only this class can read; used
|
|
2676
|
+
* by {@link QURLClient.createPortal} to refuse handles bound to a
|
|
2677
|
+
* different client.
|
|
2678
|
+
*/
|
|
2679
|
+
static isBoundTo(resource, client) {
|
|
2680
|
+
return resource.#client === client;
|
|
2681
|
+
}
|
|
2682
|
+
/**
|
|
2683
|
+
* Mint a short-lived qURL link (a portal) for this resource. See
|
|
2684
|
+
* {@link QURLClient.createPortal} for the option reference.
|
|
2685
|
+
*/
|
|
2686
|
+
async createPortal(opts = {}, requestOptions) {
|
|
2687
|
+
return this.#client.createPortal(this, opts, requestOptions);
|
|
2688
|
+
}
|
|
2689
|
+
}
|
|
2690
|
+
exports.ProtectedResource = ProtectedResource;
|
package/dist/cjs/errors.d.ts
CHANGED
|
@@ -14,6 +14,10 @@ export declare const ERROR_CODE_UNEXPECTED_RESPONSE = "unexpected_response";
|
|
|
14
14
|
export declare const ERROR_CODE_NETWORK = "network_error";
|
|
15
15
|
export declare const ERROR_CODE_TIMEOUT = "timeout";
|
|
16
16
|
export declare const ERROR_CODE_RUNTIME = "runtime_error";
|
|
17
|
+
/** `connectorResource` found no resource for the connector id (client-detected, `status: 0`). */
|
|
18
|
+
export declare const ERROR_CODE_RESOURCE_NOT_FOUND = "resource_not_found";
|
|
19
|
+
/** `connectorResource` matched more than one resource where exactly one is required (client-detected, `status: 0`). */
|
|
20
|
+
export declare const ERROR_CODE_AMBIGUOUS_RESOURCE = "ambiguous_resource";
|
|
17
21
|
/** Fallback `.code` when the server returns a non-RFC-7807 response (HTML proxy page, plaintext gateway error, JSON without `error` envelope). */
|
|
18
22
|
export declare const ERROR_CODE_UNKNOWN = "unknown";
|
|
19
23
|
/**
|
package/dist/cjs/errors.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RuntimeError = exports.TimeoutError = exports.NetworkError = exports.ServerError = exports.RateLimitError = exports.ValidationError = exports.NotFoundError = exports.AuthorizationError = exports.AuthenticationError = exports.QURLError = exports.ERROR_CODE_UNKNOWN = exports.ERROR_CODE_RUNTIME = exports.ERROR_CODE_TIMEOUT = exports.ERROR_CODE_NETWORK = exports.ERROR_CODE_UNEXPECTED_RESPONSE = exports.ERROR_CODE_CLIENT_VALIDATION = void 0;
|
|
3
|
+
exports.RuntimeError = exports.TimeoutError = exports.NetworkError = exports.ServerError = exports.RateLimitError = exports.ValidationError = exports.NotFoundError = exports.AuthorizationError = exports.AuthenticationError = exports.QURLError = exports.ERROR_CODE_UNKNOWN = exports.ERROR_CODE_AMBIGUOUS_RESOURCE = exports.ERROR_CODE_RESOURCE_NOT_FOUND = exports.ERROR_CODE_RUNTIME = exports.ERROR_CODE_TIMEOUT = exports.ERROR_CODE_NETWORK = exports.ERROR_CODE_UNEXPECTED_RESPONSE = exports.ERROR_CODE_CLIENT_VALIDATION = void 0;
|
|
4
4
|
exports.createError = createError;
|
|
5
5
|
/**
|
|
6
6
|
* Sentinel `.code` values for SDK-internal failure modes (no real HTTP
|
|
@@ -17,6 +17,10 @@ exports.ERROR_CODE_UNEXPECTED_RESPONSE = "unexpected_response";
|
|
|
17
17
|
exports.ERROR_CODE_NETWORK = "network_error";
|
|
18
18
|
exports.ERROR_CODE_TIMEOUT = "timeout";
|
|
19
19
|
exports.ERROR_CODE_RUNTIME = "runtime_error";
|
|
20
|
+
/** `connectorResource` found no resource for the connector id (client-detected, `status: 0`). */
|
|
21
|
+
exports.ERROR_CODE_RESOURCE_NOT_FOUND = "resource_not_found";
|
|
22
|
+
/** `connectorResource` matched more than one resource where exactly one is required (client-detected, `status: 0`). */
|
|
23
|
+
exports.ERROR_CODE_AMBIGUOUS_RESOURCE = "ambiguous_resource";
|
|
20
24
|
/** Fallback `.code` when the server returns a non-RFC-7807 response (HTML proxy page, plaintext gateway error, JSON without `error` envelope). */
|
|
21
25
|
exports.ERROR_CODE_UNKNOWN = "unknown";
|
|
22
26
|
/**
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { QURLClient } from "./client.js";
|
|
2
|
-
export { AuthenticationError, AuthorizationError, createError, ERROR_CODE_CLIENT_VALIDATION, ERROR_CODE_NETWORK, ERROR_CODE_RUNTIME, ERROR_CODE_TIMEOUT, ERROR_CODE_UNEXPECTED_RESPONSE, ERROR_CODE_UNKNOWN, NetworkError, NotFoundError, QURLError, RateLimitError, RuntimeError, ServerError, TimeoutError, ValidationError, } from "./errors.js";
|
|
1
|
+
export { ProtectedResource, QURLClient } from "./client.js";
|
|
2
|
+
export { AuthenticationError, AuthorizationError, createError, ERROR_CODE_AMBIGUOUS_RESOURCE, ERROR_CODE_CLIENT_VALIDATION, ERROR_CODE_NETWORK, ERROR_CODE_RESOURCE_NOT_FOUND, ERROR_CODE_RUNTIME, ERROR_CODE_TIMEOUT, ERROR_CODE_UNEXPECTED_RESPONSE, ERROR_CODE_UNKNOWN, NetworkError, NotFoundError, QURLError, RateLimitError, RuntimeError, ServerError, TimeoutError, ValidationError, } from "./errors.js";
|
|
3
3
|
export { VERSION } from "./version.js";
|
|
4
|
-
export type { AccessCode, AccessCodeListOutput, AccessGrant, AccessPolicy, AccessToken, AgentBootstrapInput, AgentBootstrapOutput, AIAgentCategory, AIAgentPolicy, ApiKey, ApiKeyListOutput, ApiKeyScope, BatchCreateInput, BatchCreateOutput, BatchItemFailure, BatchItemResult, BatchItemSuccess, BillingInvoiceListOutput, ClientOptions, ConnectorInstallation, ConnectorInstallationCapabilities, ConnectorInstallationListOutput, ConnectorInstallationStats, CreateAccessCodeInput, CreateAccessCodeOutput, CreateApiKeyInput, CreateApiKeyOutput, CreateBillingCheckoutInput, CreateInput, CreateOutput, CreateQurlForResourceInput, CreateResourceInput, CreateWebhookInput, Customer, CheckoutSession, DnsRecord, Domain, DomainCheckDetail, DomainListOutput, DomainVerifyResult, ExtendInput, Invoice, ListApiKeysInput, ListBillingInvoicesInput, ListConnectorInstallationsInput, ListDomainsInput, ListInput, ListOutput, ListWebhooksInput, ListWebhookDeliveriesInput, Meta, MintInput, MintOutput, NHPServerPeerInfo, PaginatedOutput, PortalSession, QURL, QURLErrorData, QurlSummary, Quota, RedeemAccessCodeInput, RedeemAccessCodeOutput, RegisterDomainInput, Resource, ResourceDetail, ResourceListInput, ResourceListOutput, ResourceType, RequestOptions, ResolveInput, ResolveOutput, Session, SessionListOutput, SessionTerminateOutput, TombstoneInfo, UnpaginatedOutput, UpdateApiKeyInput, UpdateCustomerInput, UpdateInput, UpdateResourceInput, UpdateResourceQurlInput, UpdateWebhookInput, UsageCostEstimate, UsageCurrentPeriod, UsageDaily, UsageDailyEntry, Webhook, WebhookDelivery, WebhookDeliveryListOutput, WebhookEventType, WebhookEventTypeInfo, WebhookListOutput, WebhookPayload, WebhookWithSecret, } from "./types.js";
|
|
4
|
+
export type { AccessCode, AccessCodeListOutput, AccessGrant, AccessPolicy, AccessToken, AgentBootstrapInput, AgentBootstrapOutput, AIAgentCategory, AIAgentPolicy, ApiKey, ApiKeyListOutput, ApiKeyScope, BatchCreateInput, BatchCreateOutput, BatchItemFailure, BatchItemResult, BatchItemSuccess, BillingInvoiceListOutput, ClientOptions, ConnectorInstallation, ConnectorInstallationCapabilities, ConnectorInstallationListOutput, ConnectorInstallationStats, CreateAccessCodeInput, CreateAccessCodeOutput, CreateApiKeyInput, CreateApiKeyOutput, CreateBillingCheckoutInput, CreateInput, CreateOutput, CreatePortalOptions, CreateQurlForResourceInput, CreateResourceInput, CreateWebhookInput, Customer, CheckoutSession, DnsRecord, Domain, DomainCheckDetail, DomainListOutput, DomainVerifyResult, ExtendInput, Invoice, ListApiKeysInput, ListBillingInvoicesInput, ListConnectorInstallationsInput, ListDomainsInput, ListInput, ListOutput, ListWebhooksInput, ListWebhookDeliveriesInput, Meta, MintInput, MintOutput, NHPServerPeerInfo, PaginatedOutput, Portal, PortalSession, ProtectUrlOptions, QURL, QURLErrorData, QurlSummary, Quota, RedeemAccessCodeInput, RedeemAccessCodeOutput, RegisterDomainInput, Resource, ResourceDetail, ResourceHandle, ResourceListInput, ResourceListOutput, ResourceType, RequestOptions, ResolveInput, ResolveOutput, Session, SessionListOutput, SessionTerminateOutput, TombstoneInfo, UnpaginatedOutput, UpdateApiKeyInput, UpdateCustomerInput, UpdateInput, UpdateResourceInput, UpdateResourceQurlInput, UpdateWebhookInput, UsageCostEstimate, UsageCurrentPeriod, UsageDaily, UsageDailyEntry, Webhook, WebhookDelivery, WebhookDeliveryListOutput, WebhookEventType, WebhookEventTypeInfo, WebhookListOutput, WebhookPayload, WebhookWithSecret, } from "./types.js";
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.VERSION = exports.ValidationError = exports.TimeoutError = exports.ServerError = exports.RuntimeError = exports.RateLimitError = exports.QURLError = exports.NotFoundError = exports.NetworkError = exports.ERROR_CODE_UNKNOWN = exports.ERROR_CODE_UNEXPECTED_RESPONSE = exports.ERROR_CODE_TIMEOUT = exports.ERROR_CODE_RUNTIME = exports.ERROR_CODE_NETWORK = exports.ERROR_CODE_CLIENT_VALIDATION = exports.createError = exports.AuthorizationError = exports.AuthenticationError = exports.QURLClient = void 0;
|
|
3
|
+
exports.VERSION = exports.ValidationError = exports.TimeoutError = exports.ServerError = exports.RuntimeError = exports.RateLimitError = exports.QURLError = exports.NotFoundError = exports.NetworkError = exports.ERROR_CODE_UNKNOWN = exports.ERROR_CODE_UNEXPECTED_RESPONSE = exports.ERROR_CODE_TIMEOUT = exports.ERROR_CODE_RUNTIME = exports.ERROR_CODE_RESOURCE_NOT_FOUND = exports.ERROR_CODE_NETWORK = exports.ERROR_CODE_CLIENT_VALIDATION = exports.ERROR_CODE_AMBIGUOUS_RESOURCE = exports.createError = exports.AuthorizationError = exports.AuthenticationError = exports.QURLClient = exports.ProtectedResource = void 0;
|
|
4
4
|
var client_js_1 = require("./client.js");
|
|
5
|
+
Object.defineProperty(exports, "ProtectedResource", { enumerable: true, get: function () { return client_js_1.ProtectedResource; } });
|
|
5
6
|
Object.defineProperty(exports, "QURLClient", { enumerable: true, get: function () { return client_js_1.QURLClient; } });
|
|
6
7
|
var errors_js_1 = require("./errors.js");
|
|
7
8
|
Object.defineProperty(exports, "AuthenticationError", { enumerable: true, get: function () { return errors_js_1.AuthenticationError; } });
|
|
8
9
|
Object.defineProperty(exports, "AuthorizationError", { enumerable: true, get: function () { return errors_js_1.AuthorizationError; } });
|
|
9
10
|
Object.defineProperty(exports, "createError", { enumerable: true, get: function () { return errors_js_1.createError; } });
|
|
11
|
+
Object.defineProperty(exports, "ERROR_CODE_AMBIGUOUS_RESOURCE", { enumerable: true, get: function () { return errors_js_1.ERROR_CODE_AMBIGUOUS_RESOURCE; } });
|
|
10
12
|
Object.defineProperty(exports, "ERROR_CODE_CLIENT_VALIDATION", { enumerable: true, get: function () { return errors_js_1.ERROR_CODE_CLIENT_VALIDATION; } });
|
|
11
13
|
Object.defineProperty(exports, "ERROR_CODE_NETWORK", { enumerable: true, get: function () { return errors_js_1.ERROR_CODE_NETWORK; } });
|
|
14
|
+
Object.defineProperty(exports, "ERROR_CODE_RESOURCE_NOT_FOUND", { enumerable: true, get: function () { return errors_js_1.ERROR_CODE_RESOURCE_NOT_FOUND; } });
|
|
12
15
|
Object.defineProperty(exports, "ERROR_CODE_RUNTIME", { enumerable: true, get: function () { return errors_js_1.ERROR_CODE_RUNTIME; } });
|
|
13
16
|
Object.defineProperty(exports, "ERROR_CODE_TIMEOUT", { enumerable: true, get: function () { return errors_js_1.ERROR_CODE_TIMEOUT; } });
|
|
14
17
|
Object.defineProperty(exports, "ERROR_CODE_UNEXPECTED_RESPONSE", { enumerable: true, get: function () { return errors_js_1.ERROR_CODE_UNEXPECTED_RESPONSE; } });
|