@blimu/nestjs 1.1.1 → 1.1.3

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 (80) hide show
  1. package/dist/__tests__/example.test.cjs +17135 -0
  2. package/dist/__tests__/example.test.cjs.map +1 -0
  3. package/dist/__tests__/example.test.d.cts +2 -0
  4. package/dist/__tests__/example.test.d.ts +2 -0
  5. package/dist/__tests__/example.test.mjs +17134 -0
  6. package/dist/__tests__/example.test.mjs.map +1 -0
  7. package/dist/config/blimu.config.cjs +31 -0
  8. package/dist/config/blimu.config.cjs.map +1 -0
  9. package/dist/config/blimu.config.d.cts +11 -0
  10. package/dist/config/blimu.config.d.ts +8 -6
  11. package/dist/config/blimu.config.mjs +6 -0
  12. package/dist/config/blimu.config.mjs.map +1 -0
  13. package/dist/decorators/entitlement.decorator.cjs +178 -0
  14. package/dist/decorators/entitlement.decorator.cjs.map +1 -0
  15. package/dist/decorators/entitlement.decorator.d.cts +9 -0
  16. package/dist/decorators/entitlement.decorator.d.ts +9 -4
  17. package/dist/decorators/entitlement.decorator.mjs +161 -0
  18. package/dist/decorators/entitlement.decorator.mjs.map +1 -0
  19. package/dist/exceptions/blimu-forbidden.exception.cjs +86 -0
  20. package/dist/exceptions/blimu-forbidden.exception.cjs.map +1 -0
  21. package/dist/exceptions/blimu-forbidden.exception.d.cts +14 -0
  22. package/dist/exceptions/blimu-forbidden.exception.d.ts +6 -4
  23. package/dist/exceptions/blimu-forbidden.exception.mjs +61 -0
  24. package/dist/exceptions/blimu-forbidden.exception.mjs.map +1 -0
  25. package/dist/guards/entitlement.guard.cjs +174 -0
  26. package/dist/guards/entitlement.guard.cjs.map +1 -0
  27. package/dist/guards/entitlement.guard.d.cts +24 -0
  28. package/dist/guards/entitlement.guard.d.ts +12 -12
  29. package/dist/guards/entitlement.guard.mjs +154 -0
  30. package/dist/guards/entitlement.guard.mjs.map +1 -0
  31. package/dist/index.cjs +445 -0
  32. package/dist/index.cjs.map +1 -0
  33. package/dist/index.d.cts +9 -0
  34. package/dist/index.d.ts +9 -7
  35. package/dist/index.mjs +420 -0
  36. package/dist/index.mjs.map +1 -0
  37. package/dist/modules/blimu.module.cjs +413 -0
  38. package/dist/modules/blimu.module.cjs.map +1 -0
  39. package/dist/modules/blimu.module.d.cts +14 -0
  40. package/dist/modules/blimu.module.d.ts +11 -8
  41. package/dist/modules/blimu.module.mjs +398 -0
  42. package/dist/modules/blimu.module.mjs.map +1 -0
  43. package/dist/services/index.cjs +93 -0
  44. package/dist/services/index.cjs.map +1 -0
  45. package/dist/services/index.d.cts +2 -0
  46. package/dist/services/index.d.ts +2 -2
  47. package/dist/services/index.mjs +69 -0
  48. package/dist/services/index.mjs.map +1 -0
  49. package/dist/services/jwk.service.cjs +91 -0
  50. package/dist/services/jwk.service.cjs.map +1 -0
  51. package/dist/services/jwk.service.d.cts +12 -0
  52. package/dist/services/jwk.service.d.ts +5 -3
  53. package/dist/services/jwk.service.mjs +69 -0
  54. package/dist/services/jwk.service.mjs.map +1 -0
  55. package/package.json +34 -13
  56. package/dist/config/blimu.config.d.ts.map +0 -1
  57. package/dist/config/blimu.config.js +0 -5
  58. package/dist/config/blimu.config.js.map +0 -1
  59. package/dist/decorators/entitlement.decorator.d.ts.map +0 -1
  60. package/dist/decorators/entitlement.decorator.js +0 -10
  61. package/dist/decorators/entitlement.decorator.js.map +0 -1
  62. package/dist/exceptions/blimu-forbidden.exception.d.ts.map +0 -1
  63. package/dist/exceptions/blimu-forbidden.exception.js +0 -38
  64. package/dist/exceptions/blimu-forbidden.exception.js.map +0 -1
  65. package/dist/guards/entitlement.guard.d.ts.map +0 -1
  66. package/dist/guards/entitlement.guard.js +0 -82
  67. package/dist/guards/entitlement.guard.js.map +0 -1
  68. package/dist/index.d.ts.map +0 -1
  69. package/dist/index.js +0 -23
  70. package/dist/index.js.map +0 -1
  71. package/dist/modules/blimu.module.d.ts.map +0 -1
  72. package/dist/modules/blimu.module.js +0 -91
  73. package/dist/modules/blimu.module.js.map +0 -1
  74. package/dist/services/index.d.ts.map +0 -1
  75. package/dist/services/index.js +0 -18
  76. package/dist/services/index.js.map +0 -1
  77. package/dist/services/jwk.service.d.ts.map +0 -1
  78. package/dist/services/jwk.service.js +0 -59
  79. package/dist/services/jwk.service.js.map +0 -1
  80. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,398 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result) __defProp(target, key, result);
9
+ return result;
10
+ };
11
+ var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
12
+
13
+ // src/modules/blimu.module.ts
14
+ import {
15
+ Module
16
+ } from "@nestjs/common";
17
+
18
+ // src/config/blimu.config.ts
19
+ var BLIMU_CONFIG = /* @__PURE__ */ Symbol("BLIMU_CONFIG");
20
+
21
+ // src/guards/entitlement.guard.ts
22
+ import {
23
+ ForbiddenException as ForbiddenException2,
24
+ Injectable,
25
+ SetMetadata,
26
+ Inject
27
+ } from "@nestjs/common";
28
+ import "reflect-metadata";
29
+
30
+ // src/exceptions/blimu-forbidden.exception.ts
31
+ import { ForbiddenException } from "@nestjs/common";
32
+ var BlimuForbiddenException = class _BlimuForbiddenException extends ForbiddenException {
33
+ /**
34
+ * The entitlement check result containing detailed failure information
35
+ */
36
+ entitlementResult;
37
+ /**
38
+ * The entitlement key that was checked
39
+ */
40
+ entitlementKey;
41
+ /**
42
+ * The resource ID that was checked
43
+ */
44
+ resourceId;
45
+ /**
46
+ * The user ID that was checked
47
+ */
48
+ userId;
49
+ constructor(entitlementResult, entitlementKey, resourceId, userId) {
50
+ const message = _BlimuForbiddenException.buildMessage(entitlementResult, entitlementKey);
51
+ super({
52
+ message,
53
+ entitlementResult,
54
+ entitlementKey,
55
+ resourceId,
56
+ userId
57
+ });
58
+ this.entitlementResult = entitlementResult;
59
+ this.entitlementKey = entitlementKey;
60
+ this.resourceId = resourceId;
61
+ this.userId = userId;
62
+ }
63
+ /**
64
+ * Builds a user-friendly error message from the entitlement check result
65
+ */
66
+ static buildMessage(result, entitlementKey) {
67
+ const reasons = [];
68
+ if (result.roles && !result.roles.allowed) {
69
+ reasons.push(
70
+ `Insufficient roles. Required: ${result.roles.allowedRoles?.join(", ") || "unknown"}. User has: ${result.roles.userRoles?.join(", ") || "none"}.`
71
+ );
72
+ }
73
+ if (result.plans && !result.plans.allowed) {
74
+ reasons.push(
75
+ `Plan restriction. Required plans: ${result.plans.allowedPlans?.join(", ") || "unknown"}. Current plan: ${result.plans.plan || "none"}.`
76
+ );
77
+ }
78
+ if (result.limit && !result.limit.allowed) {
79
+ reasons.push(`Usage limit exceeded. ${result.limit.reason || "Limit has been reached"}.`);
80
+ }
81
+ if (reasons.length === 0) {
82
+ return `Access denied for entitlement: ${entitlementKey}`;
83
+ }
84
+ return `Access denied for entitlement "${entitlementKey}": ${reasons.join(" ")}`;
85
+ }
86
+ };
87
+
88
+ // src/guards/entitlement.guard.ts
89
+ import { Blimu } from "@blimu/backend";
90
+ var ENTITLEMENT_METADATA_KEY = /* @__PURE__ */ Symbol("entitlement");
91
+ var EntitlementGuard = class {
92
+ constructor(config, runtime) {
93
+ this.config = config;
94
+ this.runtime = runtime;
95
+ }
96
+ async canActivate(context) {
97
+ const request = context.switchToHttp().getRequest();
98
+ const handler = context.getHandler();
99
+ const metadata = Reflect.getMetadata(ENTITLEMENT_METADATA_KEY, handler);
100
+ if (!metadata) {
101
+ return true;
102
+ }
103
+ let userId;
104
+ try {
105
+ userId = await this.config.getUserId(request);
106
+ } catch {
107
+ throw new ForbiddenException2("Failed to extract user ID from request");
108
+ }
109
+ if (!userId) {
110
+ throw new ForbiddenException2("User ID is required for entitlement check");
111
+ }
112
+ const entitlementInfo = await metadata.getEntitlementInfo(request);
113
+ if (!entitlementInfo?.resourceId) {
114
+ throw new ForbiddenException2("Resource ID is required for entitlement check");
115
+ }
116
+ try {
117
+ const result = await this.runtime.entitlements.checkEntitlement({
118
+ userId,
119
+ entitlement: metadata.entitlementKey,
120
+ resourceId: entitlementInfo.resourceId,
121
+ ...entitlementInfo.amount !== void 0 ? { amount: entitlementInfo.amount } : {}
122
+ });
123
+ if (!result.allowed) {
124
+ throw new BlimuForbiddenException(
125
+ result,
126
+ metadata.entitlementKey,
127
+ entitlementInfo.resourceId,
128
+ userId
129
+ );
130
+ }
131
+ return true;
132
+ } catch (error) {
133
+ if (error instanceof BlimuForbiddenException || error instanceof ForbiddenException2) {
134
+ throw error;
135
+ }
136
+ console.error("Entitlement check failed:", error);
137
+ throw new ForbiddenException2("Failed to verify entitlements");
138
+ }
139
+ }
140
+ };
141
+ EntitlementGuard = __decorateClass([
142
+ Injectable(),
143
+ __decorateParam(0, Inject(BLIMU_CONFIG)),
144
+ __decorateParam(1, Inject(Blimu))
145
+ ], EntitlementGuard);
146
+
147
+ // src/services/jwk.service.ts
148
+ import { Inject as Inject2, Injectable as Injectable2, Logger } from "@nestjs/common";
149
+ import { TokenVerifier } from "@blimu/backend";
150
+ var JWKService = class {
151
+ constructor(config) {
152
+ this.config = config;
153
+ this.tokenVerifier = new TokenVerifier({
154
+ runtimeApiUrl: this.config.baseURL
155
+ });
156
+ }
157
+ logger = new Logger(JWKService.name);
158
+ tokenVerifier;
159
+ /**
160
+ * Verify JWT token using JWKs from runtime-api
161
+ */
162
+ async verifyToken(token) {
163
+ try {
164
+ this.logger.debug(
165
+ `\u{1F50D} Verifying token. Runtime API URL: ${this.config.baseURL}, API Key prefix: ${this.config.apiKey?.substring(0, 10)}...`
166
+ );
167
+ const result = await this.tokenVerifier.verifyToken({
168
+ secretKey: this.config.apiKey,
169
+ token,
170
+ runtimeApiUrl: this.config.baseURL
171
+ });
172
+ this.logger.debug(`\u2705 Token verified successfully`);
173
+ return result;
174
+ } catch (error) {
175
+ const errorMessage = error instanceof Error ? error.message : String(error);
176
+ this.logger.error(`\u274C Token verification failed: ${errorMessage}`);
177
+ if (error instanceof Error && error.stack) {
178
+ this.logger.error(`Stack trace: ${error.stack}`);
179
+ }
180
+ throw error;
181
+ }
182
+ }
183
+ /**
184
+ * Clear cache (useful for testing or key rotation)
185
+ */
186
+ clearCache() {
187
+ this.tokenVerifier.clearCache(this.config.apiKey);
188
+ this.logger.debug("JWK cache cleared");
189
+ }
190
+ };
191
+ JWKService = __decorateClass([
192
+ Injectable2(),
193
+ __decorateParam(0, Inject2(BLIMU_CONFIG))
194
+ ], JWKService);
195
+
196
+ // src/modules/blimu.module.ts
197
+ import { Blimu as Blimu2 } from "@blimu/backend";
198
+ var DEFAULT_BASE_URL = "https://api.blimu.dev";
199
+ var BlimuModule = class {
200
+ /**
201
+ * Configure the Blimu module with static configuration
202
+ *
203
+ * @param config - The Blimu configuration object
204
+ * @returns A configured dynamic module
205
+ *
206
+ * @example
207
+ * Basic usage with default Request type:
208
+ * ```typescript
209
+ * @Module({
210
+ * imports: [
211
+ * BlimuModule.forRoot({
212
+ * apiKey: 'your-api-secret-key',
213
+ * baseURL: 'https://api.blimu.dev', // optional
214
+ * environmentId: 'your-environment-id', // optional
215
+ * timeoutMs: 30000, // optional
216
+ * getUserId: (req) => req.user?.id, // required
217
+ * }),
218
+ * ],
219
+ * })
220
+ * export class AppModule {}
221
+ * ```
222
+ *
223
+ * @example
224
+ * Usage with custom request type:
225
+ * ```typescript
226
+ * interface AuthenticatedRequest {
227
+ * user: { id: string; email: string };
228
+ * }
229
+ *
230
+ * @Module({
231
+ * imports: [
232
+ * BlimuModule.forRoot<AuthenticatedRequest>({
233
+ * apiKey: 'your-api-secret-key',
234
+ * getUserId: (req) => req.user.id, // req is typed as AuthenticatedRequest
235
+ * }),
236
+ * ],
237
+ * })
238
+ * export class AppModule {}
239
+ * ```
240
+ */
241
+ static forRoot(config) {
242
+ return {
243
+ ...config.global ? { global: true } : {},
244
+ module: BlimuModule,
245
+ providers: [
246
+ // Register factory providers first so dependencies are available
247
+ {
248
+ provide: BLIMU_CONFIG,
249
+ useValue: {
250
+ apiKey: config.apiKey,
251
+ baseURL: config.baseURL ?? DEFAULT_BASE_URL,
252
+ environmentId: config.environmentId,
253
+ timeoutMs: config.timeoutMs ?? 3e4,
254
+ getUserId: config.getUserId
255
+ }
256
+ },
257
+ {
258
+ provide: Blimu2,
259
+ useFactory: (config2) => {
260
+ return new Blimu2({
261
+ apiKey: config2.apiKey,
262
+ baseURL: config2.baseURL ?? DEFAULT_BASE_URL,
263
+ timeoutMs: config2.timeoutMs ?? 3e4
264
+ });
265
+ },
266
+ inject: [BLIMU_CONFIG]
267
+ },
268
+ // Register class providers after their dependencies are available
269
+ EntitlementGuard,
270
+ JWKService
271
+ ],
272
+ exports: [EntitlementGuard, Blimu2, BLIMU_CONFIG, JWKService]
273
+ };
274
+ }
275
+ /**
276
+ * Configure the Blimu module with async configuration
277
+ *
278
+ * This is useful when you need to load configuration from environment variables,
279
+ * configuration services, or other async sources.
280
+ *
281
+ * @param options - Async configuration options
282
+ * @returns A configured dynamic module
283
+ *
284
+ * @example
285
+ * Using with ConfigService:
286
+ * ```typescript
287
+ * @Module({
288
+ * imports: [
289
+ * ConfigModule.forRoot(),
290
+ * BlimuModule.forRootAsync({
291
+ * useFactory: (configService: ConfigService) => ({
292
+ * apiKey: configService.get('BLIMU_API_SECRET_KEY'),
293
+ * baseURL: configService.get('BLIMU_BASE_URL'),
294
+ * environmentId: configService.get('BLIMU_ENVIRONMENT_ID'),
295
+ * timeoutMs: configService.get('BLIMU_TIMEOUT_MS'),
296
+ * getUserId: (req) => req.user?.id,
297
+ * }),
298
+ * inject: [ConfigService],
299
+ * }),
300
+ * ],
301
+ * })
302
+ * export class AppModule {}
303
+ * ```
304
+ *
305
+ * @example
306
+ * Using with custom request type:
307
+ * ```typescript
308
+ * interface AuthenticatedRequest {
309
+ * user: { id: string; email: string };
310
+ * }
311
+ *
312
+ * @Module({
313
+ * imports: [
314
+ * BlimuModule.forRootAsync<AuthenticatedRequest>({
315
+ * useFactory: (configService: ConfigService) => ({
316
+ * apiKey: configService.get('BLIMU_API_SECRET_KEY'),
317
+ * getUserId: (req) => req.user.id, // req is typed as AuthenticatedRequest
318
+ * }),
319
+ * inject: [ConfigService],
320
+ * }),
321
+ * ],
322
+ * })
323
+ * export class AppModule {}
324
+ * ```
325
+ *
326
+ * @example
327
+ * Using with custom provider:
328
+ * ```typescript
329
+ * @Module({
330
+ * imports: [
331
+ * BlimuModule.forRootAsync({
332
+ * imports: [MyConfigModule],
333
+ * useFactory: async (myConfigService: MyConfigService) => {
334
+ * const config = await myConfigService.getBlimuConfig();
335
+ * return {
336
+ * apiKey: config.apiKey,
337
+ * baseURL: config.baseUrl,
338
+ * environmentId: config.environmentId,
339
+ * getUserId: (req) => req.user?.id,
340
+ * };
341
+ * },
342
+ * inject: [MyConfigService],
343
+ * }),
344
+ * ],
345
+ * })
346
+ * export class AppModule {}
347
+ * ```
348
+ */
349
+ static forRootAsync(options) {
350
+ const additionalImports = options.imports ?? [];
351
+ const module = {
352
+ ...options.global ? { global: true } : {},
353
+ module: BlimuModule,
354
+ imports: [...additionalImports],
355
+ providers: [
356
+ // Register factory providers first so dependencies are available
357
+ {
358
+ provide: BLIMU_CONFIG,
359
+ useFactory: async (...args) => {
360
+ const configResult = options.useFactory(...args);
361
+ const config = configResult instanceof Promise ? await configResult : configResult;
362
+ return {
363
+ apiKey: config.apiKey,
364
+ baseURL: config.baseURL ?? DEFAULT_BASE_URL,
365
+ environmentId: config.environmentId,
366
+ timeoutMs: config.timeoutMs ?? 3e4,
367
+ getUserId: config.getUserId
368
+ };
369
+ },
370
+ ...options.inject ? { inject: options.inject } : {}
371
+ },
372
+ {
373
+ provide: Blimu2,
374
+ useFactory: (config) => {
375
+ return new Blimu2({
376
+ apiKey: config.apiKey,
377
+ baseURL: config.baseURL ?? DEFAULT_BASE_URL,
378
+ timeoutMs: config.timeoutMs ?? 3e4
379
+ });
380
+ },
381
+ inject: [BLIMU_CONFIG]
382
+ },
383
+ // Register class providers after their dependencies are available
384
+ EntitlementGuard,
385
+ JWKService
386
+ ],
387
+ exports: [EntitlementGuard, Blimu2, BLIMU_CONFIG, JWKService]
388
+ };
389
+ return module;
390
+ }
391
+ };
392
+ BlimuModule = __decorateClass([
393
+ Module({})
394
+ ], BlimuModule);
395
+ export {
396
+ BlimuModule
397
+ };
398
+ //# sourceMappingURL=blimu.module.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/modules/blimu.module.ts","../../src/config/blimu.config.ts","../../src/guards/entitlement.guard.ts","../../src/exceptions/blimu-forbidden.exception.ts","../../src/services/jwk.service.ts"],"sourcesContent":["import {\n Module,\n type DynamicModule,\n type Type,\n type ForwardReference,\n type InjectionToken,\n type OptionalFactoryDependency,\n} from '@nestjs/common';\n\nimport { BLIMU_CONFIG, type BlimuConfig } from '../config/blimu.config';\nimport { EntitlementGuard } from 'guards/entitlement.guard';\nimport { JWKService } from 'services/jwk.service';\nimport { Blimu } from '@blimu/backend';\n\nconst DEFAULT_BASE_URL = 'https://api.blimu.dev';\n\n/**\n * Blimu NestJS Module\n *\n * This module provides entitlement checking capabilities and Blimu Runtime SDK integration\n * for NestJS applications. It can be configured synchronously or asynchronously.\n */\n@Module({})\nexport class BlimuModule {\n /**\n * Configure the Blimu module with static configuration\n *\n * @param config - The Blimu configuration object\n * @returns A configured dynamic module\n *\n * @example\n * Basic usage with default Request type:\n * ```typescript\n * @Module({\n * imports: [\n * BlimuModule.forRoot({\n * apiKey: 'your-api-secret-key',\n * baseURL: 'https://api.blimu.dev', // optional\n * environmentId: 'your-environment-id', // optional\n * timeoutMs: 30000, // optional\n * getUserId: (req) => req.user?.id, // required\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n *\n * @example\n * Usage with custom request type:\n * ```typescript\n * interface AuthenticatedRequest {\n * user: { id: string; email: string };\n * }\n *\n * @Module({\n * imports: [\n * BlimuModule.forRoot<AuthenticatedRequest>({\n * apiKey: 'your-api-secret-key',\n * getUserId: (req) => req.user.id, // req is typed as AuthenticatedRequest\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n */\n static forRoot<TRequest = unknown>(config: BlimuConfig<TRequest>): DynamicModule {\n return {\n ...(config.global ? { global: true } : {}),\n module: BlimuModule,\n providers: [\n // Register factory providers first so dependencies are available\n {\n provide: BLIMU_CONFIG,\n useValue: {\n apiKey: config.apiKey,\n baseURL: config.baseURL ?? DEFAULT_BASE_URL,\n environmentId: config.environmentId,\n timeoutMs: config.timeoutMs ?? 30000,\n getUserId: config.getUserId,\n },\n },\n {\n provide: Blimu,\n useFactory: (config: BlimuConfig) => {\n return new Blimu({\n apiKey: config.apiKey,\n baseURL: config.baseURL ?? DEFAULT_BASE_URL,\n timeoutMs: config.timeoutMs ?? 30000,\n });\n },\n inject: [BLIMU_CONFIG],\n },\n // Register class providers after their dependencies are available\n EntitlementGuard,\n JWKService,\n ],\n exports: [EntitlementGuard, Blimu, BLIMU_CONFIG, JWKService],\n };\n }\n\n /**\n * Configure the Blimu module with async configuration\n *\n * This is useful when you need to load configuration from environment variables,\n * configuration services, or other async sources.\n *\n * @param options - Async configuration options\n * @returns A configured dynamic module\n *\n * @example\n * Using with ConfigService:\n * ```typescript\n * @Module({\n * imports: [\n * ConfigModule.forRoot(),\n * BlimuModule.forRootAsync({\n * useFactory: (configService: ConfigService) => ({\n * apiKey: configService.get('BLIMU_API_SECRET_KEY'),\n * baseURL: configService.get('BLIMU_BASE_URL'),\n * environmentId: configService.get('BLIMU_ENVIRONMENT_ID'),\n * timeoutMs: configService.get('BLIMU_TIMEOUT_MS'),\n * getUserId: (req) => req.user?.id,\n * }),\n * inject: [ConfigService],\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n *\n * @example\n * Using with custom request type:\n * ```typescript\n * interface AuthenticatedRequest {\n * user: { id: string; email: string };\n * }\n *\n * @Module({\n * imports: [\n * BlimuModule.forRootAsync<AuthenticatedRequest>({\n * useFactory: (configService: ConfigService) => ({\n * apiKey: configService.get('BLIMU_API_SECRET_KEY'),\n * getUserId: (req) => req.user.id, // req is typed as AuthenticatedRequest\n * }),\n * inject: [ConfigService],\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n *\n * @example\n * Using with custom provider:\n * ```typescript\n * @Module({\n * imports: [\n * BlimuModule.forRootAsync({\n * imports: [MyConfigModule],\n * useFactory: async (myConfigService: MyConfigService) => {\n * const config = await myConfigService.getBlimuConfig();\n * return {\n * apiKey: config.apiKey,\n * baseURL: config.baseUrl,\n * environmentId: config.environmentId,\n * getUserId: (req) => req.user?.id,\n * };\n * },\n * inject: [MyConfigService],\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n */\n static forRootAsync<TRequest = unknown>(options: {\n global?: boolean | undefined;\n useFactory: (...args: unknown[]) => Promise<BlimuConfig<TRequest>> | BlimuConfig<TRequest>;\n inject?: (InjectionToken | OptionalFactoryDependency)[];\n imports?: (\n | Type<unknown>\n | DynamicModule\n | Promise<DynamicModule>\n | ForwardReference<() => Type<unknown>>\n )[];\n }): DynamicModule {\n const additionalImports = options.imports ?? [];\n\n const module = {\n ...(options.global ? { global: true } : {}),\n module: BlimuModule,\n imports: [...additionalImports] as (\n | Type<unknown>\n | DynamicModule\n | Promise<DynamicModule>\n | ForwardReference\n )[],\n providers: [\n // Register factory providers first so dependencies are available\n {\n provide: BLIMU_CONFIG,\n useFactory: async (...args: unknown[]) => {\n const configResult = options.useFactory(...args);\n const config = configResult instanceof Promise ? await configResult : configResult;\n return {\n apiKey: config.apiKey,\n baseURL: config.baseURL ?? DEFAULT_BASE_URL,\n environmentId: config.environmentId,\n timeoutMs: config.timeoutMs ?? 30000,\n getUserId: config.getUserId,\n };\n },\n ...(options.inject ? { inject: options.inject } : {}),\n },\n {\n provide: Blimu,\n useFactory: (config: BlimuConfig) => {\n return new Blimu({\n apiKey: config.apiKey,\n baseURL: config.baseURL ?? DEFAULT_BASE_URL,\n timeoutMs: config.timeoutMs ?? 30000,\n });\n },\n inject: [BLIMU_CONFIG],\n },\n // Register class providers after their dependencies are available\n EntitlementGuard,\n JWKService,\n ],\n exports: [EntitlementGuard, Blimu, BLIMU_CONFIG, JWKService],\n };\n return module;\n }\n}\n","/**\n * Configuration interface for Blimu NestJS integration\n */\nexport interface BlimuConfig<TRequest = unknown> {\n global?: boolean | undefined;\n /**\n * The API secret key for authenticating with Blimu Runtime API\n */\n apiKey: string;\n\n /**\n * The base URL for the Blimu Runtime API\n * @default 'https://api.blimu.dev'\n */\n baseURL?: string | undefined;\n\n /**\n * Environment ID for the Blimu environment\n * This will be used in future versions for environment-specific configurations\n */\n environmentId?: string | undefined;\n\n /**\n * Request timeout in milliseconds\n * @default 30000\n */\n timeoutMs?: number | undefined;\n\n /**\n * Function to extract user ID from the request\n *\n * This function is called by the EntitlementGuard to determine which user\n * to check entitlements for. It should return the user ID as a string.\n *\n * @param request - The incoming HTTP request\n * @returns The user ID as a string, or a Promise that resolves to the user ID\n *\n * @example\n * ```typescript\n * // Extract from JWT token in Authorization header\n * getUserId: (req) => {\n * const token = req.headers.authorization?.replace('Bearer ', '');\n * const decoded = jwt.verify(token, secret);\n * return decoded.sub;\n * }\n *\n * // Extract from request.user (common with Passport.js)\n * getUserId: (req) => req.user?.id\n *\n * // Extract from custom header\n * getUserId: (req) => req.headers['x-user-id']\n * ```\n */\n getUserId: (request: TRequest) => string | Promise<string>;\n}\n\n/**\n * Injection token for Blimu configuration\n */\nexport const BLIMU_CONFIG = Symbol('BLIMU_CONFIG');\n","import {\n type CanActivate,\n type ExecutionContext,\n ForbiddenException,\n Injectable,\n SetMetadata,\n Inject,\n} from '@nestjs/common';\nimport 'reflect-metadata';\n\nimport type { EntitlementType } from '@blimu/types';\nimport { BlimuForbiddenException } from '../exceptions/blimu-forbidden.exception';\nimport { Blimu } from '@blimu/backend';\nimport { BLIMU_CONFIG, type BlimuConfig } from 'config/blimu.config';\n\nexport const ENTITLEMENT_KEY = 'entitlement';\nexport const ENTITLEMENT_METADATA_KEY = Symbol('entitlement');\n\n/**\n * Entitlement information returned by the getEntitlementInfo callback\n */\nexport interface EntitlementInfo {\n resourceId: string;\n amount?: number; // Amount to check against usage limit (for consumption)\n}\n\n/**\n * Metadata interface for entitlement checks\n */\nexport interface EntitlementMetadata<TRequest = unknown> {\n entitlementKey: EntitlementType;\n getEntitlementInfo: (request: TRequest) => EntitlementInfo | Promise<EntitlementInfo>;\n}\n\n/**\n * Sets entitlement metadata for a route handler\n * @internal This is used internally by the @Entitlement decorator\n */\nexport const SetEntitlementMetadata = <TRequest = unknown>(\n entitlementKey: string,\n getEntitlementInfo: (request: TRequest) => EntitlementInfo | Promise<EntitlementInfo>,\n): MethodDecorator =>\n SetMetadata(ENTITLEMENT_METADATA_KEY, {\n entitlementKey,\n getEntitlementInfo,\n } as EntitlementMetadata<TRequest>);\n\n/**\n * Guard that checks if the authenticated user has the required entitlement on a resource\n *\n * This guard automatically:\n * 1. Extracts the user from the request\n * 2. Extracts the resource ID using the provided extractor function\n * 3. Calls the Blimu Runtime API to check entitlements\n * 4. Allows or denies access based on the result\n */\n@Injectable()\nexport class EntitlementGuard<TRequest = unknown> implements CanActivate {\n constructor(\n @Inject(BLIMU_CONFIG)\n private readonly config: BlimuConfig<TRequest>,\n @Inject(Blimu)\n private readonly runtime: Blimu,\n ) {}\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const request = context.switchToHttp().getRequest<TRequest>();\n const handler = context.getHandler();\n const metadata = Reflect.getMetadata(ENTITLEMENT_METADATA_KEY, handler) as\n | EntitlementMetadata<TRequest>\n | undefined;\n\n if (!metadata) {\n // No entitlement check required\n return true;\n }\n\n // Extract user ID using the configured getUserId function\n let userId: string;\n try {\n userId = await this.config.getUserId(request);\n } catch {\n throw new ForbiddenException('Failed to extract user ID from request');\n }\n\n if (!userId) {\n throw new ForbiddenException('User ID is required for entitlement check');\n }\n\n // Extract entitlement info from request\n const entitlementInfo = await metadata.getEntitlementInfo(request);\n\n if (!entitlementInfo?.resourceId) {\n throw new ForbiddenException('Resource ID is required for entitlement check');\n }\n\n try {\n // Check entitlement\n const result = await this.runtime.entitlements.checkEntitlement({\n userId,\n entitlement: metadata.entitlementKey,\n resourceId: entitlementInfo.resourceId,\n ...(entitlementInfo.amount !== undefined ? { amount: entitlementInfo.amount } : {}),\n });\n\n if (!result.allowed) {\n throw new BlimuForbiddenException(\n result,\n metadata.entitlementKey,\n entitlementInfo.resourceId,\n userId,\n );\n }\n\n return true;\n } catch (error) {\n if (error instanceof BlimuForbiddenException || error instanceof ForbiddenException) {\n throw error;\n }\n\n // Log the error for debugging but don't expose internal details\n console.error('Entitlement check failed:', error);\n throw new ForbiddenException('Failed to verify entitlements');\n }\n }\n}\n","import { ForbiddenException } from '@nestjs/common';\nimport type { Schema } from '@blimu/backend';\nimport type { EntitlementType } from '@blimu/types';\n/**\n * Custom exception for Blimu entitlement check failures\n *\n * This exception extends NestJS's ForbiddenException and includes\n * the typed EntitlementCheckResult, providing detailed information\n * about why the entitlement check failed (roles, plans, limits, etc.)\n */\nexport class BlimuForbiddenException extends ForbiddenException {\n /**\n * The entitlement check result containing detailed failure information\n */\n public readonly entitlementResult: Schema.EntitlementCheckResult;\n\n /**\n * The entitlement key that was checked\n */\n public readonly entitlementKey: EntitlementType;\n\n /**\n * The resource ID that was checked\n */\n public readonly resourceId: string;\n\n /**\n * The user ID that was checked\n */\n public readonly userId: string;\n\n constructor(\n entitlementResult: Schema.EntitlementCheckResult,\n entitlementKey: EntitlementType,\n resourceId: string,\n userId: string,\n ) {\n // Create a user-friendly message based on the failure reason\n const message = BlimuForbiddenException.buildMessage(entitlementResult, entitlementKey);\n\n super({\n message,\n entitlementResult,\n entitlementKey,\n resourceId,\n userId,\n });\n\n this.entitlementResult = entitlementResult;\n this.entitlementKey = entitlementKey;\n this.resourceId = resourceId;\n this.userId = userId;\n }\n\n /**\n * Builds a user-friendly error message from the entitlement check result\n */\n private static buildMessage(\n result: Schema.EntitlementCheckResult,\n entitlementKey: EntitlementType,\n ): string {\n const reasons: string[] = [];\n\n if (result.roles && !result.roles.allowed) {\n reasons.push(\n `Insufficient roles. Required: ${result.roles.allowedRoles?.join(', ') || 'unknown'}. User has: ${result.roles.userRoles?.join(', ') || 'none'}.`,\n );\n }\n\n if (result.plans && !result.plans.allowed) {\n reasons.push(\n `Plan restriction. Required plans: ${result.plans.allowedPlans?.join(', ') || 'unknown'}. Current plan: ${result.plans.plan || 'none'}.`,\n );\n }\n\n if (result.limit && !result.limit.allowed) {\n reasons.push(`Usage limit exceeded. ${result.limit.reason || 'Limit has been reached'}.`);\n }\n\n if (reasons.length === 0) {\n return `Access denied for entitlement: ${entitlementKey}`;\n }\n\n return `Access denied for entitlement \"${entitlementKey}\": ${reasons.join(' ')}`;\n }\n}\n","import { Inject, Injectable, Logger } from '@nestjs/common';\nimport { TokenVerifier } from '@blimu/backend';\nimport { BLIMU_CONFIG, type BlimuConfig } from '../config/blimu.config';\n\n@Injectable()\nexport class JWKService {\n private readonly logger = new Logger(JWKService.name);\n private readonly tokenVerifier: TokenVerifier;\n\n constructor(@Inject(BLIMU_CONFIG) private readonly config: BlimuConfig) {\n this.tokenVerifier = new TokenVerifier({\n runtimeApiUrl: this.config.baseURL,\n });\n }\n\n /**\n * Verify JWT token using JWKs from runtime-api\n */\n async verifyToken<T = unknown>(token: string): Promise<T> {\n try {\n this.logger.debug(\n `🔍 Verifying token. Runtime API URL: ${this.config.baseURL}, API Key prefix: ${this.config.apiKey?.substring(0, 10)}...`,\n );\n\n const result = await this.tokenVerifier.verifyToken<T>({\n secretKey: this.config.apiKey,\n token,\n runtimeApiUrl: this.config.baseURL,\n });\n\n this.logger.debug(`✅ Token verified successfully`);\n return result;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n this.logger.error(`❌ Token verification failed: ${errorMessage}`);\n if (error instanceof Error && error.stack) {\n this.logger.error(`Stack trace: ${error.stack}`);\n }\n throw error;\n }\n }\n\n /**\n * Clear cache (useful for testing or key rotation)\n */\n clearCache(): void {\n this.tokenVerifier.clearCache(this.config.apiKey);\n this.logger.debug('JWK cache cleared');\n }\n}\n"],"mappings":"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","names":["ForbiddenException","ForbiddenException","Inject","Injectable","Injectable","Inject","Blimu","Blimu","config"]}
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var __decorateClass = (decorators, target, key, kind) => {
20
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
21
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
22
+ if (decorator = decorators[i])
23
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
24
+ if (kind && result) __defProp(target, key, result);
25
+ return result;
26
+ };
27
+ var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
28
+
29
+ // src/services/index.ts
30
+ var services_exports = {};
31
+ __export(services_exports, {
32
+ JWKService: () => JWKService
33
+ });
34
+ module.exports = __toCommonJS(services_exports);
35
+
36
+ // src/services/jwk.service.ts
37
+ var import_common = require("@nestjs/common");
38
+ var import_backend = require("@blimu/backend");
39
+
40
+ // src/config/blimu.config.ts
41
+ var BLIMU_CONFIG = /* @__PURE__ */ Symbol("BLIMU_CONFIG");
42
+
43
+ // src/services/jwk.service.ts
44
+ var JWKService = class {
45
+ constructor(config) {
46
+ this.config = config;
47
+ this.tokenVerifier = new import_backend.TokenVerifier({
48
+ runtimeApiUrl: this.config.baseURL
49
+ });
50
+ }
51
+ logger = new import_common.Logger(JWKService.name);
52
+ tokenVerifier;
53
+ /**
54
+ * Verify JWT token using JWKs from runtime-api
55
+ */
56
+ async verifyToken(token) {
57
+ try {
58
+ this.logger.debug(
59
+ `\u{1F50D} Verifying token. Runtime API URL: ${this.config.baseURL}, API Key prefix: ${this.config.apiKey?.substring(0, 10)}...`
60
+ );
61
+ const result = await this.tokenVerifier.verifyToken({
62
+ secretKey: this.config.apiKey,
63
+ token,
64
+ runtimeApiUrl: this.config.baseURL
65
+ });
66
+ this.logger.debug(`\u2705 Token verified successfully`);
67
+ return result;
68
+ } catch (error) {
69
+ const errorMessage = error instanceof Error ? error.message : String(error);
70
+ this.logger.error(`\u274C Token verification failed: ${errorMessage}`);
71
+ if (error instanceof Error && error.stack) {
72
+ this.logger.error(`Stack trace: ${error.stack}`);
73
+ }
74
+ throw error;
75
+ }
76
+ }
77
+ /**
78
+ * Clear cache (useful for testing or key rotation)
79
+ */
80
+ clearCache() {
81
+ this.tokenVerifier.clearCache(this.config.apiKey);
82
+ this.logger.debug("JWK cache cleared");
83
+ }
84
+ };
85
+ JWKService = __decorateClass([
86
+ (0, import_common.Injectable)(),
87
+ __decorateParam(0, (0, import_common.Inject)(BLIMU_CONFIG))
88
+ ], JWKService);
89
+ // Annotate the CommonJS export names for ESM import in node:
90
+ 0 && (module.exports = {
91
+ JWKService
92
+ });
93
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/services/index.ts","../../src/services/jwk.service.ts","../../src/config/blimu.config.ts"],"sourcesContent":["export * from './jwk.service';\n","import { Inject, Injectable, Logger } from '@nestjs/common';\nimport { TokenVerifier } from '@blimu/backend';\nimport { BLIMU_CONFIG, type BlimuConfig } from '../config/blimu.config';\n\n@Injectable()\nexport class JWKService {\n private readonly logger = new Logger(JWKService.name);\n private readonly tokenVerifier: TokenVerifier;\n\n constructor(@Inject(BLIMU_CONFIG) private readonly config: BlimuConfig) {\n this.tokenVerifier = new TokenVerifier({\n runtimeApiUrl: this.config.baseURL,\n });\n }\n\n /**\n * Verify JWT token using JWKs from runtime-api\n */\n async verifyToken<T = unknown>(token: string): Promise<T> {\n try {\n this.logger.debug(\n `🔍 Verifying token. Runtime API URL: ${this.config.baseURL}, API Key prefix: ${this.config.apiKey?.substring(0, 10)}...`,\n );\n\n const result = await this.tokenVerifier.verifyToken<T>({\n secretKey: this.config.apiKey,\n token,\n runtimeApiUrl: this.config.baseURL,\n });\n\n this.logger.debug(`✅ Token verified successfully`);\n return result;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n this.logger.error(`❌ Token verification failed: ${errorMessage}`);\n if (error instanceof Error && error.stack) {\n this.logger.error(`Stack trace: ${error.stack}`);\n }\n throw error;\n }\n }\n\n /**\n * Clear cache (useful for testing or key rotation)\n */\n clearCache(): void {\n this.tokenVerifier.clearCache(this.config.apiKey);\n this.logger.debug('JWK cache cleared');\n }\n}\n","/**\n * Configuration interface for Blimu NestJS integration\n */\nexport interface BlimuConfig<TRequest = unknown> {\n global?: boolean | undefined;\n /**\n * The API secret key for authenticating with Blimu Runtime API\n */\n apiKey: string;\n\n /**\n * The base URL for the Blimu Runtime API\n * @default 'https://api.blimu.dev'\n */\n baseURL?: string | undefined;\n\n /**\n * Environment ID for the Blimu environment\n * This will be used in future versions for environment-specific configurations\n */\n environmentId?: string | undefined;\n\n /**\n * Request timeout in milliseconds\n * @default 30000\n */\n timeoutMs?: number | undefined;\n\n /**\n * Function to extract user ID from the request\n *\n * This function is called by the EntitlementGuard to determine which user\n * to check entitlements for. It should return the user ID as a string.\n *\n * @param request - The incoming HTTP request\n * @returns The user ID as a string, or a Promise that resolves to the user ID\n *\n * @example\n * ```typescript\n * // Extract from JWT token in Authorization header\n * getUserId: (req) => {\n * const token = req.headers.authorization?.replace('Bearer ', '');\n * const decoded = jwt.verify(token, secret);\n * return decoded.sub;\n * }\n *\n * // Extract from request.user (common with Passport.js)\n * getUserId: (req) => req.user?.id\n *\n * // Extract from custom header\n * getUserId: (req) => req.headers['x-user-id']\n * ```\n */\n getUserId: (request: TRequest) => string | Promise<string>;\n}\n\n/**\n * Injection token for Blimu configuration\n */\nexport const BLIMU_CONFIG = Symbol('BLIMU_CONFIG');\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,oBAA2C;AAC3C,qBAA8B;;;AC0DvB,IAAM,eAAe,uBAAO,cAAc;;;ADtD1C,IAAM,aAAN,MAAiB;AAAA,EAItB,YAAmD,QAAqB;AAArB;AACjD,SAAK,gBAAgB,IAAI,6BAAc;AAAA,MACrC,eAAe,KAAK,OAAO;AAAA,IAC7B,CAAC;AAAA,EACH;AAAA,EAPiB,SAAS,IAAI,qBAAO,WAAW,IAAI;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAWjB,MAAM,YAAyB,OAA2B;AACxD,QAAI;AACF,WAAK,OAAO;AAAA,QACV,+CAAwC,KAAK,OAAO,OAAO,qBAAqB,KAAK,OAAO,QAAQ,UAAU,GAAG,EAAE,CAAC;AAAA,MACtH;AAEA,YAAM,SAAS,MAAM,KAAK,cAAc,YAAe;AAAA,QACrD,WAAW,KAAK,OAAO;AAAA,QACvB;AAAA,QACA,eAAe,KAAK,OAAO;AAAA,MAC7B,CAAC;AAED,WAAK,OAAO,MAAM,oCAA+B;AACjD,aAAO;AAAA,IACT,SAAS,OAAO;AACd,YAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC1E,WAAK,OAAO,MAAM,qCAAgC,YAAY,EAAE;AAChE,UAAI,iBAAiB,SAAS,MAAM,OAAO;AACzC,aAAK,OAAO,MAAM,gBAAgB,MAAM,KAAK,EAAE;AAAA,MACjD;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,aAAmB;AACjB,SAAK,cAAc,WAAW,KAAK,OAAO,MAAM;AAChD,SAAK,OAAO,MAAM,mBAAmB;AAAA,EACvC;AACF;AA5Ca,aAAN;AAAA,MADN,0BAAW;AAAA,EAKG,6CAAO,YAAY;AAAA,GAJrB;","names":[]}
@@ -0,0 +1,2 @@
1
+ export { JWKService } from './jwk.service.cjs';
2
+ import '../config/blimu.config.cjs';
@@ -1,2 +1,2 @@
1
- export * from './jwk.service';
2
- //# sourceMappingURL=index.d.ts.map
1
+ export { JWKService } from './jwk.service.js';
2
+ import '../config/blimu.config.js';
@@ -0,0 +1,69 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result) __defProp(target, key, result);
9
+ return result;
10
+ };
11
+ var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
12
+
13
+ // src/services/jwk.service.ts
14
+ import { Inject, Injectable, Logger } from "@nestjs/common";
15
+ import { TokenVerifier } from "@blimu/backend";
16
+
17
+ // src/config/blimu.config.ts
18
+ var BLIMU_CONFIG = /* @__PURE__ */ Symbol("BLIMU_CONFIG");
19
+
20
+ // src/services/jwk.service.ts
21
+ var JWKService = class {
22
+ constructor(config) {
23
+ this.config = config;
24
+ this.tokenVerifier = new TokenVerifier({
25
+ runtimeApiUrl: this.config.baseURL
26
+ });
27
+ }
28
+ logger = new Logger(JWKService.name);
29
+ tokenVerifier;
30
+ /**
31
+ * Verify JWT token using JWKs from runtime-api
32
+ */
33
+ async verifyToken(token) {
34
+ try {
35
+ this.logger.debug(
36
+ `\u{1F50D} Verifying token. Runtime API URL: ${this.config.baseURL}, API Key prefix: ${this.config.apiKey?.substring(0, 10)}...`
37
+ );
38
+ const result = await this.tokenVerifier.verifyToken({
39
+ secretKey: this.config.apiKey,
40
+ token,
41
+ runtimeApiUrl: this.config.baseURL
42
+ });
43
+ this.logger.debug(`\u2705 Token verified successfully`);
44
+ return result;
45
+ } catch (error) {
46
+ const errorMessage = error instanceof Error ? error.message : String(error);
47
+ this.logger.error(`\u274C Token verification failed: ${errorMessage}`);
48
+ if (error instanceof Error && error.stack) {
49
+ this.logger.error(`Stack trace: ${error.stack}`);
50
+ }
51
+ throw error;
52
+ }
53
+ }
54
+ /**
55
+ * Clear cache (useful for testing or key rotation)
56
+ */
57
+ clearCache() {
58
+ this.tokenVerifier.clearCache(this.config.apiKey);
59
+ this.logger.debug("JWK cache cleared");
60
+ }
61
+ };
62
+ JWKService = __decorateClass([
63
+ Injectable(),
64
+ __decorateParam(0, Inject(BLIMU_CONFIG))
65
+ ], JWKService);
66
+ export {
67
+ JWKService
68
+ };
69
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/services/jwk.service.ts","../../src/config/blimu.config.ts"],"sourcesContent":["import { Inject, Injectable, Logger } from '@nestjs/common';\nimport { TokenVerifier } from '@blimu/backend';\nimport { BLIMU_CONFIG, type BlimuConfig } from '../config/blimu.config';\n\n@Injectable()\nexport class JWKService {\n private readonly logger = new Logger(JWKService.name);\n private readonly tokenVerifier: TokenVerifier;\n\n constructor(@Inject(BLIMU_CONFIG) private readonly config: BlimuConfig) {\n this.tokenVerifier = new TokenVerifier({\n runtimeApiUrl: this.config.baseURL,\n });\n }\n\n /**\n * Verify JWT token using JWKs from runtime-api\n */\n async verifyToken<T = unknown>(token: string): Promise<T> {\n try {\n this.logger.debug(\n `🔍 Verifying token. Runtime API URL: ${this.config.baseURL}, API Key prefix: ${this.config.apiKey?.substring(0, 10)}...`,\n );\n\n const result = await this.tokenVerifier.verifyToken<T>({\n secretKey: this.config.apiKey,\n token,\n runtimeApiUrl: this.config.baseURL,\n });\n\n this.logger.debug(`✅ Token verified successfully`);\n return result;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n this.logger.error(`❌ Token verification failed: ${errorMessage}`);\n if (error instanceof Error && error.stack) {\n this.logger.error(`Stack trace: ${error.stack}`);\n }\n throw error;\n }\n }\n\n /**\n * Clear cache (useful for testing or key rotation)\n */\n clearCache(): void {\n this.tokenVerifier.clearCache(this.config.apiKey);\n this.logger.debug('JWK cache cleared');\n }\n}\n","/**\n * Configuration interface for Blimu NestJS integration\n */\nexport interface BlimuConfig<TRequest = unknown> {\n global?: boolean | undefined;\n /**\n * The API secret key for authenticating with Blimu Runtime API\n */\n apiKey: string;\n\n /**\n * The base URL for the Blimu Runtime API\n * @default 'https://api.blimu.dev'\n */\n baseURL?: string | undefined;\n\n /**\n * Environment ID for the Blimu environment\n * This will be used in future versions for environment-specific configurations\n */\n environmentId?: string | undefined;\n\n /**\n * Request timeout in milliseconds\n * @default 30000\n */\n timeoutMs?: number | undefined;\n\n /**\n * Function to extract user ID from the request\n *\n * This function is called by the EntitlementGuard to determine which user\n * to check entitlements for. It should return the user ID as a string.\n *\n * @param request - The incoming HTTP request\n * @returns The user ID as a string, or a Promise that resolves to the user ID\n *\n * @example\n * ```typescript\n * // Extract from JWT token in Authorization header\n * getUserId: (req) => {\n * const token = req.headers.authorization?.replace('Bearer ', '');\n * const decoded = jwt.verify(token, secret);\n * return decoded.sub;\n * }\n *\n * // Extract from request.user (common with Passport.js)\n * getUserId: (req) => req.user?.id\n *\n * // Extract from custom header\n * getUserId: (req) => req.headers['x-user-id']\n * ```\n */\n getUserId: (request: TRequest) => string | Promise<string>;\n}\n\n/**\n * Injection token for Blimu configuration\n */\nexport const BLIMU_CONFIG = Symbol('BLIMU_CONFIG');\n"],"mappings":";;;;;;;;;;;;;AAAA,SAAS,QAAQ,YAAY,cAAc;AAC3C,SAAS,qBAAqB;;;AC0DvB,IAAM,eAAe,uBAAO,cAAc;;;ADtD1C,IAAM,aAAN,MAAiB;AAAA,EAItB,YAAmD,QAAqB;AAArB;AACjD,SAAK,gBAAgB,IAAI,cAAc;AAAA,MACrC,eAAe,KAAK,OAAO;AAAA,IAC7B,CAAC;AAAA,EACH;AAAA,EAPiB,SAAS,IAAI,OAAO,WAAW,IAAI;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAWjB,MAAM,YAAyB,OAA2B;AACxD,QAAI;AACF,WAAK,OAAO;AAAA,QACV,+CAAwC,KAAK,OAAO,OAAO,qBAAqB,KAAK,OAAO,QAAQ,UAAU,GAAG,EAAE,CAAC;AAAA,MACtH;AAEA,YAAM,SAAS,MAAM,KAAK,cAAc,YAAe;AAAA,QACrD,WAAW,KAAK,OAAO;AAAA,QACvB;AAAA,QACA,eAAe,KAAK,OAAO;AAAA,MAC7B,CAAC;AAED,WAAK,OAAO,MAAM,oCAA+B;AACjD,aAAO;AAAA,IACT,SAAS,OAAO;AACd,YAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC1E,WAAK,OAAO,MAAM,qCAAgC,YAAY,EAAE;AAChE,UAAI,iBAAiB,SAAS,MAAM,OAAO;AACzC,aAAK,OAAO,MAAM,gBAAgB,MAAM,KAAK,EAAE;AAAA,MACjD;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,aAAmB;AACjB,SAAK,cAAc,WAAW,KAAK,OAAO,MAAM;AAChD,SAAK,OAAO,MAAM,mBAAmB;AAAA,EACvC;AACF;AA5Ca,aAAN;AAAA,EADN,WAAW;AAAA,EAKG,0BAAO,YAAY;AAAA,GAJrB;","names":[]}