├── .eslintrc.cjs
├── .gitattributes
├── .github
├── CODEOWNERS
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── dependabot.yml
├── pull_request_template.md
└── workflows
│ ├── containers.yml
│ ├── pull-request.yml
│ ├── push.yml
│ ├── screenshot.yml
│ └── smoke-test.yml
├── .gitignore
├── .hyperfine.json
├── .prettierrc.cjs
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── docs
├── README.md
├── configuration.md
├── deployment.md
├── developer-guide
│ ├── API
│ │ └── .gitignore
│ ├── README.md
│ ├── cli-methods
│ │ ├── bundle-the-basemaps-assets-archive.md
│ │ └── bundle-the-basemaps-config-file.md
│ ├── run-basemaps-locally.md
│ └── server-methods
│ │ ├── serve-basemaps-with-bundled-config-file.md
│ │ └── serve-basemaps-with-collection-of-geotiff-files.md
├── examples
│ ├── _overview.md
│ ├── index.leaflet.xyz.3857.html
│ ├── index.maplibre.opacity.3857.html
│ ├── index.maplibre.vector.3857.html
│ ├── leaflet.xyz.3857.md
│ ├── maplibre.opacity.3857.md
│ └── maplibre.vector.3857.md
├── index.css
├── operator-guide
│ ├── README.md
│ ├── cog-quality.md
│ ├── empty-tiles.md
│ ├── gebco.md
│ ├── quick-start.md
│ ├── relief-shade.md
│ ├── static
│ │ ├── 2023-06-26-gisborne-2023.png
│ │ ├── projection_beehive_fakenztm2000.webp
│ │ ├── projection_beehive_nztm2000quad.webp
│ │ ├── projection_nztm2000quad_0_0_0.webp
│ │ ├── quality__005_006_0_bilinear.webp
│ │ ├── quality__005_006_0_lanczos.webp
│ │ ├── quality__i6.bilinear.webp
│ │ ├── quality__i6.cubic.webp
│ │ ├── quality__i6.lanczos.webp
│ │ ├── quality__resampling-overview.webp
│ │ ├── quick-start__layers.png
│ │ ├── relief__aerial.webp
│ │ ├── relief__base.webp
│ │ ├── relief__darken.webp
│ │ └── relief__lighten.webp
│ ├── texture-shade.md
│ └── xyz-projection.md
├── quick-start.md
├── static
│ ├── basemaps-service.png
│ ├── tile-resize.png
│ └── workflow-run.png
└── user-guide
│ ├── _get-started.md
│ ├── api-documentation.md
│ ├── swagger-api.json
│ ├── technical-documentation.md
│ └── use-in-esri-software
│ ├── README.md
│ ├── how-to-add-emergency-imagery-to-arcgis
│ ├── README.md
│ └── static
│ │ └── emergency-response-group.png
│ ├── how-to-add-individual-linz-basemaps-layers-to-arcgis
│ ├── README.md
│ └── static
│ │ ├── basemaps-menu-button.png
│ │ ├── copy-url-apikey.png
│ │ ├── custom-parameters.png
│ │ ├── layer-search.png
│ │ ├── layer-selector.png
│ │ └── move-apikey-info.png
│ ├── how-to-add-linz-aerial-imagery-basemaps-to-arcgis-online
│ ├── README.md
│ └── static
│ │ ├── step-1-agol-map-viewer.png
│ │ ├── step-2-layers-panel.png
│ │ ├── step-3-browse-layers-option.png
│ │ ├── step-4-agol-option.png
│ │ ├── step-5-search-box.png
│ │ └── step-6-desired-layer-on-map.png
│ └── how-to-add-linz-basemaps-to-arcgis-online-basemaps
│ ├── README.md
│ └── static
│ ├── LINZ-basemaps-group.png
│ └── basemaps-in-esri-chooser.png
├── lerna.json
├── mkdocs.yml
├── package-lock.json
├── package.json
├── packages
├── __tests__
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── assert.ts
│ │ ├── index.ts
│ │ ├── rounding.ts
│ │ └── test.tiff.ts
│ ├── static
│ │ ├── abel-tasman-and-golden-bay_2016_dem_1m_BP25_10000_0404.tiff
│ │ ├── generate-tiff.sh
│ │ ├── rgba8.google.png
│ │ ├── rgba8.google.tiff
│ │ ├── rgba8.nztm2000.png
│ │ ├── rgba8.nztm2000.tiff
│ │ └── rgba8_tiled.tiff
│ └── tsconfig.json
├── _infra
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── cdk.json
│ ├── package.json
│ ├── src
│ │ ├── analytics
│ │ │ └── edge.analytics.ts
│ │ ├── config.ts
│ │ ├── deploy.env.ts
│ │ ├── edge
│ │ │ └── index.ts
│ │ ├── index.ts
│ │ ├── parameters.ts
│ │ ├── serve
│ │ │ ├── db.ts
│ │ │ ├── index.ts
│ │ │ └── lambda.tiler.ts
│ │ └── version.ts
│ └── tsconfig.json
├── attribution
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── __tests__
│ │ │ ├── attr.test.ts
│ │ │ └── utils.test.ts
│ │ ├── attribution.index.ts
│ │ ├── attribution.ts
│ │ ├── index.ts
│ │ └── utils.ts
│ ├── tsconfig.json
│ └── typedoc.json
├── bathymetry
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── images
│ │ ├── bathyoutput.png
│ │ └── bathyprocess.png
│ ├── package.json
│ ├── src
│ │ ├── @types
│ │ │ └── muiltihash.d.ts
│ │ ├── __tests__
│ │ │ ├── hash.test.ts
│ │ │ ├── stac.test.ts
│ │ │ └── test-file.txt
│ │ ├── bathy.maker.ts
│ │ ├── file.ts
│ │ ├── folder.ts
│ │ ├── gdal
│ │ │ ├── __tests__
│ │ │ │ └── gdal.progress.test.ts
│ │ │ ├── gdal.command.ts
│ │ │ ├── gdal.docker.ts
│ │ │ ├── gdal.local.ts
│ │ │ ├── gdal.progress.ts
│ │ │ └── gdal.ts
│ │ ├── hash.ts
│ │ ├── index.ts
│ │ ├── mapnik.ts
│ │ └── stac.ts
│ └── tsconfig.json
├── cli-config
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── __tests__
│ │ │ └── util.test.ts
│ │ ├── bin.ts
│ │ ├── cli
│ │ │ ├── action.bundle.assets.ts
│ │ │ ├── action.bundle.ts
│ │ │ ├── action.create.config.ts
│ │ │ ├── action.import.ts
│ │ │ ├── config.diff.ts
│ │ │ └── config.update.ts
│ │ ├── index.ts
│ │ └── util.ts
│ ├── tsconfig.json
│ └── typedoc.json
├── cli-raster
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── bin.ts
│ │ ├── cogify
│ │ │ ├── __test__
│ │ │ │ ├── covering.test.ts
│ │ │ │ └── extract.test.ts
│ │ │ ├── cli.ts
│ │ │ ├── cli
│ │ │ │ ├── __test__
│ │ │ │ │ ├── cli.cover.test.ts
│ │ │ │ │ └── cli.topo.test.ts
│ │ │ │ ├── cli.cog.ts
│ │ │ │ ├── cli.cover.ts
│ │ │ │ ├── cli.topo.ts
│ │ │ │ └── cli.validate.ts
│ │ │ ├── covering
│ │ │ │ ├── covering.ts
│ │ │ │ ├── cutline.ts
│ │ │ │ └── tile.cover.ts
│ │ │ ├── gdal
│ │ │ │ ├── gdal.command.ts
│ │ │ │ └── gdal.runner.ts
│ │ │ ├── stac.ts
│ │ │ └── topo
│ │ │ │ ├── extract.ts
│ │ │ │ ├── slug.ts
│ │ │ │ └── stac.creation.ts
│ │ ├── download.ts
│ │ ├── hash.stream.ts
│ │ ├── index.ts
│ │ └── preset.ts
│ ├── static
│ │ ├── example-covering.png
│ │ └── nztm-tile-index.png
│ ├── tsconfig.json
│ └── typedoc.json
├── cli-vector
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── schema
│ │ ├── addresses.json
│ │ ├── aerialways.json
│ │ ├── boundaries.json
│ │ ├── buildings.json
│ │ ├── contours.json
│ │ ├── dam_lines.json
│ │ ├── ferries.json
│ │ ├── land.json
│ │ ├── parcel_boundaries.json
│ │ ├── pier_lines.json
│ │ ├── place_labels.json
│ │ ├── pois.json
│ │ ├── public_transport.json
│ │ ├── sites.json
│ │ ├── street_labels.json
│ │ ├── street_polygons.json
│ │ ├── streets.json
│ │ ├── water_lines.json
│ │ └── water_polygons.json
│ ├── src
│ │ ├── bin.ts
│ │ ├── cli
│ │ │ ├── cli.create.ts
│ │ │ ├── cli.extract.ts
│ │ │ └── cli.join.ts
│ │ ├── extract.ts
│ │ ├── generalization
│ │ │ ├── generalization.ts
│ │ │ └── simplify.ts
│ │ ├── index.ts
│ │ ├── modify
│ │ │ ├── consts.ts
│ │ │ ├── layers
│ │ │ │ ├── __test__
│ │ │ │ │ └── contours.test.ts
│ │ │ │ ├── contours.ts
│ │ │ │ ├── place_labels.ts
│ │ │ │ ├── pois.ts
│ │ │ │ ├── public_transport.ts
│ │ │ │ ├── street_labels.ts
│ │ │ │ ├── streets.ts
│ │ │ │ └── water_polygons.ts
│ │ │ ├── modify.ts
│ │ │ ├── parser.ts
│ │ │ ├── schema.ts
│ │ │ └── shared.ts
│ │ ├── schema-loader
│ │ │ ├── parser.ts
│ │ │ ├── schema.loader.ts
│ │ │ └── schema.ts
│ │ ├── stac.ts
│ │ ├── transform
│ │ │ ├── covt.ts
│ │ │ ├── mbtiles.to.ttiles.ts
│ │ │ ├── ogr2ogr.ts
│ │ │ └── tippecanoe.ts
│ │ ├── types
│ │ │ └── VectorGeoFeature.ts
│ │ └── util.ts
│ ├── tsconfig.json
│ └── typedoc.json
├── cli
│ ├── CHANGELOG.md
│ ├── Dockerfile
│ ├── README.md
│ ├── __test.assets__
│ │ ├── kapiti.geojson
│ │ ├── mana.geojson
│ │ ├── tif1.tiff
│ │ └── tif2.tiff
│ ├── bin
│ │ └── bmc.js
│ ├── package.json
│ ├── src
│ │ └── cli
│ │ │ ├── bin.ts
│ │ │ └── index.ts
│ ├── tsconfig.json
│ └── typedoc.json
├── config-loader
│ ├── CHANGELOG.md
│ ├── package.json
│ ├── src
│ │ ├── index.ts
│ │ └── json
│ │ │ ├── __tests__
│ │ │ ├── config.loader.test.ts
│ │ │ ├── tiff.config.test.ts
│ │ │ └── tiff.load.test.ts
│ │ │ ├── imagery.config.cache.ts
│ │ │ ├── json.config.ts
│ │ │ ├── log.ts
│ │ │ ├── parse.provider.ts
│ │ │ ├── parse.style.ts
│ │ │ ├── parse.tile.set.ts
│ │ │ └── tiff.config.ts
│ └── tsconfig.json
├── config
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── __tests__
│ │ │ ├── layer.name.test.ts
│ │ │ ├── names.ts
│ │ │ └── prefix.test.ts
│ │ ├── base.config.ts
│ │ ├── base58.node.ts
│ │ ├── base58.ts
│ │ ├── color.ts
│ │ ├── config
│ │ │ ├── __test__
│ │ │ │ └── config.test.ts
│ │ │ ├── base.ts
│ │ │ ├── config.bundle.ts
│ │ │ ├── imagery.ts
│ │ │ ├── prefix.ts
│ │ │ ├── provider.ts
│ │ │ ├── tile.set.output.ts
│ │ │ ├── tile.set.pipeline.ts
│ │ │ ├── tile.set.ts
│ │ │ └── vector.style.ts
│ │ ├── index.ts
│ │ ├── memory
│ │ │ ├── __tests__
│ │ │ │ └── memory.config.test.ts
│ │ │ └── memory.config.ts
│ │ └── name.convertor.ts
│ ├── tsconfig.json
│ └── typedoc.json
├── geo
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── __tests__
│ │ │ ├── bounds.test.ts
│ │ │ ├── epsg.test.ts
│ │ │ ├── quad.key.test.ts
│ │ │ ├── slug.test.ts
│ │ │ └── tile.matrix.set.test.ts
│ │ ├── bounds.ts
│ │ ├── epsg.ts
│ │ ├── formats.ts
│ │ ├── index.ts
│ │ ├── proj
│ │ │ ├── __tests__
│ │ │ │ ├── projection.test.ts
│ │ │ │ ├── projection.tile.matrix.set.test.ts
│ │ │ │ └── test.util.ts
│ │ │ ├── citm2000.ts
│ │ │ ├── nztm2000.ts
│ │ │ ├── projection.loader.ts
│ │ │ ├── projection.ts
│ │ │ └── tile.set.name.ts
│ │ ├── quad.key.ts
│ │ ├── simplify.ts
│ │ ├── slug.ts
│ │ ├── stac
│ │ │ ├── index.ts
│ │ │ └── stac.attribution.ts
│ │ ├── tile.json
│ │ │ └── tile.json.ts
│ │ ├── tile.matrix.set.ts
│ │ ├── tile.ts
│ │ ├── tms
│ │ │ ├── citm2000.ts
│ │ │ ├── google.ts
│ │ │ ├── index.ts
│ │ │ └── nztm2000.ts
│ │ ├── wmts
│ │ │ └── wmts.ts
│ │ └── xy.order.ts
│ ├── tsconfig.json
│ └── typedoc.json
├── lambda-analytic-cloudfront
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── __test__
│ │ │ ├── analytics.test.ts
│ │ │ └── log.data.ts
│ │ ├── bin.ts
│ │ ├── date.ts
│ │ ├── elastic.ts
│ │ ├── handler.ts
│ │ ├── index.ts
│ │ ├── log.reader.ts
│ │ ├── log.stats.ts
│ │ ├── log
│ │ │ ├── __test__
│ │ │ │ └── tile.url.test.ts
│ │ │ ├── query.ts
│ │ │ ├── referer.ts
│ │ │ └── tile.url.ts
│ │ └── useragent
│ │ │ ├── __test__
│ │ │ └── parser.test.ts
│ │ │ ├── agent.ts
│ │ │ ├── agents
│ │ │ ├── gis.ts
│ │ │ └── programming.ts
│ │ │ ├── parser.ts
│ │ │ └── parser.types.ts
│ ├── tsconfig.json
│ └── typedoc.json
├── lambda-analytics
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── __tests__
│ │ │ ├── file.process.test.ts
│ │ │ ├── index.test.ts
│ │ │ └── ua.test.ts
│ │ ├── file.process.ts
│ │ ├── index.ts
│ │ ├── stats.ts
│ │ └── ua.ts
│ ├── tsconfig.json
│ └── typedoc.json
├── lambda-tiler
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── bundle.sh
│ ├── package.json
│ ├── scripts
│ │ └── create.deployment.package.mjs
│ ├── src
│ │ ├── __tests__
│ │ │ ├── config.data.ts
│ │ │ ├── index.test.ts
│ │ │ ├── tile.style.json.test.ts
│ │ │ ├── wmts.capability.test.ts
│ │ │ └── xyz.util.ts
│ │ ├── cli
│ │ │ ├── render.preview.ts
│ │ │ └── render.tile.ts
│ │ ├── index.ts
│ │ ├── routes
│ │ │ ├── __tests__
│ │ │ │ ├── attribution.test.ts
│ │ │ │ ├── fonts.test.ts
│ │ │ │ ├── health.test.ts
│ │ │ │ ├── imagery.test.ts
│ │ │ │ ├── link.test.ts
│ │ │ │ ├── memory.fs.ts
│ │ │ │ ├── preview.index.test.ts
│ │ │ │ ├── sprites.test.ts
│ │ │ │ ├── tile.json.test.ts
│ │ │ │ ├── tile.style.json.attribution.test.ts
│ │ │ │ ├── tile.style.json.test.ts
│ │ │ │ ├── wmts.test.ts
│ │ │ │ └── xyz.test.ts
│ │ │ ├── attribution.ts
│ │ │ ├── config.ts
│ │ │ ├── fonts.ts
│ │ │ ├── health.ts
│ │ │ ├── imagery.ts
│ │ │ ├── link.ts
│ │ │ ├── ping.ts
│ │ │ ├── preview.index.ts
│ │ │ ├── preview.ts
│ │ │ ├── sprites.ts
│ │ │ ├── tile.json.ts
│ │ │ ├── tile.style.json.ts
│ │ │ ├── tile.wmts.ts
│ │ │ ├── tile.xyz.raster.ts
│ │ │ ├── tile.xyz.ts
│ │ │ ├── tile.xyz.vector.ts
│ │ │ └── version.ts
│ │ ├── util
│ │ │ ├── __test__
│ │ │ │ ├── cache.test.ts
│ │ │ │ ├── config.loader.test.ts
│ │ │ │ ├── nztm.style.test.ts
│ │ │ │ └── validate.test.ts
│ │ │ ├── assets.provider.ts
│ │ │ ├── config.cache.ts
│ │ │ ├── config.loader.ts
│ │ │ ├── cotar.serve.ts
│ │ │ ├── etag.ts
│ │ │ ├── nztm.style.ts
│ │ │ ├── response.ts
│ │ │ ├── source.cache.ts
│ │ │ ├── swapping.lru.ts
│ │ │ └── validate.ts
│ │ └── wmts.capability.ts
│ ├── static
│ │ ├── expected_tile_2193_153_255_z7.png
│ │ ├── expected_tile_NZTM2000Quad_30_33_z6.png
│ │ └── expected_tile_WebMercatorQuad_252_156_z8.png
│ ├── tsconfig.json
│ └── typedoc.json
├── landing
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── scripts
│ │ └── deploy.mjs
│ ├── serve.mjs
│ ├── src
│ │ ├── __tests__
│ │ │ ├── NZTMTileLocation.png
│ │ │ ├── config.debug.test.ts
│ │ │ ├── config.test.ts
│ │ │ ├── geojson.test.ts
│ │ │ ├── map.config.test.ts
│ │ │ └── tile.matrix.test.ts
│ │ ├── attribution.ts
│ │ ├── components
│ │ │ ├── copyable.tsx
│ │ │ ├── debug.tsx
│ │ │ ├── feature.updates.tsx
│ │ │ ├── layer.switcher.dropdown.tsx
│ │ │ ├── layout.footer.tsx
│ │ │ ├── layout.header.tsx
│ │ │ ├── link.tsx
│ │ │ ├── map.label.tsx
│ │ │ ├── map.switcher.tsx
│ │ │ ├── map.tsx
│ │ │ └── new-features
│ │ │ │ └── 3d.map.tsx
│ │ ├── config.debug.ts
│ │ ├── config.layer.ts
│ │ ├── config.map.ts
│ │ ├── config.ts
│ │ ├── debug.map.ts
│ │ ├── global.ts
│ │ ├── index.tsx
│ │ ├── tile.matrix.ts
│ │ ├── url.ts
│ │ └── webp.ts
│ ├── static
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ ├── apple-touch-icon.png
│ │ ├── basemaps-card.jpeg
│ │ ├── examples
│ │ │ ├── index.html
│ │ │ ├── index.leaflet.xyz.3857.html
│ │ │ ├── index.maplibre.compare.3857.html
│ │ │ ├── index.maplibre.elevation.3857.html
│ │ │ ├── index.maplibre.opacity.3857.html
│ │ │ ├── index.maplibre.vector.3857.html
│ │ │ ├── index.openlayers.attribution.wmts.3857.html
│ │ │ ├── index.openlayers.wmts.3857.html
│ │ │ └── index.openlayers.xyz.3857.html
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon.ico
│ │ ├── index.css
│ │ ├── index.html
│ │ └── json-schema
│ │ │ └── stac-basemaps-extension
│ │ │ └── 1.0
│ │ │ └── schema.json
│ ├── tsconfig.json
│ └── typedoc.json
├── linzjs-docker-command
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── __tests__
│ │ │ └── example.ts
│ │ ├── command.execution.ts
│ │ ├── command.ts
│ │ ├── execution
│ │ │ ├── __tests__
│ │ │ │ ├── execute.docker.test.ts
│ │ │ │ └── execute.local.test.ts
│ │ │ ├── execute.docker.ts
│ │ │ ├── execute.local.ts
│ │ │ ├── execute.result.ts
│ │ │ └── execute.ts
│ │ └── index.ts
│ ├── tsconfig.json
│ └── typedoc.json
├── linzjs-geojson
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── @types
│ │ │ └── lineclip.d.ts
│ │ ├── __tests__
│ │ │ ├── bbox.test.ts
│ │ │ ├── construct.test.ts
│ │ │ └── wgs84.test.ts
│ │ ├── bbox.ts
│ │ ├── construct.ts
│ │ ├── index.ts
│ │ ├── multipolygon
│ │ │ ├── __tests__
│ │ │ │ ├── area.test.ts
│ │ │ │ ├── clipped.test.ts
│ │ │ │ └── convert.test.ts
│ │ │ ├── area.ts
│ │ │ ├── clipped.ts
│ │ │ └── convert.ts
│ │ ├── types.ts
│ │ ├── util
│ │ │ ├── __test__
│ │ │ │ ├── iterate.test.ts
│ │ │ │ └── truncate.test.ts
│ │ │ ├── iterate.ts
│ │ │ └── truncate.ts
│ │ └── wgs84.ts
│ ├── tsconfig.json
│ └── typedoc.json
├── linzjs-metrics
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── __tests__
│ │ │ └── metrics.test.ts
│ │ └── metrics.ts
│ ├── tsconfig.json
│ └── typedoc.json
├── server
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── Dockerfile
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── bin.ts
│ │ ├── cli.ts
│ │ ├── config.ts
│ │ ├── index.ts
│ │ ├── route.layers.ts
│ │ └── server.ts
│ ├── tsconfig.json
│ └── typedoc.json
├── shared
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── __tests__
│ │ │ ├── api.test.ts
│ │ │ ├── env.test.ts
│ │ │ ├── fqdn.test.ts
│ │ │ ├── url.test.ts
│ │ │ ├── util.test.ts
│ │ │ └── vdom.test.ts
│ │ ├── api.ts
│ │ ├── cli
│ │ │ ├── __tests__
│ │ │ │ └── git.tag.test.ts
│ │ │ ├── argo.ts
│ │ │ ├── base.ts
│ │ │ ├── git.tag.ts
│ │ │ ├── info.ts
│ │ │ ├── log.ts
│ │ │ └── parsers.ts
│ │ ├── config.ts
│ │ ├── const.ts
│ │ ├── dynamo
│ │ │ ├── __tests__
│ │ │ │ ├── config.dynamo.test.ts
│ │ │ │ ├── config.imagery.test.ts
│ │ │ │ └── config.provider.test.ts
│ │ │ ├── dynamo.config.base.ts
│ │ │ ├── dynamo.config.cached.ts
│ │ │ └── dynamo.config.ts
│ │ ├── file.system.middleware.ts
│ │ ├── file.system.ts
│ │ ├── imagery.url.ts
│ │ ├── index.ts
│ │ ├── log.ts
│ │ ├── logger.fatal.error.ts
│ │ ├── scripts
│ │ │ └── debug.tile.matrix.ts
│ │ ├── url.ts
│ │ ├── util.ts
│ │ └── vdom.ts
│ ├── tsconfig.json
│ └── typedoc.json
├── smoke
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── base.ts
│ │ ├── fonts.test.ts
│ │ ├── health.test.ts
│ │ ├── index.test.ts
│ │ ├── tile.test.ts
│ │ └── wmts.test.ts
│ ├── tsconfig.json
│ └── typedoc.json
├── sprites
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── bin
│ │ └── basemaps-sprites.mjs
│ ├── package.json
│ ├── src
│ │ ├── __test__
│ │ │ ├── readme.test.ts
│ │ │ └── sprite.test.ts
│ │ ├── cli.ts
│ │ ├── fs.ts
│ │ ├── index.ts
│ │ └── sprites.ts
│ ├── static
│ │ └── sprites
│ │ │ ├── airport_aerodrome_pnt_fill.svg
│ │ │ ├── circle.png
│ │ │ ├── embankment_no_gap_cl_thick_wide.svg
│ │ │ ├── mast_pnt.svg
│ │ │ ├── openstreetmap_poi_bus.svg
│ │ │ ├── openstreetmap_poi_plane.svg
│ │ │ ├── openstreetmap_shield_ca_qc_a_2.svg
│ │ │ └── openstreetmap_shield_kr_expressway_2.svg
│ ├── tsconfig.json
│ └── typedoc.json
├── tiler-sharp
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── __tests__
│ │ │ ├── tile.benchmark.ts
│ │ │ └── tile.creation.test.ts
│ │ ├── index.ts
│ │ └── pipeline
│ │ │ ├── __tests__
│ │ │ ├── pipeline.color.ramp.test.ts
│ │ │ ├── pipeline.resize.test.ts
│ │ │ └── terrain.rgb.test.ts
│ │ │ ├── colorize
│ │ │ ├── color.ramp.ts
│ │ │ ├── colorize.ts
│ │ │ └── grey.scale.ts
│ │ │ ├── decompressor.lerc.ts
│ │ │ ├── decompressor.ts
│ │ │ ├── pipeline.color.ramp.ts
│ │ │ ├── pipeline.resize.ts
│ │ │ ├── pipeline.terrain.rgb.ts
│ │ │ └── pipelines.ts
│ ├── static
│ │ ├── expected_tile_2193_256x256_0_1_z0.png
│ │ ├── expected_tile_2193_256x256_0_2_z0.png
│ │ ├── expected_tile_2193_256x256_1_1_z0.png
│ │ ├── expected_tile_2193_256x256_1_2_z0.png
│ │ ├── expected_tile_2193_256x256_4_7_z2.png
│ │ ├── expected_tile_2193_256x256_4_8_z2.png
│ │ ├── expected_tile_2193_256x256_5_8_z2.png
│ │ ├── expected_tile_2193_256x256_6_8_z2.png
│ │ ├── expected_tile_3857_256x256_0_0_z1.png
│ │ ├── expected_tile_3857_256x256_0_1_z1.png
│ │ ├── expected_tile_3857_256x256_1024_1024_z11.png
│ │ ├── expected_tile_3857_256x256_128_128_z8.png
│ │ ├── expected_tile_3857_256x256_1_0_z1.png
│ │ ├── expected_tile_3857_256x256_1_1_z1.png
│ │ ├── expected_tile_3857_256x256_2048_2048_z12.png
│ │ ├── expected_tile_3857_256x256_256_256_z9.png
│ │ ├── expected_tile_3857_256x256_2_2_z2.png
│ │ ├── expected_tile_3857_256x256_4096_4096_z13.png
│ │ ├── expected_tile_3857_256x256_4_4_z3.png
│ │ ├── expected_tile_3857_256x256_4_5_z3.png
│ │ ├── expected_tile_3857_256x256_512_512_z10.png
│ │ ├── expected_tile_3857_256x256_5_4_z3.png
│ │ ├── expected_tile_3857_256x256_5_5_z3.png
│ │ └── expected_tile_3857_256x256_64_64_z7.png
│ ├── tsconfig.json
│ └── typedoc.json
└── tiler
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ ├── __tests__
│ │ └── tiler.test.ts
│ ├── index.ts
│ ├── raster.ts
│ └── tiler.ts
│ ├── tsconfig.json
│ └── typedoc.json
├── scripts
├── bundle.mjs
├── detect.unlinked.dep.mjs
├── file.util.mjs
└── version.bump.sh
├── tsconfig.base.json
├── tsconfig.json
└── typedoc.json
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | const cfg = {
2 | ...require('@linzjs/style/.eslintrc.cjs'),
3 | };
4 |
5 | cfg.rules['no-console'] = ['error', { allow: ['warn', 'error'] }];
6 |
7 | // Disable no floating promises in tests until https://github.com/nodejs/node/issues/51292 is solved
8 | const testOverrides = cfg.overrides.find((ovr) => ovr.files.find((f) => f.includes('.test.ts')));
9 | testOverrides.rules['@typescript-eslint/no-floating-promises'] = 'off';
10 |
11 | // Allow console.log in tests and scripts
12 | cfg.overrides.push({
13 | files: ['**/*.mjs', '**/__tests__/**/*.ts'],
14 | rules: { 'no-console': 'off', '@typescript-eslint/no-explicit-any': 'off' },
15 | });
16 |
17 | // Disable required importing of react as typescript does this for us
18 | cfg.overrides.push({
19 | files: '**/*.tsx',
20 | rules: { 'react/react-in-jsx-scope': 'off' },
21 | });
22 |
23 | // cfg.parserOptions.ecmaVersion = 2020;
24 |
25 | module.exports = cfg;
26 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto eol=lf
2 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @linz/proj-basemaps-dev
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | labels: bug
5 | ---
6 |
7 | ### Bug Description
8 |
9 | A clear and concise description of what the bug is and what you expected to happen.
10 |
11 | #### Steps to Reproduce
12 |
13 | Steps to reproduce the behavior:
14 |
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | #### Desktop
21 |
22 | - Environment: [e.g. Windows / DaaS / Ubuntu]
23 | - Relevant Software Versions [e.g. QGIS 2.18.21]
24 |
25 | #### Screenshots
26 |
27 | If applicable, add screenshots to help explain your problem.
28 |
29 | **Add an _Assignee_, _Milestone_, _Release_ and any relevant _Labels_.**
30 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | labels: enhancement
5 | ---
6 |
7 | ### User Story
8 |
9 | In order to [accomplish goal] as a [role] I want [capability]
10 | (optional: instead of [existing behaviour]).
11 |
12 | #### Acceptance Criteria
13 |
14 | - [ ] ...
15 | - [ ] ...
16 | - [ ] ...
17 |
18 | **Add an _Assignee_, _Milestone_, _Release_ and any relevant _Labels_.**
19 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: 'github-actions'
4 | directory: '/'
5 | schedule:
6 | interval: daily
7 | - package-ecosystem: npm
8 | directory: '/'
9 | schedule:
10 | interval: daily
11 | ignore:
12 | - dependency-name: '@aws-cdk/*'
13 | - dependency-name: 'aws-cdk'
14 | - dependency-name: 'aws-sdk'
15 | open-pull-requests-limit: 10
16 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ### Motivation
2 |
3 |
4 |
5 | ### Modifications
6 |
7 |
8 |
9 |
10 |
11 | ### Verification
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.github/workflows/pull-request.yml:
--------------------------------------------------------------------------------
1 | name: Pull Request lint
2 |
3 | on:
4 | pull_request:
5 | types: ['opened', 'edited', 'reopened', 'synchronize']
6 |
7 | jobs:
8 | lint:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: linz/action-pull-request-lint@v1
12 | with:
13 | conventional: 'error' # require conventional pull request title (default: "error" options: "error", "warn", "off")
14 |
15 | jira: 'warn' # Require JIRA ticket references (default: "warn", options: "error", "warn", "off")
16 | jira-projects: 'BM,TDE' # optional list of jira projects
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | build
3 | tsconfig.tsbuildinfo
4 | dist
5 | .cache
6 | cdk.out
7 | cdk.context.json
8 | *.tgz
--------------------------------------------------------------------------------
/.hyperfine.json:
--------------------------------------------------------------------------------
1 | [
2 | { "name": "Tile 256x256", "command": "node packages/tiler-sharp/build/__tests__/tile.benchmark.js 256" },
3 | { "name": "Tile 512x512", "command": "node packages/tiler-sharp/build/__tests__/tile.benchmark.js 512" }
4 | ]
--------------------------------------------------------------------------------
/.prettierrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | ...require('@linzjs/style/.prettierrc.cjs'),
3 | };
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Crown copyright (c), Toitū Te Whenua Land Information New Zealand on behalf of the New Zealand Government.
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
18 | THE 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.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Basemaps
2 |
3 | [](https://github.com/linz/basemaps/actions)
4 | [](https://github.com/linz/basemaps/blob/master/LICENSE)
5 |
6 |
7 | A digital basemap provides a consistent background detail necessary to orient location and add to aesthetic appeal. Basemaps can be made up of streets, parcels, boundaries (country, regional, and city boundaries), shaded relief of a digital elevation model, waterways, hydrography, aerial and satellite imagery. Basemaps can be used as desktop, website or mobile phone application components, or as a 3rd party layers within a GIS or desktop mapping application.
8 |
9 |
10 | ## License
11 |
12 | This system is licensed under the MIT License, except where otherwise specified. See the [LICENSE](https://github.com/linz/basemaps/blob/master/LICENSE) file for more details.
13 |
14 | ## Development
15 |
16 | For background information about the basemaps service and its development see [Documentation](./docs/README.md)
17 |
18 | ## Building
19 |
20 | For building and contributing guide see [Contributing](./CONTRIBUTING.md)
21 |
22 | ## Changes
23 |
24 | For a history of basemaps changes see the [Changelog](./CHANGELOG.md)
--------------------------------------------------------------------------------
/docs/developer-guide/API/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore everything in this directory
2 | *
3 | # Except this file
4 | !.gitignore
5 |
--------------------------------------------------------------------------------
/docs/developer-guide/README.md:
--------------------------------------------------------------------------------
1 | # Developer guide
2 |
3 | Documentation of the Basemaps codebase for developers
4 |
5 | - [How to run `basemaps` locally](./run-basemaps-locally.md)
6 | - Contributing guidelines
7 | - TypeDoc API docs
8 |
9 | ## Creating and updating docs
10 |
11 | The best way to run the docs locally is to use the same container as the CI process
12 |
13 | To start the container in a local dev mode which creates a server on [http://localhost:8000](http://localhost:8000)
14 |
15 | ```bash
16 | docker run --rm \
17 | -v $PWD:/docs \
18 | -p 8000:8000 \
19 | squidfunk/mkdocs-material:9.4 serve -a 0.0.0.0:8000
20 | ```
21 |
22 | As it is run inside of a container the additional `-a` to allow external connections to access it.
23 |
--------------------------------------------------------------------------------
/docs/developer-guide/server-methods/serve-basemaps-with-collection-of-geotiff-files.md:
--------------------------------------------------------------------------------
1 | # Serve `basemaps` using a collection of GeoTIFF files
2 |
3 | This guide shows you how to configure and run the **basemaps/server** package using a collection of GeoTIFF files.
4 |
5 | ## Configure the `basemaps/server` package
6 |
7 | The **basemaps/server** package requires a collection of GeoTIFF files from which it can serve the **basemaps** system.
8 |
9 | !!! abstract "Path"
10 |
11 | Make a note of the following path:
12 |
13 | === "`IMAGERY_DIR`"
14 |
15 | The path to the root folder of your GeoTIFF file collection.
16 |
17 | ```bash
18 | $IMAGERY_DIR = {path_to_imagery_directory}
19 | ```
20 |
21 | ## Run the `basemaps/server` package
22 |
23 | !!! abstract "Path"
24 |
25 | The **basemaps/server** package provides a default function to serve the **basemaps** system. Note the following path:
26 |
27 | === "`BM_SERVER_BUILD`"
28 |
29 | The path to the **build** folder of the **basemaps/server** package.
30 |
31 | ```bash
32 | $BM_SERVER_BUILD = $BM_REPO/packages/server/build
33 | ```
34 |
35 | ### Command
36 |
37 | Use the following command to run the **Basemaps** system:
38 |
39 | ```bash
40 | node $BM_SERVER_BUILD/bin.js $IMAGERY_DIR
41 | ```
42 |
--------------------------------------------------------------------------------
/docs/examples/_overview.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | [Use leaflet render raster map](./leaflet.xyz.3857.md)
4 |
5 |
6 |
7 | [Use Maplibre adjust opacity of the map](./maplibre.opacity.3857.md)
8 |
9 |
10 |
11 | [Use Maplibre to load vector tiles](./maplibre.vector.3857.md)
12 |
13 |
14 |
--------------------------------------------------------------------------------
/docs/examples/index.leaflet.xyz.3857.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Leaflet WGS84 Basemaps Demo
6 |
7 |
12 |
19 |
20 |
21 |
22 |
23 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/docs/examples/leaflet.xyz.3857.md:
--------------------------------------------------------------------------------
1 | # Leaflet Raster Map
2 |
3 | Use leaflet render raster map
4 |
5 |
6 |
7 | ```html
8 | --8<-- "examples/index.leaflet.xyz.3857.html"
9 | ```
10 |
--------------------------------------------------------------------------------
/docs/examples/maplibre.opacity.3857.md:
--------------------------------------------------------------------------------
1 | # Maplibre Opacity Slider
2 |
3 | Use Maplibre adjust opacity of the map
4 |
5 |
6 |
7 | ```html
8 | --8<-- "examples/index.maplibre.opacity.3857.html"
9 | ```
10 |
--------------------------------------------------------------------------------
/docs/examples/maplibre.vector.3857.md:
--------------------------------------------------------------------------------
1 | # Maplibre Vector Map
2 |
3 | Use Maplibre to load vector tiles
4 |
5 |
6 |
7 | ```html
8 | --8<-- "examples/index.maplibre.vector.3857.html"
9 | ```
10 |
--------------------------------------------------------------------------------
/docs/index.css:
--------------------------------------------------------------------------------
1 | .md-header {
2 | background: linear-gradient(70deg, #00425d 12%, #007198);
3 | }
4 |
--------------------------------------------------------------------------------
/docs/operator-guide/README.md:
--------------------------------------------------------------------------------
1 | # Basemaps operator guide
2 |
3 | How to deploy your own instance of Basemaps
4 |
5 | - How to run basemaps on your own imagery
6 | - Simple CLI examples on how to serve tiffs from docker
7 | - How to process imagery into more efficent formats
8 | - Complex TIFF examples
9 |
--------------------------------------------------------------------------------
/docs/operator-guide/static/2023-06-26-gisborne-2023.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/operator-guide/static/2023-06-26-gisborne-2023.png
--------------------------------------------------------------------------------
/docs/operator-guide/static/projection_beehive_fakenztm2000.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/operator-guide/static/projection_beehive_fakenztm2000.webp
--------------------------------------------------------------------------------
/docs/operator-guide/static/projection_beehive_nztm2000quad.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/operator-guide/static/projection_beehive_nztm2000quad.webp
--------------------------------------------------------------------------------
/docs/operator-guide/static/projection_nztm2000quad_0_0_0.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/operator-guide/static/projection_nztm2000quad_0_0_0.webp
--------------------------------------------------------------------------------
/docs/operator-guide/static/quality__005_006_0_bilinear.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/operator-guide/static/quality__005_006_0_bilinear.webp
--------------------------------------------------------------------------------
/docs/operator-guide/static/quality__005_006_0_lanczos.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/operator-guide/static/quality__005_006_0_lanczos.webp
--------------------------------------------------------------------------------
/docs/operator-guide/static/quality__i6.bilinear.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/operator-guide/static/quality__i6.bilinear.webp
--------------------------------------------------------------------------------
/docs/operator-guide/static/quality__i6.cubic.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/operator-guide/static/quality__i6.cubic.webp
--------------------------------------------------------------------------------
/docs/operator-guide/static/quality__i6.lanczos.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/operator-guide/static/quality__i6.lanczos.webp
--------------------------------------------------------------------------------
/docs/operator-guide/static/quality__resampling-overview.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/operator-guide/static/quality__resampling-overview.webp
--------------------------------------------------------------------------------
/docs/operator-guide/static/quick-start__layers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/operator-guide/static/quick-start__layers.png
--------------------------------------------------------------------------------
/docs/operator-guide/static/relief__aerial.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/operator-guide/static/relief__aerial.webp
--------------------------------------------------------------------------------
/docs/operator-guide/static/relief__base.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/operator-guide/static/relief__base.webp
--------------------------------------------------------------------------------
/docs/operator-guide/static/relief__darken.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/operator-guide/static/relief__darken.webp
--------------------------------------------------------------------------------
/docs/operator-guide/static/relief__lighten.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/operator-guide/static/relief__lighten.webp
--------------------------------------------------------------------------------
/docs/quick-start.md:
--------------------------------------------------------------------------------
1 | # Quick start guide
2 |
3 | This document is broken down into three user types: User, Operator and Developer.
4 |
5 | - **User** wants to use the basemaps service running on [https://basemaps.linz.govt.nz](https://basemaps.linz.govt.nz)
6 | - **Operator** wants to use `@basemaps/server` or `@linzjs/lambda-tiler` on their own imagery
7 | - **Developer** wants to modify the linz/basemaps source code to meet their needs.
8 |
9 | There are three separate quick start guides for these users.
10 |
11 | - [User Quick Start](./user-guide/quick-start.md)
12 | - [Operator Quick Start](./operator-guide/quick-start.md)
13 | - [Developer Quick Start](./developer-guide/quick-start.md)
14 |
--------------------------------------------------------------------------------
/docs/static/basemaps-service.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/static/basemaps-service.png
--------------------------------------------------------------------------------
/docs/static/tile-resize.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/static/tile-resize.png
--------------------------------------------------------------------------------
/docs/static/workflow-run.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/static/workflow-run.png
--------------------------------------------------------------------------------
/docs/user-guide/api-documentation.md:
--------------------------------------------------------------------------------
1 | # API documentation
2 |
3 | This page provide examples of Basemaps APIs that allow you to programmatically access LINZ map tile services to integrate into your mobile, web.
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/user-guide/use-in-esri-software/README.md:
--------------------------------------------------------------------------------
1 | # Use in Esri software
2 |
3 | This page provides a step-by-step guide to several common ways LINZ Basemaps APIs can be used within Esri software, including ArcGIS Online (AGOL) and Enterprise.
4 |
5 | - [How to add LINZ Aerial Imagery Basemaps to ArcGIS Online][1]
6 | - [How to add imagery captured during an emergency to ArcGIS][2]
7 | - [How to add an individual basemap or imagery layer from LINZ Basemaps to ArcGIS][3]
8 | - [How to add LINZ Imagery Basemaps to your AGOL basemaps][4]
9 |
10 | [1]: how-to-add-linz-aerial-imagery-basemaps-to-arcgis-online/README.md
11 | [2]: how-to-add-emergency-imagery-to-arcgis/README.md
12 | [3]: how-to-add-individual-linz-basemaps-layers-to-arcgis/README.md
13 | [4]: how-to-add-linz-basemaps-to-arcgis-online-basemaps/README.md
14 |
--------------------------------------------------------------------------------
/docs/user-guide/use-in-esri-software/how-to-add-emergency-imagery-to-arcgis/README.md:
--------------------------------------------------------------------------------
1 | # How to add imagery captured during an emergency to ArcGIS
2 |
3 | During an emergency response, LINZ will create an ArcGIS Online item for each imagery dataset published on LINZ Basemaps. The ArcGIS Online item will make it easier to discover and add the imagery to ArcGIS Online.
4 |
5 | Either search ArcGIS Online for LINZ imagery emergency or view all available emergency response imagery from the [LINZ Emergency Response Imagery Collection AGOL Group](https://linz.maps.arcgis.com/home/group.html?id=b71aee8952d84164a0ea9c06d5c988fd).
6 |
7 | Note the imagery is hosted from LINZ Imagery Basemaps in Web Map Tile Service (WMTS) format.
8 |
9 | !!! tip
10 |
11 | If you join the [LINZ Emergency Response Imagery Collection AGOL Group](https://linz.maps.arcgis.com/home/group.html?id=b71aee8952d84164a0ea9c06d5c988fd), it will be easier to find response imagery in future.
12 |
13 | 
14 |
--------------------------------------------------------------------------------
/docs/user-guide/use-in-esri-software/how-to-add-emergency-imagery-to-arcgis/static/emergency-response-group.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/user-guide/use-in-esri-software/how-to-add-emergency-imagery-to-arcgis/static/emergency-response-group.png
--------------------------------------------------------------------------------
/docs/user-guide/use-in-esri-software/how-to-add-individual-linz-basemaps-layers-to-arcgis/static/basemaps-menu-button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/user-guide/use-in-esri-software/how-to-add-individual-linz-basemaps-layers-to-arcgis/static/basemaps-menu-button.png
--------------------------------------------------------------------------------
/docs/user-guide/use-in-esri-software/how-to-add-individual-linz-basemaps-layers-to-arcgis/static/copy-url-apikey.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/user-guide/use-in-esri-software/how-to-add-individual-linz-basemaps-layers-to-arcgis/static/copy-url-apikey.png
--------------------------------------------------------------------------------
/docs/user-guide/use-in-esri-software/how-to-add-individual-linz-basemaps-layers-to-arcgis/static/custom-parameters.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/user-guide/use-in-esri-software/how-to-add-individual-linz-basemaps-layers-to-arcgis/static/custom-parameters.png
--------------------------------------------------------------------------------
/docs/user-guide/use-in-esri-software/how-to-add-individual-linz-basemaps-layers-to-arcgis/static/layer-search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/user-guide/use-in-esri-software/how-to-add-individual-linz-basemaps-layers-to-arcgis/static/layer-search.png
--------------------------------------------------------------------------------
/docs/user-guide/use-in-esri-software/how-to-add-individual-linz-basemaps-layers-to-arcgis/static/layer-selector.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/user-guide/use-in-esri-software/how-to-add-individual-linz-basemaps-layers-to-arcgis/static/layer-selector.png
--------------------------------------------------------------------------------
/docs/user-guide/use-in-esri-software/how-to-add-individual-linz-basemaps-layers-to-arcgis/static/move-apikey-info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/user-guide/use-in-esri-software/how-to-add-individual-linz-basemaps-layers-to-arcgis/static/move-apikey-info.png
--------------------------------------------------------------------------------
/docs/user-guide/use-in-esri-software/how-to-add-linz-aerial-imagery-basemaps-to-arcgis-online/README.md:
--------------------------------------------------------------------------------
1 | # How to add LINZ Aerial Imagery Basemaps to ArcGIS Online
2 |
3 | 1. Open the [ArcGIS Online Map Viewer](https://www.arcgis.com/apps/mapviewer/index.html) in a web browser.
4 |
5 | 
6 |
7 | 2. Open the **`Layers`** panel.
8 |
9 | 
10 |
11 | 3. From the dropdown, select the **`Browse layers`** option.
12 |
13 | 
14 |
15 | 4. From the dropdown, select the **`ArcGIS Online`** option.
16 |
17 | 
18 |
19 | 5. Type **`LINZ Aerial Imagery Basemap`** in the search box. You should see two layers in particular:
20 |
21 | 1. `LINZ Aerial Imagery Basemap - Web Mercator`
22 | 2. `LINZ Aerial Imagery Basemap - NZTM`
23 |
24 | The two layers are unique by projection. Click the **`+ Add`** button for the desired layer.
25 |
26 | 
27 |
28 | 6. You should now see the desired **`LINZ Aerial Imagery Basemap`** layer on the map.
29 |
30 | 
31 |
--------------------------------------------------------------------------------
/docs/user-guide/use-in-esri-software/how-to-add-linz-aerial-imagery-basemaps-to-arcgis-online/static/step-1-agol-map-viewer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/user-guide/use-in-esri-software/how-to-add-linz-aerial-imagery-basemaps-to-arcgis-online/static/step-1-agol-map-viewer.png
--------------------------------------------------------------------------------
/docs/user-guide/use-in-esri-software/how-to-add-linz-aerial-imagery-basemaps-to-arcgis-online/static/step-2-layers-panel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/user-guide/use-in-esri-software/how-to-add-linz-aerial-imagery-basemaps-to-arcgis-online/static/step-2-layers-panel.png
--------------------------------------------------------------------------------
/docs/user-guide/use-in-esri-software/how-to-add-linz-aerial-imagery-basemaps-to-arcgis-online/static/step-3-browse-layers-option.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/user-guide/use-in-esri-software/how-to-add-linz-aerial-imagery-basemaps-to-arcgis-online/static/step-3-browse-layers-option.png
--------------------------------------------------------------------------------
/docs/user-guide/use-in-esri-software/how-to-add-linz-aerial-imagery-basemaps-to-arcgis-online/static/step-4-agol-option.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/user-guide/use-in-esri-software/how-to-add-linz-aerial-imagery-basemaps-to-arcgis-online/static/step-4-agol-option.png
--------------------------------------------------------------------------------
/docs/user-guide/use-in-esri-software/how-to-add-linz-aerial-imagery-basemaps-to-arcgis-online/static/step-5-search-box.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/user-guide/use-in-esri-software/how-to-add-linz-aerial-imagery-basemaps-to-arcgis-online/static/step-5-search-box.png
--------------------------------------------------------------------------------
/docs/user-guide/use-in-esri-software/how-to-add-linz-aerial-imagery-basemaps-to-arcgis-online/static/step-6-desired-layer-on-map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/user-guide/use-in-esri-software/how-to-add-linz-aerial-imagery-basemaps-to-arcgis-online/static/step-6-desired-layer-on-map.png
--------------------------------------------------------------------------------
/docs/user-guide/use-in-esri-software/how-to-add-linz-basemaps-to-arcgis-online-basemaps/README.md:
--------------------------------------------------------------------------------
1 | # How to add LINZ Imagery Basemaps to your AGOL basemaps
2 |
3 | 
4 |
5 | To change the basemap options for your organisation to offer both Esri, Eagle and LINZ basemaps:
6 |
7 | 1. Sign in to ArcGIS Online as a role with ArcGIS Administrator privileges
8 |
9 | 2. Join the [NZ Basemaps Group](https://arcgis.com/home/group.html?id=4033cd7bf65a443cbaf7e1cae0e76f59)
10 |
11 | 3. In ArcGIS Online, open Organization > Settings > Map
12 |
13 | 4. Under Basemap Gallery, click the Edit button to open the Group drop-down menu and choose NZ Basemaps Group
14 |
15 | 
16 |
--------------------------------------------------------------------------------
/docs/user-guide/use-in-esri-software/how-to-add-linz-basemaps-to-arcgis-online-basemaps/static/LINZ-basemaps-group.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/user-guide/use-in-esri-software/how-to-add-linz-basemaps-to-arcgis-online-basemaps/static/LINZ-basemaps-group.png
--------------------------------------------------------------------------------
/docs/user-guide/use-in-esri-software/how-to-add-linz-basemaps-to-arcgis-online-basemaps/static/basemaps-in-esri-chooser.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/docs/user-guide/use-in-esri-software/how-to-add-linz-basemaps-to-arcgis-online-basemaps/static/basemaps-in-esri-chooser.png
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "useYarn": true,
3 | "packages": ["packages/*"],
4 | "command": {
5 | "version": {
6 | "yes": true,
7 | "conventionalCommits": true
8 | }
9 | },
10 | "version": "8.1.0"
11 | }
12 |
--------------------------------------------------------------------------------
/packages/__tests__/README.md:
--------------------------------------------------------------------------------
1 | # @basemaps/test
2 |
3 | Testing utilities and assets
4 |
5 | ## Approx equal
6 |
7 | ```typescript
8 | import { approxEqual } from '@basemaps/test';
9 |
10 | o('should be near', () => {
11 | approxEqual(1, 2, 'one two'); // `one two (1 vs 2) should be less than 0.001`
12 | });
13 | ```
14 |
15 | ## TestTiffs
16 |
17 | Two RGB Testing tiffs are provided for Google (epsg:3857) and NZTM2000 (epgs:2193) projections
18 |
19 | ```typescript
20 | import { TestTiff } from '@basemaps/test';
21 |
22 | // Create a new CogTiff for each projection
23 | const google = TestTiff.Google;
24 | const nztm2000 = TestTiff.Nztm2000;
25 |
26 | // They need to be initialized
27 | await Promise.all([google.init(), nztm2000.init()]);
28 | ```
29 |
30 | ### rgba8.google.tiff
31 |
32 | 
33 |
34 | ### rgba8.nztm.tiff
35 |
36 | Due to NZTM2000 being a weird tiling scheme and z0 having 2x4 with half the tiles being outside of the extent, this tiff is centered around tiles: 0.5, 1.5 -> 1.5, 2.5
37 |
38 | 
39 |
--------------------------------------------------------------------------------
/packages/__tests__/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@basemaps/test",
3 | "version": "8.0.0",
4 | "private": true,
5 | "main": "./build/index.js",
6 | "types": "./build/index.d.ts",
7 | "repository": "git@github.com:linz/basemaps.git",
8 | "author": {
9 | "name": "Land Information New Zealand",
10 | "url": "https://linz.govt.nz",
11 | "organization": true
12 | },
13 | "type": "module",
14 | "engines": {
15 | "node": ">=16.0.0"
16 | },
17 | "license": "MIT",
18 | "scripts": {}
19 | }
20 |
--------------------------------------------------------------------------------
/packages/__tests__/src/index.ts:
--------------------------------------------------------------------------------
1 | export { Approx } from './assert.js';
2 | export { TestTiff } from './test.tiff.js';
3 |
--------------------------------------------------------------------------------
/packages/__tests__/src/test.tiff.ts:
--------------------------------------------------------------------------------
1 | export const TestDataPath = new URL('../static/', import.meta.url);
2 |
3 | const TiffGooglePath = new URL('rgba8.google.tiff', TestDataPath);
4 | const TiffNztm2000Path = new URL('rgba8.nztm2000.tiff', TestDataPath);
5 |
6 | export class TestTiff {
7 | static get Nztm2000(): URL {
8 | return TiffNztm2000Path;
9 | }
10 |
11 | static get Google(): URL {
12 | return TiffGooglePath;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/packages/__tests__/static/abel-tasman-and-golden-bay_2016_dem_1m_BP25_10000_0404.tiff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/packages/__tests__/static/abel-tasman-and-golden-bay_2016_dem_1m_BP25_10000_0404.tiff
--------------------------------------------------------------------------------
/packages/__tests__/static/generate-tiff.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # NZTM2000 has a weird tiling scheme, this creates a tiff centered around
4 | # tiles: 0.5, 1.5 -> 1.5, 2.5
5 | gdal_translate -a_srs epsg:2193 \
6 | -a_ullr 146880 6559360 2440640 4265600 \
7 | -of GTiff -co COMPRESS=WEBP -co WEBP_LOSSLESS=TRUE \
8 | -co TILED=YES -co BLOCKXSIZE=16 -co BLOCKYSIZE=16 \
9 | rgba8_tiled.tiff rgba8.nztm2000.tiff
10 |
11 |
12 |
13 | # Webmercator bounds are 20037508.3427892 x -20037508.3427892 square
14 | # So create a tiff approx half the size
15 | gdal_translate -a_srs epsg:3857 \
16 | -a_ullr -10018754.1713946 10018754.1713946 10018754.1713946 -10018754.1713946 \
17 | -of GTiff -co COMPRESS=WEBP -co WEBP_LOSSLESS=TRUE -co TILED=YES \
18 | -co TILED=YES -co BLOCKXSIZE=16 -co BLOCKYSIZE=16 \
19 | rgba8_tiled.tiff rgba8.google.tiff
20 |
--------------------------------------------------------------------------------
/packages/__tests__/static/rgba8.google.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/packages/__tests__/static/rgba8.google.png
--------------------------------------------------------------------------------
/packages/__tests__/static/rgba8.google.tiff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/packages/__tests__/static/rgba8.google.tiff
--------------------------------------------------------------------------------
/packages/__tests__/static/rgba8.nztm2000.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/packages/__tests__/static/rgba8.nztm2000.png
--------------------------------------------------------------------------------
/packages/__tests__/static/rgba8.nztm2000.tiff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/packages/__tests__/static/rgba8.nztm2000.tiff
--------------------------------------------------------------------------------
/packages/__tests__/static/rgba8_tiled.tiff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/packages/__tests__/static/rgba8_tiled.tiff
--------------------------------------------------------------------------------
/packages/__tests__/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "outDir": "./build",
5 | "rootDir": "./src"
6 | },
7 | "include": ["src"],
8 | "references": []
9 | }
10 |
--------------------------------------------------------------------------------
/packages/_infra/.gitignore:
--------------------------------------------------------------------------------
1 | cdk.out
2 |
--------------------------------------------------------------------------------
/packages/_infra/cdk.json:
--------------------------------------------------------------------------------
1 | {
2 | "app": "node build/index.js"
3 | }
4 |
--------------------------------------------------------------------------------
/packages/_infra/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@basemaps/infra",
3 | "version": "8.1.0",
4 | "private": true,
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/linz/basemaps.git",
8 | "directory": "packages/_infra"
9 | },
10 | "author": {
11 | "name": "Land Information New Zealand",
12 | "url": "https://linz.govt.nz",
13 | "organization": true
14 | },
15 | "type": "module",
16 | "engines": {
17 | "node": ">=16.0.0"
18 | },
19 | "license": "MIT",
20 | "scripts": {
21 | "deploy:synth": "cdk synth",
22 | "deploy:diff": "cdk diff || true",
23 | "deploy:deploy": "cdk deploy '*' -y --require-approval never",
24 | "test": "node --test"
25 | },
26 | "devDependencies": {
27 | "@aws-sdk/client-acm": "^3.470.0",
28 | "@aws-sdk/client-cloudformation": "^3.470.0",
29 | "@basemaps/lambda-tiler": "^8.1.0",
30 | "@basemaps/shared": "^8.1.0",
31 | "@linzjs/cdk-tags": "^1.7.0",
32 | "aws-cdk": "2.162.x",
33 | "aws-cdk-lib": "2.162.x",
34 | "constructs": "^10.4.2"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/packages/_infra/src/deploy.env.ts:
--------------------------------------------------------------------------------
1 | export const DeployEnv = {
2 | /** Default AWS accountId to use */
3 | CdkAccount: 'CDK_DEFAULT_ACCOUNT',
4 | };
5 |
--------------------------------------------------------------------------------
/packages/_infra/src/serve/db.ts:
--------------------------------------------------------------------------------
1 | import { Const } from '@basemaps/shared';
2 | import cdk from 'aws-cdk-lib';
3 | import dynamoDb from 'aws-cdk-lib/aws-dynamodb';
4 | import { Construct } from 'constructs';
5 |
6 | export class TileMetadataTable extends Construct {
7 | public table: dynamoDb.Table;
8 | public constructor(scope: Construct, id: string) {
9 | super(scope, id);
10 |
11 | this.table = new dynamoDb.Table(this, 'TileMetadataDynamoTable', {
12 | tableName: Const.TileMetadata.TableName,
13 | billingMode: dynamoDb.BillingMode.PAY_PER_REQUEST,
14 | partitionKey: { name: 'id', type: dynamoDb.AttributeType.STRING },
15 | pointInTimeRecovery: true,
16 | });
17 |
18 | new cdk.CfnOutput(this, 'TileMetadataTable', { value: this.table.tableArn });
19 | }
20 | }
21 |
22 | export const TileMetadataTableArn = {
23 | /**
24 | * get the ARN for the TileMetadata table
25 | *
26 | * @returns ARN of the TileMetadata table
27 | */
28 | getArn(scope: cdk.Stack): string {
29 | return cdk.Arn.format(
30 | {
31 | service: 'dynamodb',
32 | region: '*',
33 | resource: 'table',
34 | resourceName: Const.TileMetadata.TableName,
35 | },
36 | scope,
37 | );
38 | },
39 | };
40 |
--------------------------------------------------------------------------------
/packages/_infra/src/serve/index.ts:
--------------------------------------------------------------------------------
1 | import cdk from 'aws-cdk-lib';
2 | import { Construct } from 'constructs';
3 |
4 | import { ParametersServeKeys } from '../parameters.js';
5 | import { TileMetadataTable } from './db.js';
6 | import { LambdaTiler } from './lambda.tiler.js';
7 |
8 | export interface ServeStackProps extends cdk.StackProps {
9 | /** Location of static files */
10 | staticBucketName?: string;
11 | }
12 |
13 | /**
14 | * Tile serving infrastructure
15 | */
16 | export class ServeStack extends cdk.Stack {
17 | public constructor(scope: Construct, id: string, props: ServeStackProps) {
18 | super(scope, id, props);
19 |
20 | const lambda = new LambdaTiler(this, 'LambdaTiler', { staticBucketName: props.staticBucketName });
21 | const table = new TileMetadataTable(this, 'TileMetadata');
22 | table.table.grantReadData(lambda.lambdaNoVpc);
23 |
24 | new cdk.CfnOutput(this, ParametersServeKeys.LambdaXyzUrl, { value: lambda.functionUrl.url });
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/packages/_infra/src/version.ts:
--------------------------------------------------------------------------------
1 | import { GitTag } from '@basemaps/shared/build/cli/git.tag.js';
2 |
3 | export interface VersionInfo {
4 | /** Current git tag */
5 | version: string;
6 | /** Current commit hash */
7 | hash: string;
8 | }
9 |
10 | let versionInfo: VersionInfo | null = null;
11 | export const VersionUtil = {
12 | /**
13 | * Get version information about the current build
14 | *
15 | */
16 | version(): VersionInfo {
17 | if (versionInfo == null) {
18 | versionInfo = GitTag();
19 | }
20 | return versionInfo;
21 | },
22 | };
23 |
--------------------------------------------------------------------------------
/packages/_infra/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 |
4 | "compilerOptions": {
5 | "outDir": "./build",
6 | "rootDir": "./src"
7 | },
8 | "include": ["src"],
9 | "references": [{ "path": "../shared/tsconfig.json" }]
10 | }
11 |
--------------------------------------------------------------------------------
/packages/attribution/README.md:
--------------------------------------------------------------------------------
1 | # @basemaps/attribution
2 |
3 | Library to determine to applicable attribution for a given extent and zoom level.
4 |
5 | ## Usage
6 |
7 | ```bash
8 | npm install @basemaps/attribution
9 | ```
10 |
11 | ```typescript
12 | import { Attribution } from '@basemaps/attribution';
13 |
14 | const attributions = await Attribution.load('https://basemaps.linz.govt.nz/v1/tiles/aerial/EPSG:3857/attribution.json?api=...');
15 |
16 | // Find all imagery sets inside the following bounding box
17 | const attrList = attributions.filter([144.7377202, -45.8938181, 195.62639, -37.65336], 6);
18 |
19 | // Convert the attrubtion list to a human readable description
20 | const description = attributions.renderList(attrList);
21 | // "NZ 10m Satellite Imagery (2020-2021) & GEBCO 2020 Grid"
22 | ```
23 |
24 | Using a CDN see https://basemaps.linz.govt.nz/examples/index.openlayers.attribution.wmts.3857.html.
25 |
26 | ## License
27 |
28 | This system is licensed under the MIT License, except where otherwise specified. See the [LICENSE](https://github.com/linz/basemaps/blob/master/LICENSE) file for more details.
29 |
--------------------------------------------------------------------------------
/packages/attribution/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@basemaps/attribution",
3 | "version": "8.0.0",
4 | "repository": {
5 | "type": "git",
6 | "url": "https://github.com/linz/basemaps.git",
7 | "directory": "packages/attribution"
8 | },
9 | "author": {
10 | "name": "Land Information New Zealand",
11 | "url": "https://linz.govt.nz",
12 | "organization": true
13 | },
14 | "type": "module",
15 | "engines": {
16 | "node": ">=16.0.0"
17 | },
18 | "license": "MIT",
19 | "main": "./build/index.js",
20 | "types": "./build/index.d.ts",
21 | "scripts": {
22 | "test": "node --test",
23 | "bundle": "../../scripts/bundle.mjs package.json"
24 | },
25 | "publishConfig": {
26 | "access": "public"
27 | },
28 | "files": [
29 | "dist/",
30 | "build/"
31 | ],
32 | "dependencies": {
33 | "@basemaps/geo": "^8.0.0",
34 | "@linzjs/geojson": "^8.0.0"
35 | },
36 | "bundle": {
37 | "entry": "src/attribution.index.ts",
38 | "outfile": "dist/attribution.js",
39 | "platform": "browser"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/packages/attribution/src/attribution.index.ts:
--------------------------------------------------------------------------------
1 | import { Attribution } from './attribution.js';
2 |
3 | declare global {
4 | interface Window {
5 | // Access to basemaps global
6 | BasemapsAttribution: typeof Attribution;
7 | }
8 | }
9 |
10 | window.BasemapsAttribution = Attribution;
11 |
--------------------------------------------------------------------------------
/packages/attribution/src/index.ts:
--------------------------------------------------------------------------------
1 | export { Attribution } from './attribution.js';
2 |
--------------------------------------------------------------------------------
/packages/attribution/src/utils.ts:
--------------------------------------------------------------------------------
1 | import { Stac, StacProvider } from '@basemaps/geo';
2 |
3 | export const copyright = `© ${Stac.License}`;
4 |
5 | /**
6 | * Create a licensor attribution string.
7 | *
8 | * @param providers The optional list of providers.
9 | *
10 | * @returns A copyright string comprising the names of licensor providers.
11 | *
12 | * @example
13 | * "CC BY 4.0 LINZ"
14 | *
15 | * @example
16 | * "CC BY 4.0 Nelson City Council, Tasman District Council, Waka Kotahi"
17 | */
18 | export function createLicensorAttribution(providers?: StacProvider[]): string {
19 | if (providers == null) return `${copyright} LINZ`;
20 |
21 | const licensors = providers.filter((p) => p.roles?.includes('licensor'));
22 | if (licensors.length === 0) return `${copyright} LINZ`;
23 |
24 | return `${copyright} ${licensors.map((l) => l.name).join(', ')}`;
25 | }
26 |
--------------------------------------------------------------------------------
/packages/attribution/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "lib": ["DOM"],
5 | "rootDir": "./src",
6 | "outDir": "./build"
7 | },
8 | "include": ["src"],
9 | "references": [{ "path": "../__tests__/tsconfig.json" }]
10 | }
11 |
--------------------------------------------------------------------------------
/packages/attribution/typedoc.json:
--------------------------------------------------------------------------------
1 | {
2 | "entryPoints": ["./src/**/*.ts"],
3 | "exclude": ["./**/__tests__/*.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/packages/bathymetry/README.md:
--------------------------------------------------------------------------------
1 | # @basemaps/bathymetry
2 |
3 | ## Bathymetry creation
4 |
5 | This process takes batheymetric data from [GEBCO](https://www.gebco.net/) and converts it into a colorized hillshaded geotiff.
6 |
7 | 
8 |
9 | ## Usage
10 |
11 | You will need:
12 |
13 | - Gebco netcdf file [here](https://www.gebco.net/data_and_products/gridded_bathymetry_data/)
14 | - Docker (or a new gdal 3+ with netcdf support)
15 | - Node >= v12
16 |
17 | ```bash
18 | # Install dependencies
19 | npm install @basemaps/bathymetry
20 |
21 | # To prevent very long CI/Dev build times, mapnik will need to be manually installed
22 | npm install mapnik
23 |
24 | # Ensure the javascript has been built
25 | npm run build
26 |
27 | # Create a the data file
28 | node build/index.js -v create --input gebco_2020.nc --docker --output gebco/
29 | ```
30 |
31 | ## Process
32 |
33 | 
34 |
--------------------------------------------------------------------------------
/packages/bathymetry/images/bathyoutput.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/packages/bathymetry/images/bathyoutput.png
--------------------------------------------------------------------------------
/packages/bathymetry/images/bathyprocess.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/packages/bathymetry/images/bathyprocess.png
--------------------------------------------------------------------------------
/packages/bathymetry/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@basemaps/bathymetry",
3 | "version": "8.1.0",
4 | "repository": {
5 | "type": "git",
6 | "url": "https://github.com/linz/basemaps.git",
7 | "directory": "packages/bathymetry"
8 | },
9 | "author": {
10 | "name": "Land Information New Zealand",
11 | "url": "https://linz.govt.nz",
12 | "organization": true
13 | },
14 | "type": "module",
15 | "engines": {
16 | "node": ">=16.0.0"
17 | },
18 | "license": "MIT",
19 | "main": "./build/index.js",
20 | "types": "./build/index.d.ts",
21 | "scripts": {
22 | "test": "node --test"
23 | },
24 | "publishConfig": {
25 | "access": "public"
26 | },
27 | "files": [
28 | "build/"
29 | ],
30 | "dependencies": {
31 | "@basemaps/geo": "^8.0.0",
32 | "@basemaps/shared": "^8.1.0",
33 | "@rushstack/ts-command-line": "^4.3.13",
34 | "ulid": "^2.3.0"
35 | },
36 | "devDependencies": {
37 | "@types/mapnik": "^3.0.1"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/packages/bathymetry/src/@types/muiltihash.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'multihashes' {
2 | interface MultiHashStatic {
3 | encode(buf: Buffer, type: 'sha2-256'): Buffer;
4 | }
5 | const multiHash: MultiHashStatic;
6 | export = multiHash;
7 | }
8 |
--------------------------------------------------------------------------------
/packages/bathymetry/src/__tests__/hash.test.ts:
--------------------------------------------------------------------------------
1 | import assert from 'node:assert';
2 | import * as fs from 'node:fs';
3 | import { describe, it } from 'node:test';
4 |
5 | import { Hash } from '../hash.js';
6 |
7 | describe('hash', () => {
8 | it('hash', async () => {
9 | fs.writeFileSync('./test-file', Buffer.from('I am a test file for hashing\n'));
10 | const ans = await Hash.hash('./test-file');
11 | assert.equal(ans, '122076427149ca45100f317f16821ef934885cc49352447ee64c9f5e9655c95c695e');
12 | fs.unlinkSync('./test-file');
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/packages/bathymetry/src/__tests__/test-file.txt:
--------------------------------------------------------------------------------
1 | I am a test file for hashing
2 |
--------------------------------------------------------------------------------
/packages/bathymetry/src/folder.ts:
--------------------------------------------------------------------------------
1 | import { Env } from '@basemaps/shared';
2 | import { promises as fs } from 'fs';
3 | import * as path from 'path';
4 |
5 | /** Make a temp folder inside TEMP_FOLDER's path */
6 | export async function makeTempFolder(folder: string): Promise {
7 | const tempPath = Env.get(Env.TempFolder) ?? '/tmp';
8 | const folderPath = path.join(tempPath, folder);
9 |
10 | await fs.mkdir(folderPath, { recursive: true });
11 | return folderPath;
12 | }
13 |
14 | /** Make a tiff folder inside TEMP_FOLDER's path */
15 | export async function makeTiffFolder(tmpFolder: string, name: string): Promise {
16 | const folderPath = path.join(tmpFolder, name);
17 |
18 | await fs.mkdir(folderPath, { recursive: true });
19 | return folderPath;
20 | }
21 |
--------------------------------------------------------------------------------
/packages/bathymetry/src/gdal/__tests__/gdal.progress.test.ts:
--------------------------------------------------------------------------------
1 | import assert from 'node:assert';
2 | import { describe, it } from 'node:test';
3 |
4 | import { GdalProgressParser } from '../gdal.progress.js';
5 |
6 | describe('GdalProgressParser', () => {
7 | it('should emit on progress', () => {
8 | const prog = new GdalProgressParser();
9 | assert.equal(prog.progress, 0);
10 |
11 | prog.data(Buffer.from('\n.'));
12 | assert.equal(prog.progress.toFixed(2), '3.23');
13 | });
14 |
15 | it('should take 31 dots to finish', () => {
16 | const prog = new GdalProgressParser();
17 | let processCount = 0;
18 | prog.data(Buffer.from('\n'));
19 | prog.on('progress', () => processCount++);
20 |
21 | for (let i = 0; i < 31; i++) {
22 | prog.data(Buffer.from('.'));
23 | assert.equal(processCount, i + 1);
24 | }
25 | assert.equal(prog.progress.toFixed(2), '100.00');
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/packages/bathymetry/src/gdal/gdal.local.ts:
--------------------------------------------------------------------------------
1 | import { LogType } from '@basemaps/shared';
2 |
3 | import { GdalCommand } from './gdal.command.js';
4 |
5 | export class GdalLocal extends GdalCommand {
6 | override async env(): Promise> {
7 | if (this.credentials == null) {
8 | return process.env;
9 | }
10 | if (this.credentials.needsRefresh()) {
11 | await this.credentials.refreshPromise();
12 | }
13 | return {
14 | ...process.env,
15 | AWS_ACCESS_KEY_ID: this.credentials.accessKeyId,
16 | AWS_SECRET_ACCESS_KEY: this.credentials.secretAccessKey,
17 | AWS_SESSION_TOKEN: this.credentials.sessionToken,
18 | };
19 | }
20 |
21 | override async run(cmd: string, args: string[], log: LogType): Promise<{ stdout: string; stderr: string }> {
22 | log.debug({ cmd, gdalArgs: args.slice(0, 50).join(' ') }, 'StartGdal:Local');
23 | return super.run(cmd, args, log);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/packages/bathymetry/src/gdal/gdal.ts:
--------------------------------------------------------------------------------
1 | import { Env, LogType } from '@basemaps/shared';
2 |
3 | import { GdalCommand } from './gdal.command.js';
4 | import { GdalDocker } from './gdal.docker.js';
5 | import { GdalLocal } from './gdal.local.js';
6 |
7 | export class Gdal {
8 | /**
9 | * Create a new GdalCommand instance ready to run commands
10 | *
11 | * This could be a local or docker container depending on environment variables
12 | * @see Env.Gdal.UseDocker
13 | */
14 | static create(): GdalCommand {
15 | if (Env.get(Env.Gdal.UseDocker)) return new GdalDocker();
16 | return new GdalLocal();
17 | }
18 |
19 | /**
20 | * Run a `gdal_translate --version` to extract the current gdal version
21 | *
22 | * @example "GDAL 2.4.2, released 2019/06/28"
23 | * @example "GDAL 3.2.0dev-69b0c4ec4174fde36c609a4aac6f4281424021b3, released 2020/06/26"
24 | */
25 | static async version(logger: LogType): Promise {
26 | const gdal = Gdal.create();
27 | const { stdout } = await gdal.run('gdal_translate', ['--version'], logger);
28 | return stdout;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/packages/bathymetry/src/hash.ts:
--------------------------------------------------------------------------------
1 | import * as crypto from 'crypto';
2 | import * as fs from 'fs';
3 |
4 | /** Stream a file though */
5 | function hashFile(filePath: string, hashName: string): Promise {
6 | return new Promise((resolve, reject) => {
7 | const hash = crypto.createHash(hashName);
8 | const stream = fs.createReadStream(filePath);
9 | stream.on('error', (err) => reject(err));
10 | stream.on('data', (chunk) => hash.update(chunk));
11 | stream.on('end', () => resolve(hash.digest('hex')));
12 | });
13 | }
14 |
15 | /** Create a multihash of a file */
16 | async function hash(filePath: string): Promise {
17 | const hashData = await hashFile(filePath, 'sha256');
18 | // 0x12 - sha256
19 | // 0x20 - 32bytes
20 | return '1220' + hashData;
21 | }
22 |
23 | export const Hash = { hash };
24 |
--------------------------------------------------------------------------------
/packages/bathymetry/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 |
4 | "compilerOptions": {
5 | "outDir": "./build",
6 | "rootDir": "./src"
7 | },
8 | "include": ["src"],
9 | "references": [
10 | { "path": "../__tests__/tsconfig.json" },
11 | { "path": "../shared/tsconfig.json" },
12 | { "path": "../cli/tsconfig.json" }
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/packages/cli-config/src/__tests__/util.test.ts:
--------------------------------------------------------------------------------
1 | import assert from 'node:assert';
2 | import { describe, it } from 'node:test';
3 |
4 | import { nameImageryTitle } from '../util.js';
5 |
6 | describe('util', () => {
7 | it('nameImageryTitle', () => {
8 | assert.equal(nameImageryTitle('Palmerston-north urban 2016-17 12.125m'), 'palmerston-north_urban_2016-17_12-125m');
9 | assert.equal(nameImageryTitle('Palmerston-north urban 2016-17 12-125'), 'palmerston-north_urban_2016-17_12-125');
10 | assert.equal(nameImageryTitle('Palmerston-north / urban 2016-17 12.125'), 'palmerston-north_urban_2016-17_12-125');
11 | assert.equal(nameImageryTitle('Palmerston.north / urban 2016-17 12.125'), 'palmerston-north_urban_2016-17_12-125');
12 | assert.equal(nameImageryTitle('Manawatū urban 2016-17 12.125m'), 'manawatu_urban_2016-17_12-125m');
13 | assert.equal(nameImageryTitle('ĀāĒēĪīŌōŪū urban 2016-17 12.125m'), 'aaeeiioouu_urban_2016-17_12-125m');
14 | assert.equal(
15 | nameImageryTitle('Marlborough / Wellington 0.75m SNC50451 (2004-2005)'),
16 | 'marlborough_wellington_0-75m_snc50451_2004-2005',
17 | );
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/packages/cli-config/src/bin.ts:
--------------------------------------------------------------------------------
1 | Error.stackTraceLimit = 100;
2 | import { LogConfig } from '@basemaps/shared';
3 | import { run } from 'cmd-ts';
4 |
5 | import { ConfigCli } from './index.js';
6 |
7 | run(ConfigCli, process.argv.slice(2)).catch((err) => {
8 | const logger = LogConfig.get();
9 | logger.fatal({ err }, 'Command:Failed');
10 |
11 | // Give the logger some time to flush before exiting
12 | setTimeout(() => process.exit(1), 25);
13 | });
14 |
--------------------------------------------------------------------------------
/packages/cli-config/src/index.ts:
--------------------------------------------------------------------------------
1 | import { subcommands } from 'cmd-ts';
2 |
3 | import { BundleAssetsCommand } from './cli/action.bundle.assets.js';
4 | import { BundleCommand } from './cli/action.bundle.js';
5 | import { CreateConfigCommand } from './cli/action.create.config.js';
6 | import { ImportCommand } from './cli/action.import.js';
7 |
8 | export const ConfigCli = subcommands({
9 | name: 'config',
10 | cmds: {
11 | bundle: BundleCommand,
12 | 'bundle-assets': BundleAssetsCommand,
13 | import: ImportCommand,
14 | 'create-config': CreateConfigCommand,
15 | },
16 | });
17 |
--------------------------------------------------------------------------------
/packages/cli-config/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 |
4 | "compilerOptions": {
5 | "outDir": "./build",
6 | "rootDir": "./src"
7 | },
8 | "include": ["src"],
9 | "references": [
10 | { "path": "../config/tsconfig.json" },
11 | { "path": "../config-loader/tsconfig.json" },
12 | { "path": "../geo/tsconfig.json" },
13 | { "path": "../linzjs-metrics/tsconfig.json" },
14 | { "path": "../shared/tsconfig.json" }
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/packages/cli-config/typedoc.json:
--------------------------------------------------------------------------------
1 | {
2 | "entryPoints": ["./src/**/*.ts"],
3 | "exclude": ["./**/__tests__/*.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/packages/cli-raster/src/bin.ts:
--------------------------------------------------------------------------------
1 | Error.stackTraceLimit = 100;
2 |
3 | import { Fqdn, fsa, LogConfig } from '@basemaps/shared';
4 | import { run } from 'cmd-ts';
5 |
6 | import { CogifyCli } from './cogify/cli.js';
7 |
8 | // Force Fully qualified domain names to reduce DNS lookups
9 | Fqdn.isForcedFqdn = true;
10 |
11 | // remove the source caching / chunking as it is not needed for cogify, cogify only reads tiffs once so caching the result is not helpful
12 | fsa.middleware = fsa.middleware.filter((f) => f.name !== 'source:chunk');
13 | fsa.middleware = fsa.middleware.filter((f) => f.name !== 'source:cache');
14 |
15 | run(CogifyCli, process.argv.slice(2)).catch((err) => {
16 | const logger = LogConfig.get();
17 | logger.fatal({ err }, 'Command:Failed');
18 |
19 | // Give the logger some time to flush before exiting
20 | setTimeout(() => process.exit(1), 25);
21 | });
22 |
--------------------------------------------------------------------------------
/packages/cli-raster/src/cogify/cli.ts:
--------------------------------------------------------------------------------
1 | import { subcommands } from 'cmd-ts';
2 |
3 | import { BasemapsCogifyCreateCommand } from './cli/cli.cog.js';
4 | import { BasemapsCogifyCoverCommand } from './cli/cli.cover.js';
5 | import { TopoStacCreationCommand } from './cli/cli.topo.js';
6 | import { BasemapsCogifyValidateCommand } from './cli/cli.validate.js';
7 |
8 | export const CogifyCli = subcommands({
9 | name: 'cogify',
10 | cmds: {
11 | cover: BasemapsCogifyCoverCommand,
12 | create: BasemapsCogifyCreateCommand,
13 | validate: BasemapsCogifyValidateCommand,
14 | topo: TopoStacCreationCommand,
15 | },
16 | });
17 |
--------------------------------------------------------------------------------
/packages/cli-raster/src/cogify/cli/cli.validate.ts:
--------------------------------------------------------------------------------
1 | import { getLogger, logArguments, Url } from '@basemaps/shared';
2 | import { CliInfo } from '@basemaps/shared/build/cli/info.js';
3 | import { command, number, option, restPositionals } from 'cmd-ts';
4 | import pLimit from 'p-limit';
5 |
6 | import { validateOutputTiff } from './cli.cog.js';
7 |
8 | export const BasemapsCogifyValidateCommand = command({
9 | name: 'cogify-validate',
10 | version: CliInfo.version,
11 | description: 'Validate a COG is created in a way basemaps likes',
12 | args: {
13 | ...logArguments,
14 | concurrency: option({
15 | type: number,
16 | long: 'concurrency',
17 | description: 'How many COGs to initialise at once',
18 | defaultValue: () => 25,
19 | defaultValueIsSerializable: true,
20 | }),
21 | tiffs: restPositionals({ type: Url, displayName: 'paths', description: 'COG to validate' }),
22 | },
23 |
24 | async handler(args) {
25 | const logger = getLogger(this, args, 'cli-raster');
26 | const q = pLimit(args.concurrency);
27 |
28 | const promises = args.tiffs.map((tiff) => {
29 | return q(() => validateOutputTiff(tiff, undefined, logger));
30 | });
31 |
32 | await Promise.allSettled(promises);
33 | },
34 | });
35 |
--------------------------------------------------------------------------------
/packages/cli-raster/src/cogify/topo/slug.ts:
--------------------------------------------------------------------------------
1 | import { EpsgCode } from '@basemaps/geo';
2 | import { LogType } from '@basemaps/shared';
3 |
4 | const Slugs: Partial> = {
5 | [EpsgCode.Nztm2000]: 'new-zealand-mainland',
6 | [EpsgCode.Citm2000]: 'chatham-islands',
7 | };
8 |
9 | /**
10 | * Attempts to map the given EpsgCode enum to a slug.
11 | *
12 | * @param epsg: The EpsgCode enum to map to a slug
13 | *
14 | * @returns if succeeded, a slug string. Otherwise, null.
15 | */
16 | export function mapEpsgToSlug(epsg: EpsgCode, logger?: LogType): string | null {
17 | const slug = Slugs[epsg];
18 |
19 | logger?.info({ found: slug != null }, 'mapEpsgToSlug()');
20 | return slug ?? null;
21 | }
22 |
--------------------------------------------------------------------------------
/packages/cli-raster/src/index.ts:
--------------------------------------------------------------------------------
1 | export { CogifyCli } from './cogify/cli.js';
2 |
--------------------------------------------------------------------------------
/packages/cli-raster/static/example-covering.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/packages/cli-raster/static/example-covering.png
--------------------------------------------------------------------------------
/packages/cli-raster/static/nztm-tile-index.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/packages/cli-raster/static/nztm-tile-index.png
--------------------------------------------------------------------------------
/packages/cli-raster/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 |
4 | "compilerOptions": {
5 | "outDir": "./build",
6 | "rootDir": "./src"
7 | },
8 | "include": ["src"],
9 | "references": [
10 | { "path": "../config/tsconfig.json" },
11 | { "path": "../geo/tsconfig.json" },
12 | { "path": "../server/tsconfig.json" },
13 | { "path": "../shared/tsconfig.json" },
14 | { "path": "../lambda-tiler/tsconfig.json" },
15 | { "path": "../tiler-sharp/tsconfig.json" }
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/packages/cli-raster/typedoc.json:
--------------------------------------------------------------------------------
1 | {
2 | "entryPoints": ["./src/**/*.ts"],
3 | "exclude": ["./**/__test__/*.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/packages/cli-vector/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | # [8.1.0](https://github.com/linz/basemaps/compare/v8.0.0...v8.1.0) (2025-05-18)
7 |
8 | **Note:** Version bump only for package @basemaps/cli-vector
9 |
10 |
11 |
12 |
13 |
14 | # [8.0.0](https://github.com/linz/basemaps/compare/v7.17.0...v8.0.0) (2025-05-11)
15 |
16 |
17 | ### Features
18 |
19 | * **cli-vector:** Extract cli to load schema json and prepare jobs to process vector mbtiles. BM-1267 ([#3429](https://github.com/linz/basemaps/issues/3429)) ([db113e2](https://github.com/linz/basemaps/commit/db113e27ad935fab4538ffad607c2cd04f52dbdd))
20 | * **cli:** move cogify create-config into cli-config package BM-1261 ([#3432](https://github.com/linz/basemaps/issues/3432)) ([5f72430](https://github.com/linz/basemaps/commit/5f72430690d330e8542d272ede461d3a711493de))
21 |
22 |
23 |
24 |
25 |
26 | # Change Log
27 |
--------------------------------------------------------------------------------
/packages/cli-vector/README.md:
--------------------------------------------------------------------------------
1 | # @basemaps/cli-vector
2 |
3 | CLI to create vector mbtiles for topographic map.
4 |
5 | ## Usage -- Bundle
6 |
7 | Extract and load schema.json config files then prepare tasks for the next step to create mbtiles
8 |
9 | ```bash
10 | node build/bin.js extract --path schema/ --cache s3://linz-basemaps-staging/vector/cache/
11 | ```
12 |
--------------------------------------------------------------------------------
/packages/cli-vector/schema/addresses.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "addresses",
3 | "metadata": { "attributes": ["housenumber", "name", "id"] },
4 | "layers": [
5 | {
6 | "id": "105689",
7 | "name": "105689-nz-addresses-pilot",
8 | "source": "s3://linz-lds-cache/105689/",
9 | "tags": {},
10 | "attributes": { "address_id": "id", "full_address_number": "housenumber" },
11 | "style": { "minZoom": 15, "maxZoom": 15 }
12 | }
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/packages/cli-vector/schema/buildings.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "buildings",
3 | "metadata": { "attributes": ["building", "store_item", "kind", "name", "use"] },
4 | "layers": [
5 | {
6 | "id": "101290",
7 | "name": "101290-nz-building-outlines",
8 | "source": "s3://linz-lds-cache/101290/",
9 | "tags": { "kind": "building" },
10 | "style": { "minZoom": 14, "maxZoom": 15 },
11 | "tippecanoe": ["--detect-shared-borders"]
12 | },
13 | {
14 | "id": "50361",
15 | "name": "50361-nz-tank-polygons-topo-150k",
16 | "source": "s3://linz-lds-cache/50361/",
17 | "tags": { "building": "storage_tank" },
18 | "style": { "minZoom": 12, "maxZoom": 15 }
19 | },
20 | {
21 | "id": "52280",
22 | "name": "52280-cook-islands-tank-polygons-topo-125k-zone4",
23 | "source": "s3://linz-lds-cache/52280/",
24 | "tags": { "building": "storage_tank" },
25 | "style": { "minZoom": 0, "maxZoom": 15 }
26 | }
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------
/packages/cli-vector/schema/dam_lines.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dam_lines",
3 | "metadata": { "attributes": ["kind", "name", "dam_status"] },
4 | "layers": [
5 | {
6 | "id": "50075",
7 | "name": "50075-nz-chatham-island-dam-centrelines-topo-150k",
8 | "source": "s3://linz-lds-cache/50075/",
9 | "tags": { "kind": "dam" },
10 | "style": { "minZoom": 0, "maxZoom": 15 }
11 | },
12 | {
13 | "id": "50260",
14 | "name": "50260-nz-dam-centrelines-topo-150k",
15 | "source": "s3://linz-lds-cache/50260/",
16 | "tags": { "kind": "dam" },
17 | "style": { "minZoom": 12, "maxZoom": 15 }
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/packages/cli-vector/schema/ferries.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ferries",
3 | "metadata": { "attributes": ["kind", "name"] },
4 | "layers": [
5 | {
6 | "id": "50269",
7 | "name": "50269-nz-ferry-crossing-centrelines-topo-150k",
8 | "source": "s3://linz-lds-cache/50269/",
9 | "tags": { "kind": "ferry" },
10 | "style": { "minZoom": 10, "maxZoom": 15 }
11 | }
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/packages/cli-vector/schema/parcel_boundaries.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "parcel_boundaries",
3 | "metadata": { "attributes": ["parcel_intent", "name", "id"] },
4 | "layers": [
5 | {
6 | "id": "50772",
7 | "name": "50772-nz-primary-parcels",
8 | "source": "s3://linz-lds-cache/50772/",
9 | "tags": { "kind": "parcel" },
10 | "style": { "minZoom": 14, "maxZoom": 15, "detail": 14 },
11 | "tippecanoe": ["--detect-shared-borders"]
12 | }
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/packages/cli-vector/schema/pier_lines.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pier_lines",
3 | "metadata": { "attributes": ["kind", "name"] },
4 | "layers": [
5 | {
6 | "id": "50243",
7 | "name": "50243-nz-breakwater-centrelines-topo-150k",
8 | "source": "s3://linz-lds-cache/50243/",
9 | "tags": { "kind": "breakwater" },
10 | "style": { "minZoom": 12, "maxZoom": 15 }
11 | },
12 | {
13 | "id": "50066",
14 | "name": "50066-nz-chatham-island-breakwater-centrelines-topo-150k",
15 | "source": "s3://linz-lds-cache/50066/",
16 | "tags": { "kind": "breakwater" },
17 | "style": { "minZoom": 12, "maxZoom": 15 }
18 | },
19 | {
20 | "id": "52141",
21 | "name": "52141-tokelau-breakwater-centrelines-topo-125k",
22 | "source": "s3://linz-lds-cache/52141/",
23 | "tags": { "kind": "breakwater" },
24 | "style": { "minZoom": 12, "maxZoom": 15 }
25 | },
26 | {
27 | "id": "52234",
28 | "name": "52234-cook-islands-breakwater-centrelines-topo-125k-zone4",
29 | "source": "s3://linz-lds-cache/52234/",
30 | "tags": { "kind": "breakwater" },
31 | "style": { "minZoom": 12, "maxZoom": 15 }
32 | }
33 | ]
34 | }
35 |
--------------------------------------------------------------------------------
/packages/cli-vector/schema/place_labels.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "place_labels",
3 | "metadata": { "attributes": ["water", "name", "natural", "place"] },
4 | "layers": [
5 | {
6 | "id": "51154",
7 | "name": "51154-nzgb-gazetteer-application-labels-wfs-layer",
8 | "source": "s3://linz-lds-cache/51154/",
9 | "tags": { "kind": "place" },
10 | "style": { "minZoom": 0, "maxZoom": 15 }
11 | }
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/packages/cli-vector/schema/street_labels.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "street_labels",
3 | "metadata": { "attributes": ["kind", "ref", "name"] },
4 | "layers": [
5 | {
6 | "id": "50329",
7 | "name": "50329-nz-road-centrelines-topo-150k",
8 | "source": "s3://linz-lds-cache/50329/",
9 | "tags": { "kind": "road" },
10 | "style": { "minZoom": 8, "maxZoom": 15 },
11 | "simplify": [
12 | { "style": { "minZoom": 0, "maxZoom": 0 }, "tolerance": 0.1 },
13 | { "style": { "minZoom": 1, "maxZoom": 1 }, "tolerance": 0.01 },
14 | { "style": { "minZoom": 2, "maxZoom": 2 }, "tolerance": 0.01 },
15 | { "style": { "minZoom": 3, "maxZoom": 3 }, "tolerance": 0.03 },
16 | { "style": { "minZoom": 4, "maxZoom": 4 }, "tolerance": 0.008 },
17 | { "style": { "minZoom": 5, "maxZoom": 5 }, "tolerance": 0.004 },
18 | { "style": { "minZoom": 6, "maxZoom": 6 }, "tolerance": 0.001 },
19 | { "style": { "minZoom": 7, "maxZoom": 7 }, "tolerance": 0.00075 },
20 | { "style": { "minZoom": 8, "maxZoom": 8 }, "tolerance": 0.0005 },
21 | { "style": { "minZoom": 9, "maxZoom": 9 }, "tolerance": 0.00025 },
22 | { "style": { "minZoom": 10, "maxZoom": 10 }, "tolerance": 0.0001 },
23 | { "style": { "minZoom": 11, "maxZoom": 15 } }
24 | ]
25 | }
26 | ]
27 | }
28 |
--------------------------------------------------------------------------------
/packages/cli-vector/src/bin.ts:
--------------------------------------------------------------------------------
1 | Error.stackTraceLimit = 100;
2 | import { LogConfig } from '@basemaps/shared';
3 | import { run } from 'cmd-ts';
4 |
5 | import { VectorCli } from './index.js';
6 |
7 | run(VectorCli, process.argv.slice(2)).catch((err) => {
8 | const logger = LogConfig.get();
9 | logger.fatal({ err }, 'Command:Failed');
10 |
11 | // Give the logger some time to flush before exiting
12 | setTimeout(() => process.exit(1), 25);
13 | });
14 |
--------------------------------------------------------------------------------
/packages/cli-vector/src/index.ts:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line simple-import-sort/imports
2 | import { subcommands } from 'cmd-ts';
3 | import { ExtractCommand } from './cli/cli.extract.js';
4 | import { CreateCommand } from './cli/cli.create.js';
5 | import { JoinCommand } from './cli/cli.join.js';
6 |
7 | export const VectorCli = subcommands({
8 | name: 'vector',
9 | cmds: {
10 | extract: ExtractCommand,
11 | create: CreateCommand,
12 | join: JoinCommand,
13 | },
14 | });
15 |
--------------------------------------------------------------------------------
/packages/cli-vector/src/modify/consts.ts:
--------------------------------------------------------------------------------
1 | export const MajorHighWays: Readonly> = new Set([
2 | '1',
3 | '1B',
4 | '2',
5 | '3',
6 | '3A',
7 | '4',
8 | '5',
9 | '6',
10 | '6A',
11 | '7',
12 | '8',
13 | '8A',
14 | '18',
15 | '20',
16 | '51',
17 | '76',
18 | '73',
19 | '1,3',
20 | '6,94',
21 | '6,96',
22 | ]);
23 |
--------------------------------------------------------------------------------
/packages/cli-vector/src/modify/layers/pois.ts:
--------------------------------------------------------------------------------
1 | import { LogType } from '@basemaps/shared';
2 |
3 | import { VectorGeoFeature } from '../../types/VectorGeoFeature.js';
4 |
5 | /**
6 | * Processes a 'pois' layer feature.
7 | *
8 | * @param feature - the feature to process
9 | * @param options - the layer's options
10 | * @param logger - a logger instance
11 | * @returns the processed feature
12 | */
13 | export function handleLayerPois(feature: VectorGeoFeature, logger: LogType): VectorGeoFeature | null {
14 | logger.trace({}, 'HandlePois:Start');
15 | feature = structuredClone(feature);
16 |
17 | // REVIEW: We don't have any use for this criteria as we don't include the following layers:
18 | // 1. 50245-nz-building-points-topo-150k
19 | // 2. 50246-nz-building-polygons-topo-150k
20 | if (feature.properties['building'] === 'building') {
21 | const bldgUse = feature.properties['bldg_use'];
22 |
23 | if (bldgUse == null) {
24 | // discard the feature
25 | logger.trace({}, 'HandlePois:End');
26 | return null;
27 | }
28 |
29 | feature.properties['building'] = bldgUse;
30 | }
31 |
32 | logger.trace({}, 'HandlePois:End');
33 | return feature;
34 | }
35 |
--------------------------------------------------------------------------------
/packages/cli-vector/src/modify/parser.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod';
2 |
3 | export const zPlaceLabelsProperties = z.object({
4 | /** @example "Kaitaia" */
5 | label: z.string(),
6 |
7 | /** @example "TWN1" */
8 | style: z.string(),
9 |
10 | /** @example "city" */
11 | place: z.string(),
12 |
13 | /** @example 7 */
14 | adminlevel: z.number(),
15 |
16 | /** @example "0" */
17 | natural: z.string(),
18 |
19 | /** @example "0" */
20 | water: z.string(),
21 | });
22 |
23 | export const zPlaceLabelsTippecanoe = z.object({
24 | /** @example "place_labels" */
25 | layer: z.string(),
26 |
27 | /** @example 8 */
28 | minzoom: z.number(),
29 |
30 | /** @example 8 */
31 | maxzoom: z.number(),
32 | });
33 |
34 | export type zTypePlaceLabelsProperties = z.infer;
35 | export type zTypePlaceLabelsTippecanoe = z.infer;
36 |
--------------------------------------------------------------------------------
/packages/cli-vector/src/modify/schema.ts:
--------------------------------------------------------------------------------
1 | import { VectorGeoFeature } from '../types/VectorGeoFeature.js';
2 |
3 | export interface VectorGeoPlaceLabelsFeature extends VectorGeoFeature {
4 | properties: {
5 | /** @example "Kaitaia" */
6 | name: string;
7 |
8 | /** @example "ant" */
9 | kind: string;
10 |
11 | /** @example "city" */
12 | place: string;
13 |
14 | /** @example 7 */
15 | adminlevel: number;
16 |
17 | /** @example "0" */
18 | natural: string;
19 |
20 | /** @example "0" */
21 | water: string;
22 | };
23 | }
24 |
--------------------------------------------------------------------------------
/packages/cli-vector/src/schema-loader/parser.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod';
2 |
3 | export const zStyling = z.object({
4 | minZoom: z.number(),
5 | maxZoom: z.number(),
6 | detail: z.number().optional(),
7 | });
8 |
9 | export const zTags = z.record(z.string().or(z.boolean()));
10 |
11 | export const zAttributes = z.record(z.string());
12 |
13 | export const zSpecialTag = z.object({
14 | condition: z.string(),
15 | tags: zTags,
16 | });
17 |
18 | export const zSimplify = z.object({
19 | style: zStyling,
20 | tolerance: z.number().optional(),
21 | });
22 |
23 | export const zLayer = z.object({
24 | id: z.string(),
25 | name: z.string(),
26 | version: z.number().optional(),
27 | source: z.string(),
28 | tags: zTags,
29 | attributes: zAttributes.optional(),
30 | style: zStyling,
31 | simplify: z.array(zSimplify).optional(),
32 | tippecanoe: z.array(z.string()).optional(),
33 | });
34 |
35 | export const zSchema = z.object({
36 | name: z.string(),
37 | metadata: z.object({
38 | attributes: z.array(z.string()),
39 | }),
40 | simplify: z.array(zSimplify).optional(),
41 | layers: z.array(zLayer),
42 | });
43 |
44 | export type zTypeLayer = z.infer;
45 | export type zTypeSchema = z.infer;
46 |
--------------------------------------------------------------------------------
/packages/cli-vector/src/transform/covt.ts:
--------------------------------------------------------------------------------
1 | import { fsa, LogType, SourceMemory } from '@basemaps/shared';
2 | import { CotarIndexBuilder, CotarIndexOptions, TarReader } from '@cotar/builder';
3 | import { CotarIndex } from '@cotar/core';
4 | import { promises as fs } from 'fs';
5 |
6 | /**
7 | * Create index for the COVT tar file
8 | */
9 | export async function toTarIndex(input: string, output: string, logger: LogType): Promise {
10 | logger.info({ output: output }, 'Cotar.Index:Start');
11 |
12 | const fd = await fs.open(input, 'r');
13 |
14 | const opts: CotarIndexOptions = { packingFactor: 1.25, maxSearch: 50 }; // Default package rule.
15 | const { buffer, count } = await CotarIndexBuilder.create(fd, opts);
16 |
17 | const index = await CotarIndex.create(new SourceMemory('index', buffer));
18 | await TarReader.validate(fd, index);
19 | await fs.writeFile(output, buffer);
20 | await fs.appendFile(input, buffer);
21 |
22 | await fd.close();
23 | if (!(await fsa.exists(fsa.toUrl(output)))) throw new Error('Error - Cotar.Index creation Failure.');
24 |
25 | logger.info({ index, count }, 'Cotar.Index:Done');
26 | return output;
27 | }
28 |
--------------------------------------------------------------------------------
/packages/cli-vector/src/transform/ogr2ogr.ts:
--------------------------------------------------------------------------------
1 | import { Epsg } from '@basemaps/geo';
2 | import { LogType } from '@basemaps/shared';
3 | import { Command } from '@linzjs/docker-command';
4 |
5 | /**
6 | * ogr2ogr GeoJSONSeq usage, return cmd for ogr2ogr
7 | *
8 | * @returns {cmd: string, args: string[]} cmd and arguments for ogr2ogr
9 | */
10 | export async function ogr2ogrNDJson(input: URL, output: URL, logger: LogType): Promise {
11 | const cmd = Command.create('ogr2ogr');
12 |
13 | cmd.args.push('-f', 'GeoJSONSeq');
14 | cmd.args.push(output.pathname);
15 |
16 | cmd.args.push('-t_srs', Epsg.Wgs84.toEpsgString());
17 | cmd.args.push(input.pathname);
18 |
19 | const res = await cmd.run();
20 | if (res.exitCode !== 0) {
21 | logger.fatal({ Gdal: res }, 'Failure');
22 | throw new Error('Gdal failed to run');
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/packages/cli-vector/src/types/VectorGeoFeature.ts:
--------------------------------------------------------------------------------
1 | import { Feature } from 'geojson';
2 |
3 | export interface VectorGeoFeature extends Feature {
4 | properties: Record;
5 | tippecanoe: {
6 | layer: string;
7 | minzoom: number;
8 | maxzoom: number;
9 | };
10 | }
11 |
--------------------------------------------------------------------------------
/packages/cli-vector/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 |
4 | "compilerOptions": {
5 | "outDir": "./build",
6 | "rootDir": "./src"
7 | },
8 | "include": ["src"],
9 | "references": [
10 | { "path": "../shared/tsconfig.json" },
11 | { "path": "../geo/tsconfig.json" },
12 | { "path": "../config/tsconfig.json" }
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/packages/cli-vector/typedoc.json:
--------------------------------------------------------------------------------
1 | {
2 | "entryPoints": ["./src/**/*.ts"],
3 | "exclude": ["./**/__test__/*.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/packages/cli/README.md:
--------------------------------------------------------------------------------
1 | # @basemaps/cli
2 |
3 | This package contains cli's that are mainly used by the configuration and CICD processes in the LINZ Basemaps. All of the cli commands in this package will be build into docker container and publish as a [github container](https://github.com/linz/basemaps/pkgs/container/basemaps%2Fcli)
4 |
5 | ## Install
6 |
7 | This script requires docker to be installed
8 |
9 | To install
10 |
11 | ```bash
12 | npm i @basemaps/cli
13 | ```
14 |
15 | ## Usage -- Config
16 |
17 | Config clis in @basemap/cli-config
18 |
19 | ```bash
20 | ./bin/bmc.js config --help
21 | ```
--------------------------------------------------------------------------------
/packages/cli/__test.assets__/kapiti.geojson:
--------------------------------------------------------------------------------
1 | {
2 | "type": "FeatureCollection",
3 | "name": "kapiti2",
4 | "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
5 | "features": [
6 | { "type": "Feature", "properties": { "name": "Kapiti Island", "macronated": "N", "grp_macron": "N", "TARGET_FID": "4827", "grp_ascii": null, "grp_name": null, "name_ascii": "Kapiti Island" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 174.939296001000116, -40.820378950066505 ], [ 174.951823768000025, -40.826017232066491 ], [ 174.943638325000052, -40.832650322066435 ], [ 174.94016643300003, -40.840112962066449 ], [ 174.933772999000126, -40.849095342066356 ], [ 174.919346271000109, -40.866022574066292 ], [ 174.909681521000039, -40.871987498066268 ], [ 174.903924421999989, -40.87847411406625 ], [ 174.897163602000063, -40.883725928066241 ], [ 174.889816430000138, -40.887456639066237 ], [ 174.882710580000094, -40.889738312066214 ], [ 174.876440507000069, -40.8898498640662 ], [ 174.86980983700002, -40.882956531066256 ], [ 174.879634448000047, -40.870214745066271 ], [ 174.891214816000087, -40.858532232066331 ], [ 174.910775275000105, -40.844398138066403 ], [ 174.92093585300006, -40.827471407066497 ], [ 174.922485574000063, -40.822283591066508 ], [ 174.932190368000079, -40.822727489066523 ], [ 174.936550736000044, -40.820684332066527 ], [ 174.936722733000096, -40.820648581066479 ], [ 174.939296001000116, -40.820378950066505 ] ] ] ] } }
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/packages/cli/__test.assets__/tif1.tiff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/packages/cli/__test.assets__/tif1.tiff
--------------------------------------------------------------------------------
/packages/cli/__test.assets__/tif2.tiff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/packages/cli/__test.assets__/tif2.tiff
--------------------------------------------------------------------------------
/packages/cli/bin/bmc.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | import '../build/cli/bin.js';
4 |
--------------------------------------------------------------------------------
/packages/cli/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@basemaps/cli",
3 | "version": "8.1.0",
4 | "private": false,
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/linz/basemaps.git",
8 | "directory": "packages/cli"
9 | },
10 | "author": {
11 | "name": "Land Information New Zealand",
12 | "url": "https://linz.govt.nz",
13 | "organization": true
14 | },
15 | "license": "MIT",
16 | "main": "./build/index.js",
17 | "types": "./build/index.d.ts",
18 | "bin": {
19 | "bmc": "./bmc.js"
20 | },
21 | "scripts": {
22 | "build": "tsc",
23 | "bundle": "../../scripts/bundle.mjs package.json",
24 | "test": "node --test"
25 | },
26 | "bundle": [
27 | {
28 | "entry": "src/cli/bin.ts",
29 | "minify": false,
30 | "outfile": "dist/index.cjs",
31 | "external": [
32 | "sharp",
33 | "pino-pretty",
34 | "node:sqlite",
35 | "lerc"
36 | ]
37 | }
38 | ],
39 | "type": "module",
40 | "engines": {
41 | "node": ">=16.0.0"
42 | },
43 | "dependencies": {
44 | "@basemaps/cli-config": "^8.1.0",
45 | "@basemaps/cli-raster": "^8.1.0",
46 | "@basemaps/cli-vector": "^8.1.0",
47 | "@basemaps/shared": "^8.1.0",
48 | "cmd-ts": "^0.13.0"
49 | },
50 | "publishConfig": {
51 | "access": "public"
52 | },
53 | "files": [
54 | "build/"
55 | ]
56 | }
57 |
--------------------------------------------------------------------------------
/packages/cli/src/cli/bin.ts:
--------------------------------------------------------------------------------
1 | Error.stackTraceLimit = 100;
2 | import { LogConfig } from '@basemaps/shared';
3 | import { run } from 'cmd-ts';
4 |
5 | import { Cli } from './index.js';
6 |
7 | run(Cli, process.argv.slice(2)).catch((err) => {
8 | const logger = LogConfig.get();
9 | logger.fatal({ err }, 'Command:Failed');
10 |
11 | // Give the logger some time to flush before exiting
12 | setTimeout(() => process.exit(1), 25);
13 | });
14 |
--------------------------------------------------------------------------------
/packages/cli/src/cli/index.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | import { ConfigCli } from '@basemaps/cli-config';
3 | import { CogifyCli } from '@basemaps/cli-raster';
4 | import { VectorCli } from '@basemaps/cli-vector';
5 | import { subcommands } from 'cmd-ts';
6 |
7 | export const Cli = subcommands({
8 | name: 'bmc',
9 | description: 'Basemaps command tools',
10 | cmds: {
11 | config: ConfigCli,
12 | cogify: CogifyCli,
13 | vector: VectorCli,
14 | },
15 | });
16 |
--------------------------------------------------------------------------------
/packages/cli/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 |
4 | "compilerOptions": {
5 | "outDir": "./build",
6 | "rootDir": "./src"
7 | },
8 | "include": ["src"],
9 | "references": [
10 | { "path": "../cli-config/tsconfig.json" },
11 | { "path": "../cli-raster/tsconfig.json" },
12 | { "path": "../cli-vector/tsconfig.json" },
13 | { "path": "../shared/tsconfig.json" }
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/packages/cli/typedoc.json:
--------------------------------------------------------------------------------
1 | {
2 | "entryPoints": ["./src/**/*.ts"],
3 | "exclude": ["./**/__tests__/*.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/packages/config-loader/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@basemaps/config-loader",
3 | "version": "8.1.0",
4 | "repository": {
5 | "type": "git",
6 | "url": "https://github.com/linz/basemaps.git",
7 | "directory": "packages/config-loader"
8 | },
9 | "author": {
10 | "name": "Land Information New Zealand",
11 | "url": "https://linz.govt.nz",
12 | "organization": true
13 | },
14 | "type": "module",
15 | "engines": {
16 | "node": ">=16.0.0"
17 | },
18 | "license": "MIT",
19 | "main": "./build/index.js",
20 | "types": "./build/index.d.ts",
21 | "scripts": {
22 | "test": "node --test"
23 | },
24 | "publishConfig": {
25 | "access": "public"
26 | },
27 | "files": [
28 | "build/"
29 | ],
30 | "dependencies": {
31 | "@basemaps/config": "^8.1.0",
32 | "@basemaps/geo": "^8.0.0",
33 | "@basemaps/shared": "^8.1.0"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/packages/config-loader/src/index.ts:
--------------------------------------------------------------------------------
1 | export { ConfigJson, isEmptyTiff } from './json/json.config.js';
2 | export { ConfigImageryTiff, initConfigFromUrls, initImageryFromTiffUrl } from './json/tiff.config.js';
3 |
--------------------------------------------------------------------------------
/packages/config-loader/src/json/log.ts:
--------------------------------------------------------------------------------
1 | export interface LogFunc {
2 | (msg: string): void;
3 | (obj: Record, msg: string): void;
4 | }
5 |
6 | /**
7 | * Expose log type so functions that do not have direct access to pino have access to the log type
8 | */
9 | export interface LogType {
10 | level: string;
11 | trace: LogFunc;
12 | debug: LogFunc;
13 | info: LogFunc;
14 | warn: LogFunc;
15 | error: LogFunc;
16 | fatal: LogFunc;
17 | child: (obj: Record) => LogType;
18 | }
19 |
--------------------------------------------------------------------------------
/packages/config-loader/src/json/parse.provider.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod';
2 |
3 | const zServiceIdentification = z.object({
4 | title: z.string(),
5 | description: z.string(),
6 | fees: z.string(),
7 | accessConstraints: z.string(),
8 | });
9 |
10 | const zAddress = z.object({
11 | deliveryPoint: z.string(),
12 | city: z.string(),
13 | postalCode: z.string(),
14 | country: z.string(),
15 | email: z.string(),
16 | });
17 |
18 | const zContact = z.object({
19 | individualName: z.string(),
20 | position: z.string(),
21 | phone: z.string(),
22 | address: zAddress,
23 | });
24 |
25 | const zServiceProvider = z.object({
26 | name: z.string(),
27 | site: z.string(),
28 | contact: zContact,
29 | });
30 |
31 | export const zProviderConfig = z.object({
32 | id: z.string(),
33 | serviceIdentification: zServiceIdentification,
34 | serviceProvider: zServiceProvider,
35 | });
36 |
37 | export type ProviderConfigSchema = z.infer;
38 |
--------------------------------------------------------------------------------
/packages/config-loader/src/json/parse.style.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod';
2 |
3 | export const zStyleJson = z.object({
4 | id: z.string(),
5 | version: z.number(),
6 | name: z.string(),
7 | metadata: z.unknown().optional(),
8 | sprite: z.string().optional(),
9 | glyphs: z.string().optional(),
10 | sources: z.unknown(),
11 |
12 | // TODO it would be good to actually validate all the styles
13 | layers: z.array(z.unknown()),
14 | sky: z.unknown(),
15 | });
16 |
17 | export type StyleJsonConfigSchema = z.infer;
18 |
--------------------------------------------------------------------------------
/packages/config-loader/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "outDir": "./build",
5 | "rootDir": "./src"
6 | },
7 | "include": ["src"],
8 | "references": [
9 | { "path": "../__tests__/tsconfig.json" },
10 | { "path": "../config/tsconfig.json" },
11 | { "path": "../shared/tsconfig.json" }
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/packages/config/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@basemaps/config",
3 | "version": "8.1.0",
4 | "repository": {
5 | "type": "git",
6 | "url": "https://github.com/linz/basemaps.git",
7 | "directory": "packages/config"
8 | },
9 | "author": {
10 | "name": "Land Information New Zealand",
11 | "url": "https://linz.govt.nz",
12 | "organization": true
13 | },
14 | "type": "module",
15 | "engines": {
16 | "node": ">=16.0.0"
17 | },
18 | "license": "MIT",
19 | "main": "./build/index.js",
20 | "types": "./build/index.d.ts",
21 | "scripts": {
22 | "test": "node --test"
23 | },
24 | "publishConfig": {
25 | "access": "public"
26 | },
27 | "files": [
28 | "build/"
29 | ],
30 | "dependencies": {
31 | "@basemaps/geo": "^8.0.0",
32 | "base-x": "^4.0.0",
33 | "zod": "^3.17.3"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/packages/config/src/__tests__/prefix.test.ts:
--------------------------------------------------------------------------------
1 | import assert from 'node:assert';
2 | import { describe, it } from 'node:test';
3 |
4 | import { ConfigId } from '../base.config.js';
5 | import { ConfigPrefix } from '../config/prefix.js';
6 |
7 | describe('ConfigPrefix', () => {
8 | it('should prefix values', () => {
9 | assert.equal(ConfigId.prefix(ConfigPrefix.TileSet, '123'), 'ts_123');
10 | assert.equal(ConfigId.prefix(ConfigPrefix.Imagery, '123'), 'im_123');
11 | });
12 |
13 | it('should unprefix values', () => {
14 | assert.equal(ConfigId.unprefix(ConfigPrefix.TileSet, 'ts_123'), '123');
15 | assert.equal(ConfigId.unprefix(ConfigPrefix.Imagery, 'im_123'), '123');
16 | });
17 |
18 | it('should not unprefix unknown values', () => {
19 | assert.equal(ConfigId.unprefix(ConfigPrefix.TileSet, 'im_123'), 'im_123');
20 | assert.equal(ConfigId.unprefix(ConfigPrefix.Imagery, 'ts_123'), 'ts_123');
21 | });
22 |
23 | it('should get prefix values', () => {
24 | assert.equal(ConfigId.getPrefix('ts_123'), ConfigPrefix.TileSet);
25 | assert.equal(ConfigId.getPrefix('im_123'), ConfigPrefix.Imagery);
26 | });
27 |
28 | it('should not return unknown prefixes', () => {
29 | assert.equal(ConfigId.getPrefix('jj_123'), null);
30 | assert.equal(ConfigId.getPrefix('123'), null);
31 | assert.equal(ConfigId.getPrefix('_123'), null);
32 | assert.equal(ConfigId.getPrefix('123_123'), null);
33 | });
34 | });
35 |
--------------------------------------------------------------------------------
/packages/config/src/base58.node.ts:
--------------------------------------------------------------------------------
1 | import { BinaryLike, createHash } from 'crypto';
2 |
3 | import { base58, isBase58 } from './base58.js';
4 |
5 | /** Hash something with sha256 then encode it as a base58 text string */
6 | export function sha256base58(obj: BinaryLike): string {
7 | return base58.encode(createHash('sha256').update(obj).digest());
8 | }
9 |
10 | export function ensureBase58(s: null): null;
11 | export function ensureBase58(s: string): string;
12 | export function ensureBase58(s: string | null): string | null;
13 | export function ensureBase58(s: string | null): string | null {
14 | if (s == null) return null;
15 | if (isBase58(s)) return s;
16 | return base58.encode(Buffer.from(s));
17 | }
18 |
--------------------------------------------------------------------------------
/packages/config/src/base58.ts:
--------------------------------------------------------------------------------
1 | /** This file is able to be directly imported in the web, soo all nodejs logic is in ./base58.node.ts */
2 | import baseX from 'base-x';
3 |
4 | const Base58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
5 | export const base58 = baseX(Base58);
6 |
7 | const Base58ValidCharacters = new Set(Base58);
8 |
9 | export function isBase58(s: string): boolean {
10 | for (let i = 0; i < s.length; i++) {
11 | if (!Base58ValidCharacters.has(s.charAt(i))) return false;
12 | }
13 | return true;
14 | }
15 |
--------------------------------------------------------------------------------
/packages/config/src/color.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Parse a string as hex, return 0 on failure
3 | * @param str string to parse
4 | */
5 | export function parseHex(str: string): number {
6 | if (str === '') return 0;
7 | const val = parseInt(str, 16);
8 | if (isNaN(val)) {
9 | throw new Error('Invalid hex byte: ' + str);
10 | }
11 | return val;
12 | }
13 |
14 | export interface Rgba {
15 | r: number;
16 | g: number;
17 | b: number;
18 | alpha: number;
19 | }
20 |
21 | /**
22 | * Parse a hexstring into RGBA
23 | *
24 | * Defaults to 0 if missing values
25 | * @param str string to parse
26 | */
27 | export function parseRgba(str: string): Rgba {
28 | if (str.startsWith('0x')) str = str.slice(2);
29 | else if (str.startsWith('#')) str = str.slice(1);
30 | if (str.length !== 6 && str.length !== 8) {
31 | throw new Error('Invalid hex color: ' + str);
32 | }
33 | return {
34 | r: parseHex(str.substr(0, 2)),
35 | g: parseHex(str.substr(2, 2)),
36 | b: parseHex(str.substr(4, 2)),
37 | alpha: parseHex(str.substr(6, 2)),
38 | };
39 | }
40 |
--------------------------------------------------------------------------------
/packages/config/src/config/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod';
2 |
3 | import { ConfigId } from '../index.js';
4 |
5 | /**
6 | * Ensure a ID is prefixed with one of the configuration objects
7 | */
8 | export const IdParser = z.string().refine((r) => ConfigId.getPrefix(r) != null);
9 |
10 | /**
11 | * Base interface for all dynamo records
12 | *
13 | * all records should have these values.
14 | */
15 | export const ConfigBase = z.object({
16 | /**
17 | * Primary key of the table
18 | *
19 | * Needs to be prefixed with the type {@link ConfigPrefix}
20 | *
21 | * @example
22 | * - "ts_aerial"
23 | * - "im_ada2b434dede4c64b782c1fd373bb0b9ac"
24 | */
25 | id: IdParser,
26 |
27 | /**
28 | * Slug friendly name for the objects
29 | *
30 | * @example
31 | * - "gebco_2023-305m"
32 | * - "taranaki-2022-2023-0.1m"
33 | */
34 | name: z.string(),
35 |
36 | /**
37 | * Timestamp when this object was last modified
38 | */
39 | updatedAt: z.number().optional(),
40 |
41 | /**
42 | * Was this configuration object generated from another object
43 | *
44 | * @default undefined / false
45 | */
46 | virtual: z.boolean().optional(),
47 | });
48 |
49 | export type ConfigBase = z.infer;
50 |
--------------------------------------------------------------------------------
/packages/config/src/config/config.bundle.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod';
2 |
3 | import { ConfigBase } from './base.js';
4 |
5 | export const ConfigBundleParser = ConfigBase.extend({
6 | /**
7 | * path to the configuration bundle
8 | *
9 | * This should be a full URL
10 | *
11 | * @example
12 | * - "s3://linz-basemaps/config/config-latest.gz"
13 | */
14 | path: z.string(),
15 | /**
16 | * sha256base58 hash of the configuration
17 | *
18 | * {@link sha256base58}
19 | *
20 | * @example
21 | * - "HPV7UAB97VZXMs7iryoPYksxRNEbbBsvroyvTak4vSjt"
22 | */
23 | hash: z.string(),
24 |
25 | /**
26 | * Location to the assets are all the fonts and sprites, this is generally
27 | * a cotar {@link https://github.com/linz/cotar}
28 | *
29 | * @example
30 | * - "s3://linz-basemaps/assets/assets-HPV7UAB97VZXMs7iryoPYksxRNEbbBsvroyvTak4vSjt.tar.co"
31 | */
32 | assets: z.string().optional(),
33 | });
34 |
35 | export type ConfigBundle = z.infer;
36 |
--------------------------------------------------------------------------------
/packages/config/src/config/prefix.ts:
--------------------------------------------------------------------------------
1 | export enum ConfigPrefix {
2 | /** Prefix for imagery {@link ConfigImagery} */
3 | Imagery = 'im',
4 | /** Prefix for tile sets {@link ConfigTileSet} */
5 | TileSet = 'ts',
6 | /** Prefix for provider {@link ConfigProvider} */
7 | Provider = 'pv',
8 | /** Prefix for style {@link ConfigVectorStyle} */
9 | Style = 'st',
10 | /** Configuration bundled into a single file {@link ConfigBundle} */
11 | ConfigBundle = 'cb',
12 | }
13 |
14 | export const ConfigPrefixes: Set = new Set(Object.values(ConfigPrefix));
15 |
--------------------------------------------------------------------------------
/packages/config/src/config/provider.ts:
--------------------------------------------------------------------------------
1 | import { WmtsProvider } from '@basemaps/geo';
2 |
3 | import { ConfigBase } from './base.js';
4 |
5 | export type ConfigProvider = WmtsProvider & ConfigBase;
6 |
--------------------------------------------------------------------------------
/packages/config/src/index.ts:
--------------------------------------------------------------------------------
1 | export {
2 | BaseConfigWriteableObject,
3 | BasemapsConfigObject,
4 | BasemapsConfigProvider,
5 | ConfigId,
6 | getAllImagery,
7 | } from './base.config.js';
8 | export { base58, isBase58 } from './base58.js';
9 | export { ensureBase58, sha256base58 } from './base58.node.js';
10 | export { parseHex, parseRgba, Rgba } from './color.js';
11 | export { ConfigBase as BaseConfig } from './config/base.js';
12 | export { ConfigBundle } from './config/config.bundle.js';
13 | export { ConfigImagery, ConfigImageryOverview, ImageryBandType, ImageryDataType } from './config/imagery.js';
14 | export { ConfigPrefix } from './config/prefix.js';
15 | export { ConfigProvider } from './config/provider.js';
16 | export {
17 | ConfigLayer,
18 | ConfigTileSet,
19 | ConfigTileSetRaster,
20 | ConfigTileSetRasterOutput,
21 | ConfigTileSetVector,
22 | TileResizeKernel,
23 | TileSetType,
24 | } from './config/tile.set.js';
25 | export { DefaultColorRamp, DefaultColorRampOutput, DefaultTerrainRgbOutput } from './config/tile.set.output.js';
26 | export { ConfigTileSetOutputParser } from './config/tile.set.pipeline.js';
27 | export { ConfigVectorStyle, Layer, SourceRaster, Sources, SourceVector, StyleJson } from './config/vector.style.js';
28 | export { ConfigBundled, ConfigProviderMemory } from './memory/memory.config.js';
29 | export { standardizeLayerName } from './name.convertor.js';
30 |
--------------------------------------------------------------------------------
/packages/config/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "outDir": "./build",
5 | "rootDir": "./src"
6 | },
7 | "include": ["src"],
8 | "references": [{ "path": "../__tests__/tsconfig.json" }, { "path": "../geo/tsconfig.json" }]
9 | }
10 |
--------------------------------------------------------------------------------
/packages/config/typedoc.json:
--------------------------------------------------------------------------------
1 | {
2 | "entryPoints": ["./src/**/*.ts"],
3 | "exclude": ["./**/__tests__/*.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/packages/geo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@basemaps/geo",
3 | "version": "8.0.0",
4 | "repository": {
5 | "type": "git",
6 | "url": "https://github.com/linz/basemaps.git",
7 | "directory": "packages/geo"
8 | },
9 | "author": {
10 | "name": "Land Information New Zealand",
11 | "url": "https://linz.govt.nz",
12 | "organization": true
13 | },
14 | "type": "module",
15 | "engines": {
16 | "node": ">=16.0.0"
17 | },
18 | "license": "MIT",
19 | "main": "./build/index.js",
20 | "types": "./build/index.d.ts",
21 | "scripts": {
22 | "test": "node --test"
23 | },
24 | "publishConfig": {
25 | "access": "public"
26 | },
27 | "files": [
28 | "build/"
29 | ],
30 | "devDependencies": {
31 | "@types/geojson": "^7946.0.7",
32 | "@types/proj4": "^2.5.2"
33 | },
34 | "dependencies": {
35 | "@linzjs/geojson": "^8.0.0",
36 | "@linzjs/tile-matrix-set": "^0.0.1",
37 | "proj4": "^2.8.0"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/packages/geo/src/formats.ts:
--------------------------------------------------------------------------------
1 | /** Image formats supported by basemaps */
2 | export type ImageFormat = 'webp' | 'png' | 'jpeg' | 'avif';
3 |
4 | /** Vector tile formats supported by basemaps */
5 | export type VectorFormat = 'pbf';
6 |
7 | /** Supported output formats */
8 | export type OutputFormat = ImageFormat | VectorFormat;
9 |
--------------------------------------------------------------------------------
/packages/geo/src/index.ts:
--------------------------------------------------------------------------------
1 | export { BoundingBox, Bounds, NamedBounds, Point, Size } from './bounds.js';
2 | export { Epsg, EpsgCode } from './epsg.js';
3 | export { ImageFormat, OutputFormat, VectorFormat } from './formats.js';
4 | export * from './proj/projection.js';
5 | export { ProjectionLoader } from './proj/projection.loader.js';
6 | export { TileSetName, TileSetNameValues } from './proj/tile.set.name.js';
7 | export { QuadKey } from './quad.key.js';
8 | export { Simplify } from './simplify.js';
9 | export { LocationSlug as LocationUrl, LonLat, LonLatZoom } from './slug.js';
10 | export * from './stac/index.js';
11 | export { AttributionCollection, AttributionItem, AttributionStac } from './stac/stac.attribution.js';
12 | export { TileId } from './tile.js';
13 | export { TileJson, TileJsonV3, TileJsonVectorLayer } from './tile.json/tile.json.js';
14 | export { Tile, TileMatrixSet } from './tile.matrix.set.js';
15 | export { Citm2000Tms } from './tms/citm2000.js';
16 | export { GoogleTms } from './tms/google.js';
17 | export { TileMatrixSets } from './tms/index.js';
18 | export { Nztm2000QuadTms, Nztm2000Tms } from './tms/nztm2000.js';
19 | export { WmtsProvider } from './wmts/wmts.js';
20 | export { getXyOrder } from './xy.order.js';
21 | export { TileMatrixSetType, TileMatrixType } from '@linzjs/tile-matrix-set';
22 |
--------------------------------------------------------------------------------
/packages/geo/src/proj/citm2000.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Well known text for NZGD2000 / Chatham Islands TM 2000
3 | *
4 | * @see https://epsg.io/3793
5 | */
6 | export const Citm2000 = `PROJCS["NZGD2000 / Chatham Islands TM 2000",
7 | GEOGCS["NZGD2000",
8 | DATUM["New_Zealand_Geodetic_Datum_2000",
9 | SPHEROID["GRS 1980",6378137,298.257222101,
10 | AUTHORITY["EPSG","7019"]],
11 | TOWGS84[0,0,0,0,0,0,0],
12 | AUTHORITY["EPSG","6167"]],
13 | PRIMEM["Greenwich",0,
14 | AUTHORITY["EPSG","8901"]],
15 | UNIT["degree",0.01745329251994328,
16 | AUTHORITY["EPSG","9122"]],
17 | AUTHORITY["EPSG","4167"]],
18 | UNIT["metre",1,
19 | AUTHORITY["EPSG","9001"]],
20 | PROJECTION["Transverse_Mercator"],
21 | PARAMETER["latitude_of_origin",0],
22 | PARAMETER["central_meridian",-176.5],
23 | PARAMETER["scale_factor",1],
24 | PARAMETER["false_easting",3500000],
25 | PARAMETER["false_northing",10000000],
26 | AUTHORITY["EPSG","3793"],
27 | AXIS["Easting",EAST],
28 | AXIS["Northing",NORTH]]`;
29 |
--------------------------------------------------------------------------------
/packages/geo/src/proj/nztm2000.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Well known text for NZGD2000
3 | *
4 | * @see https://epsg.io/2193
5 | */
6 | export const Nztm2000 = `PROJCS["NZGD2000 / New Zealand Transverse Mercator 2000",
7 | GEOGCS["NZGD2000",
8 | DATUM["New_Zealand_Geodetic_Datum_2000",
9 | SPHEROID["GRS 1980",6378137,298.257222101,
10 | AUTHORITY["EPSG","7019"]],
11 | TOWGS84[0,0,0,0,0,0,0],
12 | AUTHORITY["EPSG","6167"]],
13 | PRIMEM["Greenwich",0,
14 | AUTHORITY["EPSG","8901"]],
15 | UNIT["degree",0.0174532925199433,
16 | AUTHORITY["EPSG","9122"]],
17 | AUTHORITY["EPSG","4167"]],
18 | PROJECTION["Transverse_Mercator"],
19 | PARAMETER["latitude_of_origin",0],
20 | PARAMETER["central_meridian",173],
21 | PARAMETER["scale_factor",0.9996],
22 | PARAMETER["false_easting",1600000],
23 | PARAMETER["false_northing",10000000],
24 | UNIT["metre",1,
25 | AUTHORITY["EPSG","9001"]],
26 | AUTHORITY["EPSG","2193"]]`;
27 |
--------------------------------------------------------------------------------
/packages/geo/src/proj/projection.loader.ts:
--------------------------------------------------------------------------------
1 | import { Epsg } from '../epsg.js';
2 | import { Projection } from './projection.js';
3 |
4 | declare const fetch: (r: string) => Promise<{ ok: boolean; text: () => Promise }>;
5 |
6 | export class ProjectionLoader {
7 | // Exposed for testing
8 | static _fetch = fetch;
9 |
10 | /**
11 | * Ensure that a projection EPSG code is avialable for use in Proj4js
12 | *
13 | * If its not already loaded, lookup definition from spatialreference.org
14 | * @param code
15 | */
16 | static async load(code: number): Promise {
17 | if (Projection.tryGet(code) != null) return Epsg.get(code);
18 | const url = `https://spatialreference.org/ref/epsg/${code}/ogcwkt/`;
19 |
20 | const res = await this._fetch(url);
21 | if (!res.ok) throw new Error('Failed to load projection information for:' + code);
22 |
23 | let epsg = Epsg.tryGet(code);
24 | if (epsg == null) epsg = new Epsg(code);
25 |
26 | const text = await res.text();
27 | Projection.define(epsg, text);
28 | return epsg;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/packages/geo/src/proj/tile.set.name.ts:
--------------------------------------------------------------------------------
1 | export enum TileSetName {
2 | aerial = 'aerial',
3 | }
4 |
5 | export function TileSetNameValues(): TileSetName[] {
6 | return [TileSetName.aerial];
7 | }
8 |
--------------------------------------------------------------------------------
/packages/geo/src/tile.ts:
--------------------------------------------------------------------------------
1 | import { Tile } from './tile.matrix.set.js';
2 |
3 | export const TileId = {
4 | /** Create a tile from a tile ID in the format `:z-:x-:y` */
5 | toTile(tileId: string): Tile {
6 | const parts = tileId.split('-');
7 | if (parts.length !== 3) throw new Error('Invalid TileId: ' + tileId);
8 | const tile: Tile = { z: Number(parts[0]), x: Number(parts[1]), y: Number(parts[2]) };
9 | if (isNaN(tile.x) || isNaN(tile.y) || isNaN(tile.z)) throw new Error('Tile is not a number: ' + tileId);
10 | return tile;
11 | },
12 | /** Create a tileID `:z-:x-:y */
13 | fromTile(tile: Tile): string {
14 | return `${tile.z}-${tile.x}-${tile.y}`;
15 | },
16 | };
17 |
--------------------------------------------------------------------------------
/packages/geo/src/tms/nztm2000.ts:
--------------------------------------------------------------------------------
1 | import * as Nztm2000 from '@linzjs/tile-matrix-set';
2 |
3 | import { TileMatrixSet } from '../tile.matrix.set.js';
4 |
5 | export const Nztm2000Tms = new TileMatrixSet(Nztm2000.Nztm2000);
6 | export const Nztm2000QuadTms = new TileMatrixSet(Nztm2000.Nztm2000Quad);
7 |
--------------------------------------------------------------------------------
/packages/geo/src/wmts/wmts.ts:
--------------------------------------------------------------------------------
1 | /** WMTS Provider information */
2 | export interface WmtsProvider {
3 | version: number;
4 | serviceIdentification: {
5 | title: string;
6 | description: string;
7 | fees: string;
8 | accessConstraints: string;
9 | };
10 | serviceProvider: {
11 | name: string;
12 | site: string;
13 | contact: {
14 | individualName: string;
15 | position: string;
16 | phone: string;
17 | address: {
18 | deliveryPoint: string;
19 | city: string;
20 | postalCode: string;
21 | country: string;
22 | email: string;
23 | };
24 | };
25 | };
26 | }
27 |
--------------------------------------------------------------------------------
/packages/geo/src/xy.order.ts:
--------------------------------------------------------------------------------
1 | import { Epsg, EpsgCode } from './epsg.js';
2 |
3 | /**
4 | * Order of X & Y coordinates when defined as a array
5 | *
6 | * `[x,y]` vs `[y,x]`
7 | */
8 | export type XyOrder = 'xy' | 'yx';
9 |
10 | /**
11 | * Get the X & Y coordinate order for a given EPSG
12 | * @param epsg EPSG to lookup
13 | */
14 | export function getXyOrder(epsg: Epsg | EpsgCode): XyOrder {
15 | const code = typeof epsg === 'number' ? epsg : epsg.code;
16 | /**
17 | * - [EPSG:2193](https://www.opengis.net/def/crs/EPSG/0/2193) (NZTM) is defined in [y, x]
18 | * - [EPSG:3793](https://www.opengis.net/def/crs/EPSG/0/3793) (CITM) is defined in [y, x]
19 | * specified by the coordinate system [cs:4500](https://www.opengis.net/def/cs/EPSG/0/4500)
20 | */
21 | if (code === EpsgCode.Nztm2000 || code === EpsgCode.Citm2000) return 'yx';
22 |
23 | // TODO there are other projections that are YX,
24 | // TileMatrixSet v2 specification includes Xy ordering, https://docs.ogc.org/is/17-083r4/21-066r1.html#_adding_optional_orderedaxes_to_highlight_crs_axis_ordering
25 | return 'xy';
26 | }
27 |
--------------------------------------------------------------------------------
/packages/geo/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 |
4 | "compilerOptions": {
5 | "outDir": "./build",
6 | "rootDir": "./src"
7 | },
8 | "include": ["src"],
9 | "references": [{ "path": "../__tests__/tsconfig.json" }, { "path": "../linzjs-geojson/tsconfig.json" }]
10 | }
11 |
--------------------------------------------------------------------------------
/packages/geo/typedoc.json:
--------------------------------------------------------------------------------
1 | {
2 | "entryPoints": ["./src/**/*.ts"],
3 | "exclude": ["./**/__tests__/*.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/packages/lambda-analytic-cloudfront/README.md:
--------------------------------------------------------------------------------
1 | # @basemaps/lambda-analytic-cloudfront
2 |
3 | Generate analytics from CloudFront distribution statistics
4 |
5 | Every hour this lambda function runs and generates a rolled up summary of usage by API Key
6 |
--------------------------------------------------------------------------------
/packages/lambda-analytic-cloudfront/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@basemaps/lambda-analytic-cloudfront",
3 | "version": "8.1.0",
4 | "private": true,
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/linz/basemaps.git",
8 | "directory": "packages/lambda-analytic-cloudfront"
9 | },
10 | "author": {
11 | "name": "Land Information New Zealand",
12 | "url": "https://linz.govt.nz",
13 | "organization": true
14 | },
15 | "type": "module",
16 | "engines": {
17 | "node": ">=16.0.0"
18 | },
19 | "license": "MIT",
20 | "dependencies": {
21 | "@basemaps/config": "^8.1.0",
22 | "@basemaps/geo": "^8.0.0",
23 | "@basemaps/shared": "^8.1.0",
24 | "@elastic/elasticsearch": "^8.16.2",
25 | "@linzjs/lambda": "^4.0.0",
26 | "ua-parser-js": "^1.0.39"
27 | },
28 | "scripts": {
29 | "test": "node --test",
30 | "bundle": "../../scripts/bundle.mjs package.json"
31 | },
32 | "devDependencies": {
33 | "@types/ua-parser-js": "^0.7.36"
34 | },
35 | "bundle": {
36 | "entry": "src/index.ts",
37 | "outdir": "dist/",
38 | "external": [
39 | "pino-pretty"
40 | ]
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/packages/lambda-analytic-cloudfront/src/bin.ts:
--------------------------------------------------------------------------------
1 | import { LogConfig } from '@basemaps/shared';
2 | import { LambdaRequest } from '@linzjs/lambda';
3 | import { Context } from 'aws-lambda';
4 |
5 | import { main } from './handler.js';
6 |
7 | /**
8 | * Manually run the lambda function, this can be helpful for debugging the analytic roll up process
9 | */
10 | main(new LambdaRequest(null, {} as Context, LogConfig.get())).catch((e) => console.error(e));
11 |
--------------------------------------------------------------------------------
/packages/lambda-analytic-cloudfront/src/date.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Create a UTC time date that is rounded down to one hour ago
3 | *
4 | * @example
5 | * 2025-03-17T03:19:33.599Z -> 2025-03-17T02:00:00.000Z
6 | *
7 | * @returns
8 | */
9 | export function getOneHourAgo(): Date {
10 | const maxDate = new Date();
11 | maxDate.setUTCMinutes(0);
12 | maxDate.setUTCSeconds(0);
13 | maxDate.setUTCMilliseconds(0);
14 | maxDate.setUTCHours(maxDate.getUTCHours() - 1);
15 | return maxDate;
16 | }
17 |
18 | export function* byDay(startDate: Date, endDate: Date): Generator {
19 | const currentDate = new Date(startDate);
20 | currentDate.setUTCMinutes(0);
21 | currentDate.setUTCSeconds(0);
22 | currentDate.setUTCMilliseconds(0);
23 | while (true) {
24 | yield currentDate.toISOString().slice(0, 10);
25 | currentDate.setUTCDate(currentDate.getUTCDate() - 1);
26 | if (currentDate.getTime() < endDate.getTime()) break;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/packages/lambda-analytic-cloudfront/src/index.ts:
--------------------------------------------------------------------------------
1 | import { LogConfig } from '@basemaps/shared';
2 | import { lf } from '@linzjs/lambda';
3 |
4 | import { main } from './handler.js';
5 |
6 | export const handler = lf.handler(main, { tracePercent: 0, rejectOnError: true }, LogConfig.get());
7 |
--------------------------------------------------------------------------------
/packages/lambda-analytic-cloudfront/src/log/query.ts:
--------------------------------------------------------------------------------
1 | export interface QueryStringInfo {
2 | api: string;
3 | pipeline?: string;
4 | }
5 | function getQuery(str: string): QueryStringInfo {
6 | const urlSearch = new URLSearchParams(str);
7 | const api = _getApi(urlSearch);
8 | const pipeline = urlSearch.get('pipeline') ?? undefined;
9 | return { api, pipeline };
10 | }
11 |
12 | function _getApi(url: URLSearchParams): string {
13 | const api = url.get('api') ?? '';
14 | // api keys are 27 chars starting with d or c
15 | if (api.length !== 27) return 'invalid';
16 | if (api.startsWith('d')) return api;
17 | if (api.startsWith('c')) return api;
18 | return 'invalid';
19 | }
20 | const QueryMap = new Map();
21 |
22 | export function parseQueryString(str: string): QueryStringInfo {
23 | let existing = QueryMap.get(str);
24 | if (existing == null) {
25 | existing = getQuery(str);
26 | QueryMap.set(str, existing);
27 | }
28 | // This can get very very large so periodically clear it
29 | if (QueryMap.size > 5_000_000) QueryMap.clear();
30 | return existing;
31 | }
32 |
--------------------------------------------------------------------------------
/packages/lambda-analytic-cloudfront/src/log/referer.ts:
--------------------------------------------------------------------------------
1 | const hostCache = new Map();
2 |
3 | export function getUrlHost(ref: string): string {
4 | let existing = hostCache.get(ref);
5 | if (existing == null) {
6 | existing = _getUrlHost(ref);
7 | hostCache.set(ref, existing);
8 | }
9 | return existing;
10 | }
11 | /** Extract the hostname from a url */
12 | export function _getUrlHost(ref: string): string {
13 | if (ref == null) return 'unknown';
14 | if (ref === '-') return 'unknown';
15 |
16 | try {
17 | const { hostname } = new URL(ref);
18 | if (hostname == null) return ref;
19 | if (hostname.startsWith('www.')) return hostname.slice(4);
20 | return hostname;
21 | } catch (e) {
22 | if (!ref.startsWith('http')) return _getUrlHost('https://' + ref);
23 | // Ignore invalid referer hostname
24 | // eslint-disable-next-line no-console
25 | console.log(ref);
26 | }
27 | return 'unknown';
28 | }
29 |
--------------------------------------------------------------------------------
/packages/lambda-analytic-cloudfront/src/useragent/agent.ts:
--------------------------------------------------------------------------------
1 | import { Gis } from './agents/gis.js';
2 | import { Bot, Programming } from './agents/programming.js';
3 | import { UserAgentParsers } from './parser.js';
4 |
5 | export const UaParser = new UserAgentParsers();
6 |
7 | Object.entries(Programming).forEach(([key, create]) => UaParser.addParser(key, create));
8 | Object.entries(Gis).forEach(([key, create]) => UaParser.addParser(key, create));
9 | Object.entries(Bot).forEach(([key, create]) => UaParser.addParser(key, create));
10 |
--------------------------------------------------------------------------------
/packages/lambda-analytic-cloudfront/src/useragent/parser.types.ts:
--------------------------------------------------------------------------------
1 | export type UserAgentParser = (ua: string) => UserAgentInfo | undefined;
2 | export interface UserAgentInfo {
3 | name: string;
4 | variant?: string;
5 | version?: string;
6 | os?: UserAgentOs;
7 | }
8 |
9 | export type UserAgentOs = 'windows' | 'macos' | 'ios' | 'android' | 'linux' | 'unknown';
10 | export const ValidOs = new Set(['windows', 'macos', 'ios', 'android', 'linux']);
11 |
12 | export function isValidOs(os: string): os is UserAgentOs {
13 | return ValidOs.has(os);
14 | }
15 |
--------------------------------------------------------------------------------
/packages/lambda-analytic-cloudfront/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 |
4 | "compilerOptions": {
5 | "outDir": "./build",
6 | "rootDir": "./src"
7 | },
8 | "include": ["src"],
9 | "references": [{ "path": "../config" }, { "path": "../geo" }, { "path": "../shared" }]
10 | }
11 |
--------------------------------------------------------------------------------
/packages/lambda-analytic-cloudfront/typedoc.json:
--------------------------------------------------------------------------------
1 | {
2 | "entryPoints": ["./src/**/*.ts"],
3 | "exclude": ["./**/__tests__/*.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/packages/lambda-analytics/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@basemaps/lambda-analytics",
3 | "version": "8.1.0",
4 | "private": true,
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/linz/basemaps.git",
8 | "directory": "packages/lambda-analytics"
9 | },
10 | "author": {
11 | "name": "Land Information New Zealand",
12 | "url": "https://linz.govt.nz",
13 | "organization": true
14 | },
15 | "type": "module",
16 | "engines": {
17 | "node": ">=16.0.0"
18 | },
19 | "license": "MIT",
20 | "dependencies": {
21 | "@basemaps/config": "^8.1.0",
22 | "@basemaps/geo": "^8.0.0",
23 | "@basemaps/shared": "^8.1.0",
24 | "ua-parser-js": "^1.0.2"
25 | },
26 | "scripts": {
27 | "test": "node --test",
28 | "bundle": "../../scripts/bundle.mjs package.json"
29 | },
30 | "devDependencies": {
31 | "@types/ua-parser-js": "^0.7.36"
32 | },
33 | "bundle": {
34 | "entry": "src/index.ts",
35 | "outdir": "dist/",
36 | "external": [
37 | "pino-pretty"
38 | ]
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/packages/lambda-analytics/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 |
4 | "compilerOptions": {
5 | "outDir": "./build",
6 | "rootDir": "./src"
7 | },
8 | "include": ["src"],
9 | "references": [{ "path": "../config" }, { "path": "../geo" }, { "path": "../shared" }]
10 | }
11 |
--------------------------------------------------------------------------------
/packages/lambda-analytics/typedoc.json:
--------------------------------------------------------------------------------
1 | {
2 | "entryPoints": ["./src/**/*.ts"],
3 | "exclude": ["./**/__tests__/*.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/packages/lambda-tiler/bundle.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Create a deployment bundle with sharp/libvips prebuilt included
4 | #
5 | ../../scripts/bundle.mjs package.json
6 | cd dist
7 | ../scripts/create.deployment.package.mjs
8 | # Make the new package a commonjs module
9 | cp -r ../static .
10 | # @see https://sharp.pixelplumbing.com/en/stable/install/#aws-lambda
11 | npm install --cpu=arm64 --arch=arm64 --platform=linux --omit=dev
12 |
--------------------------------------------------------------------------------
/packages/lambda-tiler/scripts/create.deployment.package.mjs:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /**
3 | * Create a package.json for the `dist` bundle based off the parent package.json
4 | *
5 | * This is needed as libsharp has to be "installed" into the dist node_modules so that lambda has access to sharp
6 | */
7 | import * as fs from 'fs';
8 |
9 | const parentPackage = JSON.parse(fs.readFileSync('../package.json').toString());
10 |
11 | // Find the exact version of a package in the package-lock lock
12 | export function getPackageVersion(packageName) {
13 | const parentLock = JSON.parse(fs.readFileSync('../../../package-lock.json').toString());
14 | return parentLock.packages['node_modules/' + packageName].version;
15 | }
16 |
17 | // the bundle is a commonjs module
18 | parentPackage.type = 'commonjs';
19 | parentPackage.main = 'index.js';
20 | parentPackage.dependencies = { sharp: getPackageVersion('sharp'), lerc: getPackageVersion('lerc') };
21 |
22 | // Clean up
23 | delete parentPackage.types;
24 | delete parentPackage.devDependencies;
25 |
26 | console.log('Installing dependencies', parentPackage.dependencies);
27 | fs.writeFileSync('./package.json', JSON.stringify(parentPackage, null, 2));
28 |
--------------------------------------------------------------------------------
/packages/lambda-tiler/src/routes/__tests__/memory.fs.ts:
--------------------------------------------------------------------------------
1 | import { Readable } from 'stream';
2 |
3 | export async function toBuffer(stream: Readable): Promise {
4 | return new Promise((resolve, reject) => {
5 | const buf: Buffer[] = [];
6 |
7 | stream.on('data', (chunk: Buffer) => buf.push(chunk));
8 | stream.on('end', () => resolve(Buffer.concat(buf)));
9 | stream.on('error', (err) => reject(`error converting stream - ${String(err)}`));
10 | });
11 | }
12 | export function toReadable(r: string | Buffer | Readable): Readable {
13 | if (typeof r === 'string') r = Buffer.from(r);
14 | return Readable.from(r);
15 | }
16 |
--------------------------------------------------------------------------------
/packages/lambda-tiler/src/routes/fonts.ts:
--------------------------------------------------------------------------------
1 | import { LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
2 |
3 | import { assetProvider } from '../util/assets.provider.js';
4 |
5 | interface FontGet {
6 | Params: { fontStack: string; range: string };
7 | }
8 |
9 | export async function fontGet(req: LambdaHttpRequest): Promise {
10 | const targetFile = `fonts/${req.params.fontStack}/${req.params.range}.pbf`;
11 | return assetProvider.serve(req, targetFile, 'application/x-protobuf');
12 | }
13 |
14 | export async function fontList(req: LambdaHttpRequest): Promise {
15 | return assetProvider.serve(req, 'fonts/fonts.json', 'application/json');
16 | }
17 |
--------------------------------------------------------------------------------
/packages/lambda-tiler/src/routes/ping.ts:
--------------------------------------------------------------------------------
1 | import { HttpHeader, LambdaHttpResponse } from '@linzjs/lambda';
2 |
3 | const OkResponse = new LambdaHttpResponse(200, 'ok');
4 | OkResponse.header(HttpHeader.CacheControl, 'no-store');
5 |
6 | export function pingGet(): Promise {
7 | return Promise.resolve(OkResponse);
8 | }
9 |
--------------------------------------------------------------------------------
/packages/lambda-tiler/src/routes/sprites.ts:
--------------------------------------------------------------------------------
1 | import { LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
2 | import path from 'path';
3 |
4 | import { assetProvider } from '../util/assets.provider.js';
5 | import { NotFound } from '../util/response.js';
6 |
7 | interface SpriteGet {
8 | Params: {
9 | spriteName: string;
10 | };
11 | }
12 |
13 | const Extensions = new Map();
14 | Extensions.set('.png', 'image/png');
15 | Extensions.set('.json', 'application/json');
16 |
17 | export async function spriteGet(req: LambdaHttpRequest): Promise {
18 | const extension = path.extname(req.params.spriteName);
19 | const mimeType = Extensions.get(extension);
20 | if (mimeType == null) return NotFound();
21 |
22 | return assetProvider.serve(req, `sprites/${req.params.spriteName}`, mimeType);
23 | }
24 |
--------------------------------------------------------------------------------
/packages/lambda-tiler/src/util/__test__/cache.test.ts:
--------------------------------------------------------------------------------
1 | import assert from 'node:assert';
2 | import { describe, it } from 'node:test';
3 |
4 | import { fsa, FsMemory } from '@chunkd/fs';
5 |
6 | import { SourceCache } from '../source.cache.js';
7 |
8 | describe('CoSourceCache', () => {
9 | it('should not exit if a promise rejection happens for tiff', async () => {
10 | const cache = new SourceCache(5);
11 |
12 | const mem = new FsMemory();
13 | const tiffLoc = new URL('memory://foo/bar.tiff');
14 | await mem.write(tiffLoc, Buffer.from('ABC123'));
15 | fsa.register('memory://', mem);
16 |
17 | let failCount = 0;
18 | await cache.getCog(tiffLoc).catch(() => failCount++);
19 | assert.equal(cache.cache.currentSize, 0);
20 | assert.equal(failCount, 1);
21 | });
22 |
23 | it('should not exit if a promise rejection happens for tar', async () => {
24 | const cache = new SourceCache(5);
25 |
26 | const mem = new FsMemory();
27 | const tiffLoc = new URL('memory://foo/bar.tar');
28 | await mem.write(tiffLoc, Buffer.from('ABC123'));
29 | fsa.register('memory://', mem);
30 |
31 | let failCount = 0;
32 | await cache.getCotar(tiffLoc).catch(() => failCount++);
33 | assert.equal(cache.cache.currentSize, 0);
34 | assert.equal(failCount, 1);
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/packages/lambda-tiler/src/util/etag.ts:
--------------------------------------------------------------------------------
1 | import { sha256base58 } from '@basemaps/config';
2 | import { HttpHeader, LambdaHttpRequest } from '@linzjs/lambda';
3 |
4 | export const Etag = {
5 | key(obj: unknown): string {
6 | if (Buffer.isBuffer(obj) || typeof obj === 'string') return sha256base58(obj);
7 | return sha256base58(JSON.stringify(obj));
8 | },
9 |
10 | isNotModified(req: LambdaHttpRequest, cacheKey: string): boolean {
11 | // If the user has supplied a IfNoneMatch Header and it contains the full sha256 sum for our
12 | // etag this tile has not been modified.
13 | const ifNoneMatch = req.header(HttpHeader.IfNoneMatch);
14 | if (ifNoneMatch != null && ifNoneMatch.indexOf(cacheKey) > -1) {
15 | req.set('cache', { hit: true, match: ifNoneMatch });
16 | return true;
17 | }
18 | return false;
19 | },
20 | };
21 |
--------------------------------------------------------------------------------
/packages/lambda-tiler/src/util/response.ts:
--------------------------------------------------------------------------------
1 | import { LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
2 |
3 | export const NotFound = (msg: string = 'Not Found'): LambdaHttpResponse => new LambdaHttpResponse(404, msg);
4 | export const NotModified = (): LambdaHttpResponse => new LambdaHttpResponse(304, 'Not modified');
5 | export const NoContent = (): LambdaHttpResponse => new LambdaHttpResponse(204, 'No Content');
6 | export const OkResponse = (req: LambdaHttpRequest): LambdaHttpResponse =>
7 | new LambdaHttpResponse(200, 'ok').json({ id: req.id, correlationId: req.correlationId, message: 'ok' });
8 |
--------------------------------------------------------------------------------
/packages/lambda-tiler/static/expected_tile_2193_153_255_z7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/packages/lambda-tiler/static/expected_tile_2193_153_255_z7.png
--------------------------------------------------------------------------------
/packages/lambda-tiler/static/expected_tile_NZTM2000Quad_30_33_z6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/packages/lambda-tiler/static/expected_tile_NZTM2000Quad_30_33_z6.png
--------------------------------------------------------------------------------
/packages/lambda-tiler/static/expected_tile_WebMercatorQuad_252_156_z8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/packages/lambda-tiler/static/expected_tile_WebMercatorQuad_252_156_z8.png
--------------------------------------------------------------------------------
/packages/lambda-tiler/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "outDir": "./build",
5 | "rootDir": "./src"
6 | },
7 | "include": ["src"],
8 | "references": [
9 | { "path": "../config/tsconfig.json" },
10 | { "path": "../config-loader/tsconfig.json" },
11 | { "path": "../shared/tsconfig.json" },
12 | { "path": "../geo/tsconfig.json" },
13 | { "path": "../tiler/tsconfig.json" },
14 | { "path": "../tiler-sharp/tsconfig.json" },
15 | { "path": "../attribution/tsconfig.json" }
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/packages/lambda-tiler/typedoc.json:
--------------------------------------------------------------------------------
1 | {
2 | "entryPoints": ["./src/**/*.ts"],
3 | "exclude": ["./**/__tests__/*.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/packages/landing/README.md:
--------------------------------------------------------------------------------
1 | # @basemaps/landing
2 |
3 | The landing page for basemaps https://basemaps.linz.govt.nz
4 |
5 | ## Development
6 |
7 | To start a local test server there are two options
8 |
9 | ### Create a full basemaps server
10 |
11 | Using [@basemaps/server](../server/README.md) a entire local test environment can be run. to ensure the latest assets are served by the local server `npm run bundle` should be run first
12 |
13 | this is best when testing larger basemaps changes across multiple packages, but needs access to some imagery.
14 |
15 | ### Simple local server
16 |
17 | The simple local server is used to validate html/css/js changes in the landing page this does not run a basemaps tile server and will default to `https://dev.basemaps.linz.govt.nz`
18 |
19 | ```bash
20 | npm run bundle
21 | node serve.mjs
22 | ```
23 |
--------------------------------------------------------------------------------
/packages/landing/serve.mjs:
--------------------------------------------------------------------------------
1 | import fs from 'node:fs';
2 | import http from 'node:http';
3 | import path from 'node:path';
4 |
5 | import mime from 'mime-types';
6 |
7 | /**
8 | * Very basic http server that redirects all 404's back to index.html
9 | * as basemaps uses `/@location` for its main page these `/@*` has to be served with `index.html`
10 | */
11 | const srv = http.createServer(function (request, response) {
12 | const target = path.join('dist', request.url);
13 | const stat = fs.existsSync(target);
14 | if (!request.url.endsWith('/') && stat) {
15 | const type = mime.lookup(target);
16 | response.statusCode = 200;
17 | response.setHeader('content-type', type);
18 |
19 | fs.createReadStream(target, {
20 | bufferSize: 4 * 1024,
21 | }).pipe(response);
22 | console.log(new Date().toISOString(), 200, type, request.url);
23 | return;
24 | }
25 |
26 | response.statusCode = 200;
27 | fs.createReadStream('dist/index.html', {
28 | bufferSize: 4 * 1024,
29 | }).pipe(response);
30 | });
31 |
32 | const port = process.env.PORT ? Number(process.env.PORT) : 5000;
33 | srv.listen(port, () => {
34 | process.stdout.write(`listening.. http://localhost:${port}\n`);
35 | });
36 |
--------------------------------------------------------------------------------
/packages/landing/src/__tests__/NZTMTileLocation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/packages/landing/src/__tests__/NZTMTileLocation.png
--------------------------------------------------------------------------------
/packages/landing/src/__tests__/config.debug.test.ts:
--------------------------------------------------------------------------------
1 | import assert from 'node:assert';
2 | import { describe, it } from 'node:test';
3 |
4 | import { ConfigDebug, DebugDefaults, DebugState } from '../config.debug.js';
5 |
6 | function urlToString(o: Partial): string {
7 | const url = new URLSearchParams();
8 | ConfigDebug.toUrl(o as DebugState, url);
9 | return url.toString();
10 | }
11 |
12 | describe('ConfigDebug', () => {
13 | it('should only serialize when not defaults', () => {
14 | assert.equal(urlToString(DebugDefaults), '');
15 | });
16 |
17 | it('should write to url', () => {
18 | assert.equal(urlToString({ debug: true }), 'debug=true');
19 | assert.equal(urlToString({ debug: false }), '');
20 | assert.equal(urlToString({ debug: true, 'debug.background': 'magenta' }), 'debug=true&debug.background=magenta');
21 | });
22 |
23 | it('should round trip', () => {
24 | const cfg = { ...DebugDefaults };
25 | cfg.debug = true;
26 | cfg['debug.background'] = 'magenta';
27 | cfg['debug.layer.linz-topographic'] = 0.5;
28 | cfg['debug.layer.linz-aerial'] = -1;
29 |
30 | const url = urlToString(cfg);
31 | const newCfg = { ...DebugDefaults };
32 | ConfigDebug.fromUrl(newCfg, new URLSearchParams(`?${url}`));
33 | assert.deepEqual(newCfg, cfg);
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/packages/landing/src/__tests__/config.test.ts:
--------------------------------------------------------------------------------
1 | import assert from 'node:assert';
2 | import { describe, it } from 'node:test';
3 |
4 | import { Config } from '../config.js';
5 |
6 | describe('Config', () => {
7 | it('should return the same api key', () => {
8 | const keyA = Config.ApiKey;
9 | assert.equal(keyA, Config.ApiKey);
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/packages/landing/src/components/link.tsx:
--------------------------------------------------------------------------------
1 | import { Component, ReactNode } from 'react';
2 |
3 | interface IconProps {
4 | name: string;
5 | }
6 | export class Icon extends Component {
7 | override render(): ReactNode {
8 | return {this.props.name};
9 | }
10 | }
11 |
12 | interface LinkProps {
13 | href: string;
14 | icon?: string;
15 | ariaLabel?: string;
16 | children: ReactNode[] | ReactNode;
17 | }
18 | export class Link extends Component {
19 | override render(): ReactNode {
20 | return (
21 |
28 | {this.props.children}
29 | {this.props.icon ? : undefined}
30 |
31 | );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/packages/landing/src/global.ts:
--------------------------------------------------------------------------------
1 | export {};
2 |
3 | declare global {
4 | interface Window {
5 | // Google analytics
6 | dataLayer: unknown[];
7 | gtag(...args: unknown[]): void;
8 |
9 | // Expose for testing
10 | MaplibreMap?: maplibregl.Map;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/packages/landing/src/index.tsx:
--------------------------------------------------------------------------------
1 | import { Component, Fragment, ReactNode } from 'react';
2 | import { createRoot } from 'react-dom/client';
3 |
4 | import { Footer } from './components/layout.footer.js';
5 | import { Header } from './components/layout.header.js';
6 | import { Basemaps } from './components/map.js';
7 | import { NewFeature } from './components/new-features/3d.map.js';
8 | import { Config } from './config.js';
9 | import { WindowUrl } from './url.js';
10 | import { isWebpSupported } from './webp.js';
11 |
12 | class Page extends Component {
13 | override render(): ReactNode {
14 | return (
15 |
16 |
17 |
18 |
19 |
20 |
21 | );
22 | }
23 | }
24 |
25 | document.addEventListener('DOMContentLoaded', () => {
26 | void isWebpSupported().then(() => {
27 | WindowUrl.ImageFormat = 'webp';
28 | Config.map.updateFromUrl();
29 |
30 | const mainEl = document.getElementById('main');
31 | if (mainEl == null) throw new Error('Missing #main');
32 | const root = createRoot(mainEl);
33 | root.render();
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/packages/landing/src/webp.ts:
--------------------------------------------------------------------------------
1 | const WebpImage = `data:image/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoBAAEAAwA0JaQAA3AA/vuUAAA=`;
2 |
3 | // Source https://stackoverflow.com/questions/5573096/detecting-webp-support
4 | function isCanvasWebpSupported(): boolean {
5 | const elem = document.createElement('canvas');
6 |
7 | if (!!(elem.getContext && elem.getContext('2d'))) {
8 | // was able or not to get WebP representation
9 | return elem.toDataURL('image/webp').indexOf('data:image/webp') === 0;
10 | }
11 |
12 | // very old browser like IE 8, canvas not supported
13 | return false;
14 | }
15 |
16 | /**
17 | * Is this runtime able to support webp
18 | */
19 | function isWebpImageSupported(): Promise {
20 | // Some browsers (firefox) support rendering webp but not creating with canvas
21 | const img = new Image();
22 | const promise = new Promise((resolve) => {
23 | img.onload = (): void => resolve(true);
24 | img.onerror = (): void => resolve(false);
25 | });
26 | img.src = WebpImage;
27 | return promise;
28 | }
29 |
30 | /** Is WebP able to be rendered in this environment */
31 | export function isWebpSupported(): Promise {
32 | return new Promise((resolve) => {
33 | if (isCanvasWebpSupported()) return resolve(true);
34 | isWebpImageSupported()
35 | .then(resolve)
36 | .catch(() => resolve(false));
37 | });
38 | }
39 |
--------------------------------------------------------------------------------
/packages/landing/static/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/packages/landing/static/android-chrome-192x192.png
--------------------------------------------------------------------------------
/packages/landing/static/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/packages/landing/static/android-chrome-512x512.png
--------------------------------------------------------------------------------
/packages/landing/static/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/packages/landing/static/apple-touch-icon.png
--------------------------------------------------------------------------------
/packages/landing/static/basemaps-card.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/packages/landing/static/basemaps-card.jpeg
--------------------------------------------------------------------------------
/packages/landing/static/examples/index.leaflet.xyz.3857.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Leaflet WGS84 Basemaps Demo
6 |
10 |
11 |
18 |
19 |
20 |
21 |
22 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/packages/landing/static/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/packages/landing/static/favicon-16x16.png
--------------------------------------------------------------------------------
/packages/landing/static/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/packages/landing/static/favicon-32x32.png
--------------------------------------------------------------------------------
/packages/landing/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linz/basemaps/8cbef0b0a9ef3db804d05b533b6858f55c9064c9/packages/landing/static/favicon.ico
--------------------------------------------------------------------------------
/packages/landing/static/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | $CSS_FILE
15 |
16 | Basemaps | Land Information New Zealand (LINZ)
17 |
18 |
19 |
20 |
21 | $JS_FILE
22 |
23 |
24 |
--------------------------------------------------------------------------------
/packages/landing/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "checkJs": true,
5 | "jsx": "react-jsx",
6 | "rootDir": ".",
7 | "outDir": "./build",
8 | "lib": ["DOM"]
9 | },
10 | "include": ["scripts", "src"],
11 | "references": [
12 | { "path": "../cli-config/tsconfig.json" },
13 | { "path": "../config/tsconfig.json" },
14 | { "path": "../geo/tsconfig.json" },
15 | { "path": "../shared/tsconfig.json" }
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/packages/landing/typedoc.json:
--------------------------------------------------------------------------------
1 | {
2 | "entryPoints": ["./src/**/*.ts"],
3 | "exclude": ["./**/__tests__/*.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/packages/linzjs-docker-command/README.md:
--------------------------------------------------------------------------------
1 | ## @linzjs/docker-command
2 |
3 | Run a command in either docker or on you local system
4 |
5 | ```typescript
6 | import { Command } from '@linzjs/docker-command';
7 |
8 | const cmd = new Command('echo', { container: 'ubuntu', tag: 'latest' });
9 |
10 | // Spawn a docker container and run `echo hello world`
11 | await cmd.create().arg('Hello World').run(); // {stdout: "Hello World\n"}
12 | // Spawn a echo process and run `echo hello world`
13 | await cmd.create({ useDocker: false }).arg('Hello World').run(); // {stdout: "Hello World\n"}
14 | ```
15 |
16 | ## Mounting folders in docker
17 |
18 | folders can be mounted into the docker container volumes with `.mount`
19 |
20 | `.mount(path)` will create a single `--volume path:path`
21 |
22 | ```typescript
23 | import { Command } from '@linzjs/docker-command';
24 |
25 | const proc = await Command.create('ls', { container: 'ubuntu' });
26 | proc.mount('/home/blacha');
27 | proc.arg('/home/blacha');
28 |
29 | await proc.run(); // ls results for local /home/blacha
30 | ```
31 |
32 | ## Passing environment variables
33 |
34 | ```typescript
35 | import { Command } from '@linzjs/docker-command';
36 |
37 | const proc = await Command.create('env', { container: 'ubuntu' });
38 | proc.env('AWS_ACCESS_KEY_ID'); // Load process.env.AWS_ACCESS_KEY_ID into docker
39 | proc.env('AWS_ACCESS_KEY_ID', 'fakeKey'); // set a specific AWS_ACCESS_KEY_ID into docker
40 | ```
41 |
--------------------------------------------------------------------------------
/packages/linzjs-docker-command/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@linzjs/docker-command",
3 | "version": "8.0.0",
4 | "repository": {
5 | "type": "git",
6 | "url": "https://github.com/linz/basemaps.git",
7 | "directory": "packages/docker-command"
8 | },
9 | "author": {
10 | "name": "Land Information New Zealand",
11 | "url": "https://linz.govt.nz",
12 | "organization": true
13 | },
14 | "type": "module",
15 | "engines": {
16 | "node": ">=16.0.0"
17 | },
18 | "license": "MIT",
19 | "main": "./build/index.js",
20 | "types": "./build/index.d.ts",
21 | "scripts": {
22 | "test": "node --test"
23 | },
24 | "publishConfig": {
25 | "access": "public"
26 | },
27 | "files": [
28 | "build/"
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/packages/linzjs-docker-command/src/__tests__/example.ts:
--------------------------------------------------------------------------------
1 | import { Command } from '../command.js';
2 |
3 | const echo = new Command('echo', { container: 'ubuntu' });
4 |
5 | async function main(): Promise {
6 | const res = await echo.create().arg('Hello world').run();
7 | console.log(res.command.toCommand(), { duration: res.duration });
8 |
9 | const resLocal = await echo.create({ useDocker: false }).arg('Hello world').run();
10 | console.log(resLocal.command.toCommand(), { duration: resLocal.duration });
11 | }
12 |
13 | main().catch((e) => console.log(e));
14 |
--------------------------------------------------------------------------------
/packages/linzjs-docker-command/src/command.ts:
--------------------------------------------------------------------------------
1 | import { CommandExecution, CommandExecutionOptions } from './command.execution.js';
2 |
3 | export interface CommandOptions {
4 | container: string;
5 | tag?: string;
6 | }
7 | export class Command {
8 | executable: string;
9 |
10 | container?: string;
11 | containerTag?: string;
12 |
13 | useDocker = true;
14 |
15 | static Docker = new Command('docker');
16 |
17 | constructor(executable: string, opts?: CommandOptions) {
18 | this.executable = executable;
19 | if (opts) {
20 | this.container = opts.container;
21 | this.containerTag = opts.tag;
22 | }
23 | if (this.container == null) this.useDocker = false;
24 | }
25 |
26 | static create(cmd: string, opts?: CommandOptions): CommandExecution {
27 | return new Command(cmd, opts).create();
28 | }
29 |
30 | get containerName(): string {
31 | if (this.container == null) throw new Error(`No container specified for command "${this.executable}"`);
32 | if (this.containerTag == null) return this.container;
33 | return `${this.container}:${this.containerTag}`;
34 | }
35 |
36 | create(opts?: CommandExecutionOptions): CommandExecution {
37 | return new CommandExecution(this, opts);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/packages/linzjs-docker-command/src/execution/__tests__/execute.local.test.ts:
--------------------------------------------------------------------------------
1 | import assert from 'node:assert';
2 | import { describe, it } from 'node:test';
3 |
4 | import { Command } from '../../command.js';
5 |
6 | describe('LocalExecution', () => {
7 | it('should run hello world', () => {
8 | const cmd = Command.create('echo', { container: 'ubuntu' }).arg('hello world');
9 | assert.equal(cmd.toCommand(), `echo hello world`);
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/packages/linzjs-docker-command/src/execution/execute.docker.ts:
--------------------------------------------------------------------------------
1 | import { CommandExecution } from '../command.execution.js';
2 | import { Command } from '../command.js';
3 | import { Executor } from './execute.js';
4 | import { ExecutorLocal } from './execute.local.js';
5 | import { CommandExecutionResult } from './execute.result.js';
6 |
7 | export const ExecutorDockerDefaultArgs = [
8 | // Remove container after running
9 | '--rm',
10 | ];
11 |
12 | export function toDockerExecution(cmd: CommandExecution): CommandExecution {
13 | const proc = Command.Docker.create();
14 | const containerName = cmd.cmd.containerName;
15 | if (containerName == null) throw new Error(`Failed to execute command: ${cmd.cmd.executable} as it has no container`);
16 |
17 | proc.args.push('run');
18 | proc.args.push(...ExecutorDockerDefaultArgs);
19 |
20 | for (const path of cmd.paths) proc.args.push('--volume', `${path}:${path}`);
21 | for (const [key, value] of cmd.envs.entries()) {
22 | if (value == null) proc.args.push('--env', key);
23 | else proc.args.push('--env', `${key}=${value}`);
24 | }
25 |
26 | proc.args.push(containerName);
27 | proc.args.push(cmd.cmd.executable);
28 | proc.args.push(...cmd.args);
29 | return proc;
30 | }
31 |
32 | export const ExecutorDocker: Executor = {
33 | run(cmd: CommandExecution): Promise {
34 | return ExecutorLocal.run(toDockerExecution(cmd));
35 | },
36 | };
37 |
--------------------------------------------------------------------------------
/packages/linzjs-docker-command/src/execution/execute.local.ts:
--------------------------------------------------------------------------------
1 | import { spawn } from 'child_process';
2 |
3 | import { CommandExecution } from '../command.execution.js';
4 | import { Executor } from './execute.js';
5 | import { CommandExecutionResult } from './execute.result.js';
6 |
7 | export const ExecutorLocal: Executor = {
8 | run(cmd: CommandExecution): Promise {
9 | const startTime = Date.now();
10 | const child = spawn(cmd.cmd.executable, cmd.args);
11 |
12 | const stdout: string[] = [];
13 | const stderr: string[] = [];
14 |
15 | child.stdout.on('data', (chunk: string) => stdout.push(chunk));
16 | child.stderr.on('data', (chunk: string) => stderr.push(chunk));
17 |
18 | return new Promise((resolve) => {
19 | child.on('exit', (exitCode: number) => {
20 | resolve(new CommandExecutionResult(cmd, exitCode, stdout.join(''), stderr.join(''), Date.now() - startTime));
21 | });
22 | });
23 | },
24 | };
25 |
--------------------------------------------------------------------------------
/packages/linzjs-docker-command/src/execution/execute.result.ts:
--------------------------------------------------------------------------------
1 | import { CommandExecution } from '../command.execution.js';
2 |
3 | export class CommandExecutionResult {
4 | stdout: string;
5 | stderr: string;
6 | command: CommandExecution;
7 | exitCode: number;
8 | duration: number;
9 |
10 | constructor(command: CommandExecution, exitCode: number, stdout: string, stderr: string, duration: number) {
11 | this.command = command;
12 | this.exitCode = exitCode;
13 | this.stdout = stdout;
14 | this.stderr = stderr;
15 | this.duration = duration;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/packages/linzjs-docker-command/src/execution/execute.ts:
--------------------------------------------------------------------------------
1 | import { CommandExecution } from '../command.execution.js';
2 | import { CommandExecutionResult } from './execute.result.js';
3 |
4 | export interface Executor {
5 | run(cmd: CommandExecution): Promise;
6 | }
7 |
--------------------------------------------------------------------------------
/packages/linzjs-docker-command/src/index.ts:
--------------------------------------------------------------------------------
1 | export { CommandExecution, CommandExecutionOptions } from './command.execution.js';
2 | export { Command, CommandOptions } from './command.js';
3 | export { CommandExecutionResult } from './execution/execute.result.js';
4 |
--------------------------------------------------------------------------------
/packages/linzjs-docker-command/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 |
4 | "compilerOptions": {
5 | "outDir": "./build",
6 | "rootDir": "./src"
7 | },
8 | "include": ["src"],
9 | "references": [{ "path": "../__tests__/tsconfig.json" }]
10 | }
11 |
--------------------------------------------------------------------------------
/packages/linzjs-docker-command/typedoc.json:
--------------------------------------------------------------------------------
1 | {
2 | "entryPoints": ["./src/**/*.ts"],
3 | "exclude": ["./**/__tests__/*.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/packages/linzjs-geojson/README.md:
--------------------------------------------------------------------------------
1 | # @linzjs/geojson
2 |
3 | ## GeoJSON computation
4 |
5 | Utility functions for working with GeoJSON multi polygons and bounding boxes. In particular for handling the anti-meridian.
6 |
7 | ## Usage
8 |
9 | ### Wgs84
10 |
11 | ```javascript
12 | import { Wgs84 } from '@linzjs/geojson';
13 |
14 | assert(Wgs84.normLon(-163.12345 - 720) == -163.12345;
15 |
16 | assert(Wgs84.crossesAM(-175, 175));
17 |
18 | assert(Wgs84.delta(-175, 170) == -15);
19 |
20 | assert(deepEqual(Wgs84.union([175, -42, -178, -41], [-170, -43, -160, -42]), [175, -43, -160, -41]));
21 | ```
22 |
23 | ### MultiPolygon
24 |
25 | ```javascript
26 | import { clipMultipolygon, multiPolygonToWgs84 } from '@linzjs/geojson';
27 | import * as Proj from 'proj4';
28 |
29 | // polygons clipped to bounding box; no degenerate edges
30 | const clipped = clipMultipolygon(polygons, [-2, -2, 1, 1]);
31 |
32 | const nztmToWgs84 = Proj('epsg:2193', 'epsg:4326').forward;
33 |
34 | // nztm polygons converted to wgs84 split at anti-meridian
35 | const splitPolys = multiPolygonToWgs84(nztmPolygons, nztmToWgs84);
36 | ```
37 |
--------------------------------------------------------------------------------
/packages/linzjs-geojson/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@linzjs/geojson",
3 | "version": "8.0.0",
4 | "repository": {
5 | "type": "git",
6 | "url": "https://github.com/linz/basemaps.git",
7 | "directory": "packages/linzjs-geojson"
8 | },
9 | "author": {
10 | "name": "Land Information New Zealand",
11 | "url": "https://linz.govt.nz",
12 | "organization": true
13 | },
14 | "type": "module",
15 | "engines": {
16 | "node": ">=16.0.0"
17 | },
18 | "license": "MIT",
19 | "main": "./build/index.js",
20 | "types": "./build/index.d.ts",
21 | "scripts": {
22 | "test": "node --test"
23 | },
24 | "publishConfig": {
25 | "access": "public"
26 | },
27 | "files": [
28 | "build/"
29 | ],
30 | "dependencies": {
31 | "@types/geojson": "^7946.0.7",
32 | "lineclip": "^1.1.5",
33 | "polygon-clipping": "^0.15.1"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/packages/linzjs-geojson/src/@types/lineclip.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'lineclip' {
2 | export function polygon(points: number[][], bbox: number[]): [number, number][];
3 | }
4 |
--------------------------------------------------------------------------------
/packages/linzjs-geojson/src/__tests__/bbox.test.ts:
--------------------------------------------------------------------------------
1 | import assert from 'node:assert';
2 | import { describe, it } from 'node:test';
3 |
4 | import { bboxContains, bboxToPolygon } from '../bbox.js';
5 |
6 | describe('bbox', () => {
7 | it('bboxContains', () => {
8 | assert.equal(bboxContains([4, 4, 6, 6], [4, 4, 5, 5]), true);
9 | assert.equal(bboxContains([4, 4, 6, 6], [4, 4, 6, 6]), true);
10 | assert.equal(bboxContains([4, 4, 6, 6], [4.5, 4.5, 5.5, 5.5]), true);
11 |
12 | assert.equal(bboxContains([4, 4, 6, 6], [4.5, 4.5, 5.5, 6.5]), false);
13 | assert.equal(bboxContains([4, 4, 6, 6], [4.5, 4.5, 6.5, 5.5]), false);
14 | assert.equal(bboxContains([4, 4, 6, 6], [4.5, 3.5, 5.5, 5.5]), false);
15 | assert.equal(bboxContains([4, 4, 6, 6], [3.5, 4.5, 5.5, 5.5]), false);
16 | });
17 |
18 | it('bboxToPolygon', () => {
19 | assert.deepEqual(bboxToPolygon([74, -57, 94, -39]), [
20 | [
21 | [74, -57],
22 | [94, -57],
23 | [94, -39],
24 | [74, -39],
25 | [74, -57],
26 | ],
27 | ]);
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/packages/linzjs-geojson/src/bbox.ts:
--------------------------------------------------------------------------------
1 | import { Position } from 'geojson';
2 |
3 | import { BBox } from './types.js';
4 |
5 | /**
6 | * Build a polygon from a bounding box.
7 |
8 | * @param bbox not necessarily in WGS84 coordinates. Does not handle lines crossing the antimeridian
9 | * in WGS84.
10 |
11 | * @returns a GeoJSON Polygon in the coordinates of `bbox`
12 | */
13 | export function bboxToPolygon(bbox: BBox): Position[][] {
14 | return [
15 | [
16 | [bbox[0], bbox[1]],
17 | [bbox[2], bbox[1]],
18 | [bbox[2], bbox[3]],
19 | [bbox[0], bbox[3]],
20 | [bbox[0], bbox[1]],
21 | ],
22 | ];
23 | }
24 |
25 | /**
26 | * Does bounding box `a` contain `b`. Is `b` within `a`
27 |
28 | * @param a not necessarily in WGS84 coordinates. Does not handle lines crossing the antimeridian
29 | * in WGS84.
30 | * @param b not necessarily in WGS84 coordinates. Does not handle lines crossing the antimeridian
31 | * in WGS84.
32 | */
33 | export function bboxContains(a: BBox, b: BBox): boolean {
34 | return a[0] <= b[0] && a[2] >= b[2] && a[1] <= b[1] && a[3] >= b[3];
35 | }
36 |
--------------------------------------------------------------------------------
/packages/linzjs-geojson/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './bbox.js';
2 | export * from './construct.js';
3 | export * from './multipolygon/area.js';
4 | export * from './multipolygon/clipped.js';
5 | export * from './multipolygon/convert.js';
6 | export * from './types.js';
7 | export * from './util/iterate.js';
8 | export * from './util/truncate.js';
9 | export * from './wgs84.js';
10 |
--------------------------------------------------------------------------------
/packages/linzjs-geojson/src/multipolygon/clipped.ts:
--------------------------------------------------------------------------------
1 | import lineclip from 'lineclip';
2 | import pc from 'polygon-clipping';
3 |
4 | import { bboxToPolygon } from '../bbox.js';
5 | import { BBox, MultiPolygon, Polygon } from '../types.js';
6 |
7 | export const { intersection, union } = pc;
8 |
9 | function samePoint(a: number[], b: number[]): boolean {
10 | return a[0] === b[0] && a[1] === b[1];
11 | }
12 |
13 | function removeDegenerateEdges(polygons: MultiPolygon, bbox: BBox): MultiPolygon {
14 | return intersection(polygons, bboxToPolygon(bbox) as Polygon);
15 | }
16 |
17 | /**
18 | * Clip a MultiPolygon to a bounding box.
19 | *
20 | * @param polygons a GeoJSON MultiPolygon not necessarily in WGS84 coordinates. Does not handle
21 | * lines crossing the antimeridian in WGS84.
22 | *
23 | * @param bbox bounding box in the same coordinates and the `polygons`.
24 | */
25 | export function clipMultipolygon(polygons: MultiPolygon, bbox: BBox): MultiPolygon {
26 | const result: MultiPolygon = [];
27 | for (const poly of polygons) {
28 | const clipped = lineclip.polygon(poly[0], bbox);
29 | if (clipped.length !== 0) {
30 | if (!samePoint(clipped[0], clipped[clipped.length - 1])) clipped.push(clipped[0]);
31 | result.push([clipped]);
32 | }
33 | }
34 | return removeDegenerateEdges(result, bbox);
35 | }
36 |
--------------------------------------------------------------------------------
/packages/linzjs-geojson/src/types.ts:
--------------------------------------------------------------------------------
1 | export { MultiPolygon, Pair, Polygon, Ring } from 'polygon-clipping';
2 |
3 | export type BBox = [number, number, number, number];
4 |
5 | /**
6 | * GeoJSON Feature with compulsory `bbox`
7 | */
8 | export interface BBoxFeature<
9 | G extends GeoJSON.Geometry = GeoJSON.Polygon | GeoJSON.MultiPolygon,
10 | P = GeoJSON.GeoJsonProperties,
11 | > extends GeoJSON.Feature {
12 | bbox: BBox;
13 | }
14 |
15 | /**
16 | * GeoJSON FeatureCollection with compulsory `bbox`
17 | */
18 | export interface BBoxFeatureCollection<
19 | G extends GeoJSON.Geometry = GeoJSON.Polygon | GeoJSON.MultiPolygon,
20 | P = GeoJSON.GeoJsonProperties,
21 | > extends GeoJSON.FeatureCollection {
22 | features: Array>;
23 | }
24 |
25 | /**
26 | * GeoJSON FeatureCollection with coordinate reference
27 | *
28 | * Useful for creating non standard GeoJSON files with projection other than WGS84
29 | */
30 | export interface FeatureCollectionWithCrs extends GeoJSON.FeatureCollection {
31 | crs: {
32 | type: string;
33 | properties: {
34 | /**
35 | * CRS definition, a EPSG reference
36 | * @example "urn:ogc:def:crs:EPSG::2193"
37 | */
38 | name: string;
39 | };
40 | };
41 | }
42 |
--------------------------------------------------------------------------------
/packages/linzjs-geojson/src/util/truncate.ts:
--------------------------------------------------------------------------------
1 | import { iterate } from './iterate.js';
2 |
3 | /**
4 | * Number of decimal places to restrict capture areas to
5 | * Rough numbers of decimal places to precision in meters
6 | *
7 | * 5DP - 1m
8 | * 6DP - 0.1m
9 | * 7DP - 0.01m (1cm)
10 | * 8DP - 0.001m (1mm)
11 | */
12 | const DefaultTruncationFactor = 8;
13 |
14 | /**
15 | * Truncate a multi polygon in lat,lng to {@link DefaultTruncationFactor} decimal places
16 | *
17 | * @warning This destroys the source geometry
18 | * @param polygons
19 | */
20 | export function truncate(feature: GeoJSON.Feature, truncateFactor = DefaultTruncationFactor): void {
21 | const factor = Math.pow(10, truncateFactor);
22 |
23 | iterate(feature, (pt) => {
24 | pt[0] = Math.round(pt[0] * factor) / factor;
25 | pt[1] = Math.round(pt[1] * factor) / factor;
26 | });
27 | }
28 |
--------------------------------------------------------------------------------
/packages/linzjs-geojson/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "rootDir": "./src",
5 | "outDir": "./build"
6 | },
7 | "include": ["src"],
8 | "references": [{ "path": "../__tests__" }]
9 | }
10 |
--------------------------------------------------------------------------------
/packages/linzjs-geojson/typedoc.json:
--------------------------------------------------------------------------------
1 | {
2 | "entryPoints": ["./src/**/*.ts"],
3 | "exclude": ["./**/__tests__/*.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/packages/linzjs-metrics/README.md:
--------------------------------------------------------------------------------
1 | # @linzjs/metrics
2 |
3 | Simple timing metric tracker for NodeJS
4 |
5 | ## Usage
6 |
7 | ```typescript
8 |
9 | import { Metrics } from '@linzjs/metrics';
10 |
11 | const metrics = new Metrics();
12 |
13 | metrics.start('timer');
14 | const duration = metrics.end('timer') // 0.1 (in ms)
15 |
16 | const allMetrics = metrics.metrics // { timer: 1e6 }
17 |
18 |
19 | // Unfinished
20 | metrics.start('timer');
21 |
22 | metrics.unfinished // ['timer']
23 | ```
24 |
--------------------------------------------------------------------------------
/packages/linzjs-metrics/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@linzjs/metrics",
3 | "version": "8.0.0",
4 | "repository": {
5 | "type": "git",
6 | "url": "https://github.com/linz/basemaps.git",
7 | "directory": "packages/metrics"
8 | },
9 | "author": {
10 | "name": "Land Information New Zealand",
11 | "url": "https://linz.govt.nz",
12 | "organization": true
13 | },
14 | "type": "module",
15 | "engines": {
16 | "node": ">=16.0.0"
17 | },
18 | "license": "MIT",
19 | "main": "./build/metrics.js",
20 | "types": "./build/metrics.d.ts",
21 | "scripts": {
22 | "test": "node --test"
23 | },
24 | "publishConfig": {
25 | "access": "public"
26 | },
27 | "files": [
28 | "build/"
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/packages/linzjs-metrics/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "lib": ["DOM"],
5 | "rootDir": "./src",
6 | "outDir": "./build"
7 | },
8 | "include": ["src"],
9 | "references": []
10 | }
11 |
--------------------------------------------------------------------------------
/packages/linzjs-metrics/typedoc.json:
--------------------------------------------------------------------------------
1 | {
2 | "entryPoints": ["./src/**/*.ts"],
3 | "exclude": ["./**/__tests__/*.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/packages/server/.gitignore:
--------------------------------------------------------------------------------
1 | bin/basemaps-server.cjs
--------------------------------------------------------------------------------
/packages/server/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:20-slim@sha256:363a50faa3a561618775c1bab18dae9b4d0910a28f249bf8b72c0251c83791ff
2 |
3 | # Node does not like running as PID 1, use dumb-init to handle the init
4 | #
5 | # https://snyk.io/blog/10-best-practices-to-containerize-nodejs-web-applications-with-docker/
6 | RUN apt-get update && apt-get install -y --no-install-recommends dumb-init
7 |
8 |
9 | ENV NODE_ENV=PRODUCTION
10 |
11 | WORKDIR /app/basemaps
12 | COPY ./basemaps-landing*.tgz /app/basemaps/
13 | COPY ./basemaps-server*.tgz /app/basemaps/
14 |
15 | # Copy the static files for v1/health check
16 | COPY ./static/ /app/basemaps/static/
17 |
18 | RUN npm install ./basemaps-landing*.tgz
19 | RUN npm install ./basemaps-server*.tgz
20 |
21 | # Switch to a non root user
22 | USER node
23 |
24 | ENTRYPOINT ["/usr/bin/dumb-init", "--", "node", "/app/basemaps/node_modules/.bin/basemaps-server"]
25 | EXPOSE 5000
26 |
--------------------------------------------------------------------------------
/packages/server/src/bin.ts:
--------------------------------------------------------------------------------
1 | Error.stackTraceLimit = 100;
2 |
3 | import { LogConfig } from '@basemaps/shared';
4 | import { run } from 'cmd-ts';
5 |
6 | import { BasemapsServerCommand } from './cli.js';
7 |
8 | run(BasemapsServerCommand, process.argv.slice(2)).catch((err) => {
9 | const logger = LogConfig.get();
10 | logger.fatal({ err }, 'Command:Failed');
11 |
12 | // Give the logger some time to flush before exiting
13 | setTimeout(() => process.exit(1), 25);
14 | });
15 |
--------------------------------------------------------------------------------
/packages/server/src/index.ts:
--------------------------------------------------------------------------------
1 | export { createServer } from './server.js';
2 |
--------------------------------------------------------------------------------
/packages/server/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 |
4 | "compilerOptions": {
5 | "outDir": "./build",
6 | "rootDir": "./src"
7 | },
8 | "include": ["src"],
9 | "references": [{ "path": "../lambda-tiler/tsconfig.json" }, { "path": "../config-loader/tsconfig.json" }]
10 | }
11 |
--------------------------------------------------------------------------------
/packages/server/typedoc.json:
--------------------------------------------------------------------------------
1 | {
2 | "entryPoints": ["./src/**/*.ts"],
3 | "exclude": ["./**/__tests__/*.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/packages/shared/README.md:
--------------------------------------------------------------------------------
1 | # @basemaps/shared
2 |
3 | This contains all code that is shared between multiple services, such as AWS connection logic and constant values
4 |
5 |
--------------------------------------------------------------------------------
/packages/shared/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@basemaps/shared",
3 | "version": "8.1.0",
4 | "private": false,
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/linz/basemaps.git",
8 | "directory": "packages/shared"
9 | },
10 | "author": {
11 | "name": "Land Information New Zealand",
12 | "url": "https://linz.govt.nz",
13 | "organization": true
14 | },
15 | "type": "module",
16 | "engines": {
17 | "node": ">=16.0.0"
18 | },
19 | "license": "MIT",
20 | "main": "./build/index.js",
21 | "types": "./build/index.d.ts",
22 | "scripts": {
23 | "test": "node --test"
24 | },
25 | "dependencies": {
26 | "@aws-sdk/client-dynamodb": "^3.470.0",
27 | "@aws-sdk/client-s3": "^3.472.0",
28 | "@aws-sdk/util-dynamodb": "^3.470.0",
29 | "@basemaps/config": "^8.1.0",
30 | "@basemaps/geo": "^8.0.0",
31 | "@chunkd/fs": "^11.2.0",
32 | "@chunkd/fs-aws": "^11.3.0",
33 | "@chunkd/middleware": "^11.1.0",
34 | "@cogeotiff/core": "^9.0.3",
35 | "@cotar/core": "^6.0.1",
36 | "@linzjs/geojson": "^8.0.0",
37 | "@linzjs/metrics": "^8.0.0",
38 | "cmd-ts": "^0.12.1",
39 | "entities": "^4.3.0",
40 | "pino": "^8.6.1",
41 | "ulid": "^2.3.0"
42 | },
43 | "devDependencies": {
44 | "@types/aws-lambda": "^8.10.75"
45 | },
46 | "publishConfig": {
47 | "access": "public"
48 | },
49 | "files": [
50 | "build/"
51 | ]
52 | }
53 |
--------------------------------------------------------------------------------
/packages/shared/src/__tests__/env.test.ts:
--------------------------------------------------------------------------------
1 | import assert from 'node:assert';
2 | import { describe, it } from 'node:test';
3 |
4 | import { Env } from '../const.js';
5 |
6 | describe('Environment', () => {
7 | it('should load a number from environment var', () => {
8 | process.env[Env.TiffConcurrency] = '5';
9 | assert.equal(Env.getNumber(Env.TiffConcurrency, -1), 5);
10 | });
11 |
12 | it('should default from environment var', () => {
13 | delete process.env[Env.TiffConcurrency];
14 | assert.equal(Env.getNumber(Env.TiffConcurrency, -1), -1);
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/packages/shared/src/__tests__/url.test.ts:
--------------------------------------------------------------------------------
1 | import assert from 'node:assert';
2 | import { describe, it } from 'node:test';
3 |
4 | import { toQueryString } from '../url.js';
5 |
6 | describe('toQueryString', () => {
7 | it('should create a query string', () => {
8 | assert.equal(toQueryString({ api: 'foo' }), '?api=foo');
9 | });
10 |
11 | it('should not create empty query strings', () => {
12 | assert.equal(toQueryString({}), '');
13 | assert.equal(toQueryString({ api: undefined }), '');
14 | assert.equal(toQueryString({ api: null }), '');
15 | });
16 |
17 | it('should sort keys', () => {
18 | assert.equal(toQueryString({ z: 'z', a: 'a' }), '?a=a&z=z');
19 | });
20 | });
21 |
--------------------------------------------------------------------------------
/packages/shared/src/cli/__tests__/git.tag.test.ts:
--------------------------------------------------------------------------------
1 | import assert from 'node:assert';
2 | import { describe, it } from 'node:test';
3 |
4 | import { GitTag } from '../git.tag.js';
5 |
6 | describe('git.tag', () => {
7 | it('format', () => {
8 | const ans = GitTag();
9 | assert.equal(/^v\d+\.\d+\.\d+(-\d+-g[0-9a-f]+)?$/.test(ans.version), true, `Got: ${ans.version}`);
10 | assert.equal(/^[0-9a-f]+$/.test(ans.hash), true, `Got: ${ans.hash}`);
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/packages/shared/src/cli/argo.ts:
--------------------------------------------------------------------------------
1 | /** Is this script running inside of argo */
2 | export function isArgo(): boolean {
3 | return process.env['ARGO_NODE_ID'] != null;
4 | }
5 |
--------------------------------------------------------------------------------
/packages/shared/src/cli/git.tag.ts:
--------------------------------------------------------------------------------
1 | import { execFileSync } from 'child_process';
2 |
3 | export function GitTag(): { version: string; hash: string } {
4 | return {
5 | version: execFileSync('git', ['describe', '--tags', '--always', '--match', 'v*']).toString().trim(),
6 | hash: execFileSync('git', ['rev-parse', 'HEAD']).toString().trim(),
7 | };
8 | }
9 |
--------------------------------------------------------------------------------
/packages/shared/src/cli/info.ts:
--------------------------------------------------------------------------------
1 | import * as ulid from 'ulid';
2 |
3 | import { GitTag } from './git.tag.js';
4 |
5 | /** Useful traceability information */
6 | export const CliInfo: { package: string; version: string; hash: string; buildId?: string } = {
7 | // Detect unlinked packages looks for this string since its a package name, slightly work around it
8 | package: '@' + 'basemaps/cli',
9 | version: process.env['GIT_VERSION'] ?? GitTag().version,
10 | hash: process.env['GIT_HASH'] ?? GitTag().hash,
11 | buildId: process.env['BUILD_ID'],
12 | };
13 |
14 | /** ISO date of when this command was run */
15 | export const CliDate = new Date().toISOString();
16 |
17 | /** Unique Id for this instance of the cli being run */
18 | export const CliId = ulid.ulid();
19 |
--------------------------------------------------------------------------------
/packages/shared/src/cli/log.ts:
--------------------------------------------------------------------------------
1 | import { flag } from 'cmd-ts';
2 |
3 | import { LogConfig, LogType } from '../log.js';
4 | import { isArgo } from './argo.js';
5 | import { CliInfo } from './info.js';
6 |
7 | export const logArguments = {
8 | verbose: flag({ long: 'verbose', description: 'Enable verbose logging' }),
9 | extraVerbose: flag({ long: 'extra-verbose', description: 'Extra verbose logging' }),
10 | };
11 |
12 | export function getLogger(
13 | cli: { name: string },
14 | args: { verbose: boolean; extraVerbose: boolean },
15 | packageName?: string,
16 | ): LogType {
17 | const logger = LogConfig.get();
18 | if (packageName) CliInfo.package = packageName.startsWith('@') ? packageName : '@' + packageName;
19 | if (args.verbose) logger.level = 'debug';
20 | if (args.extraVerbose) logger.level = 'trace';
21 | logger.info({ package: CliInfo, cli: cli.name, args, isArgo: isArgo() }, 'Cli:Start');
22 | return logger;
23 | }
24 |
--------------------------------------------------------------------------------
/packages/shared/src/config.ts:
--------------------------------------------------------------------------------
1 | import { BasemapsConfigProvider } from '@basemaps/config';
2 |
3 | import { Const } from './const.js';
4 | import { ConfigProviderDynamo } from './dynamo/dynamo.config.js';
5 |
6 | let ConfigDefault: BasemapsConfigProvider = new ConfigProviderDynamo(Const.TileMetadata.TableName);
7 |
8 | export function setDefaultConfig(cfg: BasemapsConfigProvider): BasemapsConfigProvider {
9 | ConfigDefault = cfg;
10 | return ConfigDefault;
11 | }
12 |
13 | export function getDefaultConfig(): BasemapsConfigProvider {
14 | return ConfigDefault;
15 | }
16 |
--------------------------------------------------------------------------------
/packages/shared/src/dynamo/__tests__/config.provider.test.ts:
--------------------------------------------------------------------------------
1 | import assert from 'node:assert';
2 | import { describe, it } from 'node:test';
3 |
4 | import { ConfigProviderDynamo } from '../dynamo.config.js';
5 |
6 | describe('ConfigProviderDynamo', () => {
7 | const Config = new ConfigProviderDynamo('table');
8 |
9 | describe('id', () => {
10 | it('should create ids', () => {
11 | assert.equal(Config.Provider.id('linz'), 'pv_linz');
12 | });
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/packages/shared/src/dynamo/dynamo.config.cached.ts:
--------------------------------------------------------------------------------
1 | import { BaseConfig } from '@basemaps/config';
2 |
3 | import { ConfigDynamoBase } from './dynamo.config.base.js';
4 |
5 | export class ConfigDynamoCached extends ConfigDynamoBase {
6 | cache: Map = new Map();
7 |
8 | public override async get(id: string): Promise {
9 | const queryKey = this.ensureId(id);
10 | let existing: T | null | undefined = this.cache.get(queryKey);
11 | if (existing == null) {
12 | existing = await super.get(queryKey);
13 | if (existing == null) return null;
14 | this.cache.set(queryKey, existing);
15 | }
16 |
17 | return existing;
18 | }
19 |
20 | public override async getAll(ids: Set): Promise