@utiliread/http 1.27.0 → 1.27.1
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/cursor.rollup.config.mjs +35 -35
- package/dist/plugins/cursor/index.d.ts +1 -0
- package/dist/plugins/cursor/index.js +1 -0
- package/dist/plugins/cursor/index.js.map +1 -1
- package/dist/plugins/cursor/index.mjs +1 -0
- package/dist/plugins/cursor/index.mjs.map +1 -1
- package/package.json +91 -91
- package/src/errors/http-error.ts +52 -52
- package/src/http-builder.ts +318 -318
- package/src/plugins/cursor/index.ts +47 -45
- package/src/query-string.spec.ts +96 -96
- package/src/query-string.ts +75 -75
|
@@ -1,45 +1,47 @@
|
|
|
1
|
-
import {
|
|
2
|
-
HttpBuilder,
|
|
3
|
-
TypeOrMapper,
|
|
4
|
-
getMapper,
|
|
5
|
-
} from "@utiliread/http";
|
|
6
|
-
import { deserialize } from "@utiliread/json";
|
|
7
|
-
|
|
8
|
-
export interface ICursorPage<T> {
|
|
9
|
-
items: T[];
|
|
10
|
-
nextCursor: string | null;
|
|
11
|
-
hasMore: boolean;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
//
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
1
|
+
import {
|
|
2
|
+
HttpBuilder,
|
|
3
|
+
TypeOrMapper,
|
|
4
|
+
getMapper,
|
|
5
|
+
} from "@utiliread/http";
|
|
6
|
+
import { deserialize } from "@utiliread/json";
|
|
7
|
+
|
|
8
|
+
export interface ICursorPage<T> {
|
|
9
|
+
items: T[];
|
|
10
|
+
nextCursor: string | null;
|
|
11
|
+
hasMore: boolean;
|
|
12
|
+
totalCount?: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Force declarations to be module augmentations instead of ambient module declarations
|
|
16
|
+
// https://www.typescriptlang.org/docs/handbook/modules/reference.html#ambient-modules
|
|
17
|
+
export default {};
|
|
18
|
+
|
|
19
|
+
// https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation
|
|
20
|
+
declare module "@utiliread/http" {
|
|
21
|
+
interface HttpBuilder {
|
|
22
|
+
expectCursorPage<T>(
|
|
23
|
+
typeOrMapper: TypeOrMapper<T>,
|
|
24
|
+
): HttpBuilderOfT<ICursorPage<T>>;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
HttpBuilder.prototype.expectCursorPage = function <T>(
|
|
29
|
+
this: HttpBuilder,
|
|
30
|
+
typeOrMapper: TypeOrMapper<T>,
|
|
31
|
+
) {
|
|
32
|
+
this.message.headers.set("Accept", "application/json");
|
|
33
|
+
return this.useHandler((response) => {
|
|
34
|
+
const promise = response.rawResponse
|
|
35
|
+
.json()
|
|
36
|
+
.then((x: ICursorPage<any>): ICursorPage<T> => {
|
|
37
|
+
const itemFactory = getMapper(deserialize, typeOrMapper);
|
|
38
|
+
return {
|
|
39
|
+
items: x.items.map(itemFactory),
|
|
40
|
+
nextCursor: x.nextCursor,
|
|
41
|
+
hasMore: x.hasMore,
|
|
42
|
+
totalCount: x.totalCount,
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
return promise;
|
|
46
|
+
});
|
|
47
|
+
};
|
package/src/query-string.spec.ts
CHANGED
|
@@ -1,96 +1,96 @@
|
|
|
1
|
-
import { DateTime, Duration } from "luxon";
|
|
2
|
-
|
|
3
|
-
import { QueryString } from "./query-string";
|
|
4
|
-
import { expect } from "chai";
|
|
5
|
-
|
|
6
|
-
describe("query-string", () => {
|
|
7
|
-
it("should handle string", () => {
|
|
8
|
-
const qs = QueryString.serialize({
|
|
9
|
-
aString: "hello",
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
expect(qs).to.equal("?aString=hello");
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it("should handle string array", () => {
|
|
16
|
-
const qs = QueryString.serialize({
|
|
17
|
-
aString: ["hello", "world"],
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
expect(qs).to.equal("?aString[0]=hello&aString[1]=world");
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it("should handle object array", () => {
|
|
24
|
-
const qs = QueryString.serialize({
|
|
25
|
-
array: [{ a: "hello" }, { b: "world" }],
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
expect(qs).to.equal("?array[0].a=hello&array[1].b=world");
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it("should handle luxon DateTime in local timezone", () => {
|
|
32
|
-
const datetime = DateTime.fromObject({
|
|
33
|
-
year: 2014,
|
|
34
|
-
month: 11,
|
|
35
|
-
day: 12,
|
|
36
|
-
hour: 21,
|
|
37
|
-
minute: 6,
|
|
38
|
-
});
|
|
39
|
-
const qs = QueryString.serialize({
|
|
40
|
-
aDateTime: datetime,
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
expect(qs).to.equal(
|
|
44
|
-
"?aDateTime=" + encodeURIComponent("2014-11-12T21:06:00.000+01:00"),
|
|
45
|
-
);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it("should handle luxon DateTime in utc", () => {
|
|
49
|
-
const datetime = DateTime.fromObject({
|
|
50
|
-
year: 2014,
|
|
51
|
-
month: 11,
|
|
52
|
-
day: 12,
|
|
53
|
-
hour: 21,
|
|
54
|
-
minute: 6,
|
|
55
|
-
}).toUTC();
|
|
56
|
-
const qs = QueryString.serialize({
|
|
57
|
-
aDateTime: datetime,
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
expect(qs).to.equal(
|
|
61
|
-
"?aDateTime=" + encodeURIComponent("2014-11-12T20:06:00.000Z"),
|
|
62
|
-
);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it("should handle luxon Duration", () => {
|
|
66
|
-
const duration = Duration.fromObject({
|
|
67
|
-
years: 1,
|
|
68
|
-
months: 2,
|
|
69
|
-
days: 3,
|
|
70
|
-
hours: 4,
|
|
71
|
-
minutes: 5,
|
|
72
|
-
seconds: 6,
|
|
73
|
-
});
|
|
74
|
-
const qs = QueryString.serialize({
|
|
75
|
-
aDuration: duration,
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
expect(qs).to.equal("?aDuration=" + encodeURIComponent("P1Y2M3DT4H5M6S"));
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it("should handle null", () => {
|
|
82
|
-
const qs = QueryString.serialize({
|
|
83
|
-
null: null,
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
expect(qs).to.equal("?null");
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it("should not include undefined", () => {
|
|
90
|
-
const qs = QueryString.serialize({
|
|
91
|
-
null: undefined,
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
expect(qs).to.equal("");
|
|
95
|
-
});
|
|
96
|
-
});
|
|
1
|
+
import { DateTime, Duration } from "luxon";
|
|
2
|
+
|
|
3
|
+
import { QueryString } from "./query-string";
|
|
4
|
+
import { expect } from "chai";
|
|
5
|
+
|
|
6
|
+
describe("query-string", () => {
|
|
7
|
+
it("should handle string", () => {
|
|
8
|
+
const qs = QueryString.serialize({
|
|
9
|
+
aString: "hello",
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
expect(qs).to.equal("?aString=hello");
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("should handle string array", () => {
|
|
16
|
+
const qs = QueryString.serialize({
|
|
17
|
+
aString: ["hello", "world"],
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
expect(qs).to.equal("?aString[0]=hello&aString[1]=world");
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("should handle object array", () => {
|
|
24
|
+
const qs = QueryString.serialize({
|
|
25
|
+
array: [{ a: "hello" }, { b: "world" }],
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
expect(qs).to.equal("?array[0].a=hello&array[1].b=world");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("should handle luxon DateTime in local timezone", () => {
|
|
32
|
+
const datetime = DateTime.fromObject({
|
|
33
|
+
year: 2014,
|
|
34
|
+
month: 11,
|
|
35
|
+
day: 12,
|
|
36
|
+
hour: 21,
|
|
37
|
+
minute: 6,
|
|
38
|
+
});
|
|
39
|
+
const qs = QueryString.serialize({
|
|
40
|
+
aDateTime: datetime,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
expect(qs).to.equal(
|
|
44
|
+
"?aDateTime=" + encodeURIComponent("2014-11-12T21:06:00.000+01:00"),
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("should handle luxon DateTime in utc", () => {
|
|
49
|
+
const datetime = DateTime.fromObject({
|
|
50
|
+
year: 2014,
|
|
51
|
+
month: 11,
|
|
52
|
+
day: 12,
|
|
53
|
+
hour: 21,
|
|
54
|
+
minute: 6,
|
|
55
|
+
}).toUTC();
|
|
56
|
+
const qs = QueryString.serialize({
|
|
57
|
+
aDateTime: datetime,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
expect(qs).to.equal(
|
|
61
|
+
"?aDateTime=" + encodeURIComponent("2014-11-12T20:06:00.000Z"),
|
|
62
|
+
);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("should handle luxon Duration", () => {
|
|
66
|
+
const duration = Duration.fromObject({
|
|
67
|
+
years: 1,
|
|
68
|
+
months: 2,
|
|
69
|
+
days: 3,
|
|
70
|
+
hours: 4,
|
|
71
|
+
minutes: 5,
|
|
72
|
+
seconds: 6,
|
|
73
|
+
});
|
|
74
|
+
const qs = QueryString.serialize({
|
|
75
|
+
aDuration: duration,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
expect(qs).to.equal("?aDuration=" + encodeURIComponent("P1Y2M3DT4H5M6S"));
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("should handle null", () => {
|
|
82
|
+
const qs = QueryString.serialize({
|
|
83
|
+
null: null,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
expect(qs).to.equal("?null");
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("should not include undefined", () => {
|
|
90
|
+
const qs = QueryString.serialize({
|
|
91
|
+
null: undefined,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
expect(qs).to.equal("");
|
|
95
|
+
});
|
|
96
|
+
});
|
package/src/query-string.ts
CHANGED
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
import { DateTime, Duration } from "luxon";
|
|
2
|
-
|
|
3
|
-
export class QueryString {
|
|
4
|
-
static serialize(params: any) {
|
|
5
|
-
if (!params) {
|
|
6
|
-
return "";
|
|
7
|
-
}
|
|
8
|
-
const serialized = this._serializeQueryString(params);
|
|
9
|
-
if (!serialized.length) {
|
|
10
|
-
return "";
|
|
11
|
-
}
|
|
12
|
-
return "?" + serialized;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
static append(url: string, params: any) {
|
|
16
|
-
if (!params) {
|
|
17
|
-
return url;
|
|
18
|
-
}
|
|
19
|
-
const any = url.indexOf("?") >= 0;
|
|
20
|
-
const separator = any ? "&" : "?";
|
|
21
|
-
|
|
22
|
-
return url + separator + this._serializeQueryString(params);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
static getParameter(name: string) {
|
|
26
|
-
const regex = new RegExp(`[?&]${name}(=([^&#]*)|&|#|$)`);
|
|
27
|
-
const match = regex.exec(window.location.href);
|
|
28
|
-
if (match) {
|
|
29
|
-
if (match[1].length > 0) {
|
|
30
|
-
return decodeURIComponent(match[2]);
|
|
31
|
-
} else {
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
private static _serializeQueryString(source: any, prefix?: string) {
|
|
38
|
-
const parts: string[] = [];
|
|
39
|
-
for (const propertyName in source) {
|
|
40
|
-
if (source.hasOwnProperty(propertyName)) {
|
|
41
|
-
const key =
|
|
42
|
-
prefix != null
|
|
43
|
-
? prefix +
|
|
44
|
-
(Array.isArray(source)
|
|
45
|
-
? "[" + encodeURIComponent(propertyName) + "]"
|
|
46
|
-
: "." + encodeURIComponent(propertyName))
|
|
47
|
-
: encodeURIComponent(propertyName);
|
|
48
|
-
const value = source[propertyName];
|
|
49
|
-
|
|
50
|
-
if (value instanceof DateTime) {
|
|
51
|
-
if (value.isValid) {
|
|
52
|
-
parts.push(key + "=" + encodeURIComponent(value.toISO()!));
|
|
53
|
-
}
|
|
54
|
-
} else if (value instanceof Duration) {
|
|
55
|
-
if (value.isValid) {
|
|
56
|
-
parts.push(key + "=" + encodeURIComponent(value.toISO()!));
|
|
57
|
-
}
|
|
58
|
-
} else if (value === null) {
|
|
59
|
-
parts.push(key);
|
|
60
|
-
} else if (value !== undefined) {
|
|
61
|
-
if ("function" === typeof value.toISOString) {
|
|
62
|
-
parts.push(key + "=" + encodeURIComponent(value.toISOString()));
|
|
63
|
-
}
|
|
64
|
-
if (typeof value === "object") {
|
|
65
|
-
parts.push(this._serializeQueryString(value, key));
|
|
66
|
-
} else {
|
|
67
|
-
parts.push(key + "=" + encodeURIComponent(value));
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return parts.join("&");
|
|
74
|
-
}
|
|
75
|
-
}
|
|
1
|
+
import { DateTime, Duration } from "luxon";
|
|
2
|
+
|
|
3
|
+
export class QueryString {
|
|
4
|
+
static serialize(params: any) {
|
|
5
|
+
if (!params) {
|
|
6
|
+
return "";
|
|
7
|
+
}
|
|
8
|
+
const serialized = this._serializeQueryString(params);
|
|
9
|
+
if (!serialized.length) {
|
|
10
|
+
return "";
|
|
11
|
+
}
|
|
12
|
+
return "?" + serialized;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
static append(url: string, params: any) {
|
|
16
|
+
if (!params) {
|
|
17
|
+
return url;
|
|
18
|
+
}
|
|
19
|
+
const any = url.indexOf("?") >= 0;
|
|
20
|
+
const separator = any ? "&" : "?";
|
|
21
|
+
|
|
22
|
+
return url + separator + this._serializeQueryString(params);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static getParameter(name: string) {
|
|
26
|
+
const regex = new RegExp(`[?&]${name}(=([^&#]*)|&|#|$)`);
|
|
27
|
+
const match = regex.exec(window.location.href);
|
|
28
|
+
if (match) {
|
|
29
|
+
if (match[1].length > 0) {
|
|
30
|
+
return decodeURIComponent(match[2]);
|
|
31
|
+
} else {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private static _serializeQueryString(source: any, prefix?: string) {
|
|
38
|
+
const parts: string[] = [];
|
|
39
|
+
for (const propertyName in source) {
|
|
40
|
+
if (source.hasOwnProperty(propertyName)) {
|
|
41
|
+
const key =
|
|
42
|
+
prefix != null
|
|
43
|
+
? prefix +
|
|
44
|
+
(Array.isArray(source)
|
|
45
|
+
? "[" + encodeURIComponent(propertyName) + "]"
|
|
46
|
+
: "." + encodeURIComponent(propertyName))
|
|
47
|
+
: encodeURIComponent(propertyName);
|
|
48
|
+
const value = source[propertyName];
|
|
49
|
+
|
|
50
|
+
if (value instanceof DateTime) {
|
|
51
|
+
if (value.isValid) {
|
|
52
|
+
parts.push(key + "=" + encodeURIComponent(value.toISO()!));
|
|
53
|
+
}
|
|
54
|
+
} else if (value instanceof Duration) {
|
|
55
|
+
if (value.isValid) {
|
|
56
|
+
parts.push(key + "=" + encodeURIComponent(value.toISO()!));
|
|
57
|
+
}
|
|
58
|
+
} else if (value === null) {
|
|
59
|
+
parts.push(key);
|
|
60
|
+
} else if (value !== undefined) {
|
|
61
|
+
if ("function" === typeof value.toISOString) {
|
|
62
|
+
parts.push(key + "=" + encodeURIComponent(value.toISOString()));
|
|
63
|
+
}
|
|
64
|
+
if (typeof value === "object") {
|
|
65
|
+
parts.push(this._serializeQueryString(value, key));
|
|
66
|
+
} else {
|
|
67
|
+
parts.push(key + "=" + encodeURIComponent(value));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return parts.join("&");
|
|
74
|
+
}
|
|
75
|
+
}
|