@hot-updater/aws 1.0.0-rc.3 → 1.0.0-rc.4

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.
@@ -9437,6 +9437,41 @@ const hasExpectedSchema = (table) => {
9437
9437
  return keyAttributes.every((attributeName) => table?.AttributeDefinitions?.some(({ AttributeName, AttributeType }) => AttributeName === attributeName && AttributeType === "S")) && table?.BillingModeSummary?.BillingMode === "PAY_PER_REQUEST" && table.OnDemandThroughput?.MaxReadRequestUnits === onDemandThroughput.MaxReadRequestUnits && table.OnDemandThroughput?.MaxWriteRequestUnits === onDemandThroughput.MaxWriteRequestUnits && hasKeySchema(table?.KeySchema, primaryKeySchema) && hasKeySchema(updateIndex?.KeySchema, updateIndexKeySchema) && updateIndex?.OnDemandThroughput?.MaxReadRequestUnits === onDemandThroughput.MaxReadRequestUnits && updateIndex?.OnDemandThroughput?.MaxWriteRequestUnits === onDemandThroughput.MaxWriteRequestUnits && updateIndex?.Projection?.ProjectionType === "ALL";
9438
9438
  };
9439
9439
  const isResourceNotFound = (error) => typeof error === "object" && error !== null && Reflect.get(error, "name") === "ResourceNotFoundException";
9440
+ const buildDynamoDBCreateTableInput = (tableName) => ({
9441
+ AttributeDefinitions: [
9442
+ {
9443
+ AttributeName: "pk",
9444
+ AttributeType: "S"
9445
+ },
9446
+ {
9447
+ AttributeName: "sk",
9448
+ AttributeType: "S"
9449
+ },
9450
+ {
9451
+ AttributeName: "gsi1pk",
9452
+ AttributeType: "S"
9453
+ },
9454
+ {
9455
+ AttributeName: "gsi1sk",
9456
+ AttributeType: "S"
9457
+ }
9458
+ ],
9459
+ BillingMode: "PAY_PER_REQUEST",
9460
+ DeletionProtectionEnabled: true,
9461
+ GlobalSecondaryIndexes: [{
9462
+ IndexName: DYNAMODB_UPDATE_INDEX_NAME,
9463
+ KeySchema: [...updateIndexKeySchema],
9464
+ Projection: { ProjectionType: "ALL" },
9465
+ OnDemandThroughput: onDemandThroughput
9466
+ }],
9467
+ KeySchema: [...primaryKeySchema],
9468
+ OnDemandThroughput: onDemandThroughput,
9469
+ TableName: tableName
9470
+ });
9471
+ const buildDynamoDBBackupInput = (tableName) => ({
9472
+ PointInTimeRecoverySpecification: { PointInTimeRecoveryEnabled: true },
9473
+ TableName: tableName
9474
+ });
9440
9475
  var DynamoDBManager = class {
9441
9476
  region;
9442
9477
  client;
@@ -9457,37 +9492,7 @@ var DynamoDBManager = class {
9457
9492
  if (error instanceof Error && error.name === "AccessDeniedException" && error.message.includes(DYNAMODB_DESCRIBE_TABLE_ACTION)) throw new DynamoDBPermissionError(tableName, this.region, error);
9458
9493
  if (!isResourceNotFound(error)) throw error;
9459
9494
  }
9460
- await this.client.createTable({
9461
- AttributeDefinitions: [
9462
- {
9463
- AttributeName: "pk",
9464
- AttributeType: "S"
9465
- },
9466
- {
9467
- AttributeName: "sk",
9468
- AttributeType: "S"
9469
- },
9470
- {
9471
- AttributeName: "gsi1pk",
9472
- AttributeType: "S"
9473
- },
9474
- {
9475
- AttributeName: "gsi1sk",
9476
- AttributeType: "S"
9477
- }
9478
- ],
9479
- BillingMode: "PAY_PER_REQUEST",
9480
- DeletionProtectionEnabled: true,
9481
- GlobalSecondaryIndexes: [{
9482
- IndexName: DYNAMODB_UPDATE_INDEX_NAME,
9483
- KeySchema: [...updateIndexKeySchema],
9484
- Projection: { ProjectionType: "ALL" },
9485
- OnDemandThroughput: onDemandThroughput
9486
- }],
9487
- KeySchema: [...primaryKeySchema],
9488
- OnDemandThroughput: onDemandThroughput,
9489
- TableName: tableName
9490
- });
9495
+ await this.client.createTable(buildDynamoDBCreateTableInput(tableName));
9491
9496
  await (0, _aws_sdk_client_dynamodb.waitUntilTableExists)({
9492
9497
  client: this.client,
9493
9498
  maxWaitTime: 120
@@ -9497,14 +9502,80 @@ var DynamoDBManager = class {
9497
9502
  async ensureLifecycle(tableName) {
9498
9503
  const { ContinuousBackupsDescription } = await this.client.describeContinuousBackups({ TableName: tableName });
9499
9504
  if (ContinuousBackupsDescription?.PointInTimeRecoveryDescription?.PointInTimeRecoveryStatus === "ENABLED") return;
9500
- await this.client.updateContinuousBackups({
9501
- PointInTimeRecoverySpecification: { PointInTimeRecoveryEnabled: true },
9502
- TableName: tableName
9503
- });
9505
+ await this.client.updateContinuousBackups(buildDynamoDBBackupInput(tableName));
9504
9506
  }
9505
9507
  };
9506
9508
  //#endregion
9507
9509
  //#region iac/iam.ts
9510
+ const buildDynamoDBPolicy = (region, accountId, tableName) => {
9511
+ const tableArn = `arn:aws:dynamodb:${region}:${accountId}:table/${tableName}`;
9512
+ return {
9513
+ Version: "2012-10-17",
9514
+ Statement: [{
9515
+ Action: ["dynamodb:Query"],
9516
+ Effect: "Allow",
9517
+ Resource: [`${tableArn}/index/${DYNAMODB_UPDATE_INDEX_NAME}`]
9518
+ }, {
9519
+ Action: [
9520
+ "dynamodb:BatchGetItem",
9521
+ "dynamodb:DeleteItem",
9522
+ "dynamodb:GetItem",
9523
+ "dynamodb:PutItem",
9524
+ "dynamodb:Query",
9525
+ "dynamodb:TransactWriteItems",
9526
+ "dynamodb:UpdateItem"
9527
+ ],
9528
+ Condition: { "ForAllValues:StringLike": { "dynamodb:LeadingKeys": [
9529
+ "_hot-updater",
9530
+ "bundles",
9531
+ "bundle_patches",
9532
+ DYNAMODB_CHANNEL_PARTITION,
9533
+ DYNAMODB_CHANNEL_NAME_PARTITION,
9534
+ DYNAMODB_INSIGHTS_PARTITION,
9535
+ DYNAMODB_INSIGHTS_INSTALLATIONS_PARTITION,
9536
+ DYNAMODB_INSIGHTS_EVENT_IDS_PARTITION,
9537
+ `${DYNAMODB_INSIGHTS_BUNDLE_PREFIX}*`,
9538
+ "_hot-updater#insights-user#*",
9539
+ DYNAMODB_API_KEY_PARTITION,
9540
+ DYNAMODB_API_KEY_HASH_PARTITION
9541
+ ] } },
9542
+ Effect: "Allow",
9543
+ Resource: [tableArn]
9544
+ }]
9545
+ };
9546
+ };
9547
+ const buildS3Policy = (bucketName) => {
9548
+ return {
9549
+ Version: "2012-10-17",
9550
+ Statement: [{
9551
+ Action: ["s3:ListBucket"],
9552
+ Effect: "Allow",
9553
+ Resource: [`arn:aws:s3:::${bucketName}`]
9554
+ }, {
9555
+ Action: ["s3:GetObject"],
9556
+ Effect: "Allow",
9557
+ Resource: [`arn:aws:s3:::${bucketName}/*`]
9558
+ }]
9559
+ };
9560
+ };
9561
+ const buildSsmPolicy = (region, accountId, parameterName) => {
9562
+ return {
9563
+ Version: "2012-10-17",
9564
+ Statement: [{
9565
+ Effect: "Allow",
9566
+ Action: ["ssm:GetParameter"],
9567
+ Resource: `arn:aws:ssm:${region}:${accountId}:parameter/${parameterName.replace(/^\/+/, "")}`
9568
+ }]
9569
+ };
9570
+ };
9571
+ const LAMBDA_EDGE_TRUST_POLICY = {
9572
+ Version: "2012-10-17",
9573
+ Statement: [{
9574
+ Effect: "Allow",
9575
+ Principal: { Service: ["lambda.amazonaws.com", "edgelambda.amazonaws.com"] },
9576
+ Action: "sts:AssumeRole"
9577
+ }]
9578
+ };
9508
9579
  var IAMManager = class {
9509
9580
  region;
9510
9581
  credentials;
@@ -9521,75 +9592,22 @@ var IAMManager = class {
9521
9592
  });
9522
9593
  }
9523
9594
  async ensureDynamoDBPolicy(iamClient, roleName, accountId, tableName) {
9524
- const tableArn = `arn:aws:dynamodb:${this.region}:${accountId}:table/${tableName}`;
9525
9595
  await iamClient.putRolePolicy({
9526
- PolicyDocument: JSON.stringify({
9527
- Version: "2012-10-17",
9528
- Statement: [{
9529
- Action: ["dynamodb:Query"],
9530
- Effect: "Allow",
9531
- Resource: [`${tableArn}/index/${DYNAMODB_UPDATE_INDEX_NAME}`]
9532
- }, {
9533
- Action: [
9534
- "dynamodb:BatchGetItem",
9535
- "dynamodb:DeleteItem",
9536
- "dynamodb:GetItem",
9537
- "dynamodb:PutItem",
9538
- "dynamodb:Query",
9539
- "dynamodb:TransactWriteItems",
9540
- "dynamodb:UpdateItem"
9541
- ],
9542
- Condition: { "ForAllValues:StringLike": { "dynamodb:LeadingKeys": [
9543
- "_hot-updater",
9544
- "bundles",
9545
- "bundle_patches",
9546
- DYNAMODB_CHANNEL_PARTITION,
9547
- DYNAMODB_CHANNEL_NAME_PARTITION,
9548
- DYNAMODB_INSIGHTS_PARTITION,
9549
- DYNAMODB_INSIGHTS_INSTALLATIONS_PARTITION,
9550
- DYNAMODB_INSIGHTS_EVENT_IDS_PARTITION,
9551
- `${DYNAMODB_INSIGHTS_BUNDLE_PREFIX}*`,
9552
- "_hot-updater#insights-user#*",
9553
- DYNAMODB_API_KEY_PARTITION,
9554
- DYNAMODB_API_KEY_HASH_PARTITION
9555
- ] } },
9556
- Effect: "Allow",
9557
- Resource: [tableArn]
9558
- }]
9559
- }),
9596
+ PolicyDocument: JSON.stringify(buildDynamoDBPolicy(this.region, accountId, tableName)),
9560
9597
  PolicyName: "HotUpdaterDynamoDBReadAccess",
9561
9598
  RoleName: roleName
9562
9599
  });
9563
9600
  }
9564
9601
  async ensureS3Policy(iamClient, roleName, bucketName) {
9565
9602
  await iamClient.putRolePolicy({
9566
- PolicyDocument: JSON.stringify({
9567
- Version: "2012-10-17",
9568
- Statement: [{
9569
- Action: ["s3:ListBucket"],
9570
- Effect: "Allow",
9571
- Resource: [`arn:aws:s3:::${bucketName}`]
9572
- }, {
9573
- Action: ["s3:GetObject"],
9574
- Effect: "Allow",
9575
- Resource: [`arn:aws:s3:::${bucketName}/*`]
9576
- }]
9577
- }),
9603
+ PolicyDocument: JSON.stringify(buildS3Policy(bucketName)),
9578
9604
  PolicyName: "HotUpdaterS3ReadAccess",
9579
9605
  RoleName: roleName
9580
9606
  });
9581
9607
  }
9582
9608
  async ensureSsmPolicy(iamClient, roleName, accountId, parameterName) {
9583
- const parameterPath = parameterName.replace(/^\/+/, "");
9584
9609
  await iamClient.putRolePolicy({
9585
- PolicyDocument: JSON.stringify({
9586
- Version: "2012-10-17",
9587
- Statement: [{
9588
- Effect: "Allow",
9589
- Action: ["ssm:GetParameter"],
9590
- Resource: `arn:aws:ssm:${this.region}:${accountId}:parameter/${parameterPath}`
9591
- }]
9592
- }),
9610
+ PolicyDocument: JSON.stringify(buildSsmPolicy(this.region, accountId, parameterName)),
9593
9611
  PolicyName: "HotUpdaterSSMAccess",
9594
9612
  RoleName: roleName
9595
9613
  });
@@ -9604,14 +9622,7 @@ var IAMManager = class {
9604
9622
  credentials: this.credentials
9605
9623
  }).getCallerIdentity({})).Account;
9606
9624
  if (!accountId) throw new Error("Failed to get AWS account ID");
9607
- const assumeRolePolicyDocument = JSON.stringify({
9608
- Version: "2012-10-17",
9609
- Statement: [{
9610
- Effect: "Allow",
9611
- Principal: { Service: ["lambda.amazonaws.com", "edgelambda.amazonaws.com"] },
9612
- Action: "sts:AssumeRole"
9613
- }]
9614
- });
9625
+ const assumeRolePolicyDocument = JSON.stringify(LAMBDA_EDGE_TRUST_POLICY);
9615
9626
  const roleName = `hot-updater-edge-${(0, node_crypto.createHash)("sha256").update(options.lambdaName).digest("hex").slice(0, 16)}`;
9616
9627
  try {
9617
9628
  const { Role: existingRole } = await iamClient.getRole({ RoleName: roleName });
@@ -10282,6 +10293,12 @@ const runInit = async ({ build, envFile }) => {
10282
10293
  _hot_updater_cli_tools.p.log.success("Done! 🎉");
10283
10294
  };
10284
10295
  //#endregion
10296
+ exports.LAMBDA_EDGE_TRUST_POLICY = LAMBDA_EDGE_TRUST_POLICY;
10297
+ exports.buildDynamoDBBackupInput = buildDynamoDBBackupInput;
10298
+ exports.buildDynamoDBCreateTableInput = buildDynamoDBCreateTableInput;
10299
+ exports.buildDynamoDBPolicy = buildDynamoDBPolicy;
10300
+ exports.buildS3Policy = buildS3Policy;
10301
+ exports.buildSsmPolicy = buildSsmPolicy;
10285
10302
  exports.prepareDynamoDBApiKey = prepareDynamoDBApiKey;
10286
10303
  exports.prepareDynamoDBDeployment = prepareDynamoDBDeployment;
10287
10304
  exports.runInit = runInit;
@@ -1,5 +1,96 @@
1
1
  import { RunInitOptions } from "@hot-updater/cli-tools";
2
2
  import { ApiKeyModel } from "@hot-updater/plugin-core";
3
+ //#region iac/dynamodb.d.ts
4
+ declare const buildDynamoDBCreateTableInput: (tableName: string) => {
5
+ AttributeDefinitions: {
6
+ AttributeName: string;
7
+ AttributeType: "S";
8
+ }[];
9
+ BillingMode: "PAY_PER_REQUEST";
10
+ DeletionProtectionEnabled: true;
11
+ GlobalSecondaryIndexes: {
12
+ IndexName: string;
13
+ KeySchema: ({
14
+ readonly AttributeName: "gsi1pk";
15
+ readonly KeyType: "HASH";
16
+ } | {
17
+ readonly AttributeName: "gsi1sk";
18
+ readonly KeyType: "RANGE";
19
+ })[];
20
+ Projection: {
21
+ ProjectionType: "ALL";
22
+ };
23
+ OnDemandThroughput: {
24
+ readonly MaxReadRequestUnits: 4000;
25
+ readonly MaxWriteRequestUnits: 100;
26
+ };
27
+ }[];
28
+ KeySchema: ({
29
+ readonly AttributeName: "pk";
30
+ readonly KeyType: "HASH";
31
+ } | {
32
+ readonly AttributeName: "sk";
33
+ readonly KeyType: "RANGE";
34
+ })[];
35
+ OnDemandThroughput: {
36
+ readonly MaxReadRequestUnits: 4000;
37
+ readonly MaxWriteRequestUnits: 100;
38
+ };
39
+ TableName: string;
40
+ };
41
+ declare const buildDynamoDBBackupInput: (tableName: string) => {
42
+ PointInTimeRecoverySpecification: {
43
+ PointInTimeRecoveryEnabled: true;
44
+ };
45
+ TableName: string;
46
+ };
47
+ //#endregion
48
+ //#region iac/iam.d.ts
49
+ declare const buildDynamoDBPolicy: (region: string, accountId: string, tableName: string) => {
50
+ Version: string;
51
+ Statement: ({
52
+ Action: string[];
53
+ Effect: string;
54
+ Resource: string[];
55
+ Condition?: undefined;
56
+ } | {
57
+ Action: string[];
58
+ Condition: {
59
+ "ForAllValues:StringLike": {
60
+ "dynamodb:LeadingKeys": string[];
61
+ };
62
+ };
63
+ Effect: string;
64
+ Resource: string[];
65
+ })[];
66
+ };
67
+ declare const buildS3Policy: (bucketName: string) => {
68
+ Version: string;
69
+ Statement: {
70
+ Action: string[];
71
+ Effect: string;
72
+ Resource: string[];
73
+ }[];
74
+ };
75
+ declare const buildSsmPolicy: (region: string, accountId: string, parameterName: string) => {
76
+ Version: string;
77
+ Statement: {
78
+ Effect: string;
79
+ Action: string[];
80
+ Resource: string;
81
+ }[];
82
+ };
83
+ declare const LAMBDA_EDGE_TRUST_POLICY: {
84
+ Version: string;
85
+ Statement: {
86
+ Effect: string;
87
+ Principal: {
88
+ Service: string[];
89
+ };
90
+ Action: string;
91
+ }[];
92
+ };
93
+ //#endregion
3
94
  //#region iac/index.d.ts
4
95
  declare const prepareDynamoDBDeployment: (input: {
5
96
  readonly credentials: {
@@ -16,4 +107,4 @@ declare const prepareDynamoDBApiKey: (input: {
16
107
  }) => Promise<string>;
17
108
  declare const runInit: ({ build, envFile }: RunInitOptions) => Promise<void>;
18
109
  //#endregion
19
- export { prepareDynamoDBApiKey, prepareDynamoDBDeployment, runInit };
110
+ export { LAMBDA_EDGE_TRUST_POLICY, buildDynamoDBBackupInput, buildDynamoDBCreateTableInput, buildDynamoDBPolicy, buildS3Policy, buildSsmPolicy, prepareDynamoDBApiKey, prepareDynamoDBDeployment, runInit };
@@ -1,5 +1,96 @@
1
- import { RunInitOptions } from "@hot-updater/cli-tools";
1
+ import { InitError, RunInitOptions } from "@hot-updater/cli-tools";
2
2
  import { ApiKeyModel } from "@hot-updater/plugin-core";
3
+ //#region iac/dynamodb.d.ts
4
+ declare const buildDynamoDBCreateTableInput: (tableName: string) => {
5
+ AttributeDefinitions: {
6
+ AttributeName: string;
7
+ AttributeType: "S";
8
+ }[];
9
+ BillingMode: "PAY_PER_REQUEST";
10
+ DeletionProtectionEnabled: true;
11
+ GlobalSecondaryIndexes: {
12
+ IndexName: string;
13
+ KeySchema: ({
14
+ readonly AttributeName: "gsi1pk";
15
+ readonly KeyType: "HASH";
16
+ } | {
17
+ readonly AttributeName: "gsi1sk";
18
+ readonly KeyType: "RANGE";
19
+ })[];
20
+ Projection: {
21
+ ProjectionType: "ALL";
22
+ };
23
+ OnDemandThroughput: {
24
+ readonly MaxReadRequestUnits: 4000;
25
+ readonly MaxWriteRequestUnits: 100;
26
+ };
27
+ }[];
28
+ KeySchema: ({
29
+ readonly AttributeName: "pk";
30
+ readonly KeyType: "HASH";
31
+ } | {
32
+ readonly AttributeName: "sk";
33
+ readonly KeyType: "RANGE";
34
+ })[];
35
+ OnDemandThroughput: {
36
+ readonly MaxReadRequestUnits: 4000;
37
+ readonly MaxWriteRequestUnits: 100;
38
+ };
39
+ TableName: string;
40
+ };
41
+ declare const buildDynamoDBBackupInput: (tableName: string) => {
42
+ PointInTimeRecoverySpecification: {
43
+ PointInTimeRecoveryEnabled: true;
44
+ };
45
+ TableName: string;
46
+ };
47
+ //#endregion
48
+ //#region iac/iam.d.ts
49
+ declare const buildDynamoDBPolicy: (region: string, accountId: string, tableName: string) => {
50
+ Version: string;
51
+ Statement: ({
52
+ Action: string[];
53
+ Effect: string;
54
+ Resource: string[];
55
+ Condition?: undefined;
56
+ } | {
57
+ Action: string[];
58
+ Condition: {
59
+ "ForAllValues:StringLike": {
60
+ "dynamodb:LeadingKeys": string[];
61
+ };
62
+ };
63
+ Effect: string;
64
+ Resource: string[];
65
+ })[];
66
+ };
67
+ declare const buildS3Policy: (bucketName: string) => {
68
+ Version: string;
69
+ Statement: {
70
+ Action: string[];
71
+ Effect: string;
72
+ Resource: string[];
73
+ }[];
74
+ };
75
+ declare const buildSsmPolicy: (region: string, accountId: string, parameterName: string) => {
76
+ Version: string;
77
+ Statement: {
78
+ Effect: string;
79
+ Action: string[];
80
+ Resource: string;
81
+ }[];
82
+ };
83
+ declare const LAMBDA_EDGE_TRUST_POLICY: {
84
+ Version: string;
85
+ Statement: {
86
+ Effect: string;
87
+ Principal: {
88
+ Service: string[];
89
+ };
90
+ Action: string;
91
+ }[];
92
+ };
93
+ //#endregion
3
94
  //#region iac/index.d.ts
4
95
  declare const prepareDynamoDBDeployment: (input: {
5
96
  readonly credentials: {
@@ -16,4 +107,4 @@ declare const prepareDynamoDBApiKey: (input: {
16
107
  }) => Promise<string>;
17
108
  declare const runInit: ({ build, envFile }: RunInitOptions) => Promise<void>;
18
109
  //#endregion
19
- export { prepareDynamoDBApiKey, prepareDynamoDBDeployment, runInit };
110
+ export { LAMBDA_EDGE_TRUST_POLICY, buildDynamoDBBackupInput, buildDynamoDBCreateTableInput, buildDynamoDBPolicy, buildS3Policy, buildSsmPolicy, prepareDynamoDBApiKey, prepareDynamoDBDeployment, runInit };
@@ -9432,6 +9432,41 @@ const hasExpectedSchema = (table) => {
9432
9432
  return keyAttributes.every((attributeName) => table?.AttributeDefinitions?.some(({ AttributeName, AttributeType }) => AttributeName === attributeName && AttributeType === "S")) && table?.BillingModeSummary?.BillingMode === "PAY_PER_REQUEST" && table.OnDemandThroughput?.MaxReadRequestUnits === onDemandThroughput.MaxReadRequestUnits && table.OnDemandThroughput?.MaxWriteRequestUnits === onDemandThroughput.MaxWriteRequestUnits && hasKeySchema(table?.KeySchema, primaryKeySchema) && hasKeySchema(updateIndex?.KeySchema, updateIndexKeySchema) && updateIndex?.OnDemandThroughput?.MaxReadRequestUnits === onDemandThroughput.MaxReadRequestUnits && updateIndex?.OnDemandThroughput?.MaxWriteRequestUnits === onDemandThroughput.MaxWriteRequestUnits && updateIndex?.Projection?.ProjectionType === "ALL";
9433
9433
  };
9434
9434
  const isResourceNotFound = (error) => typeof error === "object" && error !== null && Reflect.get(error, "name") === "ResourceNotFoundException";
9435
+ const buildDynamoDBCreateTableInput = (tableName) => ({
9436
+ AttributeDefinitions: [
9437
+ {
9438
+ AttributeName: "pk",
9439
+ AttributeType: "S"
9440
+ },
9441
+ {
9442
+ AttributeName: "sk",
9443
+ AttributeType: "S"
9444
+ },
9445
+ {
9446
+ AttributeName: "gsi1pk",
9447
+ AttributeType: "S"
9448
+ },
9449
+ {
9450
+ AttributeName: "gsi1sk",
9451
+ AttributeType: "S"
9452
+ }
9453
+ ],
9454
+ BillingMode: "PAY_PER_REQUEST",
9455
+ DeletionProtectionEnabled: true,
9456
+ GlobalSecondaryIndexes: [{
9457
+ IndexName: DYNAMODB_UPDATE_INDEX_NAME,
9458
+ KeySchema: [...updateIndexKeySchema],
9459
+ Projection: { ProjectionType: "ALL" },
9460
+ OnDemandThroughput: onDemandThroughput
9461
+ }],
9462
+ KeySchema: [...primaryKeySchema],
9463
+ OnDemandThroughput: onDemandThroughput,
9464
+ TableName: tableName
9465
+ });
9466
+ const buildDynamoDBBackupInput = (tableName) => ({
9467
+ PointInTimeRecoverySpecification: { PointInTimeRecoveryEnabled: true },
9468
+ TableName: tableName
9469
+ });
9435
9470
  var DynamoDBManager = class {
9436
9471
  region;
9437
9472
  client;
@@ -9452,37 +9487,7 @@ var DynamoDBManager = class {
9452
9487
  if (error instanceof Error && error.name === "AccessDeniedException" && error.message.includes(DYNAMODB_DESCRIBE_TABLE_ACTION)) throw new DynamoDBPermissionError(tableName, this.region, error);
9453
9488
  if (!isResourceNotFound(error)) throw error;
9454
9489
  }
9455
- await this.client.createTable({
9456
- AttributeDefinitions: [
9457
- {
9458
- AttributeName: "pk",
9459
- AttributeType: "S"
9460
- },
9461
- {
9462
- AttributeName: "sk",
9463
- AttributeType: "S"
9464
- },
9465
- {
9466
- AttributeName: "gsi1pk",
9467
- AttributeType: "S"
9468
- },
9469
- {
9470
- AttributeName: "gsi1sk",
9471
- AttributeType: "S"
9472
- }
9473
- ],
9474
- BillingMode: "PAY_PER_REQUEST",
9475
- DeletionProtectionEnabled: true,
9476
- GlobalSecondaryIndexes: [{
9477
- IndexName: DYNAMODB_UPDATE_INDEX_NAME,
9478
- KeySchema: [...updateIndexKeySchema],
9479
- Projection: { ProjectionType: "ALL" },
9480
- OnDemandThroughput: onDemandThroughput
9481
- }],
9482
- KeySchema: [...primaryKeySchema],
9483
- OnDemandThroughput: onDemandThroughput,
9484
- TableName: tableName
9485
- });
9490
+ await this.client.createTable(buildDynamoDBCreateTableInput(tableName));
9486
9491
  await waitUntilTableExists({
9487
9492
  client: this.client,
9488
9493
  maxWaitTime: 120
@@ -9492,14 +9497,80 @@ var DynamoDBManager = class {
9492
9497
  async ensureLifecycle(tableName) {
9493
9498
  const { ContinuousBackupsDescription } = await this.client.describeContinuousBackups({ TableName: tableName });
9494
9499
  if (ContinuousBackupsDescription?.PointInTimeRecoveryDescription?.PointInTimeRecoveryStatus === "ENABLED") return;
9495
- await this.client.updateContinuousBackups({
9496
- PointInTimeRecoverySpecification: { PointInTimeRecoveryEnabled: true },
9497
- TableName: tableName
9498
- });
9500
+ await this.client.updateContinuousBackups(buildDynamoDBBackupInput(tableName));
9499
9501
  }
9500
9502
  };
9501
9503
  //#endregion
9502
9504
  //#region iac/iam.ts
9505
+ const buildDynamoDBPolicy = (region, accountId, tableName) => {
9506
+ const tableArn = `arn:aws:dynamodb:${region}:${accountId}:table/${tableName}`;
9507
+ return {
9508
+ Version: "2012-10-17",
9509
+ Statement: [{
9510
+ Action: ["dynamodb:Query"],
9511
+ Effect: "Allow",
9512
+ Resource: [`${tableArn}/index/${DYNAMODB_UPDATE_INDEX_NAME}`]
9513
+ }, {
9514
+ Action: [
9515
+ "dynamodb:BatchGetItem",
9516
+ "dynamodb:DeleteItem",
9517
+ "dynamodb:GetItem",
9518
+ "dynamodb:PutItem",
9519
+ "dynamodb:Query",
9520
+ "dynamodb:TransactWriteItems",
9521
+ "dynamodb:UpdateItem"
9522
+ ],
9523
+ Condition: { "ForAllValues:StringLike": { "dynamodb:LeadingKeys": [
9524
+ "_hot-updater",
9525
+ "bundles",
9526
+ "bundle_patches",
9527
+ DYNAMODB_CHANNEL_PARTITION,
9528
+ DYNAMODB_CHANNEL_NAME_PARTITION,
9529
+ DYNAMODB_INSIGHTS_PARTITION,
9530
+ DYNAMODB_INSIGHTS_INSTALLATIONS_PARTITION,
9531
+ DYNAMODB_INSIGHTS_EVENT_IDS_PARTITION,
9532
+ `${DYNAMODB_INSIGHTS_BUNDLE_PREFIX}*`,
9533
+ "_hot-updater#insights-user#*",
9534
+ DYNAMODB_API_KEY_PARTITION,
9535
+ DYNAMODB_API_KEY_HASH_PARTITION
9536
+ ] } },
9537
+ Effect: "Allow",
9538
+ Resource: [tableArn]
9539
+ }]
9540
+ };
9541
+ };
9542
+ const buildS3Policy = (bucketName) => {
9543
+ return {
9544
+ Version: "2012-10-17",
9545
+ Statement: [{
9546
+ Action: ["s3:ListBucket"],
9547
+ Effect: "Allow",
9548
+ Resource: [`arn:aws:s3:::${bucketName}`]
9549
+ }, {
9550
+ Action: ["s3:GetObject"],
9551
+ Effect: "Allow",
9552
+ Resource: [`arn:aws:s3:::${bucketName}/*`]
9553
+ }]
9554
+ };
9555
+ };
9556
+ const buildSsmPolicy = (region, accountId, parameterName) => {
9557
+ return {
9558
+ Version: "2012-10-17",
9559
+ Statement: [{
9560
+ Effect: "Allow",
9561
+ Action: ["ssm:GetParameter"],
9562
+ Resource: `arn:aws:ssm:${region}:${accountId}:parameter/${parameterName.replace(/^\/+/, "")}`
9563
+ }]
9564
+ };
9565
+ };
9566
+ const LAMBDA_EDGE_TRUST_POLICY = {
9567
+ Version: "2012-10-17",
9568
+ Statement: [{
9569
+ Effect: "Allow",
9570
+ Principal: { Service: ["lambda.amazonaws.com", "edgelambda.amazonaws.com"] },
9571
+ Action: "sts:AssumeRole"
9572
+ }]
9573
+ };
9503
9574
  var IAMManager = class {
9504
9575
  region;
9505
9576
  credentials;
@@ -9516,75 +9587,22 @@ var IAMManager = class {
9516
9587
  });
9517
9588
  }
9518
9589
  async ensureDynamoDBPolicy(iamClient, roleName, accountId, tableName) {
9519
- const tableArn = `arn:aws:dynamodb:${this.region}:${accountId}:table/${tableName}`;
9520
9590
  await iamClient.putRolePolicy({
9521
- PolicyDocument: JSON.stringify({
9522
- Version: "2012-10-17",
9523
- Statement: [{
9524
- Action: ["dynamodb:Query"],
9525
- Effect: "Allow",
9526
- Resource: [`${tableArn}/index/${DYNAMODB_UPDATE_INDEX_NAME}`]
9527
- }, {
9528
- Action: [
9529
- "dynamodb:BatchGetItem",
9530
- "dynamodb:DeleteItem",
9531
- "dynamodb:GetItem",
9532
- "dynamodb:PutItem",
9533
- "dynamodb:Query",
9534
- "dynamodb:TransactWriteItems",
9535
- "dynamodb:UpdateItem"
9536
- ],
9537
- Condition: { "ForAllValues:StringLike": { "dynamodb:LeadingKeys": [
9538
- "_hot-updater",
9539
- "bundles",
9540
- "bundle_patches",
9541
- DYNAMODB_CHANNEL_PARTITION,
9542
- DYNAMODB_CHANNEL_NAME_PARTITION,
9543
- DYNAMODB_INSIGHTS_PARTITION,
9544
- DYNAMODB_INSIGHTS_INSTALLATIONS_PARTITION,
9545
- DYNAMODB_INSIGHTS_EVENT_IDS_PARTITION,
9546
- `${DYNAMODB_INSIGHTS_BUNDLE_PREFIX}*`,
9547
- "_hot-updater#insights-user#*",
9548
- DYNAMODB_API_KEY_PARTITION,
9549
- DYNAMODB_API_KEY_HASH_PARTITION
9550
- ] } },
9551
- Effect: "Allow",
9552
- Resource: [tableArn]
9553
- }]
9554
- }),
9591
+ PolicyDocument: JSON.stringify(buildDynamoDBPolicy(this.region, accountId, tableName)),
9555
9592
  PolicyName: "HotUpdaterDynamoDBReadAccess",
9556
9593
  RoleName: roleName
9557
9594
  });
9558
9595
  }
9559
9596
  async ensureS3Policy(iamClient, roleName, bucketName) {
9560
9597
  await iamClient.putRolePolicy({
9561
- PolicyDocument: JSON.stringify({
9562
- Version: "2012-10-17",
9563
- Statement: [{
9564
- Action: ["s3:ListBucket"],
9565
- Effect: "Allow",
9566
- Resource: [`arn:aws:s3:::${bucketName}`]
9567
- }, {
9568
- Action: ["s3:GetObject"],
9569
- Effect: "Allow",
9570
- Resource: [`arn:aws:s3:::${bucketName}/*`]
9571
- }]
9572
- }),
9598
+ PolicyDocument: JSON.stringify(buildS3Policy(bucketName)),
9573
9599
  PolicyName: "HotUpdaterS3ReadAccess",
9574
9600
  RoleName: roleName
9575
9601
  });
9576
9602
  }
9577
9603
  async ensureSsmPolicy(iamClient, roleName, accountId, parameterName) {
9578
- const parameterPath = parameterName.replace(/^\/+/, "");
9579
9604
  await iamClient.putRolePolicy({
9580
- PolicyDocument: JSON.stringify({
9581
- Version: "2012-10-17",
9582
- Statement: [{
9583
- Effect: "Allow",
9584
- Action: ["ssm:GetParameter"],
9585
- Resource: `arn:aws:ssm:${this.region}:${accountId}:parameter/${parameterPath}`
9586
- }]
9587
- }),
9605
+ PolicyDocument: JSON.stringify(buildSsmPolicy(this.region, accountId, parameterName)),
9588
9606
  PolicyName: "HotUpdaterSSMAccess",
9589
9607
  RoleName: roleName
9590
9608
  });
@@ -9599,14 +9617,7 @@ var IAMManager = class {
9599
9617
  credentials: this.credentials
9600
9618
  }).getCallerIdentity({})).Account;
9601
9619
  if (!accountId) throw new Error("Failed to get AWS account ID");
9602
- const assumeRolePolicyDocument = JSON.stringify({
9603
- Version: "2012-10-17",
9604
- Statement: [{
9605
- Effect: "Allow",
9606
- Principal: { Service: ["lambda.amazonaws.com", "edgelambda.amazonaws.com"] },
9607
- Action: "sts:AssumeRole"
9608
- }]
9609
- });
9620
+ const assumeRolePolicyDocument = JSON.stringify(LAMBDA_EDGE_TRUST_POLICY);
9610
9621
  const roleName = `hot-updater-edge-${createHash("sha256").update(options.lambdaName).digest("hex").slice(0, 16)}`;
9611
9622
  try {
9612
9623
  const { Role: existingRole } = await iamClient.getRole({ RoleName: roleName });
@@ -10277,4 +10288,4 @@ const runInit = async ({ build, envFile }) => {
10277
10288
  p.log.success("Done! 🎉");
10278
10289
  };
10279
10290
  //#endregion
10280
- export { prepareDynamoDBApiKey, prepareDynamoDBDeployment, runInit };
10291
+ export { LAMBDA_EDGE_TRUST_POLICY, buildDynamoDBBackupInput, buildDynamoDBCreateTableInput, buildDynamoDBPolicy, buildS3Policy, buildSsmPolicy, prepareDynamoDBApiKey, prepareDynamoDBDeployment, runInit };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hot-updater/aws",
3
3
  "type": "module",
4
- "version": "1.0.0-rc.3",
4
+ "version": "1.0.0-rc.4",
5
5
  "description": "React Native OTA solution for self-hosted",
6
6
  "main": "dist/index.cjs",
7
7
  "module": "dist/index.mjs",
@@ -69,8 +69,8 @@
69
69
  "hono": "4.12.34",
70
70
  "aws-lambda": "1.0.7",
71
71
  "@hot-updater/cli-tools": "1.0.0-rc.3",
72
- "@hot-updater/server": "1.0.0-rc.3",
73
- "@hot-updater/plugin-core": "1.0.0-rc.3"
72
+ "@hot-updater/plugin-core": "1.0.0-rc.3",
73
+ "@hot-updater/server": "1.0.0-rc.3"
74
74
  },
75
75
  "scripts": {
76
76
  "build": "tsdown",