@mountainpass/addressr 2.1.2 → 2.1.4
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/README.md +72 -10
- package/lib/src/proxy-auth.js +53 -0
- package/lib/src/waycharter-server.js +636 -172
- package/lib/version.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,18 +1,38 @@
|
|
|
1
1
|
# Addressr
|
|
2
2
|
|
|
3
|
-

|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**The only open-source, free self-hosted Australian address validation API.**
|
|
6
6
|
|
|
7
|
-
[
|
|
7
|
+
[Australian Address Validation, Search and Autocomplete](https://addressr.io) — [addressr.io](https://addressr.io)
|
|
8
8
|
|
|
9
|
-
[](https://github.com/mountain-pass/addressr/blob/master/LICENSE) [](https://www.npmjs.com/package/@mountainpass/addressr) [](https://www.npmjs.com/package/@mountainpass/addressr)
|
|
10
10
|
|
|
11
11
|
[](https://github.com/mountain-pass/addressr/issues) [](https://github.com/mountain-pass/addressr/pulls)
|
|
12
12
|
|
|
13
13
|
# About
|
|
14
14
|
|
|
15
|
-
Australian Address Validation, Search and Autocomplete powered by the Geocoded National Address File (G-NAF), Australia
|
|
15
|
+
Australian Address Validation, Search and Autocomplete powered by the Geocoded National Address File (G-NAF), Australia's **authoritative** address database with 15+ million addresses.
|
|
16
|
+
|
|
17
|
+
- **Validated addresses** from the official G-NAF source
|
|
18
|
+
- **Real-time autocomplete** with fuzzy matching
|
|
19
|
+
- **Locality, postcode, and state search** for area pickers
|
|
20
|
+
- **Geocoding** to latitude/longitude (optional)
|
|
21
|
+
- **Self-hosted or SaaS** — your choice, your data
|
|
22
|
+
- **Open source** — audit the code, customize as needed
|
|
23
|
+
|
|
24
|
+
# Why Addressr
|
|
25
|
+
|
|
26
|
+
| | Addressr | [Addressify](https://addressify.com.au/) | [AddressFinder](https://addressfinder.com.au/) | [Geoscape](https://geoscape.com.au/) | Google Maps |
|
|
27
|
+
| ---------------------------------- | -------- | ---------------------------------------- | ---------------------------------------------- | ------------------------------------ | ----------- |
|
|
28
|
+
| Self-hosted | ✅ | ❌ | ❌ | ❌ | ❌ |
|
|
29
|
+
| Open source | ✅ | ❌ | ❌ | ❌ | ❌ |
|
|
30
|
+
| Free tier (unlimited, self-hosted) | ✅ | ❌ | ❌ | ❌ | ❌ |
|
|
31
|
+
| G-NAF data source | ✅ | ✅ | ✅ | ✅ (creator) | ❌ |
|
|
32
|
+
| Data sovereignty | ✅ | ❌ | ❌ | ❌ | ❌ |
|
|
33
|
+
| MCP integration for AI assistants | ✅ | ❌ | ❌ | ❌ | ❌ |
|
|
34
|
+
|
|
35
|
+
**Stop paying Google Maps for Australian addresses.** Stop locking your data into third-party SaaS. Addressr gives you unlimited address validation on your own infrastructure, or a cheap hosted API if you prefer.
|
|
16
36
|
|
|
17
37
|
# Quick Start
|
|
18
38
|
|
|
@@ -85,15 +105,15 @@ Run Addressr on your own infrastructure for full control over your data.
|
|
|
85
105
|
export ADDRESSR_INDEX_BACKOFF_MAX=10000
|
|
86
106
|
```
|
|
87
107
|
|
|
88
|
-
1. Optional
|
|
89
|
-
**NOTE:** with geocodes enabled, indexing takes much longer and needs much more memory. Only
|
|
108
|
+
1. Optional — enable geocodes by setting the following env vars for the data loader. In the third window run:
|
|
109
|
+
**NOTE:** with geocodes enabled, indexing takes much longer and needs much more memory. Only turn them on if you need them. You can always add them later.
|
|
90
110
|
|
|
91
111
|
```
|
|
92
112
|
export ADDRESSR_ENABLE_GEO=1
|
|
93
113
|
export NODE_OPTIONS=--max_old_space_size=8196
|
|
94
114
|
```
|
|
95
115
|
|
|
96
|
-
2. Optional
|
|
116
|
+
2. Optional — limit the addresses to a single state by setting the `COVERED_STATES` env var for the data loader.
|
|
97
117
|
This dramatically speeds up indexing. For example, in the third window run:
|
|
98
118
|
|
|
99
119
|
```
|
|
@@ -117,7 +137,8 @@ Run Addressr on your own infrastructure for full control over your data.
|
|
|
117
137
|
addressr-loader
|
|
118
138
|
```
|
|
119
139
|
|
|
120
|
-
6. OK, so we stretched the truth a bit with the "Quick Start" heading. The truth is that it takes quite a while to download, store and index the
|
|
140
|
+
6. OK, so we stretched the truth a bit with the "Quick Start" heading. The truth is that it takes quite a while to download, store and index the 15+ million addresses from [data.gov.au](http://data.gov.au/). So make a coffee, or tea, or find something else to do and come back in about an hour when it's done.
|
|
141
|
+
|
|
121
142
|
7. Search for an address using the command line
|
|
122
143
|
|
|
123
144
|
```
|
|
@@ -125,7 +146,24 @@ Run Addressr on your own infrastructure for full control over your data.
|
|
|
125
146
|
```
|
|
126
147
|
|
|
127
148
|
8. An updated G-NAF is released every 3 months. Put `addressr-loader` in a cron job or similar to keep addressr regularly updated
|
|
128
|
-
9. Wire
|
|
149
|
+
9. Wire your address form up to the address-server api.
|
|
150
|
+
|
|
151
|
+
# API Endpoints
|
|
152
|
+
|
|
153
|
+
Addressr exposes a HATEOAS REST API. Start at the root (`/`) and follow links to discover endpoints. A supplementary OpenAPI 3.x spec is available at `/api-docs`.
|
|
154
|
+
|
|
155
|
+
| Endpoint | Purpose | Example |
|
|
156
|
+
| ---------------------------- | ------------------------------------------------------------------ | --------------------------------- |
|
|
157
|
+
| `GET /addresses?q=` | Search and autocomplete addresses | `/addresses?q=1+george+st+sydney` |
|
|
158
|
+
| `GET /addresses/{pid}` | Get full address details (with links to locality, postcode, state) | `/addresses/GAOT_717882967` |
|
|
159
|
+
| `GET /localities?q=` | Search suburbs/localities by name | `/localities?q=lilydale` |
|
|
160
|
+
| `GET /localities/{pid}` | Get locality details (with links to postcode, state) | `/localities/loc9984d8beb142` |
|
|
161
|
+
| `GET /postcodes?q=` | Search postcodes (q optional) | `/postcodes?q=3140` |
|
|
162
|
+
| `GET /postcodes/{postcode}` | Get postcode with associated localities | `/postcodes/6798` |
|
|
163
|
+
| `GET /states?q=` | Search states/territories (q optional) | `/states?q=New` |
|
|
164
|
+
| `GET /states/{abbreviation}` | Get state details | `/states/NSW` |
|
|
165
|
+
| `GET /api-docs` | OpenAPI 3.x specification | `/api-docs` |
|
|
166
|
+
| `GET /health` | Health check | `/health` |
|
|
129
167
|
|
|
130
168
|
## How it Works
|
|
131
169
|
|
|
@@ -148,6 +186,30 @@ Run Addressr on your own infrastructure for full control over your data.
|
|
|
148
186
|
| ADDRESSR_ACCESS_CONTROL_EXPOSE_HEADERS | _non-blank_ | An `Access-Control-Expose-Headers` response header is returned with the value in the environment variable | |
|
|
149
187
|
| ADDRESSR_ACCESS_CONTROL_ALLOW_HEADERS | _blank_ | An `Access-Control-Allow-Headers` response header is **not** returned | ✅ |
|
|
150
188
|
| ADDRESSR_ACCESS_CONTROL_ALLOW_HEADERS | _non-blank_ | An `Access-Control-Allow-Headers` response header is returned with the value in the environment variable | |
|
|
189
|
+
| ADDRESSR_PROXY_AUTH_HEADER | _blank_ | No gateway auth header enforcement (self-hosted default) | ✅ |
|
|
190
|
+
| ADDRESSR_PROXY_AUTH_HEADER | _non-blank_ | Name of the header the origin requires — set alongside `ADDRESSR_PROXY_AUTH_VALUE` | |
|
|
191
|
+
| ADDRESSR_PROXY_AUTH_VALUE | _blank_ | No gateway auth header enforcement (self-hosted default) | ✅ |
|
|
192
|
+
| ADDRESSR_PROXY_AUTH_VALUE | _non-blank_ | Expected value the header must carry — set alongside `ADDRESSR_PROXY_AUTH_HEADER` | |
|
|
193
|
+
|
|
194
|
+
### Gateway auth header (optional)
|
|
195
|
+
|
|
196
|
+
By default Addressr does not enforce any proxy authentication — self-hosted npm and Docker deployments work with zero configuration.
|
|
197
|
+
|
|
198
|
+
If you front Addressr with an API gateway (RapidAPI, Kong, Tyk, Apigee, AWS API Gateway, nginx, Caddy, or your own Cloudflare Worker) and want the origin to reject traffic that bypasses your gateway, set both environment variables to the header name your gateway injects and the shared secret it forwards:
|
|
199
|
+
|
|
200
|
+
| Variable | Example | Notes |
|
|
201
|
+
| ---------------------------- | ------------------------- | ------------------------------------------- |
|
|
202
|
+
| `ADDRESSR_PROXY_AUTH_HEADER` | `X-RapidAPI-Proxy-Secret` | Header name your gateway forwards |
|
|
203
|
+
| `ADDRESSR_PROXY_AUTH_VALUE` | `<your-gateway-secret>` | Expected value; keep out of version control |
|
|
204
|
+
|
|
205
|
+
Behaviour:
|
|
206
|
+
|
|
207
|
+
- Both unset → no enforcement (default).
|
|
208
|
+
- Both set → requests without a matching header receive `401 Authentication required`.
|
|
209
|
+
- Exactly one set → the process exits at startup with a clear error (fails loud to prevent silent bypass).
|
|
210
|
+
- `/health` and `/api-docs` remain reachable without the header so uptime monitors and gateway OpenAPI imports keep working.
|
|
211
|
+
|
|
212
|
+
See [ADR 024](docs/decisions/024-origin-gateway-auth-header-enforcement.proposed.md) for the decision record.
|
|
151
213
|
|
|
152
214
|
NOTE: When adjusting PAGE_SIZE, you should take into account how quickly you want the initial results returned to the user. In many use cases, you want this to be as fast as possible. If you need show more results to the user, you are often better off leaving it a 8 and using the paging links to get more results while you are displaying the first 8.
|
|
153
215
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.proxyAuthMiddleware = proxyAuthMiddleware;
|
|
7
|
+
exports.validateProxyAuthConfig = validateProxyAuthConfig;
|
|
8
|
+
var _debug = _interopRequireDefault(require("debug"));
|
|
9
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
/* eslint-disable @eslint-community/eslint-comments/disable-enable-pair */
|
|
11
|
+
/* eslint-disable security/detect-object-injection -- env var names are compile-time constants, not user input */
|
|
12
|
+
|
|
13
|
+
const error = (0, _debug.default)('error');
|
|
14
|
+
error.log = console.error.bind(console);
|
|
15
|
+
const HEADER_VAR = 'ADDRESSR_PROXY_AUTH_HEADER';
|
|
16
|
+
const VALUE_VAR = 'ADDRESSR_PROXY_AUTH_VALUE';
|
|
17
|
+
|
|
18
|
+
// Closed list per ADR 024: /health for monitoring, /api-docs for gateway
|
|
19
|
+
// OpenAPI imports (ADR 023). Exact-match, not prefix.
|
|
20
|
+
const ALLOWLIST = new Set(['/health', '/api-docs']);
|
|
21
|
+
function isNonEmpty(value) {
|
|
22
|
+
return typeof value === 'string' && value.length > 0;
|
|
23
|
+
}
|
|
24
|
+
function validateProxyAuthConfig(environment = process.env) {
|
|
25
|
+
const headerSet = isNonEmpty(environment[HEADER_VAR]);
|
|
26
|
+
const valueSet = isNonEmpty(environment[VALUE_VAR]);
|
|
27
|
+
if (headerSet && !valueSet) {
|
|
28
|
+
throw new Error(`Proxy auth misconfigured: ${HEADER_VAR} is set but ${VALUE_VAR} is missing. Set both to enforce a gateway auth header, or unset both to disable enforcement.`);
|
|
29
|
+
}
|
|
30
|
+
if (valueSet && !headerSet) {
|
|
31
|
+
throw new Error(`Proxy auth misconfigured: ${VALUE_VAR} is set but ${HEADER_VAR} is missing. Set both to enforce a gateway auth header, or unset both to disable enforcement.`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function proxyAuthMiddleware() {
|
|
35
|
+
return function proxyAuth(request, response, next) {
|
|
36
|
+
const headerName = process.env[HEADER_VAR];
|
|
37
|
+
const expected = process.env[VALUE_VAR];
|
|
38
|
+
if (!isNonEmpty(headerName) || !isNonEmpty(expected)) {
|
|
39
|
+
return next();
|
|
40
|
+
}
|
|
41
|
+
if (ALLOWLIST.has(request.path)) {
|
|
42
|
+
return next();
|
|
43
|
+
}
|
|
44
|
+
const presented = request.get ? request.get(headerName) : undefined;
|
|
45
|
+
if (presented === expected) {
|
|
46
|
+
return next();
|
|
47
|
+
}
|
|
48
|
+
error('proxy-auth rejected %s', request.path);
|
|
49
|
+
return response.status(401).json({
|
|
50
|
+
message: 'Authentication required'
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -12,12 +12,645 @@ var _waycharter = require("@mountainpass/waycharter");
|
|
|
12
12
|
var _addressService = require("../service/address-service");
|
|
13
13
|
var _version = require("../version");
|
|
14
14
|
var _nodeCrypto = _interopRequireDefault(require("node:crypto"));
|
|
15
|
+
var _proxyAuth = require("./proxy-auth");
|
|
15
16
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
16
17
|
//import connect from 'connect';
|
|
17
18
|
|
|
18
19
|
var app = (0, _express.default)();
|
|
19
20
|
const ONE_DAY = 60 * 60 * 24;
|
|
20
21
|
const ONE_WEEK = ONE_DAY * 7;
|
|
22
|
+
function buildOpenApiSpec(apiVersion) {
|
|
23
|
+
const schemas = {
|
|
24
|
+
AddressSearchResult: {
|
|
25
|
+
type: 'object',
|
|
26
|
+
properties: {
|
|
27
|
+
sla: {
|
|
28
|
+
type: 'string',
|
|
29
|
+
description: 'Single line address',
|
|
30
|
+
example: 'UNIT 1, 19 MURRAY RD, CHRISTMAS ISLAND OT 6798'
|
|
31
|
+
},
|
|
32
|
+
ssla: {
|
|
33
|
+
type: 'string',
|
|
34
|
+
description: 'Short single line address (for addresses with flats)',
|
|
35
|
+
example: '1/19 MURRAY RD, CHRISTMAS ISLAND OT 6798'
|
|
36
|
+
},
|
|
37
|
+
highlight: {
|
|
38
|
+
type: 'object',
|
|
39
|
+
description: 'Search term highlights in the address',
|
|
40
|
+
properties: {
|
|
41
|
+
sla: {
|
|
42
|
+
type: 'string'
|
|
43
|
+
},
|
|
44
|
+
ssla: {
|
|
45
|
+
type: 'string'
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
score: {
|
|
50
|
+
type: 'number',
|
|
51
|
+
description: 'Search relevance score',
|
|
52
|
+
example: 5.43
|
|
53
|
+
},
|
|
54
|
+
pid: {
|
|
55
|
+
type: 'string',
|
|
56
|
+
description: 'Persistent identifier for the address',
|
|
57
|
+
example: 'GAOT_717882967'
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
Address: {
|
|
62
|
+
type: 'object',
|
|
63
|
+
properties: {
|
|
64
|
+
sla: {
|
|
65
|
+
type: 'string',
|
|
66
|
+
example: 'UNIT 1, 19 MURRAY RD, CHRISTMAS ISLAND OT 6798'
|
|
67
|
+
},
|
|
68
|
+
structured: {
|
|
69
|
+
type: 'object',
|
|
70
|
+
properties: {
|
|
71
|
+
confidence: {
|
|
72
|
+
type: 'integer',
|
|
73
|
+
example: 2
|
|
74
|
+
},
|
|
75
|
+
flat: {
|
|
76
|
+
type: 'object',
|
|
77
|
+
properties: {
|
|
78
|
+
number: {
|
|
79
|
+
type: 'integer',
|
|
80
|
+
example: 1
|
|
81
|
+
},
|
|
82
|
+
type: {
|
|
83
|
+
type: 'object',
|
|
84
|
+
properties: {
|
|
85
|
+
code: {
|
|
86
|
+
type: 'string',
|
|
87
|
+
example: 'UNIT'
|
|
88
|
+
},
|
|
89
|
+
name: {
|
|
90
|
+
type: 'string',
|
|
91
|
+
example: 'UNIT'
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
number: {
|
|
98
|
+
type: 'object',
|
|
99
|
+
properties: {
|
|
100
|
+
number: {
|
|
101
|
+
type: 'integer',
|
|
102
|
+
example: 19
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
street: {
|
|
107
|
+
type: 'object',
|
|
108
|
+
properties: {
|
|
109
|
+
name: {
|
|
110
|
+
type: 'string',
|
|
111
|
+
example: 'MURRAY'
|
|
112
|
+
},
|
|
113
|
+
type: {
|
|
114
|
+
type: 'object',
|
|
115
|
+
properties: {
|
|
116
|
+
code: {
|
|
117
|
+
type: 'string',
|
|
118
|
+
example: 'ROAD'
|
|
119
|
+
},
|
|
120
|
+
name: {
|
|
121
|
+
type: 'string',
|
|
122
|
+
example: 'RD'
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
locality: {
|
|
129
|
+
type: 'object',
|
|
130
|
+
properties: {
|
|
131
|
+
name: {
|
|
132
|
+
type: 'string',
|
|
133
|
+
example: 'CHRISTMAS ISLAND'
|
|
134
|
+
},
|
|
135
|
+
class: {
|
|
136
|
+
type: 'object',
|
|
137
|
+
properties: {
|
|
138
|
+
code: {
|
|
139
|
+
type: 'string',
|
|
140
|
+
example: 'U'
|
|
141
|
+
},
|
|
142
|
+
name: {
|
|
143
|
+
type: 'string',
|
|
144
|
+
example: 'UNOFFICIAL SUBURB'
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
postcode: {
|
|
151
|
+
type: 'string',
|
|
152
|
+
example: '6798'
|
|
153
|
+
},
|
|
154
|
+
state: {
|
|
155
|
+
type: 'object',
|
|
156
|
+
properties: {
|
|
157
|
+
abbreviation: {
|
|
158
|
+
type: 'string',
|
|
159
|
+
example: 'OT'
|
|
160
|
+
},
|
|
161
|
+
name: {
|
|
162
|
+
type: 'string',
|
|
163
|
+
example: 'OTHER TERRITORIES'
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
LocalitySearchResult: {
|
|
172
|
+
type: 'object',
|
|
173
|
+
properties: {
|
|
174
|
+
name: {
|
|
175
|
+
type: 'string',
|
|
176
|
+
example: 'LILYDALE'
|
|
177
|
+
},
|
|
178
|
+
state: {
|
|
179
|
+
type: 'object',
|
|
180
|
+
properties: {
|
|
181
|
+
name: {
|
|
182
|
+
type: 'string',
|
|
183
|
+
example: 'VICTORIA'
|
|
184
|
+
},
|
|
185
|
+
abbreviation: {
|
|
186
|
+
type: 'string',
|
|
187
|
+
example: 'VIC'
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
class: {
|
|
192
|
+
type: 'object',
|
|
193
|
+
properties: {
|
|
194
|
+
code: {
|
|
195
|
+
type: 'string',
|
|
196
|
+
description: 'Classification code (G=Gazetted, U=Unofficial, T=Topographic, I=Informal)',
|
|
197
|
+
example: 'G'
|
|
198
|
+
},
|
|
199
|
+
name: {
|
|
200
|
+
type: 'string',
|
|
201
|
+
example: 'GAZETTED LOCALITY'
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
postcode: {
|
|
206
|
+
type: 'string',
|
|
207
|
+
description: 'Primary postcode for this locality',
|
|
208
|
+
example: '3140'
|
|
209
|
+
},
|
|
210
|
+
score: {
|
|
211
|
+
type: 'number',
|
|
212
|
+
example: 5.23
|
|
213
|
+
},
|
|
214
|
+
pid: {
|
|
215
|
+
type: 'string',
|
|
216
|
+
example: 'loc1234567890ab'
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
Locality: {
|
|
221
|
+
type: 'object',
|
|
222
|
+
properties: {
|
|
223
|
+
locality_name: {
|
|
224
|
+
type: 'string',
|
|
225
|
+
example: 'CHRISTMAS ISLAND'
|
|
226
|
+
},
|
|
227
|
+
locality_class_code: {
|
|
228
|
+
type: 'string',
|
|
229
|
+
example: 'U'
|
|
230
|
+
},
|
|
231
|
+
locality_class_name: {
|
|
232
|
+
type: 'string',
|
|
233
|
+
example: 'UNOFFICIAL SUBURB'
|
|
234
|
+
},
|
|
235
|
+
primary_postcode: {
|
|
236
|
+
type: 'string',
|
|
237
|
+
example: '6798'
|
|
238
|
+
},
|
|
239
|
+
postcodes: {
|
|
240
|
+
type: 'array',
|
|
241
|
+
items: {
|
|
242
|
+
type: 'string'
|
|
243
|
+
},
|
|
244
|
+
example: ['6798']
|
|
245
|
+
},
|
|
246
|
+
state_abbreviation: {
|
|
247
|
+
type: 'string',
|
|
248
|
+
example: 'OT'
|
|
249
|
+
},
|
|
250
|
+
state_name: {
|
|
251
|
+
type: 'string',
|
|
252
|
+
example: 'OTHER TERRITORIES'
|
|
253
|
+
},
|
|
254
|
+
locality_pid: {
|
|
255
|
+
type: 'string',
|
|
256
|
+
example: 'loc9984d8beb142'
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
PostcodeSearchResult: {
|
|
261
|
+
type: 'object',
|
|
262
|
+
properties: {
|
|
263
|
+
postcode: {
|
|
264
|
+
type: 'string',
|
|
265
|
+
example: '3140'
|
|
266
|
+
},
|
|
267
|
+
localities: {
|
|
268
|
+
type: 'array',
|
|
269
|
+
items: {
|
|
270
|
+
type: 'object',
|
|
271
|
+
properties: {
|
|
272
|
+
name: {
|
|
273
|
+
type: 'string',
|
|
274
|
+
example: 'LILYDALE'
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
PostcodeDetail: {
|
|
282
|
+
type: 'object',
|
|
283
|
+
properties: {
|
|
284
|
+
postcode: {
|
|
285
|
+
type: 'string',
|
|
286
|
+
example: '6798'
|
|
287
|
+
},
|
|
288
|
+
localities: {
|
|
289
|
+
type: 'array',
|
|
290
|
+
description: 'Locality names. Individual locality resources are linked via related Link headers.',
|
|
291
|
+
items: {
|
|
292
|
+
type: 'object',
|
|
293
|
+
properties: {
|
|
294
|
+
name: {
|
|
295
|
+
type: 'string',
|
|
296
|
+
example: 'CHRISTMAS ISLAND'
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
State: {
|
|
304
|
+
type: 'object',
|
|
305
|
+
properties: {
|
|
306
|
+
abbreviation: {
|
|
307
|
+
type: 'string',
|
|
308
|
+
example: 'NSW'
|
|
309
|
+
},
|
|
310
|
+
name: {
|
|
311
|
+
type: 'string',
|
|
312
|
+
example: 'NEW SOUTH WALES'
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
Health: {
|
|
317
|
+
type: 'object',
|
|
318
|
+
properties: {
|
|
319
|
+
status: {
|
|
320
|
+
type: 'string',
|
|
321
|
+
example: 'healthy'
|
|
322
|
+
},
|
|
323
|
+
version: {
|
|
324
|
+
type: 'string',
|
|
325
|
+
example: '2.1.2'
|
|
326
|
+
},
|
|
327
|
+
timestamp: {
|
|
328
|
+
type: 'string',
|
|
329
|
+
format: 'date-time',
|
|
330
|
+
example: '2026-04-14T11:17:54.637Z'
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
return {
|
|
336
|
+
openapi: '3.0.3',
|
|
337
|
+
info: {
|
|
338
|
+
title: 'Addressr by Mountain Pass',
|
|
339
|
+
description: 'Free Australian Address Validation, Search and Autocomplete. This OpenAPI spec is supplementary — the HATEOAS link-driven API is the authoritative contract. Follow `related` Link headers to navigate between addresses, localities, postcodes and states.\n\nDirect requests to upstream hosts may be rejected when the operator has configured a gateway auth header. Consumers should always call Addressr through its published gateway endpoint; monitoring (`/health`) and spec discovery (`/api-docs`) remain openly reachable.',
|
|
340
|
+
version: apiVersion
|
|
341
|
+
},
|
|
342
|
+
servers: [{
|
|
343
|
+
url: 'https://addressr.p.rapidapi.com',
|
|
344
|
+
description: 'RapidAPI'
|
|
345
|
+
}],
|
|
346
|
+
paths: {
|
|
347
|
+
'/addresses': {
|
|
348
|
+
get: {
|
|
349
|
+
summary: 'Search Addresses',
|
|
350
|
+
description: 'Search Australian addresses by any component — street, suburb, postcode, state. Supports fuzzy and prefix matching.',
|
|
351
|
+
operationId: 'searchAddresses',
|
|
352
|
+
tags: ['Addresses'],
|
|
353
|
+
parameters: [{
|
|
354
|
+
name: 'q',
|
|
355
|
+
in: 'query',
|
|
356
|
+
required: true,
|
|
357
|
+
schema: {
|
|
358
|
+
type: 'string',
|
|
359
|
+
minLength: 3
|
|
360
|
+
},
|
|
361
|
+
example: 'UNIT 1, 19 MURRAY RD, CHRISTMAS ISLAND',
|
|
362
|
+
description: 'Address search query (min 3 characters)'
|
|
363
|
+
}, {
|
|
364
|
+
name: 'page',
|
|
365
|
+
in: 'query',
|
|
366
|
+
required: false,
|
|
367
|
+
schema: {
|
|
368
|
+
type: 'integer',
|
|
369
|
+
minimum: 0
|
|
370
|
+
},
|
|
371
|
+
example: 0,
|
|
372
|
+
description: 'Zero-based page number for pagination'
|
|
373
|
+
}],
|
|
374
|
+
responses: {
|
|
375
|
+
200: {
|
|
376
|
+
description: 'List of matching addresses',
|
|
377
|
+
content: {
|
|
378
|
+
'application/json': {
|
|
379
|
+
schema: {
|
|
380
|
+
type: 'array',
|
|
381
|
+
items: {
|
|
382
|
+
$ref: '#/components/schemas/AddressSearchResult'
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
},
|
|
391
|
+
'/addresses/{pid}': {
|
|
392
|
+
get: {
|
|
393
|
+
summary: 'Get Address',
|
|
394
|
+
description: 'Get full structured details for a specific address. Response includes Link headers with `related` rels to the locality, postcode, and state.',
|
|
395
|
+
operationId: 'getAddress',
|
|
396
|
+
tags: ['Addresses'],
|
|
397
|
+
parameters: [{
|
|
398
|
+
name: 'pid',
|
|
399
|
+
in: 'path',
|
|
400
|
+
required: true,
|
|
401
|
+
schema: {
|
|
402
|
+
type: 'string'
|
|
403
|
+
},
|
|
404
|
+
example: 'GAOT_717882967',
|
|
405
|
+
description: 'Address persistent identifier (G-NAF PID)'
|
|
406
|
+
}],
|
|
407
|
+
responses: {
|
|
408
|
+
200: {
|
|
409
|
+
description: 'Address details with structured data',
|
|
410
|
+
content: {
|
|
411
|
+
'application/json': {
|
|
412
|
+
schema: {
|
|
413
|
+
$ref: '#/components/schemas/Address'
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
},
|
|
421
|
+
'/localities': {
|
|
422
|
+
get: {
|
|
423
|
+
summary: 'Search Localities',
|
|
424
|
+
description: 'Search Australian suburbs and localities by name. Supports fuzzy and prefix matching. Returns localities with state, postcode, and classification.',
|
|
425
|
+
operationId: 'searchLocalities',
|
|
426
|
+
tags: ['Localities'],
|
|
427
|
+
parameters: [{
|
|
428
|
+
name: 'q',
|
|
429
|
+
in: 'query',
|
|
430
|
+
required: true,
|
|
431
|
+
schema: {
|
|
432
|
+
type: 'string',
|
|
433
|
+
minLength: 2
|
|
434
|
+
},
|
|
435
|
+
example: 'lilydale',
|
|
436
|
+
description: 'Locality/suburb name search query (min 2 characters)'
|
|
437
|
+
}],
|
|
438
|
+
responses: {
|
|
439
|
+
200: {
|
|
440
|
+
description: 'List of matching localities',
|
|
441
|
+
content: {
|
|
442
|
+
'application/json': {
|
|
443
|
+
schema: {
|
|
444
|
+
type: 'array',
|
|
445
|
+
items: {
|
|
446
|
+
$ref: '#/components/schemas/LocalitySearchResult'
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
},
|
|
455
|
+
'/localities/{pid}': {
|
|
456
|
+
get: {
|
|
457
|
+
summary: 'Get Locality',
|
|
458
|
+
description: 'Get details for a specific locality. Response includes Link headers with `related` rels to the postcode and state.',
|
|
459
|
+
operationId: 'getLocality',
|
|
460
|
+
tags: ['Localities'],
|
|
461
|
+
parameters: [{
|
|
462
|
+
name: 'pid',
|
|
463
|
+
in: 'path',
|
|
464
|
+
required: true,
|
|
465
|
+
schema: {
|
|
466
|
+
type: 'string'
|
|
467
|
+
},
|
|
468
|
+
example: 'loc9984d8beb142',
|
|
469
|
+
description: 'Locality persistent identifier'
|
|
470
|
+
}],
|
|
471
|
+
responses: {
|
|
472
|
+
200: {
|
|
473
|
+
description: 'Locality details',
|
|
474
|
+
content: {
|
|
475
|
+
'application/json': {
|
|
476
|
+
schema: {
|
|
477
|
+
$ref: '#/components/schemas/Locality'
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
},
|
|
485
|
+
'/postcodes': {
|
|
486
|
+
get: {
|
|
487
|
+
summary: 'Search Postcodes',
|
|
488
|
+
description: 'Search Australian postcodes by prefix. Returns matching postcodes with their associated localities. Omit `q` to list all postcodes in ascending order.',
|
|
489
|
+
operationId: 'searchPostcodes',
|
|
490
|
+
tags: ['Postcodes'],
|
|
491
|
+
parameters: [{
|
|
492
|
+
name: 'q',
|
|
493
|
+
in: 'query',
|
|
494
|
+
required: false,
|
|
495
|
+
schema: {
|
|
496
|
+
type: 'string'
|
|
497
|
+
},
|
|
498
|
+
example: '314',
|
|
499
|
+
description: 'Postcode prefix search query (0+ characters). Omit to list all postcodes.'
|
|
500
|
+
}],
|
|
501
|
+
responses: {
|
|
502
|
+
200: {
|
|
503
|
+
description: 'List of matching postcodes with associated localities',
|
|
504
|
+
content: {
|
|
505
|
+
'application/json': {
|
|
506
|
+
schema: {
|
|
507
|
+
type: 'array',
|
|
508
|
+
items: {
|
|
509
|
+
$ref: '#/components/schemas/PostcodeSearchResult'
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
},
|
|
518
|
+
'/postcodes/{postcode}': {
|
|
519
|
+
get: {
|
|
520
|
+
summary: 'Get Postcode',
|
|
521
|
+
description: 'Get details for a specific postcode including all associated localities. Each locality is linked via a `related` Link header.',
|
|
522
|
+
operationId: 'getPostcode',
|
|
523
|
+
tags: ['Postcodes'],
|
|
524
|
+
parameters: [{
|
|
525
|
+
name: 'postcode',
|
|
526
|
+
in: 'path',
|
|
527
|
+
required: true,
|
|
528
|
+
schema: {
|
|
529
|
+
type: 'string'
|
|
530
|
+
},
|
|
531
|
+
example: '6798',
|
|
532
|
+
description: 'Australian postcode'
|
|
533
|
+
}],
|
|
534
|
+
responses: {
|
|
535
|
+
200: {
|
|
536
|
+
description: 'Postcode details with associated localities',
|
|
537
|
+
content: {
|
|
538
|
+
'application/json': {
|
|
539
|
+
schema: {
|
|
540
|
+
$ref: '#/components/schemas/PostcodeDetail'
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
},
|
|
548
|
+
'/states': {
|
|
549
|
+
get: {
|
|
550
|
+
summary: 'Search States',
|
|
551
|
+
description: 'Search Australian states and territories by name or abbreviation. Omit `q` to list all states alphabetically.',
|
|
552
|
+
operationId: 'searchStates',
|
|
553
|
+
tags: ['States'],
|
|
554
|
+
parameters: [{
|
|
555
|
+
name: 'q',
|
|
556
|
+
in: 'query',
|
|
557
|
+
required: false,
|
|
558
|
+
schema: {
|
|
559
|
+
type: 'string'
|
|
560
|
+
},
|
|
561
|
+
example: 'New',
|
|
562
|
+
description: 'State name or abbreviation search (0+ characters). Omit to list all states.'
|
|
563
|
+
}],
|
|
564
|
+
responses: {
|
|
565
|
+
200: {
|
|
566
|
+
description: 'List of matching states and territories',
|
|
567
|
+
content: {
|
|
568
|
+
'application/json': {
|
|
569
|
+
schema: {
|
|
570
|
+
type: 'array',
|
|
571
|
+
items: {
|
|
572
|
+
$ref: '#/components/schemas/State'
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
},
|
|
581
|
+
'/states/{abbreviation}': {
|
|
582
|
+
get: {
|
|
583
|
+
summary: 'Get State',
|
|
584
|
+
description: 'Get details for a specific state or territory. Use `/localities?q=` or `/postcodes?q=` to search within a state.',
|
|
585
|
+
operationId: 'getState',
|
|
586
|
+
tags: ['States'],
|
|
587
|
+
parameters: [{
|
|
588
|
+
name: 'abbreviation',
|
|
589
|
+
in: 'path',
|
|
590
|
+
required: true,
|
|
591
|
+
schema: {
|
|
592
|
+
type: 'string',
|
|
593
|
+
enum: ['ACT', 'NSW', 'NT', 'QLD', 'SA', 'TAS', 'VIC', 'WA', 'OT']
|
|
594
|
+
},
|
|
595
|
+
example: 'NSW',
|
|
596
|
+
description: 'State/territory abbreviation'
|
|
597
|
+
}],
|
|
598
|
+
responses: {
|
|
599
|
+
200: {
|
|
600
|
+
description: 'State/territory details',
|
|
601
|
+
content: {
|
|
602
|
+
'application/json': {
|
|
603
|
+
schema: {
|
|
604
|
+
$ref: '#/components/schemas/State'
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
},
|
|
612
|
+
'/health': {
|
|
613
|
+
get: {
|
|
614
|
+
summary: 'Health Check',
|
|
615
|
+
description: 'Check API service status. Returns version, timestamp, and health status.',
|
|
616
|
+
operationId: 'healthCheck',
|
|
617
|
+
tags: ['System'],
|
|
618
|
+
responses: {
|
|
619
|
+
200: {
|
|
620
|
+
description: 'API is healthy',
|
|
621
|
+
content: {
|
|
622
|
+
'application/json': {
|
|
623
|
+
schema: {
|
|
624
|
+
$ref: '#/components/schemas/Health'
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
},
|
|
633
|
+
components: {
|
|
634
|
+
schemas
|
|
635
|
+
},
|
|
636
|
+
tags: [{
|
|
637
|
+
name: 'Addresses',
|
|
638
|
+
description: 'Search and retrieve addresses'
|
|
639
|
+
}, {
|
|
640
|
+
name: 'Localities',
|
|
641
|
+
description: 'Search and retrieve suburbs/localities'
|
|
642
|
+
}, {
|
|
643
|
+
name: 'Postcodes',
|
|
644
|
+
description: 'Search and retrieve postcodes'
|
|
645
|
+
}, {
|
|
646
|
+
name: 'States',
|
|
647
|
+
description: 'Search and retrieve states/territories'
|
|
648
|
+
}, {
|
|
649
|
+
name: 'System',
|
|
650
|
+
description: 'System endpoints'
|
|
651
|
+
}]
|
|
652
|
+
};
|
|
653
|
+
}
|
|
21
654
|
var serverPort = process.env.PORT || 8080;
|
|
22
655
|
var logger = (0, _debug.default)('api');
|
|
23
656
|
var error = (0, _debug.default)('error');
|
|
@@ -25,6 +658,7 @@ error.log = console.error.bind(console);
|
|
|
25
658
|
let server;
|
|
26
659
|
const PAGE_SIZE = process.env.PAGE_SIZE || 8;
|
|
27
660
|
function startRest2Server() {
|
|
661
|
+
(0, _proxyAuth.validateProxyAuthConfig)();
|
|
28
662
|
app.use((_request, response, next) => {
|
|
29
663
|
if (process.env.ADDRESSR_ACCESS_CONTROL_ALLOW_ORIGIN !== undefined) {
|
|
30
664
|
response.append('Access-Control-Allow-Origin', process.env.ADDRESSR_ACCESS_CONTROL_ALLOW_ORIGIN);
|
|
@@ -37,6 +671,7 @@ function startRest2Server() {
|
|
|
37
671
|
}
|
|
38
672
|
next();
|
|
39
673
|
});
|
|
674
|
+
app.use((0, _proxyAuth.proxyAuthMiddleware)());
|
|
40
675
|
const waycharter = new _waycharter.WayCharter();
|
|
41
676
|
app.use(waycharter.router);
|
|
42
677
|
const addressesType = waycharter.registerCollection({
|
|
@@ -340,178 +975,7 @@ function startRest2Server() {
|
|
|
340
975
|
waycharter.registerResourceType({
|
|
341
976
|
path: '/api-docs',
|
|
342
977
|
loader: async () => {
|
|
343
|
-
const spec =
|
|
344
|
-
openapi: '3.0.3',
|
|
345
|
-
info: {
|
|
346
|
-
title: 'Addressr by Mountain Pass',
|
|
347
|
-
description: 'Free Australian Address Validation, Search and Autocomplete. This OpenAPI spec is supplementary — the HATEOAS link-driven API is the authoritative contract.',
|
|
348
|
-
version: _version.version
|
|
349
|
-
},
|
|
350
|
-
paths: {
|
|
351
|
-
'/addresses': {
|
|
352
|
-
get: {
|
|
353
|
-
summary: 'Search Addresses',
|
|
354
|
-
operationId: 'searchAddresses',
|
|
355
|
-
parameters: [{
|
|
356
|
-
name: 'q',
|
|
357
|
-
in: 'query',
|
|
358
|
-
required: true,
|
|
359
|
-
schema: {
|
|
360
|
-
type: 'string',
|
|
361
|
-
minLength: 3
|
|
362
|
-
},
|
|
363
|
-
description: 'Address search query'
|
|
364
|
-
}],
|
|
365
|
-
responses: {
|
|
366
|
-
200: {
|
|
367
|
-
description: 'List of matching addresses'
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
},
|
|
372
|
-
'/addresses/{pid}': {
|
|
373
|
-
get: {
|
|
374
|
-
summary: 'Get Address',
|
|
375
|
-
operationId: 'getAddress',
|
|
376
|
-
parameters: [{
|
|
377
|
-
name: 'pid',
|
|
378
|
-
in: 'path',
|
|
379
|
-
required: true,
|
|
380
|
-
schema: {
|
|
381
|
-
type: 'string'
|
|
382
|
-
},
|
|
383
|
-
description: 'Address persistent identifier'
|
|
384
|
-
}],
|
|
385
|
-
responses: {
|
|
386
|
-
200: {
|
|
387
|
-
description: 'Address details with structured data'
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
},
|
|
392
|
-
'/localities': {
|
|
393
|
-
get: {
|
|
394
|
-
summary: 'Search Localities',
|
|
395
|
-
operationId: 'searchLocalities',
|
|
396
|
-
parameters: [{
|
|
397
|
-
name: 'q',
|
|
398
|
-
in: 'query',
|
|
399
|
-
required: true,
|
|
400
|
-
schema: {
|
|
401
|
-
type: 'string',
|
|
402
|
-
minLength: 2
|
|
403
|
-
},
|
|
404
|
-
description: 'Locality/suburb name search query'
|
|
405
|
-
}],
|
|
406
|
-
responses: {
|
|
407
|
-
200: {
|
|
408
|
-
description: 'List of matching localities'
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
},
|
|
413
|
-
'/localities/{pid}': {
|
|
414
|
-
get: {
|
|
415
|
-
summary: 'Get Locality',
|
|
416
|
-
operationId: 'getLocality',
|
|
417
|
-
parameters: [{
|
|
418
|
-
name: 'pid',
|
|
419
|
-
in: 'path',
|
|
420
|
-
required: true,
|
|
421
|
-
schema: {
|
|
422
|
-
type: 'string'
|
|
423
|
-
},
|
|
424
|
-
description: 'Locality persistent identifier'
|
|
425
|
-
}],
|
|
426
|
-
responses: {
|
|
427
|
-
200: {
|
|
428
|
-
description: 'Locality details'
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
},
|
|
433
|
-
'/postcodes': {
|
|
434
|
-
get: {
|
|
435
|
-
summary: 'Search Postcodes',
|
|
436
|
-
operationId: 'searchPostcodes',
|
|
437
|
-
parameters: [{
|
|
438
|
-
name: 'q',
|
|
439
|
-
in: 'query',
|
|
440
|
-
required: false,
|
|
441
|
-
schema: {
|
|
442
|
-
type: 'string'
|
|
443
|
-
},
|
|
444
|
-
description: 'Postcode prefix search query. Omit to list all postcodes.'
|
|
445
|
-
}],
|
|
446
|
-
responses: {
|
|
447
|
-
200: {
|
|
448
|
-
description: 'List of matching postcodes with associated localities'
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
},
|
|
453
|
-
'/postcodes/{postcode}': {
|
|
454
|
-
get: {
|
|
455
|
-
summary: 'Get Postcode',
|
|
456
|
-
operationId: 'getPostcode',
|
|
457
|
-
parameters: [{
|
|
458
|
-
name: 'postcode',
|
|
459
|
-
in: 'path',
|
|
460
|
-
required: true,
|
|
461
|
-
schema: {
|
|
462
|
-
type: 'string'
|
|
463
|
-
},
|
|
464
|
-
description: 'Australian postcode'
|
|
465
|
-
}],
|
|
466
|
-
responses: {
|
|
467
|
-
200: {
|
|
468
|
-
description: 'Postcode details with associated localities'
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
},
|
|
473
|
-
'/states': {
|
|
474
|
-
get: {
|
|
475
|
-
summary: 'Search States',
|
|
476
|
-
operationId: 'searchStates',
|
|
477
|
-
parameters: [{
|
|
478
|
-
name: 'q',
|
|
479
|
-
in: 'query',
|
|
480
|
-
required: false,
|
|
481
|
-
schema: {
|
|
482
|
-
type: 'string'
|
|
483
|
-
},
|
|
484
|
-
description: 'State name or abbreviation search. Omit to list all states.'
|
|
485
|
-
}],
|
|
486
|
-
responses: {
|
|
487
|
-
200: {
|
|
488
|
-
description: 'List of matching states and territories'
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
},
|
|
493
|
-
'/states/{abbreviation}': {
|
|
494
|
-
get: {
|
|
495
|
-
summary: 'Get State',
|
|
496
|
-
operationId: 'getState',
|
|
497
|
-
parameters: [{
|
|
498
|
-
name: 'abbreviation',
|
|
499
|
-
in: 'path',
|
|
500
|
-
required: true,
|
|
501
|
-
schema: {
|
|
502
|
-
type: 'string'
|
|
503
|
-
},
|
|
504
|
-
description: 'State/territory abbreviation (e.g., NSW, VIC)'
|
|
505
|
-
}],
|
|
506
|
-
responses: {
|
|
507
|
-
200: {
|
|
508
|
-
description: 'State/territory details'
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
};
|
|
978
|
+
const spec = buildOpenApiSpec(_version.version);
|
|
515
979
|
return {
|
|
516
980
|
body: spec,
|
|
517
981
|
headers: {
|
package/lib/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mountainpass/addressr",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.4",
|
|
4
4
|
"description": "Australian Address Validation, Search and Autocomplete",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Mountain Pass",
|
|
@@ -207,7 +207,7 @@
|
|
|
207
207
|
"dry-aged-deps": "^2.6.0",
|
|
208
208
|
"eslint": "^9.39.4",
|
|
209
209
|
"eslint-config-prettier": "^10.1.8",
|
|
210
|
-
"eslint-plugin-chai-friendly": "^1.
|
|
210
|
+
"eslint-plugin-chai-friendly": "^1.2.0",
|
|
211
211
|
"eslint-plugin-import-x": "^4.16.2",
|
|
212
212
|
"eslint-plugin-n": "^17.24.0",
|
|
213
213
|
"eslint-plugin-prettier": "^5.5.5",
|