@mfeflow/url-factory 0.1.0 → 0.2.0
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/dist/index.d.ts +16 -2
- package/dist/index.js +12 -6
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
type IdChar = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '_';
|
|
2
|
+
/** The leading letters, digits and underscores of `S`: where `fillPath` ends a param name. */
|
|
3
|
+
type Ident<S extends string, Acc extends string = ''> = S extends `${infer C}${infer Rest}` ? C extends IdChar ? Ident<Rest, `${Acc}${C}`> : Acc : Acc;
|
|
4
|
+
/**
|
|
5
|
+
* Names of `:params` in a path template, e.g. `'/v1/orders/:orderId/items/:itemId'` gives
|
|
6
|
+
* `'orderId' | 'itemId'`. A name is letters, digits and underscores, as in `fillPath`, so
|
|
7
|
+
* `'/a/:order-id'` has the param `order`.
|
|
8
|
+
*/
|
|
9
|
+
export type PathParams<P extends string> = string extends P ? string : P extends `${string}:${infer Rest}` ? Exclude<Ident<Rest>, ''> | PathParams<Rest> : never;
|
|
10
|
+
/**
|
|
11
|
+
* Fills the `:params` of a path template with encoded values. Throws for a missing param and for
|
|
12
|
+
* the values `.` and `..`, which would walk out of the path. `scope` and `id` only name the caller in
|
|
13
|
+
* the message.
|
|
14
|
+
*/
|
|
15
|
+
export declare function fillPath(template: string, params: Readonly<Record<string, string | number>> | undefined, scope: string, id: string): string;
|
|
3
16
|
export type QueryValue = string | number | boolean | null | undefined | readonly (string | number | boolean)[];
|
|
4
17
|
export type Query = Readonly<Record<string, QueryValue>>;
|
|
5
18
|
export interface Endpoint {
|
|
@@ -30,3 +43,4 @@ export declare function defineEndpoints<const E extends Endpoints>(endpoints: E)
|
|
|
30
43
|
* ```
|
|
31
44
|
*/
|
|
32
45
|
export declare function createUrlFactory<E extends Endpoints>(endpoints: E, baseUrl: (service: E[keyof E]['service']) => string | undefined): UrlFactory<E>;
|
|
46
|
+
export {};
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
const PARAM = /:([A-Za-z0-9_]+)/g;
|
|
2
|
+
function fillPath(template, params, scope, id) {
|
|
3
|
+
return template.replace(PARAM, (_match, name)=>{
|
|
4
|
+
const value = params?.[name];
|
|
5
|
+
if (void 0 === value) throw new Error(`${scope}: missing param "${name}" for "${id}"`);
|
|
6
|
+
const text = String(value);
|
|
7
|
+
if ('.' === text || '..' === text) throw new Error(`${scope}: param "${name}" for "${id}" cannot be "${text}"`);
|
|
8
|
+
return encodeURIComponent(text);
|
|
9
|
+
});
|
|
10
|
+
}
|
|
1
11
|
function defineEndpoints(endpoints) {
|
|
2
12
|
for (const [key, e] of Object.entries(endpoints))if (!e.path.startsWith('/')) throw new Error(`Endpoint "${key}": path must start with "/"`);
|
|
3
13
|
return endpoints;
|
|
@@ -14,14 +24,10 @@ function createUrlFactory(endpoints, baseUrl) {
|
|
|
14
24
|
const base = baseUrl(endpoint.service);
|
|
15
25
|
if (!base) throw new Error(`url-factory: no base URL for service "${endpoint.service}" (endpoint "${key}")`);
|
|
16
26
|
const options = args[0];
|
|
17
|
-
const path = endpoint.path
|
|
18
|
-
const value = options?.params?.[name];
|
|
19
|
-
if (void 0 === value) throw new Error(`url-factory: missing param "${name}" for "${key}"`);
|
|
20
|
-
return encodeURIComponent(String(value));
|
|
21
|
-
});
|
|
27
|
+
const path = fillPath(endpoint.path, options?.params, 'url-factory', key);
|
|
22
28
|
const url = new URL(path.slice(1), base.endsWith('/') ? base : `${base}/`);
|
|
23
29
|
appendQuery(url, options?.query);
|
|
24
30
|
return url.toString();
|
|
25
31
|
};
|
|
26
32
|
}
|
|
27
|
-
export { createUrlFactory, defineEndpoints };
|
|
33
|
+
export { createUrlFactory, defineEndpoints, fillPath };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mfeflow/url-factory",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Typed API URLs for micro-frontends: path params are checked from the template at compile time, base URLs come from runtime config, so one build runs in every environment.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"micro-frontend",
|