@beignet/core 0.0.49 → 0.0.50
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/CHANGELOG.md +22 -0
- package/README.md +160 -6
- package/dist/events/index.d.ts +54 -5
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +183 -32
- package/dist/events/index.js.map +1 -1
- package/dist/idempotency/index.d.ts +7 -3
- package/dist/idempotency/index.d.ts.map +1 -1
- package/dist/idempotency/index.js +45 -12
- package/dist/idempotency/index.js.map +1 -1
- package/dist/mail/index.d.ts.map +1 -1
- package/dist/mail/index.js +6 -3
- package/dist/mail/index.js.map +1 -1
- package/dist/ports/best-effort-work.d.ts +21 -0
- package/dist/ports/best-effort-work.d.ts.map +1 -0
- package/dist/ports/best-effort-work.js +2 -0
- package/dist/ports/best-effort-work.js.map +1 -0
- package/dist/ports/events.d.ts +7 -5
- package/dist/ports/events.d.ts.map +1 -1
- package/dist/ports/index.d.ts +6 -1
- package/dist/ports/index.d.ts.map +1 -1
- package/dist/ports/index.js +1 -0
- package/dist/ports/index.js.map +1 -1
- package/dist/ports/testing.d.ts +15 -0
- package/dist/ports/testing.d.ts.map +1 -1
- package/dist/ports/testing.js +38 -0
- package/dist/ports/testing.js.map +1 -1
- package/dist/providers/provider.d.ts +8 -5
- package/dist/providers/provider.d.ts.map +1 -1
- package/dist/providers/provider.js.map +1 -1
- package/dist/server/hooks/cors.d.ts +2 -2
- package/dist/server/hooks/cors.d.ts.map +1 -1
- package/dist/server/hooks/cors.js +2 -1
- package/dist/server/hooks/cors.js.map +1 -1
- package/dist/server/hooks/logging.d.ts +2 -2
- package/dist/server/hooks/logging.d.ts.map +1 -1
- package/dist/server/hooks/logging.js.map +1 -1
- package/dist/server/hooks/security.d.ts +2 -2
- package/dist/server/hooks/security.d.ts.map +1 -1
- package/dist/server/hooks/security.js.map +1 -1
- package/dist/server/http.d.ts +21 -2
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/index.d.ts +4 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +4 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/instrumentation.d.ts.map +1 -1
- package/dist/server/instrumentation.js +5 -3
- package/dist/server/instrumentation.js.map +1 -1
- package/dist/server/request-executor.d.ts.map +1 -1
- package/dist/server/request-executor.js +9 -0
- package/dist/server/request-executor.js.map +1 -1
- package/dist/server/request-preparation.d.ts.map +1 -1
- package/dist/server/request-preparation.js +20 -2
- package/dist/server/request-preparation.js.map +1 -1
- package/dist/server/response-finalization.d.ts +2 -2
- package/dist/server/response-finalization.d.ts.map +1 -1
- package/dist/server/response-finalization.js +25 -8
- package/dist/server/response-finalization.js.map +1 -1
- package/dist/server/route-matching.d.ts.map +1 -1
- package/dist/server/route-matching.js +12 -1
- package/dist/server/route-matching.js.map +1 -1
- package/dist/server/server-sent-events.d.ts +94 -0
- package/dist/server/server-sent-events.d.ts.map +1 -0
- package/dist/server/server-sent-events.js +275 -0
- package/dist/server/server-sent-events.js.map +1 -0
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +41 -22
- package/dist/server/server.js.map +1 -1
- package/dist/server/trusted-proxy-internal.d.ts +4 -0
- package/dist/server/trusted-proxy-internal.d.ts.map +1 -1
- package/dist/server/trusted-proxy-internal.js +20 -0
- package/dist/server/trusted-proxy-internal.js.map +1 -1
- package/dist/server/trusted-proxy.d.ts.map +1 -1
- package/dist/server/trusted-proxy.js +3 -8
- package/dist/server/trusted-proxy.js.map +1 -1
- package/dist/testing/index.d.ts +17 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +6 -1
- package/dist/testing/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/app-architecture/SKILL.md +23 -3
- package/src/events/index.ts +263 -38
- package/src/idempotency/index.ts +65 -17
- package/src/mail/index.ts +7 -3
- package/src/ports/best-effort-work.ts +21 -0
- package/src/ports/events.ts +9 -4
- package/src/ports/index.ts +9 -0
- package/src/ports/testing.ts +45 -0
- package/src/providers/provider.ts +8 -5
- package/src/server/hooks/cors.ts +11 -5
- package/src/server/hooks/logging.ts +6 -2
- package/src/server/hooks/security.ts +8 -4
- package/src/server/http.ts +23 -2
- package/src/server/index.ts +4 -0
- package/src/server/instrumentation.ts +12 -4
- package/src/server/request-executor.ts +14 -0
- package/src/server/request-preparation.ts +23 -3
- package/src/server/response-finalization.ts +51 -15
- package/src/server/route-matching.ts +24 -1
- package/src/server/server-sent-events.ts +415 -0
- package/src/server/server.ts +46 -22
- package/src/server/trusted-proxy-internal.ts +20 -0
- package/src/server/trusted-proxy.ts +6 -7
- package/src/testing/index.ts +30 -0
- package/dist/query-codec.d.ts +0 -27
- package/dist/query-codec.d.ts.map +0 -1
- package/dist/query-codec.js +0 -245
- package/dist/query-codec.js.map +0 -1
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
import type { TrustedProxyConfig } from "./trusted-proxy.js";
|
|
2
2
|
|
|
3
|
+
export class InvalidRequestUrlError extends Error {
|
|
4
|
+
constructor() {
|
|
5
|
+
super("req.url must be an absolute HTTP or HTTPS URL.");
|
|
6
|
+
this.name = "InvalidRequestUrlError";
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function parseHttpRequestUrl(value: string): URL {
|
|
11
|
+
try {
|
|
12
|
+
const url = new URL(value);
|
|
13
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
14
|
+
throw new InvalidRequestUrlError();
|
|
15
|
+
}
|
|
16
|
+
return url;
|
|
17
|
+
} catch (error) {
|
|
18
|
+
if (error instanceof InvalidRequestUrlError) throw error;
|
|
19
|
+
throw new InvalidRequestUrlError();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
3
23
|
export function requireTrustedProxyHeaderName(
|
|
4
24
|
name: string,
|
|
5
25
|
optionName: string,
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { HttpRequestLike } from "./http.js";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
parseHttpRequestUrl,
|
|
4
|
+
requireTrustedProxyHeaderName,
|
|
5
|
+
} from "./trusted-proxy-internal.js";
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* Header source used to resolve a client IP after an app has explicitly opted
|
|
@@ -141,17 +144,13 @@ function normalizeHost(
|
|
|
141
144
|
}
|
|
142
145
|
|
|
143
146
|
function baseRequestUrl(req: HttpRequestLike): URL {
|
|
144
|
-
|
|
145
|
-
return new URL(req.url);
|
|
146
|
-
} catch {
|
|
147
|
-
throw new Error("req.url must be an absolute URL.");
|
|
148
|
-
}
|
|
147
|
+
return parseHttpRequestUrl(req.url);
|
|
149
148
|
}
|
|
150
149
|
|
|
151
150
|
function normalizedBaseProtocol(url: URL): "http" | "https" {
|
|
152
151
|
const protocol = normalizeProtocol(url.protocol);
|
|
153
152
|
if (protocol) return protocol;
|
|
154
|
-
throw new Error("
|
|
153
|
+
throw new Error("Resolved request URL must use HTTP or HTTPS.");
|
|
155
154
|
}
|
|
156
155
|
|
|
157
156
|
/**
|
package/src/testing/index.ts
CHANGED
|
@@ -29,6 +29,10 @@ import {
|
|
|
29
29
|
createMemoryAuditLog,
|
|
30
30
|
type MemoryAuditLogPort,
|
|
31
31
|
} from "../ports/audit.js";
|
|
32
|
+
import type {
|
|
33
|
+
BestEffortWork,
|
|
34
|
+
BestEffortWorkPort,
|
|
35
|
+
} from "../ports/best-effort-work.js";
|
|
32
36
|
import { type CachePort, createMemoryCache } from "../ports/cache.js";
|
|
33
37
|
import {
|
|
34
38
|
type ClockPort,
|
|
@@ -56,6 +60,7 @@ import {
|
|
|
56
60
|
type UnitOfWorkPort,
|
|
57
61
|
} from "../ports/index.js";
|
|
58
62
|
import {
|
|
63
|
+
createRecordingBestEffortWork,
|
|
59
64
|
createRecordingEventBus,
|
|
60
65
|
createRecordingJobDispatcher,
|
|
61
66
|
createTestActivityContext,
|
|
@@ -107,6 +112,10 @@ export interface CommonTestPorts<TxPorts = AnyPorts> {
|
|
|
107
112
|
* Recording event bus.
|
|
108
113
|
*/
|
|
109
114
|
eventBus: EventBusPort;
|
|
115
|
+
/**
|
|
116
|
+
* Recording non-durable best-effort work.
|
|
117
|
+
*/
|
|
118
|
+
bestEffortWork: BestEffortWorkPort;
|
|
110
119
|
/**
|
|
111
120
|
* In-memory error reporter.
|
|
112
121
|
*/
|
|
@@ -193,6 +202,18 @@ export interface TestPortsFixture<
|
|
|
193
202
|
* Recording event bus port.
|
|
194
203
|
*/
|
|
195
204
|
eventBus: EventBusPort;
|
|
205
|
+
/**
|
|
206
|
+
* Recording best-effort-work port.
|
|
207
|
+
*/
|
|
208
|
+
bestEffortWork: BestEffortWorkPort;
|
|
209
|
+
/**
|
|
210
|
+
* Work currently waiting in the recording best-effort-work adapter.
|
|
211
|
+
*/
|
|
212
|
+
pendingBestEffortWork: BestEffortWork[];
|
|
213
|
+
/**
|
|
214
|
+
* Run the currently pending best-effort-work batch in FIFO order.
|
|
215
|
+
*/
|
|
216
|
+
flushBestEffortWork(): Promise<void>;
|
|
196
217
|
/**
|
|
197
218
|
* Recorded events published through `eventBus`.
|
|
198
219
|
*/
|
|
@@ -380,6 +401,11 @@ export function createTestPorts<
|
|
|
380
401
|
const audit = createMemoryAuditLog();
|
|
381
402
|
const cache = createMemoryCache();
|
|
382
403
|
const clock = options.clock ?? createFrozenClock();
|
|
404
|
+
const {
|
|
405
|
+
bestEffortWork,
|
|
406
|
+
pending: pendingBestEffortWork,
|
|
407
|
+
flush: flushBestEffortWork,
|
|
408
|
+
} = createRecordingBestEffortWork();
|
|
383
409
|
const { bus: eventBus, events } = createRecordingEventBus();
|
|
384
410
|
const errorReporter = createMemoryErrorReporter();
|
|
385
411
|
const flags = createMemoryFlags();
|
|
@@ -408,6 +434,7 @@ export function createTestPorts<
|
|
|
408
434
|
audit: createAmbientAuditLog(audit),
|
|
409
435
|
cache,
|
|
410
436
|
clock,
|
|
437
|
+
bestEffortWork,
|
|
411
438
|
eventBus,
|
|
412
439
|
errorReporter,
|
|
413
440
|
flags,
|
|
@@ -490,6 +517,9 @@ export function createTestPorts<
|
|
|
490
517
|
return {
|
|
491
518
|
ports,
|
|
492
519
|
audit,
|
|
520
|
+
bestEffortWork,
|
|
521
|
+
pendingBestEffortWork,
|
|
522
|
+
flushBestEffortWork,
|
|
493
523
|
eventBus,
|
|
494
524
|
events,
|
|
495
525
|
errorReporter,
|
package/dist/query-codec.d.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
export declare const QUERY_NESTING_DEPTH_LIMIT = 32;
|
|
2
|
-
export declare function decodeQueryExtension(value: string): {
|
|
3
|
-
decoded: true;
|
|
4
|
-
value: unknown;
|
|
5
|
-
} | {
|
|
6
|
-
decoded: false;
|
|
7
|
-
value: string;
|
|
8
|
-
};
|
|
9
|
-
/**
|
|
10
|
-
* Serialize one query value using ordinary URI scalar values and JSON for
|
|
11
|
-
* structured values. Arrays are normally emitted as repeated parameters by
|
|
12
|
-
* the typed client; direct callers can still encode a complete array here.
|
|
13
|
-
*/
|
|
14
|
-
export declare function encodeQueryValue(value: unknown): string;
|
|
15
|
-
/**
|
|
16
|
-
* Decode a standard query scalar or JSON value. Request validation applies
|
|
17
|
-
* this only to fields that fail in their raw string form, preserving numeric,
|
|
18
|
-
* boolean, and date-looking strings when the contract expects strings.
|
|
19
|
-
*/
|
|
20
|
-
export declare function decodeQueryValue(value: string): unknown;
|
|
21
|
-
/**
|
|
22
|
-
* Append a typed query value using OpenAPI form/explode semantics. Objects use
|
|
23
|
-
* deepObject bracket names and arrays use repeated parameter names. Nested
|
|
24
|
-
* objects and object-valued array entries use Beignet's recursive extension.
|
|
25
|
-
*/
|
|
26
|
-
export declare function appendQueryValue(params: URLSearchParams, name: string, value: unknown): void;
|
|
27
|
-
//# sourceMappingURL=query-codec.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"query-codec.d.ts","sourceRoot":"","sources":["../src/query-codec.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAmD5C,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,GACZ;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAgCvE;AAoED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAcvD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAYvD;AA+CD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,GACb,IAAI,CAuBN"}
|
package/dist/query-codec.js
DELETED
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
const QUERY_EXTENSION_PREFIX = "~beignet-query:v1:";
|
|
2
|
-
export const QUERY_NESTING_DEPTH_LIMIT = 32;
|
|
3
|
-
const DATE_TIME_PATTERN = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?(Z|([+-])(\d{2}):(\d{2}))$/;
|
|
4
|
-
function isLeapYear(year) {
|
|
5
|
-
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
6
|
-
}
|
|
7
|
-
function daysInMonth(year, month) {
|
|
8
|
-
if (month === 2)
|
|
9
|
-
return isLeapYear(year) ? 29 : 28;
|
|
10
|
-
return [4, 6, 9, 11].includes(month) ? 30 : 31;
|
|
11
|
-
}
|
|
12
|
-
function decodeDateTime(value) {
|
|
13
|
-
const match = DATE_TIME_PATTERN.exec(value);
|
|
14
|
-
if (!match)
|
|
15
|
-
return undefined;
|
|
16
|
-
const year = Number(match[1]);
|
|
17
|
-
const month = Number(match[2]);
|
|
18
|
-
const day = Number(match[3]);
|
|
19
|
-
const hour = Number(match[4]);
|
|
20
|
-
const minute = Number(match[5]);
|
|
21
|
-
const second = Number(match[6]);
|
|
22
|
-
const offsetHour = match[9] === undefined ? 0 : Number(match[9]);
|
|
23
|
-
const offsetMinute = match[10] === undefined ? 0 : Number(match[10]);
|
|
24
|
-
if (month < 1 ||
|
|
25
|
-
month > 12 ||
|
|
26
|
-
day < 1 ||
|
|
27
|
-
day > daysInMonth(year, month) ||
|
|
28
|
-
hour > 23 ||
|
|
29
|
-
minute > 59 ||
|
|
30
|
-
second > 59 ||
|
|
31
|
-
offsetHour > 23 ||
|
|
32
|
-
offsetMinute > 59) {
|
|
33
|
-
return undefined;
|
|
34
|
-
}
|
|
35
|
-
const date = new Date(value);
|
|
36
|
-
return Number.isFinite(date.getTime()) ? date : undefined;
|
|
37
|
-
}
|
|
38
|
-
function encodeQueryExtension(value) {
|
|
39
|
-
const extension = typeof value === "string" && value.startsWith(QUERY_EXTENSION_PREFIX)
|
|
40
|
-
? { kind: "escaped-string", value }
|
|
41
|
-
: { kind: "empty-preserving", value };
|
|
42
|
-
return `${QUERY_EXTENSION_PREFIX}${JSON.stringify(extension)}`;
|
|
43
|
-
}
|
|
44
|
-
export function decodeQueryExtension(value) {
|
|
45
|
-
if (!value.startsWith(QUERY_EXTENSION_PREFIX)) {
|
|
46
|
-
return { decoded: false, value };
|
|
47
|
-
}
|
|
48
|
-
try {
|
|
49
|
-
const extension = JSON.parse(value.slice(QUERY_EXTENSION_PREFIX.length));
|
|
50
|
-
if (!isPlainObject(extension))
|
|
51
|
-
return { decoded: false, value };
|
|
52
|
-
const keys = Object.keys(extension).sort();
|
|
53
|
-
if (keys.length !== 2 || keys[0] !== "kind" || keys[1] !== "value") {
|
|
54
|
-
return { decoded: false, value };
|
|
55
|
-
}
|
|
56
|
-
if (extension.kind === "escaped-string" &&
|
|
57
|
-
typeof extension.value === "string" &&
|
|
58
|
-
extension.value.startsWith(QUERY_EXTENSION_PREFIX)) {
|
|
59
|
-
return { decoded: true, value: extension.value };
|
|
60
|
-
}
|
|
61
|
-
if (extension.kind === "empty-preserving" &&
|
|
62
|
-
isWithinQueryNestingLimit(extension.value) &&
|
|
63
|
-
containsEmptyCollection(extension.value)) {
|
|
64
|
-
return { decoded: true, value: extension.value };
|
|
65
|
-
}
|
|
66
|
-
return { decoded: false, value };
|
|
67
|
-
}
|
|
68
|
-
catch {
|
|
69
|
-
return { decoded: false, value };
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
function normalizeQueryValue(value, ancestors, depth = 0) {
|
|
73
|
-
if (depth > QUERY_NESTING_DEPTH_LIMIT) {
|
|
74
|
-
throw new TypeError(`Query value exceeds the maximum nesting depth of ${QUERY_NESTING_DEPTH_LIMIT}.`);
|
|
75
|
-
}
|
|
76
|
-
if (value === null || typeof value === "string")
|
|
77
|
-
return value;
|
|
78
|
-
if (typeof value === "number" && Number.isFinite(value))
|
|
79
|
-
return value;
|
|
80
|
-
if (typeof value === "boolean")
|
|
81
|
-
return value;
|
|
82
|
-
if (value instanceof Date && Number.isFinite(value.getTime())) {
|
|
83
|
-
return value.toISOString();
|
|
84
|
-
}
|
|
85
|
-
if (typeof value !== "object" || value === null) {
|
|
86
|
-
throw new TypeError("Query value is not serializable.");
|
|
87
|
-
}
|
|
88
|
-
if (ancestors.has(value)) {
|
|
89
|
-
throw new TypeError("Query value contains a circular reference.");
|
|
90
|
-
}
|
|
91
|
-
ancestors.add(value);
|
|
92
|
-
try {
|
|
93
|
-
if (Array.isArray(value)) {
|
|
94
|
-
return value.map((entry) => normalizeQueryValue(entry, ancestors, depth + 1));
|
|
95
|
-
}
|
|
96
|
-
const prototype = Object.getPrototypeOf(value);
|
|
97
|
-
if (prototype !== Object.prototype && prototype !== null) {
|
|
98
|
-
throw new TypeError("Query value contains a non-plain object.");
|
|
99
|
-
}
|
|
100
|
-
return Object.fromEntries(Object.entries(value)
|
|
101
|
-
.filter(([, entry]) => entry !== undefined)
|
|
102
|
-
.map(([key, entry]) => [
|
|
103
|
-
key,
|
|
104
|
-
normalizeQueryValue(entry, ancestors, depth + 1),
|
|
105
|
-
]));
|
|
106
|
-
}
|
|
107
|
-
finally {
|
|
108
|
-
ancestors.delete(value);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
function isWithinQueryNestingLimit(value) {
|
|
112
|
-
const pending = [
|
|
113
|
-
{ value, depth: 0 },
|
|
114
|
-
];
|
|
115
|
-
while (pending.length > 0) {
|
|
116
|
-
const candidate = pending.pop();
|
|
117
|
-
if (!candidate)
|
|
118
|
-
break;
|
|
119
|
-
if (candidate.depth > QUERY_NESTING_DEPTH_LIMIT)
|
|
120
|
-
return false;
|
|
121
|
-
if (typeof candidate.value !== "object" || candidate.value === null) {
|
|
122
|
-
continue;
|
|
123
|
-
}
|
|
124
|
-
for (const entry of Object.values(candidate.value)) {
|
|
125
|
-
pending.push({ value: entry, depth: candidate.depth + 1 });
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
return true;
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Serialize one query value using ordinary URI scalar values and JSON for
|
|
132
|
-
* structured values. Arrays are normally emitted as repeated parameters by
|
|
133
|
-
* the typed client; direct callers can still encode a complete array here.
|
|
134
|
-
*/
|
|
135
|
-
export function encodeQueryValue(value) {
|
|
136
|
-
const normalized = normalizeQueryValue(value, new Set());
|
|
137
|
-
if (typeof normalized === "string") {
|
|
138
|
-
return normalized.startsWith(QUERY_EXTENSION_PREFIX)
|
|
139
|
-
? encodeQueryExtension(normalized)
|
|
140
|
-
: normalized;
|
|
141
|
-
}
|
|
142
|
-
if (typeof normalized === "number" || typeof normalized === "boolean") {
|
|
143
|
-
return String(normalized);
|
|
144
|
-
}
|
|
145
|
-
if (containsEmptyCollection(normalized)) {
|
|
146
|
-
return encodeQueryExtension(normalized);
|
|
147
|
-
}
|
|
148
|
-
return JSON.stringify(normalized);
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Decode a standard query scalar or JSON value. Request validation applies
|
|
152
|
-
* this only to fields that fail in their raw string form, preserving numeric,
|
|
153
|
-
* boolean, and date-looking strings when the contract expects strings.
|
|
154
|
-
*/
|
|
155
|
-
export function decodeQueryValue(value) {
|
|
156
|
-
const extension = decodeQueryExtension(value);
|
|
157
|
-
if (extension.decoded)
|
|
158
|
-
return extension.value;
|
|
159
|
-
try {
|
|
160
|
-
const decoded = JSON.parse(value);
|
|
161
|
-
return isWithinQueryNestingLimit(decoded) ? decoded : value;
|
|
162
|
-
}
|
|
163
|
-
catch {
|
|
164
|
-
const date = decodeDateTime(value);
|
|
165
|
-
if (date)
|
|
166
|
-
return date;
|
|
167
|
-
return value;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
function isPlainObject(value) {
|
|
171
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
172
|
-
return false;
|
|
173
|
-
}
|
|
174
|
-
const prototype = Object.getPrototypeOf(value);
|
|
175
|
-
return prototype === Object.prototype || prototype === null;
|
|
176
|
-
}
|
|
177
|
-
function containsEmptyCollection(value) {
|
|
178
|
-
if (Array.isArray(value)) {
|
|
179
|
-
return value.length === 0 || value.some(containsEmptyCollection);
|
|
180
|
-
}
|
|
181
|
-
if (!isPlainObject(value))
|
|
182
|
-
return false;
|
|
183
|
-
const entries = Object.values(value);
|
|
184
|
-
return entries.length === 0 || entries.some(containsEmptyCollection);
|
|
185
|
-
}
|
|
186
|
-
function appendDeepObject(params, name, value) {
|
|
187
|
-
for (const [key, entry] of Object.entries(value)) {
|
|
188
|
-
if (entry === undefined)
|
|
189
|
-
continue;
|
|
190
|
-
const nestedName = `${name}[${key}]`;
|
|
191
|
-
if (Array.isArray(entry)) {
|
|
192
|
-
if (containsEmptyCollection(entry)) {
|
|
193
|
-
params.append(nestedName, encodeQueryExtension(entry));
|
|
194
|
-
}
|
|
195
|
-
else {
|
|
196
|
-
for (const item of entry) {
|
|
197
|
-
params.append(nestedName, encodeQueryValue(item));
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
else if (isPlainObject(entry)) {
|
|
202
|
-
if (Object.keys(entry).length === 0) {
|
|
203
|
-
params.append(nestedName, encodeQueryExtension(entry));
|
|
204
|
-
}
|
|
205
|
-
else {
|
|
206
|
-
appendDeepObject(params, nestedName, entry);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
else {
|
|
210
|
-
params.append(nestedName, encodeQueryValue(entry));
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
/**
|
|
215
|
-
* Append a typed query value using OpenAPI form/explode semantics. Objects use
|
|
216
|
-
* deepObject bracket names and arrays use repeated parameter names. Nested
|
|
217
|
-
* objects and object-valued array entries use Beignet's recursive extension.
|
|
218
|
-
*/
|
|
219
|
-
export function appendQueryValue(params, name, value) {
|
|
220
|
-
// Count the parameter name as the root so the client and server enforce the
|
|
221
|
-
// same bound for deepObject bracket paths.
|
|
222
|
-
const normalized = normalizeQueryValue(value, new Set(), 1);
|
|
223
|
-
if (Array.isArray(normalized)) {
|
|
224
|
-
if (containsEmptyCollection(normalized)) {
|
|
225
|
-
params.append(name, encodeQueryExtension(normalized));
|
|
226
|
-
}
|
|
227
|
-
else {
|
|
228
|
-
for (const entry of normalized) {
|
|
229
|
-
params.append(name, encodeQueryValue(entry));
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
if (isPlainObject(normalized)) {
|
|
235
|
-
if (Object.keys(normalized).length === 0) {
|
|
236
|
-
params.append(name, encodeQueryExtension(normalized));
|
|
237
|
-
}
|
|
238
|
-
else {
|
|
239
|
-
appendDeepObject(params, name, normalized);
|
|
240
|
-
}
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
params.append(name, encodeQueryValue(normalized));
|
|
244
|
-
}
|
|
245
|
-
//# sourceMappingURL=query-codec.js.map
|
package/dist/query-codec.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"query-codec.js","sourceRoot":"","sources":["../src/query-codec.ts"],"names":[],"mappings":"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"}
|