@numerum-tech/yeriasdk 1.0.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 (94) hide show
  1. package/README.md +864 -0
  2. package/dist/core/action-grid-view.d.ts +57 -0
  3. package/dist/core/action-grid-view.d.ts.map +1 -0
  4. package/dist/core/action-grid-view.js +112 -0
  5. package/dist/core/action-grid-view.js.map +1 -0
  6. package/dist/core/action-list-view.d.ts +39 -0
  7. package/dist/core/action-list-view.d.ts.map +1 -0
  8. package/dist/core/action-list-view.js +77 -0
  9. package/dist/core/action-list-view.js.map +1 -0
  10. package/dist/core/base/base-action-view.d.ts +82 -0
  11. package/dist/core/base/base-action-view.d.ts.map +1 -0
  12. package/dist/core/base/base-action-view.js +143 -0
  13. package/dist/core/base/base-action-view.js.map +1 -0
  14. package/dist/core/base-view.d.ts +105 -0
  15. package/dist/core/base-view.d.ts.map +1 -0
  16. package/dist/core/base-view.js +426 -0
  17. package/dist/core/base-view.js.map +1 -0
  18. package/dist/core/card-view.d.ts +24 -0
  19. package/dist/core/card-view.d.ts.map +1 -0
  20. package/dist/core/card-view.js +127 -0
  21. package/dist/core/card-view.js.map +1 -0
  22. package/dist/core/carousel-view.d.ts +22 -0
  23. package/dist/core/carousel-view.d.ts.map +1 -0
  24. package/dist/core/carousel-view.js +99 -0
  25. package/dist/core/carousel-view.js.map +1 -0
  26. package/dist/core/form-view.d.ts +165 -0
  27. package/dist/core/form-view.d.ts.map +1 -0
  28. package/dist/core/form-view.js +365 -0
  29. package/dist/core/form-view.js.map +1 -0
  30. package/dist/core/jsonapp.d.ts +263 -0
  31. package/dist/core/jsonapp.d.ts.map +1 -0
  32. package/dist/core/jsonapp.js +528 -0
  33. package/dist/core/jsonapp.js.map +1 -0
  34. package/dist/core/key-store.d.ts +51 -0
  35. package/dist/core/key-store.d.ts.map +1 -0
  36. package/dist/core/key-store.js +138 -0
  37. package/dist/core/key-store.js.map +1 -0
  38. package/dist/core/map-view.d.ts +45 -0
  39. package/dist/core/map-view.d.ts.map +1 -0
  40. package/dist/core/map-view.js +318 -0
  41. package/dist/core/map-view.js.map +1 -0
  42. package/dist/core/media-view.d.ts +20 -0
  43. package/dist/core/media-view.d.ts.map +1 -0
  44. package/dist/core/media-view.js +75 -0
  45. package/dist/core/media-view.js.map +1 -0
  46. package/dist/core/message-view.d.ts +53 -0
  47. package/dist/core/message-view.d.ts.map +1 -0
  48. package/dist/core/message-view.js +109 -0
  49. package/dist/core/message-view.js.map +1 -0
  50. package/dist/core/notification.d.ts +17 -0
  51. package/dist/core/notification.d.ts.map +1 -0
  52. package/dist/core/notification.js +33 -0
  53. package/dist/core/notification.js.map +1 -0
  54. package/dist/core/qr-display-view.d.ts +32 -0
  55. package/dist/core/qr-display-view.d.ts.map +1 -0
  56. package/dist/core/qr-display-view.js +66 -0
  57. package/dist/core/qr-display-view.js.map +1 -0
  58. package/dist/core/qr-scan-view.d.ts +148 -0
  59. package/dist/core/qr-scan-view.d.ts.map +1 -0
  60. package/dist/core/qr-scan-view.js +259 -0
  61. package/dist/core/qr-scan-view.js.map +1 -0
  62. package/dist/core/reader-view.d.ts +73 -0
  63. package/dist/core/reader-view.d.ts.map +1 -0
  64. package/dist/core/reader-view.js +285 -0
  65. package/dist/core/reader-view.js.map +1 -0
  66. package/dist/core/timeline-view.d.ts +16 -0
  67. package/dist/core/timeline-view.d.ts.map +1 -0
  68. package/dist/core/timeline-view.js +68 -0
  69. package/dist/core/timeline-view.js.map +1 -0
  70. package/dist/errors/index.d.ts +276 -0
  71. package/dist/errors/index.d.ts.map +1 -0
  72. package/dist/errors/index.js +431 -0
  73. package/dist/errors/index.js.map +1 -0
  74. package/dist/index.d.ts +26 -0
  75. package/dist/index.d.ts.map +1 -0
  76. package/dist/index.js +103 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/types/index.d.ts +576 -0
  79. package/dist/types/index.d.ts.map +1 -0
  80. package/dist/types/index.js +48 -0
  81. package/dist/types/index.js.map +1 -0
  82. package/dist/utils/fileFormats.d.ts +52 -0
  83. package/dist/utils/fileFormats.d.ts.map +1 -0
  84. package/dist/utils/fileFormats.js +198 -0
  85. package/dist/utils/fileFormats.js.map +1 -0
  86. package/dist/utils/logger.d.ts +38 -0
  87. package/dist/utils/logger.d.ts.map +1 -0
  88. package/dist/utils/logger.js +109 -0
  89. package/dist/utils/logger.js.map +1 -0
  90. package/dist/utils/validators.d.ts +48 -0
  91. package/dist/utils/validators.d.ts.map +1 -0
  92. package/dist/utils/validators.js +445 -0
  93. package/dist/utils/validators.js.map +1 -0
  94. package/package.json +65 -0
@@ -0,0 +1,528 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JsonApp = void 0;
4
+ const crypto_1 = require("crypto");
5
+ const form_view_1 = require("./form-view");
6
+ const reader_view_1 = require("./reader-view");
7
+ const action_list_view_1 = require("./action-list-view");
8
+ const action_grid_view_1 = require("./action-grid-view");
9
+ const qr_scan_view_1 = require("./qr-scan-view");
10
+ const qr_display_view_1 = require("./qr-display-view");
11
+ const message_view_1 = require("./message-view");
12
+ const card_view_1 = require("./card-view");
13
+ const carousel_view_1 = require("./carousel-view");
14
+ const timeline_view_1 = require("./timeline-view");
15
+ const media_view_1 = require("./media-view");
16
+ const map_view_1 = require("./map-view");
17
+ const errors_1 = require("../errors");
18
+ const notification_1 = require("./notification");
19
+ class JsonApp {
20
+ constructor(config) {
21
+ this.config = {
22
+ allowedDomains: [],
23
+ viewExpirationMinutes: 60,
24
+ ...config
25
+ };
26
+ // Génération ou utilisation des clés Ed25519
27
+ if (config.privateKey && config.publicKey) {
28
+ this.privateKey = config.privateKey;
29
+ this.publicKey = config.publicKey;
30
+ }
31
+ else {
32
+ // Génération automatique des clés Ed25519
33
+ const keyPair = (0, crypto_1.generateKeyPairSync)('ed25519');
34
+ this.privateKey = keyPair.privateKey.export({ type: 'pkcs8', format: 'pem' });
35
+ this.publicKey = keyPair.publicKey.export({ type: 'spki', format: 'pem' });
36
+ }
37
+ }
38
+ /**
39
+ * Crée une vue de formulaire sécurisée
40
+ */
41
+ createFormView(formId, title, processId) {
42
+ return new form_view_1.FormView(formId, title, processId);
43
+ }
44
+ /**
45
+ * Crée une vue de lecture sécurisée
46
+ */
47
+ createReaderView(viewId, title, processId) {
48
+ return new reader_view_1.ReaderView(viewId, title, processId);
49
+ }
50
+ /**
51
+ * Crée une vue de liste d'actions sécurisée
52
+ */
53
+ createActionListView(viewId, title, processId) {
54
+ return new action_list_view_1.ActionListView(viewId, title, processId);
55
+ }
56
+ /**
57
+ * Crée une vue de grille d'actions sécurisée
58
+ */
59
+ createActionGridView(viewId, title, processId) {
60
+ return new action_grid_view_1.ActionGridView(viewId, title, processId);
61
+ }
62
+ /**
63
+ * Crée une vue de scan QR sécurisée
64
+ */
65
+ createQRScanView(viewId, title, processId) {
66
+ return new qr_scan_view_1.QRScanView(viewId, title, processId);
67
+ }
68
+ /**
69
+ * Crée une vue d'affichage QR sécurisée
70
+ */
71
+ createQRDisplayView(viewId, title, processId) {
72
+ return new qr_display_view_1.QRDisplayView(viewId, title, processId);
73
+ }
74
+ /**
75
+ * Crée une vue de message sécurisée
76
+ */
77
+ createMessageView(viewId, title, processId) {
78
+ return new message_view_1.MessageView(viewId, title, processId);
79
+ }
80
+ createCardView(viewId, title, processId) {
81
+ return new card_view_1.CardView(viewId, title, processId);
82
+ }
83
+ createCarouselView(viewId, title, processId) {
84
+ return new carousel_view_1.CarouselView(viewId, title, processId);
85
+ }
86
+ createTimelineView(viewId, title, processId) {
87
+ return new timeline_view_1.TimelineView(viewId, title, processId);
88
+ }
89
+ createMediaView(viewId, title, processId) {
90
+ return new media_view_1.MediaView(viewId, title, processId);
91
+ }
92
+ createMapView(viewId, title, processId) {
93
+ return new map_view_1.MapView(viewId, title, processId);
94
+ }
95
+ /**
96
+ * Crée une notification pour un utilisateur spécifique
97
+ */
98
+ createNotification(userId, title, body, link) {
99
+ return new notification_1.Notification(userId, title, body, link);
100
+ }
101
+ /**
102
+ * Signe une notification avec Ed25519
103
+ */
104
+ signNotification(notification) {
105
+ const notificationJson = notification.toJSON();
106
+ const timestamp = Date.now();
107
+ // Payload must match backend reconstruction: { notification (object), timestamp, appId }
108
+ const payload = JSON.stringify({
109
+ notification: notificationJson,
110
+ timestamp: timestamp,
111
+ appId: this.config.appId
112
+ });
113
+ const signatureBuffer = (0, crypto_1.sign)(null, Buffer.from(payload), this.privateKey);
114
+ const signature = signatureBuffer.toString('base64');
115
+ return {
116
+ appId: this.config.appId,
117
+ signature,
118
+ timestamp,
119
+ notification: notificationJson
120
+ };
121
+ }
122
+ /**
123
+ * Envoie une notification signée à la plateforme City-Mate
124
+ * @param notification - Notification à envoyer
125
+ * @param platformUrl - URL de la plateforme (optionnel, utilise config.platformUrl si non fourni)
126
+ * @throws {ConfigurationError} Si aucune URL de plateforme n'est configurée
127
+ * @throws {ExternalError} Si l'envoi échoue
128
+ */
129
+ async sendNotification(notification, platformUrl) {
130
+ const signedNotification = this.signNotification(notification);
131
+ const url = platformUrl || this.config.platformUrl;
132
+ if (!url) {
133
+ throw new errors_1.ConfigurationError('Platform URL required for sending notifications. Set platformUrl in JsonAppConfig or pass it as parameter.');
134
+ }
135
+ try {
136
+ const response = await fetch(url, {
137
+ method: 'POST',
138
+ headers: { 'Content-Type': 'application/json' },
139
+ body: JSON.stringify(signedNotification),
140
+ signal: AbortSignal.timeout(this.config.notificationTimeout || 5000)
141
+ });
142
+ if (!response.ok) {
143
+ throw new errors_1.ExternalError(errors_1.ERROR_CODES.NOTIFICATION_FAILED, `Failed to send notification: ${response.status} ${response.statusText}`, 'fetch');
144
+ }
145
+ }
146
+ catch (error) {
147
+ if (error instanceof errors_1.ExternalError || error instanceof errors_1.ConfigurationError) {
148
+ throw error;
149
+ }
150
+ throw new errors_1.ExternalError(errors_1.ERROR_CODES.NOTIFICATION_FAILED, `Failed to send notification: ${error instanceof Error ? error.message : String(error)}`, 'fetch', error instanceof Error ? error : undefined);
151
+ }
152
+ }
153
+ /**
154
+ * Rotate the service's signing key on the Yeria registry. The rotation
155
+ * envelope is signed with the *current* private key — the caller proves
156
+ * they own the still-valid keypair before the new one is accepted.
157
+ *
158
+ * After this call succeeds:
159
+ * - The new public key becomes Active on Yeria.
160
+ * - The old key keeps validating signatures for ~5 minutes (grace
161
+ * window so in-flight signed responses still verify).
162
+ * - This JsonApp instance is mutated to use the new keypair locally.
163
+ *
164
+ * @param yeriaApiBaseUrl - Yeria registry root, e.g. `https://yeria.app`
165
+ * @param serviceId - The service id assigned by Yeria
166
+ * @param newKeys - The freshly-generated keypair to switch to
167
+ */
168
+ async rotateKey(yeriaApiBaseUrl, serviceId, newKeys) {
169
+ if (!newKeys?.privateKey || !newKeys?.publicKey) {
170
+ throw new errors_1.ConfigurationError('rotateKey requires { privateKey, publicKey } in PEM');
171
+ }
172
+ const envelope = {
173
+ serviceId: String(serviceId),
174
+ newPublicKey: newKeys.publicKey,
175
+ timestamp: Date.now()
176
+ };
177
+ const payload = JSON.stringify(envelope);
178
+ const signature = (0, crypto_1.sign)(null, Buffer.from(payload), this.privateKey).toString('base64');
179
+ const url = `${yeriaApiBaseUrl.replace(/\/+$/, '')}/api/v1/services/${serviceId}/keys/rotate`;
180
+ let response;
181
+ try {
182
+ response = await fetch(url, {
183
+ method: 'POST',
184
+ headers: { 'Content-Type': 'application/json' },
185
+ body: JSON.stringify({
186
+ envelope,
187
+ signature,
188
+ currentPublicKey: this.publicKey
189
+ }),
190
+ signal: AbortSignal.timeout(this.config.notificationTimeout || 5000)
191
+ });
192
+ }
193
+ catch (error) {
194
+ throw new errors_1.ExternalError(errors_1.ERROR_CODES.NOTIFICATION_FAILED, `Key rotation request failed: ${error instanceof Error ? error.message : String(error)}`, 'fetch', error instanceof Error ? error : undefined);
195
+ }
196
+ if (!response.ok) {
197
+ const text = await response.text().catch(() => '');
198
+ throw new errors_1.ExternalError(errors_1.ERROR_CODES.NOTIFICATION_FAILED, `Key rotation rejected: ${response.status} ${response.statusText} ${text}`, 'fetch');
199
+ }
200
+ const body = await response.json();
201
+ // Locally swap to the new keypair so subsequent serve() calls sign
202
+ // with it. Old responses still verify against the old public key
203
+ // during the grace window because Yeria keeps both rows Active.
204
+ this.privateKey = newKeys.privateKey;
205
+ this.publicKey = newKeys.publicKey;
206
+ return {
207
+ keyId: body.data?.key?.id,
208
+ expiresAt: body.data?.key?.expires_at,
209
+ gracePeriodMinutes: body.data?.grace_period_minutes ?? 5
210
+ };
211
+ }
212
+ /**
213
+ * Sérialise une vue, signe les bytes sérialisés, et retourne une
214
+ * enveloppe `{payload, signature}` à envoyer telle quelle au client.
215
+ *
216
+ * Usage côté provider (Express) :
217
+ * res.json(jsonApp.serve(view));
218
+ * res.status(400).json(jsonApp.serve(errorMessage));
219
+ *
220
+ * La signature est dans la structure de retour — impossible de
221
+ * l'oublier en l'envoyant. Le client vérifie sur `payload` (string)
222
+ * sans re-stringification.
223
+ */
224
+ serve(view) {
225
+ const decoded = {
226
+ appId: this.config.appId,
227
+ timestamp: Date.now(),
228
+ view: view.toJSON()
229
+ };
230
+ const payload = JSON.stringify(decoded);
231
+ const signature = (0, crypto_1.sign)(null, Buffer.from(payload, 'utf8'), this.privateKey).toString('base64');
232
+ return { payload, signature };
233
+ }
234
+ /**
235
+ * Obtient la clé publique pour la vérification côté frontend
236
+ */
237
+ getPublicKey() {
238
+ return this.publicKey;
239
+ }
240
+ /**
241
+ * Vérifie l'intégrité d'une enveloppe signée reçue du wire.
242
+ *
243
+ * @throws {AppIdMismatchError} si appId ne matche pas this.config.appId
244
+ * @throws {ViewExpiredError} si timestamp > viewExpirationMinutes
245
+ * @throws {SignatureVerificationError} si signature invalide ou payload malformé
246
+ */
247
+ verifyIntegrity(envelope) {
248
+ try {
249
+ // 1. Verify signature on payload bytes — no re-stringification
250
+ const signatureBuffer = Buffer.from(envelope.signature, 'base64');
251
+ const isValid = (0, crypto_1.verify)(null, Buffer.from(envelope.payload, 'utf8'), this.publicKey, signatureBuffer);
252
+ if (!isValid) {
253
+ throw new errors_1.SignatureVerificationError(this.config.appId);
254
+ }
255
+ // 2. Parse the now-trusted payload
256
+ const decoded = JSON.parse(envelope.payload);
257
+ // 3. appId match
258
+ if (decoded.appId !== this.config.appId) {
259
+ throw new errors_1.AppIdMismatchError(this.config.appId, decoded.appId);
260
+ }
261
+ // 4. Expiration window
262
+ const now = Date.now();
263
+ const expirationTime = this.config.viewExpirationMinutes * 60 * 1000;
264
+ const age = now - decoded.timestamp;
265
+ if (age > expirationTime) {
266
+ const viewId = typeof decoded.view['id'] === 'string'
267
+ ? decoded.view['id']
268
+ : 'unknown';
269
+ throw new errors_1.ViewExpiredError(viewId, age, expirationTime);
270
+ }
271
+ return true;
272
+ }
273
+ catch (error) {
274
+ if (error instanceof errors_1.AppIdMismatchError ||
275
+ error instanceof errors_1.ViewExpiredError ||
276
+ error instanceof errors_1.SignatureVerificationError) {
277
+ throw error;
278
+ }
279
+ throw new errors_1.SignatureVerificationError(this.config.appId);
280
+ }
281
+ }
282
+ /**
283
+ * Méthode statique pour vérifier une signature.
284
+ * @param publicKey - Clé publique Ed25519 (PEM format)
285
+ * @param payload - JSON string signée (extraite de l'enveloppe)
286
+ * @param signature - Signature base64
287
+ * @param onError - Optional error callback for logging
288
+ * @returns true si la signature est valide
289
+ */
290
+ static verifySignature(publicKey, payload, signature, onError) {
291
+ try {
292
+ const signatureBuffer = Buffer.from(signature, 'base64');
293
+ return (0, crypto_1.verify)(null, Buffer.from(payload, 'utf8'), publicKey, signatureBuffer);
294
+ }
295
+ catch (error) {
296
+ const err = error instanceof Error ? error : new Error('Unknown error');
297
+ if (onError) {
298
+ onError(err);
299
+ }
300
+ else if (typeof process !== 'undefined' && process.env?.['NODE_ENV'] !== 'production') {
301
+ console.error('[JsonApp] Error verifying signature:', err);
302
+ }
303
+ return false;
304
+ }
305
+ }
306
+ /**
307
+ * Génère statiquement une enveloppe signée sans instance JsonApp.
308
+ */
309
+ static signView(view, appId, privateKey, timestamp = Date.now()) {
310
+ const decoded = { appId, timestamp, view };
311
+ const payload = JSON.stringify(decoded);
312
+ const signature = (0, crypto_1.sign)(null, Buffer.from(payload, 'utf8'), privateKey).toString('base64');
313
+ return { payload, signature };
314
+ }
315
+ /**
316
+ * Verify a Yeria-issued user token (RS256 JWT signed by Yeria's
317
+ * Registry RSA key). Used by providers to authenticate inbound
318
+ * requests carrying `Authorization: Bearer <serviceToken>`.
319
+ *
320
+ * @param jwtToken Compact JWT (header.payload.signature, base64url).
321
+ * @param yeriaPublicKey Yeria's Registry public key in PEM format.
322
+ * Fetch once at boot from
323
+ * `GET /api/v1/registry/public-key` and cache.
324
+ * @param expectedServiceId When supplied, asserts `aud === String(expectedServiceId)`.
325
+ * Pass the service id your backend is hosting; refuse
326
+ * tokens scoped to a different service.
327
+ * @returns The verified claims object.
328
+ * @throws SignatureVerificationError if signature invalid / token malformed / wrong issuer / wrong audience.
329
+ * @throws ViewExpiredError if the `exp` claim is in the past.
330
+ */
331
+ static verifyUserToken(jwtToken, yeriaPublicKey, expectedServiceId) {
332
+ if (typeof jwtToken !== 'string' || jwtToken.length === 0) {
333
+ throw new errors_1.SignatureVerificationError('yeria', 'missing jwt');
334
+ }
335
+ const parts = jwtToken.split('.');
336
+ if (parts.length !== 3 || !parts[0] || !parts[1] || !parts[2]) {
337
+ throw new errors_1.SignatureVerificationError('yeria', 'malformed jwt');
338
+ }
339
+ const headerB64 = parts[0];
340
+ const payloadB64 = parts[1];
341
+ const signatureB64 = parts[2];
342
+ let header;
343
+ let claims;
344
+ try {
345
+ header = JSON.parse(base64UrlDecodeToString(headerB64));
346
+ claims = JSON.parse(base64UrlDecodeToString(payloadB64));
347
+ }
348
+ catch (_e) {
349
+ throw new errors_1.SignatureVerificationError('yeria', 'invalid base64 / json');
350
+ }
351
+ if (header['alg'] !== 'RS256') {
352
+ throw new errors_1.SignatureVerificationError('yeria', `unsupported alg: ${String(header['alg'])}`);
353
+ }
354
+ // Verify RSA-SHA256 over the canonical signing input.
355
+ const signingInput = `${headerB64}.${payloadB64}`;
356
+ const signatureBytes = base64UrlDecodeToBuffer(signatureB64);
357
+ const verifier = (0, crypto_1.createVerify)('RSA-SHA256');
358
+ verifier.update(signingInput);
359
+ verifier.end();
360
+ const sigOk = verifier.verify(yeriaPublicKey, signatureBytes);
361
+ if (!sigOk) {
362
+ throw new errors_1.SignatureVerificationError('yeria', 'signature mismatch');
363
+ }
364
+ if (claims.iss !== 'yeria') {
365
+ throw new errors_1.SignatureVerificationError('yeria', `unexpected issuer: ${String(claims.iss)}`);
366
+ }
367
+ if (expectedServiceId !== undefined && claims.aud !== String(expectedServiceId)) {
368
+ throw new errors_1.SignatureVerificationError('yeria', `audience mismatch: token aud=${claims.aud}, expected=${String(expectedServiceId)}`);
369
+ }
370
+ const nowSec = Math.floor(Date.now() / 1000);
371
+ if (typeof claims.exp !== 'number' || claims.exp <= nowSec) {
372
+ throw new errors_1.ViewExpiredError('user-token', (nowSec - (claims.exp || 0)) * 1000, 0);
373
+ }
374
+ // Surface kid from the header for caller convenience.
375
+ if (typeof header['kid'] === 'string') {
376
+ claims.kid = header['kid'];
377
+ }
378
+ return claims;
379
+ }
380
+ /**
381
+ * Same audience-scoped JWT verify as `verifyUserToken`, but the second
382
+ * argument is a kid resolver instead of a fixed PEM. The SDK pulls
383
+ * the `kid` from the JWT header, calls `resolver(kid)`, and verifies
384
+ * the signature against whatever PEM comes back.
385
+ *
386
+ * Pair with `YeriaKeyStore` so providers don't have to write key-
387
+ * fetching, caching or rotation-grace handling themselves.
388
+ *
389
+ * @throws SignatureVerificationError if the resolver returns null, the
390
+ * signature fails, the issuer / audience mismatches, or the
391
+ * JWT is malformed.
392
+ * @throws ViewExpiredError when `exp` is in the past.
393
+ */
394
+ static async verifyUserTokenWithResolver(jwtToken, resolver, expectedServiceId) {
395
+ if (typeof jwtToken !== 'string' || jwtToken.length === 0) {
396
+ throw new errors_1.SignatureVerificationError('yeria', 'missing jwt');
397
+ }
398
+ const parts = jwtToken.split('.');
399
+ if (parts.length !== 3 || !parts[0] || !parts[1] || !parts[2]) {
400
+ throw new errors_1.SignatureVerificationError('yeria', 'malformed jwt');
401
+ }
402
+ let header;
403
+ try {
404
+ header = JSON.parse(base64UrlDecodeToString(parts[0]));
405
+ }
406
+ catch (_e) {
407
+ throw new errors_1.SignatureVerificationError('yeria', 'invalid header');
408
+ }
409
+ const kid = header['kid'];
410
+ if (typeof kid !== 'string' || kid.length === 0) {
411
+ throw new errors_1.SignatureVerificationError('yeria', 'jwt header missing kid');
412
+ }
413
+ const pem = await resolver(kid);
414
+ if (!pem) {
415
+ // Resolver returns null when Yeria says the key is expired or
416
+ // the kid is unknown. Either way the token cannot be trusted.
417
+ throw new errors_1.SignatureVerificationError('yeria', `no trusted key for kid=${kid}`);
418
+ }
419
+ return JsonApp.verifyUserToken(jwtToken, pem, expectedServiceId);
420
+ }
421
+ /**
422
+ * Provider-side helper: fetch a Yeria user's profile by `sub`.
423
+ *
424
+ * Builds an Ed25519-signed envelope and POSTs to
425
+ * `POST /api/v1/provider/services/{serviceId}/users/{userId}/profile`.
426
+ * Yeria already holds every Active public key for this service, so
427
+ * the envelope itself is the only credential — no user JWT is sent
428
+ * in the body and the PEM is never disclosed.
429
+ *
430
+ * Typical usage (provider middleware after `verifyUserTokenWithResolver`):
431
+ *
432
+ * let user = await db.users.findByYeriaSub(claims.sub);
433
+ * if (!user) {
434
+ * const profile = await JsonApp.fetchUserProfile({
435
+ * baseUrl: process.env.YERIA_BASE_URL,
436
+ * serviceId: MY_SERVICE_ID,
437
+ * userId: claims.sub,
438
+ * privateKey: SERVICE_ED25519_PRIVATE_KEY,
439
+ * });
440
+ * user = await db.users.insert({ yeria_sub: claims.sub, ...profile });
441
+ * }
442
+ *
443
+ * The hot path stays local-DB after the first miss.
444
+ */
445
+ static async fetchUserProfile(opts) {
446
+ if (!opts || !opts.baseUrl)
447
+ throw new Error('fetchUserProfile: baseUrl is required');
448
+ if (opts.serviceId === undefined || opts.serviceId === null) {
449
+ throw new Error('fetchUserProfile: serviceId is required');
450
+ }
451
+ if (opts.userId === undefined || opts.userId === null) {
452
+ throw new Error('fetchUserProfile: userId is required');
453
+ }
454
+ if (typeof opts.privateKey !== 'string' || opts.privateKey.length === 0) {
455
+ throw new Error('fetchUserProfile: privateKey (PEM) is required');
456
+ }
457
+ const fetchImpl = opts.fetch ?? globalThis.fetch;
458
+ if (typeof fetchImpl !== 'function') {
459
+ throw new Error('fetchUserProfile: no fetch available — pass opts.fetch on Node < 18 or non-browser runtimes');
460
+ }
461
+ const envelope = {
462
+ service_id: opts.serviceId,
463
+ user_id: opts.userId,
464
+ timestamp: Date.now(),
465
+ nonce: (0, crypto_1.randomBytes)(16).toString('hex'),
466
+ };
467
+ const payloadStr = JSON.stringify(envelope);
468
+ const signature = (0, crypto_1.sign)(null, Buffer.from(payloadStr, 'utf8'), opts.privateKey).toString('base64');
469
+ const baseUrl = opts.baseUrl.replace(/\/+$/, '');
470
+ const url = `${baseUrl}/api/v1/provider/services/${encodeURIComponent(String(opts.serviceId))}/users/${encodeURIComponent(String(opts.userId))}/profile`;
471
+ const res = await fetchImpl(url, {
472
+ method: 'POST',
473
+ headers: { 'Content-Type': 'application/json' },
474
+ body: JSON.stringify({ envelope, signature }),
475
+ });
476
+ let body;
477
+ try {
478
+ body = await res.json();
479
+ }
480
+ catch (_e) {
481
+ body = null;
482
+ }
483
+ if (!res.ok) {
484
+ const msg = extractErrorMessage(body) || `HTTP ${res.status}`;
485
+ throw new Error(`Yeria profile fetch failed: ${msg}`);
486
+ }
487
+ const result = (body && typeof body === 'object' && 'result' in body)
488
+ ? body.result
489
+ : body;
490
+ if (!result || typeof result !== 'object') {
491
+ throw new Error('Yeria profile fetch: unexpected response shape');
492
+ }
493
+ const r = result;
494
+ return {
495
+ user_id: Number(r['user_id']),
496
+ first_name: typeof r['first_name'] === 'string' ? r['first_name'] : null,
497
+ last_name: typeof r['last_name'] === 'string' ? r['last_name'] : null,
498
+ country_code: typeof r['country_code'] === 'string' ? r['country_code'] : null,
499
+ };
500
+ }
501
+ }
502
+ exports.JsonApp = JsonApp;
503
+ function extractErrorMessage(body) {
504
+ if (!body || typeof body !== 'object')
505
+ return null;
506
+ const b = body;
507
+ if (typeof b['message'] === 'string')
508
+ return b['message'];
509
+ if (b['error'] && typeof b['error'] === 'object') {
510
+ const e = b['error'];
511
+ if (typeof e['message'] === 'string')
512
+ return e['message'];
513
+ }
514
+ if (typeof b['error'] === 'string')
515
+ return b['error'];
516
+ return null;
517
+ }
518
+ // ── base64url helpers (stateless, no dep) ────────────────────────────────
519
+ // JWT uses base64url (RFC 4648 §5): `-` for `+`, `_` for `/`, no padding.
520
+ function base64UrlDecodeToBuffer(input) {
521
+ const padded = input.replace(/-/g, '+').replace(/_/g, '/') +
522
+ '==='.slice((input.length + 3) % 4);
523
+ return Buffer.from(padded, 'base64');
524
+ }
525
+ function base64UrlDecodeToString(input) {
526
+ return base64UrlDecodeToBuffer(input).toString('utf8');
527
+ }
528
+ //# sourceMappingURL=jsonapp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonapp.js","sourceRoot":"","sources":["../../src/core/jsonapp.ts"],"names":[],"mappings":";;;AAAA,mCAAsF;AAEtF,2CAAuC;AACvC,+CAA2C;AAC3C,yDAAoD;AACpD,yDAAoD;AACpD,iDAA4C;AAC5C,uDAAkD;AAClD,iDAA6C;AAC7C,2CAAuC;AACvC,mDAA+C;AAC/C,mDAA+C;AAC/C,6CAAyC;AACzC,yCAAqC;AACrC,sCAOmB;AACnB,iDAA8C;AA8E9C,MAAa,OAAO;IAKhB,YAAY,MAAqB;QAC7B,IAAI,CAAC,MAAM,GAAG;YACV,cAAc,EAAE,EAAE;YAClB,qBAAqB,EAAE,EAAE;YACzB,GAAG,MAAM;SACZ,CAAC;QAEF,6CAA6C;QAC7C,IAAI,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACxC,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;YACpC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QACtC,CAAC;aAAM,CAAC;YACJ,0CAA0C;YAC1C,MAAM,OAAO,GAAG,IAAA,4BAAmB,EAAC,SAAS,CAAC,CAAC;YAC/C,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAW,CAAC;YACxF,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAW,CAAC;QACzF,CAAC;IACL,CAAC;IAED;;OAEG;IACH,cAAc,CAAC,MAAc,EAAE,KAAa,EAAE,SAAkB;QAC5D,OAAO,IAAI,oBAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IAClD,CAAC;IAED;;OAEG;IACH,gBAAgB,CAAC,MAAc,EAAE,KAAa,EAAE,SAAkB;QAC9D,OAAO,IAAI,wBAAU,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IACpD,CAAC;IAED;;OAEG;IACH,oBAAoB,CAAC,MAAc,EAAE,KAAa,EAAE,SAAkB;QAClE,OAAO,IAAI,iCAAc,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IACxD,CAAC;IAED;;OAEG;IACH,oBAAoB,CAAC,MAAc,EAAE,KAAa,EAAE,SAAkB;QAClE,OAAO,IAAI,iCAAc,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IACxD,CAAC;IAED;;OAEG;IACH,gBAAgB,CAAC,MAAc,EAAE,KAAa,EAAE,SAAkB;QAC9D,OAAO,IAAI,yBAAU,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IACpD,CAAC;IAED;;OAEG;IACH,mBAAmB,CAAC,MAAc,EAAE,KAAa,EAAE,SAAkB;QACjE,OAAO,IAAI,+BAAa,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IACvD,CAAC;IAED;;OAEG;IACH,iBAAiB,CAAC,MAAc,EAAE,KAAa,EAAE,SAAkB;QAC/D,OAAO,IAAI,0BAAW,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IACrD,CAAC;IAED,cAAc,CAAC,MAAc,EAAE,KAAa,EAAE,SAAkB;QAC5D,OAAO,IAAI,oBAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IAClD,CAAC;IAED,kBAAkB,CAAC,MAAc,EAAE,KAAa,EAAE,SAAkB;QAChE,OAAO,IAAI,4BAAY,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IACtD,CAAC;IAED,kBAAkB,CAAC,MAAc,EAAE,KAAa,EAAE,SAAkB;QAChE,OAAO,IAAI,4BAAY,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IACtD,CAAC;IAED,eAAe,CAAC,MAAc,EAAE,KAAa,EAAE,SAAkB;QAC7D,OAAO,IAAI,sBAAS,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IACnD,CAAC;IAED,aAAa,CAAC,MAAc,EAAE,KAAa,EAAE,SAAkB;QAC3D,OAAO,IAAI,kBAAO,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IACjD,CAAC;IAED;;OAEG;IACH,kBAAkB,CAAC,MAAc,EAAE,KAAa,EAAE,IAAY,EAAE,IAAa;QACzE,OAAO,IAAI,2BAAY,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACvD,CAAC;IAED;;OAEG;IACH,gBAAgB,CAAC,YAA0B;QACvC,MAAM,gBAAgB,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC;QAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,yFAAyF;QACzF,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC;YAC3B,YAAY,EAAE,gBAAgB;YAC9B,SAAS,EAAE,SAAS;YACpB,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;SAC3B,CAAC,CAAC;QACH,MAAM,eAAe,GAAG,IAAA,aAAI,EAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAC1E,MAAM,SAAS,GAAG,eAAe,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAErD,OAAO;YACH,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;YACxB,SAAS;YACT,SAAS;YACT,YAAY,EAAE,gBAAgB;SACjC,CAAC;IACN,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,gBAAgB,CAClB,YAA0B,EAC1B,WAAoB;QAEpB,MAAM,kBAAkB,GAAG,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAC/D,MAAM,GAAG,GAAG,WAAW,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;QAEnD,IAAI,CAAC,GAAG,EAAE,CAAC;YACP,MAAM,IAAI,2BAAkB,CAAC,4GAA4G,CAAC,CAAC;QAC/I,CAAC;QAED,IAAI,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAC9B,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC;gBACxC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,mBAAmB,IAAI,IAAI,CAAC;aACvE,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACf,MAAM,IAAI,sBAAa,CACnB,oBAAW,CAAC,mBAAmB,EAC/B,gCAAgC,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,EACxE,OAAO,CACV,CAAC;YACN,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,IAAI,KAAK,YAAY,sBAAa,IAAI,KAAK,YAAY,2BAAkB,EAAE,CAAC;gBACxE,MAAM,KAAK,CAAC;YAChB,CAAC;YACD,MAAM,IAAI,sBAAa,CACnB,oBAAW,CAAC,mBAAmB,EAC/B,gCAAgC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EACxF,OAAO,EACP,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAC7C,CAAC;QACN,CAAC;IACL,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,SAAS,CACX,eAAuB,EACvB,SAA0B,EAC1B,OAAkD;QAElD,IAAI,CAAC,OAAO,EAAE,UAAU,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC;YAC9C,MAAM,IAAI,2BAAkB,CAAC,qDAAqD,CAAC,CAAC;QACxF,CAAC;QAED,MAAM,QAAQ,GAAG;YACb,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC;YAC5B,YAAY,EAAE,OAAO,CAAC,SAAS;YAC/B,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACxB,CAAC;QACF,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,SAAS,GAAG,IAAA,aAAI,EAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAEvF,MAAM,GAAG,GAAG,GAAG,eAAe,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,oBAAoB,SAAS,cAAc,CAAC;QAC9F,IAAI,QAAkB,CAAC;QACvB,IAAI,CAAC;YACD,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBACxB,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACjB,QAAQ;oBACR,SAAS;oBACT,gBAAgB,EAAE,IAAI,CAAC,SAAS;iBACnC,CAAC;gBACF,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,mBAAmB,IAAI,IAAI,CAAC;aACvE,CAAC,CAAC;QACP,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,IAAI,sBAAa,CACnB,oBAAW,CAAC,mBAAmB,EAC/B,gCAAgC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EACxF,OAAO,EACP,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAC7C,CAAC;QACN,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACf,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YACnD,MAAM,IAAI,sBAAa,CACnB,oBAAW,CAAC,mBAAmB,EAC/B,0BAA0B,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,IAAI,IAAI,EAAE,EAC1E,OAAO,CACV,CAAC;QACN,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAK/B,CAAC;QAEF,mEAAmE;QACnE,iEAAiE;QACjE,gEAAgE;QAChE,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QACrC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QAEnC,OAAO;YACH,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,EAAY;YACnC,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,UAAoB;YAC/C,kBAAkB,EAAE,IAAI,CAAC,IAAI,EAAE,oBAAoB,IAAI,CAAC;SAC3D,CAAC;IACN,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,IAAc;QAChB,MAAM,OAAO,GAAmB;YAC5B,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;YACxB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE;SACtB,CAAC;QACF,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACxC,MAAM,SAAS,GAAG,IAAA,aAAI,EAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC/F,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;IAClC,CAAC;IAED;;OAEG;IACH,YAAY;QACR,OAAO,IAAI,CAAC,SAAS,CAAC;IAC1B,CAAC;IAED;;;;;;OAMG;IACH,eAAe,CAAC,QAAwB;QACpC,IAAI,CAAC;YACD,+DAA+D;YAC/D,MAAM,eAAe,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;YAClE,MAAM,OAAO,GAAG,IAAA,eAAM,EAClB,IAAI,EACJ,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,EACrC,IAAI,CAAC,SAAS,EACd,eAAe,CAClB,CAAC;YACF,IAAI,CAAC,OAAO,EAAE,CAAC;gBACX,MAAM,IAAI,mCAA0B,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC5D,CAAC;YAED,mCAAmC;YACnC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAmB,CAAC;YAE/D,iBAAiB;YACjB,IAAI,OAAO,CAAC,KAAK,KAAK,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;gBACtC,MAAM,IAAI,2BAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;YACnE,CAAC;YAED,uBAAuB;YACvB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC,qBAAsB,GAAG,EAAE,GAAG,IAAI,CAAC;YACtE,MAAM,GAAG,GAAG,GAAG,GAAG,OAAO,CAAC,SAAS,CAAC;YACpC,IAAI,GAAG,GAAG,cAAc,EAAE,CAAC;gBACvB,MAAM,MAAM,GAAG,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,QAAQ;oBACjD,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAW;oBAC9B,CAAC,CAAC,SAAS,CAAC;gBAChB,MAAM,IAAI,yBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,cAAc,CAAC,CAAC;YAC5D,CAAC;YAED,OAAO,IAAI,CAAC;QAChB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,IAAI,KAAK,YAAY,2BAAkB;gBACnC,KAAK,YAAY,yBAAgB;gBACjC,KAAK,YAAY,mCAA0B,EAAE,CAAC;gBAC9C,MAAM,KAAK,CAAC;YAChB,CAAC;YACD,MAAM,IAAI,mCAA0B,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5D,CAAC;IACL,CAAC;IAED;;;;;;;OAOG;IACH,MAAM,CAAC,eAAe,CAClB,SAAiB,EACjB,OAAe,EACf,SAAiB,EACjB,OAAgC;QAEhC,IAAI,CAAC;YACD,MAAM,eAAe,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;YACzD,OAAO,IAAA,eAAM,EAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;QAClF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;YACxE,IAAI,OAAO,EAAE,CAAC;gBACV,OAAO,CAAC,GAAG,CAAC,CAAC;YACjB,CAAC;iBAAM,IAAI,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,YAAY,EAAE,CAAC;gBACtF,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,GAAG,CAAC,CAAC;YAC/D,CAAC;YACD,OAAO,KAAK,CAAC;QACjB,CAAC;IACL,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,QAAQ,CACX,IAA6B,EAC7B,KAAa,EACb,UAAkB,EAClB,YAAoB,IAAI,CAAC,GAAG,EAAE;QAE9B,MAAM,OAAO,GAAmB,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QAC3D,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACxC,MAAM,SAAS,GAAG,IAAA,aAAI,EAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC1F,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;IAClC,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACH,MAAM,CAAC,eAAe,CAClB,QAAgB,EAChB,cAAsB,EACtB,iBAAmC;QAEnC,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxD,MAAM,IAAI,mCAA0B,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;QACjE,CAAC;QACD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5D,MAAM,IAAI,mCAA0B,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;QACnE,CAAC;QACD,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3B,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAC5B,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAE9B,IAAI,MAA+B,CAAC;QACpC,IAAI,MAAuB,CAAC;QAC5B,IAAI,CAAC;YACD,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,uBAAuB,CAAC,SAAS,CAAC,CAAC,CAAC;YACxD,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,uBAAuB,CAAC,UAAU,CAAC,CAAoB,CAAC;QAChF,CAAC;QAAC,OAAO,EAAE,EAAE,CAAC;YACV,MAAM,IAAI,mCAA0B,CAAC,OAAO,EAAE,uBAAuB,CAAC,CAAC;QAC3E,CAAC;QAED,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,OAAO,EAAE,CAAC;YAC5B,MAAM,IAAI,mCAA0B,CAChC,OAAO,EACP,oBAAoB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAC9C,CAAC;QACN,CAAC;QAED,sDAAsD;QACtD,MAAM,YAAY,GAAG,GAAG,SAAS,IAAI,UAAU,EAAE,CAAC;QAClD,MAAM,cAAc,GAAG,uBAAuB,CAAC,YAAY,CAAC,CAAC;QAC7D,MAAM,QAAQ,GAAG,IAAA,qBAAY,EAAC,YAAY,CAAC,CAAC;QAC5C,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QAC9B,QAAQ,CAAC,GAAG,EAAE,CAAC;QACf,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;QAC9D,IAAI,CAAC,KAAK,EAAE,CAAC;YACT,MAAM,IAAI,mCAA0B,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAC;QACxE,CAAC;QAED,IAAI,MAAM,CAAC,GAAG,KAAK,OAAO,EAAE,CAAC;YACzB,MAAM,IAAI,mCAA0B,CAChC,OAAO,EACP,sBAAsB,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC7C,CAAC;QACN,CAAC;QACD,IAAI,iBAAiB,KAAK,SAAS,IAAI,MAAM,CAAC,GAAG,KAAK,MAAM,CAAC,iBAAiB,CAAC,EAAE,CAAC;YAC9E,MAAM,IAAI,mCAA0B,CAChC,OAAO,EACP,gCAAgC,MAAM,CAAC,GAAG,cAAc,MAAM,CAAC,iBAAiB,CAAC,EAAE,CACtF,CAAC;QACN,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAC7C,IAAI,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,IAAI,MAAM,CAAC,GAAG,IAAI,MAAM,EAAE,CAAC;YACzD,MAAM,IAAI,yBAAgB,CAAC,YAAY,EAAE,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC;QACrF,CAAC;QAED,sDAAsD;QACtD,IAAI,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,QAAQ,EAAE,CAAC;YACpC,MAAM,CAAC,GAAG,GAAG,MAAM,CAAC,KAAK,CAAW,CAAC;QACzC,CAAC;QACD,OAAO,MAAM,CAAC;IAClB,CAAC;IAED;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,KAAK,CAAC,2BAA2B,CACpC,QAAgB,EAChB,QAAgC,EAChC,iBAAmC;QAEnC,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxD,MAAM,IAAI,mCAA0B,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;QACjE,CAAC;QACD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5D,MAAM,IAAI,mCAA0B,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;QACnE,CAAC;QAED,IAAI,MAA+B,CAAC;QACpC,IAAI,CAAC;YACD,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3D,CAAC;QAAC,OAAO,EAAE,EAAE,CAAC;YACV,MAAM,IAAI,mCAA0B,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;QACpE,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC1B,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,mCAA0B,CAAC,OAAO,EAAE,wBAAwB,CAAC,CAAC;QAC5E,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,CAAC,GAAG,EAAE,CAAC;YACP,8DAA8D;YAC9D,8DAA8D;YAC9D,MAAM,IAAI,mCAA0B,CAChC,OAAO,EACP,0BAA0B,GAAG,EAAE,CAClC,CAAC;QACN,CAAC;QAED,OAAO,OAAO,CAAC,eAAe,CAAC,QAAQ,EAAE,GAAG,EAAE,iBAAiB,CAAC,CAAC;IACrE,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAM7B;QACG,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO;YAAK,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QACxF,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;YAC1D,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAC/D,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YACpD,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC5D,CAAC;QACD,IAAI,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;QACtE,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC;QACjD,IAAI,OAAO,SAAS,KAAK,UAAU,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CACX,6FAA6F,CAChG,CAAC;QACN,CAAC;QAED,MAAM,QAAQ,GAAG;YACb,UAAU,EAAE,IAAI,CAAC,SAAS;YAC1B,OAAO,EAAE,IAAI,CAAC,MAAM;YACpB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,KAAK,EAAE,IAAA,oBAAW,EAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;SACzC,CAAC;QACF,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC5C,MAAM,SAAS,GAAG,IAAA,aAAI,EAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAElG,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACjD,MAAM,GAAG,GAAG,GAAG,OAAO,6BAA6B,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,UAAU,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC;QAEzJ,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE;YAC7B,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;SAChD,CAAC,CAAC;QAEH,IAAI,IAAa,CAAC;QAClB,IAAI,CAAC;YAAC,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAAC,CAAC;QAChC,OAAO,EAAE,EAAE,CAAC;YAAC,IAAI,GAAG,IAAI,CAAC;QAAC,CAAC;QAE3B,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACV,MAAM,GAAG,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC;YAC9D,MAAM,IAAI,KAAK,CAAC,+BAA+B,GAAG,EAAE,CAAC,CAAC;QAC1D,CAAC;QAED,MAAM,MAAM,GAAG,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,QAAQ,IAAI,IAAI,CAAC;YACjE,CAAC,CAAE,IAA4B,CAAC,MAAM;YACtC,CAAC,CAAC,IAAI,CAAC;QACX,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;QACtE,CAAC;QACD,MAAM,CAAC,GAAG,MAAiC,CAAC;QAC5C,OAAO;YACH,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YAC7B,UAAU,EAAE,OAAO,CAAC,CAAC,YAAY,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAW,CAAC,CAAC,CAAC,IAAI;YAClF,SAAS,EAAG,OAAO,CAAC,CAAC,WAAW,CAAC,KAAM,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAY,CAAC,CAAC,CAAC,IAAI;YAClF,YAAY,EAAE,OAAO,CAAC,CAAC,cAAc,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,CAAW,CAAC,CAAC,CAAC,IAAI;SAC3F,CAAC;IACN,CAAC;CACJ;AA1lBD,0BA0lBC;AAED,SAAS,mBAAmB,CAAC,IAAa;IACtC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACnD,MAAM,CAAC,GAAG,IAA+B,CAAC;IAC1C,IAAI,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC,SAAS,CAAW,CAAC;IACpE,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC/C,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAA4B,CAAC;QAChD,IAAI,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,QAAQ;YAAE,OAAO,CAAC,CAAC,SAAS,CAAW,CAAC;IACxE,CAAC;IACD,IAAI,OAAO,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC,OAAO,CAAW,CAAC;IAChE,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,4EAA4E;AAC5E,0EAA0E;AAE1E,SAAS,uBAAuB,CAAC,KAAa;IAC1C,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC;QACtD,KAAK,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACxC,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,uBAAuB,CAAC,KAAa;IAC1C,OAAO,uBAAuB,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,51 @@
1
+ export type KeyState = 'active' | 'rotating' | 'expired' | 'unknown';
2
+ export interface KeyLookup {
3
+ state: KeyState;
4
+ publicKey: string | null;
5
+ expiresAt: string | null;
6
+ }
7
+ export interface YeriaKeyStoreOptions {
8
+ /**
9
+ * Base URL of the Yeria platform — e.g. `https://yeria.app`. Trailing
10
+ * slash optional. The store appends `/api/v1/public/registry/...`.
11
+ */
12
+ baseUrl: string;
13
+ /**
14
+ * Cache lifetime per kid, in milliseconds. Default 10 minutes.
15
+ * Applies to both positive (PEM) and negative (expired/unknown)
16
+ * cache entries.
17
+ */
18
+ ttlMs?: number;
19
+ /**
20
+ * Inject a `fetch` implementation. Defaults to the global `fetch` —
21
+ * Node 18+ ships it natively. Tests override to avoid real HTTP.
22
+ */
23
+ fetch?: typeof fetch;
24
+ }
25
+ export declare class YeriaKeyStore {
26
+ private readonly baseUrl;
27
+ private readonly ttlMs;
28
+ private readonly fetchImpl;
29
+ private readonly cache;
30
+ constructor(opts: YeriaKeyStoreOptions);
31
+ /**
32
+ * Resolve a kid to a PEM. Returns null when the key is expired or
33
+ * unknown — the caller should reject the inbound token in that case.
34
+ */
35
+ getByKid(kid: string): Promise<string | null>;
36
+ /**
37
+ * Resolve a kid to its full trust state. Same network/cache behaviour
38
+ * as `getByKid` — exposed for callers that want to log / branch on
39
+ * the state.
40
+ */
41
+ getState(kid: string): Promise<KeyState>;
42
+ /** Drop a single cache entry. Use after a verify failure to force a
43
+ * refetch on the retry — covers the case where Yeria rotated a key
44
+ * out from under our cache. */
45
+ invalidate(kid: string): void;
46
+ /** Drop the entire cache. */
47
+ invalidateAll(): void;
48
+ private lookup;
49
+ private fetchFromYeria;
50
+ }
51
+ //# sourceMappingURL=key-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key-store.d.ts","sourceRoot":"","sources":["../../src/core/key-store.ts"],"names":[],"mappings":"AAyBA,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;AAErE,MAAM,WAAW,SAAS;IACtB,KAAK,EAAE,QAAQ,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACjC;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AASD,qBAAa,aAAa;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;gBAE3C,IAAI,EAAE,oBAAoB;IAetC;;;OAGG;IACG,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAKnD;;;;OAIG;IACG,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAK9C;;oCAEgC;IAChC,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAI7B,6BAA6B;IAC7B,aAAa,IAAI,IAAI;YAIP,MAAM;YAeN,cAAc;CAuC/B"}