@defra/forms-engine-plugin 4.0.42 → 4.0.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.public/javascripts/shared.min.js +1 -1
- package/.public/javascripts/shared.min.js.map +1 -1
- package/.server/client/javascripts/location-map.js +8 -4
- package/.server/client/javascripts/location-map.js.map +1 -1
- package/.server/server/plugins/engine/configureEnginePlugin.d.ts +1 -1
- package/.server/server/plugins/engine/configureEnginePlugin.js +4 -2
- package/.server/server/plugins/engine/configureEnginePlugin.js.map +1 -1
- package/.server/server/plugins/engine/options.js +2 -1
- package/.server/server/plugins/engine/options.js.map +1 -1
- package/.server/server/plugins/engine/plugin.js +6 -4
- package/.server/server/plugins/engine/plugin.js.map +1 -1
- package/.server/server/plugins/engine/types.d.ts +1 -0
- package/.server/server/plugins/engine/types.js.map +1 -1
- package/.server/server/plugins/map/routes/get-os-token.d.ts +6 -0
- package/.server/server/plugins/map/routes/get-os-token.js +41 -0
- package/.server/server/plugins/map/routes/get-os-token.js.map +1 -0
- package/.server/server/plugins/map/routes/get-os-token.test.js +49 -0
- package/.server/server/plugins/map/routes/get-os-token.test.js.map +1 -0
- package/.server/server/plugins/map/routes/index.d.ts +1 -11
- package/.server/server/plugins/map/routes/index.js +60 -16
- package/.server/server/plugins/map/routes/index.js.map +1 -1
- package/.server/server/plugins/map/types.d.ts +1 -0
- package/.server/server/plugins/map/types.js +1 -0
- package/.server/server/plugins/map/types.js.map +1 -1
- package/.server/server/types.d.ts +1 -0
- package/.server/server/types.js.map +1 -1
- package/package.json +1 -1
- package/src/client/javascripts/location-map.js +12 -4
- package/src/server/plugins/engine/configureEnginePlugin.ts +4 -2
- package/src/server/plugins/engine/options.js +2 -1
- package/src/server/plugins/engine/plugin.ts +6 -4
- package/src/server/plugins/engine/types.ts +1 -0
- package/src/server/plugins/map/routes/get-os-token.js +41 -0
- package/src/server/plugins/map/routes/get-os-token.test.js +55 -0
- package/src/server/plugins/map/routes/index.js +70 -24
- package/src/server/plugins/map/types.js +1 -0
- package/src/server/types.ts +1 -0
|
@@ -2,17 +2,7 @@
|
|
|
2
2
|
* Gets the map support routes
|
|
3
3
|
* @param {MapConfiguration} options - ordnance survey names api key
|
|
4
4
|
*/
|
|
5
|
-
export function getRoutes(options: MapConfiguration): (ServerRoute<MapProxyGetRequestRefs> | ServerRoute<MapGeocodeGetRequestRefs> | ServerRoute<MapReverseGeocodeGetRequestRefs>
|
|
6
|
-
method: string;
|
|
7
|
-
path: string;
|
|
8
|
-
options: {
|
|
9
|
-
handler: {
|
|
10
|
-
directory: {
|
|
11
|
-
path: string;
|
|
12
|
-
};
|
|
13
|
-
};
|
|
14
|
-
};
|
|
15
|
-
})[];
|
|
5
|
+
export function getRoutes(options: MapConfiguration): (ServerRoute<MapProxyGetRequestRefs> | ServerRoute<MapGeocodeGetRequestRefs> | ServerRoute<MapReverseGeocodeGetRequestRefs>)[];
|
|
16
6
|
import type { MapConfiguration } from '~/src/server/plugins/map/types.js';
|
|
17
7
|
import type { MapProxyGetRequestRefs } from '~/src/server/plugins/map/types.js';
|
|
18
8
|
import type { ServerRoute } from '@hapi/hapi';
|
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import { resolve } from 'node:path';
|
|
2
|
+
import { StatusCodes } from 'http-status-codes';
|
|
2
3
|
import Joi from 'joi';
|
|
4
|
+
import { getAccessToken } from "./get-os-token.js";
|
|
3
5
|
import { find, nearest } from "../service.js";
|
|
4
|
-
import { request as httpRequest } from "../../../services/httpService.js";
|
|
6
|
+
import { get, request as httpRequest } from "../../../services/httpService.js";
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* Gets the map support routes
|
|
8
10
|
* @param {MapConfiguration} options - ordnance survey names api key
|
|
9
11
|
*/
|
|
10
12
|
export function getRoutes(options) {
|
|
11
|
-
return [mapProxyRoute(options),
|
|
13
|
+
return [mapStyleResourceRoutes(), mapProxyRoute(options), tileProxyRoute(options), geocodeProxyRoute(options), reverseGeocodeProxyRoute(options)];
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
/**
|
|
15
17
|
* Proxies ordnance survey requests from the front end to api.os.com
|
|
16
|
-
* Used for VTS map
|
|
17
|
-
* and adding the
|
|
18
|
+
* Used for the VTS map source by forwarding on the request
|
|
19
|
+
* and adding the auth token and SRS (spatial reference system)
|
|
18
20
|
* @param {MapConfiguration} options - the map options
|
|
19
21
|
* @returns {ServerRoute<MapProxyGetRequestRefs>}
|
|
20
22
|
*/
|
|
@@ -27,13 +29,13 @@ function mapProxyRoute(options) {
|
|
|
27
29
|
query
|
|
28
30
|
} = request;
|
|
29
31
|
const targetUrl = new URL(decodeURIComponent(query.url));
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
const token = await getAccessToken(options);
|
|
33
|
+
targetUrl.searchParams.set('srs', '3857');
|
|
34
|
+
const proxyResponse = await httpRequest('get', targetUrl.toString(), {
|
|
35
|
+
headers: {
|
|
36
|
+
Authorization: `Bearer ${token}`
|
|
37
|
+
}
|
|
38
|
+
});
|
|
37
39
|
const buffer = proxyResponse.payload;
|
|
38
40
|
const contentType = proxyResponse.res.headers['content-type'];
|
|
39
41
|
const response = h.response(buffer);
|
|
@@ -53,7 +55,44 @@ function mapProxyRoute(options) {
|
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
/**
|
|
56
|
-
* Proxies ordnance survey
|
|
58
|
+
* Proxies ordnance survey requests from the front end to api.os.uk
|
|
59
|
+
* Used for VTS map tiles forwarding on the request and adding the auth token
|
|
60
|
+
* @param {MapConfiguration} options - the map options
|
|
61
|
+
* @returns {ServerRoute<MapProxyGetRequestRefs>}
|
|
62
|
+
*/
|
|
63
|
+
function tileProxyRoute(options) {
|
|
64
|
+
return {
|
|
65
|
+
method: 'GET',
|
|
66
|
+
path: '/api/tile/{z}/{y}/{x}.pbf',
|
|
67
|
+
handler: async (request, h) => {
|
|
68
|
+
const {
|
|
69
|
+
z,
|
|
70
|
+
y,
|
|
71
|
+
x
|
|
72
|
+
} = request.params;
|
|
73
|
+
const token = await getAccessToken(options);
|
|
74
|
+
const url = `https://api.os.uk/maps/vector/v1/vts/tile/${z}/${y}/${x}.pbf?srs=3857`;
|
|
75
|
+
const {
|
|
76
|
+
payload,
|
|
77
|
+
res
|
|
78
|
+
} = await get(url, {
|
|
79
|
+
headers: {
|
|
80
|
+
Authorization: `Bearer ${token}`,
|
|
81
|
+
Accept: 'application/x-protobuf'
|
|
82
|
+
},
|
|
83
|
+
json: false,
|
|
84
|
+
gunzip: true
|
|
85
|
+
});
|
|
86
|
+
if (res.statusCode && res.statusCode !== StatusCodes.OK.valueOf()) {
|
|
87
|
+
return h.response('Tile fetch failed').code(res.statusCode);
|
|
88
|
+
}
|
|
89
|
+
return h.response(payload).type('application/x-protobuf').header('Cache-Control', 'public, max-age=86400');
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Proxies ordnance survey geocode requests from the front end to api.os.uk
|
|
57
96
|
* Used for the gazzeteer address lookup to find name from query strings like postcode and place names
|
|
58
97
|
* @param {MapConfiguration} options - the map options
|
|
59
98
|
* @returns {ServerRoute<MapGeocodeGetRequestRefs>}
|
|
@@ -80,7 +119,7 @@ function geocodeProxyRoute(options) {
|
|
|
80
119
|
}
|
|
81
120
|
|
|
82
121
|
/**
|
|
83
|
-
* Proxies ordnance survey reverse geocode requests from the front end to api.os.
|
|
122
|
+
* Proxies ordnance survey reverse geocode requests from the front end to api.os.uk
|
|
84
123
|
* Used to find name from easting and northing points.
|
|
85
124
|
* N.B this endpoint is currently not used by the front end but will be soon in "maps V2"
|
|
86
125
|
* @param {MapConfiguration} options - the map options
|
|
@@ -107,8 +146,13 @@ function reverseGeocodeProxyRoute(options) {
|
|
|
107
146
|
}
|
|
108
147
|
};
|
|
109
148
|
}
|
|
110
|
-
|
|
111
|
-
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Resource routes to return sprites and glyphs
|
|
152
|
+
* @returns {ServerRoute<MapProxyGetRequestRefs>}
|
|
153
|
+
*/
|
|
154
|
+
function mapStyleResourceRoutes() {
|
|
155
|
+
return {
|
|
112
156
|
method: 'GET',
|
|
113
157
|
path: '/api/maps/vts/{path*}',
|
|
114
158
|
options: {
|
|
@@ -118,7 +162,7 @@ function tileRoutes() {
|
|
|
118
162
|
}
|
|
119
163
|
}
|
|
120
164
|
}
|
|
121
|
-
}
|
|
165
|
+
};
|
|
122
166
|
}
|
|
123
167
|
|
|
124
168
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["resolve","Joi","find","nearest","request","httpRequest","getRoutes","options","mapProxyRoute","
|
|
1
|
+
{"version":3,"file":"index.js","names":["resolve","StatusCodes","Joi","getAccessToken","find","nearest","get","request","httpRequest","getRoutes","options","mapStyleResourceRoutes","mapProxyRoute","tileProxyRoute","geocodeProxyRoute","reverseGeocodeProxyRoute","method","path","handler","h","query","targetUrl","URL","decodeURIComponent","url","token","searchParams","set","proxyResponse","toString","headers","Authorization","buffer","payload","contentType","res","response","type","validate","object","keys","string","required","optional","z","y","x","params","Accept","json","gunzip","statusCode","OK","valueOf","code","header","_h","data","ordnanceSurveyApiKey","easting","northing","number","directory","import","meta","dirname"],"sources":["../../../../../src/server/plugins/map/routes/index.js"],"sourcesContent":["import { resolve } from 'node:path'\n\nimport { StatusCodes } from 'http-status-codes'\nimport Joi from 'joi'\n\nimport { getAccessToken } from '~/src/server/plugins/map/routes/get-os-token.js'\nimport { find, nearest } from '~/src/server/plugins/map/service.js'\nimport {\n get,\n request as httpRequest\n} from '~/src/server/services/httpService.js'\n\n/**\n * Gets the map support routes\n * @param {MapConfiguration} options - ordnance survey names api key\n */\nexport function getRoutes(options) {\n return [\n mapStyleResourceRoutes(),\n mapProxyRoute(options),\n tileProxyRoute(options),\n geocodeProxyRoute(options),\n reverseGeocodeProxyRoute(options)\n ]\n}\n\n/**\n * Proxies ordnance survey requests from the front end to api.os.com\n * Used for the VTS map source by forwarding on the request\n * and adding the auth token and SRS (spatial reference system)\n * @param {MapConfiguration} options - the map options\n * @returns {ServerRoute<MapProxyGetRequestRefs>}\n */\nfunction mapProxyRoute(options) {\n return {\n method: 'GET',\n path: '/api/map-proxy',\n handler: async (request, h) => {\n const { query } = request\n const targetUrl = new URL(decodeURIComponent(query.url))\n const token = await getAccessToken(options)\n\n targetUrl.searchParams.set('srs', '3857')\n\n const proxyResponse = await httpRequest('get', targetUrl.toString(), {\n headers: {\n Authorization: `Bearer ${token}`\n }\n })\n const buffer = proxyResponse.payload\n const contentType = proxyResponse.res.headers['content-type']\n const response = h.response(buffer)\n\n if (contentType) {\n response.type(contentType)\n }\n\n return response\n },\n options: {\n validate: {\n query: Joi.object()\n .keys({\n url: Joi.string().required()\n })\n .optional()\n }\n }\n }\n}\n\n/**\n * Proxies ordnance survey requests from the front end to api.os.uk\n * Used for VTS map tiles forwarding on the request and adding the auth token\n * @param {MapConfiguration} options - the map options\n * @returns {ServerRoute<MapProxyGetRequestRefs>}\n */\nfunction tileProxyRoute(options) {\n return {\n method: 'GET',\n path: '/api/tile/{z}/{y}/{x}.pbf',\n handler: async (request, h) => {\n const { z, y, x } = request.params\n const token = await getAccessToken(options)\n\n const url = `https://api.os.uk/maps/vector/v1/vts/tile/${z}/${y}/${x}.pbf?srs=3857`\n\n const { payload, res } = await get(url, {\n headers: {\n Authorization: `Bearer ${token}`,\n Accept: 'application/x-protobuf'\n },\n json: false,\n gunzip: true\n })\n\n if (res.statusCode && res.statusCode !== StatusCodes.OK.valueOf()) {\n return h.response('Tile fetch failed').code(res.statusCode)\n }\n\n return h\n .response(payload)\n .type('application/x-protobuf')\n .header('Cache-Control', 'public, max-age=86400')\n }\n }\n}\n\n/**\n * Proxies ordnance survey geocode requests from the front end to api.os.uk\n * Used for the gazzeteer address lookup to find name from query strings like postcode and place names\n * @param {MapConfiguration} options - the map options\n * @returns {ServerRoute<MapGeocodeGetRequestRefs>}\n */\nfunction geocodeProxyRoute(options) {\n return {\n method: 'GET',\n path: '/api/geocode-proxy',\n async handler(request, _h) {\n const { query } = request\n const data = await find(query.query, options.ordnanceSurveyApiKey)\n\n return data\n },\n options: {\n validate: {\n query: Joi.object()\n .keys({\n query: Joi.string().required()\n })\n .required()\n }\n }\n }\n}\n\n/**\n * Proxies ordnance survey reverse geocode requests from the front end to api.os.uk\n * Used to find name from easting and northing points.\n * N.B this endpoint is currently not used by the front end but will be soon in \"maps V2\"\n * @param {MapConfiguration} options - the map options\n * @returns {ServerRoute<MapReverseGeocodeGetRequestRefs>}\n */\nfunction reverseGeocodeProxyRoute(options) {\n return {\n method: 'GET',\n path: '/api/reverse-geocode-proxy',\n async handler(request, _h) {\n const { query } = request\n const data = await nearest(\n query.easting,\n query.northing,\n options.ordnanceSurveyApiKey\n )\n\n return data\n },\n options: {\n validate: {\n query: Joi.object()\n .keys({\n easting: Joi.number().required(),\n northing: Joi.number().required()\n })\n .required()\n }\n }\n }\n}\n\n/**\n * Resource routes to return sprites and glyphs\n * @returns {ServerRoute<MapProxyGetRequestRefs>}\n */\nfunction mapStyleResourceRoutes() {\n return {\n method: 'GET',\n path: '/api/maps/vts/{path*}',\n options: {\n handler: {\n directory: {\n path: resolve(import.meta.dirname, './vts')\n }\n }\n }\n }\n}\n\n/**\n * @import { ServerRoute } from '@hapi/hapi'\n * @import { MapConfiguration, MapProxyGetRequestRefs, MapGeocodeGetRequestRefs, MapReverseGeocodeGetRequestRefs } from '~/src/server/plugins/map/types.js'\n */\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../../../../src/server/plugins/map/types.js"],"sourcesContent":["/**\n * @typedef {{\n * ordnanceSurveyApiKey: string\n * }} MapConfiguration\n */\n\n//\n// Route types\n//\n\n/**\n * Map proxy query params\n * @typedef {object} MapProxyQuery\n * @property {string} url - the proxied url\n */\n\n/**\n * Map geocode query params\n * @typedef {object} MapGeocodeQuery\n * @property {string} query - name query\n */\n\n/**\n * Map reverse geocode query params\n * @typedef {object} MapReverseGeocodeQuery\n * @property {number} easting - the Easting point\n * @property {number} northing - the Northing point\n */\n\n/**\n * Map geocode get request\n * @typedef {object} MapProxyGetRequestRefs\n * @property {MapProxyQuery} Query - Request query\n */\n\n/**\n * Map geocode get request\n * @typedef {object} MapGeocodeGetRequestRefs\n * @property {MapGeocodeQuery} Query - Request query\n */\n\n/**\n * Map reverst geocode get request\n * @typedef {object} MapReverseGeocodeGetRequestRefs\n * @property {MapReverseGeocodeQuery} Query - Request query\n */\n\n/**\n * @typedef {MapProxyGetRequestRefs} MapProxyRequestRefs\n * @typedef {MapGeocodeGetRequestRefs} MapGeocodeRequestRefs\n * @typedef {MapReverseGeocodeGetRequestRefs} MapReverseGeocodeRequestRefs\n * @typedef {Request<MapGeocodeGetRequestRefs>} MapProxyGetRequest\n * @typedef {Request<MapGeocodeGetRequestRefs>} MapGeocodeGetRequest\n * @typedef {Request<MapReverseGeocodeGetRequestRefs>} MapReverseGeocodeGetRequest\n * @typedef {MapProxyGetRequest | MapGeocodeGetRequest | MapReverseGeocodeGetRequest} MapRequest\n */\n\n//\n// Service types\n//\n\n/**\n * @typedef {object} OsNamesFindResponse\n * @property {OsNamesFindHeader} header - Metadata about the search request and results.\n * @property {OsNamesFindResult[]} results - An array of matched place records from the search.\n */\n\n/**\n * @typedef {object} OsNamesFindHeader\n * @property {string} uri - The query URI (usually same as search text).\n * @property {string} query - The original text query string passed to the API.\n * @property {string} format - The response format returned (e.g., \"JSON\").\n * @property {number} maxresults - The maximum number of results requested.\n * @property {number} offset - The offset used in the search results.\n * @property {number} totalresults - The total number of results that matched the query.\n * @property {string} filter - The original filter string passed to the API.\n */\n\n/**\n * @typedef {object} OsNamesFindGazetteerEntry\n * @property {string} ID - Unique identifier for the place/feature.\n * @property {string} NAMES_URI - A URI (identifier) for this named feature.\n * @property {string} NAME1 - Primary name of the feature.\n * @property {string} TYPE - General type classification of the feature.\n * @property {string} LOCAL_TYPE - Local or more specific type classification.\n * @property {number} GEOMETRY_X - Easting coordinate (British National Grid).\n * @property {number} GEOMETRY_Y - Northing coordinate (British National Grid).\n * @property {number} MOST_DETAIL_VIEW_RES - Most detailed resolution available.\n * @property {number} LEAST_DETAIL_VIEW_RES - Least detailed resolution available.\n * @property {number} [MBR_XMIN] - Minimum bounding box X (easting).\n * @property {number} [MBR_YMIN] - Minimum bounding box Y (northing).\n * @property {number} [MBR_XMAX] - Maximum bounding box X (easting).\n * @property {number} [MBR_YMAX] - Maximum bounding box Y (northing).\n * @property {string} [DISTRICT_BOROUGH] - (Optional) District borough.\n * @property {string} [DISTRICT_BOROUGH_URI] - (Optional) URI for the district borough.\n * @property {string} [DISTRICT_BOROUGH_TYPE] - (Optional) Type of the district borough.\n * @property {string} [POSTCODE_DISTRICT] - (Optional) Postcode district.\n * @property {string} [POSTCODE_DISTRICT_URI] - (Optional) URI for the postcode district.\n * @property {string} [POPULATED_PLACE] - (Optional) Name of associated populated place.\n * @property {string} [POPULATED_PLACE_URI] - (Optional) URI of populated place.\n * @property {string} [POPULATED_PLACE_TYPE] - (Optional) Type of populated place.\n * @property {string} [COUNTY_UNITARY] - (Optional) County or unitary authority name.\n * @property {string} [COUNTY_UNITARY_URI] - (Optional) URI for county/unitary authority.\n * @property {string} [COUNTY_UNITARY_TYPE] - (Optional) Classification of county/unitary authority.\n * @property {string} [REGION] - (Optional) Region name.\n * @property {string} [REGION_URI] - (Optional) URI for region.\n * @property {string} [COUNTRY] - (Optional) Country name.\n * @property {string} [COUNTRY_URI] - (Optional) URI for country.\n */\n\n/**\n * OS names GAZETTEER_ENTRY response\n * @typedef {object} OsNamesFindResult\n * @property {OsNamesFindGazetteerEntry} GAZETTEER_ENTRY - Gazetteer entry\n */\n\n/**\n * @import { Request } from '@hapi/hapi'\n */\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../../../../src/server/plugins/map/types.js"],"sourcesContent":["/**\n * @typedef {{\n * ordnanceSurveyApiKey: string\n * ordnanceSurveyApiSecret: string\n * }} MapConfiguration\n */\n\n//\n// Route types\n//\n\n/**\n * Map proxy query params\n * @typedef {object} MapProxyQuery\n * @property {string} url - the proxied url\n */\n\n/**\n * Map geocode query params\n * @typedef {object} MapGeocodeQuery\n * @property {string} query - name query\n */\n\n/**\n * Map reverse geocode query params\n * @typedef {object} MapReverseGeocodeQuery\n * @property {number} easting - the Easting point\n * @property {number} northing - the Northing point\n */\n\n/**\n * Map geocode get request\n * @typedef {object} MapProxyGetRequestRefs\n * @property {MapProxyQuery} Query - Request query\n */\n\n/**\n * Map geocode get request\n * @typedef {object} MapGeocodeGetRequestRefs\n * @property {MapGeocodeQuery} Query - Request query\n */\n\n/**\n * Map reverst geocode get request\n * @typedef {object} MapReverseGeocodeGetRequestRefs\n * @property {MapReverseGeocodeQuery} Query - Request query\n */\n\n/**\n * @typedef {MapProxyGetRequestRefs} MapProxyRequestRefs\n * @typedef {MapGeocodeGetRequestRefs} MapGeocodeRequestRefs\n * @typedef {MapReverseGeocodeGetRequestRefs} MapReverseGeocodeRequestRefs\n * @typedef {Request<MapGeocodeGetRequestRefs>} MapProxyGetRequest\n * @typedef {Request<MapGeocodeGetRequestRefs>} MapGeocodeGetRequest\n * @typedef {Request<MapReverseGeocodeGetRequestRefs>} MapReverseGeocodeGetRequest\n * @typedef {MapProxyGetRequest | MapGeocodeGetRequest | MapReverseGeocodeGetRequest} MapRequest\n */\n\n//\n// Service types\n//\n\n/**\n * @typedef {object} OsNamesFindResponse\n * @property {OsNamesFindHeader} header - Metadata about the search request and results.\n * @property {OsNamesFindResult[]} results - An array of matched place records from the search.\n */\n\n/**\n * @typedef {object} OsNamesFindHeader\n * @property {string} uri - The query URI (usually same as search text).\n * @property {string} query - The original text query string passed to the API.\n * @property {string} format - The response format returned (e.g., \"JSON\").\n * @property {number} maxresults - The maximum number of results requested.\n * @property {number} offset - The offset used in the search results.\n * @property {number} totalresults - The total number of results that matched the query.\n * @property {string} filter - The original filter string passed to the API.\n */\n\n/**\n * @typedef {object} OsNamesFindGazetteerEntry\n * @property {string} ID - Unique identifier for the place/feature.\n * @property {string} NAMES_URI - A URI (identifier) for this named feature.\n * @property {string} NAME1 - Primary name of the feature.\n * @property {string} TYPE - General type classification of the feature.\n * @property {string} LOCAL_TYPE - Local or more specific type classification.\n * @property {number} GEOMETRY_X - Easting coordinate (British National Grid).\n * @property {number} GEOMETRY_Y - Northing coordinate (British National Grid).\n * @property {number} MOST_DETAIL_VIEW_RES - Most detailed resolution available.\n * @property {number} LEAST_DETAIL_VIEW_RES - Least detailed resolution available.\n * @property {number} [MBR_XMIN] - Minimum bounding box X (easting).\n * @property {number} [MBR_YMIN] - Minimum bounding box Y (northing).\n * @property {number} [MBR_XMAX] - Maximum bounding box X (easting).\n * @property {number} [MBR_YMAX] - Maximum bounding box Y (northing).\n * @property {string} [DISTRICT_BOROUGH] - (Optional) District borough.\n * @property {string} [DISTRICT_BOROUGH_URI] - (Optional) URI for the district borough.\n * @property {string} [DISTRICT_BOROUGH_TYPE] - (Optional) Type of the district borough.\n * @property {string} [POSTCODE_DISTRICT] - (Optional) Postcode district.\n * @property {string} [POSTCODE_DISTRICT_URI] - (Optional) URI for the postcode district.\n * @property {string} [POPULATED_PLACE] - (Optional) Name of associated populated place.\n * @property {string} [POPULATED_PLACE_URI] - (Optional) URI of populated place.\n * @property {string} [POPULATED_PLACE_TYPE] - (Optional) Type of populated place.\n * @property {string} [COUNTY_UNITARY] - (Optional) County or unitary authority name.\n * @property {string} [COUNTY_UNITARY_URI] - (Optional) URI for county/unitary authority.\n * @property {string} [COUNTY_UNITARY_TYPE] - (Optional) Classification of county/unitary authority.\n * @property {string} [REGION] - (Optional) Region name.\n * @property {string} [REGION_URI] - (Optional) URI for region.\n * @property {string} [COUNTRY] - (Optional) Country name.\n * @property {string} [COUNTRY_URI] - (Optional) URI for country.\n */\n\n/**\n * OS names GAZETTEER_ENTRY response\n * @typedef {object} OsNamesFindResult\n * @property {OsNamesFindGazetteerEntry} GAZETTEER_ENTRY - Gazetteer entry\n */\n\n/**\n * @import { Request } from '@hapi/hapi'\n */\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA","ignoreList":[]}
|
|
@@ -34,6 +34,7 @@ export interface RouteConfig {
|
|
|
34
34
|
saveAndExit?: PluginOptions['saveAndExit'];
|
|
35
35
|
cacheServiceCreator?: (server: Server) => CacheService;
|
|
36
36
|
ordnanceSurveyApiKey?: string;
|
|
37
|
+
ordnanceSurveyApiSecret?: string;
|
|
37
38
|
}
|
|
38
39
|
export interface OutputService {
|
|
39
40
|
submit: (context: FormContext, request: FormRequestPayload, model: FormModel, emailAddress: string, items: DetailItem[], submitResponse: SubmitResponsePayload, formMetadata?: FormMetadata) => Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../../src/server/types.ts"],"sourcesContent":["import {\n type FormDefinition,\n type FormMetadata,\n type SubmitPayload,\n type SubmitResponsePayload\n} from '@defra/forms-model'\nimport { type Server } from '@hapi/hapi'\n\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type DetailItem } from '~/src/server/plugins/engine/models/types.js'\nimport { type PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'\nimport {\n type FormContext,\n type OnRequestCallback,\n type PluginOptions,\n type PreparePageEventRequestOptions\n} from '~/src/server/plugins/engine/types.js'\nimport {\n type FormRequestPayload,\n type FormStatus\n} from '~/src/server/routes/types.js'\nimport { type CacheService } from '~/src/server/services/cacheService.js'\n\nexport interface FormsService {\n getFormMetadata: (slug: string) => Promise<FormMetadata>\n getFormMetadataById: (id: string) => Promise<FormMetadata>\n getFormDefinition: (\n id: string,\n state: FormStatus\n ) => Promise<FormDefinition | undefined>\n}\n\nexport interface FormSubmissionService {\n persistFiles: (\n files: { fileId: string; initiatedRetrievalKey: string }[],\n persistedRetrievalKey: string\n ) => Promise<object>\n submit: (data: SubmitPayload) => Promise<SubmitResponsePayload | undefined>\n}\n\nexport interface Services {\n formsService: FormsService\n formSubmissionService: FormSubmissionService\n outputService: OutputService\n}\n\nexport interface RouteConfig {\n formFileName?: string\n formFilePath?: string\n enforceCsrf?: boolean\n services?: Services\n controllers?: Record<string, typeof PageController>\n preparePageEventRequestOptions?: PreparePageEventRequestOptions\n onRequest?: OnRequestCallback\n saveAndExit?: PluginOptions['saveAndExit']\n cacheServiceCreator?: (server: Server) => CacheService\n ordnanceSurveyApiKey?: string\n}\n\nexport interface OutputService {\n submit: (\n context: FormContext,\n request: FormRequestPayload,\n model: FormModel,\n emailAddress: string,\n items: DetailItem[],\n submitResponse: SubmitResponsePayload,\n formMetadata?: FormMetadata\n ) => Promise<void>\n}\n"],"mappings":"","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../../src/server/types.ts"],"sourcesContent":["import {\n type FormDefinition,\n type FormMetadata,\n type SubmitPayload,\n type SubmitResponsePayload\n} from '@defra/forms-model'\nimport { type Server } from '@hapi/hapi'\n\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type DetailItem } from '~/src/server/plugins/engine/models/types.js'\nimport { type PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'\nimport {\n type FormContext,\n type OnRequestCallback,\n type PluginOptions,\n type PreparePageEventRequestOptions\n} from '~/src/server/plugins/engine/types.js'\nimport {\n type FormRequestPayload,\n type FormStatus\n} from '~/src/server/routes/types.js'\nimport { type CacheService } from '~/src/server/services/cacheService.js'\n\nexport interface FormsService {\n getFormMetadata: (slug: string) => Promise<FormMetadata>\n getFormMetadataById: (id: string) => Promise<FormMetadata>\n getFormDefinition: (\n id: string,\n state: FormStatus\n ) => Promise<FormDefinition | undefined>\n}\n\nexport interface FormSubmissionService {\n persistFiles: (\n files: { fileId: string; initiatedRetrievalKey: string }[],\n persistedRetrievalKey: string\n ) => Promise<object>\n submit: (data: SubmitPayload) => Promise<SubmitResponsePayload | undefined>\n}\n\nexport interface Services {\n formsService: FormsService\n formSubmissionService: FormSubmissionService\n outputService: OutputService\n}\n\nexport interface RouteConfig {\n formFileName?: string\n formFilePath?: string\n enforceCsrf?: boolean\n services?: Services\n controllers?: Record<string, typeof PageController>\n preparePageEventRequestOptions?: PreparePageEventRequestOptions\n onRequest?: OnRequestCallback\n saveAndExit?: PluginOptions['saveAndExit']\n cacheServiceCreator?: (server: Server) => CacheService\n ordnanceSurveyApiKey?: string\n ordnanceSurveyApiSecret?: string\n}\n\nexport interface OutputService {\n submit: (\n context: FormContext,\n request: FormRequestPayload,\n model: FormModel,\n emailAddress: string,\n items: DetailItem[],\n submitResponse: SubmitResponsePayload,\n formMetadata?: FormMetadata\n ) => Promise<void>\n}\n"],"mappings":"","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -138,10 +138,18 @@ export function makeTileRequestTransformer(apiPath) {
|
|
|
138
138
|
* @param {string} resourceType - the resource type
|
|
139
139
|
*/
|
|
140
140
|
return function transformTileRequest(url, resourceType) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
141
|
+
if (url.startsWith('https://api.os.uk')) {
|
|
142
|
+
if (resourceType === 'Tile') {
|
|
143
|
+
return {
|
|
144
|
+
url: url.replace(
|
|
145
|
+
'https://api.os.uk/maps/vector/v1/vts',
|
|
146
|
+
`${window.location.origin}${apiPath}`
|
|
147
|
+
),
|
|
148
|
+
headers: {}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (resourceType !== 'Style') {
|
|
145
153
|
return {
|
|
146
154
|
url: `${apiPath}/map-proxy?url=${encodeURIComponent(url)}`,
|
|
147
155
|
headers: {}
|
|
@@ -22,7 +22,8 @@ export const configureEnginePlugin = async (
|
|
|
22
22
|
preparePageEventRequestOptions,
|
|
23
23
|
onRequest,
|
|
24
24
|
saveAndExit,
|
|
25
|
-
ordnanceSurveyApiKey
|
|
25
|
+
ordnanceSurveyApiKey,
|
|
26
|
+
ordnanceSurveyApiSecret
|
|
26
27
|
}: RouteConfig = {},
|
|
27
28
|
cache?: CacheService
|
|
28
29
|
): Promise<{
|
|
@@ -65,7 +66,8 @@ export const configureEnginePlugin = async (
|
|
|
65
66
|
onRequest,
|
|
66
67
|
baseUrl: 'http://localhost:3009', // always runs locally
|
|
67
68
|
saveAndExit,
|
|
68
|
-
ordnanceSurveyApiKey
|
|
69
|
+
ordnanceSurveyApiKey,
|
|
70
|
+
ordnanceSurveyApiSecret
|
|
69
71
|
}
|
|
70
72
|
}
|
|
71
73
|
}
|
|
@@ -26,7 +26,8 @@ const pluginRegistrationOptionsSchema = Joi.object({
|
|
|
26
26
|
onRequest: Joi.function().optional(),
|
|
27
27
|
baseUrl: Joi.string().uri().required(),
|
|
28
28
|
saveAndExit: Joi.function().optional(),
|
|
29
|
-
ordnanceSurveyApiKey: Joi.string().optional()
|
|
29
|
+
ordnanceSurveyApiKey: Joi.string().optional(),
|
|
30
|
+
ordnanceSurveyApiSecret: Joi.string().optional()
|
|
30
31
|
})
|
|
31
32
|
|
|
32
33
|
/**
|
|
@@ -38,7 +38,8 @@ export const plugin = {
|
|
|
38
38
|
viewContext,
|
|
39
39
|
preparePageEventRequestOptions,
|
|
40
40
|
onRequest,
|
|
41
|
-
ordnanceSurveyApiKey
|
|
41
|
+
ordnanceSurveyApiKey,
|
|
42
|
+
ordnanceSurveyApiSecret
|
|
42
43
|
} = options
|
|
43
44
|
|
|
44
45
|
const cacheService =
|
|
@@ -58,12 +59,13 @@ export const plugin = {
|
|
|
58
59
|
})
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
// Register the maps plugin only if we have an OS api key
|
|
62
|
-
if (ordnanceSurveyApiKey) {
|
|
62
|
+
// Register the maps plugin only if we have an OS api key & secret
|
|
63
|
+
if (ordnanceSurveyApiKey && ordnanceSurveyApiSecret) {
|
|
63
64
|
await server.register({
|
|
64
65
|
plugin: mapPlugin,
|
|
65
66
|
options: {
|
|
66
|
-
ordnanceSurveyApiKey
|
|
67
|
+
ordnanceSurveyApiKey,
|
|
68
|
+
ordnanceSurveyApiSecret
|
|
67
69
|
}
|
|
68
70
|
})
|
|
69
71
|
}
|
|
@@ -423,6 +423,7 @@ export interface PluginOptions {
|
|
|
423
423
|
onRequest?: OnRequestCallback
|
|
424
424
|
baseUrl: string // base URL of the application, protocol and hostname e.g. "https://myapp.com"
|
|
425
425
|
ordnanceSurveyApiKey?: string
|
|
426
|
+
ordnanceSurveyApiSecret?: string
|
|
426
427
|
}
|
|
427
428
|
|
|
428
429
|
export interface FormAdapterSubmissionMessageMeta {
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { post } from '~/src/server/services/httpService.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @type {string}
|
|
5
|
+
*/
|
|
6
|
+
let cachedToken
|
|
7
|
+
let tokenExpiry = 0
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Get Ordnance Survey OAuth token
|
|
11
|
+
* @param {MapConfiguration} options - Ordnance survey map options
|
|
12
|
+
*/
|
|
13
|
+
export async function getAccessToken(options) {
|
|
14
|
+
const { ordnanceSurveyApiKey: key, ordnanceSurveyApiSecret: secret } = options
|
|
15
|
+
const now = Date.now()
|
|
16
|
+
|
|
17
|
+
if (cachedToken && now < tokenExpiry) {
|
|
18
|
+
return cachedToken
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const creds = `${key}:${secret}`
|
|
22
|
+
const result = await post('https://api.os.uk/oauth2/token/v1', {
|
|
23
|
+
headers: {
|
|
24
|
+
Authorization: `Basic ${btoa(creds)}`,
|
|
25
|
+
'Content-Type': 'application/x-www-form-urlencoded'
|
|
26
|
+
},
|
|
27
|
+
payload: 'grant_type=client_credentials',
|
|
28
|
+
json: true
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
const data = result.payload
|
|
32
|
+
|
|
33
|
+
cachedToken = data.access_token
|
|
34
|
+
tokenExpiry = now + (data.expires_in - 60) * 1000 // refresh early
|
|
35
|
+
|
|
36
|
+
return cachedToken
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @import { MapConfiguration } from '~/src/server/plugins/map/types.js'
|
|
41
|
+
*/
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { getAccessToken } from '~/src/server/plugins/map/routes/get-os-token.js'
|
|
2
|
+
import { post } from '~/src/server/services/httpService.js'
|
|
3
|
+
|
|
4
|
+
jest.mock('~/src/server/services/httpService.ts')
|
|
5
|
+
|
|
6
|
+
describe('OS OAuth token', () => {
|
|
7
|
+
describe('getAccessToken', () => {
|
|
8
|
+
it('should get access token', async () => {
|
|
9
|
+
jest.mocked(post).mockResolvedValueOnce({
|
|
10
|
+
res: /** @type {IncomingMessage} */ ({
|
|
11
|
+
statusCode: 200,
|
|
12
|
+
headers: {}
|
|
13
|
+
}),
|
|
14
|
+
payload: {
|
|
15
|
+
access_token: 'access_token',
|
|
16
|
+
expires_in: '299',
|
|
17
|
+
issued_at: '1770036762387',
|
|
18
|
+
token_type: 'Bearer'
|
|
19
|
+
},
|
|
20
|
+
error: undefined
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const token = await getAccessToken({
|
|
24
|
+
ordnanceSurveyApiKey: 'apikey',
|
|
25
|
+
ordnanceSurveyApiSecret: 'apisecret'
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
expect(token).toBe('access_token')
|
|
29
|
+
|
|
30
|
+
expect(post).toHaveBeenCalledWith('https://api.os.uk/oauth2/token/v1', {
|
|
31
|
+
headers: {
|
|
32
|
+
Authorization: `Basic ${btoa('apikey:apisecret')}`,
|
|
33
|
+
'Content-Type': 'application/x-www-form-urlencoded'
|
|
34
|
+
},
|
|
35
|
+
payload: 'grant_type=client_credentials',
|
|
36
|
+
json: true
|
|
37
|
+
})
|
|
38
|
+
expect(post).toHaveBeenCalledTimes(1)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('should return an cached token', async () => {
|
|
42
|
+
const token = await getAccessToken({
|
|
43
|
+
ordnanceSurveyApiKey: 'apikey',
|
|
44
|
+
ordnanceSurveyApiSecret: 'apisecret'
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
expect(token).toBe('access_token')
|
|
48
|
+
expect(post).toHaveBeenCalledTimes(0)
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @import { IncomingMessage } from 'node:http'
|
|
55
|
+
*/
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { resolve } from 'node:path'
|
|
2
2
|
|
|
3
|
+
import { StatusCodes } from 'http-status-codes'
|
|
3
4
|
import Joi from 'joi'
|
|
4
5
|
|
|
6
|
+
import { getAccessToken } from '~/src/server/plugins/map/routes/get-os-token.js'
|
|
5
7
|
import { find, nearest } from '~/src/server/plugins/map/service.js'
|
|
6
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
get,
|
|
10
|
+
request as httpRequest
|
|
11
|
+
} from '~/src/server/services/httpService.js'
|
|
7
12
|
|
|
8
13
|
/**
|
|
9
14
|
* Gets the map support routes
|
|
@@ -11,17 +16,18 @@ import { request as httpRequest } from '~/src/server/services/httpService.js'
|
|
|
11
16
|
*/
|
|
12
17
|
export function getRoutes(options) {
|
|
13
18
|
return [
|
|
19
|
+
mapStyleResourceRoutes(),
|
|
14
20
|
mapProxyRoute(options),
|
|
21
|
+
tileProxyRoute(options),
|
|
15
22
|
geocodeProxyRoute(options),
|
|
16
|
-
reverseGeocodeProxyRoute(options)
|
|
17
|
-
...tileRoutes()
|
|
23
|
+
reverseGeocodeProxyRoute(options)
|
|
18
24
|
]
|
|
19
25
|
}
|
|
20
26
|
|
|
21
27
|
/**
|
|
22
28
|
* Proxies ordnance survey requests from the front end to api.os.com
|
|
23
|
-
* Used for VTS map
|
|
24
|
-
* and adding the
|
|
29
|
+
* Used for the VTS map source by forwarding on the request
|
|
30
|
+
* and adding the auth token and SRS (spatial reference system)
|
|
25
31
|
* @param {MapConfiguration} options - the map options
|
|
26
32
|
* @returns {ServerRoute<MapProxyGetRequestRefs>}
|
|
27
33
|
*/
|
|
@@ -32,14 +38,15 @@ function mapProxyRoute(options) {
|
|
|
32
38
|
handler: async (request, h) => {
|
|
33
39
|
const { query } = request
|
|
34
40
|
const targetUrl = new URL(decodeURIComponent(query.url))
|
|
41
|
+
const token = await getAccessToken(options)
|
|
35
42
|
|
|
36
|
-
|
|
37
|
-
targetUrl.searchParams.set('key', options.ordnanceSurveyApiKey)
|
|
38
|
-
if (!targetUrl.searchParams.has('srs')) {
|
|
39
|
-
targetUrl.searchParams.set('srs', '3857')
|
|
40
|
-
}
|
|
43
|
+
targetUrl.searchParams.set('srs', '3857')
|
|
41
44
|
|
|
42
|
-
const proxyResponse = await httpRequest('get', targetUrl.toString()
|
|
45
|
+
const proxyResponse = await httpRequest('get', targetUrl.toString(), {
|
|
46
|
+
headers: {
|
|
47
|
+
Authorization: `Bearer ${token}`
|
|
48
|
+
}
|
|
49
|
+
})
|
|
43
50
|
const buffer = proxyResponse.payload
|
|
44
51
|
const contentType = proxyResponse.res.headers['content-type']
|
|
45
52
|
const response = h.response(buffer)
|
|
@@ -63,7 +70,44 @@ function mapProxyRoute(options) {
|
|
|
63
70
|
}
|
|
64
71
|
|
|
65
72
|
/**
|
|
66
|
-
* Proxies ordnance survey
|
|
73
|
+
* Proxies ordnance survey requests from the front end to api.os.uk
|
|
74
|
+
* Used for VTS map tiles forwarding on the request and adding the auth token
|
|
75
|
+
* @param {MapConfiguration} options - the map options
|
|
76
|
+
* @returns {ServerRoute<MapProxyGetRequestRefs>}
|
|
77
|
+
*/
|
|
78
|
+
function tileProxyRoute(options) {
|
|
79
|
+
return {
|
|
80
|
+
method: 'GET',
|
|
81
|
+
path: '/api/tile/{z}/{y}/{x}.pbf',
|
|
82
|
+
handler: async (request, h) => {
|
|
83
|
+
const { z, y, x } = request.params
|
|
84
|
+
const token = await getAccessToken(options)
|
|
85
|
+
|
|
86
|
+
const url = `https://api.os.uk/maps/vector/v1/vts/tile/${z}/${y}/${x}.pbf?srs=3857`
|
|
87
|
+
|
|
88
|
+
const { payload, res } = await get(url, {
|
|
89
|
+
headers: {
|
|
90
|
+
Authorization: `Bearer ${token}`,
|
|
91
|
+
Accept: 'application/x-protobuf'
|
|
92
|
+
},
|
|
93
|
+
json: false,
|
|
94
|
+
gunzip: true
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
if (res.statusCode && res.statusCode !== StatusCodes.OK.valueOf()) {
|
|
98
|
+
return h.response('Tile fetch failed').code(res.statusCode)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return h
|
|
102
|
+
.response(payload)
|
|
103
|
+
.type('application/x-protobuf')
|
|
104
|
+
.header('Cache-Control', 'public, max-age=86400')
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Proxies ordnance survey geocode requests from the front end to api.os.uk
|
|
67
111
|
* Used for the gazzeteer address lookup to find name from query strings like postcode and place names
|
|
68
112
|
* @param {MapConfiguration} options - the map options
|
|
69
113
|
* @returns {ServerRoute<MapGeocodeGetRequestRefs>}
|
|
@@ -91,7 +135,7 @@ function geocodeProxyRoute(options) {
|
|
|
91
135
|
}
|
|
92
136
|
|
|
93
137
|
/**
|
|
94
|
-
* Proxies ordnance survey reverse geocode requests from the front end to api.os.
|
|
138
|
+
* Proxies ordnance survey reverse geocode requests from the front end to api.os.uk
|
|
95
139
|
* Used to find name from easting and northing points.
|
|
96
140
|
* N.B this endpoint is currently not used by the front end but will be soon in "maps V2"
|
|
97
141
|
* @param {MapConfiguration} options - the map options
|
|
@@ -124,20 +168,22 @@ function reverseGeocodeProxyRoute(options) {
|
|
|
124
168
|
}
|
|
125
169
|
}
|
|
126
170
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
171
|
+
/**
|
|
172
|
+
* Resource routes to return sprites and glyphs
|
|
173
|
+
* @returns {ServerRoute<MapProxyGetRequestRefs>}
|
|
174
|
+
*/
|
|
175
|
+
function mapStyleResourceRoutes() {
|
|
176
|
+
return {
|
|
177
|
+
method: 'GET',
|
|
178
|
+
path: '/api/maps/vts/{path*}',
|
|
179
|
+
options: {
|
|
180
|
+
handler: {
|
|
181
|
+
directory: {
|
|
182
|
+
path: resolve(import.meta.dirname, './vts')
|
|
137
183
|
}
|
|
138
184
|
}
|
|
139
185
|
}
|
|
140
|
-
|
|
186
|
+
}
|
|
141
187
|
}
|
|
142
188
|
|
|
143
189
|
/**
|
package/src/server/types.ts
CHANGED