@intentius/chant-lexicon-aws 0.18.31 → 0.18.33

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.
@@ -27,21 +27,40 @@ export interface SnapshotBeforeOutput {
27
27
  export declare function createSnapshotBeforeCapability(executor?: CloudExecutor): Capability<SnapshotBeforeInput, SnapshotBeforeOutput>;
28
28
  /** Default `snapshot-before` capability, backed by the real `CloudExecutor`. */
29
29
  export declare const snapshotBeforeCapability: Capability<SnapshotBeforeInput, SnapshotBeforeOutput>;
30
- export interface RollbackPreviousInput {
30
+ /** Restore a resource from a prior `snapshot-before` capture (DynamoDB/RDS/EBS). */
31
+ export interface RollbackPreviousSnapshotInput {
31
32
  /** Snapshot identifier to restore (typically `"@snapshot-before.snapshotId"`). */
32
33
  snapshotId: string;
33
34
  /** Resource identifier being restored. */
34
35
  resource: string;
35
36
  }
37
+ /** Roll an ECS service back to its previously recorded task definition — the
38
+ * shape the `ecs-fargate` preset and the ALB/ECS pilot compose (e.g. loomster's
39
+ * `loom-frontend`). */
40
+ export interface RollbackPreviousEcsInput {
41
+ /** ECS service name. */
42
+ service: string;
43
+ /** ECS cluster (name or ARN). */
44
+ cluster: string;
45
+ /** Explicit task definition to roll to; omitted → the executor's recorded previous. */
46
+ taskDefinition?: string;
47
+ desiredCount?: number;
48
+ }
49
+ /** `rollback-previous` accepts EITHER a snapshot restore or an ECS service
50
+ * rollback — the two things components actually compose it for. */
51
+ export type RollbackPreviousInput = RollbackPreviousSnapshotInput | RollbackPreviousEcsInput;
36
52
  export interface RollbackPreviousOutput {
37
- /** True once the restore completed. */
53
+ /** True once the restore/rollback completed. */
38
54
  restored: boolean;
39
55
  }
40
56
  /**
41
- * Restore a resource from a prior `snapshot-before` capture — an explicit,
42
- * caller-composed rollback (not the auto-triggered per-capability compensation).
43
- * Dispatches by the snapshot-id shape through the `CloudExecutor` and waits for
44
- * the restore to become available.
57
+ * Roll a resource back to its prior state — an explicit, caller-composed
58
+ * compensation (not the auto-triggered per-capability `rollback`). Dispatches by
59
+ * the input shape: an ECS service (`{service, cluster}`) rolls to its previous
60
+ * task definition; a snapshot (`{snapshotId, resource}`) restores that capture.
61
+ * An unrecognized shape fails with a clear message rather than a cryptic
62
+ * `undefined` access (chant #990 — an ECS-shaped input used to reach the
63
+ * snapshot path and throw "reading 'includes'" on the absent snapshotId).
45
64
  */
46
65
  export declare function createRollbackPreviousCapability(executor?: CloudExecutor): Capability<RollbackPreviousInput, RollbackPreviousOutput>;
47
66
  /** Default `rollback-previous` capability, backed by the real `CloudExecutor`. */
@@ -1 +1 @@
1
- {"version":3,"file":"safety.d.ts","sourceRoot":"","sources":["../../src/components/safety.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AACzE,OAAO,EAAwB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAI5E,MAAM,WAAW,mBAAmB;IAClC,wFAAwF;IACxF,QAAQ,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,YAAY,EAAE,gBAAgB,GAAG,cAAc,GAAG,mBAAmB,GAAG,YAAY,CAAC;CACtF;AAED,MAAM,WAAW,oBAAoB;IACnC,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAAC,QAAQ,GAAE,aAAsC,GAAG,UAAU,CAAC,mBAAmB,EAAE,oBAAoB,CAAC,CAOtJ;AAED,gFAAgF;AAChF,eAAO,MAAM,wBAAwB,EAAE,UAAU,CAAC,mBAAmB,EAAE,oBAAoB,CACzD,CAAC;AAInC,MAAM,WAAW,qBAAqB;IACpC,kFAAkF;IAClF,UAAU,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,uCAAuC;IACvC,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAAC,QAAQ,GAAE,aAAsC,GAAG,UAAU,CAAC,qBAAqB,EAAE,sBAAsB,CAAC,CAQ5J;AAED,kFAAkF;AAClF,eAAO,MAAM,0BAA0B,EAAE,UAAU,CAAC,qBAAqB,EAAE,sBAAsB,CAC7D,CAAC"}
1
+ {"version":3,"file":"safety.d.ts","sourceRoot":"","sources":["../../src/components/safety.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AACzE,OAAO,EAAwB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAI5E,MAAM,WAAW,mBAAmB;IAClC,wFAAwF;IACxF,QAAQ,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,YAAY,EAAE,gBAAgB,GAAG,cAAc,GAAG,mBAAmB,GAAG,YAAY,CAAC;CACtF;AAED,MAAM,WAAW,oBAAoB;IACnC,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAAC,QAAQ,GAAE,aAAsC,GAAG,UAAU,CAAC,mBAAmB,EAAE,oBAAoB,CAAC,CAOtJ;AAED,gFAAgF;AAChF,eAAO,MAAM,wBAAwB,EAAE,UAAU,CAAC,mBAAmB,EAAE,oBAAoB,CACzD,CAAC;AAInC,oFAAoF;AACpF,MAAM,WAAW,6BAA6B;IAC5C,kFAAkF;IAClF,UAAU,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;uBAEuB;AACvB,MAAM,WAAW,wBAAwB;IACvC,wBAAwB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,uFAAuF;IACvF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;mEACmE;AACnE,MAAM,MAAM,qBAAqB,GAAG,6BAA6B,GAAG,wBAAwB,CAAC;AAE7F,MAAM,WAAW,sBAAsB;IACrC,gDAAgD;IAChD,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gCAAgC,CAAC,QAAQ,GAAE,aAAsC,GAAG,UAAU,CAAC,qBAAqB,EAAE,sBAAsB,CAAC,CAuB5J;AAED,kFAAkF;AAClF,eAAO,MAAM,0BAA0B,EAAE,UAAU,CAAC,qBAAqB,EAAE,sBAAsB,CAC7D,CAAC"}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "algorithm": "sha256",
3
3
  "artifacts": {
4
- "manifest.json": "e25bec3d6323be764670c586fffab6adc33895137024397b876a20081dbf0dcc",
4
+ "manifest.json": "456e448089ef28e208e31f64fc3ec3acf6a5e7c12cf3404dbd9b88c30afe3b55",
5
5
  "meta.json": "f753beb9ef6a89191cc76afc3be19f4bc7142751ce6b2d37bea8008bc37c7793",
6
6
  "types/index.d.ts": "22463a37dc0a2e3dd8baf0ddbb72f9e12ec4e5b6dd33ecfe22a1a8a8cff272b9",
7
7
  "rules/hardcoded-region.ts": "5a0eaf7ab391231fe6cd51426ece29539cb4b36f31c8dd060956638fed55722a",
@@ -58,5 +58,5 @@
58
58
  "skills/chant-aws.md": "4d65eb160e001f2af42eb7c622a5b498c2fd1f5afbd6c8155615c010fb265c63",
59
59
  "skills/chant-aws-eks.md": "8789255709ff004ad0a875fd5999edcdc66fc6e33d710db058d9f42703bcfdfe"
60
60
  },
61
- "composite": "fee1c2b17ebb822926bb8d501766aac055bd5328fb19bf9cf15209fe4c58784a"
61
+ "composite": "8f41b82f4bff8c5e9ce33534403696cc709574bd784ec71cc3f952ba6ae9602f"
62
62
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aws",
3
- "version": "0.18.31",
3
+ "version": "0.18.33",
4
4
  "chantVersion": ">=0.1.0",
5
5
  "namespace": "AWS",
6
6
  "intrinsics": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant-lexicon-aws",
3
- "version": "0.18.31",
3
+ "version": "0.18.33",
4
4
  "description": "AWS CloudFormation lexicon for chant \u2014 declarative IaC in TypeScript",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://intentius.io/chant",
@@ -80,7 +80,7 @@
80
80
  "typescript": "^5.9.3"
81
81
  },
82
82
  "peerDependencies": {
83
- "@intentius/chant": "^0.18.31",
83
+ "@intentius/chant": "^0.18.33",
84
84
  "typescript": "^5.9.3"
85
85
  }
86
86
  }
@@ -41,6 +41,27 @@ describe("rollback-previous (#557)", () => {
41
41
  ]);
42
42
  });
43
43
 
44
+ it("rolls an ECS service back via the executor for the {service, cluster} shape (#990)", async () => {
45
+ // The ecs-fargate preset / ALB-ECS pilot (and loomster's loom-frontend)
46
+ // compose rollback-previous with an ECS service, NOT a snapshot id. This
47
+ // used to reach the snapshot path and throw "Cannot read properties of
48
+ // undefined (reading 'includes')" on the absent snapshotId.
49
+ const mock = createMockCloudExecutor();
50
+ const out = await createRollbackPreviousCapability(mock.executor).run(ctx, {
51
+ service: "loom-frontend-svc",
52
+ cluster: "arn:aws:ecs:us-east-1:1:cluster/loom",
53
+ });
54
+ expect(out).toEqual({ restored: true });
55
+ expect(mock.calls).toEqual([
56
+ { client: "ecs", method: "rollbackService", args: { cluster: "arn:aws:ecs:us-east-1:1:cluster/loom", service: "loom-frontend-svc", taskDefinition: undefined, desiredCount: undefined } },
57
+ ]);
58
+ });
59
+
60
+ it("fails with a clear message (not a cryptic undefined access) for an unrecognized shape", async () => {
61
+ const cap = createRollbackPreviousCapability(createMockCloudExecutor().executor);
62
+ await expect(cap.run(ctx, {} as never)).rejects.toThrow(/expected \{ service, cluster \}|\{ snapshotId, resource \}/);
63
+ });
64
+
44
65
  it("declares no rollback — it is the rollback", () => {
45
66
  expect(createRollbackPreviousCapability(createMockCloudExecutor().executor).rollback).toBeUndefined();
46
67
  });
@@ -45,30 +45,66 @@ export const snapshotBeforeCapability: Capability<SnapshotBeforeInput, SnapshotB
45
45
 
46
46
  // ── rollback-previous ────────────────────────────────────────────────────────
47
47
 
48
- export interface RollbackPreviousInput {
48
+ /** Restore a resource from a prior `snapshot-before` capture (DynamoDB/RDS/EBS). */
49
+ export interface RollbackPreviousSnapshotInput {
49
50
  /** Snapshot identifier to restore (typically `"@snapshot-before.snapshotId"`). */
50
51
  snapshotId: string;
51
52
  /** Resource identifier being restored. */
52
53
  resource: string;
53
54
  }
54
55
 
56
+ /** Roll an ECS service back to its previously recorded task definition — the
57
+ * shape the `ecs-fargate` preset and the ALB/ECS pilot compose (e.g. loomster's
58
+ * `loom-frontend`). */
59
+ export interface RollbackPreviousEcsInput {
60
+ /** ECS service name. */
61
+ service: string;
62
+ /** ECS cluster (name or ARN). */
63
+ cluster: string;
64
+ /** Explicit task definition to roll to; omitted → the executor's recorded previous. */
65
+ taskDefinition?: string;
66
+ desiredCount?: number;
67
+ }
68
+
69
+ /** `rollback-previous` accepts EITHER a snapshot restore or an ECS service
70
+ * rollback — the two things components actually compose it for. */
71
+ export type RollbackPreviousInput = RollbackPreviousSnapshotInput | RollbackPreviousEcsInput;
72
+
55
73
  export interface RollbackPreviousOutput {
56
- /** True once the restore completed. */
74
+ /** True once the restore/rollback completed. */
57
75
  restored: boolean;
58
76
  }
59
77
 
60
78
  /**
61
- * Restore a resource from a prior `snapshot-before` capture — an explicit,
62
- * caller-composed rollback (not the auto-triggered per-capability compensation).
63
- * Dispatches by the snapshot-id shape through the `CloudExecutor` and waits for
64
- * the restore to become available.
79
+ * Roll a resource back to its prior state — an explicit, caller-composed
80
+ * compensation (not the auto-triggered per-capability `rollback`). Dispatches by
81
+ * the input shape: an ECS service (`{service, cluster}`) rolls to its previous
82
+ * task definition; a snapshot (`{snapshotId, resource}`) restores that capture.
83
+ * An unrecognized shape fails with a clear message rather than a cryptic
84
+ * `undefined` access (chant #990 — an ECS-shaped input used to reach the
85
+ * snapshot path and throw "reading 'includes'" on the absent snapshotId).
65
86
  */
66
87
  export function createRollbackPreviousCapability(executor: CloudExecutor = defaultCloudExecutor()): Capability<RollbackPreviousInput, RollbackPreviousOutput> {
67
88
  return {
68
89
  kind: "rollback-previous",
69
90
  async run(_ctx, input) {
70
- await executor.snapshot.restore({ resource: input.resource, snapshotId: input.snapshotId });
71
- return { restored: true };
91
+ if ("service" in input && input.service) {
92
+ await executor.ecs.rollbackService({
93
+ cluster: input.cluster,
94
+ service: input.service,
95
+ taskDefinition: input.taskDefinition,
96
+ desiredCount: input.desiredCount,
97
+ });
98
+ return { restored: true };
99
+ }
100
+ if ("snapshotId" in input && input.snapshotId) {
101
+ await executor.snapshot.restore({ resource: input.resource, snapshotId: input.snapshotId });
102
+ return { restored: true };
103
+ }
104
+ throw new Error(
105
+ `rollback-previous: unrecognized input — expected { service, cluster } (ECS service rollback) or ` +
106
+ `{ snapshotId, resource } (snapshot restore), got keys [${Object.keys(input).join(", ")}]`,
107
+ );
72
108
  },
73
109
  };
74
110
  }