@openhi/constructs 0.0.151 → 0.0.153

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.
@@ -23,7 +23,7 @@ import {
23
23
  createTenantOperation,
24
24
  createWorkspaceOperation,
25
25
  extractDenormalizedReferenceDisplay
26
- } from "./chunk-AWYZJFPL.mjs";
26
+ } from "./chunk-CFJDATDK.mjs";
27
27
  import {
28
28
  buildMembershipUserProjectionItem,
29
29
  buildMembershipWorkspaceProjectionItem,
@@ -1,6 +1,6 @@
1
1
  import { WorkflowDedupClient } from '@openhi/workflows';
2
2
  import { EventBridgeEvent } from 'aws-lambda';
3
- import { d as DemoDevUser } from './events-CMG8xanm.mjs';
3
+ import { d as DemoDevUser } from './events-DTgo2dcW.mjs';
4
4
  import { O as OpenHiContext } from './openhi-context-CaBH8SFo.mjs';
5
5
  import '@openhi/types';
6
6
 
@@ -68,6 +68,19 @@ interface SeedDemoDataDependencies {
68
68
  * put is keyed by a deterministic stable id so re-runs after
69
69
  * dedup-TTL expiry upsert the same records.
70
70
  *
71
+ * Self-healing-on-every-deploy contract: every individual upsert
72
+ * across all three phases is wrapped via {@link tryRun}. A single
73
+ * item's failure (transient AWS error, write-time constraint
74
+ * violation, etc.) is collected into a per-call accumulator and
75
+ * does not skip the remaining items in its phase. After all phases
76
+ * run, collected failures are aggregate-thrown as a single error so
77
+ * EventBridge still routes the workflow into its failure-detection
78
+ * path (DLQ + CloudWatch alarm) and the outer `runSeedDemoData`
79
+ * records `markFailed` on the dedup row. Because every put is keyed
80
+ * by a deterministic stable id, the next deploy re-attempts every
81
+ * item — failed items eventually heal, successful items overwrite
82
+ * themselves with the same body.
83
+ *
71
84
  * Exported so the seeder test file can exercise it directly against
72
85
  * a mocked DynamoControlService; the production handler reaches it
73
86
  * through {@link SeedDemoDataDependencies.seedDemoGraph}.
@@ -84,13 +97,40 @@ declare const seedDemoGraph: (params: {
84
97
  */
85
98
  declare const runSeedDemoData: (event: SeedDemoDataEvent, deps: SeedDemoDataDependencies, devUsers: ReadonlyArray<DemoDevUser>) => Promise<void>;
86
99
  /**
87
- * Deterministic password derived from the user's email. Re-running
88
- * the algorithm with the same email reproduces the password, so devs
89
- * can recover their own credentials from the docs page without the
90
- * workflow ever surfacing them. The shape satisfies the default
91
- * Cognito password policy (≥8 chars, upper + lower + number + symbol).
100
+ * SSM parameter-path prefix that hosts every seeded dev user's
101
+ * password. The full path for a single user is
102
+ * `${SEED_USER_PASSWORD_PARAMETER_PREFIX}<email_safe>/password`
103
+ * where `<email_safe>` is `<user>_at_<domain>` (see
104
+ * {@link emailToSsmPath}). The trailing `/password` segment leaves
105
+ * room for additional per-user parameters under the same email
106
+ * prefix in future phases without renaming the existing entries.
92
107
  */
93
- declare const devPasswordForEmail: (email: string) => string;
108
+ declare const SEED_USER_PASSWORD_PARAMETER_PREFIX = "/openhi/seed/users/";
109
+ /**
110
+ * Map an email address to its canonical SSM parameter path. The
111
+ * `@` separator is replaced with the literal sentinel `_at_` so
112
+ * the resulting path is a single SSM-legal name. Throws when the
113
+ * email is empty, missing exactly one `@`, or contains characters
114
+ * that would produce an invalid SSM path.
115
+ *
116
+ * Example: `alice@codedrifters.com` →
117
+ * `/openhi/seed/users/alice_at_codedrifters.com/password`.
118
+ */
119
+ declare const emailToSsmPath: (email: string) => string;
120
+ /**
121
+ * Test seam: reset the module-scoped SSM client cache. Unit tests
122
+ * that swap in different mocks across `it` blocks call this in
123
+ * `beforeEach` so each test gets a fresh client instance.
124
+ */
125
+ declare const __resetSsmClientForTests: () => void;
126
+ /**
127
+ * Read a seeded dev user's password from SSM Parameter Store. The
128
+ * parameter is expected to be a `SecureString` provisioned out of
129
+ * band by an operator (see the runbook in phase 3 of #1249). On
130
+ * `ParameterNotFound`, the error message includes the exact
131
+ * expected path so the operator can copy-paste-fix.
132
+ */
133
+ declare const fetchSeedUserPassword: (email: string) => Promise<string>;
94
134
  /**
95
135
  * Production Cognito provisioner backed by the AWS SDK. Reads the
96
136
  * user-pool id from the env var the lambda construct injects.
@@ -98,13 +138,21 @@ declare const devPasswordForEmail: (email: string) => string;
98
138
  * Idempotency contract:
99
139
  * - On first invocation, calls `AdminCreateUser` (with
100
140
  * `MessageAction: SUPPRESS` so no invitation email fires) then
101
- * `AdminSetUserPassword` (permanent). Returns the new user's sub.
141
+ * `AdminSetUserPassword` (permanent, from the SSM-sourced
142
+ * value). Returns the new user's sub.
102
143
  * - On subsequent invocations, `AdminCreateUser` throws
103
144
  * `UsernameExistsException`; the provisioner catches it, calls
104
- * `AdminGetUser` to read the existing user's sub, and returns
105
- * **without** touching the password or any attribute.
145
+ * `AdminGetUser` to read the existing user's sub, and **also
146
+ * re-applies the current SSM-sourced password** via
147
+ * `AdminSetUserPassword`. This is the rotation seam: operators
148
+ * update the SSM SecureString value and re-publish the seed
149
+ * event to push a fresh password down to Cognito.
150
+ *
151
+ * The SSM password is fetched once per email up-front so the new-
152
+ * user and rotation branches share the same value and at most one
153
+ * `GetParameter` call lands per `ensureUser` invocation.
106
154
  */
107
155
  declare const productionCognitoProvisioner: () => CognitoProvisioner;
108
156
  declare const handler: (event: SeedDemoDataEvent) => Promise<void>;
109
157
 
110
- export { type CognitoProvisioner, SEED_DEMO_DATA_USER_POOL_ID_ENV_VAR, type SeedDemoDataDependencies, devPasswordForEmail, handler, productionCognitoProvisioner, runSeedDemoData, seedDemoGraph };
158
+ export { type CognitoProvisioner, SEED_DEMO_DATA_USER_POOL_ID_ENV_VAR, SEED_USER_PASSWORD_PARAMETER_PREFIX, type SeedDemoDataDependencies, __resetSsmClientForTests, emailToSsmPath, fetchSeedUserPassword, handler, productionCognitoProvisioner, runSeedDemoData, seedDemoGraph };
@@ -1,6 +1,6 @@
1
1
  import { WorkflowDedupClient } from '@openhi/workflows';
2
2
  import { EventBridgeEvent } from 'aws-lambda';
3
- import { d as DemoDevUser } from './events-CMG8xanm.js';
3
+ import { d as DemoDevUser } from './events-DTgo2dcW.js';
4
4
  import { O as OpenHiContext } from './openhi-context-CaBH8SFo.js';
5
5
  import '@openhi/types';
6
6
 
@@ -68,6 +68,19 @@ interface SeedDemoDataDependencies {
68
68
  * put is keyed by a deterministic stable id so re-runs after
69
69
  * dedup-TTL expiry upsert the same records.
70
70
  *
71
+ * Self-healing-on-every-deploy contract: every individual upsert
72
+ * across all three phases is wrapped via {@link tryRun}. A single
73
+ * item's failure (transient AWS error, write-time constraint
74
+ * violation, etc.) is collected into a per-call accumulator and
75
+ * does not skip the remaining items in its phase. After all phases
76
+ * run, collected failures are aggregate-thrown as a single error so
77
+ * EventBridge still routes the workflow into its failure-detection
78
+ * path (DLQ + CloudWatch alarm) and the outer `runSeedDemoData`
79
+ * records `markFailed` on the dedup row. Because every put is keyed
80
+ * by a deterministic stable id, the next deploy re-attempts every
81
+ * item — failed items eventually heal, successful items overwrite
82
+ * themselves with the same body.
83
+ *
71
84
  * Exported so the seeder test file can exercise it directly against
72
85
  * a mocked DynamoControlService; the production handler reaches it
73
86
  * through {@link SeedDemoDataDependencies.seedDemoGraph}.
@@ -84,13 +97,40 @@ declare const seedDemoGraph: (params: {
84
97
  */
85
98
  declare const runSeedDemoData: (event: SeedDemoDataEvent, deps: SeedDemoDataDependencies, devUsers: ReadonlyArray<DemoDevUser>) => Promise<void>;
86
99
  /**
87
- * Deterministic password derived from the user's email. Re-running
88
- * the algorithm with the same email reproduces the password, so devs
89
- * can recover their own credentials from the docs page without the
90
- * workflow ever surfacing them. The shape satisfies the default
91
- * Cognito password policy (≥8 chars, upper + lower + number + symbol).
100
+ * SSM parameter-path prefix that hosts every seeded dev user's
101
+ * password. The full path for a single user is
102
+ * `${SEED_USER_PASSWORD_PARAMETER_PREFIX}<email_safe>/password`
103
+ * where `<email_safe>` is `<user>_at_<domain>` (see
104
+ * {@link emailToSsmPath}). The trailing `/password` segment leaves
105
+ * room for additional per-user parameters under the same email
106
+ * prefix in future phases without renaming the existing entries.
92
107
  */
93
- declare const devPasswordForEmail: (email: string) => string;
108
+ declare const SEED_USER_PASSWORD_PARAMETER_PREFIX = "/openhi/seed/users/";
109
+ /**
110
+ * Map an email address to its canonical SSM parameter path. The
111
+ * `@` separator is replaced with the literal sentinel `_at_` so
112
+ * the resulting path is a single SSM-legal name. Throws when the
113
+ * email is empty, missing exactly one `@`, or contains characters
114
+ * that would produce an invalid SSM path.
115
+ *
116
+ * Example: `alice@codedrifters.com` →
117
+ * `/openhi/seed/users/alice_at_codedrifters.com/password`.
118
+ */
119
+ declare const emailToSsmPath: (email: string) => string;
120
+ /**
121
+ * Test seam: reset the module-scoped SSM client cache. Unit tests
122
+ * that swap in different mocks across `it` blocks call this in
123
+ * `beforeEach` so each test gets a fresh client instance.
124
+ */
125
+ declare const __resetSsmClientForTests: () => void;
126
+ /**
127
+ * Read a seeded dev user's password from SSM Parameter Store. The
128
+ * parameter is expected to be a `SecureString` provisioned out of
129
+ * band by an operator (see the runbook in phase 3 of #1249). On
130
+ * `ParameterNotFound`, the error message includes the exact
131
+ * expected path so the operator can copy-paste-fix.
132
+ */
133
+ declare const fetchSeedUserPassword: (email: string) => Promise<string>;
94
134
  /**
95
135
  * Production Cognito provisioner backed by the AWS SDK. Reads the
96
136
  * user-pool id from the env var the lambda construct injects.
@@ -98,13 +138,21 @@ declare const devPasswordForEmail: (email: string) => string;
98
138
  * Idempotency contract:
99
139
  * - On first invocation, calls `AdminCreateUser` (with
100
140
  * `MessageAction: SUPPRESS` so no invitation email fires) then
101
- * `AdminSetUserPassword` (permanent). Returns the new user's sub.
141
+ * `AdminSetUserPassword` (permanent, from the SSM-sourced
142
+ * value). Returns the new user's sub.
102
143
  * - On subsequent invocations, `AdminCreateUser` throws
103
144
  * `UsernameExistsException`; the provisioner catches it, calls
104
- * `AdminGetUser` to read the existing user's sub, and returns
105
- * **without** touching the password or any attribute.
145
+ * `AdminGetUser` to read the existing user's sub, and **also
146
+ * re-applies the current SSM-sourced password** via
147
+ * `AdminSetUserPassword`. This is the rotation seam: operators
148
+ * update the SSM SecureString value and re-publish the seed
149
+ * event to push a fresh password down to Cognito.
150
+ *
151
+ * The SSM password is fetched once per email up-front so the new-
152
+ * user and rotation branches share the same value and at most one
153
+ * `GetParameter` call lands per `ensureUser` invocation.
106
154
  */
107
155
  declare const productionCognitoProvisioner: () => CognitoProvisioner;
108
156
  declare const handler: (event: SeedDemoDataEvent) => Promise<void>;
109
157
 
110
- export { type CognitoProvisioner, SEED_DEMO_DATA_USER_POOL_ID_ENV_VAR, type SeedDemoDataDependencies, devPasswordForEmail, handler, productionCognitoProvisioner, runSeedDemoData, seedDemoGraph };
158
+ export { type CognitoProvisioner, SEED_DEMO_DATA_USER_POOL_ID_ENV_VAR, SEED_USER_PASSWORD_PARAMETER_PREFIX, type SeedDemoDataDependencies, __resetSsmClientForTests, emailToSsmPath, fetchSeedUserPassword, handler, productionCognitoProvisioner, runSeedDemoData, seedDemoGraph };