@openhi/constructs 0.0.110 → 0.0.112
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-23PUSHBV.mjs +24 -0
- package/lib/chunk-23PUSHBV.mjs.map +1 -0
- package/lib/chunk-2O3CXY2C.mjs +79 -0
- package/lib/chunk-2O3CXY2C.mjs.map +1 -0
- package/lib/{chunk-7FUAMZOF.mjs → chunk-53OHXLIL.mjs} +3 -3
- package/lib/chunk-6NBGYGFL.mjs +1803 -0
- package/lib/chunk-6NBGYGFL.mjs.map +1 -0
- package/lib/chunk-7RZHFI77.mjs +22 -0
- package/lib/chunk-7RZHFI77.mjs.map +1 -0
- package/lib/{chunk-7Q2IJ2J5.mjs → chunk-CUUKXDB2.mjs} +6 -6
- package/lib/chunk-FYHBHHWK.mjs +47 -0
- package/lib/chunk-FYHBHHWK.mjs.map +1 -0
- package/lib/{chunk-MULKGFIJ.mjs → chunk-GBDIGTNV.mjs} +165 -10
- package/lib/chunk-GBDIGTNV.mjs.map +1 -0
- package/lib/chunk-HQ67J7BP.mjs +199 -0
- package/lib/chunk-HQ67J7BP.mjs.map +1 -0
- package/lib/{chunk-AJ3G3THO.mjs → chunk-KO64HPWQ.mjs} +2 -2
- package/lib/{chunk-BB5MK4L3.mjs → chunk-KSFC72TT.mjs} +3 -3
- package/lib/{chunk-2TPJ6HOF.mjs → chunk-NZRW7ROK.mjs} +72 -54
- package/lib/chunk-NZRW7ROK.mjs.map +1 -0
- package/lib/chunk-QJDHVMKT.mjs +117 -0
- package/lib/chunk-QJDHVMKT.mjs.map +1 -0
- package/lib/{chunk-IS4VQRI4.mjs → chunk-QMBJ4VHC.mjs} +12 -47
- package/lib/chunk-QMBJ4VHC.mjs.map +1 -0
- package/lib/chunk-TRY7JGWO.mjs +16 -0
- package/lib/chunk-TRY7JGWO.mjs.map +1 -0
- package/lib/chunk-W4KR4CSL.mjs +236 -0
- package/lib/chunk-W4KR4CSL.mjs.map +1 -0
- package/lib/{chunk-AGF3RAAZ.mjs → chunk-WPCBVDFZ.mjs} +2 -2
- package/lib/chunk-WQWFVEVX.mjs +66 -0
- package/lib/chunk-WQWFVEVX.mjs.map +1 -0
- package/lib/{chunk-SYBADQXI.mjs → chunk-ZM4GDHHC.mjs} +77 -2
- package/lib/chunk-ZM4GDHHC.mjs.map +1 -0
- package/lib/data-store-postgres-replication.handler.js +26 -17
- package/lib/data-store-postgres-replication.handler.js.map +1 -1
- package/lib/data-store-postgres-replication.handler.mjs +5 -65
- package/lib/data-store-postgres-replication.handler.mjs.map +1 -1
- package/lib/delete-chunk.handler.d.mts +29 -0
- package/lib/delete-chunk.handler.d.ts +29 -0
- package/lib/delete-chunk.handler.js +2716 -0
- package/lib/delete-chunk.handler.js.map +1 -0
- package/lib/delete-chunk.handler.mjs +47 -0
- package/lib/delete-chunk.handler.mjs.map +1 -0
- package/lib/events-CjS-sm0W.d.mts +107 -0
- package/lib/events-CjS-sm0W.d.ts +107 -0
- package/lib/events-Da_cFgtc.d.mts +208 -0
- package/lib/events-Da_cFgtc.d.ts +208 -0
- package/lib/finalize.handler.d.mts +35 -0
- package/lib/finalize.handler.d.ts +35 -0
- package/lib/finalize.handler.js +875 -0
- package/lib/finalize.handler.js.map +1 -0
- package/lib/finalize.handler.mjs +166 -0
- package/lib/finalize.handler.mjs.map +1 -0
- package/lib/index.d.mts +189 -2
- package/lib/index.d.ts +500 -3
- package/lib/index.js +1753 -174
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +571 -17
- package/lib/index.mjs.map +1 -1
- package/lib/list-chunks.handler.d.mts +28 -0
- package/lib/list-chunks.handler.d.ts +28 -0
- package/lib/list-chunks.handler.js +2746 -0
- package/lib/list-chunks.handler.js.map +1 -0
- package/lib/list-chunks.handler.mjs +54 -0
- package/lib/list-chunks.handler.mjs.map +1 -0
- package/lib/platform-deploy-bridge.handler.js +76 -1
- 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 +1106 -155
- package/lib/pre-token-generation.handler.js.map +1 -1
- package/lib/pre-token-generation.handler.mjs +6 -4
- package/lib/pre-token-generation.handler.mjs.map +1 -1
- package/lib/provision-default-workspace.handler.js +1529 -142
- package/lib/provision-default-workspace.handler.js.map +1 -1
- package/lib/provision-default-workspace.handler.mjs +8 -4
- package/lib/provision-default-workspace.handler.mjs.map +1 -1
- package/lib/rename-finalize.handler.d.mts +30 -0
- package/lib/rename-finalize.handler.d.ts +30 -0
- package/lib/rename-finalize.handler.js +795 -0
- package/lib/rename-finalize.handler.js.map +1 -0
- package/lib/rename-finalize.handler.mjs +90 -0
- package/lib/rename-finalize.handler.mjs.map +1 -0
- package/lib/rename-list-targets.handler.d.mts +26 -0
- package/lib/rename-list-targets.handler.d.ts +26 -0
- package/lib/rename-list-targets.handler.js +2985 -0
- package/lib/rename-list-targets.handler.js.map +1 -0
- package/lib/rename-list-targets.handler.mjs +431 -0
- package/lib/rename-list-targets.handler.mjs.map +1 -0
- package/lib/rename-rewrite-chunk.handler.d.mts +35 -0
- package/lib/rename-rewrite-chunk.handler.d.ts +35 -0
- package/lib/rename-rewrite-chunk.handler.js +2021 -0
- package/lib/rename-rewrite-chunk.handler.js.map +1 -0
- package/lib/rename-rewrite-chunk.handler.mjs +27 -0
- package/lib/rename-rewrite-chunk.handler.mjs.map +1 -0
- package/lib/rest-api-lambda.handler.js +4087 -921
- package/lib/rest-api-lambda.handler.js.map +1 -1
- package/lib/rest-api-lambda.handler.mjs +1827 -81
- package/lib/rest-api-lambda.handler.mjs.map +1 -1
- package/lib/seed-demo-data.handler.js +1588 -124
- package/lib/seed-demo-data.handler.js.map +1 -1
- package/lib/seed-demo-data.handler.mjs +10 -6
- package/lib/seed-system-data.handler.js +1179 -155
- package/lib/seed-system-data.handler.js.map +1 -1
- package/lib/seed-system-data.handler.mjs +5 -4
- package/lib/seed-system-data.handler.mjs.map +1 -1
- package/package.json +1 -1
- package/lib/chunk-2TPJ6HOF.mjs.map +0 -1
- package/lib/chunk-IS4VQRI4.mjs.map +0 -1
- package/lib/chunk-MULKGFIJ.mjs.map +0 -1
- package/lib/chunk-QR5JVSCF.mjs +0 -862
- package/lib/chunk-QR5JVSCF.mjs.map +0 -1
- package/lib/chunk-SYBADQXI.mjs.map +0 -1
- /package/lib/{chunk-7FUAMZOF.mjs.map → chunk-53OHXLIL.mjs.map} +0 -0
- /package/lib/{chunk-7Q2IJ2J5.mjs.map → chunk-CUUKXDB2.mjs.map} +0 -0
- /package/lib/{chunk-AJ3G3THO.mjs.map → chunk-KO64HPWQ.mjs.map} +0 -0
- /package/lib/{chunk-BB5MK4L3.mjs.map → chunk-KSFC72TT.mjs.map} +0 -0
- /package/lib/{chunk-AGF3RAAZ.mjs.map → chunk-WPCBVDFZ.mjs.map} +0 -0
package/lib/index.js
CHANGED
|
@@ -194,6 +194,56 @@ var require_registry = __commonJS({
|
|
|
194
194
|
}
|
|
195
195
|
});
|
|
196
196
|
|
|
197
|
+
// ../workflows/lib/detail-types/control-plane.js
|
|
198
|
+
var require_control_plane = __commonJS({
|
|
199
|
+
"../workflows/lib/detail-types/control-plane.js"(exports2) {
|
|
200
|
+
"use strict";
|
|
201
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
202
|
+
exports2.ControlPlaneRenameFailedV1 = exports2.ControlPlaneRenameCompleteV1 = exports2.ControlPlaneRenameV1 = exports2.RENAMABLE_ENTITY_TYPE = exports2.ControlPlaneOwningDeleteFailedV1 = exports2.ControlPlaneOwningDeleteCompleteV1 = exports2.ControlPlaneOwningDeleteV1 = exports2.OWNING_ENTITY_TYPE = void 0;
|
|
203
|
+
var sources_1 = require_sources();
|
|
204
|
+
var registry_1 = require_registry();
|
|
205
|
+
exports2.OWNING_ENTITY_TYPE = {
|
|
206
|
+
Workspace: "Workspace",
|
|
207
|
+
User: "User"
|
|
208
|
+
};
|
|
209
|
+
exports2.ControlPlaneOwningDeleteV1 = (0, registry_1.defineDetailType)({
|
|
210
|
+
detailType: "control-plane.owning-delete.v1",
|
|
211
|
+
source: sources_1.OPENHI_DATA_SOURCE,
|
|
212
|
+
dedupRequired: true
|
|
213
|
+
});
|
|
214
|
+
exports2.ControlPlaneOwningDeleteCompleteV1 = (0, registry_1.defineDetailType)({
|
|
215
|
+
detailType: "control-plane.owning-delete-complete.v1",
|
|
216
|
+
source: sources_1.OPENHI_OPS_SOURCE,
|
|
217
|
+
dedupRequired: true
|
|
218
|
+
});
|
|
219
|
+
exports2.ControlPlaneOwningDeleteFailedV1 = (0, registry_1.defineDetailType)({
|
|
220
|
+
detailType: "control-plane.owning-delete-failed.v1",
|
|
221
|
+
source: sources_1.OPENHI_OPS_SOURCE,
|
|
222
|
+
dedupRequired: true
|
|
223
|
+
});
|
|
224
|
+
exports2.RENAMABLE_ENTITY_TYPE = {
|
|
225
|
+
Tenant: "Tenant",
|
|
226
|
+
User: "User",
|
|
227
|
+
Role: "Role"
|
|
228
|
+
};
|
|
229
|
+
exports2.ControlPlaneRenameV1 = (0, registry_1.defineDetailType)({
|
|
230
|
+
detailType: "control-plane.rename.v1",
|
|
231
|
+
source: sources_1.OPENHI_DATA_SOURCE,
|
|
232
|
+
dedupRequired: true
|
|
233
|
+
});
|
|
234
|
+
exports2.ControlPlaneRenameCompleteV1 = (0, registry_1.defineDetailType)({
|
|
235
|
+
detailType: "control-plane.rename-complete.v1",
|
|
236
|
+
source: sources_1.OPENHI_OPS_SOURCE,
|
|
237
|
+
dedupRequired: true
|
|
238
|
+
});
|
|
239
|
+
exports2.ControlPlaneRenameFailedV1 = (0, registry_1.defineDetailType)({
|
|
240
|
+
detailType: "control-plane.rename-failed.v1",
|
|
241
|
+
source: sources_1.OPENHI_OPS_SOURCE,
|
|
242
|
+
dedupRequired: true
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
|
|
197
247
|
// ../workflows/lib/detail-types/platform.js
|
|
198
248
|
var require_platform = __commonJS({
|
|
199
249
|
"../workflows/lib/detail-types/platform.js"(exports2) {
|
|
@@ -236,6 +286,7 @@ var require_detail_types = __commonJS({
|
|
|
236
286
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
|
|
237
287
|
};
|
|
238
288
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
289
|
+
__exportStar(require_control_plane(), exports2);
|
|
239
290
|
__exportStar(require_platform(), exports2);
|
|
240
291
|
__exportStar(require_registry(), exports2);
|
|
241
292
|
}
|
|
@@ -587,7 +638,7 @@ var require_lib2 = __commonJS({
|
|
|
587
638
|
"../workflows/lib/index.js"(exports2) {
|
|
588
639
|
"use strict";
|
|
589
640
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
590
|
-
exports2.workflowDedupClient = exports2.recordIfAbsent = exports2.markFailed = exports2.encodeSortKey = exports2.WorkflowDedupTableNameMissingError = exports2.WorkflowDedupInvalidInputError = exports2.WORKFLOW_DEDUP_TABLE_NAME_ENV_VAR = exports2.WORKFLOW_DEDUP_MAX_CONSUMER_NAME_LENGTH = exports2.WORKFLOW_DEDUP_DEFAULT_TTL_SECONDS = exports2.parseWorkflowEvent = exports2.UnsupportedEnvelopeVersionError = exports2.InvalidWorkflowEventError = exports2.workflowsClient = exports2.publishWorkflowEvent = exports2.WorkflowPublishError = exports2.isWellFormedDetailType = exports2.defineDetailType = exports2.PlatformSystemDataSeededV1 = exports2.PlatformDeploymentCompletedV1 = exports2.InvalidDetailTypeRegistrationError = exports2.OPENHI_OPS_SOURCE = exports2.OPENHI_DATA_SOURCE = exports2.OPENHI_CONTROL_SOURCE = exports2.DEFAULT_BUS_NAME_BY_SOURCE = exports2.workflowUserActorFromClaims = exports2.isWorkflowUserActor = exports2.isWorkflowSystemActor = exports2.MissingActorContextError = exports2.isSupportedEnvelopeVersion = exports2.ENVELOPE_VERSION = void 0;
|
|
641
|
+
exports2.workflowDedupClient = exports2.recordIfAbsent = exports2.markFailed = exports2.encodeSortKey = exports2.WorkflowDedupTableNameMissingError = exports2.WorkflowDedupInvalidInputError = exports2.WORKFLOW_DEDUP_TABLE_NAME_ENV_VAR = exports2.WORKFLOW_DEDUP_MAX_CONSUMER_NAME_LENGTH = exports2.WORKFLOW_DEDUP_DEFAULT_TTL_SECONDS = exports2.parseWorkflowEvent = exports2.UnsupportedEnvelopeVersionError = exports2.InvalidWorkflowEventError = exports2.workflowsClient = exports2.publishWorkflowEvent = exports2.WorkflowPublishError = exports2.isWellFormedDetailType = exports2.defineDetailType = exports2.RENAMABLE_ENTITY_TYPE = exports2.PlatformSystemDataSeededV1 = exports2.PlatformDeploymentCompletedV1 = exports2.OWNING_ENTITY_TYPE = exports2.InvalidDetailTypeRegistrationError = exports2.ControlPlaneRenameV1 = exports2.ControlPlaneRenameFailedV1 = exports2.ControlPlaneRenameCompleteV1 = exports2.ControlPlaneOwningDeleteV1 = exports2.ControlPlaneOwningDeleteFailedV1 = exports2.ControlPlaneOwningDeleteCompleteV1 = exports2.OPENHI_OPS_SOURCE = exports2.OPENHI_DATA_SOURCE = exports2.OPENHI_CONTROL_SOURCE = exports2.DEFAULT_BUS_NAME_BY_SOURCE = exports2.workflowUserActorFromClaims = exports2.isWorkflowUserActor = exports2.isWorkflowSystemActor = exports2.MissingActorContextError = exports2.isSupportedEnvelopeVersion = exports2.ENVELOPE_VERSION = void 0;
|
|
591
642
|
var envelope_version_1 = require_envelope_version();
|
|
592
643
|
Object.defineProperty(exports2, "ENVELOPE_VERSION", { enumerable: true, get: function() {
|
|
593
644
|
return envelope_version_1.ENVELOPE_VERSION;
|
|
@@ -622,15 +673,39 @@ var require_lib2 = __commonJS({
|
|
|
622
673
|
return sources_1.OPENHI_OPS_SOURCE;
|
|
623
674
|
} });
|
|
624
675
|
var detail_types_1 = require_detail_types();
|
|
676
|
+
Object.defineProperty(exports2, "ControlPlaneOwningDeleteCompleteV1", { enumerable: true, get: function() {
|
|
677
|
+
return detail_types_1.ControlPlaneOwningDeleteCompleteV1;
|
|
678
|
+
} });
|
|
679
|
+
Object.defineProperty(exports2, "ControlPlaneOwningDeleteFailedV1", { enumerable: true, get: function() {
|
|
680
|
+
return detail_types_1.ControlPlaneOwningDeleteFailedV1;
|
|
681
|
+
} });
|
|
682
|
+
Object.defineProperty(exports2, "ControlPlaneOwningDeleteV1", { enumerable: true, get: function() {
|
|
683
|
+
return detail_types_1.ControlPlaneOwningDeleteV1;
|
|
684
|
+
} });
|
|
685
|
+
Object.defineProperty(exports2, "ControlPlaneRenameCompleteV1", { enumerable: true, get: function() {
|
|
686
|
+
return detail_types_1.ControlPlaneRenameCompleteV1;
|
|
687
|
+
} });
|
|
688
|
+
Object.defineProperty(exports2, "ControlPlaneRenameFailedV1", { enumerable: true, get: function() {
|
|
689
|
+
return detail_types_1.ControlPlaneRenameFailedV1;
|
|
690
|
+
} });
|
|
691
|
+
Object.defineProperty(exports2, "ControlPlaneRenameV1", { enumerable: true, get: function() {
|
|
692
|
+
return detail_types_1.ControlPlaneRenameV1;
|
|
693
|
+
} });
|
|
625
694
|
Object.defineProperty(exports2, "InvalidDetailTypeRegistrationError", { enumerable: true, get: function() {
|
|
626
695
|
return detail_types_1.InvalidDetailTypeRegistrationError;
|
|
627
696
|
} });
|
|
697
|
+
Object.defineProperty(exports2, "OWNING_ENTITY_TYPE", { enumerable: true, get: function() {
|
|
698
|
+
return detail_types_1.OWNING_ENTITY_TYPE;
|
|
699
|
+
} });
|
|
628
700
|
Object.defineProperty(exports2, "PlatformDeploymentCompletedV1", { enumerable: true, get: function() {
|
|
629
701
|
return detail_types_1.PlatformDeploymentCompletedV1;
|
|
630
702
|
} });
|
|
631
703
|
Object.defineProperty(exports2, "PlatformSystemDataSeededV1", { enumerable: true, get: function() {
|
|
632
704
|
return detail_types_1.PlatformSystemDataSeededV1;
|
|
633
705
|
} });
|
|
706
|
+
Object.defineProperty(exports2, "RENAMABLE_ENTITY_TYPE", { enumerable: true, get: function() {
|
|
707
|
+
return detail_types_1.RENAMABLE_ENTITY_TYPE;
|
|
708
|
+
} });
|
|
634
709
|
Object.defineProperty(exports2, "defineDetailType", { enumerable: true, get: function() {
|
|
635
710
|
return detail_types_1.defineDetailType;
|
|
636
711
|
} });
|
|
@@ -702,6 +777,12 @@ __export(src_exports, {
|
|
|
702
777
|
CognitoUserPoolDomain: () => CognitoUserPoolDomain,
|
|
703
778
|
CognitoUserPoolKmsKey: () => CognitoUserPoolKmsKey,
|
|
704
779
|
ControlEventBus: () => ControlEventBus,
|
|
780
|
+
ControlPlaneOwningDeleteCompleteV1: () => import_workflows5.ControlPlaneOwningDeleteCompleteV1,
|
|
781
|
+
ControlPlaneOwningDeleteFailedV1: () => import_workflows5.ControlPlaneOwningDeleteFailedV1,
|
|
782
|
+
ControlPlaneOwningDeleteV1: () => import_workflows5.ControlPlaneOwningDeleteV1,
|
|
783
|
+
ControlPlaneRenameCompleteV1: () => import_workflows6.ControlPlaneRenameCompleteV1,
|
|
784
|
+
ControlPlaneRenameFailedV1: () => import_workflows6.ControlPlaneRenameFailedV1,
|
|
785
|
+
ControlPlaneRenameV1: () => import_workflows6.ControlPlaneRenameV1,
|
|
705
786
|
DATA_STORE_CHANGE_DETAIL_MAX_UTF8_BYTES: () => DATA_STORE_CHANGE_DETAIL_MAX_UTF8_BYTES,
|
|
706
787
|
DATA_STORE_CHANGE_DETAIL_TYPE: () => DATA_STORE_CHANGE_DETAIL_TYPE,
|
|
707
788
|
DATA_STORE_CHANGE_EVENT_SOURCE: () => DATA_STORE_CHANGE_EVENT_SOURCE,
|
|
@@ -721,6 +802,11 @@ __export(src_exports, {
|
|
|
721
802
|
OPENHI_TAG_SUFFIX_REPO_NAME: () => OPENHI_TAG_SUFFIX_REPO_NAME,
|
|
722
803
|
OPENHI_TAG_SUFFIX_SERVICE_TYPE: () => OPENHI_TAG_SUFFIX_SERVICE_TYPE,
|
|
723
804
|
OPENHI_TAG_SUFFIX_STAGE_TYPE: () => OPENHI_TAG_SUFFIX_STAGE_TYPE,
|
|
805
|
+
OWNING_DELETE_CASCADE_CONSUMER_NAME: () => OWNING_DELETE_CASCADE_CONSUMER_NAME,
|
|
806
|
+
OWNING_DELETE_CASCADE_DEFAULT_CONCURRENCY: () => OWNING_DELETE_CASCADE_DEFAULT_CONCURRENCY,
|
|
807
|
+
OWNING_DELETE_CASCADE_STUCK_THRESHOLD_MINUTES: () => OWNING_DELETE_CASCADE_STUCK_THRESHOLD_MINUTES,
|
|
808
|
+
OWNING_DELETE_OPS_EVENT_BUS_ENV_VAR: () => OWNING_DELETE_OPS_EVENT_BUS_ENV_VAR,
|
|
809
|
+
OWNING_ENTITY_TYPE: () => import_workflows5.OWNING_ENTITY_TYPE,
|
|
724
810
|
OpenHiApp: () => OpenHiApp,
|
|
725
811
|
OpenHiAuthService: () => OpenHiAuthService,
|
|
726
812
|
OpenHiDataService: () => OpenHiDataService,
|
|
@@ -731,6 +817,8 @@ __export(src_exports, {
|
|
|
731
817
|
OpenHiService: () => OpenHiService,
|
|
732
818
|
OpenHiStage: () => OpenHiStage,
|
|
733
819
|
OpsEventBus: () => OpsEventBus,
|
|
820
|
+
OwningDeleteCascadeLambdas: () => OwningDeleteCascadeLambdas,
|
|
821
|
+
OwningDeleteCascadeWorkflow: () => OwningDeleteCascadeWorkflow,
|
|
734
822
|
PLACEHOLDER_TENANT_ID: () => PLACEHOLDER_TENANT_ID,
|
|
735
823
|
PLACEHOLDER_WORKSPACE_ID: () => PLACEHOLDER_WORKSPACE_ID,
|
|
736
824
|
PLATFORM_DEPLOY_BRIDGE_ACTOR_SYSTEM: () => PLATFORM_DEPLOY_BRIDGE_ACTOR_SYSTEM,
|
|
@@ -746,7 +834,15 @@ __export(src_exports, {
|
|
|
746
834
|
PostConfirmationLambda: () => PostConfirmationLambda,
|
|
747
835
|
PreTokenGenerationLambda: () => PreTokenGenerationLambda,
|
|
748
836
|
ProvisionDefaultWorkspaceLambda: () => ProvisionDefaultWorkspaceLambda,
|
|
837
|
+
RENAMABLE_ENTITY_TYPE: () => import_workflows6.RENAMABLE_ENTITY_TYPE,
|
|
838
|
+
RENAME_CASCADE_CONSUMER_NAME: () => RENAME_CASCADE_CONSUMER_NAME,
|
|
839
|
+
RENAME_CASCADE_DEFAULT_CONCURRENCY: () => RENAME_CASCADE_DEFAULT_CONCURRENCY,
|
|
840
|
+
RENAME_CASCADE_FAILED_THRESHOLD: () => RENAME_CASCADE_FAILED_THRESHOLD,
|
|
841
|
+
RENAME_CASCADE_OPS_EVENT_BUS_ENV_VAR: () => RENAME_CASCADE_OPS_EVENT_BUS_ENV_VAR,
|
|
842
|
+
RENAME_CASCADE_SLOW_THRESHOLD_SECONDS: () => RENAME_CASCADE_SLOW_THRESHOLD_SECONDS,
|
|
749
843
|
REST_API_BASE_URL_SSM_NAME: () => REST_API_BASE_URL_SSM_NAME,
|
|
844
|
+
RenameCascadeLambdas: () => RenameCascadeLambdas,
|
|
845
|
+
RenameCascadeWorkflow: () => RenameCascadeWorkflow,
|
|
750
846
|
RootGraphqlApi: () => RootGraphqlApi,
|
|
751
847
|
RootHostedZone: () => RootHostedZone,
|
|
752
848
|
RootHttpApi: () => RootHttpApi,
|
|
@@ -2721,7 +2817,7 @@ var demoDevUserPartitionKeys = (devUsers) => {
|
|
|
2721
2817
|
// src/workflows/control-plane/seed-demo-data/seed-demo-data-lambda.ts
|
|
2722
2818
|
var import_node_fs7 = __toESM(require("fs"));
|
|
2723
2819
|
var import_node_path7 = __toESM(require("path"));
|
|
2724
|
-
var
|
|
2820
|
+
var import_types13 = require("@openhi/types");
|
|
2725
2821
|
var import_aws_cdk_lib12 = require("aws-cdk-lib");
|
|
2726
2822
|
var import_aws_events6 = require("aws-cdk-lib/aws-events");
|
|
2727
2823
|
var import_aws_events_targets2 = require("aws-cdk-lib/aws-events-targets");
|
|
@@ -2734,11 +2830,11 @@ var import_constructs11 = require("constructs");
|
|
|
2734
2830
|
var import_node_crypto = require("crypto");
|
|
2735
2831
|
var import_client_cognito_identity_provider = require("@aws-sdk/client-cognito-identity-provider");
|
|
2736
2832
|
var import_client_dynamodb2 = require("@aws-sdk/client-dynamodb");
|
|
2737
|
-
var
|
|
2833
|
+
var import_types12 = require("@openhi/types");
|
|
2738
2834
|
var import_workflows3 = __toESM(require_lib2());
|
|
2739
2835
|
|
|
2740
2836
|
// src/data/dynamo/dynamo-control-service.ts
|
|
2741
|
-
var
|
|
2837
|
+
var import_electrodb14 = require("electrodb");
|
|
2742
2838
|
|
|
2743
2839
|
// src/data/dynamo/dynamo-client.ts
|
|
2744
2840
|
var import_client_dynamodb = require("@aws-sdk/client-dynamodb");
|
|
@@ -2802,6 +2898,60 @@ var gsi1skAttribute = {
|
|
|
2802
2898
|
return label !== void 0 ? `${label}#${id}` : fallback;
|
|
2803
2899
|
}
|
|
2804
2900
|
};
|
|
2901
|
+
function extractRoleId(resource) {
|
|
2902
|
+
const flat = resource.roleId;
|
|
2903
|
+
if (typeof flat === "string" && flat.length > 0) return flat;
|
|
2904
|
+
const role = resource.role;
|
|
2905
|
+
if (role && typeof role === "object") {
|
|
2906
|
+
const reference = role.reference;
|
|
2907
|
+
if (typeof reference === "string" && reference.length > 0) {
|
|
2908
|
+
const slash = reference.lastIndexOf("/");
|
|
2909
|
+
const tail = slash >= 0 ? reference.slice(slash + 1) : reference;
|
|
2910
|
+
if (tail.length > 0) return tail;
|
|
2911
|
+
}
|
|
2912
|
+
}
|
|
2913
|
+
return void 0;
|
|
2914
|
+
}
|
|
2915
|
+
var roleAssignmentGsi1skAttribute = {
|
|
2916
|
+
type: "string",
|
|
2917
|
+
watch: ["resource", "denormalizedUserName", "lastUpdated", "id"],
|
|
2918
|
+
set: (_val, item) => {
|
|
2919
|
+
const id = typeof item?.id === "string" ? item.id : "";
|
|
2920
|
+
const lastUpdated = typeof item?.lastUpdated === "string" ? item.lastUpdated : "";
|
|
2921
|
+
const fallback = `${lastUpdated}#${id}`;
|
|
2922
|
+
if (typeof item?.resource !== "string" || item.resource.length === 0) {
|
|
2923
|
+
return fallback;
|
|
2924
|
+
}
|
|
2925
|
+
let parsed;
|
|
2926
|
+
try {
|
|
2927
|
+
parsed = JSON.parse(item.resource);
|
|
2928
|
+
} catch {
|
|
2929
|
+
return fallback;
|
|
2930
|
+
}
|
|
2931
|
+
if (!parsed || typeof parsed !== "object") return fallback;
|
|
2932
|
+
const roleId = extractRoleId(parsed);
|
|
2933
|
+
if (roleId === void 0) return fallback;
|
|
2934
|
+
const denormalizedUserName = typeof item.denormalizedUserName === "string" ? item.denormalizedUserName : "";
|
|
2935
|
+
const normalizedUserName = denormalizedUserName.length > 0 ? (0, import_types2.normalizeLabel)(denormalizedUserName) : "";
|
|
2936
|
+
if (normalizedUserName.length === 0) return fallback;
|
|
2937
|
+
return `${roleId}#${normalizedUserName}#${id}`;
|
|
2938
|
+
}
|
|
2939
|
+
};
|
|
2940
|
+
var membershipGsi1skAttribute = {
|
|
2941
|
+
type: "string",
|
|
2942
|
+
watch: ["denormalizedUserName", "lastUpdated", "id"],
|
|
2943
|
+
set: (_val, item) => {
|
|
2944
|
+
const id = typeof item?.id === "string" ? item.id : "";
|
|
2945
|
+
const lastUpdated = typeof item?.lastUpdated === "string" ? item.lastUpdated : "";
|
|
2946
|
+
const fallback = `${lastUpdated}#${id}`;
|
|
2947
|
+
const denormalizedUserName = typeof item?.denormalizedUserName === "string" ? item.denormalizedUserName : "";
|
|
2948
|
+
const normalizedUserName = denormalizedUserName.length > 0 ? (0, import_types2.normalizeLabel)(denormalizedUserName) : "";
|
|
2949
|
+
if (normalizedUserName.length === 0) {
|
|
2950
|
+
return fallback;
|
|
2951
|
+
}
|
|
2952
|
+
return `${normalizedUserName}#${id}`;
|
|
2953
|
+
}
|
|
2954
|
+
};
|
|
2805
2955
|
|
|
2806
2956
|
// src/data/dynamo/entities/control/configuration-entity.ts
|
|
2807
2957
|
var ConfigurationEntity = new import_electrodb.Entity({
|
|
@@ -2928,218 +3078,241 @@ var ConfigurationEntity = new import_electrodb.Entity({
|
|
|
2928
3078
|
}
|
|
2929
3079
|
});
|
|
2930
3080
|
|
|
2931
|
-
// src/data/dynamo/entities/control/
|
|
3081
|
+
// src/data/dynamo/entities/control/configuration-user-projection-entity.ts
|
|
2932
3082
|
var import_electrodb2 = require("electrodb");
|
|
2933
|
-
var
|
|
3083
|
+
var ConfigurationUserProjectionEntity = new import_electrodb2.Entity({
|
|
2934
3084
|
model: {
|
|
2935
|
-
entity: "
|
|
3085
|
+
entity: "configurationUserProjection",
|
|
2936
3086
|
service: "control",
|
|
2937
3087
|
version: "01"
|
|
2938
3088
|
},
|
|
2939
3089
|
attributes: {
|
|
2940
|
-
/**
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
/** Tenant in which the user has membership (required). */
|
|
2947
|
-
tenantId: {
|
|
3090
|
+
/**
|
|
3091
|
+
* User partition discriminator. Renders as `USER#ID#<userId>` on the
|
|
3092
|
+
* base-table PK. Always required — the projection has no meaning
|
|
3093
|
+
* outside a user partition.
|
|
3094
|
+
*/
|
|
3095
|
+
userId: {
|
|
2948
3096
|
type: "string",
|
|
2949
3097
|
required: true
|
|
2950
3098
|
},
|
|
2951
|
-
/**
|
|
2952
|
-
|
|
3099
|
+
/**
|
|
3100
|
+
* Pre-composed sort key — built by the operations-layer projection
|
|
3101
|
+
* writer via `buildConfigurationUserProjectionSk`. The entity stores
|
|
3102
|
+
* the value verbatim so the SK grammar (pattern #10 user-scope) is
|
|
3103
|
+
* owned by the operations layer, not duplicated here.
|
|
3104
|
+
*/
|
|
3105
|
+
sk: {
|
|
2953
3106
|
type: "string",
|
|
2954
3107
|
required: true
|
|
2955
3108
|
},
|
|
2956
|
-
/**
|
|
2957
|
-
|
|
3109
|
+
/**
|
|
3110
|
+
* Configuration canonical-record id. Stored as a discriminating
|
|
3111
|
+
* field so consumers can hydrate the canonical row via the
|
|
3112
|
+
* Configuration get-by-id operation when the projection's `summary`
|
|
3113
|
+
* is insufficient.
|
|
3114
|
+
*/
|
|
3115
|
+
configurationId: {
|
|
2958
3116
|
type: "string",
|
|
2959
3117
|
required: true
|
|
2960
3118
|
},
|
|
2961
3119
|
/**
|
|
2962
|
-
*
|
|
2963
|
-
*
|
|
3120
|
+
* Tenant the Configuration is associated with. The canonical row
|
|
3121
|
+
* keys off `(tenantId, workspaceId, userId, roleId)`; the projection
|
|
3122
|
+
* carries `tenantId` so consumers reconstructing the canonical PK
|
|
3123
|
+
* have the tenant segment without a hop.
|
|
2964
3124
|
*/
|
|
2965
|
-
|
|
3125
|
+
tenantId: {
|
|
2966
3126
|
type: "string",
|
|
2967
3127
|
required: true
|
|
2968
3128
|
},
|
|
2969
|
-
/**
|
|
2970
|
-
|
|
3129
|
+
/**
|
|
3130
|
+
* Scope marker. Always `"user"` on this projection — recorded
|
|
3131
|
+
* explicitly so future scope-bearing projections (workspace,
|
|
3132
|
+
* tenant, role) can share filter semantics in a unified
|
|
3133
|
+
* cross-projection list query if one ever lands.
|
|
3134
|
+
*/
|
|
3135
|
+
scope: {
|
|
2971
3136
|
type: "string",
|
|
2972
|
-
required: true
|
|
3137
|
+
required: true,
|
|
3138
|
+
default: "user"
|
|
2973
3139
|
},
|
|
2974
|
-
|
|
3140
|
+
/**
|
|
3141
|
+
* Configuration's `key` attribute (config category, e.g. endpoints,
|
|
3142
|
+
* branding, display). Mirrored from the canonical row so consumers
|
|
3143
|
+
* reading the projection get the natural display label without a
|
|
3144
|
+
* BatchGet hop. Doubles as the source of `<normalizedConfigName>` in
|
|
3145
|
+
* the SK.
|
|
3146
|
+
*/
|
|
3147
|
+
displayName: {
|
|
2975
3148
|
type: "string",
|
|
2976
|
-
required: true
|
|
2977
|
-
},
|
|
2978
|
-
gsi1Shard: gsi1ShardAttribute,
|
|
2979
|
-
/** Derived GSI1 sort key — name-based when extractable; else `<lastUpdated>#<id>`. */
|
|
2980
|
-
gsi1sk: gsi1skAttribute,
|
|
2981
|
-
deleted: {
|
|
2982
|
-
type: "boolean",
|
|
2983
3149
|
required: false
|
|
2984
3150
|
},
|
|
2985
|
-
|
|
3151
|
+
/**
|
|
3152
|
+
* Summary projection (key display fields as JSON string) — mirrored
|
|
3153
|
+
* from the canonical Configuration row so user-partition queries do
|
|
3154
|
+
* not need a BatchGet hop.
|
|
3155
|
+
*/
|
|
3156
|
+
summary: {
|
|
2986
3157
|
type: "string",
|
|
2987
|
-
required:
|
|
3158
|
+
required: true
|
|
2988
3159
|
},
|
|
2989
|
-
|
|
3160
|
+
/** Version id mirrored from the canonical Configuration row. */
|
|
3161
|
+
vid: {
|
|
2990
3162
|
type: "string",
|
|
2991
|
-
required:
|
|
3163
|
+
required: true
|
|
2992
3164
|
},
|
|
2993
|
-
/**
|
|
2994
|
-
|
|
2995
|
-
* Populated from the FHIR extension on the Membership resource at write
|
|
2996
|
-
* time so future GSIs can index data-plane identity lookups without
|
|
2997
|
-
* deserializing the full resource JSON. See ADR 2026-03-13-02 §6.
|
|
2998
|
-
*/
|
|
2999
|
-
linkedDataIdentityRef: {
|
|
3165
|
+
/** Last-updated timestamp mirrored from the canonical Configuration row. */
|
|
3166
|
+
lastUpdated: {
|
|
3000
3167
|
type: "string",
|
|
3001
|
-
required:
|
|
3168
|
+
required: true
|
|
3002
3169
|
}
|
|
3003
3170
|
},
|
|
3004
3171
|
indexes: {
|
|
3005
|
-
/**
|
|
3172
|
+
/**
|
|
3173
|
+
* Base table: PK = USER#ID#<userId>, SK = operation-supplied. A
|
|
3174
|
+
* single `Query(PK = USER#ID#<userId>, SK begins_with
|
|
3175
|
+
* 'CONFIGURATION#')` returns the user's user-scoped Configurations
|
|
3176
|
+
* sorted by `<normalizedConfigName>` (then `<configurationId>` as
|
|
3177
|
+
* the tiebreaker).
|
|
3178
|
+
*/
|
|
3006
3179
|
record: {
|
|
3007
3180
|
pk: {
|
|
3008
3181
|
field: "PK",
|
|
3009
|
-
composite: ["
|
|
3010
|
-
template: "
|
|
3182
|
+
composite: ["userId"],
|
|
3183
|
+
template: "USER#ID#${userId}"
|
|
3011
3184
|
},
|
|
3012
3185
|
sk: {
|
|
3013
3186
|
field: "SK",
|
|
3187
|
+
casing: "none",
|
|
3014
3188
|
composite: ["sk"],
|
|
3015
3189
|
template: "${sk}"
|
|
3016
3190
|
}
|
|
3017
|
-
},
|
|
3018
|
-
/**
|
|
3019
|
-
* GSI1 — Unified Sharded List per ADR-011: list all Memberships for a tenant across the
|
|
3020
|
-
* four shards. Membership is tenant-scoped only, so `WID#-` is a sentinel.
|
|
3021
|
-
* SK is derived via `gsi1skAttribute` — uses the resource's natural label when
|
|
3022
|
-
* extractable, else `<lastUpdated>#<id>` (DR-004). `casing: "none"` preserves the
|
|
3023
|
-
* normalized label and ISO-8601 `T`/`Z`.
|
|
3024
|
-
*/
|
|
3025
|
-
gsi1: {
|
|
3026
|
-
index: "GSI1",
|
|
3027
|
-
pk: {
|
|
3028
|
-
field: "GSI1PK",
|
|
3029
|
-
composite: ["tenantId", "gsi1Shard"],
|
|
3030
|
-
template: "TID#${tenantId}#WID#-#RT#Membership#SHARD#${gsi1Shard}"
|
|
3031
|
-
},
|
|
3032
|
-
sk: {
|
|
3033
|
-
field: "GSI1SK",
|
|
3034
|
-
casing: "none",
|
|
3035
|
-
composite: ["gsi1sk"],
|
|
3036
|
-
template: "${gsi1sk}"
|
|
3037
|
-
}
|
|
3038
3191
|
}
|
|
3039
3192
|
}
|
|
3040
3193
|
});
|
|
3041
3194
|
|
|
3042
|
-
// src/data/dynamo/entities/control/
|
|
3195
|
+
// src/data/dynamo/entities/control/configuration-workspace-projection-entity.ts
|
|
3043
3196
|
var import_electrodb3 = require("electrodb");
|
|
3044
|
-
var
|
|
3197
|
+
var ConfigurationWorkspaceProjectionEntity = new import_electrodb3.Entity({
|
|
3045
3198
|
model: {
|
|
3046
|
-
entity: "
|
|
3199
|
+
entity: "configurationWorkspaceProjection",
|
|
3047
3200
|
service: "control",
|
|
3048
3201
|
version: "01"
|
|
3049
3202
|
},
|
|
3050
3203
|
attributes: {
|
|
3051
|
-
/**
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
/** FHIR Resource.id; role id. */
|
|
3058
|
-
id: {
|
|
3204
|
+
/**
|
|
3205
|
+
* Tenant the workspace belongs to. Renders as the leading segment
|
|
3206
|
+
* of the base-table PK. Always required — the workspace partition
|
|
3207
|
+
* is tenant-scoped per ADR-011.
|
|
3208
|
+
*/
|
|
3209
|
+
tenantId: {
|
|
3059
3210
|
type: "string",
|
|
3060
3211
|
required: true
|
|
3061
3212
|
},
|
|
3062
|
-
/**
|
|
3063
|
-
|
|
3213
|
+
/**
|
|
3214
|
+
* Workspace partition discriminator. Renders as the trailing
|
|
3215
|
+
* segment of the base-table PK
|
|
3216
|
+
* (`TID#<tenantId>#WORKSPACE#ID#<workspaceId>`). Always required —
|
|
3217
|
+
* the projection has no meaning outside a workspace partition.
|
|
3218
|
+
*/
|
|
3219
|
+
workspaceId: {
|
|
3064
3220
|
type: "string",
|
|
3065
3221
|
required: true
|
|
3066
3222
|
},
|
|
3067
3223
|
/**
|
|
3068
|
-
*
|
|
3069
|
-
*
|
|
3224
|
+
* Pre-composed sort key — built by the operations-layer projection
|
|
3225
|
+
* writer via `buildConfigurationWorkspaceProjectionSk`. The entity
|
|
3226
|
+
* stores the value verbatim so the SK grammar (pattern #10
|
|
3227
|
+
* workspace-scope) is owned by the operations layer, not
|
|
3228
|
+
* duplicated here.
|
|
3070
3229
|
*/
|
|
3071
|
-
|
|
3230
|
+
sk: {
|
|
3072
3231
|
type: "string",
|
|
3073
3232
|
required: true
|
|
3074
3233
|
},
|
|
3075
|
-
/**
|
|
3076
|
-
|
|
3234
|
+
/**
|
|
3235
|
+
* Configuration canonical-record id. Stored as a discriminating
|
|
3236
|
+
* field so consumers can hydrate the canonical row via the
|
|
3237
|
+
* Configuration get-by-id operation when the projection's `summary`
|
|
3238
|
+
* is insufficient.
|
|
3239
|
+
*/
|
|
3240
|
+
configurationId: {
|
|
3077
3241
|
type: "string",
|
|
3078
3242
|
required: true
|
|
3079
3243
|
},
|
|
3080
|
-
|
|
3244
|
+
/**
|
|
3245
|
+
* Scope marker. Always `"workspace"` on this projection — recorded
|
|
3246
|
+
* explicitly so future scope-bearing projections (user, tenant,
|
|
3247
|
+
* role) can share filter semantics in a unified cross-projection
|
|
3248
|
+
* list query if one ever lands.
|
|
3249
|
+
*/
|
|
3250
|
+
scope: {
|
|
3081
3251
|
type: "string",
|
|
3082
|
-
required: true
|
|
3252
|
+
required: true,
|
|
3253
|
+
default: "workspace"
|
|
3083
3254
|
},
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3255
|
+
/**
|
|
3256
|
+
* Configuration's `key` attribute (config category, e.g. endpoints,
|
|
3257
|
+
* branding, display). Mirrored from the canonical row so consumers
|
|
3258
|
+
* reading the projection get the natural display label without a
|
|
3259
|
+
* BatchGet hop. Doubles as the source of `<normalizedConfigName>`
|
|
3260
|
+
* in the SK.
|
|
3261
|
+
*/
|
|
3262
|
+
displayName: {
|
|
3263
|
+
type: "string",
|
|
3089
3264
|
required: false
|
|
3090
3265
|
},
|
|
3091
|
-
|
|
3266
|
+
/**
|
|
3267
|
+
* Summary projection (key display fields as JSON string) — mirrored
|
|
3268
|
+
* from the canonical Configuration row so workspace-partition
|
|
3269
|
+
* queries do not need a BatchGet hop.
|
|
3270
|
+
*/
|
|
3271
|
+
summary: {
|
|
3092
3272
|
type: "string",
|
|
3093
|
-
required:
|
|
3273
|
+
required: true
|
|
3094
3274
|
},
|
|
3095
|
-
|
|
3275
|
+
/** Version id mirrored from the canonical Configuration row. */
|
|
3276
|
+
vid: {
|
|
3096
3277
|
type: "string",
|
|
3097
|
-
required:
|
|
3278
|
+
required: true
|
|
3279
|
+
},
|
|
3280
|
+
/** Last-updated timestamp mirrored from the canonical Configuration row. */
|
|
3281
|
+
lastUpdated: {
|
|
3282
|
+
type: "string",
|
|
3283
|
+
required: true
|
|
3098
3284
|
}
|
|
3099
3285
|
},
|
|
3100
3286
|
indexes: {
|
|
3101
|
-
/**
|
|
3287
|
+
/**
|
|
3288
|
+
* Base table: PK = TID#<tenantId>#WORKSPACE#ID#<workspaceId>,
|
|
3289
|
+
* SK = operation-supplied. A single
|
|
3290
|
+
* `Query(PK = TID#<tenantId>#WORKSPACE#ID#<workspaceId>, SK begins_with 'CONFIGURATION#')`
|
|
3291
|
+
* returns the workspace's workspace-scoped Configurations sorted by
|
|
3292
|
+
* `<normalizedConfigName>` (then `<configurationId>` as the
|
|
3293
|
+
* tiebreaker).
|
|
3294
|
+
*/
|
|
3102
3295
|
record: {
|
|
3103
3296
|
pk: {
|
|
3104
3297
|
field: "PK",
|
|
3105
|
-
composite: ["
|
|
3106
|
-
template: "
|
|
3298
|
+
composite: ["tenantId", "workspaceId"],
|
|
3299
|
+
template: "TID#${tenantId}#WORKSPACE#ID#${workspaceId}"
|
|
3107
3300
|
},
|
|
3108
3301
|
sk: {
|
|
3109
3302
|
field: "SK",
|
|
3303
|
+
casing: "none",
|
|
3110
3304
|
composite: ["sk"],
|
|
3111
3305
|
template: "${sk}"
|
|
3112
3306
|
}
|
|
3113
|
-
},
|
|
3114
|
-
/**
|
|
3115
|
-
* GSI1 — Unified Sharded List per ADR-011: list all Roles across the four shards.
|
|
3116
|
-
* Non-tenant-isolated, so `TID#-#WID#-` sentinels precede `RT#Role#SHARD#<n>`.
|
|
3117
|
-
* SK is derived via `gsi1skAttribute` — uses the resource's natural label when
|
|
3118
|
-
* extractable, else `<lastUpdated>#<id>` (DR-004). `casing: "none"` preserves the
|
|
3119
|
-
* normalized label and ISO-8601 `T`/`Z`.
|
|
3120
|
-
*/
|
|
3121
|
-
gsi1: {
|
|
3122
|
-
index: "GSI1",
|
|
3123
|
-
pk: {
|
|
3124
|
-
field: "GSI1PK",
|
|
3125
|
-
composite: ["gsi1Shard"],
|
|
3126
|
-
template: "TID#-#WID#-#RT#Role#SHARD#${gsi1Shard}"
|
|
3127
|
-
},
|
|
3128
|
-
sk: {
|
|
3129
|
-
field: "GSI1SK",
|
|
3130
|
-
casing: "none",
|
|
3131
|
-
composite: ["gsi1sk"],
|
|
3132
|
-
template: "${gsi1sk}"
|
|
3133
|
-
}
|
|
3134
3307
|
}
|
|
3135
3308
|
}
|
|
3136
3309
|
});
|
|
3137
3310
|
|
|
3138
|
-
// src/data/dynamo/entities/control/
|
|
3311
|
+
// src/data/dynamo/entities/control/membership-entity.ts
|
|
3139
3312
|
var import_electrodb4 = require("electrodb");
|
|
3140
|
-
var
|
|
3313
|
+
var MembershipEntity = new import_electrodb4.Entity({
|
|
3141
3314
|
model: {
|
|
3142
|
-
entity: "
|
|
3315
|
+
entity: "membership",
|
|
3143
3316
|
service: "control",
|
|
3144
3317
|
version: "01"
|
|
3145
3318
|
},
|
|
@@ -3150,17 +3323,17 @@ var RoleAssignmentEntity = new import_electrodb4.Entity({
|
|
|
3150
3323
|
required: true,
|
|
3151
3324
|
default: "CURRENT"
|
|
3152
3325
|
},
|
|
3153
|
-
/** Tenant in which the
|
|
3326
|
+
/** Tenant in which the user has membership (required). */
|
|
3154
3327
|
tenantId: {
|
|
3155
3328
|
type: "string",
|
|
3156
3329
|
required: true
|
|
3157
3330
|
},
|
|
3158
|
-
/** FHIR Resource.id;
|
|
3331
|
+
/** FHIR Resource.id; membership id. */
|
|
3159
3332
|
id: {
|
|
3160
3333
|
type: "string",
|
|
3161
3334
|
required: true
|
|
3162
3335
|
},
|
|
3163
|
-
/** Full
|
|
3336
|
+
/** Full Membership resource serialized as JSON string. */
|
|
3164
3337
|
resource: {
|
|
3165
3338
|
type: "string",
|
|
3166
3339
|
required: true
|
|
@@ -3183,8 +3356,14 @@ var RoleAssignmentEntity = new import_electrodb4.Entity({
|
|
|
3183
3356
|
required: true
|
|
3184
3357
|
},
|
|
3185
3358
|
gsi1Shard: gsi1ShardAttribute,
|
|
3186
|
-
/**
|
|
3187
|
-
|
|
3359
|
+
/**
|
|
3360
|
+
* Derived GSI1 sort key — `<normalizedUserName>#<id>` per ADR-018
|
|
3361
|
+
* pattern #1 so a GSI1 query partitioned on the tenant range-scans
|
|
3362
|
+
* by user-name prefix and returns memberships sorted by user name.
|
|
3363
|
+
* Falls back to `<lastUpdated>#<id>` when `denormalizedUserName`
|
|
3364
|
+
* is missing.
|
|
3365
|
+
*/
|
|
3366
|
+
gsi1sk: membershipGsi1skAttribute,
|
|
3188
3367
|
deleted: {
|
|
3189
3368
|
type: "boolean",
|
|
3190
3369
|
required: false
|
|
@@ -3196,49 +3375,863 @@ var RoleAssignmentEntity = new import_electrodb4.Entity({
|
|
|
3196
3375
|
msgId: {
|
|
3197
3376
|
type: "string",
|
|
3198
3377
|
required: false
|
|
3199
|
-
}
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3378
|
+
},
|
|
3379
|
+
/**
|
|
3380
|
+
* Denormalized `linked-data-identity` Reference (e.g. `Practitioner/abc`).
|
|
3381
|
+
* Populated from the FHIR extension on the Membership resource at write
|
|
3382
|
+
* time so future GSIs can index data-plane identity lookups without
|
|
3383
|
+
* deserializing the full resource JSON. See ADR 2026-03-13-02 §6.
|
|
3384
|
+
*/
|
|
3385
|
+
linkedDataIdentityRef: {
|
|
3386
|
+
type: "string",
|
|
3387
|
+
required: false
|
|
3388
|
+
},
|
|
3389
|
+
/**
|
|
3390
|
+
* Denormalized display name of the linked Tenant, captured at row
|
|
3391
|
+
* last-write time. Promoted to a top-level attribute so the ADR-018
|
|
3392
|
+
* adjacency-list projection SKs (pattern #3 — `MEMBERSHIP#TENANT#<normalizedTenantName>#…`)
|
|
3393
|
+
* can be composed from a top-level field instead of digging into the
|
|
3394
|
+
* `resource` JSON. Optional on the schema so pre-TR-024 rows do not
|
|
3395
|
+
* break; the operations-layer multi-write helper (#1010) makes the
|
|
3396
|
+
* field load-bearing at write time per TR-024 rule 2 (write-time
|
|
3397
|
+
* source = canonical Tenant.displayName).
|
|
3398
|
+
* @see TR-024 — Denormalized display-name attributes
|
|
3399
|
+
*/
|
|
3400
|
+
denormalizedTenantName: {
|
|
3401
|
+
type: "string",
|
|
3402
|
+
required: false
|
|
3403
|
+
},
|
|
3404
|
+
/**
|
|
3405
|
+
* Denormalized display name of the linked User, captured at row
|
|
3406
|
+
* last-write time. Promoted to a top-level attribute so the ADR-018
|
|
3407
|
+
* adjacency-list canonical-record GSI1SK (pattern #1 —
|
|
3408
|
+
* `<normalizedUserName>#<id>`) and workspace-projection SK (pattern #2)
|
|
3409
|
+
* can be composed from a top-level field. Optional on the schema so
|
|
3410
|
+
* pre-TR-024 rows do not break; the operations-layer multi-write helper
|
|
3411
|
+
* (#1010) makes the field load-bearing at write time per TR-024 rule 2
|
|
3412
|
+
* (write-time source = canonical User.displayName).
|
|
3413
|
+
* @see TR-024 — Denormalized display-name attributes
|
|
3414
|
+
*/
|
|
3415
|
+
denormalizedUserName: {
|
|
3416
|
+
type: "string",
|
|
3417
|
+
required: false
|
|
3418
|
+
}
|
|
3419
|
+
},
|
|
3420
|
+
indexes: {
|
|
3421
|
+
/** Base table: PK = TID#<tenantId>#MEMBERSHIP#ID#<id>, SK = CURRENT. Do not supply PK or SK from outside. */
|
|
3422
|
+
record: {
|
|
3423
|
+
pk: {
|
|
3424
|
+
field: "PK",
|
|
3425
|
+
composite: ["tenantId", "id"],
|
|
3426
|
+
template: "TID#${tenantId}#MEMBERSHIP#ID#${id}"
|
|
3427
|
+
},
|
|
3428
|
+
sk: {
|
|
3429
|
+
field: "SK",
|
|
3430
|
+
composite: ["sk"],
|
|
3431
|
+
template: "${sk}"
|
|
3432
|
+
}
|
|
3433
|
+
},
|
|
3434
|
+
/**
|
|
3435
|
+
* GSI1 — Unified Sharded List per ADR-011: list all Memberships for a tenant across the
|
|
3436
|
+
* four shards. Membership is tenant-scoped only, so `WID#-` is a sentinel.
|
|
3437
|
+
* SK is derived via `membershipGsi1skAttribute` — composes
|
|
3438
|
+
* `<normalizedUserName>#<id>` per ADR-018 pattern #1 (users in a
|
|
3439
|
+
* tenant, sorted by user name); falls back to `<lastUpdated>#<id>`
|
|
3440
|
+
* when `denormalizedUserName` is missing. `casing: "none"` preserves
|
|
3441
|
+
* the normalized label and ISO-8601 `T`/`Z`.
|
|
3442
|
+
*/
|
|
3443
|
+
gsi1: {
|
|
3444
|
+
index: "GSI1",
|
|
3445
|
+
pk: {
|
|
3446
|
+
field: "GSI1PK",
|
|
3447
|
+
composite: ["tenantId", "gsi1Shard"],
|
|
3448
|
+
template: "TID#${tenantId}#WID#-#RT#Membership#SHARD#${gsi1Shard}"
|
|
3449
|
+
},
|
|
3450
|
+
sk: {
|
|
3451
|
+
field: "GSI1SK",
|
|
3452
|
+
casing: "none",
|
|
3453
|
+
composite: ["gsi1sk"],
|
|
3454
|
+
template: "${gsi1sk}"
|
|
3455
|
+
}
|
|
3456
|
+
}
|
|
3457
|
+
}
|
|
3458
|
+
});
|
|
3459
|
+
|
|
3460
|
+
// src/data/dynamo/entities/control/membership-user-projection-entity.ts
|
|
3461
|
+
var import_electrodb5 = require("electrodb");
|
|
3462
|
+
var MembershipUserProjectionEntity = new import_electrodb5.Entity({
|
|
3463
|
+
model: {
|
|
3464
|
+
entity: "membershipUserProjection",
|
|
3465
|
+
service: "control",
|
|
3466
|
+
version: "01"
|
|
3467
|
+
},
|
|
3468
|
+
attributes: {
|
|
3469
|
+
/**
|
|
3470
|
+
* User partition discriminator. Renders as `USER#ID#<userId>` on the
|
|
3471
|
+
* base-table PK. Always required — the projection has no meaning
|
|
3472
|
+
* outside a user partition.
|
|
3473
|
+
*/
|
|
3474
|
+
userId: {
|
|
3475
|
+
type: "string",
|
|
3476
|
+
required: true
|
|
3477
|
+
},
|
|
3478
|
+
/**
|
|
3479
|
+
* Pre-composed sort key — built by the operations-layer projection
|
|
3480
|
+
* writer via `buildMembershipUserProjectionSk*` helpers. The entity
|
|
3481
|
+
* stores the value verbatim so the SK grammar (patterns #3 and #4)
|
|
3482
|
+
* is owned by the operations layer, not duplicated here.
|
|
3483
|
+
*/
|
|
3484
|
+
sk: {
|
|
3485
|
+
type: "string",
|
|
3486
|
+
required: true
|
|
3487
|
+
},
|
|
3488
|
+
/** Tenant in which the membership applies. Always required. */
|
|
3489
|
+
tenantId: {
|
|
3490
|
+
type: "string",
|
|
3491
|
+
required: true
|
|
3492
|
+
},
|
|
3493
|
+
/**
|
|
3494
|
+
* Workspace the membership scopes to. Present iff the projection
|
|
3495
|
+
* row is a pattern-#4 workspace sub-lane row; absent for pattern-#3
|
|
3496
|
+
* tenant sub-lane rows.
|
|
3497
|
+
*/
|
|
3498
|
+
workspaceId: {
|
|
3499
|
+
type: "string",
|
|
3500
|
+
required: false
|
|
3501
|
+
},
|
|
3502
|
+
/**
|
|
3503
|
+
* Membership canonical-record id. Stored as a discriminating field
|
|
3504
|
+
* so consumers can hydrate the canonical row via
|
|
3505
|
+
* `MembershipEntity.get({ tenantId, id: membershipId })` when the
|
|
3506
|
+
* projection's `summary` is insufficient.
|
|
3507
|
+
*/
|
|
3508
|
+
membershipId: {
|
|
3509
|
+
type: "string",
|
|
3510
|
+
required: true
|
|
3511
|
+
},
|
|
3512
|
+
/**
|
|
3513
|
+
* Summary projection (key display fields as JSON string: id,
|
|
3514
|
+
* displayName, status) — mirrored from the canonical Membership row
|
|
3515
|
+
* so user-partition queries do not need a BatchGet hop.
|
|
3516
|
+
*/
|
|
3517
|
+
summary: {
|
|
3518
|
+
type: "string",
|
|
3519
|
+
required: true
|
|
3520
|
+
},
|
|
3521
|
+
/** Version id mirrored from the canonical Membership row. */
|
|
3522
|
+
vid: {
|
|
3523
|
+
type: "string",
|
|
3524
|
+
required: true
|
|
3525
|
+
},
|
|
3526
|
+
/** Last-updated timestamp mirrored from the canonical Membership row. */
|
|
3527
|
+
lastUpdated: {
|
|
3528
|
+
type: "string",
|
|
3529
|
+
required: true
|
|
3530
|
+
},
|
|
3531
|
+
/**
|
|
3532
|
+
* Denormalized Tenant display name — required to compose pattern-#3
|
|
3533
|
+
* SK (`MEMBERSHIP#TENANT#<normalizedTenantName>#…`). Optional on the
|
|
3534
|
+
* schema because pre-TR-024 rows may not carry a display name; the
|
|
3535
|
+
* operations layer falls back gracefully when missing.
|
|
3536
|
+
*/
|
|
3537
|
+
denormalizedTenantName: {
|
|
3538
|
+
type: "string",
|
|
3539
|
+
required: false
|
|
3540
|
+
},
|
|
3541
|
+
/**
|
|
3542
|
+
* Denormalized User display name — mirrored from the canonical
|
|
3543
|
+
* Membership row per TR-024 rule 3 (canonical-record symmetry).
|
|
3544
|
+
* Carried on the projection so consumers can render the user's
|
|
3545
|
+
* display name without a hop to the User record.
|
|
3546
|
+
*/
|
|
3547
|
+
denormalizedUserName: {
|
|
3548
|
+
type: "string",
|
|
3549
|
+
required: false
|
|
3550
|
+
},
|
|
3551
|
+
/**
|
|
3552
|
+
* Denormalized Workspace display name — required to compose
|
|
3553
|
+
* pattern-#4 SK (`MEMBERSHIP#WORKSPACE#TID#<tenantId>#<normalizedWorkspaceName>#…`).
|
|
3554
|
+
* Optional on the schema (TR-024 § Open Item #4 defers a formal
|
|
3555
|
+
* Workspace-rename cascade); the operations layer falls back to a
|
|
3556
|
+
* sentinel when missing so the SK still has a valid shape.
|
|
3557
|
+
*/
|
|
3558
|
+
denormalizedWorkspaceName: {
|
|
3559
|
+
type: "string",
|
|
3560
|
+
required: false
|
|
3561
|
+
}
|
|
3562
|
+
},
|
|
3563
|
+
indexes: {
|
|
3564
|
+
/**
|
|
3565
|
+
* Base table: PK = USER#ID#<userId>, SK = operation-supplied.
|
|
3566
|
+
* Both pattern #3 and pattern #4 use this same index — the SK string
|
|
3567
|
+
* encodes the lane discriminator (`MEMBERSHIP#TENANT#…` vs
|
|
3568
|
+
* `MEMBERSHIP#WORKSPACE#…`) so a single `Query(PK = USER#ID#<userId>,
|
|
3569
|
+
* SK begins_with 'MEMBERSHIP#')` returns both lanes interleaved.
|
|
3570
|
+
*/
|
|
3571
|
+
record: {
|
|
3572
|
+
pk: {
|
|
3573
|
+
field: "PK",
|
|
3574
|
+
composite: ["userId"],
|
|
3575
|
+
template: "USER#ID#${userId}"
|
|
3576
|
+
},
|
|
3577
|
+
sk: {
|
|
3578
|
+
field: "SK",
|
|
3579
|
+
casing: "none",
|
|
3580
|
+
composite: ["sk"],
|
|
3581
|
+
template: "${sk}"
|
|
3582
|
+
}
|
|
3583
|
+
}
|
|
3584
|
+
}
|
|
3585
|
+
});
|
|
3586
|
+
|
|
3587
|
+
// src/data/dynamo/entities/control/membership-workspace-projection-entity.ts
|
|
3588
|
+
var import_electrodb6 = require("electrodb");
|
|
3589
|
+
var MembershipWorkspaceProjectionEntity = new import_electrodb6.Entity({
|
|
3590
|
+
model: {
|
|
3591
|
+
entity: "membershipWorkspaceProjection",
|
|
3592
|
+
service: "control",
|
|
3593
|
+
version: "01"
|
|
3594
|
+
},
|
|
3595
|
+
attributes: {
|
|
3596
|
+
/**
|
|
3597
|
+
* Tenant the workspace belongs to. Renders as the leading segment
|
|
3598
|
+
* of the base-table PK. Always required — the workspace partition
|
|
3599
|
+
* is tenant-scoped per ADR-011.
|
|
3600
|
+
*/
|
|
3601
|
+
tenantId: {
|
|
3602
|
+
type: "string",
|
|
3603
|
+
required: true
|
|
3604
|
+
},
|
|
3605
|
+
/**
|
|
3606
|
+
* Workspace partition discriminator. Renders as the trailing
|
|
3607
|
+
* segment of the base-table PK
|
|
3608
|
+
* (`TID#<tenantId>#WORKSPACE#ID#<workspaceId>`). Always required —
|
|
3609
|
+
* the projection has no meaning outside a workspace partition.
|
|
3610
|
+
*/
|
|
3611
|
+
workspaceId: {
|
|
3612
|
+
type: "string",
|
|
3613
|
+
required: true
|
|
3614
|
+
},
|
|
3615
|
+
/**
|
|
3616
|
+
* Pre-composed sort key — built by the operations-layer projection
|
|
3617
|
+
* writer via `buildMembershipWorkspaceProjectionSk`. The entity
|
|
3618
|
+
* stores the value verbatim so the SK grammar (pattern #2) is
|
|
3619
|
+
* owned by the operations layer, not duplicated here.
|
|
3620
|
+
*/
|
|
3621
|
+
sk: {
|
|
3622
|
+
type: "string",
|
|
3623
|
+
required: true
|
|
3624
|
+
},
|
|
3625
|
+
/**
|
|
3626
|
+
* User the membership links. Stored as a discriminating field so
|
|
3627
|
+
* consumers can hydrate the canonical User row via
|
|
3628
|
+
* `UserEntity.get({ id: userId, sk: "CURRENT" })` when the
|
|
3629
|
+
* projection's `summary` is insufficient.
|
|
3630
|
+
*/
|
|
3631
|
+
userId: {
|
|
3632
|
+
type: "string",
|
|
3633
|
+
required: true
|
|
3634
|
+
},
|
|
3635
|
+
/**
|
|
3636
|
+
* Membership canonical-record id. Stored as a discriminating field
|
|
3637
|
+
* so consumers can hydrate the canonical row via
|
|
3638
|
+
* `MembershipEntity.get({ tenantId, id: membershipId })` when the
|
|
3639
|
+
* projection's `summary` is insufficient.
|
|
3640
|
+
*/
|
|
3641
|
+
membershipId: {
|
|
3642
|
+
type: "string",
|
|
3643
|
+
required: true
|
|
3644
|
+
},
|
|
3645
|
+
/**
|
|
3646
|
+
* Summary projection (key display fields as JSON string: id,
|
|
3647
|
+
* displayName, status) — mirrored from the canonical Membership row
|
|
3648
|
+
* so workspace-partition queries do not need a BatchGet hop.
|
|
3649
|
+
*/
|
|
3650
|
+
summary: {
|
|
3651
|
+
type: "string",
|
|
3652
|
+
required: true
|
|
3653
|
+
},
|
|
3654
|
+
/** Version id mirrored from the canonical Membership row. */
|
|
3655
|
+
vid: {
|
|
3656
|
+
type: "string",
|
|
3657
|
+
required: true
|
|
3658
|
+
},
|
|
3659
|
+
/** Last-updated timestamp mirrored from the canonical Membership row. */
|
|
3660
|
+
lastUpdated: {
|
|
3661
|
+
type: "string",
|
|
3662
|
+
required: true
|
|
3663
|
+
},
|
|
3664
|
+
/**
|
|
3665
|
+
* Denormalized User display name — required to compose the
|
|
3666
|
+
* pattern-#2 SK (`MEMBERSHIP#<normalizedUserName>#…`). Optional on
|
|
3667
|
+
* the schema because pre-TR-024 rows may not carry a display name;
|
|
3668
|
+
* the operations layer falls back to a sentinel when missing so
|
|
3669
|
+
* the SK still has a valid shape. The TR-023 rename-cascade
|
|
3670
|
+
* pipeline rewrites the SK on a User rename.
|
|
3671
|
+
*/
|
|
3672
|
+
denormalizedUserName: {
|
|
3673
|
+
type: "string",
|
|
3674
|
+
required: false
|
|
3675
|
+
}
|
|
3676
|
+
},
|
|
3677
|
+
indexes: {
|
|
3678
|
+
/**
|
|
3679
|
+
* Base table: PK = TID#<tenantId>#WORKSPACE#ID#<workspaceId>,
|
|
3680
|
+
* SK = operation-supplied. Pattern #2 uses this index — the SK
|
|
3681
|
+
* encodes the entity-type prefix (`MEMBERSHIP#…`) so a
|
|
3682
|
+
* `Query(PK = TID#<tenantId>#WORKSPACE#ID#<workspaceId>, SK begins_with 'MEMBERSHIP#')`
|
|
3683
|
+
* returns every member projection for the workspace in normalized-
|
|
3684
|
+
* user-name sort order.
|
|
3685
|
+
*/
|
|
3686
|
+
record: {
|
|
3687
|
+
pk: {
|
|
3688
|
+
field: "PK",
|
|
3689
|
+
composite: ["tenantId", "workspaceId"],
|
|
3690
|
+
template: "TID#${tenantId}#WORKSPACE#ID#${workspaceId}"
|
|
3691
|
+
},
|
|
3692
|
+
sk: {
|
|
3693
|
+
field: "SK",
|
|
3694
|
+
casing: "none",
|
|
3695
|
+
composite: ["sk"],
|
|
3696
|
+
template: "${sk}"
|
|
3697
|
+
}
|
|
3698
|
+
}
|
|
3699
|
+
}
|
|
3700
|
+
});
|
|
3701
|
+
|
|
3702
|
+
// src/data/dynamo/entities/control/role-entity.ts
|
|
3703
|
+
var import_electrodb7 = require("electrodb");
|
|
3704
|
+
var RoleEntity = new import_electrodb7.Entity({
|
|
3705
|
+
model: {
|
|
3706
|
+
entity: "role",
|
|
3707
|
+
service: "control",
|
|
3708
|
+
version: "01"
|
|
3709
|
+
},
|
|
3710
|
+
attributes: {
|
|
3711
|
+
/** Sort key sentinel. Always "CURRENT". */
|
|
3712
|
+
sk: {
|
|
3713
|
+
type: "string",
|
|
3714
|
+
required: true,
|
|
3715
|
+
default: "CURRENT"
|
|
3716
|
+
},
|
|
3717
|
+
/** FHIR Resource.id; role id. */
|
|
3718
|
+
id: {
|
|
3719
|
+
type: "string",
|
|
3720
|
+
required: true
|
|
3721
|
+
},
|
|
3722
|
+
/** Full Role resource serialized as JSON string. */
|
|
3723
|
+
resource: {
|
|
3724
|
+
type: "string",
|
|
3725
|
+
required: true
|
|
3726
|
+
},
|
|
3727
|
+
/**
|
|
3728
|
+
* Summary projection (key display fields as JSON string: id, displayName, status).
|
|
3729
|
+
* Populated on every write via extractSummary(resource); GSI1 INCLUDE surfaces it on lists.
|
|
3730
|
+
*/
|
|
3731
|
+
summary: {
|
|
3732
|
+
type: "string",
|
|
3733
|
+
required: true
|
|
3734
|
+
},
|
|
3735
|
+
/** Version id (e.g. ULID). */
|
|
3736
|
+
vid: {
|
|
3737
|
+
type: "string",
|
|
3738
|
+
required: true
|
|
3739
|
+
},
|
|
3740
|
+
lastUpdated: {
|
|
3741
|
+
type: "string",
|
|
3742
|
+
required: true
|
|
3743
|
+
},
|
|
3744
|
+
gsi1Shard: gsi1ShardAttribute,
|
|
3745
|
+
/** Derived GSI1 sort key — name-based when extractable; else `<lastUpdated>#<id>`. */
|
|
3746
|
+
gsi1sk: gsi1skAttribute,
|
|
3747
|
+
deleted: {
|
|
3748
|
+
type: "boolean",
|
|
3749
|
+
required: false
|
|
3750
|
+
},
|
|
3751
|
+
bundleId: {
|
|
3752
|
+
type: "string",
|
|
3753
|
+
required: false
|
|
3754
|
+
},
|
|
3755
|
+
msgId: {
|
|
3756
|
+
type: "string",
|
|
3757
|
+
required: false
|
|
3758
|
+
}
|
|
3759
|
+
},
|
|
3760
|
+
indexes: {
|
|
3761
|
+
/** Base table: PK = ROLE#ID#<id>, SK = CURRENT. Do not supply PK or SK from outside. */
|
|
3762
|
+
record: {
|
|
3763
|
+
pk: {
|
|
3764
|
+
field: "PK",
|
|
3765
|
+
composite: ["id"],
|
|
3766
|
+
template: "ROLE#ID#${id}"
|
|
3767
|
+
},
|
|
3768
|
+
sk: {
|
|
3769
|
+
field: "SK",
|
|
3770
|
+
composite: ["sk"],
|
|
3771
|
+
template: "${sk}"
|
|
3772
|
+
}
|
|
3773
|
+
},
|
|
3774
|
+
/**
|
|
3775
|
+
* GSI1 — Unified Sharded List per ADR-011: list all Roles across the four shards.
|
|
3776
|
+
* Non-tenant-isolated, so `TID#-#WID#-` sentinels precede `RT#Role#SHARD#<n>`.
|
|
3777
|
+
* SK is derived via `gsi1skAttribute` — uses the resource's natural label when
|
|
3778
|
+
* extractable, else `<lastUpdated>#<id>` (DR-004). `casing: "none"` preserves the
|
|
3779
|
+
* normalized label and ISO-8601 `T`/`Z`.
|
|
3780
|
+
*/
|
|
3781
|
+
gsi1: {
|
|
3782
|
+
index: "GSI1",
|
|
3783
|
+
pk: {
|
|
3784
|
+
field: "GSI1PK",
|
|
3785
|
+
composite: ["gsi1Shard"],
|
|
3786
|
+
template: "TID#-#WID#-#RT#Role#SHARD#${gsi1Shard}"
|
|
3787
|
+
},
|
|
3788
|
+
sk: {
|
|
3789
|
+
field: "GSI1SK",
|
|
3790
|
+
casing: "none",
|
|
3791
|
+
composite: ["gsi1sk"],
|
|
3792
|
+
template: "${gsi1sk}"
|
|
3793
|
+
}
|
|
3794
|
+
}
|
|
3795
|
+
}
|
|
3796
|
+
});
|
|
3797
|
+
|
|
3798
|
+
// src/data/dynamo/entities/control/roleassignment-entity.ts
|
|
3799
|
+
var import_electrodb8 = require("electrodb");
|
|
3800
|
+
var RoleAssignmentEntity = new import_electrodb8.Entity({
|
|
3801
|
+
model: {
|
|
3802
|
+
entity: "roleassignment",
|
|
3803
|
+
service: "control",
|
|
3804
|
+
version: "01"
|
|
3805
|
+
},
|
|
3806
|
+
attributes: {
|
|
3807
|
+
/** Sort key sentinel. Always "CURRENT". */
|
|
3808
|
+
sk: {
|
|
3809
|
+
type: "string",
|
|
3810
|
+
required: true,
|
|
3811
|
+
default: "CURRENT"
|
|
3812
|
+
},
|
|
3813
|
+
/** Tenant in which the role assignment applies (required). */
|
|
3814
|
+
tenantId: {
|
|
3815
|
+
type: "string",
|
|
3816
|
+
required: true
|
|
3817
|
+
},
|
|
3818
|
+
/** FHIR Resource.id; role assignment id. */
|
|
3819
|
+
id: {
|
|
3820
|
+
type: "string",
|
|
3821
|
+
required: true
|
|
3822
|
+
},
|
|
3823
|
+
/** Full RoleAssignment resource serialized as JSON string. */
|
|
3824
|
+
resource: {
|
|
3825
|
+
type: "string",
|
|
3826
|
+
required: true
|
|
3827
|
+
},
|
|
3828
|
+
/**
|
|
3829
|
+
* Summary projection (key display fields as JSON string: id, displayName, status).
|
|
3830
|
+
* Populated on every write via extractSummary(resource); GSI1 INCLUDE surfaces it on lists.
|
|
3831
|
+
*/
|
|
3832
|
+
summary: {
|
|
3833
|
+
type: "string",
|
|
3834
|
+
required: true
|
|
3835
|
+
},
|
|
3836
|
+
/** Version id (e.g. ULID). */
|
|
3837
|
+
vid: {
|
|
3838
|
+
type: "string",
|
|
3839
|
+
required: true
|
|
3840
|
+
},
|
|
3841
|
+
lastUpdated: {
|
|
3842
|
+
type: "string",
|
|
3843
|
+
required: true
|
|
3844
|
+
},
|
|
3845
|
+
gsi1Shard: gsi1ShardAttribute,
|
|
3846
|
+
/**
|
|
3847
|
+
* Derived GSI1 sort key — discriminator-first
|
|
3848
|
+
* `<roleId>#<normalizedUserName>#<id>` per ADR-018 pattern #8 so a
|
|
3849
|
+
* GSI1 query partitioned on the tenant can `begins_with('<roleId>#')`
|
|
3850
|
+
* to enumerate every user assigned to a given role, sorted by user
|
|
3851
|
+
* name. Falls back to `<lastUpdated>#<id>` when either component is
|
|
3852
|
+
* missing.
|
|
3853
|
+
*/
|
|
3854
|
+
gsi1sk: roleAssignmentGsi1skAttribute,
|
|
3855
|
+
deleted: {
|
|
3856
|
+
type: "boolean",
|
|
3857
|
+
required: false
|
|
3858
|
+
},
|
|
3859
|
+
bundleId: {
|
|
3860
|
+
type: "string",
|
|
3861
|
+
required: false
|
|
3862
|
+
},
|
|
3863
|
+
msgId: {
|
|
3864
|
+
type: "string",
|
|
3865
|
+
required: false
|
|
3866
|
+
},
|
|
3867
|
+
/**
|
|
3868
|
+
* Denormalized display name of the linked Tenant, captured at row
|
|
3869
|
+
* last-write time. Promoted to a top-level attribute so the ADR-018
|
|
3870
|
+
* adjacency-list user-projection SK (pattern #5 —
|
|
3871
|
+
* `ROLEASSIGNMENT#TENANT#<normalizedRoleName>#<roleId>#TID#<tenantId>#<id>`)
|
|
3872
|
+
* can be composed from a top-level field instead of digging into the
|
|
3873
|
+
* `resource` JSON. Optional on the schema so pre-TR-024 rows do not
|
|
3874
|
+
* break; the operations-layer multi-write helper (#1010) makes the
|
|
3875
|
+
* field load-bearing at write time per TR-024 rule 2 (write-time
|
|
3876
|
+
* source = canonical Tenant.displayName).
|
|
3877
|
+
* @see TR-024 — Denormalized display-name attributes
|
|
3878
|
+
*/
|
|
3879
|
+
denormalizedTenantName: {
|
|
3880
|
+
type: "string",
|
|
3881
|
+
required: false
|
|
3882
|
+
},
|
|
3883
|
+
/**
|
|
3884
|
+
* Denormalized display name of the linked User, captured at row
|
|
3885
|
+
* last-write time. Promoted to a top-level attribute so the ADR-018
|
|
3886
|
+
* adjacency-list canonical-record GSI1SK (pattern #8 —
|
|
3887
|
+
* `<roleId>#<normalizedUserName>#<id>`) and workspace-projection SK
|
|
3888
|
+
* (pattern #9) can be composed from a top-level field. Optional on
|
|
3889
|
+
* the schema so pre-TR-024 rows do not break; the operations-layer
|
|
3890
|
+
* multi-write helper (#1010) makes the field load-bearing at write
|
|
3891
|
+
* time per TR-024 rule 2 (write-time source = canonical
|
|
3892
|
+
* User.displayName).
|
|
3893
|
+
* @see TR-024 — Denormalized display-name attributes
|
|
3894
|
+
*/
|
|
3895
|
+
denormalizedUserName: {
|
|
3896
|
+
type: "string",
|
|
3897
|
+
required: false
|
|
3898
|
+
},
|
|
3899
|
+
/**
|
|
3900
|
+
* Denormalized display name of the linked Role, captured at row
|
|
3901
|
+
* last-write time. Promoted to a top-level attribute so the ADR-018
|
|
3902
|
+
* adjacency-list user-projection SK (pattern #5 —
|
|
3903
|
+
* `ROLEASSIGNMENT#TENANT#<normalizedRoleName>#…`) can be composed from
|
|
3904
|
+
* a top-level field. Optional on the schema so pre-TR-024 rows do not
|
|
3905
|
+
* break; the operations-layer multi-write helper (#1010) makes the
|
|
3906
|
+
* field load-bearing at write time per TR-024 rule 2 (write-time
|
|
3907
|
+
* source = canonical Role.displayName).
|
|
3908
|
+
* @see TR-024 — Denormalized display-name attributes
|
|
3909
|
+
*/
|
|
3910
|
+
denormalizedRoleName: {
|
|
3911
|
+
type: "string",
|
|
3912
|
+
required: false
|
|
3913
|
+
}
|
|
3914
|
+
},
|
|
3915
|
+
indexes: {
|
|
3916
|
+
/** Base table: PK = TID#<tenantId>#ROLEASSIGNMENT#ID#<id>, SK = CURRENT. Do not supply PK or SK from outside. */
|
|
3917
|
+
record: {
|
|
3918
|
+
pk: {
|
|
3919
|
+
field: "PK",
|
|
3920
|
+
composite: ["tenantId", "id"],
|
|
3921
|
+
template: "TID#${tenantId}#ROLEASSIGNMENT#ID#${id}"
|
|
3922
|
+
},
|
|
3923
|
+
sk: {
|
|
3924
|
+
field: "SK",
|
|
3925
|
+
composite: ["sk"],
|
|
3926
|
+
template: "${sk}"
|
|
3927
|
+
}
|
|
3928
|
+
},
|
|
3929
|
+
/**
|
|
3930
|
+
* GSI1 — Unified Sharded List per ADR-011: list all RoleAssignments for a tenant across the
|
|
3931
|
+
* four shards. Tenant-scoped only, so `WID#-` is a sentinel.
|
|
3932
|
+
* SK is derived via `roleAssignmentGsi1skAttribute` — composes the
|
|
3933
|
+
* discriminator-first `<roleId>#<normalizedUserName>#<id>` shape per
|
|
3934
|
+
* ADR-018 pattern #8 (users with a specific role in a tenant, sorted
|
|
3935
|
+
* by user name); falls back to `<lastUpdated>#<id>` when either
|
|
3936
|
+
* component is missing. `casing: "none"` preserves the normalized
|
|
3937
|
+
* label and ISO-8601 `T`/`Z`.
|
|
3938
|
+
*/
|
|
3939
|
+
gsi1: {
|
|
3940
|
+
index: "GSI1",
|
|
3941
|
+
pk: {
|
|
3942
|
+
field: "GSI1PK",
|
|
3943
|
+
composite: ["tenantId", "gsi1Shard"],
|
|
3944
|
+
template: "TID#${tenantId}#WID#-#RT#RoleAssignment#SHARD#${gsi1Shard}"
|
|
3945
|
+
},
|
|
3946
|
+
sk: {
|
|
3947
|
+
field: "GSI1SK",
|
|
3948
|
+
casing: "none",
|
|
3949
|
+
composite: ["gsi1sk"],
|
|
3950
|
+
template: "${gsi1sk}"
|
|
3951
|
+
}
|
|
3952
|
+
}
|
|
3953
|
+
}
|
|
3954
|
+
});
|
|
3955
|
+
|
|
3956
|
+
// src/data/dynamo/entities/control/roleassignment-user-projection-entity.ts
|
|
3957
|
+
var import_electrodb9 = require("electrodb");
|
|
3958
|
+
var RoleAssignmentUserProjectionEntity = new import_electrodb9.Entity({
|
|
3959
|
+
model: {
|
|
3960
|
+
entity: "roleAssignmentUserProjection",
|
|
3961
|
+
service: "control",
|
|
3962
|
+
version: "01"
|
|
3963
|
+
},
|
|
3964
|
+
attributes: {
|
|
3965
|
+
/**
|
|
3966
|
+
* User partition discriminator. Renders as `USER#ID#<userId>` on the
|
|
3967
|
+
* base-table PK. Always required — the projection has no meaning
|
|
3968
|
+
* outside a user partition.
|
|
3969
|
+
*/
|
|
3970
|
+
userId: {
|
|
3971
|
+
type: "string",
|
|
3972
|
+
required: true
|
|
3973
|
+
},
|
|
3974
|
+
/**
|
|
3975
|
+
* Pre-composed sort key — built by the operations-layer projection
|
|
3976
|
+
* writer via `buildRoleAssignmentUserProjectionSk*` helpers. The
|
|
3977
|
+
* entity stores the value verbatim so the SK grammar (tenant-lane
|
|
3978
|
+
* vs workspace-lane) is owned by the operations layer, not
|
|
3979
|
+
* duplicated here.
|
|
3980
|
+
*/
|
|
3981
|
+
sk: {
|
|
3982
|
+
type: "string",
|
|
3983
|
+
required: true
|
|
3984
|
+
},
|
|
3985
|
+
/** Tenant in which the role assignment applies. Always required. */
|
|
3986
|
+
tenantId: {
|
|
3987
|
+
type: "string",
|
|
3988
|
+
required: true
|
|
3989
|
+
},
|
|
3990
|
+
/**
|
|
3991
|
+
* Workspace the role assignment scopes to. Present iff the
|
|
3992
|
+
* projection row is the workspace-level sub-lane; absent for
|
|
3993
|
+
* tenant-level sub-lane rows.
|
|
3994
|
+
*/
|
|
3995
|
+
workspaceId: {
|
|
3996
|
+
type: "string",
|
|
3997
|
+
required: false
|
|
3998
|
+
},
|
|
3999
|
+
/**
|
|
4000
|
+
* Role the assignment grants. Stored as a discriminating field so
|
|
4001
|
+
* `Query(PK = USER#ID#<userId>, SK begins_with 'ROLEASSIGNMENT#…')`
|
|
4002
|
+
* results carry the role id without a hop to the canonical row.
|
|
4003
|
+
*/
|
|
4004
|
+
roleId: {
|
|
4005
|
+
type: "string",
|
|
4006
|
+
required: true
|
|
4007
|
+
},
|
|
4008
|
+
/**
|
|
4009
|
+
* RoleAssignment canonical-record id. Stored as a discriminating
|
|
4010
|
+
* field so consumers can hydrate the canonical row via
|
|
4011
|
+
* `RoleAssignmentEntity.get({ tenantId, id: roleAssignmentId })`
|
|
4012
|
+
* when the projection's `summary` is insufficient.
|
|
4013
|
+
*/
|
|
4014
|
+
roleAssignmentId: {
|
|
4015
|
+
type: "string",
|
|
4016
|
+
required: true
|
|
4017
|
+
},
|
|
4018
|
+
/**
|
|
4019
|
+
* Summary projection (key display fields as JSON string: id,
|
|
4020
|
+
* displayName, status) — mirrored from the canonical RoleAssignment
|
|
4021
|
+
* row so user-partition queries do not need a BatchGet hop.
|
|
4022
|
+
*/
|
|
4023
|
+
summary: {
|
|
4024
|
+
type: "string",
|
|
4025
|
+
required: true
|
|
4026
|
+
},
|
|
4027
|
+
/** Version id mirrored from the canonical RoleAssignment row. */
|
|
4028
|
+
vid: {
|
|
4029
|
+
type: "string",
|
|
4030
|
+
required: true
|
|
4031
|
+
},
|
|
4032
|
+
/** Last-updated timestamp mirrored from the canonical RoleAssignment row. */
|
|
4033
|
+
lastUpdated: {
|
|
4034
|
+
type: "string",
|
|
4035
|
+
required: true
|
|
4036
|
+
},
|
|
4037
|
+
/**
|
|
4038
|
+
* Denormalized Tenant display name — mirrored from the canonical
|
|
4039
|
+
* RoleAssignment row per TR-024 rule 3 (canonical-record symmetry).
|
|
4040
|
+
* Optional on the schema because pre-TR-024 rows may not carry a
|
|
4041
|
+
* display name; the operations layer falls back gracefully when
|
|
4042
|
+
* missing.
|
|
4043
|
+
*/
|
|
4044
|
+
denormalizedTenantName: {
|
|
4045
|
+
type: "string",
|
|
4046
|
+
required: false
|
|
4047
|
+
},
|
|
4048
|
+
/**
|
|
4049
|
+
* Denormalized User display name — mirrored from the canonical
|
|
4050
|
+
* RoleAssignment row per TR-024 rule 3 (canonical-record symmetry).
|
|
4051
|
+
* Carried on the projection so consumers can render the user's
|
|
4052
|
+
* display name without a hop to the User record.
|
|
4053
|
+
*/
|
|
4054
|
+
denormalizedUserName: {
|
|
4055
|
+
type: "string",
|
|
4056
|
+
required: false
|
|
4057
|
+
},
|
|
4058
|
+
/**
|
|
4059
|
+
* Denormalized Role display name — required to compose the SK's
|
|
4060
|
+
* `<normalizedRoleName>` segment. Optional on the schema (pre-TR-024
|
|
4061
|
+
* rows fall back to a sentinel) but expected to be present at write
|
|
4062
|
+
* time per TR-024 rule 2 (write-time source =
|
|
4063
|
+
* canonical Role.displayName).
|
|
4064
|
+
*/
|
|
4065
|
+
denormalizedRoleName: {
|
|
4066
|
+
type: "string",
|
|
4067
|
+
required: false
|
|
4068
|
+
}
|
|
4069
|
+
},
|
|
4070
|
+
indexes: {
|
|
4071
|
+
/**
|
|
4072
|
+
* Base table: PK = USER#ID#<userId>, SK = operation-supplied. Both
|
|
4073
|
+
* sub-lanes (tenant-level and workspace-level) use this same index —
|
|
4074
|
+
* the SK string encodes the lane discriminator
|
|
4075
|
+
* (`ROLEASSIGNMENT#TENANT#…` vs `ROLEASSIGNMENT#WORKSPACE#…`) so a
|
|
4076
|
+
* single `Query(PK = USER#ID#<userId>, SK begins_with
|
|
4077
|
+
* 'ROLEASSIGNMENT#')` returns both lanes interleaved.
|
|
4078
|
+
*/
|
|
4079
|
+
record: {
|
|
4080
|
+
pk: {
|
|
4081
|
+
field: "PK",
|
|
4082
|
+
composite: ["userId"],
|
|
4083
|
+
template: "USER#ID#${userId}"
|
|
4084
|
+
},
|
|
4085
|
+
sk: {
|
|
3210
4086
|
field: "SK",
|
|
4087
|
+
casing: "none",
|
|
3211
4088
|
composite: ["sk"],
|
|
3212
4089
|
template: "${sk}"
|
|
3213
4090
|
}
|
|
4091
|
+
}
|
|
4092
|
+
}
|
|
4093
|
+
});
|
|
4094
|
+
|
|
4095
|
+
// src/data/dynamo/entities/control/roleassignment-workspace-projection-entity.ts
|
|
4096
|
+
var import_electrodb10 = require("electrodb");
|
|
4097
|
+
var RoleAssignmentWorkspaceProjectionEntity = new import_electrodb10.Entity({
|
|
4098
|
+
model: {
|
|
4099
|
+
entity: "roleAssignmentWorkspaceProjection",
|
|
4100
|
+
service: "control",
|
|
4101
|
+
version: "01"
|
|
4102
|
+
},
|
|
4103
|
+
attributes: {
|
|
4104
|
+
/**
|
|
4105
|
+
* Tenant the workspace belongs to. Renders as the leading segment
|
|
4106
|
+
* of the base-table PK. Always required — the workspace partition
|
|
4107
|
+
* is tenant-scoped per ADR-011.
|
|
4108
|
+
*/
|
|
4109
|
+
tenantId: {
|
|
4110
|
+
type: "string",
|
|
4111
|
+
required: true
|
|
3214
4112
|
},
|
|
3215
4113
|
/**
|
|
3216
|
-
*
|
|
3217
|
-
*
|
|
3218
|
-
*
|
|
3219
|
-
*
|
|
3220
|
-
* normalized label and ISO-8601 `T`/`Z`.
|
|
4114
|
+
* Workspace partition discriminator. Renders as the trailing
|
|
4115
|
+
* segment of the base-table PK
|
|
4116
|
+
* (`TID#<tenantId>#WORKSPACE#ID#<workspaceId>`). Always required —
|
|
4117
|
+
* the projection has no meaning outside a workspace partition.
|
|
3221
4118
|
*/
|
|
3222
|
-
|
|
3223
|
-
|
|
4119
|
+
workspaceId: {
|
|
4120
|
+
type: "string",
|
|
4121
|
+
required: true
|
|
4122
|
+
},
|
|
4123
|
+
/**
|
|
4124
|
+
* Pre-composed sort key — built by the operations-layer projection
|
|
4125
|
+
* writer via `buildRoleAssignmentWorkspaceProjectionSk`. The entity
|
|
4126
|
+
* stores the value verbatim so the SK grammar (pattern #9) is
|
|
4127
|
+
* owned by the operations layer, not duplicated here.
|
|
4128
|
+
*/
|
|
4129
|
+
sk: {
|
|
4130
|
+
type: "string",
|
|
4131
|
+
required: true
|
|
4132
|
+
},
|
|
4133
|
+
/**
|
|
4134
|
+
* User the role assignment grants the role to. Stored as a
|
|
4135
|
+
* discriminating field so consumers can hydrate the canonical User
|
|
4136
|
+
* row via `UserEntity.get({ id: userId, sk: "CURRENT" })` when the
|
|
4137
|
+
* projection's `summary` is insufficient.
|
|
4138
|
+
*/
|
|
4139
|
+
userId: {
|
|
4140
|
+
type: "string",
|
|
4141
|
+
required: true
|
|
4142
|
+
},
|
|
4143
|
+
/**
|
|
4144
|
+
* Role the assignment grants. Stored as a discriminating field —
|
|
4145
|
+
* also rendered into the SK as the discriminator-first segment so
|
|
4146
|
+
* `begins_with('ROLEASSIGNMENT#<roleId>#')` filters one role.
|
|
4147
|
+
*/
|
|
4148
|
+
roleId: {
|
|
4149
|
+
type: "string",
|
|
4150
|
+
required: true
|
|
4151
|
+
},
|
|
4152
|
+
/**
|
|
4153
|
+
* RoleAssignment canonical-record id. Stored as a discriminating
|
|
4154
|
+
* field so consumers can hydrate the canonical row via
|
|
4155
|
+
* `RoleAssignmentEntity.get({ tenantId, id: roleAssignmentId })`
|
|
4156
|
+
* when the projection's `summary` is insufficient.
|
|
4157
|
+
*/
|
|
4158
|
+
roleAssignmentId: {
|
|
4159
|
+
type: "string",
|
|
4160
|
+
required: true
|
|
4161
|
+
},
|
|
4162
|
+
/**
|
|
4163
|
+
* Summary projection (key display fields as JSON string: id,
|
|
4164
|
+
* displayName, status) — mirrored from the canonical RoleAssignment
|
|
4165
|
+
* row so workspace-partition queries do not need a BatchGet hop.
|
|
4166
|
+
*/
|
|
4167
|
+
summary: {
|
|
4168
|
+
type: "string",
|
|
4169
|
+
required: true
|
|
4170
|
+
},
|
|
4171
|
+
/** Version id mirrored from the canonical RoleAssignment row. */
|
|
4172
|
+
vid: {
|
|
4173
|
+
type: "string",
|
|
4174
|
+
required: true
|
|
4175
|
+
},
|
|
4176
|
+
/** Last-updated timestamp mirrored from the canonical RoleAssignment row. */
|
|
4177
|
+
lastUpdated: {
|
|
4178
|
+
type: "string",
|
|
4179
|
+
required: true
|
|
4180
|
+
},
|
|
4181
|
+
/**
|
|
4182
|
+
* Denormalized User display name — required to compose the
|
|
4183
|
+
* pattern-#9 SK (`ROLEASSIGNMENT#<roleId>#<normalizedUserName>#…`).
|
|
4184
|
+
* Optional on the schema because pre-TR-024 rows may not carry a
|
|
4185
|
+
* display name; the operations layer falls back to a sentinel when
|
|
4186
|
+
* missing so the SK still has a valid shape. The TR-023 rename-
|
|
4187
|
+
* cascade pipeline rewrites the SK on a User rename.
|
|
4188
|
+
*/
|
|
4189
|
+
denormalizedUserName: {
|
|
4190
|
+
type: "string",
|
|
4191
|
+
required: false
|
|
4192
|
+
},
|
|
4193
|
+
/**
|
|
4194
|
+
* Denormalized Role display name — mirrored from the canonical
|
|
4195
|
+
* RoleAssignment row per TR-024 rule 3 (canonical-record symmetry).
|
|
4196
|
+
* Carried on the projection so consumers can render the role's
|
|
4197
|
+
* display name without a hop to the Role record. Not part of the
|
|
4198
|
+
* SK (pattern #9 sorts on `<normalizedUserName>`, not role name) —
|
|
4199
|
+
* a Role rename does NOT rewrite this SK.
|
|
4200
|
+
*/
|
|
4201
|
+
denormalizedRoleName: {
|
|
4202
|
+
type: "string",
|
|
4203
|
+
required: false
|
|
4204
|
+
}
|
|
4205
|
+
},
|
|
4206
|
+
indexes: {
|
|
4207
|
+
/**
|
|
4208
|
+
* Base table: PK = TID#<tenantId>#WORKSPACE#ID#<workspaceId>,
|
|
4209
|
+
* SK = operation-supplied. Pattern #9 uses this index — the SK
|
|
4210
|
+
* encodes the entity-type prefix and discriminator-first roleId
|
|
4211
|
+
* (`ROLEASSIGNMENT#<roleId>#…`) so
|
|
4212
|
+
* `Query(PK = TID#<tenantId>#WORKSPACE#ID#<workspaceId>, SK begins_with 'ROLEASSIGNMENT#<roleId>#')`
|
|
4213
|
+
* returns every user-assignment for that role in the workspace, sorted
|
|
4214
|
+
* by normalized user name.
|
|
4215
|
+
*/
|
|
4216
|
+
record: {
|
|
3224
4217
|
pk: {
|
|
3225
|
-
field: "
|
|
3226
|
-
composite: ["tenantId", "
|
|
3227
|
-
template: "TID#${tenantId}#
|
|
4218
|
+
field: "PK",
|
|
4219
|
+
composite: ["tenantId", "workspaceId"],
|
|
4220
|
+
template: "TID#${tenantId}#WORKSPACE#ID#${workspaceId}"
|
|
3228
4221
|
},
|
|
3229
4222
|
sk: {
|
|
3230
|
-
field: "
|
|
4223
|
+
field: "SK",
|
|
3231
4224
|
casing: "none",
|
|
3232
|
-
composite: ["
|
|
3233
|
-
template: "${
|
|
4225
|
+
composite: ["sk"],
|
|
4226
|
+
template: "${sk}"
|
|
3234
4227
|
}
|
|
3235
4228
|
}
|
|
3236
4229
|
}
|
|
3237
4230
|
});
|
|
3238
4231
|
|
|
3239
4232
|
// src/data/dynamo/entities/control/tenant-entity.ts
|
|
3240
|
-
var
|
|
3241
|
-
var TenantEntity = new
|
|
4233
|
+
var import_electrodb11 = require("electrodb");
|
|
4234
|
+
var TenantEntity = new import_electrodb11.Entity({
|
|
3242
4235
|
model: {
|
|
3243
4236
|
entity: "tenant",
|
|
3244
4237
|
service: "control",
|
|
@@ -3338,8 +4331,8 @@ var TenantEntity = new import_electrodb5.Entity({
|
|
|
3338
4331
|
});
|
|
3339
4332
|
|
|
3340
4333
|
// src/data/dynamo/entities/control/user-entity.ts
|
|
3341
|
-
var
|
|
3342
|
-
var UserEntity = new
|
|
4334
|
+
var import_electrodb12 = require("electrodb");
|
|
4335
|
+
var UserEntity = new import_electrodb12.Entity({
|
|
3343
4336
|
model: {
|
|
3344
4337
|
entity: "user",
|
|
3345
4338
|
service: "control",
|
|
@@ -3394,6 +4387,28 @@ var UserEntity = new import_electrodb6.Entity({
|
|
|
3394
4387
|
type: "boolean",
|
|
3395
4388
|
required: false
|
|
3396
4389
|
},
|
|
4390
|
+
/**
|
|
4391
|
+
* TR-022 / ADR-018 lifecycle state for the cascade pipeline.
|
|
4392
|
+
*
|
|
4393
|
+
* - `active` (or undefined) — normal, readable state.
|
|
4394
|
+
* - `deleting` — intermediate state set synchronously by the
|
|
4395
|
+
* hard-delete API entry point. The owning-delete cascade state
|
|
4396
|
+
* machine fans out from this transition (DynamoDB stream →
|
|
4397
|
+
* `control-plane.owning-delete.v1` → Step Functions). Readers MUST
|
|
4398
|
+
* short-circuit on `deleting` so partial cascades stay invisible.
|
|
4399
|
+
* - `deleted-failed` — terminal failure state set by the cascade
|
|
4400
|
+
* finalize Lambda when the cascade run fails irrecoverably.
|
|
4401
|
+
* Operators recover by re-running the cascade or by direct
|
|
4402
|
+
* intervention.
|
|
4403
|
+
*
|
|
4404
|
+
* The cascade finalize step deletes the canonical record conditional
|
|
4405
|
+
* on `lifecycleState = "deleting"`; on replay the conditional check
|
|
4406
|
+
* fails and the finalize step treats that as a no-op success.
|
|
4407
|
+
*/
|
|
4408
|
+
lifecycleState: {
|
|
4409
|
+
type: ["active", "deleting", "deleted-failed"],
|
|
4410
|
+
required: false
|
|
4411
|
+
},
|
|
3397
4412
|
bundleId: {
|
|
3398
4413
|
type: "string",
|
|
3399
4414
|
required: false
|
|
@@ -3463,8 +4478,8 @@ var UserEntity = new import_electrodb6.Entity({
|
|
|
3463
4478
|
});
|
|
3464
4479
|
|
|
3465
4480
|
// src/data/dynamo/entities/control/workspace-entity.ts
|
|
3466
|
-
var
|
|
3467
|
-
var WorkspaceEntity = new
|
|
4481
|
+
var import_electrodb13 = require("electrodb");
|
|
4482
|
+
var WorkspaceEntity = new import_electrodb13.Entity({
|
|
3468
4483
|
model: {
|
|
3469
4484
|
entity: "workspace",
|
|
3470
4485
|
service: "control",
|
|
@@ -3516,6 +4531,28 @@ var WorkspaceEntity = new import_electrodb7.Entity({
|
|
|
3516
4531
|
type: "boolean",
|
|
3517
4532
|
required: false
|
|
3518
4533
|
},
|
|
4534
|
+
/**
|
|
4535
|
+
* TR-022 / ADR-018 lifecycle state for the cascade pipeline.
|
|
4536
|
+
*
|
|
4537
|
+
* - `active` (or undefined) — normal, readable state.
|
|
4538
|
+
* - `deleting` — intermediate state set synchronously by the
|
|
4539
|
+
* hard-delete API entry point. The owning-delete cascade state
|
|
4540
|
+
* machine fans out from this transition (DynamoDB stream →
|
|
4541
|
+
* `control-plane.owning-delete.v1` → Step Functions). Readers MUST
|
|
4542
|
+
* short-circuit on `deleting` so partial cascades stay invisible.
|
|
4543
|
+
* - `deleted-failed` — terminal failure state set by the cascade
|
|
4544
|
+
* finalize Lambda when the cascade run fails irrecoverably.
|
|
4545
|
+
* Operators recover by re-running the cascade or by direct
|
|
4546
|
+
* intervention.
|
|
4547
|
+
*
|
|
4548
|
+
* The cascade finalize step deletes the canonical record conditional
|
|
4549
|
+
* on `lifecycleState = "deleting"`; on replay the conditional check
|
|
4550
|
+
* fails and the finalize step treats that as a no-op success.
|
|
4551
|
+
*/
|
|
4552
|
+
lifecycleState: {
|
|
4553
|
+
type: ["active", "deleting", "deleted-failed"],
|
|
4554
|
+
required: false
|
|
4555
|
+
},
|
|
3519
4556
|
bundleId: {
|
|
3520
4557
|
type: "string",
|
|
3521
4558
|
required: false
|
|
@@ -3566,38 +4603,57 @@ var WorkspaceEntity = new import_electrodb7.Entity({
|
|
|
3566
4603
|
// src/data/dynamo/dynamo-control-service.ts
|
|
3567
4604
|
var controlPlaneEntities = {
|
|
3568
4605
|
configuration: ConfigurationEntity,
|
|
4606
|
+
configurationUserProjection: ConfigurationUserProjectionEntity,
|
|
4607
|
+
configurationWorkspaceProjection: ConfigurationWorkspaceProjectionEntity,
|
|
3569
4608
|
membership: MembershipEntity,
|
|
4609
|
+
membershipUserProjection: MembershipUserProjectionEntity,
|
|
4610
|
+
membershipWorkspaceProjection: MembershipWorkspaceProjectionEntity,
|
|
3570
4611
|
role: RoleEntity,
|
|
3571
4612
|
roleAssignment: RoleAssignmentEntity,
|
|
4613
|
+
roleAssignmentUserProjection: RoleAssignmentUserProjectionEntity,
|
|
4614
|
+
roleAssignmentWorkspaceProjection: RoleAssignmentWorkspaceProjectionEntity,
|
|
3572
4615
|
tenant: TenantEntity,
|
|
3573
4616
|
user: UserEntity,
|
|
3574
4617
|
workspace: WorkspaceEntity
|
|
3575
4618
|
};
|
|
3576
|
-
var controlPlaneService = new
|
|
4619
|
+
var controlPlaneService = new import_electrodb14.Service(controlPlaneEntities, {
|
|
3577
4620
|
table: defaultTableName,
|
|
3578
4621
|
client: dynamoClient
|
|
3579
4622
|
});
|
|
3580
4623
|
var DynamoControlService = {
|
|
3581
|
-
entities: controlPlaneService.entities
|
|
4624
|
+
entities: controlPlaneService.entities,
|
|
4625
|
+
transaction: controlPlaneService.transaction
|
|
3582
4626
|
};
|
|
3583
4627
|
|
|
3584
4628
|
// src/data/operations/control/membership/membership-create-operation.ts
|
|
4629
|
+
var import_types5 = require("@openhi/types");
|
|
4630
|
+
|
|
4631
|
+
// src/data/operations/control/membership/membership-user-projection.ts
|
|
3585
4632
|
var import_types3 = require("@openhi/types");
|
|
3586
4633
|
|
|
3587
|
-
// src/data/operations/control/
|
|
4634
|
+
// src/data/operations/control/membership/membership-workspace-projection.ts
|
|
3588
4635
|
var import_types4 = require("@openhi/types");
|
|
3589
4636
|
|
|
4637
|
+
// src/data/operations/control/roleassignment/roleassignment-create-operation.ts
|
|
4638
|
+
var import_types8 = require("@openhi/types");
|
|
4639
|
+
|
|
4640
|
+
// src/data/operations/control/roleassignment/roleassignment-user-projection.ts
|
|
4641
|
+
var import_types6 = require("@openhi/types");
|
|
4642
|
+
|
|
4643
|
+
// src/data/operations/control/roleassignment/roleassignment-workspace-projection.ts
|
|
4644
|
+
var import_types7 = require("@openhi/types");
|
|
4645
|
+
|
|
3590
4646
|
// src/data/operations/control/tenant/tenant-create-operation.ts
|
|
3591
|
-
var
|
|
4647
|
+
var import_types9 = require("@openhi/types");
|
|
3592
4648
|
|
|
3593
4649
|
// src/data/operations/control/workspace/workspace-create-operation.ts
|
|
3594
|
-
var
|
|
4650
|
+
var import_types11 = require("@openhi/types");
|
|
3595
4651
|
|
|
3596
4652
|
// src/data/dynamo/dynamo-data-service.ts
|
|
3597
|
-
var
|
|
4653
|
+
var import_electrodb16 = require("electrodb");
|
|
3598
4654
|
|
|
3599
4655
|
// src/data/dynamo/entities/data-entity-common.ts
|
|
3600
|
-
var
|
|
4656
|
+
var import_electrodb15 = require("electrodb");
|
|
3601
4657
|
var dataEntityAttributes = {
|
|
3602
4658
|
/** Sort key. "CURRENT" for current version; version history in S3. */
|
|
3603
4659
|
sk: {
|
|
@@ -3693,7 +4749,7 @@ var dataEntityAttributes = {
|
|
|
3693
4749
|
}
|
|
3694
4750
|
};
|
|
3695
4751
|
function createDataEntity(entity, resourceTypeLabel) {
|
|
3696
|
-
return new
|
|
4752
|
+
return new import_electrodb15.Entity({
|
|
3697
4753
|
model: {
|
|
3698
4754
|
entity,
|
|
3699
4755
|
service: "data",
|
|
@@ -4607,16 +5663,17 @@ var dataPlaneEntities = {
|
|
|
4607
5663
|
visionprescription: VisionPrescriptionEntity,
|
|
4608
5664
|
verificationresult: VerificationResultEntity
|
|
4609
5665
|
};
|
|
4610
|
-
var dataPlaneService = new
|
|
5666
|
+
var dataPlaneService = new import_electrodb16.Service(dataPlaneEntities, {
|
|
4611
5667
|
table: defaultTableName,
|
|
4612
5668
|
client: dynamoClient
|
|
4613
5669
|
});
|
|
4614
5670
|
var DynamoDataService = {
|
|
4615
|
-
entities: dataPlaneService.entities
|
|
5671
|
+
entities: dataPlaneService.entities,
|
|
5672
|
+
transaction: dataPlaneService.transaction
|
|
4616
5673
|
};
|
|
4617
5674
|
|
|
4618
5675
|
// src/data/operations/data-operations-common.ts
|
|
4619
|
-
var
|
|
5676
|
+
var import_types10 = require("@openhi/types");
|
|
4620
5677
|
|
|
4621
5678
|
// src/lib/compression.ts
|
|
4622
5679
|
var import_node_zlib = require("zlib");
|
|
@@ -4646,7 +5703,7 @@ var SeedDemoDataLambda = class extends import_constructs11.Construct {
|
|
|
4646
5703
|
[SEED_DEMO_DATA_USER_POOL_ID_ENV_VAR]: props.userPool.userPoolId
|
|
4647
5704
|
}
|
|
4648
5705
|
});
|
|
4649
|
-
const roleReadKeys = Object.values(
|
|
5706
|
+
const roleReadKeys = Object.values(import_types13.PLATFORM_ROLE_IDS).map(rolePartitionKey);
|
|
4650
5707
|
this.lambda.addToRolePolicy(
|
|
4651
5708
|
new import_aws_iam3.PolicyStatement({
|
|
4652
5709
|
effect: import_aws_iam3.Effect.ALLOW,
|
|
@@ -4735,7 +5792,7 @@ var SEED_SYSTEM_DATA_CONTROL_BUS_ENV_VAR = "CONTROL_EVENT_BUS_NAME";
|
|
|
4735
5792
|
// src/workflows/control-plane/seed-system-data/seed-system-data-lambda.ts
|
|
4736
5793
|
var import_node_fs8 = __toESM(require("fs"));
|
|
4737
5794
|
var import_node_path8 = __toESM(require("path"));
|
|
4738
|
-
var
|
|
5795
|
+
var import_types14 = require("@openhi/types");
|
|
4739
5796
|
var import_aws_cdk_lib13 = require("aws-cdk-lib");
|
|
4740
5797
|
var import_aws_events7 = require("aws-cdk-lib/aws-events");
|
|
4741
5798
|
var import_aws_events_targets3 = require("aws-cdk-lib/aws-events-targets");
|
|
@@ -4764,7 +5821,7 @@ var SeedSystemDataLambda = class extends import_constructs13.Construct {
|
|
|
4764
5821
|
[SEED_SYSTEM_DATA_CONTROL_BUS_ENV_VAR]: props.controlEventBus.eventBusName
|
|
4765
5822
|
}
|
|
4766
5823
|
});
|
|
4767
|
-
const roleArns = Object.values(
|
|
5824
|
+
const roleArns = Object.values(import_types14.PLATFORM_ROLE_IDS).map(
|
|
4768
5825
|
(id) => `role#id#${id}`
|
|
4769
5826
|
);
|
|
4770
5827
|
this.lambda.addToRolePolicy(
|
|
@@ -5715,6 +6772,507 @@ var _OpenHiGraphqlService = class _OpenHiGraphqlService extends OpenHiService {
|
|
|
5715
6772
|
};
|
|
5716
6773
|
_OpenHiGraphqlService.SERVICE_TYPE = "graphql-api";
|
|
5717
6774
|
var OpenHiGraphqlService = _OpenHiGraphqlService;
|
|
6775
|
+
|
|
6776
|
+
// src/workflows/control-plane/owning-delete-cascade/events.ts
|
|
6777
|
+
var import_workflows5 = __toESM(require_lib2());
|
|
6778
|
+
var OWNING_DELETE_CASCADE_CONSUMER_NAME = "owning-delete-cascade";
|
|
6779
|
+
var OWNING_DELETE_CASCADE_DEFAULT_CONCURRENCY = 8;
|
|
6780
|
+
var OWNING_DELETE_CASCADE_STUCK_THRESHOLD_MINUTES = 15;
|
|
6781
|
+
var OWNING_DELETE_OPS_EVENT_BUS_ENV_VAR = "OWNING_DELETE_OPS_EVENT_BUS_NAME";
|
|
6782
|
+
|
|
6783
|
+
// src/workflows/control-plane/owning-delete-cascade/owning-delete-cascade-lambdas.ts
|
|
6784
|
+
var import_node_fs12 = __toESM(require("fs"));
|
|
6785
|
+
var import_node_path12 = __toESM(require("path"));
|
|
6786
|
+
var import_aws_cdk_lib15 = require("aws-cdk-lib");
|
|
6787
|
+
var import_aws_iam8 = require("aws-cdk-lib/aws-iam");
|
|
6788
|
+
var import_aws_lambda12 = require("aws-cdk-lib/aws-lambda");
|
|
6789
|
+
var import_aws_lambda_nodejs12 = require("aws-cdk-lib/aws-lambda-nodejs");
|
|
6790
|
+
var import_constructs19 = require("constructs");
|
|
6791
|
+
function resolveHandlerEntry12(dirname, handlerName) {
|
|
6792
|
+
const sameDir = import_node_path12.default.join(dirname, handlerName);
|
|
6793
|
+
if (import_node_fs12.default.existsSync(sameDir)) {
|
|
6794
|
+
return { entry: sameDir, handler: "handler" };
|
|
6795
|
+
}
|
|
6796
|
+
const libDir = import_node_path12.default.join(dirname, "..", "..", "..", "..", "lib", handlerName);
|
|
6797
|
+
return { entry: libDir, handler: "handler" };
|
|
6798
|
+
}
|
|
6799
|
+
var OwningDeleteCascadeLambdas = class extends import_constructs19.Construct {
|
|
6800
|
+
constructor(scope, props) {
|
|
6801
|
+
super(scope, "owning-delete-cascade-lambdas");
|
|
6802
|
+
const listResolved = resolveHandlerEntry12(
|
|
6803
|
+
__dirname,
|
|
6804
|
+
"list-chunks.handler.js"
|
|
6805
|
+
);
|
|
6806
|
+
this.listChunks = new import_aws_lambda_nodejs12.NodejsFunction(this, "list-chunks-handler", {
|
|
6807
|
+
entry: listResolved.entry,
|
|
6808
|
+
runtime: import_aws_lambda12.Runtime.NODEJS_LATEST,
|
|
6809
|
+
memorySize: 512,
|
|
6810
|
+
timeout: import_aws_cdk_lib15.Duration.minutes(1),
|
|
6811
|
+
environment: {
|
|
6812
|
+
DYNAMO_TABLE_NAME: props.dataStoreTable.tableName
|
|
6813
|
+
}
|
|
6814
|
+
});
|
|
6815
|
+
props.dataStoreTable.grant(this.listChunks, "dynamodb:Query");
|
|
6816
|
+
const deleteResolved = resolveHandlerEntry12(
|
|
6817
|
+
__dirname,
|
|
6818
|
+
"delete-chunk.handler.js"
|
|
6819
|
+
);
|
|
6820
|
+
this.deleteChunk = new import_aws_lambda_nodejs12.NodejsFunction(this, "delete-chunk-handler", {
|
|
6821
|
+
entry: deleteResolved.entry,
|
|
6822
|
+
runtime: import_aws_lambda12.Runtime.NODEJS_LATEST,
|
|
6823
|
+
memorySize: 512,
|
|
6824
|
+
timeout: import_aws_cdk_lib15.Duration.minutes(1),
|
|
6825
|
+
environment: {
|
|
6826
|
+
DYNAMO_TABLE_NAME: props.dataStoreTable.tableName
|
|
6827
|
+
}
|
|
6828
|
+
});
|
|
6829
|
+
props.dataStoreTable.grant(
|
|
6830
|
+
this.deleteChunk,
|
|
6831
|
+
"dynamodb:DeleteItem",
|
|
6832
|
+
"dynamodb:UpdateItem",
|
|
6833
|
+
"dynamodb:PutItem"
|
|
6834
|
+
);
|
|
6835
|
+
const finalizeResolved = resolveHandlerEntry12(
|
|
6836
|
+
__dirname,
|
|
6837
|
+
"finalize.handler.js"
|
|
6838
|
+
);
|
|
6839
|
+
this.finalize = new import_aws_lambda_nodejs12.NodejsFunction(this, "finalize-handler", {
|
|
6840
|
+
entry: finalizeResolved.entry,
|
|
6841
|
+
runtime: import_aws_lambda12.Runtime.NODEJS_LATEST,
|
|
6842
|
+
memorySize: 512,
|
|
6843
|
+
timeout: import_aws_cdk_lib15.Duration.minutes(1),
|
|
6844
|
+
environment: {
|
|
6845
|
+
DYNAMO_TABLE_NAME: props.dataStoreTable.tableName,
|
|
6846
|
+
[OWNING_DELETE_OPS_EVENT_BUS_ENV_VAR]: props.opsEventBus.eventBusName
|
|
6847
|
+
}
|
|
6848
|
+
});
|
|
6849
|
+
props.dataStoreTable.grant(this.finalize, "dynamodb:DeleteItem");
|
|
6850
|
+
this.finalize.addToRolePolicy(
|
|
6851
|
+
new import_aws_iam8.PolicyStatement({
|
|
6852
|
+
effect: import_aws_iam8.Effect.ALLOW,
|
|
6853
|
+
actions: ["events:PutEvents"],
|
|
6854
|
+
resources: [props.opsEventBus.eventBusArn]
|
|
6855
|
+
})
|
|
6856
|
+
);
|
|
6857
|
+
}
|
|
6858
|
+
};
|
|
6859
|
+
|
|
6860
|
+
// src/workflows/control-plane/owning-delete-cascade/owning-delete-cascade-workflow.ts
|
|
6861
|
+
var import_aws_cdk_lib16 = require("aws-cdk-lib");
|
|
6862
|
+
var import_aws_events9 = require("aws-cdk-lib/aws-events");
|
|
6863
|
+
var import_aws_events_targets5 = require("aws-cdk-lib/aws-events-targets");
|
|
6864
|
+
var import_aws_stepfunctions = require("aws-cdk-lib/aws-stepfunctions");
|
|
6865
|
+
var import_aws_stepfunctions_tasks = require("aws-cdk-lib/aws-stepfunctions-tasks");
|
|
6866
|
+
var import_constructs20 = require("constructs");
|
|
6867
|
+
var OwningDeleteCascadeWorkflow = class extends import_constructs20.Construct {
|
|
6868
|
+
constructor(scope, props) {
|
|
6869
|
+
super(scope, "owning-delete-cascade-workflow");
|
|
6870
|
+
this.lambdas = new OwningDeleteCascadeLambdas(this, {
|
|
6871
|
+
dataStoreTable: props.dataStoreTable,
|
|
6872
|
+
opsEventBus: props.opsEventBus
|
|
6873
|
+
});
|
|
6874
|
+
const concurrency = props.cascadeMapConcurrency ?? OWNING_DELETE_CASCADE_DEFAULT_CONCURRENCY;
|
|
6875
|
+
const initState = new import_aws_stepfunctions.Pass(this, "init-state", {
|
|
6876
|
+
parameters: {
|
|
6877
|
+
"ownerType.$": "$.detail.payload.ownerType",
|
|
6878
|
+
"ownerId.$": "$.detail.payload.ownerId",
|
|
6879
|
+
"tenantId.$": "$.detail.payload.tenantId",
|
|
6880
|
+
cursors: {},
|
|
6881
|
+
projectionsRemoved: 0,
|
|
6882
|
+
chunkCount: 0,
|
|
6883
|
+
// Used by the finalize step to compute `durationMs`.
|
|
6884
|
+
"startedAt.$": "$$.Execution.StartTime",
|
|
6885
|
+
// Propagate envelope identity for ADR-016 causation chaining.
|
|
6886
|
+
"eventId.$": "$.detail.eventId",
|
|
6887
|
+
"correlationId.$": "$.detail.correlationId",
|
|
6888
|
+
"causationId.$": "$.detail.eventId"
|
|
6889
|
+
}
|
|
6890
|
+
});
|
|
6891
|
+
const listChunks = new import_aws_stepfunctions_tasks.LambdaInvoke(this, "list-chunks", {
|
|
6892
|
+
lambdaFunction: this.lambdas.listChunks,
|
|
6893
|
+
resultPath: "$.listResult",
|
|
6894
|
+
retryOnServiceExceptions: true
|
|
6895
|
+
});
|
|
6896
|
+
const updateAfterList = new import_aws_stepfunctions.Pass(this, "update-after-list", {
|
|
6897
|
+
parameters: {
|
|
6898
|
+
"ownerType.$": "$.ownerType",
|
|
6899
|
+
"ownerId.$": "$.ownerId",
|
|
6900
|
+
"tenantId.$": "$.tenantId",
|
|
6901
|
+
"cursors.$": "$.listResult.Payload.cursors",
|
|
6902
|
+
"projectionsRemoved.$": "$.listResult.Payload.projectionsRemoved",
|
|
6903
|
+
"chunkCount.$": "$.listResult.Payload.chunkCount",
|
|
6904
|
+
"exhausted.$": "$.listResult.Payload.exhausted",
|
|
6905
|
+
"chunks.$": "$.listResult.Payload.chunks",
|
|
6906
|
+
"startedAt.$": "$.startedAt",
|
|
6907
|
+
"eventId.$": "$.eventId",
|
|
6908
|
+
"correlationId.$": "$.correlationId",
|
|
6909
|
+
"causationId.$": "$.causationId"
|
|
6910
|
+
}
|
|
6911
|
+
});
|
|
6912
|
+
const rewriteChunks = new import_aws_stepfunctions.CustomState(this, "rewrite-chunks", {
|
|
6913
|
+
stateJson: {
|
|
6914
|
+
Type: "Map",
|
|
6915
|
+
ItemsPath: "$.chunks",
|
|
6916
|
+
MaxConcurrency: concurrency,
|
|
6917
|
+
ResultPath: "$.rewriteResults",
|
|
6918
|
+
ItemSelector: {
|
|
6919
|
+
// The handler receives `CascadeChunkInput` verbatim from the
|
|
6920
|
+
// `listChunks` output, no additional wrapping.
|
|
6921
|
+
"ownerType.$": "$$.Map.Item.Value.ownerType",
|
|
6922
|
+
"ownerId.$": "$$.Map.Item.Value.ownerId",
|
|
6923
|
+
"tenantId.$": "$$.Map.Item.Value.tenantId",
|
|
6924
|
+
"rows.$": "$$.Map.Item.Value.rows",
|
|
6925
|
+
"chunkToken.$": "$$.Map.Item.Value.chunkToken"
|
|
6926
|
+
},
|
|
6927
|
+
ItemProcessor: {
|
|
6928
|
+
ProcessorConfig: {
|
|
6929
|
+
// Inline mode (NOT Distributed). Per TR-022 Choice 2A.
|
|
6930
|
+
Mode: "INLINE"
|
|
6931
|
+
},
|
|
6932
|
+
StartAt: "DeleteChunk",
|
|
6933
|
+
States: {
|
|
6934
|
+
DeleteChunk: {
|
|
6935
|
+
Type: "Task",
|
|
6936
|
+
Resource: "arn:aws:states:::lambda:invoke",
|
|
6937
|
+
Parameters: {
|
|
6938
|
+
FunctionName: this.lambdas.deleteChunk.functionArn,
|
|
6939
|
+
"Payload.$": "$"
|
|
6940
|
+
},
|
|
6941
|
+
Retry: [
|
|
6942
|
+
{
|
|
6943
|
+
ErrorEquals: [
|
|
6944
|
+
"DynamoDB.ProvisionedThroughputExceededException",
|
|
6945
|
+
"DynamoDB.ThrottlingException",
|
|
6946
|
+
"DynamoDB.TransactionConflictException",
|
|
6947
|
+
"Lambda.ServiceException",
|
|
6948
|
+
"Lambda.AWSLambdaException",
|
|
6949
|
+
"Lambda.SdkClientException"
|
|
6950
|
+
],
|
|
6951
|
+
IntervalSeconds: 1,
|
|
6952
|
+
MaxAttempts: 3,
|
|
6953
|
+
BackoffRate: 2,
|
|
6954
|
+
MaxDelaySeconds: 30
|
|
6955
|
+
}
|
|
6956
|
+
],
|
|
6957
|
+
Catch: [
|
|
6958
|
+
{
|
|
6959
|
+
// Replay path: the rows in this chunk are already
|
|
6960
|
+
// gone. Treat as a no-op success so the outer loop
|
|
6961
|
+
// keeps draining the partition.
|
|
6962
|
+
ErrorEquals: ["DynamoDB.TransactionCanceledException"],
|
|
6963
|
+
Next: "ChunkAlreadyDeleted"
|
|
6964
|
+
}
|
|
6965
|
+
],
|
|
6966
|
+
End: true
|
|
6967
|
+
},
|
|
6968
|
+
ChunkAlreadyDeleted: {
|
|
6969
|
+
Type: "Succeed"
|
|
6970
|
+
}
|
|
6971
|
+
}
|
|
6972
|
+
}
|
|
6973
|
+
}
|
|
6974
|
+
});
|
|
6975
|
+
const interPageWait = new import_aws_stepfunctions.Wait(this, "inter-page-wait", {
|
|
6976
|
+
time: import_aws_stepfunctions.WaitTime.duration(import_aws_cdk_lib16.Duration.seconds(0))
|
|
6977
|
+
});
|
|
6978
|
+
const isExhausted = new import_aws_stepfunctions.Choice(this, "is-exhausted");
|
|
6979
|
+
const finalize = new import_aws_stepfunctions_tasks.LambdaInvoke(this, "finalize", {
|
|
6980
|
+
lambdaFunction: this.lambdas.finalize,
|
|
6981
|
+
payload: import_aws_stepfunctions.TaskInput.fromObject({
|
|
6982
|
+
"ownerType.$": "$.ownerType",
|
|
6983
|
+
"ownerId.$": "$.ownerId",
|
|
6984
|
+
"tenantId.$": "$.tenantId",
|
|
6985
|
+
"projectionsRemoved.$": "$.projectionsRemoved",
|
|
6986
|
+
"chunkCount.$": "$.chunkCount",
|
|
6987
|
+
"startedAt.$": "$.startedAt",
|
|
6988
|
+
"eventId.$": "$.eventId",
|
|
6989
|
+
"correlationId.$": "$.correlationId",
|
|
6990
|
+
"causationId.$": "$.causationId"
|
|
6991
|
+
}),
|
|
6992
|
+
resultPath: "$.finalizeResult",
|
|
6993
|
+
retryOnServiceExceptions: true
|
|
6994
|
+
});
|
|
6995
|
+
const success = new import_aws_stepfunctions.Succeed(this, "success");
|
|
6996
|
+
const definition = initState.next(listChunks).next(updateAfterList).next(rewriteChunks).next(interPageWait).next(
|
|
6997
|
+
isExhausted.when(
|
|
6998
|
+
import_aws_stepfunctions.Condition.booleanEquals("$.exhausted", true),
|
|
6999
|
+
finalize.next(success)
|
|
7000
|
+
).otherwise(listChunks)
|
|
7001
|
+
);
|
|
7002
|
+
this.stateMachine = new import_aws_stepfunctions.StateMachine(this, "state-machine", {
|
|
7003
|
+
definitionBody: import_aws_stepfunctions.DefinitionBody.fromChainable(definition),
|
|
7004
|
+
// Long timeout because real-world cascades can run minutes when
|
|
7005
|
+
// a workspace has thousands of members. The stuck-cascade alarm
|
|
7006
|
+
// fires at 15 minutes; the state machine itself does not abort.
|
|
7007
|
+
timeout: import_aws_cdk_lib16.Duration.hours(2)
|
|
7008
|
+
});
|
|
7009
|
+
this.rule = new import_aws_events9.Rule(this, "rule", {
|
|
7010
|
+
eventBus: props.dataEventBus,
|
|
7011
|
+
eventPattern: {
|
|
7012
|
+
source: [import_workflows5.OPENHI_DATA_SOURCE],
|
|
7013
|
+
detailType: [import_workflows5.ControlPlaneOwningDeleteV1.detailType]
|
|
7014
|
+
},
|
|
7015
|
+
targets: [
|
|
7016
|
+
new import_aws_events_targets5.SfnStateMachine(this.stateMachine, {
|
|
7017
|
+
retryAttempts: 2,
|
|
7018
|
+
maxEventAge: import_aws_cdk_lib16.Duration.hours(2)
|
|
7019
|
+
})
|
|
7020
|
+
]
|
|
7021
|
+
});
|
|
7022
|
+
}
|
|
7023
|
+
};
|
|
7024
|
+
|
|
7025
|
+
// src/workflows/control-plane/rename-cascade/events.ts
|
|
7026
|
+
var import_workflows6 = __toESM(require_lib2());
|
|
7027
|
+
var RENAME_CASCADE_CONSUMER_NAME = "rename-cascade";
|
|
7028
|
+
var RENAME_CASCADE_DEFAULT_CONCURRENCY = 10;
|
|
7029
|
+
var RENAME_CASCADE_FAILED_THRESHOLD = 0;
|
|
7030
|
+
var RENAME_CASCADE_SLOW_THRESHOLD_SECONDS = 300;
|
|
7031
|
+
var RENAME_CASCADE_OPS_EVENT_BUS_ENV_VAR = "RENAME_CASCADE_OPS_EVENT_BUS_NAME";
|
|
7032
|
+
|
|
7033
|
+
// src/workflows/control-plane/rename-cascade/rename-cascade-lambdas.ts
|
|
7034
|
+
var import_node_fs13 = __toESM(require("fs"));
|
|
7035
|
+
var import_node_path13 = __toESM(require("path"));
|
|
7036
|
+
var import_aws_cdk_lib17 = require("aws-cdk-lib");
|
|
7037
|
+
var import_aws_iam9 = require("aws-cdk-lib/aws-iam");
|
|
7038
|
+
var import_aws_lambda13 = require("aws-cdk-lib/aws-lambda");
|
|
7039
|
+
var import_aws_lambda_nodejs13 = require("aws-cdk-lib/aws-lambda-nodejs");
|
|
7040
|
+
var import_constructs21 = require("constructs");
|
|
7041
|
+
function resolveHandlerEntry13(dirname, handlerName) {
|
|
7042
|
+
const sameDir = import_node_path13.default.join(dirname, handlerName);
|
|
7043
|
+
if (import_node_fs13.default.existsSync(sameDir)) {
|
|
7044
|
+
return { entry: sameDir, handler: "handler" };
|
|
7045
|
+
}
|
|
7046
|
+
const libDir = import_node_path13.default.join(dirname, "..", "..", "..", "..", "lib", handlerName);
|
|
7047
|
+
return { entry: libDir, handler: "handler" };
|
|
7048
|
+
}
|
|
7049
|
+
var RenameCascadeLambdas = class extends import_constructs21.Construct {
|
|
7050
|
+
constructor(scope, props) {
|
|
7051
|
+
super(scope, "rename-cascade-lambdas");
|
|
7052
|
+
const listResolved = resolveHandlerEntry13(
|
|
7053
|
+
__dirname,
|
|
7054
|
+
"rename-list-targets.handler.js"
|
|
7055
|
+
);
|
|
7056
|
+
this.listTargets = new import_aws_lambda_nodejs13.NodejsFunction(this, "list-targets-handler", {
|
|
7057
|
+
entry: listResolved.entry,
|
|
7058
|
+
runtime: import_aws_lambda13.Runtime.NODEJS_LATEST,
|
|
7059
|
+
memorySize: 512,
|
|
7060
|
+
timeout: import_aws_cdk_lib17.Duration.minutes(1),
|
|
7061
|
+
environment: {
|
|
7062
|
+
DYNAMO_TABLE_NAME: props.dataStoreTable.tableName
|
|
7063
|
+
}
|
|
7064
|
+
});
|
|
7065
|
+
props.dataStoreTable.grant(this.listTargets, "dynamodb:Query");
|
|
7066
|
+
const rewriteResolved = resolveHandlerEntry13(
|
|
7067
|
+
__dirname,
|
|
7068
|
+
"rename-rewrite-chunk.handler.js"
|
|
7069
|
+
);
|
|
7070
|
+
this.rewriteChunk = new import_aws_lambda_nodejs13.NodejsFunction(this, "rewrite-chunk-handler", {
|
|
7071
|
+
entry: rewriteResolved.entry,
|
|
7072
|
+
runtime: import_aws_lambda13.Runtime.NODEJS_LATEST,
|
|
7073
|
+
memorySize: 512,
|
|
7074
|
+
timeout: import_aws_cdk_lib17.Duration.minutes(1),
|
|
7075
|
+
environment: {
|
|
7076
|
+
DYNAMO_TABLE_NAME: props.dataStoreTable.tableName
|
|
7077
|
+
}
|
|
7078
|
+
});
|
|
7079
|
+
props.dataStoreTable.grant(
|
|
7080
|
+
this.rewriteChunk,
|
|
7081
|
+
"dynamodb:DeleteItem",
|
|
7082
|
+
"dynamodb:PutItem",
|
|
7083
|
+
"dynamodb:UpdateItem"
|
|
7084
|
+
);
|
|
7085
|
+
const finalizeResolved = resolveHandlerEntry13(
|
|
7086
|
+
__dirname,
|
|
7087
|
+
"rename-finalize.handler.js"
|
|
7088
|
+
);
|
|
7089
|
+
this.finalize = new import_aws_lambda_nodejs13.NodejsFunction(this, "finalize-handler", {
|
|
7090
|
+
entry: finalizeResolved.entry,
|
|
7091
|
+
runtime: import_aws_lambda13.Runtime.NODEJS_LATEST,
|
|
7092
|
+
memorySize: 512,
|
|
7093
|
+
timeout: import_aws_cdk_lib17.Duration.minutes(1),
|
|
7094
|
+
environment: {
|
|
7095
|
+
[RENAME_CASCADE_OPS_EVENT_BUS_ENV_VAR]: props.opsEventBus.eventBusName
|
|
7096
|
+
}
|
|
7097
|
+
});
|
|
7098
|
+
this.finalize.addToRolePolicy(
|
|
7099
|
+
new import_aws_iam9.PolicyStatement({
|
|
7100
|
+
effect: import_aws_iam9.Effect.ALLOW,
|
|
7101
|
+
actions: ["events:PutEvents"],
|
|
7102
|
+
resources: [props.opsEventBus.eventBusArn]
|
|
7103
|
+
})
|
|
7104
|
+
);
|
|
7105
|
+
}
|
|
7106
|
+
};
|
|
7107
|
+
|
|
7108
|
+
// src/workflows/control-plane/rename-cascade/rename-cascade-workflow.ts
|
|
7109
|
+
var import_aws_cdk_lib18 = require("aws-cdk-lib");
|
|
7110
|
+
var import_aws_events10 = require("aws-cdk-lib/aws-events");
|
|
7111
|
+
var import_aws_events_targets6 = require("aws-cdk-lib/aws-events-targets");
|
|
7112
|
+
var import_aws_stepfunctions2 = require("aws-cdk-lib/aws-stepfunctions");
|
|
7113
|
+
var import_aws_stepfunctions_tasks2 = require("aws-cdk-lib/aws-stepfunctions-tasks");
|
|
7114
|
+
var import_constructs22 = require("constructs");
|
|
7115
|
+
var RenameCascadeWorkflow = class extends import_constructs22.Construct {
|
|
7116
|
+
constructor(scope, props) {
|
|
7117
|
+
super(scope, "rename-cascade-workflow");
|
|
7118
|
+
this.lambdas = new RenameCascadeLambdas(this, {
|
|
7119
|
+
dataStoreTable: props.dataStoreTable,
|
|
7120
|
+
opsEventBus: props.opsEventBus
|
|
7121
|
+
});
|
|
7122
|
+
const concurrency = props.cascadeMapConcurrency ?? RENAME_CASCADE_DEFAULT_CONCURRENCY;
|
|
7123
|
+
const initState = new import_aws_stepfunctions2.Pass(this, "init-state", {
|
|
7124
|
+
parameters: {
|
|
7125
|
+
"entityType.$": "$.detail.payload.entityType",
|
|
7126
|
+
"entityId.$": "$.detail.payload.entityId",
|
|
7127
|
+
"tenantId.$": "$.detail.payload.tenantId",
|
|
7128
|
+
"oldName.$": "$.detail.payload.oldName",
|
|
7129
|
+
"newName.$": "$.detail.payload.newName",
|
|
7130
|
+
"oldNormalizedName.$": "$.detail.payload.oldNormalizedName",
|
|
7131
|
+
"newNormalizedName.$": "$.detail.payload.newNormalizedName",
|
|
7132
|
+
cursors: {},
|
|
7133
|
+
itemsRewritten: 0,
|
|
7134
|
+
chunkCount: 0,
|
|
7135
|
+
"startedAt.$": "$$.Execution.StartTime",
|
|
7136
|
+
"eventId.$": "$.detail.eventId",
|
|
7137
|
+
"correlationId.$": "$.detail.correlationId",
|
|
7138
|
+
"causationId.$": "$.detail.eventId"
|
|
7139
|
+
}
|
|
7140
|
+
});
|
|
7141
|
+
const listTargets = new import_aws_stepfunctions_tasks2.LambdaInvoke(this, "list-targets", {
|
|
7142
|
+
lambdaFunction: this.lambdas.listTargets,
|
|
7143
|
+
resultPath: "$.listResult",
|
|
7144
|
+
retryOnServiceExceptions: true
|
|
7145
|
+
});
|
|
7146
|
+
const updateAfterList = new import_aws_stepfunctions2.Pass(this, "update-after-list", {
|
|
7147
|
+
parameters: {
|
|
7148
|
+
"entityType.$": "$.entityType",
|
|
7149
|
+
"entityId.$": "$.entityId",
|
|
7150
|
+
"tenantId.$": "$.tenantId",
|
|
7151
|
+
"oldName.$": "$.oldName",
|
|
7152
|
+
"newName.$": "$.newName",
|
|
7153
|
+
"oldNormalizedName.$": "$.oldNormalizedName",
|
|
7154
|
+
"newNormalizedName.$": "$.newNormalizedName",
|
|
7155
|
+
"cursors.$": "$.listResult.Payload.cursors",
|
|
7156
|
+
"itemsRewritten.$": "$.listResult.Payload.itemsRewritten",
|
|
7157
|
+
"chunkCount.$": "$.listResult.Payload.chunkCount",
|
|
7158
|
+
"exhausted.$": "$.listResult.Payload.exhausted",
|
|
7159
|
+
"chunks.$": "$.listResult.Payload.chunks",
|
|
7160
|
+
"startedAt.$": "$.startedAt",
|
|
7161
|
+
"eventId.$": "$.eventId",
|
|
7162
|
+
"correlationId.$": "$.correlationId",
|
|
7163
|
+
"causationId.$": "$.causationId"
|
|
7164
|
+
}
|
|
7165
|
+
});
|
|
7166
|
+
const rewriteChunks = new import_aws_stepfunctions2.CustomState(this, "rewrite-chunks", {
|
|
7167
|
+
stateJson: {
|
|
7168
|
+
Type: "Map",
|
|
7169
|
+
ItemsPath: "$.chunks",
|
|
7170
|
+
MaxConcurrency: concurrency,
|
|
7171
|
+
ResultPath: "$.rewriteResults",
|
|
7172
|
+
ItemSelector: {
|
|
7173
|
+
"entityType.$": "$$.Map.Item.Value.entityType",
|
|
7174
|
+
"entityId.$": "$$.Map.Item.Value.entityId",
|
|
7175
|
+
"tenantId.$": "$$.Map.Item.Value.tenantId",
|
|
7176
|
+
"targets.$": "$$.Map.Item.Value.targets",
|
|
7177
|
+
"chunkToken.$": "$$.Map.Item.Value.chunkToken"
|
|
7178
|
+
},
|
|
7179
|
+
ItemProcessor: {
|
|
7180
|
+
ProcessorConfig: {
|
|
7181
|
+
// DISTRIBUTED mode — per TR-023 (NOT INLINE; that is
|
|
7182
|
+
// TR-022's territory).
|
|
7183
|
+
Mode: "DISTRIBUTED",
|
|
7184
|
+
ExecutionType: "STANDARD"
|
|
7185
|
+
},
|
|
7186
|
+
StartAt: "RewriteChunk",
|
|
7187
|
+
States: {
|
|
7188
|
+
RewriteChunk: {
|
|
7189
|
+
Type: "Task",
|
|
7190
|
+
Resource: "arn:aws:states:::lambda:invoke",
|
|
7191
|
+
Parameters: {
|
|
7192
|
+
FunctionName: this.lambdas.rewriteChunk.functionArn,
|
|
7193
|
+
"Payload.$": "$"
|
|
7194
|
+
},
|
|
7195
|
+
Retry: [
|
|
7196
|
+
{
|
|
7197
|
+
ErrorEquals: [
|
|
7198
|
+
"DynamoDB.ProvisionedThroughputExceededException",
|
|
7199
|
+
"DynamoDB.ThrottlingException",
|
|
7200
|
+
"DynamoDB.TransactionConflictException",
|
|
7201
|
+
"Lambda.ServiceException",
|
|
7202
|
+
"Lambda.AWSLambdaException",
|
|
7203
|
+
"Lambda.SdkClientException"
|
|
7204
|
+
],
|
|
7205
|
+
IntervalSeconds: 1,
|
|
7206
|
+
MaxAttempts: 5,
|
|
7207
|
+
BackoffRate: 2,
|
|
7208
|
+
MaxDelaySeconds: 30
|
|
7209
|
+
}
|
|
7210
|
+
],
|
|
7211
|
+
Catch: [
|
|
7212
|
+
{
|
|
7213
|
+
// Replay path: the rewrite race "lost to a later
|
|
7214
|
+
// write" per TR-023 idempotency. Treat as a no-op
|
|
7215
|
+
// success so the outer loop keeps draining the page.
|
|
7216
|
+
ErrorEquals: ["DynamoDB.TransactionCanceledException"],
|
|
7217
|
+
Next: "ChunkAlreadyRewritten"
|
|
7218
|
+
}
|
|
7219
|
+
],
|
|
7220
|
+
End: true
|
|
7221
|
+
},
|
|
7222
|
+
ChunkAlreadyRewritten: {
|
|
7223
|
+
Type: "Succeed"
|
|
7224
|
+
}
|
|
7225
|
+
}
|
|
7226
|
+
}
|
|
7227
|
+
}
|
|
7228
|
+
});
|
|
7229
|
+
const isExhausted = new import_aws_stepfunctions2.Choice(this, "is-exhausted");
|
|
7230
|
+
const finalize = new import_aws_stepfunctions_tasks2.LambdaInvoke(this, "finalize", {
|
|
7231
|
+
lambdaFunction: this.lambdas.finalize,
|
|
7232
|
+
payload: import_aws_stepfunctions2.TaskInput.fromObject({
|
|
7233
|
+
"entityType.$": "$.entityType",
|
|
7234
|
+
"entityId.$": "$.entityId",
|
|
7235
|
+
"tenantId.$": "$.tenantId",
|
|
7236
|
+
"newName.$": "$.newName",
|
|
7237
|
+
"itemsRewritten.$": "$.itemsRewritten",
|
|
7238
|
+
"chunkCount.$": "$.chunkCount",
|
|
7239
|
+
"startedAt.$": "$.startedAt",
|
|
7240
|
+
"eventId.$": "$.eventId",
|
|
7241
|
+
"correlationId.$": "$.correlationId",
|
|
7242
|
+
"causationId.$": "$.causationId"
|
|
7243
|
+
}),
|
|
7244
|
+
resultPath: "$.finalizeResult",
|
|
7245
|
+
retryOnServiceExceptions: true
|
|
7246
|
+
});
|
|
7247
|
+
const success = new import_aws_stepfunctions2.Succeed(this, "success");
|
|
7248
|
+
const definition = initState.next(listTargets).next(updateAfterList).next(rewriteChunks).next(
|
|
7249
|
+
isExhausted.when(
|
|
7250
|
+
import_aws_stepfunctions2.Condition.booleanEquals("$.exhausted", true),
|
|
7251
|
+
finalize.next(success)
|
|
7252
|
+
).otherwise(listTargets)
|
|
7253
|
+
);
|
|
7254
|
+
this.stateMachine = new import_aws_stepfunctions2.StateMachine(this, "state-machine", {
|
|
7255
|
+
definitionBody: import_aws_stepfunctions2.DefinitionBody.fromChainable(definition),
|
|
7256
|
+
// Long timeout — large renames may rewrite thousands of rows;
|
|
7257
|
+
// the `CascadeSlow` alarm fires at 300s p99 but the state
|
|
7258
|
+
// machine itself does not abort.
|
|
7259
|
+
timeout: import_aws_cdk_lib18.Duration.hours(2)
|
|
7260
|
+
});
|
|
7261
|
+
this.rule = new import_aws_events10.Rule(this, "rule", {
|
|
7262
|
+
eventBus: props.dataEventBus,
|
|
7263
|
+
eventPattern: {
|
|
7264
|
+
source: [import_workflows6.OPENHI_DATA_SOURCE],
|
|
7265
|
+
detailType: [import_workflows6.ControlPlaneRenameV1.detailType]
|
|
7266
|
+
},
|
|
7267
|
+
targets: [
|
|
7268
|
+
new import_aws_events_targets6.SfnStateMachine(this.stateMachine, {
|
|
7269
|
+
retryAttempts: 2,
|
|
7270
|
+
maxEventAge: import_aws_cdk_lib18.Duration.hours(2)
|
|
7271
|
+
})
|
|
7272
|
+
]
|
|
7273
|
+
});
|
|
7274
|
+
}
|
|
7275
|
+
};
|
|
5718
7276
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5719
7277
|
0 && (module.exports = {
|
|
5720
7278
|
BRIDGED_STATUSES,
|
|
@@ -5728,6 +7286,12 @@ var OpenHiGraphqlService = _OpenHiGraphqlService;
|
|
|
5728
7286
|
CognitoUserPoolDomain,
|
|
5729
7287
|
CognitoUserPoolKmsKey,
|
|
5730
7288
|
ControlEventBus,
|
|
7289
|
+
ControlPlaneOwningDeleteCompleteV1,
|
|
7290
|
+
ControlPlaneOwningDeleteFailedV1,
|
|
7291
|
+
ControlPlaneOwningDeleteV1,
|
|
7292
|
+
ControlPlaneRenameCompleteV1,
|
|
7293
|
+
ControlPlaneRenameFailedV1,
|
|
7294
|
+
ControlPlaneRenameV1,
|
|
5731
7295
|
DATA_STORE_CHANGE_DETAIL_MAX_UTF8_BYTES,
|
|
5732
7296
|
DATA_STORE_CHANGE_DETAIL_TYPE,
|
|
5733
7297
|
DATA_STORE_CHANGE_EVENT_SOURCE,
|
|
@@ -5747,6 +7311,11 @@ var OpenHiGraphqlService = _OpenHiGraphqlService;
|
|
|
5747
7311
|
OPENHI_TAG_SUFFIX_REPO_NAME,
|
|
5748
7312
|
OPENHI_TAG_SUFFIX_SERVICE_TYPE,
|
|
5749
7313
|
OPENHI_TAG_SUFFIX_STAGE_TYPE,
|
|
7314
|
+
OWNING_DELETE_CASCADE_CONSUMER_NAME,
|
|
7315
|
+
OWNING_DELETE_CASCADE_DEFAULT_CONCURRENCY,
|
|
7316
|
+
OWNING_DELETE_CASCADE_STUCK_THRESHOLD_MINUTES,
|
|
7317
|
+
OWNING_DELETE_OPS_EVENT_BUS_ENV_VAR,
|
|
7318
|
+
OWNING_ENTITY_TYPE,
|
|
5750
7319
|
OpenHiApp,
|
|
5751
7320
|
OpenHiAuthService,
|
|
5752
7321
|
OpenHiDataService,
|
|
@@ -5757,6 +7326,8 @@ var OpenHiGraphqlService = _OpenHiGraphqlService;
|
|
|
5757
7326
|
OpenHiService,
|
|
5758
7327
|
OpenHiStage,
|
|
5759
7328
|
OpsEventBus,
|
|
7329
|
+
OwningDeleteCascadeLambdas,
|
|
7330
|
+
OwningDeleteCascadeWorkflow,
|
|
5760
7331
|
PLACEHOLDER_TENANT_ID,
|
|
5761
7332
|
PLACEHOLDER_WORKSPACE_ID,
|
|
5762
7333
|
PLATFORM_DEPLOY_BRIDGE_ACTOR_SYSTEM,
|
|
@@ -5772,7 +7343,15 @@ var OpenHiGraphqlService = _OpenHiGraphqlService;
|
|
|
5772
7343
|
PostConfirmationLambda,
|
|
5773
7344
|
PreTokenGenerationLambda,
|
|
5774
7345
|
ProvisionDefaultWorkspaceLambda,
|
|
7346
|
+
RENAMABLE_ENTITY_TYPE,
|
|
7347
|
+
RENAME_CASCADE_CONSUMER_NAME,
|
|
7348
|
+
RENAME_CASCADE_DEFAULT_CONCURRENCY,
|
|
7349
|
+
RENAME_CASCADE_FAILED_THRESHOLD,
|
|
7350
|
+
RENAME_CASCADE_OPS_EVENT_BUS_ENV_VAR,
|
|
7351
|
+
RENAME_CASCADE_SLOW_THRESHOLD_SECONDS,
|
|
5775
7352
|
REST_API_BASE_URL_SSM_NAME,
|
|
7353
|
+
RenameCascadeLambdas,
|
|
7354
|
+
RenameCascadeWorkflow,
|
|
5776
7355
|
RootGraphqlApi,
|
|
5777
7356
|
RootHostedZone,
|
|
5778
7357
|
RootHttpApi,
|