@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":"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","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.11",
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.11",
18
- "@twin.org/crypto": "0.0.3-next.11",
19
- "@twin.org/nameof": "0.0.3-next.11",
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",