@opengis/gis 0.1.66 → 0.1.68

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -78,6 +78,12 @@
78
78
  "id": "search",
79
79
  "type": "Text",
80
80
  "columns": "name,holder"
81
+ },
82
+ {
83
+ "label": "Ключові слова",
84
+ "id": "keywords",
85
+ "type": "Check",
86
+ "inline": true
81
87
  }
82
88
  ]
83
89
  }
@@ -7,20 +7,6 @@
7
7
  "title": "name",
8
8
  "search": "name,description,source_path"
9
9
  },
10
- "sql": [
11
- {
12
- "sql": "select source, date_updated, size, region from gis.metadata where layer_id=t.service_id limit 1",
13
- "name": "metadata_sql"
14
- },
15
- {
16
- "sql": "select json_agg(q) as metadata_all from (select scale, katottg,srid, region, name, purpose, source,keywords,update_frequency,year,date_created,size,access_constraints,license from gis.metadata where layer_id=t.service_id limit 1)q ",
17
- "name": "metadata_list_sql"
18
- },
19
- {
20
- "name": "is_export_sql",
21
- "sql": "select jsonb_path_exists(attributes, '$[*] ? (@.is_export == true)') as is_export"
22
- }
23
- ],
24
10
  "title": "Сервіси",
25
11
  "form": "gis.services.form",
26
12
  "sqlColumns": "*",
@@ -85,10 +71,17 @@
85
71
  }
86
72
  ],
87
73
  "filterList": [
74
+ {
75
+ "label": "Назва, Опис",
76
+ "id": "search",
77
+ "type": "Text",
78
+ "columns": "name,description",
79
+ "inline": true
80
+ },
88
81
  {
89
82
  "label": "Ключові слова",
90
83
  "id": "keywords",
91
- "type": "Text",
84
+ "type": "Check",
92
85
  "inline": true
93
86
  },
94
87
  {
@@ -108,7 +101,7 @@
108
101
  {
109
102
  "label": "Утримувач",
110
103
  "id": "holder",
111
- "type": "Text"
104
+ "type": "Check"
112
105
  }
113
106
  ]
114
107
  }
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@opengis/gis",
3
- "version": "0.1.66",
3
+ "version": "0.1.68",
4
4
  "type": "module",
5
5
  "author": "Softpro",
6
- "main": "dist/import-file.js",
6
+ "main": "./dist/index.js",
7
7
  "files": [
8
8
  "dist/*",
9
9
  "module/*",
@@ -28,20 +28,20 @@
28
28
  "docs:preview": "npm run --prefix ./docs docs:preview",
29
29
  "prepublishOnly": "npm run build"
30
30
  },
31
- "dependencies": {},
31
+ "dependencies": {
32
+ "@mapbox/sphericalmercator": "1.2.0",
33
+ "carto": "0.16.3"
34
+ },
32
35
  "peerDependencies": {
33
36
  "@opengis/fastify-table": "^1.4.24",
34
37
  "@opengis/filter": "^0.1.7",
35
38
  "@opengis/core": "^0.0.18"
36
39
  },
37
40
  "devDependencies": {
38
- "@mapbox/sphericalmercator": "1.2.0",
39
41
  "lucide-vue-next": "^0.514.0",
40
- "carto": "0.16.3",
41
42
  "vue": "^3.5.13",
42
43
  "vue-router": "4.5.1",
43
44
  "vuedraggable": "^4.1.0",
44
- "yaml": "^2.8.0",
45
45
  "@opengis/core": "^0.0.18",
46
46
  "@opengis/filter": "^0.1.7",
47
47
  "@opengis/fastify-table": "^1.4.77",
@@ -0,0 +1,241 @@
1
+ syntax = "proto3";
2
+
3
+
4
+ message render_in {
5
+ string path = 1;
6
+ string name = 2;
7
+ repeated double bbox = 3 [packed=true];
8
+ string tile = 4;
9
+ string xml = 5;
10
+ int32 width = 6;
11
+ int32 height = 7;
12
+ }
13
+
14
+
15
+ message render_out {
16
+ string err = 1;
17
+ string base64 = 2;
18
+ string tile = 3;
19
+ }
20
+
21
+ message xml_in {
22
+ string path = 1;
23
+ string name = 2;
24
+ string xml = 3;
25
+ bool reload = 4;
26
+ }
27
+
28
+ message xml_out {
29
+ string err = 1;
30
+ bool is_ok = 2;
31
+ }
32
+
33
+ message cmd_in {
34
+ string cmd = 1;
35
+ string svg = 2;
36
+ string filename = 3;
37
+ }
38
+
39
+ message cmd_out {
40
+ string err = 1;
41
+ string base64 = 2;
42
+ }
43
+
44
+ message gdal_in {
45
+ string name = 1;
46
+ string path = 2;
47
+ string out = 3;
48
+ string params = 4;
49
+ }
50
+ message gdal_out {
51
+ string result = 1;
52
+ string err = 2;
53
+ }
54
+
55
+ message clear_tiles_in {
56
+ string path = 1;
57
+ }
58
+
59
+ message clear_tiles_out {
60
+ oneof clear_message {
61
+ bool ok = 1;
62
+ string err = 2;
63
+ }
64
+ }
65
+
66
+ message empty {}
67
+
68
+ message statusRenderInfo {
69
+ string name = 1;
70
+ bool isActive = 2;
71
+ float workTime = 3;
72
+ }
73
+
74
+ message statusInfo {
75
+ repeated statusRenderInfo info = 1;
76
+ }
77
+
78
+ message printMapOut {
79
+ string map = 1;
80
+ string err = 2;
81
+ }
82
+
83
+ message xyz {
84
+ float x = 1;
85
+ float y = 2;
86
+ float z = 3;
87
+ }
88
+
89
+ message printMapIn {
90
+ string baseurl = 1;
91
+ string baseImg = 2;
92
+ repeated string xml = 3;
93
+ string overlayXml = 4;
94
+ string overlay = 5;
95
+ int32 width = 6;
96
+ int32 height = 7;
97
+ repeated double bbox = 8;
98
+ xyz pos = 9;
99
+ string geojsonSettings = 10;
100
+ }
101
+
102
+ message log_in {
103
+ uint32 rows = 1;
104
+ string level = 2;
105
+ }
106
+
107
+ message log_out {
108
+ repeated string logs = 1;
109
+ }
110
+
111
+ message sqlToShpIn {
112
+ string db = 1;
113
+ string host = 2;
114
+ string port = 3;
115
+ string sql = 4;
116
+ string savePath = 5;
117
+ string shpName = 6;
118
+ }
119
+
120
+ message shapeOut {
121
+ string zipPath = 1;
122
+ }
123
+
124
+ message fileIn {
125
+ bytes fileBytes = 1;
126
+ string relativeFilepath = 2;
127
+ }
128
+
129
+ message deleteFileIn {
130
+ string dir = 1;
131
+ repeated string objectList = 2;
132
+ }
133
+
134
+ message fileManagerOut {
135
+ bool status = 1;
136
+ string operation = 2;
137
+ }
138
+
139
+ message checkFilesDir {
140
+ string dir = 1;
141
+ repeated string filesSearch = 2;
142
+ }
143
+
144
+ enum status {
145
+ LOADING = 0;
146
+ OK = 1;
147
+ }
148
+
149
+ message filesStatus {
150
+ status fileLoadingStatus = 1;
151
+ }
152
+
153
+ message fileListIn {
154
+ string dir = 1;
155
+ }
156
+
157
+ message fileInfo {
158
+ repeated fileInfoL fileInfoList = 1;
159
+ }
160
+
161
+ message fileInfoL {
162
+ oneof fileInfo {
163
+ fileInfoObj file = 1;
164
+ dirInfoObj dir = 2;
165
+ }
166
+ }
167
+
168
+ message fileInfoObj {
169
+ string type = 1;
170
+ string birthtime = 2;
171
+ string name = 3;
172
+ uint64 size = 4;
173
+ string ext = 5;
174
+ string server = 6;
175
+ }
176
+
177
+ message dirInfoObj {
178
+ string type = 1;
179
+ string birthtime = 2;
180
+ string name = 3;
181
+ uint64 size = 4;
182
+ uint64 count = 5;
183
+ string server = 6;
184
+ }
185
+
186
+ message deleteOut {
187
+ repeated deleteObjSuccess success = 1;
188
+ repeated deleteObjError error = 2;
189
+
190
+ }
191
+
192
+ message deleteObjSuccess {
193
+ string object = 1;
194
+ string type = 2;
195
+ string status = 3;
196
+ }
197
+
198
+ message deleteObjError {
199
+ string object = 1;
200
+ string fullPath = 2;
201
+ string result = 3;
202
+ }
203
+
204
+ message readDirIn {
205
+ string dir = 1;
206
+ repeated string filter = 2;
207
+ string fullPath = 3;
208
+ }
209
+
210
+ message readDirOut {
211
+ repeated string res = 1;
212
+
213
+ }
214
+
215
+ message downloadFileIn {
216
+ string filePath = 1;
217
+ }
218
+
219
+ message downloadFileOut {
220
+ bytes chunk_data = 1;
221
+ }
222
+
223
+
224
+ service Map {
225
+ rpc Render(render_in) returns (render_out) {}
226
+ rpc RenderXML(render_in) returns (render_out) {}
227
+ rpc LoadXML(xml_in) returns (xml_out) {}
228
+ rpc MarkerIcon(cmd_in) returns (cmd_out) {}
229
+ rpc Gdal(gdal_in) returns (gdal_out) {}
230
+ rpc ClearTiles(clear_tiles_in) returns (clear_tiles_out) {}
231
+ rpc RenderStatus(empty) returns (statusInfo) {}
232
+ rpc PrintMap(printMapIn) returns (printMapOut) {}
233
+ rpc Log(log_in) returns (log_out) {}
234
+ rpc SqlToShp(sqlToShpIn) returns (shapeOut) {}
235
+ rpc uploadFile(fileIn) returns (fileManagerOut) {}
236
+ rpc deleteFiles(deleteFileIn) returns (deleteOut) {}
237
+ rpc checkFiles(checkFilesDir) returns (filesStatus) {}
238
+ rpc fileList(fileListIn) returns (fileInfo) {}
239
+ rpc readDir(readDirIn) returns (readDirOut) {}
240
+ rpc downloadFile(downloadFileIn) returns (stream downloadFileOut) {}
241
+ }
@@ -9,89 +9,90 @@ import { config, logger } from '@opengis/fastify-table/utils.js';
9
9
  config.ready = config.ready || {};
10
10
 
11
11
  const { mapServerAddress } = config || {};
12
-
12
+ const funcs1 =[]
13
13
  if (!mapServerAddress) {
14
- throw new Error('mapServerAddress not set in config');
15
- }
14
+ console.log("\x1b[34m%s\x1b[0m",'mapServerAddress not set in config');
15
+ } else {
16
16
 
17
- const proto = grpc.loadPackageDefinition(
18
- protoLoader.loadSync(path.join(process.cwd(), '/server/plugins/mapnik/utils/map.proto'), {
19
- keepCase: true,
20
- longs: String,
21
- enums: String,
22
- defaults: true,
23
- oneofs: true,
24
- }),
25
- );
17
+ const PROTO_PATH = path.join(__dirname, 'map.proto')
26
18
 
27
- const mapClient = mapServerAddress ? new proto.Map(
28
- mapServerAddress,
29
- grpc.credentials.createInsecure(),
30
- ) : null;
19
+ const proto = grpc.loadPackageDefinition(
20
+ protoLoader.loadSync(PROTO_PATH, {
21
+ keepCase: true,
22
+ longs: String,
23
+ enums: String,
24
+ defaults: true,
25
+ oneofs: true,
26
+ }),
27
+ );
31
28
 
32
- mapClient.waitForReady(Date.now() + 5000, (err) => {
33
- if (err) {
34
- config.ready.mapnik = false;
35
- console.error('Mapnik client connection timeout or failure:', err);
36
- }
37
- else {
38
- config.ready.mapnik = true;
39
- console.log('Mapnik client connected successfully.');
40
- // You can now make RPC calls safely
41
- }
42
- });
29
+ const mapClient = mapServerAddress ? new proto.Map(
30
+ mapServerAddress,
31
+ grpc.credentials.createInsecure(),
32
+ ) : null;
33
+
34
+ mapClient.waitForReady(Date.now() + 5000, (err) => {
35
+ if (err) {
36
+ config.ready.mapnik = false;
37
+ console.error('Mapnik client connection timeout or failure:', err);
38
+ }
39
+ else {
40
+ config.ready.mapnik = true;
41
+ console.log('Mapnik client connected successfully.');
42
+ // You can now make RPC calls safely
43
+ }
44
+ });
43
45
 
44
- const fsFuncsList = ['uploadFile', 'deleteFiles', 'downloadFile', 'checkFiles', 'fileList', 'readDir'];
46
+ const fsFuncsList = ['uploadFile', 'deleteFiles', 'downloadFile', 'checkFiles', 'fileList', 'readDir'];
45
47
 
46
- const funcs1 = [
47
- 'render', 'renderXML', 'loadXML', 'markerIcon', 'gdal',
48
- 'printMap', 'log', 'sqlToShp', 'uploadFile', 'deleteFiles',
49
- 'downloadFile', 'checkFiles', 'fileList', 'readDir', 'renderStatus',
50
- ].reduce((p, el) => {
51
- // eslint-disable-next-line no-param-reassign
52
- p[el] = mapServerAddress ? async (data) => new Promise((res, rej) => {
53
- const capitalized = fsFuncsList.includes(el) ? el : el.charAt(0).toUpperCase() + el.slice(1);
48
+ [
49
+ 'render', 'renderXML', 'loadXML', 'markerIcon', 'gdal',
50
+ 'printMap', 'log', 'sqlToShp', 'uploadFile', 'deleteFiles',
51
+ 'downloadFile', 'checkFiles', 'fileList', 'readDir', 'renderStatus',
52
+ ].forEach(el => {
54
53
  // eslint-disable-next-line no-param-reassign
55
- if (data) {
56
- if (data?.path && data.path?.[0] !== '"') {
57
- // eslint-disable-next-line no-param-reassign
58
- data.path = `"${data.path}"`;
54
+ funcs1[el] = mapServerAddress ? async (data) => new Promise((res, rej) => {
55
+ const capitalized = fsFuncsList.includes(el) ? el : el.charAt(0).toUpperCase() + el.slice(1);
56
+ // eslint-disable-next-line no-param-reassign
57
+ if (data) {
58
+ if (data?.path && data.path?.[0] !== '"') {
59
+ // eslint-disable-next-line no-param-reassign
60
+ data.path = `"${data.path}"`;
61
+ }
59
62
  }
60
- }
61
63
 
62
- if (el === 'downloadFile') {
63
- const downloadBuffer = [];
64
- const download = mapClient[capitalized].call(mapClient, data, (err, data1) => {
65
- if (err || data1?.result?.startsWith?.('Usage:')) {
66
- logger.file('grpc/mapnik', { error: err.toString(), stack: err.stack, ready: config.ready.mapnik });
67
- if (!config.ready.mapnik) {
68
- return rej(new Error('no grpc mapnik connection'));
64
+ if (el === 'downloadFile') {
65
+ const downloadBuffer = [];
66
+ const download = mapClient[capitalized].call(mapClient, data, (err, data1) => {
67
+ if (err || data1?.result?.startsWith?.('Usage:')) {
68
+ logger.file('grpc/mapnik', { error: err.toString(), stack: err.stack, ready: config.ready.mapnik });
69
+ if (!config.ready.mapnik) {
70
+ return rej(new Error('no grpc mapnik connection'));
71
+ }
72
+ return rej(err || data1?.result);
69
73
  }
70
- return rej(err || data1?.result);
71
- }
72
- res(data1);
73
- });
74
- download.on('data', (resp) => {
75
- downloadBuffer.push(...resp.chunk_data);
76
- });
77
- download.on('end', () => res({ data: Buffer.from(downloadBuffer) }));
78
- }
79
- else {
80
- mapClient[capitalized].call(mapClient, data, (err, data1) => {
81
- if (err || data1?.result?.startsWith?.('Usage:')) {
82
- logger.file('grpc/mapnik', { error: err.toString(), stack: err.stack, ready: config.ready.mapnik });
83
- if (!config.ready.mapnik) {
84
- return rej(new Error('no grpc mapnik connection'));
74
+ res(data1);
75
+ });
76
+ download.on('data', (resp) => {
77
+ downloadBuffer.push(...resp.chunk_data);
78
+ });
79
+ download.on('end', () => res({ data: Buffer.from(downloadBuffer) }));
80
+ }
81
+ else {
82
+ mapClient[capitalized].call(mapClient, data, (err, data1) => {
83
+ if (err || data1?.result?.startsWith?.('Usage:')) {
84
+ logger.file('grpc/mapnik', { error: err.toString(), stack: err.stack, ready: config.ready.mapnik });
85
+ if (!config.ready.mapnik) {
86
+ return rej(new Error('no grpc mapnik connection'));
87
+ }
88
+ return rej(err || data1?.result);
85
89
  }
86
- return rej(err || data1?.result);
87
- }
88
- res(data1);
89
- });
90
- }
91
- }) : null;
92
- return p;
93
- }, {});
94
-
90
+ res(data1);
91
+ });
92
+ }
93
+ }) : null;
94
+ });
95
+ }
95
96
 
96
97
  const getMapnik = () => ({
97
98
  ...funcs1,
@@ -33,6 +33,7 @@ const autoGenerate = {};
33
33
  export default async function rtile({
34
34
  pg = pgClients.client, params = {}, query = {}, user = {},
35
35
  }, reply) {
36
+ if(!render) return reply.status(400).send('mapnik server address needed');
36
37
  const { id, z, y } = params;
37
38
  const { debug, nocache } = query;
38
39
  const db = pg.options?.database;
@@ -6,6 +6,7 @@ import mapCatalog from './controllers/mapCatalog.js';
6
6
  import mapCatalogAttribute from './controllers/mapCatalogAttribute.js';
7
7
  import rtile from './controllers/rtile.js';
8
8
  import vtile from './controllers/vtile.js';
9
+ import vtile1 from './vtile1.js';
9
10
 
10
11
  import mapFormat from './controllers/mapFormat.js';
11
12
  import maps from './controllers/maps.js';
@@ -49,6 +50,11 @@ export default async function route(app) {
49
50
  app.get('/layer-rtile/:id/:z/:y/:x', { config: { policy }, schema: {} }, rtile);
50
51
  app.get('/layer-vtile/:id/:z/:y/:x', { config: { policy }, schema: schemaInfo }, vtile);
51
52
 
53
+ if (!app.hasRoute({ method: 'GET', url: '/api/vtile/:layer/:lang/:z/:y/:x', })) {
54
+ console.log("\x1b[34m%s\x1b[0m",'add vtile from gis');
55
+ app.get('/vtile/:layer/:lang/:z/:y/:x', { config: { policy }, schema: schemaInfo }, vtile1);
56
+ }
57
+
52
58
  app.get('/marker-icon/*', { config: { policy }, schema: {} }, markerIconApi);
53
59
  app.get('/map-format', { config: { policy }, schema: {} }, mapFormat);
54
60
  }
@@ -0,0 +1,98 @@
1
+ const headers = {
2
+ 'Content-Type': 'application/x-protobuf',
3
+ 'Cache-Control': 'no-cache',
4
+ };
5
+ import Sphericalmercator from '@mapbox/sphericalmercator';
6
+ const mercator = new Sphericalmercator({ size: 256 });
7
+ import { getTemplate, getMeta, getFilterSQL } from '@opengis/fastify-table/utils.js';
8
+
9
+ export default async function vtile({ params = {}, query, pg }, reply) {
10
+ const { y, z, layer } = params;
11
+ const x = params.x.split('.')[0] - 0;
12
+
13
+ // layer
14
+ const data = await getTemplate('layer', layer);
15
+ if (!data) return { status: 404, message: 'not found' }
16
+
17
+ // bbox
18
+ const bbox = mercator.bbox(+y, +x, +z, false/* , '900913' */);
19
+ const bbox2d = `'BOX(${bbox[0]} ${bbox[1]},${bbox[2]} ${bbox[3]})'::box2d`;
20
+
21
+ // columns
22
+ const geom = 'geom';
23
+ const table = data.table_name;
24
+ const filterData = query.filter ? await getFilterSQL({
25
+ filter: query.filter, table, filterList: data.filter_list,
26
+ }) : {};
27
+
28
+ // meta
29
+ const metaTable = await getMeta({ pg, table });
30
+ if (metaTable.error) { return metaTable; }
31
+ const { pk: pkey, columns } = metaTable;
32
+
33
+ // props
34
+ const columnsFiltered = columns.filter(el => !['json', 'geometry'].includes(pg.pgType[el.dataTypeID]) && !['uid', 'cdate', 'editor_id', 'editor_date'].includes(el.name));
35
+ const props = columnsFiltered.map(el => {
36
+ return el.type?.[0] === '_' ? `${el.name}[1] as ${el.name}` : `${el.name}${['int4'].includes(el.type) ? '::text' : ''}`;
37
+ });
38
+
39
+ const geomCol = (data?.style?.type === 'point' ? `ST_Centroid(${geom})` : null)
40
+ || (parseInt(z, 10) < parseInt(query.pointZoom || data?.style?.pointZoom || data?.style?.iconZoom || '0', 10) ? `ST_Centroid(${geom})` : geom);
41
+
42
+ const koef = {
43
+ 10: 0.1, 11: 0.05, 12: 0.005, 13: 0.001, 14: 0.001, 15: 0.0005,
44
+ }[z] || 0.0005;
45
+
46
+ const { type } = query;
47
+ const types = { point: 'ST_Point' /* ,ST_MultiPoint */, polygon: 'ST_Polygon,ST_MultiPolygon' };
48
+ const sql = ((query.clusterZoom - z) > 2
49
+ ? `SELECT ST_AsMVT(q, '${layer}', 4096, 'geom','row') as tile
50
+ FROM (
51
+ SELECT floor(random() * 100000 + 1)::int + row_number() over() as row, point_count, ST_AsMVTGeom(st_transform(geom,3857),ST_TileEnvelope(${z},${y},${x})::box2d,4096,256,false) geom
52
+ FROM (
53
+ SELECT st_centroid(st_union(geom)) as geom, count(*) as point_count
54
+ FROM ${table} where ${data?.query || 'true'} and ${filterData?.q || 'true'} and ${geom} && ${bbox2d} ) j
55
+ )q`: null
56
+ ) || ((query.clusterZoom - z) > 0 ?
57
+ `SELECT ST_AsMVT(q, '${layer}', 4096, 'geom','row') as tile
58
+ FROM (
59
+ SELECT floor(random() * 100000 + 1)::int +row_number() over() as row, count(*) as point_count, ST_AsMVTGeom(st_transform(st_centroid(ST_Union(geom)),3857),ST_TileEnvelope(${z},${y},${x})::box2d,4096,256,false) geom
60
+ FROM (
61
+ SELECT geom, ST_ClusterDBSCAN(geom,${koef},1) OVER () AS cluster
62
+ FROM ${table} where ${data?.query || 'true'} and ${filterData?.q || 'true'} and ${geom} && ${bbox2d} ) j
63
+ WHERE cluster IS NOT NULL
64
+ GROUP BY cluster
65
+ ORDER BY 1 DESC
66
+ )q`
67
+
68
+ : `SELECT ST_AsMVT(q, '${layer}', 4096, 'geom','row') as tile
69
+ FROM (
70
+ SELECT
71
+
72
+ floor(random() * 100000 + 1)::int + row_number() over() as row,
73
+
74
+ ${props?.length ? `${props.map(el => `"${el}"`).join(',')},` : ''}
75
+
76
+ ${pkey} as id,
77
+ ST_AsMVTGeom(st_transform(${geomCol},3857),ST_TileEnvelope(${z},${y},${x})::box2d,4096,256,false) geom
78
+
79
+ FROM (select * from ${table} where ${data.query || 'true'} and ${filterData?.q || 'true'} and ${geom} && ${bbox2d}
80
+
81
+ and ${geom} is not null and st_srid(${geom}) >0
82
+
83
+
84
+
85
+ ${types[type] ? ` and ST_GeometryType(geom) = any ('{ ${types[type]} }') ` : ''}
86
+
87
+ and ${data?.query || 'true'} and ${filterData?.q || 'true'} and ${data?.filter || '1=1'}
88
+
89
+ ${(data?.style?.type || data?.geometry_type) === 'polygon' ? `order by st_area(st_transform(${geom},3857)) desc` : ''}
90
+
91
+ limit 3000)q
92
+ ) q`);
93
+
94
+ if (query.sql === '1') { return sql; }
95
+ const tile = await pg.query(sql);
96
+ const buffer = Buffer.concat(tile.rows.map((el) => Buffer.from(el.tile)));
97
+ return reply.headers(headers).send(buffer);
98
+ }
@@ -1,12 +0,0 @@
1
- import fp from 'fastify-plugin';
2
- // import config from '../config.js';
3
-
4
- import mapnik from './funcs/mapnik.js';
5
- import gdalWrapper from './funcs/gdalWrapper.js';
6
-
7
- async function plugin(fastify, opts) {
8
- // fastify.decorate('mapnik', mapnik);
9
- // fastify.decorate('gdalWrapper', gdalWrapper);
10
- }
11
-
12
- export default fp(plugin);