@pidgeon-ai/issuer 0.4.0 → 0.4.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 CHANGED
@@ -93,8 +93,9 @@ An agent is an active OAuth service app whose profile names it:
93
93
  `"profile": { "pidgeon": { "key": "…", "address": "…", "kind": "agent",
94
94
  "groups": ["refunds"] } }`. Deactivate the app to switch it off. The issuer
95
95
  reads them with a service app of its own granted `okta.apps.read` and a
96
- read-only admin role, signing in with Private Key JWT; its RSA or P-256
97
- private key is `OKTA_PRIVATE_KEY`.
96
+ read-only admin role (`READ_ONLY_ADMIN` is enough), signing in with Private
97
+ Key JWT; its RSA or P-256 private key is `OKTA_PRIVATE_KEY`, and its `kid`
98
+ is `key_id`.
98
99
 
99
100
  ```json
100
101
  "directory": { "okta": { "org": "https://acme.okta.com", "client_id": "<the issuer's app>" } }
package/dist/bin.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  UsageError,
4
4
  runIssuer
5
- } from "./chunk-5GZMAASA.js";
5
+ } from "./chunk-IKGE6SNR.js";
6
6
 
7
7
  // src/bin.ts
8
8
  async function main() {
@@ -30,6 +30,20 @@ function cachedDirectory(inner, seconds = 60, now = () => Date.now()) {
30
30
  };
31
31
  }
32
32
 
33
+ // src/rate-limit.ts
34
+ async function withBackoff(attempt, now = () => Date.now(), sleep = (ms) => new Promise((done) => setTimeout(done, ms))) {
35
+ for (let tries = 0; ; tries++) {
36
+ const response = await attempt();
37
+ if (response.status !== 429 || tries >= 2) return response;
38
+ const reset = Number(
39
+ response.headers.get("x-ratelimit-reset") ?? response.headers.get("x-rate-limit-reset")
40
+ );
41
+ const retryAfter = Number(response.headers.get("retry-after"));
42
+ const wait = Number.isFinite(reset) && reset > 0 ? reset * 1e3 - now() : Number.isFinite(retryAfter) && retryAfter > 0 ? retryAfter * 1e3 : 1e3;
43
+ await sleep(Math.min(2e3, Math.max(250, wait)));
44
+ }
45
+ }
46
+
33
47
  // src/auth0.ts
34
48
  var PER_PAGE = 100;
35
49
  function auth0Directory(options) {
@@ -60,9 +74,13 @@ function auth0Directory(options) {
60
74
  return token.value;
61
75
  }
62
76
  async function management(path) {
63
- const response = await fetcher(`${base}/api/v2${path}`, {
64
- headers: { authorization: `Bearer ${await accessToken()}`, accept: "application/json" }
65
- });
77
+ const bearer = await accessToken();
78
+ const response = await withBackoff(
79
+ () => fetcher(`${base}/api/v2${path}`, {
80
+ headers: { authorization: `Bearer ${bearer}`, accept: "application/json" }
81
+ }),
82
+ now
83
+ );
66
84
  if (response.status === 404) return null;
67
85
  if (!response.ok) throw new Error(`Auth0 answered ${response.status} for ${path}.`);
68
86
  return await response.json();
@@ -271,9 +289,13 @@ function oktaDirectory(options) {
271
289
  return token.value;
272
290
  }
273
291
  async function api(url) {
274
- const response = await fetcher(url, {
275
- headers: { authorization: `Bearer ${await accessToken()}`, accept: "application/json" }
276
- });
292
+ const bearer = await accessToken();
293
+ const response = await withBackoff(
294
+ () => fetcher(url, {
295
+ headers: { authorization: `Bearer ${bearer}`, accept: "application/json" }
296
+ }),
297
+ now
298
+ );
277
299
  if (!response.ok && response.status !== 404) {
278
300
  throw new Error(`Okta answered ${response.status} for ${new URL(url).pathname}.`);
279
301
  }
@@ -2199,4 +2221,4 @@ export {
2199
2221
  UsageError2 as UsageError,
2200
2222
  runIssuer
2201
2223
  };
2202
- //# sourceMappingURL=chunk-5GZMAASA.js.map
2224
+ //# sourceMappingURL=chunk-IKGE6SNR.js.map