@beignet/core 0.0.1
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 +5 -0
- package/README.md +288 -0
- package/dist/application/index.d.ts +260 -0
- package/dist/application/index.d.ts.map +1 -0
- package/dist/application/index.js +324 -0
- package/dist/application/index.js.map +1 -0
- package/dist/client/client.d.ts +241 -0
- package/dist/client/client.d.ts.map +1 -0
- package/dist/client/client.js +531 -0
- package/dist/client/client.js.map +1 -0
- package/dist/client/index.d.ts +10 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +8 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/types.d.ts +139 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +2 -0
- package/dist/client/types.js.map +1 -0
- package/dist/config/index.d.ts +122 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +216 -0
- package/dist/config/index.js.map +1 -0
- package/dist/contracts/contract-builder.d.ts +121 -0
- package/dist/contracts/contract-builder.d.ts.map +1 -0
- package/dist/contracts/contract-builder.js +346 -0
- package/dist/contracts/contract-builder.js.map +1 -0
- package/dist/contracts/contract-group.d.ts +106 -0
- package/dist/contracts/contract-group.d.ts.map +1 -0
- package/dist/contracts/contract-group.js +240 -0
- package/dist/contracts/contract-group.js.map +1 -0
- package/dist/contracts/contract-like.d.ts +21 -0
- package/dist/contracts/contract-like.d.ts.map +1 -0
- package/dist/contracts/contract-like.js +9 -0
- package/dist/contracts/contract-like.js.map +1 -0
- package/dist/contracts/index.d.ts +15 -0
- package/dist/contracts/index.d.ts.map +1 -0
- package/dist/contracts/index.js +11 -0
- package/dist/contracts/index.js.map +1 -0
- package/dist/contracts/openapi-meta.d.ts +23 -0
- package/dist/contracts/openapi-meta.d.ts.map +1 -0
- package/dist/contracts/openapi-meta.js +2 -0
- package/dist/contracts/openapi-meta.js.map +1 -0
- package/dist/contracts/path-template.d.ts +17 -0
- package/dist/contracts/path-template.d.ts.map +1 -0
- package/dist/contracts/path-template.js +50 -0
- package/dist/contracts/path-template.js.map +1 -0
- package/dist/contracts/rate-limit.d.ts +50 -0
- package/dist/contracts/rate-limit.d.ts.map +1 -0
- package/dist/contracts/rate-limit.js +2 -0
- package/dist/contracts/rate-limit.js.map +1 -0
- package/dist/contracts/types.d.ts +97 -0
- package/dist/contracts/types.d.ts.map +1 -0
- package/dist/contracts/types.js +54 -0
- package/dist/contracts/types.js.map +1 -0
- package/dist/contracts/utils.d.ts +3 -0
- package/dist/contracts/utils.d.ts.map +1 -0
- package/dist/contracts/utils.js +44 -0
- package/dist/contracts/utils.js.map +1 -0
- package/dist/domain/entity.d.ts +87 -0
- package/dist/domain/entity.d.ts.map +1 -0
- package/dist/domain/entity.js +155 -0
- package/dist/domain/entity.js.map +1 -0
- package/dist/domain/events.d.ts +41 -0
- package/dist/domain/events.d.ts.map +1 -0
- package/dist/domain/events.js +21 -0
- package/dist/domain/events.js.map +1 -0
- package/dist/domain/index.d.ts +14 -0
- package/dist/domain/index.d.ts.map +1 -0
- package/dist/domain/index.js +14 -0
- package/dist/domain/index.js.map +1 -0
- package/dist/domain/value-object.d.ts +60 -0
- package/dist/domain/value-object.d.ts.map +1 -0
- package/dist/domain/value-object.js +87 -0
- package/dist/domain/value-object.js.map +1 -0
- package/dist/errors/catalog.d.ts +71 -0
- package/dist/errors/catalog.d.ts.map +1 -0
- package/dist/errors/catalog.js +71 -0
- package/dist/errors/catalog.js.map +1 -0
- package/dist/errors/http.d.ts +77 -0
- package/dist/errors/http.d.ts.map +1 -0
- package/dist/errors/http.js +74 -0
- package/dist/errors/http.js.map +1 -0
- package/dist/errors/index.d.ts +10 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +14 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/errors/response.d.ts +26 -0
- package/dist/errors/response.d.ts.map +1 -0
- package/dist/errors/response.js +34 -0
- package/dist/errors/response.js.map +1 -0
- package/dist/errors/validation.d.ts +18 -0
- package/dist/errors/validation.d.ts.map +1 -0
- package/dist/errors/validation.js +21 -0
- package/dist/errors/validation.js.map +1 -0
- package/dist/events/index.d.ts +58 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +102 -0
- package/dist/events/index.js.map +1 -0
- package/dist/jobs/index.d.ts +56 -0
- package/dist/jobs/index.d.ts.map +1 -0
- package/dist/jobs/index.js +89 -0
- package/dist/jobs/index.js.map +1 -0
- package/dist/mail/index.d.ts +75 -0
- package/dist/mail/index.d.ts.map +1 -0
- package/dist/mail/index.js +84 -0
- package/dist/mail/index.js.map +1 -0
- package/dist/openapi/index.d.ts +207 -0
- package/dist/openapi/index.d.ts.map +1 -0
- package/dist/openapi/index.js +449 -0
- package/dist/openapi/index.js.map +1 -0
- package/dist/openapi/schema-introspector.d.ts +38 -0
- package/dist/openapi/schema-introspector.d.ts.map +1 -0
- package/dist/openapi/schema-introspector.js +67 -0
- package/dist/openapi/schema-introspector.js.map +1 -0
- package/dist/ports/audit.d.ts +58 -0
- package/dist/ports/audit.d.ts.map +1 -0
- package/dist/ports/audit.js +74 -0
- package/dist/ports/audit.js.map +1 -0
- package/dist/ports/auth.d.ts +23 -0
- package/dist/ports/auth.d.ts.map +1 -0
- package/dist/ports/auth.js +31 -0
- package/dist/ports/auth.js.map +1 -0
- package/dist/ports/builder.d.ts +61 -0
- package/dist/ports/builder.d.ts.map +1 -0
- package/dist/ports/builder.js +48 -0
- package/dist/ports/builder.js.map +1 -0
- package/dist/ports/cache.d.ts +15 -0
- package/dist/ports/cache.d.ts.map +1 -0
- package/dist/ports/cache.js +57 -0
- package/dist/ports/cache.js.map +1 -0
- package/dist/ports/clock.d.ts +10 -0
- package/dist/ports/clock.d.ts.map +1 -0
- package/dist/ports/clock.js +21 -0
- package/dist/ports/clock.js.map +1 -0
- package/dist/ports/events.d.ts +71 -0
- package/dist/ports/events.d.ts.map +1 -0
- package/dist/ports/events.js +2 -0
- package/dist/ports/events.js.map +1 -0
- package/dist/ports/id-generator.d.ts +12 -0
- package/dist/ports/id-generator.d.ts.map +1 -0
- package/dist/ports/id-generator.js +22 -0
- package/dist/ports/id-generator.js.map +1 -0
- package/dist/ports/index.d.ts +98 -0
- package/dist/ports/index.d.ts.map +1 -0
- package/dist/ports/index.js +67 -0
- package/dist/ports/index.js.map +1 -0
- package/dist/ports/logger.d.ts +22 -0
- package/dist/ports/logger.d.ts.map +1 -0
- package/dist/ports/logger.js +34 -0
- package/dist/ports/logger.js.map +1 -0
- package/dist/ports/mailer.d.ts +6 -0
- package/dist/ports/mailer.d.ts.map +1 -0
- package/dist/ports/mailer.js +2 -0
- package/dist/ports/mailer.js.map +1 -0
- package/dist/ports/policy.d.ts +53 -0
- package/dist/ports/policy.d.ts.map +1 -0
- package/dist/ports/policy.js +81 -0
- package/dist/ports/policy.js.map +1 -0
- package/dist/ports/rate-limit.d.ts +41 -0
- package/dist/ports/rate-limit.d.ts.map +1 -0
- package/dist/ports/rate-limit.js +37 -0
- package/dist/ports/rate-limit.js.map +1 -0
- package/dist/ports/redaction.d.ts +26 -0
- package/dist/ports/redaction.d.ts.map +1 -0
- package/dist/ports/redaction.js +126 -0
- package/dist/ports/redaction.js.map +1 -0
- package/dist/ports/schedules.d.ts +9 -0
- package/dist/ports/schedules.d.ts.map +1 -0
- package/dist/ports/schedules.js +2 -0
- package/dist/ports/schedules.js.map +1 -0
- package/dist/ports/storage.d.ts +47 -0
- package/dist/ports/storage.d.ts.map +1 -0
- package/dist/ports/storage.js +185 -0
- package/dist/ports/storage.js.map +1 -0
- package/dist/ports/testing.d.ts +73 -0
- package/dist/ports/testing.d.ts.map +1 -0
- package/dist/ports/testing.js +105 -0
- package/dist/ports/testing.js.map +1 -0
- package/dist/ports/unit-of-work.d.ts +56 -0
- package/dist/ports/unit-of-work.d.ts.map +1 -0
- package/dist/ports/unit-of-work.js +64 -0
- package/dist/ports/unit-of-work.js.map +1 -0
- package/dist/providers/index.d.ts +8 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +8 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/instrumentation.d.ts +91 -0
- package/dist/providers/instrumentation.d.ts.map +1 -0
- package/dist/providers/instrumentation.js +93 -0
- package/dist/providers/instrumentation.js.map +1 -0
- package/dist/providers/provider.d.ts +146 -0
- package/dist/providers/provider.d.ts.map +1 -0
- package/dist/providers/provider.js +31 -0
- package/dist/providers/provider.js.map +1 -0
- package/dist/schedules/index.d.ts +105 -0
- package/dist/schedules/index.d.ts.map +1 -0
- package/dist/schedules/index.js +178 -0
- package/dist/schedules/index.js.map +1 -0
- package/dist/server/contract-like.d.ts +5 -0
- package/dist/server/contract-like.d.ts.map +1 -0
- package/dist/server/contract-like.js +5 -0
- package/dist/server/contract-like.js.map +1 -0
- package/dist/server/health.d.ts +41 -0
- package/dist/server/health.d.ts.map +1 -0
- package/dist/server/health.js +46 -0
- package/dist/server/health.js.map +1 -0
- package/dist/server/hooks/auth.d.ts +42 -0
- package/dist/server/hooks/auth.d.ts.map +1 -0
- package/dist/server/hooks/auth.js +61 -0
- package/dist/server/hooks/auth.js.map +1 -0
- package/dist/server/hooks/cors.d.ts +13 -0
- package/dist/server/hooks/cors.d.ts.map +1 -0
- package/dist/server/hooks/cors.js +70 -0
- package/dist/server/hooks/cors.js.map +1 -0
- package/dist/server/hooks/errors.d.ts +66 -0
- package/dist/server/hooks/errors.d.ts.map +1 -0
- package/dist/server/hooks/errors.js +83 -0
- package/dist/server/hooks/errors.js.map +1 -0
- package/dist/server/hooks/index.d.ts +12 -0
- package/dist/server/hooks/index.d.ts.map +1 -0
- package/dist/server/hooks/index.js +12 -0
- package/dist/server/hooks/index.js.map +1 -0
- package/dist/server/hooks/logging.d.ts +33 -0
- package/dist/server/hooks/logging.d.ts.map +1 -0
- package/dist/server/hooks/logging.js +90 -0
- package/dist/server/hooks/logging.js.map +1 -0
- package/dist/server/hooks/rate-limit.d.ts +29 -0
- package/dist/server/hooks/rate-limit.d.ts.map +1 -0
- package/dist/server/hooks/rate-limit.js +93 -0
- package/dist/server/hooks/rate-limit.js.map +1 -0
- package/dist/server/hooks/utils.d.ts +9 -0
- package/dist/server/hooks/utils.d.ts.map +1 -0
- package/dist/server/hooks/utils.js +16 -0
- package/dist/server/hooks/utils.js.map +1 -0
- package/dist/server/hooks.d.ts +2 -0
- package/dist/server/hooks.d.ts.map +1 -0
- package/dist/server/hooks.js +2 -0
- package/dist/server/hooks.js.map +1 -0
- package/dist/server/http.d.ts +124 -0
- package/dist/server/http.d.ts.map +1 -0
- package/dist/server/http.js +2 -0
- package/dist/server/http.js.map +1 -0
- package/dist/server/index.d.ts +19 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +15 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/openapi.d.ts +32 -0
- package/dist/server/openapi.d.ts.map +1 -0
- package/dist/server/openapi.js +43 -0
- package/dist/server/openapi.js.map +1 -0
- package/dist/server/providers/index.d.ts +4 -0
- package/dist/server/providers/index.d.ts.map +1 -0
- package/dist/server/providers/index.js +4 -0
- package/dist/server/providers/index.js.map +1 -0
- package/dist/server/providers/loadProviderConfig.d.ts +7 -0
- package/dist/server/providers/loadProviderConfig.d.ts.map +1 -0
- package/dist/server/providers/loadProviderConfig.js +42 -0
- package/dist/server/providers/loadProviderConfig.js.map +1 -0
- package/dist/server/server.d.ts +86 -0
- package/dist/server/server.d.ts.map +1 -0
- package/dist/server/server.js +1031 -0
- package/dist/server/server.js.map +1 -0
- package/dist/server/types.d.ts +3 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/types.js +3 -0
- package/dist/server/types.js.map +1 -0
- package/package.json +129 -0
- package/src/application/index.ts +747 -0
- package/src/client/client.ts +1105 -0
- package/src/client/index.ts +45 -0
- package/src/client/types.ts +305 -0
- package/src/config/index.ts +497 -0
- package/src/contracts/contract-builder.ts +583 -0
- package/src/contracts/contract-group.ts +502 -0
- package/src/contracts/contract-like.ts +29 -0
- package/src/contracts/index.ts +53 -0
- package/src/contracts/openapi-meta.ts +22 -0
- package/src/contracts/path-template.ts +91 -0
- package/src/contracts/rate-limit.ts +50 -0
- package/src/contracts/types.ts +207 -0
- package/src/contracts/utils.ts +56 -0
- package/src/domain/entity.ts +256 -0
- package/src/domain/events.ts +52 -0
- package/src/domain/index.ts +18 -0
- package/src/domain/value-object.ts +135 -0
- package/src/errors/catalog.ts +149 -0
- package/src/errors/http.ts +80 -0
- package/src/errors/index.ts +28 -0
- package/src/errors/response.ts +54 -0
- package/src/errors/validation.ts +35 -0
- package/src/events/index.ts +246 -0
- package/src/jobs/index.ts +211 -0
- package/src/mail/index.ts +177 -0
- package/src/openapi/index.ts +865 -0
- package/src/openapi/schema-introspector.ts +107 -0
- package/src/ports/audit.ts +176 -0
- package/src/ports/auth.ts +76 -0
- package/src/ports/builder.ts +97 -0
- package/src/ports/cache.ts +94 -0
- package/src/ports/clock.ts +34 -0
- package/src/ports/events.ts +100 -0
- package/src/ports/id-generator.ts +36 -0
- package/src/ports/index.ts +221 -0
- package/src/ports/logger.ts +67 -0
- package/src/ports/policy.ts +242 -0
- package/src/ports/rate-limit.ts +91 -0
- package/src/ports/redaction.ts +199 -0
- package/src/ports/storage.ts +282 -0
- package/src/ports/testing.ts +234 -0
- package/src/ports/unit-of-work.ts +134 -0
- package/src/providers/index.ts +40 -0
- package/src/providers/instrumentation.ts +248 -0
- package/src/providers/provider.ts +191 -0
- package/src/schedules/index.ts +442 -0
- package/src/server/contract-like.ts +8 -0
- package/src/server/health.ts +82 -0
- package/src/server/hooks/auth.ts +147 -0
- package/src/server/hooks/cors.ts +87 -0
- package/src/server/hooks/errors.ts +126 -0
- package/src/server/hooks/index.ts +43 -0
- package/src/server/hooks/logging.ts +121 -0
- package/src/server/hooks/rate-limit.ts +171 -0
- package/src/server/hooks/utils.ts +16 -0
- package/src/server/hooks.ts +1 -0
- package/src/server/http.ts +189 -0
- package/src/server/index.ts +35 -0
- package/src/server/openapi.ts +72 -0
- package/src/server/providers/index.ts +3 -0
- package/src/server/providers/loadProviderConfig.ts +72 -0
- package/src/server/server.ts +1521 -0
- package/src/server/types.ts +2 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema introspection adapter.
|
|
3
|
+
*
|
|
4
|
+
* Abstracts the details of reading metadata from a schema library (e.g. Zod)
|
|
5
|
+
* so that the OpenAPI generator is not directly coupled to `_def` internals.
|
|
6
|
+
*
|
|
7
|
+
* A default Zod implementation is provided via `createZodIntrospector()`.
|
|
8
|
+
* To support a different schema library, implement this interface.
|
|
9
|
+
*/
|
|
10
|
+
export interface SchemaIntrospector {
|
|
11
|
+
/**
|
|
12
|
+
* Extract the shape (field name → field schema) from an object schema.
|
|
13
|
+
* Returns undefined if the schema is not an object type or cannot be inspected.
|
|
14
|
+
*/
|
|
15
|
+
getShape(schema: unknown): Record<string, unknown> | undefined;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Extract the user-supplied `.describe()` string from a schema.
|
|
19
|
+
*/
|
|
20
|
+
getDescription(schema: unknown): string | undefined;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Return true if the schema represents an optional wrapper.
|
|
24
|
+
*/
|
|
25
|
+
isOptional(schema: unknown): boolean;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* If the schema is an optional wrapper, return the inner (unwrapped) schema.
|
|
29
|
+
* Otherwise return the original schema unchanged.
|
|
30
|
+
*/
|
|
31
|
+
unwrapOptional(schema: unknown): unknown;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Create a schema introspector for Zod schemas.
|
|
36
|
+
*
|
|
37
|
+
* This accesses Zod's internal `_def` property, which is a common pattern in
|
|
38
|
+
* Zod ecosystem libraries but may break with major Zod updates. Each helper
|
|
39
|
+
* gracefully returns a safe default if the structure is unexpected.
|
|
40
|
+
*/
|
|
41
|
+
export function createZodIntrospector(): SchemaIntrospector {
|
|
42
|
+
return {
|
|
43
|
+
getShape(schema: unknown): Record<string, unknown> | undefined {
|
|
44
|
+
if (!schema || typeof schema !== "object") return undefined;
|
|
45
|
+
|
|
46
|
+
const schemaDef = (schema as Record<string, unknown>)?._def;
|
|
47
|
+
if (!schemaDef || typeof schemaDef !== "object") return undefined;
|
|
48
|
+
|
|
49
|
+
if (!("shape" in schemaDef)) return undefined;
|
|
50
|
+
|
|
51
|
+
let shape: unknown;
|
|
52
|
+
if (typeof schemaDef.shape === "function") {
|
|
53
|
+
shape = schemaDef.shape();
|
|
54
|
+
} else if (typeof schemaDef.shape === "object") {
|
|
55
|
+
shape = schemaDef.shape;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!shape || typeof shape !== "object") return undefined;
|
|
59
|
+
|
|
60
|
+
return shape as Record<string, unknown>;
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
getDescription(schema: unknown): string | undefined {
|
|
64
|
+
if (!schema || typeof schema !== "object") return undefined;
|
|
65
|
+
|
|
66
|
+
const directDescription = (schema as { description?: unknown })
|
|
67
|
+
.description;
|
|
68
|
+
if (typeof directDescription === "string") {
|
|
69
|
+
return directDescription;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const schemaDef = (schema as Record<string, unknown>)?._def;
|
|
73
|
+
if (!schemaDef || typeof schemaDef !== "object") return undefined;
|
|
74
|
+
|
|
75
|
+
const description = (schemaDef as Record<string, unknown>).description;
|
|
76
|
+
return typeof description === "string" ? description : undefined;
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
isOptional(schema: unknown): boolean {
|
|
80
|
+
if (!schema || typeof schema !== "object") return false;
|
|
81
|
+
|
|
82
|
+
const schemaWithOptional = schema as {
|
|
83
|
+
isOptional?: () => boolean;
|
|
84
|
+
};
|
|
85
|
+
if (typeof schemaWithOptional.isOptional === "function") {
|
|
86
|
+
return schemaWithOptional.isOptional();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const schemaDef = (schema as Record<string, unknown>)?._def;
|
|
90
|
+
if (!schemaDef || typeof schemaDef !== "object") return false;
|
|
91
|
+
|
|
92
|
+
const def = schemaDef as Record<string, unknown>;
|
|
93
|
+
return def.typeName === "ZodOptional" || def.type === "optional";
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
unwrapOptional(schema: unknown): unknown {
|
|
97
|
+
const schemaDef = (schema as Record<string, unknown>)?._def;
|
|
98
|
+
const def = schemaDef as Record<string, unknown> | undefined;
|
|
99
|
+
if (def?.typeName !== "ZodOptional" && def?.type !== "optional") {
|
|
100
|
+
return schema;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const innerType = def?.innerType;
|
|
104
|
+
return innerType ?? schema;
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { redactValue } from "./redaction";
|
|
2
|
+
|
|
3
|
+
export type ActivityActorType = "anonymous" | "service" | "system" | "user";
|
|
4
|
+
|
|
5
|
+
export type AuditOutcome = "success" | "failure";
|
|
6
|
+
|
|
7
|
+
export type ActivityMetadataValue =
|
|
8
|
+
| ActivityMetadataValue[]
|
|
9
|
+
| boolean
|
|
10
|
+
| null
|
|
11
|
+
| number
|
|
12
|
+
| string
|
|
13
|
+
| { [key: string]: ActivityMetadataValue | undefined };
|
|
14
|
+
|
|
15
|
+
export type ActivityMetadata = Record<
|
|
16
|
+
string,
|
|
17
|
+
ActivityMetadataValue | undefined
|
|
18
|
+
>;
|
|
19
|
+
|
|
20
|
+
export interface ActivityActor {
|
|
21
|
+
type: ActivityActorType;
|
|
22
|
+
id?: string;
|
|
23
|
+
displayName?: string;
|
|
24
|
+
metadata?: ActivityMetadata;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ActivityTenant {
|
|
28
|
+
id: string;
|
|
29
|
+
slug?: string;
|
|
30
|
+
metadata?: ActivityMetadata;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface ActivityResource {
|
|
34
|
+
type: string;
|
|
35
|
+
id?: string;
|
|
36
|
+
name?: string;
|
|
37
|
+
metadata?: ActivityMetadata;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface AuditLogEntry {
|
|
41
|
+
action: string;
|
|
42
|
+
actor: ActivityActor;
|
|
43
|
+
occurredAt: Date;
|
|
44
|
+
outcome: AuditOutcome;
|
|
45
|
+
metadata?: ActivityMetadata;
|
|
46
|
+
message?: string;
|
|
47
|
+
requestId?: string;
|
|
48
|
+
resource?: ActivityResource;
|
|
49
|
+
tenant?: ActivityTenant;
|
|
50
|
+
traceId?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export type AuditLogEntryInput = Omit<
|
|
54
|
+
AuditLogEntry,
|
|
55
|
+
"occurredAt" | "outcome"
|
|
56
|
+
> & {
|
|
57
|
+
occurredAt?: Date;
|
|
58
|
+
outcome?: AuditOutcome;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export interface AuditLogPort {
|
|
62
|
+
record(entry: AuditLogEntryInput): Promise<void> | void;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface MemoryAuditLogPort extends AuditLogPort {
|
|
66
|
+
entries: AuditLogEntry[];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface AuditLogOptions {
|
|
70
|
+
redact?: (entry: AuditLogEntry) => AuditLogEntry;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function createAnonymousActor(
|
|
74
|
+
options: Omit<ActivityActor, "type"> = {},
|
|
75
|
+
): ActivityActor {
|
|
76
|
+
return { type: "anonymous", ...options };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function createServiceActor(
|
|
80
|
+
id: string,
|
|
81
|
+
options: Omit<ActivityActor, "type" | "id"> = {},
|
|
82
|
+
): ActivityActor {
|
|
83
|
+
return { type: "service", id, ...options };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function createSystemActor(
|
|
87
|
+
id = "system",
|
|
88
|
+
options: Omit<ActivityActor, "type" | "id"> = {},
|
|
89
|
+
): ActivityActor {
|
|
90
|
+
return { type: "system", id, ...options };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function createUserActor(
|
|
94
|
+
id: string,
|
|
95
|
+
options: Omit<ActivityActor, "type" | "id"> = {},
|
|
96
|
+
): ActivityActor {
|
|
97
|
+
return { type: "user", id, ...options };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function createTenant(
|
|
101
|
+
id: string,
|
|
102
|
+
options: Omit<ActivityTenant, "id"> = {},
|
|
103
|
+
): ActivityTenant {
|
|
104
|
+
return { id, ...options };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function normalizeAuditLogEntry(
|
|
108
|
+
entry: AuditLogEntryInput,
|
|
109
|
+
): AuditLogEntry {
|
|
110
|
+
return {
|
|
111
|
+
...entry,
|
|
112
|
+
occurredAt: entry.occurredAt ?? new Date(),
|
|
113
|
+
outcome: entry.outcome ?? "success",
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function redactAuditLogEntry(entry: AuditLogEntry): AuditLogEntry {
|
|
118
|
+
return {
|
|
119
|
+
...entry,
|
|
120
|
+
actor: {
|
|
121
|
+
...entry.actor,
|
|
122
|
+
metadata: entry.actor.metadata
|
|
123
|
+
? redactValue(entry.actor.metadata)
|
|
124
|
+
: entry.actor.metadata,
|
|
125
|
+
},
|
|
126
|
+
tenant: entry.tenant
|
|
127
|
+
? {
|
|
128
|
+
...entry.tenant,
|
|
129
|
+
metadata: entry.tenant.metadata
|
|
130
|
+
? redactValue(entry.tenant.metadata)
|
|
131
|
+
: entry.tenant.metadata,
|
|
132
|
+
}
|
|
133
|
+
: entry.tenant,
|
|
134
|
+
resource: entry.resource
|
|
135
|
+
? {
|
|
136
|
+
...entry.resource,
|
|
137
|
+
metadata: entry.resource.metadata
|
|
138
|
+
? redactValue(entry.resource.metadata)
|
|
139
|
+
: entry.resource.metadata,
|
|
140
|
+
}
|
|
141
|
+
: entry.resource,
|
|
142
|
+
metadata: entry.metadata ? redactValue(entry.metadata) : entry.metadata,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function createRedactedAuditLog(
|
|
147
|
+
audit: AuditLogPort,
|
|
148
|
+
options: AuditLogOptions = {},
|
|
149
|
+
): AuditLogPort {
|
|
150
|
+
return {
|
|
151
|
+
record(entry) {
|
|
152
|
+
const normalized = normalizeAuditLogEntry(entry);
|
|
153
|
+
const redacted = options.redact
|
|
154
|
+
? options.redact(redactAuditLogEntry(normalized))
|
|
155
|
+
: redactAuditLogEntry(normalized);
|
|
156
|
+
return audit.record(redacted);
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function createMemoryAuditLog(
|
|
162
|
+
entries: AuditLogEntry[] = [],
|
|
163
|
+
options: AuditLogOptions = {},
|
|
164
|
+
): MemoryAuditLogPort {
|
|
165
|
+
return {
|
|
166
|
+
entries,
|
|
167
|
+
record(entry) {
|
|
168
|
+
const normalized = normalizeAuditLogEntry(entry);
|
|
169
|
+
entries.push(
|
|
170
|
+
options.redact
|
|
171
|
+
? options.redact(redactAuditLogEntry(normalized))
|
|
172
|
+
: redactAuditLogEntry(normalized),
|
|
173
|
+
);
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export interface AuthRequestLike {
|
|
2
|
+
headers: Headers;
|
|
3
|
+
raw?: Request;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface AuthSession<User = unknown, Session = unknown> {
|
|
7
|
+
user: User;
|
|
8
|
+
session?: Session;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class AuthUnauthorizedError extends Error {
|
|
12
|
+
readonly code = "UNAUTHORIZED";
|
|
13
|
+
|
|
14
|
+
constructor(message = "Unauthorized") {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = "AuthUnauthorizedError";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface AuthPort<
|
|
21
|
+
User = unknown,
|
|
22
|
+
Session = unknown,
|
|
23
|
+
RequestLike extends AuthRequestLike = AuthRequestLike,
|
|
24
|
+
> {
|
|
25
|
+
getSession(req: RequestLike): Promise<AuthSession<User, Session> | null>;
|
|
26
|
+
getUser(req: RequestLike): Promise<User | null>;
|
|
27
|
+
requireUser(req: RequestLike): Promise<User>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
31
|
+
|
|
32
|
+
export type StaticAuthSessionFactory<
|
|
33
|
+
User,
|
|
34
|
+
Session,
|
|
35
|
+
RequestLike extends AuthRequestLike,
|
|
36
|
+
> = (req: RequestLike) => MaybePromise<AuthSession<User, Session> | null>;
|
|
37
|
+
|
|
38
|
+
export function createStaticAuth<
|
|
39
|
+
User,
|
|
40
|
+
Session = unknown,
|
|
41
|
+
RequestLike extends AuthRequestLike = AuthRequestLike,
|
|
42
|
+
>(
|
|
43
|
+
session:
|
|
44
|
+
| AuthSession<User, Session>
|
|
45
|
+
| null
|
|
46
|
+
| StaticAuthSessionFactory<User, Session, RequestLike>,
|
|
47
|
+
): AuthPort<User, Session, RequestLike> {
|
|
48
|
+
async function resolveSession(req: RequestLike) {
|
|
49
|
+
return typeof session === "function" ? session(req) : session;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
async getSession(req) {
|
|
54
|
+
return resolveSession(req);
|
|
55
|
+
},
|
|
56
|
+
async getUser(req) {
|
|
57
|
+
return (await resolveSession(req))?.user ?? null;
|
|
58
|
+
},
|
|
59
|
+
async requireUser(req) {
|
|
60
|
+
const user = (await resolveSession(req))?.user ?? null;
|
|
61
|
+
if (!user) {
|
|
62
|
+
throw new AuthUnauthorizedError();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return user;
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function createAnonymousAuth<
|
|
71
|
+
User = unknown,
|
|
72
|
+
Session = unknown,
|
|
73
|
+
RequestLike extends AuthRequestLike = AuthRequestLike,
|
|
74
|
+
>(): AuthPort<User, Session, RequestLike> {
|
|
75
|
+
return createStaticAuth<User, Session, RequestLike>(null);
|
|
76
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PortsBuilder - Mutable builder for composing ports during app initialization
|
|
3
|
+
*
|
|
4
|
+
* This builder is a small composition helper for tests and custom bootstrapping
|
|
5
|
+
* code that wants to assemble ports incrementally.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A mutable builder around a ports object.
|
|
10
|
+
* Used during app composition and provider registration.
|
|
11
|
+
*/
|
|
12
|
+
export interface PortsBuilder<Ports> {
|
|
13
|
+
/**
|
|
14
|
+
* The current ports object being built.
|
|
15
|
+
* This is mutated internally when extend/replace are called.
|
|
16
|
+
*/
|
|
17
|
+
ports: Ports;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Extend ports with a new key. If the key already exists, it's overwritten.
|
|
21
|
+
*
|
|
22
|
+
* Returns the same builder instance with an extended type:
|
|
23
|
+
* Ports & { [K in key]: Value }
|
|
24
|
+
*/
|
|
25
|
+
extend<K extends string, V>(
|
|
26
|
+
key: K,
|
|
27
|
+
value: V,
|
|
28
|
+
): PortsBuilder<Ports & { [P in K]: V }>;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Replace an existing key. Does not change the type, but updates the runtime value.
|
|
32
|
+
* Returns the same builder instance.
|
|
33
|
+
*/
|
|
34
|
+
replace<K extends keyof Ports>(key: K, value: Ports[K]): PortsBuilder<Ports>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Create a new PortsBuilder from an initial ports object.
|
|
39
|
+
*
|
|
40
|
+
* The builder wraps a mutable object internally and provides type-safe methods
|
|
41
|
+
* to extend or replace ports. This is used during application composition
|
|
42
|
+
* helpers that want to modify ports before passing them to a server.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* const initialPorts = definePorts({ db: dbAdapter });
|
|
47
|
+
* const builder = createPortsBuilder(initialPorts);
|
|
48
|
+
*
|
|
49
|
+
* // Provider extends with cache
|
|
50
|
+
* builder.extend("cache", cacheAdapter);
|
|
51
|
+
*
|
|
52
|
+
* // Final ports includes both db and cache
|
|
53
|
+
* const finalPorts = builder.ports;
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export function createPortsBuilder<Ports>(
|
|
57
|
+
initialPorts: Ports,
|
|
58
|
+
): PortsBuilder<Ports> {
|
|
59
|
+
// Keep a mutable object internally
|
|
60
|
+
// biome-ignore lint/suspicious/noExplicitAny: internal mutable state needs any to accept arbitrary port extensions
|
|
61
|
+
const state: { ports: any } = {
|
|
62
|
+
ports: { ...initialPorts },
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const builder: PortsBuilder<Ports> = {
|
|
66
|
+
get ports() {
|
|
67
|
+
// Could freeze in dev, but keep simple
|
|
68
|
+
return state.ports as Ports;
|
|
69
|
+
},
|
|
70
|
+
extend<K extends string, V>(
|
|
71
|
+
key: K,
|
|
72
|
+
value: V,
|
|
73
|
+
): PortsBuilder<Ports & { [P in K]: V }> {
|
|
74
|
+
state.ports[key] = value;
|
|
75
|
+
return builder as unknown as PortsBuilder<Ports & { [P in K]: V }>;
|
|
76
|
+
},
|
|
77
|
+
replace<K extends keyof Ports>(
|
|
78
|
+
key: K,
|
|
79
|
+
value: Ports[K],
|
|
80
|
+
): PortsBuilder<Ports> {
|
|
81
|
+
state.ports[key] = value;
|
|
82
|
+
return builder;
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
return builder;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Extract the Ports type from a PortsBuilder
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```ts
|
|
94
|
+
* type MyPorts = PortsOf<typeof builder>;
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
export type PortsOf<PB> = PB extends PortsBuilder<infer P> ? P : never;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
export interface CacheSetOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Time-to-live in seconds. Omit this for a value that does not expire.
|
|
4
|
+
*/
|
|
5
|
+
ttlSeconds?: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface CachePort {
|
|
9
|
+
get(key: string): Promise<string | null>;
|
|
10
|
+
set(key: string, value: string, options?: CacheSetOptions): Promise<void>;
|
|
11
|
+
delete(key: string): Promise<boolean>;
|
|
12
|
+
has(key: string): Promise<boolean>;
|
|
13
|
+
remember(
|
|
14
|
+
key: string,
|
|
15
|
+
factory: () => Promise<string>,
|
|
16
|
+
options?: CacheSetOptions,
|
|
17
|
+
): Promise<string>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type MemoryCacheEntry = {
|
|
21
|
+
value: string;
|
|
22
|
+
expiresAt: number | null;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
function resolveExpiresAt(options: CacheSetOptions | undefined): number | null {
|
|
26
|
+
if (options?.ttlSeconds == null) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (options.ttlSeconds <= 0) {
|
|
31
|
+
return Date.now();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return Date.now() + options.ttlSeconds * 1000;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function isExpired(entry: MemoryCacheEntry): boolean {
|
|
38
|
+
return entry.expiresAt != null && entry.expiresAt <= Date.now();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function createMemoryCache(
|
|
42
|
+
initialValues: Record<string, string> = {},
|
|
43
|
+
): CachePort {
|
|
44
|
+
const values = new Map<string, MemoryCacheEntry>(
|
|
45
|
+
Object.entries(initialValues).map(([key, value]) => [
|
|
46
|
+
key,
|
|
47
|
+
{ value, expiresAt: null },
|
|
48
|
+
]),
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
async function getFreshEntry(key: string): Promise<MemoryCacheEntry | null> {
|
|
52
|
+
const entry = values.get(key);
|
|
53
|
+
if (!entry) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (isExpired(entry)) {
|
|
58
|
+
values.delete(key);
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return entry;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const cache: CachePort = {
|
|
66
|
+
async get(key) {
|
|
67
|
+
return (await getFreshEntry(key))?.value ?? null;
|
|
68
|
+
},
|
|
69
|
+
async set(key, value, options) {
|
|
70
|
+
values.set(key, {
|
|
71
|
+
value,
|
|
72
|
+
expiresAt: resolveExpiresAt(options),
|
|
73
|
+
});
|
|
74
|
+
},
|
|
75
|
+
async delete(key) {
|
|
76
|
+
return values.delete(key);
|
|
77
|
+
},
|
|
78
|
+
async has(key) {
|
|
79
|
+
return (await getFreshEntry(key)) != null;
|
|
80
|
+
},
|
|
81
|
+
async remember(key, factory, options) {
|
|
82
|
+
const cached = await cache.get(key);
|
|
83
|
+
if (cached != null) {
|
|
84
|
+
return cached;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const value = await factory();
|
|
88
|
+
await cache.set(key, value, options);
|
|
89
|
+
return value;
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
return cache;
|
|
94
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export interface ClockPort {
|
|
2
|
+
now(): Date;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export interface FrozenClockPort extends ClockPort {
|
|
6
|
+
setNow(value: Date | string | number): void;
|
|
7
|
+
advance(milliseconds: number): void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function toDate(value: Date | string | number): Date {
|
|
11
|
+
return value instanceof Date ? new Date(value.getTime()) : new Date(value);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function createSystemClock(): ClockPort {
|
|
15
|
+
return {
|
|
16
|
+
now: () => new Date(),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function createFrozenClock(
|
|
21
|
+
initial: Date | string | number = new Date(0),
|
|
22
|
+
): FrozenClockPort {
|
|
23
|
+
let current = toDate(initial);
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
now: () => new Date(current.getTime()),
|
|
27
|
+
setNow: (value) => {
|
|
28
|
+
current = toDate(value);
|
|
29
|
+
},
|
|
30
|
+
advance: (milliseconds) => {
|
|
31
|
+
current = new Date(current.getTime() + milliseconds);
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
EventPayloadDef,
|
|
3
|
+
InferEventPayload as InferContractEventPayload,
|
|
4
|
+
StandardSchema,
|
|
5
|
+
} from "../events";
|
|
6
|
+
import type {
|
|
7
|
+
JobDef as ContractJobDef,
|
|
8
|
+
InferJobPayload as InferContractJobPayload,
|
|
9
|
+
} from "../jobs";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Represents a defined Domain Event with name and payload schema.
|
|
13
|
+
* This is a minimal interface that ports need - implementations can use
|
|
14
|
+
* the full DomainEventDef from @beignet/core/domain if desired.
|
|
15
|
+
*/
|
|
16
|
+
export interface DomainEventDef<
|
|
17
|
+
Name extends string = string,
|
|
18
|
+
Payload extends StandardSchema = StandardSchema,
|
|
19
|
+
> extends EventPayloadDef<Name, Payload> {}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Infer the payload type from a DomainEventDef.
|
|
23
|
+
*/
|
|
24
|
+
export type InferEventPayload<E extends DomainEventDef> =
|
|
25
|
+
InferContractEventPayload<E>;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Represents a job definition with a typed payload schema.
|
|
29
|
+
*
|
|
30
|
+
* Job dispatchers use Beignet's first-class job definitions. Inline
|
|
31
|
+
* dispatchers can run the handler directly;
|
|
32
|
+
* durable dispatchers can ignore it and enqueue the job name plus parsed
|
|
33
|
+
* payload.
|
|
34
|
+
*/
|
|
35
|
+
export type JobDef<
|
|
36
|
+
Name extends string = string,
|
|
37
|
+
Payload extends StandardSchema = StandardSchema,
|
|
38
|
+
Ctx = unknown,
|
|
39
|
+
> = ContractJobDef<Name, Payload, Ctx>;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Infer the payload type from a JobDef.
|
|
43
|
+
*/
|
|
44
|
+
export type InferJobPayload<J extends JobDef> = InferContractJobPayload<J>;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* An EventBus port for publishing and subscribing to domain events.
|
|
48
|
+
*
|
|
49
|
+
* This interface defines a framework-agnostic contract for event-driven
|
|
50
|
+
* communication within your application.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* import { createInMemoryEventBus } from "@beignet/provider-event-bus-memory";
|
|
55
|
+
*
|
|
56
|
+
* const eventBus = createInMemoryEventBus();
|
|
57
|
+
*
|
|
58
|
+
* // Subscribe to an event
|
|
59
|
+
* const unsubscribe = eventBus.subscribe(UserRegistered, (payload) => {
|
|
60
|
+
* console.log(`User registered: ${payload.email}`);
|
|
61
|
+
* });
|
|
62
|
+
*
|
|
63
|
+
* // Publish an event
|
|
64
|
+
* await eventBus.publish(UserRegistered, { userId: "123", email: "test@example.com" });
|
|
65
|
+
*
|
|
66
|
+
* // Unsubscribe when done
|
|
67
|
+
* unsubscribe();
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export interface EventBusPort {
|
|
71
|
+
/**
|
|
72
|
+
* Publish a domain event with a typed payload.
|
|
73
|
+
*/
|
|
74
|
+
publish<E extends DomainEventDef>(
|
|
75
|
+
event: E,
|
|
76
|
+
payload: InferEventPayload<E>,
|
|
77
|
+
): Promise<void> | void;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Subscribe to a domain event. Returns an unsubscribe function.
|
|
81
|
+
*/
|
|
82
|
+
subscribe<E extends DomainEventDef>(
|
|
83
|
+
event: E,
|
|
84
|
+
handler: (payload: InferEventPayload<E>) => Promise<void> | void,
|
|
85
|
+
): () => void;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* A port for dispatching explicit background jobs.
|
|
90
|
+
*
|
|
91
|
+
* Jobs represent work to do, not facts that happened. Implementations may run
|
|
92
|
+
* inline in tests, enqueue into a durable worker, or call an external job
|
|
93
|
+
* system.
|
|
94
|
+
*/
|
|
95
|
+
export interface JobDispatcherPort {
|
|
96
|
+
dispatch<J extends JobDef>(
|
|
97
|
+
job: J,
|
|
98
|
+
payload: InferJobPayload<J>,
|
|
99
|
+
): Promise<void> | void;
|
|
100
|
+
}
|