@cratis/arc 20.33.9 → 20.33.17

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/UrlHelpers.ts CHANGED
@@ -1,6 +1,18 @@
1
1
  // Copyright (c) Cratis. All rights reserved.
2
2
  // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
3
 
4
+ /**
5
+ * Format a single query / route parameter value into a string the .NET TypeConverter
6
+ * infrastructure can round-trip. Date values are emitted as ISO 8601 so DateTimeOffset
7
+ * binding succeeds; everything else falls back to the JS String coercion.
8
+ */
9
+ function formatQueryValue(value: unknown): string {
10
+ if (value instanceof Date) {
11
+ return value.toISOString();
12
+ }
13
+ return String(value);
14
+ }
15
+
4
16
  export class UrlHelpers {
5
17
  /**
6
18
  * Creates a URL from the given origin, API base path, and route.
@@ -40,8 +52,8 @@ export class UrlHelpers {
40
52
  }
41
53
 
42
54
  const pattern = new RegExp(`\\{${key}\\}`, 'gi');
43
- const newRoute = result.replace(pattern, encodeURIComponent(String(value)));
44
-
55
+ const newRoute = result.replace(pattern, encodeURIComponent(formatQueryValue(value)));
56
+
45
57
  if (newRoute !== result) {
46
58
  delete unusedParameters[key as keyof T];
47
59
  result = newRoute;
@@ -65,20 +77,20 @@ export class UrlHelpers {
65
77
  if (value !== undefined && value !== null) {
66
78
  if (Array.isArray(value)) {
67
79
  for (const item of value) {
68
- queryParams.append(key, String(item));
80
+ queryParams.append(key, formatQueryValue(item));
69
81
  }
70
82
  } else {
71
- queryParams.set(key, String(value));
83
+ queryParams.set(key, formatQueryValue(value));
72
84
  }
73
85
  }
74
86
  }
75
87
 
76
88
  if (additionalParams) {
77
89
  for (const [key, value] of Object.entries(additionalParams)) {
78
- queryParams.set(key, String(value));
90
+ queryParams.set(key, formatQueryValue(value));
79
91
  }
80
92
  }
81
93
 
82
94
  return queryParams;
83
95
  }
84
- }
96
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"UrlHelpers.d.ts","sourceRoot":"","sources":["../../UrlHelpers.ts"],"names":[],"mappings":"AAGA,qBAAa,UAAU;IAQnB,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG;IAe7E,MAAM,CAAC,sBAAsB,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;KAAE;IAkC/H,MAAM,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,eAAe;CAuBzH"}
1
+ {"version":3,"file":"UrlHelpers.d.ts","sourceRoot":"","sources":["../../UrlHelpers.ts"],"names":[],"mappings":"AAeA,qBAAa,UAAU;IAQnB,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG;IAe7E,MAAM,CAAC,sBAAsB,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;KAAE;IAkC/H,MAAM,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,eAAe;CAuBzH"}
@@ -1,5 +1,11 @@
1
1
  'use strict';
2
2
 
3
+ function formatQueryValue(value) {
4
+ if (value instanceof Date) {
5
+ return value.toISOString();
6
+ }
7
+ return String(value);
8
+ }
3
9
  class UrlHelpers {
4
10
  static createUrlFrom(origin, apiBasePath, route) {
5
11
  if ((!origin || origin.length === 0) && typeof document !== 'undefined') {
@@ -18,7 +24,7 @@ class UrlHelpers {
18
24
  continue;
19
25
  }
20
26
  const pattern = new RegExp(`\\{${key}\\}`, 'gi');
21
- const newRoute = result.replace(pattern, encodeURIComponent(String(value)));
27
+ const newRoute = result.replace(pattern, encodeURIComponent(formatQueryValue(value)));
22
28
  if (newRoute !== result) {
23
29
  delete unusedParameters[key];
24
30
  result = newRoute;
@@ -32,17 +38,17 @@ class UrlHelpers {
32
38
  if (value !== undefined && value !== null) {
33
39
  if (Array.isArray(value)) {
34
40
  for (const item of value) {
35
- queryParams.append(key, String(item));
41
+ queryParams.append(key, formatQueryValue(item));
36
42
  }
37
43
  }
38
44
  else {
39
- queryParams.set(key, String(value));
45
+ queryParams.set(key, formatQueryValue(value));
40
46
  }
41
47
  }
42
48
  }
43
49
  if (additionalParams) {
44
50
  for (const [key, value] of Object.entries(additionalParams)) {
45
- queryParams.set(key, String(value));
51
+ queryParams.set(key, formatQueryValue(value));
46
52
  }
47
53
  }
48
54
  return queryParams;
@@ -1 +1 @@
1
- {"version":3,"file":"UrlHelpers.js","sources":["../../UrlHelpers.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nexport class UrlHelpers {\n /**\n * Creates a URL from the given origin, API base path, and route.\n * @param origin The origin of the request. If not provided, it defaults to the current document's origin.\n * @param apiBasePath The base path for the API.\n * @param route The specific route for the request.\n * @returns The constructed URL.\n */\n static createUrlFrom(origin: string, apiBasePath: string, route: string): URL {\n if ((!origin || origin.length === 0) && typeof document !== 'undefined') {\n origin = document.location?.origin ?? '';\n }\n\n return new URL(route, `${origin}${apiBasePath}`);\n }\n\n /**\n * Replaces route parameters in the route template with values from the parameters object.\n * Returns both the updated route and the parameters that were not used in the route.\n * @param route The route template with placeholders like {paramName}.\n * @param parameters The parameters to replace in the route.\n * @returns An object containing the updated route and unused parameters.\n */\n static replaceRouteParameters<T extends object>(route: string, parameters?: T): { route: string; unusedParameters: Partial<T> } {\n if (!parameters) {\n return { route, unusedParameters: {} };\n }\n\n let result = route;\n const unusedParameters: Partial<T> = { ...parameters };\n\n for (const [key, value] of Object.entries(parameters)) {\n // Array values cannot be encoded as a single route segment — leave them as unused so\n // they are serialized as repeated query string parameters (e.g. ?ids=1&ids=2&ids=3).\n if (Array.isArray(value)) {\n continue;\n }\n\n const pattern = new RegExp(`\\\\{${key}\\\\}`, 'gi');\n const newRoute = result.replace(pattern, encodeURIComponent(String(value)));\n \n if (newRoute !== result) {\n delete unusedParameters[key as keyof T];\n result = newRoute;\n }\n }\n\n return { route: result, unusedParameters };\n }\n\n /**\n * Builds URLSearchParams from the given parameters and additional query parameters.\n * Array values are serialized as repeated key=value pairs (e.g. ?ids=1&ids=2&ids=3).\n * @param unusedParameters Parameters that were not used in route replacement.\n * @param additionalParams Additional query parameters to include.\n * @returns URLSearchParams containing all parameters.\n */\n static buildQueryParams(unusedParameters: object, additionalParams?: Record<string, string | number>): URLSearchParams {\n const queryParams = new URLSearchParams();\n\n for (const [key, value] of Object.entries(unusedParameters)) {\n if (value !== undefined && value !== null) {\n if (Array.isArray(value)) {\n for (const item of value) {\n queryParams.append(key, String(item));\n }\n } else {\n queryParams.set(key, String(value));\n }\n }\n }\n\n if (additionalParams) {\n for (const [key, value] of Object.entries(additionalParams)) {\n queryParams.set(key, String(value));\n }\n }\n\n return queryParams;\n }\n}"],"names":[],"mappings":";;MAGa,UAAU,CAAA;AAQnB,IAAA,OAAO,aAAa,CAAC,MAAc,EAAE,WAAmB,EAAE,KAAa,EAAA;AACnE,QAAA,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,KAAK,OAAO,QAAQ,KAAK,WAAW,EAAE;YACrE,MAAM,GAAG,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE;QAC5C;QAEA,OAAO,IAAI,GAAG,CAAC,KAAK,EAAE,CAAA,EAAG,MAAM,CAAA,EAAG,WAAW,CAAA,CAAE,CAAC;IACpD;AASA,IAAA,OAAO,sBAAsB,CAAmB,KAAa,EAAE,UAAc,EAAA;QACzE,IAAI,CAAC,UAAU,EAAE;AACb,YAAA,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,EAAE,EAAE;QAC1C;QAEA,IAAI,MAAM,GAAG,KAAK;AAClB,QAAA,MAAM,gBAAgB,GAAe,EAAE,GAAG,UAAU,EAAE;AAEtD,QAAA,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;AAGnD,YAAA,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;gBACtB;YACJ;YAEA,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,CAAA,GAAA,EAAM,GAAG,CAAA,GAAA,CAAK,EAAE,IAAI,CAAC;AAChD,YAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,kBAAkB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AAE3E,YAAA,IAAI,QAAQ,KAAK,MAAM,EAAE;AACrB,gBAAA,OAAO,gBAAgB,CAAC,GAAc,CAAC;gBACvC,MAAM,GAAG,QAAQ;YACrB;QACJ;AAEA,QAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE;IAC9C;AASA,IAAA,OAAO,gBAAgB,CAAC,gBAAwB,EAAE,gBAAkD,EAAA;AAChG,QAAA,MAAM,WAAW,GAAG,IAAI,eAAe,EAAE;AAEzC,QAAA,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE;YACzD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE;AACvC,gBAAA,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;AACtB,oBAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;wBACtB,WAAW,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;oBACzC;gBACJ;qBAAO;oBACH,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;gBACvC;YACJ;QACJ;QAEA,IAAI,gBAAgB,EAAE;AAClB,YAAA,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE;gBACzD,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YACvC;QACJ;AAEA,QAAA,OAAO,WAAW;IACtB;AACH;;;;"}
1
+ {"version":3,"file":"UrlHelpers.js","sources":["../../UrlHelpers.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n/**\n * Format a single query / route parameter value into a string the .NET TypeConverter\n * infrastructure can round-trip. Date values are emitted as ISO 8601 so DateTimeOffset\n * binding succeeds; everything else falls back to the JS String coercion.\n */\nfunction formatQueryValue(value: unknown): string {\n if (value instanceof Date) {\n return value.toISOString();\n }\n return String(value);\n}\n\nexport class UrlHelpers {\n /**\n * Creates a URL from the given origin, API base path, and route.\n * @param origin The origin of the request. If not provided, it defaults to the current document's origin.\n * @param apiBasePath The base path for the API.\n * @param route The specific route for the request.\n * @returns The constructed URL.\n */\n static createUrlFrom(origin: string, apiBasePath: string, route: string): URL {\n if ((!origin || origin.length === 0) && typeof document !== 'undefined') {\n origin = document.location?.origin ?? '';\n }\n\n return new URL(route, `${origin}${apiBasePath}`);\n }\n\n /**\n * Replaces route parameters in the route template with values from the parameters object.\n * Returns both the updated route and the parameters that were not used in the route.\n * @param route The route template with placeholders like {paramName}.\n * @param parameters The parameters to replace in the route.\n * @returns An object containing the updated route and unused parameters.\n */\n static replaceRouteParameters<T extends object>(route: string, parameters?: T): { route: string; unusedParameters: Partial<T> } {\n if (!parameters) {\n return { route, unusedParameters: {} };\n }\n\n let result = route;\n const unusedParameters: Partial<T> = { ...parameters };\n\n for (const [key, value] of Object.entries(parameters)) {\n // Array values cannot be encoded as a single route segment — leave them as unused so\n // they are serialized as repeated query string parameters (e.g. ?ids=1&ids=2&ids=3).\n if (Array.isArray(value)) {\n continue;\n }\n\n const pattern = new RegExp(`\\\\{${key}\\\\}`, 'gi');\n const newRoute = result.replace(pattern, encodeURIComponent(formatQueryValue(value)));\n\n if (newRoute !== result) {\n delete unusedParameters[key as keyof T];\n result = newRoute;\n }\n }\n\n return { route: result, unusedParameters };\n }\n\n /**\n * Builds URLSearchParams from the given parameters and additional query parameters.\n * Array values are serialized as repeated key=value pairs (e.g. ?ids=1&ids=2&ids=3).\n * @param unusedParameters Parameters that were not used in route replacement.\n * @param additionalParams Additional query parameters to include.\n * @returns URLSearchParams containing all parameters.\n */\n static buildQueryParams(unusedParameters: object, additionalParams?: Record<string, string | number>): URLSearchParams {\n const queryParams = new URLSearchParams();\n\n for (const [key, value] of Object.entries(unusedParameters)) {\n if (value !== undefined && value !== null) {\n if (Array.isArray(value)) {\n for (const item of value) {\n queryParams.append(key, formatQueryValue(item));\n }\n } else {\n queryParams.set(key, formatQueryValue(value));\n }\n }\n }\n\n if (additionalParams) {\n for (const [key, value] of Object.entries(additionalParams)) {\n queryParams.set(key, formatQueryValue(value));\n }\n }\n\n return queryParams;\n }\n}\n"],"names":[],"mappings":";;AAQA,SAAS,gBAAgB,CAAC,KAAc,EAAA;AACpC,IAAA,IAAI,KAAK,YAAY,IAAI,EAAE;AACvB,QAAA,OAAO,KAAK,CAAC,WAAW,EAAE;IAC9B;AACA,IAAA,OAAO,MAAM,CAAC,KAAK,CAAC;AACxB;MAEa,UAAU,CAAA;AAQnB,IAAA,OAAO,aAAa,CAAC,MAAc,EAAE,WAAmB,EAAE,KAAa,EAAA;AACnE,QAAA,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,KAAK,OAAO,QAAQ,KAAK,WAAW,EAAE;YACrE,MAAM,GAAG,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE;QAC5C;QAEA,OAAO,IAAI,GAAG,CAAC,KAAK,EAAE,CAAA,EAAG,MAAM,CAAA,EAAG,WAAW,CAAA,CAAE,CAAC;IACpD;AASA,IAAA,OAAO,sBAAsB,CAAmB,KAAa,EAAE,UAAc,EAAA;QACzE,IAAI,CAAC,UAAU,EAAE;AACb,YAAA,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,EAAE,EAAE;QAC1C;QAEA,IAAI,MAAM,GAAG,KAAK;AAClB,QAAA,MAAM,gBAAgB,GAAe,EAAE,GAAG,UAAU,EAAE;AAEtD,QAAA,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;AAGnD,YAAA,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;gBACtB;YACJ;YAEA,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,CAAA,GAAA,EAAM,GAAG,CAAA,GAAA,CAAK,EAAE,IAAI,CAAC;AAChD,YAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,kBAAkB,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC;AAErF,YAAA,IAAI,QAAQ,KAAK,MAAM,EAAE;AACrB,gBAAA,OAAO,gBAAgB,CAAC,GAAc,CAAC;gBACvC,MAAM,GAAG,QAAQ;YACrB;QACJ;AAEA,QAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE;IAC9C;AASA,IAAA,OAAO,gBAAgB,CAAC,gBAAwB,EAAE,gBAAkD,EAAA;AAChG,QAAA,MAAM,WAAW,GAAG,IAAI,eAAe,EAAE;AAEzC,QAAA,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE;YACzD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE;AACvC,gBAAA,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;AACtB,oBAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;wBACtB,WAAW,CAAC,MAAM,CAAC,GAAG,EAAE,gBAAgB,CAAC,IAAI,CAAC,CAAC;oBACnD;gBACJ;qBAAO;oBACH,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC;gBACjD;YACJ;QACJ;QAEA,IAAI,gBAAgB,EAAE;AAClB,YAAA,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE;gBACzD,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC;YACjD;QACJ;AAEA,QAAA,OAAO,WAAW;IACtB;AACH;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"UrlHelpers.d.ts","sourceRoot":"","sources":["../../UrlHelpers.ts"],"names":[],"mappings":"AAGA,qBAAa,UAAU;IAQnB,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG;IAe7E,MAAM,CAAC,sBAAsB,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;KAAE;IAkC/H,MAAM,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,eAAe;CAuBzH"}
1
+ {"version":3,"file":"UrlHelpers.d.ts","sourceRoot":"","sources":["../../UrlHelpers.ts"],"names":[],"mappings":"AAeA,qBAAa,UAAU;IAQnB,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG;IAe7E,MAAM,CAAC,sBAAsB,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;KAAE;IAkC/H,MAAM,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,eAAe;CAuBzH"}
@@ -1,3 +1,9 @@
1
+ function formatQueryValue(value) {
2
+ if (value instanceof Date) {
3
+ return value.toISOString();
4
+ }
5
+ return String(value);
6
+ }
1
7
  class UrlHelpers {
2
8
  static createUrlFrom(origin, apiBasePath, route) {
3
9
  if ((!origin || origin.length === 0) && typeof document !== 'undefined') {
@@ -16,7 +22,7 @@ class UrlHelpers {
16
22
  continue;
17
23
  }
18
24
  const pattern = new RegExp(`\\{${key}\\}`, 'gi');
19
- const newRoute = result.replace(pattern, encodeURIComponent(String(value)));
25
+ const newRoute = result.replace(pattern, encodeURIComponent(formatQueryValue(value)));
20
26
  if (newRoute !== result) {
21
27
  delete unusedParameters[key];
22
28
  result = newRoute;
@@ -30,17 +36,17 @@ class UrlHelpers {
30
36
  if (value !== undefined && value !== null) {
31
37
  if (Array.isArray(value)) {
32
38
  for (const item of value) {
33
- queryParams.append(key, String(item));
39
+ queryParams.append(key, formatQueryValue(item));
34
40
  }
35
41
  }
36
42
  else {
37
- queryParams.set(key, String(value));
43
+ queryParams.set(key, formatQueryValue(value));
38
44
  }
39
45
  }
40
46
  }
41
47
  if (additionalParams) {
42
48
  for (const [key, value] of Object.entries(additionalParams)) {
43
- queryParams.set(key, String(value));
49
+ queryParams.set(key, formatQueryValue(value));
44
50
  }
45
51
  }
46
52
  return queryParams;
@@ -1 +1 @@
1
- {"version":3,"file":"UrlHelpers.js","sources":["../../UrlHelpers.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nexport class UrlHelpers {\n /**\n * Creates a URL from the given origin, API base path, and route.\n * @param origin The origin of the request. If not provided, it defaults to the current document's origin.\n * @param apiBasePath The base path for the API.\n * @param route The specific route for the request.\n * @returns The constructed URL.\n */\n static createUrlFrom(origin: string, apiBasePath: string, route: string): URL {\n if ((!origin || origin.length === 0) && typeof document !== 'undefined') {\n origin = document.location?.origin ?? '';\n }\n\n return new URL(route, `${origin}${apiBasePath}`);\n }\n\n /**\n * Replaces route parameters in the route template with values from the parameters object.\n * Returns both the updated route and the parameters that were not used in the route.\n * @param route The route template with placeholders like {paramName}.\n * @param parameters The parameters to replace in the route.\n * @returns An object containing the updated route and unused parameters.\n */\n static replaceRouteParameters<T extends object>(route: string, parameters?: T): { route: string; unusedParameters: Partial<T> } {\n if (!parameters) {\n return { route, unusedParameters: {} };\n }\n\n let result = route;\n const unusedParameters: Partial<T> = { ...parameters };\n\n for (const [key, value] of Object.entries(parameters)) {\n // Array values cannot be encoded as a single route segment — leave them as unused so\n // they are serialized as repeated query string parameters (e.g. ?ids=1&ids=2&ids=3).\n if (Array.isArray(value)) {\n continue;\n }\n\n const pattern = new RegExp(`\\\\{${key}\\\\}`, 'gi');\n const newRoute = result.replace(pattern, encodeURIComponent(String(value)));\n \n if (newRoute !== result) {\n delete unusedParameters[key as keyof T];\n result = newRoute;\n }\n }\n\n return { route: result, unusedParameters };\n }\n\n /**\n * Builds URLSearchParams from the given parameters and additional query parameters.\n * Array values are serialized as repeated key=value pairs (e.g. ?ids=1&ids=2&ids=3).\n * @param unusedParameters Parameters that were not used in route replacement.\n * @param additionalParams Additional query parameters to include.\n * @returns URLSearchParams containing all parameters.\n */\n static buildQueryParams(unusedParameters: object, additionalParams?: Record<string, string | number>): URLSearchParams {\n const queryParams = new URLSearchParams();\n\n for (const [key, value] of Object.entries(unusedParameters)) {\n if (value !== undefined && value !== null) {\n if (Array.isArray(value)) {\n for (const item of value) {\n queryParams.append(key, String(item));\n }\n } else {\n queryParams.set(key, String(value));\n }\n }\n }\n\n if (additionalParams) {\n for (const [key, value] of Object.entries(additionalParams)) {\n queryParams.set(key, String(value));\n }\n }\n\n return queryParams;\n }\n}"],"names":[],"mappings":"MAGa,UAAU,CAAA;AAQnB,IAAA,OAAO,aAAa,CAAC,MAAc,EAAE,WAAmB,EAAE,KAAa,EAAA;AACnE,QAAA,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,KAAK,OAAO,QAAQ,KAAK,WAAW,EAAE;YACrE,MAAM,GAAG,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE;QAC5C;QAEA,OAAO,IAAI,GAAG,CAAC,KAAK,EAAE,CAAA,EAAG,MAAM,CAAA,EAAG,WAAW,CAAA,CAAE,CAAC;IACpD;AASA,IAAA,OAAO,sBAAsB,CAAmB,KAAa,EAAE,UAAc,EAAA;QACzE,IAAI,CAAC,UAAU,EAAE;AACb,YAAA,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,EAAE,EAAE;QAC1C;QAEA,IAAI,MAAM,GAAG,KAAK;AAClB,QAAA,MAAM,gBAAgB,GAAe,EAAE,GAAG,UAAU,EAAE;AAEtD,QAAA,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;AAGnD,YAAA,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;gBACtB;YACJ;YAEA,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,CAAA,GAAA,EAAM,GAAG,CAAA,GAAA,CAAK,EAAE,IAAI,CAAC;AAChD,YAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,kBAAkB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AAE3E,YAAA,IAAI,QAAQ,KAAK,MAAM,EAAE;AACrB,gBAAA,OAAO,gBAAgB,CAAC,GAAc,CAAC;gBACvC,MAAM,GAAG,QAAQ;YACrB;QACJ;AAEA,QAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE;IAC9C;AASA,IAAA,OAAO,gBAAgB,CAAC,gBAAwB,EAAE,gBAAkD,EAAA;AAChG,QAAA,MAAM,WAAW,GAAG,IAAI,eAAe,EAAE;AAEzC,QAAA,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE;YACzD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE;AACvC,gBAAA,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;AACtB,oBAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;wBACtB,WAAW,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;oBACzC;gBACJ;qBAAO;oBACH,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;gBACvC;YACJ;QACJ;QAEA,IAAI,gBAAgB,EAAE;AAClB,YAAA,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE;gBACzD,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YACvC;QACJ;AAEA,QAAA,OAAO,WAAW;IACtB;AACH;;;;"}
1
+ {"version":3,"file":"UrlHelpers.js","sources":["../../UrlHelpers.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n/**\n * Format a single query / route parameter value into a string the .NET TypeConverter\n * infrastructure can round-trip. Date values are emitted as ISO 8601 so DateTimeOffset\n * binding succeeds; everything else falls back to the JS String coercion.\n */\nfunction formatQueryValue(value: unknown): string {\n if (value instanceof Date) {\n return value.toISOString();\n }\n return String(value);\n}\n\nexport class UrlHelpers {\n /**\n * Creates a URL from the given origin, API base path, and route.\n * @param origin The origin of the request. If not provided, it defaults to the current document's origin.\n * @param apiBasePath The base path for the API.\n * @param route The specific route for the request.\n * @returns The constructed URL.\n */\n static createUrlFrom(origin: string, apiBasePath: string, route: string): URL {\n if ((!origin || origin.length === 0) && typeof document !== 'undefined') {\n origin = document.location?.origin ?? '';\n }\n\n return new URL(route, `${origin}${apiBasePath}`);\n }\n\n /**\n * Replaces route parameters in the route template with values from the parameters object.\n * Returns both the updated route and the parameters that were not used in the route.\n * @param route The route template with placeholders like {paramName}.\n * @param parameters The parameters to replace in the route.\n * @returns An object containing the updated route and unused parameters.\n */\n static replaceRouteParameters<T extends object>(route: string, parameters?: T): { route: string; unusedParameters: Partial<T> } {\n if (!parameters) {\n return { route, unusedParameters: {} };\n }\n\n let result = route;\n const unusedParameters: Partial<T> = { ...parameters };\n\n for (const [key, value] of Object.entries(parameters)) {\n // Array values cannot be encoded as a single route segment — leave them as unused so\n // they are serialized as repeated query string parameters (e.g. ?ids=1&ids=2&ids=3).\n if (Array.isArray(value)) {\n continue;\n }\n\n const pattern = new RegExp(`\\\\{${key}\\\\}`, 'gi');\n const newRoute = result.replace(pattern, encodeURIComponent(formatQueryValue(value)));\n\n if (newRoute !== result) {\n delete unusedParameters[key as keyof T];\n result = newRoute;\n }\n }\n\n return { route: result, unusedParameters };\n }\n\n /**\n * Builds URLSearchParams from the given parameters and additional query parameters.\n * Array values are serialized as repeated key=value pairs (e.g. ?ids=1&ids=2&ids=3).\n * @param unusedParameters Parameters that were not used in route replacement.\n * @param additionalParams Additional query parameters to include.\n * @returns URLSearchParams containing all parameters.\n */\n static buildQueryParams(unusedParameters: object, additionalParams?: Record<string, string | number>): URLSearchParams {\n const queryParams = new URLSearchParams();\n\n for (const [key, value] of Object.entries(unusedParameters)) {\n if (value !== undefined && value !== null) {\n if (Array.isArray(value)) {\n for (const item of value) {\n queryParams.append(key, formatQueryValue(item));\n }\n } else {\n queryParams.set(key, formatQueryValue(value));\n }\n }\n }\n\n if (additionalParams) {\n for (const [key, value] of Object.entries(additionalParams)) {\n queryParams.set(key, formatQueryValue(value));\n }\n }\n\n return queryParams;\n }\n}\n"],"names":[],"mappings":"AAQA,SAAS,gBAAgB,CAAC,KAAc,EAAA;AACpC,IAAA,IAAI,KAAK,YAAY,IAAI,EAAE;AACvB,QAAA,OAAO,KAAK,CAAC,WAAW,EAAE;IAC9B;AACA,IAAA,OAAO,MAAM,CAAC,KAAK,CAAC;AACxB;MAEa,UAAU,CAAA;AAQnB,IAAA,OAAO,aAAa,CAAC,MAAc,EAAE,WAAmB,EAAE,KAAa,EAAA;AACnE,QAAA,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,KAAK,OAAO,QAAQ,KAAK,WAAW,EAAE;YACrE,MAAM,GAAG,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE;QAC5C;QAEA,OAAO,IAAI,GAAG,CAAC,KAAK,EAAE,CAAA,EAAG,MAAM,CAAA,EAAG,WAAW,CAAA,CAAE,CAAC;IACpD;AASA,IAAA,OAAO,sBAAsB,CAAmB,KAAa,EAAE,UAAc,EAAA;QACzE,IAAI,CAAC,UAAU,EAAE;AACb,YAAA,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,EAAE,EAAE;QAC1C;QAEA,IAAI,MAAM,GAAG,KAAK;AAClB,QAAA,MAAM,gBAAgB,GAAe,EAAE,GAAG,UAAU,EAAE;AAEtD,QAAA,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;AAGnD,YAAA,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;gBACtB;YACJ;YAEA,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,CAAA,GAAA,EAAM,GAAG,CAAA,GAAA,CAAK,EAAE,IAAI,CAAC;AAChD,YAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,kBAAkB,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC;AAErF,YAAA,IAAI,QAAQ,KAAK,MAAM,EAAE;AACrB,gBAAA,OAAO,gBAAgB,CAAC,GAAc,CAAC;gBACvC,MAAM,GAAG,QAAQ;YACrB;QACJ;AAEA,QAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE;IAC9C;AASA,IAAA,OAAO,gBAAgB,CAAC,gBAAwB,EAAE,gBAAkD,EAAA;AAChG,QAAA,MAAM,WAAW,GAAG,IAAI,eAAe,EAAE;AAEzC,QAAA,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE;YACzD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE;AACvC,gBAAA,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;AACtB,oBAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;wBACtB,WAAW,CAAC,MAAM,CAAC,GAAG,EAAE,gBAAgB,CAAC,IAAI,CAAC,CAAC;oBACnD;gBACJ;qBAAO;oBACH,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC;gBACjD;YACJ;QACJ;QAEA,IAAI,gBAAgB,EAAE;AAClB,YAAA,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE;gBACzD,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC;YACjD;QACJ;AAEA,QAAA,OAAO,WAAW;IACtB;AACH;;;;"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=with_date_values.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with_date_values.d.ts","sourceRoot":"","sources":["../../../../for_UrlHelpers/when_building_query_params/with_date_values.ts"],"names":[],"mappings":""}
@@ -0,0 +1,13 @@
1
+ import { describe, it, beforeEach } from 'vitest';
2
+ import { UrlHelpers } from '../../UrlHelpers';
3
+ describe('when building query params with date values', () => {
4
+ const startTime = new Date(Date.UTC(2026, 5, 3, 13, 57, 6));
5
+ const endTime = new Date(Date.UTC(2026, 5, 3, 14, 0, 32));
6
+ let result;
7
+ beforeEach(() => {
8
+ result = UrlHelpers.buildQueryParams({ startTime, endTime });
9
+ });
10
+ it('should serialize startTime as ISO 8601', () => result.get('startTime').should.equal('2026-06-03T13:57:06.000Z'));
11
+ it('should serialize endTime as ISO 8601', () => result.get('endTime').should.equal('2026-06-03T14:00:32.000Z'));
12
+ });
13
+ //# sourceMappingURL=with_date_values.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with_date_values.js","sourceRoot":"","sources":["../../../../for_UrlHelpers/when_building_query_params/with_date_values.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,QAAQ,CAAC,6CAA6C,EAAE,GAAG,EAAE;IACzD,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IAC1D,IAAI,MAAuB,CAAC;IAE5B,UAAU,CAAC,GAAG,EAAE;QACZ,MAAM,GAAG,UAAU,CAAC,gBAAgB,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAE,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC,CAAC;IACtH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAE,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC,CAAC;AACtH,CAAC,CAAC,CAAC"}