@beignet/core 0.0.50 → 0.0.52
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 +24 -0
- package/README.md +99 -32
- package/dist/application/index.d.ts +5 -5
- package/dist/application/index.d.ts.map +1 -1
- package/dist/application/index.js +8 -4
- package/dist/application/index.js.map +1 -1
- package/dist/events/index.d.ts +26 -2
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +84 -7
- package/dist/events/index.js.map +1 -1
- package/dist/events/payload-state.d.ts +16 -0
- package/dist/events/payload-state.d.ts.map +1 -0
- package/dist/events/payload-state.js +123 -0
- package/dist/events/payload-state.js.map +1 -0
- package/dist/events/transport.d.ts +25 -0
- package/dist/events/transport.d.ts.map +1 -0
- package/dist/events/transport.js +192 -0
- package/dist/events/transport.js.map +1 -0
- 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/openapi/index.d.ts.map +1 -1
- package/dist/openapi/index.js +27 -4
- package/dist/openapi/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 -155
- 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/events.d.ts +4 -1
- package/dist/ports/events.d.ts.map +1 -1
- package/dist/ports/index.d.ts +1 -1
- package/dist/ports/index.d.ts.map +1 -1
- package/dist/ports/index.js.map +1 -1
- package/dist/ports/storage.d.ts +7 -0
- package/dist/ports/storage.d.ts.map +1 -1
- package/dist/ports/storage.js +4 -0
- package/dist/ports/storage.js.map +1 -1
- package/dist/ports/testing.d.ts +16 -2
- package/dist/ports/testing.d.ts.map +1 -1
- package/dist/ports/testing.js +19 -4
- 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 -7
- 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 +0 -38
- 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 +2 -6
- package/dist/search/index.js.map +1 -1
- package/dist/server/hooks/cors.d.ts +5 -0
- package/dist/server/hooks/cors.d.ts.map +1 -1
- package/dist/server/hooks/cors.js +29 -1
- package/dist/server/hooks/cors.js.map +1 -1
- package/dist/server/instrumentation.d.ts +5 -5
- package/dist/server/instrumentation.d.ts.map +1 -1
- package/dist/server/instrumentation.js +3 -4
- package/dist/server/instrumentation.js.map +1 -1
- package/dist/server/response-finalization.d.ts.map +1 -1
- package/dist/server/response-finalization.js +25 -13
- package/dist/server/response-finalization.js.map +1 -1
- package/dist/server/server.d.ts +8 -5
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +35 -12
- package/dist/server/server.js.map +1 -1
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +12 -6
- package/dist/testing/index.js.map +1 -1
- package/dist/uploads/index.d.ts.map +1 -1
- package/dist/uploads/index.js +37 -16
- package/dist/uploads/index.js.map +1 -1
- package/package.json +2 -2
- package/skills/app-architecture/SKILL.md +16 -0
- package/src/application/index.ts +39 -7
- package/src/events/index.ts +137 -7
- package/src/events/payload-state.ts +223 -0
- package/src/events/transport.ts +242 -0
- package/src/locks/index.ts +0 -4
- package/src/openapi/index.ts +41 -3
- package/src/outbox/index.ts +1393 -178
- package/src/payments/index.ts +0 -4
- package/src/ports/events.ts +4 -1
- package/src/ports/index.ts +3 -0
- package/src/ports/storage.ts +10 -0
- package/src/ports/testing.ts +42 -4
- package/src/ports/unit-of-work.ts +33 -15
- package/src/providers/index.ts +0 -1
- package/src/providers/provider.ts +0 -40
- package/src/search/index.ts +2 -6
- package/src/server/hooks/cors.ts +42 -0
- package/src/server/instrumentation.ts +10 -8
- package/src/server/response-finalization.ts +33 -15
- package/src/server/server.ts +61 -27
- package/src/testing/index.ts +20 -9
- package/src/uploads/index.ts +34 -16
package/src/server/server.ts
CHANGED
|
@@ -204,15 +204,18 @@ export type CreateServerOptions<
|
|
|
204
204
|
* `ports.devtools`) when one is installed.
|
|
205
205
|
*
|
|
206
206
|
* Pass `false` to disable headers and event recording. Context factories
|
|
207
|
-
* still receive `requestId` and `trace` arguments
|
|
207
|
+
* still receive `requestId` and `trace` arguments, and request-scoped
|
|
208
|
+
* correlation remains available to ambient audit wrappers.
|
|
208
209
|
*/
|
|
209
210
|
instrumentation?: ServerInstrumentationOptions<Ctx> | false;
|
|
210
211
|
/**
|
|
211
|
-
* Whether route-owned responses are
|
|
212
|
-
*
|
|
212
|
+
* Whether route-owned responses are parsed against the contract's declared
|
|
213
|
+
* statuses and response schemas before they are sent. The parsed schema
|
|
214
|
+
* output becomes the response body.
|
|
213
215
|
*
|
|
214
|
-
* Disable this to
|
|
215
|
-
* client-side
|
|
216
|
+
* Disable this to send route-owned handler bodies as-is without validation,
|
|
217
|
+
* unknown-key stripping, or transforms, mirroring the client-side
|
|
218
|
+
* `validateResponses` option.
|
|
216
219
|
*
|
|
217
220
|
* @default true
|
|
218
221
|
*/
|
|
@@ -407,9 +410,7 @@ export async function createServer<
|
|
|
407
410
|
options.instrumentation,
|
|
408
411
|
);
|
|
409
412
|
const hooks = [
|
|
410
|
-
|
|
411
|
-
? [instrumentation.hook as ServerHook<Ctx, FinalPorts>]
|
|
412
|
-
: []),
|
|
413
|
+
instrumentation.hook as ServerHook<Ctx, FinalPorts>,
|
|
413
414
|
...((options.hooks ?? []) as ServerHook<Ctx, FinalPorts>[]),
|
|
414
415
|
];
|
|
415
416
|
const contracts = options.routes ? contractsFromRoutes(options.routes) : [];
|
|
@@ -669,24 +670,6 @@ export async function createServer<
|
|
|
669
670
|
registryNeedsSort = true;
|
|
670
671
|
};
|
|
671
672
|
|
|
672
|
-
const createBuilder = <C extends HttpContractConfig>(
|
|
673
|
-
contract: C,
|
|
674
|
-
shouldRegister: boolean,
|
|
675
|
-
): RouteBuilder<Ctx, C> => ({
|
|
676
|
-
handle: (fn) => {
|
|
677
|
-
const wrapped = buildHandler(
|
|
678
|
-
options,
|
|
679
|
-
finalPorts,
|
|
680
|
-
contextRuntime,
|
|
681
|
-
contract,
|
|
682
|
-
fn,
|
|
683
|
-
hooks,
|
|
684
|
-
);
|
|
685
|
-
if (shouldRegister) registerRoute(contract, fn);
|
|
686
|
-
return wrapped;
|
|
687
|
-
},
|
|
688
|
-
});
|
|
689
|
-
|
|
690
673
|
if (options.routes) {
|
|
691
674
|
try {
|
|
692
675
|
for (const route of options.routes) {
|
|
@@ -917,7 +900,58 @@ export async function createServer<
|
|
|
917
900
|
api,
|
|
918
901
|
route: (contractLike) => {
|
|
919
902
|
const contract = resolveContract(contractLike);
|
|
920
|
-
return
|
|
903
|
+
return {
|
|
904
|
+
handle: (fn) => {
|
|
905
|
+
const wrapped = buildHandler(
|
|
906
|
+
options,
|
|
907
|
+
finalPorts,
|
|
908
|
+
contextRuntime,
|
|
909
|
+
contract,
|
|
910
|
+
fn,
|
|
911
|
+
hooks,
|
|
912
|
+
);
|
|
913
|
+
registerRoute(contract, fn);
|
|
914
|
+
const compiled = compilePath(contract.path);
|
|
915
|
+
|
|
916
|
+
return async (req: HttpRequestLike) => {
|
|
917
|
+
const method = req.method.toUpperCase();
|
|
918
|
+
let url: URL;
|
|
919
|
+
try {
|
|
920
|
+
url = parseHttpRequestUrl(req.url);
|
|
921
|
+
} catch (error) {
|
|
922
|
+
return await executeFallback(
|
|
923
|
+
{
|
|
924
|
+
contract: fallbackContract("invalidRequestUrl", method, "/"),
|
|
925
|
+
handler: async () => {
|
|
926
|
+
throw error;
|
|
927
|
+
},
|
|
928
|
+
},
|
|
929
|
+
req,
|
|
930
|
+
{},
|
|
931
|
+
);
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
const requestMethod = method;
|
|
935
|
+
const contractMethod = contract.method.toUpperCase();
|
|
936
|
+
const methodMatches =
|
|
937
|
+
requestMethod === contractMethod ||
|
|
938
|
+
(requestMethod === "HEAD" && contractMethod === "GET");
|
|
939
|
+
if (!methodMatches || !compiled.pattern.test(url.pathname)) {
|
|
940
|
+
const pathname = url.pathname || "/";
|
|
941
|
+
return await executeFallback(
|
|
942
|
+
{
|
|
943
|
+
contract: fallbackContract("notFound", method, pathname),
|
|
944
|
+
handler: notFoundHandler,
|
|
945
|
+
},
|
|
946
|
+
req,
|
|
947
|
+
{},
|
|
948
|
+
);
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
return await wrapped(req);
|
|
952
|
+
};
|
|
953
|
+
},
|
|
954
|
+
};
|
|
921
955
|
},
|
|
922
956
|
rawRoute: (init) => ({
|
|
923
957
|
handle: (fn) => {
|
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 {
|
|
@@ -489,10 +489,17 @@ export function createTestPorts<
|
|
|
489
489
|
outbox: MemoryOutboxPort;
|
|
490
490
|
}
|
|
491
491
|
).outbox;
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
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
|
+
});
|
|
496
503
|
}
|
|
497
504
|
await transactionOptions?.afterCommit?.(tx);
|
|
498
505
|
},
|
|
@@ -619,18 +626,19 @@ function completeTestPortOverrides<Ports extends AnyPorts>(
|
|
|
619
626
|
|
|
620
627
|
function resolveBufferedTransactionEvents(
|
|
621
628
|
tx: unknown,
|
|
622
|
-
): Pick<BufferedDomainEventRecorder, "entries" | "clear"> {
|
|
629
|
+
): Pick<BufferedDomainEventRecorder, "entries" | "clear" | "flush"> {
|
|
623
630
|
const events =
|
|
624
631
|
tx && typeof tx === "object"
|
|
625
632
|
? (tx as { events?: unknown }).events
|
|
626
633
|
: undefined;
|
|
627
634
|
const recorder = events as
|
|
628
|
-
| Partial<Pick<BufferedDomainEventRecorder, "entries" | "clear">>
|
|
635
|
+
| Partial<Pick<BufferedDomainEventRecorder, "entries" | "clear" | "flush">>
|
|
629
636
|
| undefined;
|
|
630
637
|
if (
|
|
631
638
|
!recorder ||
|
|
632
639
|
typeof recorder.entries !== "function" ||
|
|
633
|
-
typeof recorder.clear !== "function"
|
|
640
|
+
typeof recorder.clear !== "function" ||
|
|
641
|
+
typeof recorder.flush !== "function"
|
|
634
642
|
) {
|
|
635
643
|
throw new Error(
|
|
636
644
|
"createTestPorts transaction.outbox requires tx.events to be a buffered domain event recorder. " +
|
|
@@ -638,7 +646,10 @@ function resolveBufferedTransactionEvents(
|
|
|
638
646
|
);
|
|
639
647
|
}
|
|
640
648
|
|
|
641
|
-
return recorder as Pick<
|
|
649
|
+
return recorder as Pick<
|
|
650
|
+
BufferedDomainEventRecorder,
|
|
651
|
+
"entries" | "clear" | "flush"
|
|
652
|
+
>;
|
|
642
653
|
}
|
|
643
654
|
|
|
644
655
|
/**
|
package/src/uploads/index.ts
CHANGED
|
@@ -968,29 +968,47 @@ export function createUploadRouter<Ctx>(
|
|
|
968
968
|
},
|
|
969
969
|
});
|
|
970
970
|
}
|
|
971
|
-
const
|
|
971
|
+
const verifyBody = needsUploadBodyVerification(upload, file);
|
|
972
|
+
const objectBody = verifyBody
|
|
972
973
|
? await options.storage.get(file.key)
|
|
974
|
+
: null;
|
|
975
|
+
const object = verifyBody
|
|
976
|
+
? objectBody
|
|
973
977
|
: await options.storage.stat(file.key);
|
|
974
978
|
if (!object) {
|
|
975
979
|
throw new UploadObjectNotFoundError({
|
|
976
980
|
message: `Uploaded object "${file.key}" was not found.`,
|
|
977
981
|
});
|
|
978
982
|
}
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
983
|
+
let operationFailed = false;
|
|
984
|
+
try {
|
|
985
|
+
assertStoredObject(upload, file, object);
|
|
986
|
+
const verified = await verifyStoredUploadFile(upload, file, object);
|
|
987
|
+
const completedObject = storageObjectMetadata(object);
|
|
988
|
+
const completedFile = {
|
|
989
|
+
...file,
|
|
990
|
+
...(verified.checksum ? { checksum: verified.checksum } : {}),
|
|
991
|
+
object: completedObject,
|
|
992
|
+
};
|
|
993
|
+
await assertVerifiedFile(upload, {
|
|
994
|
+
ctx,
|
|
995
|
+
metadata,
|
|
996
|
+
file: completedFile,
|
|
997
|
+
storage: options.storage,
|
|
998
|
+
});
|
|
999
|
+
files.push(completedFile);
|
|
1000
|
+
} catch (error) {
|
|
1001
|
+
operationFailed = true;
|
|
1002
|
+
throw error;
|
|
1003
|
+
} finally {
|
|
1004
|
+
if (objectBody && !objectBody.bodyUsed) {
|
|
1005
|
+
if (operationFailed) {
|
|
1006
|
+
await objectBody.cancel().catch(() => undefined);
|
|
1007
|
+
} else {
|
|
1008
|
+
await objectBody.cancel();
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
994
1012
|
}
|
|
995
1013
|
|
|
996
1014
|
const result = await upload.onComplete?.({ ctx, metadata, files });
|