@twin.org/web 0.0.3-next.11 → 0.0.3-next.13
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.
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
// Copyright 2024 IOTA Stiftung.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0.
|
|
3
|
-
import { Is } from "@twin.org/core";
|
|
3
|
+
import { GeneralError, Guards, Is } from "@twin.org/core";
|
|
4
4
|
/**
|
|
5
5
|
* Class to helper with header operations.
|
|
6
6
|
*/
|
|
7
7
|
export class HeaderHelper {
|
|
8
|
+
/**
|
|
9
|
+
* Runtime name for the class.
|
|
10
|
+
*/
|
|
11
|
+
static CLASS_NAME = "HeaderHelper";
|
|
8
12
|
/**
|
|
9
13
|
* Create a bearer token header.
|
|
10
14
|
* @param token The token to create the header for.
|
|
@@ -30,5 +34,135 @@ export class HeaderHelper {
|
|
|
30
34
|
}
|
|
31
35
|
return "";
|
|
32
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Extract the properties from a Link header for a specific relation type.
|
|
39
|
+
* @param linkHeader The Link header value in format `<url>; rel="..."; param1=""; param2=""`.
|
|
40
|
+
* @param relation The relation type to extract.
|
|
41
|
+
* @returns The extracted URL, rel and optional params or undefined if invalid/missing.
|
|
42
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Link
|
|
43
|
+
*/
|
|
44
|
+
static extractLinkHeaderRelation(linkHeader, relation) {
|
|
45
|
+
const headers = HeaderHelper.extractLinkHeaders(linkHeader);
|
|
46
|
+
if (Is.arrayValue(headers)) {
|
|
47
|
+
return headers.find(h => h.rel === relation);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Extract the link headers.
|
|
52
|
+
* @param linkHeader The Link header value in format `<url>; rel="..."; param1=""; param2=""`.
|
|
53
|
+
* @returns The extracted possible array of URL, rel and optional params or undefined if invalid/missing.
|
|
54
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Link
|
|
55
|
+
*/
|
|
56
|
+
static extractLinkHeaders(linkHeader) {
|
|
57
|
+
if (Is.stringValue(linkHeader)) {
|
|
58
|
+
const header = HeaderHelper.extractLinkHeader(linkHeader);
|
|
59
|
+
return header ? [header] : [];
|
|
60
|
+
}
|
|
61
|
+
if (Is.arrayValue(linkHeader)) {
|
|
62
|
+
const results = [];
|
|
63
|
+
for (const singleLinkHeader of linkHeader) {
|
|
64
|
+
const header = HeaderHelper.extractLinkHeader(singleLinkHeader);
|
|
65
|
+
if (header) {
|
|
66
|
+
results.push(header);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return results;
|
|
70
|
+
}
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Extract the properties from a Link header.
|
|
75
|
+
* @param linkHeader The Link header value in format `<url>; rel="..."; param1=""; param2=""`.
|
|
76
|
+
* @returns The extracted URL, rel and optional params or undefined if invalid/missing.
|
|
77
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Link
|
|
78
|
+
*/
|
|
79
|
+
static extractLinkHeader(linkHeader) {
|
|
80
|
+
if (!Is.stringValue(linkHeader)) {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
const parts = linkHeader.split(";");
|
|
84
|
+
if (parts.length >= 2) {
|
|
85
|
+
let url;
|
|
86
|
+
let urlQueryParams;
|
|
87
|
+
const urlMatch = /<([^>]+)>/.exec(parts[0]);
|
|
88
|
+
if (Is.stringValue(urlMatch?.[1])) {
|
|
89
|
+
url = urlMatch[1];
|
|
90
|
+
const queryIndex = url.indexOf("?");
|
|
91
|
+
if (queryIndex !== -1) {
|
|
92
|
+
const urlParamsString = url.slice(queryIndex + 1);
|
|
93
|
+
const queryParts = urlParamsString.split("&");
|
|
94
|
+
for (const queryPart of queryParts) {
|
|
95
|
+
const [key, value] = queryPart.split("=");
|
|
96
|
+
if (Is.stringValue(key) && Is.stringValue(value)) {
|
|
97
|
+
urlQueryParams ??= {};
|
|
98
|
+
urlQueryParams[key] = decodeURIComponent(value);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
let rel;
|
|
104
|
+
const params = {};
|
|
105
|
+
for (let i = 1; i < parts.length; i++) {
|
|
106
|
+
const relMatch = /rel="([^"]+)"/.exec(parts[i].trim());
|
|
107
|
+
if (relMatch?.[1]) {
|
|
108
|
+
rel = relMatch[1];
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
const paramMatch = /([^=]+)="([^"]+)"/.exec(parts[i].trim());
|
|
112
|
+
if (paramMatch?.[1] && paramMatch?.[2]) {
|
|
113
|
+
params[paramMatch[1]] = paramMatch[2];
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (Is.stringValue(url) && Is.stringValue(rel)) {
|
|
118
|
+
return {
|
|
119
|
+
url,
|
|
120
|
+
urlQueryParams,
|
|
121
|
+
rel,
|
|
122
|
+
params: Object.keys(params).length > 0 ? params : undefined
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Create a compliant Link header.
|
|
130
|
+
* @param url The URL to include in the Link header.
|
|
131
|
+
* @param urlQueryParams Optional query parameters to include in the URL.
|
|
132
|
+
* @param rel The relation type (e.g., "next", "prev", "self").
|
|
133
|
+
* @returns The formatted Link header string.
|
|
134
|
+
* @throws GeneralError if the URL or rel are invalid.
|
|
135
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Link
|
|
136
|
+
*/
|
|
137
|
+
static createLinkHeader(url, urlQueryParams, rel, params) {
|
|
138
|
+
Guards.stringValue(HeaderHelper.CLASS_NAME, "url", url);
|
|
139
|
+
Guards.stringValue(HeaderHelper.CLASS_NAME, "rel", rel);
|
|
140
|
+
if (url.includes(">")) {
|
|
141
|
+
throw new GeneralError(HeaderHelper.CLASS_NAME, "invalidLinkHeaderURL");
|
|
142
|
+
}
|
|
143
|
+
if (rel.includes('"')) {
|
|
144
|
+
throw new GeneralError(HeaderHelper.CLASS_NAME, "invalidLinkHeaderRel");
|
|
145
|
+
}
|
|
146
|
+
if (Is.objectValue(urlQueryParams)) {
|
|
147
|
+
const queryParamsString = Object.entries(urlQueryParams)
|
|
148
|
+
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
|
|
149
|
+
.join("&");
|
|
150
|
+
const queryIndex = url.indexOf("?");
|
|
151
|
+
if (queryIndex === -1) {
|
|
152
|
+
url += `?${queryParamsString}`;
|
|
153
|
+
}
|
|
154
|
+
else if (queryIndex === url.length - 1) {
|
|
155
|
+
url += queryParamsString;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
url += `&${queryParamsString}`;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return `<${url}>; rel="${rel}"${params
|
|
162
|
+
? Object.entries(params)
|
|
163
|
+
.map(([key, value]) => `; ${key}="${value}"`)
|
|
164
|
+
.join("")
|
|
165
|
+
: ""}`;
|
|
166
|
+
}
|
|
33
167
|
}
|
|
34
168
|
//# sourceMappingURL=headerHelper.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"headerHelper.js","sourceRoot":"","sources":["../../../src/utils/headerHelper.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AAEpC;;GAEG;AACH,MAAM,OAAO,YAAY;IACxB;;;;OAIG;IACI,MAAM,CAAC,YAAY,CAAC,KAAc;QACxC,IAAI,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3B,IAAI,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBACjC,OAAO,KAAK,CAAC;YACd,CAAC;YACD,OAAO,UAAU,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QACjC,CAAC;QACD,OAAO,EAAE,CAAC;IACX,CAAC;IAED;;;;OAIG;IACI,MAAM,CAAC,aAAa,CAAC,MAAe;QAC1C,IAAI,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC5D,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QAC9C,CAAC;QACD,OAAO,EAAE,CAAC;IACX,CAAC;CACD","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { Is } from \"@twin.org/core\";\n\n/**\n * Class to helper with header operations.\n */\nexport class HeaderHelper {\n\t/**\n\t * Create a bearer token header.\n\t * @param token The token to create the header for.\n\t * @returns The bearer token header.\n\t */\n\tpublic static createBearer(token: unknown): string {\n\t\tif (Is.stringValue(token)) {\n\t\t\tif (token.startsWith(\"Bearer \")) {\n\t\t\t\treturn token;\n\t\t\t}\n\t\t\treturn `Bearer ${token.trim()}`;\n\t\t}\n\t\treturn \"\";\n\t}\n\n\t/**\n\t * Extract the bearer token from a header.\n\t * @param header The header value to extract the token from.\n\t * @returns The extracted token if it exists.\n\t */\n\tpublic static extractBearer(header: unknown): string {\n\t\tif (Is.stringValue(header) && header.startsWith(\"Bearer \")) {\n\t\t\treturn header.slice(7, header.length).trim();\n\t\t}\n\t\treturn \"\";\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"headerHelper.js","sourceRoot":"","sources":["../../../src/utils/headerHelper.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AAG1D;;GAEG;AACH,MAAM,OAAO,YAAY;IACxB;;OAEG;IACI,MAAM,CAAU,UAAU,kBAAkC;IAEnE;;;;OAIG;IACI,MAAM,CAAC,YAAY,CAAC,KAAc;QACxC,IAAI,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3B,IAAI,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBACjC,OAAO,KAAK,CAAC;YACd,CAAC;YACD,OAAO,UAAU,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QACjC,CAAC;QACD,OAAO,EAAE,CAAC;IACX,CAAC;IAED;;;;OAIG;IACI,MAAM,CAAC,aAAa,CAAC,MAAe;QAC1C,IAAI,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC5D,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QAC9C,CAAC;QACD,OAAO,EAAE,CAAC;IACX,CAAC;IAED;;;;;;OAMG;IACI,MAAM,CAAC,yBAAyB,CACtC,UAAmB,EACnB,QAAgB;QAShB,MAAM,OAAO,GAAG,YAAY,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC;QAC5D,IAAI,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC;QAC9C,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,kBAAkB,CAAC,UAAmB;QAQnD,IAAI,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC;YAChC,MAAM,MAAM,GAAG,YAAY,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;YAC1D,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/B,CAAC;QACD,IAAI,EAAE,CAAC,UAAU,CAAS,UAAU,CAAC,EAAE,CAAC;YACvC,MAAM,OAAO,GAAG,EAAE,CAAC;YACnB,KAAK,MAAM,gBAAgB,IAAI,UAAU,EAAE,CAAC;gBAC3C,MAAM,MAAM,GAAG,YAAY,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,CAAC;gBAChE,IAAI,MAAM,EAAE,CAAC;oBACZ,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACtB,CAAC;YACF,CAAC;YACD,OAAO,OAAO,CAAC;QAChB,CAAC;QACD,OAAO,SAAS,CAAC;IAClB,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,iBAAiB,CAAC,UAAkB;QAQjD,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC;YACjC,OAAO,SAAS,CAAC;QAClB,CAAC;QAED,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAEpC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YACvB,IAAI,GAAG,CAAC;YACR,IAAI,cAAoD,CAAC;YAEzD,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5C,IAAI,EAAE,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnC,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;gBAElB,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBACpC,IAAI,UAAU,KAAK,CAAC,CAAC,EAAE,CAAC;oBACvB,MAAM,eAAe,GAAG,GAAG,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;oBAClD,MAAM,UAAU,GAAG,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;oBAE9C,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;wBACpC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;wBAC1C,IAAI,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;4BAClD,cAAc,KAAK,EAAE,CAAC;4BACtB,cAAc,CAAC,GAAG,CAAC,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;wBACjD,CAAC;oBACF,CAAC;gBACF,CAAC;YACF,CAAC;YAED,IAAI,GAAG,CAAC;YACR,MAAM,MAAM,GAA6B,EAAE,CAAC;YAE5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACvC,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;gBACvD,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACnB,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;gBACnB,CAAC;qBAAM,CAAC;oBACP,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;oBAC7D,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;wBACxC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;oBACvC,CAAC;gBACF,CAAC;YACF,CAAC;YAED,IAAI,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;gBAChD,OAAO;oBACN,GAAG;oBACH,cAAc;oBACd,GAAG;oBACH,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;iBAC3D,CAAC;YACH,CAAC;QACF,CAAC;QAED,OAAO,SAAS,CAAC;IAClB,CAAC;IAED;;;;;;;;OAQG;IACI,MAAM,CAAC,gBAAgB,CAC7B,GAAW,EACX,cAAoD,EACpD,GAAW,EACX,MAAiC;QAEjC,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,UAAU,SAAe,GAAG,CAAC,CAAC;QAC9D,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,UAAU,SAAe,GAAG,CAAC,CAAC;QAE9D,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,YAAY,CAAC,YAAY,CAAC,UAAU,EAAE,sBAAsB,CAAC,CAAC;QACzE,CAAC;QACD,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,YAAY,CAAC,YAAY,CAAC,UAAU,EAAE,sBAAsB,CAAC,CAAC;QACzE,CAAC;QAED,IAAI,EAAE,CAAC,WAAW,CAAC,cAAc,CAAC,EAAE,CAAC;YACpC,MAAM,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC;iBACtD,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;iBAC5D,IAAI,CAAC,GAAG,CAAC,CAAC;YACZ,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACpC,IAAI,UAAU,KAAK,CAAC,CAAC,EAAE,CAAC;gBACvB,GAAG,IAAI,IAAI,iBAAiB,EAAE,CAAC;YAChC,CAAC;iBAAM,IAAI,UAAU,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1C,GAAG,IAAI,iBAAiB,CAAC;YAC1B,CAAC;iBAAM,CAAC;gBACP,GAAG,IAAI,IAAI,iBAAiB,EAAE,CAAC;YAChC,CAAC;QACF,CAAC;QAED,OAAO,IAAI,GAAG,WAAW,GAAG,IAC3B,MAAM;YACL,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;iBACrB,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,GAAG,KAAK,KAAK,GAAG,CAAC;iBAC5C,IAAI,CAAC,EAAE,CAAC;YACX,CAAC,CAAC,EACJ,EAAE,CAAC;IACJ,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { GeneralError, Guards, Is } from \"@twin.org/core\";\nimport { nameof } from \"@twin.org/nameof\";\n\n/**\n * Class to helper with header operations.\n */\nexport class HeaderHelper {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<HeaderHelper>();\n\n\t/**\n\t * Create a bearer token header.\n\t * @param token The token to create the header for.\n\t * @returns The bearer token header.\n\t */\n\tpublic static createBearer(token: unknown): string {\n\t\tif (Is.stringValue(token)) {\n\t\t\tif (token.startsWith(\"Bearer \")) {\n\t\t\t\treturn token;\n\t\t\t}\n\t\t\treturn `Bearer ${token.trim()}`;\n\t\t}\n\t\treturn \"\";\n\t}\n\n\t/**\n\t * Extract the bearer token from a header.\n\t * @param header The header value to extract the token from.\n\t * @returns The extracted token if it exists.\n\t */\n\tpublic static extractBearer(header: unknown): string {\n\t\tif (Is.stringValue(header) && header.startsWith(\"Bearer \")) {\n\t\t\treturn header.slice(7, header.length).trim();\n\t\t}\n\t\treturn \"\";\n\t}\n\n\t/**\n\t * Extract the properties from a Link header for a specific relation type.\n\t * @param linkHeader The Link header value in format `<url>; rel=\"...\"; param1=\"\"; param2=\"\"`.\n\t * @param relation The relation type to extract.\n\t * @returns The extracted URL, rel and optional params or undefined if invalid/missing.\n\t * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Link\n\t */\n\tpublic static extractLinkHeaderRelation(\n\t\tlinkHeader: unknown,\n\t\trelation: string\n\t):\n\t\t| {\n\t\t\t\turl: string;\n\t\t\t\turlQueryParams?: { [id: string]: string };\n\t\t\t\trel: string;\n\t\t\t\tparams?: { [id: string]: string };\n\t\t }\n\t\t| undefined {\n\t\tconst headers = HeaderHelper.extractLinkHeaders(linkHeader);\n\t\tif (Is.arrayValue(headers)) {\n\t\t\treturn headers.find(h => h.rel === relation);\n\t\t}\n\t}\n\n\t/**\n\t * Extract the link headers.\n\t * @param linkHeader The Link header value in format `<url>; rel=\"...\"; param1=\"\"; param2=\"\"`.\n\t * @returns The extracted possible array of URL, rel and optional params or undefined if invalid/missing.\n\t * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Link\n\t */\n\tpublic static extractLinkHeaders(linkHeader: unknown):\n\t\t| {\n\t\t\t\turl: string;\n\t\t\t\turlQueryParams?: { [id: string]: string };\n\t\t\t\trel: string;\n\t\t\t\tparams?: { [id: string]: string };\n\t\t }[]\n\t\t| undefined {\n\t\tif (Is.stringValue(linkHeader)) {\n\t\t\tconst header = HeaderHelper.extractLinkHeader(linkHeader);\n\t\t\treturn header ? [header] : [];\n\t\t}\n\t\tif (Is.arrayValue<string>(linkHeader)) {\n\t\t\tconst results = [];\n\t\t\tfor (const singleLinkHeader of linkHeader) {\n\t\t\t\tconst header = HeaderHelper.extractLinkHeader(singleLinkHeader);\n\t\t\t\tif (header) {\n\t\t\t\t\tresults.push(header);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn results;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Extract the properties from a Link header.\n\t * @param linkHeader The Link header value in format `<url>; rel=\"...\"; param1=\"\"; param2=\"\"`.\n\t * @returns The extracted URL, rel and optional params or undefined if invalid/missing.\n\t * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Link\n\t */\n\tpublic static extractLinkHeader(linkHeader: string):\n\t\t| {\n\t\t\t\turl: string;\n\t\t\t\turlQueryParams?: { [id: string]: string };\n\t\t\t\trel: string;\n\t\t\t\tparams?: { [id: string]: string };\n\t\t }\n\t\t| undefined {\n\t\tif (!Is.stringValue(linkHeader)) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst parts = linkHeader.split(\";\");\n\n\t\tif (parts.length >= 2) {\n\t\t\tlet url;\n\t\t\tlet urlQueryParams: { [id: string]: string } | undefined;\n\n\t\t\tconst urlMatch = /<([^>]+)>/.exec(parts[0]);\n\t\t\tif (Is.stringValue(urlMatch?.[1])) {\n\t\t\t\turl = urlMatch[1];\n\n\t\t\t\tconst queryIndex = url.indexOf(\"?\");\n\t\t\t\tif (queryIndex !== -1) {\n\t\t\t\t\tconst urlParamsString = url.slice(queryIndex + 1);\n\t\t\t\t\tconst queryParts = urlParamsString.split(\"&\");\n\n\t\t\t\t\tfor (const queryPart of queryParts) {\n\t\t\t\t\t\tconst [key, value] = queryPart.split(\"=\");\n\t\t\t\t\t\tif (Is.stringValue(key) && Is.stringValue(value)) {\n\t\t\t\t\t\t\turlQueryParams ??= {};\n\t\t\t\t\t\t\turlQueryParams[key] = decodeURIComponent(value);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet rel;\n\t\t\tconst params: { [id: string]: string } = {};\n\n\t\t\tfor (let i = 1; i < parts.length; i++) {\n\t\t\t\tconst relMatch = /rel=\"([^\"]+)\"/.exec(parts[i].trim());\n\t\t\t\tif (relMatch?.[1]) {\n\t\t\t\t\trel = relMatch[1];\n\t\t\t\t} else {\n\t\t\t\t\tconst paramMatch = /([^=]+)=\"([^\"]+)\"/.exec(parts[i].trim());\n\t\t\t\t\tif (paramMatch?.[1] && paramMatch?.[2]) {\n\t\t\t\t\t\tparams[paramMatch[1]] = paramMatch[2];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Is.stringValue(url) && Is.stringValue(rel)) {\n\t\t\t\treturn {\n\t\t\t\t\turl,\n\t\t\t\t\turlQueryParams,\n\t\t\t\t\trel,\n\t\t\t\t\tparams: Object.keys(params).length > 0 ? params : undefined\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Create a compliant Link header.\n\t * @param url The URL to include in the Link header.\n\t * @param urlQueryParams Optional query parameters to include in the URL.\n\t * @param rel The relation type (e.g., \"next\", \"prev\", \"self\").\n\t * @returns The formatted Link header string.\n\t * @throws GeneralError if the URL or rel are invalid.\n\t * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Link\n\t */\n\tpublic static createLinkHeader(\n\t\turl: string,\n\t\turlQueryParams: { [id: string]: string } | undefined,\n\t\trel: string,\n\t\tparams?: { [id: string]: string }\n\t): string {\n\t\tGuards.stringValue(HeaderHelper.CLASS_NAME, nameof(url), url);\n\t\tGuards.stringValue(HeaderHelper.CLASS_NAME, nameof(rel), rel);\n\n\t\tif (url.includes(\">\")) {\n\t\t\tthrow new GeneralError(HeaderHelper.CLASS_NAME, \"invalidLinkHeaderURL\");\n\t\t}\n\t\tif (rel.includes('\"')) {\n\t\t\tthrow new GeneralError(HeaderHelper.CLASS_NAME, \"invalidLinkHeaderRel\");\n\t\t}\n\n\t\tif (Is.objectValue(urlQueryParams)) {\n\t\t\tconst queryParamsString = Object.entries(urlQueryParams)\n\t\t\t\t.map(([key, value]) => `${key}=${encodeURIComponent(value)}`)\n\t\t\t\t.join(\"&\");\n\t\t\tconst queryIndex = url.indexOf(\"?\");\n\t\t\tif (queryIndex === -1) {\n\t\t\t\turl += `?${queryParamsString}`;\n\t\t\t} else if (queryIndex === url.length - 1) {\n\t\t\t\turl += queryParamsString;\n\t\t\t} else {\n\t\t\t\turl += `&${queryParamsString}`;\n\t\t\t}\n\t\t}\n\n\t\treturn `<${url}>; rel=\"${rel}\"${\n\t\t\tparams\n\t\t\t\t? Object.entries(params)\n\t\t\t\t\t\t.map(([key, value]) => `; ${key}=\"${value}\"`)\n\t\t\t\t\t\t.join(\"\")\n\t\t\t\t: \"\"\n\t\t}`;\n\t}\n}\n"]}
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
* Class to helper with header operations.
|
|
3
3
|
*/
|
|
4
4
|
export declare class HeaderHelper {
|
|
5
|
+
/**
|
|
6
|
+
* Runtime name for the class.
|
|
7
|
+
*/
|
|
8
|
+
static readonly CLASS_NAME: string;
|
|
5
9
|
/**
|
|
6
10
|
* Create a bearer token header.
|
|
7
11
|
* @param token The token to create the header for.
|
|
@@ -14,4 +18,67 @@ export declare class HeaderHelper {
|
|
|
14
18
|
* @returns The extracted token if it exists.
|
|
15
19
|
*/
|
|
16
20
|
static extractBearer(header: unknown): string;
|
|
21
|
+
/**
|
|
22
|
+
* Extract the properties from a Link header for a specific relation type.
|
|
23
|
+
* @param linkHeader The Link header value in format `<url>; rel="..."; param1=""; param2=""`.
|
|
24
|
+
* @param relation The relation type to extract.
|
|
25
|
+
* @returns The extracted URL, rel and optional params or undefined if invalid/missing.
|
|
26
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Link
|
|
27
|
+
*/
|
|
28
|
+
static extractLinkHeaderRelation(linkHeader: unknown, relation: string): {
|
|
29
|
+
url: string;
|
|
30
|
+
urlQueryParams?: {
|
|
31
|
+
[id: string]: string;
|
|
32
|
+
};
|
|
33
|
+
rel: string;
|
|
34
|
+
params?: {
|
|
35
|
+
[id: string]: string;
|
|
36
|
+
};
|
|
37
|
+
} | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Extract the link headers.
|
|
40
|
+
* @param linkHeader The Link header value in format `<url>; rel="..."; param1=""; param2=""`.
|
|
41
|
+
* @returns The extracted possible array of URL, rel and optional params or undefined if invalid/missing.
|
|
42
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Link
|
|
43
|
+
*/
|
|
44
|
+
static extractLinkHeaders(linkHeader: unknown): {
|
|
45
|
+
url: string;
|
|
46
|
+
urlQueryParams?: {
|
|
47
|
+
[id: string]: string;
|
|
48
|
+
};
|
|
49
|
+
rel: string;
|
|
50
|
+
params?: {
|
|
51
|
+
[id: string]: string;
|
|
52
|
+
};
|
|
53
|
+
}[] | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* Extract the properties from a Link header.
|
|
56
|
+
* @param linkHeader The Link header value in format `<url>; rel="..."; param1=""; param2=""`.
|
|
57
|
+
* @returns The extracted URL, rel and optional params or undefined if invalid/missing.
|
|
58
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Link
|
|
59
|
+
*/
|
|
60
|
+
static extractLinkHeader(linkHeader: string): {
|
|
61
|
+
url: string;
|
|
62
|
+
urlQueryParams?: {
|
|
63
|
+
[id: string]: string;
|
|
64
|
+
};
|
|
65
|
+
rel: string;
|
|
66
|
+
params?: {
|
|
67
|
+
[id: string]: string;
|
|
68
|
+
};
|
|
69
|
+
} | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* Create a compliant Link header.
|
|
72
|
+
* @param url The URL to include in the Link header.
|
|
73
|
+
* @param urlQueryParams Optional query parameters to include in the URL.
|
|
74
|
+
* @param rel The relation type (e.g., "next", "prev", "self").
|
|
75
|
+
* @returns The formatted Link header string.
|
|
76
|
+
* @throws GeneralError if the URL or rel are invalid.
|
|
77
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Link
|
|
78
|
+
*/
|
|
79
|
+
static createLinkHeader(url: string, urlQueryParams: {
|
|
80
|
+
[id: string]: string;
|
|
81
|
+
} | undefined, rel: string, params?: {
|
|
82
|
+
[id: string]: string;
|
|
83
|
+
}): string;
|
|
17
84
|
}
|
package/docs/changelog.md
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
# @twin.org/web - Changelog
|
|
2
2
|
|
|
3
|
+
## [0.0.3-next.13](https://github.com/twinfoundation/framework/compare/web-v0.0.3-next.12...web-v0.0.3-next.13) (2026-01-08)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add Link header array support ([aff32a3](https://github.com/twinfoundation/framework/commit/aff32a3ff8ad3d076cade7c889444220706bfb1e))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* dependencies
|
|
15
|
+
* @twin.org/core bumped from 0.0.3-next.12 to 0.0.3-next.13
|
|
16
|
+
* @twin.org/crypto bumped from 0.0.3-next.12 to 0.0.3-next.13
|
|
17
|
+
* @twin.org/nameof bumped from 0.0.3-next.12 to 0.0.3-next.13
|
|
18
|
+
* devDependencies
|
|
19
|
+
* @twin.org/nameof-transformer bumped from 0.0.3-next.12 to 0.0.3-next.13
|
|
20
|
+
* @twin.org/nameof-vitest-plugin bumped from 0.0.3-next.12 to 0.0.3-next.13
|
|
21
|
+
* @twin.org/validate-locales bumped from 0.0.3-next.12 to 0.0.3-next.13
|
|
22
|
+
|
|
23
|
+
## [0.0.3-next.12](https://github.com/twinfoundation/framework/compare/web-v0.0.3-next.11...web-v0.0.3-next.12) (2026-01-08)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
### Features
|
|
27
|
+
|
|
28
|
+
* adding link header helper ([#225](https://github.com/twinfoundation/framework/issues/225)) ([703c072](https://github.com/twinfoundation/framework/commit/703c0725aceac6b6ec0c4fa729ef832d12fb3fd7))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
### Dependencies
|
|
32
|
+
|
|
33
|
+
* The following workspace dependencies were updated
|
|
34
|
+
* dependencies
|
|
35
|
+
* @twin.org/core bumped from 0.0.3-next.11 to 0.0.3-next.12
|
|
36
|
+
* @twin.org/crypto bumped from 0.0.3-next.11 to 0.0.3-next.12
|
|
37
|
+
* @twin.org/nameof bumped from 0.0.3-next.11 to 0.0.3-next.12
|
|
38
|
+
* devDependencies
|
|
39
|
+
* @twin.org/nameof-transformer bumped from 0.0.3-next.11 to 0.0.3-next.12
|
|
40
|
+
* @twin.org/nameof-vitest-plugin bumped from 0.0.3-next.11 to 0.0.3-next.12
|
|
41
|
+
* @twin.org/validate-locales bumped from 0.0.3-next.11 to 0.0.3-next.12
|
|
42
|
+
|
|
3
43
|
## [0.0.3-next.11](https://github.com/twinfoundation/framework/compare/web-v0.0.3-next.10...web-v0.0.3-next.11) (2026-01-07)
|
|
4
44
|
|
|
5
45
|
|
|
@@ -12,6 +12,14 @@ Class to helper with header operations.
|
|
|
12
12
|
|
|
13
13
|
`HeaderHelper`
|
|
14
14
|
|
|
15
|
+
## Properties
|
|
16
|
+
|
|
17
|
+
### CLASS\_NAME
|
|
18
|
+
|
|
19
|
+
> `readonly` `static` **CLASS\_NAME**: `string`
|
|
20
|
+
|
|
21
|
+
Runtime name for the class.
|
|
22
|
+
|
|
15
23
|
## Methods
|
|
16
24
|
|
|
17
25
|
### createBearer()
|
|
@@ -55,3 +63,131 @@ The header value to extract the token from.
|
|
|
55
63
|
`string`
|
|
56
64
|
|
|
57
65
|
The extracted token if it exists.
|
|
66
|
+
|
|
67
|
+
***
|
|
68
|
+
|
|
69
|
+
### extractLinkHeaderRelation()
|
|
70
|
+
|
|
71
|
+
> `static` **extractLinkHeaderRelation**(`linkHeader`, `relation`): \{ `url`: `string`; `urlQueryParams?`: \{\[`id`: `string`\]: `string`; \}; `rel`: `string`; `params?`: \{\[`id`: `string`\]: `string`; \}; \} \| `undefined`
|
|
72
|
+
|
|
73
|
+
Extract the properties from a Link header for a specific relation type.
|
|
74
|
+
|
|
75
|
+
#### Parameters
|
|
76
|
+
|
|
77
|
+
##### linkHeader
|
|
78
|
+
|
|
79
|
+
`unknown`
|
|
80
|
+
|
|
81
|
+
The Link header value in format `<url>; rel="..."; param1=""; param2=""`.
|
|
82
|
+
|
|
83
|
+
##### relation
|
|
84
|
+
|
|
85
|
+
`string`
|
|
86
|
+
|
|
87
|
+
The relation type to extract.
|
|
88
|
+
|
|
89
|
+
#### Returns
|
|
90
|
+
|
|
91
|
+
\{ `url`: `string`; `urlQueryParams?`: \{\[`id`: `string`\]: `string`; \}; `rel`: `string`; `params?`: \{\[`id`: `string`\]: `string`; \}; \} \| `undefined`
|
|
92
|
+
|
|
93
|
+
The extracted URL, rel and optional params or undefined if invalid/missing.
|
|
94
|
+
|
|
95
|
+
#### See
|
|
96
|
+
|
|
97
|
+
https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Link
|
|
98
|
+
|
|
99
|
+
***
|
|
100
|
+
|
|
101
|
+
### extractLinkHeaders()
|
|
102
|
+
|
|
103
|
+
> `static` **extractLinkHeaders**(`linkHeader`): `object`[] \| `undefined`
|
|
104
|
+
|
|
105
|
+
Extract the link headers.
|
|
106
|
+
|
|
107
|
+
#### Parameters
|
|
108
|
+
|
|
109
|
+
##### linkHeader
|
|
110
|
+
|
|
111
|
+
`unknown`
|
|
112
|
+
|
|
113
|
+
The Link header value in format `<url>; rel="..."; param1=""; param2=""`.
|
|
114
|
+
|
|
115
|
+
#### Returns
|
|
116
|
+
|
|
117
|
+
`object`[] \| `undefined`
|
|
118
|
+
|
|
119
|
+
The extracted possible array of URL, rel and optional params or undefined if invalid/missing.
|
|
120
|
+
|
|
121
|
+
#### See
|
|
122
|
+
|
|
123
|
+
https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Link
|
|
124
|
+
|
|
125
|
+
***
|
|
126
|
+
|
|
127
|
+
### extractLinkHeader()
|
|
128
|
+
|
|
129
|
+
> `static` **extractLinkHeader**(`linkHeader`): \{ `url`: `string`; `urlQueryParams?`: \{\[`id`: `string`\]: `string`; \}; `rel`: `string`; `params?`: \{\[`id`: `string`\]: `string`; \}; \} \| `undefined`
|
|
130
|
+
|
|
131
|
+
Extract the properties from a Link header.
|
|
132
|
+
|
|
133
|
+
#### Parameters
|
|
134
|
+
|
|
135
|
+
##### linkHeader
|
|
136
|
+
|
|
137
|
+
`string`
|
|
138
|
+
|
|
139
|
+
The Link header value in format `<url>; rel="..."; param1=""; param2=""`.
|
|
140
|
+
|
|
141
|
+
#### Returns
|
|
142
|
+
|
|
143
|
+
\{ `url`: `string`; `urlQueryParams?`: \{\[`id`: `string`\]: `string`; \}; `rel`: `string`; `params?`: \{\[`id`: `string`\]: `string`; \}; \} \| `undefined`
|
|
144
|
+
|
|
145
|
+
The extracted URL, rel and optional params or undefined if invalid/missing.
|
|
146
|
+
|
|
147
|
+
#### See
|
|
148
|
+
|
|
149
|
+
https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Link
|
|
150
|
+
|
|
151
|
+
***
|
|
152
|
+
|
|
153
|
+
### createLinkHeader()
|
|
154
|
+
|
|
155
|
+
> `static` **createLinkHeader**(`url`, `urlQueryParams`, `rel`, `params?`): `string`
|
|
156
|
+
|
|
157
|
+
Create a compliant Link header.
|
|
158
|
+
|
|
159
|
+
#### Parameters
|
|
160
|
+
|
|
161
|
+
##### url
|
|
162
|
+
|
|
163
|
+
`string`
|
|
164
|
+
|
|
165
|
+
The URL to include in the Link header.
|
|
166
|
+
|
|
167
|
+
##### urlQueryParams
|
|
168
|
+
|
|
169
|
+
Optional query parameters to include in the URL.
|
|
170
|
+
|
|
171
|
+
\{\[`id`: `string`\]: `string`; \} | `undefined`
|
|
172
|
+
|
|
173
|
+
##### rel
|
|
174
|
+
|
|
175
|
+
`string`
|
|
176
|
+
|
|
177
|
+
The relation type (e.g., "next", "prev", "self").
|
|
178
|
+
|
|
179
|
+
##### params?
|
|
180
|
+
|
|
181
|
+
#### Returns
|
|
182
|
+
|
|
183
|
+
`string`
|
|
184
|
+
|
|
185
|
+
The formatted Link header string.
|
|
186
|
+
|
|
187
|
+
#### Throws
|
|
188
|
+
|
|
189
|
+
GeneralError if the URL or rel are invalid.
|
|
190
|
+
|
|
191
|
+
#### See
|
|
192
|
+
|
|
193
|
+
https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Link
|
package/locales/en.json
CHANGED
|
@@ -21,6 +21,10 @@
|
|
|
21
21
|
"jws": {
|
|
22
22
|
"createFailed": "Failed to create JWS",
|
|
23
23
|
"verifyFailed": "Failed to verify JWS"
|
|
24
|
+
},
|
|
25
|
+
"headerHelper": {
|
|
26
|
+
"invalidLinkHeaderURL": "URL for Link header cannot contain \">\" character.",
|
|
27
|
+
"invalidLinkHeaderRel": "Relation type for Link header cannot contain \" character."
|
|
24
28
|
}
|
|
25
29
|
},
|
|
26
30
|
"errorMessages": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twin.org/web",
|
|
3
|
-
"version": "0.0.3-next.
|
|
3
|
+
"version": "0.0.3-next.13",
|
|
4
4
|
"description": "Contains classes for use with web operations",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
"node": ">=20.0.0"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@twin.org/core": "0.0.3-next.
|
|
18
|
-
"@twin.org/crypto": "0.0.3-next.
|
|
19
|
-
"@twin.org/nameof": "0.0.3-next.
|
|
17
|
+
"@twin.org/core": "0.0.3-next.13",
|
|
18
|
+
"@twin.org/crypto": "0.0.3-next.13",
|
|
19
|
+
"@twin.org/nameof": "0.0.3-next.13",
|
|
20
20
|
"jose": "6.1.1"
|
|
21
21
|
},
|
|
22
22
|
"main": "./dist/es/index.js",
|