@opentdf/sdk 0.9.0-beta.85 → 0.9.0-beta.87

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.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.UnsupportedFeatureError = exports.PermissionDeniedError = exports.UnauthenticatedError = exports.ServiceError = exports.NetworkError = exports.UnsafeUrlError = exports.IntegrityError = exports.DecryptError = exports.InvalidFileError = exports.AttributeValidationError = exports.ConfigurationError = exports.TdfError = void 0;
3
+ exports.AttributeNotFoundError = exports.UnsupportedFeatureError = exports.PermissionDeniedError = exports.UnauthenticatedError = exports.ServiceError = exports.NetworkError = exports.UnsafeUrlError = exports.IntegrityError = exports.DecryptError = exports.InvalidFileError = exports.AttributeValidationError = exports.ConfigurationError = exports.TdfError = void 0;
4
4
  function scrubCause(error, d) {
5
5
  if (!error || (d && d > 4)) {
6
6
  return {};
@@ -138,4 +138,16 @@ class UnsupportedFeatureError extends TdfError {
138
138
  }
139
139
  }
140
140
  exports.UnsupportedFeatureError = UnsupportedFeatureError;
141
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3JzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2Vycm9ycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxTQUFTLFVBQVUsQ0FBQyxLQUFhLEVBQUUsQ0FBVTtJQUMzQyxJQUFJLENBQUMsS0FBSyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQzNCLE9BQU8sRUFBRSxDQUFDO0lBQ1osQ0FBQztJQUNELElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDaEIsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDO0lBQ0QsTUFBTSxLQUFLLEdBQUcsSUFBSSxLQUFLLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxVQUFVLENBQUMsS0FBSyxDQUFDLEtBQWMsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3BGLElBQUksS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ2xCLEtBQUssQ0FBQyxPQUFPLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQztJQUNoQyxDQUFDO0lBQ0QsSUFBSSxLQUFLLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDaEIsS0FBSyxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDO0lBQzVCLENBQUM7SUFDRCxPQUFPLEVBQUUsS0FBSyxFQUFFLENBQUM7QUFDbkIsQ0FBQztBQUVEOzs7R0FHRztBQUNILE1BQWEsUUFBUyxTQUFRLEtBQUs7SUFHakMsWUFBWSxPQUFnQixFQUFFLEtBQWE7UUFDekMsS0FBSyxDQUFDLE9BQU8sRUFBRSxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztRQUgzQixTQUFJLEdBQUcsVUFBVSxDQUFDO1FBSXpCLDRFQUE0RTtRQUM1RSw2SUFBNkk7UUFDN0kseUdBQXlHO1FBQ3pHLE1BQU0sQ0FBQyxjQUFjLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDcEQsQ0FBQztDQUNGO0FBVkQsNEJBVUM7QUFFRDs7R0FFRztBQUNILE1BQWEsa0JBQW1CLFNBQVEsUUFBUTtJQUFoRDs7UUFDVyxTQUFJLEdBQUcsb0JBQW9CLENBQUM7SUFDdkMsQ0FBQztDQUFBO0FBRkQsZ0RBRUM7QUFFRDs7R0FFRztBQUNILE1BQWEsd0JBQXlCLFNBQVEsa0JBQWtCO0lBRzlELFlBQVksT0FBZSxFQUFFLFNBQWtCLEVBQUUsS0FBYTtRQUM1RCxLQUFLLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBSGYsU0FBSSxHQUFHLDBCQUEwQixDQUFDO1FBSXpDLElBQUksQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFDO0lBQzdCLENBQUM7Q0FDRjtBQVBELDREQU9DO0FBRUQ7O0dBRUc7QUFDSCxNQUFhLGdCQUFpQixTQUFRLFFBQVE7Q0FBRztBQUFqRCw0Q0FBaUQ7QUFFakQ7O0dBRUc7QUFDSCxNQUFhLFlBQWEsU0FBUSxnQkFBZ0I7SUFBbEQ7O1FBQ1csU0FBSSxHQUFHLGNBQWMsQ0FBQztJQUNqQyxDQUFDO0NBQUE7QUFGRCxvQ0FFQztBQUVELE1BQWEsY0FBZSxTQUFRLGdCQUFnQjtJQUFwRDs7UUFDVyxTQUFJLEdBQUcsZ0JBQWdCLENBQUM7SUFDbkMsQ0FBQztDQUFBO0FBRkQsd0NBRUM7QUFFRDs7O0dBR0c7QUFDSCxNQUFhLGNBQWUsU0FBUSxnQkFBZ0I7SUFJbEQsWUFBWSxPQUFlLEVBQUUsR0FBRyxHQUFhO1FBQzNDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUpSLFNBQUksR0FBRyxnQkFBZ0IsQ0FBQztRQUsvQixNQUFNLENBQUMsY0FBYyxDQUFDLElBQUksRUFBRSxHQUFHLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ2xELElBQUksQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDO0lBQ2pCLENBQUM7Q0FDRjtBQVRELHdDQVNDO0FBRUQ7O0dBRUc7QUFDSCxNQUFhLFlBQWEsU0FBUSxRQUFRO0lBQTFDOztRQUNXLFNBQUksR0FBRyxjQUFjLENBQUM7SUFDakMsQ0FBQztDQUFBO0FBRkQsb0NBRUM7QUFFRDs7R0FFRztBQUNILE1BQWEsWUFBYSxTQUFRLFFBQVE7SUFBMUM7O1FBQ1csU0FBSSxHQUFHLGNBQWMsQ0FBQztJQUNqQyxDQUFDO0NBQUE7QUFGRCxvQ0FFQztBQUVELG1DQUFtQztBQUNuQyxNQUFhLG9CQUFxQixTQUFRLFFBQVE7SUFBbEQ7O1FBQ1csU0FBSSxHQUFHLHNCQUFzQixDQUFDO0lBQ3pDLENBQUM7Q0FBQTtBQUZELG9EQUVDO0FBRUQsa0NBQWtDO0FBQ2xDLE1BQWEscUJBQXNCLFNBQVEsUUFBUTtJQUlqRCxZQUFZLE9BQWUsRUFBRSxXQUFzQixFQUFFLEtBQWE7UUFDaEUsS0FBSyxDQUFDLE9BQU8sRUFBRSxLQUFLLENBQUMsQ0FBQztRQUpmLFNBQUksR0FBRyx1QkFBdUIsQ0FBQztRQUt0QyxJQUFJLFdBQVcsSUFBSSxXQUFXLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQzFDLElBQUksQ0FBQyxtQkFBbUIsR0FBRyxXQUFXLENBQUM7UUFDekMsQ0FBQztJQUNILENBQUM7Q0FDRjtBQVZELHNEQVVDO0FBRUQ7O0dBRUc7QUFDSCxNQUFhLHVCQUF3QixTQUFRLFFBQVE7SUFBckQ7O1FBQ1csU0FBSSxHQUFHLHlCQUF5QixDQUFDO0lBQzVDLENBQUM7Q0FBQTtBQUZELDBEQUVDIn0=
141
+ /**
142
+ * One or more attribute value FQNs were not found on the platform.
143
+ * Thrown by {@link validateAttributes} and {@link validateAttributeValue} when the platform
144
+ * does not recognize the requested FQNs.
145
+ */
146
+ class AttributeNotFoundError extends TdfError {
147
+ constructor() {
148
+ super(...arguments);
149
+ this.name = 'AttributeNotFoundError';
150
+ }
151
+ }
152
+ exports.AttributeNotFoundError = AttributeNotFoundError;
153
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3JzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2Vycm9ycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxTQUFTLFVBQVUsQ0FBQyxLQUFhLEVBQUUsQ0FBVTtJQUMzQyxJQUFJLENBQUMsS0FBSyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQzNCLE9BQU8sRUFBRSxDQUFDO0lBQ1osQ0FBQztJQUNELElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDaEIsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDO0lBQ0QsTUFBTSxLQUFLLEdBQUcsSUFBSSxLQUFLLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxVQUFVLENBQUMsS0FBSyxDQUFDLEtBQWMsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3BGLElBQUksS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ2xCLEtBQUssQ0FBQyxPQUFPLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQztJQUNoQyxDQUFDO0lBQ0QsSUFBSSxLQUFLLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDaEIsS0FBSyxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDO0lBQzVCLENBQUM7SUFDRCxPQUFPLEVBQUUsS0FBSyxFQUFFLENBQUM7QUFDbkIsQ0FBQztBQUVEOzs7R0FHRztBQUNILE1BQWEsUUFBUyxTQUFRLEtBQUs7SUFHakMsWUFBWSxPQUFnQixFQUFFLEtBQWE7UUFDekMsS0FBSyxDQUFDLE9BQU8sRUFBRSxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztRQUgzQixTQUFJLEdBQUcsVUFBVSxDQUFDO1FBSXpCLDRFQUE0RTtRQUM1RSw2SUFBNkk7UUFDN0kseUdBQXlHO1FBQ3pHLE1BQU0sQ0FBQyxjQUFjLENBQUMsSUFBSSxFQUFF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
@@ -36,13 +36,18 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
36
36
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.ConfigurationError = exports.AttributeValidationError = exports.NetworkError = exports.DecryptError = exports.InvalidFileError = exports.IntegrityError = exports.PermissionDeniedError = exports.TdfError = exports.PlatformClient = exports.tdfSpecVersion = exports.clientType = exports.version = exports.attributeFQNsAsValues = exports.AuthProviders = exports.withHeaders = exports.HttpRequest = void 0;
39
+ exports.ConfigurationError = exports.AttributeNotFoundError = exports.AttributeValidationError = exports.NetworkError = exports.DecryptError = exports.InvalidFileError = exports.IntegrityError = exports.PermissionDeniedError = exports.TdfError = exports.PlatformClient = exports.tdfSpecVersion = exports.clientType = exports.version = exports.attributeValueExists = exports.attributeExists = exports.validateAttributes = exports.listAttributes = exports.attributeFQNsAsValues = exports.AuthProviders = exports.withHeaders = exports.HttpRequest = void 0;
40
40
  var auth_js_1 = require("./auth/auth.js");
41
41
  Object.defineProperty(exports, "HttpRequest", { enumerable: true, get: function () { return auth_js_1.HttpRequest; } });
42
42
  Object.defineProperty(exports, "withHeaders", { enumerable: true, get: function () { return auth_js_1.withHeaders; } });
43
43
  exports.AuthProviders = __importStar(require("./auth/providers.js"));
44
44
  var api_js_1 = require("./policy/api.js");
45
45
  Object.defineProperty(exports, "attributeFQNsAsValues", { enumerable: true, get: function () { return api_js_1.attributeFQNsAsValues; } });
46
+ var discovery_js_1 = require("./policy/discovery.js");
47
+ Object.defineProperty(exports, "listAttributes", { enumerable: true, get: function () { return discovery_js_1.listAttributes; } });
48
+ Object.defineProperty(exports, "validateAttributes", { enumerable: true, get: function () { return discovery_js_1.validateAttributes; } });
49
+ Object.defineProperty(exports, "attributeExists", { enumerable: true, get: function () { return discovery_js_1.attributeExists; } });
50
+ Object.defineProperty(exports, "attributeValueExists", { enumerable: true, get: function () { return discovery_js_1.attributeValueExists; } });
46
51
  var version_js_1 = require("./version.js");
47
52
  Object.defineProperty(exports, "version", { enumerable: true, get: function () { return version_js_1.version; } });
48
53
  Object.defineProperty(exports, "clientType", { enumerable: true, get: function () { return version_js_1.clientType; } });
@@ -58,7 +63,8 @@ Object.defineProperty(exports, "InvalidFileError", { enumerable: true, get: func
58
63
  Object.defineProperty(exports, "DecryptError", { enumerable: true, get: function () { return errors_js_1.DecryptError; } });
59
64
  Object.defineProperty(exports, "NetworkError", { enumerable: true, get: function () { return errors_js_1.NetworkError; } });
60
65
  Object.defineProperty(exports, "AttributeValidationError", { enumerable: true, get: function () { return errors_js_1.AttributeValidationError; } });
66
+ Object.defineProperty(exports, "AttributeNotFoundError", { enumerable: true, get: function () { return errors_js_1.AttributeNotFoundError; } });
61
67
  Object.defineProperty(exports, "ConfigurationError", { enumerable: true, get: function () { return errors_js_1.ConfigurationError; } });
62
68
  __exportStar(require("./seekable.js"), exports);
63
69
  __exportStar(require("../tdf3/src/models/index.js"), exports);
64
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsMENBQThGO0FBQWpELHNHQUFBLFdBQVcsT0FBQTtBQUFFLHNHQUFBLFdBQVcsT0FBQTtBQUNyRSxxRUFBcUQ7QUFDckQsMENBQXdEO0FBQS9DLCtHQUFBLHFCQUFxQixPQUFBO0FBQzlCLDJDQUFtRTtBQUExRCxxR0FBQSxPQUFPLE9BQUE7QUFBRSx3R0FBQSxVQUFVLE9BQUE7QUFBRSw0R0FBQSxjQUFjLE9BQUE7QUFDNUMsNkNBQWtHO0FBQXpGLDZHQUFBLGNBQWMsT0FBQTtBQUN2QiwrQ0FBNkI7QUFDN0IseUNBU3FCO0FBUm5CLHFHQUFBLFFBQVEsT0FBQTtBQUNSLGtIQUFBLHFCQUFxQixPQUFBO0FBQ3JCLDJHQUFBLGNBQWMsT0FBQTtBQUNkLDZHQUFBLGdCQUFnQixPQUFBO0FBQ2hCLHlHQUFBLFlBQVksT0FBQTtBQUNaLHlHQUFBLFlBQVksT0FBQTtBQUNaLHFIQUFBLHdCQUF3QixPQUFBO0FBQ3hCLCtHQUFBLGtCQUFrQixPQUFBO0FBRXBCLGdEQUE4QjtBQUM5Qiw4REFBNEMifQ==
70
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsMENBQThGO0FBQWpELHNHQUFBLFdBQVcsT0FBQTtBQUFFLHNHQUFBLFdBQVcsT0FBQTtBQUNyRSxxRUFBcUQ7QUFDckQsMENBQXdEO0FBQS9DLCtHQUFBLHFCQUFxQixPQUFBO0FBQzlCLHNEQUsrQjtBQUo3Qiw4R0FBQSxjQUFjLE9BQUE7QUFDZCxrSEFBQSxrQkFBa0IsT0FBQTtBQUNsQiwrR0FBQSxlQUFlLE9BQUE7QUFDZixvSEFBQSxvQkFBb0IsT0FBQTtBQUV0QiwyQ0FBbUU7QUFBMUQscUdBQUEsT0FBTyxPQUFBO0FBQUUsd0dBQUEsVUFBVSxPQUFBO0FBQUUsNEdBQUEsY0FBYyxPQUFBO0FBQzVDLDZDQUFrRztBQUF6Riw2R0FBQSxjQUFjLE9BQUE7QUFDdkIsK0NBQTZCO0FBQzdCLHlDQVVxQjtBQVRuQixxR0FBQSxRQUFRLE9BQUE7QUFDUixrSEFBQSxxQkFBcUIsT0FBQTtBQUNyQiwyR0FBQSxjQUFjLE9BQUE7QUFDZCw2R0FBQSxnQkFBZ0IsT0FBQTtBQUNoQix5R0FBQSxZQUFZLE9BQUE7QUFDWix5R0FBQSxZQUFZLE9BQUE7QUFDWixxSEFBQSx3QkFBd0IsT0FBQTtBQUN4QixtSEFBQSxzQkFBc0IsT0FBQTtBQUN0QiwrR0FBQSxrQkFBa0IsT0FBQTtBQUVwQixnREFBOEI7QUFDOUIsOERBQTRDIn0=
@@ -0,0 +1,188 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.listAttributes = listAttributes;
4
+ exports.validateAttributes = validateAttributes;
5
+ exports.attributeExists = attributeExists;
6
+ exports.attributeValueExists = attributeValueExists;
7
+ const connect_1 = require("@connectrpc/connect");
8
+ const errors_js_1 = require("../errors.js");
9
+ const utils_js_1 = require("../utils.js");
10
+ const platform_js_1 = require("../platform.js");
11
+ // Caps the pagination loop in listAttributes. 10 pages × 1000 records = 10,000
12
+ // attributes maximum, which is generous for browser use while preventing runaway
13
+ // memory growth if a server repeatedly returns a non-zero next_offset.
14
+ const MAX_LIST_ATTRIBUTES_PAGES = 10;
15
+ // Number of attributes to request per page. Matches the platform's default
16
+ // (ListRequestLimitDefault = 1000) so behavior is stable regardless of server config.
17
+ const LIST_ATTRIBUTES_PAGE_SIZE = 1000;
18
+ // Matches the server-side proto constraint: GetAttributeValuesByFqnsRequest has
19
+ // max_items: 250 on the fqns field, so the client rejects oversized requests
20
+ // locally instead of receiving a cryptic server validation error.
21
+ const MAX_VALIDATE_FQNS = 250;
22
+ // Attribute value FQN format: https://<namespace>/attr/<name>/value/<value>
23
+ // Restricts to safe URL characters to prevent XSS via FQNs in error messages
24
+ const ATTRIBUTE_VALUE_FQN_RE = /^https?:\/\/[a-zA-Z0-9._~%-]+\/attr\/[a-zA-Z0-9._~%-]+\/value\/[a-zA-Z0-9._~%-]+$/i;
25
+ // Attribute-level FQN format: https://<namespace>/attr/<name> (no /value/ segment)
26
+ // Restricts to safe URL characters to prevent XSS via FQNs in error messages
27
+ const ATTRIBUTE_FQN_RE = /^https?:\/\/[a-zA-Z0-9._~%-]+\/attr\/[a-zA-Z0-9._~%-]+$/i;
28
+ /**
29
+ * Returns all active attributes available on the platform, auto-paginating through all results.
30
+ * An optional namespace name or ID may be provided to filter results.
31
+ *
32
+ * Use this before calling `createZTDF()` to see what attributes are available for data tagging.
33
+ *
34
+ * @param platformUrl The platform base URL.
35
+ * @param authProvider An auth provider for the request.
36
+ * @param namespace Optional namespace name or ID to filter results.
37
+ * @returns All active {@link Attribute} objects on the platform.
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * const attrs = await listAttributes(platformUrl, authProvider);
42
+ * for (const a of attrs) {
43
+ * console.log(a.fqn);
44
+ * }
45
+ * ```
46
+ */
47
+ async function listAttributes(platformUrl, authProvider, namespace) {
48
+ if (!(0, utils_js_1.validateSecureUrl)(platformUrl)) {
49
+ throw new errors_js_1.ConfigurationError('platformUrl must use HTTPS protocol');
50
+ }
51
+ const platform = new platform_js_1.PlatformClient({ authProvider, platformUrl });
52
+ const result = [];
53
+ let nextOffset = 0;
54
+ for (let pages = 0; pages < MAX_LIST_ATTRIBUTES_PAGES; pages++) {
55
+ let resp;
56
+ try {
57
+ resp = await platform.v1.attributes.listAttributes({
58
+ namespace: namespace ?? '',
59
+ pagination: { offset: nextOffset, limit: LIST_ATTRIBUTES_PAGE_SIZE },
60
+ });
61
+ }
62
+ catch (e) {
63
+ throw new errors_js_1.NetworkError(`[ListAttributes] ${(0, utils_js_1.extractRpcErrorMessage)(e)}`);
64
+ }
65
+ result.push(...resp.attributes);
66
+ nextOffset = resp.pagination?.nextOffset ?? 0;
67
+ if (nextOffset === 0) {
68
+ return result;
69
+ }
70
+ }
71
+ throw new errors_js_1.ConfigurationError(`listAttributes returned more than ${MAX_LIST_ATTRIBUTES_PAGES * LIST_ATTRIBUTES_PAGE_SIZE} attributes. Use the namespace parameter to narrow results.`);
72
+ }
73
+ /**
74
+ * Checks that all provided attribute value FQNs exist on the platform.
75
+ * Validates FQN format first, then verifies existence via the platform API.
76
+ *
77
+ * Use this before `createZTDF()` to catch missing or misspelled attributes early
78
+ * instead of discovering the problem at decryption time.
79
+ *
80
+ * @param platformUrl The platform base URL.
81
+ * @param authProvider An auth provider for the request.
82
+ * @param fqns Attribute value FQNs to validate, in the form
83
+ * `https://<namespace>/attr/<name>/value/<value>`.
84
+ * @throws {@link AttributeNotFoundError} if any FQNs are not found on the platform.
85
+ * @throws {@link ConfigurationError} if the FQN format is invalid or there are too many FQNs.
86
+ *
87
+ * @example
88
+ * ```ts
89
+ * await validateAttributes(platformUrl, authProvider, [
90
+ * 'https://opentdf.io/attr/department/value/marketing',
91
+ * ]);
92
+ * // Safe to encrypt — all attributes confirmed present
93
+ * ```
94
+ */
95
+ async function validateAttributes(platformUrl, authProvider, fqns) {
96
+ if (!fqns || fqns.length === 0) {
97
+ return;
98
+ }
99
+ if (!(0, utils_js_1.validateSecureUrl)(platformUrl)) {
100
+ throw new errors_js_1.ConfigurationError('platformUrl must use HTTPS protocol');
101
+ }
102
+ if (fqns.length > MAX_VALIDATE_FQNS) {
103
+ throw new errors_js_1.ConfigurationError(`too many attribute FQNs: ${fqns.length} exceeds maximum of ${MAX_VALIDATE_FQNS}`);
104
+ }
105
+ for (const fqn of fqns) {
106
+ if (!ATTRIBUTE_VALUE_FQN_RE.test(fqn)) {
107
+ throw new errors_js_1.ConfigurationError('invalid attribute value FQN format');
108
+ }
109
+ }
110
+ const platform = new platform_js_1.PlatformClient({ authProvider, platformUrl });
111
+ let resp;
112
+ try {
113
+ resp = await platform.v1.attributes.getAttributeValuesByFqns({ fqns });
114
+ }
115
+ catch (e) {
116
+ throw new errors_js_1.NetworkError(`[GetAttributeValuesByFqns] ${(0, utils_js_1.extractRpcErrorMessage)(e)}`);
117
+ }
118
+ const found = resp.fqnAttributeValues;
119
+ const missing = fqns.filter((fqn) => !(fqn in found));
120
+ if (missing.length > 0) {
121
+ throw new errors_js_1.AttributeNotFoundError(`attribute not found: ${missing.length} FQN(s) missing`);
122
+ }
123
+ }
124
+ /**
125
+ * Reports whether the attribute definition identified by `attributeFqn` exists on the platform.
126
+ *
127
+ * `attributeFqn` should be an attribute-level FQN (no `/value/` segment):
128
+ * `https://<namespace>/attr/<attribute_name>`
129
+ *
130
+ * @param platformUrl The platform base URL.
131
+ * @param authProvider An auth provider for the request.
132
+ * @param attributeFqn The attribute-level FQN to check.
133
+ * @returns `true` if the attribute exists, `false` if it does not.
134
+ * @throws {@link ConfigurationError} if the FQN format is invalid or the URL is insecure.
135
+ * @throws {@link NetworkError} if a non-not-found service error occurs.
136
+ */
137
+ async function attributeExists(platformUrl, authProvider, attributeFqn) {
138
+ if (!(0, utils_js_1.validateSecureUrl)(platformUrl)) {
139
+ throw new errors_js_1.ConfigurationError('platformUrl must use HTTPS protocol');
140
+ }
141
+ if (!ATTRIBUTE_FQN_RE.test(attributeFqn)) {
142
+ throw new errors_js_1.ConfigurationError('invalid attribute FQN format');
143
+ }
144
+ const platform = new platform_js_1.PlatformClient({ authProvider, platformUrl });
145
+ try {
146
+ await platform.v1.attributes.getAttribute({
147
+ identifier: { case: 'fqn', value: attributeFqn },
148
+ });
149
+ return true;
150
+ }
151
+ catch (e) {
152
+ if (e instanceof connect_1.ConnectError && e.code === connect_1.Code.NotFound) {
153
+ return false;
154
+ }
155
+ throw new errors_js_1.NetworkError(`[GetAttribute] ${(0, utils_js_1.extractRpcErrorMessage)(e)}`);
156
+ }
157
+ }
158
+ /**
159
+ * Reports whether the attribute value FQN exists on the platform.
160
+ *
161
+ * `valueFqn` should be a full attribute value FQN (with `/value/` segment):
162
+ * `https://<namespace>/attr/<attribute_name>/value/<value>`
163
+ *
164
+ * @param platformUrl The platform base URL.
165
+ * @param authProvider An auth provider for the request.
166
+ * @param valueFqn The attribute value FQN to check.
167
+ * @returns `true` if the value exists, `false` if it does not.
168
+ * @throws {@link ConfigurationError} if the FQN format is invalid or the URL is insecure.
169
+ * @throws {@link NetworkError} if a service error occurs.
170
+ */
171
+ async function attributeValueExists(platformUrl, authProvider, valueFqn) {
172
+ if (!(0, utils_js_1.validateSecureUrl)(platformUrl)) {
173
+ throw new errors_js_1.ConfigurationError('platformUrl must use HTTPS protocol');
174
+ }
175
+ if (!ATTRIBUTE_VALUE_FQN_RE.test(valueFqn)) {
176
+ throw new errors_js_1.ConfigurationError('invalid attribute value FQN format');
177
+ }
178
+ const platform = new platform_js_1.PlatformClient({ authProvider, platformUrl });
179
+ let resp;
180
+ try {
181
+ resp = await platform.v1.attributes.getAttributeValuesByFqns({ fqns: [valueFqn] });
182
+ }
183
+ catch (e) {
184
+ throw new errors_js_1.NetworkError(`[GetAttributeValuesByFqns] ${(0, utils_js_1.extractRpcErrorMessage)(e)}`);
185
+ }
186
+ return valueFqn in resp.fqnAttributeValues;
187
+ }
188
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGlzY292ZXJ5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3BvbGljeS9kaXNjb3ZlcnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFpREEsd0NBaUNDO0FBd0JELGdEQXNDQztBQWVELDBDQXlCQztBQWVELG9EQXNCQztBQTdORCxpREFBeUQ7QUFDekQsNENBQXdGO0FBRXhGLDBDQUF3RTtBQUN4RSxnREFBZ0Q7QUFHaEQsK0VBQStFO0FBQy9FLGlGQUFpRjtBQUNqRix1RUFBdUU7QUFDdkUsTUFBTSx5QkFBeUIsR0FBRyxFQUFFLENBQUM7QUFFckMsMkVBQTJFO0FBQzNFLHNGQUFzRjtBQUN0RixNQUFNLHlCQUF5QixHQUFHLElBQUksQ0FBQztBQUV2QyxnRkFBZ0Y7QUFDaEYsNkVBQTZFO0FBQzdFLGtFQUFrRTtBQUNsRSxNQUFNLGlCQUFpQixHQUFHLEdBQUcsQ0FBQztBQUU5Qiw0RUFBNEU7QUFDNUUsNkVBQTZFO0FBQzdFLE1BQU0sc0JBQXNCLEdBQzFCLG9GQUFvRixDQUFDO0FBRXZGLG9GQUFvRjtBQUNwRiw2RUFBNkU7QUFDN0UsTUFBTSxnQkFBZ0IsR0FBRywwREFBMEQsQ0FBQztBQUVwRjs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBa0JHO0FBQ0ksS0FBSyxVQUFVLGNBQWMsQ0FDbEMsV0FBbUIsRUFDbkIsWUFBMEIsRUFDMUIsU0FBa0I7SUFFbEIsSUFBSSxDQUFDLElBQUEsNEJBQWlCLEVBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztRQUNwQyxNQUFNLElBQUksOEJBQWtCLENBQUMscUNBQXFDLENBQUMsQ0FBQztJQUN0RSxDQUFDO0lBQ0QsTUFBTSxRQUFRLEdBQUcsSUFBSSw0QkFBYyxDQUFDLEVBQUUsWUFBWSxFQUFFLFdBQVcsRUFBRSxDQUFDLENBQUM7SUFDbkUsTUFBTSxNQUFNLEdBQWdCLEVBQUUsQ0FBQztJQUMvQixJQUFJLFVBQVUsR0FBRyxDQUFDLENBQUM7SUFFbkIsS0FBSyxJQUFJLEtB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
@@ -71,4 +71,12 @@ export declare class PermissionDeniedError extends TdfError {
71
71
  export declare class UnsupportedFeatureError extends TdfError {
72
72
  name: string;
73
73
  }
74
+ /**
75
+ * One or more attribute value FQNs were not found on the platform.
76
+ * Thrown by {@link validateAttributes} and {@link validateAttributeValue} when the platform
77
+ * does not recognize the requested FQNs.
78
+ */
79
+ export declare class AttributeNotFoundError extends TdfError {
80
+ name: string;
81
+ }
74
82
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/errors.ts"],"names":[],"mappings":"AAiBA;;;GAGG;AACH,qBAAa,QAAS,SAAQ,KAAK;IACxB,IAAI,SAAc;gBAEf,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAO5C;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,QAAQ;IACrC,IAAI,SAAwB;CACtC;AAED;;GAEG;AACH,qBAAa,wBAAyB,SAAQ,kBAAkB;IACrD,IAAI,SAA8B;IAC3C,SAAS,EAAE,OAAO,CAAC;gBACP,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,KAAK;CAI/D;AAED;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,QAAQ;CAAG;AAEjD;;GAEG;AACH,qBAAa,YAAa,SAAQ,gBAAgB;IACvC,IAAI,SAAkB;CAChC;AAED,qBAAa,cAAe,SAAQ,gBAAgB;IACzC,IAAI,SAAoB;CAClC;AAED;;;GAGG;AACH,qBAAa,cAAe,SAAQ,gBAAgB;IACzC,IAAI,SAAoB;IACjC,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC;gBAEX,OAAO,EAAE,MAAM,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE;CAK9C;AAED;;GAEG;AACH,qBAAa,YAAa,SAAQ,QAAQ;IAC/B,IAAI,SAAkB;CAChC;AAED;;GAEG;AACH,qBAAa,YAAa,SAAQ,QAAQ;IAC/B,IAAI,SAAkB;CAChC;AAED,mCAAmC;AACnC,qBAAa,oBAAqB,SAAQ,QAAQ;IACvC,IAAI,SAA0B;CACxC;AAED,kCAAkC;AAClC,qBAAa,qBAAsB,SAAQ,QAAQ;IACxC,IAAI,SAA2B;IACxC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;gBAE5B,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,EAAE,KAAK,CAAC,EAAE,KAAK;CAMnE;AAED;;GAEG;AACH,qBAAa,uBAAwB,SAAQ,QAAQ;IAC1C,IAAI,SAA6B;CAC3C"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/errors.ts"],"names":[],"mappings":"AAiBA;;;GAGG;AACH,qBAAa,QAAS,SAAQ,KAAK;IACxB,IAAI,SAAc;gBAEf,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAO5C;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,QAAQ;IACrC,IAAI,SAAwB;CACtC;AAED;;GAEG;AACH,qBAAa,wBAAyB,SAAQ,kBAAkB;IACrD,IAAI,SAA8B;IAC3C,SAAS,EAAE,OAAO,CAAC;gBACP,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,KAAK;CAI/D;AAED;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,QAAQ;CAAG;AAEjD;;GAEG;AACH,qBAAa,YAAa,SAAQ,gBAAgB;IACvC,IAAI,SAAkB;CAChC;AAED,qBAAa,cAAe,SAAQ,gBAAgB;IACzC,IAAI,SAAoB;CAClC;AAED;;;GAGG;AACH,qBAAa,cAAe,SAAQ,gBAAgB;IACzC,IAAI,SAAoB;IACjC,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC;gBAEX,OAAO,EAAE,MAAM,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE;CAK9C;AAED;;GAEG;AACH,qBAAa,YAAa,SAAQ,QAAQ;IAC/B,IAAI,SAAkB;CAChC;AAED;;GAEG;AACH,qBAAa,YAAa,SAAQ,QAAQ;IAC/B,IAAI,SAAkB;CAChC;AAED,mCAAmC;AACnC,qBAAa,oBAAqB,SAAQ,QAAQ;IACvC,IAAI,SAA0B;CACxC;AAED,kCAAkC;AAClC,qBAAa,qBAAsB,SAAQ,QAAQ;IACxC,IAAI,SAA2B;IACxC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;gBAE5B,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,EAAE,KAAK,CAAC,EAAE,KAAK;CAMnE;AAED;;GAEG;AACH,qBAAa,uBAAwB,SAAQ,QAAQ;IAC1C,IAAI,SAA6B;CAC3C;AAED;;;;GAIG;AACH,qBAAa,sBAAuB,SAAQ,QAAQ;IACzC,IAAI,SAA4B;CAC1C"}
@@ -1,10 +1,11 @@
1
1
  export { type AuthProvider, type HttpMethod, HttpRequest, withHeaders } from './auth/auth.js';
2
2
  export * as AuthProviders from './auth/providers.js';
3
3
  export { attributeFQNsAsValues } from './policy/api.js';
4
+ export { listAttributes, validateAttributes, attributeExists, attributeValueExists, } from './policy/discovery.js';
4
5
  export { version, clientType, tdfSpecVersion } from './version.js';
5
6
  export { PlatformClient, type PlatformClientOptions, type PlatformServices } from './platform.js';
6
7
  export * from './opentdf.js';
7
- export { TdfError, PermissionDeniedError, IntegrityError, InvalidFileError, DecryptError, NetworkError, AttributeValidationError, ConfigurationError, } from './errors.js';
8
+ export { TdfError, PermissionDeniedError, IntegrityError, InvalidFileError, DecryptError, NetworkError, AttributeValidationError, AttributeNotFoundError, ConfigurationError, } from './errors.js';
8
9
  export * from './seekable.js';
9
10
  export * from '../tdf3/src/models/index.js';
10
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC9F,OAAO,KAAK,aAAa,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAClG,cAAc,cAAc,CAAC;AAC7B,OAAO,EACL,QAAQ,EACR,qBAAqB,EACrB,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,cAAc,eAAe,CAAC;AAC9B,cAAc,6BAA6B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC9F,OAAO,KAAK,aAAa,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,eAAe,EACf,oBAAoB,GACrB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAClG,cAAc,cAAc,CAAC;AAC7B,OAAO,EACL,QAAQ,EACR,qBAAqB,EACrB,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,wBAAwB,EACxB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,cAAc,eAAe,CAAC;AAC9B,cAAc,6BAA6B,CAAC"}
@@ -0,0 +1,74 @@
1
+ import { type AuthProvider } from '../auth/auth.js';
2
+ import type { Attribute } from '../platform/policy/objects_pb.js';
3
+ /**
4
+ * Returns all active attributes available on the platform, auto-paginating through all results.
5
+ * An optional namespace name or ID may be provided to filter results.
6
+ *
7
+ * Use this before calling `createZTDF()` to see what attributes are available for data tagging.
8
+ *
9
+ * @param platformUrl The platform base URL.
10
+ * @param authProvider An auth provider for the request.
11
+ * @param namespace Optional namespace name or ID to filter results.
12
+ * @returns All active {@link Attribute} objects on the platform.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * const attrs = await listAttributes(platformUrl, authProvider);
17
+ * for (const a of attrs) {
18
+ * console.log(a.fqn);
19
+ * }
20
+ * ```
21
+ */
22
+ export declare function listAttributes(platformUrl: string, authProvider: AuthProvider, namespace?: string): Promise<Attribute[]>;
23
+ /**
24
+ * Checks that all provided attribute value FQNs exist on the platform.
25
+ * Validates FQN format first, then verifies existence via the platform API.
26
+ *
27
+ * Use this before `createZTDF()` to catch missing or misspelled attributes early
28
+ * instead of discovering the problem at decryption time.
29
+ *
30
+ * @param platformUrl The platform base URL.
31
+ * @param authProvider An auth provider for the request.
32
+ * @param fqns Attribute value FQNs to validate, in the form
33
+ * `https://<namespace>/attr/<name>/value/<value>`.
34
+ * @throws {@link AttributeNotFoundError} if any FQNs are not found on the platform.
35
+ * @throws {@link ConfigurationError} if the FQN format is invalid or there are too many FQNs.
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * await validateAttributes(platformUrl, authProvider, [
40
+ * 'https://opentdf.io/attr/department/value/marketing',
41
+ * ]);
42
+ * // Safe to encrypt — all attributes confirmed present
43
+ * ```
44
+ */
45
+ export declare function validateAttributes(platformUrl: string, authProvider: AuthProvider, fqns: string[]): Promise<void>;
46
+ /**
47
+ * Reports whether the attribute definition identified by `attributeFqn` exists on the platform.
48
+ *
49
+ * `attributeFqn` should be an attribute-level FQN (no `/value/` segment):
50
+ * `https://<namespace>/attr/<attribute_name>`
51
+ *
52
+ * @param platformUrl The platform base URL.
53
+ * @param authProvider An auth provider for the request.
54
+ * @param attributeFqn The attribute-level FQN to check.
55
+ * @returns `true` if the attribute exists, `false` if it does not.
56
+ * @throws {@link ConfigurationError} if the FQN format is invalid or the URL is insecure.
57
+ * @throws {@link NetworkError} if a non-not-found service error occurs.
58
+ */
59
+ export declare function attributeExists(platformUrl: string, authProvider: AuthProvider, attributeFqn: string): Promise<boolean>;
60
+ /**
61
+ * Reports whether the attribute value FQN exists on the platform.
62
+ *
63
+ * `valueFqn` should be a full attribute value FQN (with `/value/` segment):
64
+ * `https://<namespace>/attr/<attribute_name>/value/<value>`
65
+ *
66
+ * @param platformUrl The platform base URL.
67
+ * @param authProvider An auth provider for the request.
68
+ * @param valueFqn The attribute value FQN to check.
69
+ * @returns `true` if the value exists, `false` if it does not.
70
+ * @throws {@link ConfigurationError} if the FQN format is invalid or the URL is insecure.
71
+ * @throws {@link NetworkError} if a service error occurs.
72
+ */
73
+ export declare function attributeValueExists(platformUrl: string, authProvider: AuthProvider, valueFqn: string): Promise<boolean>;
74
+ //# sourceMappingURL=discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../../../src/policy/discovery.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAyBlE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,YAAY,EAC1B,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,SAAS,EAAE,CAAC,CA6BtB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,YAAY,EAC1B,IAAI,EAAE,MAAM,EAAE,GACb,OAAO,CAAC,IAAI,CAAC,CAkCf;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,YAAY,EAC1B,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,OAAO,CAAC,CAqBlB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,CAAC,CAkBlB"}
@@ -123,4 +123,15 @@ export class UnsupportedFeatureError extends TdfError {
123
123
  this.name = 'UnsupportedFeatureError';
124
124
  }
125
125
  }
126
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3JzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2Vycm9ycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxTQUFTLFVBQVUsQ0FBQyxLQUFhLEVBQUUsQ0FBVTtJQUMzQyxJQUFJLENBQUMsS0FBSyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQzNCLE9BQU8sRUFBRSxDQUFDO0lBQ1osQ0FBQztJQUNELElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDaEIsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDO0lBQ0QsTUFBTSxLQUFLLEdBQUcsSUFBSSxLQUFLLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxVQUFVLENBQUMsS0FBSyxDQUFDLEtBQWMsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3BGLElBQUksS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ2xCLEtBQUssQ0FBQyxPQUFPLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQztJQUNoQyxDQUFDO0lBQ0QsSUFBSSxLQUFLLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDaEIsS0FBSyxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDO0lBQzVCLENBQUM7SUFDRCxPQUFPLEVBQUUsS0FBSyxFQUFFLENBQUM7QUFDbkIsQ0FBQztBQUVEOzs7R0FHRztBQUNILE1BQU0sT0FBTyxRQUFTLFNBQVEsS0FBSztJQUdqQyxZQUFZLE9BQWdCLEVBQUUsS0FBYTtRQUN6QyxLQUFLLENBQUMsT0FBTyxFQUFFLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1FBSDNCLFNBQUksR0FBRyxVQUFVLENBQUM7UUFJekIsNEVBQTRFO1FBQzVFLDZJQUE2STtRQUM3SSx5R0FBeUc7UUFDekcsTUFBTSxDQUFDLGNBQWMsQ0FBQyxJQUFJLEVBQUUsR0FBRyxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUNwRCxDQUFDO0NBQ0Y7QUFFRDs7R0FFRztBQUNILE1BQU0sT0FBTyxrQkFBbUIsU0FBUSxRQUFRO0lBQWhEOztRQUNXLFNBQUksR0FBRyxvQkFBb0IsQ0FBQztJQUN2QyxDQUFDO0NBQUE7QUFFRDs7R0FFRztBQUNILE1BQU0sT0FBTyx3QkFBeUIsU0FBUSxrQkFBa0I7SUFHOUQsWUFBWSxPQUFlLEVBQUUsU0FBa0IsRUFBRSxLQUFhO1FBQzVELEtBQUssQ0FBQyxPQUFPLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFIZixTQUFJLEdBQUcsMEJBQTBCLENBQUM7UUFJekMsSUFBSSxDQUFDLFNBQVMsR0FBRyxTQUFTLENBQUM7SUFDN0IsQ0FBQztDQUNGO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLE9BQU8sZ0JBQWlCLFNBQVEsUUFBUTtDQUFHO0FBRWpEOztHQUVHO0FBQ0gsTUFBTSxPQUFPLFlBQWEsU0FBUSxnQkFBZ0I7SUFBbEQ7O1FBQ1csU0FBSSxHQUFHLGNBQWMsQ0FBQztJQUNqQyxDQUFDO0NBQUE7QUFFRCxNQUFNLE9BQU8sY0FBZSxTQUFRLGdCQUFnQjtJQUFwRDs7UUFDVyxTQUFJLEdBQUcsZ0JBQWdCLENBQUM7SUFDbkMsQ0FBQztDQUFBO0FBRUQ7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLGNBQWUsU0FBUSxnQkFBZ0I7SUFJbEQsWUFBWSxPQUFlLEVBQUUsR0FBRyxHQUFhO1FBQzNDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUpSLFNBQUksR0FBRyxnQkFBZ0IsQ0FBQztRQUsvQixNQUFNLENBQUMsY0FBYyxDQUFDLElBQUksRUFBRSxHQUFHLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ2xELElBQUksQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDO0lBQ2pCLENBQUM7Q0FDRjtBQUVEOztHQUVHO0FBQ0gsTUFBTSxPQUFPLFlBQWEsU0FBUSxRQUFRO0lBQTFDOztRQUNXLFNBQUksR0FBRyxjQUFjLENBQUM7SUFDakMsQ0FBQztDQUFBO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLE9BQU8sWUFBYSxTQUFRLFFBQVE7SUFBMUM7O1FBQ1csU0FBSSxHQUFHLGNBQWMsQ0FBQztJQUNqQyxDQUFDO0NBQUE7QUFFRCxtQ0FBbUM7QUFDbkMsTUFBTSxPQUFPLG9CQUFxQixTQUFRLFFBQVE7SUFBbEQ7O1FBQ1csU0FBSSxHQUFHLHNCQUFzQixDQUFDO0lBQ3pDLENBQUM7Q0FBQTtBQUVELGtDQUFrQztBQUNsQyxNQUFNLE9BQU8scUJBQXNCLFNBQVEsUUFBUTtJQUlqRCxZQUFZLE9BQWUsRUFBRSxXQUFzQixFQUFFLEtBQWE7UUFDaEUsS0FBSyxDQUFDLE9BQU8sRUFBRSxLQUFLLENBQUMsQ0FBQztRQUpmLFNBQUksR0FBRyx1QkFBdUIsQ0FBQztRQUt0QyxJQUFJLFdBQVcsSUFBSSxXQUFXLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQzFDLElBQUksQ0FBQyxtQkFBbUIsR0FBRyxXQUFXLENBQUM7UUFDekMsQ0FBQztJQUNILENBQUM7Q0FDRjtBQUVEOztHQUVHO0FBQ0gsTUFBTSxPQUFPLHVCQUF3QixTQUFRLFFBQVE7SUFBckQ7O1FBQ1csU0FBSSxHQUFHLHlCQUF5QixDQUFDO0lBQzVDLENBQUM7Q0FBQSJ9
126
+ /**
127
+ * One or more attribute value FQNs were not found on the platform.
128
+ * Thrown by {@link validateAttributes} and {@link validateAttributeValue} when the platform
129
+ * does not recognize the requested FQNs.
130
+ */
131
+ export class AttributeNotFoundError extends TdfError {
132
+ constructor() {
133
+ super(...arguments);
134
+ this.name = 'AttributeNotFoundError';
135
+ }
136
+ }
137
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3JzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2Vycm9ycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxTQUFTLFVBQVUsQ0FBQyxLQUFhLEVBQUUsQ0FBVTtJQUMzQyxJQUFJLENBQUMsS0FBSyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQzNCLE9BQU8sRUFBRSxDQUFDO0lBQ1osQ0FBQztJQUNELElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDaEIsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDO0lBQ0QsTUFBTSxLQUFLLEdBQUcsSUFBSSxLQUFLLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxVQUFVLENBQUMsS0FBSyxDQUFDLEtBQWMsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3BGLElBQUksS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ2xCLEtBQUssQ0FBQyxPQUFPLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQztJQUNoQyxDQUFDO0lBQ0QsSUFBSSxLQUFLLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDaEIsS0FBSyxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDO0lBQzVCLENBQUM7SUFDRCxPQUFPLEVBQUUsS0FBSyxFQUFFLENBQUM7QUFDbkIsQ0FBQztBQUVEOzs7R0FHRztBQUNILE1BQU0sT0FBTyxRQUFTLFNBQVEsS0FBSztJQUdqQyxZQUFZLE9BQWdCLEVBQUUsS0FBYTtRQUN6QyxLQUFLLENBQUMsT0FBTyxFQUFFLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1FBSDNCLFNBQUksR0FBRyxVQUFVLENBQUM7UUFJekIsNEVBQTRFO1FBQzVFLDZJQUE2STtRQUM3SSx5R0FBeUc7UUFDekcsTUFBTSxDQUFDLGNBQWMsQ0FBQyxJQUFJLEVB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
@@ -1,10 +1,11 @@
1
1
  export { HttpRequest, withHeaders } from './auth/auth.js';
2
2
  export * as AuthProviders from './auth/providers.js';
3
3
  export { attributeFQNsAsValues } from './policy/api.js';
4
+ export { listAttributes, validateAttributes, attributeExists, attributeValueExists, } from './policy/discovery.js';
4
5
  export { version, clientType, tdfSpecVersion } from './version.js';
5
6
  export { PlatformClient } from './platform.js';
6
7
  export * from './opentdf.js';
7
- export { TdfError, PermissionDeniedError, IntegrityError, InvalidFileError, DecryptError, NetworkError, AttributeValidationError, ConfigurationError, } from './errors.js';
8
+ export { TdfError, PermissionDeniedError, IntegrityError, InvalidFileError, DecryptError, NetworkError, AttributeValidationError, AttributeNotFoundError, ConfigurationError, } from './errors.js';
8
9
  export * from './seekable.js';
9
10
  export * from '../tdf3/src/models/index.js';
10
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFzQyxXQUFXLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDOUYsT0FBTyxLQUFLLGFBQWEsTUFBTSxxQkFBcUIsQ0FBQztBQUNyRCxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUN4RCxPQUFPLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxjQUFjLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDbkUsT0FBTyxFQUFFLGNBQWMsRUFBcUQsTUFBTSxlQUFlLENBQUM7QUFDbEcsY0FBYyxjQUFjLENBQUM7QUFDN0IsT0FBTyxFQUNMLFFBQVEsRUFDUixxQkFBcUIsRUFDckIsY0FBYyxFQUNkLGdCQUFnQixFQUNoQixZQUFZLEVBQ1osWUFBWSxFQUNaLHdCQUF3QixFQUN4QixrQkFBa0IsR0FDbkIsTUFBTSxhQUFhLENBQUM7QUFDckIsY0FBYyxlQUFlLENBQUM7QUFDOUIsY0FBYyw2QkFBNkIsQ0FBQyJ9
11
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFzQyxXQUFXLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDOUYsT0FBTyxLQUFLLGFBQWEsTUFBTSxxQkFBcUIsQ0FBQztBQUNyRCxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUN4RCxPQUFPLEVBQ0wsY0FBYyxFQUNkLGtCQUFrQixFQUNsQixlQUFlLEVBQ2Ysb0JBQW9CLEdBQ3JCLE1BQU0sdUJBQXVCLENBQUM7QUFDL0IsT0FBTyxFQUFFLE9BQU8sRUFBRSxVQUFVLEVBQUUsY0FBYyxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ25FLE9BQU8sRUFBRSxjQUFjLEVBQXFELE1BQU0sZUFBZSxDQUFDO0FBQ2xHLGNBQWMsY0FBYyxDQUFDO0FBQzdCLE9BQU8sRUFDTCxRQUFRLEVBQ1IscUJBQXFCLEVBQ3JCLGNBQWMsRUFDZCxnQkFBZ0IsRUFDaEIsWUFBWSxFQUNaLFlBQVksRUFDWix3QkFBd0IsRUFDeEIsc0JBQXNCLEVBQ3RCLGtCQUFrQixHQUNuQixNQUFNLGFBQWEsQ0FBQztBQUNyQixjQUFjLGVBQWUsQ0FBQztBQUM5QixjQUFjLDZCQUE2QixDQUFDIn0=
@@ -0,0 +1,182 @@
1
+ import { ConnectError, Code } from '@connectrpc/connect';
2
+ import { AttributeNotFoundError, ConfigurationError, NetworkError } from '../errors.js';
3
+ import { extractRpcErrorMessage, validateSecureUrl } from '../utils.js';
4
+ import { PlatformClient } from '../platform.js';
5
+ // Caps the pagination loop in listAttributes. 10 pages × 1000 records = 10,000
6
+ // attributes maximum, which is generous for browser use while preventing runaway
7
+ // memory growth if a server repeatedly returns a non-zero next_offset.
8
+ const MAX_LIST_ATTRIBUTES_PAGES = 10;
9
+ // Number of attributes to request per page. Matches the platform's default
10
+ // (ListRequestLimitDefault = 1000) so behavior is stable regardless of server config.
11
+ const LIST_ATTRIBUTES_PAGE_SIZE = 1000;
12
+ // Matches the server-side proto constraint: GetAttributeValuesByFqnsRequest has
13
+ // max_items: 250 on the fqns field, so the client rejects oversized requests
14
+ // locally instead of receiving a cryptic server validation error.
15
+ const MAX_VALIDATE_FQNS = 250;
16
+ // Attribute value FQN format: https://<namespace>/attr/<name>/value/<value>
17
+ // Restricts to safe URL characters to prevent XSS via FQNs in error messages
18
+ const ATTRIBUTE_VALUE_FQN_RE = /^https?:\/\/[a-zA-Z0-9._~%-]+\/attr\/[a-zA-Z0-9._~%-]+\/value\/[a-zA-Z0-9._~%-]+$/i;
19
+ // Attribute-level FQN format: https://<namespace>/attr/<name> (no /value/ segment)
20
+ // Restricts to safe URL characters to prevent XSS via FQNs in error messages
21
+ const ATTRIBUTE_FQN_RE = /^https?:\/\/[a-zA-Z0-9._~%-]+\/attr\/[a-zA-Z0-9._~%-]+$/i;
22
+ /**
23
+ * Returns all active attributes available on the platform, auto-paginating through all results.
24
+ * An optional namespace name or ID may be provided to filter results.
25
+ *
26
+ * Use this before calling `createZTDF()` to see what attributes are available for data tagging.
27
+ *
28
+ * @param platformUrl The platform base URL.
29
+ * @param authProvider An auth provider for the request.
30
+ * @param namespace Optional namespace name or ID to filter results.
31
+ * @returns All active {@link Attribute} objects on the platform.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * const attrs = await listAttributes(platformUrl, authProvider);
36
+ * for (const a of attrs) {
37
+ * console.log(a.fqn);
38
+ * }
39
+ * ```
40
+ */
41
+ export async function listAttributes(platformUrl, authProvider, namespace) {
42
+ if (!validateSecureUrl(platformUrl)) {
43
+ throw new ConfigurationError('platformUrl must use HTTPS protocol');
44
+ }
45
+ const platform = new PlatformClient({ authProvider, platformUrl });
46
+ const result = [];
47
+ let nextOffset = 0;
48
+ for (let pages = 0; pages < MAX_LIST_ATTRIBUTES_PAGES; pages++) {
49
+ let resp;
50
+ try {
51
+ resp = await platform.v1.attributes.listAttributes({
52
+ namespace: namespace ?? '',
53
+ pagination: { offset: nextOffset, limit: LIST_ATTRIBUTES_PAGE_SIZE },
54
+ });
55
+ }
56
+ catch (e) {
57
+ throw new NetworkError(`[ListAttributes] ${extractRpcErrorMessage(e)}`);
58
+ }
59
+ result.push(...resp.attributes);
60
+ nextOffset = resp.pagination?.nextOffset ?? 0;
61
+ if (nextOffset === 0) {
62
+ return result;
63
+ }
64
+ }
65
+ throw new ConfigurationError(`listAttributes returned more than ${MAX_LIST_ATTRIBUTES_PAGES * LIST_ATTRIBUTES_PAGE_SIZE} attributes. Use the namespace parameter to narrow results.`);
66
+ }
67
+ /**
68
+ * Checks that all provided attribute value FQNs exist on the platform.
69
+ * Validates FQN format first, then verifies existence via the platform API.
70
+ *
71
+ * Use this before `createZTDF()` to catch missing or misspelled attributes early
72
+ * instead of discovering the problem at decryption time.
73
+ *
74
+ * @param platformUrl The platform base URL.
75
+ * @param authProvider An auth provider for the request.
76
+ * @param fqns Attribute value FQNs to validate, in the form
77
+ * `https://<namespace>/attr/<name>/value/<value>`.
78
+ * @throws {@link AttributeNotFoundError} if any FQNs are not found on the platform.
79
+ * @throws {@link ConfigurationError} if the FQN format is invalid or there are too many FQNs.
80
+ *
81
+ * @example
82
+ * ```ts
83
+ * await validateAttributes(platformUrl, authProvider, [
84
+ * 'https://opentdf.io/attr/department/value/marketing',
85
+ * ]);
86
+ * // Safe to encrypt — all attributes confirmed present
87
+ * ```
88
+ */
89
+ export async function validateAttributes(platformUrl, authProvider, fqns) {
90
+ if (!fqns || fqns.length === 0) {
91
+ return;
92
+ }
93
+ if (!validateSecureUrl(platformUrl)) {
94
+ throw new ConfigurationError('platformUrl must use HTTPS protocol');
95
+ }
96
+ if (fqns.length > MAX_VALIDATE_FQNS) {
97
+ throw new ConfigurationError(`too many attribute FQNs: ${fqns.length} exceeds maximum of ${MAX_VALIDATE_FQNS}`);
98
+ }
99
+ for (const fqn of fqns) {
100
+ if (!ATTRIBUTE_VALUE_FQN_RE.test(fqn)) {
101
+ throw new ConfigurationError('invalid attribute value FQN format');
102
+ }
103
+ }
104
+ const platform = new PlatformClient({ authProvider, platformUrl });
105
+ let resp;
106
+ try {
107
+ resp = await platform.v1.attributes.getAttributeValuesByFqns({ fqns });
108
+ }
109
+ catch (e) {
110
+ throw new NetworkError(`[GetAttributeValuesByFqns] ${extractRpcErrorMessage(e)}`);
111
+ }
112
+ const found = resp.fqnAttributeValues;
113
+ const missing = fqns.filter((fqn) => !(fqn in found));
114
+ if (missing.length > 0) {
115
+ throw new AttributeNotFoundError(`attribute not found: ${missing.length} FQN(s) missing`);
116
+ }
117
+ }
118
+ /**
119
+ * Reports whether the attribute definition identified by `attributeFqn` exists on the platform.
120
+ *
121
+ * `attributeFqn` should be an attribute-level FQN (no `/value/` segment):
122
+ * `https://<namespace>/attr/<attribute_name>`
123
+ *
124
+ * @param platformUrl The platform base URL.
125
+ * @param authProvider An auth provider for the request.
126
+ * @param attributeFqn The attribute-level FQN to check.
127
+ * @returns `true` if the attribute exists, `false` if it does not.
128
+ * @throws {@link ConfigurationError} if the FQN format is invalid or the URL is insecure.
129
+ * @throws {@link NetworkError} if a non-not-found service error occurs.
130
+ */
131
+ export async function attributeExists(platformUrl, authProvider, attributeFqn) {
132
+ if (!validateSecureUrl(platformUrl)) {
133
+ throw new ConfigurationError('platformUrl must use HTTPS protocol');
134
+ }
135
+ if (!ATTRIBUTE_FQN_RE.test(attributeFqn)) {
136
+ throw new ConfigurationError('invalid attribute FQN format');
137
+ }
138
+ const platform = new PlatformClient({ authProvider, platformUrl });
139
+ try {
140
+ await platform.v1.attributes.getAttribute({
141
+ identifier: { case: 'fqn', value: attributeFqn },
142
+ });
143
+ return true;
144
+ }
145
+ catch (e) {
146
+ if (e instanceof ConnectError && e.code === Code.NotFound) {
147
+ return false;
148
+ }
149
+ throw new NetworkError(`[GetAttribute] ${extractRpcErrorMessage(e)}`);
150
+ }
151
+ }
152
+ /**
153
+ * Reports whether the attribute value FQN exists on the platform.
154
+ *
155
+ * `valueFqn` should be a full attribute value FQN (with `/value/` segment):
156
+ * `https://<namespace>/attr/<attribute_name>/value/<value>`
157
+ *
158
+ * @param platformUrl The platform base URL.
159
+ * @param authProvider An auth provider for the request.
160
+ * @param valueFqn The attribute value FQN to check.
161
+ * @returns `true` if the value exists, `false` if it does not.
162
+ * @throws {@link ConfigurationError} if the FQN format is invalid or the URL is insecure.
163
+ * @throws {@link NetworkError} if a service error occurs.
164
+ */
165
+ export async function attributeValueExists(platformUrl, authProvider, valueFqn) {
166
+ if (!validateSecureUrl(platformUrl)) {
167
+ throw new ConfigurationError('platformUrl must use HTTPS protocol');
168
+ }
169
+ if (!ATTRIBUTE_VALUE_FQN_RE.test(valueFqn)) {
170
+ throw new ConfigurationError('invalid attribute value FQN format');
171
+ }
172
+ const platform = new PlatformClient({ authProvider, platformUrl });
173
+ let resp;
174
+ try {
175
+ resp = await platform.v1.attributes.getAttributeValuesByFqns({ fqns: [valueFqn] });
176
+ }
177
+ catch (e) {
178
+ throw new NetworkError(`[GetAttributeValuesByFqns] ${extractRpcErrorMessage(e)}`);
179
+ }
180
+ return valueFqn in resp.fqnAttributeValues;
181
+ }
182
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGlzY292ZXJ5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3BvbGljeS9kaXNjb3ZlcnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFlBQVksRUFBRSxJQUFJLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsa0JBQWtCLEVBQUUsWUFBWSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBRXhGLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUN4RSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFHaEQsK0VBQStFO0FBQy9FLGlGQUFpRjtBQUNqRix1RUFBdUU7QUFDdkUsTUFBTSx5QkFBeUIsR0FBRyxFQUFFLENBQUM7QUFFckMsMkVBQTJFO0FBQzNFLHNGQUFzRjtBQUN0RixNQUFNLHlCQUF5QixHQUFHLElBQUksQ0FBQztBQUV2QyxnRkFBZ0Y7QUFDaEYsNkVBQTZFO0FBQzdFLGtFQUFrRTtBQUNsRSxNQUFNLGlCQUFpQixHQUFHLEdBQUcsQ0FBQztBQUU5Qiw0RUFBNEU7QUFDNUUsNkVBQTZFO0FBQzdFLE1BQU0sc0JBQXNCLEdBQzFCLG9GQUFvRixDQUFDO0FBRXZGLG9GQUFvRjtBQUNwRiw2RUFBNkU7QUFDN0UsTUFBTSxnQkFBZ0IsR0FBRywwREFBMEQsQ0FBQztBQUVwRjs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBa0JHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxjQUFjLENBQ2xDLFdBQW1CLEVBQ25CLFlBQTBCLEVBQzFCLFNBQWtCO0lBRWxCLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO1FBQ3BDLE1BQU0sSUFBSSxrQkFBa0IsQ0FBQyxxQ0FBcUMsQ0FBQyxDQUFDO0lBQ3RFLENBQUM7SUFDRCxNQUFNLFFBQVEsR0FBRyxJQUFJLGNBQWMsQ0FBQyxFQUFFLFlBQVksRUFBRSxXQUFXLEVBQUUsQ0FBQyxDQUFDO0lBQ25FLE1BQU0sTUFBTSxHQUFnQixFQUFFLENBQUM7SUFDL0IsSUFBSSxVQUFVLEdBQUcsQ0FBQyxDQUFDO0lBRW5CLEtBQUssSUFBSSxLQUFLLEdBQUcsQ0FBQyxFQUFFLEtBQUssR0FBRyx5QkFBeUIsRUFBRSxLQUFLLEVBQUUsRUFBRSxDQUFDO1FBQy9ELElBQUksSUFBSSxDQUFDO1FBQ1QsSUFBSSxDQUFDO1lBQ0gsSUFBSSxHQUFHLE1BQU0sUUFBUSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsY0FBYyxDQUFDO2dCQUNqRCxTQUFTLEVBQUUsU0FBUyxJQUFJLEVBQUU7Z0JBQzFCLFVBQVUsRUFBRSxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFFLHlCQUF5QixFQUFFO2FBQ3JFLENBQUMsQ0FBQztRQUNMLENBQUM7UUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQ1gsTUFBTSxJQUFJLFlBQVksQ0FBQyxvQkFBb0Isc0JBQXNCLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQzFFLENBQUM7UUFFRCxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ2hDLFVBQVUsR0FBRyxJQUFJLENBQUMsVUFBVSxFQUFFLFVBQVUsSUFBSSxDQUFDLENBQUM7UUFDOUMsSUFBSSxVQUFVLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDckIsT0FBTyxNQUFNLENBQUM7UUFDaEIsQ0FBQztJQUNILENBQUM7SUFFRCxNQUFNLElBQUksa0JBQWtCLENBQzFCLHFDQUFxQyx5QkFBeUIsR0FBRyx5QkFBeUIsNkRBQTZELENBQ3hKLENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXFCRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsa0JBQWtCLENBQ3RDLFdBQW1CLEVBQ25CLFlBQTBCLEVBQzFCLElBQWM7SUFFZCxJQUFJLENBQUMsSUFBSSxJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDL0IsT0FBTztJQUNULENBQUM7SUFFRCxJQUFJLENBQUMsaUJBQWlCLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztRQUNwQyxNQUFNLElBQUksa0JBQWtCLENBQUMscUNBQXFDLENBQUMsQ0FBQztJQUN0RSxDQUFDO0lBRUQsSUFBSSxJQUFJLENBQUMsTUFBTSxHQUFHLGlCQUFpQixFQUFFLENBQUM7UUFDcEMsTUFBTSxJQUFJLGtCQUFrQixDQUMxQiw0QkFBNEIsSUFBSSxDQUFDLE1BQU0sdUJBQXVCLGlCQUFpQixFQUFFLENBQ2xGLENBQUM7SUFDSixDQUFDO0lBRUQsS0FBSyxNQUFNLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUN2QixJQUFJLENBQUMsc0JBQXNCLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDdEMsTUFBTSxJQUFJLGtCQUFrQixDQUFDLG9DQUFvQyxDQUFDLENBQUM7UUFDckUsQ0FBQztJQUNILENBQUM7SUFFRCxNQUFNLFFBQVEsR0FBRyxJQUFJLGNBQWMsQ0FBQyxFQUFFLFlBQVksRUFBRSxXQUFXLEVBQUUsQ0FBQyxDQUFDO0lBQ25FLElBQUksSUFBSSxDQUFDO0lBQ1QsSUFBSSxDQUFDO1FBQ0gsSUFBSSxHQUFHLE1BQU0sUUFBUSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsd0JBQXdCLENBQUMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ3pFLENBQUM7SUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1FBQ1gsTUFBTSxJQUFJLFlBQVksQ0FBQyw4QkFBOEIsc0JBQXNCLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3BGLENBQUM7SUFFRCxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUM7SUFDdEMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDO0lBQ3RELElBQUksT0FBTyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUN2QixNQUFNLElBQUksc0JBQXNCLENBQUMsd0JBQXdCLE9BQU8sQ0FBQyxNQUFNLGlCQUFpQixDQUFDLENBQUM7SUFDNUYsQ0FBQztBQUNILENBQUM7QUFFRDs7Ozs7Ozs7Ozs7O0dBWUc7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLGVBQWUsQ0FDbkMsV0FBbUIsRUFDbkIsWUFBMEIsRUFDMUIsWUFBb0I7SUFFcEIsSUFBSSxDQUFDLGlCQUFpQixDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUM7UUFDcEMsTUFBTSxJQUFJLGtCQUFrQixDQUFDLHFDQUFxQyxDQUFDLENBQUM7SUFDdEUsQ0FBQztJQUVELElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLEVBQUUsQ0FBQztRQUN6QyxNQUFNLElBQUksa0JBQWtCLENBQUMsOEJBQThCLENBQUMsQ0FBQztJQUMvRCxDQUFDO0lBRUQsTUFBTSxRQUFRLEdBQUcsSUFBSSxjQUFjLENBQUMsRUFBRSxZQUFZLEVBQUUsV0FBVyxFQUFFLENBQUMsQ0FBQztJQUNuRSxJQUFJLENBQUM7UUFDSCxNQUFNLFFBQVEsQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLFlBQVksQ0FBQztZQUN4QyxVQUFVLEVBQUUsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUU7U0FDakQsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztRQUNYLElBQUksQ0FBQyxZQUFZLFlBQVksSUFBSSxDQUFDLENBQUMsSUFBSSxLQUFLLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUMxRCxPQUFPLEtBQUssQ0FBQztRQUNmLENBQUM7UUFDRCxNQUFNLElBQUksWUFBWSxDQUFDLGtCQUFrQixzQkFBc0IsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDeEUsQ0FBQztBQUNILENBQUM7QUFFRDs7Ozs7Ozs7Ozs7O0dBWUc7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLG9CQUFvQixDQUN4QyxXQUFtQixFQUNuQixZQUEwQixFQUMxQixRQUFnQjtJQUVoQixJQUFJLENBQUMsaUJBQWlCLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztRQUNwQyxNQUFNLElBQUksa0JBQWtCLENBQUMscUNBQXFDLENBQUMsQ0FBQztJQUN0RSxDQUFDO0lBRUQsSUFBSSxDQUFDLHNCQUFzQixDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1FBQzNDLE1BQU0sSUFBSSxrQkFBa0IsQ0FBQyxvQ0FBb0MsQ0FBQyxDQUFDO0lBQ3JFLENBQUM7SUFFRCxNQUFNLFFBQVEsR0FBRyxJQUFJLGNBQWMsQ0FBQyxFQUFFLFlBQVksRUFBRSxXQUFXLEVBQUUsQ0FBQyxDQUFDO0lBQ25FLElBQUksSUFBSSxDQUFDO0lBQ1QsSUFBSSxDQUFDO1FBQ0gsSUFBSSxHQUFHLE1BQU0sUUFBUSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsd0JBQXdCLENBQUMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDckYsQ0FBQztJQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7UUFDWCxNQUFNLElBQUksWUFBWSxDQUFDLDhCQUE4QixzQkFBc0IsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDcEYsQ0FBQztJQUVELE9BQU8sUUFBUSxJQUFJLElBQUksQ0FBQyxrQkFBa0IsQ0FBQztBQUM3QyxDQUFDIn0=
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opentdf/sdk",
3
- "version": "0.9.0-beta.85",
3
+ "version": "0.9.0-beta.87",
4
4
  "description": "OpenTDF for the Web",
5
5
  "homepage": "https://github.com/opentdf/web-sdk",
6
6
  "bugs": {
package/src/errors.ts CHANGED
@@ -119,3 +119,12 @@ export class PermissionDeniedError extends TdfError {
119
119
  export class UnsupportedFeatureError extends TdfError {
120
120
  override name = 'UnsupportedFeatureError';
121
121
  }
122
+
123
+ /**
124
+ * One or more attribute value FQNs were not found on the platform.
125
+ * Thrown by {@link validateAttributes} and {@link validateAttributeValue} when the platform
126
+ * does not recognize the requested FQNs.
127
+ */
128
+ export class AttributeNotFoundError extends TdfError {
129
+ override name = 'AttributeNotFoundError';
130
+ }
package/src/index.ts CHANGED
@@ -1,6 +1,12 @@
1
1
  export { type AuthProvider, type HttpMethod, HttpRequest, withHeaders } from './auth/auth.js';
2
2
  export * as AuthProviders from './auth/providers.js';
3
3
  export { attributeFQNsAsValues } from './policy/api.js';
4
+ export {
5
+ listAttributes,
6
+ validateAttributes,
7
+ attributeExists,
8
+ attributeValueExists,
9
+ } from './policy/discovery.js';
4
10
  export { version, clientType, tdfSpecVersion } from './version.js';
5
11
  export { PlatformClient, type PlatformClientOptions, type PlatformServices } from './platform.js';
6
12
  export * from './opentdf.js';
@@ -12,6 +18,7 @@ export {
12
18
  DecryptError,
13
19
  NetworkError,
14
20
  AttributeValidationError,
21
+ AttributeNotFoundError,
15
22
  ConfigurationError,
16
23
  } from './errors.js';
17
24
  export * from './seekable.js';
@@ -0,0 +1,222 @@
1
+ import { ConnectError, Code } from '@connectrpc/connect';
2
+ import { AttributeNotFoundError, ConfigurationError, NetworkError } from '../errors.js';
3
+ import { type AuthProvider } from '../auth/auth.js';
4
+ import { extractRpcErrorMessage, validateSecureUrl } from '../utils.js';
5
+ import { PlatformClient } from '../platform.js';
6
+ import type { Attribute } from '../platform/policy/objects_pb.js';
7
+
8
+ // Caps the pagination loop in listAttributes. 10 pages × 1000 records = 10,000
9
+ // attributes maximum, which is generous for browser use while preventing runaway
10
+ // memory growth if a server repeatedly returns a non-zero next_offset.
11
+ const MAX_LIST_ATTRIBUTES_PAGES = 10;
12
+
13
+ // Number of attributes to request per page. Matches the platform's default
14
+ // (ListRequestLimitDefault = 1000) so behavior is stable regardless of server config.
15
+ const LIST_ATTRIBUTES_PAGE_SIZE = 1000;
16
+
17
+ // Matches the server-side proto constraint: GetAttributeValuesByFqnsRequest has
18
+ // max_items: 250 on the fqns field, so the client rejects oversized requests
19
+ // locally instead of receiving a cryptic server validation error.
20
+ const MAX_VALIDATE_FQNS = 250;
21
+
22
+ // Attribute value FQN format: https://<namespace>/attr/<name>/value/<value>
23
+ // Restricts to safe URL characters to prevent XSS via FQNs in error messages
24
+ const ATTRIBUTE_VALUE_FQN_RE =
25
+ /^https?:\/\/[a-zA-Z0-9._~%-]+\/attr\/[a-zA-Z0-9._~%-]+\/value\/[a-zA-Z0-9._~%-]+$/i;
26
+
27
+ // Attribute-level FQN format: https://<namespace>/attr/<name> (no /value/ segment)
28
+ // Restricts to safe URL characters to prevent XSS via FQNs in error messages
29
+ const ATTRIBUTE_FQN_RE = /^https?:\/\/[a-zA-Z0-9._~%-]+\/attr\/[a-zA-Z0-9._~%-]+$/i;
30
+
31
+ /**
32
+ * Returns all active attributes available on the platform, auto-paginating through all results.
33
+ * An optional namespace name or ID may be provided to filter results.
34
+ *
35
+ * Use this before calling `createZTDF()` to see what attributes are available for data tagging.
36
+ *
37
+ * @param platformUrl The platform base URL.
38
+ * @param authProvider An auth provider for the request.
39
+ * @param namespace Optional namespace name or ID to filter results.
40
+ * @returns All active {@link Attribute} objects on the platform.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * const attrs = await listAttributes(platformUrl, authProvider);
45
+ * for (const a of attrs) {
46
+ * console.log(a.fqn);
47
+ * }
48
+ * ```
49
+ */
50
+ export async function listAttributes(
51
+ platformUrl: string,
52
+ authProvider: AuthProvider,
53
+ namespace?: string
54
+ ): Promise<Attribute[]> {
55
+ if (!validateSecureUrl(platformUrl)) {
56
+ throw new ConfigurationError('platformUrl must use HTTPS protocol');
57
+ }
58
+ const platform = new PlatformClient({ authProvider, platformUrl });
59
+ const result: Attribute[] = [];
60
+ let nextOffset = 0;
61
+
62
+ for (let pages = 0; pages < MAX_LIST_ATTRIBUTES_PAGES; pages++) {
63
+ let resp;
64
+ try {
65
+ resp = await platform.v1.attributes.listAttributes({
66
+ namespace: namespace ?? '',
67
+ pagination: { offset: nextOffset, limit: LIST_ATTRIBUTES_PAGE_SIZE },
68
+ });
69
+ } catch (e) {
70
+ throw new NetworkError(`[ListAttributes] ${extractRpcErrorMessage(e)}`);
71
+ }
72
+
73
+ result.push(...resp.attributes);
74
+ nextOffset = resp.pagination?.nextOffset ?? 0;
75
+ if (nextOffset === 0) {
76
+ return result;
77
+ }
78
+ }
79
+
80
+ throw new ConfigurationError(
81
+ `listAttributes returned more than ${MAX_LIST_ATTRIBUTES_PAGES * LIST_ATTRIBUTES_PAGE_SIZE} attributes. Use the namespace parameter to narrow results.`
82
+ );
83
+ }
84
+
85
+ /**
86
+ * Checks that all provided attribute value FQNs exist on the platform.
87
+ * Validates FQN format first, then verifies existence via the platform API.
88
+ *
89
+ * Use this before `createZTDF()` to catch missing or misspelled attributes early
90
+ * instead of discovering the problem at decryption time.
91
+ *
92
+ * @param platformUrl The platform base URL.
93
+ * @param authProvider An auth provider for the request.
94
+ * @param fqns Attribute value FQNs to validate, in the form
95
+ * `https://<namespace>/attr/<name>/value/<value>`.
96
+ * @throws {@link AttributeNotFoundError} if any FQNs are not found on the platform.
97
+ * @throws {@link ConfigurationError} if the FQN format is invalid or there are too many FQNs.
98
+ *
99
+ * @example
100
+ * ```ts
101
+ * await validateAttributes(platformUrl, authProvider, [
102
+ * 'https://opentdf.io/attr/department/value/marketing',
103
+ * ]);
104
+ * // Safe to encrypt — all attributes confirmed present
105
+ * ```
106
+ */
107
+ export async function validateAttributes(
108
+ platformUrl: string,
109
+ authProvider: AuthProvider,
110
+ fqns: string[]
111
+ ): Promise<void> {
112
+ if (!fqns || fqns.length === 0) {
113
+ return;
114
+ }
115
+
116
+ if (!validateSecureUrl(platformUrl)) {
117
+ throw new ConfigurationError('platformUrl must use HTTPS protocol');
118
+ }
119
+
120
+ if (fqns.length > MAX_VALIDATE_FQNS) {
121
+ throw new ConfigurationError(
122
+ `too many attribute FQNs: ${fqns.length} exceeds maximum of ${MAX_VALIDATE_FQNS}`
123
+ );
124
+ }
125
+
126
+ for (const fqn of fqns) {
127
+ if (!ATTRIBUTE_VALUE_FQN_RE.test(fqn)) {
128
+ throw new ConfigurationError('invalid attribute value FQN format');
129
+ }
130
+ }
131
+
132
+ const platform = new PlatformClient({ authProvider, platformUrl });
133
+ let resp;
134
+ try {
135
+ resp = await platform.v1.attributes.getAttributeValuesByFqns({ fqns });
136
+ } catch (e) {
137
+ throw new NetworkError(`[GetAttributeValuesByFqns] ${extractRpcErrorMessage(e)}`);
138
+ }
139
+
140
+ const found = resp.fqnAttributeValues;
141
+ const missing = fqns.filter((fqn) => !(fqn in found));
142
+ if (missing.length > 0) {
143
+ throw new AttributeNotFoundError(`attribute not found: ${missing.length} FQN(s) missing`);
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Reports whether the attribute definition identified by `attributeFqn` exists on the platform.
149
+ *
150
+ * `attributeFqn` should be an attribute-level FQN (no `/value/` segment):
151
+ * `https://<namespace>/attr/<attribute_name>`
152
+ *
153
+ * @param platformUrl The platform base URL.
154
+ * @param authProvider An auth provider for the request.
155
+ * @param attributeFqn The attribute-level FQN to check.
156
+ * @returns `true` if the attribute exists, `false` if it does not.
157
+ * @throws {@link ConfigurationError} if the FQN format is invalid or the URL is insecure.
158
+ * @throws {@link NetworkError} if a non-not-found service error occurs.
159
+ */
160
+ export async function attributeExists(
161
+ platformUrl: string,
162
+ authProvider: AuthProvider,
163
+ attributeFqn: string
164
+ ): Promise<boolean> {
165
+ if (!validateSecureUrl(platformUrl)) {
166
+ throw new ConfigurationError('platformUrl must use HTTPS protocol');
167
+ }
168
+
169
+ if (!ATTRIBUTE_FQN_RE.test(attributeFqn)) {
170
+ throw new ConfigurationError('invalid attribute FQN format');
171
+ }
172
+
173
+ const platform = new PlatformClient({ authProvider, platformUrl });
174
+ try {
175
+ await platform.v1.attributes.getAttribute({
176
+ identifier: { case: 'fqn', value: attributeFqn },
177
+ });
178
+ return true;
179
+ } catch (e) {
180
+ if (e instanceof ConnectError && e.code === Code.NotFound) {
181
+ return false;
182
+ }
183
+ throw new NetworkError(`[GetAttribute] ${extractRpcErrorMessage(e)}`);
184
+ }
185
+ }
186
+
187
+ /**
188
+ * Reports whether the attribute value FQN exists on the platform.
189
+ *
190
+ * `valueFqn` should be a full attribute value FQN (with `/value/` segment):
191
+ * `https://<namespace>/attr/<attribute_name>/value/<value>`
192
+ *
193
+ * @param platformUrl The platform base URL.
194
+ * @param authProvider An auth provider for the request.
195
+ * @param valueFqn The attribute value FQN to check.
196
+ * @returns `true` if the value exists, `false` if it does not.
197
+ * @throws {@link ConfigurationError} if the FQN format is invalid or the URL is insecure.
198
+ * @throws {@link NetworkError} if a service error occurs.
199
+ */
200
+ export async function attributeValueExists(
201
+ platformUrl: string,
202
+ authProvider: AuthProvider,
203
+ valueFqn: string
204
+ ): Promise<boolean> {
205
+ if (!validateSecureUrl(platformUrl)) {
206
+ throw new ConfigurationError('platformUrl must use HTTPS protocol');
207
+ }
208
+
209
+ if (!ATTRIBUTE_VALUE_FQN_RE.test(valueFqn)) {
210
+ throw new ConfigurationError('invalid attribute value FQN format');
211
+ }
212
+
213
+ const platform = new PlatformClient({ authProvider, platformUrl });
214
+ let resp;
215
+ try {
216
+ resp = await platform.v1.attributes.getAttributeValuesByFqns({ fqns: [valueFqn] });
217
+ } catch (e) {
218
+ throw new NetworkError(`[GetAttributeValuesByFqns] ${extractRpcErrorMessage(e)}`);
219
+ }
220
+
221
+ return valueFqn in resp.fqnAttributeValues;
222
+ }