@continuous-excellence/ze-great-dashboard-aws 0.31.41 → 0.31.42

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.
@@ -85,11 +85,31 @@ export type BootstrapConsistency = {
85
85
  ok: boolean;
86
86
  mismatches: string[];
87
87
  };
88
+ export type CloudFormationTemplateDocument = {
89
+ Metadata?: {
90
+ PackageManagedParameters?: unknown;
91
+ };
92
+ Outputs?: Record<string, {
93
+ Value?: unknown;
94
+ }>;
95
+ Parameters?: Record<string, {
96
+ Default?: unknown;
97
+ }>;
98
+ Resources?: Record<string, {
99
+ Type?: unknown;
100
+ }>;
101
+ };
88
102
  export declare function requireComputeMode(persisted: Pick<BootstrapConfig, 'mode'>, explicit?: string): ComputeMode;
89
103
  export declare function bootstrapTemplatePath(kind: BootstrapKind, mode?: ComputeMode): Promise<string>;
90
104
  export declare function bootstrapTemplate(kind: BootstrapKind, mode?: ComputeMode): Promise<string>;
91
105
  /** Resolves the package-owned identity intended for a manifest at the selected compute mode. */
92
106
  export declare function installedBootstrapDesiredState(config?: Pick<BootstrapConfig, 'mode'>): Promise<BootstrapDesiredState>;
107
+ /**
108
+ * Reads the structural portions of a CloudFormation YAML template that this package owns.
109
+ * CloudFormation's short-form intrinsic tags are intentionally opaque here: this package only
110
+ * inspects scalar metadata and declarations, and does not evaluate a template.
111
+ */
112
+ export declare function parseCloudFormationTemplate(template: string): CloudFormationTemplateDocument;
93
113
  export declare function bootstrapContractVersion(template: string): string;
94
114
  export declare function bootstrapTemplateRevision(template: string): string;
95
115
  /** Returns installed templates and a reviewable, non-secret plan without external calls. */
package/dist/cli.js CHANGED
@@ -4,17 +4,16 @@
4
4
  import { execFile as execFile2 } from "node:child_process";
5
5
  import { readFile as readFile7, writeFile as writeFile4 } from "node:fs/promises";
6
6
  import { promisify as promisify2 } from "node:util";
7
- import { parse as parse2 } from "yaml";
8
7
 
9
8
  // packages/aws/src/doctor.ts
10
9
  import { execFile } from "node:child_process";
11
10
  import { readFile as readFile6 } from "node:fs/promises";
12
11
  import { promisify } from "node:util";
13
- import { parse } from "yaml";
14
12
 
15
13
  // packages/aws/src/bootstrap.ts
16
14
  import { readFile as readFile3 } from "node:fs/promises";
17
15
  import { fileURLToPath } from "node:url";
16
+ import { parseDocument } from "yaml";
18
17
 
19
18
  // packages/aws/src/compute-mode.ts
20
19
  function valid(value2, label) {
@@ -1225,35 +1224,60 @@ async function installedTemplateInspections(mode) {
1225
1224
  })
1226
1225
  );
1227
1226
  }
1227
+ function parseCloudFormationTemplate(template) {
1228
+ const document = parseDocument(template);
1229
+ if (document.errors.length)
1230
+ throw new Error(`Invalid CloudFormation template: ${document.errors[0]}`);
1231
+ const parsed = document.toJS();
1232
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
1233
+ throw new Error("CloudFormation template must contain a YAML object");
1234
+ return parsed;
1235
+ }
1236
+ function outputValue(template, name) {
1237
+ const value2 = parseCloudFormationTemplate(template).Outputs?.[name]?.Value;
1238
+ return typeof value2 === "string" ? value2 : void 0;
1239
+ }
1228
1240
  function bootstrapContractVersion(template) {
1229
- const version = template.match(/BootstrapContractVersion:\s*\{\s*Value:\s*'([^']+)'\s*}/)?.[1];
1241
+ const version = outputValue(template, "BootstrapContractVersion");
1230
1242
  if (!version) throw new Error("Bootstrap template has no BootstrapContractVersion output");
1231
1243
  return version;
1232
1244
  }
1233
1245
  function bootstrapTemplateRevision(template) {
1234
- const revision = template.match(/BootstrapTemplateRevision:\s*\{\s*Value:\s*'([^']+)'\s*}/)?.[1];
1246
+ const revision = outputValue(template, "BootstrapTemplateRevision");
1235
1247
  if (!revision) throw new Error("Bootstrap template has no BootstrapTemplateRevision output");
1236
1248
  return revision;
1237
1249
  }
1238
- function templateRevisionIfPresent(template) {
1239
- return template.match(/BootstrapTemplateRevision:\s*\{\s*Value:\s*'([^']+)'\s*}/)?.[1];
1240
- }
1241
1250
  function inspectTemplate(kind, path, template) {
1242
- const resourcesBlock = template.match(/^Resources:\n([\s\S]*?)(?=^[A-Za-z][A-Za-z0-9]*:\s*$)/m)?.[1] ?? "";
1243
- const resources = [
1244
- ...resourcesBlock.matchAll(/^ {2}([A-Za-z][A-Za-z0-9]+):\n {4}Type: ([^\n]+)$/gm)
1245
- ].map((match) => ({ logicalId: match[1], type: match[2] }));
1246
- const iamActions = [...template.matchAll(/^\s+Action: (?:\[([^\]]+)\]|([^\n]+))$/gm)].flatMap(([, list, scalar]) => (list ?? scalar ?? "").split(",").map((action) => action.trim())).filter(Boolean);
1251
+ const document = parseCloudFormationTemplate(template);
1252
+ const contractVersion = document.Outputs?.BootstrapContractVersion?.Value;
1253
+ if (typeof contractVersion !== "string" || !contractVersion)
1254
+ throw new Error("Bootstrap template has no BootstrapContractVersion output");
1255
+ const resources = Object.entries(document.Resources ?? {}).flatMap(
1256
+ ([logicalId, resource]) => typeof resource?.Type === "string" ? [{ logicalId, type: resource.Type }] : []
1257
+ );
1258
+ const iamActions = declaredIamActions(document.Resources);
1247
1259
  return {
1248
1260
  kind,
1249
1261
  path,
1250
- contractVersion: bootstrapContractVersion(template),
1251
- templateRevision: templateRevisionIfPresent(template),
1262
+ contractVersion,
1263
+ templateRevision: typeof document.Outputs?.BootstrapTemplateRevision?.Value === "string" ? document.Outputs.BootstrapTemplateRevision.Value : void 0,
1252
1264
  sha256: sha256(template),
1253
1265
  resources,
1254
1266
  iamActions: [...new Set(iamActions)]
1255
1267
  };
1256
1268
  }
1269
+ function declaredIamActions(value2) {
1270
+ if (Array.isArray(value2)) return value2.flatMap(declaredIamActions);
1271
+ if (!value2 || typeof value2 !== "object") return [];
1272
+ const record = value2;
1273
+ const actions = actionValues(record.Action);
1274
+ return [...actions, ...Object.values(record).flatMap(declaredIamActions)];
1275
+ }
1276
+ function actionValues(value2) {
1277
+ if (typeof value2 === "string") return [value2];
1278
+ if (Array.isArray(value2)) return value2.flatMap(actionValues);
1279
+ return [];
1280
+ }
1257
1281
  async function bootstrapPlan(config) {
1258
1282
  const packageManifest = JSON.parse(
1259
1283
  await readFile3(new URL("../package.json", import.meta.url), "utf8")
@@ -2150,7 +2174,7 @@ function zipSync(data, opts) {
2150
2174
  }
2151
2175
 
2152
2176
  // packages/aws/src/index.ts
2153
- import { parseDocument, Scalar } from "yaml";
2177
+ import { parseDocument as parseDocument2, Scalar } from "yaml";
2154
2178
 
2155
2179
  // packages/aws/src/bootstrap-check.ts
2156
2180
  function formatBootstrapCheckText(result) {
@@ -3249,7 +3273,7 @@ function requireImageDigest(image) {
3249
3273
  return image;
3250
3274
  }
3251
3275
  function deploymentTemplate(template, values) {
3252
- const document = parseDocument(template);
3276
+ const document = parseDocument2(template);
3253
3277
  if (document.errors.length)
3254
3278
  throw new Error(`Invalid CloudFormation template: ${document.errors[0]}`);
3255
3279
  const managedValue = document.toJS().Metadata?.PackageManagedParameters;
@@ -3414,16 +3438,9 @@ async function templateContract(parameters) {
3414
3438
  parameters.map((item) => [item.ParameterKey, item.ParameterValue])
3415
3439
  );
3416
3440
  const mode = computeMode({ mode: values.ComputeMode });
3417
- const template = await cloudFormationTemplate(mode);
3418
- const parametersBlock = template.match(
3419
- /^Parameters:\n[\s\S]*?(?=^[A-Za-z][A-Za-z0-9]*:\s*$)/m
3420
- )?.[0];
3421
- const metadataBlock = template.match(/^Metadata:\n[\s\S]*?(?=^Parameters:\s*$)/m)?.[0];
3422
- if (!parametersBlock) throw new Error("template has no Parameters block");
3423
- const parsedParameters = parse(parametersBlock);
3424
- const parsedMetadata = metadataBlock ? parse(metadataBlock) : {};
3425
- const definitions = parsedParameters.Parameters ?? {};
3426
- const managedValue = parsedMetadata.Metadata?.PackageManagedParameters ?? [];
3441
+ const template = parseCloudFormationTemplate(await cloudFormationTemplate(mode));
3442
+ const definitions = template.Parameters ?? {};
3443
+ const managedValue = template.Metadata?.PackageManagedParameters ?? [];
3427
3444
  if (!Array.isArray(managedValue) || !managedValue.every((key) => typeof key === "string"))
3428
3445
  throw new Error("template has invalid PackageManagedParameters metadata");
3429
3446
  const managed = new Set(managedValue);
@@ -3677,24 +3694,20 @@ var preflightRunner = {
3677
3694
  }
3678
3695
  };
3679
3696
  async function templateParameters(mode = "lambda") {
3680
- const template = await cloudFormationTemplate(mode);
3681
- const block = template.match(/^Parameters:\n[\s\S]*?(?=^[A-Za-z][A-Za-z0-9]*:\s*$)/m)?.[0];
3682
- if (!block) throw new Error("Unable to read Parameters from the CloudFormation template");
3683
- const parsed = parse2(block);
3684
- if (!parsed.Parameters) throw new Error("CloudFormation template has no Parameters");
3685
- const metadataBlock = template.match(/^Metadata:\n[\s\S]*?(?=^Parameters:\s*$)/m)?.[0];
3686
- const metadata = metadataBlock ? parse2(metadataBlock).Metadata ?? {} : {};
3697
+ const template = parseCloudFormationTemplate(await cloudFormationTemplate(mode));
3698
+ if (!template.Parameters) throw new Error("CloudFormation template has no Parameters");
3699
+ const metadata = template.Metadata ?? {};
3687
3700
  if (metadata.PackageManagedParameters !== void 0 && (!Array.isArray(metadata.PackageManagedParameters) || !metadata.PackageManagedParameters.every((key) => typeof key === "string")))
3688
3701
  throw new Error("CloudFormation template has invalid PackageManagedParameters metadata");
3689
3702
  const packageManaged = new Set(metadata.PackageManagedParameters ?? []);
3690
3703
  const unknownManaged = [...packageManaged].filter(
3691
- (key) => !Object.hasOwn(parsed.Parameters ?? {}, key)
3704
+ (key) => !Object.hasOwn(template.Parameters ?? {}, key)
3692
3705
  );
3693
3706
  if (unknownManaged.length)
3694
3707
  throw new Error(
3695
3708
  `CloudFormation template has unknown package-managed parameters: ${unknownManaged.join(", ")}`
3696
3709
  );
3697
- return { definitions: parsed.Parameters, packageManaged };
3710
+ return { definitions: template.Parameters, packageManaged };
3698
3711
  }
3699
3712
  function validateConsumerParameters(supplied, template) {
3700
3713
  const values = Object.fromEntries(
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { ComputeMode } from './bootstrap.js';
2
- export { type BootstrapConfig, type BootstrapConsistency, type BootstrapDesiredState, type BootstrapDesiredStateComparison, type BootstrapKind, type BootstrapPlan, type BootstrapTemplateInspection, bootstrapConsistency, bootstrapContractVersion, bootstrapPlan, bootstrapTemplate, bootstrapTemplatePath, bootstrapTemplateRevision, type CloudFormationParameterValue, type ComputeMode, computeMode, coreBootstrapOutputs, type DeployedBootstrapStack, deployedBootstrapStack, installedBootstrapDesiredState, mergeBootstrapParameters, requireComputeMode, requiredBootstrapParameters, resolveComputeMode, } from './bootstrap.js';
2
+ export { type BootstrapConfig, type BootstrapConsistency, type BootstrapDesiredState, type BootstrapDesiredStateComparison, type BootstrapKind, type BootstrapPlan, type BootstrapTemplateInspection, bootstrapConsistency, bootstrapContractVersion, bootstrapPlan, bootstrapTemplate, bootstrapTemplatePath, bootstrapTemplateRevision, type CloudFormationParameterValue, type CloudFormationTemplateDocument, type ComputeMode, computeMode, coreBootstrapOutputs, type DeployedBootstrapStack, deployedBootstrapStack, installedBootstrapDesiredState, mergeBootstrapParameters, parseCloudFormationTemplate, requireComputeMode, requiredBootstrapParameters, resolveComputeMode, } from './bootstrap.js';
3
3
  export { type BootstrapCheck, type BootstrapCheckDependencies, type BootstrapResourceDifference, type BootstrapResourceDrift, type BootstrapResourceDriftResult, type BootstrapStackCheck, checkBootstrap, formatBootstrapCheckText, } from './bootstrap-check.js';
4
4
  export { type BootstrapCheckStatus, type BootstrapGuideReport, type BootstrapInitInput, type BootstrapManifestUpgrade, type BootstrapPreflight, type BootstrapPreflightCheck, bootstrapGuide, bootstrapGuideReport, bootstrapPreflight, scaffoldBootstrapManifest, upgradeBootstrapManifest, } from './guided.js';
5
5
  export { type BootstrapHandoff, type BootstrapPhase, type BootstrapProvider, type BootstrapVerification, bootstrapHandoff, type CommandRunner, githubOidcProvider, verifyBootstrap, } from './handoff.js';
package/dist/index.js CHANGED
@@ -720,7 +720,7 @@ function zipSync(data, opts) {
720
720
  }
721
721
 
722
722
  // packages/aws/src/index.ts
723
- import { parseDocument, Scalar } from "yaml";
723
+ import { parseDocument as parseDocument2, Scalar } from "yaml";
724
724
 
725
725
  // packages/aws/src/release.ts
726
726
  import { createHash } from "node:crypto";
@@ -1757,6 +1757,7 @@ function sha256(value2) {
1757
1757
  // packages/aws/src/bootstrap.ts
1758
1758
  import { readFile as readFile3 } from "node:fs/promises";
1759
1759
  import { fileURLToPath } from "node:url";
1760
+ import { parseDocument } from "yaml";
1760
1761
 
1761
1762
  // packages/aws/src/compute-mode.ts
1762
1763
  function valid(value2, label) {
@@ -1935,35 +1936,60 @@ async function installedTemplateInspections(mode) {
1935
1936
  })
1936
1937
  );
1937
1938
  }
1939
+ function parseCloudFormationTemplate(template) {
1940
+ const document = parseDocument(template);
1941
+ if (document.errors.length)
1942
+ throw new Error(`Invalid CloudFormation template: ${document.errors[0]}`);
1943
+ const parsed = document.toJS();
1944
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
1945
+ throw new Error("CloudFormation template must contain a YAML object");
1946
+ return parsed;
1947
+ }
1948
+ function outputValue(template, name) {
1949
+ const value2 = parseCloudFormationTemplate(template).Outputs?.[name]?.Value;
1950
+ return typeof value2 === "string" ? value2 : void 0;
1951
+ }
1938
1952
  function bootstrapContractVersion(template) {
1939
- const version = template.match(/BootstrapContractVersion:\s*\{\s*Value:\s*'([^']+)'\s*}/)?.[1];
1953
+ const version = outputValue(template, "BootstrapContractVersion");
1940
1954
  if (!version) throw new Error("Bootstrap template has no BootstrapContractVersion output");
1941
1955
  return version;
1942
1956
  }
1943
1957
  function bootstrapTemplateRevision(template) {
1944
- const revision = template.match(/BootstrapTemplateRevision:\s*\{\s*Value:\s*'([^']+)'\s*}/)?.[1];
1958
+ const revision = outputValue(template, "BootstrapTemplateRevision");
1945
1959
  if (!revision) throw new Error("Bootstrap template has no BootstrapTemplateRevision output");
1946
1960
  return revision;
1947
1961
  }
1948
- function templateRevisionIfPresent(template) {
1949
- return template.match(/BootstrapTemplateRevision:\s*\{\s*Value:\s*'([^']+)'\s*}/)?.[1];
1950
- }
1951
1962
  function inspectTemplate(kind, path, template) {
1952
- const resourcesBlock = template.match(/^Resources:\n([\s\S]*?)(?=^[A-Za-z][A-Za-z0-9]*:\s*$)/m)?.[1] ?? "";
1953
- const resources = [
1954
- ...resourcesBlock.matchAll(/^ {2}([A-Za-z][A-Za-z0-9]+):\n {4}Type: ([^\n]+)$/gm)
1955
- ].map((match) => ({ logicalId: match[1], type: match[2] }));
1956
- const iamActions = [...template.matchAll(/^\s+Action: (?:\[([^\]]+)\]|([^\n]+))$/gm)].flatMap(([, list, scalar]) => (list ?? scalar ?? "").split(",").map((action) => action.trim())).filter(Boolean);
1963
+ const document = parseCloudFormationTemplate(template);
1964
+ const contractVersion = document.Outputs?.BootstrapContractVersion?.Value;
1965
+ if (typeof contractVersion !== "string" || !contractVersion)
1966
+ throw new Error("Bootstrap template has no BootstrapContractVersion output");
1967
+ const resources = Object.entries(document.Resources ?? {}).flatMap(
1968
+ ([logicalId, resource]) => typeof resource?.Type === "string" ? [{ logicalId, type: resource.Type }] : []
1969
+ );
1970
+ const iamActions = declaredIamActions(document.Resources);
1957
1971
  return {
1958
1972
  kind,
1959
1973
  path,
1960
- contractVersion: bootstrapContractVersion(template),
1961
- templateRevision: templateRevisionIfPresent(template),
1974
+ contractVersion,
1975
+ templateRevision: typeof document.Outputs?.BootstrapTemplateRevision?.Value === "string" ? document.Outputs.BootstrapTemplateRevision.Value : void 0,
1962
1976
  sha256: sha256(template),
1963
1977
  resources,
1964
1978
  iamActions: [...new Set(iamActions)]
1965
1979
  };
1966
1980
  }
1981
+ function declaredIamActions(value2) {
1982
+ if (Array.isArray(value2)) return value2.flatMap(declaredIamActions);
1983
+ if (!value2 || typeof value2 !== "object") return [];
1984
+ const record = value2;
1985
+ const actions = actionValues(record.Action);
1986
+ return [...actions, ...Object.values(record).flatMap(declaredIamActions)];
1987
+ }
1988
+ function actionValues(value2) {
1989
+ if (typeof value2 === "string") return [value2];
1990
+ if (Array.isArray(value2)) return value2.flatMap(actionValues);
1991
+ return [];
1992
+ }
1967
1993
  async function bootstrapPlan(config) {
1968
1994
  const packageManifest = JSON.parse(
1969
1995
  await readFile3(new URL("../package.json", import.meta.url), "utf8")
@@ -3238,7 +3264,7 @@ function requireImageDigest(image) {
3238
3264
  return image;
3239
3265
  }
3240
3266
  function deploymentTemplate(template, values) {
3241
- const document = parseDocument(template);
3267
+ const document = parseDocument2(template);
3242
3268
  if (document.errors.length)
3243
3269
  throw new Error(`Invalid CloudFormation template: ${document.errors[0]}`);
3244
3270
  const managedValue = document.toJS().Metadata?.PackageManagedParameters;
@@ -3398,6 +3424,7 @@ export {
3398
3424
  mergeBootstrapParameters,
3399
3425
  packageEcs,
3400
3426
  packageLambda,
3427
+ parseCloudFormationTemplate,
3401
3428
  requireComputeMode,
3402
3429
  requiredBootstrapParameters,
3403
3430
  resolveComputeMode,
package/dist/lambda.mjs CHANGED
@@ -1889,12 +1889,14 @@ var init_schemaLogFilter = __esm({
1889
1889
  });
1890
1890
 
1891
1891
  // node_modules/@smithy/core/dist-es/submodules/client/smithy-client/command.js
1892
- var import_types2, Command, ClassBuilder;
1892
+ var import_types2, operationEventStreamMarker, Command, ClassBuilder;
1893
1893
  var init_command = __esm({
1894
1894
  "node_modules/@smithy/core/dist-es/submodules/client/smithy-client/command.js"() {
1895
1895
  import_types2 = __toESM(require_dist_cjs());
1896
1896
  init_MiddlewareStack();
1897
1897
  init_schemaLogFilter();
1898
+ init_schema();
1899
+ operationEventStreamMarker = /* @__PURE__ */ Symbol.for("@smithy/op-event-stream");
1898
1900
  Command = class {
1899
1901
  middlewareStack = constructStack();
1900
1902
  schema;
@@ -1928,9 +1930,20 @@ var init_command = __esm({
1928
1930
  requestOptions = { ...requestOptions };
1929
1931
  delete requestOptions.metricsRecorder;
1930
1932
  }
1931
- if (smithyContext.eventStream) {
1933
+ let isEventStream;
1934
+ const schema = this.schema;
1935
+ const marker = schema?.[operationEventStreamMarker];
1936
+ if (marker !== void 0) {
1937
+ isEventStream = marker;
1938
+ } else if (schema) {
1939
+ if (Array.isArray(schema) && schema[0] === 9) {
1940
+ const [, , , , input$, output$] = schema;
1941
+ isEventStream = schema[operationEventStreamMarker] = Boolean(NormalizedSchema.of(input$).getEventStreamMember() || NormalizedSchema.of(output$).getEventStreamMember());
1942
+ }
1943
+ }
1944
+ if (isEventStream) {
1932
1945
  requestOptions = {
1933
- isEventStream: true,
1946
+ isEventStream,
1934
1947
  ...requestOptions
1935
1948
  };
1936
1949
  }
@@ -7908,7 +7921,7 @@ var init_Int64 = __esm({
7908
7921
  });
7909
7922
 
7910
7923
  // node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-codec/HeaderMarshaller.js
7911
- var HeaderMarshaller, HEADER_VALUE_TYPE, BOOLEAN_TAG, BYTE_TAG, SHORT_TAG, INT_TAG, LONG_TAG, BINARY_TAG, STRING_TAG, TIMESTAMP_TAG, UUID_TAG, UUID_PATTERN;
7924
+ var HeaderMarshaller, HEADER_VALUE_TYPE, BOOLEAN_TAG, BYTE_TAG, SHORT_TAG, INT_TAG, LONG_TAG, BINARY_TAG, STRING_TAG, TIMESTAMP_TAG, UUID_TAG, UUID_PATTERN, MAX_HEADER_VALUE_BYTES;
7912
7925
  var init_HeaderMarshaller = __esm({
7913
7926
  "node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-codec/HeaderMarshaller.js"() {
7914
7927
  init_transport();
@@ -7927,6 +7940,9 @@ var init_HeaderMarshaller = __esm({
7927
7940
  if (!hasOwn(headers, headerName))
7928
7941
  continue;
7929
7942
  const bytes = this.fromUtf8(headerName);
7943
+ if (bytes.byteLength > 255) {
7944
+ throw new Error(`@smithy/core/event-streams - header name exceeds 255 bytes: ${bytes.byteLength}`);
7945
+ }
7930
7946
  chunks.push(Uint8Array.from([bytes.byteLength]), bytes, this.formatHeaderValue(headers[headerName]));
7931
7947
  }
7932
7948
  const out = new Uint8Array(chunks.reduce((carry, bytes) => carry + bytes.byteLength, 0));
@@ -7959,6 +7975,9 @@ var init_HeaderMarshaller = __esm({
7959
7975
  longBytes.set(header.value.bytes, 1);
7960
7976
  return longBytes;
7961
7977
  case "binary":
7978
+ if (header.value.byteLength > MAX_HEADER_VALUE_BYTES) {
7979
+ throw new Error(`@smithy/core/event-streams - header value (binary) exceeds ${MAX_HEADER_VALUE_BYTES} bytes: ${header.value.byteLength}`);
7980
+ }
7962
7981
  const binView = new DataView(new ArrayBuffer(3 + header.value.byteLength));
7963
7982
  binView.setUint8(0, 6);
7964
7983
  binView.setUint16(1, header.value.byteLength, false);
@@ -7967,6 +7986,9 @@ var init_HeaderMarshaller = __esm({
7967
7986
  return binBytes;
7968
7987
  case "string":
7969
7988
  const utf8Bytes = this.fromUtf8(header.value);
7989
+ if (utf8Bytes.byteLength > MAX_HEADER_VALUE_BYTES) {
7990
+ throw new Error(`@smithy/core/event-streams - header value (string) exceeds ${MAX_HEADER_VALUE_BYTES} bytes: ${utf8Bytes.byteLength}`);
7991
+ }
7970
7992
  const strView = new DataView(new ArrayBuffer(3 + utf8Bytes.byteLength));
7971
7993
  strView.setUint8(0, 7);
7972
7994
  strView.setUint16(1, utf8Bytes.byteLength, false);
@@ -8097,6 +8119,7 @@ var init_HeaderMarshaller = __esm({
8097
8119
  TIMESTAMP_TAG = "timestamp";
8098
8120
  UUID_TAG = "uuid";
8099
8121
  UUID_PATTERN = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/;
8122
+ MAX_HEADER_VALUE_BYTES = 32767;
8100
8123
  }
8101
8124
  });
8102
8125
 
@@ -10811,9 +10834,9 @@ var init_JsonShapeSerializer2 = __esm({
10811
10834
  this.i = i5;
10812
10835
  }
10813
10836
  writeJsonString(s2) {
10814
- this.ensure(s2.length * 3 + 2);
10815
- this.json[this.i++] = QUOTE;
10816
10837
  const z2 = s2.length;
10838
+ this.ensure(z2 * 3 + 2);
10839
+ this.json[this.i++] = QUOTE;
10817
10840
  for (let j5 = 0; j5 < z2; ++j5) {
10818
10841
  const c5 = s2.charCodeAt(j5);
10819
10842
  if (c5 > 34 && c5 < 92) {
@@ -10821,7 +10844,7 @@ var init_JsonShapeSerializer2 = __esm({
10821
10844
  } else if (c5 < 128) {
10822
10845
  const esc2 = ESCAPE_TABLE[c5];
10823
10846
  if (esc2 !== null) {
10824
- this.ensure(esc2.length + 1);
10847
+ this.ensure(esc2.length + 1 + (z2 - j5 - 1) * 3 + 1);
10825
10848
  this.json[this.i++] = BACKSLASH;
10826
10849
  for (let k5 = 0; k5 < esc2.length; k5++) {
10827
10850
  this.json[this.i++] = esc2.charCodeAt(k5);
@@ -10837,11 +10860,11 @@ var init_JsonShapeSerializer2 = __esm({
10837
10860
  this.i += written;
10838
10861
  ++j5;
10839
10862
  } else {
10840
- this.ensure(6);
10863
+ this.ensure(6 + (z2 - j5 - 1) * 3 + 1);
10841
10864
  this.writeUnicodeEscape(c5);
10842
10865
  }
10843
10866
  } else if (c5 >= 56320 && c5 <= 57343) {
10844
- this.ensure(6);
10867
+ this.ensure(6 + (z2 - j5 - 1) * 3 + 1);
10845
10868
  this.writeUnicodeEscape(c5);
10846
10869
  } else {
10847
10870
  let { i: i5, json: json2 } = this;
@@ -17925,7 +17948,7 @@ var init_package = __esm({
17925
17948
  "node_modules/@aws-sdk/nested-clients/package.json"() {
17926
17949
  package_default = {
17927
17950
  name: "@aws-sdk/nested-clients",
17928
- version: "3.997.49",
17951
+ version: "3.997.50",
17929
17952
  description: "Nested clients for AWS SDK packages.",
17930
17953
  homepage: "https://github.com/aws/aws-sdk-js-v3/tree/main/packages/nested-clients",
17931
17954
  license: "Apache-2.0",
@@ -18025,10 +18048,10 @@ var init_package = __esm({
18025
18048
  "test:watch": "yarn g:vitest watch"
18026
18049
  },
18027
18050
  dependencies: {
18028
- "@aws-sdk/core": "^3.978.4",
18029
- "@aws-sdk/signature-v4-multi-region": "^3.996.48",
18030
- "@aws-sdk/types": "^3.974.6",
18031
- "@smithy/core": "^3.36.0",
18051
+ "@aws-sdk/core": "^3.978.5",
18052
+ "@aws-sdk/signature-v4-multi-region": "^3.996.49",
18053
+ "@aws-sdk/types": "^3.975.0",
18054
+ "@smithy/core": "^3.36.1",
18032
18055
  "@smithy/fetch-http-handler": "^5.8.0",
18033
18056
  "@smithy/node-http-handler": "^4.12.1",
18034
18057
  "@smithy/types": "^4.19.0",
@@ -26418,7 +26441,7 @@ var require_dist_cjs16 = __commonJS({
26418
26441
  Region: { type: "builtInParams", name: "region" },
26419
26442
  UseDualStack: { type: "builtInParams", name: "useDualstackEndpoint" }
26420
26443
  };
26421
- var version2 = "3.1153.0";
26444
+ var version2 = "3.1155.0";
26422
26445
  var packageInfo = {
26423
26446
  version: version2
26424
26447
  };
@@ -28209,7 +28232,7 @@ var require_dist_cjs17 = __commonJS({
28209
28232
  Region: { type: "builtInParams", name: "region" },
28210
28233
  UseDualStack: { type: "builtInParams", name: "useDualstackEndpoint" }
28211
28234
  };
28212
- var version2 = "3.1153.0";
28235
+ var version2 = "3.1155.0";
28213
28236
  var packageInfo = {
28214
28237
  version: version2
28215
28238
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@continuous-excellence/ze-great-dashboard-aws",
3
- "version": "0.31.41",
3
+ "version": "0.31.42",
4
4
  "type": "module",
5
5
  "description": "AWS server runtime and CloudFormation deployment tooling for Ze Great Dashboard.",
6
6
  "keywords": [
package/template-ecs.yml CHANGED
@@ -1,4 +1,4 @@
1
- AWSTemplateFormatVersion: '2010-09-09'
1
+ AWSTemplateFormatVersion: "2010-09-09"
2
2
  Description: Ze Great Dashboard ECS/Fargate application (consumer-owned network and ingress)
3
3
 
4
4
  Metadata:
@@ -13,14 +13,14 @@ Parameters:
13
13
  Subnets: { Type: List<AWS::EC2::Subnet::Id> }
14
14
  SecurityGroups: { Type: List<AWS::EC2::SecurityGroup::Id> }
15
15
  DesiredCount: { Type: Number, Default: 1, MinValue: 1 }
16
- Cpu: { Type: String, Default: '256' }
17
- Memory: { Type: String, Default: '512' }
16
+ Cpu: { Type: String, Default: "256" }
17
+ Memory: { Type: String, Default: "512" }
18
18
  ContainerPort: { Type: Number, Default: 3000 }
19
19
  LogRetentionInDays: { Type: Number, Default: 14, MinValue: 1 }
20
- SecretReference: { Type: String, Default: '' }
20
+ SecretReference: { Type: String, Default: "" }
21
21
 
22
22
  Conditions:
23
- HasSecretReference: !Not [!Equals [!Ref SecretReference, '']]
23
+ HasSecretReference: !Not [!Equals [!Ref SecretReference, ""]]
24
24
 
25
25
  Resources:
26
26
  Cluster:
@@ -28,36 +28,68 @@ Resources:
28
28
  Properties: { ClusterName: !Ref Name }
29
29
  LogGroup:
30
30
  Type: AWS::Logs::LogGroup
31
- Properties: { LogGroupName: !Sub '/aws/ecs/${Name}', RetentionInDays: !Ref LogRetentionInDays }
31
+ Properties: { LogGroupName: !Sub "/aws/ecs/${Name}", RetentionInDays: !Ref LogRetentionInDays }
32
32
  ExecutionRole:
33
33
  Type: AWS::IAM::Role
34
34
  Properties:
35
- RoleName: !Sub '${Name}-execution'
36
- AssumeRolePolicyDocument: { Version: '2012-10-17', Statement: [{ Effect: Allow, Principal: { Service: ecs-tasks.amazonaws.com }, Action: sts:AssumeRole }] }
35
+ RoleName: !Sub "${Name}-execution"
36
+ AssumeRolePolicyDocument:
37
+ {
38
+ Version: "2012-10-17",
39
+ Statement:
40
+ [
41
+ {
42
+ Effect: Allow,
43
+ Principal: { Service: ecs-tasks.amazonaws.com },
44
+ Action: sts:AssumeRole,
45
+ },
46
+ ],
47
+ }
37
48
  ManagedPolicyArns: [arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy]
38
49
  TaskRole:
39
50
  Type: AWS::IAM::Role
40
51
  Properties:
41
- RoleName: !Sub '${Name}-task'
42
- AssumeRolePolicyDocument: { Version: '2012-10-17', Statement: [{ Effect: Allow, Principal: { Service: ecs-tasks.amazonaws.com }, Action: sts:AssumeRole }] }
52
+ RoleName: !Sub "${Name}-task"
53
+ AssumeRolePolicyDocument:
54
+ {
55
+ Version: "2012-10-17",
56
+ Statement:
57
+ [
58
+ {
59
+ Effect: Allow,
60
+ Principal: { Service: ecs-tasks.amazonaws.com },
61
+ Action: sts:AssumeRole,
62
+ },
63
+ ],
64
+ }
43
65
  Policies:
44
66
  - PolicyName: read-consumer-credentials
45
67
  PolicyDocument:
46
- Version: '2012-10-17'
68
+ Version: "2012-10-17"
47
69
  Statement:
48
70
  - Effect: Allow
49
71
  Action: [secretsmanager:DescribeSecret, secretsmanager:GetSecretValue]
50
- Resource: !If [HasSecretReference, !Ref SecretReference, !Sub 'arn:${AWS::Partition}:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:ze-great-dashboard-no-secret-configured']
72
+ Resource:
73
+ !If [
74
+ HasSecretReference,
75
+ !Ref SecretReference,
76
+ !Sub "arn:${AWS::Partition}:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:ze-great-dashboard-no-secret-configured",
77
+ ]
51
78
  - Effect: Allow
52
79
  Action: ssm:GetParameter
53
- Resource: !If [HasSecretReference, !Ref SecretReference, !Sub 'arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/ze-great-dashboard-no-credential-configured']
80
+ Resource:
81
+ !If [
82
+ HasSecretReference,
83
+ !Ref SecretReference,
84
+ !Sub "arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/ze-great-dashboard-no-credential-configured",
85
+ ]
54
86
  - Effect: Allow
55
87
  Action: kms:Decrypt
56
- Resource: '*'
88
+ Resource: "*"
57
89
  Condition:
58
90
  StringEquals:
59
- 'kms:ViaService': !Sub 'ssm.${AWS::Region}.amazonaws.com'
60
- 'kms:EncryptionContext:PARAMETER_ARN': !Ref SecretReference
91
+ "kms:ViaService": !Sub "ssm.${AWS::Region}.amazonaws.com"
92
+ "kms:EncryptionContext:PARAMETER_ARN": !Ref SecretReference
61
93
  TaskDefinition:
62
94
  Type: AWS::ECS::TaskDefinition
63
95
  Properties:
@@ -77,10 +109,26 @@ Resources:
77
109
  - { Name: ASSET_PATH, Value: !Ref AssetPath }
78
110
  - { Name: BOARD_CONFIG_URL, Value: !Ref BoardConfigPath }
79
111
  - { Name: HOST, Value: 0.0.0.0 }
80
- - { Name: PORT, Value: '3000' }
81
- - { Name: SECRET_REFERENCE, Value: !If [HasSecretReference, !Ref SecretReference, ''] }
82
- LogConfiguration: { LogDriver: awslogs, Options: { awslogs-group: !Ref LogGroup, awslogs-region: !Ref AWS::Region, awslogs-stream-prefix: dashboard } }
83
- HealthCheck: { Command: [CMD-SHELL, 'node /app/docker-healthcheck.mjs'], Interval: 30, Timeout: 5, Retries: 3, StartPeriod: 20 }
112
+ - { Name: PORT, Value: "3000" }
113
+ - { Name: SECRET_REFERENCE, Value: !If [HasSecretReference, !Ref SecretReference, ""] }
114
+ LogConfiguration:
115
+ {
116
+ LogDriver: awslogs,
117
+ Options:
118
+ {
119
+ awslogs-group: !Ref LogGroup,
120
+ awslogs-region: !Ref AWS::Region,
121
+ awslogs-stream-prefix: dashboard,
122
+ },
123
+ }
124
+ HealthCheck:
125
+ {
126
+ Command: [CMD-SHELL, "node /app/docker-healthcheck.mjs"],
127
+ Interval: 30,
128
+ Timeout: 5,
129
+ Retries: 3,
130
+ StartPeriod: 20,
131
+ }
84
132
  Service:
85
133
  Type: AWS::ECS::Service
86
134
  DependsOn: LogGroup
@@ -90,7 +138,15 @@ Resources:
90
138
  DesiredCount: !Ref DesiredCount
91
139
  LaunchType: FARGATE
92
140
  TaskDefinition: !Ref TaskDefinition
93
- NetworkConfiguration: { AwsvpcConfiguration: { AssignPublicIp: DISABLED, Subnets: !Ref Subnets, SecurityGroups: !Ref SecurityGroups } }
141
+ NetworkConfiguration:
142
+ {
143
+ AwsvpcConfiguration:
144
+ {
145
+ AssignPublicIp: DISABLED,
146
+ Subnets: !Ref Subnets,
147
+ SecurityGroups: !Ref SecurityGroups,
148
+ },
149
+ }
94
150
 
95
151
  Outputs:
96
152
  ComputeMode: { Value: !Ref ComputeMode }