@outfoxx/sunday 1.0.8 → 1.1.0-alpha.10
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/README.md +35 -2
- package/dist/any-type.d.ts +2 -0
- package/dist/class-type.d.ts +2 -2
- package/dist/date-time-types.d.ts +2 -7
- package/dist/date-time-types.js +2 -4
- package/dist/date-time-types.js.map +1 -1
- package/dist/event-parser.d.ts +17 -0
- package/dist/event-parser.js +140 -0
- package/dist/event-parser.js.map +1 -0
- package/dist/fetch-event-source.d.ts +12 -10
- package/dist/fetch-event-source.js +141 -138
- package/dist/fetch-event-source.js.map +1 -1
- package/dist/fetch-request-factory.d.ts +10 -5
- package/dist/fetch-request-factory.js +87 -71
- package/dist/fetch-request-factory.js.map +1 -1
- package/dist/fetch.d.ts +7 -1
- package/dist/fetch.js +61 -8
- package/dist/fetch.js.map +1 -1
- package/dist/header-parameters.d.ts +3 -0
- package/dist/header-parameters.js +40 -0
- package/dist/header-parameters.js.map +1 -0
- package/dist/index.d.ts +12 -12
- package/dist/index.js +12 -12
- package/dist/index.js.map +1 -1
- package/dist/{binary-decoder.d.ts → media-type-codecs/binary-decoder.d.ts} +2 -2
- package/dist/{binary-decoder.js → media-type-codecs/binary-decoder.js} +0 -0
- package/dist/media-type-codecs/binary-decoder.js.map +1 -0
- package/dist/{binary-encoder.d.ts → media-type-codecs/binary-encoder.d.ts} +0 -0
- package/dist/{binary-encoder.js → media-type-codecs/binary-encoder.js} +0 -0
- package/dist/media-type-codecs/binary-encoder.js.map +1 -0
- package/dist/media-type-codecs/cbor-decoder.d.ts +39 -0
- package/dist/media-type-codecs/cbor-decoder.js +413 -0
- package/dist/media-type-codecs/cbor-decoder.js.map +1 -0
- package/dist/media-type-codecs/cbor-encoder.d.ts +43 -0
- package/dist/media-type-codecs/cbor-encoder.js +226 -0
- package/dist/media-type-codecs/cbor-encoder.js.map +1 -0
- package/dist/media-type-codecs/cbor-tags.d.ts +4 -0
- package/dist/media-type-codecs/cbor-tags.js +5 -0
- package/dist/media-type-codecs/cbor-tags.js.map +1 -0
- package/dist/media-type-codecs/json-decoder.d.ts +39 -0
- package/dist/media-type-codecs/json-decoder.js +367 -0
- package/dist/media-type-codecs/json-decoder.js.map +1 -0
- package/dist/media-type-codecs/json-encoder.d.ts +44 -0
- package/dist/media-type-codecs/json-encoder.js +263 -0
- package/dist/media-type-codecs/json-encoder.js.map +1 -0
- package/dist/media-type-codecs/media-type-decoder.d.ts +11 -0
- package/dist/media-type-codecs/media-type-decoder.js +6 -0
- package/dist/media-type-codecs/media-type-decoder.js.map +1 -0
- package/dist/{media-type-decoders.d.ts → media-type-codecs/media-type-decoders.d.ts} +5 -4
- package/dist/{media-type-decoders.js → media-type-codecs/media-type-decoders.js} +6 -6
- package/dist/media-type-codecs/media-type-decoders.js.map +1 -0
- package/dist/{media-type-encoder.d.ts → media-type-codecs/media-type-encoder.d.ts} +5 -1
- package/dist/media-type-codecs/media-type-encoder.js +11 -0
- package/dist/media-type-codecs/media-type-encoder.js.map +1 -0
- package/dist/{media-type-encoders.d.ts → media-type-codecs/media-type-encoders.d.ts} +5 -4
- package/dist/{media-type-encoders.js → media-type-codecs/media-type-encoders.js} +8 -8
- package/dist/media-type-codecs/media-type-encoders.js.map +1 -0
- package/dist/{url-encoder.d.ts → media-type-codecs/www-form-url-encoder.d.ts} +8 -8
- package/dist/{url-encoder.js → media-type-codecs/www-form-url-encoder.js} +38 -37
- package/dist/media-type-codecs/www-form-url-encoder.js.map +1 -0
- package/dist/media-type.d.ts +91 -13
- package/dist/media-type.js +273 -15
- package/dist/media-type.js.map +1 -1
- package/dist/problem.d.ts +24 -9
- package/dist/problem.js +140 -6
- package/dist/problem.js.map +1 -1
- package/dist/request-factory.d.ts +10 -10
- package/dist/sunday-error.d.ts +11 -0
- package/dist/sunday-error.js +18 -0
- package/dist/sunday-error.js.map +1 -0
- package/dist/util/any.d.ts +2 -0
- package/dist/util/any.js +11 -0
- package/dist/util/any.js.map +1 -0
- package/dist/util/error.d.ts +2 -0
- package/dist/util/error.js +13 -0
- package/dist/util/error.js.map +1 -0
- package/dist/util/hex.js +3 -2
- package/dist/util/hex.js.map +1 -1
- package/dist/util/rxjs.d.ts +3 -0
- package/dist/util/rxjs.js +9 -5
- package/dist/util/rxjs.js.map +1 -1
- package/dist/util/temporal.d.ts +2 -0
- package/dist/util/temporal.js +18 -0
- package/dist/util/temporal.js.map +1 -0
- package/package.json +27 -21
- package/src/any-type.ts +4 -0
- package/src/class-type.ts +6 -2
- package/src/date-time-types.ts +22 -9
- package/src/event-parser.ts +190 -0
- package/src/fetch-event-source.ts +149 -159
- package/src/fetch-request-factory.ts +129 -101
- package/src/fetch.ts +65 -14
- package/src/header-parameters.ts +52 -0
- package/src/index.ts +12 -12
- package/src/{binary-decoder.ts → media-type-codecs/binary-decoder.ts} +3 -3
- package/src/{binary-encoder.ts → media-type-codecs/binary-encoder.ts} +0 -0
- package/src/media-type-codecs/cbor-decoder.ts +515 -0
- package/src/media-type-codecs/cbor-encoder.ts +307 -0
- package/src/media-type-codecs/cbor-tags.ts +4 -0
- package/src/media-type-codecs/json-decoder.ts +470 -0
- package/src/media-type-codecs/json-encoder.ts +328 -0
- package/src/media-type-codecs/media-type-decoder.ts +20 -0
- package/src/{media-type-decoders.ts → media-type-codecs/media-type-decoders.ts} +21 -13
- package/src/media-type-codecs/media-type-encoder.ts +31 -0
- package/src/{media-type-encoders.ts → media-type-codecs/media-type-encoders.ts} +23 -15
- package/src/{url-encoder.ts → media-type-codecs/www-form-url-encoder.ts} +53 -47
- package/src/media-type.ts +326 -22
- package/src/problem.ts +144 -12
- package/src/request-factory.ts +21 -12
- package/src/sunday-error.ts +37 -0
- package/src/util/any.ts +10 -0
- package/src/util/error.ts +14 -0
- package/src/util/hex.ts +3 -2
- package/src/util/rxjs.ts +16 -5
- package/src/util/temporal.ts +18 -0
- package/dist/binary-decoder.js.map +0 -1
- package/dist/binary-encoder.js.map +0 -1
- package/dist/cbor-decoder.d.ts +0 -15
- package/dist/cbor-decoder.js +0 -126
- package/dist/cbor-decoder.js.map +0 -1
- package/dist/cbor-encoder.d.ts +0 -29
- package/dist/cbor-encoder.js +0 -81
- package/dist/cbor-encoder.js.map +0 -1
- package/dist/cbor-tags.d.ts +0 -3
- package/dist/cbor-tags.js +0 -4
- package/dist/cbor-tags.js.map +0 -1
- package/dist/http-error.d.ts +0 -10
- package/dist/http-error.js +0 -45
- package/dist/http-error.js.map +0 -1
- package/dist/json-decoder.d.ts +0 -31
- package/dist/json-decoder.js +0 -139
- package/dist/json-decoder.js.map +0 -1
- package/dist/json-encoder.d.ts +0 -35
- package/dist/json-encoder.js +0 -116
- package/dist/json-encoder.js.map +0 -1
- package/dist/media-type-decoder.d.ts +0 -4
- package/dist/media-type-decoder.js +0 -2
- package/dist/media-type-decoder.js.map +0 -1
- package/dist/media-type-decoders.js.map +0 -1
- package/dist/media-type-encoder.js +0 -6
- package/dist/media-type-encoder.js.map +0 -1
- package/dist/media-type-encoders.js.map +0 -1
- package/dist/url-encoder.js.map +0 -1
- package/src/cbor-decoder.ts +0 -148
- package/src/cbor-encoder.ts +0 -95
- package/src/cbor-tags.ts +0 -3
- package/src/http-error.ts +0 -55
- package/src/json-decoder.ts +0 -164
- package/src/json-encoder.ts +0 -144
- package/src/media-type-decoder.ts +0 -5
- package/src/media-type-encoder.ts +0 -16
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ChronoField,
|
|
3
|
+
DateTimeFormatter,
|
|
4
|
+
DateTimeFormatterBuilder,
|
|
5
|
+
Instant,
|
|
6
|
+
LocalDate,
|
|
7
|
+
LocalDateTime,
|
|
8
|
+
LocalTime,
|
|
9
|
+
OffsetDateTime,
|
|
10
|
+
OffsetTime,
|
|
11
|
+
ResolverStyle,
|
|
12
|
+
ZonedDateTime,
|
|
13
|
+
} from '@js-joda/core';
|
|
14
|
+
import { JsonIncludeType, JsonStringifier } from '@outfoxx/jackson-js';
|
|
15
|
+
import { CustomMapper, Serializer } from '@outfoxx/jackson-js/dist/@types';
|
|
16
|
+
import 'reflect-metadata';
|
|
17
|
+
import { AnyType } from '../any-type';
|
|
18
|
+
import { Base64 } from '../util/base64';
|
|
19
|
+
import { encodeSeconds, secondsToNumber } from '../util/temporal';
|
|
20
|
+
import { StructuredMediaTypeEncoder } from './media-type-encoder';
|
|
21
|
+
|
|
22
|
+
export class JSONEncoder implements StructuredMediaTypeEncoder {
|
|
23
|
+
static get default(): JSONEncoder {
|
|
24
|
+
return new JSONEncoder(
|
|
25
|
+
JSONEncoder.DateEncoding.DECIMAL_SECONDS_SINCE_EPOCH
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private readonly customSerializers: CustomMapper<Serializer>[];
|
|
30
|
+
private stringifier = new JsonStringifier();
|
|
31
|
+
|
|
32
|
+
constructor(readonly dateEncoding: JSONEncoder.DateEncoding) {
|
|
33
|
+
this.customSerializers = [
|
|
34
|
+
{
|
|
35
|
+
type: () => Date,
|
|
36
|
+
mapper: this.dateSerializer,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
type: () => Instant,
|
|
40
|
+
mapper: this.instantSerializer,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
type: () => ZonedDateTime,
|
|
44
|
+
mapper: this.zonedDateTimeSerializer,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
type: () => OffsetDateTime,
|
|
48
|
+
mapper: this.offsetDateTimeSerializer,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
type: () => OffsetTime,
|
|
52
|
+
mapper: this.offsetTimeSerializer,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
type: () => LocalDateTime,
|
|
56
|
+
mapper: this.localDateTimeSerializer,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
type: () => LocalDate,
|
|
60
|
+
mapper: this.localDateSerializer,
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
type: () => LocalTime,
|
|
64
|
+
mapper: this.localTimeSerializer,
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
type: () => URL,
|
|
68
|
+
mapper: this.urlSerializer,
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
type: () => ArrayBuffer,
|
|
72
|
+
mapper: this.arrayBufferSerializer,
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
encode<T>(value: T, type?: AnyType, includeNulls = false): string {
|
|
78
|
+
// Use natural type when subtypes exist
|
|
79
|
+
if (
|
|
80
|
+
Reflect.hasMetadata(
|
|
81
|
+
'jackson:defaultContextGroup:JsonSubTypes',
|
|
82
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
83
|
+
(value as any).constructor ?? {}
|
|
84
|
+
)
|
|
85
|
+
) {
|
|
86
|
+
type = [Object];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return this.stringifier.stringify(value, {
|
|
90
|
+
serializers: this.customSerializers,
|
|
91
|
+
features: {
|
|
92
|
+
serialization: {
|
|
93
|
+
DEFAULT_PROPERTY_INCLUSION: {
|
|
94
|
+
value: includeNulls
|
|
95
|
+
? JsonIncludeType.ALWAYS
|
|
96
|
+
: JsonIncludeType.NON_NULL,
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
mainCreator: () => type ?? [Object],
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
encodeObject<T>(
|
|
105
|
+
value: T,
|
|
106
|
+
type?: AnyType,
|
|
107
|
+
includeNulls = false
|
|
108
|
+
): Record<string, unknown> {
|
|
109
|
+
// Use natural type when subtypes exist
|
|
110
|
+
if (
|
|
111
|
+
Reflect.hasMetadata(
|
|
112
|
+
'jackson:defaultContextGroup:JsonSubTypes',
|
|
113
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
114
|
+
(value as any).constructor ?? {}
|
|
115
|
+
)
|
|
116
|
+
) {
|
|
117
|
+
type = [Object];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return this.stringifier.transform(value, {
|
|
121
|
+
serializers: this.customSerializers,
|
|
122
|
+
features: {
|
|
123
|
+
serialization: {
|
|
124
|
+
DEFAULT_PROPERTY_INCLUSION: {
|
|
125
|
+
value: includeNulls
|
|
126
|
+
? JsonIncludeType.ALWAYS
|
|
127
|
+
: JsonIncludeType.NON_NULL,
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
mainCreator: () => type ?? [Object],
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private instantSerializer: Serializer = (_, value: Instant) => {
|
|
136
|
+
if (value == null) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
switch (this.dateEncoding) {
|
|
141
|
+
case JSONEncoder.DateEncoding.ISO8601:
|
|
142
|
+
return DateTimeFormatter.ISO_INSTANT.format(value);
|
|
143
|
+
case JSONEncoder.DateEncoding.MILLISECONDS_SINCE_EPOCH:
|
|
144
|
+
return value.toEpochMilli();
|
|
145
|
+
case JSONEncoder.DateEncoding.DECIMAL_SECONDS_SINCE_EPOCH:
|
|
146
|
+
return secondsToNumber(value.epochSecond(), value.nano());
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
private zonedDateTimeSerializer: Serializer = (_, value: ZonedDateTime) => {
|
|
151
|
+
if (value == null) {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
switch (this.dateEncoding) {
|
|
156
|
+
case JSONEncoder.DateEncoding.ISO8601:
|
|
157
|
+
return DateTimeFormatter.ISO_ZONED_DATE_TIME.format(value);
|
|
158
|
+
case JSONEncoder.DateEncoding.MILLISECONDS_SINCE_EPOCH:
|
|
159
|
+
return value.toInstant().toEpochMilli();
|
|
160
|
+
case JSONEncoder.DateEncoding.DECIMAL_SECONDS_SINCE_EPOCH:
|
|
161
|
+
const instant = value.toInstant();
|
|
162
|
+
return secondsToNumber(instant.epochSecond(), instant.nano());
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
private offsetDateTimeSerializer: Serializer = (_, value: OffsetDateTime) => {
|
|
167
|
+
if (value == null) {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
switch (this.dateEncoding) {
|
|
172
|
+
case JSONEncoder.DateEncoding.ISO8601:
|
|
173
|
+
return DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(value);
|
|
174
|
+
case JSONEncoder.DateEncoding.MILLISECONDS_SINCE_EPOCH:
|
|
175
|
+
return value.toInstant().toEpochMilli();
|
|
176
|
+
case JSONEncoder.DateEncoding.DECIMAL_SECONDS_SINCE_EPOCH:
|
|
177
|
+
const instant = value.toInstant();
|
|
178
|
+
return secondsToNumber(instant.epochSecond(), instant.nano());
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
private offsetTimeFormatter = new DateTimeFormatterBuilder()
|
|
183
|
+
.parseCaseInsensitive()
|
|
184
|
+
.append(DateTimeFormatter.ISO_LOCAL_TIME)
|
|
185
|
+
.appendOffsetId()
|
|
186
|
+
.toFormatter(ResolverStyle.STRICT);
|
|
187
|
+
|
|
188
|
+
private offsetTimeSerializer: Serializer = (_, value: OffsetTime) => {
|
|
189
|
+
if (value == null) {
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
switch (this.dateEncoding) {
|
|
194
|
+
case JSONEncoder.DateEncoding.ISO8601:
|
|
195
|
+
return this.offsetTimeFormatter.format(value);
|
|
196
|
+
default:
|
|
197
|
+
return [
|
|
198
|
+
value.hour(),
|
|
199
|
+
value.minute(),
|
|
200
|
+
...encodeSeconds(
|
|
201
|
+
value.second(),
|
|
202
|
+
this.dateEncoding ==
|
|
203
|
+
JSONEncoder.DateEncoding.MILLISECONDS_SINCE_EPOCH
|
|
204
|
+
? value.get(ChronoField.MILLI_OF_SECOND)
|
|
205
|
+
: value.nano()
|
|
206
|
+
),
|
|
207
|
+
value.offset().toString(),
|
|
208
|
+
];
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
private localDateTimeSerializer: Serializer = (_, value: LocalDateTime) => {
|
|
213
|
+
if (value == null) {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
switch (this.dateEncoding) {
|
|
218
|
+
case JSONEncoder.DateEncoding.ISO8601:
|
|
219
|
+
return DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(value);
|
|
220
|
+
default:
|
|
221
|
+
return [
|
|
222
|
+
value.year(),
|
|
223
|
+
value.monthValue(),
|
|
224
|
+
value.dayOfMonth(),
|
|
225
|
+
value.hour(),
|
|
226
|
+
value.minute(),
|
|
227
|
+
...encodeSeconds(
|
|
228
|
+
value.second(),
|
|
229
|
+
this.dateEncoding ==
|
|
230
|
+
JSONEncoder.DateEncoding.MILLISECONDS_SINCE_EPOCH
|
|
231
|
+
? value.get(ChronoField.MILLI_OF_SECOND)
|
|
232
|
+
: value.nano()
|
|
233
|
+
),
|
|
234
|
+
];
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
private localDateSerializer: Serializer = (_, value: LocalDate) => {
|
|
239
|
+
if (value == null) {
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
switch (this.dateEncoding) {
|
|
244
|
+
case JSONEncoder.DateEncoding.ISO8601:
|
|
245
|
+
return DateTimeFormatter.ISO_LOCAL_DATE.format(value);
|
|
246
|
+
default:
|
|
247
|
+
return [value.year(), value.monthValue(), value.dayOfMonth()];
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
private localTimeSerializer: Serializer = (_, value: LocalTime) => {
|
|
252
|
+
if (value == null) {
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
switch (this.dateEncoding) {
|
|
257
|
+
case JSONEncoder.DateEncoding.ISO8601:
|
|
258
|
+
return DateTimeFormatter.ISO_LOCAL_TIME.format(value);
|
|
259
|
+
default:
|
|
260
|
+
return [
|
|
261
|
+
value.hour(),
|
|
262
|
+
value.minute(),
|
|
263
|
+
...encodeSeconds(
|
|
264
|
+
value.second(),
|
|
265
|
+
this.dateEncoding ==
|
|
266
|
+
JSONEncoder.DateEncoding.MILLISECONDS_SINCE_EPOCH
|
|
267
|
+
? value.get(ChronoField.MILLI_OF_SECOND)
|
|
268
|
+
: value.nano()
|
|
269
|
+
),
|
|
270
|
+
];
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
private dateSerializer: Serializer = (_, value: Date) => {
|
|
275
|
+
if (value == null) {
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
switch (this.dateEncoding) {
|
|
280
|
+
case JSONEncoder.DateEncoding.ISO8601:
|
|
281
|
+
return value.toISOString();
|
|
282
|
+
case JSONEncoder.DateEncoding.MILLISECONDS_SINCE_EPOCH:
|
|
283
|
+
return value.getTime();
|
|
284
|
+
case JSONEncoder.DateEncoding.DECIMAL_SECONDS_SINCE_EPOCH:
|
|
285
|
+
return value.getTime() / 1000.0;
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
private urlSerializer: Serializer = (_, value: URL) => {
|
|
290
|
+
if (value == null) {
|
|
291
|
+
return null;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return value.toString();
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
private arrayBufferSerializer: Serializer = (_, value: ArrayBuffer) => {
|
|
298
|
+
if (value == null) {
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return Base64.encode(value);
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export namespace JSONEncoder {
|
|
307
|
+
/**
|
|
308
|
+
* Configures how temporal values are encoded.
|
|
309
|
+
*/
|
|
310
|
+
export enum DateEncoding {
|
|
311
|
+
/**
|
|
312
|
+
* Encode temporal values numerically using seconds with decimal
|
|
313
|
+
* sub-second precision.
|
|
314
|
+
*/
|
|
315
|
+
DECIMAL_SECONDS_SINCE_EPOCH,
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Encode temporal values numerically using integer milliseconds.
|
|
319
|
+
*/
|
|
320
|
+
MILLISECONDS_SINCE_EPOCH,
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Encode temporal values values as an ISO-8601-formatted string (in
|
|
324
|
+
* RFC 3339 format). This is the default behavior.
|
|
325
|
+
*/
|
|
326
|
+
ISO8601,
|
|
327
|
+
}
|
|
328
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { AnyType } from '../any-type';
|
|
2
|
+
|
|
3
|
+
export interface MediaTypeDecoder {
|
|
4
|
+
decode<T>(response: Response, type: AnyType): Promise<T>;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface TextMediaTypeDecoder extends MediaTypeDecoder {
|
|
8
|
+
decodeText<T>(text: string, type: AnyType): T;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface StructuredMediaTypeDecoder extends MediaTypeDecoder {
|
|
12
|
+
decodeObject<T>(data: unknown, type: AnyType): T;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function isStructuredMediaTypeDecoder(
|
|
16
|
+
decoder: MediaTypeDecoder | StructuredMediaTypeDecoder | undefined
|
|
17
|
+
): decoder is StructuredMediaTypeDecoder {
|
|
18
|
+
const rec = decoder as unknown as Record<string, unknown>;
|
|
19
|
+
return !!rec.decodeObject ?? false;
|
|
20
|
+
}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { BinaryDecoder } from './binary-decoder';
|
|
2
2
|
import { CBORDecoder } from './cbor-decoder';
|
|
3
3
|
import { JSONDecoder } from './json-decoder';
|
|
4
|
-
import { MediaType } from '
|
|
4
|
+
import { MediaType } from '../media-type';
|
|
5
5
|
import { MediaTypeDecoder } from './media-type-decoder';
|
|
6
6
|
|
|
7
7
|
export interface MediaTypeDecodersBuilder {
|
|
8
8
|
addDefaults(): MediaTypeDecodersBuilder;
|
|
9
9
|
|
|
10
|
-
add(
|
|
10
|
+
add(
|
|
11
|
+
mediaType: MediaType,
|
|
12
|
+
decoder: MediaTypeDecoder
|
|
13
|
+
): MediaTypeDecodersBuilder;
|
|
11
14
|
|
|
12
15
|
build(): MediaTypeDecoders;
|
|
13
16
|
}
|
|
@@ -17,11 +20,12 @@ export interface MediaTypeDecodersBuilderConstructor {
|
|
|
17
20
|
|
|
18
21
|
export class MediaTypeDecoders {
|
|
19
22
|
static Builder: MediaTypeDecodersBuilderConstructor = class Builder
|
|
20
|
-
implements MediaTypeDecodersBuilder
|
|
21
|
-
|
|
23
|
+
implements MediaTypeDecodersBuilder
|
|
24
|
+
{
|
|
25
|
+
decoders = new Map<MediaType, MediaTypeDecoder>();
|
|
22
26
|
|
|
23
27
|
add(
|
|
24
|
-
mediaType:
|
|
28
|
+
mediaType: MediaType,
|
|
25
29
|
decoder: MediaTypeDecoder
|
|
26
30
|
): MediaTypeDecodersBuilder {
|
|
27
31
|
this.decoders.set(mediaType, decoder);
|
|
@@ -30,7 +34,7 @@ export class MediaTypeDecoders {
|
|
|
30
34
|
|
|
31
35
|
addDefaults(): MediaTypeDecodersBuilder {
|
|
32
36
|
return this.add(MediaType.JSON, JSONDecoder.default)
|
|
33
|
-
.add(MediaType.
|
|
37
|
+
.add(MediaType.OctetStream, new BinaryDecoder())
|
|
34
38
|
.add(MediaType.CBOR, CBORDecoder.default);
|
|
35
39
|
}
|
|
36
40
|
|
|
@@ -43,17 +47,21 @@ export class MediaTypeDecoders {
|
|
|
43
47
|
.addDefaults()
|
|
44
48
|
.build();
|
|
45
49
|
|
|
46
|
-
constructor(private decoders: Map<
|
|
50
|
+
constructor(private decoders: Map<MediaType, MediaTypeDecoder>) {}
|
|
47
51
|
|
|
48
|
-
supports(mediaType:
|
|
49
|
-
return this.decoders.
|
|
52
|
+
supports(mediaType: MediaType): boolean {
|
|
53
|
+
return Array.from(this.decoders.keys()).some((key) =>
|
|
54
|
+
key.compatible(mediaType)
|
|
55
|
+
);
|
|
50
56
|
}
|
|
51
57
|
|
|
52
|
-
find(mediaType:
|
|
53
|
-
const
|
|
54
|
-
|
|
58
|
+
find(mediaType: MediaType): MediaTypeDecoder {
|
|
59
|
+
const found = Array.from(this.decoders.entries()).find(([type]) =>
|
|
60
|
+
type.compatible(mediaType)
|
|
61
|
+
);
|
|
62
|
+
if (!found) {
|
|
55
63
|
throw Error(`Unsupported media type - ${mediaType}`);
|
|
56
64
|
}
|
|
57
|
-
return
|
|
65
|
+
return found[1];
|
|
58
66
|
}
|
|
59
67
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { AnyType } from '../any-type';
|
|
2
|
+
|
|
3
|
+
export interface MediaTypeEncoder {
|
|
4
|
+
encode<T = unknown>(value: T, type: AnyType | undefined): BodyInit;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface URLQueryParamsEncoder extends MediaTypeEncoder {
|
|
8
|
+
encodeQueryString(value: Record<string, unknown>): string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function isURLQueryParamsEncoder(
|
|
12
|
+
encoder: MediaTypeEncoder | URLQueryParamsEncoder | undefined
|
|
13
|
+
): encoder is URLQueryParamsEncoder {
|
|
14
|
+
const rec = encoder as unknown as Record<string, unknown>;
|
|
15
|
+
return !!rec.encodeQueryString ?? false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface StructuredMediaTypeEncoder extends MediaTypeEncoder {
|
|
19
|
+
encodeObject<T = unknown>(
|
|
20
|
+
value: T,
|
|
21
|
+
type?: AnyType,
|
|
22
|
+
includeNulls?: boolean
|
|
23
|
+
): Record<string, unknown>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function isStructuredMediaTypeEncoder(
|
|
27
|
+
encoder: MediaTypeEncoder | StructuredMediaTypeEncoder | undefined
|
|
28
|
+
): encoder is StructuredMediaTypeEncoder {
|
|
29
|
+
const rec = encoder as unknown as Record<string, unknown>;
|
|
30
|
+
return !!rec.encodeObject ?? false;
|
|
31
|
+
}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
+
import { MediaType } from '../media-type';
|
|
1
2
|
import { BinaryEncoder } from './binary-encoder';
|
|
2
3
|
import { CBOREncoder } from './cbor-encoder';
|
|
3
4
|
import { JSONEncoder } from './json-encoder';
|
|
4
|
-
import { MediaType } from './media-type';
|
|
5
5
|
import { MediaTypeEncoder } from './media-type-encoder';
|
|
6
|
-
import {
|
|
6
|
+
import { WWWFormUrlEncoder } from './www-form-url-encoder';
|
|
7
7
|
|
|
8
8
|
export interface MediaTypeEncodersBuilder {
|
|
9
9
|
addDefaults(): MediaTypeEncodersBuilder;
|
|
10
10
|
|
|
11
|
-
add(
|
|
11
|
+
add(
|
|
12
|
+
mediaType: MediaType,
|
|
13
|
+
encoder: MediaTypeEncoder
|
|
14
|
+
): MediaTypeEncodersBuilder;
|
|
12
15
|
|
|
13
16
|
build(): MediaTypeEncoders;
|
|
14
17
|
}
|
|
@@ -18,11 +21,12 @@ export interface MediaTypeEncodersBuilderConstructor {
|
|
|
18
21
|
|
|
19
22
|
export class MediaTypeEncoders {
|
|
20
23
|
static Builder: MediaTypeEncodersBuilderConstructor = class Builder
|
|
21
|
-
implements MediaTypeEncodersBuilder
|
|
22
|
-
|
|
24
|
+
implements MediaTypeEncodersBuilder
|
|
25
|
+
{
|
|
26
|
+
encoders = new Map<MediaType, MediaTypeEncoder>();
|
|
23
27
|
|
|
24
28
|
add(
|
|
25
|
-
mediaType:
|
|
29
|
+
mediaType: MediaType,
|
|
26
30
|
encoder: MediaTypeEncoder
|
|
27
31
|
): MediaTypeEncodersBuilder {
|
|
28
32
|
this.encoders.set(mediaType, encoder);
|
|
@@ -31,8 +35,8 @@ export class MediaTypeEncoders {
|
|
|
31
35
|
|
|
32
36
|
addDefaults(): MediaTypeEncodersBuilder {
|
|
33
37
|
return this.add(MediaType.JSON, JSONEncoder.default)
|
|
34
|
-
.add(MediaType.
|
|
35
|
-
.add(MediaType.
|
|
38
|
+
.add(MediaType.OctetStream, BinaryEncoder.default)
|
|
39
|
+
.add(MediaType.WWWFormUrlEncoded, WWWFormUrlEncoder.default)
|
|
36
40
|
.add(MediaType.CBOR, CBOREncoder.default);
|
|
37
41
|
}
|
|
38
42
|
|
|
@@ -45,17 +49,21 @@ export class MediaTypeEncoders {
|
|
|
45
49
|
.addDefaults()
|
|
46
50
|
.build();
|
|
47
51
|
|
|
48
|
-
constructor(private encoders: Map<
|
|
52
|
+
constructor(private encoders: Map<MediaType, MediaTypeEncoder>) {}
|
|
49
53
|
|
|
50
|
-
supports(mediaType:
|
|
51
|
-
return this.encoders.
|
|
54
|
+
supports(mediaType: MediaType): boolean {
|
|
55
|
+
return Array.from(this.encoders.keys()).some((key) =>
|
|
56
|
+
key.compatible(mediaType)
|
|
57
|
+
);
|
|
52
58
|
}
|
|
53
59
|
|
|
54
|
-
find(mediaType:
|
|
55
|
-
const
|
|
56
|
-
|
|
60
|
+
find(mediaType: MediaType): MediaTypeEncoder {
|
|
61
|
+
const found = Array.from(this.encoders.entries()).find(([type]) =>
|
|
62
|
+
type.compatible(mediaType)
|
|
63
|
+
);
|
|
64
|
+
if (!found) {
|
|
57
65
|
throw Error(`Unsupported media type - ${mediaType}`);
|
|
58
66
|
}
|
|
59
|
-
return
|
|
67
|
+
return found[1];
|
|
60
68
|
}
|
|
61
69
|
}
|