@company-semantics/contracts 9.1.0 → 9.2.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/package.json +4 -1
- package/src/__tests__/resource-keys.test.ts +30 -23
- package/src/admin/authz-simulate.ts +4 -4
- package/src/admin/direct-grants.ts +2 -2
- package/src/api/generated-spec-hash.ts +2 -2
- package/src/api/generated.ts +97 -0
- package/src/api/http/routes/ai-chat.ts +3 -3
- package/src/api/http/utils/resource-response.ts +5 -2
- package/src/api/index.ts +4 -4
- package/src/api/primitives.ts +6 -2
- package/src/auth/README.md +1 -0
- package/src/auth/index.ts +12 -5
- package/src/autotune.ts +5 -1
- package/src/billing/index.ts +1 -1
- package/src/billing/types.ts +1 -1
- package/src/chat/README.md +3 -0
- package/src/chat/__tests__/runtime-profile.test.ts +68 -48
- package/src/chat/index.ts +10 -4
- package/src/chat/runtime-profile.ts +25 -10
- package/src/chat/schemas.ts +49 -41
- package/src/chat/types.ts +48 -42
- package/src/ci-envelope/README.md +2 -0
- package/src/ci-envelope/__tests__/transitions.test.ts +56 -56
- package/src/ci-envelope/index.ts +2 -2
- package/src/ci-envelope/types.ts +20 -20
- package/src/ci-results/index.ts +2 -2
- package/src/ci-results/repo-ci-result.ts +15 -12
- package/src/compatibility.ts +6 -6
- package/src/content/index.ts +10 -4
- package/src/content/schemas.ts +42 -24
- package/src/dispatch/index.ts +18 -15
- package/src/email/__tests__/registry.test.ts +81 -77
- package/src/email/index.ts +3 -3
- package/src/email/registry.ts +25 -25
- package/src/email/types.ts +43 -43
- package/src/errors/index.ts +8 -8
- package/src/execution/__tests__/events.test.ts +42 -42
- package/src/execution/__tests__/lifecycle.test.ts +192 -190
- package/src/execution/__tests__/registry.test.ts +114 -114
- package/src/execution/audit-export.ts +4 -4
- package/src/execution/errors.ts +7 -7
- package/src/execution/event-metadata.ts +4 -4
- package/src/execution/events.ts +23 -21
- package/src/execution/expiry.ts +5 -5
- package/src/execution/hash-chain.ts +2 -2
- package/src/execution/index.ts +19 -28
- package/src/execution/kinds.ts +7 -7
- package/src/execution/lifecycle.ts +33 -33
- package/src/execution/registry.ts +63 -63
- package/src/execution/schemas.ts +31 -23
- package/src/execution/status.ts +45 -26
- package/src/execution/summary.ts +16 -17
- package/src/execution/timeline-ui.ts +9 -9
- package/src/execution/types.ts +31 -25
- package/src/generated/openapi-routes.ts +1 -0
- package/src/guards/config.ts +22 -18
- package/src/guards/index.ts +4 -4
- package/src/guards/types.ts +32 -24
- package/src/identity/__tests__/avatar.test.ts +68 -59
- package/src/identity/avatar.ts +8 -8
- package/src/identity/display-name.ts +3 -3
- package/src/identity/index.ts +8 -8
- package/src/identity/people-org-chart.ts +8 -4
- package/src/identity/schemas.ts +28 -18
- package/src/identity/types.ts +5 -5
- package/src/impersonation/index.ts +5 -5
- package/src/impersonation/schemas.ts +15 -9
- package/src/impersonation-events.ts +21 -21
- package/src/impersonation.ts +25 -24
- package/src/index.ts +118 -90
- package/src/interfaces/mcp/tools/help.ts +19 -19
- package/src/internal-admin.ts +6 -6
- package/src/mcp/README.md +2 -0
- package/src/mcp/__tests__/capability-graph.test.ts +290 -290
- package/src/mcp/capability-graph.ts +42 -40
- package/src/mcp/failure-context.ts +1 -3
- package/src/mcp/index.ts +57 -57
- package/src/mcp/resources.ts +9 -9
- package/src/meetings/index.ts +2 -2
- package/src/meetings/schemas.ts +51 -34
- package/src/message-parts/README.md +2 -0
- package/src/message-parts/__tests__/builder.test.ts +142 -142
- package/src/message-parts/__tests__/confirmation.test.ts +100 -86
- package/src/message-parts/__tests__/preview.test.ts +63 -63
- package/src/message-parts/__tests__/wire.test.ts +130 -124
- package/src/message-parts/builder.ts +23 -23
- package/src/message-parts/confirmation.ts +17 -14
- package/src/message-parts/execution.ts +7 -7
- package/src/message-parts/index.ts +10 -10
- package/src/message-parts/lifecycle.ts +25 -25
- package/src/message-parts/preview.ts +30 -30
- package/src/message-parts/types.ts +27 -27
- package/src/message-parts/wire.ts +24 -24
- package/src/mutations.ts +2 -2
- package/src/observability.ts +23 -11
- package/src/org/__tests__/org-units.test.ts +131 -96
- package/src/org/__tests__/tree-ordering.test.ts +57 -37
- package/src/org/__tests__/view-scopes.test.ts +40 -40
- package/src/org/domain.ts +9 -9
- package/src/org/index.ts +24 -21
- package/src/org/org-units.ts +34 -20
- package/src/org/schemas.ts +201 -127
- package/src/org/sharing.ts +17 -13
- package/src/org/tree-ordering.ts +3 -1
- package/src/org/types.ts +54 -47
- package/src/org/view-scopes.ts +9 -9
- package/src/permissions/access-levels.ts +7 -2
- package/src/permissions/access-source.ts +6 -6
- package/src/permissions/index.ts +5 -5
- package/src/permissions/orgchart-roles.ts +7 -7
- package/src/permissions/permission-introspection.ts +7 -5
- package/src/permissions/share-api.ts +19 -9
- package/src/pressure.ts +4 -4
- package/src/queryIntent.ts +21 -21
- package/src/ralph/__tests__/prd-groups.test.ts +159 -159
- package/src/ralph/__tests__/prd.test.ts +30 -30
- package/src/ralph/index.ts +3 -8
- package/src/ralph/prd.ts +33 -33
- package/src/ralph/progress.ts +1 -1
- package/src/rate-limit/README.md +4 -4
- package/src/rate-limit/index.ts +3 -3
- package/src/requests.ts +36 -8
- package/src/resource-keys.ts +207 -124
- package/src/resource-registry.ts +5 -5
- package/src/route-builder.ts +3 -3
- package/src/safe-mode.ts +2 -2
- package/src/security/index.ts +4 -4
- package/src/security/org-secrets.ts +13 -9
- package/src/security/secret.ts +3 -3
- package/src/sse.ts +3 -1
- package/src/system/README.md +3 -0
- package/src/system/capabilities.ts +22 -23
- package/src/system/diagram.ts +45 -45
- package/src/system/index.ts +14 -14
- package/src/tiers.ts +1 -1
- package/src/timeouts.ts +1 -1
- package/src/tracing.ts +30 -30
- package/src/types/analytics.ts +2 -2
- package/src/usage/README.md +3 -0
- package/src/usage/execution-types.ts +69 -69
- package/src/usage/types.ts +7 -3
|
@@ -1,261 +1,263 @@
|
|
|
1
|
-
import { describe, it, expect } from
|
|
2
|
-
import type { ExecutionState } from
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import type { ExecutionState } from "../status.js";
|
|
3
3
|
import {
|
|
4
4
|
VALID_TRANSITIONS,
|
|
5
5
|
TERMINAL_STATES,
|
|
6
6
|
EFFECTIVE_TERMINAL_STATES,
|
|
7
7
|
assertValidTransition,
|
|
8
|
-
} from
|
|
9
|
-
import { LIFECYCLE_DECISIONS, applyIntent } from
|
|
10
|
-
import type { ExecutionErrorCode } from
|
|
11
|
-
import { parseExpiresAt, isConfirmationExpired } from
|
|
8
|
+
} from "../status.js";
|
|
9
|
+
import { LIFECYCLE_DECISIONS, applyIntent } from "../lifecycle.js";
|
|
10
|
+
import type { ExecutionErrorCode } from "../errors.js";
|
|
11
|
+
import { parseExpiresAt, isConfirmationExpired } from "../expiry.js";
|
|
12
12
|
|
|
13
13
|
const ALL_STATES: ExecutionState[] = [
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
]
|
|
14
|
+
"pending_confirmation",
|
|
15
|
+
"blocked_pending_approval",
|
|
16
|
+
"ready",
|
|
17
|
+
"executing",
|
|
18
|
+
"completed",
|
|
19
|
+
"completed_with_rollbacks",
|
|
20
|
+
"failed_retryable",
|
|
21
|
+
"failed_exhausted",
|
|
22
|
+
"failed_terminal",
|
|
23
|
+
"failed_with_partial_execution",
|
|
24
|
+
"cancelled",
|
|
25
|
+
"expired",
|
|
26
|
+
"undone",
|
|
27
|
+
];
|
|
28
28
|
|
|
29
29
|
// ---------------------------------------------------------------------------
|
|
30
30
|
// 1. EXHAUSTIVE TRANSITION MATRIX
|
|
31
31
|
// ---------------------------------------------------------------------------
|
|
32
|
-
describe(
|
|
32
|
+
describe("exhaustive transition matrix", () => {
|
|
33
33
|
for (const from of ALL_STATES) {
|
|
34
34
|
for (const to of ALL_STATES) {
|
|
35
|
-
const allowed = VALID_TRANSITIONS[from].includes(to)
|
|
36
|
-
it(`${from} -> ${to} should be ${allowed ?
|
|
35
|
+
const allowed = VALID_TRANSITIONS[from].includes(to);
|
|
36
|
+
it(`${from} -> ${to} should be ${allowed ? "valid" : "invalid"}`, () => {
|
|
37
37
|
if (allowed) {
|
|
38
|
-
expect(() => assertValidTransition(from, to)).not.toThrow()
|
|
38
|
+
expect(() => assertValidTransition(from, to)).not.toThrow();
|
|
39
39
|
} else {
|
|
40
40
|
expect(() => assertValidTransition(from, to)).toThrow(
|
|
41
41
|
`Invalid execution state transition: ${from} -> ${to}`,
|
|
42
|
-
)
|
|
42
|
+
);
|
|
43
43
|
}
|
|
44
|
-
})
|
|
44
|
+
});
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
-
})
|
|
47
|
+
});
|
|
48
48
|
|
|
49
49
|
// ---------------------------------------------------------------------------
|
|
50
50
|
// 2. TERMINAL_STATES CONSISTENCY
|
|
51
51
|
// ---------------------------------------------------------------------------
|
|
52
|
-
describe(
|
|
53
|
-
it(
|
|
52
|
+
describe("TERMINAL_STATES consistency", () => {
|
|
53
|
+
it("contains exactly the states with empty transition arrays", () => {
|
|
54
54
|
const expectedTerminal = ALL_STATES.filter(
|
|
55
55
|
(s) => VALID_TRANSITIONS[s].length === 0,
|
|
56
|
-
)
|
|
57
|
-
expect(expectedTerminal.length).toBeGreaterThan(0)
|
|
56
|
+
);
|
|
57
|
+
expect(expectedTerminal.length).toBeGreaterThan(0);
|
|
58
58
|
for (const state of expectedTerminal) {
|
|
59
|
-
expect(TERMINAL_STATES.has(state)).toBe(true)
|
|
59
|
+
expect(TERMINAL_STATES.has(state)).toBe(true);
|
|
60
60
|
}
|
|
61
|
-
expect(TERMINAL_STATES.size).toBe(expectedTerminal.length)
|
|
62
|
-
})
|
|
61
|
+
expect(TERMINAL_STATES.size).toBe(expectedTerminal.length);
|
|
62
|
+
});
|
|
63
63
|
|
|
64
|
-
it(
|
|
64
|
+
it("does not contain states with non-empty transition arrays", () => {
|
|
65
65
|
const nonTerminal = ALL_STATES.filter(
|
|
66
66
|
(s) => VALID_TRANSITIONS[s].length > 0,
|
|
67
|
-
)
|
|
67
|
+
);
|
|
68
68
|
for (const state of nonTerminal) {
|
|
69
|
-
expect(TERMINAL_STATES.has(state)).toBe(false)
|
|
69
|
+
expect(TERMINAL_STATES.has(state)).toBe(false);
|
|
70
70
|
}
|
|
71
|
-
})
|
|
72
|
-
})
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
73
|
|
|
74
74
|
// ---------------------------------------------------------------------------
|
|
75
75
|
// 3. EFFECTIVE_TERMINAL_STATES
|
|
76
76
|
// ---------------------------------------------------------------------------
|
|
77
|
-
describe(
|
|
78
|
-
it(
|
|
77
|
+
describe("EFFECTIVE_TERMINAL_STATES", () => {
|
|
78
|
+
it("contains all TERMINAL_STATES", () => {
|
|
79
79
|
for (const state of TERMINAL_STATES) {
|
|
80
|
-
expect(EFFECTIVE_TERMINAL_STATES.has(state)).toBe(true)
|
|
80
|
+
expect(EFFECTIVE_TERMINAL_STATES.has(state)).toBe(true);
|
|
81
81
|
}
|
|
82
|
-
})
|
|
82
|
+
});
|
|
83
83
|
|
|
84
|
-
it(
|
|
85
|
-
expect(EFFECTIVE_TERMINAL_STATES.has(
|
|
86
|
-
})
|
|
84
|
+
it("contains completed", () => {
|
|
85
|
+
expect(EFFECTIVE_TERMINAL_STATES.has("completed")).toBe(true);
|
|
86
|
+
});
|
|
87
87
|
|
|
88
|
-
it(
|
|
89
|
-
expect(EFFECTIVE_TERMINAL_STATES.size).toBe(TERMINAL_STATES.size + 1)
|
|
90
|
-
})
|
|
88
|
+
it("has size equal to TERMINAL_STATES + 1 (completed)", () => {
|
|
89
|
+
expect(EFFECTIVE_TERMINAL_STATES.size).toBe(TERMINAL_STATES.size + 1);
|
|
90
|
+
});
|
|
91
91
|
|
|
92
|
-
it(
|
|
92
|
+
it("does not contain non-terminal, non-completed states", () => {
|
|
93
93
|
const nonEffectiveTerminal = ALL_STATES.filter(
|
|
94
|
-
(s) => !TERMINAL_STATES.has(s) && s !==
|
|
95
|
-
)
|
|
94
|
+
(s) => !TERMINAL_STATES.has(s) && s !== "completed",
|
|
95
|
+
);
|
|
96
96
|
for (const state of nonEffectiveTerminal) {
|
|
97
|
-
expect(EFFECTIVE_TERMINAL_STATES.has(state)).toBe(false)
|
|
97
|
+
expect(EFFECTIVE_TERMINAL_STATES.has(state)).toBe(false);
|
|
98
98
|
}
|
|
99
|
-
})
|
|
100
|
-
})
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
101
|
|
|
102
102
|
// ---------------------------------------------------------------------------
|
|
103
103
|
// 4. DECISION TABLE KEY CONSISTENCY
|
|
104
104
|
// ---------------------------------------------------------------------------
|
|
105
|
-
describe(
|
|
106
|
-
it(
|
|
107
|
-
const transitionKeys = Object.keys(VALID_TRANSITIONS).sort()
|
|
108
|
-
const decisionKeys = Object.keys(LIFECYCLE_DECISIONS.confirm).sort()
|
|
109
|
-
expect(decisionKeys).toEqual(transitionKeys)
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
it(
|
|
113
|
-
const transitionKeys = Object.keys(VALID_TRANSITIONS).sort()
|
|
114
|
-
const decisionKeys = Object.keys(LIFECYCLE_DECISIONS.reject).sort()
|
|
115
|
-
expect(decisionKeys).toEqual(transitionKeys)
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
it(
|
|
119
|
-
const intents = Object.keys(LIFECYCLE_DECISIONS) as Array<
|
|
120
|
-
|
|
105
|
+
describe("decision table key consistency", () => {
|
|
106
|
+
it("LIFECYCLE_DECISIONS.confirm keys match VALID_TRANSITIONS keys", () => {
|
|
107
|
+
const transitionKeys = Object.keys(VALID_TRANSITIONS).sort();
|
|
108
|
+
const decisionKeys = Object.keys(LIFECYCLE_DECISIONS.confirm).sort();
|
|
109
|
+
expect(decisionKeys).toEqual(transitionKeys);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("LIFECYCLE_DECISIONS.reject keys match VALID_TRANSITIONS keys", () => {
|
|
113
|
+
const transitionKeys = Object.keys(VALID_TRANSITIONS).sort();
|
|
114
|
+
const decisionKeys = Object.keys(LIFECYCLE_DECISIONS.reject).sort();
|
|
115
|
+
expect(decisionKeys).toEqual(transitionKeys);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it("all intent rows have the same set of state keys", () => {
|
|
119
|
+
const intents = Object.keys(LIFECYCLE_DECISIONS) as Array<
|
|
120
|
+
keyof typeof LIFECYCLE_DECISIONS
|
|
121
|
+
>;
|
|
122
|
+
const referenceKeys = Object.keys(LIFECYCLE_DECISIONS[intents[0]]).sort();
|
|
121
123
|
for (const intent of intents) {
|
|
122
|
-
expect(Object.keys(LIFECYCLE_DECISIONS[intent]).sort()).toEqual(
|
|
124
|
+
expect(Object.keys(LIFECYCLE_DECISIONS[intent]).sort()).toEqual(
|
|
125
|
+
referenceKeys,
|
|
126
|
+
);
|
|
123
127
|
}
|
|
124
|
-
})
|
|
125
|
-
})
|
|
128
|
+
});
|
|
129
|
+
});
|
|
126
130
|
|
|
127
131
|
// ---------------------------------------------------------------------------
|
|
128
132
|
// 5. APPROVE-TRANSITION DRIFT
|
|
129
133
|
// ---------------------------------------------------------------------------
|
|
130
|
-
describe(
|
|
131
|
-
it(
|
|
134
|
+
describe("approve-transition drift", () => {
|
|
135
|
+
it("every state with approve decision can transition to ready", () => {
|
|
132
136
|
for (const state of ALL_STATES) {
|
|
133
|
-
if (LIFECYCLE_DECISIONS.confirm[state] ===
|
|
134
|
-
expect(
|
|
135
|
-
VALID_TRANSITIONS[state].includes('ready'),
|
|
136
|
-
).toBe(true)
|
|
137
|
+
if (LIFECYCLE_DECISIONS.confirm[state] === "approve") {
|
|
138
|
+
expect(VALID_TRANSITIONS[state].includes("ready")).toBe(true);
|
|
137
139
|
}
|
|
138
140
|
}
|
|
139
|
-
})
|
|
140
|
-
})
|
|
141
|
+
});
|
|
142
|
+
});
|
|
141
143
|
|
|
142
144
|
// ---------------------------------------------------------------------------
|
|
143
145
|
// 6. APPLY_INTENT UNIT TESTS
|
|
144
146
|
// ---------------------------------------------------------------------------
|
|
145
|
-
describe(
|
|
146
|
-
it(
|
|
147
|
-
expect(applyIntent(
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
it(
|
|
151
|
-
expect(applyIntent(
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
it(
|
|
155
|
-
expect(applyIntent(
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
it(
|
|
159
|
-
expect(applyIntent(
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
it(
|
|
163
|
-
expect(applyIntent(
|
|
164
|
-
|
|
165
|
-
)
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
it(
|
|
169
|
-
expect(applyIntent(
|
|
170
|
-
})
|
|
171
|
-
|
|
172
|
-
it(
|
|
173
|
-
expect(applyIntent(
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
it(
|
|
177
|
-
expect(applyIntent(
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
it(
|
|
181
|
-
expect(applyIntent(
|
|
182
|
-
})
|
|
183
|
-
|
|
184
|
-
it(
|
|
185
|
-
expect(applyIntent(
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
it(
|
|
189
|
-
expect(applyIntent(
|
|
190
|
-
})
|
|
191
|
-
|
|
192
|
-
it(
|
|
193
|
-
expect(applyIntent(
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
it(
|
|
197
|
-
expect(applyIntent(
|
|
198
|
-
})
|
|
199
|
-
})
|
|
147
|
+
describe("applyIntent", () => {
|
|
148
|
+
it("pending_confirmation + confirm = approve", () => {
|
|
149
|
+
expect(applyIntent("pending_confirmation", "confirm")).toBe("approve");
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("expired + confirm = expired", () => {
|
|
153
|
+
expect(applyIntent("expired", "confirm")).toBe("expired");
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it("cancelled + confirm = conflict", () => {
|
|
157
|
+
expect(applyIntent("cancelled", "confirm")).toBe("conflict");
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it("ready + confirm = already_confirmed", () => {
|
|
161
|
+
expect(applyIntent("ready", "confirm")).toBe("already_confirmed");
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("blocked_pending_approval + confirm = awaiting_approval", () => {
|
|
165
|
+
expect(applyIntent("blocked_pending_approval", "confirm")).toBe(
|
|
166
|
+
"awaiting_approval",
|
|
167
|
+
);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("failed_terminal + confirm = conflict", () => {
|
|
171
|
+
expect(applyIntent("failed_terminal", "confirm")).toBe("conflict");
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it("undone + confirm = conflict", () => {
|
|
175
|
+
expect(applyIntent("undone", "confirm")).toBe("conflict");
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it("pending_confirmation + reject resolves as approve (rejection uses same cancel path)", () => {
|
|
179
|
+
expect(applyIntent("pending_confirmation", "reject")).toBe("approve");
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("expired + reject = expired", () => {
|
|
183
|
+
expect(applyIntent("expired", "reject")).toBe("expired");
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("cancelled + reject = conflict", () => {
|
|
187
|
+
expect(applyIntent("cancelled", "reject")).toBe("conflict");
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it("ready + reject = conflict", () => {
|
|
191
|
+
expect(applyIntent("ready", "reject")).toBe("conflict");
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it("executing + reject = conflict", () => {
|
|
195
|
+
expect(applyIntent("executing", "reject")).toBe("conflict");
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it("completed + reject = conflict", () => {
|
|
199
|
+
expect(applyIntent("completed", "reject")).toBe("conflict");
|
|
200
|
+
});
|
|
201
|
+
});
|
|
200
202
|
|
|
201
203
|
// ---------------------------------------------------------------------------
|
|
202
204
|
// 7. EXECUTION_ERROR TYPE TESTS
|
|
203
205
|
// ---------------------------------------------------------------------------
|
|
204
|
-
describe(
|
|
205
|
-
it(
|
|
206
|
+
describe("ExecutionErrorCode", () => {
|
|
207
|
+
it("covers all expected error codes", () => {
|
|
206
208
|
const codes: ExecutionErrorCode[] = [
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
]
|
|
214
|
-
expect(codes).toHaveLength(6)
|
|
215
|
-
})
|
|
216
|
-
})
|
|
209
|
+
"execution_expired",
|
|
210
|
+
"execution_already_confirmed",
|
|
211
|
+
"execution_awaiting_approval",
|
|
212
|
+
"execution_not_found",
|
|
213
|
+
"execution_forbidden",
|
|
214
|
+
"execution_invalid_transition",
|
|
215
|
+
];
|
|
216
|
+
expect(codes).toHaveLength(6);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
217
219
|
|
|
218
220
|
// ---------------------------------------------------------------------------
|
|
219
221
|
// 8. EXPIRY HELPER TESTS
|
|
220
222
|
// ---------------------------------------------------------------------------
|
|
221
|
-
describe(
|
|
222
|
-
it(
|
|
223
|
-
expect(parseExpiresAt(undefined)).toBeUndefined()
|
|
224
|
-
})
|
|
225
|
-
|
|
226
|
-
it(
|
|
227
|
-
expect(parseExpiresAt(
|
|
228
|
-
})
|
|
229
|
-
|
|
230
|
-
it(
|
|
231
|
-
const result = parseExpiresAt(
|
|
232
|
-
expect(result).toBe(new Date(
|
|
233
|
-
})
|
|
234
|
-
|
|
235
|
-
it(
|
|
236
|
-
expect(parseExpiresAt(
|
|
237
|
-
})
|
|
238
|
-
})
|
|
239
|
-
|
|
240
|
-
describe(
|
|
241
|
-
it(
|
|
242
|
-
expect(isConfirmationExpired(undefined)).toBe(false)
|
|
243
|
-
})
|
|
244
|
-
|
|
245
|
-
it(
|
|
246
|
-
const pastMs = Date.now() - 60_000
|
|
247
|
-
expect(isConfirmationExpired(pastMs)).toBe(true)
|
|
248
|
-
})
|
|
249
|
-
|
|
250
|
-
it(
|
|
251
|
-
const futureMs = Date.now() + 60_000
|
|
252
|
-
expect(isConfirmationExpired(futureMs)).toBe(false)
|
|
253
|
-
})
|
|
254
|
-
|
|
255
|
-
it(
|
|
256
|
-
const expiresAtMs = 1000
|
|
257
|
-
expect(isConfirmationExpired(expiresAtMs, 999)).toBe(false)
|
|
258
|
-
expect(isConfirmationExpired(expiresAtMs, 1000)).toBe(true)
|
|
259
|
-
expect(isConfirmationExpired(expiresAtMs, 1001)).toBe(true)
|
|
260
|
-
})
|
|
261
|
-
})
|
|
223
|
+
describe("parseExpiresAt", () => {
|
|
224
|
+
it("returns undefined for undefined input", () => {
|
|
225
|
+
expect(parseExpiresAt(undefined)).toBeUndefined();
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it("returns undefined for invalid date string", () => {
|
|
229
|
+
expect(parseExpiresAt("invalid")).toBeUndefined();
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it("returns correct epoch ms for valid ISO string", () => {
|
|
233
|
+
const result = parseExpiresAt("2026-01-01T00:00:00Z");
|
|
234
|
+
expect(result).toBe(new Date("2026-01-01T00:00:00Z").getTime());
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it("returns undefined for empty string", () => {
|
|
238
|
+
expect(parseExpiresAt("")).toBeUndefined();
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
describe("isConfirmationExpired", () => {
|
|
243
|
+
it("returns false for undefined expiresAtMs", () => {
|
|
244
|
+
expect(isConfirmationExpired(undefined)).toBe(false);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it("returns true for past timestamp", () => {
|
|
248
|
+
const pastMs = Date.now() - 60_000;
|
|
249
|
+
expect(isConfirmationExpired(pastMs)).toBe(true);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it("returns false for future timestamp", () => {
|
|
253
|
+
const futureMs = Date.now() + 60_000;
|
|
254
|
+
expect(isConfirmationExpired(futureMs)).toBe(false);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it("works with custom now parameter", () => {
|
|
258
|
+
const expiresAtMs = 1000;
|
|
259
|
+
expect(isConfirmationExpired(expiresAtMs, 999)).toBe(false);
|
|
260
|
+
expect(isConfirmationExpired(expiresAtMs, 1000)).toBe(true);
|
|
261
|
+
expect(isConfirmationExpired(expiresAtMs, 1001)).toBe(true);
|
|
262
|
+
});
|
|
263
|
+
});
|