@openhi/constructs 0.0.178 → 0.0.180

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 (54) hide show
  1. package/lib/{chunk-Z4PZSLYY.mjs → chunk-3M4QTQH6.mjs} +2 -2
  2. package/lib/{chunk-JUSVETWK.mjs → chunk-4LQR32D2.mjs} +38 -40
  3. package/lib/{chunk-JUSVETWK.mjs.map → chunk-4LQR32D2.mjs.map} +1 -1
  4. package/lib/{chunk-XNUCKVSE.mjs → chunk-7GMTHOYF.mjs} +2 -2
  5. package/lib/{chunk-E2OWEBBH.mjs → chunk-DIVYB6GD.mjs} +18 -4
  6. package/lib/chunk-DIVYB6GD.mjs.map +1 -0
  7. package/lib/chunk-F2LY4TEI.mjs +272 -0
  8. package/lib/chunk-F2LY4TEI.mjs.map +1 -0
  9. package/lib/{chunk-GG2WD6TA.mjs → chunk-JJ3AQ6G5.mjs} +9 -3
  10. package/lib/{chunk-GG2WD6TA.mjs.map → chunk-JJ3AQ6G5.mjs.map} +1 -1
  11. package/lib/{chunk-EBB4RNUG.mjs → chunk-PIQISEGW.mjs} +2 -2
  12. package/lib/{chunk-FDBBTNCI.mjs → chunk-Q4KQD2NB.mjs} +117 -5
  13. package/lib/chunk-Q4KQD2NB.mjs.map +1 -0
  14. package/lib/{chunk-Y4RGUAM2.mjs → chunk-V6KLFEHC.mjs} +105 -34
  15. package/lib/chunk-V6KLFEHC.mjs.map +1 -0
  16. package/lib/chunk-VQY57NOV.mjs +60 -0
  17. package/lib/chunk-VQY57NOV.mjs.map +1 -0
  18. package/lib/counter-maintenance.handler.mjs +4 -4
  19. package/lib/counter-reconciliation.handler.js +2 -2
  20. package/lib/counter-reconciliation.handler.js.map +1 -1
  21. package/lib/counter-reconciliation.handler.mjs +9 -267
  22. package/lib/counter-reconciliation.handler.mjs.map +1 -1
  23. package/lib/index.d.mts +117 -2
  24. package/lib/index.d.ts +117 -2
  25. package/lib/index.js +6454 -6243
  26. package/lib/index.js.map +1 -1
  27. package/lib/index.mjs +106 -4
  28. package/lib/index.mjs.map +1 -1
  29. package/lib/pre-token-generation.handler.js +28 -19
  30. package/lib/pre-token-generation.handler.js.map +1 -1
  31. package/lib/pre-token-generation.handler.mjs +4 -5
  32. package/lib/pre-token-generation.handler.mjs.map +1 -1
  33. package/lib/provision-default-workspace.handler.js +22 -19
  34. package/lib/provision-default-workspace.handler.js.map +1 -1
  35. package/lib/provision-default-workspace.handler.mjs +3 -4
  36. package/lib/provision-default-workspace.handler.mjs.map +1 -1
  37. package/lib/rest-api-lambda.handler.js +367 -208
  38. package/lib/rest-api-lambda.handler.js.map +1 -1
  39. package/lib/rest-api-lambda.handler.mjs +210 -165
  40. package/lib/rest-api-lambda.handler.mjs.map +1 -1
  41. package/lib/seed-demo-data.handler.d.mts +19 -0
  42. package/lib/seed-demo-data.handler.d.ts +19 -0
  43. package/lib/seed-demo-data.handler.js +805 -159
  44. package/lib/seed-demo-data.handler.js.map +1 -1
  45. package/lib/seed-demo-data.handler.mjs +8 -4
  46. package/package.json +1 -1
  47. package/lib/chunk-6HGSR3TG.mjs +0 -123
  48. package/lib/chunk-6HGSR3TG.mjs.map +0 -1
  49. package/lib/chunk-E2OWEBBH.mjs.map +0 -1
  50. package/lib/chunk-FDBBTNCI.mjs.map +0 -1
  51. package/lib/chunk-Y4RGUAM2.mjs.map +0 -1
  52. /package/lib/{chunk-Z4PZSLYY.mjs.map → chunk-3M4QTQH6.mjs.map} +0 -0
  53. /package/lib/{chunk-XNUCKVSE.mjs.map → chunk-7GMTHOYF.mjs.map} +0 -0
  54. /package/lib/{chunk-EBB4RNUG.mjs.map → chunk-PIQISEGW.mjs.map} +0 -0
@@ -1,277 +1,19 @@
1
1
  import {
2
- COUNTER_TARGET,
3
- isAdminRoleAssignment
4
- } from "./chunk-RQKJNMX5.mjs";
5
- import {
6
- countMembershipsByUserOperation,
7
- listTenantsOperation,
8
- listWorkspacesOperation,
9
- membershipListByWorkspaceOperation,
10
- roleAssignmentListByWorkspaceOperation
11
- } from "./chunk-JUSVETWK.mjs";
12
- import {
13
- listMembershipsOperation
14
- } from "./chunk-EBB4RNUG.mjs";
15
- import {
16
- extractRoleLevel
17
- } from "./chunk-BUAYVN3C.mjs";
18
- import {
19
- extractReferenceSlug
20
- } from "./chunk-I6LUPJUY.mjs";
21
- import {
22
- listUsersOperation
23
- } from "./chunk-6HGSR3TG.mjs";
24
- import "./chunk-FDBBTNCI.mjs";
2
+ reconcileAllCountersOperation
3
+ } from "./chunk-F2LY4TEI.mjs";
4
+ import "./chunk-RQKJNMX5.mjs";
5
+ import "./chunk-4LQR32D2.mjs";
6
+ import "./chunk-PIQISEGW.mjs";
7
+ import "./chunk-BUAYVN3C.mjs";
8
+ import "./chunk-I6LUPJUY.mjs";
9
+ import "./chunk-Q4KQD2NB.mjs";
25
10
  import "./chunk-APVVG7BO.mjs";
26
11
  import "./chunk-FYHBHHWK.mjs";
27
- import {
28
- getDynamoControlService
29
- } from "./chunk-EUIP2U5F.mjs";
12
+ import "./chunk-EUIP2U5F.mjs";
30
13
  import "./chunk-TRY7JGWO.mjs";
31
14
  import "./chunk-KMEWULMX.mjs";
32
15
  import "./chunk-LZOMFHX3.mjs";
33
16
 
34
- // src/data/operations/control/counters/counter-reconcile-operation.ts
35
- function counterValue(value) {
36
- return typeof value === "number" && Number.isFinite(value) ? value : 0;
37
- }
38
- function reconcileContext(tenantId) {
39
- return {
40
- tenantId,
41
- workspaceId: "",
42
- date: (/* @__PURE__ */ new Date()).toISOString(),
43
- actorId: "counter-reconciliation",
44
- actorName: "Counter Reconciliation Job",
45
- actorType: "internal-system",
46
- source: "step-function"
47
- };
48
- }
49
- async function reconcileTenantCountersOperation(params) {
50
- const { tenantId, tableName } = params;
51
- const service = getDynamoControlService(tableName);
52
- const context = reconcileContext(tenantId);
53
- const workspacesResult = await listWorkspacesOperation({
54
- context,
55
- tableName,
56
- mode: "count"
57
- });
58
- const workspacesInTenant = workspacesResult.total;
59
- const memberships = await listMembershipsOperation({
60
- context,
61
- tableName,
62
- mode: "full"
63
- });
64
- let usersInTenant = 0;
65
- for (const entry of memberships.entries) {
66
- const workspaceSlug = extractReferenceSlug(entry.resource, "workspace");
67
- if (workspaceSlug === void 0) {
68
- usersInTenant += 1;
69
- }
70
- }
71
- const current = await service.entities.tenant.get({ tenantId, sk: "CURRENT" }).go();
72
- const drift = [];
73
- const recomputed = {
74
- usersInTenant,
75
- workspacesInTenant
76
- };
77
- for (const counter of Object.keys(recomputed)) {
78
- const oldValue = counterValue(current.data?.[counter]);
79
- const newValue = recomputed[counter];
80
- if (oldValue !== newValue) {
81
- drift.push({
82
- target: COUNTER_TARGET.Tenant,
83
- id: tenantId,
84
- counter,
85
- old: oldValue,
86
- new: newValue
87
- });
88
- }
89
- }
90
- if (drift.length > 0) {
91
- await service.entities.tenant.patch({ tenantId, sk: "CURRENT" }).set(recomputed).go();
92
- }
93
- return { drift };
94
- }
95
- async function reconcileWorkspaceCountersOperation(params) {
96
- const { tenantId, workspaceId, tableName } = params;
97
- const service = getDynamoControlService(tableName);
98
- let usersInWorkspace = 0;
99
- let membershipCursor = null;
100
- do {
101
- const page = await membershipListByWorkspaceOperation({
102
- tenantId,
103
- workspaceId,
104
- cursor: membershipCursor,
105
- tableName
106
- });
107
- usersInWorkspace += page.items.length;
108
- membershipCursor = page.cursor;
109
- } while (membershipCursor !== null);
110
- let adminUsersInWorkspace = 0;
111
- let normalUsersInWorkspace = 0;
112
- let roleAssignmentCursor = null;
113
- do {
114
- const page = await roleAssignmentListByWorkspaceOperation({
115
- tenantId,
116
- workspaceId,
117
- cursor: roleAssignmentCursor,
118
- tableName
119
- });
120
- for (const item of page.items) {
121
- const roleLevel = await readRoleLevel(
122
- service,
123
- tenantId,
124
- item.roleAssignmentId
125
- );
126
- if (isAdminRoleAssignment({ roleLevel, roleId: item.roleId })) {
127
- adminUsersInWorkspace += 1;
128
- } else {
129
- normalUsersInWorkspace += 1;
130
- }
131
- }
132
- roleAssignmentCursor = page.cursor;
133
- } while (roleAssignmentCursor !== null);
134
- const current = await service.entities.workspace.get({ tenantId, id: workspaceId, sk: "CURRENT" }).go();
135
- const drift = [];
136
- const recomputed = {
137
- usersInWorkspace,
138
- adminUsersInWorkspace,
139
- normalUsersInWorkspace
140
- };
141
- for (const counter of Object.keys(recomputed)) {
142
- const oldValue = counterValue(current.data?.[counter]);
143
- const newValue = recomputed[counter];
144
- if (oldValue !== newValue) {
145
- drift.push({
146
- target: COUNTER_TARGET.Workspace,
147
- id: workspaceId,
148
- tenantId,
149
- counter,
150
- old: oldValue,
151
- new: newValue
152
- });
153
- }
154
- }
155
- if (drift.length > 0) {
156
- await service.entities.workspace.patch({ tenantId, id: workspaceId, sk: "CURRENT" }).set(recomputed).go();
157
- }
158
- return { drift };
159
- }
160
- async function reconcileUserCountersOperation(params) {
161
- const { userId, tableName } = params;
162
- const service = getDynamoControlService(tableName);
163
- const tenantsForUser = await countMembershipsByUserOperation({
164
- userId,
165
- mode: "tenant",
166
- tableName
167
- });
168
- const workspacesForUser = await countMembershipsByUserOperation({
169
- userId,
170
- mode: "workspace",
171
- tableName
172
- });
173
- const current = await service.entities.user.get({ id: userId, sk: "CURRENT" }).go();
174
- const drift = [];
175
- const recomputed = {
176
- tenantsForUser,
177
- workspacesForUser
178
- };
179
- for (const counter of Object.keys(recomputed)) {
180
- const oldValue = counterValue(current.data?.[counter]);
181
- const newValue = recomputed[counter];
182
- if (oldValue !== newValue) {
183
- drift.push({
184
- target: COUNTER_TARGET.User,
185
- id: userId,
186
- counter,
187
- old: oldValue,
188
- new: newValue
189
- });
190
- }
191
- }
192
- if (drift.length > 0) {
193
- await service.entities.user.patch({ id: userId, sk: "CURRENT" }).set(recomputed).go();
194
- }
195
- return { drift };
196
- }
197
- async function readRoleLevel(service, tenantId, roleAssignmentId) {
198
- const response = await service.entities.roleAssignment.get({ tenantId, id: roleAssignmentId, sk: "CURRENT" }).go();
199
- if (!response.data) {
200
- return void 0;
201
- }
202
- const resource = JSON.parse(response.data.resource);
203
- return extractRoleLevel(resource);
204
- }
205
-
206
- // src/data/operations/control/counters/counter-reconcile-driver.ts
207
- function driverContext(tenantId) {
208
- return {
209
- tenantId,
210
- workspaceId: "",
211
- date: (/* @__PURE__ */ new Date()).toISOString(),
212
- actorId: "counter-reconciliation",
213
- actorName: "Counter Reconciliation Job",
214
- actorType: "internal-system",
215
- source: "step-function"
216
- };
217
- }
218
- async function reconcileAllCountersOperation(params = {}) {
219
- const { tableName } = params;
220
- const drift = [];
221
- let tenantsScanned = 0;
222
- let workspacesScanned = 0;
223
- let usersScanned = 0;
224
- const tenants = await listTenantsOperation({
225
- context: driverContext(""),
226
- tableName,
227
- mode: "summary"
228
- });
229
- for (const tenant of tenants.entries) {
230
- tenantsScanned += 1;
231
- const tenantResult = await reconcileTenantCountersOperation({
232
- tenantId: tenant.id,
233
- tableName
234
- });
235
- drift.push(...tenantResult.drift);
236
- const workspaces = await listWorkspacesOperation({
237
- context: driverContext(tenant.id),
238
- tableName,
239
- mode: "summary"
240
- });
241
- for (const workspace of workspaces.entries) {
242
- workspacesScanned += 1;
243
- const workspaceResult = await reconcileWorkspaceCountersOperation({
244
- tenantId: tenant.id,
245
- workspaceId: workspace.id,
246
- tableName
247
- });
248
- drift.push(...workspaceResult.drift);
249
- }
250
- }
251
- const users = await listUsersOperation({
252
- context: driverContext(""),
253
- tableName,
254
- mode: "summary"
255
- });
256
- for (const user of users.entries) {
257
- usersScanned += 1;
258
- const userResult = await reconcileUserCountersOperation({
259
- userId: user.id,
260
- tableName
261
- });
262
- drift.push(...userResult.drift);
263
- }
264
- return {
265
- drift,
266
- scanned: {
267
- tenants: tenantsScanned,
268
- workspaces: workspacesScanned,
269
- users: usersScanned
270
- },
271
- countersCorrected: drift.length
272
- };
273
- }
274
-
275
17
  // src/workflows/control-plane/counter-reconciliation/counter-reconciliation.handler.ts
276
18
  var runCounterReconciliation = async (deps) => {
277
19
  const report = await deps.reconcileAll();
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/data/operations/control/counters/counter-reconcile-operation.ts","../src/data/operations/control/counters/counter-reconcile-driver.ts","../src/workflows/control-plane/counter-reconciliation/counter-reconciliation.handler.ts"],"sourcesContent":["import {\n COUNTER_TARGET,\n type CounterTarget,\n type TenantCounter,\n type UserCounter,\n type WorkspaceCounter,\n} from \"./counter-apply-operation\";\nimport { isAdminRoleAssignment } from \"./role-admin-classification\";\nimport { getDynamoControlService } from \"../../../dynamo/dynamo-control-service\";\nimport type { OpenHiContext } from \"../../../openhi-context\";\nimport { extractRoleLevel } from \"../control-event-publisher\";\nimport { countMembershipsByUserOperation } from \"../membership/membership-count-by-user-operation\";\nimport { membershipListByWorkspaceOperation } from \"../membership/membership-list-by-workspace-operation\";\nimport { listMembershipsOperation } from \"../membership/membership-list-operation\";\nimport { extractReferenceSlug } from \"../membership/membership-user-projection\";\nimport { roleAssignmentListByWorkspaceOperation } from \"../roleassignment/roleassignment-list-by-workspace-operation\";\nimport { listWorkspacesOperation } from \"../workspace/workspace-list-operation\";\n\n/**\n * ADR-028 counter reconciliation — recompute the denormalized\n * control-plane counters from canonical data and repair drift.\n *\n * The atomic-ADD path ({@link applyCounterDeltaOperation}) maintains the\n * counters incrementally off domain events, but events can be missed,\n * replayed, or arrive after a record was created without one (rows that\n * predate the counter work). This operation is the correctness backstop\n * ADR-028 names: it ignores the current counter value, recomputes the\n * true value from canonical records, and writes the absolute recomputed\n * value back with a DynamoDB `SET` (not `ADD`). A `SET` repairs both\n * directions of drift and backfills an absent / `0` attribute to its\n * correct value in one write.\n *\n * Counter semantics recomputed here MUST match {@link counterEventRouter}:\n *\n * - `Tenant.usersInTenant` = # tenant-scoped Memberships in the tenant\n * (membership with NO workspace reference).\n * - `Tenant.workspacesInTenant` = # Workspaces in the tenant.\n * - `Workspace.usersInWorkspace` = # workspace-scoped Memberships for the workspace.\n * - `Workspace.adminUsersInWorkspace` / `normalUsersInWorkspace` =\n * # workspace-scoped RoleAssignments for the workspace, bucketed by\n * {@link isAdminRoleAssignment} on the assignment's role level / role id.\n * - `User.tenantsForUser` = # tenant-scoped Memberships for the user.\n * - `User.workspacesForUser` = # workspace-scoped Memberships for the user.\n *\n * @see counter-apply-operation.ts — the incremental ADD path this reconciles against.\n * @see counter-event-router.ts — the event → counter semantics this mirrors.\n */\n\n/** One counter's old → new transition, recorded only when `old !== new`. */\nexport interface CounterDriftEntry {\n /** Which canonical entity the counter lives on. */\n readonly target: CounterTarget;\n /** Identity of the canonical record (tenantId for Tenant, workspaceId for Workspace, userId for User). */\n readonly id: string;\n /** Tenant the record belongs to (Workspace only; omitted for Tenant / User). */\n readonly tenantId?: string;\n /** The counter attribute name. */\n readonly counter: string;\n /** The value found on the record before reconciliation (0 when the attribute was absent). */\n readonly old: number;\n /** The recomputed-from-canonical value written back. */\n readonly new: number;\n}\n\n/** Result of reconciling one target record. */\nexport interface CounterReconcileResult {\n /** Every counter whose value changed (empty when the record was already correct). */\n readonly drift: Array<CounterDriftEntry>;\n}\n\n/** Coerce a possibly-absent counter attribute to a non-negative number (default 0). */\nfunction counterValue(value: unknown): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : 0;\n}\n\n/** Minimal actor context the underlying list operations need (they read only `tenantId`). */\nfunction reconcileContext(tenantId: string): OpenHiContext {\n return {\n tenantId,\n workspaceId: \"\",\n date: new Date().toISOString(),\n actorId: \"counter-reconciliation\",\n actorName: \"Counter Reconciliation Job\",\n actorType: \"internal-system\",\n source: \"step-function\",\n };\n}\n\n/**\n * Recompute and repair the two counters on one Tenant record.\n *\n * - `workspacesInTenant` is the workspace count from\n * {@link listWorkspacesOperation} (`mode: \"count\"`, GSI1 fan-out).\n * - `usersInTenant` is the number of *tenant-scoped* Memberships in the\n * tenant. Memberships have no tenant-partition projection, so this\n * enumerates the tenant's canonical Memberships via\n * {@link listMembershipsOperation} (`mode: \"full\"`) and counts the rows\n * whose `resource` carries no `workspace` reference — the same\n * tenant-vs-workspace discriminator the create path uses\n * ({@link extractReferenceSlug} on the `workspace` field).\n */\nexport async function reconcileTenantCountersOperation(params: {\n readonly tenantId: string;\n readonly tableName?: string;\n}): Promise<CounterReconcileResult> {\n const { tenantId, tableName } = params;\n const service = getDynamoControlService(tableName);\n const context = reconcileContext(tenantId);\n\n const workspacesResult = await listWorkspacesOperation({\n context,\n tableName,\n mode: \"count\",\n });\n const workspacesInTenant = workspacesResult.total;\n\n // Full enumeration of the tenant's canonical Memberships; discriminate\n // tenant-scoped (no workspace reference) from workspace-scoped by the\n // resource's `workspace` reference, mirroring the create path.\n const memberships = await listMembershipsOperation({\n context,\n tableName,\n mode: \"full\",\n });\n let usersInTenant = 0;\n for (const entry of memberships.entries) {\n const workspaceSlug = extractReferenceSlug(entry.resource, \"workspace\");\n if (workspaceSlug === undefined) {\n usersInTenant += 1;\n }\n }\n\n const current = await service.entities.tenant\n .get({ tenantId, sk: \"CURRENT\" })\n .go();\n\n const drift: Array<CounterDriftEntry> = [];\n const recomputed: Record<TenantCounter, number> = {\n usersInTenant,\n workspacesInTenant,\n };\n\n for (const counter of Object.keys(recomputed) as Array<TenantCounter>) {\n const oldValue = counterValue(current.data?.[counter]);\n const newValue = recomputed[counter];\n if (oldValue !== newValue) {\n drift.push({\n target: COUNTER_TARGET.Tenant,\n id: tenantId,\n counter,\n old: oldValue,\n new: newValue,\n });\n }\n }\n\n if (drift.length > 0) {\n await service.entities.tenant\n .patch({ tenantId, sk: \"CURRENT\" })\n .set(recomputed)\n .go();\n }\n\n return { drift };\n}\n\n/**\n * Recompute and repair the three counters on one Workspace record.\n *\n * - `usersInWorkspace` pages every workspace-scoped Membership via\n * {@link membershipListByWorkspaceOperation} (ADR-018 pattern #2).\n * - `adminUsersInWorkspace` / `normalUsersInWorkspace` page every\n * workspace-scoped RoleAssignment via\n * {@link roleAssignmentListByWorkspaceOperation} (pattern #9), then\n * classify each with {@link isAdminRoleAssignment}. The projection row\n * does not carry the ADR-019 role level (its `summary` is the\n * id/displayName/status projection), so each assignment's canonical\n * RoleAssignment resource is read to extract the role level via\n * {@link extractRoleLevel} — the same signal the create path publishes.\n * The projection's `roleId` is passed alongside as the fallback signal.\n */\nexport async function reconcileWorkspaceCountersOperation(params: {\n readonly tenantId: string;\n readonly workspaceId: string;\n readonly tableName?: string;\n}): Promise<CounterReconcileResult> {\n const { tenantId, workspaceId, tableName } = params;\n const service = getDynamoControlService(tableName);\n\n // usersInWorkspace — page every workspace-scoped membership.\n let usersInWorkspace = 0;\n let membershipCursor: string | null = null;\n do {\n const page = await membershipListByWorkspaceOperation({\n tenantId,\n workspaceId,\n cursor: membershipCursor,\n tableName,\n });\n usersInWorkspace += page.items.length;\n membershipCursor = page.cursor;\n } while (membershipCursor !== null);\n\n // admin/normal — page every workspace-scoped role assignment, then read\n // each canonical RoleAssignment to recover the role level for the\n // admin/normal split (the projection summary does not carry it).\n let adminUsersInWorkspace = 0;\n let normalUsersInWorkspace = 0;\n let roleAssignmentCursor: string | null = null;\n do {\n const page = await roleAssignmentListByWorkspaceOperation({\n tenantId,\n workspaceId,\n cursor: roleAssignmentCursor,\n tableName,\n });\n for (const item of page.items) {\n const roleLevel = await readRoleLevel(\n service,\n tenantId,\n item.roleAssignmentId,\n );\n if (isAdminRoleAssignment({ roleLevel, roleId: item.roleId })) {\n adminUsersInWorkspace += 1;\n } else {\n normalUsersInWorkspace += 1;\n }\n }\n roleAssignmentCursor = page.cursor;\n } while (roleAssignmentCursor !== null);\n\n const current = await service.entities.workspace\n .get({ tenantId, id: workspaceId, sk: \"CURRENT\" })\n .go();\n\n const drift: Array<CounterDriftEntry> = [];\n const recomputed: Record<WorkspaceCounter, number> = {\n usersInWorkspace,\n adminUsersInWorkspace,\n normalUsersInWorkspace,\n };\n\n for (const counter of Object.keys(recomputed) as Array<WorkspaceCounter>) {\n const oldValue = counterValue(current.data?.[counter]);\n const newValue = recomputed[counter];\n if (oldValue !== newValue) {\n drift.push({\n target: COUNTER_TARGET.Workspace,\n id: workspaceId,\n tenantId,\n counter,\n old: oldValue,\n new: newValue,\n });\n }\n }\n\n if (drift.length > 0) {\n await service.entities.workspace\n .patch({ tenantId, id: workspaceId, sk: \"CURRENT\" })\n .set(recomputed)\n .go();\n }\n\n return { drift };\n}\n\n/**\n * Recompute and repair the two counters on one User record.\n *\n * Both derive from {@link countMembershipsByUserOperation} over the\n * ADR-018 user-partition projection lanes: `tenantsForUser` from the\n * `tenant` lane (pattern #3), `workspacesForUser` from the `workspace`\n * lane (pattern #4).\n */\nexport async function reconcileUserCountersOperation(params: {\n readonly userId: string;\n readonly tableName?: string;\n}): Promise<CounterReconcileResult> {\n const { userId, tableName } = params;\n const service = getDynamoControlService(tableName);\n\n const tenantsForUser = await countMembershipsByUserOperation({\n userId,\n mode: \"tenant\",\n tableName,\n });\n const workspacesForUser = await countMembershipsByUserOperation({\n userId,\n mode: \"workspace\",\n tableName,\n });\n\n const current = await service.entities.user\n .get({ id: userId, sk: \"CURRENT\" })\n .go();\n\n const drift: Array<CounterDriftEntry> = [];\n const recomputed: Record<UserCounter, number> = {\n tenantsForUser,\n workspacesForUser,\n };\n\n for (const counter of Object.keys(recomputed) as Array<UserCounter>) {\n const oldValue = counterValue(current.data?.[counter]);\n const newValue = recomputed[counter];\n if (oldValue !== newValue) {\n drift.push({\n target: COUNTER_TARGET.User,\n id: userId,\n counter,\n old: oldValue,\n new: newValue,\n });\n }\n }\n\n if (drift.length > 0) {\n await service.entities.user\n .patch({ id: userId, sk: \"CURRENT\" })\n .set(recomputed)\n .go();\n }\n\n return { drift };\n}\n\n/**\n * Read the ADR-019 role level off a canonical RoleAssignment so the\n * admin/normal split classifies the same way the create path published\n * it. Returns `undefined` when the record or its code is missing — the\n * classifier then falls back to the `roleId` signal.\n */\nasync function readRoleLevel(\n service: ReturnType<typeof getDynamoControlService>,\n tenantId: string,\n roleAssignmentId: string,\n): Promise<string | undefined> {\n const response = await service.entities.roleAssignment\n .get({ tenantId, id: roleAssignmentId, sk: \"CURRENT\" })\n .go();\n if (!response.data) {\n return undefined;\n }\n const resource = JSON.parse(response.data.resource) as Record<\n string,\n unknown\n >;\n return extractRoleLevel(resource);\n}\n","import {\n type CounterDriftEntry,\n reconcileTenantCountersOperation,\n reconcileUserCountersOperation,\n reconcileWorkspaceCountersOperation,\n} from \"./counter-reconcile-operation\";\nimport type { OpenHiContext } from \"../../../openhi-context\";\nimport { listTenantsOperation } from \"../tenant/tenant-list-operation\";\nimport { listUsersOperation } from \"../user/user-list-operation\";\nimport { listWorkspacesOperation } from \"../workspace/workspace-list-operation\";\n\n/**\n * ADR-028 counter-reconciliation driver — walks every canonical Tenant,\n * Workspace, and User, reconciles each record's denormalized counters\n * against canonical data, and accumulates a single drift report.\n *\n * Enumeration reuses the existing GSI1-sharded list operations\n * (`summary` mode — ids only, no per-record BatchGet hydration):\n *\n * - All Tenants via {@link listTenantsOperation}.\n * - Per tenant, all Workspaces in that tenant via\n * {@link listWorkspacesOperation} (the workspace GSI1 partition is\n * tenant-scoped).\n * - All Users via {@link listUsersOperation}.\n *\n * Each record is then handed to the matching per-target recompute\n * ({@link reconcileTenantCountersOperation},\n * {@link reconcileWorkspaceCountersOperation},\n * {@link reconcileUserCountersOperation}), which owns the SET-back repair\n * and returns the per-counter old → new drift it corrected.\n *\n * @see counter-reconcile-operation.ts — the per-target recompute + repair.\n */\n\n/** Totals summarizing one reconciliation run, alongside the per-counter drift list. */\nexport interface CounterReconcileReport {\n /** Every counter that changed across every record, in walk order. */\n readonly drift: Array<CounterDriftEntry>;\n /** How many canonical records of each kind were scanned. */\n readonly scanned: {\n readonly tenants: number;\n readonly workspaces: number;\n readonly users: number;\n };\n /** Total number of individual counters corrected (== `drift.length`). */\n readonly countersCorrected: number;\n}\n\n/** Minimal actor context the list operations need (they read only `tenantId`). */\nfunction driverContext(tenantId: string): OpenHiContext {\n return {\n tenantId,\n workspaceId: \"\",\n date: new Date().toISOString(),\n actorId: \"counter-reconciliation\",\n actorName: \"Counter Reconciliation Job\",\n actorType: \"internal-system\",\n source: \"step-function\",\n };\n}\n\n/**\n * Run a full reconciliation sweep across every Tenant, Workspace, and\n * User. Returns the accumulated drift report; the per-target operations\n * have already written the repairs by the time this resolves.\n */\nexport async function reconcileAllCountersOperation(\n params: {\n readonly tableName?: string;\n } = {},\n): Promise<CounterReconcileReport> {\n const { tableName } = params;\n const drift: Array<CounterDriftEntry> = [];\n let tenantsScanned = 0;\n let workspacesScanned = 0;\n let usersScanned = 0;\n\n // Tenants (and, per tenant, the tenant's workspaces).\n const tenants = await listTenantsOperation({\n context: driverContext(\"\"),\n tableName,\n mode: \"summary\",\n });\n for (const tenant of tenants.entries) {\n tenantsScanned += 1;\n const tenantResult = await reconcileTenantCountersOperation({\n tenantId: tenant.id,\n tableName,\n });\n drift.push(...tenantResult.drift);\n\n const workspaces = await listWorkspacesOperation({\n context: driverContext(tenant.id),\n tableName,\n mode: \"summary\",\n });\n for (const workspace of workspaces.entries) {\n workspacesScanned += 1;\n const workspaceResult = await reconcileWorkspaceCountersOperation({\n tenantId: tenant.id,\n workspaceId: workspace.id,\n tableName,\n });\n drift.push(...workspaceResult.drift);\n }\n }\n\n // Users (platform-wide, no tenant scope).\n const users = await listUsersOperation({\n context: driverContext(\"\"),\n tableName,\n mode: \"summary\",\n });\n for (const user of users.entries) {\n usersScanned += 1;\n const userResult = await reconcileUserCountersOperation({\n userId: user.id,\n tableName,\n });\n drift.push(...userResult.drift);\n }\n\n return {\n drift,\n scanned: {\n tenants: tenantsScanned,\n workspaces: workspacesScanned,\n users: usersScanned,\n },\n countersCorrected: drift.length,\n };\n}\n","import {\n reconcileAllCountersOperation,\n type CounterReconcileReport,\n} from \"../../../data/operations/control/counters/counter-reconcile-driver\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/workflows/control-plane/counter-reconciliation/counter-reconciliation-handler.md\n *\n * ADR-028 counter-reconciliation job handler. Invoked on demand (manual\n * `aws lambda invoke`, an operator runbook, or a scheduled trigger) — not\n * an EventBridge consumer. Walks every canonical Tenant / Workspace /\n * User, recomputes the denormalized counters from canonical data, repairs\n * any drift with a `SET` write, and logs the per-counter old → new drift\n * report.\n *\n * Idempotent by construction: each per-target recompute writes the\n * absolute recomputed value, so a second run over unchanged data corrects\n * nothing and reports zero drift. That is why the job needs no dedup\n * circuit-breaker (unlike the event-driven counter-maintenance consumer,\n * whose atomic ADDs are not idempotent).\n */\n\n/** Dependency seam for tests; production wires the real driver. */\nexport interface CounterReconciliationDependencies {\n /**\n * Run the full reconciliation sweep. Defaults to\n * {@link reconcileAllCountersOperation}; tests inject a fake.\n */\n readonly reconcileAll: () => Promise<CounterReconcileReport>;\n}\n\n/**\n * Test-visible orchestrator. The production `handler` calls this with the\n * real driver; unit tests inject a fake. Returns the drift report so an\n * invoker (or test) can assert on what was corrected.\n */\nexport const runCounterReconciliation = async (\n deps: CounterReconciliationDependencies,\n): Promise<CounterReconcileReport> => {\n const report = await deps.reconcileAll();\n\n // Structured, loggable summary. One JSON line so a log query can pluck\n // the totals; the full per-counter drift list rides along for an audit.\n console.log(\n JSON.stringify({\n message: \"counter-reconciliation complete\",\n scanned: report.scanned,\n countersCorrected: report.countersCorrected,\n drift: report.drift,\n }),\n );\n\n return report;\n};\n\nconst productionDependencies = (): CounterReconciliationDependencies => ({\n reconcileAll: () => reconcileAllCountersOperation(),\n});\n\nexport const handler = async (): Promise<CounterReconcileReport> =>\n runCounterReconciliation(productionDependencies());\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/workflows/control-plane/counter-reconciliation/counter-reconciliation.handler.ts"],"sourcesContent":["import {\n reconcileAllCountersOperation,\n type CounterReconcileReport,\n} from \"../../../data/operations/control/counters/counter-reconcile-driver\";\n\n/**\n * @see sites/www-docs/content/packages/@openhi/constructs/workflows/control-plane/counter-reconciliation/counter-reconciliation-handler.md\n *\n * ADR-028 counter-reconciliation job handler. Invoked on demand (manual\n * `aws lambda invoke`, an operator runbook, or a scheduled trigger) — not\n * an EventBridge consumer. Walks every canonical Tenant / Workspace /\n * User, recomputes the denormalized counters from canonical data, repairs\n * any drift with a `SET` write, and logs the per-counter old → new drift\n * report.\n *\n * Idempotent by construction: each per-target recompute writes the\n * absolute recomputed value, so a second run over unchanged data corrects\n * nothing and reports zero drift. That is why the job needs no dedup\n * circuit-breaker (unlike the event-driven counter-maintenance consumer,\n * whose atomic ADDs are not idempotent).\n */\n\n/** Dependency seam for tests; production wires the real driver. */\nexport interface CounterReconciliationDependencies {\n /**\n * Run the full reconciliation sweep. Defaults to\n * {@link reconcileAllCountersOperation}; tests inject a fake.\n */\n readonly reconcileAll: () => Promise<CounterReconcileReport>;\n}\n\n/**\n * Test-visible orchestrator. The production `handler` calls this with the\n * real driver; unit tests inject a fake. Returns the drift report so an\n * invoker (or test) can assert on what was corrected.\n */\nexport const runCounterReconciliation = async (\n deps: CounterReconciliationDependencies,\n): Promise<CounterReconcileReport> => {\n const report = await deps.reconcileAll();\n\n // Structured, loggable summary. One JSON line so a log query can pluck\n // the totals; the full per-counter drift list rides along for an audit.\n console.log(\n JSON.stringify({\n message: \"counter-reconciliation complete\",\n scanned: report.scanned,\n countersCorrected: report.countersCorrected,\n drift: report.drift,\n }),\n );\n\n return report;\n};\n\nconst productionDependencies = (): CounterReconciliationDependencies => ({\n reconcileAll: () => reconcileAllCountersOperation(),\n});\n\nexport const handler = async (): Promise<CounterReconcileReport> =>\n runCounterReconciliation(productionDependencies());\n"],"mappings":";;;;;;;;;;;;;;;;;AAoCO,IAAM,2BAA2B,OACtC,SACoC;AACpC,QAAM,SAAS,MAAM,KAAK,aAAa;AAIvC,UAAQ;AAAA,IACN,KAAK,UAAU;AAAA,MACb,SAAS;AAAA,MACT,SAAS,OAAO;AAAA,MAChB,mBAAmB,OAAO;AAAA,MAC1B,OAAO,OAAO;AAAA,IAChB,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEA,IAAM,yBAAyB,OAA0C;AAAA,EACvE,cAAc,MAAM,8BAA8B;AACpD;AAEO,IAAM,UAAU,YACrB,yBAAyB,uBAAuB,CAAC;","names":[]}
package/lib/index.d.mts CHANGED
@@ -26,8 +26,8 @@ export { C as CascadeChunkInput, a as CascadeFinalizeInput, b as CascadeFinalize
26
26
  import { StateMachine } from 'aws-cdk-lib/aws-stepfunctions';
27
27
  export { B as BRIDGED_STATUSES, a as BridgedStatus, C as CLOUDFORMATION_EVENT_SOURCE, b as CLOUDFORMATION_STACK_STATUS_CHANGE_DETAIL_TYPE, c as CONTROL_EVENT_BUS_NAME_ENV_VAR, d as CloudFormationStackStatusChangeDetail, O as OPENHI_REPO_TAG_KEY_ENV_VAR, e as OPENHI_TAG_KEY_PREFIX_ENV_VAR, P as PLATFORM_DEPLOY_BRIDGE_ACTOR_SYSTEM } from './events-COI0BuMM.mjs';
28
28
  export { R as RENAME_CASCADE_CONSUMER_NAME, a as RENAME_CASCADE_DEFAULT_CONCURRENCY, b as RENAME_CASCADE_FAILED_THRESHOLD, c as RENAME_CASCADE_OPS_EVENT_BUS_ENV_VAR, d as RENAME_CASCADE_SLOW_THRESHOLD_SECONDS, e as RenameCascadeChunkInput, f as RenameCascadeFinalizeInput, g as RenameCascadeFinalizeOutput, h as RenameCascadeListInput, i as RenameCascadeListOutput } from './events-Da_cFgtc.mjs';
29
- import { Patient, Practitioner, Observation, Encounter, Account, Location, Organization, Coverage, Appointment, Condition, Procedure, Claim, PaymentNotice, Practitioner_Qualification } from '@openhi/types';
30
29
  import { O as OpenHiContext } from './openhi-context-CaBH8SFo.mjs';
30
+ import { Patient, Practitioner, Observation, Encounter, Account, Location, Organization, Coverage, Appointment, Condition, Procedure, Claim, PaymentNotice, Practitioner_Qualification } from '@openhi/types';
31
31
  export { D as DEMO_MIXED_TENANT_ID, a as DEMO_MIXED_WORKSPACE_PRIMARY_CARE_ID, b as DEMO_MIXED_WORKSPACE_WOUND_CARE_ID, c as DEMO_PERIOD, d as DEMO_PRIMARY_CARE_TENANT_ID, e as DEMO_PRIMARY_CARE_WORKSPACE_ID, f as DEMO_TENANT_SPECS, g as DEMO_URN_SYSTEM, h as DEMO_WOUND_CARE_TENANT_ID, i as DEMO_WOUND_CARE_WORKSPACE_ID, j as DEV_USERS, k as DemoDevUser, l as DemoTenantSpec, m as DemoWorkspaceSpec, O as ON_SITE_CLINIC_OKLAHOMA_WORKSPACE_ID, n as ON_SITE_CLINIC_TENANT_ID, o as ON_SITE_CLINIC_TEXAS_WORKSPACE_ID, p as ON_SITE_DEMO_TENANT_ID, q as ON_SITE_DEMO_WORKSPACE_ID, r as ON_SITE_MEDICAL_OKLAHOMA_WORKSPACE_ID, s as ON_SITE_MEDICAL_TENANT_ID, t as ON_SITE_MEDICAL_TEXAS_WORKSPACE_ID, u as ON_SITE_TESTERS, v as ON_SITE_UAT_TENANT_SPECS, w as ON_SITE_WOUNDS_OKLAHOMA_WORKSPACE_ID, x as ON_SITE_WOUNDS_TENANT_ID, y as ON_SITE_WOUNDS_TEXAS_WORKSPACE_ID, z as OPENHI_RESOURCE_URN_SYSTEM, A as OnSiteTester, P as PLACEHOLDER_TENANT_ID, B as PLACEHOLDER_TENANT_SPEC, C as PLACEHOLDER_WORKSPACE_ID, S as SEED_DEMO_DATA_CONSUMER_NAME, E as demoMembershipId, F as demoRoleAssignmentId, G as demoRolesForUserInTenant, H as demoScenarioIdentifier, I as onSiteRoleAssignmentId, J as onSiteTenantMembershipId, K as onSiteWorkspaceMembershipId, L as openhiResourceIdentifier } from './events-dO9nxnPa.mjs';
32
32
  export { P as PROVISION_DEFAULT_WORKSPACE_DETAIL_TYPE, a as ProvisionDefaultWorkspaceRequestedDetail, U as USER_ONBOARDING_EVENT_SOURCE, b as buildProvisionDefaultWorkspaceRequestedDetail } from './events-CVA3_eEB.mjs';
33
33
  export { ControlPlaneMembershipCreatedV1, ControlPlaneMembershipDeletedV1, ControlPlaneOwningDeleteCompleteV1, ControlPlaneOwningDeleteCompleteV1Detail, ControlPlaneOwningDeleteFailedV1, ControlPlaneOwningDeleteFailedV1Detail, ControlPlaneOwningDeleteV1, ControlPlaneOwningDeleteV1Detail, ControlPlaneRenameCompleteV1, ControlPlaneRenameCompleteV1Detail, ControlPlaneRenameFailedV1, ControlPlaneRenameFailedV1Detail, ControlPlaneRenameV1, ControlPlaneRenameV1Detail, ControlPlaneRoleAssignmentCreatedV1, ControlPlaneRoleAssignmentDeletedV1, ControlPlaneWorkspaceCreatedV1, ControlPlaneWorkspaceDeletedV1, OPENHI_DATA_SOURCE, OPENHI_OPS_SOURCE, OWNING_ENTITY_TYPE, OwningEntityType, PlatformDeploymentCompletedV1, PlatformSystemDataSeededV1, RENAMABLE_ENTITY_TYPE, RenamableEntityType } from '@openhi/workflows';
@@ -2188,6 +2188,121 @@ declare class CounterReconciliationWorkflow extends Construct {
2188
2188
  constructor(scope: Construct, props: CounterReconciliationWorkflowProps);
2189
2189
  }
2190
2190
 
2191
+ /**
2192
+ * Delete a Tenant by id. Idempotent — does not throw if the item does not exist.
2193
+ */
2194
+ interface DeleteTenantParams {
2195
+ context: OpenHiContext;
2196
+ id: string;
2197
+ tableName?: string;
2198
+ }
2199
+ declare function deleteTenantOperation(params: DeleteTenantParams): Promise<void>;
2200
+
2201
+ /**
2202
+ * Delete a Workspace by id. Idempotent — does not throw if the item does not exist.
2203
+ */
2204
+ interface DeleteWorkspaceParams {
2205
+ context: OpenHiContext;
2206
+ id: string;
2207
+ tableName?: string;
2208
+ }
2209
+ declare function deleteWorkspaceOperation(params: DeleteWorkspaceParams): Promise<void>;
2210
+
2211
+ /**
2212
+ * One-off ops cleanup script — issue #1346.
2213
+ *
2214
+ * Deletes the legacy *friendly-string-id* seed tenants and workspaces
2215
+ * that an earlier version of the seed generator created
2216
+ * (`on-site-demo-tenant`, `demo-wound-care-tenant`, …). The current
2217
+ * seed generator emits ULID-based ids (see `events.ts`), so these
2218
+ * string-id rows are stale leftovers — they are the no-name ("—")
2219
+ * tenants visible in the admin console.
2220
+ *
2221
+ * Scope guarantees:
2222
+ * - Deletes ONLY the hard-coded legacy string ids enumerated below.
2223
+ * ULID-based seed rows and the `placeholder-tenant-id` /
2224
+ * `placeholder-workspace-id` system sentinels are never touched.
2225
+ * - Workspaces are deleted before their parent tenants (children
2226
+ * before parents).
2227
+ * - Reuses {@link deleteWorkspaceOperation} / {@link deleteTenantOperation};
2228
+ * it never calls ElectroDB directly (see the data-layer-layout rule).
2229
+ *
2230
+ * INTENTIONALLY ORPHANED DATA-PLANE RECORDS: the data-plane FHIR
2231
+ * records (Patient / Practitioner / Observation / Encounter / Account /
2232
+ * …) seeded under these legacy tenants/workspaces are NOT cascaded by
2233
+ * this script. There is no production data anywhere (only branch dev
2234
+ * deployments and staging from `main`), and the orphaned data-plane
2235
+ * rows are slated for removal in a later full DB reset. Cascading them
2236
+ * here would add risk for no operational benefit. The control-plane
2237
+ * Tenant/Workspace rows are removed so the admin console stops showing
2238
+ * the no-name entries; the orphaned data-plane rows are accepted.
2239
+ *
2240
+ * The delete operations are idempotent (DynamoDB DeleteItem on a
2241
+ * missing key is a no-op), so a second run after a successful cleanup
2242
+ * is a no-op. Per-item failures are collected and aggregate-thrown so
2243
+ * a single transient error does not abort the rest of the run.
2244
+ */
2245
+
2246
+ /** Legacy friendly-string-id tenants to delete. */
2247
+ declare const LEGACY_STRING_ID_TENANTS: readonly ["on-site-demo-tenant", "demo-wound-care-tenant", "demo-primary-care-tenant", "demo-mixed-tenant"];
2248
+ /**
2249
+ * Legacy friendly-string-id workspaces to delete, each mapped to its
2250
+ * parent tenant id so the Workspace PK
2251
+ * `TID#{tenantId}#WORKSPACE#ID#{id}` can be reconstructed. The delete
2252
+ * operation derives the tenant from `context.tenantId`, so the parent
2253
+ * id is threaded through the context per workspace.
2254
+ */
2255
+ declare const LEGACY_STRING_ID_WORKSPACES: readonly [{
2256
+ readonly id: "on-site-demo-workspace";
2257
+ readonly tenantId: "on-site-demo-tenant";
2258
+ }, {
2259
+ readonly id: "demo-wound-care-workspace";
2260
+ readonly tenantId: "demo-wound-care-tenant";
2261
+ }, {
2262
+ readonly id: "demo-primary-care-workspace";
2263
+ readonly tenantId: "demo-primary-care-tenant";
2264
+ }, {
2265
+ readonly id: "demo-mixed-workspace-wound-care";
2266
+ readonly tenantId: "demo-mixed-tenant";
2267
+ }, {
2268
+ readonly id: "demo-mixed-workspace-primary-care";
2269
+ readonly tenantId: "demo-mixed-tenant";
2270
+ }];
2271
+ /** Env var that flips the script into log-only dry-run mode. */
2272
+ declare const CLEANUP_DRY_RUN_ENV_VAR = "CLEANUP_LEGACY_SEED_DRY_RUN";
2273
+ /**
2274
+ * Dependency seam mirroring the seed handler's arrangement: the
2275
+ * production wiring binds the real delete operations, while tests swap
2276
+ * in mocks to assert the exact set of calls.
2277
+ */
2278
+ interface CleanupLegacyStringIdSeedDependencies {
2279
+ readonly deleteWorkspace: typeof deleteWorkspaceOperation;
2280
+ readonly deleteTenant: typeof deleteTenantOperation;
2281
+ }
2282
+ interface CleanupLegacyStringIdSeedParams {
2283
+ /** Data-store table name passed through to the delete operations. */
2284
+ readonly tableName?: string;
2285
+ /**
2286
+ * When true, logs what WOULD be deleted without calling any delete
2287
+ * operation. Verification convenience only — not a required gate.
2288
+ */
2289
+ readonly dryRun?: boolean;
2290
+ /** Injected delete operations; defaults to the real operations. */
2291
+ readonly deps?: CleanupLegacyStringIdSeedDependencies;
2292
+ }
2293
+ /**
2294
+ * Delete the legacy string-id seed workspaces first, then their parent
2295
+ * tenants. Idempotent and resilient: missing rows are a no-op and any
2296
+ * per-item failure is collected then aggregate-thrown after the run.
2297
+ */
2298
+ declare const cleanupLegacyStringIdSeed: (params?: CleanupLegacyStringIdSeedParams) => Promise<void>;
2299
+ /**
2300
+ * Entry point for a manual `aws lambda invoke` / `node` run. Reads the
2301
+ * data-store table name from `DYNAMO_TABLE_NAME` and the dry-run flag
2302
+ * from {@link CLEANUP_DRY_RUN_ENV_VAR}.
2303
+ */
2304
+ declare const runCleanupLegacyStringIdSeed: () => Promise<void>;
2305
+
2191
2306
  /**
2192
2307
  * @see sites/www-docs/content/packages/@openhi/constructs/workflows/control-plane/seed-demo-data/data-plane-fixtures.md
2193
2308
  *
@@ -4205,4 +4320,4 @@ declare class RenameCascadeWorkflow extends Construct {
4205
4320
  constructor(scope: Construct, props: RenameCascadeWorkflowProps);
4206
4321
  }
4207
4322
 
4208
- export { ADMIN_DOMAIN_PREFIX, BLOCK_OCCURRENCES_PER_TEMPLATE, BLOCK_OCCURRENCE_WEEKS_FUTURE, BLOCK_OCCURRENCE_WEEKS_PAST, type BuildParameterNameProps, CLAIM_WORKFLOW_STATUS, CLAIM_WORKFLOW_STATUS_EXTENSION_URL, CLAIM_WORKFLOW_STATUS_LAST_TRANSITION_SUB_EXTENSION_URL, CLAIM_WORKFLOW_STATUS_VALUE_SUB_EXTENSION_URL, CONDITION_CLINICAL_STATUS_SYSTEM, COUNTER_MAINTENANCE_CONSUMER_NAME, COUNTER_MAINTENANCE_DETAIL_TYPES, COVERAGE_PAYOR_TYPE_SYSTEM, COVERAGE_QMB_STATUS_EXTENSION_URL, COVERAGE_VERIFICATION_DATE_EXTENSION_URL, CPT_SYSTEM, CREDENTIALING_STATUS, ChildHostedZone, type ChildHostedZoneProps, type ClaimWorkflowStatus, CognitoUserPool, CognitoUserPoolClient, CognitoUserPoolDomain, CognitoUserPoolKmsKey, type ComposeServiceDomainOptions, type ComputeBranchHashOptions, ControlEventBus, CounterMaintenanceLambda, type CounterMaintenanceLambdaProps, CounterMaintenanceWorkflow, type CounterMaintenanceWorkflowProps, CounterReconciliationLambda, type CounterReconciliationLambdaProps, CounterReconciliationWorkflow, type CounterReconciliationWorkflowProps, type CredentialingStatus, DATA_STORE_CHANGE_DETAIL_MAX_UTF8_BYTES, DATA_STORE_CHANGE_DETAIL_TYPE, DEFAULT_PREVIEW_EXPIRATION_DAYS, DEMO_DATA_PLANE_FIXTURES, DEV_CORS_ALLOW_ORIGINS, DIRECTOR_OF_NURSING_EMAIL_EXTENSION_URL, DIRECTOR_OF_NURSING_EXTENSION_URL, DIRECTOR_OF_NURSING_NAME_EXTENSION_URL, DIRECTOR_OF_NURSING_PHONE_EXTENSION_URL, DME_SUPPLIER_CATEGORY_CODE, DataEventBus, type DataEventBusOptions, DataStoreHistoricalArchive, type DataStoreHistoricalArchiveProps, DataStorePostgresReplica, type DataStorePostgresReplicaProps, type DemoWorkspaceDataPlaneFixtures, DiscoverableStringParameter, type DiscoverableStringParameterProps, DynamoDbDataStore, type DynamoDbDataStoreProps, ENCOUNTER_CLASS_FACILITY, ENCOUNTER_CLASS_HOME_HEALTH, ENCOUNTER_CLASS_SYSTEM, FHIR_ORGANIZATION_TYPE_SYSTEM, type FhirCurrentResourceChangeDetail, type GrantConsumerOptions, HOME_HEALTH_ELIGIBLE_EXTENSION_URL, HOME_HEALTH_VISITS_PAST, HOME_HEALTH_VISIT_CADENCE_DAYS_EXTENSION_URL, HOME_HEALTH_VISIT_CADENCE_OPTIONS, HOSPICE_EFFECTIVE_DATE_SUB_EXTENSION_URL, HOSPICE_STATUS_VALUE_SUB_EXTENSION_URL, HostingMode, INSURANCE_PAYOR_CATEGORY_CODE, INSURANCE_PAYOR_PLAN_TYPE_SYSTEM, type IsoDayOfWeek, LOCALHOST_OAUTH_CALLBACK_URLS, LOCALHOST_OAUTH_LOGOUT_URLS, LOINC_SYSTEM, ON_SITE_APPOINTMENT_TYPE_SYSTEM, ON_SITE_DEMO_BLOCK_CAPACITY_EXTENSION_URL, ON_SITE_DEMO_BLOCK_TEMPLATE_IDS, ON_SITE_DEMO_DIRECTORY_ORGANIZATIONS, ON_SITE_DEMO_DME_SUPPLIERS, ON_SITE_DEMO_DOCTORS, ON_SITE_DEMO_DOCTOR_IDS, ON_SITE_DEMO_FACILITIES, ON_SITE_DEMO_FACILITY_IDS, ON_SITE_DEMO_FIXTURES, ON_SITE_DEMO_INSURANCE_PAYORS, ON_SITE_DEMO_SCRIBES, ON_SITE_DEMO_SCRIBE_IDS, ON_SITE_DIRECTORY_CATEGORY_SYSTEM, ON_SITE_STAFF_ID_SYSTEM, OPENHI_TAG_SUFFIX_BRANCH_NAME, OPENHI_TAG_SUFFIX_REPO_NAME, OPENHI_TAG_SUFFIX_SERVICE_TYPE, OPENHI_TAG_SUFFIX_STAGE_TYPE, type OnSiteDemoEncounterMetadata, OpenHiApp, type OpenHiAppProps, OpenHiAuthService, type OpenHiAuthServiceProps, OpenHiDataService, type OpenHiDataServiceProps, OpenHiEnvironment, type OpenHiEnvironmentProps, OpenHiGlobalService, type OpenHiGlobalServiceProps, OpenHiGraphqlService, type OpenHiGraphqlServiceProps, OpenHiRestApiService, type OpenHiRestApiServiceProps, OpenHiService, type OpenHiServiceProps, type OpenHiServiceType, OpenHiStage, type OpenHiStageProps, OpenHiWebsiteService, type OpenHiWebsiteServiceProps, OpsEventBus, OwningDeleteCascadeLambdas, type OwningDeleteCascadeLambdasProps, OwningDeleteCascadeWorkflow, type OwningDeleteCascadeWorkflowProps, PATIENT_ASSIGNED_BLOCK_TEMPLATE_EXTENSION_URL, PATIENT_ASSIGNED_HOME_HEALTH_PROVIDER_EXTENSION_URL, PATIENT_DEFAULT_CARE_LOCATION_EXTENSION_URL, PATIENT_DEFAULT_CARE_SETTING_EXTENSION_URL, PATIENT_HOSPICE_STATUS_EXTENSION_URL, PATIENT_RESIDENCY_ADMISSION_DATE_EXTENSION_URL, PATIENT_RESIDENCY_ROOM_EXTENSION_URL, PAYMENT_STATUS, PAYMENT_STATUS_SYSTEM, PAYOR_PLAN_TYPE_COMMERCIAL, PAYOR_PLAN_TYPE_MEDICARE, PAYOR_PLAN_TYPE_MEDICARE_ADVANTAGE, PAYOR_TYPE_COMMERCIAL, PAYOR_TYPE_MEDICARE, PAYOR_TYPE_MEDICARE_ADVANTAGE, PER_BRANCH_PREVIEW_PREFIX, PLATFORM_SCOPE_TENANT_ID, POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME, POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME, POSTGRES_REPLICA_SECRET_ARN_SSM_NAME, PRACTITIONER_CREDENTIALING_EXTENSION_URL, PRACTITIONER_CREDENTIALING_STATE_SUB_EXTENSION_URL, PRACTITIONER_CREDENTIALING_STATUS_SUB_EXTENSION_URL, PRACTITIONER_ROLE_PHYSICIAN, PRACTITIONER_ROLE_SCRIBE, type PaymentStatus, type PayorPlanType, PerBranchHostname, type PerBranchHostnameProps, PlatformDeployBridge, PlatformDeployBridgeLambda, type PlatformDeployBridgeLambdaProps, type PlatformDeployBridgeProps, PostAuthenticationLambda, PostConfirmationLambda, type PostConfirmationLambdaProps, type PractitionerCredentialingSpec, PreTokenGenerationLambda, type PreTokenGenerationLambdaProps, ProvisionDefaultWorkspaceLambda, type ProvisionDefaultWorkspaceLambdaProps, QMB_EFFECTIVE_DATE_SUB_EXTENSION_URL, QMB_STATUS_VALUE_SUB_EXTENSION_URL, REST_API_BASE_URL_SSM_NAME, REST_API_DOMAIN_NAME_SSM_NAME, RenameCascadeLambdas, type RenameCascadeLambdasProps, RenameCascadeWorkflow, type RenameCascadeWorkflowProps, RootGraphqlApi, type RootGraphqlApiProps, RootHostedZone, RootHttpApi, type RootHttpApiProps, RootWildcardCertificate, SEED_SYSTEM_DATA_ACTOR_SYSTEM, SEED_SYSTEM_DATA_CONSUMER_NAME, SEED_SYSTEM_DATA_CONTROL_BUS_ENV_VAR, SNOMED_SYSTEM, SSM_PARAM_NAME_FULL_DOMAIN, STATE_MEDICAL_LICENSE_SYSTEM, STATIC_HOSTING_SERVICE_TYPE, SeedDemoDataLambda, type SeedDemoDataLambdaProps, SeedDemoDataWorkflow, type SeedDemoDataWorkflowProps, SeedSystemDataLambda, type SeedSystemDataLambdaProps, SeedSystemDataWorkflow, type SeedSystemDataWorkflowProps, StaticContent, type StaticContentProps, StaticHosting, type StaticHostingProps, TOTAL_HOME_HEALTH_PATIENTS, US_NPI_SYSTEM, UserOnboardingWorkflow, type UserOnboardingWorkflowProps, WOUND_DEPTH_CODE, WOUND_EXAM_PANEL_CODE, WOUND_EXAM_PANEL_DISPLAY, WOUND_LENGTH_CODE, WOUND_STATUS_CODE, WOUND_WIDTH_CODE, WorkflowDedupConsumerNameInvalidError, WorkflowDedupTable, WorkflowDedupTableDuplicateError, type WorkflowDedupTableProps, __resetOnSiteDemoClaimCachesForTests, __resetOnSiteDemoEncounterCachesForTests, buildCredentialingQualifications, buildFhirCurrentResourceChangeDetail, buildOnSiteDemoBlockAppointments, buildOnSiteDemoClaims, buildOnSiteDemoEncounters, buildOnSiteDemoFacilityCoverages, buildOnSiteDemoFacilityPatients, buildOnSiteDemoHomeHealthCoverages, buildOnSiteDemoHomeHealthPatients, buildOnSiteDemoPaymentNotices, buildOnSiteDemoWoundConditions, buildOnSiteDemoWoundObservations, buildOnSiteDemoWoundProcedures, computeBranchHash, facilityPatientsForBlock, findOnSiteDemoBlockTemplate, findOnSiteDemoFacilityPatientBlock, findOnSiteDemoHomeHealthPatientProvider, findOnSiteDemoHomeHealthPatientVisitCadenceDays, getDynamoDbDataStoreTableName, getPostgresReplicaSchemaName, getWorkflowDedupTableName, homeHealthEligibleDoctors, onSiteDemoBilledEncounterIds, onSiteDemoClaimIds, onSiteDemoDmeSupplierIds, onSiteDemoEncounterIds, onSiteDemoEncounterMetadata, onSiteDemoEncountersForPatient, onSiteDemoFacilityPatientIds, onSiteDemoHomeHealthPatientIds, onSiteDemoInsurancePayorIds, onSiteDemoIntakeOnlyFacilityPatientIds, onSiteDemoIntakeOnlyHomeHealthPatientIds, onSiteDemoPaymentNoticeIds, onSiteDemoScheduledFacilityPatientIds, onSiteDemoScheduledHomeHealthPatientIds, onSiteDemoUnbilledEncounterIds, onSiteDemoWoundBearingPatientIds, onSiteDemoWoundProcedurePatientIds, openHiTagKey, practitionerCredentialingForDoctor, practitionerCredentialingForState, woundConditionIdForPatient };
4323
+ export { ADMIN_DOMAIN_PREFIX, BLOCK_OCCURRENCES_PER_TEMPLATE, BLOCK_OCCURRENCE_WEEKS_FUTURE, BLOCK_OCCURRENCE_WEEKS_PAST, type BuildParameterNameProps, CLAIM_WORKFLOW_STATUS, CLAIM_WORKFLOW_STATUS_EXTENSION_URL, CLAIM_WORKFLOW_STATUS_LAST_TRANSITION_SUB_EXTENSION_URL, CLAIM_WORKFLOW_STATUS_VALUE_SUB_EXTENSION_URL, CLEANUP_DRY_RUN_ENV_VAR, CONDITION_CLINICAL_STATUS_SYSTEM, COUNTER_MAINTENANCE_CONSUMER_NAME, COUNTER_MAINTENANCE_DETAIL_TYPES, COVERAGE_PAYOR_TYPE_SYSTEM, COVERAGE_QMB_STATUS_EXTENSION_URL, COVERAGE_VERIFICATION_DATE_EXTENSION_URL, CPT_SYSTEM, CREDENTIALING_STATUS, ChildHostedZone, type ChildHostedZoneProps, type ClaimWorkflowStatus, type CleanupLegacyStringIdSeedDependencies, type CleanupLegacyStringIdSeedParams, CognitoUserPool, CognitoUserPoolClient, CognitoUserPoolDomain, CognitoUserPoolKmsKey, type ComposeServiceDomainOptions, type ComputeBranchHashOptions, ControlEventBus, CounterMaintenanceLambda, type CounterMaintenanceLambdaProps, CounterMaintenanceWorkflow, type CounterMaintenanceWorkflowProps, CounterReconciliationLambda, type CounterReconciliationLambdaProps, CounterReconciliationWorkflow, type CounterReconciliationWorkflowProps, type CredentialingStatus, DATA_STORE_CHANGE_DETAIL_MAX_UTF8_BYTES, DATA_STORE_CHANGE_DETAIL_TYPE, DEFAULT_PREVIEW_EXPIRATION_DAYS, DEMO_DATA_PLANE_FIXTURES, DEV_CORS_ALLOW_ORIGINS, DIRECTOR_OF_NURSING_EMAIL_EXTENSION_URL, DIRECTOR_OF_NURSING_EXTENSION_URL, DIRECTOR_OF_NURSING_NAME_EXTENSION_URL, DIRECTOR_OF_NURSING_PHONE_EXTENSION_URL, DME_SUPPLIER_CATEGORY_CODE, DataEventBus, type DataEventBusOptions, DataStoreHistoricalArchive, type DataStoreHistoricalArchiveProps, DataStorePostgresReplica, type DataStorePostgresReplicaProps, type DemoWorkspaceDataPlaneFixtures, DiscoverableStringParameter, type DiscoverableStringParameterProps, DynamoDbDataStore, type DynamoDbDataStoreProps, ENCOUNTER_CLASS_FACILITY, ENCOUNTER_CLASS_HOME_HEALTH, ENCOUNTER_CLASS_SYSTEM, FHIR_ORGANIZATION_TYPE_SYSTEM, type FhirCurrentResourceChangeDetail, type GrantConsumerOptions, HOME_HEALTH_ELIGIBLE_EXTENSION_URL, HOME_HEALTH_VISITS_PAST, HOME_HEALTH_VISIT_CADENCE_DAYS_EXTENSION_URL, HOME_HEALTH_VISIT_CADENCE_OPTIONS, HOSPICE_EFFECTIVE_DATE_SUB_EXTENSION_URL, HOSPICE_STATUS_VALUE_SUB_EXTENSION_URL, HostingMode, INSURANCE_PAYOR_CATEGORY_CODE, INSURANCE_PAYOR_PLAN_TYPE_SYSTEM, type IsoDayOfWeek, LEGACY_STRING_ID_TENANTS, LEGACY_STRING_ID_WORKSPACES, LOCALHOST_OAUTH_CALLBACK_URLS, LOCALHOST_OAUTH_LOGOUT_URLS, LOINC_SYSTEM, ON_SITE_APPOINTMENT_TYPE_SYSTEM, ON_SITE_DEMO_BLOCK_CAPACITY_EXTENSION_URL, ON_SITE_DEMO_BLOCK_TEMPLATE_IDS, ON_SITE_DEMO_DIRECTORY_ORGANIZATIONS, ON_SITE_DEMO_DME_SUPPLIERS, ON_SITE_DEMO_DOCTORS, ON_SITE_DEMO_DOCTOR_IDS, ON_SITE_DEMO_FACILITIES, ON_SITE_DEMO_FACILITY_IDS, ON_SITE_DEMO_FIXTURES, ON_SITE_DEMO_INSURANCE_PAYORS, ON_SITE_DEMO_SCRIBES, ON_SITE_DEMO_SCRIBE_IDS, ON_SITE_DIRECTORY_CATEGORY_SYSTEM, ON_SITE_STAFF_ID_SYSTEM, OPENHI_TAG_SUFFIX_BRANCH_NAME, OPENHI_TAG_SUFFIX_REPO_NAME, OPENHI_TAG_SUFFIX_SERVICE_TYPE, OPENHI_TAG_SUFFIX_STAGE_TYPE, type OnSiteDemoEncounterMetadata, OpenHiApp, type OpenHiAppProps, OpenHiAuthService, type OpenHiAuthServiceProps, OpenHiDataService, type OpenHiDataServiceProps, OpenHiEnvironment, type OpenHiEnvironmentProps, OpenHiGlobalService, type OpenHiGlobalServiceProps, OpenHiGraphqlService, type OpenHiGraphqlServiceProps, OpenHiRestApiService, type OpenHiRestApiServiceProps, OpenHiService, type OpenHiServiceProps, type OpenHiServiceType, OpenHiStage, type OpenHiStageProps, OpenHiWebsiteService, type OpenHiWebsiteServiceProps, OpsEventBus, OwningDeleteCascadeLambdas, type OwningDeleteCascadeLambdasProps, OwningDeleteCascadeWorkflow, type OwningDeleteCascadeWorkflowProps, PATIENT_ASSIGNED_BLOCK_TEMPLATE_EXTENSION_URL, PATIENT_ASSIGNED_HOME_HEALTH_PROVIDER_EXTENSION_URL, PATIENT_DEFAULT_CARE_LOCATION_EXTENSION_URL, PATIENT_DEFAULT_CARE_SETTING_EXTENSION_URL, PATIENT_HOSPICE_STATUS_EXTENSION_URL, PATIENT_RESIDENCY_ADMISSION_DATE_EXTENSION_URL, PATIENT_RESIDENCY_ROOM_EXTENSION_URL, PAYMENT_STATUS, PAYMENT_STATUS_SYSTEM, PAYOR_PLAN_TYPE_COMMERCIAL, PAYOR_PLAN_TYPE_MEDICARE, PAYOR_PLAN_TYPE_MEDICARE_ADVANTAGE, PAYOR_TYPE_COMMERCIAL, PAYOR_TYPE_MEDICARE, PAYOR_TYPE_MEDICARE_ADVANTAGE, PER_BRANCH_PREVIEW_PREFIX, PLATFORM_SCOPE_TENANT_ID, POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME, POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME, POSTGRES_REPLICA_SECRET_ARN_SSM_NAME, PRACTITIONER_CREDENTIALING_EXTENSION_URL, PRACTITIONER_CREDENTIALING_STATE_SUB_EXTENSION_URL, PRACTITIONER_CREDENTIALING_STATUS_SUB_EXTENSION_URL, PRACTITIONER_ROLE_PHYSICIAN, PRACTITIONER_ROLE_SCRIBE, type PaymentStatus, type PayorPlanType, PerBranchHostname, type PerBranchHostnameProps, PlatformDeployBridge, PlatformDeployBridgeLambda, type PlatformDeployBridgeLambdaProps, type PlatformDeployBridgeProps, PostAuthenticationLambda, PostConfirmationLambda, type PostConfirmationLambdaProps, type PractitionerCredentialingSpec, PreTokenGenerationLambda, type PreTokenGenerationLambdaProps, ProvisionDefaultWorkspaceLambda, type ProvisionDefaultWorkspaceLambdaProps, QMB_EFFECTIVE_DATE_SUB_EXTENSION_URL, QMB_STATUS_VALUE_SUB_EXTENSION_URL, REST_API_BASE_URL_SSM_NAME, REST_API_DOMAIN_NAME_SSM_NAME, RenameCascadeLambdas, type RenameCascadeLambdasProps, RenameCascadeWorkflow, type RenameCascadeWorkflowProps, RootGraphqlApi, type RootGraphqlApiProps, RootHostedZone, RootHttpApi, type RootHttpApiProps, RootWildcardCertificate, SEED_SYSTEM_DATA_ACTOR_SYSTEM, SEED_SYSTEM_DATA_CONSUMER_NAME, SEED_SYSTEM_DATA_CONTROL_BUS_ENV_VAR, SNOMED_SYSTEM, SSM_PARAM_NAME_FULL_DOMAIN, STATE_MEDICAL_LICENSE_SYSTEM, STATIC_HOSTING_SERVICE_TYPE, SeedDemoDataLambda, type SeedDemoDataLambdaProps, SeedDemoDataWorkflow, type SeedDemoDataWorkflowProps, SeedSystemDataLambda, type SeedSystemDataLambdaProps, SeedSystemDataWorkflow, type SeedSystemDataWorkflowProps, StaticContent, type StaticContentProps, StaticHosting, type StaticHostingProps, TOTAL_HOME_HEALTH_PATIENTS, US_NPI_SYSTEM, UserOnboardingWorkflow, type UserOnboardingWorkflowProps, WOUND_DEPTH_CODE, WOUND_EXAM_PANEL_CODE, WOUND_EXAM_PANEL_DISPLAY, WOUND_LENGTH_CODE, WOUND_STATUS_CODE, WOUND_WIDTH_CODE, WorkflowDedupConsumerNameInvalidError, WorkflowDedupTable, WorkflowDedupTableDuplicateError, type WorkflowDedupTableProps, __resetOnSiteDemoClaimCachesForTests, __resetOnSiteDemoEncounterCachesForTests, buildCredentialingQualifications, buildFhirCurrentResourceChangeDetail, buildOnSiteDemoBlockAppointments, buildOnSiteDemoClaims, buildOnSiteDemoEncounters, buildOnSiteDemoFacilityCoverages, buildOnSiteDemoFacilityPatients, buildOnSiteDemoHomeHealthCoverages, buildOnSiteDemoHomeHealthPatients, buildOnSiteDemoPaymentNotices, buildOnSiteDemoWoundConditions, buildOnSiteDemoWoundObservations, buildOnSiteDemoWoundProcedures, cleanupLegacyStringIdSeed, computeBranchHash, facilityPatientsForBlock, findOnSiteDemoBlockTemplate, findOnSiteDemoFacilityPatientBlock, findOnSiteDemoHomeHealthPatientProvider, findOnSiteDemoHomeHealthPatientVisitCadenceDays, getDynamoDbDataStoreTableName, getPostgresReplicaSchemaName, getWorkflowDedupTableName, homeHealthEligibleDoctors, onSiteDemoBilledEncounterIds, onSiteDemoClaimIds, onSiteDemoDmeSupplierIds, onSiteDemoEncounterIds, onSiteDemoEncounterMetadata, onSiteDemoEncountersForPatient, onSiteDemoFacilityPatientIds, onSiteDemoHomeHealthPatientIds, onSiteDemoInsurancePayorIds, onSiteDemoIntakeOnlyFacilityPatientIds, onSiteDemoIntakeOnlyHomeHealthPatientIds, onSiteDemoPaymentNoticeIds, onSiteDemoScheduledFacilityPatientIds, onSiteDemoScheduledHomeHealthPatientIds, onSiteDemoUnbilledEncounterIds, onSiteDemoWoundBearingPatientIds, onSiteDemoWoundProcedurePatientIds, openHiTagKey, practitionerCredentialingForDoctor, practitionerCredentialingForState, runCleanupLegacyStringIdSeed, woundConditionIdForPatient };