@canopy-io/node 0.6.0 → 0.7.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/dist/index.js CHANGED
@@ -82,6 +82,15 @@ function isCanopyTokenError(error) {
82
82
  return error instanceof Error && error.name === "CanopyTokenError";
83
83
  }
84
84
 
85
+ // src/strings.ts
86
+ function withoutTrailingSlashes(value) {
87
+ let end = value.length;
88
+ while (end > 0 && value[end - 1] === "/") {
89
+ end -= 1;
90
+ }
91
+ return value.slice(0, end);
92
+ }
93
+
85
94
  // src/client.ts
86
95
  function isCursorPagination(pagination) {
87
96
  return "next_cursor" in pagination;
@@ -106,7 +115,7 @@ var CanopyClient = class {
106
115
  "CanopyClient requires either `apiKey` (server-to-server) or `accessToken` (a user or identity JWT)."
107
116
  );
108
117
  }
109
- this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
118
+ this.baseUrl = withoutTrailingSlashes(options.baseUrl ?? DEFAULT_BASE_URL);
110
119
  this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
111
120
  this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
112
121
  this.maxBackoffMs = options.maxBackoffMs ?? DEFAULT_MAX_BACKOFF_MS;
@@ -1107,6 +1116,7 @@ var Canopy = class {
1107
1116
 
1108
1117
  // src/authorizer.ts
1109
1118
  var DEFAULT_TTL_MS = 6e4;
1119
+ var MAX_TTL_MS = 3e5;
1110
1120
  var MAX_WALK_DEPTH = 256;
1111
1121
  var LocalAuthorizer = class {
1112
1122
  client;
@@ -1133,6 +1143,11 @@ var LocalAuthorizer = class {
1133
1143
  constructor(client, options = {}) {
1134
1144
  this.client = client;
1135
1145
  this.ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;
1146
+ if (!Number.isFinite(this.ttlMs) || this.ttlMs < 0 || this.ttlMs > MAX_TTL_MS) {
1147
+ throw new RangeError(
1148
+ `ttlMs must be between 0 and ${MAX_TTL_MS} (five minutes); got ${String(this.ttlMs)}. It is how long a revoked user keeps access, so it is capped.`
1149
+ );
1150
+ }
1136
1151
  this.now = options.now ?? (() => Date.now());
1137
1152
  this.readOptions = {
1138
1153
  ...options.timeoutMs === void 0 ? {} : { timeoutMs: options.timeoutMs },
@@ -1308,8 +1323,16 @@ var LocalAuthorizer = class {
1308
1323
  }
1309
1324
  const parents = /* @__PURE__ */ new Map();
1310
1325
  if (result.modified) {
1326
+ const ids = /* @__PURE__ */ new Map();
1311
1327
  for (const edge of result.data.items) {
1312
- parents.set(edge.id, edge.parent_node_id ?? null);
1328
+ ids.set(edge.id, edge.id);
1329
+ }
1330
+ for (const edge of result.data.items) {
1331
+ const parent = edge.parent_node_id ?? null;
1332
+ parents.set(
1333
+ edge.id,
1334
+ parent === null ? null : ids.get(parent) ?? parent
1335
+ );
1313
1336
  }
1314
1337
  }
1315
1338
  this.tree = {
@@ -1322,12 +1345,29 @@ var LocalAuthorizer = class {
1322
1345
  };
1323
1346
 
1324
1347
  // src/verify.ts
1325
- var DEFAULT_ISSUER = "https://auth.canopy-io.com";
1348
+ var HOSTED_ORIGIN = "https://auth.canopy-io.com";
1326
1349
  var DEFAULT_JWKS_CACHE_MAX_AGE_MS = 10 * 60 * 1e3;
1327
1350
  var DEFAULT_JWKS_MIN_REFETCH_INTERVAL_MS = 30 * 1e3;
1328
1351
  var DEFAULT_JWKS_TIMEOUT_MS = 5e3;
1329
1352
  var PRINCIPAL_TYPES = /* @__PURE__ */ new Set(["user", "identity", "api_key", "platform"]);
1330
1353
  var DEFAULT_CLOCK_TOLERANCE_SEC = 60;
1354
+ function resolveIssuer(options) {
1355
+ const { environmentId, issuer } = options;
1356
+ if (environmentId && issuer) {
1357
+ throw new TypeError(
1358
+ "TokenVerifier takes environmentId or issuer, not both."
1359
+ );
1360
+ }
1361
+ if (issuer) {
1362
+ return withoutTrailingSlashes(issuer);
1363
+ }
1364
+ if (environmentId) {
1365
+ return `${HOSTED_ORIGIN}/environments/${environmentId}`;
1366
+ }
1367
+ throw new TypeError(
1368
+ "TokenVerifier needs environmentId (the Environment your tokens come from) or, on a custom auth domain or self-hosted instance, issuer."
1369
+ );
1370
+ }
1331
1371
  function orgContext(claims) {
1332
1372
  const { org_id, org_role } = claims;
1333
1373
  if (typeof org_id !== "string" || org_id === "" || typeof org_role !== "string" || org_role === "") {
@@ -1372,7 +1412,7 @@ var TokenVerifier = class {
1372
1412
  /** In-flight fetch, so a burst of requests triggers one call, not N. */
1373
1413
  inFlight = null;
1374
1414
  constructor(options = {}) {
1375
- this.issuer = (options.issuer ?? DEFAULT_ISSUER).replace(/\/+$/, "");
1415
+ this.issuer = resolveIssuer(options);
1376
1416
  this.audience = options.audience;
1377
1417
  this.jwksUri = options.jwksUri ?? `${this.issuer}/.well-known/jwks.json`;
1378
1418
  this.jwksCacheMaxAgeMs = options.jwksCacheMaxAgeMs ?? DEFAULT_JWKS_CACHE_MAX_AGE_MS;
@@ -1650,6 +1690,6 @@ function isWebhookEvent(delivery, name) {
1650
1690
  return delivery.event === name;
1651
1691
  }
1652
1692
 
1653
- export { Assignments, Canopy, CanopyAuthorizerError, CanopyClient, CanopyConnectionError, CanopyError, CanopyTokenError, Identities, LocalAuthorizer, Organizations, Paginator, Permissions, Roles, TokenVerifier, isCanopyAuthorizerError, isCanopyConnectionError, isCanopyError, isCanopyTokenError, isCursorPagination, isWebhookEvent, orgContext, paginate, withConcurrency };
1693
+ export { Assignments, Canopy, CanopyAuthorizerError, CanopyClient, CanopyConnectionError, CanopyError, CanopyTokenError, Identities, LocalAuthorizer, MAX_TTL_MS, Organizations, Paginator, Permissions, Roles, TokenVerifier, isCanopyAuthorizerError, isCanopyConnectionError, isCanopyError, isCanopyTokenError, isCursorPagination, isWebhookEvent, orgContext, paginate, withConcurrency };
1654
1694
  //# sourceMappingURL=index.js.map
1655
1695
  //# sourceMappingURL=index.js.map