@beesolve/aws-accounts 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/awsConfig.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { readFile, unlink, writeFile } from "node:fs/promises";
3
- import { join, resolve } from "node:path";
3
+ import { dirname, join, resolve } from "node:path";
4
4
  import { fileURLToPath, pathToFileURL } from "node:url";
5
5
  import { build as esbuildBuild } from "esbuild";
6
6
  import * as v from "valibot";
@@ -36,7 +36,8 @@ const deploymentSchema = v.strictObject({
36
36
  region: v.string(),
37
37
  lambdaArn: v.string(),
38
38
  stateBucketName: v.string(),
39
- stateCacheTtlSeconds: v.number()
39
+ stateCacheTtlSeconds: v.number(),
40
+ cliVersion: v.string()
40
41
  });
41
42
  const awsContextSchema = v.strictObject({
42
43
  version: nonEmptyString,
@@ -66,6 +67,17 @@ const awsConfigModelSchema = v.strictObject({
66
67
  key: v.string(),
67
68
  value: v.string()
68
69
  })
70
+ ),
71
+ alternateContacts: v.optional(
72
+ v.array(
73
+ v.strictObject({
74
+ contactType: v.picklist(["BILLING", "OPERATIONS", "SECURITY"]),
75
+ name: v.string(),
76
+ email: v.string(),
77
+ phone: v.string(),
78
+ title: v.optional(v.string())
79
+ })
80
+ )
69
81
  )
70
82
  })
71
83
  )
@@ -107,6 +119,58 @@ const awsConfigModelSchema = v.strictObject({
107
119
  user: v.optional(v.string()),
108
120
  accounts: v.array(v.string())
109
121
  })
122
+ ),
123
+ accessControlAttributes: v.optional(
124
+ v.array(
125
+ v.strictObject({
126
+ key: v.string(),
127
+ source: v.array(v.string())
128
+ })
129
+ )
130
+ ),
131
+ policies: v.optional(
132
+ v.strictObject({
133
+ serviceControlPolicies: v.optional(
134
+ v.array(
135
+ v.strictObject({
136
+ name: v.string(),
137
+ description: v.optional(v.string()),
138
+ content: v.record(v.string(), v.unknown()),
139
+ targets: v.array(v.string())
140
+ })
141
+ )
142
+ ),
143
+ resourceControlPolicies: v.optional(
144
+ v.array(
145
+ v.strictObject({
146
+ name: v.string(),
147
+ description: v.optional(v.string()),
148
+ content: v.record(v.string(), v.unknown()),
149
+ targets: v.array(v.string())
150
+ })
151
+ )
152
+ ),
153
+ tagPolicies: v.optional(
154
+ v.array(
155
+ v.strictObject({
156
+ name: v.string(),
157
+ description: v.optional(v.string()),
158
+ content: v.record(v.string(), v.unknown()),
159
+ targets: v.array(v.string())
160
+ })
161
+ )
162
+ ),
163
+ aiServicesOptOutPolicies: v.optional(
164
+ v.array(
165
+ v.strictObject({
166
+ name: v.string(),
167
+ description: v.optional(v.string()),
168
+ content: v.record(v.string(), v.unknown()),
169
+ targets: v.array(v.string())
170
+ })
171
+ )
172
+ )
173
+ })
110
174
  )
111
175
  });
112
176
  const moduleDirectoryPath = resolve(
@@ -120,11 +184,13 @@ async function writeAwsConfigFromState(props) {
120
184
  state,
121
185
  context
122
186
  });
123
- const mappedConfig = mapStateToAwsConfig({
124
- state
125
- });
187
+ const mappedConfig = mapStateToAwsConfig({ state });
188
+ const mergedConfig = props.existingConfig != null ? {
189
+ ...props.existingConfig,
190
+ policies: props.existingConfig.policies ?? mappedConfig.policies
191
+ } : mappedConfig;
126
192
  const sortedConfig = sortAwsConfigModel({
127
- config: mappedConfig
193
+ config: mergedConfig
128
194
  });
129
195
  const nextConfigContent = renderAwsConfigTs({
130
196
  config: sortedConfig
@@ -328,10 +394,12 @@ function mapStateToAwsConfig(props) {
328
394
  `Could not map account "${account.name}" to organizational unit "${ownerOuName}".`
329
395
  );
330
396
  }
397
+ const contacts = account.alternateContacts;
331
398
  ownerOu.accounts.push({
332
399
  name: account.name,
333
400
  email: account.email,
334
- tags: account.tags ?? []
401
+ tags: account.tags ?? [],
402
+ alternateContacts: contacts != null && contacts.length > 0 ? contacts : void 0
335
403
  });
336
404
  }
337
405
  const permissionSetByArn = toRecordByProperty(
@@ -417,6 +485,73 @@ function mapStateToAwsConfig(props) {
417
485
  members.push(userName);
418
486
  }
419
487
  }
488
+ const orgPolicies = props.state.organization.policies ?? [];
489
+ const orgPolicyAttachments = props.state.organization.policyAttachments ?? [];
490
+ const ouById = toRecordByProperty(
491
+ props.state.organization.organizationalUnits,
492
+ "id"
493
+ );
494
+ const orgAccountById = toRecordByProperty(
495
+ props.state.organization.accounts,
496
+ "id"
497
+ );
498
+ function resolveTargetName(targetId, targetType) {
499
+ if (targetType === "ROOT") {
500
+ return "root";
501
+ }
502
+ if (targetType === "ORGANIZATIONAL_UNIT") {
503
+ return ouById[targetId]?.name ?? null;
504
+ }
505
+ if (targetType === "ACCOUNT") {
506
+ return orgAccountById[targetId]?.name ?? null;
507
+ }
508
+ return null;
509
+ }
510
+ const attachmentsByPolicyId = /* @__PURE__ */ new Map();
511
+ for (const attachment of orgPolicyAttachments) {
512
+ const targetName = resolveTargetName(
513
+ attachment.targetId,
514
+ attachment.targetType
515
+ );
516
+ if (targetName == null) {
517
+ continue;
518
+ }
519
+ const targets = attachmentsByPolicyId.get(attachment.policyId) ?? [];
520
+ targets.push(targetName);
521
+ attachmentsByPolicyId.set(attachment.policyId, targets);
522
+ }
523
+ const scps = orgPolicies.filter((p) => p.type === "SERVICE_CONTROL_POLICY").map((p) => ({
524
+ name: p.name,
525
+ description: p.description.length > 0 ? p.description : void 0,
526
+ content: JSON.parse(p.content),
527
+ targets: [...attachmentsByPolicyId.get(p.id) ?? []].sort(
528
+ (a, b) => a.localeCompare(b)
529
+ )
530
+ }));
531
+ const rcps = orgPolicies.filter((p) => p.type === "RESOURCE_CONTROL_POLICY").map((p) => ({
532
+ name: p.name,
533
+ description: p.description.length > 0 ? p.description : void 0,
534
+ content: JSON.parse(p.content),
535
+ targets: [...attachmentsByPolicyId.get(p.id) ?? []].sort(
536
+ (a, b) => a.localeCompare(b)
537
+ )
538
+ }));
539
+ const tagPolicies = orgPolicies.filter((p) => p.type === "TAG_POLICY").map((p) => ({
540
+ name: p.name,
541
+ description: p.description.length > 0 ? p.description : void 0,
542
+ content: JSON.parse(p.content),
543
+ targets: [...attachmentsByPolicyId.get(p.id) ?? []].sort(
544
+ (a, b) => a.localeCompare(b)
545
+ )
546
+ }));
547
+ const aiServicesOptOutPolicies = orgPolicies.filter((p) => p.type === "AISERVICES_OPT_OUT_POLICY").map((p) => ({
548
+ name: p.name,
549
+ description: p.description.length > 0 ? p.description : void 0,
550
+ content: JSON.parse(p.content),
551
+ targets: [...attachmentsByPolicyId.get(p.id) ?? []].sort(
552
+ (a, b) => a.localeCompare(b)
553
+ )
554
+ }));
420
555
  const mapped = {
421
556
  organizationalUnits,
422
557
  users: props.state.identityCenter.users.map((user) => ({
@@ -447,7 +582,17 @@ function mapStateToAwsConfig(props) {
447
582
  )
448
583
  })
449
584
  ),
450
- assignments: [...assignmentsByKey.values()]
585
+ assignments: [...assignmentsByKey.values()],
586
+ accessControlAttributes: props.state.identityCenter.accessControlAttributes.length > 0 ? props.state.identityCenter.accessControlAttributes.map((attr) => ({
587
+ key: attr.key,
588
+ source: [...attr.source]
589
+ })) : void 0,
590
+ policies: scps.length > 0 || rcps.length > 0 || tagPolicies.length > 0 || aiServicesOptOutPolicies.length > 0 ? {
591
+ serviceControlPolicies: scps.length > 0 ? scps : void 0,
592
+ resourceControlPolicies: rcps.length > 0 ? rcps : void 0,
593
+ tagPolicies: tagPolicies.length > 0 ? tagPolicies : void 0,
594
+ aiServicesOptOutPolicies: aiServicesOptOutPolicies.length > 0 ? aiServicesOptOutPolicies : void 0
595
+ } : void 0
451
596
  };
452
597
  assertUniqueNames({
453
598
  values: mapped.organizationalUnits.map((ou) => ou.name),
@@ -614,7 +759,8 @@ function mapAwsConfigToState(props) {
614
759
  email: account.email,
615
760
  status: matchedAccount?.status ?? "ACTIVE",
616
761
  parentId: ownerParentId,
617
- tags: account.tags
762
+ tags: account.tags,
763
+ alternateContacts: account.alternateContacts != null && account.alternateContacts.length > 0 ? account.alternateContacts : void 0
618
764
  });
619
765
  mappedAccountIdByName.set(account.name, mappedId);
620
766
  }
@@ -628,10 +774,7 @@ function mapAwsConfigToState(props) {
628
774
  email: user.email
629
775
  };
630
776
  });
631
- const mappedUserByUserName = toRecordByProperty(
632
- mappedUsers,
633
- "userName"
634
- );
777
+ const mappedUserByUserName = toRecordByProperty(mappedUsers, "userName");
635
778
  const mappedGroups = props.config.groups.map((group) => {
636
779
  const matchedGroup = groupByDisplayName[group.displayName];
637
780
  return {
@@ -710,13 +853,107 @@ function mapAwsConfigToState(props) {
710
853
  });
711
854
  }
712
855
  }
856
+ const configPolicies = props.config.policies;
857
+ const allConfigPolicies = [];
858
+ const ouByName = toRecordByProperty(
859
+ props.currentState.organization.organizationalUnits,
860
+ "name"
861
+ );
862
+ const stateAccountByName = toRecordByProperty(
863
+ props.currentState.organization.accounts,
864
+ "name"
865
+ );
866
+ function resolveTargetId(targetName) {
867
+ if (targetName === "root") {
868
+ return {
869
+ targetId: props.context.organization.rootId,
870
+ targetType: "ROOT"
871
+ };
872
+ }
873
+ const ou = ouByName[targetName];
874
+ if (ou != null) {
875
+ return { targetId: ou.id, targetType: "ORGANIZATIONAL_UNIT" };
876
+ }
877
+ const acct = stateAccountByName[targetName];
878
+ if (acct != null) {
879
+ return { targetId: acct.id, targetType: "ACCOUNT" };
880
+ }
881
+ return { targetId: pendingCreationId, targetType: "ACCOUNT" };
882
+ }
883
+ for (const policy of configPolicies?.serviceControlPolicies ?? []) {
884
+ allConfigPolicies.push({
885
+ name: policy.name,
886
+ description: policy.description ?? "",
887
+ type: "SERVICE_CONTROL_POLICY",
888
+ content: JSON.stringify(policy.content),
889
+ targets: policy.targets.map((t) => resolveTargetId(t))
890
+ });
891
+ }
892
+ for (const policy of configPolicies?.resourceControlPolicies ?? []) {
893
+ allConfigPolicies.push({
894
+ name: policy.name,
895
+ description: policy.description ?? "",
896
+ type: "RESOURCE_CONTROL_POLICY",
897
+ content: JSON.stringify(policy.content),
898
+ targets: policy.targets.map((t) => resolveTargetId(t))
899
+ });
900
+ }
901
+ for (const policy of configPolicies?.tagPolicies ?? []) {
902
+ allConfigPolicies.push({
903
+ name: policy.name,
904
+ description: policy.description ?? "",
905
+ type: "TAG_POLICY",
906
+ content: JSON.stringify(policy.content),
907
+ targets: policy.targets.map((t) => resolveTargetId(t))
908
+ });
909
+ }
910
+ for (const policy of configPolicies?.aiServicesOptOutPolicies ?? []) {
911
+ allConfigPolicies.push({
912
+ name: policy.name,
913
+ description: policy.description ?? "",
914
+ type: "AISERVICES_OPT_OUT_POLICY",
915
+ content: JSON.stringify(policy.content),
916
+ targets: policy.targets.map((t) => resolveTargetId(t))
917
+ });
918
+ }
919
+ const currentPoliciesByNameAndType = new Map(
920
+ (props.currentState.organization.policies ?? []).map((p) => [
921
+ `${p.type}|${p.name}`,
922
+ p
923
+ ])
924
+ );
925
+ const mappedPolicies = allConfigPolicies.map((p) => {
926
+ const current = currentPoliciesByNameAndType.get(`${p.type}|${p.name}`);
927
+ return {
928
+ id: current?.id ?? pendingCreationId,
929
+ arn: current?.arn ?? pendingCreationId,
930
+ name: p.name,
931
+ description: p.description,
932
+ type: p.type,
933
+ content: p.content
934
+ };
935
+ });
936
+ const mappedPolicyAttachments = [];
937
+ for (let i = 0; i < allConfigPolicies.length; i++) {
938
+ const configPolicy = allConfigPolicies[i];
939
+ const mappedPolicy = mappedPolicies[i];
940
+ for (const target of configPolicy.targets) {
941
+ mappedPolicyAttachments.push({
942
+ policyId: mappedPolicy.id,
943
+ targetId: target.targetId,
944
+ targetType: target.targetType
945
+ });
946
+ }
947
+ }
713
948
  const mapped = {
714
949
  version: props.currentState.version,
715
950
  generatedAt: props.currentState.generatedAt,
716
951
  organization: {
717
952
  rootId: props.context.organization.rootId,
718
953
  organizationalUnits: mappedOrganizationalUnits,
719
- accounts: mappedAccounts
954
+ accounts: mappedAccounts,
955
+ policies: mappedPolicies,
956
+ policyAttachments: mappedPolicyAttachments
720
957
  },
721
958
  identityCenter: {
722
959
  instanceArn: props.context.identityCenter.instanceArn,
@@ -732,7 +969,10 @@ function mapAwsConfigToState(props) {
732
969
  principalId: assignment.principalId,
733
970
  principalType: assignment.principalType,
734
971
  roleName: createAccessRoleName(assignment)
735
- }))
972
+ })),
973
+ accessControlAttributes: (props.config.accessControlAttributes ?? []).map(
974
+ (attr) => ({ key: attr.key, source: [...attr.source] })
975
+ )
736
976
  }
737
977
  };
738
978
  assertUniqueNames({
@@ -761,6 +1001,28 @@ function mapAwsConfigToState(props) {
761
1001
  ),
762
1002
  entityName: "permission set"
763
1003
  });
1004
+ assertUniqueNames({
1005
+ values: (props.config.policies?.serviceControlPolicies ?? []).map(
1006
+ (p) => p.name
1007
+ ),
1008
+ entityName: "SCP"
1009
+ });
1010
+ assertUniqueNames({
1011
+ values: (props.config.policies?.resourceControlPolicies ?? []).map(
1012
+ (p) => p.name
1013
+ ),
1014
+ entityName: "RCP"
1015
+ });
1016
+ assertUniqueNames({
1017
+ values: (props.config.policies?.tagPolicies ?? []).map((p) => p.name),
1018
+ entityName: "tag policy"
1019
+ });
1020
+ assertUniqueNames({
1021
+ values: (props.config.policies?.aiServicesOptOutPolicies ?? []).map(
1022
+ (p) => p.name
1023
+ ),
1024
+ entityName: "AI services opt-out policy"
1025
+ });
764
1026
  return validateState(mapped);
765
1027
  }
766
1028
  function sortAwsConfigModel(props) {
@@ -795,9 +1057,12 @@ function sortAwsConfigModel(props) {
795
1057
  for (const child of children) {
796
1058
  orderedOrganizationalUnits.push({
797
1059
  ...child,
798
- accounts: [...child.accounts].sort(
799
- (left, right) => left.name.localeCompare(right.name)
800
- )
1060
+ accounts: [...child.accounts].sort((left, right) => left.name.localeCompare(right.name)).map((account) => ({
1061
+ ...account,
1062
+ alternateContacts: account.alternateContacts == null ? void 0 : [...account.alternateContacts].sort(
1063
+ (a, b) => a.contactType.localeCompare(b.contactType)
1064
+ )
1065
+ }))
801
1066
  });
802
1067
  queue.push(child.name);
803
1068
  }
@@ -819,7 +1084,9 @@ function sortAwsConfigModel(props) {
819
1084
  awsManagedPolicies: [...permissionSet.awsManagedPolicies].sort(
820
1085
  (left, right) => left.localeCompare(right)
821
1086
  ),
822
- customerManagedPolicies: [...permissionSet.customerManagedPolicies].sort(
1087
+ customerManagedPolicies: [
1088
+ ...permissionSet.customerManagedPolicies
1089
+ ].sort(
823
1090
  (left, right) => compareStringKeys(left.path, right.path, left.name, right.name)
824
1091
  )
825
1092
  })).sort((left, right) => left.name.localeCompare(right.name)),
@@ -836,7 +1103,41 @@ function sortAwsConfigModel(props) {
836
1103
  return principalComparison;
837
1104
  }
838
1105
  return left.permissionSet.localeCompare(right.permissionSet);
839
- })
1106
+ }),
1107
+ accessControlAttributes: props.config.accessControlAttributes == null ? void 0 : [...props.config.accessControlAttributes].map((attr) => ({
1108
+ ...attr,
1109
+ source: [...attr.source].sort((a, b) => a.localeCompare(b))
1110
+ })).sort((a, b) => a.key.localeCompare(b.key)),
1111
+ policies: props.config.policies == null ? void 0 : {
1112
+ serviceControlPolicies: props.config.policies.serviceControlPolicies == null ? void 0 : [...props.config.policies.serviceControlPolicies].map((p) => ({
1113
+ ...p,
1114
+ content: sortJsonRecord(p.content),
1115
+ targets: [...p.targets].sort(
1116
+ (a, b) => a.localeCompare(b)
1117
+ )
1118
+ })).sort((a, b) => a.name.localeCompare(b.name)),
1119
+ resourceControlPolicies: props.config.policies.resourceControlPolicies == null ? void 0 : [...props.config.policies.resourceControlPolicies].map((p) => ({
1120
+ ...p,
1121
+ content: sortJsonRecord(p.content),
1122
+ targets: [...p.targets].sort(
1123
+ (a, b) => a.localeCompare(b)
1124
+ )
1125
+ })).sort((a, b) => a.name.localeCompare(b.name)),
1126
+ tagPolicies: props.config.policies.tagPolicies == null ? void 0 : [...props.config.policies.tagPolicies].map((p) => ({
1127
+ ...p,
1128
+ content: sortJsonRecord(p.content),
1129
+ targets: [...p.targets].sort(
1130
+ (a, b) => a.localeCompare(b)
1131
+ )
1132
+ })).sort((a, b) => a.name.localeCompare(b.name)),
1133
+ aiServicesOptOutPolicies: props.config.policies.aiServicesOptOutPolicies == null ? void 0 : [...props.config.policies.aiServicesOptOutPolicies].map((p) => ({
1134
+ ...p,
1135
+ content: sortJsonRecord(p.content),
1136
+ targets: [...p.targets].sort(
1137
+ (a, b) => a.localeCompare(b)
1138
+ )
1139
+ })).sort((a, b) => a.name.localeCompare(b.name))
1140
+ }
840
1141
  };
841
1142
  }
842
1143
  function renderAwsConfigTs(props) {
@@ -867,7 +1168,9 @@ function renderTsValue(value, props) {
867
1168
  return "null";
868
1169
  }
869
1170
  if (value === void 0) {
870
- throw new Error("Undefined values must be handled before TypeScript rendering.");
1171
+ throw new Error(
1172
+ "Undefined values must be handled before TypeScript rendering."
1173
+ );
871
1174
  }
872
1175
  if (typeof value === "string") {
873
1176
  return renderTsStringValue(value, props);
@@ -907,14 +1210,16 @@ ${renderedItems.map((item) => `${childIndent}${item}`).join(",\n")}
907
1210
  ${indent}]`;
908
1211
  }
909
1212
  function renderTsObject(value, props) {
910
- const entries = Object.entries(value).filter(([, entryValue]) => entryValue !== void 0);
1213
+ const entries = Object.entries(value).filter(
1214
+ ([, entryValue]) => entryValue !== void 0
1215
+ );
911
1216
  if (entries.length === 0) {
912
1217
  return "{}";
913
1218
  }
914
1219
  const indent = " ".repeat(props.indentLevel);
915
1220
  const childIndent = " ".repeat(props.indentLevel + 1);
916
1221
  const renderedEntries = entries.map(([key, entryValue]) => {
917
- const nextWithinInlinePolicy = props.withinInlinePolicy || key === "inlinePolicy";
1222
+ const nextWithinInlinePolicy = props.withinInlinePolicy || key === "inlinePolicy" || key === "content";
918
1223
  const renderedValue = renderTsValue(entryValue, {
919
1224
  indentLevel: props.indentLevel + 1,
920
1225
  withinInlinePolicy: nextWithinInlinePolicy,
@@ -1035,6 +1340,17 @@ export const awsConfigSchema = v.strictObject({
1035
1340
  value: v.string(),
1036
1341
  }),
1037
1342
  ),
1343
+ alternateContacts: v.optional(
1344
+ v.array(
1345
+ v.strictObject({
1346
+ contactType: v.picklist(["BILLING", "OPERATIONS", "SECURITY"]),
1347
+ name: v.string(),
1348
+ email: v.string(),
1349
+ phone: v.string(),
1350
+ title: v.optional(v.string()),
1351
+ }),
1352
+ ),
1353
+ ),
1038
1354
  }),
1039
1355
  ),
1040
1356
  }),
@@ -1076,6 +1392,58 @@ export const awsConfigSchema = v.strictObject({
1076
1392
  accounts: v.array(accountNameSchema),
1077
1393
  }),
1078
1394
  ),
1395
+ accessControlAttributes: v.optional(
1396
+ v.array(
1397
+ v.strictObject({
1398
+ key: v.string(),
1399
+ source: v.array(v.string()),
1400
+ }),
1401
+ ),
1402
+ ),
1403
+ policies: v.optional(
1404
+ v.strictObject({
1405
+ serviceControlPolicies: v.optional(
1406
+ v.array(
1407
+ v.strictObject({
1408
+ name: v.string(),
1409
+ description: v.optional(v.string()),
1410
+ content: v.record(v.string(), v.unknown()),
1411
+ targets: v.array(v.union([organizationalUnitNameSchema, accountNameSchema])),
1412
+ }),
1413
+ ),
1414
+ ),
1415
+ resourceControlPolicies: v.optional(
1416
+ v.array(
1417
+ v.strictObject({
1418
+ name: v.string(),
1419
+ description: v.optional(v.string()),
1420
+ content: v.record(v.string(), v.unknown()),
1421
+ targets: v.array(v.union([organizationalUnitNameSchema, accountNameSchema])),
1422
+ }),
1423
+ ),
1424
+ ),
1425
+ tagPolicies: v.optional(
1426
+ v.array(
1427
+ v.strictObject({
1428
+ name: v.string(),
1429
+ description: v.optional(v.string()),
1430
+ content: v.record(v.string(), v.unknown()),
1431
+ targets: v.array(v.union([organizationalUnitNameSchema, accountNameSchema])),
1432
+ }),
1433
+ ),
1434
+ ),
1435
+ aiServicesOptOutPolicies: v.optional(
1436
+ v.array(
1437
+ v.strictObject({
1438
+ name: v.string(),
1439
+ description: v.optional(v.string()),
1440
+ content: v.record(v.string(), v.unknown()),
1441
+ targets: v.array(v.union([organizationalUnitNameSchema, accountNameSchema])),
1442
+ }),
1443
+ ),
1444
+ ),
1445
+ }),
1446
+ ),
1079
1447
  });
1080
1448
 
1081
1449
  export type AwsConfig = v.InferOutput<typeof awsConfigSchema>;
@@ -1234,6 +1602,16 @@ async function loadAwsConfigModelFromTsFile(props) {
1234
1602
  async function readAwsContextFromFile(path) {
1235
1603
  return readAwsContextFile(path);
1236
1604
  }
1605
+ async function readPackageVersion() {
1606
+ const thisFile = fileURLToPath(import.meta.url);
1607
+ const packageDir = dirname(dirname(thisFile));
1608
+ const raw = await readFile(join(packageDir, "package.json"), "utf8");
1609
+ const pkg = JSON.parse(raw);
1610
+ if (typeof pkg.version !== "string") {
1611
+ throw new Error("Could not read version from package.json.");
1612
+ }
1613
+ return pkg.version;
1614
+ }
1237
1615
  async function loadAwsConfigTypesModule(props) {
1238
1616
  const loadedModule = await loadTsModule({
1239
1617
  modulePath: props.typesPath
@@ -1361,6 +1739,7 @@ export {
1361
1739
  loadAwsConfigModelFromTsFile,
1362
1740
  mapAwsConfigToState,
1363
1741
  readAwsContextFromFile,
1742
+ readPackageVersion,
1364
1743
  regenerateAwsConfigTypes,
1365
1744
  regenerateTypesFromState,
1366
1745
  writeAwsConfigFromState