@grantex/sdk 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/LICENSE +185 -185
  2. package/NOTICE +16 -16
  3. package/README.md +974 -947
  4. package/dist/authorization-details.d.ts +86 -0
  5. package/dist/authorization-details.d.ts.map +1 -0
  6. package/dist/authorization-details.js +209 -0
  7. package/dist/authorization-details.js.map +1 -0
  8. package/dist/canonical.d.ts +47 -0
  9. package/dist/canonical.d.ts.map +1 -0
  10. package/dist/canonical.js +163 -0
  11. package/dist/canonical.js.map +1 -0
  12. package/dist/caps/index.d.ts +19 -0
  13. package/dist/caps/index.d.ts.map +1 -0
  14. package/dist/caps/index.js +19 -0
  15. package/dist/caps/index.js.map +1 -0
  16. package/dist/caps/limits.d.ts +40 -0
  17. package/dist/caps/limits.d.ts.map +1 -0
  18. package/dist/caps/limits.js +109 -0
  19. package/dist/caps/limits.js.map +1 -0
  20. package/dist/caps/memory.d.ts +15 -0
  21. package/dist/caps/memory.d.ts.map +1 -0
  22. package/dist/caps/memory.js +57 -0
  23. package/dist/caps/memory.js.map +1 -0
  24. package/dist/caps/meter.d.ts +107 -0
  25. package/dist/caps/meter.d.ts.map +1 -0
  26. package/dist/caps/meter.js +200 -0
  27. package/dist/caps/meter.js.map +1 -0
  28. package/dist/caps/postgres.d.ts +64 -0
  29. package/dist/caps/postgres.d.ts.map +1 -0
  30. package/dist/caps/postgres.js +221 -0
  31. package/dist/caps/postgres.js.map +1 -0
  32. package/dist/caps/redis.d.ts +45 -0
  33. package/dist/caps/redis.d.ts.map +1 -0
  34. package/dist/caps/redis.js +173 -0
  35. package/dist/caps/redis.js.map +1 -0
  36. package/dist/client.d.ts +12 -0
  37. package/dist/client.d.ts.map +1 -1
  38. package/dist/client.js +517 -57
  39. package/dist/client.js.map +1 -1
  40. package/dist/decisions/action.d.ts +51 -0
  41. package/dist/decisions/action.d.ts.map +1 -0
  42. package/dist/decisions/action.js +237 -0
  43. package/dist/decisions/action.js.map +1 -0
  44. package/dist/decisions/index.d.ts +11 -0
  45. package/dist/decisions/index.d.ts.map +1 -0
  46. package/dist/decisions/index.js +8 -0
  47. package/dist/decisions/index.js.map +1 -0
  48. package/dist/decisions/verify.d.ts +103 -0
  49. package/dist/decisions/verify.d.ts.map +1 -0
  50. package/dist/decisions/verify.js +277 -0
  51. package/dist/decisions/verify.js.map +1 -0
  52. package/dist/denials.d.ts +132 -0
  53. package/dist/denials.d.ts.map +1 -0
  54. package/dist/denials.js +129 -0
  55. package/dist/denials.js.map +1 -0
  56. package/dist/evidence/build.d.ts +63 -0
  57. package/dist/evidence/build.d.ts.map +1 -0
  58. package/dist/evidence/build.js +201 -0
  59. package/dist/evidence/build.js.map +1 -0
  60. package/dist/evidence/canonical.d.ts +3 -0
  61. package/dist/evidence/canonical.d.ts.map +1 -0
  62. package/dist/evidence/canonical.js +3 -0
  63. package/dist/evidence/canonical.js.map +1 -0
  64. package/dist/evidence/checks.d.ts +13 -0
  65. package/dist/evidence/checks.d.ts.map +1 -0
  66. package/dist/evidence/checks.js +406 -0
  67. package/dist/evidence/checks.js.map +1 -0
  68. package/dist/evidence/document.d.ts +8 -0
  69. package/dist/evidence/document.d.ts.map +1 -0
  70. package/dist/evidence/document.js +298 -0
  71. package/dist/evidence/document.js.map +1 -0
  72. package/dist/evidence/hashing.d.ts +37 -0
  73. package/dist/evidence/hashing.d.ts.map +1 -0
  74. package/dist/evidence/hashing.js +106 -0
  75. package/dist/evidence/hashing.js.map +1 -0
  76. package/dist/evidence/index.d.ts +24 -0
  77. package/dist/evidence/index.d.ts.map +1 -0
  78. package/dist/evidence/index.js +24 -0
  79. package/dist/evidence/index.js.map +1 -0
  80. package/dist/evidence/result.d.ts +88 -0
  81. package/dist/evidence/result.d.ts.map +1 -0
  82. package/dist/evidence/result.js +88 -0
  83. package/dist/evidence/result.js.map +1 -0
  84. package/dist/evidence/schema-1.0.d.ts +2 -0
  85. package/dist/evidence/schema-1.0.d.ts.map +1 -0
  86. package/dist/evidence/schema-1.0.js +1398 -0
  87. package/dist/evidence/schema-1.0.js.map +1 -0
  88. package/dist/evidence/schema.d.ts +13 -0
  89. package/dist/evidence/schema.d.ts.map +1 -0
  90. package/dist/evidence/schema.js +264 -0
  91. package/dist/evidence/schema.js.map +1 -0
  92. package/dist/evidence/signature.d.ts +23 -0
  93. package/dist/evidence/signature.d.ts.map +1 -0
  94. package/dist/evidence/signature.js +136 -0
  95. package/dist/evidence/signature.js.map +1 -0
  96. package/dist/evidence/trace.d.ts +23 -0
  97. package/dist/evidence/trace.d.ts.map +1 -0
  98. package/dist/evidence/trace.js +69 -0
  99. package/dist/evidence/trace.js.map +1 -0
  100. package/dist/evidence/verify.d.ts +29 -0
  101. package/dist/evidence/verify.d.ts.map +1 -0
  102. package/dist/evidence/verify.js +163 -0
  103. package/dist/evidence/verify.js.map +1 -0
  104. package/dist/http.d.ts +12 -1
  105. package/dist/http.d.ts.map +1 -1
  106. package/dist/http.js +11 -5
  107. package/dist/http.js.map +1 -1
  108. package/dist/index.d.ts +16 -3
  109. package/dist/index.d.ts.map +1 -1
  110. package/dist/index.js +16 -2
  111. package/dist/index.js.map +1 -1
  112. package/dist/manifest.d.ts +178 -9
  113. package/dist/manifest.d.ts.map +1 -1
  114. package/dist/manifest.js +379 -16
  115. package/dist/manifest.js.map +1 -1
  116. package/dist/purpose.d.ts +29 -0
  117. package/dist/purpose.d.ts.map +1 -0
  118. package/dist/purpose.js +60 -0
  119. package/dist/purpose.js.map +1 -0
  120. package/dist/resources/agents.js +3 -3
  121. package/dist/resources/agents.js.map +1 -1
  122. package/dist/resources/anomalies.d.ts +3 -1
  123. package/dist/resources/anomalies.d.ts.map +1 -1
  124. package/dist/resources/anomalies.js +7 -1
  125. package/dist/resources/anomalies.js.map +1 -1
  126. package/dist/resources/audit.js +1 -1
  127. package/dist/resources/audit.js.map +1 -1
  128. package/dist/resources/budgets.js +2 -2
  129. package/dist/resources/budgets.js.map +1 -1
  130. package/dist/resources/credentials.js +1 -1
  131. package/dist/resources/credentials.js.map +1 -1
  132. package/dist/resources/decisions.d.ts +69 -0
  133. package/dist/resources/decisions.d.ts.map +1 -0
  134. package/dist/resources/decisions.js +115 -0
  135. package/dist/resources/decisions.js.map +1 -0
  136. package/dist/resources/domains.js +2 -2
  137. package/dist/resources/domains.js.map +1 -1
  138. package/dist/resources/dpdp.js +4 -4
  139. package/dist/resources/dpdp.js.map +1 -1
  140. package/dist/resources/grants.js +2 -2
  141. package/dist/resources/grants.js.map +1 -1
  142. package/dist/resources/policies.js +3 -3
  143. package/dist/resources/policies.js.map +1 -1
  144. package/dist/resources/scim.js +5 -5
  145. package/dist/resources/scim.js.map +1 -1
  146. package/dist/resources/tokens.d.ts.map +1 -1
  147. package/dist/resources/tokens.js +5 -1
  148. package/dist/resources/tokens.js.map +1 -1
  149. package/dist/resources/vault.js +2 -2
  150. package/dist/resources/vault.js.map +1 -1
  151. package/dist/resources/webauthn.d.ts +6 -1
  152. package/dist/resources/webauthn.d.ts.map +1 -1
  153. package/dist/resources/webauthn.js +5 -1
  154. package/dist/resources/webauthn.js.map +1 -1
  155. package/dist/resources/webhooks.js +1 -1
  156. package/dist/resources/webhooks.js.map +1 -1
  157. package/dist/revocations/feed.d.ts +61 -0
  158. package/dist/revocations/feed.d.ts.map +1 -0
  159. package/dist/revocations/feed.js +282 -0
  160. package/dist/revocations/feed.js.map +1 -0
  161. package/dist/revocations/index.d.ts +20 -0
  162. package/dist/revocations/index.d.ts.map +1 -0
  163. package/dist/revocations/index.js +19 -0
  164. package/dist/revocations/index.js.map +1 -0
  165. package/dist/revocations/set.d.ts +59 -0
  166. package/dist/revocations/set.d.ts.map +1 -0
  167. package/dist/revocations/set.js +87 -0
  168. package/dist/revocations/set.js.map +1 -0
  169. package/dist/scopes.d.ts +26 -0
  170. package/dist/scopes.d.ts.map +1 -0
  171. package/dist/scopes.js +37 -0
  172. package/dist/scopes.js.map +1 -0
  173. package/dist/types.d.ts +121 -4
  174. package/dist/types.d.ts.map +1 -1
  175. package/dist/types.js +0 -1
  176. package/dist/types.js.map +1 -1
  177. package/dist/verify.d.ts +31 -2
  178. package/dist/verify.d.ts.map +1 -1
  179. package/dist/verify.js +236 -29
  180. package/dist/verify.js.map +1 -1
  181. package/package.json +92 -84
@@ -0,0 +1,61 @@
1
+ /**
2
+ * The revocation feed client (PRD G-6).
3
+ *
4
+ * It takes a snapshot of everything currently revoked, then follows the live
5
+ * stream, so `enforce()` can deny a call on a grant that was revoked seconds
6
+ * ago without a network round trip per call.
7
+ *
8
+ * The important part is what happens when it cannot keep up. The feed records
9
+ * when it last heard from the auth service; if that is longer ago than
10
+ * `staleAfterMs`, it reports itself stale and `enforce()` denies rather than
11
+ * allowing calls on information it knows may be out of date.
12
+ */
13
+ import type { HttpClient } from '../http.js';
14
+ import { type CredentialRef, type RevocationMatch } from './set.js';
15
+ export interface RevocationFeedOptions {
16
+ /**
17
+ * How long the feed may go without hearing from the auth service before it
18
+ * is stale and calls fail closed. Default 5000 ms.
19
+ */
20
+ staleAfterMs?: number;
21
+ /** Delay before reconnecting a dropped stream. Default 500 ms. */
22
+ reconnectDelayMs?: number;
23
+ /** `stream` (Server-Sent Events) or `poll` (long polling). Default `stream`, falling back to `poll`. */
24
+ transport?: 'stream' | 'poll';
25
+ }
26
+ export type FeedUnavailableReason = 'disabled' | 'not_ready' | 'unauthorized' | 'network';
27
+ export interface RevocationFeedState {
28
+ /** A snapshot has been read at least once. */
29
+ synced: boolean;
30
+ /**
31
+ * When the feed last heard from the auth service, on a monotonic clock
32
+ * (0 if never). Comparable with `performance.now()`, not with `Date.now()`.
33
+ */
34
+ freshAt: number;
35
+ /** Feed position of the last entry applied. */
36
+ cursor: number;
37
+ /** Identifiers currently known to be revoked or suspended. */
38
+ known: number;
39
+ /** Why the feed is not usable, if it is not. */
40
+ unavailable: FeedUnavailableReason | null;
41
+ }
42
+ export declare class RevocationFeed {
43
+ #private;
44
+ constructor(http: HttpClient, options?: RevocationFeedOptions);
45
+ get staleAfterMs(): number;
46
+ state(): RevocationFeedState;
47
+ /** Synced recently enough to be trusted. */
48
+ isFresh(now?: number): boolean;
49
+ /** Why this credential must not be used, according to what the feed knows. */
50
+ match(ref: CredentialRef, now?: number): RevocationMatch | null;
51
+ /** Start following the feed. Idempotent. */
52
+ start(): void;
53
+ /** Stop following, and forget what was known (a restarted feed re-reads the snapshot). */
54
+ stop(): Promise<void>;
55
+ /**
56
+ * Wait until the feed is fresh, or the timeout passes. Returns whether it is
57
+ * fresh: `false` means callers must fail closed.
58
+ */
59
+ ready(timeoutMs?: number): Promise<boolean>;
60
+ }
61
+ //# sourceMappingURL=feed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feed.d.ts","sourceRoot":"","sources":["../../src/revocations/feed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAc,KAAK,aAAa,EAAwB,KAAK,eAAe,EAAE,MAAM,UAAU,CAAC;AAEtG,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wGAAwG;IACxG,SAAS,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;CAC/B;AAED,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG,WAAW,GAAG,cAAc,GAAG,SAAS,CAAC;AAE1F,MAAM,WAAW,mBAAmB;IAClC,8CAA8C;IAC9C,MAAM,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,WAAW,EAAE,qBAAqB,GAAG,IAAI,CAAC;CAC3C;AAqBD,qBAAa,cAAc;;IAkBzB,YAAY,IAAI,EAAE,UAAU,EAAE,OAAO,GAAE,qBAA0B,EAKhE;IAED,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,KAAK,IAAI,mBAAmB,CAQ3B;IAED,4CAA4C;IAC5C,OAAO,CAAC,GAAG,GAAE,MAAuB,GAAG,OAAO,CAE7C;IAED,8EAA8E;IAC9E,KAAK,CAAC,GAAG,EAAE,aAAa,EAAE,GAAG,GAAE,MAAmB,GAAG,eAAe,GAAG,IAAI,CAE1E;IAED,4CAA4C;IAC5C,KAAK,IAAI,IAAI,CAKZ;IAED,0FAA0F;IACpF,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAa1B;IAED;;;OAGG;IACG,KAAK,CAAC,SAAS,GAAE,MAA2B,GAAG,OAAO,CAAC,OAAO,CAAC,CAepE;CAqJF"}
@@ -0,0 +1,282 @@
1
+ import { RevokedSet } from './set.js';
2
+ /**
3
+ * Freshness is measured on a monotonic clock: a wall-clock jump backwards
4
+ * must not make a stale feed look current.
5
+ */
6
+ const monotonicNow = () => (typeof performance !== 'undefined' && typeof performance.now === 'function' ? performance.now() : Date.now());
7
+ const DEFAULT_STALE_AFTER_MS = 5_000;
8
+ const DEFAULT_RECONNECT_DELAY_MS = 500;
9
+ const MAX_RECONNECT_DELAY_MS = 30_000;
10
+ const PRUNE_INTERVAL_MS = 60_000;
11
+ export class RevocationFeed {
12
+ #http;
13
+ #set = new RevokedSet();
14
+ #staleAfterMs;
15
+ #reconnectDelayMs;
16
+ #transport;
17
+ #running = false;
18
+ #synced = false;
19
+ #freshAt = 0;
20
+ #cursor = 0;
21
+ #unavailable = null;
22
+ #controller = null;
23
+ #loop = null;
24
+ #reader = null;
25
+ #prunedAt = 0;
26
+ #waiters = [];
27
+ constructor(http, options = {}) {
28
+ this.#http = http;
29
+ this.#staleAfterMs = options.staleAfterMs ?? DEFAULT_STALE_AFTER_MS;
30
+ this.#reconnectDelayMs = options.reconnectDelayMs ?? DEFAULT_RECONNECT_DELAY_MS;
31
+ this.#transport = options.transport ?? 'stream';
32
+ }
33
+ get staleAfterMs() {
34
+ return this.#staleAfterMs;
35
+ }
36
+ state() {
37
+ return {
38
+ synced: this.#synced,
39
+ freshAt: this.#freshAt,
40
+ cursor: this.#cursor,
41
+ known: this.#set.size,
42
+ unavailable: this.#unavailable,
43
+ };
44
+ }
45
+ /** Synced recently enough to be trusted. */
46
+ isFresh(now = monotonicNow()) {
47
+ return this.#synced && this.#unavailable === null && now - this.#freshAt <= this.#staleAfterMs;
48
+ }
49
+ /** Why this credential must not be used, according to what the feed knows. */
50
+ match(ref, now = Date.now()) {
51
+ return this.#set.match(ref, now);
52
+ }
53
+ /** Start following the feed. Idempotent. */
54
+ start() {
55
+ if (this.#running)
56
+ return;
57
+ this.#running = true;
58
+ this.#controller = new AbortController();
59
+ this.#loop = this.#run().catch(() => { });
60
+ }
61
+ /** Stop following, and forget what was known (a restarted feed re-reads the snapshot). */
62
+ async stop() {
63
+ this.#running = false;
64
+ this.#controller?.abort();
65
+ // An open stream is not interrupted by aborting a fetch that already
66
+ // resolved, so release the reader too.
67
+ await this.#reader?.cancel().catch(() => { });
68
+ const loop = this.#loop;
69
+ this.#loop = null;
70
+ this.#synced = false;
71
+ this.#freshAt = 0;
72
+ this.#set.clear();
73
+ this.#wake();
74
+ if (loop)
75
+ await loop;
76
+ }
77
+ /**
78
+ * Wait until the feed is fresh, or the timeout passes. Returns whether it is
79
+ * fresh: `false` means callers must fail closed.
80
+ */
81
+ async ready(timeoutMs = this.#staleAfterMs) {
82
+ this.start();
83
+ const deadline = monotonicNow() + timeoutMs;
84
+ for (;;) {
85
+ if (this.isFresh())
86
+ return true;
87
+ if (this.#unavailable !== null || monotonicNow() >= deadline)
88
+ return this.isFresh();
89
+ await new Promise((resolve) => {
90
+ const timer = setTimeout(resolve, Math.min(50, Math.max(1, deadline - monotonicNow())));
91
+ timer.unref?.();
92
+ this.#waiters.push(() => {
93
+ clearTimeout(timer);
94
+ resolve();
95
+ });
96
+ });
97
+ }
98
+ }
99
+ #wake() {
100
+ const waiters = this.#waiters;
101
+ this.#waiters = [];
102
+ for (const waiter of waiters)
103
+ waiter();
104
+ }
105
+ #touch() {
106
+ this.#freshAt = monotonicNow();
107
+ // Entries whose credential has expired can no longer be used; dropping
108
+ // them here bounds the set without a timer of its own.
109
+ if (this.#freshAt - this.#prunedAt > PRUNE_INTERVAL_MS) {
110
+ this.#set.prune();
111
+ this.#prunedAt = this.#freshAt;
112
+ }
113
+ this.#unavailable = null;
114
+ this.#wake();
115
+ }
116
+ async #run() {
117
+ let delay = this.#reconnectDelayMs;
118
+ while (this.#running) {
119
+ try {
120
+ await this.#snapshot();
121
+ delay = this.#reconnectDelayMs;
122
+ if (this.#transport === 'stream') {
123
+ const streamed = await this.#stream();
124
+ if (!streamed)
125
+ await this.#poll();
126
+ // A stream that ended cleanly (a server restart, a proxy timeout)
127
+ // must not be reconnected in a tight loop.
128
+ else if (this.#running)
129
+ await sleep(this.#reconnectDelayMs, this.#controller?.signal);
130
+ }
131
+ else {
132
+ await this.#poll();
133
+ }
134
+ }
135
+ catch (err) {
136
+ this.#unavailable = classify(err);
137
+ this.#synced = false;
138
+ this.#wake();
139
+ await sleep(delay, this.#controller?.signal);
140
+ delay = Math.min(delay * 2, MAX_RECONNECT_DELAY_MS);
141
+ }
142
+ }
143
+ }
144
+ async #snapshot() {
145
+ let pageToken;
146
+ let cursor = 0;
147
+ // Collected first and swapped in once every page has arrived. A snapshot
148
+ // is the whole truth about what is revoked *now*, so applying it on top
149
+ // of what the set already held kept anything resumed while this client
150
+ // was disconnected — denied until it expired. Swapping only after the
151
+ // last page means a failure part way through leaves the previous set
152
+ // intact rather than a half-built one.
153
+ const entries = [];
154
+ do {
155
+ // `pageToken` is empty only on the first pass; the loop condition ends
156
+ // it otherwise. The previous null/undefined pair was half redundant,
157
+ // which is what the static analysis was pointing at.
158
+ const query = pageToken ? `?pageToken=${encodeURIComponent(pageToken)}` : '';
159
+ const page = await this.#http.get(`/v1/revocations${query}`);
160
+ entries.push(...page.entries);
161
+ cursor = page.cursor;
162
+ pageToken = page.nextPageToken;
163
+ } while (pageToken);
164
+ this.#set.replaceAll(entries);
165
+ this.#set.prune();
166
+ this.#cursor = cursor;
167
+ this.#synced = true;
168
+ this.#touch();
169
+ }
170
+ /** Follow the Server-Sent Events stream. Returns false if streaming is not usable here. */
171
+ async #stream() {
172
+ const response = await this.#http.rawGet(`/v1/revocations/stream?since=${this.#cursor}`, this.#controller?.signal);
173
+ if (!response.ok)
174
+ throw httpError(response.status);
175
+ if (!response.body)
176
+ return false;
177
+ const reader = response.body.getReader();
178
+ this.#reader = reader;
179
+ const decoder = new TextDecoder();
180
+ let buffer = '';
181
+ // A half-open socket delivers nothing and never ends. Heartbeats are due
182
+ // every second, so silence for twice the staleness bound means the
183
+ // connection is gone: drop it and let the loop reconnect.
184
+ const silenceLimit = Math.max(2 * this.#staleAfterMs, 1_000);
185
+ let watchdog = setTimeout(() => void reader.cancel().catch(() => { }), silenceLimit);
186
+ watchdog.unref?.();
187
+ try {
188
+ while (this.#running) {
189
+ const { done, value } = await reader.read();
190
+ if (done)
191
+ break;
192
+ clearTimeout(watchdog);
193
+ watchdog = setTimeout(() => void reader.cancel().catch(() => { }), silenceLimit);
194
+ watchdog.unref?.();
195
+ buffer += decoder.decode(value, { stream: true });
196
+ let index = buffer.indexOf('\n\n');
197
+ while (index !== -1) {
198
+ this.#handleEvent(buffer.slice(0, index));
199
+ buffer = buffer.slice(index + 2);
200
+ index = buffer.indexOf('\n\n');
201
+ }
202
+ }
203
+ }
204
+ finally {
205
+ clearTimeout(watchdog);
206
+ this.#reader = null;
207
+ reader.releaseLock();
208
+ await response.body.cancel().catch(() => { });
209
+ }
210
+ return true;
211
+ }
212
+ #handleEvent(block) {
213
+ let event = 'message';
214
+ let data = '';
215
+ for (const line of block.split('\n')) {
216
+ if (line.startsWith('event:'))
217
+ event = line.slice(6).trim();
218
+ else if (line.startsWith('data:'))
219
+ data += line.slice(5).trim();
220
+ }
221
+ if (event === 'heartbeat' || event === 'ready') {
222
+ this.#touch();
223
+ return;
224
+ }
225
+ if (event !== 'revocation' || data.length === 0)
226
+ return;
227
+ try {
228
+ const entry = JSON.parse(data);
229
+ this.#set.apply(entry);
230
+ if (entry.seq > this.#cursor)
231
+ this.#cursor = entry.seq;
232
+ this.#touch();
233
+ }
234
+ catch {
235
+ // A line we cannot read is not evidence that nothing is revoked; the
236
+ // next heartbeat decides freshness.
237
+ }
238
+ }
239
+ /** Long-poll fallback for runtimes without streaming response bodies. */
240
+ async #poll() {
241
+ const wait = Math.max(1, Math.floor(this.#staleAfterMs / 2 / 1000));
242
+ while (this.#running) {
243
+ const page = await this.#http.get(`/v1/revocations?since=${this.#cursor}&wait=${wait}`);
244
+ this.#set.applyAll(page.entries);
245
+ if (page.cursor > this.#cursor)
246
+ this.#cursor = page.cursor;
247
+ for (const entry of page.entries)
248
+ if (entry.seq > this.#cursor)
249
+ this.#cursor = entry.seq;
250
+ this.#touch();
251
+ }
252
+ }
253
+ }
254
+ function httpError(status) {
255
+ const error = new Error(`revocation feed responded ${status}`);
256
+ error.status = status;
257
+ return error;
258
+ }
259
+ function classify(err) {
260
+ const status = err?.statusCode
261
+ ?? err?.status;
262
+ if (status === 404)
263
+ return 'disabled';
264
+ if (status === 503)
265
+ return 'not_ready';
266
+ if (status === 401 || status === 403)
267
+ return 'unauthorized';
268
+ return 'network';
269
+ }
270
+ async function sleep(ms, signal) {
271
+ if (signal?.aborted)
272
+ return;
273
+ await new Promise((resolve) => {
274
+ const timer = setTimeout(resolve, ms);
275
+ timer.unref?.();
276
+ signal?.addEventListener('abort', () => {
277
+ clearTimeout(timer);
278
+ resolve();
279
+ }, { once: true });
280
+ });
281
+ }
282
+ //# sourceMappingURL=feed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feed.js","sourceRoot":"","sources":["../../src/revocations/feed.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Revocation checking for `enforce()` (PRD G-6).
3
+ *
4
+ * - `offline` (default): no check. A revoked grant's token stays
5
+ * cryptographically valid until it expires, which is why the other two modes
6
+ * exist.
7
+ * - `feed`: follow the revocation feed and keep an in-memory set of revoked
8
+ * grants and tokens. Denies within seconds of a revocation, with no network
9
+ * call on the hot path, and fails closed when the feed goes stale.
10
+ * - `online`: ask the auth service about the grant on every call. Simplest,
11
+ * slowest, and denies when the service cannot be reached.
12
+ */
13
+ export declare const REVOCATION_CHECK_MODES: readonly ['offline', 'online', 'feed'];
14
+ export type RevocationCheckMode = (typeof REVOCATION_CHECK_MODES)[number];
15
+ export declare function isRevocationCheckMode(value: unknown): value is RevocationCheckMode;
16
+ export { RevokedSet } from './set.js';
17
+ export type { CredentialRef, RevocationAction, RevocationEntry, RevocationMatch } from './set.js';
18
+ export { RevocationFeed } from './feed.js';
19
+ export type { FeedUnavailableReason, RevocationFeedOptions, RevocationFeedState } from './feed.js';
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/revocations/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,YAAI,SAAS,EAAE,QAAQ,EAAE,MAAM,CAAU,CAAC;AAC7E,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1E,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,mBAAmB,CAElF;AAED,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAClG,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,YAAY,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Revocation checking for `enforce()` (PRD G-6).
3
+ *
4
+ * - `offline` (default): no check. A revoked grant's token stays
5
+ * cryptographically valid until it expires, which is why the other two modes
6
+ * exist.
7
+ * - `feed`: follow the revocation feed and keep an in-memory set of revoked
8
+ * grants and tokens. Denies within seconds of a revocation, with no network
9
+ * call on the hot path, and fails closed when the feed goes stale.
10
+ * - `online`: ask the auth service about the grant on every call. Simplest,
11
+ * slowest, and denies when the service cannot be reached.
12
+ */
13
+ export const REVOCATION_CHECK_MODES = ['offline', 'online', 'feed'];
14
+ export function isRevocationCheckMode(value) {
15
+ return typeof value === 'string' && REVOCATION_CHECK_MODES.includes(value);
16
+ }
17
+ export { RevokedSet } from './set.js';
18
+ export { RevocationFeed } from './feed.js';
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/revocations/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,SAAS,EAAE,QAAQ,EAAE,MAAM,CAAU,CAAC;AAG7E,MAAM,UAAU,qBAAqB,CAAC,KAAc;IAClD,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,sBAA4C,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACpG,CAAC;AAED,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * What the client knows is revoked.
3
+ *
4
+ * `enforce()` verifies a grant token offline, so on its own it cannot see a
5
+ * revocation: the token stays cryptographically valid until it expires. This
6
+ * set is the answer — a small in-memory index of the grants and tokens the
7
+ * auth service says are no longer usable, kept current by the revocation feed.
8
+ */
9
+ export type RevocationAction = 'revoked' | 'suspended' | 'resumed' | 'token_revoked';
10
+ export interface RevocationEntry {
11
+ seq: number;
12
+ action: RevocationAction;
13
+ grantId: string | null;
14
+ jti: string | null;
15
+ expiresAt: string | null;
16
+ at: string;
17
+ }
18
+ export interface CredentialRef {
19
+ grantId?: string | undefined;
20
+ tokenId?: string | undefined;
21
+ parentGrantId?: string | undefined;
22
+ }
23
+ export interface RevocationMatch {
24
+ /** Which identifier matched: the grant, the token, or the parent grant. */
25
+ kind: 'grant' | 'token' | 'parent_grant';
26
+ id: string;
27
+ action: RevocationAction;
28
+ }
29
+ /** The identifiers a client believes are revoked or suspended, with when they expire. */
30
+ export declare class RevokedSet {
31
+ #private;
32
+ get size(): number;
33
+ /**
34
+ * Apply one feed entry. `resumed` removes a suspension; a revocation is
35
+ * never undone, and the auth service never emits `resumed` for one.
36
+ */
37
+ apply(entry: RevocationEntry): void;
38
+ applyAll(entries: readonly RevocationEntry[]): void;
39
+ /**
40
+ * Replace everything this set knows with `entries`.
41
+ *
42
+ * A snapshot is the complete list of what is revoked or suspended *now*, so
43
+ * applying one on top of an existing set keeps anything that has since been
44
+ * resumed. A grant suspended, then resumed while the client was
45
+ * disconnected, would go on being denied until it expired: the resume
46
+ * entry passed by while nobody was listening, and the snapshot that
47
+ * replaced the stream never mentions it.
48
+ *
49
+ * Nothing awaits between clearing and refilling, so no caller can observe
50
+ * an empty set.
51
+ */
52
+ replaceAll(entries: readonly RevocationEntry[]): void;
53
+ /** Why this credential must not be used, or `null` if this set knows nothing against it. */
54
+ match(ref: CredentialRef, now?: number): RevocationMatch | null;
55
+ /** Forget entries whose credential has expired; it can no longer be used anyway. */
56
+ prune(now?: number): void;
57
+ clear(): void;
58
+ }
59
+ //# sourceMappingURL=set.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"set.d.ts","sourceRoot":"","sources":["../../src/revocations/set.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,eAAe,CAAC;AAErF,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,gBAAgB,CAAC;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC;AAED,MAAM,WAAW,eAAe;IAC9B,2EAA2E;IAC3E,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,cAAc,CAAC;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED,yFAAyF;AACzF,qBAAa,UAAU;;IAIrB,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;OAGG;IACH,KAAK,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAYlC;IAED,QAAQ,CAAC,OAAO,EAAE,SAAS,eAAe,EAAE,GAAG,IAAI,CAElD;IAED;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,OAAO,EAAE,SAAS,eAAe,EAAE,GAAG,IAAI,CAGpD;IAED,4FAA4F;IAC5F,KAAK,CAAC,GAAG,EAAE,aAAa,EAAE,GAAG,GAAE,MAAmB,GAAG,eAAe,GAAG,IAAI,CAW1E;IAED,oFAAoF;IACpF,KAAK,CAAC,GAAG,GAAE,MAAmB,GAAG,IAAI,CAGpC;IAED,KAAK,IAAI,IAAI,CAGZ;CACF"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * What the client knows is revoked.
3
+ *
4
+ * `enforce()` verifies a grant token offline, so on its own it cannot see a
5
+ * revocation: the token stays cryptographically valid until it expires. This
6
+ * set is the answer — a small in-memory index of the grants and tokens the
7
+ * auth service says are no longer usable, kept current by the revocation feed.
8
+ */
9
+ /** The identifiers a client believes are revoked or suspended, with when they expire. */
10
+ export class RevokedSet {
11
+ #grants = new Map();
12
+ #tokens = new Map();
13
+ get size() {
14
+ return this.#grants.size + this.#tokens.size;
15
+ }
16
+ /**
17
+ * Apply one feed entry. `resumed` removes a suspension; a revocation is
18
+ * never undone, and the auth service never emits `resumed` for one.
19
+ */
20
+ apply(entry) {
21
+ const until = entry.expiresAt === null ? Number.POSITIVE_INFINITY : Date.parse(entry.expiresAt);
22
+ const valid = Number.isNaN(until) ? Number.POSITIVE_INFINITY : until;
23
+ if (entry.action === 'resumed') {
24
+ if (entry.grantId !== null)
25
+ this.#grants.delete(entry.grantId);
26
+ return;
27
+ }
28
+ if (entry.action === 'token_revoked') {
29
+ if (entry.jti !== null)
30
+ this.#tokens.set(entry.jti, { until: valid, action: entry.action });
31
+ return;
32
+ }
33
+ if (entry.grantId !== null)
34
+ this.#grants.set(entry.grantId, { until: valid, action: entry.action });
35
+ }
36
+ applyAll(entries) {
37
+ for (const entry of entries)
38
+ this.apply(entry);
39
+ }
40
+ /**
41
+ * Replace everything this set knows with `entries`.
42
+ *
43
+ * A snapshot is the complete list of what is revoked or suspended *now*, so
44
+ * applying one on top of an existing set keeps anything that has since been
45
+ * resumed. A grant suspended, then resumed while the client was
46
+ * disconnected, would go on being denied until it expired: the resume
47
+ * entry passed by while nobody was listening, and the snapshot that
48
+ * replaced the stream never mentions it.
49
+ *
50
+ * Nothing awaits between clearing and refilling, so no caller can observe
51
+ * an empty set.
52
+ */
53
+ replaceAll(entries) {
54
+ this.clear();
55
+ this.applyAll(entries);
56
+ }
57
+ /** Why this credential must not be used, or `null` if this set knows nothing against it. */
58
+ match(ref, now = Date.now()) {
59
+ const grant = ref.grantId === undefined ? undefined : this.#grants.get(ref.grantId);
60
+ if (grant && grant.until > now)
61
+ return { kind: 'grant', id: ref.grantId, action: grant.action };
62
+ const token = ref.tokenId === undefined ? undefined : this.#tokens.get(ref.tokenId);
63
+ if (token && token.until > now)
64
+ return { kind: 'token', id: ref.tokenId, action: token.action };
65
+ // A cascade revokes children too, so a parent entry alone should never
66
+ // decide a call — but honouring it costs nothing and closes the window
67
+ // where a child's own entry has not arrived yet.
68
+ const parent = ref.parentGrantId === undefined ? undefined : this.#grants.get(ref.parentGrantId);
69
+ if (parent && parent.until > now)
70
+ return { kind: 'parent_grant', id: ref.parentGrantId, action: parent.action };
71
+ return null;
72
+ }
73
+ /** Forget entries whose credential has expired; it can no longer be used anyway. */
74
+ prune(now = Date.now()) {
75
+ for (const [id, entry] of this.#grants)
76
+ if (entry.until <= now)
77
+ this.#grants.delete(id);
78
+ for (const [id, entry] of this.#tokens)
79
+ if (entry.until <= now)
80
+ this.#tokens.delete(id);
81
+ }
82
+ clear() {
83
+ this.#grants.clear();
84
+ this.#tokens.clear();
85
+ }
86
+ }
87
+ //# sourceMappingURL=set.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"set.js","sourceRoot":"","sources":["../../src/revocations/set.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Canonical Grantex scope-matching semantics (SPEC §4.1).
3
+ *
4
+ * A scope is `resource:action[:constraint]`. Matching is exact: a granted
5
+ * scope satisfies a required scope only when the two strings are identical.
6
+ * In particular a constrained scope (`payments:initiate:max_500`) is never
7
+ * satisfied by its unconstrained form, and vice versa — the constraint is
8
+ * part of the permission, not a suffix to be prefix-matched away.
9
+ *
10
+ * Adapters that add their own wildcard sugar MUST reduce to these rules for
11
+ * every non-wildcard scope (see `@grantex/x402`'s `scopeMatches`).
12
+ */
13
+ export interface ParsedScope {
14
+ resource: string;
15
+ action: string;
16
+ constraint?: string;
17
+ }
18
+ /** Splits `resource:action[:constraint]`; returns undefined for malformed scopes. */
19
+ export declare function parseScope(scope: string): ParsedScope | undefined;
20
+ /** True when `granted` satisfies `required` — exact string equality. */
21
+ export declare function scopeMatches(granted: string, required: string): boolean;
22
+ /** True when a required scope is satisfied by at least one granted scope. */
23
+ export declare function hasScope(grantedScopes: readonly string[], required: string): boolean;
24
+ /** Required scopes not covered by the granted set (empty when all are satisfied). */
25
+ export declare function missingScopes(grantedScopes: readonly string[], requiredScopes: readonly string[]): string[];
26
+ //# sourceMappingURL=scopes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scopes.d.ts","sourceRoot":"","sources":["../src/scopes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qFAAqF;AACrF,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAOjE;AAED,wEAAwE;AACxE,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEvE;AAED,6EAA6E;AAC7E,wBAAgB,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEpF;AAED,qFAAqF;AACrF,wBAAgB,aAAa,CAC3B,aAAa,EAAE,SAAS,MAAM,EAAE,EAChC,cAAc,EAAE,SAAS,MAAM,EAAE,GAChC,MAAM,EAAE,CAEV"}
package/dist/scopes.js ADDED
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Canonical Grantex scope-matching semantics (SPEC §4.1).
3
+ *
4
+ * A scope is `resource:action[:constraint]`. Matching is exact: a granted
5
+ * scope satisfies a required scope only when the two strings are identical.
6
+ * In particular a constrained scope (`payments:initiate:max_500`) is never
7
+ * satisfied by its unconstrained form, and vice versa — the constraint is
8
+ * part of the permission, not a suffix to be prefix-matched away.
9
+ *
10
+ * Adapters that add their own wildcard sugar MUST reduce to these rules for
11
+ * every non-wildcard scope (see `@grantex/x402`'s `scopeMatches`).
12
+ */
13
+ /** Splits `resource:action[:constraint]`; returns undefined for malformed scopes. */
14
+ export function parseScope(scope) {
15
+ if (typeof scope !== 'string')
16
+ return undefined;
17
+ const parts = scope.split(':');
18
+ if (parts.length < 2 || parts.length > 3)
19
+ return undefined;
20
+ if (parts.some((part) => part.length === 0))
21
+ return undefined;
22
+ const [resource, action, constraint] = parts;
23
+ return constraint !== undefined ? { resource, action, constraint } : { resource, action };
24
+ }
25
+ /** True when `granted` satisfies `required` — exact string equality. */
26
+ export function scopeMatches(granted, required) {
27
+ return typeof granted === 'string' && typeof required === 'string' && granted === required;
28
+ }
29
+ /** True when a required scope is satisfied by at least one granted scope. */
30
+ export function hasScope(grantedScopes, required) {
31
+ return grantedScopes.some((granted) => scopeMatches(granted, required));
32
+ }
33
+ /** Required scopes not covered by the granted set (empty when all are satisfied). */
34
+ export function missingScopes(grantedScopes, requiredScopes) {
35
+ return requiredScopes.filter((required) => !hasScope(grantedScopes, required));
36
+ }
37
+ //# sourceMappingURL=scopes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scopes.js","sourceRoot":"","sources":["../src/scopes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAQH,qFAAqF;AACrF,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAChD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAC3D,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9D,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,GAAG,KAAkC,CAAC;IAC1E,OAAO,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AAC5F,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,QAAgB;IAC5D,OAAO,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,OAAO,KAAK,QAAQ,CAAC;AAC7F,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,QAAQ,CAAC,aAAgC,EAAE,QAAgB;IACzE,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AAC1E,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,aAAa,CAC3B,aAAgC,EAChC,cAAiC;IAEjC,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAC;AACjF,CAAC"}