@beignet/core 0.0.48 → 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 +46 -0
- package/README.md +224 -20
- package/dist/client/client.d.ts +0 -2
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +28 -25
- package/dist/client/client.js.map +1 -1
- package/dist/contracts/contract-builder.d.ts +7 -2
- package/dist/contracts/contract-builder.d.ts.map +1 -1
- package/dist/contracts/contract-builder.js +20 -2
- package/dist/contracts/contract-builder.js.map +1 -1
- package/dist/contracts/contract-group.d.ts.map +1 -1
- package/dist/contracts/contract-group.js +1 -0
- package/dist/contracts/contract-group.js.map +1 -1
- package/dist/contracts/contract-like.d.ts +2 -0
- package/dist/contracts/contract-like.d.ts.map +1 -1
- package/dist/contracts/contract-like.js +27 -1
- package/dist/contracts/contract-like.js.map +1 -1
- package/dist/contracts/index.d.ts +4 -0
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/index.js +4 -0
- package/dist/contracts/index.js.map +1 -1
- package/dist/contracts/query-transport.d.ts +126 -0
- package/dist/contracts/query-transport.d.ts.map +1 -0
- package/dist/contracts/query-transport.js +406 -0
- package/dist/contracts/query-transport.js.map +1 -0
- package/dist/contracts/schema-shape.d.ts +11 -0
- package/dist/contracts/schema-shape.d.ts.map +1 -1
- package/dist/contracts/schema-shape.js +13 -0
- package/dist/contracts/schema-shape.js.map +1 -1
- package/dist/contracts/types.d.ts +5 -0
- package/dist/contracts/types.d.ts.map +1 -1
- package/dist/contracts/types.js.map +1 -1
- 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/openapi/index.d.ts +8 -0
- package/dist/openapi/index.d.ts.map +1 -1
- package/dist/openapi/index.js +79 -5
- package/dist/openapi/index.js.map +1 -1
- package/dist/outbox/index.d.ts +8 -5
- package/dist/outbox/index.d.ts.map +1 -1
- package/dist/outbox/index.js +17 -3
- package/dist/outbox/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/cache.d.ts +9 -1
- package/dist/ports/cache.d.ts.map +1 -1
- package/dist/ports/cache.js +20 -5
- package/dist/ports/cache.js.map +1 -1
- package/dist/ports/events.d.ts +7 -5
- package/dist/ports/events.d.ts.map +1 -1
- package/dist/ports/index.d.ts +7 -2
- package/dist/ports/index.d.ts.map +1 -1
- package/dist/ports/index.js +2 -1
- 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/rate-limit.d.ts +16 -8
- package/dist/server/hooks/rate-limit.d.ts.map +1 -1
- package/dist/server/hooks/rate-limit.js +31 -17
- package/dist/server/hooks/rate-limit.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 +18 -9
- 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 +31 -11
- 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 +43 -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/server/use-case-route.d.ts +8 -5
- package/dist/server/use-case-route.d.ts.map +1 -1
- package/dist/server/use-case-route.js +44 -17
- package/dist/server/use-case-route.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 +3 -3
- package/skills/app-architecture/SKILL.md +50 -4
- package/src/client/client.ts +29 -28
- package/src/contracts/contract-builder.ts +32 -2
- package/src/contracts/contract-group.ts +1 -0
- package/src/contracts/contract-like.ts +40 -1
- package/src/contracts/index.ts +23 -0
- package/src/contracts/query-transport.ts +697 -0
- package/src/contracts/schema-shape.ts +24 -0
- package/src/contracts/types.ts +5 -0
- package/src/events/index.ts +263 -38
- package/src/idempotency/index.ts +65 -17
- package/src/mail/index.ts +7 -3
- package/src/openapi/index.ts +126 -2
- package/src/outbox/index.ts +26 -5
- package/src/ports/best-effort-work.ts +21 -0
- package/src/ports/cache.ts +29 -7
- package/src/ports/events.ts +9 -4
- package/src/ports/index.ts +10 -1
- 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/rate-limit.ts +50 -24
- 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 +31 -9
- package/src/server/request-preparation.ts +45 -12
- 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 +48 -22
- package/src/server/trusted-proxy-internal.ts +20 -0
- package/src/server/trusted-proxy.ts +6 -7
- package/src/server/use-case-route.ts +62 -23
- package/src/testing/index.ts +30 -0
- package/dist/query-codec.d.ts +0 -3
- package/dist/query-codec.d.ts.map +0 -1
- package/dist/query-codec.js +0 -110
- package/dist/query-codec.js.map +0 -1
- package/src/query-codec.ts +0 -130
|
@@ -192,8 +192,10 @@ type UseCaseRouteShape<
|
|
|
192
192
|
/**
|
|
193
193
|
* Map parsed request parts to the use case input.
|
|
194
194
|
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
195
|
+
* A sole declared path, query, or body schema is passed through unchanged
|
|
196
|
+
* when no additional path, query, or object body values are present.
|
|
197
|
+
* Otherwise `defaultBinderInput` merges query, body, and path objects (path
|
|
198
|
+
* wins collisions) and never merges headers.
|
|
197
199
|
*/
|
|
198
200
|
input?: (parts: UseCaseRouteInputParts<C>) => UseCaseRouteInput<UC>;
|
|
199
201
|
handle?: never;
|
|
@@ -330,9 +332,10 @@ function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
|
330
332
|
* Merges parsed query, body, and path objects into one input object. Path
|
|
331
333
|
* keys win all collisions, then body keys, then query keys. Headers are never
|
|
332
334
|
* merged: parsed headers include every raw request header, so merging them
|
|
333
|
-
* would poison the use case input.
|
|
334
|
-
*
|
|
335
|
-
*
|
|
335
|
+
* would poison the use case input. The route binder passes a sole declared
|
|
336
|
+
* input schema through unchanged when no other object input contains values;
|
|
337
|
+
* this merge handles every other default mapping. Routes that combine a
|
|
338
|
+
* non-object body with another source declare an explicit `input` mapper.
|
|
336
339
|
*/
|
|
337
340
|
export function defaultBinderInput(parts: {
|
|
338
341
|
path: unknown;
|
|
@@ -356,16 +359,42 @@ export function isUseCaseRouteDef(route: {
|
|
|
356
359
|
return route.useCase !== undefined && route.useCase !== null;
|
|
357
360
|
}
|
|
358
361
|
|
|
359
|
-
function
|
|
362
|
+
function computeSingleInput(
|
|
360
363
|
contract: HttpContractConfig,
|
|
361
364
|
def: RuntimeUseCaseRouteDef,
|
|
362
|
-
):
|
|
363
|
-
if (def.input) return
|
|
365
|
+
): { source: "path" | "query" | "body"; schema: unknown } | undefined {
|
|
366
|
+
if (def.input) return undefined;
|
|
367
|
+
|
|
368
|
+
const sources = [
|
|
369
|
+
{ source: "path", schema: contract.pathParams },
|
|
370
|
+
{
|
|
371
|
+
source: "query",
|
|
372
|
+
schema: contract.query,
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
source: "body",
|
|
376
|
+
schema: contract.body,
|
|
377
|
+
},
|
|
378
|
+
] as const;
|
|
379
|
+
const present = sources.filter(
|
|
380
|
+
(candidate) => candidate.schema !== null && candidate.schema !== undefined,
|
|
381
|
+
);
|
|
382
|
+
const single = present[0];
|
|
383
|
+
return present.length === 1 && single
|
|
384
|
+
? { source: single.source, schema: single.schema }
|
|
385
|
+
: undefined;
|
|
386
|
+
}
|
|
364
387
|
|
|
365
|
-
|
|
366
|
-
|
|
388
|
+
function canPassSingleInput(
|
|
389
|
+
parts: { path: unknown; query: unknown; body: unknown },
|
|
390
|
+
source: "path" | "query" | "body",
|
|
391
|
+
): boolean {
|
|
392
|
+
return (["path", "query", "body"] as const).every(
|
|
393
|
+
(candidate) =>
|
|
394
|
+
candidate === source ||
|
|
395
|
+
!isPlainObject(parts[candidate]) ||
|
|
396
|
+
Object.keys(parts[candidate]).length === 0,
|
|
367
397
|
);
|
|
368
|
-
return sources.length === 1 && sources[0] === def.useCase.inputSchema;
|
|
369
398
|
}
|
|
370
399
|
|
|
371
400
|
function computeResponseExemption(
|
|
@@ -405,11 +434,11 @@ export function createUseCaseRouteHandler<Ctx, C extends HttpContractConfig>(
|
|
|
405
434
|
);
|
|
406
435
|
}
|
|
407
436
|
|
|
408
|
-
const
|
|
409
|
-
const trustedRun =
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
437
|
+
const singleInput = computeSingleInput(contract, def);
|
|
438
|
+
const trustedRun =
|
|
439
|
+
singleInput?.schema === def.useCase.inputSchema
|
|
440
|
+
? def.useCase[USE_CASE_TRUSTED_RUN_KEY]
|
|
441
|
+
: undefined;
|
|
413
442
|
|
|
414
443
|
const handler: Handler<Ctx, C> = async ({
|
|
415
444
|
ctx,
|
|
@@ -417,13 +446,23 @@ export function createUseCaseRouteHandler<Ctx, C extends HttpContractConfig>(
|
|
|
417
446
|
query,
|
|
418
447
|
headers,
|
|
419
448
|
body,
|
|
420
|
-
}) =>
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
449
|
+
}) => {
|
|
450
|
+
const parts = { path, query, headers, body };
|
|
451
|
+
const passSingle =
|
|
452
|
+
singleInput !== undefined &&
|
|
453
|
+
canPassSingleInput(parts, singleInput.source);
|
|
454
|
+
const input = def.input
|
|
455
|
+
? def.input(parts)
|
|
456
|
+
: passSingle
|
|
457
|
+
? parts[singleInput.source]
|
|
458
|
+
: defaultBinderInput(parts);
|
|
459
|
+
const run = passSingle && trustedRun ? trustedRun : def.useCase.run;
|
|
460
|
+
|
|
461
|
+
return {
|
|
462
|
+
status,
|
|
463
|
+
body: await run.call(def.useCase, { ctx, input }),
|
|
464
|
+
};
|
|
465
|
+
};
|
|
427
466
|
|
|
428
467
|
return {
|
|
429
468
|
handler,
|
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 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"query-codec.d.ts","sourceRoot":"","sources":["../src/query-codec.ts"],"names":[],"mappings":"AA8GA,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAOvD;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAUvD"}
|
package/dist/query-codec.js
DELETED
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
const QUERY_VALUE_PREFIX = "~beignet-query:";
|
|
2
|
-
function encodeStructuredValue(value, ancestors) {
|
|
3
|
-
if (value === null)
|
|
4
|
-
return { type: "null" };
|
|
5
|
-
if (typeof value === "string")
|
|
6
|
-
return { type: "string", value };
|
|
7
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
8
|
-
return { type: "number", value };
|
|
9
|
-
}
|
|
10
|
-
if (typeof value === "boolean")
|
|
11
|
-
return { type: "boolean", value };
|
|
12
|
-
if (value instanceof Date && Number.isFinite(value.getTime())) {
|
|
13
|
-
return { type: "date", value: value.toISOString() };
|
|
14
|
-
}
|
|
15
|
-
if (typeof value !== "object" || value === null) {
|
|
16
|
-
throw new TypeError("Query value is not serializable.");
|
|
17
|
-
}
|
|
18
|
-
if (ancestors.has(value)) {
|
|
19
|
-
throw new TypeError("Query value contains a circular reference.");
|
|
20
|
-
}
|
|
21
|
-
ancestors.add(value);
|
|
22
|
-
try {
|
|
23
|
-
if (Array.isArray(value)) {
|
|
24
|
-
return {
|
|
25
|
-
type: "array",
|
|
26
|
-
value: value.map((entry) => encodeStructuredValue(entry, ancestors)),
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
const prototype = Object.getPrototypeOf(value);
|
|
30
|
-
if (prototype !== Object.prototype && prototype !== null) {
|
|
31
|
-
throw new TypeError("Query value contains a non-plain object.");
|
|
32
|
-
}
|
|
33
|
-
return {
|
|
34
|
-
type: "object",
|
|
35
|
-
value: Object.fromEntries(Object.entries(value)
|
|
36
|
-
.filter(([, entry]) => entry !== undefined)
|
|
37
|
-
.map(([key, entry]) => [
|
|
38
|
-
key,
|
|
39
|
-
encodeStructuredValue(entry, ancestors),
|
|
40
|
-
])),
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
finally {
|
|
44
|
-
ancestors.delete(value);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
function decodeStructuredValue(value) {
|
|
48
|
-
if (typeof value !== "object" || value === null || !("type" in value)) {
|
|
49
|
-
throw new TypeError("Invalid encoded query value.");
|
|
50
|
-
}
|
|
51
|
-
const encoded = value;
|
|
52
|
-
switch (encoded.type) {
|
|
53
|
-
case "null":
|
|
54
|
-
return null;
|
|
55
|
-
case "string":
|
|
56
|
-
if (typeof encoded.value === "string")
|
|
57
|
-
return encoded.value;
|
|
58
|
-
break;
|
|
59
|
-
case "number":
|
|
60
|
-
if (typeof encoded.value === "number" && Number.isFinite(encoded.value)) {
|
|
61
|
-
return encoded.value;
|
|
62
|
-
}
|
|
63
|
-
break;
|
|
64
|
-
case "boolean":
|
|
65
|
-
if (typeof encoded.value === "boolean")
|
|
66
|
-
return encoded.value;
|
|
67
|
-
break;
|
|
68
|
-
case "date": {
|
|
69
|
-
if (typeof encoded.value !== "string")
|
|
70
|
-
break;
|
|
71
|
-
const date = new Date(encoded.value);
|
|
72
|
-
if (Number.isFinite(date.getTime()))
|
|
73
|
-
return date;
|
|
74
|
-
break;
|
|
75
|
-
}
|
|
76
|
-
case "array":
|
|
77
|
-
if (Array.isArray(encoded.value)) {
|
|
78
|
-
return encoded.value.map(decodeStructuredValue);
|
|
79
|
-
}
|
|
80
|
-
break;
|
|
81
|
-
case "object":
|
|
82
|
-
if (typeof encoded.value === "object" &&
|
|
83
|
-
encoded.value !== null &&
|
|
84
|
-
!Array.isArray(encoded.value)) {
|
|
85
|
-
return Object.fromEntries(Object.entries(encoded.value).map(([key, entry]) => [
|
|
86
|
-
key,
|
|
87
|
-
decodeStructuredValue(entry),
|
|
88
|
-
]));
|
|
89
|
-
}
|
|
90
|
-
break;
|
|
91
|
-
}
|
|
92
|
-
throw new TypeError("Invalid encoded query value.");
|
|
93
|
-
}
|
|
94
|
-
export function encodeQueryValue(value) {
|
|
95
|
-
if (typeof value === "string" && !value.startsWith(QUERY_VALUE_PREFIX)) {
|
|
96
|
-
return value;
|
|
97
|
-
}
|
|
98
|
-
return `${QUERY_VALUE_PREFIX}${JSON.stringify(encodeStructuredValue(value, new Set()))}`;
|
|
99
|
-
}
|
|
100
|
-
export function decodeQueryValue(value) {
|
|
101
|
-
if (!value.startsWith(QUERY_VALUE_PREFIX))
|
|
102
|
-
return value;
|
|
103
|
-
try {
|
|
104
|
-
return decodeStructuredValue(JSON.parse(value.slice(QUERY_VALUE_PREFIX.length)));
|
|
105
|
-
}
|
|
106
|
-
catch {
|
|
107
|
-
return value;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
//# 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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"}
|
package/src/query-codec.ts
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
const QUERY_VALUE_PREFIX = "~beignet-query:";
|
|
2
|
-
|
|
3
|
-
type EncodedQueryValue =
|
|
4
|
-
| { type: "null" }
|
|
5
|
-
| { type: "string"; value: string }
|
|
6
|
-
| { type: "number"; value: number }
|
|
7
|
-
| { type: "boolean"; value: boolean }
|
|
8
|
-
| { type: "date"; value: string }
|
|
9
|
-
| { type: "array"; value: EncodedQueryValue[] }
|
|
10
|
-
| { type: "object"; value: Record<string, EncodedQueryValue> };
|
|
11
|
-
|
|
12
|
-
function encodeStructuredValue(
|
|
13
|
-
value: unknown,
|
|
14
|
-
ancestors: Set<object>,
|
|
15
|
-
): EncodedQueryValue {
|
|
16
|
-
if (value === null) return { type: "null" };
|
|
17
|
-
if (typeof value === "string") return { type: "string", value };
|
|
18
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
19
|
-
return { type: "number", value };
|
|
20
|
-
}
|
|
21
|
-
if (typeof value === "boolean") return { type: "boolean", value };
|
|
22
|
-
if (value instanceof Date && Number.isFinite(value.getTime())) {
|
|
23
|
-
return { type: "date", value: value.toISOString() };
|
|
24
|
-
}
|
|
25
|
-
if (typeof value !== "object" || value === null) {
|
|
26
|
-
throw new TypeError("Query value is not serializable.");
|
|
27
|
-
}
|
|
28
|
-
if (ancestors.has(value)) {
|
|
29
|
-
throw new TypeError("Query value contains a circular reference.");
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
ancestors.add(value);
|
|
33
|
-
try {
|
|
34
|
-
if (Array.isArray(value)) {
|
|
35
|
-
return {
|
|
36
|
-
type: "array",
|
|
37
|
-
value: value.map((entry) => encodeStructuredValue(entry, ancestors)),
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const prototype = Object.getPrototypeOf(value);
|
|
42
|
-
if (prototype !== Object.prototype && prototype !== null) {
|
|
43
|
-
throw new TypeError("Query value contains a non-plain object.");
|
|
44
|
-
}
|
|
45
|
-
return {
|
|
46
|
-
type: "object",
|
|
47
|
-
value: Object.fromEntries(
|
|
48
|
-
Object.entries(value)
|
|
49
|
-
.filter(([, entry]) => entry !== undefined)
|
|
50
|
-
.map(([key, entry]) => [
|
|
51
|
-
key,
|
|
52
|
-
encodeStructuredValue(entry, ancestors),
|
|
53
|
-
]),
|
|
54
|
-
),
|
|
55
|
-
};
|
|
56
|
-
} finally {
|
|
57
|
-
ancestors.delete(value);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function decodeStructuredValue(value: unknown): unknown {
|
|
62
|
-
if (typeof value !== "object" || value === null || !("type" in value)) {
|
|
63
|
-
throw new TypeError("Invalid encoded query value.");
|
|
64
|
-
}
|
|
65
|
-
const encoded = value as { type: unknown; value?: unknown };
|
|
66
|
-
|
|
67
|
-
switch (encoded.type) {
|
|
68
|
-
case "null":
|
|
69
|
-
return null;
|
|
70
|
-
case "string":
|
|
71
|
-
if (typeof encoded.value === "string") return encoded.value;
|
|
72
|
-
break;
|
|
73
|
-
case "number":
|
|
74
|
-
if (typeof encoded.value === "number" && Number.isFinite(encoded.value)) {
|
|
75
|
-
return encoded.value;
|
|
76
|
-
}
|
|
77
|
-
break;
|
|
78
|
-
case "boolean":
|
|
79
|
-
if (typeof encoded.value === "boolean") return encoded.value;
|
|
80
|
-
break;
|
|
81
|
-
case "date": {
|
|
82
|
-
if (typeof encoded.value !== "string") break;
|
|
83
|
-
const date = new Date(encoded.value);
|
|
84
|
-
if (Number.isFinite(date.getTime())) return date;
|
|
85
|
-
break;
|
|
86
|
-
}
|
|
87
|
-
case "array":
|
|
88
|
-
if (Array.isArray(encoded.value)) {
|
|
89
|
-
return encoded.value.map(decodeStructuredValue);
|
|
90
|
-
}
|
|
91
|
-
break;
|
|
92
|
-
case "object":
|
|
93
|
-
if (
|
|
94
|
-
typeof encoded.value === "object" &&
|
|
95
|
-
encoded.value !== null &&
|
|
96
|
-
!Array.isArray(encoded.value)
|
|
97
|
-
) {
|
|
98
|
-
return Object.fromEntries(
|
|
99
|
-
Object.entries(encoded.value).map(([key, entry]) => [
|
|
100
|
-
key,
|
|
101
|
-
decodeStructuredValue(entry),
|
|
102
|
-
]),
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
break;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
throw new TypeError("Invalid encoded query value.");
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export function encodeQueryValue(value: unknown): string {
|
|
112
|
-
if (typeof value === "string" && !value.startsWith(QUERY_VALUE_PREFIX)) {
|
|
113
|
-
return value;
|
|
114
|
-
}
|
|
115
|
-
return `${QUERY_VALUE_PREFIX}${JSON.stringify(
|
|
116
|
-
encodeStructuredValue(value, new Set()),
|
|
117
|
-
)}`;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export function decodeQueryValue(value: string): unknown {
|
|
121
|
-
if (!value.startsWith(QUERY_VALUE_PREFIX)) return value;
|
|
122
|
-
|
|
123
|
-
try {
|
|
124
|
-
return decodeStructuredValue(
|
|
125
|
-
JSON.parse(value.slice(QUERY_VALUE_PREFIX.length)) as unknown,
|
|
126
|
-
);
|
|
127
|
-
} catch {
|
|
128
|
-
return value;
|
|
129
|
-
}
|
|
130
|
-
}
|