@continuous-excellence/ze-great-dashboard-aws 0.1.13 → 0.1.15
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/LICENSE +21 -0
- package/dist/cli.js +148 -19
- package/dist/index.d.ts +4 -1
- package/dist/index.js +43 -5
- package/package.json +13 -2
- package/template.yml +4 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rob Murdock
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/cli.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// packages/aws/src/cli.ts
|
|
4
|
+
import { readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
|
|
4
5
|
import { join as join3 } from "node:path";
|
|
6
|
+
import { parse as parse2 } from "yaml";
|
|
5
7
|
|
|
6
8
|
// packages/aws/src/index.ts
|
|
7
9
|
import { execFile } from "node:child_process";
|
|
8
|
-
import { cp, mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
|
|
10
|
+
import { cp, mkdir as mkdir2, readFile as readFile2, rm, writeFile as writeFile2 } from "node:fs/promises";
|
|
9
11
|
import { join as join2, resolve as resolve2 } from "node:path";
|
|
10
12
|
import { fileURLToPath } from "node:url";
|
|
11
13
|
import { promisify } from "node:util";
|
|
@@ -116,6 +118,28 @@ function sha256(value) {
|
|
|
116
118
|
|
|
117
119
|
// packages/aws/src/index.ts
|
|
118
120
|
var run = promisify(execFile);
|
|
121
|
+
function deploymentTemplate(template, values) {
|
|
122
|
+
const listed = template.match(/^ {2}PackageManagedParameters: \[([^\]]*)\]\s*$/m)?.[1];
|
|
123
|
+
if (listed === void 0)
|
|
124
|
+
throw new Error("CloudFormation template has no PackageManagedParameters metadata");
|
|
125
|
+
const managed = listed.split(",").map((key) => key.trim()).filter(Boolean);
|
|
126
|
+
const missing = managed.filter((key) => !Object.hasOwn(values, key));
|
|
127
|
+
const unknown = Object.keys(values).filter((key) => !managed.includes(key));
|
|
128
|
+
if (missing.length || unknown.length)
|
|
129
|
+
throw new Error(
|
|
130
|
+
`Package-managed CloudFormation parameters are out of sync (missing: ${missing.join(", ") || "none"}; unknown: ${unknown.join(", ") || "none"})`
|
|
131
|
+
);
|
|
132
|
+
return managed.reduce((rendered, key) => {
|
|
133
|
+
const pattern = new RegExp(`^ ${key}: \\{[^\\n]+\\}\\s*$`, "m");
|
|
134
|
+
const declaration = rendered.match(pattern)?.[0];
|
|
135
|
+
if (!declaration || /\bDefault:/.test(declaration))
|
|
136
|
+
throw new Error(`Unable to set the CloudFormation default for ${key}`);
|
|
137
|
+
return rendered.replace(
|
|
138
|
+
pattern,
|
|
139
|
+
declaration.replace(/\s*}\s*$/, `, Default: ${JSON.stringify(values[key])} }`)
|
|
140
|
+
);
|
|
141
|
+
}, template);
|
|
142
|
+
}
|
|
119
143
|
async function packageLambda(options) {
|
|
120
144
|
const outputDir = resolve2(options.outputDir);
|
|
121
145
|
await mkdir2(outputDir, { recursive: true });
|
|
@@ -137,15 +161,31 @@ async function packageLambda(options) {
|
|
|
137
161
|
"index.mjs": sha256(await readFile2(join2(runtimeDir, "index.mjs")))
|
|
138
162
|
}
|
|
139
163
|
};
|
|
140
|
-
const clientSource = fileURLToPath(new URL("../client", import.meta.url));
|
|
141
|
-
await cp(clientSource, join2(outputDir, "assets"), { recursive: true });
|
|
142
164
|
await writeFile2(join2(runtimeDir, "release.json"), `${JSON.stringify(runtimeMetadata, null, 2)}
|
|
143
165
|
`);
|
|
144
166
|
const sums = Object.entries(runtimeMetadata.artifactChecksums).map(([name, digest]) => `${digest} ${name}`).join("\n");
|
|
145
167
|
await writeFile2(join2(runtimeDir, "SHA256SUMS"), `${sums}
|
|
146
168
|
`);
|
|
147
|
-
|
|
148
|
-
|
|
169
|
+
const lambdaPath = join2(outputDir, "lambda.zip");
|
|
170
|
+
await run("zip", ["-X", "-q", "-r", lambdaPath, "."], { cwd: runtimeDir });
|
|
171
|
+
await rm(runtimeDir, { recursive: true, force: true });
|
|
172
|
+
const lambdaChecksum = sha256(await readFile2(lambdaPath));
|
|
173
|
+
const deploymentChecksum = sha256(JSON.stringify(runtimeMetadata));
|
|
174
|
+
const packagedRelease = {
|
|
175
|
+
...runtimeMetadata,
|
|
176
|
+
artifactChecksums: { ...runtimeMetadata.artifactChecksums, "lambda.zip": lambdaChecksum },
|
|
177
|
+
artifactKey: `lambda/${deploymentChecksum}.zip`
|
|
178
|
+
};
|
|
179
|
+
await writeFile2(join2(outputDir, "release.json"), `${JSON.stringify(packagedRelease, null, 2)}
|
|
180
|
+
`);
|
|
181
|
+
await writeFile2(
|
|
182
|
+
join2(outputDir, "template.yml"),
|
|
183
|
+
deploymentTemplate(await cloudFormationTemplate(), {
|
|
184
|
+
LambdaArtifactKey: packagedRelease.artifactKey,
|
|
185
|
+
DashboardVersion: packagedRelease.dashboardVersion
|
|
186
|
+
})
|
|
187
|
+
);
|
|
188
|
+
return packagedRelease;
|
|
149
189
|
}
|
|
150
190
|
async function deployLambda(options) {
|
|
151
191
|
const artifactDir = resolve2(options.artifactDir);
|
|
@@ -193,6 +233,9 @@ async function deployLambda(options) {
|
|
|
193
233
|
]);
|
|
194
234
|
await run("aws", ["lambda", "wait", "function-updated", "--function-name", options.functionName]);
|
|
195
235
|
}
|
|
236
|
+
async function cloudFormationTemplate() {
|
|
237
|
+
return readFile2(fileURLToPath(new URL("../template.yml", import.meta.url)), "utf8");
|
|
238
|
+
}
|
|
196
239
|
|
|
197
240
|
// packages/aws/src/cli.ts
|
|
198
241
|
var args = process.argv.slice(2);
|
|
@@ -200,30 +243,116 @@ var option = (name, fallback) => {
|
|
|
200
243
|
const i = args.indexOf(name);
|
|
201
244
|
return i >= 0 ? args[i + 1] : fallback;
|
|
202
245
|
};
|
|
246
|
+
async function installedPackageVersion() {
|
|
247
|
+
const packageManifest = JSON.parse(
|
|
248
|
+
await readFile3(new URL("../package.json", import.meta.url), "utf8")
|
|
249
|
+
);
|
|
250
|
+
return typeof packageManifest.version === "string" ? packageManifest.version : "";
|
|
251
|
+
}
|
|
252
|
+
var requiredOption = (name, fallback) => {
|
|
253
|
+
const value = option(name, fallback);
|
|
254
|
+
if (!value) throw new Error(`${name} is required`);
|
|
255
|
+
return value;
|
|
256
|
+
};
|
|
257
|
+
function parameter(key, value) {
|
|
258
|
+
return { ParameterKey: key, ParameterValue: value };
|
|
259
|
+
}
|
|
260
|
+
async function existingParameters(path) {
|
|
261
|
+
try {
|
|
262
|
+
const parsed = JSON.parse(await readFile3(path, "utf8"));
|
|
263
|
+
if (!Array.isArray(parsed)) throw new Error(`${path} must contain a JSON parameter array`);
|
|
264
|
+
const values = parsed.map((value) => {
|
|
265
|
+
if (!value || typeof value !== "object" || typeof value.ParameterKey !== "string" || typeof value.ParameterValue !== "string")
|
|
266
|
+
throw new Error(
|
|
267
|
+
`${path} entries must contain string ParameterKey and ParameterValue fields`
|
|
268
|
+
);
|
|
269
|
+
return value;
|
|
270
|
+
});
|
|
271
|
+
const keys = values.map(({ ParameterKey }) => ParameterKey);
|
|
272
|
+
if (new Set(keys).size !== keys.length) throw new Error(`${path} contains duplicate parameters`);
|
|
273
|
+
return values;
|
|
274
|
+
} catch (error) {
|
|
275
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") return [];
|
|
276
|
+
throw error;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
async function templateParameters() {
|
|
280
|
+
const template = await cloudFormationTemplate();
|
|
281
|
+
const block = template.match(/^Parameters:\n[\s\S]*?(?=^[A-Za-z][A-Za-z0-9]*:\s*$)/m)?.[0];
|
|
282
|
+
if (!block) throw new Error("Unable to read Parameters from the CloudFormation template");
|
|
283
|
+
const parsed = parse2(block);
|
|
284
|
+
if (!parsed.Parameters) throw new Error("CloudFormation template has no Parameters");
|
|
285
|
+
const metadataBlock = template.match(/^Metadata:\n[\s\S]*?(?=^Parameters:\s*$)/m)?.[0];
|
|
286
|
+
const metadata = metadataBlock ? parse2(metadataBlock).Metadata ?? {} : {};
|
|
287
|
+
if (metadata.PackageManagedParameters !== void 0 && (!Array.isArray(metadata.PackageManagedParameters) || !metadata.PackageManagedParameters.every((key) => typeof key === "string")))
|
|
288
|
+
throw new Error("CloudFormation template has invalid PackageManagedParameters metadata");
|
|
289
|
+
const packageManaged = new Set(metadata.PackageManagedParameters ?? []);
|
|
290
|
+
const unknownManaged = [...packageManaged].filter(
|
|
291
|
+
(key) => !Object.hasOwn(parsed.Parameters ?? {}, key)
|
|
292
|
+
);
|
|
293
|
+
if (unknownManaged.length)
|
|
294
|
+
throw new Error(
|
|
295
|
+
`CloudFormation template has unknown package-managed parameters: ${unknownManaged.join(", ")}`
|
|
296
|
+
);
|
|
297
|
+
return { definitions: parsed.Parameters, packageManaged };
|
|
298
|
+
}
|
|
203
299
|
try {
|
|
204
300
|
if (args[0] === "deploy") {
|
|
205
|
-
const
|
|
206
|
-
const value = option(name);
|
|
207
|
-
if (!value) throw new Error(`${name} is required`);
|
|
208
|
-
return value;
|
|
209
|
-
};
|
|
210
|
-
const artifactDir = required("--artifact-dir");
|
|
301
|
+
const artifactDir = requiredOption("--artifact-dir");
|
|
211
302
|
await deployLambda({
|
|
212
303
|
artifactDir,
|
|
213
304
|
assetsDir: option("--assets-dir", join3(artifactDir, "assets")) ?? join3(artifactDir, "assets"),
|
|
214
|
-
assetsBucket:
|
|
215
|
-
assetsBaseUrl:
|
|
216
|
-
functionName:
|
|
217
|
-
version:
|
|
305
|
+
assetsBucket: requiredOption("--assets-bucket"),
|
|
306
|
+
assetsBaseUrl: requiredOption("--assets-base-url"),
|
|
307
|
+
functionName: requiredOption("--function-name"),
|
|
308
|
+
version: requiredOption("--version"),
|
|
218
309
|
dryRun: args.includes("--dry-run")
|
|
219
310
|
});
|
|
220
|
-
console.log(JSON.stringify({ deployed: true, version:
|
|
311
|
+
console.log(JSON.stringify({ deployed: true, version: requiredOption("--version") }));
|
|
312
|
+
} else if (args[0] === "parameters") {
|
|
313
|
+
const output = option("--output", "aws-dashboard-parameters.json") ?? "aws-dashboard-parameters.json";
|
|
314
|
+
const existing = await existingParameters(output);
|
|
315
|
+
const existingValues = Object.fromEntries(
|
|
316
|
+
existing.map(({ ParameterKey, ParameterValue }) => [ParameterKey, ParameterValue])
|
|
317
|
+
);
|
|
318
|
+
const artifactBucket = option("--artifact-bucket", existingValues.LambdaArtifactBucket);
|
|
319
|
+
if (!artifactBucket) throw new Error("--artifact-bucket is required");
|
|
320
|
+
const { definitions, packageManaged } = await templateParameters();
|
|
321
|
+
const templateKeys = Object.keys(definitions);
|
|
322
|
+
const hasDefault = (key) => Object.hasOwn(definitions[key] ?? {}, "Default");
|
|
323
|
+
const hasValue = (key) => key === "LambdaArtifactBucket" || Object.hasOwn(existingValues, key);
|
|
324
|
+
const missingRequired = templateKeys.filter(
|
|
325
|
+
(key) => !hasDefault(key) && !packageManaged.has(key) && !hasValue(key)
|
|
326
|
+
);
|
|
327
|
+
const staleExisting = Object.keys(existingValues).filter(
|
|
328
|
+
(key) => !Object.hasOwn(definitions, key)
|
|
329
|
+
);
|
|
330
|
+
if (missingRequired.length || staleExisting.length) {
|
|
331
|
+
throw new Error(
|
|
332
|
+
`Parameter values are out of sync with the CloudFormation template (missing: ${missingRequired.join(", ") || "none"}; stale: ${staleExisting.join(", ") || "none"})`
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
const includeDefaults = args.includes("--include-defaults");
|
|
336
|
+
const parameters = templateKeys.filter(
|
|
337
|
+
(key) => !packageManaged.has(key) && (includeDefaults || !hasDefault(key) || Object.hasOwn(existingValues, key))
|
|
338
|
+
).map((key) => {
|
|
339
|
+
const definition = definitions[key];
|
|
340
|
+
const value = key === "LambdaArtifactBucket" ? artifactBucket : existingValues[key] ?? definition?.Default;
|
|
341
|
+
if (value === void 0) throw new Error(`No value for CloudFormation parameter ${key}`);
|
|
342
|
+
return parameter(key, String(value));
|
|
343
|
+
});
|
|
344
|
+
await writeFile3(output, `${JSON.stringify(parameters, null, 2)}
|
|
345
|
+
`);
|
|
346
|
+
console.log(JSON.stringify({ output }));
|
|
221
347
|
} else if (args[0] !== "package")
|
|
222
|
-
throw new Error("Usage: ze-great-dashboard-aws package|deploy [options]");
|
|
348
|
+
throw new Error("Usage: ze-great-dashboard-aws package|parameters|deploy [options]");
|
|
223
349
|
else {
|
|
224
350
|
const boardConfig = option("--board-config");
|
|
225
|
-
const
|
|
226
|
-
|
|
351
|
+
const packageVersion = await installedPackageVersion();
|
|
352
|
+
const version = option("--version", process.env.DASHBOARD_VERSION ?? packageVersion);
|
|
353
|
+
if (!boardConfig) throw new Error("--board-config is required");
|
|
354
|
+
if (!version)
|
|
355
|
+
throw new Error("Unable to determine the package version; pass --version explicitly");
|
|
227
356
|
const metadata = await packageLambda({
|
|
228
357
|
boardConfigPath: boardConfig,
|
|
229
358
|
outputDir: option("--output", "aws-release") ?? "aws-release",
|
package/dist/index.d.ts
CHANGED
|
@@ -8,13 +8,16 @@ export type ReleaseMetadata = {
|
|
|
8
8
|
node: string;
|
|
9
9
|
};
|
|
10
10
|
};
|
|
11
|
+
export type PackagedRelease = ReleaseMetadata & {
|
|
12
|
+
artifactKey: string;
|
|
13
|
+
};
|
|
11
14
|
export type LambdaPackageOptions = {
|
|
12
15
|
boardConfigPath: string;
|
|
13
16
|
outputDir: string;
|
|
14
17
|
version: string;
|
|
15
18
|
assetDomain?: string;
|
|
16
19
|
};
|
|
17
|
-
export declare function packageLambda(options: LambdaPackageOptions): Promise<
|
|
20
|
+
export declare function packageLambda(options: LambdaPackageOptions): Promise<PackagedRelease>;
|
|
18
21
|
export type DeployLambdaOptions = {
|
|
19
22
|
artifactDir: string;
|
|
20
23
|
assetsDir: string;
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// packages/aws/src/index.ts
|
|
2
2
|
import { execFile } from "node:child_process";
|
|
3
|
-
import { cp, mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
|
|
3
|
+
import { cp, mkdir as mkdir2, readFile as readFile2, rm, writeFile as writeFile2 } from "node:fs/promises";
|
|
4
4
|
import { join as join2, resolve as resolve2 } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { promisify } from "node:util";
|
|
@@ -111,6 +111,28 @@ function sha256(value) {
|
|
|
111
111
|
|
|
112
112
|
// packages/aws/src/index.ts
|
|
113
113
|
var run = promisify(execFile);
|
|
114
|
+
function deploymentTemplate(template, values) {
|
|
115
|
+
const listed = template.match(/^ {2}PackageManagedParameters: \[([^\]]*)\]\s*$/m)?.[1];
|
|
116
|
+
if (listed === void 0)
|
|
117
|
+
throw new Error("CloudFormation template has no PackageManagedParameters metadata");
|
|
118
|
+
const managed = listed.split(",").map((key) => key.trim()).filter(Boolean);
|
|
119
|
+
const missing = managed.filter((key) => !Object.hasOwn(values, key));
|
|
120
|
+
const unknown = Object.keys(values).filter((key) => !managed.includes(key));
|
|
121
|
+
if (missing.length || unknown.length)
|
|
122
|
+
throw new Error(
|
|
123
|
+
`Package-managed CloudFormation parameters are out of sync (missing: ${missing.join(", ") || "none"}; unknown: ${unknown.join(", ") || "none"})`
|
|
124
|
+
);
|
|
125
|
+
return managed.reduce((rendered, key) => {
|
|
126
|
+
const pattern = new RegExp(`^ ${key}: \\{[^\\n]+\\}\\s*$`, "m");
|
|
127
|
+
const declaration = rendered.match(pattern)?.[0];
|
|
128
|
+
if (!declaration || /\bDefault:/.test(declaration))
|
|
129
|
+
throw new Error(`Unable to set the CloudFormation default for ${key}`);
|
|
130
|
+
return rendered.replace(
|
|
131
|
+
pattern,
|
|
132
|
+
declaration.replace(/\s*}\s*$/, `, Default: ${JSON.stringify(values[key])} }`)
|
|
133
|
+
);
|
|
134
|
+
}, template);
|
|
135
|
+
}
|
|
114
136
|
async function packageLambda(options) {
|
|
115
137
|
const outputDir = resolve2(options.outputDir);
|
|
116
138
|
await mkdir2(outputDir, { recursive: true });
|
|
@@ -132,15 +154,31 @@ async function packageLambda(options) {
|
|
|
132
154
|
"index.mjs": sha256(await readFile2(join2(runtimeDir, "index.mjs")))
|
|
133
155
|
}
|
|
134
156
|
};
|
|
135
|
-
const clientSource = fileURLToPath(new URL("../client", import.meta.url));
|
|
136
|
-
await cp(clientSource, join2(outputDir, "assets"), { recursive: true });
|
|
137
157
|
await writeFile2(join2(runtimeDir, "release.json"), `${JSON.stringify(runtimeMetadata, null, 2)}
|
|
138
158
|
`);
|
|
139
159
|
const sums = Object.entries(runtimeMetadata.artifactChecksums).map(([name, digest]) => `${digest} ${name}`).join("\n");
|
|
140
160
|
await writeFile2(join2(runtimeDir, "SHA256SUMS"), `${sums}
|
|
141
161
|
`);
|
|
142
|
-
|
|
143
|
-
|
|
162
|
+
const lambdaPath = join2(outputDir, "lambda.zip");
|
|
163
|
+
await run("zip", ["-X", "-q", "-r", lambdaPath, "."], { cwd: runtimeDir });
|
|
164
|
+
await rm(runtimeDir, { recursive: true, force: true });
|
|
165
|
+
const lambdaChecksum = sha256(await readFile2(lambdaPath));
|
|
166
|
+
const deploymentChecksum = sha256(JSON.stringify(runtimeMetadata));
|
|
167
|
+
const packagedRelease = {
|
|
168
|
+
...runtimeMetadata,
|
|
169
|
+
artifactChecksums: { ...runtimeMetadata.artifactChecksums, "lambda.zip": lambdaChecksum },
|
|
170
|
+
artifactKey: `lambda/${deploymentChecksum}.zip`
|
|
171
|
+
};
|
|
172
|
+
await writeFile2(join2(outputDir, "release.json"), `${JSON.stringify(packagedRelease, null, 2)}
|
|
173
|
+
`);
|
|
174
|
+
await writeFile2(
|
|
175
|
+
join2(outputDir, "template.yml"),
|
|
176
|
+
deploymentTemplate(await cloudFormationTemplate(), {
|
|
177
|
+
LambdaArtifactKey: packagedRelease.artifactKey,
|
|
178
|
+
DashboardVersion: packagedRelease.dashboardVersion
|
|
179
|
+
})
|
|
180
|
+
);
|
|
181
|
+
return packagedRelease;
|
|
144
182
|
}
|
|
145
183
|
async function deployLambda(options) {
|
|
146
184
|
const artifactDir = resolve2(options.artifactDir);
|
package/package.json
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@continuous-excellence/ze-great-dashboard-aws",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AWS Lambda and CloudFormation adapter for Ze Great Dashboard.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"aws",
|
|
8
|
+
"lambda",
|
|
9
|
+
"cloudformation",
|
|
10
|
+
"dashboard"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=22"
|
|
15
|
+
},
|
|
6
16
|
"repository": {
|
|
7
17
|
"type": "git",
|
|
8
18
|
"url": "git+https://github.com/robertfmurdock/ze-great-dashboard.git"
|
|
@@ -19,7 +29,8 @@
|
|
|
19
29
|
"files": [
|
|
20
30
|
"dist",
|
|
21
31
|
"client",
|
|
22
|
-
"template.yml"
|
|
32
|
+
"template.yml",
|
|
33
|
+
"LICENSE"
|
|
23
34
|
],
|
|
24
35
|
"dependencies": {
|
|
25
36
|
"yaml": "^2.8.1",
|
package/template.yml
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
AWSTemplateFormatVersion: '2010-09-09'
|
|
2
2
|
Description: Provider adapter for a Ze Great Dashboard Lambda deployment
|
|
3
3
|
|
|
4
|
+
Metadata:
|
|
5
|
+
PackageManagedParameters: [LambdaArtifactKey, DashboardVersion]
|
|
6
|
+
|
|
4
7
|
Parameters:
|
|
5
8
|
Name: { Type: String, Default: dashboard }
|
|
6
9
|
LambdaArtifactBucket: { Type: String }
|
|
@@ -36,7 +39,7 @@ Resources:
|
|
|
36
39
|
Resource: !If [HasSecretReference, !Ref SecretReference, !Ref AWS::NoValue]
|
|
37
40
|
ServerLogGroup:
|
|
38
41
|
Type: AWS::Logs::LogGroup
|
|
39
|
-
Properties: { RetentionInDays: !Ref LogRetentionInDays, LogGroupName: !Sub /aws/lambda/${Name} }
|
|
42
|
+
Properties: { RetentionInDays: !Ref LogRetentionInDays, LogGroupName: !Sub '/aws/lambda/${Name}' }
|
|
40
43
|
ServerFunction:
|
|
41
44
|
Type: AWS::Lambda::Function
|
|
42
45
|
DependsOn: ServerLogGroup
|