@openhi/constructs 0.0.159 → 0.0.161
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/lib/{chunk-HQ67J7BP.mjs → chunk-5S6VFBLT.mjs} +12 -70
- package/lib/chunk-5S6VFBLT.mjs.map +1 -0
- package/lib/{chunk-MVQWAIMC.mjs → chunk-6BB4CRSS.mjs} +3 -312
- package/lib/chunk-6BB4CRSS.mjs.map +1 -0
- package/lib/{chunk-WPCBVDFZ.mjs → chunk-76UM2LQ5.mjs} +2 -2
- package/lib/chunk-7TRO2STL.mjs +4616 -0
- package/lib/chunk-7TRO2STL.mjs.map +1 -0
- package/lib/chunk-BUAYVN3C.mjs +87 -0
- package/lib/chunk-BUAYVN3C.mjs.map +1 -0
- package/lib/{chunk-23PUSHBV.mjs → chunk-D2Y6DDOC.mjs} +2 -2
- package/lib/chunk-DWSWCUZR.mjs +123 -0
- package/lib/chunk-DWSWCUZR.mjs.map +1 -0
- package/lib/{chunk-VZCPGQXA.mjs → chunk-EUIP2U5F.mjs} +69 -1
- package/lib/{chunk-VZCPGQXA.mjs.map → chunk-EUIP2U5F.mjs.map} +1 -1
- package/lib/chunk-GJTPXJKD.mjs +46 -0
- package/lib/chunk-GJTPXJKD.mjs.map +1 -0
- package/lib/chunk-I6LUPJUY.mjs +61 -0
- package/lib/chunk-I6LUPJUY.mjs.map +1 -0
- package/lib/{chunk-KR2Y2CVQ.mjs → chunk-KA3OMP3X.mjs} +2 -2
- package/lib/{chunk-ZM4GDHHC.mjs → chunk-KMEWULMX.mjs} +51 -3
- package/lib/chunk-KMEWULMX.mjs.map +1 -0
- package/lib/chunk-LKKLO66E.mjs +25 -0
- package/lib/chunk-LKKLO66E.mjs.map +1 -0
- package/lib/{chunk-CFJDATDK.mjs → chunk-MLFMW5IF.mjs} +43 -9
- package/lib/chunk-MLFMW5IF.mjs.map +1 -0
- package/lib/chunk-O5VQWB6U.mjs +315 -0
- package/lib/chunk-O5VQWB6U.mjs.map +1 -0
- package/lib/{chunk-7BQHLC7U.mjs → chunk-P3CTZWC2.mjs} +8 -40
- package/lib/chunk-P3CTZWC2.mjs.map +1 -0
- package/lib/chunk-P3NFCKTZ.mjs +502 -0
- package/lib/chunk-P3NFCKTZ.mjs.map +1 -0
- package/lib/{chunk-M7Y3BOQW.mjs → chunk-Q3MKITPY.mjs} +5 -5
- package/lib/chunk-Q64MOYJ7.mjs +218 -0
- package/lib/chunk-Q64MOYJ7.mjs.map +1 -0
- package/lib/chunk-RQKJNMX5.mjs +89 -0
- package/lib/chunk-RQKJNMX5.mjs.map +1 -0
- package/lib/{chunk-ZWSGM6PZ.mjs → chunk-SD7J3N3C.mjs} +2 -2
- package/lib/{chunk-7RZHFI77.mjs → chunk-VESULYQQ.mjs} +2 -2
- package/lib/{chunk-AOSEKL7U.mjs → chunk-WOTU36P3.mjs} +6 -103
- package/lib/chunk-WOTU36P3.mjs.map +1 -0
- package/lib/{chunk-X5E4YJGZ.mjs → chunk-YPTJJ35S.mjs} +2 -2
- package/lib/counter-apply-operation-DZM3MIDm.d.mts +63 -0
- package/lib/counter-apply-operation-DZM3MIDm.d.ts +63 -0
- package/lib/counter-maintenance.handler.d.mts +38 -0
- package/lib/counter-maintenance.handler.d.ts +38 -0
- package/lib/counter-maintenance.handler.js +2885 -0
- package/lib/counter-maintenance.handler.js.map +1 -0
- package/lib/counter-maintenance.handler.mjs +180 -0
- package/lib/counter-maintenance.handler.mjs.map +1 -0
- package/lib/counter-reconciliation.handler.d.mts +116 -0
- package/lib/counter-reconciliation.handler.d.ts +116 -0
- package/lib/counter-reconciliation.handler.js +3324 -0
- package/lib/counter-reconciliation.handler.js.map +1 -0
- package/lib/counter-reconciliation.handler.mjs +295 -0
- package/lib/counter-reconciliation.handler.mjs.map +1 -0
- package/lib/data-store-postgres-replication.handler.js +50 -2
- package/lib/data-store-postgres-replication.handler.js.map +1 -1
- package/lib/data-store-postgres-replication.handler.mjs +2 -2
- package/lib/delete-chunk.handler.js +118 -2
- package/lib/delete-chunk.handler.js.map +1 -1
- package/lib/delete-chunk.handler.mjs +3 -3
- package/lib/{events-DTgo2dcW.d.mts → events-TG654e7L.d.mts} +68 -19
- package/lib/{events-DTgo2dcW.d.ts → events-TG654e7L.d.ts} +68 -19
- package/lib/finalize.handler.js +50 -2
- package/lib/finalize.handler.js.map +1 -1
- package/lib/finalize.handler.mjs +4 -4
- package/lib/firehose-archive-transform.handler.js +50 -2
- package/lib/firehose-archive-transform.handler.js.map +1 -1
- package/lib/firehose-archive-transform.handler.mjs +2 -2
- package/lib/index.d.mts +1283 -4
- package/lib/index.d.ts +1389 -24
- package/lib/index.js +4113 -320
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +602 -195
- package/lib/index.mjs.map +1 -1
- package/lib/list-chunks.handler.js +118 -2
- package/lib/list-chunks.handler.js.map +1 -1
- package/lib/list-chunks.handler.mjs +3 -3
- package/lib/platform-deploy-bridge.handler.js +50 -2
- package/lib/platform-deploy-bridge.handler.js.map +1 -1
- package/lib/platform-deploy-bridge.handler.mjs +1 -1
- package/lib/pre-token-generation.handler.js +68 -0
- package/lib/pre-token-generation.handler.js.map +1 -1
- package/lib/pre-token-generation.handler.mjs +9 -5
- package/lib/pre-token-generation.handler.mjs.map +1 -1
- package/lib/provision-default-workspace.handler.js +887 -4
- package/lib/provision-default-workspace.handler.js.map +1 -1
- package/lib/provision-default-workspace.handler.mjs +14 -9
- package/lib/provision-default-workspace.handler.mjs.map +1 -1
- package/lib/rename-finalize.handler.js +50 -2
- package/lib/rename-finalize.handler.js.map +1 -1
- package/lib/rename-finalize.handler.mjs +2 -2
- package/lib/rename-list-targets.handler.js +118 -2
- package/lib/rename-list-targets.handler.js.map +1 -1
- package/lib/rename-list-targets.handler.mjs +11 -9
- package/lib/rename-list-targets.handler.mjs.map +1 -1
- package/lib/rename-rewrite-chunk.handler.js +68 -0
- package/lib/rename-rewrite-chunk.handler.js.map +1 -1
- package/lib/rename-rewrite-chunk.handler.mjs +2 -2
- package/lib/rest-api-lambda.handler.js +1454 -251
- package/lib/rest-api-lambda.handler.js.map +1 -1
- package/lib/rest-api-lambda.handler.mjs +673 -821
- package/lib/rest-api-lambda.handler.mjs.map +1 -1
- package/lib/seed-demo-data.handler.d.mts +1 -1
- package/lib/seed-demo-data.handler.d.ts +1 -1
- package/lib/seed-demo-data.handler.js +4004 -201
- package/lib/seed-demo-data.handler.js.map +1 -1
- package/lib/seed-demo-data.handler.mjs +10 -7
- package/lib/seed-system-data.handler.js +118 -2
- package/lib/seed-system-data.handler.js.map +1 -1
- package/lib/seed-system-data.handler.mjs +5 -5
- package/package.json +1 -1
- package/lib/chunk-7BQHLC7U.mjs.map +0 -1
- package/lib/chunk-AOSEKL7U.mjs.map +0 -1
- package/lib/chunk-BQMJSDOD.mjs +0 -1136
- package/lib/chunk-BQMJSDOD.mjs.map +0 -1
- package/lib/chunk-CFJDATDK.mjs.map +0 -1
- package/lib/chunk-E6MCKJVS.mjs +0 -212
- package/lib/chunk-E6MCKJVS.mjs.map +0 -1
- package/lib/chunk-HQ67J7BP.mjs.map +0 -1
- package/lib/chunk-MVQWAIMC.mjs.map +0 -1
- package/lib/chunk-ZM4GDHHC.mjs.map +0 -1
- /package/lib/{chunk-WPCBVDFZ.mjs.map → chunk-76UM2LQ5.mjs.map} +0 -0
- /package/lib/{chunk-23PUSHBV.mjs.map → chunk-D2Y6DDOC.mjs.map} +0 -0
- /package/lib/{chunk-KR2Y2CVQ.mjs.map → chunk-KA3OMP3X.mjs.map} +0 -0
- /package/lib/{chunk-M7Y3BOQW.mjs.map → chunk-Q3MKITPY.mjs.map} +0 -0
- /package/lib/{chunk-ZWSGM6PZ.mjs.map → chunk-SD7J3N3C.mjs.map} +0 -0
- /package/lib/{chunk-7RZHFI77.mjs.map → chunk-VESULYQQ.mjs.map} +0 -0
- /package/lib/{chunk-X5E4YJGZ.mjs.map → chunk-YPTJJ35S.mjs.map} +0 -0
|
@@ -1,62 +1,8 @@
|
|
|
1
|
-
// src/data/operations/control/membership/membership-
|
|
1
|
+
// src/data/operations/control/membership/membership-workspace-projection.ts
|
|
2
2
|
import { normalizeLabel } from "@openhi/types";
|
|
3
3
|
var MISSING_NAME_SENTINEL = "-";
|
|
4
|
-
function buildMembershipUserProjectionSkTenantLane(params) {
|
|
5
|
-
const normalizedTenantName = typeof params.denormalizedTenantName === "string" && params.denormalizedTenantName.length > 0 ? normalizeLabel(params.denormalizedTenantName) : MISSING_NAME_SENTINEL;
|
|
6
|
-
return `MEMBERSHIP#TENANT#${normalizedTenantName}#TID#${params.tenantId}#${params.membershipId}`;
|
|
7
|
-
}
|
|
8
|
-
function buildMembershipUserProjectionSkWorkspaceLane(params) {
|
|
9
|
-
const normalizedWorkspaceName = typeof params.denormalizedWorkspaceName === "string" && params.denormalizedWorkspaceName.length > 0 ? normalizeLabel(params.denormalizedWorkspaceName) : MISSING_NAME_SENTINEL;
|
|
10
|
-
return `MEMBERSHIP#WORKSPACE#TID#${params.tenantId}#${normalizedWorkspaceName}#WID#${params.workspaceId}#${params.membershipId}`;
|
|
11
|
-
}
|
|
12
|
-
function buildMembershipUserProjectionItem(input) {
|
|
13
|
-
if (!input.userId || input.userId.length === 0) {
|
|
14
|
-
return void 0;
|
|
15
|
-
}
|
|
16
|
-
const hasWorkspace = typeof input.workspaceId === "string" && input.workspaceId.length > 0;
|
|
17
|
-
const sk = hasWorkspace ? buildMembershipUserProjectionSkWorkspaceLane({
|
|
18
|
-
tenantId: input.tenantId,
|
|
19
|
-
workspaceId: input.workspaceId,
|
|
20
|
-
membershipId: input.membershipId,
|
|
21
|
-
denormalizedWorkspaceName: input.denormalizedWorkspaceName
|
|
22
|
-
}) : buildMembershipUserProjectionSkTenantLane({
|
|
23
|
-
tenantId: input.tenantId,
|
|
24
|
-
membershipId: input.membershipId,
|
|
25
|
-
denormalizedTenantName: input.denormalizedTenantName
|
|
26
|
-
});
|
|
27
|
-
return {
|
|
28
|
-
userId: input.userId,
|
|
29
|
-
sk,
|
|
30
|
-
tenantId: input.tenantId,
|
|
31
|
-
workspaceId: hasWorkspace ? input.workspaceId : void 0,
|
|
32
|
-
membershipId: input.membershipId,
|
|
33
|
-
summary: input.summary,
|
|
34
|
-
vid: input.vid,
|
|
35
|
-
lastUpdated: input.lastUpdated,
|
|
36
|
-
denormalizedTenantName: input.denormalizedTenantName,
|
|
37
|
-
denormalizedUserName: input.denormalizedUserName,
|
|
38
|
-
denormalizedWorkspaceName: hasWorkspace ? input.denormalizedWorkspaceName : void 0
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
function extractReferenceSlug(resource, fieldName) {
|
|
42
|
-
const field = resource[fieldName];
|
|
43
|
-
if (!field || typeof field !== "object") {
|
|
44
|
-
return void 0;
|
|
45
|
-
}
|
|
46
|
-
const reference = field.reference;
|
|
47
|
-
if (typeof reference !== "string" || reference.length === 0) {
|
|
48
|
-
return void 0;
|
|
49
|
-
}
|
|
50
|
-
const slash = reference.lastIndexOf("/");
|
|
51
|
-
const tail = slash >= 0 ? reference.slice(slash + 1) : reference;
|
|
52
|
-
return tail.length > 0 ? tail : void 0;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// src/data/operations/control/membership/membership-workspace-projection.ts
|
|
56
|
-
import { normalizeLabel as normalizeLabel2 } from "@openhi/types";
|
|
57
|
-
var MISSING_NAME_SENTINEL2 = "-";
|
|
58
4
|
function buildMembershipWorkspaceProjectionSk(params) {
|
|
59
|
-
const normalizedUserName = typeof params.denormalizedUserName === "string" && params.denormalizedUserName.length > 0 ?
|
|
5
|
+
const normalizedUserName = typeof params.denormalizedUserName === "string" && params.denormalizedUserName.length > 0 ? normalizeLabel(params.denormalizedUserName) : MISSING_NAME_SENTINEL;
|
|
60
6
|
return `MEMBERSHIP#${normalizedUserName}#USER#${params.userId}#${params.membershipId}`;
|
|
61
7
|
}
|
|
62
8
|
function buildMembershipWorkspaceProjectionItem(input) {
|
|
@@ -85,14 +31,14 @@ function buildMembershipWorkspaceProjectionItem(input) {
|
|
|
85
31
|
}
|
|
86
32
|
|
|
87
33
|
// src/data/operations/control/roleassignment/roleassignment-user-projection.ts
|
|
88
|
-
import { normalizeLabel as
|
|
89
|
-
var
|
|
34
|
+
import { normalizeLabel as normalizeLabel2 } from "@openhi/types";
|
|
35
|
+
var MISSING_NAME_SENTINEL2 = "-";
|
|
90
36
|
function buildRoleAssignmentUserProjectionSkTenantLane(params) {
|
|
91
|
-
const normalizedRoleName = typeof params.denormalizedRoleName === "string" && params.denormalizedRoleName.length > 0 ?
|
|
37
|
+
const normalizedRoleName = typeof params.denormalizedRoleName === "string" && params.denormalizedRoleName.length > 0 ? normalizeLabel2(params.denormalizedRoleName) : MISSING_NAME_SENTINEL2;
|
|
92
38
|
return `ROLEASSIGNMENT#TENANT#${normalizedRoleName}#${params.roleId}#TID#${params.tenantId}#${params.roleAssignmentId}`;
|
|
93
39
|
}
|
|
94
40
|
function buildRoleAssignmentUserProjectionSkWorkspaceLane(params) {
|
|
95
|
-
const normalizedRoleName = typeof params.denormalizedRoleName === "string" && params.denormalizedRoleName.length > 0 ?
|
|
41
|
+
const normalizedRoleName = typeof params.denormalizedRoleName === "string" && params.denormalizedRoleName.length > 0 ? normalizeLabel2(params.denormalizedRoleName) : MISSING_NAME_SENTINEL2;
|
|
96
42
|
return `ROLEASSIGNMENT#WORKSPACE#${normalizedRoleName}#${params.roleId}#TID#${params.tenantId}#WID#${params.workspaceId}#${params.roleAssignmentId}`;
|
|
97
43
|
}
|
|
98
44
|
function buildRoleAssignmentUserProjectionItem(input) {
|
|
@@ -130,7 +76,7 @@ function buildRoleAssignmentUserProjectionItem(input) {
|
|
|
130
76
|
denormalizedRoleName: input.denormalizedRoleName
|
|
131
77
|
};
|
|
132
78
|
}
|
|
133
|
-
function
|
|
79
|
+
function extractReferenceSlug(resource, fieldName) {
|
|
134
80
|
const field = resource[fieldName];
|
|
135
81
|
if (!field || typeof field !== "object") {
|
|
136
82
|
return void 0;
|
|
@@ -145,10 +91,10 @@ function extractReferenceSlug2(resource, fieldName) {
|
|
|
145
91
|
}
|
|
146
92
|
|
|
147
93
|
// src/data/operations/control/roleassignment/roleassignment-workspace-projection.ts
|
|
148
|
-
import { normalizeLabel as
|
|
149
|
-
var
|
|
94
|
+
import { normalizeLabel as normalizeLabel3 } from "@openhi/types";
|
|
95
|
+
var MISSING_NAME_SENTINEL3 = "-";
|
|
150
96
|
function buildRoleAssignmentWorkspaceProjectionSk(params) {
|
|
151
|
-
const normalizedUserName = typeof params.denormalizedUserName === "string" && params.denormalizedUserName.length > 0 ?
|
|
97
|
+
const normalizedUserName = typeof params.denormalizedUserName === "string" && params.denormalizedUserName.length > 0 ? normalizeLabel3(params.denormalizedUserName) : MISSING_NAME_SENTINEL3;
|
|
152
98
|
return `ROLEASSIGNMENT#${params.roleId}#${normalizedUserName}#USER#${params.userId}#${params.roleAssignmentId}`;
|
|
153
99
|
}
|
|
154
100
|
function buildRoleAssignmentWorkspaceProjectionItem(input) {
|
|
@@ -183,17 +129,13 @@ function buildRoleAssignmentWorkspaceProjectionItem(input) {
|
|
|
183
129
|
}
|
|
184
130
|
|
|
185
131
|
export {
|
|
186
|
-
buildMembershipUserProjectionSkTenantLane,
|
|
187
|
-
buildMembershipUserProjectionSkWorkspaceLane,
|
|
188
|
-
buildMembershipUserProjectionItem,
|
|
189
|
-
extractReferenceSlug,
|
|
190
132
|
buildMembershipWorkspaceProjectionSk,
|
|
191
133
|
buildMembershipWorkspaceProjectionItem,
|
|
192
134
|
buildRoleAssignmentUserProjectionSkTenantLane,
|
|
193
135
|
buildRoleAssignmentUserProjectionSkWorkspaceLane,
|
|
194
136
|
buildRoleAssignmentUserProjectionItem,
|
|
195
|
-
|
|
137
|
+
extractReferenceSlug,
|
|
196
138
|
buildRoleAssignmentWorkspaceProjectionSk,
|
|
197
139
|
buildRoleAssignmentWorkspaceProjectionItem
|
|
198
140
|
};
|
|
199
|
-
//# sourceMappingURL=chunk-
|
|
141
|
+
//# sourceMappingURL=chunk-5S6VFBLT.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/data/operations/control/membership/membership-workspace-projection.ts","../src/data/operations/control/roleassignment/roleassignment-user-projection.ts","../src/data/operations/control/roleassignment/roleassignment-workspace-projection.ts"],"sourcesContent":["/**\n * Membership workspace-projection composer.\n *\n * Owns the SK grammar for ADR-018 pattern #2 and assembles the\n * projection-row payload consumed by the membership create / update /\n * delete operations. The {@link MembershipWorkspaceProjectionEntity}\n * stores the SK verbatim — the grammar lives here so the operations\n * layer is the single source of truth for projection-row shape (per\n * `.claude/rules/data-layer-layout.md`).\n *\n * SK grammar:\n *\n * - **Pattern #2** (users in a workspace, sorted by user name —\n * workspace-scoped Memberships only):\n * `MEMBERSHIP#<normalizedUserName>#USER#<userId>#<membershipId>`\n *\n * The projection co-locates with the canonical Workspace record under\n * `PK = TID#<tenantId>#WORKSPACE#ID#<workspaceId>` so\n * `Query(PK = TID#<tenantId>#WORKSPACE#ID#<workspaceId>, SK begins_with 'MEMBERSHIP#')`\n * returns workspace metadata + every member projection in one round\n * trip. Tenant-scoped Memberships (no `workspaceId`) skip this\n * projection entirely.\n *\n * @see ADR-018 § Access Pattern Coverage (pattern #2)\n * @see .state/adr-018-implementation-guide.md § 1 (SK grammar) and § 2 (attribute set)\n */\n\nimport { normalizeLabel } from \"@openhi/types\";\n\n/**\n * Sentinel rendered into the SK when the source display name is missing\n * or empty. Keeps the SK shape stable so a `begins_with` prefix query\n * still matches the row; the rename-cascade pipeline (TR-023) will\n * rewrite the SK once the carrier display name lands. Mirrors the\n * sibling user-projection composer's defensive posture — a missing\n * source field never produces a malformed key.\n */\nconst MISSING_NAME_SENTINEL = \"-\";\n\n/** Inputs to compose a Membership workspace-projection row. */\nexport interface MembershipWorkspaceProjectionInput {\n readonly tenantId: string;\n readonly workspaceId: string;\n readonly userId: string;\n readonly membershipId: string;\n readonly summary: string;\n readonly vid: string;\n readonly lastUpdated: string;\n readonly denormalizedUserName?: string;\n}\n\n/** A projection-row payload ready for `multi-write` consumption. */\nexport interface MembershipWorkspaceProjectionItem {\n readonly tenantId: string;\n readonly workspaceId: string;\n readonly sk: string;\n readonly userId: string;\n readonly membershipId: string;\n readonly summary: string;\n readonly vid: string;\n readonly lastUpdated: string;\n readonly denormalizedUserName?: string;\n}\n\n/**\n * Compose the SK for ADR-018 pattern #2. The `<normalizedUserName>`\n * segment sorts memberships alphabetically by user name within the\n * workspace partition. The trailing `USER#<userId>#<membershipId>`\n * disambiguates rows when two memberships share a normalized user name\n * (homonyms) and supports a per-user lookup via\n * `begins_with('MEMBERSHIP#<normalizedUserName>#USER#<userId>#')`.\n * Missing `denormalizedUserName` falls back to\n * {@link MISSING_NAME_SENTINEL} so the SK shape stays valid\n * pre-rename-cascade.\n */\nexport function buildMembershipWorkspaceProjectionSk(params: {\n readonly userId: string;\n readonly membershipId: string;\n readonly denormalizedUserName?: string;\n}): string {\n const normalizedUserName =\n typeof params.denormalizedUserName === \"string\" &&\n params.denormalizedUserName.length > 0\n ? normalizeLabel(params.denormalizedUserName)\n : MISSING_NAME_SENTINEL;\n return `MEMBERSHIP#${normalizedUserName}#USER#${params.userId}#${params.membershipId}`;\n}\n\n/**\n * Builds the projection item for a workspace-scoped Membership.\n * Returns `undefined` when `workspaceId` or `userId` is missing —\n * tenant-scoped Memberships (no workspaceId) skip the workspace\n * projection entirely, and a Membership without a linked user cannot\n * project onto the workspace partition.\n */\nexport function buildMembershipWorkspaceProjectionItem(\n input: MembershipWorkspaceProjectionInput,\n): MembershipWorkspaceProjectionItem | undefined {\n if (!input.workspaceId || input.workspaceId.length === 0) {\n return undefined;\n }\n if (!input.userId || input.userId.length === 0) {\n return undefined;\n }\n const sk = buildMembershipWorkspaceProjectionSk({\n userId: input.userId,\n membershipId: input.membershipId,\n denormalizedUserName: input.denormalizedUserName,\n });\n return {\n tenantId: input.tenantId,\n workspaceId: input.workspaceId,\n sk,\n userId: input.userId,\n membershipId: input.membershipId,\n summary: input.summary,\n vid: input.vid,\n lastUpdated: input.lastUpdated,\n denormalizedUserName: input.denormalizedUserName,\n };\n}\n","/**\n * RoleAssignment user-projection composer.\n *\n * Owns the SK grammar for ADR-018 pattern #5 and assembles the\n * projection-row payload consumed by the role-assignment create /\n * update / delete operations. The\n * {@link RoleAssignmentUserProjectionEntity} stores the SK verbatim —\n * the grammar lives here so the operations layer is the single source\n * of truth for projection-row shape (per\n * `.claude/rules/data-layer-layout.md`).\n *\n * SK grammar:\n *\n * - **tenant-level sub-lane** (`workspaceId` absent):\n * `ROLEASSIGNMENT#TENANT#<normalizedRoleName>#<roleId>#TID#<tenantId>#<roleAssignmentId>`\n * - **workspace-level sub-lane** (`workspaceId` set):\n * `ROLEASSIGNMENT#WORKSPACE#<normalizedRoleName>#<roleId>#TID#<tenantId>#WID#<workspaceId>#<roleAssignmentId>`\n *\n * Both sub-lanes share the user partition `PK = USER#ID#<userId>` so\n * `Query(PK = USER#ID#<userId>, SK begins_with 'ROLEASSIGNMENT#')`\n * returns both sub-lanes interleaved with TENANT preceding WORKSPACE\n * lexicographically.\n *\n * @see ADR-018 § Access Pattern Coverage (pattern #5)\n * @see .state/adr-018-implementation-guide.md § 1 (SK grammar) and § 2 (attribute set)\n */\n\nimport { normalizeLabel } from \"@openhi/types\";\n\n/**\n * Sentinel rendered into the SK when the source display name is missing\n * or empty. Keeps the SK shape stable so a `begins_with` prefix query\n * still matches the row; the rename-cascade pipeline (TR-023) will\n * rewrite the SK once the carrier display name lands. Matches the\n * defensive posture in `membership-user-projection` — a missing source\n * field never produces a malformed key.\n */\nconst MISSING_NAME_SENTINEL = \"-\";\n\n/** Inputs to compose a RoleAssignment user-projection row. */\nexport interface RoleAssignmentUserProjectionInput {\n readonly tenantId: string;\n readonly userId: string;\n readonly workspaceId?: string;\n readonly roleId: string;\n readonly roleAssignmentId: string;\n readonly summary: string;\n readonly vid: string;\n readonly lastUpdated: string;\n readonly denormalizedTenantName?: string;\n readonly denormalizedUserName?: string;\n readonly denormalizedRoleName?: string;\n}\n\n/** A projection-row payload ready for `multi-write` consumption. */\nexport interface RoleAssignmentUserProjectionItem {\n readonly userId: string;\n readonly sk: string;\n readonly tenantId: string;\n readonly workspaceId?: string;\n readonly roleId: string;\n readonly roleAssignmentId: string;\n readonly summary: string;\n readonly vid: string;\n readonly lastUpdated: string;\n readonly denormalizedTenantName?: string;\n readonly denormalizedUserName?: string;\n readonly denormalizedRoleName?: string;\n}\n\n/**\n * Compose the SK for ADR-018 pattern #5 — tenant-level sub-lane. The\n * `<normalizedRoleName>` segment sorts assignments alphabetically by\n * role name within the user's partition; `<roleId>` discriminates\n * rename-stable. Missing `denormalizedRoleName` falls back to\n * {@link MISSING_NAME_SENTINEL} so the SK shape stays valid\n * pre-rename-cascade.\n */\nexport function buildRoleAssignmentUserProjectionSkTenantLane(params: {\n readonly tenantId: string;\n readonly roleId: string;\n readonly roleAssignmentId: string;\n readonly denormalizedRoleName?: string;\n}): string {\n const normalizedRoleName =\n typeof params.denormalizedRoleName === \"string\" &&\n params.denormalizedRoleName.length > 0\n ? normalizeLabel(params.denormalizedRoleName)\n : MISSING_NAME_SENTINEL;\n return `ROLEASSIGNMENT#TENANT#${normalizedRoleName}#${params.roleId}#TID#${params.tenantId}#${params.roleAssignmentId}`;\n}\n\n/**\n * Compose the SK for ADR-018 pattern #5 — workspace-level sub-lane.\n * Same `<normalizedRoleName>#<roleId>` sort discriminator as the tenant\n * sub-lane; the trailing segments narrow the partition to a single\n * tenant + workspace. Missing `denormalizedRoleName` falls back to\n * {@link MISSING_NAME_SENTINEL}.\n */\nexport function buildRoleAssignmentUserProjectionSkWorkspaceLane(params: {\n readonly tenantId: string;\n readonly workspaceId: string;\n readonly roleId: string;\n readonly roleAssignmentId: string;\n readonly denormalizedRoleName?: string;\n}): string {\n const normalizedRoleName =\n typeof params.denormalizedRoleName === \"string\" &&\n params.denormalizedRoleName.length > 0\n ? normalizeLabel(params.denormalizedRoleName)\n : MISSING_NAME_SENTINEL;\n return `ROLEASSIGNMENT#WORKSPACE#${normalizedRoleName}#${params.roleId}#TID#${params.tenantId}#WID#${params.workspaceId}#${params.roleAssignmentId}`;\n}\n\n/**\n * Builds the projection item for the access lane implied by the input.\n * Tenant-level sub-lane when `workspaceId` is absent or empty;\n * workspace-level sub-lane otherwise. Returns `undefined` when `userId`\n * or `roleId` is missing — without either the projection cannot land\n * under a user partition or be sorted by role name.\n */\nexport function buildRoleAssignmentUserProjectionItem(\n input: RoleAssignmentUserProjectionInput,\n): RoleAssignmentUserProjectionItem | undefined {\n if (!input.userId || input.userId.length === 0) {\n return undefined;\n }\n if (!input.roleId || input.roleId.length === 0) {\n return undefined;\n }\n const hasWorkspace =\n typeof input.workspaceId === \"string\" && input.workspaceId.length > 0;\n const sk = hasWorkspace\n ? buildRoleAssignmentUserProjectionSkWorkspaceLane({\n tenantId: input.tenantId,\n workspaceId: input.workspaceId as string,\n roleId: input.roleId,\n roleAssignmentId: input.roleAssignmentId,\n denormalizedRoleName: input.denormalizedRoleName,\n })\n : buildRoleAssignmentUserProjectionSkTenantLane({\n tenantId: input.tenantId,\n roleId: input.roleId,\n roleAssignmentId: input.roleAssignmentId,\n denormalizedRoleName: input.denormalizedRoleName,\n });\n return {\n userId: input.userId,\n sk,\n tenantId: input.tenantId,\n workspaceId: hasWorkspace ? input.workspaceId : undefined,\n roleId: input.roleId,\n roleAssignmentId: input.roleAssignmentId,\n summary: input.summary,\n vid: input.vid,\n lastUpdated: input.lastUpdated,\n denormalizedTenantName: input.denormalizedTenantName,\n denormalizedUserName: input.denormalizedUserName,\n denormalizedRoleName: input.denormalizedRoleName,\n };\n}\n\n/**\n * Extracts a FHIR `Reference` slug — the segment after the final `/`.\n * Returns `undefined` when the reference is missing or malformed so\n * callers fall back gracefully (matches the defensive posture in\n * `extractRoleId` / `extractDenormalizedReferenceDisplay`).\n */\nexport function extractReferenceSlug(\n resource: Record<string, unknown>,\n fieldName: string,\n): string | undefined {\n const field = resource[fieldName];\n if (!field || typeof field !== \"object\") {\n return undefined;\n }\n const reference = (field as { reference?: unknown }).reference;\n if (typeof reference !== \"string\" || reference.length === 0) {\n return undefined;\n }\n const slash = reference.lastIndexOf(\"/\");\n const tail = slash >= 0 ? reference.slice(slash + 1) : reference;\n return tail.length > 0 ? tail : undefined;\n}\n","/**\n * RoleAssignment workspace-projection composer.\n *\n * Owns the SK grammar for ADR-018 pattern #9 and assembles the\n * projection-row payload consumed by the role-assignment create /\n * update / delete operations. The\n * {@link RoleAssignmentWorkspaceProjectionEntity} stores the SK\n * verbatim — the grammar lives here so the operations layer is the\n * single source of truth for projection-row shape (per\n * `.claude/rules/data-layer-layout.md`).\n *\n * SK grammar:\n *\n * - **Pattern #9** (users with a specific role in a workspace, sorted\n * by user name — workspace-scoped RoleAssignments only):\n * `ROLEASSIGNMENT#<roleId>#<normalizedUserName>#USER#<userId>#<roleAssignmentId>`\n *\n * The SK is **discriminator-first** on the raw `<roleId>` (mirroring\n * the canonical GSI1SK from pattern #8). Role id discriminates first so\n * a `begins_with('ROLEASSIGNMENT#<roleId>#')` filter returns every user\n * assigned to that role in the workspace, sorted alphabetically by\n * normalized user name. The trailing `USER#<userId>#<roleAssignmentId>`\n * disambiguates rows when two assignments share a normalized user name\n * (homonyms) and supports a per-user lookup via\n * `begins_with('ROLEASSIGNMENT#<roleId>#<normalizedUserName>#USER#<userId>#')`.\n *\n * The projection co-locates with the canonical Workspace record (and\n * the Membership workspace-projection rows from pattern #2) under\n * `PK = TID#<tenantId>#WORKSPACE#ID#<workspaceId>` so\n * `Query(PK = TID#<tenantId>#WORKSPACE#ID#<workspaceId>)` returns\n * workspace metadata + every member projection + every role-assignment\n * projection in one round trip. Tenant-scoped RoleAssignments (no\n * `workspaceId`) skip this projection entirely.\n *\n * **Rename-cascade interaction (TR-023, Phase 6).** The SK uses the\n * raw `<roleId>` (rename-stable) for the discriminator and\n * `<normalizedUserName>` for the secondary sort. A Role rename does\n * NOT rewrite this SK; a User rename DOES (cascaded by the rename\n * pipeline).\n *\n * @see ADR-018 § Access Pattern Coverage (pattern #9)\n * @see .state/adr-018-implementation-guide.md § 1 (SK grammar) and § 2 (attribute set)\n */\n\nimport { normalizeLabel } from \"@openhi/types\";\n\n/**\n * Sentinel rendered into the SK when the source user display name is\n * missing or empty. Keeps the SK shape stable so a `begins_with` prefix\n * query still matches the row; the rename-cascade pipeline (TR-023)\n * will rewrite the SK once the carrier display name lands. Mirrors the\n * sibling projection composers' defensive posture — a missing source\n * field never produces a malformed key.\n */\nconst MISSING_NAME_SENTINEL = \"-\";\n\n/** Inputs to compose a RoleAssignment workspace-projection row. */\nexport interface RoleAssignmentWorkspaceProjectionInput {\n readonly tenantId: string;\n readonly workspaceId: string;\n readonly userId: string;\n readonly roleId: string;\n readonly roleAssignmentId: string;\n readonly summary: string;\n readonly vid: string;\n readonly lastUpdated: string;\n readonly denormalizedUserName?: string;\n readonly denormalizedRoleName?: string;\n}\n\n/** A projection-row payload ready for `multi-write` consumption. */\nexport interface RoleAssignmentWorkspaceProjectionItem {\n readonly tenantId: string;\n readonly workspaceId: string;\n readonly sk: string;\n readonly userId: string;\n readonly roleId: string;\n readonly roleAssignmentId: string;\n readonly summary: string;\n readonly vid: string;\n readonly lastUpdated: string;\n readonly denormalizedUserName?: string;\n readonly denormalizedRoleName?: string;\n}\n\n/**\n * Compose the SK for ADR-018 pattern #9. The discriminator-first\n * `<roleId>` segment (raw, NOT normalized — matches the canonical\n * GSI1SK from pattern #8) lets `begins_with('ROLEASSIGNMENT#<roleId>#')`\n * filter one role. The `<normalizedUserName>` segment sorts assignments\n * alphabetically by user name within that role. The trailing\n * `USER#<userId>#<roleAssignmentId>` disambiguates homonyms and\n * supports a per-user lookup via\n * `begins_with('ROLEASSIGNMENT#<roleId>#<normalizedUserName>#USER#<userId>#')`.\n * Missing `denormalizedUserName` falls back to\n * {@link MISSING_NAME_SENTINEL} so the SK shape stays valid\n * pre-rename-cascade.\n */\nexport function buildRoleAssignmentWorkspaceProjectionSk(params: {\n readonly roleId: string;\n readonly userId: string;\n readonly roleAssignmentId: string;\n readonly denormalizedUserName?: string;\n}): string {\n const normalizedUserName =\n typeof params.denormalizedUserName === \"string\" &&\n params.denormalizedUserName.length > 0\n ? normalizeLabel(params.denormalizedUserName)\n : MISSING_NAME_SENTINEL;\n return `ROLEASSIGNMENT#${params.roleId}#${normalizedUserName}#USER#${params.userId}#${params.roleAssignmentId}`;\n}\n\n/**\n * Builds the projection item for a workspace-scoped RoleAssignment.\n * Returns `undefined` when `workspaceId`, `userId`, or `roleId` is\n * missing — tenant-scoped RoleAssignments (no workspaceId) skip the\n * workspace projection entirely; a RoleAssignment without a linked\n * user or role cannot project onto the workspace partition under the\n * pattern-#9 SK shape.\n */\nexport function buildRoleAssignmentWorkspaceProjectionItem(\n input: RoleAssignmentWorkspaceProjectionInput,\n): RoleAssignmentWorkspaceProjectionItem | undefined {\n if (!input.workspaceId || input.workspaceId.length === 0) {\n return undefined;\n }\n if (!input.userId || input.userId.length === 0) {\n return undefined;\n }\n if (!input.roleId || input.roleId.length === 0) {\n return undefined;\n }\n const sk = buildRoleAssignmentWorkspaceProjectionSk({\n roleId: input.roleId,\n userId: input.userId,\n roleAssignmentId: input.roleAssignmentId,\n denormalizedUserName: input.denormalizedUserName,\n });\n return {\n tenantId: input.tenantId,\n workspaceId: input.workspaceId,\n sk,\n userId: input.userId,\n roleId: input.roleId,\n roleAssignmentId: input.roleAssignmentId,\n summary: input.summary,\n vid: input.vid,\n lastUpdated: input.lastUpdated,\n denormalizedUserName: input.denormalizedUserName,\n denormalizedRoleName: input.denormalizedRoleName,\n };\n}\n"],"mappings":"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","names":["normalizeLabel","MISSING_NAME_SENTINEL","normalizeLabel","MISSING_NAME_SENTINEL"]}
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
-
NotFoundError
|
|
3
|
-
} from "./chunk-FYHBHHWK.mjs";
|
|
4
|
-
import {
|
|
5
|
-
SHARD_COUNT,
|
|
6
2
|
computeShard
|
|
7
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-EUIP2U5F.mjs";
|
|
8
4
|
import {
|
|
9
5
|
defaultTableName,
|
|
10
6
|
dynamoClient
|
|
@@ -1044,312 +1040,7 @@ function getDynamoDataService(tableName) {
|
|
|
1044
1040
|
};
|
|
1045
1041
|
}
|
|
1046
1042
|
|
|
1047
|
-
// src/data/audit-meta.ts
|
|
1048
|
-
var OPENHI_EXT = "http://openhi.org/fhir/StructureDefinition";
|
|
1049
|
-
function mergeAuditIntoMeta(meta, audit) {
|
|
1050
|
-
const existing = meta ?? {};
|
|
1051
|
-
const ext = [
|
|
1052
|
-
...Array.isArray(existing.extension) ? existing.extension : []
|
|
1053
|
-
];
|
|
1054
|
-
const byUrl = new Map(ext.map((e) => [e.url, e]));
|
|
1055
|
-
function set(url, value, type) {
|
|
1056
|
-
if (value == null) return;
|
|
1057
|
-
byUrl.set(url, { url, [type]: value });
|
|
1058
|
-
}
|
|
1059
|
-
set(`${OPENHI_EXT}/created-date`, audit.createdDate, "valueDateTime");
|
|
1060
|
-
set(`${OPENHI_EXT}/created-by-id`, audit.createdById, "valueString");
|
|
1061
|
-
set(`${OPENHI_EXT}/created-by-name`, audit.createdByName, "valueString");
|
|
1062
|
-
set(`${OPENHI_EXT}/modified-date`, audit.modifiedDate, "valueDateTime");
|
|
1063
|
-
set(`${OPENHI_EXT}/modified-by-id`, audit.modifiedById, "valueString");
|
|
1064
|
-
set(`${OPENHI_EXT}/modified-by-name`, audit.modifiedByName, "valueString");
|
|
1065
|
-
set(`${OPENHI_EXT}/deleted-date`, audit.deletedDate, "valueDateTime");
|
|
1066
|
-
set(`${OPENHI_EXT}/deleted-by-id`, audit.deletedById, "valueString");
|
|
1067
|
-
set(`${OPENHI_EXT}/deleted-by-name`, audit.deletedByName, "valueString");
|
|
1068
|
-
return { ...existing, extension: Array.from(byUrl.values()) };
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
// src/data/operations/data-operations-common.ts
|
|
1072
|
-
import { extractSortKey, extractSummary } from "@openhi/types";
|
|
1073
|
-
|
|
1074
|
-
// src/lib/compression.ts
|
|
1075
|
-
import { gzipSync, gunzipSync } from "zlib";
|
|
1076
|
-
var ENVELOPE_VERSION = 1;
|
|
1077
|
-
var COMPRESSION_ALGOS = {
|
|
1078
|
-
NONE: "none",
|
|
1079
|
-
GZIP: "gzip",
|
|
1080
|
-
BROTLI: "brotli",
|
|
1081
|
-
DEFLATE: "deflate"
|
|
1082
|
-
};
|
|
1083
|
-
function isEnvelope(obj) {
|
|
1084
|
-
return typeof obj === "object" && obj !== null && "v" in obj && "algo" in obj && "payload" in obj && typeof obj.payload === "string";
|
|
1085
|
-
}
|
|
1086
|
-
function compressResource(jsonString, options) {
|
|
1087
|
-
const algo = options?.algo ?? COMPRESSION_ALGOS.GZIP;
|
|
1088
|
-
if (algo === COMPRESSION_ALGOS.NONE) {
|
|
1089
|
-
const envelope2 = {
|
|
1090
|
-
v: ENVELOPE_VERSION,
|
|
1091
|
-
algo: COMPRESSION_ALGOS.NONE,
|
|
1092
|
-
payload: jsonString
|
|
1093
|
-
};
|
|
1094
|
-
return JSON.stringify(envelope2);
|
|
1095
|
-
}
|
|
1096
|
-
const buf = Buffer.from(jsonString, "utf-8");
|
|
1097
|
-
const payload = gzipSync(buf).toString("base64");
|
|
1098
|
-
const envelope = {
|
|
1099
|
-
v: ENVELOPE_VERSION,
|
|
1100
|
-
algo: COMPRESSION_ALGOS.GZIP,
|
|
1101
|
-
payload
|
|
1102
|
-
};
|
|
1103
|
-
return JSON.stringify(envelope);
|
|
1104
|
-
}
|
|
1105
|
-
function decompressResource(compressedOrRaw) {
|
|
1106
|
-
try {
|
|
1107
|
-
const parsed = JSON.parse(compressedOrRaw);
|
|
1108
|
-
if (isEnvelope(parsed)) {
|
|
1109
|
-
if (parsed.algo === COMPRESSION_ALGOS.GZIP) {
|
|
1110
|
-
const buf = Buffer.from(parsed.payload, "base64");
|
|
1111
|
-
return gunzipSync(buf).toString("utf-8");
|
|
1112
|
-
}
|
|
1113
|
-
if (parsed.algo === COMPRESSION_ALGOS.NONE) {
|
|
1114
|
-
return parsed.payload;
|
|
1115
|
-
}
|
|
1116
|
-
return parsed.payload;
|
|
1117
|
-
}
|
|
1118
|
-
} catch {
|
|
1119
|
-
}
|
|
1120
|
-
try {
|
|
1121
|
-
const buf = Buffer.from(compressedOrRaw, "base64");
|
|
1122
|
-
if (buf.length >= 2 && buf[0] === 31 && buf[1] === 139) {
|
|
1123
|
-
return gunzipSync(buf).toString("utf-8");
|
|
1124
|
-
}
|
|
1125
|
-
} catch {
|
|
1126
|
-
}
|
|
1127
|
-
return compressedOrRaw;
|
|
1128
|
-
}
|
|
1129
|
-
|
|
1130
|
-
// src/data/operations/data-operations-common.ts
|
|
1131
|
-
var DATA_ENTITY_SK = "CURRENT";
|
|
1132
|
-
async function getDataEntityById(entity, tenantId, workspaceId, id, resourceLabel) {
|
|
1133
|
-
const result = await entity.get({
|
|
1134
|
-
tenantId,
|
|
1135
|
-
workspaceId,
|
|
1136
|
-
id,
|
|
1137
|
-
sk: DATA_ENTITY_SK
|
|
1138
|
-
}).go();
|
|
1139
|
-
if (!result.data) {
|
|
1140
|
-
throw new NotFoundError(`${resourceLabel} ${id} not found`, {
|
|
1141
|
-
details: { id }
|
|
1142
|
-
});
|
|
1143
|
-
}
|
|
1144
|
-
const parsed = JSON.parse(decompressResource(result.data.resource));
|
|
1145
|
-
return {
|
|
1146
|
-
id: result.data.id,
|
|
1147
|
-
resource: { ...parsed, id: result.data.id }
|
|
1148
|
-
};
|
|
1149
|
-
}
|
|
1150
|
-
async function deleteDataEntityById(entity, tenantId, workspaceId, id) {
|
|
1151
|
-
await entity.delete({
|
|
1152
|
-
tenantId,
|
|
1153
|
-
workspaceId,
|
|
1154
|
-
id,
|
|
1155
|
-
sk: DATA_ENTITY_SK
|
|
1156
|
-
}).go();
|
|
1157
|
-
}
|
|
1158
|
-
var BATCH_GET_MAX_ATTEMPTS = 3;
|
|
1159
|
-
var BATCH_GET_BASE_BACKOFF_MS = 50;
|
|
1160
|
-
async function batchGetWithRetry(entity, keys) {
|
|
1161
|
-
if (keys.length === 0) return [];
|
|
1162
|
-
const collected = [];
|
|
1163
|
-
let pending = keys;
|
|
1164
|
-
let attempt = 0;
|
|
1165
|
-
while (pending.length > 0) {
|
|
1166
|
-
if (attempt > 0) {
|
|
1167
|
-
await new Promise(
|
|
1168
|
-
(resolve) => setTimeout(resolve, BATCH_GET_BASE_BACKOFF_MS * 2 ** (attempt - 1))
|
|
1169
|
-
);
|
|
1170
|
-
}
|
|
1171
|
-
attempt++;
|
|
1172
|
-
const result = await entity.get(pending).go();
|
|
1173
|
-
collected.push(...result.data);
|
|
1174
|
-
const unprocessed = result.unprocessed ?? [];
|
|
1175
|
-
if (unprocessed.length === 0) break;
|
|
1176
|
-
if (attempt >= BATCH_GET_MAX_ATTEMPTS) {
|
|
1177
|
-
throw new Error(
|
|
1178
|
-
`BatchGet exhausted retries: ${unprocessed.length} key(s) still unprocessed after ${BATCH_GET_MAX_ATTEMPTS} attempt(s)`
|
|
1179
|
-
);
|
|
1180
|
-
}
|
|
1181
|
-
pending = unprocessed;
|
|
1182
|
-
}
|
|
1183
|
-
return collected;
|
|
1184
|
-
}
|
|
1185
|
-
async function dispatchListMode(mode, shardResults, hooks) {
|
|
1186
|
-
if (mode === "count") {
|
|
1187
|
-
let total = 0;
|
|
1188
|
-
for (const shardResult of shardResults) {
|
|
1189
|
-
total += (shardResult.data ?? []).length;
|
|
1190
|
-
}
|
|
1191
|
-
return { entries: [], total };
|
|
1192
|
-
}
|
|
1193
|
-
if (mode === "summary") {
|
|
1194
|
-
const entries2 = [];
|
|
1195
|
-
for (const shardResult of shardResults) {
|
|
1196
|
-
for (const item of shardResult.data ?? []) {
|
|
1197
|
-
if (typeof item.summary !== "string") continue;
|
|
1198
|
-
let parsed;
|
|
1199
|
-
try {
|
|
1200
|
-
parsed = JSON.parse(item.summary);
|
|
1201
|
-
} catch {
|
|
1202
|
-
continue;
|
|
1203
|
-
}
|
|
1204
|
-
entries2.push(hooks.buildSummaryEntry(item.id, parsed));
|
|
1205
|
-
}
|
|
1206
|
-
}
|
|
1207
|
-
return { entries: entries2, total: entries2.length };
|
|
1208
|
-
}
|
|
1209
|
-
const orderedIds = [];
|
|
1210
|
-
for (const shardResult of shardResults) {
|
|
1211
|
-
for (const item of shardResult.data ?? []) {
|
|
1212
|
-
orderedIds.push(item.id);
|
|
1213
|
-
}
|
|
1214
|
-
}
|
|
1215
|
-
if (orderedIds.length === 0) return { entries: [], total: 0 };
|
|
1216
|
-
const items = await hooks.hydrate(orderedIds);
|
|
1217
|
-
const byId = new Map(items.map((item) => [hooks.getId(item), item]));
|
|
1218
|
-
const entries = [];
|
|
1219
|
-
for (const id of orderedIds) {
|
|
1220
|
-
const item = byId.get(id);
|
|
1221
|
-
if (!item) continue;
|
|
1222
|
-
entries.push(hooks.buildEntry(id, item));
|
|
1223
|
-
}
|
|
1224
|
-
return { entries, total: entries.length };
|
|
1225
|
-
}
|
|
1226
|
-
async function listDataEntitiesByWorkspace(entity, tenantId, workspaceId, mode = "full") {
|
|
1227
|
-
const shardResults = await Promise.all(
|
|
1228
|
-
Array.from(
|
|
1229
|
-
{ length: SHARD_COUNT },
|
|
1230
|
-
(_, shard) => entity.query.gsi1({ tenantId, workspaceId, gsi1Shard: String(shard) }).go()
|
|
1231
|
-
)
|
|
1232
|
-
);
|
|
1233
|
-
return dispatchListMode(
|
|
1234
|
-
mode,
|
|
1235
|
-
shardResults,
|
|
1236
|
-
{
|
|
1237
|
-
hydrate: (orderedIds) => batchGetWithRetry(
|
|
1238
|
-
entity,
|
|
1239
|
-
orderedIds.map((id) => ({
|
|
1240
|
-
tenantId,
|
|
1241
|
-
workspaceId,
|
|
1242
|
-
id,
|
|
1243
|
-
sk: DATA_ENTITY_SK
|
|
1244
|
-
}))
|
|
1245
|
-
),
|
|
1246
|
-
getId: (item) => item.id,
|
|
1247
|
-
buildEntry: (id, item) => {
|
|
1248
|
-
const parsed = JSON.parse(decompressResource(item.resource));
|
|
1249
|
-
return { id, resource: { ...parsed, id } };
|
|
1250
|
-
},
|
|
1251
|
-
buildSummaryEntry: (id, parsed) => ({
|
|
1252
|
-
id,
|
|
1253
|
-
resource: { ...parsed, id }
|
|
1254
|
-
})
|
|
1255
|
-
}
|
|
1256
|
-
);
|
|
1257
|
-
}
|
|
1258
|
-
async function createDataEntityRecord(entity, tenantId, workspaceId, id, resourceWithAudit, fallbackDate) {
|
|
1259
|
-
const lastUpdated = resourceWithAudit.meta?.lastUpdated ?? fallbackDate ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
1260
|
-
const vid = lastUpdated.replace(/[-:T.Z]/g, "").slice(0, 12) || Date.now().toString(36);
|
|
1261
|
-
const resourceLike = resourceWithAudit;
|
|
1262
|
-
const summary = JSON.stringify(extractSummary(resourceLike));
|
|
1263
|
-
const gsi1sk = extractSortKey(resourceLike);
|
|
1264
|
-
await entity.put({
|
|
1265
|
-
sk: DATA_ENTITY_SK,
|
|
1266
|
-
tenantId,
|
|
1267
|
-
workspaceId,
|
|
1268
|
-
id,
|
|
1269
|
-
resource: compressResource(JSON.stringify(resourceWithAudit)),
|
|
1270
|
-
summary,
|
|
1271
|
-
vid,
|
|
1272
|
-
lastUpdated,
|
|
1273
|
-
gsi1sk
|
|
1274
|
-
}).go();
|
|
1275
|
-
return {
|
|
1276
|
-
id,
|
|
1277
|
-
resource: resourceWithAudit
|
|
1278
|
-
};
|
|
1279
|
-
}
|
|
1280
|
-
function buildUpdatedResourceWithAudit(body, id, date, actorId, actorName, existingResourceStr, resourceType) {
|
|
1281
|
-
const existingMeta = JSON.parse(existingResourceStr).meta;
|
|
1282
|
-
const bodyWithMeta = body;
|
|
1283
|
-
const resourceWithVersion = {
|
|
1284
|
-
...body,
|
|
1285
|
-
resourceType,
|
|
1286
|
-
id,
|
|
1287
|
-
meta: {
|
|
1288
|
-
...bodyWithMeta.meta ?? {},
|
|
1289
|
-
lastUpdated: date,
|
|
1290
|
-
versionId: "2"
|
|
1291
|
-
}
|
|
1292
|
-
};
|
|
1293
|
-
const resourceWithAudit = {
|
|
1294
|
-
...resourceWithVersion,
|
|
1295
|
-
meta: mergeAuditIntoMeta(resourceWithVersion.meta ?? existingMeta, {
|
|
1296
|
-
modifiedDate: date,
|
|
1297
|
-
modifiedById: actorId,
|
|
1298
|
-
modifiedByName: actorName
|
|
1299
|
-
})
|
|
1300
|
-
};
|
|
1301
|
-
return {
|
|
1302
|
-
resource: resourceWithAudit,
|
|
1303
|
-
lastUpdated: date
|
|
1304
|
-
};
|
|
1305
|
-
}
|
|
1306
|
-
async function updateDataEntityById(entity, tenantId, workspaceId, id, resourceLabel, context, buildPatched) {
|
|
1307
|
-
const existing = await entity.get({
|
|
1308
|
-
tenantId,
|
|
1309
|
-
workspaceId,
|
|
1310
|
-
id,
|
|
1311
|
-
sk: DATA_ENTITY_SK
|
|
1312
|
-
}).go();
|
|
1313
|
-
if (!existing.data) {
|
|
1314
|
-
throw new NotFoundError(`${resourceLabel} ${id} not found`, {
|
|
1315
|
-
details: { id }
|
|
1316
|
-
});
|
|
1317
|
-
}
|
|
1318
|
-
const existingStr = decompressResource(existing.data.resource);
|
|
1319
|
-
const { resource, lastUpdated } = buildPatched(existingStr);
|
|
1320
|
-
const resourceLike = resource;
|
|
1321
|
-
const summary = JSON.stringify(extractSummary(resourceLike));
|
|
1322
|
-
const gsi1sk = extractSortKey(resourceLike);
|
|
1323
|
-
await entity.patch({
|
|
1324
|
-
tenantId,
|
|
1325
|
-
workspaceId,
|
|
1326
|
-
id,
|
|
1327
|
-
sk: DATA_ENTITY_SK
|
|
1328
|
-
}).set({
|
|
1329
|
-
resource: compressResource(JSON.stringify(resource)),
|
|
1330
|
-
summary,
|
|
1331
|
-
lastUpdated,
|
|
1332
|
-
gsi1sk
|
|
1333
|
-
}).go();
|
|
1334
|
-
return {
|
|
1335
|
-
id,
|
|
1336
|
-
resource
|
|
1337
|
-
};
|
|
1338
|
-
}
|
|
1339
|
-
|
|
1340
1043
|
export {
|
|
1341
|
-
getDynamoDataService
|
|
1342
|
-
compressResource,
|
|
1343
|
-
decompressResource,
|
|
1344
|
-
mergeAuditIntoMeta,
|
|
1345
|
-
DATA_ENTITY_SK,
|
|
1346
|
-
getDataEntityById,
|
|
1347
|
-
deleteDataEntityById,
|
|
1348
|
-
batchGetWithRetry,
|
|
1349
|
-
dispatchListMode,
|
|
1350
|
-
listDataEntitiesByWorkspace,
|
|
1351
|
-
createDataEntityRecord,
|
|
1352
|
-
buildUpdatedResourceWithAudit,
|
|
1353
|
-
updateDataEntityById
|
|
1044
|
+
getDynamoDataService
|
|
1354
1045
|
};
|
|
1355
|
-
//# sourceMappingURL=chunk-
|
|
1046
|
+
//# sourceMappingURL=chunk-6BB4CRSS.mjs.map
|