@blimu/backend 1.1.1 → 1.1.4

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 (145) hide show
  1. package/README.md +6 -13
  2. package/dist/__tests__/token-verifier.test.cjs +17662 -0
  3. package/dist/__tests__/token-verifier.test.cjs.map +1 -0
  4. package/dist/__tests__/token-verifier.test.d.mts +2 -0
  5. package/dist/__tests__/token-verifier.test.d.ts +2 -0
  6. package/dist/__tests__/token-verifier.test.mjs +17661 -0
  7. package/dist/__tests__/token-verifier.test.mjs.map +1 -0
  8. package/dist/auth-strategies.cjs +42 -0
  9. package/dist/auth-strategies.cjs.map +1 -0
  10. package/dist/auth-strategies.d.mts +16 -0
  11. package/dist/auth-strategies.d.ts +16 -0
  12. package/dist/auth-strategies.mjs +17 -0
  13. package/dist/auth-strategies.mjs.map +1 -0
  14. package/dist/client.cjs +483 -0
  15. package/dist/client.cjs.map +1 -0
  16. package/dist/client.d.mts +26 -18
  17. package/dist/client.d.ts +26 -18
  18. package/dist/client.mjs +447 -39
  19. package/dist/client.mjs.map +1 -1
  20. package/dist/{main.js → index.cjs} +290 -407
  21. package/dist/index.cjs.map +1 -0
  22. package/dist/index.d.mts +15 -33
  23. package/dist/index.d.ts +15 -33
  24. package/dist/index.mjs +440 -339
  25. package/dist/index.mjs.map +1 -1
  26. package/dist/{schema-B1usIXCr.d.mts → schema-BbKn_i-U.d.mts} +82 -93
  27. package/dist/{schema-B1usIXCr.d.ts → schema-BbKn_i-U.d.ts} +82 -93
  28. package/dist/{schema.js → schema.cjs} +1 -1
  29. package/dist/schema.cjs.map +1 -0
  30. package/dist/schema.d.mts +1 -2
  31. package/dist/schema.d.ts +1 -2
  32. package/dist/{schema.zod-CRNAHxbc.d.mts → schema.zod-DtXVS-1g.d.mts} +38 -48
  33. package/dist/{schema.zod-CRNAHxbc.d.ts → schema.zod-DtXVS-1g.d.ts} +38 -48
  34. package/dist/{schema.zod.js → schema.zod.cjs} +174 -248
  35. package/dist/schema.zod.cjs.map +1 -0
  36. package/dist/schema.zod.d.mts +1 -1
  37. package/dist/schema.zod.d.ts +1 -1
  38. package/dist/schema.zod.mjs +173 -242
  39. package/dist/schema.zod.mjs.map +1 -1
  40. package/dist/services/{bulk_resources.js → bulk_resources.cjs} +3 -2
  41. package/dist/services/bulk_resources.cjs.map +1 -0
  42. package/dist/services/bulk_resources.d.mts +4 -6
  43. package/dist/services/bulk_resources.d.ts +4 -6
  44. package/dist/services/bulk_resources.mjs +2 -1
  45. package/dist/services/bulk_resources.mjs.map +1 -1
  46. package/dist/services/{bulk_roles.js → bulk_roles.cjs} +3 -2
  47. package/dist/services/bulk_roles.cjs.map +1 -0
  48. package/dist/services/bulk_roles.d.mts +3 -5
  49. package/dist/services/bulk_roles.d.ts +3 -5
  50. package/dist/services/bulk_roles.mjs +2 -1
  51. package/dist/services/bulk_roles.mjs.map +1 -1
  52. package/dist/services/{entitlements.js → entitlements.cjs} +5 -4
  53. package/dist/services/entitlements.cjs.map +1 -0
  54. package/dist/services/entitlements.d.mts +4 -6
  55. package/dist/services/entitlements.d.ts +4 -6
  56. package/dist/services/entitlements.mjs +4 -3
  57. package/dist/services/entitlements.mjs.map +1 -1
  58. package/dist/services/{plans.js → plans.cjs} +5 -4
  59. package/dist/services/plans.cjs.map +1 -0
  60. package/dist/services/plans.d.mts +6 -8
  61. package/dist/services/plans.d.ts +6 -8
  62. package/dist/services/plans.mjs +4 -3
  63. package/dist/services/plans.mjs.map +1 -1
  64. package/dist/services/{resource_members.js → resource_members.cjs} +3 -2
  65. package/dist/services/resource_members.cjs.map +1 -0
  66. package/dist/services/resource_members.d.mts +4 -6
  67. package/dist/services/resource_members.d.ts +4 -6
  68. package/dist/services/resource_members.mjs +2 -1
  69. package/dist/services/resource_members.mjs.map +1 -1
  70. package/dist/services/{resources.js → resources.cjs} +7 -6
  71. package/dist/services/resources.cjs.map +1 -0
  72. package/dist/services/resources.d.mts +8 -10
  73. package/dist/services/resources.d.ts +8 -10
  74. package/dist/services/resources.mjs +6 -5
  75. package/dist/services/resources.mjs.map +1 -1
  76. package/dist/services/{roles.js → roles.cjs} +5 -4
  77. package/dist/services/roles.cjs.map +1 -0
  78. package/dist/services/roles.d.mts +4 -6
  79. package/dist/services/roles.d.ts +4 -6
  80. package/dist/services/roles.mjs +4 -3
  81. package/dist/services/roles.mjs.map +1 -1
  82. package/dist/services/{usage.js → usage.cjs} +7 -6
  83. package/dist/services/usage.cjs.map +1 -0
  84. package/dist/services/usage.d.mts +5 -7
  85. package/dist/services/usage.d.ts +5 -7
  86. package/dist/services/usage.mjs +6 -5
  87. package/dist/services/usage.mjs.map +1 -1
  88. package/dist/services/{users.js → users.cjs} +8 -7
  89. package/dist/services/users.cjs.map +1 -0
  90. package/dist/services/users.d.mts +3 -5
  91. package/dist/services/users.d.ts +3 -5
  92. package/dist/services/users.mjs +7 -6
  93. package/dist/services/users.mjs.map +1 -1
  94. package/dist/{token-verifier.js → token-verifier.cjs} +10 -30
  95. package/dist/token-verifier.cjs.map +1 -0
  96. package/dist/token-verifier.d.mts +5 -5
  97. package/dist/token-verifier.d.ts +5 -5
  98. package/dist/token-verifier.mjs +10 -33
  99. package/dist/token-verifier.mjs.map +1 -1
  100. package/dist/tsconfig.tsbuildinfo +1 -1
  101. package/dist/{utils.js → utils.cjs} +9 -3
  102. package/dist/utils.cjs.map +1 -0
  103. package/dist/utils.d.mts +4 -3
  104. package/dist/utils.d.ts +4 -3
  105. package/dist/utils.mjs +7 -2
  106. package/dist/utils.mjs.map +1 -1
  107. package/package.json +36 -24
  108. package/dist/client.js +0 -71
  109. package/dist/client.js.map +0 -1
  110. package/dist/index.js +0 -1052
  111. package/dist/index.js.map +0 -1
  112. package/dist/main.d.mts +0 -19
  113. package/dist/main.d.ts +0 -19
  114. package/dist/main.js.map +0 -1
  115. package/dist/main.mjs +0 -1275
  116. package/dist/main.mjs.map +0 -1
  117. package/dist/schema.js.map +0 -1
  118. package/dist/schema.zod.js.map +0 -1
  119. package/dist/services/bulk_resources.js.map +0 -1
  120. package/dist/services/bulk_roles.js.map +0 -1
  121. package/dist/services/entitlements.js.map +0 -1
  122. package/dist/services/plans.js.map +0 -1
  123. package/dist/services/resource_members.js.map +0 -1
  124. package/dist/services/resources.js.map +0 -1
  125. package/dist/services/roles.js.map +0 -1
  126. package/dist/services/usage.js.map +0 -1
  127. package/dist/services/users.js.map +0 -1
  128. package/dist/token-verifier.js.map +0 -1
  129. package/dist/utils.js.map +0 -1
  130. package/src/client.ts +0 -74
  131. package/src/index.ts +0 -55
  132. package/src/main.ts +0 -3
  133. package/src/schema.ts +0 -430
  134. package/src/schema.zod.ts +0 -558
  135. package/src/services/bulk_resources.ts +0 -24
  136. package/src/services/bulk_roles.ts +0 -22
  137. package/src/services/entitlements.ts +0 -58
  138. package/src/services/plans.ts +0 -57
  139. package/src/services/resource_members.ts +0 -25
  140. package/src/services/resources.ts +0 -91
  141. package/src/services/roles.ts +0 -58
  142. package/src/services/usage.ts +0 -93
  143. package/src/services/users.ts +0 -100
  144. package/src/token-verifier.ts +0 -280
  145. package/src/utils.ts +0 -56
@@ -1,280 +0,0 @@
1
- import { FetchError } from 'client';
2
- import * as crypto from 'crypto';
3
- import * as jwt from 'jsonwebtoken';
4
-
5
- export interface JWK {
6
- kty: string;
7
- use: string;
8
- kid: string;
9
- alg: string;
10
- n: string;
11
- e: string;
12
- }
13
-
14
- export interface JWKSet {
15
- keys: JWK[];
16
- }
17
-
18
- interface CachedJWK {
19
- key: crypto.KeyObject;
20
- kid: string;
21
- expiresAt: number;
22
- }
23
-
24
- export interface VerifyTokenOptions {
25
- url?: string; // Direct URL to JWK endpoint (for custom scenarios)
26
- secretKey?: string; // API key/secret key - uses runtimeApiUrl + JWK endpoint
27
- token: string;
28
- runtimeApiUrl?: string; // Optional override for runtime API URL
29
- }
30
-
31
- export interface TokenVerifierOptions {
32
- runtimeApiUrl?: string; // Default from BLIMU_AUTH_API_URL env var
33
- cacheTTL?: number; // Default: 1 hour
34
- }
35
-
36
- export class TokenVerifier {
37
- private readonly cache = new Map<string, CachedJWK>();
38
- private readonly cacheTTL: number;
39
- private readonly runtimeApiUrl: string;
40
-
41
- constructor(options?: TokenVerifierOptions) {
42
- this.cacheTTL = options?.cacheTTL ?? 60 * 60 * 1000; // 1 hour
43
-
44
- const blimuAuthApiUrl =
45
- typeof process !== 'undefined' && process.env.BLIMU_AUTH_API_URL
46
- ? process.env.BLIMU_AUTH_API_URL
47
- : undefined;
48
-
49
- // if we have secretKey, we can call runtime-api directly, otherwise we need to use customer specific auth-api
50
- this.runtimeApiUrl = blimuAuthApiUrl ?? 'https://api.blimu.dev';
51
- }
52
-
53
- /**
54
- * Fetch JWK Set from runtime-api
55
- */
56
- private async fetchJWKSet(
57
- endpoint: string,
58
- headers?: Record<string, string>
59
- ): Promise<JWKSet> {
60
- console.log(`[TokenVerifier] 📡 Fetching JWK Set from: ${endpoint}`);
61
- if (headers) {
62
- console.log(
63
- `[TokenVerifier] 📡 Request headers: ${JSON.stringify(Object.keys(headers).map((k) => `${k}: ${k === 'x-api-key' ? '***' : headers[k]}`))}`
64
- );
65
- }
66
-
67
- const response = await fetch(endpoint, {
68
- method: 'GET',
69
- headers: {
70
- 'Content-Type': 'application/json',
71
- ...headers,
72
- },
73
- });
74
-
75
- console.log(
76
- `[TokenVerifier] 📡 Response status: ${response.status} ${response.statusText}`
77
- );
78
-
79
- if (!response.ok) {
80
- const errorText = await response.text();
81
- console.error(
82
- `[TokenVerifier] ❌ Failed to fetch JWKs: ${response.status} ${errorText}`
83
- );
84
- throw new FetchError('Failed to fetch JWKs', response.status, errorText);
85
- }
86
-
87
- const jwkSet = (await response.json()) as JWKSet;
88
- console.log(
89
- `[TokenVerifier] ✅ Successfully fetched JWK Set with ${jwkSet.keys.length} keys`
90
- );
91
- return jwkSet;
92
- }
93
-
94
- /**
95
- * Convert JWK to KeyObject
96
- */
97
- private jwkToKeyObject(jwk: JWK): crypto.KeyObject {
98
- return crypto.createPublicKey({
99
- key: {
100
- kty: jwk.kty,
101
- n: jwk.n,
102
- e: jwk.e,
103
- alg: jwk.alg,
104
- },
105
- format: 'jwk',
106
- });
107
- }
108
-
109
- /**
110
- * Get public key for a specific key ID
111
- */
112
- private async getPublicKey(
113
- kid: string,
114
- cacheKey: string,
115
- endpoint: string,
116
- headers?: Record<string, string>
117
- ): Promise<crypto.KeyObject> {
118
- // Check cache first
119
- const cached = this.cache.get(cacheKey);
120
- if (cached && cached.expiresAt > Date.now()) {
121
- console.log(`[TokenVerifier] ✅ Using cached key for kid: ${kid}`);
122
- return cached.key;
123
- }
124
-
125
- console.log(
126
- `[TokenVerifier] 🔍 Cache miss or expired. Fetching new key for kid: ${kid}`
127
- );
128
-
129
- // Fetch JWK Set
130
- const jwkSet = await this.fetchJWKSet(endpoint, headers);
131
-
132
- // Find the key with matching kid
133
- const jwk = jwkSet.keys.find((k) => k.kid === kid);
134
- if (!jwk) {
135
- const availableKids = jwkSet.keys.map((k) => k.kid).join(', ');
136
- console.error(
137
- `[TokenVerifier] ❌ Key with kid '${kid}' not found in JWK Set. Available kids: ${availableKids}`
138
- );
139
- throw new Error(
140
- `Key with kid '${kid}' not found in JWK Set. Available kids: ${availableKids}`
141
- );
142
- }
143
-
144
- console.log(`[TokenVerifier] ✅ Found key with kid: ${kid}`);
145
-
146
- // Convert JWK to KeyObject
147
- const keyObject = this.jwkToKeyObject(jwk);
148
-
149
- // Cache the key
150
- this.cache.set(cacheKey, {
151
- key: keyObject,
152
- kid,
153
- expiresAt: Date.now() + this.cacheTTL,
154
- });
155
-
156
- return keyObject;
157
- }
158
-
159
- /**
160
- * Verify JWT token using JWKs from runtime-api
161
- */
162
- async verifyToken<T = any>(options: VerifyTokenOptions): Promise<T> {
163
- const { url, secretKey, token, runtimeApiUrl } = options;
164
-
165
- if (!url && !secretKey) {
166
- throw new Error('Either url or secretKey must be provided');
167
- }
168
-
169
- if (url && secretKey) {
170
- throw new Error('Cannot provide both url and secretKey');
171
- }
172
-
173
- // Decode token header to get kid (without verification)
174
- const decoded = jwt.decode(token, { complete: true });
175
- if (!decoded || typeof decoded === 'string') {
176
- throw new Error('Invalid token format');
177
- }
178
-
179
- const header = decoded.header;
180
- if (!header.kid) {
181
- throw new Error('Token missing kid in header');
182
- }
183
-
184
- let endpoint: string;
185
- let cacheKey: string;
186
- let headers: Record<string, string> | undefined;
187
-
188
- if (secretKey) {
189
- // Use secretKey with runtimeApiUrl
190
- const apiUrl = runtimeApiUrl ?? this.runtimeApiUrl;
191
- endpoint = `${apiUrl}/v1/auth/.well-known/jwks.json`;
192
- cacheKey = secretKey;
193
- headers = {
194
- 'x-api-key': secretKey,
195
- };
196
- console.log(
197
- `[TokenVerifier] 🔍 Verifying token with kid: ${header.kid}, endpoint: ${endpoint}`
198
- );
199
- } else {
200
- // Use direct URL
201
- endpoint = url!;
202
- cacheKey = url!;
203
- console.log(
204
- `[TokenVerifier] 🔍 Verifying token with kid: ${header.kid}, endpoint: ${endpoint}`
205
- );
206
- }
207
-
208
- // Get public key for this kid
209
- let publicKey: crypto.KeyObject;
210
- try {
211
- publicKey = await this.getPublicKey(
212
- header.kid,
213
- cacheKey,
214
- endpoint,
215
- headers
216
- );
217
- console.log(
218
- `[TokenVerifier] ✅ Successfully retrieved public key for kid: ${header.kid}`
219
- );
220
- } catch (error) {
221
- console.error(
222
- `[TokenVerifier] ❌ Failed to get public key (first attempt): ${error instanceof Error ? error.message : String(error)}`
223
- );
224
- // If verification fails, clear cache and retry once (handles key rotation)
225
- this.clearCache(cacheKey);
226
- console.log(`[TokenVerifier] 🔄 Retrying after cache clear...`);
227
- try {
228
- publicKey = await this.getPublicKey(
229
- header.kid,
230
- cacheKey,
231
- endpoint,
232
- headers
233
- );
234
- console.log(
235
- `[TokenVerifier] ✅ Successfully retrieved public key for kid: ${header.kid} (retry)`
236
- );
237
- } catch (retryError) {
238
- console.error(
239
- `[TokenVerifier] ❌ Failed to get public key (retry): ${retryError instanceof Error ? retryError.message : String(retryError)}`
240
- );
241
- throw retryError;
242
- }
243
- }
244
-
245
- // Verify token
246
- try {
247
- const payload = jwt.verify(token, publicKey, {
248
- algorithms: ['RS256'],
249
- }) as T;
250
- console.log(`[TokenVerifier] ✅ Token verified successfully`);
251
- return payload;
252
- } catch (error) {
253
- console.error(
254
- `[TokenVerifier] ❌ JWT verification failed: ${error instanceof Error ? error.message : String(error)}`
255
- );
256
- throw error;
257
- }
258
- }
259
-
260
- /**
261
- * Clear cache (useful for testing or key rotation)
262
- */
263
- clearCache(secretKeyOrUrl?: string): void {
264
- if (secretKeyOrUrl) {
265
- this.cache.delete(secretKeyOrUrl);
266
- } else {
267
- this.cache.clear();
268
- }
269
- }
270
- }
271
-
272
- /**
273
- * Convenience function to verify a token
274
- */
275
- export async function verifyToken<T = any>(
276
- options: VerifyTokenOptions
277
- ): Promise<T> {
278
- const verifier = new TokenVerifier();
279
- return verifier.verifyToken<T>(options);
280
- }
package/src/utils.ts DELETED
@@ -1,56 +0,0 @@
1
- import { parseSSEStream, parseNDJSONStream } from '@blimu/fetch';
2
-
3
- export type PaginableQuery = { limit?: number; offset?: number } & Record<
4
- string,
5
- unknown
6
- >;
7
-
8
- export async function* paginate<T>(
9
- fetchPage: (
10
- query?: any,
11
- init?: Omit<RequestInit, 'method' | 'body'>
12
- ) => Promise<{
13
- data?: T[];
14
- hasMore?: boolean;
15
- limit?: number;
16
- offset?: number;
17
- }>,
18
- initialQuery: PaginableQuery = {},
19
- pageSize = 100
20
- ): AsyncGenerator<T, void, unknown> {
21
- let offset = Number(initialQuery.offset ?? 0);
22
- const limit = Number(initialQuery.limit ?? pageSize);
23
- // shallow copy to avoid mutating caller
24
- const baseQuery: any = { ...initialQuery };
25
- while (true) {
26
- const page = await fetchPage({ ...baseQuery, limit, offset });
27
- const items = page.data ?? [];
28
- for (const item of items) {
29
- yield item as T;
30
- }
31
- if (!page.hasMore || items.length < limit) break;
32
- offset += limit;
33
- }
34
- }
35
-
36
- export async function listAll<T>(
37
- fetchPage: (
38
- query?: any,
39
- init?: Omit<RequestInit, 'method' | 'body'>
40
- ) => Promise<{
41
- data?: T[];
42
- hasMore?: boolean;
43
- limit?: number;
44
- offset?: number;
45
- }>,
46
- query: PaginableQuery = {},
47
- pageSize = 100
48
- ): Promise<T[]> {
49
- const out: T[] = [];
50
- for await (const item of paginate<T>(fetchPage, query, pageSize))
51
- out.push(item);
52
- return out;
53
- }
54
-
55
- // Re-export streaming parsers from @blimu/fetch
56
- export { parseSSEStream, parseNDJSONStream };