@classytic/primitives 0.15.0 → 0.16.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/CHANGELOG.md +16 -0
- package/dist/approval.d.mts +17 -2
- package/dist/approval.mjs +13 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,22 @@
|
|
|
3
3
|
Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
4
4
|
adhering to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
5
5
|
|
|
6
|
+
## [0.16.0] - 2026-07-27
|
|
7
|
+
|
|
8
|
+
### Added — `assertApproved` + `CHAIN_INCOMPLETE` (`/approval`)
|
|
9
|
+
|
|
10
|
+
- **`ApprovalErrorCode` gains `'CHAIN_INCOMPLETE'`** — the single canonical
|
|
11
|
+
error code for "finalize/commit attempted before the chain reached `approved`".
|
|
12
|
+
Hosts route it through `rethrowApprovalError` to the `approval.chain_incomplete`
|
|
13
|
+
wire code so all commit/post/finalize boundaries raise the same structured error.
|
|
14
|
+
- **`assertApproved(chain, message?)`** — canonical finalize-time gate: asserts
|
|
15
|
+
the chain has reached `approved`, else throws `ApprovalError('CHAIN_INCOMPLETE')`.
|
|
16
|
+
A `null`/absent chain passes (no chain required). Use at every journal-entry
|
|
17
|
+
post, PO approve, transfer dispatch, etc. to replace per-domain hand-rolled
|
|
18
|
+
divergent codes with one definition.
|
|
19
|
+
|
|
20
|
+
Purely additive — no existing exports changed.
|
|
21
|
+
|
|
6
22
|
## [0.15.0] - 2026-07-25
|
|
7
23
|
|
|
8
24
|
### Added — `/retention`: `PurgeEvidence` value object
|
package/dist/approval.d.mts
CHANGED
|
@@ -83,7 +83,12 @@ interface CreateStepInput {
|
|
|
83
83
|
readonly requiredApprovals?: number;
|
|
84
84
|
readonly threshold?: ApprovalThreshold;
|
|
85
85
|
}
|
|
86
|
-
type ApprovalErrorCode = 'EMPTY_STEPS' | 'DUPLICATE_STEP_ID' | 'EMPTY_APPROVERS' | 'DUPLICATE_APPROVER_ID' | 'INVALID_QUORUM' | 'UNKNOWN_STEP' | 'UNAUTHORIZED_APPROVER' | 'STEP_NOT_ACTIVE' | 'STEP_ALREADY_DECIDED_BY_APPROVER'
|
|
86
|
+
type ApprovalErrorCode = 'EMPTY_STEPS' | 'DUPLICATE_STEP_ID' | 'EMPTY_APPROVERS' | 'DUPLICATE_APPROVER_ID' | 'INVALID_QUORUM' | 'UNKNOWN_STEP' | 'UNAUTHORIZED_APPROVER' | 'STEP_NOT_ACTIVE' | 'STEP_ALREADY_DECIDED_BY_APPROVER'
|
|
87
|
+
/** A finalize/commit was attempted while the chain has not reached
|
|
88
|
+
* `approved` (still `pending`, or `rejected`). The single canonical
|
|
89
|
+
* "not yet approved" gate — hosts route it through arc-approval's
|
|
90
|
+
* `rethrowApprovalError` to the `approval.chain_incomplete` wire code. */
|
|
91
|
+
| 'CHAIN_INCOMPLETE';
|
|
87
92
|
declare class ApprovalError extends Error {
|
|
88
93
|
readonly name = "ApprovalError";
|
|
89
94
|
readonly code: ApprovalErrorCode;
|
|
@@ -123,6 +128,16 @@ declare function applyDecision(chain: ApprovalChain, input: DecisionInput): Appr
|
|
|
123
128
|
*/
|
|
124
129
|
declare function skipStep(chain: ApprovalChain, stepId: string, reason?: string): ApprovalChain;
|
|
125
130
|
declare function isApproved(chain: ApprovalChain): boolean;
|
|
131
|
+
/**
|
|
132
|
+
* The canonical finalize-time gate: assert `chain` has reached `approved`,
|
|
133
|
+
* else throw `ApprovalError('CHAIN_INCOMPLETE')`. Use this at every
|
|
134
|
+
* commit/post/finalize boundary that must not proceed on an unapproved chain
|
|
135
|
+
* (journal-entry post, PO approve, transfer dispatch, …) so they all raise the
|
|
136
|
+
* SAME error instead of hand-rolling divergent codes. A `null`/absent chain is
|
|
137
|
+
* treated as "no chain required" and passes — callers that require a chain
|
|
138
|
+
* check presence separately.
|
|
139
|
+
*/
|
|
140
|
+
declare function assertApproved(chain: ApprovalChain | null | undefined, message?: string): void;
|
|
126
141
|
declare function isRejected(chain: ApprovalChain): boolean;
|
|
127
142
|
declare function isPending(chain: ApprovalChain): boolean;
|
|
128
143
|
/**
|
|
@@ -130,4 +145,4 @@ declare function isPending(chain: ApprovalChain): boolean;
|
|
|
130
145
|
*/
|
|
131
146
|
declare function decisionCount(chain: ApprovalChain): number;
|
|
132
147
|
//#endregion
|
|
133
|
-
export { ApprovalChain, ApprovalDecision, ApprovalError, ApprovalErrorCode, ApprovalStatus, ApprovalStep, ApprovalThreshold, Approver, ChainOrder, CreateChainInput, CreateStepInput, DecisionInput, applyDecision, createChain, decisionCount, isApproved, isPending, isRejected, nextPendingStep, pendingSteps, skipStep };
|
|
148
|
+
export { ApprovalChain, ApprovalDecision, ApprovalError, ApprovalErrorCode, ApprovalStatus, ApprovalStep, ApprovalThreshold, Approver, ChainOrder, CreateChainInput, CreateStepInput, DecisionInput, applyDecision, assertApproved, createChain, decisionCount, isApproved, isPending, isRejected, nextPendingStep, pendingSteps, skipStep };
|
package/dist/approval.mjs
CHANGED
|
@@ -115,6 +115,18 @@ function skipStep(chain, stepId, reason) {
|
|
|
115
115
|
function isApproved(chain) {
|
|
116
116
|
return chain.status === "approved";
|
|
117
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* The canonical finalize-time gate: assert `chain` has reached `approved`,
|
|
120
|
+
* else throw `ApprovalError('CHAIN_INCOMPLETE')`. Use this at every
|
|
121
|
+
* commit/post/finalize boundary that must not proceed on an unapproved chain
|
|
122
|
+
* (journal-entry post, PO approve, transfer dispatch, …) so they all raise the
|
|
123
|
+
* SAME error instead of hand-rolling divergent codes. A `null`/absent chain is
|
|
124
|
+
* treated as "no chain required" and passes — callers that require a chain
|
|
125
|
+
* check presence separately.
|
|
126
|
+
*/
|
|
127
|
+
function assertApproved(chain, message) {
|
|
128
|
+
if (chain != null && !isApproved(chain)) throw new ApprovalError("CHAIN_INCOMPLETE", message ?? `approval chain has not reached 'approved' (status='${chain.status}')`);
|
|
129
|
+
}
|
|
118
130
|
function isRejected(chain) {
|
|
119
131
|
return chain.status === "rejected";
|
|
120
132
|
}
|
|
@@ -143,4 +155,4 @@ function computeChainStatus(steps) {
|
|
|
143
155
|
return steps.every((s) => s.status === "approved" || s.status === "skipped") ? "approved" : "pending";
|
|
144
156
|
}
|
|
145
157
|
//#endregion
|
|
146
|
-
export { ApprovalError, applyDecision, createChain, decisionCount, isApproved, isPending, isRejected, nextPendingStep, pendingSteps, skipStep };
|
|
158
|
+
export { ApprovalError, applyDecision, assertApproved, createChain, decisionCount, isApproved, isPending, isRejected, nextPendingStep, pendingSteps, skipStep };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classytic/primitives",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Framework-agnostic TypeScript primitives shared across Classytic packages — Money, events, pagination, tenant config, and other building blocks.",
|
|
5
5
|
"author": "Classytic",
|
|
6
6
|
"license": "MIT",
|