ropegeo-common 1.10.2 → 1.10.3

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.
@@ -5,28 +5,29 @@ import './registerDifficultyParamsParsers';
5
5
  import { DifficultyParams } from './difficultyParams';
6
6
  /**
7
7
  * Validated params for getRoutes (GET /routes).
8
- * Global request: no `region` query param. Region-scoped: `region` id required; optional `source`
9
- * pipe-list (omit or empty = all sources). `source` must not appear without `region`.
10
- * Optional `route-types` query param is a pipe-list of {@link RouteType} values (omit or empty = all types).
8
+ * Either a region scope (`region-id` + `region-source`) or a global source allow-list (`sources`),
9
+ * never both. Optional `route-types` query param is a pipe-list of {@link RouteType} values.
11
10
  * Includes page-based `limit` and `page` (defaults {@link PaginationParams.DEFAULT_LIMIT} / {@link PaginationParams.DEFAULT_PAGE}).
12
11
  */
13
12
  export declare class RoutesParams extends PaginationParams {
14
13
  /**
15
- * Null when not region-scoped. When set, `source` null or empty list means all sources
16
- * for that region.
14
+ * Null when not region-scoped. When set, `source` is the single catalogue for that region.
17
15
  */
18
16
  readonly region: {
19
17
  id: string;
20
- source: PageDataSource[] | null;
18
+ source: PageDataSource;
21
19
  } | null;
20
+ /** Global source allow-list when not region-scoped; null = all sources. Mutually exclusive with `region`. */
21
+ readonly sources: PageDataSource[] | null;
22
22
  /** Null = no route-type filter; non-empty = allow-list (pipe-encoded in query strings as `route-types`). */
23
23
  readonly routeTypes: RouteType[] | null;
24
24
  readonly difficulty: DifficultyParams | null;
25
25
  constructor(options: {
26
26
  region: {
27
27
  id: string;
28
- source: PageDataSource[] | null;
28
+ source: PageDataSource;
29
29
  } | null;
30
+ sources?: PageDataSource[] | null;
30
31
  routeTypes?: RouteType[] | null;
31
32
  difficulty?: DifficultyParams | null;
32
33
  limit?: number;
@@ -34,7 +35,7 @@ export declare class RoutesParams extends PaginationParams {
34
35
  });
35
36
  withPage(page: number): RoutesParams;
36
37
  /** Null = all sources; non-empty = allow-list. */
37
- private static normalizeSourceList;
38
+ private static normalizeSourcesList;
38
39
  toQueryString(): string;
39
40
  static fromQueryStringParams(q: Record<string, string | undefined>): RoutesParams;
40
41
  private static parseLimitQuery;
@@ -48,10 +49,12 @@ export declare class RoutesParams extends PaginationParams {
48
49
  private static parseSourcePipe;
49
50
  private static parseSourceToken;
50
51
  /**
51
- * Validates a JSON-like object: optional `region` null or `{ id, source }` where `source`
52
- * is `PageDataSource[]`, null, or a single `PageDataSource` string (legacy).
52
+ * Validates a JSON-like object: optional `region` null or `{ id, source }` with a single
53
+ * `source` string, optional top-level `region-id` / `region-source`, optional `sources`
54
+ * (string pipe-list or string array). `region` and `sources` must not both be active.
53
55
  */
54
56
  static fromResult(result: unknown, requiredRegion?: boolean): RoutesParams;
57
+ private static optionalSourcesFromResult;
55
58
  private static paginationFromResult;
56
59
  private static optionalPositiveInt;
57
60
  private static optionalRouteTypesFromResult;
@@ -1 +1 @@
1
- {"version":3,"file":"routesParams.d.ts","sourceRoot":"","sources":["../../../../src/models/api/params/routesParams.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,mCAAmC,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAKtD;;;;;;GAMG;AACH,qBAAa,YAAa,SAAQ,gBAAgB;IAC9C;;;OAGG;IACH,SAAgB,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,cAAc,EAAE,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IAC/E,4GAA4G;IAC5G,SAAgB,UAAU,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;IAC/C,SAAgB,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;gBAExC,OAAO,EAAE;QACjB,MAAM,EAAE;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,cAAc,EAAE,GAAG,IAAI,CAAA;SAAE,GAAG,IAAI,CAAC;QAC/D,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;QAChC,UAAU,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;QACrC,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;KACjB;IAkCD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY;IAUpC,kDAAkD;IAClD,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAclC,aAAa,IAAI,MAAM;IAevB,MAAM,CAAC,qBAAqB,CACxB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GACtC,YAAY;IA0Cf,OAAO,CAAC,MAAM,CAAC,eAAe;IAiB9B,OAAO,CAAC,MAAM,CAAC,cAAc;IAY7B,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAOlC,OAAO,CAAC,MAAM,CAAC,cAAc;IAQ7B,0EAA0E;IAC1E,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAcrC,kFAAkF;IAClF,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAUjC,OAAO,CAAC,MAAM,CAAC,eAAe;IAS9B,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAU/B;;;OAGG;IACH,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,cAAc,UAAQ,GAAG,YAAY;IAoFxE,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAkBnC,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAsBlC,OAAO,CAAC,MAAM,CAAC,4BAA4B;IAwB3C,OAAO,CAAC,MAAM,CAAC,4BAA4B;IAkB3C,OAAO,CAAC,MAAM,CAAC,mBAAmB;CAWrC"}
1
+ {"version":3,"file":"routesParams.d.ts","sourceRoot":"","sources":["../../../../src/models/api/params/routesParams.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,mCAAmC,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAKtD;;;;;GAKG;AACH,qBAAa,YAAa,SAAQ,gBAAgB;IAC9C;;OAEG;IACH,SAAgB,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,cAAc,CAAA;KAAE,GAAG,IAAI,CAAC;IACtE,6GAA6G;IAC7G,SAAgB,OAAO,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC;IACjD,4GAA4G;IAC5G,SAAgB,UAAU,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;IAC/C,SAAgB,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;gBAExC,OAAO,EAAE;QACjB,MAAM,EAAE;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,cAAc,CAAA;SAAE,GAAG,IAAI,CAAC;QACtD,OAAO,CAAC,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC;QAClC,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;QAChC,UAAU,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;QACrC,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;KACjB;IAiDD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY;IAWpC,kDAAkD;IAClD,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAcnC,aAAa,IAAI,MAAM;IAgBvB,MAAM,CAAC,qBAAqB,CACxB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GACtC,YAAY;IAgEf,OAAO,CAAC,MAAM,CAAC,eAAe;IAiB9B,OAAO,CAAC,MAAM,CAAC,cAAc;IAY7B,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAOlC,OAAO,CAAC,MAAM,CAAC,cAAc;IAQ7B,0EAA0E;IAC1E,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAcrC,kFAAkF;IAClF,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAUjC,OAAO,CAAC,MAAM,CAAC,eAAe;IAS9B,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAU/B;;;;OAIG;IACH,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,cAAc,UAAQ,GAAG,YAAY;IAkHxE,OAAO,CAAC,MAAM,CAAC,yBAAyB;IAsBxC,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAkBnC,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAsBlC,OAAO,CAAC,MAAM,CAAC,4BAA4B;IAwB3C,OAAO,CAAC,MAAM,CAAC,4BAA4B;IAkB3C,OAAO,CAAC,MAAM,CAAC,mBAAmB;CAWrC"}
@@ -10,9 +10,8 @@ const difficultyParams_1 = require("./difficultyParams");
10
10
  const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
11
11
  /**
12
12
  * Validated params for getRoutes (GET /routes).
13
- * Global request: no `region` query param. Region-scoped: `region` id required; optional `source`
14
- * pipe-list (omit or empty = all sources). `source` must not appear without `region`.
15
- * Optional `route-types` query param is a pipe-list of {@link RouteType} values (omit or empty = all types).
13
+ * Either a region scope (`region-id` + `region-source`) or a global source allow-list (`sources`),
14
+ * never both. Optional `route-types` query param is a pipe-list of {@link RouteType} values.
16
15
  * Includes page-based `limit` and `page` (defaults {@link PaginationParams.DEFAULT_LIMIT} / {@link PaginationParams.DEFAULT_PAGE}).
17
16
  */
18
17
  class RoutesParams extends paginationParams_1.PaginationParams {
@@ -33,19 +32,29 @@ class RoutesParams extends paginationParams_1.PaginationParams {
33
32
  throw new Error('RoutesParams.region.id must be non-empty when region is set');
34
33
  }
35
34
  if (!UUID_REGEX.test(id)) {
36
- throw new Error('Query parameter "region" must be a valid UUID');
35
+ throw new Error('Query parameter "region-id" must be a valid UUID');
37
36
  }
38
- const src = RoutesParams.normalizeSourceList(reg.source);
39
- regionNorm = { id, source: src };
37
+ if (!Object.values(pageDataSource_1.PageDataSource).includes(reg.source)) {
38
+ throw new Error(`Invalid PageDataSource for region: ${JSON.stringify(reg.source)}`);
39
+ }
40
+ regionNorm = { id, source: reg.source };
41
+ }
42
+ const sourcesNorm = RoutesParams.normalizeSourcesList(options.sources ?? null);
43
+ if (regionNorm !== null &&
44
+ sourcesNorm !== null &&
45
+ sourcesNorm.length > 0) {
46
+ throw new Error('RoutesParams: region and sources cannot both be set');
40
47
  }
41
48
  super(limit, page);
42
49
  this.region = regionNorm;
50
+ this.sources = sourcesNorm;
43
51
  this.routeTypes = routeTypes;
44
52
  this.difficulty = diff;
45
53
  }
46
54
  withPage(page) {
47
55
  return new RoutesParams({
48
56
  region: this.region,
57
+ sources: this.sources,
49
58
  routeTypes: this.routeTypes,
50
59
  difficulty: this.difficulty,
51
60
  limit: this.limit,
@@ -53,7 +62,7 @@ class RoutesParams extends paginationParams_1.PaginationParams {
53
62
  });
54
63
  }
55
64
  /** Null = all sources; non-empty = allow-list. */
56
- static normalizeSourceList(list) {
65
+ static normalizeSourcesList(list) {
57
66
  if (list == null || list.length === 0)
58
67
  return null;
59
68
  const out = [];
@@ -69,10 +78,11 @@ class RoutesParams extends paginationParams_1.PaginationParams {
69
78
  toQueryString() {
70
79
  const p = new URLSearchParams(super.toQueryString());
71
80
  if (this.region !== null) {
72
- p.set('region', this.region.id);
73
- if (this.region.source != null && this.region.source.length > 0) {
74
- p.set('source', this.region.source.join('|'));
75
- }
81
+ p.set('region-id', this.region.id);
82
+ p.set('region-source', this.region.source);
83
+ }
84
+ if (this.sources != null && this.sources.length > 0) {
85
+ p.set('sources', this.sources.join('|'));
76
86
  }
77
87
  if (this.routeTypes != null && this.routeTypes.length > 0) {
78
88
  p.set('route-types', this.routeTypes.join('|'));
@@ -83,30 +93,45 @@ class RoutesParams extends paginationParams_1.PaginationParams {
83
93
  static fromQueryStringParams(q) {
84
94
  const limit = RoutesParams.parseLimitQuery(q);
85
95
  const page = RoutesParams.parsePageQuery(q);
86
- const regionRaw = (q.region ?? q.Region ?? '').trim();
87
- const sourceRaw = (q.source ?? q.Source ?? '').trim();
96
+ const regionIdRaw = (q['region-id'] ?? q['Region-Id'] ?? '').trim();
97
+ const regionSourceRaw = (q['region-source'] ??
98
+ q['Region-Source'] ??
99
+ '').trim();
100
+ const sourcesRaw = (q.sources ?? q.Sources ?? '').trim();
88
101
  const routeTypesStr = (q['route-types'] ?? q['Route-Types'] ?? '').trim();
89
102
  const routeTypes = routeTypesStr === ''
90
103
  ? null
91
104
  : RoutesParams.parseRouteTypePipe(routeTypesStr);
92
105
  const difficulty = RoutesParams.normalizeDifficulty(difficultyParams_1.DifficultyParams.fromQueryStringParams(q));
93
- if (regionRaw === '') {
94
- if (sourceRaw !== '') {
95
- throw new Error('Query parameter "source" must not be set without "region"');
106
+ const sourcesParsed = sourcesRaw === ''
107
+ ? null
108
+ : RoutesParams.parseSourcePipe(sourcesRaw);
109
+ if (regionIdRaw === '') {
110
+ if (regionSourceRaw !== '') {
111
+ throw new Error('Query parameter "region-source" must not be set without "region-id"');
96
112
  }
97
113
  return new RoutesParams({
98
114
  region: null,
115
+ sources: sourcesParsed,
99
116
  routeTypes,
100
117
  difficulty,
101
118
  limit,
102
119
  page,
103
120
  });
104
121
  }
105
- const sources = sourceRaw === ''
106
- ? null
107
- : RoutesParams.parseSourcePipe(sourceRaw);
122
+ if (!UUID_REGEX.test(regionIdRaw)) {
123
+ throw new Error('Query parameter "region-id" must be a valid UUID');
124
+ }
125
+ if (regionSourceRaw === '') {
126
+ throw new Error('Query parameter "region-source" is required when "region-id" is set');
127
+ }
128
+ if (sourcesParsed != null && sourcesParsed.length > 0) {
129
+ throw new Error('Query parameters "region-id" / "region-source" cannot be combined with "sources"');
130
+ }
131
+ const regionSource = RoutesParams.parseSourceToken(regionSourceRaw);
108
132
  return new RoutesParams({
109
- region: { id: regionRaw, source: sources },
133
+ region: { id: regionIdRaw, source: regionSource },
134
+ sources: null,
110
135
  routeTypes,
111
136
  difficulty,
112
137
  limit,
@@ -189,11 +214,12 @@ class RoutesParams extends paginationParams_1.PaginationParams {
189
214
  if (s === lower || s === value)
190
215
  return s;
191
216
  }
192
- throw new Error(`Query parameter "source" token must be one of: ${Object.values(pageDataSource_1.PageDataSource).join(', ')}`);
217
+ throw new Error(`PageDataSource token must be one of: ${Object.values(pageDataSource_1.PageDataSource).join(', ')}`);
193
218
  }
194
219
  /**
195
- * Validates a JSON-like object: optional `region` null or `{ id, source }` where `source`
196
- * is `PageDataSource[]`, null, or a single `PageDataSource` string (legacy).
220
+ * Validates a JSON-like object: optional `region` null or `{ id, source }` with a single
221
+ * `source` string, optional top-level `region-id` / `region-source`, optional `sources`
222
+ * (string pipe-list or string array). `region` and `sources` must not both be active.
197
223
  */
198
224
  static fromResult(result, requiredRegion = false) {
199
225
  if (result == null || typeof result !== 'object') {
@@ -201,69 +227,94 @@ class RoutesParams extends paginationParams_1.PaginationParams {
201
227
  }
202
228
  const r = result;
203
229
  const { limit, page } = RoutesParams.paginationFromResult(r);
204
- const raw = r.region ?? r.Region;
205
- if (typeof raw === 'string') {
206
- throw new Error('RoutesParams.region must be an object { id, source? } or null, not a string');
207
- }
208
- if (raw === null || raw === undefined) {
209
- if (requiredRegion) {
210
- throw new Error('RoutesParams: region must be a non-null { id, source? } object when requiredRegion is true');
230
+ const flatId = RoutesParams.coerceTrimmedString(r['region-id'] ?? r['Region-Id'], 'region-id');
231
+ const flatSource = RoutesParams.coerceTrimmedString(r['region-source'] ?? r['Region-Source'], 'region-source');
232
+ const rawNested = r.region ?? r.Region;
233
+ if (typeof rawNested === 'string') {
234
+ throw new Error('RoutesParams.region must be an object { id, source } or null, not a string');
235
+ }
236
+ let regionNorm = null;
237
+ const hasFlatRegion = flatId !== '' || flatSource !== '';
238
+ const hasNestedRegion = rawNested !== null &&
239
+ rawNested !== undefined &&
240
+ typeof rawNested === 'object';
241
+ if (hasFlatRegion && hasNestedRegion) {
242
+ throw new Error('RoutesParams: use either nested region or region-id / region-source, not both');
243
+ }
244
+ if (hasFlatRegion) {
245
+ if (flatId === '') {
246
+ throw new Error('RoutesParams.region-id must be non-empty when region-source is set');
211
247
  }
212
- const routeTypes = RoutesParams.optionalRouteTypesFromResult(r);
213
- const difficulty = RoutesParams.normalizeDifficulty(RoutesParams.optionalDifficultyFromResult(r));
214
- return new RoutesParams({
215
- region: null,
216
- routeTypes,
217
- difficulty,
218
- limit,
219
- page,
220
- });
221
- }
222
- if (typeof raw !== 'object') {
223
- throw new Error('RoutesParams.region must be an object or null, got: ' + typeof raw);
224
- }
225
- const reg = raw;
226
- const idStr = RoutesParams.coerceTrimmedString(reg.id ?? reg.Id, 'region.id');
227
- if (idStr === '') {
228
- throw new Error('RoutesParams.region must include non-empty id');
229
- }
230
- if (!UUID_REGEX.test(idStr)) {
231
- throw new Error('RoutesParams.region.id must be a valid UUID');
232
- }
233
- const sourceRaw = reg.source ?? reg.Source;
234
- let sourceList = null;
235
- if (sourceRaw === null || sourceRaw === undefined) {
236
- sourceList = null;
237
- }
238
- else if (Array.isArray(sourceRaw)) {
239
- sourceList = sourceRaw.map((item, i) => {
240
- if (typeof item !== 'string') {
241
- throw new Error(`RoutesParams.region.source[${i}] must be a string`);
242
- }
243
- return RoutesParams.parseSourceToken(item);
244
- });
245
- }
246
- else if (typeof sourceRaw === 'string') {
247
- if (sourceRaw.trim() !== '') {
248
- sourceList = [RoutesParams.parseSourceToken(sourceRaw.trim())];
248
+ if (!UUID_REGEX.test(flatId)) {
249
+ throw new Error('RoutesParams.region-id must be a valid UUID');
250
+ }
251
+ if (flatSource === '') {
252
+ throw new Error('RoutesParams.region-source must be non-empty when region-id is set');
253
+ }
254
+ regionNorm = {
255
+ id: flatId,
256
+ source: RoutesParams.parseSourceToken(flatSource),
257
+ };
258
+ }
259
+ else if (hasNestedRegion) {
260
+ const reg = rawNested;
261
+ const idStr = RoutesParams.coerceTrimmedString(reg.id ?? reg.Id, 'region.id');
262
+ if (idStr === '') {
263
+ throw new Error('RoutesParams.region must include non-empty id');
264
+ }
265
+ if (!UUID_REGEX.test(idStr)) {
266
+ throw new Error('RoutesParams.region.id must be a valid UUID');
249
267
  }
268
+ const sourceRaw = reg.source ?? reg.Source;
269
+ if (sourceRaw === null || sourceRaw === undefined) {
270
+ throw new Error('RoutesParams.region.source must be a non-empty string');
271
+ }
272
+ if (typeof sourceRaw !== 'string' || sourceRaw.trim() === '') {
273
+ throw new Error('RoutesParams.region.source must be a non-empty string');
274
+ }
275
+ regionNorm = {
276
+ id: idStr,
277
+ source: RoutesParams.parseSourceToken(sourceRaw.trim()),
278
+ };
250
279
  }
251
- else {
252
- throw new Error('RoutesParams.region.source must be string, string[], or null');
280
+ if (requiredRegion && regionNorm === null) {
281
+ throw new Error('RoutesParams: region must be set when requiredRegion is true');
282
+ }
283
+ const sourcesNorm = RoutesParams.optionalSourcesFromResult(r);
284
+ if (regionNorm !== null &&
285
+ sourcesNorm !== null &&
286
+ sourcesNorm.length > 0) {
287
+ throw new Error('RoutesParams: region and sources cannot both be set');
253
288
  }
254
289
  const routeTypes = RoutesParams.optionalRouteTypesFromResult(r);
255
290
  const difficulty = RoutesParams.normalizeDifficulty(RoutesParams.optionalDifficultyFromResult(r));
256
291
  return new RoutesParams({
257
- region: {
258
- id: idStr,
259
- source: RoutesParams.normalizeSourceList(sourceList),
260
- },
292
+ region: regionNorm,
293
+ sources: sourcesNorm,
261
294
  routeTypes,
262
295
  difficulty,
263
296
  limit,
264
297
  page,
265
298
  });
266
299
  }
300
+ static optionalSourcesFromResult(r) {
301
+ const v = r.sources ?? r.Sources;
302
+ if (v === null || v === undefined || v === '')
303
+ return null;
304
+ if (typeof v === 'string') {
305
+ return RoutesParams.parseSourcePipe(v);
306
+ }
307
+ if (Array.isArray(v)) {
308
+ const list = v.map((item, i) => {
309
+ if (typeof item !== 'string') {
310
+ throw new Error(`RoutesParams.sources[${i}] must be a string`);
311
+ }
312
+ return RoutesParams.parseSourceToken(item);
313
+ });
314
+ return RoutesParams.normalizeSourcesList(list);
315
+ }
316
+ throw new Error('RoutesParams.sources must be a string, string[], or null');
317
+ }
267
318
  static paginationFromResult(r) {
268
319
  const limit = RoutesParams.optionalPositiveInt(r.limit ?? r.Limit, 'limit', paginationParams_1.PaginationParams.DEFAULT_LIMIT);
269
320
  const page = RoutesParams.optionalPositiveInt(r.page ?? r.Page, 'page', paginationParams_1.PaginationParams.DEFAULT_PAGE);
@@ -310,10 +361,10 @@ class RoutesParams extends paginationParams_1.PaginationParams {
310
361
  typeof nested !== 'object') {
311
362
  throw new Error('RoutesParams.difficulty must be an object or null');
312
363
  }
313
- const source = nested !== null && nested !== undefined
364
+ const diffInput = nested !== null && nested !== undefined
314
365
  ? nested
315
366
  : r;
316
- return difficultyParams_1.DifficultyParams.fromResult(source);
367
+ return difficultyParams_1.DifficultyParams.fromResult(diffInput);
317
368
  }
318
369
  static coerceTrimmedString(v, key) {
319
370
  if (v === null || v === undefined) {
@@ -5,23 +5,23 @@ import './registerDifficultyFilterOptionsParsers';
5
5
  import { DifficultyFilterOptions } from './difficultyFilterOptions';
6
6
  /**
7
7
  * Persisted explore / minimap route filter. Null fields mean “no constraint” on that axis.
8
+ * Maps only to {@link RoutesParams} `sources`, `routeTypes`, and `difficulty` — not `region`.
8
9
  */
9
10
  export declare class RouteFilter {
10
- source: PageDataSource[] | null;
11
- regionId: string | null;
11
+ /** Null/empty = all data sources. */
12
+ sources: PageDataSource[] | null;
12
13
  /** Null or empty = no route-type filter (all types). */
13
14
  routeTypes: RouteType[] | null;
14
15
  difficultyOptions: DifficultyFilterOptions | null;
15
- constructor(source?: PageDataSource[] | null, regionId?: string | null, routeTypes?: RouteType[] | null, difficultyOptions?: DifficultyFilterOptions | null);
16
+ constructor(sources?: PageDataSource[] | null, routeTypes?: RouteType[] | null, difficultyOptions?: DifficultyFilterOptions | null);
16
17
  toRoutesParams(): RoutesParams;
17
18
  toJSON(): Record<string, unknown>;
18
19
  toString(): string;
19
20
  static fromJsonString(json: string): RouteFilter;
20
21
  static fromJSON(parsed: unknown): RouteFilter;
21
22
  private static normalizeRouteTypesList;
22
- /** Accepts `routeTypes` array or legacy singular `routeType` string. */
23
23
  private static parseRouteTypesField;
24
24
  private static parseRouteTypeToken;
25
- private static parseSourceField;
25
+ private static parseSourcesField;
26
26
  }
27
27
  //# sourceMappingURL=routeFilter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"routeFilter.d.ts","sourceRoot":"","sources":["../../../src/models/filters/routeFilter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,0CAA0C,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAEpE;;GAEG;AACH,qBAAa,WAAW;IACpB,MAAM,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC;IAChC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,wDAAwD;IACxD,UAAU,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;IAC/B,iBAAiB,EAAE,uBAAuB,GAAG,IAAI,CAAC;gBAG9C,MAAM,GAAE,cAAc,EAAE,GAAG,IAAW,EACtC,QAAQ,GAAE,MAAM,GAAG,IAAW,EAC9B,UAAU,GAAE,SAAS,EAAE,GAAG,IAAW,EACrC,iBAAiB,GAAE,uBAAuB,GAAG,IAAW;IAQ5D,cAAc,IAAI,YAAY;IAwC9B,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAYjC,QAAQ,IAAI,MAAM;IAIlB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW;IAYhD,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,WAAW;IAkB7C,OAAO,CAAC,MAAM,CAAC,uBAAuB;IActC,wEAAwE;IACxE,OAAO,CAAC,MAAM,CAAC,oBAAoB;IA0BnC,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAOlC,OAAO,CAAC,MAAM,CAAC,gBAAgB;CAmBlC"}
1
+ {"version":3,"file":"routeFilter.d.ts","sourceRoot":"","sources":["../../../src/models/filters/routeFilter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,0CAA0C,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAEpE;;;GAGG;AACH,qBAAa,WAAW;IACpB,qCAAqC;IACrC,OAAO,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC;IACjC,wDAAwD;IACxD,UAAU,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;IAC/B,iBAAiB,EAAE,uBAAuB,GAAG,IAAI,CAAC;gBAG9C,OAAO,GAAE,cAAc,EAAE,GAAG,IAAW,EACvC,UAAU,GAAE,SAAS,EAAE,GAAG,IAAW,EACrC,iBAAiB,GAAE,uBAAuB,GAAG,IAAW;IAO5D,cAAc,IAAI,YAAY;IAoB9B,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAWjC,QAAQ,IAAI,MAAM;IAIlB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW;IAYhD,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,WAAW;IAc7C,OAAO,CAAC,MAAM,CAAC,uBAAuB;IActC,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAiBnC,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAOlC,OAAO,CAAC,MAAM,CAAC,iBAAiB;CAmBnC"}
@@ -8,37 +8,21 @@ require("./registerDifficultyFilterOptionsParsers");
8
8
  const difficultyFilterOptions_1 = require("./difficultyFilterOptions");
9
9
  /**
10
10
  * Persisted explore / minimap route filter. Null fields mean “no constraint” on that axis.
11
+ * Maps only to {@link RoutesParams} `sources`, `routeTypes`, and `difficulty` — not `region`.
11
12
  */
12
13
  class RouteFilter {
13
- constructor(source = null, regionId = null, routeTypes = null, difficultyOptions = null) {
14
- this.source = source;
15
- this.regionId = regionId;
14
+ constructor(sources = null, routeTypes = null, difficultyOptions = null) {
15
+ this.sources = sources;
16
16
  this.routeTypes = RouteFilter.normalizeRouteTypesList(routeTypes);
17
17
  this.difficultyOptions = difficultyOptions;
18
18
  }
19
19
  toRoutesParams() {
20
- const rid = this.regionId != null && this.regionId.trim() !== ''
21
- ? this.regionId.trim()
22
- : null;
23
- if (rid === null) {
24
- if (this.source != null && this.source.length > 0) {
25
- throw new Error('RouteFilter: source allow-list requires a non-empty regionId');
26
- }
27
- return new routesParams_1.RoutesParams({
28
- region: null,
29
- routeTypes: this.routeTypes != null && this.routeTypes.length > 0
30
- ? [...this.routeTypes]
31
- : null,
32
- difficulty: this.difficultyOptions !== null
33
- ? this.difficultyOptions.toDifficultyParams()
34
- : null,
35
- });
36
- }
37
- const src = this.source == null || this.source.length === 0
20
+ const srcList = this.sources == null || this.sources.length === 0
38
21
  ? null
39
- : [...this.source];
22
+ : [...this.sources];
40
23
  return new routesParams_1.RoutesParams({
41
- region: { id: rid, source: src },
24
+ region: null,
25
+ sources: srcList,
42
26
  routeTypes: this.routeTypes != null && this.routeTypes.length > 0
43
27
  ? [...this.routeTypes]
44
28
  : null,
@@ -49,8 +33,7 @@ class RouteFilter {
49
33
  }
50
34
  toJSON() {
51
35
  return {
52
- source: this.source,
53
- regionId: this.regionId,
36
+ sources: this.sources,
54
37
  routeTypes: this.routeTypes,
55
38
  difficultyOptions: this.difficultyOptions !== null
56
39
  ? this.difficultyOptions.toJSON()
@@ -75,16 +58,13 @@ class RouteFilter {
75
58
  throw new Error('RouteFilter must be a JSON object');
76
59
  }
77
60
  const o = parsed;
78
- const source = RouteFilter.parseSourceField(o.source);
79
- const regionId = o.regionId === null || o.regionId === undefined
80
- ? null
81
- : String(o.regionId);
61
+ const sources = RouteFilter.parseSourcesField(o.sources);
82
62
  const routeTypes = RouteFilter.parseRouteTypesField(o);
83
63
  let difficultyOptions = null;
84
64
  if (o.difficultyOptions != null && typeof o.difficultyOptions === 'object') {
85
65
  difficultyOptions = difficultyFilterOptions_1.DifficultyFilterOptions.fromResult(o.difficultyOptions);
86
66
  }
87
- return new RouteFilter(source, regionId, routeTypes, difficultyOptions);
67
+ return new RouteFilter(sources, routeTypes, difficultyOptions);
88
68
  }
89
69
  static normalizeRouteTypesList(list) {
90
70
  if (list == null || list.length === 0)
@@ -99,31 +79,21 @@ class RouteFilter {
99
79
  }
100
80
  return out;
101
81
  }
102
- /** Accepts `routeTypes` array or legacy singular `routeType` string. */
103
82
  static parseRouteTypesField(o) {
104
83
  const raw = o.routeTypes;
105
- if (raw !== null && raw !== undefined) {
106
- if (!Array.isArray(raw)) {
107
- throw new Error('RouteFilter.routeTypes must be an array or null');
108
- }
109
- const types = raw.map((item, i) => {
110
- if (typeof item !== 'string') {
111
- throw new Error(`RouteFilter.routeTypes[${i}] must be a string`);
112
- }
113
- return RouteFilter.parseRouteTypeToken(item);
114
- });
115
- return RouteFilter.normalizeRouteTypesList(types);
116
- }
117
- const legacy = o.routeType;
118
- if (legacy === null || legacy === undefined) {
84
+ if (raw === null || raw === undefined) {
119
85
  return null;
120
86
  }
121
- if (typeof legacy !== 'string') {
122
- throw new Error('RouteFilter.routeType must be a string or null');
87
+ if (!Array.isArray(raw)) {
88
+ throw new Error('RouteFilter.routeTypes must be an array or null');
123
89
  }
124
- return RouteFilter.normalizeRouteTypesList([
125
- RouteFilter.parseRouteTypeToken(legacy),
126
- ]);
90
+ const types = raw.map((item, i) => {
91
+ if (typeof item !== 'string') {
92
+ throw new Error(`RouteFilter.routeTypes[${i}] must be a string`);
93
+ }
94
+ return RouteFilter.parseRouteTypeToken(item);
95
+ });
96
+ return RouteFilter.normalizeRouteTypesList(types);
127
97
  }
128
98
  static parseRouteTypeToken(v) {
129
99
  if (!Object.values(routeType_1.RouteType).includes(v)) {
@@ -131,16 +101,16 @@ class RouteFilter {
131
101
  }
132
102
  return v;
133
103
  }
134
- static parseSourceField(v) {
104
+ static parseSourcesField(v) {
135
105
  if (v === null || v === undefined)
136
106
  return null;
137
107
  if (!Array.isArray(v)) {
138
- throw new Error('RouteFilter.source must be an array or null');
108
+ throw new Error('RouteFilter.sources must be an array or null');
139
109
  }
140
110
  const out = [];
141
111
  for (const item of v) {
142
112
  if (typeof item !== 'string') {
143
- throw new Error('RouteFilter.source entries must be strings');
113
+ throw new Error('RouteFilter.sources entries must be strings');
144
114
  }
145
115
  if (!Object.values(pageDataSource_1.PageDataSource).includes(item)) {
146
116
  throw new Error(`Invalid PageDataSource: ${JSON.stringify(item)}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ropegeo-common",
3
- "version": "1.10.2",
3
+ "version": "1.10.3",
4
4
  "description": "Shared domain models and helpers for RopeGeo and WebScraper",
5
5
  "license": "ISC",
6
6
  "repository": {