@learncard/lca-api-service 1.5.3 → 1.6.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 (45) hide show
  1. package/.env.example +10 -0
  2. package/CHANGELOG.md +26 -0
  3. package/bundle.mjs +1 -1
  4. package/dist/app.d.ts +4 -1
  5. package/dist/config/cacheEnvironment.d.ts +4 -4
  6. package/dist/config/environment.d.ts +145 -114
  7. package/dist/config/oidcEnvironment.d.ts +22 -22
  8. package/dist/didkit_wasm_bg.wasm +0 -0
  9. package/dist/helpers/bedrockGeneration.d.ts +17 -0
  10. package/dist/helpers/bedrockGeneration.test.d.ts +1 -0
  11. package/dist/helpers/bedrockSchema.d.ts +10 -0
  12. package/dist/helpers/imageGeneration.d.ts +42 -0
  13. package/dist/helpers/imageGeneration.test.d.ts +1 -0
  14. package/dist/index.js +2 -2
  15. package/dist/models/Notification.d.ts +3 -1
  16. package/dist/publish-metafile.json +1 -1
  17. package/dist/routes/ai.skill-icons.test.d.ts +1 -0
  18. package/dist/routes/keys.d.ts +1 -0
  19. package/dist/routes/notifications.d.ts +3 -1
  20. package/dist/types/notifications.d.ts +3 -1
  21. package/docs/bedrock-generation.md +119 -0
  22. package/docs/image-generation.md +120 -0
  23. package/package.json +20 -15
  24. package/scripts/node24-runtime.cjs +9 -0
  25. package/scripts/verify-node24-layer.cjs +49 -0
  26. package/serverless-local.yml +3 -1
  27. package/serverless.function-env.cjs +2 -4
  28. package/serverless.yml +76 -3
  29. package/src/config/environment.ts +14 -0
  30. package/src/helpers/bedrockGeneration.test.ts +222 -0
  31. package/src/helpers/bedrockGeneration.ts +110 -0
  32. package/src/helpers/bedrockSchema.ts +352 -0
  33. package/src/helpers/imageGeneration.test.ts +456 -0
  34. package/src/helpers/imageGeneration.ts +432 -0
  35. package/src/routes/ai.skill-icons.test.ts +92 -0
  36. package/src/routes/ai.test.ts +68 -91
  37. package/src/routes/ai.ts +31 -143
  38. package/src/routes/keys.ts +18 -0
  39. package/src/services/escrow-enclave/enclaveTrustAnchors.ts +19 -0
  40. package/src/services/escrow-enclave/logFailure.test.ts +8 -0
  41. package/src/services/escrow-enclave/logFailure.ts +17 -0
  42. package/src/services/escrow-enclave/remoteEnclave.tls.test.ts +10 -0
  43. package/test/keys-auth-share-escrow.spec.ts +103 -0
  44. package/test/oidc.spec.ts +41 -2
  45. package/tsconfig.bedrock.json +10 -0
package/test/oidc.spec.ts CHANGED
@@ -6,6 +6,7 @@ import { issueLoginTicket, redeemLoginTicket } from '../src/cache/login-tickets'
6
6
  import cache from '@cache';
7
7
  import { GetSecretValueCommand } from '@aws-sdk/client-secrets-manager';
8
8
  import { getOidcSigningKey, resetOidcSigningKeyForTests } from '../src/helpers/oidc.helpers';
9
+ import { ACCESS_TOKEN_PREFIX } from '../src/helpers/login-ticket.helpers';
9
10
 
10
11
  const { env, entries, sendSecret } = vi.hoisted(() => ({
11
12
  sendSecret: vi.fn(),
@@ -188,8 +189,12 @@ beforeEach(async () => {
188
189
  });
189
190
  });
190
191
  afterEach(async () => {
191
- await app.close();
192
- vi.restoreAllMocks();
192
+ try {
193
+ await app.close();
194
+ } finally {
195
+ vi.useRealTimers();
196
+ vi.restoreAllMocks();
197
+ }
193
198
  });
194
199
 
195
200
  describe('OIDC provider', () => {
@@ -397,6 +402,11 @@ describe('OIDC provider', () => {
397
402
  it.each<BasicMode>(['encoded', 'raw', false])(
398
403
  'exchanges a code using Basic=%s and verifies RS256 through served JWKS',
399
404
  async basic => {
405
+ // Freeze wall-clock time only; Fastify's I/O timers keep running normally.
406
+ // expires_in is remaining time, so an uncontrolled second boundary can
407
+ // make it 299 even though the signed JWT lifetime is exactly 300 seconds.
408
+ vi.useFakeTimers({ toFake: ['Date'] });
409
+ vi.setSystemTime(new Date('2026-10-14T12:00:00.999Z'));
400
410
  const response = await exchange(await code(), {}, basic);
401
411
  expect(response.statusCode).toBe(200);
402
412
  const tokens = response.json();
@@ -427,6 +437,35 @@ describe('OIDC provider', () => {
427
437
  expect(response.headers.pragma).toBe('no-cache');
428
438
  }
429
439
  );
440
+ it('reports 299 seconds remaining when access-token persistence crosses a second', async () => {
441
+ vi.useFakeTimers({ toFake: ['Date'] });
442
+ const start = new Date('2026-10-14T12:00:00.999Z');
443
+ vi.setSystemTime(start);
444
+ const set = cache.set.bind(cache);
445
+ vi.spyOn(cache, 'set').mockImplementation(async (...args) => {
446
+ const result = await set(...args);
447
+ if (args[0].startsWith(ACCESS_TOKEN_PREFIX)) {
448
+ // Advance after JWT signing, before expires_in is calculated.
449
+ vi.setSystemTime(start.getTime() + 1);
450
+ }
451
+ return result;
452
+ });
453
+
454
+ const response = await exchange(await code());
455
+ expect(response.statusCode).toBe(200);
456
+ const tokens = response.json();
457
+ const jwks = createLocalJWKSet((await app.inject('/oidc/jwks')).json());
458
+ const options = { issuer: env.OIDC_ISSUER, audience: env.OIDC_CLIENT_ID };
459
+ const { payload } = await jwtVerify(tokens.id_token, jwks, options);
460
+ expect(payload.exp! - payload.iat!).toBe(300);
461
+ expect(tokens.expires_in).toBe(299);
462
+
463
+ // The clock control must not hide an extended JWT lifetime.
464
+ vi.setSystemTime(payload.exp! * 1000);
465
+ await expect(jwtVerify(tokens.id_token, jwks, options)).rejects.toMatchObject({
466
+ code: 'ERR_JWT_EXPIRED',
467
+ });
468
+ });
430
469
  it('URL-decodes Basic client credentials', async () => {
431
470
  env.OIDC_CLIENT_SECRET = 'a+b:c %';
432
471
  expect((await exchange(await code(), {}, 'encoded')).statusCode).toBe(200);
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": { "noEmit": true },
4
+ "include": [
5
+ "src/helpers/bedrockGeneration.ts",
6
+ "src/helpers/bedrockGeneration.test.ts",
7
+ "src/helpers/bedrockSchema.ts",
8
+ "src/types/skills.ts"
9
+ ]
10
+ }