@cullet/erp-core 1.3.0 → 1.4.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 +5 -3
- package/README.md +160 -0
- package/dist/abac/index.cjs +7 -0
- package/dist/abac/index.d.cts +2 -0
- package/dist/abac/index.d.ts +2 -0
- package/dist/abac/index.js +2 -0
- package/dist/app-error.cjs +193 -0
- package/dist/app-error.cjs.map +1 -0
- package/dist/app-error.js +170 -0
- package/dist/app-error.js.map +1 -0
- package/dist/application/index.cjs +2 -1
- package/dist/application/index.d.cts +2 -1
- package/dist/application/index.d.ts +2 -1
- package/dist/application/index.js +2 -1
- package/dist/authorization-error.cjs +157 -0
- package/dist/authorization-error.cjs.map +1 -0
- package/dist/authorization-error.d.cts +113 -0
- package/dist/authorization-error.d.ts +113 -0
- package/dist/authorization-error.js +152 -0
- package/dist/authorization-error.js.map +1 -0
- package/dist/authorizer.port.d.cts +130 -0
- package/dist/authorizer.port.d.ts +130 -0
- package/dist/composite-authorizer.d.cts +216 -0
- package/dist/composite-authorizer.d.ts +216 -0
- package/dist/condition-evaluator.cjs +565 -0
- package/dist/condition-evaluator.cjs.map +1 -0
- package/dist/condition-evaluator.js +536 -0
- package/dist/condition-evaluator.js.map +1 -0
- package/dist/{gate-types.d.ts → core-config.d.cts} +78 -77
- package/dist/{gate-types.d.cts → core-config.d.ts} +78 -77
- package/dist/domain/index.cjs +2 -1
- package/dist/domain/index.d.cts +2 -1
- package/dist/domain/index.d.ts +2 -1
- package/dist/domain/index.js +2 -1
- package/dist/domain-event-contracts.cjs +3 -2
- package/dist/domain-event-contracts.cjs.map +1 -1
- package/dist/domain-event-contracts.js +2 -1
- package/dist/domain-event-contracts.js.map +1 -1
- package/dist/entity.cjs +126 -0
- package/dist/entity.cjs.map +1 -0
- package/dist/entity.js +115 -0
- package/dist/entity.js.map +1 -0
- package/dist/errors/index.cjs +8 -6
- package/dist/errors/index.d.cts +2 -1
- package/dist/errors/index.d.ts +2 -1
- package/dist/errors/index.js +4 -2
- package/dist/gate-engine-registry.cjs +5 -4
- package/dist/gate-engine-registry.cjs.map +1 -1
- package/dist/gate-engine-registry.d.cts +3 -2
- package/dist/gate-engine-registry.d.ts +3 -2
- package/dist/gate-engine-registry.js +2 -1
- package/dist/gate-engine-registry.js.map +1 -1
- package/dist/gate-v1-payload.schema.cjs +0 -562
- package/dist/gate-v1-payload.schema.cjs.map +1 -1
- package/dist/gate-v1-payload.schema.js +1 -533
- package/dist/gate-v1-payload.schema.js.map +1 -1
- package/dist/index.cjs +34 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -12
- package/dist/index.d.ts +19 -12
- package/dist/index.js +15 -9
- package/dist/index.js.map +1 -1
- package/dist/not-found-error.cjs +5 -5
- package/dist/not-found-error.cjs.map +1 -1
- package/dist/not-found-error.js +1 -1
- package/dist/outcome.d.cts +1 -83
- package/dist/outcome.d.ts +1 -83
- package/dist/parse-gate-payload.d.cts +2 -2
- package/dist/parse-gate-payload.d.ts +2 -2
- package/dist/path.d.cts +2 -2
- package/dist/path.d.ts +2 -2
- package/dist/policies/engines/index.d.cts +1 -1
- package/dist/policies/engines/index.d.ts +1 -1
- package/dist/policies/engines/v1/gate/index.cjs +5 -4
- package/dist/policies/engines/v1/gate/index.cjs.map +1 -1
- package/dist/policies/engines/v1/gate/index.d.cts +2 -2
- package/dist/policies/engines/v1/gate/index.d.ts +2 -2
- package/dist/policies/engines/v1/gate/index.js +2 -1
- package/dist/policies/engines/v1/gate/index.js.map +1 -1
- package/dist/policies/index.cjs +5 -5
- package/dist/policies/index.d.cts +3 -2
- package/dist/policies/index.d.ts +3 -2
- package/dist/policies/index.js +2 -2
- package/dist/policy-bridge.cjs +437 -0
- package/dist/policy-bridge.cjs.map +1 -0
- package/dist/policy-bridge.d.cts +185 -0
- package/dist/policy-bridge.d.ts +185 -0
- package/dist/policy-bridge.js +396 -0
- package/dist/policy-bridge.js.map +1 -0
- package/dist/policy-service.cjs +239 -239
- package/dist/policy-service.cjs.map +1 -1
- package/dist/policy-service.d.cts +2 -2
- package/dist/policy-service.d.ts +2 -2
- package/dist/policy-service.js +239 -239
- package/dist/policy-service.js.map +1 -1
- package/dist/rbac/index.cjs +9 -0
- package/dist/rbac/index.d.cts +3 -0
- package/dist/rbac/index.d.ts +3 -0
- package/dist/rbac/index.js +2 -0
- package/dist/requested-by.cjs +54 -0
- package/dist/requested-by.cjs.map +1 -0
- package/dist/requested-by.d.cts +25 -0
- package/dist/requested-by.d.ts +25 -0
- package/dist/requested-by.js +49 -0
- package/dist/requested-by.js.map +1 -0
- package/dist/result/index.d.cts +2 -1
- package/dist/result/index.d.ts +2 -1
- package/dist/result.d.cts +84 -0
- package/dist/result.d.ts +84 -0
- package/dist/rule.cjs +327 -0
- package/dist/rule.cjs.map +1 -0
- package/dist/rule.js +298 -0
- package/dist/rule.js.map +1 -0
- package/dist/temporal-use-case.cjs +1 -53
- package/dist/temporal-use-case.cjs.map +1 -1
- package/dist/temporal-use-case.d.cts +5 -27
- package/dist/temporal-use-case.d.ts +5 -27
- package/dist/temporal-use-case.js +2 -48
- package/dist/temporal-use-case.js.map +1 -1
- package/dist/unexpected-error.cjs +3 -192
- package/dist/unexpected-error.cjs.map +1 -1
- package/dist/unexpected-error.js +2 -167
- package/dist/unexpected-error.js.map +1 -1
- package/dist/uuid-identifier.d.cts +2 -85
- package/dist/uuid-identifier.d.ts +2 -85
- package/dist/validation-error.cjs +33 -166
- package/dist/validation-error.cjs.map +1 -1
- package/dist/validation-error.d.cts +2 -98
- package/dist/validation-error.d.ts +2 -98
- package/dist/validation-error.js +7 -134
- package/dist/validation-error.js.map +1 -1
- package/dist/value-object.cjs +0 -123
- package/dist/value-object.cjs.map +1 -1
- package/dist/value-object.d.cts +89 -0
- package/dist/value-object.d.ts +89 -0
- package/dist/value-object.js +1 -112
- package/dist/value-object.js.map +1 -1
- package/meta.json +18 -4
- package/package.json +27 -1
- package/src/abac/index.ts +1 -0
- package/src/core/abac/abac-request.ts +29 -0
- package/src/core/abac/attributes.ts +39 -0
- package/src/core/abac/authorizer.ts +108 -0
- package/src/core/abac/combining.ts +63 -0
- package/src/core/abac/composite-authorizer.ts +45 -0
- package/src/core/abac/domain/policy-set.ts +52 -0
- package/src/core/abac/domain/rule.ts +197 -0
- package/src/core/abac/index.ts +21 -0
- package/src/core/application/ports/abac-authorizer.port.ts +20 -0
- package/src/core/application/ports/authorizer.port.ts +22 -0
- package/src/core/errors/authorization-error.ts +26 -0
- package/src/core/errors/error-codes.ts +1 -0
- package/src/core/index.ts +7 -0
- package/src/core/rbac/access-request.ts +32 -0
- package/src/core/rbac/authorizer.ts +91 -0
- package/src/core/rbac/domain/grant.ts +96 -0
- package/src/core/rbac/domain/permission-set.ts +67 -0
- package/src/core/rbac/domain/permission.ts +119 -0
- package/src/core/rbac/domain/role.ts +101 -0
- package/src/core/rbac/domain/scope.ts +84 -0
- package/src/core/rbac/index.ts +15 -0
- package/src/core/rbac/policy-bridge.ts +44 -0
- package/src/examples/application/authorize-cancel-order-abac.example.ts +107 -0
- package/src/examples/application/authorize-cancel-order.example.ts +101 -0
- package/src/rbac/index.ts +1 -0
- package/src/version.ts +1 -1
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end reference for the ABAC seam: a concrete {@link Command} that refines
|
|
3
|
+
* a mutation through an {@link AbacAuthorizerPort} — deciding on the *attributes*
|
|
4
|
+
* of the request (the order's live status, the environment) rather than a static
|
|
5
|
+
* capability.
|
|
6
|
+
*
|
|
7
|
+
* Unlike the RBAC example, the aggregate is loaded *before* authorizing: ABAC
|
|
8
|
+
* reasons over resource state, so that state has to exist first. A denial comes
|
|
9
|
+
* back as `Result.err(AuthorizationError)` (translated to a 403 at the edge); a
|
|
10
|
+
* missing aggregate or a repository failure stays in band as `Result.err` too —
|
|
11
|
+
* the "errors as values" contract, never a thrown exception.
|
|
12
|
+
*
|
|
13
|
+
* Consumers import these symbols from `@cullet/erp-core` and
|
|
14
|
+
* `@cullet/erp-core/abac`; inside the kit we use relative paths so the example
|
|
15
|
+
* stays compilable and test-covered, guarding the README/KIT_CONTEXT snippet
|
|
16
|
+
* against rot.
|
|
17
|
+
*/
|
|
18
|
+
import type { AbacAuthorizerPort } from "../../core/abac/index.js";
|
|
19
|
+
import { Command, type CommandInput } from "../../core/application/index.js";
|
|
20
|
+
import type { ResultRepository } from "../../core/application/index.js";
|
|
21
|
+
import { AuthorizationError } from "../../core/errors/authorization-error.js";
|
|
22
|
+
import { NotFoundError } from "../../core/errors/not-found-error.js";
|
|
23
|
+
import { Result } from "../../core/result/result.js";
|
|
24
|
+
|
|
25
|
+
// ─── Minimal domain ─────────────────────────────────────────────────────────
|
|
26
|
+
|
|
27
|
+
type OrderStatus = "OPEN" | "CANCELLED";
|
|
28
|
+
|
|
29
|
+
interface Order {
|
|
30
|
+
readonly id: string;
|
|
31
|
+
readonly status: OrderStatus;
|
|
32
|
+
readonly locked: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ─── Command contract ────────────────────────────────────────────────────────
|
|
36
|
+
|
|
37
|
+
interface CancelOrderInput extends CommandInput {
|
|
38
|
+
readonly orderId: string;
|
|
39
|
+
/** An environment attribute the composition root resolves from its clock. */
|
|
40
|
+
readonly businessHours: boolean;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
type CancelOrderError = NotFoundError | AuthorizationError;
|
|
44
|
+
|
|
45
|
+
// ─── The use case ─────────────────────────────────────────────────────────────
|
|
46
|
+
|
|
47
|
+
class CancelOrder extends Command<
|
|
48
|
+
CancelOrderInput,
|
|
49
|
+
Result<Order, CancelOrderError>
|
|
50
|
+
> {
|
|
51
|
+
constructor(
|
|
52
|
+
private readonly orders: ResultRepository<
|
|
53
|
+
Order,
|
|
54
|
+
string,
|
|
55
|
+
CancelOrderError
|
|
56
|
+
>,
|
|
57
|
+
private readonly authorizer: AbacAuthorizerPort,
|
|
58
|
+
) {
|
|
59
|
+
super();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
protected async execute(
|
|
63
|
+
input: CancelOrderInput,
|
|
64
|
+
): Promise<Result<Order, CancelOrderError>> {
|
|
65
|
+
// 1. Load the aggregate — its live state feeds the ABAC decision.
|
|
66
|
+
const found = await this.orders.findById(input.orderId);
|
|
67
|
+
if (found.isErr()) {
|
|
68
|
+
return found;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const order = found.getOrThrow();
|
|
72
|
+
if (!order) {
|
|
73
|
+
return Result.err(
|
|
74
|
+
new NotFoundError("Order", { id: input.orderId }),
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// 2. Gate on attributes: the order's status/lock plus the environment.
|
|
79
|
+
// `CommandInput.requestedBy` is the ABAC subject.
|
|
80
|
+
const allowed = await this.authorizer.authorize({
|
|
81
|
+
actor: input.requestedBy,
|
|
82
|
+
action: "order.cancel",
|
|
83
|
+
resource: { type: "Order", id: order.id },
|
|
84
|
+
attributes: {
|
|
85
|
+
resource: { status: order.status, locked: order.locked },
|
|
86
|
+
environment: { businessHours: input.businessHours },
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
if (allowed.isErr()) {
|
|
90
|
+
// AuthorizationError → 403 at the boundary.
|
|
91
|
+
return Result.err(allowed.error);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 3. Mutate and persist. A version conflict on save also surfaces as
|
|
95
|
+
// Result.err — never an exception crossing the boundary.
|
|
96
|
+
const cancelled: Order = { ...order, status: "CANCELLED" };
|
|
97
|
+
const saved = await this.orders.save(cancelled);
|
|
98
|
+
if (saved.isErr()) {
|
|
99
|
+
return saved;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return Result.ok(cancelled);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export { CancelOrder };
|
|
107
|
+
export type { CancelOrderError, CancelOrderInput, Order, OrderStatus };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end reference for the RBAC seam: a concrete {@link Command} that gates
|
|
3
|
+
* a mutation through an {@link AuthorizerPort} before touching the aggregate.
|
|
4
|
+
*
|
|
5
|
+
* Flow: ask the injected authorizer whether the actor may cancel the order →
|
|
6
|
+
* load the aggregate → mutate and persist. An authorization denial comes back
|
|
7
|
+
* as `Result.err(AuthorizationError)` (translated to a 403 at the edge), and a
|
|
8
|
+
* missing aggregate or a repository failure stays in band as `Result.err`
|
|
9
|
+
* too — the "errors as values" contract, never a thrown exception.
|
|
10
|
+
*
|
|
11
|
+
* Consumers import these symbols from `@cullet/erp-core` and
|
|
12
|
+
* `@cullet/erp-core/rbac`; inside the kit we use relative paths so the example
|
|
13
|
+
* stays compilable and test-covered, guarding the README/KIT_CONTEXT snippet
|
|
14
|
+
* against rot.
|
|
15
|
+
*/
|
|
16
|
+
import { Command, type CommandInput } from "../../core/application/index.js";
|
|
17
|
+
import type { ResultRepository } from "../../core/application/index.js";
|
|
18
|
+
import type { AuthorizerPort } from "../../core/application/ports/authorizer.port.js";
|
|
19
|
+
import { AuthorizationError } from "../../core/errors/authorization-error.js";
|
|
20
|
+
import { NotFoundError } from "../../core/errors/not-found-error.js";
|
|
21
|
+
import { Permission, Scope } from "../../core/rbac/index.js";
|
|
22
|
+
import { Result } from "../../core/result/result.js";
|
|
23
|
+
|
|
24
|
+
// ─── Minimal domain ─────────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
type OrderStatus = "OPEN" | "CANCELLED";
|
|
27
|
+
|
|
28
|
+
interface Order {
|
|
29
|
+
readonly id: string;
|
|
30
|
+
readonly status: OrderStatus;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ─── Command contract ────────────────────────────────────────────────────────
|
|
34
|
+
|
|
35
|
+
interface CancelOrderInput extends CommandInput {
|
|
36
|
+
readonly orderId: string;
|
|
37
|
+
readonly schoolId: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
type CancelOrderError = NotFoundError | AuthorizationError;
|
|
41
|
+
|
|
42
|
+
// ─── The use case ─────────────────────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
class CancelOrder extends Command<
|
|
45
|
+
CancelOrderInput,
|
|
46
|
+
Result<Order, CancelOrderError>
|
|
47
|
+
> {
|
|
48
|
+
constructor(
|
|
49
|
+
private readonly orders: ResultRepository<
|
|
50
|
+
Order,
|
|
51
|
+
string,
|
|
52
|
+
CancelOrderError
|
|
53
|
+
>,
|
|
54
|
+
private readonly authorizer: AuthorizerPort,
|
|
55
|
+
) {
|
|
56
|
+
super();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
protected async execute(
|
|
60
|
+
input: CancelOrderInput,
|
|
61
|
+
): Promise<Result<Order, CancelOrderError>> {
|
|
62
|
+
// 1. Gate the action. `CommandInput.requestedBy` is the RBAC actor.
|
|
63
|
+
const allowed = await this.authorizer.authorize({
|
|
64
|
+
actor: input.requestedBy,
|
|
65
|
+
action: "order.cancel",
|
|
66
|
+
required: Permission.of("orders:cancel"),
|
|
67
|
+
resource: { type: "Order", id: input.orderId },
|
|
68
|
+
scope: Scope.of(`school:${input.schoolId}`),
|
|
69
|
+
});
|
|
70
|
+
if (allowed.isErr()) {
|
|
71
|
+
// AuthorizationError → 403 at the boundary.
|
|
72
|
+
return Result.err(allowed.error);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 2. Load the aggregate. Infra failures stay in band as Result.err.
|
|
76
|
+
const found = await this.orders.findById(input.orderId);
|
|
77
|
+
if (found.isErr()) {
|
|
78
|
+
return found;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const order = found.getOrThrow();
|
|
82
|
+
if (!order) {
|
|
83
|
+
return Result.err(
|
|
84
|
+
new NotFoundError("Order", { id: input.orderId }),
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// 3. Mutate and persist. A version conflict on save also surfaces as
|
|
89
|
+
// Result.err — never an exception crossing the boundary.
|
|
90
|
+
const cancelled: Order = { ...order, status: "CANCELLED" };
|
|
91
|
+
const saved = await this.orders.save(cancelled);
|
|
92
|
+
if (saved.isErr()) {
|
|
93
|
+
return saved;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return Result.ok(cancelled);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export { CancelOrder };
|
|
101
|
+
export type { CancelOrderError, CancelOrderInput, Order, OrderStatus };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../core/rbac/index.js";
|
package/src/version.ts
CHANGED
|
@@ -4,4 +4,4 @@
|
|
|
4
4
|
// Mantemos a versao aqui, dentro de src/, para que a copia full-control seja
|
|
5
5
|
// auto-contida: ao copiar so o conteudo de src/, o entry nao depende de um
|
|
6
6
|
// `../package.json` que deixaria de existir no projeto consumidor.
|
|
7
|
-
export const version = "1.
|
|
7
|
+
export const version = "1.4.0";
|