@cogeotiff/cli 9.0.7 → 9.1.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.
package/CHANGELOG.md CHANGED
@@ -24,6 +24,20 @@
24
24
  * dependencies
25
25
  * @cogeotiff/core bumped from ^9.1.1 to ^9.1.2
26
26
 
27
+ ## [9.1.0](https://github.com/blacha/cogeotiff/compare/cli-v9.0.7...cli-v9.1.0) (2026-02-20)
28
+
29
+
30
+ ### Features
31
+
32
+ * **cli:** trace how a tiff is loaded with fetch-tile ([#1414](https://github.com/blacha/cogeotiff/issues/1414)) ([8a69302](https://github.com/blacha/cogeotiff/commit/8a693021e2c07fd08c6e2470d00106126e5b9f70))
33
+
34
+
35
+ ### Dependencies
36
+
37
+ * The following workspace dependencies were updated
38
+ * dependencies
39
+ * @cogeotiff/core bumped from ^9.2.0 to ^9.3.0
40
+
27
41
  ## [9.0.7](https://github.com/blacha/cogeotiff/compare/cli-v9.0.6...cli-v9.0.7) (2026-02-18)
28
42
 
29
43
 
@@ -0,0 +1,20 @@
1
+ export declare const commandFetchTile: Partial<import("cmd-ts/dist/cjs/argparser.js").Register> & {
2
+ parse(context: import("cmd-ts/dist/cjs/argparser.js").ParseContext): Promise<import("cmd-ts/dist/cjs/argparser.js").ParsingResult<{
3
+ tile: string;
4
+ output: URL | undefined;
5
+ readSize: number;
6
+ path: URL;
7
+ verbose: boolean;
8
+ extraVerbose: boolean;
9
+ }>>;
10
+ } & import("cmd-ts/dist/cjs/helpdoc.js").PrintHelp & import("cmd-ts/dist/cjs/helpdoc.js").ProvidesHelp & import("cmd-ts/dist/cjs/helpdoc.js").Named & Partial<import("cmd-ts/dist/cjs/helpdoc.js").Versioned> & import("cmd-ts/dist/cjs/argparser.js").Register & import("cmd-ts/dist/cjs/runner.js").Handling<{
11
+ tile: string;
12
+ output: URL | undefined;
13
+ readSize: number;
14
+ path: URL;
15
+ verbose: boolean;
16
+ extraVerbose: boolean;
17
+ }, Promise<void>> & {
18
+ run(context: import("cmd-ts/dist/cjs/argparser.js").ParseContext): Promise<import("cmd-ts/dist/cjs/argparser.js").ParsingResult<Promise<void>>>;
19
+ } & Partial<import("cmd-ts/dist/cjs/helpdoc.js").Versioned & import("cmd-ts/dist/cjs/helpdoc.js").Descriptive & import("cmd-ts/dist/cjs/helpdoc.js").Aliased>;
20
+ //# sourceMappingURL=fetch-tile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-tile.d.ts","sourceRoot":"","sources":["../../src/commands/fetch-tile.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;6JAsF3B,CAAC"}
@@ -0,0 +1,85 @@
1
+ import { fsa } from '@chunkd/fs';
2
+ import { Tiff, TiffTag } from '@cogeotiff/core';
3
+ import { command, number, option, optional, positional, string } from 'cmd-ts';
4
+ import { DefaultArgs, Url } from '../common.js';
5
+ import { FetchLog } from '../fs.js';
6
+ import { setupLogger } from '../log.js';
7
+ export const commandFetchTile = command({
8
+ name: 'fetch-tile',
9
+ args: {
10
+ ...DefaultArgs,
11
+ tile: option({
12
+ short: 't',
13
+ long: 'tile',
14
+ description: 'tile to process "z-x-y" multiple tiles can be fetched by comma separating them "z-x-y,z-x-y"',
15
+ type: string,
16
+ defaultValue: () => '0-0-0',
17
+ }),
18
+ output: option({ short: 'o', long: 'output', type: optional(Url) }),
19
+ readSize: option({
20
+ long: 'read-size',
21
+ description: 'Size of bytes to read for the tile, default is to read the whole tile in KB',
22
+ type: number,
23
+ defaultValue: () => 16,
24
+ }),
25
+ path: positional({ type: Url, description: 'File to process' }),
26
+ },
27
+ async handler(args) {
28
+ const logger = setupLogger(args);
29
+ if (logger.level === 'warn')
30
+ logger.level = 'info';
31
+ fsa.middleware = [FetchLog]; // reset middleware so we don't cache or chunk requests
32
+ const tiles = args.tile.split(',').map((t) => t.split('-').map((s) => parseInt(s, 10)));
33
+ for (const t of tiles) {
34
+ if (isNaN(t[0]) || isNaN(t[1]) || isNaN(t[2])) {
35
+ logger.error('Invalid tile format, expected {z-x-y}', { tile: args.tile });
36
+ return;
37
+ }
38
+ }
39
+ const tiff = new Tiff(fsa.source(args.path));
40
+ tiff.defaultReadSize = args.readSize * 1024;
41
+ logger.debug('Tiff:load', { path: args.path.href });
42
+ const loadStart = performance.now();
43
+ await tiff.init();
44
+ const loadEnd = performance.now();
45
+ logger.info('Tiff:loaded', {
46
+ path: args.path.href,
47
+ fetches: FetchLog.fetches.length,
48
+ bytesRead: FetchLog.bytesRead,
49
+ duration: loadEnd - loadStart,
50
+ });
51
+ for (const i of tiff.images) {
52
+ const byteCount = i.tags.get(TiffTag.TileByteCounts);
53
+ const tileOffsets = i.tags.get(TiffTag.TileOffsets);
54
+ logger.debug('Image:TileInfo', {
55
+ image: i.id,
56
+ toLoaded: tileOffsets?.isLoaded,
57
+ bcLoaded: byteCount?.isLoaded,
58
+ bcOffset: byteCount?.dataOffset,
59
+ toOffset: tileOffsets?.dataOffset,
60
+ count: byteCount?.count,
61
+ });
62
+ }
63
+ for (const t of tiles) {
64
+ const [z, x, y] = t;
65
+ if (tiff.images.length < z || z < 0) {
66
+ logger.error('Invalid tile z level', { z, max: tiff.images.length });
67
+ return;
68
+ }
69
+ const image = tiff.images[z];
70
+ const tile = await image.getTile(x, y);
71
+ if (tile == null) {
72
+ logger.error('Failed to fetch tile', { z, x, y });
73
+ return;
74
+ }
75
+ logger.info('Tile:fetched', {
76
+ z,
77
+ x,
78
+ y,
79
+ bytes: tile.bytes.byteLength,
80
+ fetches: FetchLog.fetches.length,
81
+ bytesRead: FetchLog.bytesRead,
82
+ });
83
+ }
84
+ },
85
+ });
package/build/fs.js CHANGED
@@ -4,7 +4,7 @@ export const FetchLog = {
4
4
  fetch(req, next) {
5
5
  this.fetches.push(req);
6
6
  this.bytesRead += req.length ?? 0;
7
- logger.info('Tiff:fetch', { href: req.source.url.href, offset: req.offset, length: req.length });
7
+ logger.debug('Tiff:fetch', { href: req.source.url.href, offset: req.offset, length: req.length });
8
8
  return next(req);
9
9
  },
10
10
  reset() {
package/build/index.d.ts CHANGED
@@ -9,6 +9,16 @@ export declare const cmd: Partial<import("cmd-ts/dist/cjs/argparser.js").Registe
9
9
  verbose: boolean;
10
10
  extraVerbose: boolean;
11
11
  };
12
+ } | {
13
+ command: "fetch-tile";
14
+ args: {
15
+ tile: string;
16
+ output: URL | undefined;
17
+ readSize: number;
18
+ path: URL;
19
+ verbose: boolean;
20
+ extraVerbose: boolean;
21
+ };
12
22
  } | {
13
23
  command: "info";
14
24
  args: {
@@ -31,6 +41,16 @@ export declare const cmd: Partial<import("cmd-ts/dist/cjs/argparser.js").Registe
31
41
  verbose: boolean;
32
42
  extraVerbose: boolean;
33
43
  };
44
+ } | {
45
+ command: "fetch-tile";
46
+ args: {
47
+ tile: string;
48
+ output: URL | undefined;
49
+ readSize: number;
50
+ path: URL;
51
+ verbose: boolean;
52
+ extraVerbose: boolean;
53
+ };
34
54
  } | {
35
55
  command: "info";
36
56
  args: {
@@ -45,6 +65,9 @@ export declare const cmd: Partial<import("cmd-ts/dist/cjs/argparser.js").Registe
45
65
  }, {
46
66
  command: "dump";
47
67
  value: Promise<void>;
68
+ } | {
69
+ command: "fetch-tile";
70
+ value: Promise<void>;
48
71
  } | {
49
72
  command: "info";
50
73
  value: Promise<void>;
@@ -52,6 +75,9 @@ export declare const cmd: Partial<import("cmd-ts/dist/cjs/argparser.js").Registe
52
75
  run(context: import("cmd-ts/dist/cjs/argparser.js").ParseContext): Promise<import("cmd-ts/dist/cjs/argparser.js").ParsingResult<{
53
76
  command: "dump";
54
77
  value: Promise<void>;
78
+ } | {
79
+ command: "fetch-tile";
80
+ value: Promise<void>;
55
81
  } | {
56
82
  command: "info";
57
83
  value: Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAOd,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAQd,CAAC"}
package/build/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { subcommands } from 'cmd-ts';
2
2
  import { commandDump } from './commands/dump.js';
3
+ import { commandFetchTile } from './commands/fetch-tile.js';
3
4
  import { commandInfo } from './commands/info.js';
4
5
  export const cmd = subcommands({
5
6
  name: 'cogeotiff',
@@ -7,5 +8,6 @@ export const cmd = subcommands({
7
8
  cmds: {
8
9
  info: commandInfo,
9
10
  dump: commandDump,
11
+ 'fetch-tile': commandFetchTile,
10
12
  },
11
13
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cogeotiff/cli",
3
- "version": "9.0.7",
3
+ "version": "9.1.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/blacha/cogeotiff.git",
@@ -21,7 +21,7 @@
21
21
  "@chunkd/fs-aws": "^11.0.2",
22
22
  "@chunkd/middleware": "^11.0.0",
23
23
  "@chunkd/source": "^11.0.0",
24
- "@cogeotiff/core": "^9.2.0",
24
+ "@cogeotiff/core": "^9.3.0",
25
25
  "@linzjs/tracing": "^1.1.1",
26
26
  "ansi-colors": "^4.1.1",
27
27
  "cmd-ts": "^0.14.3",
@@ -35,5 +35,5 @@
35
35
  "publishConfig": {
36
36
  "access": "public"
37
37
  },
38
- "gitHead": "62a59096f2df47bd12cc969afdda1d90c31d679e"
38
+ "gitHead": "82b82e9d9f8996dfb0cb48827c143e134acc9865"
39
39
  }
@@ -0,0 +1,95 @@
1
+ import { fsa } from '@chunkd/fs';
2
+ import { TagOffset, Tiff, TiffTag } from '@cogeotiff/core';
3
+ import { command, number, option, optional, positional, string } from 'cmd-ts';
4
+
5
+ import { DefaultArgs, Url } from '../common.js';
6
+ import { FetchLog } from '../fs.js';
7
+ import { setupLogger } from '../log.js';
8
+
9
+ export const commandFetchTile = command({
10
+ name: 'fetch-tile',
11
+ args: {
12
+ ...DefaultArgs,
13
+ tile: option({
14
+ short: 't',
15
+ long: 'tile',
16
+ description: 'tile to process "z-x-y" multiple tiles can be fetched by comma separating them "z-x-y,z-x-y"',
17
+ type: string,
18
+ defaultValue: () => '0-0-0',
19
+ }),
20
+ output: option({ short: 'o', long: 'output', type: optional(Url) }),
21
+ readSize: option({
22
+ long: 'read-size',
23
+ description: 'Size of bytes to read for the tile, default is to read the whole tile in KB',
24
+ type: number,
25
+ defaultValue: () => 16,
26
+ }),
27
+ path: positional({ type: Url, description: 'File to process' }),
28
+ },
29
+
30
+ async handler(args) {
31
+ const logger = setupLogger(args);
32
+ if (logger.level === 'warn') logger.level = 'info';
33
+ fsa.middleware = [FetchLog]; // reset middleware so we don't cache or chunk requests
34
+
35
+ const tiles = args.tile.split(',').map((t) => t.split('-').map((s) => parseInt(s, 10)));
36
+ for (const t of tiles) {
37
+ if (isNaN(t[0]) || isNaN(t[1]) || isNaN(t[2])) {
38
+ logger.error('Invalid tile format, expected {z-x-y}', { tile: args.tile });
39
+ return;
40
+ }
41
+ }
42
+
43
+ const tiff = new Tiff(fsa.source(args.path));
44
+ tiff.defaultReadSize = args.readSize * 1024;
45
+
46
+ logger.debug('Tiff:load', { path: args.path.href });
47
+ const loadStart = performance.now();
48
+ await tiff.init();
49
+ const loadEnd = performance.now();
50
+ logger.info('Tiff:loaded', {
51
+ path: args.path.href,
52
+ fetches: FetchLog.fetches.length,
53
+ bytesRead: FetchLog.bytesRead,
54
+ duration: loadEnd - loadStart,
55
+ });
56
+
57
+ for (const i of tiff.images) {
58
+ const byteCount = i.tags.get(TiffTag.TileByteCounts) as TagOffset | undefined;
59
+ const tileOffsets = i.tags.get(TiffTag.TileOffsets) as TagOffset | undefined;
60
+ logger.debug('Image:TileInfo', {
61
+ image: i.id,
62
+ toLoaded: tileOffsets?.isLoaded,
63
+ bcLoaded: byteCount?.isLoaded,
64
+ bcOffset: byteCount?.dataOffset,
65
+ toOffset: tileOffsets?.dataOffset,
66
+ count: byteCount?.count,
67
+ });
68
+ }
69
+
70
+ for (const t of tiles) {
71
+ const [z, x, y] = t;
72
+
73
+ if (tiff.images.length < z || z < 0) {
74
+ logger.error('Invalid tile z level', { z, max: tiff.images.length });
75
+ return;
76
+ }
77
+
78
+ const image = tiff.images[z];
79
+ const tile = await image.getTile(x, y);
80
+ if (tile == null) {
81
+ logger.error('Failed to fetch tile', { z, x, y });
82
+ return;
83
+ }
84
+
85
+ logger.info('Tile:fetched', {
86
+ z,
87
+ x,
88
+ y,
89
+ bytes: tile.bytes.byteLength,
90
+ fetches: FetchLog.fetches.length,
91
+ bytesRead: FetchLog.bytesRead,
92
+ });
93
+ }
94
+ },
95
+ });
package/src/fs.ts CHANGED
@@ -7,7 +7,7 @@ export const FetchLog: SourceMiddleware & { reset(): void; fetches: SourceReques
7
7
  fetch(req: SourceRequest, next: SourceCallback) {
8
8
  this.fetches.push(req);
9
9
  this.bytesRead += req.length ?? 0;
10
- logger.info('Tiff:fetch', { href: req.source.url.href, offset: req.offset, length: req.length });
10
+ logger.debug('Tiff:fetch', { href: req.source.url.href, offset: req.offset, length: req.length });
11
11
  return next(req);
12
12
  },
13
13
  reset() {
package/src/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { subcommands } from 'cmd-ts';
2
2
 
3
3
  import { commandDump } from './commands/dump.js';
4
+ import { commandFetchTile } from './commands/fetch-tile.js';
4
5
  import { commandInfo } from './commands/info.js';
5
6
 
6
7
  export const cmd = subcommands({
@@ -9,5 +10,6 @@ export const cmd = subcommands({
9
10
  cmds: {
10
11
  info: commandInfo,
11
12
  dump: commandDump,
13
+ 'fetch-tile': commandFetchTile,
12
14
  },
13
15
  });