@@ -10,8 +10,9 @@ import {
1010import { fsa } from '@chunkd/fs' ;
1111import { CogTiff } from '@cogeotiff/core' ;
1212import pLimit , { LimitFunction } from 'p-limit' ;
13- import { basename , resolve } from 'path' ;
13+ import { basename } from 'path' ;
1414import { StacCollection } from 'stac-ts' ;
15+ import { fileURLToPath } from 'url' ;
1516import { sha256base58 } from '../base58.node.js' ;
1617import { ConfigImagery } from '../config/imagery.js' ;
1718import { ConfigTileSetRaster , TileSetType } from '../config/tile.set.js' ;
@@ -47,9 +48,10 @@ export type ConfigImageryTiff = ConfigImagery & TiffSummary;
4748 *
4849 * @throws if any of the tiffs have differing EPSG or GSD
4950 **/
50- function computeTiffSummary ( target : string , tiffs : CogTiff [ ] ) : TiffSummary {
51+ function computeTiffSummary ( target : URL , tiffs : CogTiff [ ] ) : TiffSummary {
5152 const res : Partial < TiffSummary > = { files : [ ] } ;
5253
54+ const targetPath = urlToString ( target ) ;
5355 let bounds : Bounds | undefined ;
5456 for ( const tiff of tiffs ) {
5557 const firstImage = tiff . getImage ( 0 ) ;
@@ -78,7 +80,9 @@ function computeTiffSummary(target: string, tiffs: CogTiff[]): TiffSummary {
7880 else bounds = bounds . union ( imgBounds ) ;
7981
8082 if ( res . files == null ) res . files = [ ] ;
81- res . files . push ( { name : tiff . source . uri , ...imgBounds } ) ;
83+
84+ const relativePath = toRelative ( targetPath , tiff . source . uri ) ;
85+ res . files . push ( { name : relativePath , ...imgBounds } ) ;
8286 }
8387 res . bounds = bounds ?. toJson ( ) ;
8488 if ( res . bounds == null ) throw new Error ( 'Failed to extract imagery bounds from:' + target ) ;
@@ -87,11 +91,28 @@ function computeTiffSummary(target: string, tiffs: CogTiff[]): TiffSummary {
8791 return res as TiffSummary ;
8892}
8993
94+ /** Convert a path to a relative path
95+ * @param base the path to be relative to
96+ * @param other the path to convert
97+ */
98+ function toRelative ( base : string , other : string ) : string {
99+ if ( ! other . startsWith ( base ) ) throw new Error ( 'Paths are not relative' ) ;
100+ const part = other . slice ( base . length ) ;
101+ if ( part . startsWith ( '/' ) || part . startsWith ( '\\' ) ) return part . slice ( 1 ) ;
102+ return part ;
103+ }
104+
105+ /** Convert a URL to a string using fileUrlToPath if the URL is a file:// */
106+ function urlToString ( u : URL ) : string {
107+ if ( u . protocol === 'file:' ) return fileURLToPath ( u ) ;
108+ return u . href ;
109+ }
110+
90111/** Attempt to read a stac collection.json from the target path if it exists or return null if anything goes wrong. */
91- async function loadStacFromPath ( target : string ) : Promise < StacCollection | null > {
92- const collectionPath = fsa . join ( target , 'collection.json' ) ;
112+ async function loadStacFromURL ( target : URL ) : Promise < StacCollection | null > {
113+ const collectionPath = new URL ( 'collection.json' , target ) ;
93114 try {
94- return await fsa . readJson ( collectionPath ) ;
115+ return await fsa . readJson ( urlToString ( collectionPath ) ) ;
95116 } catch ( e ) {
96117 return null ;
97118 }
@@ -104,30 +125,31 @@ async function loadStacFromPath(target: string): Promise<StacCollection | null>
104125 *
105126 * @returns Imagery configuration generated from the path
106127 */
107- export async function imageryFromTiffPath ( target : string , Q : LimitFunction , log ?: LogType ) : Promise < ConfigImageryTiff > {
108- const sourceFiles = await fsa . toArray ( fsa . list ( target ) ) ;
128+ export async function imageryFromTiffUrl ( target : URL , Q : LimitFunction , log ?: LogType ) : Promise < ConfigImageryTiff > {
129+ const targetPath = urlToString ( target ) ;
130+ const sourceFiles = await fsa . toArray ( fsa . list ( targetPath ) ) ;
109131 const tiffs = await Promise . all (
110132 sourceFiles . filter ( isTiff ) . map ( ( c ) => Q ( ( ) => new CogTiff ( fsa . source ( c ) ) . init ( true ) ) ) ,
111133 ) ;
112134
113135 try {
114- const stac = await loadStacFromPath ( target ) ;
136+ const stac = await loadStacFromURL ( target ) ;
115137 const params = computeTiffSummary ( target , tiffs ) ;
116138
117- const folderName = basename ( target ) ;
139+ const folderName = basename ( targetPath ) ;
118140 const title = stac ?. title ?? folderName ;
119141 const tileMatrix =
120142 params . projection === EpsgCode . Nztm2000 ? Nztm2000QuadTms : TileMatrixSets . tryGet ( params . projection ) ;
121143
122144 const imagery : ConfigImageryTiff = {
123- id : sha256base58 ( target ) ,
145+ id : sha256base58 ( target . href ) ,
124146 name : folderName ,
125147 title,
126148 updatedAt : Date . now ( ) ,
127149 projection : params . projection ,
128150 tileMatrix : tileMatrix ?. identifier ?? 'none' ,
129151 gsd : params . gsd ,
130- uri : resolve ( target ) ,
152+ uri : targetPath ,
131153 bounds : params . bounds ,
132154 files : params . files ,
133155 collection : stac ?? undefined ,
@@ -177,16 +199,16 @@ export async function imageryFromTiffPath(target: string, Q: LimitFunction, log?
177199 * @param concurrency number of tiff files to load at a time
178200 * @returns
179201 */
180- export async function initConfigFromPaths (
202+ export async function initConfigFromUrls (
181203 provider : ConfigProviderMemory ,
182- targets : string [ ] ,
204+ targets : URL [ ] ,
183205 concurrency = 25 ,
184206 log ?: LogType ,
185207) : Promise < { tileSet : ConfigTileSetRaster ; imagery : ConfigImageryTiff [ ] } > {
186208 const q = pLimit ( concurrency ) ;
187209
188210 const imageryConfig : Promise < ConfigImageryTiff > [ ] = [ ] ;
189- for ( const target of targets ) imageryConfig . push ( imageryFromTiffPath ( target , q , log ) ) ;
211+ for ( const target of targets ) imageryConfig . push ( imageryFromTiffUrl ( target , q , log ) ) ;
190212
191213 const aerialTileSet : ConfigTileSetRaster = {
192214 id : 'ts_aerial' ,
0 commit comments