@learncard/learn-cloud-service 2.5.34 → 2.5.36

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 (124) hide show
  1. package/.env.example +24 -12
  2. package/CHANGELOG.md +43 -0
  3. package/bootstrapLambda.test.ts +68 -0
  4. package/config/config.dev.json +8 -0
  5. package/config/config.example.json +8 -0
  6. package/config/config.json +1 -0
  7. package/config/config.production.json +8 -0
  8. package/config/config.scouts.dev.json +3 -0
  9. package/config/config.scouts.production.json +4 -0
  10. package/didWebLambda.test.ts +41 -0
  11. package/didWebLambda.ts +13 -19
  12. package/didWebLambdaApp.ts +23 -0
  13. package/dist/accesslayer/share-content/delete.d.ts +5 -0
  14. package/dist/accesslayer/share-content/delete.d.ts.map +1 -0
  15. package/dist/accesslayer/share-content/index.d.ts +8 -0
  16. package/dist/accesslayer/share-content/index.d.ts.map +1 -0
  17. package/dist/accesslayer/share-content/initialize.d.ts +5 -0
  18. package/dist/accesslayer/share-content/initialize.d.ts.map +1 -0
  19. package/dist/accesslayer/share-content/internal.d.ts +12 -0
  20. package/dist/accesslayer/share-content/internal.d.ts.map +1 -0
  21. package/dist/accesslayer/share-content/put.d.ts +5 -0
  22. package/dist/accesslayer/share-content/put.d.ts.map +1 -0
  23. package/dist/accesslayer/share-content/read.d.ts +7 -0
  24. package/dist/accesslayer/share-content/read.d.ts.map +1 -0
  25. package/dist/accesslayer/share-content/types.d.ts +85 -0
  26. package/dist/accesslayer/share-content/types.d.ts.map +1 -0
  27. package/dist/config/applyDockerStageConfig.d.ts +2 -0
  28. package/dist/config/applyDockerStageConfig.d.ts.map +1 -0
  29. package/dist/config/environment.d.ts +12 -0
  30. package/dist/config/environment.d.ts.map +1 -1
  31. package/dist/config/serverlessFunctionEnv.test.d.ts +2 -0
  32. package/dist/config/serverlessFunctionEnv.test.d.ts.map +1 -0
  33. package/dist/config/stageConfig.d.ts +10 -0
  34. package/dist/config/stageConfig.d.ts.map +1 -0
  35. package/dist/config/stageConfig.test.d.ts +2 -0
  36. package/dist/config/stageConfig.test.d.ts.map +1 -0
  37. package/dist/didkit_wasm_bg.wasm +0 -0
  38. package/dist/docker-entry.d.ts +1 -1
  39. package/dist/docker-entry.d.ts.map +1 -1
  40. package/dist/helpers/share-content-auth/adapters.d.ts +12 -0
  41. package/dist/helpers/share-content-auth/adapters.d.ts.map +1 -0
  42. package/dist/helpers/share-content-auth/canonical.d.ts +15 -0
  43. package/dist/helpers/share-content-auth/canonical.d.ts.map +1 -0
  44. package/dist/helpers/share-content-auth/claims.d.ts +19 -0
  45. package/dist/helpers/share-content-auth/claims.d.ts.map +1 -0
  46. package/dist/helpers/share-content-auth/config.d.ts +12 -0
  47. package/dist/helpers/share-content-auth/config.d.ts.map +1 -0
  48. package/dist/helpers/share-content-auth/index.d.ts +8 -0
  49. package/dist/helpers/share-content-auth/index.d.ts.map +1 -0
  50. package/dist/helpers/share-content-auth/token.d.ts +28 -0
  51. package/dist/helpers/share-content-auth/token.d.ts.map +1 -0
  52. package/dist/helpers/share-content-auth/types.d.ts +70 -0
  53. package/dist/helpers/share-content-auth/types.d.ts.map +1 -0
  54. package/dist/helpers/share-content-auth/verifier.d.ts +9 -0
  55. package/dist/helpers/share-content-auth/verifier.d.ts.map +1 -0
  56. package/dist/index.js +2 -2
  57. package/dist/models/ShareContent.d.ts +160 -0
  58. package/dist/models/ShareContent.d.ts.map +1 -0
  59. package/dist/models/index.d.ts +1 -0
  60. package/dist/models/index.d.ts.map +1 -1
  61. package/dist/share-content/config.d.ts +28 -0
  62. package/dist/share-content/config.d.ts.map +1 -0
  63. package/dist/share-content/index.d.ts +6 -0
  64. package/dist/share-content/index.d.ts.map +1 -0
  65. package/dist/share-content/plugin.d.ts +5 -0
  66. package/dist/share-content/plugin.d.ts.map +1 -0
  67. package/dist/share-content/production.d.ts +15 -0
  68. package/dist/share-content/production.d.ts.map +1 -0
  69. package/dist/share-content/runtime.d.ts +23 -0
  70. package/dist/share-content/runtime.d.ts.map +1 -0
  71. package/dist/share-content/types.d.ts +23 -0
  72. package/dist/share-content/types.d.ts.map +1 -0
  73. package/esbuildPlugins.cjs +1 -0
  74. package/lambda.ts +22 -92
  75. package/lambdaApp.ts +163 -0
  76. package/oidcLambda.test.ts +41 -0
  77. package/oidcLambda.ts +13 -19
  78. package/oidcLambdaApp.ts +23 -0
  79. package/package.json +18 -16
  80. package/serverless-local.yml +3 -1
  81. package/serverless.function-env.cjs +31 -0
  82. package/serverless.yml +31 -22
  83. package/src/accesslayer/share-content/delete.ts +124 -0
  84. package/src/accesslayer/share-content/index.ts +70 -0
  85. package/src/accesslayer/share-content/initialize.ts +24 -0
  86. package/src/accesslayer/share-content/internal.ts +89 -0
  87. package/src/accesslayer/share-content/put.ts +93 -0
  88. package/src/accesslayer/share-content/read.ts +124 -0
  89. package/src/accesslayer/share-content/types.ts +155 -0
  90. package/src/config/applyDockerStageConfig.ts +6 -0
  91. package/src/config/environment.ts +33 -0
  92. package/src/config/serverlessFunctionEnv.test.ts +81 -0
  93. package/src/config/stageConfig.test.ts +26 -0
  94. package/src/config/stageConfig.ts +24 -0
  95. package/src/docker-entry.ts +21 -0
  96. package/src/helpers/share-content-auth/adapters.ts +48 -0
  97. package/src/helpers/share-content-auth/canonical.ts +91 -0
  98. package/src/helpers/share-content-auth/claims.ts +164 -0
  99. package/src/helpers/share-content-auth/config.ts +160 -0
  100. package/src/helpers/share-content-auth/index.ts +59 -0
  101. package/src/helpers/share-content-auth/token.ts +148 -0
  102. package/src/helpers/share-content-auth/types.ts +195 -0
  103. package/src/helpers/share-content-auth/verifier.ts +220 -0
  104. package/src/models/ShareContent.ts +198 -0
  105. package/src/models/index.ts +1 -0
  106. package/src/share-content/config.ts +199 -0
  107. package/src/share-content/index.ts +5 -0
  108. package/src/share-content/plugin.ts +317 -0
  109. package/src/share-content/production.ts +107 -0
  110. package/src/share-content/runtime.ts +90 -0
  111. package/src/share-content/types.ts +59 -0
  112. package/test/share-content-auth.spec.ts +1161 -0
  113. package/test/share-content-config.spec.ts +252 -0
  114. package/test/share-content-didkit.spec.ts +411 -0
  115. package/test/share-content-endpoint.spec.ts +825 -0
  116. package/test/share-content-redis-setup.ts +18 -0
  117. package/test/share-content.spec.ts +681 -0
  118. package/vitest.config.ts +4 -0
  119. package/vitest.share-content-config-unit.config.ts +8 -0
  120. package/vitest.share-content-endpoint.config.ts +21 -0
  121. package/vitest.share-content.config.ts +19 -0
  122. package/xApiLambda.test.ts +41 -0
  123. package/xApiLambda.ts +13 -19
  124. package/xApiLambdaApp.ts +23 -0
package/vitest.config.ts CHANGED
@@ -6,6 +6,10 @@ export default createVitestConfig(nodePreset, {
6
6
  'test/uri-helpers.spec.ts',
7
7
  'test/query.helpers.spec.ts',
8
8
  'test/xapi.helpers.spec.ts',
9
+ 'test/share-content-auth.spec.ts',
10
+ 'src/config/stageConfig.test.ts',
11
+ 'src/config/serverlessFunctionEnv.test.ts',
12
+ '*Lambda.test.ts',
9
13
  ],
10
14
  },
11
15
  });
@@ -0,0 +1,8 @@
1
+ import tsconfigPaths from 'vite-tsconfig-paths';
2
+ import { createVitestConfig, nodePreset } from '../../../vitest.shared';
3
+
4
+ /** Configuration and boot-order checks without starting databases or services. */
5
+ export default createVitestConfig(
6
+ { ...nodePreset, plugins: [tsconfigPaths({ root: '../../' })] },
7
+ { test: { include: ['test/share-content-config.spec.ts'] } }
8
+ );
@@ -0,0 +1,21 @@
1
+ import { createVitestConfig, serviceIntegrationPreset } from '../../../vitest.shared';
2
+
3
+ /**
4
+ * Isolated LC-2187 endpoint suite.
5
+ *
6
+ * These specs exercise the real Fastify inject path, the real C1 verification
7
+ * module, a real ephemeral MongoDB and a real Redis container (global setup).
8
+ * They import no service `@mongo` singleton and touch no application database.
9
+ */
10
+ export default createVitestConfig(serviceIntegrationPreset, {
11
+ test: {
12
+ globalSetup: './test/share-content-redis-setup.ts',
13
+ include: [
14
+ 'test/share-content-config.spec.ts',
15
+ 'test/share-content-endpoint.spec.ts',
16
+ 'test/share-content-didkit.spec.ts',
17
+ ],
18
+ hookTimeout: 240_000,
19
+ testTimeout: 120_000,
20
+ },
21
+ });
@@ -0,0 +1,19 @@
1
+ import { createVitestConfig, serviceIntegrationPreset } from '../../../vitest.shared';
2
+
3
+ /**
4
+ * Isolated real-Mongo test config for the LC-2187 share-content repository and
5
+ * authorization module.
6
+ *
7
+ * These specs start their own `MongoMemoryServer` (or none at all) and never
8
+ * import the service `@mongo` singleton, so they do not need the shared
9
+ * integration global setup, Redis, the app router or any environment. The
10
+ * endpoint/transport suite lives in `vitest.share-content-endpoint.config.ts`
11
+ * and requires a real Redis container; it is deliberately excluded here so this
12
+ * repository-level config stays independent of Redis.
13
+ */
14
+ export default createVitestConfig(serviceIntegrationPreset, {
15
+ test: {
16
+ include: ['test/share-content.spec.ts', 'test/share-content-auth.spec.ts'],
17
+ hookTimeout: 120_000,
18
+ },
19
+ });
@@ -0,0 +1,41 @@
1
+ import type { APIGatewayProxyEventV2, Context } from 'aws-lambda';
2
+ import { beforeEach, expect, it, vi } from 'vitest';
3
+
4
+ const mocks = vi.hoisted(() => ({ bootstrap: vi.fn(), getApp: vi.fn(), handler: vi.fn() }));
5
+
6
+ vi.mock('@learncard/service-config', () => ({ bootstrapLambda: mocks.bootstrap }));
7
+ vi.mock('./src/config/stageConfig', () => ({ base: {}, stages: { dev: {}, production: {} } }));
8
+ vi.mock('./xApiLambdaApp', () => ({ xApiHandler: mocks.handler }));
9
+
10
+ beforeEach(() => {
11
+ vi.resetModules();
12
+ vi.clearAllMocks();
13
+ mocks.bootstrap.mockReturnValue(mocks.getApp);
14
+ mocks.getApp.mockResolvedValue({ xApiHandler: mocks.handler });
15
+ mocks.handler.mockResolvedValue({ statusCode: 200 });
16
+ });
17
+
18
+ it('bootstraps the xApi app with checked-in stage config and the deploy stage', async () => {
19
+ vi.stubEnv('AWS_LAMBDA_FUNCTION_NAME', 'learn-cloud-service-dev-xapi');
20
+ vi.stubEnv('LAMBDA_STAGE', 'dev');
21
+ await import('./xApiLambda');
22
+ expect(mocks.bootstrap).toHaveBeenCalledTimes(1);
23
+ expect(mocks.bootstrap).toHaveBeenCalledWith({
24
+ base: {},
25
+ stages: { dev: {}, production: {} },
26
+ stage: 'dev',
27
+ importApp: expect.any(Function),
28
+ });
29
+ vi.unstubAllEnvs();
30
+ });
31
+
32
+ it('resolves the app once per cold start and forwards every argument', async () => {
33
+ const { xApiHandler } = await import('./xApiLambda');
34
+ const event = {} as APIGatewayProxyEventV2;
35
+ const context = {} as Context;
36
+ const callback = vi.fn();
37
+ await xApiHandler(event, context, callback);
38
+ await xApiHandler(event, context, callback);
39
+ expect(mocks.getApp).toHaveBeenCalledTimes(2);
40
+ expect(mocks.handler).toHaveBeenLastCalledWith(event, context, callback);
41
+ });
package/xApiLambda.ts CHANGED
@@ -1,23 +1,17 @@
1
- import serverlessHttp from 'serverless-http';
2
- import * as Sentry from '@sentry/serverless';
1
+ import { bootstrapLambda } from '@learncard/service-config';
3
2
 
4
- import xApiApp from './src/xapi';
5
- import { environment } from './src/config/environment';
6
- import { toServerlessApplication } from './src/helpers/serverlessApplication';
3
+ import { base, stages } from './src/config/stageConfig';
7
4
 
8
- Sentry.AWSLambda.init({
9
- dsn: environment.SENTRY_DSN,
10
- environment: environment.SENTRY_ENV,
11
- enabled: Boolean(environment.SENTRY_DSN),
12
- tracesSampleRate: 1.0,
13
- integrations: [
14
- new Sentry.Integrations.Console(),
15
- new Sentry.Integrations.Http(),
16
- new Sentry.Integrations.ContextLines(),
17
- new Sentry.Integrations.Mongo(),
18
- ],
5
+ type XApiApp = typeof import('./xApiLambdaApp');
6
+
7
+ const getApplication = bootstrapLambda<XApiApp>({
8
+ base,
9
+ stages,
10
+ stage: process.env.AWS_LAMBDA_FUNCTION_NAME
11
+ ? process.env.LAMBDA_STAGE
12
+ : process.env.CONFIG_STAGE,
13
+ importApp: () => import('./xApiLambdaApp'),
19
14
  });
20
15
 
21
- export const xApiHandler = Sentry.AWSLambda.wrapHandler(
22
- serverlessHttp(toServerlessApplication(xApiApp))
23
- );
16
+ export const xApiHandler = async (...args: Parameters<XApiApp['xApiHandler']>) =>
17
+ (await getApplication()).xApiHandler(...args);
@@ -0,0 +1,23 @@
1
+ import serverlessHttp from 'serverless-http';
2
+ import * as Sentry from '@sentry/serverless';
3
+
4
+ import xApiApp from './src/xapi';
5
+ import { environment } from './src/config/environment';
6
+ import { toServerlessApplication } from './src/helpers/serverlessApplication';
7
+
8
+ Sentry.AWSLambda.init({
9
+ dsn: environment.SENTRY_DSN,
10
+ environment: environment.SENTRY_ENV,
11
+ enabled: Boolean(environment.SENTRY_DSN),
12
+ tracesSampleRate: 1.0,
13
+ integrations: [
14
+ new Sentry.Integrations.Console(),
15
+ new Sentry.Integrations.Http(),
16
+ new Sentry.Integrations.ContextLines(),
17
+ new Sentry.Integrations.Mongo(),
18
+ ],
19
+ });
20
+
21
+ export const xApiHandler = Sentry.AWSLambda.wrapHandler(
22
+ serverlessHttp(toServerlessApplication(xApiApp))
23
+ );