@mettlecast/domain-runtime 0.2.72 → 0.2.73
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.
- package/dist/ctx/cognito.d.ts +65 -0
- package/dist/ctx/cognito.js +1 -0
- package/dist/ctx/context.d.ts +3 -0
- package/dist/ctx/index.d.ts +1 -0
- package/dist/runtime/cognito.d.ts +32 -0
- package/dist/runtime/cognito.js +108 -0
- package/dist/runtime/hydrate.d.ts +3 -0
- package/dist/runtime/hydrate.js +7 -1
- package/dist/runtime/index.d.ts +2 -0
- package/dist/runtime/index.js +1 -0
- package/dist/runtime/secrets.d.ts +6 -0
- package/dist/runtime/secrets.js +19 -0
- package/package.json +1 -1
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cognito control-plane context. Automatically scoped to the configured
|
|
3
|
+
* user pool — domain code never passes `UserPoolId`.
|
|
4
|
+
*
|
|
5
|
+
* The runtime creates this when `COGNITO_USER_POOL_ID` is set in the
|
|
6
|
+
* Lambda environment. Domain code accesses it via `ctx.cognito`.
|
|
7
|
+
*/
|
|
8
|
+
export interface CognitoContext {
|
|
9
|
+
/**
|
|
10
|
+
* Create a user in the configured user pool. Tolerates
|
|
11
|
+
* `UsernameExistsException` — returns normally if the user already exists.
|
|
12
|
+
*
|
|
13
|
+
* @param params.username - Email or username.
|
|
14
|
+
* @param params.userAttributes - Optional attributes (defaults to email + email_verified=true).
|
|
15
|
+
* @param params.suppressMessage - If true (default), suppresses the welcome email.
|
|
16
|
+
*/
|
|
17
|
+
adminCreateUser(params: {
|
|
18
|
+
username: string;
|
|
19
|
+
userAttributes?: Record<string, string>;
|
|
20
|
+
suppressMessage?: boolean;
|
|
21
|
+
}): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Set a user's password, optionally permanent.
|
|
24
|
+
*
|
|
25
|
+
* @param params.username - Email or username.
|
|
26
|
+
* @param params.password - The password to set.
|
|
27
|
+
* @param params.permanent - If true (default), the user does not need to change it on first login.
|
|
28
|
+
*/
|
|
29
|
+
adminSetUserPassword(params: {
|
|
30
|
+
username: string;
|
|
31
|
+
password: string;
|
|
32
|
+
permanent?: boolean;
|
|
33
|
+
}): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Fetch a user's attributes and status.
|
|
36
|
+
*
|
|
37
|
+
* @param params.username - Email or username.
|
|
38
|
+
* @returns User attributes as a flat record, plus enabled/status flags.
|
|
39
|
+
*/
|
|
40
|
+
adminGetUser(params: {
|
|
41
|
+
username: string;
|
|
42
|
+
}): Promise<{
|
|
43
|
+
userAttributes: Record<string, string>;
|
|
44
|
+
enabled: boolean;
|
|
45
|
+
userStatus: string;
|
|
46
|
+
}>;
|
|
47
|
+
/**
|
|
48
|
+
* Delete a user from the configured user pool.
|
|
49
|
+
*
|
|
50
|
+
* @param params.username - Email or username.
|
|
51
|
+
*/
|
|
52
|
+
adminDeleteUser(params: {
|
|
53
|
+
username: string;
|
|
54
|
+
}): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Update a user's attributes.
|
|
57
|
+
*
|
|
58
|
+
* @param params.username - Email or username.
|
|
59
|
+
* @param params.attributes - Attributes to set.
|
|
60
|
+
*/
|
|
61
|
+
adminUpdateUserAttributes(params: {
|
|
62
|
+
username: string;
|
|
63
|
+
attributes: Record<string, string>;
|
|
64
|
+
}): Promise<void>;
|
|
65
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/ctx/context.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { FeatureFlags } from '../runtime/feature-flags.js';
|
|
|
6
6
|
import type { AuditContext } from '../runtime/audit.js';
|
|
7
7
|
import type { DomainStoreContext } from './store.js';
|
|
8
8
|
import type { DomainFilesContext } from './files.js';
|
|
9
|
+
import type { CognitoContext } from './cognito.js';
|
|
9
10
|
/**
|
|
10
11
|
* The unified domain context injected into every handler.
|
|
11
12
|
* All fields are always populated by the runtime; no field is ever null.
|
|
@@ -47,6 +48,8 @@ export interface DomainContext {
|
|
|
47
48
|
store: DomainStoreContext;
|
|
48
49
|
/** Per-domain S3 file store, automatically scoped to the current tenant. */
|
|
49
50
|
files: DomainFilesContext;
|
|
51
|
+
/** Cognito control-plane client (Admin* operations). Noop when no user pool is configured. */
|
|
52
|
+
cognito: CognitoContext;
|
|
50
53
|
/** URL path parameters from the incoming request, excluding tenantId (e.g. { tableName: 'users' }). */
|
|
51
54
|
pathParams: Record<string, string>;
|
|
52
55
|
}
|
package/dist/ctx/index.d.ts
CHANGED
|
@@ -4,3 +4,4 @@ export type { PublishFn, IdempotencyContext, CacheContext, TibFetch, Logger, Tra
|
|
|
4
4
|
export type { DomainContext } from './context.js';
|
|
5
5
|
export type { DomainStoreContext, StoreQueryOptions, StoreQueryResult } from './store.js';
|
|
6
6
|
export type { DomainFilesContext, FilesPutOptions, FilesListResult } from './files.js';
|
|
7
|
+
export type { CognitoContext } from './cognito.js';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { CognitoContext } from '../ctx/cognito.js';
|
|
2
|
+
/** Options for the Cognito context factory. */
|
|
3
|
+
export interface CognitoOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Cognito User Pool ID. Defaults to process.env.COGNITO_USER_POOL_ID.
|
|
6
|
+
* If not set, the factory returns a noop context that throws on any call.
|
|
7
|
+
*/
|
|
8
|
+
userPoolId?: string;
|
|
9
|
+
/**
|
|
10
|
+
* AWS region. Defaults to process.env.COGNITO_AWS_REGION or process.env.AWS_REGION.
|
|
11
|
+
*/
|
|
12
|
+
region?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Create a CognitoIdentityProvider-backed CognitoContext.
|
|
16
|
+
*
|
|
17
|
+
* The SDK client is created lazily on first use. The `UserPoolId` is
|
|
18
|
+
* captured at construction time from `COGNITO_USER_POOL_ID` — domain
|
|
19
|
+
* code never needs to pass it.
|
|
20
|
+
*
|
|
21
|
+
* `adminCreateUser` tolerates `UsernameExistsException` so that
|
|
22
|
+
* idempotent retries (e.g. bootstrap re-runs) don't fail.
|
|
23
|
+
*
|
|
24
|
+
* @param options - CognitoOptions. If userPoolId is not resolved, returns a noop.
|
|
25
|
+
* @returns A CognitoContext backed by the AWS SDK, or a noop that throws.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createCognito(options?: CognitoOptions): CognitoContext;
|
|
28
|
+
/**
|
|
29
|
+
* Create a noop CognitoContext for tests or environments without Cognito.
|
|
30
|
+
* Every method throws with a clear message.
|
|
31
|
+
*/
|
|
32
|
+
export declare function createNoopCognito(): CognitoContext;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create a CognitoIdentityProvider-backed CognitoContext.
|
|
3
|
+
*
|
|
4
|
+
* The SDK client is created lazily on first use. The `UserPoolId` is
|
|
5
|
+
* captured at construction time from `COGNITO_USER_POOL_ID` — domain
|
|
6
|
+
* code never needs to pass it.
|
|
7
|
+
*
|
|
8
|
+
* `adminCreateUser` tolerates `UsernameExistsException` so that
|
|
9
|
+
* idempotent retries (e.g. bootstrap re-runs) don't fail.
|
|
10
|
+
*
|
|
11
|
+
* @param options - CognitoOptions. If userPoolId is not resolved, returns a noop.
|
|
12
|
+
* @returns A CognitoContext backed by the AWS SDK, or a noop that throws.
|
|
13
|
+
*/
|
|
14
|
+
export function createCognito(options = {}) {
|
|
15
|
+
const userPoolId = options.userPoolId ?? process.env['COGNITO_USER_POOL_ID'];
|
|
16
|
+
if (!userPoolId) {
|
|
17
|
+
return createNoopCognito();
|
|
18
|
+
}
|
|
19
|
+
const region = options.region ?? process.env['COGNITO_AWS_REGION'] ?? process.env['AWS_REGION'] ?? 'eu-north-1';
|
|
20
|
+
let client;
|
|
21
|
+
async function getClient() {
|
|
22
|
+
if (!client) {
|
|
23
|
+
const sdk = await import('@aws-sdk/client-cognito-identity-provider');
|
|
24
|
+
client = new sdk.CognitoIdentityProviderClient({ region });
|
|
25
|
+
}
|
|
26
|
+
return client;
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
async adminCreateUser(params) {
|
|
30
|
+
const sdk = await import('@aws-sdk/client-cognito-identity-provider');
|
|
31
|
+
const c = await getClient();
|
|
32
|
+
try {
|
|
33
|
+
await c.send(new sdk.AdminCreateUserCommand({
|
|
34
|
+
UserPoolId: userPoolId,
|
|
35
|
+
Username: params.username,
|
|
36
|
+
MessageAction: params.suppressMessage === false ? undefined : 'SUPPRESS',
|
|
37
|
+
UserAttributes: Object.entries(params.userAttributes ?? { email: params.username, email_verified: 'true' }).map(([Name, Value]) => ({ Name, Value })),
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
if (err instanceof Error && err.name === 'UsernameExistsException') {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
throw err;
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
async adminSetUserPassword(params) {
|
|
48
|
+
const sdk = await import('@aws-sdk/client-cognito-identity-provider');
|
|
49
|
+
const c = await getClient();
|
|
50
|
+
await c.send(new sdk.AdminSetUserPasswordCommand({
|
|
51
|
+
UserPoolId: userPoolId,
|
|
52
|
+
Username: params.username,
|
|
53
|
+
Password: params.password,
|
|
54
|
+
Permanent: params.permanent ?? true,
|
|
55
|
+
}));
|
|
56
|
+
},
|
|
57
|
+
async adminGetUser(params) {
|
|
58
|
+
const sdk = await import('@aws-sdk/client-cognito-identity-provider');
|
|
59
|
+
const c = await getClient();
|
|
60
|
+
const result = await c.send(new sdk.AdminGetUserCommand({
|
|
61
|
+
UserPoolId: userPoolId,
|
|
62
|
+
Username: params.username,
|
|
63
|
+
}));
|
|
64
|
+
const userAttributes = {};
|
|
65
|
+
for (const attr of result.UserAttributes ?? []) {
|
|
66
|
+
if (attr.Name && attr.Value) {
|
|
67
|
+
userAttributes[attr.Name] = attr.Value;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
userAttributes,
|
|
72
|
+
enabled: result.Enabled ?? true,
|
|
73
|
+
userStatus: result.UserStatus ?? 'UNKNOWN',
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
async adminDeleteUser(params) {
|
|
77
|
+
const sdk = await import('@aws-sdk/client-cognito-identity-provider');
|
|
78
|
+
const c = await getClient();
|
|
79
|
+
await c.send(new sdk.AdminDeleteUserCommand({
|
|
80
|
+
UserPoolId: userPoolId,
|
|
81
|
+
Username: params.username,
|
|
82
|
+
}));
|
|
83
|
+
},
|
|
84
|
+
async adminUpdateUserAttributes(params) {
|
|
85
|
+
const sdk = await import('@aws-sdk/client-cognito-identity-provider');
|
|
86
|
+
const c = await getClient();
|
|
87
|
+
await c.send(new sdk.AdminUpdateUserAttributesCommand({
|
|
88
|
+
UserPoolId: userPoolId,
|
|
89
|
+
Username: params.username,
|
|
90
|
+
UserAttributes: Object.entries(params.attributes).map(([Name, Value]) => ({ Name, Value })),
|
|
91
|
+
}));
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Create a noop CognitoContext for tests or environments without Cognito.
|
|
97
|
+
* Every method throws with a clear message.
|
|
98
|
+
*/
|
|
99
|
+
export function createNoopCognito() {
|
|
100
|
+
const msg = 'ctx.cognito: COGNITO_USER_POOL_ID is not set. Configure the auth stack to enable Cognito operations.';
|
|
101
|
+
return {
|
|
102
|
+
async adminCreateUser() { throw new Error(msg); },
|
|
103
|
+
async adminSetUserPassword() { throw new Error(msg); },
|
|
104
|
+
async adminGetUser() { throw new Error(msg); },
|
|
105
|
+
async adminDeleteUser() { throw new Error(msg); },
|
|
106
|
+
async adminUpdateUserAttributes() { throw new Error(msg); },
|
|
107
|
+
};
|
|
108
|
+
}
|
|
@@ -6,6 +6,7 @@ import type { DbContext } from '../ctx/db.js';
|
|
|
6
6
|
import type { IntegrationDefinition } from '../primitives/integration.js';
|
|
7
7
|
import type { DomainStoreContext } from '../ctx/store.js';
|
|
8
8
|
import type { DomainFilesContext } from '../ctx/files.js';
|
|
9
|
+
import type { CognitoContext } from '../ctx/cognito.js';
|
|
9
10
|
import type { ActionRegistry } from './actions.js';
|
|
10
11
|
/**
|
|
11
12
|
* Full options for hydrateCtx. All fields are optional — defaults are used for
|
|
@@ -110,6 +111,8 @@ export interface HydrateOptions {
|
|
|
110
111
|
domainBucketName?: string;
|
|
111
112
|
/** URL path parameters to expose via ctx.pathParams (tenantId already excluded by caller). */
|
|
112
113
|
pathParams?: Record<string, string>;
|
|
114
|
+
/** Override the Cognito context. If omitted, createCognito() is used (reads COGNITO_USER_POOL_ID from env). */
|
|
115
|
+
cognito?: CognitoContext;
|
|
113
116
|
}
|
|
114
117
|
/**
|
|
115
118
|
* Hydrates a fully populated DomainContext from a Lambda invocation event and options bag.
|
package/dist/runtime/hydrate.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createLogger } from './logger.js';
|
|
|
2
2
|
import { createTracer } from './tracer.js';
|
|
3
3
|
import { createCache } from './cache.js';
|
|
4
4
|
import { createFetch } from './fetch.js';
|
|
5
|
-
import { createSecrets, createEmptySecrets } from './secrets.js';
|
|
5
|
+
import { createSecrets, createEmptySecrets, createSecretsFromAppSecret } from './secrets.js';
|
|
6
6
|
import { createIdempotency, createNoopIdempotency } from './idempotency.js';
|
|
7
7
|
import { createPublisher } from './publisher.js';
|
|
8
8
|
import { createDb, createMockDb } from './db.js';
|
|
@@ -15,6 +15,7 @@ import { createAudit } from './audit.js';
|
|
|
15
15
|
import { extractObservabilityBindings } from './observability-bindings.js';
|
|
16
16
|
import { createStore, createNoopStore } from './store.js';
|
|
17
17
|
import { createFiles, createNoopFiles } from './files.js';
|
|
18
|
+
import { createCognito } from './cognito.js';
|
|
18
19
|
/**
|
|
19
20
|
* Hydrates a fully populated DomainContext from a Lambda invocation event and options bag.
|
|
20
21
|
* All 14 DomainContext fields are populated. Fields with AWS dependencies fall back to
|
|
@@ -75,6 +76,9 @@ export async function hydrateCtx(_event, options = {}) {
|
|
|
75
76
|
else if (options.secretNames && options.secretNames.length > 0) {
|
|
76
77
|
secrets = await createSecrets({ secretNames: options.secretNames });
|
|
77
78
|
}
|
|
79
|
+
else if (process.env['APP_SECRET_ARN']) {
|
|
80
|
+
secrets = await createSecretsFromAppSecret(process.env['APP_SECRET_ARN']);
|
|
81
|
+
}
|
|
78
82
|
else {
|
|
79
83
|
secrets = createEmptySecrets();
|
|
80
84
|
}
|
|
@@ -167,6 +171,7 @@ export async function hydrateCtx(_event, options = {}) {
|
|
|
167
171
|
const files = options.files ?? ((options.domainBucketName ?? process.env['DOMAIN_BUCKET_NAME'])
|
|
168
172
|
? createFiles({ bucketName: options.domainBucketName ?? process.env['DOMAIN_BUCKET_NAME'], tenantId: tenant.id, tenantRoleArn: process.env['DOMAIN_TENANT_ROLE_ARN'] })
|
|
169
173
|
: createNoopFiles());
|
|
174
|
+
const cognito = options.cognito ?? createCognito();
|
|
170
175
|
ctx = {
|
|
171
176
|
db,
|
|
172
177
|
publish,
|
|
@@ -186,6 +191,7 @@ export async function hydrateCtx(_event, options = {}) {
|
|
|
186
191
|
audit,
|
|
187
192
|
store,
|
|
188
193
|
files,
|
|
194
|
+
cognito,
|
|
189
195
|
pathParams: options.pathParams ?? {},
|
|
190
196
|
};
|
|
191
197
|
return ctx;
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -60,3 +60,5 @@ export type { CreateWebhookHandlerOptions } from './webhook-handler.js';
|
|
|
60
60
|
export { healthHandler, readinessHandler } from './health-handler.js';
|
|
61
61
|
export { createStore, createNoopStore } from './store.js';
|
|
62
62
|
export { createFiles, createNoopFiles } from './files.js';
|
|
63
|
+
export { createCognito, createNoopCognito } from './cognito.js';
|
|
64
|
+
export type { CognitoOptions } from './cognito.js';
|
package/dist/runtime/index.js
CHANGED
|
@@ -63,3 +63,4 @@ export { healthHandler, readinessHandler } from './health-handler.js';
|
|
|
63
63
|
// Storage runtime
|
|
64
64
|
export { createStore, createNoopStore } from './store.js';
|
|
65
65
|
export { createFiles, createNoopFiles } from './files.js';
|
|
66
|
+
export { createCognito, createNoopCognito } from './cognito.js';
|
|
@@ -27,3 +27,9 @@ export declare function createSecrets(options: SecretsOptions): Promise<SecretsP
|
|
|
27
27
|
* @returns An empty frozen SecretsProxy.
|
|
28
28
|
*/
|
|
29
29
|
export declare function createEmptySecrets(): SecretsProxy;
|
|
30
|
+
/**
|
|
31
|
+
* Fetches a single Secrets Manager secret by ARN, parses it as JSON
|
|
32
|
+
* key-value pairs, and returns a SecretsProxy. Used when APP_SECRET_ARN
|
|
33
|
+
* is set — the AppSecret stores all domain secrets as a JSON object.
|
|
34
|
+
*/
|
|
35
|
+
export declare function createSecretsFromAppSecret(secretArn: string): Promise<SecretsProxy>;
|
package/dist/runtime/secrets.js
CHANGED
|
@@ -27,3 +27,22 @@ export async function createSecrets(options) {
|
|
|
27
27
|
export function createEmptySecrets() {
|
|
28
28
|
return Object.freeze({});
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Fetches a single Secrets Manager secret by ARN, parses it as JSON
|
|
32
|
+
* key-value pairs, and returns a SecretsProxy. Used when APP_SECRET_ARN
|
|
33
|
+
* is set — the AppSecret stores all domain secrets as a JSON object.
|
|
34
|
+
*/
|
|
35
|
+
export async function createSecretsFromAppSecret(secretArn) {
|
|
36
|
+
const region = process.env['AWS_REGION'] ?? 'eu-north-1';
|
|
37
|
+
const client = new SecretsManagerClient({ region });
|
|
38
|
+
const cmd = new GetSecretValueCommand({ SecretId: secretArn });
|
|
39
|
+
const res = await client.send(cmd);
|
|
40
|
+
const raw = res.SecretString ?? '{}';
|
|
41
|
+
try {
|
|
42
|
+
const parsed = JSON.parse(raw);
|
|
43
|
+
return Object.freeze({ ...parsed });
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return Object.freeze({});
|
|
47
|
+
}
|
|
48
|
+
}
|