@basemaps/cli 6.28.1 → 6.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +46 -13
  3. package/build/cli/bin.d.ts +2 -0
  4. package/build/cli/bin.d.ts.map +1 -0
  5. package/build/cli/bin.js +3 -0
  6. package/build/cli/cogify/__tests__/batch.job.test.js +48 -22
  7. package/build/cli/cogify/action.cog.d.ts +2 -1
  8. package/build/cli/cogify/action.cog.d.ts.map +1 -1
  9. package/build/cli/cogify/action.cog.js +49 -42
  10. package/build/cli/cogify/action.job.d.ts +1 -1
  11. package/build/cli/cogify/action.job.d.ts.map +1 -1
  12. package/build/cli/cogify/action.job.js +1 -1
  13. package/build/cli/cogify/batch.job.d.ts +6 -4
  14. package/build/cli/cogify/batch.job.d.ts.map +1 -1
  15. package/build/cli/cogify/batch.job.js +63 -49
  16. package/build/cli/cogify/imagery.config.d.ts.map +1 -1
  17. package/build/cli/cogify/imagery.config.js +0 -2
  18. package/build/cli/config/action.bundle.d.ts +11 -0
  19. package/build/cli/config/action.bundle.d.ts.map +1 -0
  20. package/build/cli/config/action.bundle.js +36 -0
  21. package/build/cli/config/action.import.d.ts +14 -0
  22. package/build/cli/config/action.import.d.ts.map +1 -0
  23. package/build/cli/config/action.import.js +80 -0
  24. package/build/cli/config/config.diff.d.ts +10 -0
  25. package/build/cli/config/config.diff.d.ts.map +1 -0
  26. package/build/cli/config/config.diff.js +47 -0
  27. package/build/cli/config/config.update.d.ts +23 -0
  28. package/build/cli/config/config.update.d.ts.map +1 -0
  29. package/build/cli/config/config.update.js +71 -0
  30. package/build/cli/{cogify/index.d.ts → index.d.ts} +1 -1
  31. package/build/cli/index.d.ts.map +1 -0
  32. package/build/cli/index.js +21 -0
  33. package/build/cli/screenshot/action.screenshot.d.ts +61 -0
  34. package/build/cli/screenshot/action.screenshot.d.ts.map +1 -0
  35. package/build/cli/screenshot/action.screenshot.js +121 -0
  36. package/build/cog/job.factory.d.ts.map +1 -1
  37. package/build/cog/job.factory.js +12 -4
  38. package/package.json +15 -9
  39. package/build/cli/cogify/index.d.ts.map +0 -1
  40. package/build/cli/cogify/index.js +0 -16
  41. package/cogify.js +0 -3
@@ -1 +1 @@
1
- {"version":3,"file":"imagery.config.d.ts","sourceRoot":"","sources":["../../../src/cli/cogify/imagery.config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBzF;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBzF"}
1
+ {"version":3,"file":"imagery.config.d.ts","sourceRoot":"","sources":["../../../src/cli/cogify/imagery.config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAezF;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAezF"}
@@ -10,7 +10,6 @@ export async function insertConfigImagery(job, logger) {
10
10
  const configImagery = {
11
11
  id: imgId,
12
12
  name: job.name,
13
- createdAt: now,
14
13
  updatedAt: now,
15
14
  projection: job.tileMatrix.projection.code,
16
15
  tileMatrix: job.tileMatrix.identifier,
@@ -37,7 +36,6 @@ export async function insertConfigTileSet(job, logger) {
37
36
  name: job.name,
38
37
  layers: [{ [job.tileMatrix.projection.code]: imId, name: job.name, minZoom: 0, maxZoom: 32 }],
39
38
  background: { r: 0, g: 0, b: 0, alpha: 0 },
40
- createdAt: now,
41
39
  updatedAt: now,
42
40
  };
43
41
  if (Config.TileSet.isWriteable())
@@ -0,0 +1,11 @@
1
+ import { CommandLineAction } from '@rushstack/ts-command-line';
2
+ export declare const DefaultConfig = "config/";
3
+ export declare const DefaultOutput = "config/config.json";
4
+ export declare class CommandBundle extends CommandLineAction {
5
+ private config;
6
+ private output;
7
+ constructor();
8
+ protected onDefineParameters(): void;
9
+ onExecute(): Promise<void>;
10
+ }
11
+ //# sourceMappingURL=action.bundle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action.bundle.d.ts","sourceRoot":"","sources":["../../../src/cli/config/action.bundle.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAA8B,MAAM,4BAA4B,CAAC;AAE3F,eAAO,MAAM,aAAa,YAAY,CAAC;AACvC,eAAO,MAAM,aAAa,uBAAuB,CAAC;AAElD,qBAAa,aAAc,SAAQ,iBAAiB;IAClD,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,MAAM,CAA6B;;IAU3C,SAAS,CAAC,kBAAkB,IAAI,IAAI;IAa9B,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CASjC"}
@@ -0,0 +1,36 @@
1
+ import { fsa, LogConfig } from '@basemaps/shared';
2
+ import { ConfigJson } from '@basemaps/config';
3
+ import { CommandLineAction } from '@rushstack/ts-command-line';
4
+ export const DefaultConfig = 'config/';
5
+ export const DefaultOutput = 'config/config.json';
6
+ export class CommandBundle extends CommandLineAction {
7
+ constructor() {
8
+ super({
9
+ actionName: 'bundle',
10
+ summary: 'bundle a config json from config files',
11
+ documentation: 'Given a path of config files and bundle them into one config json',
12
+ });
13
+ }
14
+ onDefineParameters() {
15
+ this.config = this.defineStringParameter({
16
+ argumentName: 'CONFIG',
17
+ parameterLongName: '--config',
18
+ description: 'Path of config files',
19
+ });
20
+ this.output = this.defineStringParameter({
21
+ argumentName: 'OUTPUT',
22
+ parameterLongName: '--output',
23
+ description: 'Output of the bundle file',
24
+ });
25
+ }
26
+ async onExecute() {
27
+ var _a, _b;
28
+ const logger = LogConfig.get();
29
+ const config = (_a = this.config.value) !== null && _a !== void 0 ? _a : DefaultConfig;
30
+ const bundle = (_b = this.output.value) !== null && _b !== void 0 ? _b : DefaultOutput;
31
+ const mem = await ConfigJson.fromPath(config, logger);
32
+ await fsa.writeJson(bundle, mem.toJson());
33
+ logger.info({ path: bundle }, 'ConfigBundled');
34
+ return;
35
+ }
36
+ }
@@ -0,0 +1,14 @@
1
+ import { BaseConfig } from '@basemaps/config';
2
+ import { CommandLineAction } from '@rushstack/ts-command-line';
3
+ export declare class CommandImport extends CommandLineAction {
4
+ private config;
5
+ private commit;
6
+ promises: Promise<boolean>[];
7
+ /** List of paths to invalidate at the end of the request */
8
+ invalidations: string[];
9
+ constructor();
10
+ protected onDefineParameters(): void;
11
+ onExecute(): Promise<void>;
12
+ update(config: BaseConfig, commit: boolean): void;
13
+ }
14
+ //# sourceMappingURL=action.import.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action.import.d.ts","sourceRoot":"","sources":["../../../src/cli/config/action.import.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAuC,MAAM,kBAAkB,CAAC;AACnF,OAAO,EAAE,iBAAiB,EAAwD,MAAM,4BAA4B,CAAC;AAIrH,qBAAa,aAAc,SAAQ,iBAAiB;IAClD,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,MAAM,CAA2B;IAEzC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,CAAM;IAClC,4DAA4D;IAC5D,aAAa,EAAE,MAAM,EAAE,CAAM;;IAU7B,SAAS,CAAC,kBAAkB,IAAI,IAAI;IAc9B,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IA0ChC,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI;CASlD"}
@@ -0,0 +1,80 @@
1
+ import { Env, fsa, LogConfig } from '@basemaps/shared';
2
+ import { ConfigProviderMemory } from '@basemaps/config';
3
+ import { CommandLineAction } from '@rushstack/ts-command-line';
4
+ import { Q, Updater } from './config.update.js';
5
+ import { invalidateCache } from '../util.js';
6
+ export class CommandImport extends CommandLineAction {
7
+ constructor() {
8
+ super({
9
+ actionName: 'import',
10
+ summary: 'import a config json into dynamodb',
11
+ documentation: 'Given a valid bundle config json and import them into dynamodb',
12
+ });
13
+ this.promises = [];
14
+ /** List of paths to invalidate at the end of the request */
15
+ this.invalidations = [];
16
+ }
17
+ onDefineParameters() {
18
+ this.config = this.defineStringParameter({
19
+ argumentName: 'CONFIG',
20
+ parameterLongName: '--config',
21
+ description: 'Path of config json',
22
+ required: true,
23
+ });
24
+ this.commit = this.defineFlagParameter({
25
+ parameterLongName: '--commit',
26
+ description: 'Actually start the import',
27
+ required: false,
28
+ });
29
+ }
30
+ async onExecute() {
31
+ var _a;
32
+ const logger = LogConfig.get();
33
+ logger.level = 'trace';
34
+ const commit = (_a = this.commit.value) !== null && _a !== void 0 ? _a : false;
35
+ const config = this.config.value;
36
+ if (config == null)
37
+ throw new Error('Please provide a config json');
38
+ const HostPrefix = Env.isProduction() ? '' : 'dev.';
39
+ const healthEndpoint = `https://${HostPrefix}basemaps.linz.govt.nz/v1/health`;
40
+ logger.info({ url: healthEndpoint }, 'Import:ValidateHealth');
41
+ if (commit) {
42
+ const res = await fetch(healthEndpoint);
43
+ if (!res.ok)
44
+ throw new Error('Cannot update basemaps is unhealthy');
45
+ }
46
+ logger.info({ config }, 'Import:Load');
47
+ const configJson = await fsa.readJson(config);
48
+ const mem = ConfigProviderMemory.fromJson(configJson);
49
+ mem.createVirtualTileSets();
50
+ logger.info({ config }, 'Import:Start');
51
+ for (const config of mem.objects.values())
52
+ this.update(config, commit);
53
+ await Promise.all(this.promises);
54
+ if (commit && this.invalidations.length > 0) {
55
+ // Lots of invalidations just invalidate everything
56
+ if (this.invalidations.length > 10) {
57
+ await invalidateCache('/*', commit);
58
+ }
59
+ else {
60
+ await invalidateCache(this.invalidations, commit);
61
+ }
62
+ await new Promise((resolve) => setTimeout(resolve, 1000));
63
+ const res = await fetch(healthEndpoint);
64
+ if (!res.ok)
65
+ throw new Error('Basemaps is unhealthy');
66
+ }
67
+ if (commit !== true)
68
+ logger.info('DryRun:Done');
69
+ }
70
+ update(config, commit) {
71
+ const promise = Q(async () => {
72
+ const updater = new Updater(config, commit);
73
+ const hasChanges = await updater.reconcile();
74
+ if (hasChanges)
75
+ this.invalidations.push(updater.invalidatePath());
76
+ return true;
77
+ });
78
+ this.promises.push(promise);
79
+ }
80
+ }
@@ -0,0 +1,10 @@
1
+ import { LogType } from '@basemaps/shared';
2
+ import diff from 'deep-diff';
3
+ export declare const IgnoredProperties: string[];
4
+ export declare class ConfigDiff {
5
+ static printDiff<T>(changes: diff.Diff<T, T>[]): string;
6
+ static showDiff<T extends {
7
+ id: string;
8
+ }>(type: string, oldData: T, newData: T, logger: LogType): boolean;
9
+ }
10
+ //# sourceMappingURL=config.diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.diff.d.ts","sourceRoot":"","sources":["../../../src/cli/config/config.diff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE3C,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,eAAO,MAAM,iBAAiB,UAAyD,CAAC;AAExF,qBAAa,UAAU;IACrB,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,MAAM;IA0BvD,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO;CAS1G"}
@@ -0,0 +1,47 @@
1
+ import c from 'ansi-colors';
2
+ import diff from 'deep-diff';
3
+ export const IgnoredProperties = ['id', 'createdAt', 'updatedAt', 'year', 'resolution'];
4
+ export class ConfigDiff {
5
+ static printDiff(changes) {
6
+ let output = '';
7
+ let isArray = false;
8
+ for (const change of changes) {
9
+ if (change.kind === 'A') {
10
+ if (change.path)
11
+ output += change.path.join();
12
+ output += this.printDiff([change.item]);
13
+ isArray = true; // Stop displaying the array changes for each line.
14
+ }
15
+ else {
16
+ if (isArray)
17
+ continue;
18
+ if (change.kind === 'E') {
19
+ if (change.path)
20
+ output += change.path.join();
21
+ output += c.green('\t+' + JSON.stringify(change.rhs));
22
+ output += c.red('\t-' + JSON.stringify(change.lhs)) + '\n';
23
+ }
24
+ else if (change.kind === 'N') {
25
+ if (change.path)
26
+ output += change.path.join();
27
+ output += c.green('\t+' + JSON.stringify(change.rhs)) + '\n';
28
+ }
29
+ else if (change.kind === 'D') {
30
+ if (change.path)
31
+ output += change.path.join();
32
+ output += c.red('\t-' + JSON.stringify(change.lhs)) + '\n';
33
+ }
34
+ }
35
+ }
36
+ return output;
37
+ }
38
+ static showDiff(type, oldData, newData, logger) {
39
+ const changes = diff.diff(oldData, newData, (_path, key) => IgnoredProperties.indexOf(key) >= 0);
40
+ if (changes) {
41
+ logger.info({ type, record: newData.id }, 'Changes');
42
+ ConfigDiff.printDiff(changes);
43
+ return true;
44
+ }
45
+ return false;
46
+ }
47
+ }
@@ -0,0 +1,23 @@
1
+ import { BaseConfig, ConfigTileSet, ConfigImagery, ConfigProvider, ConfigVectorStyle } from '@basemaps/config';
2
+ import { BasemapsConfigObject } from '@basemaps/config/build/base.config.js';
3
+ import { LogType } from '@basemaps/shared';
4
+ export declare const Q: import("p-limit").LimitFunction;
5
+ export declare class Updater<S extends BaseConfig = BaseConfig> {
6
+ config: S;
7
+ prefix: string;
8
+ isCommit: boolean;
9
+ logger: LogType;
10
+ /**
11
+ * Class to apply an TileSetConfig source to the tile metadata db
12
+ * @param config a string or TileSetConfig to use
13
+ */
14
+ constructor(config: S, isCommit: boolean);
15
+ getDB(): BasemapsConfigObject<ConfigTileSet | ConfigImagery | ConfigProvider | ConfigVectorStyle>;
16
+ getConfig(): ConfigTileSet | ConfigImagery | ConfigProvider | ConfigVectorStyle;
17
+ invalidatePath(): string;
18
+ /**
19
+ * Reconcile the differences between the config and the tile metadata DB and update if changed.
20
+ */
21
+ reconcile(): Promise<boolean>;
22
+ }
23
+ //# sourceMappingURL=config.update.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.update.d.ts","sourceRoot":"","sources":["../../../src/cli/config/config.update.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EAGV,aAAa,EACb,aAAa,EACb,cAAc,EACd,iBAAiB,EAElB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,EAAa,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAItD,eAAO,MAAM,CAAC,iCAAa,CAAC;AAE5B,qBAAa,OAAO,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU;IACpD,MAAM,EAAE,CAAC,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAEhB;;;OAGG;gBACS,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,OAAO;IASxC,KAAK,IAAI,oBAAoB,CAAC,aAAa,GAAG,aAAa,GAAG,cAAc,GAAG,iBAAiB,CAAC;IAQjG,SAAS,IAAI,aAAa,GAAG,aAAa,GAAG,cAAc,GAAG,iBAAiB;IAQ/E,cAAc,IAAI,MAAM;IAMxB;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;CAkBpC"}
@@ -0,0 +1,71 @@
1
+ import { ConfigDynamoBase, Config, ConfigPrefix, } from '@basemaps/config';
2
+ import { LogConfig } from '@basemaps/shared';
3
+ import { ConfigDiff } from './config.diff.js';
4
+ import PLimit from 'p-limit';
5
+ export const Q = PLimit(10);
6
+ export class Updater {
7
+ /**
8
+ * Class to apply an TileSetConfig source to the tile metadata db
9
+ * @param config a string or TileSetConfig to use
10
+ */
11
+ constructor(config, isCommit) {
12
+ this.config = config;
13
+ const prefix = Config.getPrefix(config.id);
14
+ if (prefix == null)
15
+ throw new Error(`Incorrect Config Id ${config.id}`);
16
+ this.prefix = prefix;
17
+ this.isCommit = isCommit ? isCommit : false;
18
+ this.logger = LogConfig.get();
19
+ }
20
+ getDB() {
21
+ if (this.prefix === ConfigPrefix.Imagery)
22
+ return Config.Imagery;
23
+ if (this.prefix === ConfigPrefix.TileSet)
24
+ return Config.TileSet;
25
+ if (this.prefix === ConfigPrefix.Provider)
26
+ return Config.Provider;
27
+ if (this.prefix === ConfigPrefix.Style)
28
+ return Config.Style;
29
+ throw Error(`Unable to find the database table for prefix ${this.prefix}`);
30
+ }
31
+ getConfig() {
32
+ if (this.prefix === ConfigPrefix.Imagery)
33
+ return this.config;
34
+ if (this.prefix === ConfigPrefix.TileSet)
35
+ return this.config;
36
+ if (this.prefix === ConfigPrefix.Provider)
37
+ return this.config;
38
+ if (this.prefix === ConfigPrefix.Style)
39
+ return this.config;
40
+ throw Error(`Failed to cast the config ${this.config}`);
41
+ }
42
+ invalidatePath() {
43
+ if (this.prefix === ConfigPrefix.Provider)
44
+ return '/v1/*/WMTSCapabilities.xml';
45
+ else if (this.prefix === ConfigPrefix.Style)
46
+ return `/v1/tiles/togographic/style/${this.config.id.slice(3)}.json`;
47
+ else
48
+ return `/v1/tiles/${this.config.id.slice(3)}/*`;
49
+ }
50
+ /**
51
+ * Reconcile the differences between the config and the tile metadata DB and update if changed.
52
+ */
53
+ async reconcile() {
54
+ const db = this.getDB();
55
+ const oldData = await db.get(this.config.id);
56
+ const newData = this.getConfig();
57
+ if (oldData == null || ConfigDiff.showDiff(db.prefix, oldData, newData, this.logger)) {
58
+ const operation = oldData == null ? 'Insert' : 'Update';
59
+ this.logger.info({ type: db.prefix, record: newData.id, commit: this.isCommit }, `Change:${operation}`);
60
+ if (this.isCommit) {
61
+ if (db instanceof ConfigDynamoBase)
62
+ await db.put(newData);
63
+ else
64
+ throw new Error('Unable to commit changes to: ' + db.prefix);
65
+ }
66
+ return true;
67
+ }
68
+ this.logger.trace({ type: db.prefix, record: newData.id }, 'NoChanges');
69
+ return false;
70
+ }
71
+ }
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { BaseCommandLine } from '@basemaps/shared/build/cli/base.js';
3
3
  import 'source-map-support/register.js';
4
- export declare class CogifyCommandLine extends BaseCommandLine {
4
+ export declare class BasemapsConfigCommandLine extends BaseCommandLine {
5
5
  constructor();
6
6
  }
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,gCAAgC,CAAC;AAOxC,qBAAa,yBAA0B,SAAQ,eAAe;;CAe7D"}
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ import { BaseCommandLine } from '@basemaps/shared/build/cli/base.js';
3
+ import 'source-map-support/register.js';
4
+ import { CommandCogCreate } from './cogify/action.cog.js';
5
+ import { CommandJobCreate } from './cogify/action.job.js';
6
+ import { CommandBundle } from './config/action.bundle.js';
7
+ import { CommandImport } from './config/action.import.js';
8
+ import { CommandScreenShot } from './screenshot/action.screenshot.js';
9
+ export class BasemapsConfigCommandLine extends BaseCommandLine {
10
+ constructor() {
11
+ super({
12
+ toolFilename: 'bmc',
13
+ toolDescription: 'Basemaps config command tools',
14
+ });
15
+ this.addAction(new CommandCogCreate());
16
+ this.addAction(new CommandJobCreate());
17
+ this.addAction(new CommandBundle());
18
+ this.addAction(new CommandImport());
19
+ this.addAction(new CommandScreenShot());
20
+ }
21
+ }
@@ -0,0 +1,61 @@
1
+ import { LogType } from '@basemaps/shared';
2
+ import { Browser } from 'playwright';
3
+ import { CommandLineAction } from '@rushstack/ts-command-line';
4
+ import { z } from 'zod';
5
+ export declare const DefaultTestTiles = "./test-tiles/default.test.tiles.json";
6
+ export declare const DefaultHost = "basemaps.linz.govt.nz";
7
+ declare enum TileMatrixIdentifier {
8
+ Nztm2000Quad = "NZTM2000Quad",
9
+ Google = "WebMercatorQuad"
10
+ }
11
+ declare const zTileTest: z.ZodObject<{
12
+ name: z.ZodString;
13
+ tileMatrix: z.ZodNativeEnum<typeof TileMatrixIdentifier>;
14
+ location: z.ZodObject<{
15
+ lat: z.ZodNumber;
16
+ lng: z.ZodNumber;
17
+ z: z.ZodNumber;
18
+ }, "strip", z.ZodTypeAny, {
19
+ z: number;
20
+ lat: number;
21
+ lng: number;
22
+ }, {
23
+ z: number;
24
+ lat: number;
25
+ lng: number;
26
+ }>;
27
+ tileSet: z.ZodString;
28
+ style: z.ZodOptional<z.ZodString>;
29
+ }, "strip", z.ZodTypeAny, {
30
+ style?: string | undefined;
31
+ name: string;
32
+ location: {
33
+ z: number;
34
+ lat: number;
35
+ lng: number;
36
+ };
37
+ tileMatrix: TileMatrixIdentifier;
38
+ tileSet: string;
39
+ }, {
40
+ style?: string | undefined;
41
+ name: string;
42
+ location: {
43
+ z: number;
44
+ lat: number;
45
+ lng: number;
46
+ };
47
+ tileMatrix: TileMatrixIdentifier;
48
+ tileSet: string;
49
+ }>;
50
+ export declare type TileTestSchema = z.infer<typeof zTileTest>;
51
+ export declare class CommandScreenShot extends CommandLineAction {
52
+ private config;
53
+ private host;
54
+ private tiles;
55
+ constructor();
56
+ protected onDefineParameters(): void;
57
+ onExecute(): Promise<void>;
58
+ }
59
+ export declare function takeScreenshots(host: string, tiles: string, chrome: Browser, logger: LogType): Promise<void>;
60
+ export {};
61
+ //# sourceMappingURL=action.screenshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action.screenshot.d.ts","sourceRoot":"","sources":["../../../src/cli/screenshot/action.screenshot.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAExE,OAAO,EAAE,OAAO,EAAY,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAA8B,MAAM,4BAA4B,CAAC;AAC3F,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,eAAO,MAAM,gBAAgB,yCAAyC,CAAC;AACvE,eAAO,MAAM,WAAW,0BAA0B,CAAC;AAEnD,aAAK,oBAAoB;IACvB,YAAY,iBAAiB;IAC7B,MAAM,oBAAoB;CAC3B;AAQD,QAAA,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAMb,CAAC;AAEH,oBAAY,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAC;AAEvD,qBAAa,iBAAkB,SAAQ,iBAAiB;IACtD,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,IAAI,CAA6B;IACzC,OAAO,CAAC,KAAK,CAA6B;;IAU1C,SAAS,CAAC,kBAAkB,IAAI,IAAI;IAsB9B,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CAyBjC;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAkClH"}
@@ -0,0 +1,121 @@
1
+ import { Config, Env, fsa, LogConfig } from '@basemaps/shared';
2
+ import { mkdir } from 'fs/promises';
3
+ import { chromium } from 'playwright';
4
+ import { CommandLineAction } from '@rushstack/ts-command-line';
5
+ import { z } from 'zod';
6
+ import getPort from 'get-port';
7
+ import { createServer } from '@basemaps/server';
8
+ import { ConfigProviderMemory } from '@basemaps/config';
9
+ export const DefaultTestTiles = './test-tiles/default.test.tiles.json';
10
+ export const DefaultHost = 'basemaps.linz.govt.nz';
11
+ var TileMatrixIdentifier;
12
+ (function (TileMatrixIdentifier) {
13
+ TileMatrixIdentifier["Nztm2000Quad"] = "NZTM2000Quad";
14
+ TileMatrixIdentifier["Google"] = "WebMercatorQuad";
15
+ })(TileMatrixIdentifier || (TileMatrixIdentifier = {}));
16
+ const zLocation = z.object({
17
+ lat: z.number().gte(-90).lte(90),
18
+ lng: z.number().gte(-180).lte(180),
19
+ z: z.number().gte(0).lte(32),
20
+ });
21
+ const zTileTest = z.object({
22
+ name: z.string(),
23
+ tileMatrix: z.nativeEnum(TileMatrixIdentifier),
24
+ location: zLocation,
25
+ tileSet: z.string(),
26
+ style: z.string().optional(),
27
+ });
28
+ export class CommandScreenShot extends CommandLineAction {
29
+ constructor() {
30
+ super({
31
+ actionName: 'screenshot',
32
+ summary: 'dump screenshots of from LINZ Basemaps',
33
+ documentation: 'Dump screenshots with selected tile sets',
34
+ });
35
+ }
36
+ onDefineParameters() {
37
+ this.config = this.defineStringParameter({
38
+ argumentName: 'CONFIG',
39
+ parameterLongName: '--config',
40
+ description: 'Path of config bundle file, could be both local file or s3.',
41
+ });
42
+ this.host = this.defineStringParameter({
43
+ argumentName: 'HOST',
44
+ parameterLongName: '--host',
45
+ description: 'Host to use',
46
+ defaultValue: DefaultHost,
47
+ });
48
+ this.tiles = this.defineStringParameter({
49
+ argumentName: 'TILES',
50
+ parameterLongName: '--tiles',
51
+ description: 'JSON file path for the test tiles',
52
+ defaultValue: DefaultTestTiles,
53
+ });
54
+ }
55
+ async onExecute() {
56
+ var _a, _b, _c;
57
+ const logger = LogConfig.get();
58
+ const config = this.config.value;
59
+ let host = (_a = this.host.value) !== null && _a !== void 0 ? _a : DefaultHost;
60
+ const tiles = (_b = this.tiles.value) !== null && _b !== void 0 ? _b : DefaultTestTiles;
61
+ let BasemapsServer = undefined;
62
+ if (config != null) {
63
+ const port = await getPort();
64
+ host = (_c = Env.get(Env.PublicUrlBase)) !== null && _c !== void 0 ? _c : `http://localhost:${port}`;
65
+ // Force a default url base so WMTS requests know their relative url
66
+ process.env[Env.PublicUrlBase] = host;
67
+ BasemapsServer = await startServer(port, config, logger);
68
+ logger.info({ url: host }, 'Server:Started');
69
+ }
70
+ logger.info('Page:Launch');
71
+ const chrome = await chromium.launch();
72
+ try {
73
+ await takeScreenshots(host, tiles, chrome, logger);
74
+ }
75
+ finally {
76
+ await chrome.close();
77
+ if (BasemapsServer != null)
78
+ await BasemapsServer.close();
79
+ }
80
+ }
81
+ }
82
+ export async function takeScreenshots(host, tiles, chrome, logger) {
83
+ const TestTiles = await fsa.readJson(tiles);
84
+ for (const test of TestTiles) {
85
+ const page = await chrome.newPage();
86
+ const searchParam = new URLSearchParams();
87
+ searchParam.set('p', test.tileMatrix);
88
+ searchParam.set('i', test.tileSet);
89
+ if (test.style)
90
+ searchParam.set('s', test.style);
91
+ const loc = `@${test.location.lat},${test.location.lng},z${test.location.z}`;
92
+ const fileName = '.artifacts/visual-snapshots/' + test.name + '.png';
93
+ await mkdir(`.artifacts/visual-snapshots/`, { recursive: true });
94
+ let url = `${host}/?${searchParam.toString()}&debug=true&debug.screenshot=true#${loc}`;
95
+ if (!url.startsWith('http'))
96
+ url = `https://${url}`;
97
+ logger.info({ url, expected: fileName }, 'Page:Load');
98
+ await page.goto(url);
99
+ try {
100
+ await page.waitForSelector('div#map-loaded', { state: 'attached' });
101
+ await page.waitForTimeout(1000);
102
+ await page.waitForLoadState('networkidle');
103
+ await page.screenshot({ path: fileName });
104
+ }
105
+ catch (e) {
106
+ await page.screenshot({ path: fileName });
107
+ throw e;
108
+ }
109
+ logger.info({ url, expected: fileName }, 'Page:Load:Done');
110
+ await page.close();
111
+ }
112
+ }
113
+ async function startServer(port, config, logger) {
114
+ // Bundle Config
115
+ const configJson = await fsa.readJson(config);
116
+ const mem = ConfigProviderMemory.fromJson(configJson);
117
+ Config.setConfigProvider(mem);
118
+ // Start server
119
+ const server = createServer(logger);
120
+ return await new Promise((resolve) => server.listen(port, '0.0.0.0', () => resolve(server)));
121
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"job.factory.d.ts","sourceRoot":"","sources":["../../src/cog/job.factory.ts"],"names":[],"mappings":"AAKA,OAAO,EAAc,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEnE,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAGpC,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAOxC,eAAO,MAAM,aAAa;IACxB;;OAEG;gBACe,kBAAkB,GAAG,QAAQ,MAAM,CAAC;CA4FvD,CAAC"}
1
+ {"version":3,"file":"job.factory.d.ts","sourceRoot":"","sources":["../../src/cog/job.factory.ts"],"names":[],"mappings":"AAKA,OAAO,EAAc,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEnE,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAGpC,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAiBxC,eAAO,MAAM,aAAa;IACxB;;OAEG;gBACe,kBAAkB,GAAG,QAAQ,MAAM,CAAC;CA0FvD,CAAC"}
@@ -11,6 +11,16 @@ function filterTiff(a) {
11
11
  const lowerA = a.toLowerCase();
12
12
  return lowerA.endsWith('.tiff') || lowerA.endsWith('.tif');
13
13
  }
14
+ /** Group a file list by its zoom */
15
+ function groupFiles(files) {
16
+ var _a;
17
+ const fileCounts = {};
18
+ for (const f of files) {
19
+ const zoom = f.name.split('-')[0];
20
+ fileCounts[zoom] = ((_a = fileCounts[zoom]) !== null && _a !== void 0 ? _a : 0) + 1;
21
+ }
22
+ return fileCounts;
23
+ }
14
24
  export const CogJobFactory = {
15
25
  /**
16
26
  * Create a COG Job and potentially submit it to AWS Batch for processing
@@ -55,11 +65,9 @@ export const CogJobFactory = {
55
65
  ...metadata,
56
66
  tileMatrix: ctx.tileMatrix.identifier,
57
67
  bounds: undefined,
68
+ files: undefined,
58
69
  fileCount: files.length,
59
- files: metadata.files
60
- .map((r) => r.name)
61
- .sort()
62
- .join(' '),
70
+ fileGroups: groupFiles(metadata.files),
63
71
  }, 'CoveringGenerated');
64
72
  let addAlpha = true;
65
73
  // -addalpha to vrt adds extra alpha layers even if one already exist