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