@beignet/core 0.0.49 → 0.0.51
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 +30 -0
- package/README.md +213 -32
- package/dist/application/index.d.ts +5 -5
- package/dist/application/index.d.ts.map +1 -1
- package/dist/application/index.js +5 -4
- package/dist/application/index.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 +188 -34
- package/dist/events/index.js.map +1 -1
- package/dist/events/payload-state.d.ts +4 -0
- package/dist/events/payload-state.d.ts.map +1 -0
- package/dist/events/payload-state.js +11 -0
- package/dist/events/payload-state.js.map +1 -0
- 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/locks/index.d.ts.map +1 -1
- package/dist/locks/index.js +0 -4
- package/dist/locks/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/outbox/index.d.ts +163 -15
- package/dist/outbox/index.d.ts.map +1 -1
- package/dist/outbox/index.js +1009 -152
- package/dist/outbox/index.js.map +1 -1
- package/dist/payments/index.d.ts.map +1 -1
- package/dist/payments/index.js +0 -4
- package/dist/payments/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 +7 -2
- 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 +28 -0
- package/dist/ports/testing.d.ts.map +1 -1
- package/dist/ports/testing.js +50 -0
- package/dist/ports/testing.js.map +1 -1
- package/dist/ports/unit-of-work.d.ts +9 -7
- package/dist/ports/unit-of-work.d.ts.map +1 -1
- package/dist/ports/unit-of-work.js +16 -6
- package/dist/ports/unit-of-work.js.map +1 -1
- package/dist/providers/index.d.ts +1 -1
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/provider.d.ts +8 -43
- package/dist/providers/provider.d.ts.map +1 -1
- package/dist/providers/provider.js.map +1 -1
- package/dist/search/index.d.ts.map +1 -1
- package/dist/search/index.js +0 -4
- package/dist/search/index.js.map +1 -1
- package/dist/server/hooks/cors.d.ts +7 -2
- package/dist/server/hooks/cors.d.ts.map +1 -1
- package/dist/server/hooks/cors.js +31 -2
- 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 +75 -31
- 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 +18 -7
- package/dist/testing/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/app-architecture/SKILL.md +37 -3
- package/src/application/index.ts +18 -7
- package/src/events/index.ts +268 -40
- package/src/events/payload-state.ts +24 -0
- package/src/idempotency/index.ts +65 -17
- package/src/locks/index.ts +0 -4
- package/src/mail/index.ts +7 -3
- package/src/outbox/index.ts +1382 -175
- package/src/payments/index.ts +0 -4
- package/src/ports/best-effort-work.ts +21 -0
- package/src/ports/events.ts +9 -4
- package/src/ports/index.ts +12 -0
- package/src/ports/testing.ts +76 -0
- package/src/ports/unit-of-work.ts +28 -14
- package/src/providers/index.ts +0 -1
- package/src/providers/provider.ts +8 -45
- package/src/search/index.ts +0 -4
- package/src/server/hooks/cors.ts +53 -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 +98 -41
- package/src/server/trusted-proxy-internal.ts +20 -0
- package/src/server/trusted-proxy.ts +6 -7
- package/src/testing/index.ts +50 -9
- 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
package/src/server/server.ts
CHANGED
|
@@ -78,7 +78,10 @@ import {
|
|
|
78
78
|
type TrustedProxyConfig,
|
|
79
79
|
type TrustedRequestInfo,
|
|
80
80
|
} from "./trusted-proxy.js";
|
|
81
|
-
import {
|
|
81
|
+
import {
|
|
82
|
+
assertValidTrustedProxyConfig,
|
|
83
|
+
parseHttpRequestUrl,
|
|
84
|
+
} from "./trusted-proxy-internal.js";
|
|
82
85
|
import {
|
|
83
86
|
createUseCaseRouteHandler,
|
|
84
87
|
isUseCaseRouteDef,
|
|
@@ -539,7 +542,7 @@ export async function createServer<
|
|
|
539
542
|
): Promise<unknown> => {
|
|
540
543
|
if (!serviceContextsAvailable) {
|
|
541
544
|
throw new Error(
|
|
542
|
-
"Service contexts are unavailable
|
|
545
|
+
"Service contexts are unavailable during provider setup and after provider shutdown.",
|
|
543
546
|
);
|
|
544
547
|
}
|
|
545
548
|
|
|
@@ -553,16 +556,20 @@ export async function createServer<
|
|
|
553
556
|
if (stopped) return;
|
|
554
557
|
stopped = true;
|
|
555
558
|
const errors: unknown[] = [];
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
559
|
+
try {
|
|
560
|
+
for (let i = providerResults.length - 1; i >= 0; i -= 1) {
|
|
561
|
+
const result = providerResults[i];
|
|
562
|
+
try {
|
|
563
|
+
await result?.stop?.({
|
|
564
|
+
ports: finalPorts,
|
|
565
|
+
createServiceContext: lifecycleCreateServiceContext,
|
|
566
|
+
});
|
|
567
|
+
} catch (err) {
|
|
568
|
+
errors.push(err);
|
|
569
|
+
}
|
|
565
570
|
}
|
|
571
|
+
} finally {
|
|
572
|
+
serviceContextsAvailable = false;
|
|
566
573
|
}
|
|
567
574
|
if (errors.length) {
|
|
568
575
|
throw new AggregateError(errors, "Provider shutdown errors");
|
|
@@ -662,24 +669,6 @@ export async function createServer<
|
|
|
662
669
|
registryNeedsSort = true;
|
|
663
670
|
};
|
|
664
671
|
|
|
665
|
-
const createBuilder = <C extends HttpContractConfig>(
|
|
666
|
-
contract: C,
|
|
667
|
-
shouldRegister: boolean,
|
|
668
|
-
): RouteBuilder<Ctx, C> => ({
|
|
669
|
-
handle: (fn) => {
|
|
670
|
-
const wrapped = buildHandler(
|
|
671
|
-
options,
|
|
672
|
-
finalPorts,
|
|
673
|
-
contextRuntime,
|
|
674
|
-
contract,
|
|
675
|
-
fn,
|
|
676
|
-
hooks,
|
|
677
|
-
);
|
|
678
|
-
if (shouldRegister) registerRoute(contract, fn);
|
|
679
|
-
return wrapped;
|
|
680
|
-
},
|
|
681
|
-
});
|
|
682
|
-
|
|
683
672
|
if (options.routes) {
|
|
684
673
|
try {
|
|
685
674
|
for (const route of options.routes) {
|
|
@@ -744,16 +733,6 @@ export async function createServer<
|
|
|
744
733
|
providerResults.push(result);
|
|
745
734
|
}
|
|
746
735
|
|
|
747
|
-
for (const result of providerResults) {
|
|
748
|
-
if (!result.start) continue;
|
|
749
|
-
await result.start({
|
|
750
|
-
ports: finalPorts,
|
|
751
|
-
createServiceContext: lifecycleCreateServiceContext,
|
|
752
|
-
});
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
instrumentation.attachPorts(finalPorts);
|
|
756
|
-
|
|
757
736
|
const onUnboundPorts = options.onUnboundPorts ?? "error";
|
|
758
737
|
if (onUnboundPorts !== "ignore") {
|
|
759
738
|
const unboundKeys = Object.keys(finalPorts).filter((key) =>
|
|
@@ -772,7 +751,20 @@ export async function createServer<
|
|
|
772
751
|
}
|
|
773
752
|
}
|
|
774
753
|
|
|
754
|
+
// Every provider has now contributed its ports and the unbound-port guard
|
|
755
|
+
// has passed. Start hooks may safely build service contexts while they
|
|
756
|
+
// activate consumers such as event listeners.
|
|
775
757
|
serviceContextsAvailable = true;
|
|
758
|
+
|
|
759
|
+
for (const result of providerResults) {
|
|
760
|
+
if (!result.start) continue;
|
|
761
|
+
await result.start({
|
|
762
|
+
ports: finalPorts,
|
|
763
|
+
createServiceContext: lifecycleCreateServiceContext,
|
|
764
|
+
});
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
instrumentation.attachPorts(finalPorts);
|
|
776
768
|
} catch (error) {
|
|
777
769
|
try {
|
|
778
770
|
await stop();
|
|
@@ -822,8 +814,22 @@ export async function createServer<
|
|
|
822
814
|
registryNeedsSort = false;
|
|
823
815
|
}
|
|
824
816
|
|
|
825
|
-
const url = new URL(req.url);
|
|
826
817
|
const method = req.method.toUpperCase();
|
|
818
|
+
let url: URL;
|
|
819
|
+
try {
|
|
820
|
+
url = parseHttpRequestUrl(req.url);
|
|
821
|
+
} catch (error) {
|
|
822
|
+
return await executeFallback(
|
|
823
|
+
{
|
|
824
|
+
contract: fallbackContract("invalidRequestUrl", method, "/"),
|
|
825
|
+
handler: async () => {
|
|
826
|
+
throw error;
|
|
827
|
+
},
|
|
828
|
+
},
|
|
829
|
+
req,
|
|
830
|
+
{},
|
|
831
|
+
);
|
|
832
|
+
}
|
|
827
833
|
|
|
828
834
|
let pathMatchedMethods: Set<string> | undefined;
|
|
829
835
|
let headCandidate: RegisteredRoute | undefined;
|
|
@@ -893,7 +899,58 @@ export async function createServer<
|
|
|
893
899
|
api,
|
|
894
900
|
route: (contractLike) => {
|
|
895
901
|
const contract = resolveContract(contractLike);
|
|
896
|
-
return
|
|
902
|
+
return {
|
|
903
|
+
handle: (fn) => {
|
|
904
|
+
const wrapped = buildHandler(
|
|
905
|
+
options,
|
|
906
|
+
finalPorts,
|
|
907
|
+
contextRuntime,
|
|
908
|
+
contract,
|
|
909
|
+
fn,
|
|
910
|
+
hooks,
|
|
911
|
+
);
|
|
912
|
+
registerRoute(contract, fn);
|
|
913
|
+
const compiled = compilePath(contract.path);
|
|
914
|
+
|
|
915
|
+
return async (req: HttpRequestLike) => {
|
|
916
|
+
const method = req.method.toUpperCase();
|
|
917
|
+
let url: URL;
|
|
918
|
+
try {
|
|
919
|
+
url = parseHttpRequestUrl(req.url);
|
|
920
|
+
} catch (error) {
|
|
921
|
+
return await executeFallback(
|
|
922
|
+
{
|
|
923
|
+
contract: fallbackContract("invalidRequestUrl", method, "/"),
|
|
924
|
+
handler: async () => {
|
|
925
|
+
throw error;
|
|
926
|
+
},
|
|
927
|
+
},
|
|
928
|
+
req,
|
|
929
|
+
{},
|
|
930
|
+
);
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
const requestMethod = method;
|
|
934
|
+
const contractMethod = contract.method.toUpperCase();
|
|
935
|
+
const methodMatches =
|
|
936
|
+
requestMethod === contractMethod ||
|
|
937
|
+
(requestMethod === "HEAD" && contractMethod === "GET");
|
|
938
|
+
if (!methodMatches || !compiled.pattern.test(url.pathname)) {
|
|
939
|
+
const pathname = url.pathname || "/";
|
|
940
|
+
return await executeFallback(
|
|
941
|
+
{
|
|
942
|
+
contract: fallbackContract("notFound", method, pathname),
|
|
943
|
+
handler: notFoundHandler,
|
|
944
|
+
},
|
|
945
|
+
req,
|
|
946
|
+
{},
|
|
947
|
+
);
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
return await wrapped(req);
|
|
951
|
+
};
|
|
952
|
+
},
|
|
953
|
+
};
|
|
897
954
|
},
|
|
898
955
|
rawRoute: (init) => ({
|
|
899
956
|
handle: (fn) => {
|
|
@@ -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
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from "../notifications/index.js";
|
|
16
16
|
import {
|
|
17
17
|
createMemoryOutbox,
|
|
18
|
-
|
|
18
|
+
createOutboxEventRecorder,
|
|
19
19
|
type MemoryOutboxPort,
|
|
20
20
|
} from "../outbox/index.js";
|
|
21
21
|
import {
|
|
@@ -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,
|
|
@@ -462,10 +489,17 @@ export function createTestPorts<
|
|
|
462
489
|
outbox: MemoryOutboxPort;
|
|
463
490
|
}
|
|
464
491
|
).outbox;
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
492
|
+
const outboxRecorder = createOutboxEventRecorder(outbox);
|
|
493
|
+
await events.flush({
|
|
494
|
+
publish(event, payload, options) {
|
|
495
|
+
return outboxRecorder.record(event, payload, options);
|
|
496
|
+
},
|
|
497
|
+
subscribe() {
|
|
498
|
+
throw new Error(
|
|
499
|
+
"The test outbox event publisher does not support subscriptions.",
|
|
500
|
+
);
|
|
501
|
+
},
|
|
502
|
+
});
|
|
469
503
|
}
|
|
470
504
|
await transactionOptions?.afterCommit?.(tx);
|
|
471
505
|
},
|
|
@@ -490,6 +524,9 @@ export function createTestPorts<
|
|
|
490
524
|
return {
|
|
491
525
|
ports,
|
|
492
526
|
audit,
|
|
527
|
+
bestEffortWork,
|
|
528
|
+
pendingBestEffortWork,
|
|
529
|
+
flushBestEffortWork,
|
|
493
530
|
eventBus,
|
|
494
531
|
events,
|
|
495
532
|
errorReporter,
|
|
@@ -589,18 +626,19 @@ function completeTestPortOverrides<Ports extends AnyPorts>(
|
|
|
589
626
|
|
|
590
627
|
function resolveBufferedTransactionEvents(
|
|
591
628
|
tx: unknown,
|
|
592
|
-
): Pick<BufferedDomainEventRecorder, "entries" | "clear"> {
|
|
629
|
+
): Pick<BufferedDomainEventRecorder, "entries" | "clear" | "flush"> {
|
|
593
630
|
const events =
|
|
594
631
|
tx && typeof tx === "object"
|
|
595
632
|
? (tx as { events?: unknown }).events
|
|
596
633
|
: undefined;
|
|
597
634
|
const recorder = events as
|
|
598
|
-
| Partial<Pick<BufferedDomainEventRecorder, "entries" | "clear">>
|
|
635
|
+
| Partial<Pick<BufferedDomainEventRecorder, "entries" | "clear" | "flush">>
|
|
599
636
|
| undefined;
|
|
600
637
|
if (
|
|
601
638
|
!recorder ||
|
|
602
639
|
typeof recorder.entries !== "function" ||
|
|
603
|
-
typeof recorder.clear !== "function"
|
|
640
|
+
typeof recorder.clear !== "function" ||
|
|
641
|
+
typeof recorder.flush !== "function"
|
|
604
642
|
) {
|
|
605
643
|
throw new Error(
|
|
606
644
|
"createTestPorts transaction.outbox requires tx.events to be a buffered domain event recorder. " +
|
|
@@ -608,7 +646,10 @@ function resolveBufferedTransactionEvents(
|
|
|
608
646
|
);
|
|
609
647
|
}
|
|
610
648
|
|
|
611
|
-
return recorder as Pick<
|
|
649
|
+
return recorder as Pick<
|
|
650
|
+
BufferedDomainEventRecorder,
|
|
651
|
+
"entries" | "clear" | "flush"
|
|
652
|
+
>;
|
|
612
653
|
}
|
|
613
654
|
|
|
614
655
|
/**
|
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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"}
|