@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.
Files changed (179) hide show
  1. package/LICENSE.txt +203 -0
  2. package/README.md +35 -2
  3. package/dist/any-type.d.ts +2 -0
  4. package/dist/any-type.js +13 -0
  5. package/dist/any-type.js.map +1 -1
  6. package/dist/class-type.d.ts +2 -2
  7. package/dist/class-type.js +13 -0
  8. package/dist/class-type.js.map +1 -1
  9. package/dist/date-time-types.d.ts +2 -7
  10. package/dist/date-time-types.js +15 -4
  11. package/dist/date-time-types.js.map +1 -1
  12. package/dist/event-parser.d.ts +17 -0
  13. package/dist/event-parser.js +153 -0
  14. package/dist/event-parser.js.map +1 -0
  15. package/dist/fetch-event-source.d.ts +12 -10
  16. package/dist/fetch-event-source.js +154 -138
  17. package/dist/fetch-event-source.js.map +1 -1
  18. package/dist/fetch-request-factory.d.ts +10 -5
  19. package/dist/fetch-request-factory.js +100 -71
  20. package/dist/fetch-request-factory.js.map +1 -1
  21. package/dist/fetch.d.ts +7 -1
  22. package/dist/fetch.js +74 -8
  23. package/dist/fetch.js.map +1 -1
  24. package/dist/header-parameters.d.ts +3 -0
  25. package/dist/header-parameters.js +53 -0
  26. package/dist/header-parameters.js.map +1 -0
  27. package/dist/index.d.ts +12 -12
  28. package/dist/index.js +25 -12
  29. package/dist/index.js.map +1 -1
  30. package/dist/logger.js +13 -0
  31. package/dist/logger.js.map +1 -1
  32. package/dist/{binary-decoder.d.ts → media-type-codecs/binary-decoder.d.ts} +2 -2
  33. package/dist/media-type-codecs/binary-decoder.js +29 -0
  34. package/dist/media-type-codecs/binary-decoder.js.map +1 -0
  35. package/dist/{binary-encoder.d.ts → media-type-codecs/binary-encoder.d.ts} +0 -0
  36. package/dist/media-type-codecs/binary-encoder.js +26 -0
  37. package/dist/media-type-codecs/binary-encoder.js.map +1 -0
  38. package/dist/media-type-codecs/cbor-decoder.d.ts +39 -0
  39. package/dist/media-type-codecs/cbor-decoder.js +426 -0
  40. package/dist/media-type-codecs/cbor-decoder.js.map +1 -0
  41. package/dist/media-type-codecs/cbor-encoder.d.ts +43 -0
  42. package/dist/media-type-codecs/cbor-encoder.js +239 -0
  43. package/dist/media-type-codecs/cbor-encoder.js.map +1 -0
  44. package/dist/media-type-codecs/cbor-tags.d.ts +4 -0
  45. package/dist/media-type-codecs/cbor-tags.js +18 -0
  46. package/dist/media-type-codecs/cbor-tags.js.map +1 -0
  47. package/dist/media-type-codecs/json-decoder.d.ts +39 -0
  48. package/dist/media-type-codecs/json-decoder.js +380 -0
  49. package/dist/media-type-codecs/json-decoder.js.map +1 -0
  50. package/dist/media-type-codecs/json-encoder.d.ts +44 -0
  51. package/dist/media-type-codecs/json-encoder.js +276 -0
  52. package/dist/media-type-codecs/json-encoder.js.map +1 -0
  53. package/dist/media-type-codecs/media-type-decoder.d.ts +11 -0
  54. package/dist/media-type-codecs/media-type-decoder.js +19 -0
  55. package/dist/media-type-codecs/media-type-decoder.js.map +1 -0
  56. package/dist/{media-type-decoders.d.ts → media-type-codecs/media-type-decoders.d.ts} +5 -4
  57. package/dist/media-type-codecs/media-type-decoders.js +53 -0
  58. package/dist/media-type-codecs/media-type-decoders.js.map +1 -0
  59. package/dist/{media-type-encoder.d.ts → media-type-codecs/media-type-encoder.d.ts} +5 -1
  60. package/dist/media-type-codecs/media-type-encoder.js +24 -0
  61. package/dist/media-type-codecs/media-type-encoder.js.map +1 -0
  62. package/dist/{media-type-encoders.d.ts → media-type-codecs/media-type-encoders.d.ts} +5 -4
  63. package/dist/media-type-codecs/media-type-encoders.js +55 -0
  64. package/dist/media-type-codecs/media-type-encoders.js.map +1 -0
  65. package/dist/{url-encoder.d.ts → media-type-codecs/www-form-url-encoder.d.ts} +8 -8
  66. package/dist/{url-encoder.js → media-type-codecs/www-form-url-encoder.js} +51 -37
  67. package/dist/media-type-codecs/www-form-url-encoder.js.map +1 -0
  68. package/dist/media-type.d.ts +91 -13
  69. package/dist/media-type.js +286 -15
  70. package/dist/media-type.js.map +1 -1
  71. package/dist/problem.d.ts +24 -9
  72. package/dist/problem.js +153 -6
  73. package/dist/problem.js.map +1 -1
  74. package/dist/request-factory.d.ts +10 -10
  75. package/dist/request-factory.js +13 -0
  76. package/dist/request-factory.js.map +1 -1
  77. package/dist/sunday-error.d.ts +11 -0
  78. package/dist/sunday-error.js +31 -0
  79. package/dist/sunday-error.js.map +1 -0
  80. package/dist/url-template.js +13 -0
  81. package/dist/url-template.js.map +1 -1
  82. package/dist/util/any.d.ts +2 -0
  83. package/dist/util/any.js +24 -0
  84. package/dist/util/any.js.map +1 -0
  85. package/dist/util/base64.js +13 -0
  86. package/dist/util/base64.js.map +1 -1
  87. package/dist/util/error.d.ts +2 -0
  88. package/dist/util/error.js +26 -0
  89. package/dist/util/error.js.map +1 -0
  90. package/dist/util/hex.js +16 -2
  91. package/dist/util/hex.js.map +1 -1
  92. package/dist/util/rxjs.d.ts +3 -0
  93. package/dist/util/rxjs.js +22 -5
  94. package/dist/util/rxjs.js.map +1 -1
  95. package/dist/util/stream-rxjs.js +13 -0
  96. package/dist/util/stream-rxjs.js.map +1 -1
  97. package/dist/util/temporal.d.ts +2 -0
  98. package/dist/util/temporal.js +31 -0
  99. package/dist/util/temporal.js.map +1 -0
  100. package/package.json +29 -22
  101. package/src/any-type.ts +18 -0
  102. package/src/class-type.ts +20 -2
  103. package/src/date-time-types.ts +35 -8
  104. package/src/event-parser.ts +204 -0
  105. package/src/fetch-event-source.ts +163 -159
  106. package/src/fetch-request-factory.ts +142 -100
  107. package/src/fetch.ts +79 -14
  108. package/src/header-parameters.ts +66 -0
  109. package/src/index.ts +26 -12
  110. package/src/logger.ts +14 -0
  111. package/src/media-type-codecs/binary-decoder.ts +38 -0
  112. package/src/media-type-codecs/binary-encoder.ts +33 -0
  113. package/src/media-type-codecs/cbor-decoder.ts +529 -0
  114. package/src/media-type-codecs/cbor-encoder.ts +321 -0
  115. package/src/media-type-codecs/cbor-tags.ts +18 -0
  116. package/src/media-type-codecs/json-decoder.ts +484 -0
  117. package/src/media-type-codecs/json-encoder.ts +342 -0
  118. package/src/media-type-codecs/media-type-decoder.ts +34 -0
  119. package/src/media-type-codecs/media-type-decoders.ts +81 -0
  120. package/src/media-type-codecs/media-type-encoder.ts +45 -0
  121. package/src/media-type-codecs/media-type-encoders.ts +83 -0
  122. package/src/media-type-codecs/www-form-url-encoder.ts +193 -0
  123. package/src/media-type.ts +340 -22
  124. package/src/problem.ts +158 -12
  125. package/src/request-factory.ts +35 -12
  126. package/src/sunday-error.ts +51 -0
  127. package/src/url-template.ts +14 -0
  128. package/src/util/any.ts +24 -0
  129. package/src/util/base64.ts +14 -0
  130. package/src/util/error.ts +28 -0
  131. package/src/util/hex.ts +17 -2
  132. package/src/util/rxjs.ts +30 -5
  133. package/src/util/stream-rxjs.ts +14 -0
  134. package/src/util/temporal.ts +32 -0
  135. package/dist/binary-decoder.js +0 -16
  136. package/dist/binary-decoder.js.map +0 -1
  137. package/dist/binary-encoder.js +0 -13
  138. package/dist/binary-encoder.js.map +0 -1
  139. package/dist/cbor-decoder.d.ts +0 -15
  140. package/dist/cbor-decoder.js +0 -126
  141. package/dist/cbor-decoder.js.map +0 -1
  142. package/dist/cbor-encoder.d.ts +0 -29
  143. package/dist/cbor-encoder.js +0 -81
  144. package/dist/cbor-encoder.js.map +0 -1
  145. package/dist/cbor-tags.d.ts +0 -3
  146. package/dist/cbor-tags.js +0 -4
  147. package/dist/cbor-tags.js.map +0 -1
  148. package/dist/http-error.d.ts +0 -10
  149. package/dist/http-error.js +0 -45
  150. package/dist/http-error.js.map +0 -1
  151. package/dist/json-decoder.d.ts +0 -31
  152. package/dist/json-decoder.js +0 -139
  153. package/dist/json-decoder.js.map +0 -1
  154. package/dist/json-encoder.d.ts +0 -35
  155. package/dist/json-encoder.js +0 -134
  156. package/dist/json-encoder.js.map +0 -1
  157. package/dist/media-type-decoder.d.ts +0 -4
  158. package/dist/media-type-decoder.js +0 -2
  159. package/dist/media-type-decoder.js.map +0 -1
  160. package/dist/media-type-decoders.js +0 -40
  161. package/dist/media-type-decoders.js.map +0 -1
  162. package/dist/media-type-encoder.js +0 -6
  163. package/dist/media-type-encoder.js.map +0 -1
  164. package/dist/media-type-encoders.js +0 -42
  165. package/dist/media-type-encoders.js.map +0 -1
  166. package/dist/url-encoder.js.map +0 -1
  167. package/src/binary-decoder.ts +0 -24
  168. package/src/binary-encoder.ts +0 -19
  169. package/src/cbor-decoder.ts +0 -148
  170. package/src/cbor-encoder.ts +0 -95
  171. package/src/cbor-tags.ts +0 -3
  172. package/src/http-error.ts +0 -55
  173. package/src/json-decoder.ts +0 -164
  174. package/src/json-encoder.ts +0 -162
  175. package/src/media-type-decoder.ts +0 -5
  176. package/src/media-type-decoders.ts +0 -59
  177. package/src/media-type-encoder.ts +0 -16
  178. package/src/media-type-encoders.ts +0 -61
  179. 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
+ }