@cullet/erp-core 1.0.10 → 1.1.0
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/KIT_CONTEXT.md +67 -0
- package/README.md +128 -1
- package/dist/app-error.d.ts +108 -0
- package/dist/application/index.d.ts +2 -0
- package/dist/application/index.js +2 -0
- package/dist/errors/index.d.ts +2 -1
- package/dist/errors/index.js +4 -2
- package/dist/gate-engine-registry.d.ts +80 -0
- package/dist/gate-v1-payload.schema.js +2 -28
- package/dist/gate-v1-payload.schema.js.map +1 -1
- package/dist/hashing.js +49 -0
- package/dist/hashing.js.map +1 -0
- package/dist/index.d.ts +122 -45
- package/dist/index.js +104 -85
- package/dist/index.js.map +1 -1
- package/dist/not-found-error.js +54 -0
- package/dist/not-found-error.js.map +1 -0
- package/dist/outcome.js +1 -1
- package/dist/parse-gate-payload.d.ts +3 -78
- package/dist/path.d.ts +89 -0
- package/dist/policies/engines/index.d.ts +2 -1
- package/dist/policies/index.d.ts +4 -2
- package/dist/policy-service.d.ts +102 -86
- package/dist/policy-service.js +78 -16
- package/dist/policy-service.js.map +1 -1
- package/dist/temporal-guards.js +30 -0
- package/dist/temporal-guards.js.map +1 -0
- package/dist/temporal-use-case.d.ts +309 -0
- package/dist/temporal-use-case.js +284 -0
- package/dist/temporal-use-case.js.map +1 -0
- package/dist/validation-code.js +34 -47
- package/dist/validation-code.js.map +1 -1
- package/dist/validation-error.d.ts +171 -74
- package/dist/validation-error.js +152 -38
- package/dist/validation-error.js.map +1 -1
- package/dist/validation-exception.js +18 -0
- package/dist/validation-exception.js.map +1 -0
- package/meta.json +4 -2
- package/package.json +5 -1
- package/src/application/index.ts +1 -0
- package/src/core/application/commands/index.ts +1 -0
- package/src/core/application/index.ts +12 -3
- package/src/core/application/ports/index.ts +2 -2
- package/src/core/application/ports/policy-port.ts +13 -3
- package/src/core/application/ports/repository.port.ts +37 -1
- package/src/core/application/temporal/temporal-use-case.ts +14 -2
- package/src/core/application/use-case.ts +133 -2
- package/src/core/domain/entity.ts +71 -0
- package/src/core/domain/value-object.ts +41 -0
- package/src/core/errors/app-error.ts +33 -0
- package/src/core/errors/authorization-error.ts +43 -0
- package/src/core/errors/conflict-error.ts +69 -0
- package/src/core/errors/integration-error.ts +25 -0
- package/src/core/errors/not-found-error.ts +14 -0
- package/src/core/errors/validation-error.ts +18 -0
- package/src/core/index.ts +1 -10
- package/src/core/policies/catalog/policy-catalog.ts +36 -0
- package/src/core/policies/resolver/policy-resolver.ts +10 -0
- package/src/core/policies/service/policy-service.ts +53 -0
- package/src/examples/application/cancel-order.example.ts +124 -0
- package/src/examples/application/in-memory-account-repository.example.ts +73 -0
- package/src/version.ts +1 -1
package/KIT_CONTEXT.md
CHANGED
|
@@ -23,6 +23,73 @@ Núcleo arquitetural para sistemas ERP (e domínios transacionais com temporalid
|
|
|
23
23
|
- **Policies permitem disable sem remover código**: `PolicyDefinition` aceita `enabled: false` e o repositório ignora definições desabilitadas.
|
|
24
24
|
- **Composição isolada é de primeira classe**: use `new CoreConfig()`, `new ContextResolverRegistry()` e `registerNamespacedContextResolversIn(...)` quando precisar evitar singletons compartilhados.
|
|
25
25
|
|
|
26
|
+
## [example] Exemplo end-to-end (Command + Repository + PolicyPort)
|
|
27
|
+
|
|
28
|
+
Um `Command` carrega o agregado por um `ResultRepository`, consulta um
|
|
29
|
+
`PolicyPort` (gate `ALLOW`/`DENY`) e persiste. Falhas recuperáveis voltam como
|
|
30
|
+
`Result.err`, nunca como exceção.
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
class CancelOrder extends Command<
|
|
34
|
+
CancelOrderInput,
|
|
35
|
+
Result<Order, CancelOrderError>
|
|
36
|
+
> {
|
|
37
|
+
constructor(
|
|
38
|
+
private readonly orders: ResultRepository<
|
|
39
|
+
Order,
|
|
40
|
+
string,
|
|
41
|
+
CancelOrderError
|
|
42
|
+
>,
|
|
43
|
+
private readonly policies: PolicyPort,
|
|
44
|
+
) {
|
|
45
|
+
super();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
protected async execute(input: CancelOrderInput) {
|
|
49
|
+
const found = await this.orders.findById(input.orderId);
|
|
50
|
+
if (found.isErr()) return found;
|
|
51
|
+
const order = found.getOrThrow();
|
|
52
|
+
if (!order)
|
|
53
|
+
return Result.err(
|
|
54
|
+
new NotFoundError("Order", { id: input.orderId }),
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const evaluated = await this.policies.evaluate({
|
|
58
|
+
decisionId: asPolicyDecisionId(input.orderId),
|
|
59
|
+
policyKey: "order.cancel",
|
|
60
|
+
scopeChain: [],
|
|
61
|
+
contextVersion: 1,
|
|
62
|
+
seed: {
|
|
63
|
+
tenantId: asTenantId(input.tenantId),
|
|
64
|
+
schoolId: asSchoolId(input.schoolId),
|
|
65
|
+
fields: { orderStatus: order.status },
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
if (evaluated.isErr()) return evaluated;
|
|
69
|
+
|
|
70
|
+
const result = evaluated.getOrThrow();
|
|
71
|
+
if (result.kind === "GATE" && result.decision.status === "DENY") {
|
|
72
|
+
return Result.err(
|
|
73
|
+
AuthorizationError.policyDenied({
|
|
74
|
+
action: "order.cancel",
|
|
75
|
+
policyId: result.ref.definitionId,
|
|
76
|
+
policyVersion: Number(result.ref.policyVersion),
|
|
77
|
+
evaluatedAtIso: result.evaluatedAt.toISOString(),
|
|
78
|
+
}),
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const saved = await this.orders.save({ ...order, status: "CANCELLED" });
|
|
83
|
+
if (saved.isErr()) return saved;
|
|
84
|
+
return Result.ok({ ...order, status: "CANCELLED" });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
- **Imports**: tudo do root `@cullet/erp-core`.
|
|
90
|
+
- **`Repository` vs `ResultRepository`**: `Repository` (`save`/`delete` → `Promise<void>`) é o estilo imperativo; `ResultRepository` devolve `Result` para sinalizar not-found / concorrência otimista sem quebrar o fluxo.
|
|
91
|
+
- **Referência compilada/testada**: `src/examples/application/cancel-order.example.ts` (+ `.spec.ts`).
|
|
92
|
+
|
|
26
93
|
## [extension-points] Pontos de extensão
|
|
27
94
|
|
|
28
95
|
Implemente as portas em `application/ports/` para conectar a stack real:
|
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ Para o sumário prompt-friendly veja [`KIT_CONTEXT.md`](./KIT_CONTEXT.md). Para
|
|
|
13
13
|
- **Erros de aplicação** — `AppError` discriminada por `code`: `ValidationError`, `NotFoundError`, `ConflictError`, `AuthorizationError`, `IntegrationError`.
|
|
14
14
|
- **Result** — `Result<T, E>` e `Outcome` para retorno tipado da aplicação.
|
|
15
15
|
- **Policies** — `PolicyCatalog`, `PolicyDefinition`, `PolicyResolver`, `PolicyService` e tipos associados para avaliação declarativa.
|
|
16
|
-
- **Application** — portas de observabilidade (`LoggerPort`, `MetricsPort`, `TracerPort`) e `mapPolicyEvaluationError
|
|
16
|
+
- **Application** — `UseCase`/`Command` (CQS, entrada `CommandInput` com `RequestedBy`), portas de persistência (`Repository` e a variante `ResultRepository`), `PolicyPort`, portas de observabilidade (`LoggerPort`, `MetricsPort`, `TracerPort`) e `mapPolicyEvaluationError`. Veja o [exemplo end-to-end](#exemplo-end-to-end).
|
|
17
17
|
- **Exemplos** — rulesets de referência em `examples/rulesets/`, fora da superfície principal de domínio.
|
|
18
18
|
|
|
19
19
|
## Como começa
|
|
@@ -46,6 +46,133 @@ npx cullet fc erp-core@1.0.0
|
|
|
46
46
|
|
|
47
47
|
O argumento do `fc` é o nome do kit no registry (`erp-core`), não o nome npm com escopo. O comando instala `@cullet/erp-core`, copia o `src/` para `./cullet/erp-core@1.0.0/` e registra o alias `@cullet/erp-core` no `tsconfig.json`.
|
|
48
48
|
|
|
49
|
+
## Exemplo end-to-end
|
|
50
|
+
|
|
51
|
+
Um `Command` concreto que orquestra um `ResultRepository` e um `PolicyPort`.
|
|
52
|
+
O fluxo carrega o agregado, consulta uma policy declarativa (gate `ALLOW`/`DENY`)
|
|
53
|
+
e só então persiste — toda falha recuperável (erro de infra no repositório,
|
|
54
|
+
policy negando, agregado inexistente, conflito de concorrência otimista no
|
|
55
|
+
`save`) volta como `Result.err(...)`, nunca como exceção atravessando a
|
|
56
|
+
fronteira. O código abaixo é a versão consumidora do exemplo testado em
|
|
57
|
+
[`src/examples/application/cancel-order.example.ts`](./src/examples/application/cancel-order.example.ts).
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import {
|
|
61
|
+
AuthorizationError,
|
|
62
|
+
Command,
|
|
63
|
+
NotFoundError,
|
|
64
|
+
RequestedBy,
|
|
65
|
+
Result,
|
|
66
|
+
asPolicyDecisionId,
|
|
67
|
+
asSchoolId,
|
|
68
|
+
asTenantId,
|
|
69
|
+
type CommandInput,
|
|
70
|
+
type PolicyPort,
|
|
71
|
+
type ResultRepository,
|
|
72
|
+
} from "@cullet/erp-core";
|
|
73
|
+
|
|
74
|
+
type OrderStatus = "OPEN" | "CANCELLED";
|
|
75
|
+
interface Order {
|
|
76
|
+
readonly id: string;
|
|
77
|
+
readonly status: OrderStatus;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// `CommandInput` obriga toda mutação a registrar quem a disparou.
|
|
81
|
+
interface CancelOrderInput extends CommandInput {
|
|
82
|
+
readonly orderId: string;
|
|
83
|
+
readonly tenantId: string;
|
|
84
|
+
readonly schoolId: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
type CancelOrderError = NotFoundError | AuthorizationError;
|
|
88
|
+
|
|
89
|
+
class CancelOrder extends Command<
|
|
90
|
+
CancelOrderInput,
|
|
91
|
+
Result<Order, CancelOrderError>
|
|
92
|
+
> {
|
|
93
|
+
constructor(
|
|
94
|
+
private readonly orders: ResultRepository<
|
|
95
|
+
Order,
|
|
96
|
+
string,
|
|
97
|
+
CancelOrderError
|
|
98
|
+
>,
|
|
99
|
+
private readonly policies: PolicyPort,
|
|
100
|
+
) {
|
|
101
|
+
super();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
protected async execute(
|
|
105
|
+
input: CancelOrderInput,
|
|
106
|
+
): Promise<Result<Order, CancelOrderError>> {
|
|
107
|
+
// 1. Carrega o agregado; falhas de infra ficam in-band no Result.
|
|
108
|
+
const found = await this.orders.findById(input.orderId);
|
|
109
|
+
if (found.isErr()) return found;
|
|
110
|
+
|
|
111
|
+
const order = found.getOrThrow();
|
|
112
|
+
if (!order) {
|
|
113
|
+
return Result.err(
|
|
114
|
+
new NotFoundError("Order", { id: input.orderId }),
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// 2. Decide via policy declarativa (um GATE retorna ALLOW/DENY).
|
|
119
|
+
const evaluated = await this.policies.evaluate({
|
|
120
|
+
decisionId: asPolicyDecisionId(input.orderId),
|
|
121
|
+
policyKey: "order.cancel",
|
|
122
|
+
scopeChain: [],
|
|
123
|
+
contextVersion: 1,
|
|
124
|
+
seed: {
|
|
125
|
+
tenantId: asTenantId(input.tenantId),
|
|
126
|
+
schoolId: asSchoolId(input.schoolId),
|
|
127
|
+
fields: { orderStatus: order.status },
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
if (evaluated.isErr()) return evaluated;
|
|
131
|
+
|
|
132
|
+
const result = evaluated.getOrThrow();
|
|
133
|
+
if (result.kind === "GATE" && result.decision.status === "DENY") {
|
|
134
|
+
return Result.err(
|
|
135
|
+
AuthorizationError.policyDenied({
|
|
136
|
+
action: "order.cancel",
|
|
137
|
+
resource: { type: "Order", id: order.id },
|
|
138
|
+
policyId: result.ref.definitionId,
|
|
139
|
+
policyVersion: Number(result.ref.policyVersion),
|
|
140
|
+
evaluatedAtIso: result.evaluatedAt.toISOString(),
|
|
141
|
+
}),
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// 3. Muta e persiste; um conflito de versão no save também volta como
|
|
146
|
+
// Result.err — nunca uma exceção atravessando a fronteira.
|
|
147
|
+
const cancelled: Order = { ...order, status: "CANCELLED" };
|
|
148
|
+
const saved = await this.orders.save(cancelled);
|
|
149
|
+
if (saved.isErr()) return saved;
|
|
150
|
+
|
|
151
|
+
return Result.ok(cancelled);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Chamada — `run` recebe a entrada e devolve o Result tipado.
|
|
156
|
+
const result = await new CancelOrder(orderRepository, policyPort).run({
|
|
157
|
+
orderId: "order-42",
|
|
158
|
+
tenantId: "tenant-1",
|
|
159
|
+
schoolId: "school-1",
|
|
160
|
+
requestedBy: RequestedBy.fromUser("550e8400-e29b-41d4-a716-446655440000"),
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
result.match({
|
|
164
|
+
ok: (order) => console.log("cancelado", order.id),
|
|
165
|
+
err: (error) => console.error(error.code, error.message),
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
`Repository<TEntity, TId>` (estilo imperativo, `save`/`delete` retornam
|
|
170
|
+
`Promise<void>`) continua disponível quando você prefere lançar exceções;
|
|
171
|
+
`ResultRepository` é a variante alinhada à filosofia "erros como valor" e
|
|
172
|
+
permite sinalizar not-found / concorrência otimista sem quebrar o fluxo. Uma
|
|
173
|
+
implementação in-memory de referência está em
|
|
174
|
+
[`src/examples/application/in-memory-account-repository.example.ts`](./src/examples/application/in-memory-account-repository.example.ts).
|
|
175
|
+
|
|
49
176
|
## Composicao sem singletons
|
|
50
177
|
|
|
51
178
|
Para isolamento por tenant, request ou teste, prefira instancias locais em vez
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
//#region src/core/errors/types.d.ts
|
|
2
|
+
type ErrorSeverity = "low" | "medium" | "high" | "critical";
|
|
3
|
+
type JsonSafePrimitive = string | number | boolean | null;
|
|
4
|
+
type JsonSafeValue = JsonSafePrimitive | JsonSafeValue[] | {
|
|
5
|
+
[key: string]: JsonSafeValue;
|
|
6
|
+
};
|
|
7
|
+
type JsonSafeRecord = Record<string, JsonSafeValue>;
|
|
8
|
+
/**
|
|
9
|
+
* Options accepted by the AppError constructor.
|
|
10
|
+
* Subclasses can extend or pick from this type.
|
|
11
|
+
*/
|
|
12
|
+
type AppErrorOptions = {
|
|
13
|
+
/** Original error or exception that caused this error. */
|
|
14
|
+
cause?: unknown;
|
|
15
|
+
/** Arbitrary key-value metadata (will be sanitized to JSON-safe values). */
|
|
16
|
+
metadata?: Record<string, unknown>;
|
|
17
|
+
/** Error category/type for grouping (e.g., "authentication", "validation"). */
|
|
18
|
+
type?: string;
|
|
19
|
+
/** severity level for alerting/logging prioritization. */
|
|
20
|
+
severity?: ErrorSeverity;
|
|
21
|
+
/**
|
|
22
|
+
* Identifies a single execution "story" in the system. All operations
|
|
23
|
+
* related to the same logical flow must share the same correlationId.
|
|
24
|
+
*/
|
|
25
|
+
correlationId?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Identifies a specific technical request attempt (each retry may produce
|
|
28
|
+
* a new requestId), even when the correlationId stays the same.
|
|
29
|
+
*/
|
|
30
|
+
requestId?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Identifies a unique business intent (idempotency key); stays the same
|
|
33
|
+
* across technical retries and multiple requests that represent the same intent.
|
|
34
|
+
*/
|
|
35
|
+
commandId?: string;
|
|
36
|
+
/** ISO timestamp of when the error was created (defaults to now). */
|
|
37
|
+
createdAtIso?: string;
|
|
38
|
+
/** Safe message that can be exposed to end users (no internal details). */
|
|
39
|
+
publicMessage?: string;
|
|
40
|
+
};
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region src/core/errors/app-error.d.ts
|
|
43
|
+
/**
|
|
44
|
+
* Root of the application/domain error hierarchy. Every error the system raises
|
|
45
|
+
* on purpose extends `AppError`, which gives callers a single `instanceof` to
|
|
46
|
+
* catch and a uniform, serializable shape to log and transport.
|
|
47
|
+
*
|
|
48
|
+
* Beyond the native `Error` message it carries a stable `code` (the contract the
|
|
49
|
+
* outside world matches on), an optional non-leaking `publicMessage`, a
|
|
50
|
+
* severity, JSON-safe `metadata`, and the correlation/request/command ids that
|
|
51
|
+
* stitch an error back to the request that produced it. The metadata is
|
|
52
|
+
* validated as JSON-safe on construction, so a logger can serialize any
|
|
53
|
+
* `AppError` without hitting a circular reference or a non-serializable value.
|
|
54
|
+
*
|
|
55
|
+
* Abstract on purpose: callers should throw a specific subclass (e.g.
|
|
56
|
+
* {@link ValidationError}, {@link NotFoundError}) so the `code` and shape are
|
|
57
|
+
* meaningful, never a bare `AppError`.
|
|
58
|
+
*/
|
|
59
|
+
declare abstract class AppError extends Error {
|
|
60
|
+
readonly code: string;
|
|
61
|
+
readonly cause?: unknown;
|
|
62
|
+
readonly metadata?: JsonSafeRecord;
|
|
63
|
+
readonly type?: string;
|
|
64
|
+
readonly severity?: ErrorSeverity;
|
|
65
|
+
readonly createdAtIso: string;
|
|
66
|
+
readonly publicMessage?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Identifies a single execution "story" in the system. All operations
|
|
69
|
+
* related to the same logical flow must share the same correlationId.
|
|
70
|
+
*/
|
|
71
|
+
readonly correlationId?: string;
|
|
72
|
+
/**
|
|
73
|
+
* Identifies a specific technical request attempt (each retry may produce
|
|
74
|
+
* a new requestId), even when the correlationId stays the same.
|
|
75
|
+
*/
|
|
76
|
+
readonly requestId?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Marks the business intent / idempotency key; stays the same across
|
|
79
|
+
* technical retries and multiple requests that represent the same intent.
|
|
80
|
+
*/
|
|
81
|
+
readonly commandId?: string;
|
|
82
|
+
/**
|
|
83
|
+
* Builds the common error envelope shared by every subclass.
|
|
84
|
+
*
|
|
85
|
+
* `name` is taken from `new.target` so the thrown instance reports its
|
|
86
|
+
* concrete subclass name (not `"AppError"`), and the prototype is re-pinned
|
|
87
|
+
* via `setPrototypeOf` so `instanceof` keeps working after transpilation to
|
|
88
|
+
* older targets where extending built-ins breaks the chain. `createdAtIso`
|
|
89
|
+
* defaults to now, and `metadata` is validated as JSON-safe so the error is
|
|
90
|
+
* always serializable.
|
|
91
|
+
*
|
|
92
|
+
* Declared `protected`: instantiate a concrete subclass, never `AppError`.
|
|
93
|
+
*
|
|
94
|
+
* @param message - The internal, developer-facing message.
|
|
95
|
+
* @param code - The stable machine-readable code callers match on.
|
|
96
|
+
* @param options - Optional cause, metadata, severity, and correlation ids.
|
|
97
|
+
* @throws When `options.metadata` contains a value that is not JSON-safe.
|
|
98
|
+
*/
|
|
99
|
+
protected constructor(message: string, code: string, options?: AppErrorOptions);
|
|
100
|
+
/**
|
|
101
|
+
* Returns a JSON-safe representation of the error.
|
|
102
|
+
* Does NOT include `cause` by default (to avoid leaking internal details).
|
|
103
|
+
*/
|
|
104
|
+
toJSON(): Record<string, unknown>;
|
|
105
|
+
}
|
|
106
|
+
//#endregion
|
|
107
|
+
export { JsonSafeRecord as a, JsonSafePrimitive as i, AppErrorOptions as n, JsonSafeValue as o, ErrorSeverity as r, AppError as t };
|
|
108
|
+
//# sourceMappingURL=app-error.d.ts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { A as TracerPort, C as RequestedBy, D as UseCaseObservability, E as UseCase, M as MetricsPort, N as LogPayload, O as TraceAttributeValue, P as LoggerPort, S as CommandInput, T as MaybePromise, _ as PolicyEvaluationInput, a as TemporalContext, b as PolicyPortError, c as CacheStrategy, d as mapPolicyEvaluationError, f as TemporalHistory, g as ResultRepository, h as Repository, i as CreateTemporalContextInput, j as MetricLabels, k as TraceSpan, l as Page, n as TemporalUseCaseInput, o as assertTemporalContext, p as TemporalRepository, r as TemporalizedContextSeed, s as createTemporalContext, t as TemporalUseCase, u as Query, v as PolicyEvaluationOutput, w as RequestedByKind, x as Command, y as PolicyPort } from "../temporal-use-case.js";
|
|
2
|
+
export { CacheStrategy, Command, CommandInput, CreateTemporalContextInput, LogPayload, LoggerPort, MaybePromise, MetricLabels, MetricsPort, Page, PolicyEvaluationInput, PolicyEvaluationOutput, PolicyPort, PolicyPortError, Query, Repository, RequestedBy, RequestedByKind, ResultRepository, TemporalContext, TemporalHistory, TemporalRepository, TemporalUseCase, TemporalUseCaseInput, TemporalizedContextSeed, TraceAttributeValue, TraceSpan, TracerPort, UseCase, UseCaseObservability, assertTemporalContext, createTemporalContext, mapPolicyEvaluationError };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as Query, c as RequestedBy, l as UseCase, n as assertTemporalContext, o as mapPolicyEvaluationError, r as createTemporalContext, s as Command, t as TemporalUseCase } from "../temporal-use-case.js";
|
|
2
|
+
export { Command, Query, RequestedBy, TemporalUseCase, UseCase, assertTemporalContext, createTemporalContext, mapPolicyEvaluationError };
|
package/dist/errors/index.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as JsonSafeRecord, i as JsonSafePrimitive, n as AppErrorOptions, o as JsonSafeValue, r as ErrorSeverity, t as AppError } from "../app-error.js";
|
|
2
|
+
import { $ as serializationErrorCode, A as IdempotencyPayloadMismatchError, B as UniqueConstraintViolation, C as IntegrationErrorMetadata, D as IdempotencyFailureKind, E as IdempotencyErrorMetadata, F as AlreadyExistsError, G as AuthorizationErrorMetadata, H as translateUniqueViolationToDuplicate, I as ConflictError, J as AuthenticationError, K as AuthorizationErrorReason, L as ConflictErrorMetadata, M as payloadHash, N as sha256Hex, O as IdempotencyInProgressError, P as stableStringify, Q as ErrorCodes, R as ConflictKind, S as IntegrationError, T as IdempotencyError, U as BusinessRuleViolationError, V as UniqueConstraintViolationError, W as AuthorizationError, X as AuthenticationErrorReason, Y as AuthenticationErrorMetadata, Z as assertJsonSafeMetadata, _ as SerializationMessages, a as TemporalError, b as NotFoundError, c as TemporalPrecision, d as SerializationCodes, f as SerializationDirection, g as SerializationInError, h as SerializationFailureCategory, i as NotYetValidError, j as IdempotencyReplayNotSupportedError, k as IdempotencyKeyMissingError, l as evaluateTemporalWindow, m as SerializationErrorMetadata, n as UnexpectedError, o as TemporalErrorMetadata, p as SerializationError, q as AuthorizationRequirement, r as ExpiredError, s as TemporalKind, t as ValidationError, u as SerializationBoundary, v as SerializationOutError, w as IntegrationErrorReason, x as LegacyIncompatibleError, y as safePreview, z as DuplicateError } from "../validation-error.js";
|
|
2
3
|
export { AlreadyExistsError, AppError, AppErrorOptions, AuthenticationError, AuthenticationErrorMetadata, AuthenticationErrorReason, AuthorizationError, AuthorizationErrorMetadata, AuthorizationErrorReason, AuthorizationRequirement, BusinessRuleViolationError, ConflictError, ConflictErrorMetadata, ConflictKind, SerializationInError as DeserializationError, SerializationInError, DuplicateError, ErrorCodes, ErrorSeverity, ExpiredError, TemporalErrorMetadata as ExpiredErrorMetadata, TemporalErrorMetadata, TemporalPrecision as ExpiredErrorPrecision, TemporalPrecision, IdempotencyError, IdempotencyErrorMetadata, IdempotencyFailureKind, IdempotencyInProgressError, IdempotencyKeyMissingError, IdempotencyPayloadMismatchError, IdempotencyReplayNotSupportedError, IntegrationError, IntegrationErrorMetadata, IntegrationErrorReason, JsonSafePrimitive, JsonSafeRecord, JsonSafeValue, LegacyIncompatibleError, NotFoundError, NotYetValidError, SerializationBoundary, SerializationCodes, SerializationDirection, SerializationError, SerializationErrorMetadata, SerializationFailureCategory, SerializationMessages, SerializationOutError, TemporalError, TemporalKind, UnexpectedError, UniqueConstraintViolation, UniqueConstraintViolationError, ValidationError, assertJsonSafeMetadata, evaluateTemporalWindow, payloadHash, safePreview, serializationErrorCode, sha256Hex, stableStringify, translateUniqueViolationToDuplicate };
|
package/dist/errors/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
import { C as
|
|
1
|
+
import { a as ErrorCodes, i as assertJsonSafeMetadata, n as UnexpectedError, o as serializationErrorCode, r as AppError } from "../validation-code.js";
|
|
2
|
+
import { C as translateUniqueViolationToDuplicate, S as UniqueConstraintViolationError, T as AuthenticationError, _ as IdempotencyPayloadMismatchError, a as evaluateTemporalWindow, b as ConflictError, c as SerializationInError, d as safePreview, f as LegacyIncompatibleError, g as IdempotencyKeyMissingError, h as IdempotencyInProgressError, i as TemporalError, l as SerializationMessages, m as IdempotencyError, n as ExpiredError, o as SerializationCodes, p as IntegrationError, r as NotYetValidError, s as SerializationError, t as ValidationError, u as SerializationOutError, v as IdempotencyReplayNotSupportedError, w as AuthorizationError, x as DuplicateError, y as AlreadyExistsError } from "../validation-error.js";
|
|
3
|
+
import { n as BusinessRuleViolationError, t as NotFoundError } from "../not-found-error.js";
|
|
4
|
+
import { n as sha256Hex, r as stableStringify, t as payloadHash } from "../hashing.js";
|
|
3
5
|
export { AlreadyExistsError, AppError, AuthenticationError, AuthorizationError, BusinessRuleViolationError, ConflictError, SerializationInError as DeserializationError, SerializationInError, DuplicateError, ErrorCodes, ExpiredError, IdempotencyError, IdempotencyInProgressError, IdempotencyKeyMissingError, IdempotencyPayloadMismatchError, IdempotencyReplayNotSupportedError, IntegrationError, LegacyIncompatibleError, NotFoundError, NotYetValidError, SerializationCodes, SerializationError, SerializationMessages, SerializationOutError, TemporalError, UnexpectedError, UniqueConstraintViolationError, ValidationError, assertJsonSafeMetadata, evaluateTemporalWindow, payloadHash, safePreview, serializationErrorCode, sha256Hex, stableStringify, translateUniqueViolationToDuplicate };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { I as Result, c as PolicyViolation, g as CoreConfig, h as Outcome, l as VersionedGateEngine, p as ConditionNode, s as PolicyContext, t as GateOutcome } from "./gate-types.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
//#region src/core/policies/engines/v1/compute/compute-payload.schema.d.ts
|
|
5
|
+
interface ComputeParamsPayload {
|
|
6
|
+
readonly type: "params";
|
|
7
|
+
readonly data: Readonly<Record<string, unknown>>;
|
|
8
|
+
}
|
|
9
|
+
interface ComputeDecisionTableRule<R = unknown> {
|
|
10
|
+
readonly conditions: ConditionNode;
|
|
11
|
+
readonly result: R;
|
|
12
|
+
}
|
|
13
|
+
interface ComputeDecisionTablePayload<R = unknown> {
|
|
14
|
+
readonly type: "decision-table";
|
|
15
|
+
readonly rules: readonly ComputeDecisionTableRule<R>[];
|
|
16
|
+
readonly default: R;
|
|
17
|
+
}
|
|
18
|
+
type ComputePayloadV1 = ComputeDecisionTablePayload<unknown> | ComputeParamsPayload;
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region src/core/policies/engines/compute-payload.d.ts
|
|
21
|
+
type ComputePayload = ComputePayloadV1;
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/core/policies/engines/compute-types.d.ts
|
|
24
|
+
type ComputeStatus = "OK" | "NOT_APPLICABLE" | "ERROR";
|
|
25
|
+
interface ComputeOutcomeData {
|
|
26
|
+
readonly values: unknown | null;
|
|
27
|
+
readonly violations: readonly PolicyViolation[];
|
|
28
|
+
}
|
|
29
|
+
/** Semantic outcome of a COMPUTE policy evaluation. */
|
|
30
|
+
type ComputeOutcome = Outcome<ComputeStatus, ComputeOutcomeData>;
|
|
31
|
+
/**
|
|
32
|
+
* Pure compute operation: receives a resolved value + context, returns a
|
|
33
|
+
* business decision. Registration metadata (policy key/version) lives outside
|
|
34
|
+
* this contract.
|
|
35
|
+
*
|
|
36
|
+
* The engine resolves the structural payload before calling the evaluator:
|
|
37
|
+
* - `params` -> `payload.data`
|
|
38
|
+
* - `decision-table` -> matching `rule.result` or `default`
|
|
39
|
+
*
|
|
40
|
+
* Result wraps technical failures (invalid value shape).
|
|
41
|
+
* Outcome carries the semantic business decision.
|
|
42
|
+
*/
|
|
43
|
+
interface ComputeEvaluator {
|
|
44
|
+
evaluate(resolvedValue: unknown, context: Record<string, unknown>): Result<ComputeOutcome, string>;
|
|
45
|
+
}
|
|
46
|
+
interface ComputeEvaluatorRegistration {
|
|
47
|
+
readonly policyKey: string;
|
|
48
|
+
readonly version: number;
|
|
49
|
+
readonly evaluator: ComputeEvaluator;
|
|
50
|
+
}
|
|
51
|
+
interface VersionedComputeEngine {
|
|
52
|
+
readonly version: number;
|
|
53
|
+
evaluate(payload: ComputePayload, context: PolicyContext, evaluator: ComputeEvaluator): Result<ComputeOutcome, string>;
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/core/policies/engines/compute-registry.d.ts
|
|
57
|
+
interface ComputeRegistryOptions {
|
|
58
|
+
readonly coreConfig?: CoreConfig;
|
|
59
|
+
}
|
|
60
|
+
declare class ComputeRegistry {
|
|
61
|
+
private readonly engines;
|
|
62
|
+
private readonly evaluators;
|
|
63
|
+
constructor(params?: ComputeRegistryOptions);
|
|
64
|
+
register(registration: ComputeEvaluatorRegistration): void;
|
|
65
|
+
registerEngine(engine: VersionedComputeEngine): void;
|
|
66
|
+
getEngine(version: number): VersionedComputeEngine | undefined;
|
|
67
|
+
getEvaluator(policyKey: string, version: number): ComputeEvaluator | undefined;
|
|
68
|
+
evaluate(policyKey: string, computeEngineVersion: number, payloadSchemaVersion: number, payload: unknown, context: PolicyContext): Result<ComputeOutcome, string>;
|
|
69
|
+
}
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region src/core/policies/engines/gate-engine-registry.d.ts
|
|
72
|
+
declare class GateEngineRegistry {
|
|
73
|
+
private readonly engines;
|
|
74
|
+
register(engine: VersionedGateEngine): void;
|
|
75
|
+
get(version: number): VersionedGateEngine | undefined;
|
|
76
|
+
evaluate(version: number, payload: unknown, context: PolicyContext): Result<GateOutcome, string>;
|
|
77
|
+
}
|
|
78
|
+
//#endregion
|
|
79
|
+
export { ComputeOutcome as a, VersionedComputeEngine as c, ComputeDecisionTableRule as d, ComputeParamsPayload as f, ComputeEvaluatorRegistration as i, ComputePayload as l, ComputeRegistry as n, ComputeOutcomeData as o, ComputePayloadV1 as p, ComputeEvaluator as r, ComputeStatus as s, GateEngineRegistry as t, ComputeDecisionTablePayload as u };
|
|
80
|
+
//# sourceMappingURL=gate-engine-registry.d.ts.map
|
|
@@ -1,31 +1,5 @@
|
|
|
1
|
+
import { r as isValidDate } from "./temporal-guards.js";
|
|
1
2
|
import { z } from "zod";
|
|
2
|
-
//#region src/core/exceptions/domain-exception.ts
|
|
3
|
-
var DomainException = class extends Error {
|
|
4
|
-
constructor(message) {
|
|
5
|
-
super(message);
|
|
6
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
7
|
-
this.name = new.target.name;
|
|
8
|
-
}
|
|
9
|
-
};
|
|
10
|
-
//#endregion
|
|
11
|
-
//#region src/core/exceptions/invariant-violation-exception.ts
|
|
12
|
-
var InvariantViolationException = class extends DomainException {
|
|
13
|
-
constructor(message) {
|
|
14
|
-
super(message);
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
//#endregion
|
|
18
|
-
//#region src/core/shared/temporal-guards.ts
|
|
19
|
-
function isValidDate(value) {
|
|
20
|
-
return value instanceof Date && !Number.isNaN(value.getTime());
|
|
21
|
-
}
|
|
22
|
-
function cloneDate(date) {
|
|
23
|
-
return new Date(date.getTime());
|
|
24
|
-
}
|
|
25
|
-
function assertValidDate(fieldName, value) {
|
|
26
|
-
if (!isValidDate(value)) throw new InvariantViolationException(`${fieldName} must be a valid Date instance`);
|
|
27
|
-
}
|
|
28
|
-
//#endregion
|
|
29
3
|
//#region src/core/config/silent-policy-reporter.ts
|
|
30
4
|
var SilentPolicyReporter = class {
|
|
31
5
|
report(_event) {}
|
|
@@ -720,6 +694,6 @@ var GatePayloadSchemaV1 = class GatePayloadSchemaV1 {
|
|
|
720
694
|
};
|
|
721
695
|
const gatePayloadSchema = GatePayloadSchemaV1.schema;
|
|
722
696
|
//#endregion
|
|
723
|
-
export {
|
|
697
|
+
export { conditionNodeSchema as a, Ok as c, CoreConfig as d, SilentPolicyReporter as f, conditionLeafNodeSchema as i, Result as l, gatePayloadSchema as n, PolicyContextPath as o, ConditionEvaluatorV1 as r, Err as s, GatePayloadSchemaV1 as t, coreConfig as u };
|
|
724
698
|
|
|
725
699
|
//# sourceMappingURL=gate-v1-payload.schema.js.map
|