@voyantjs/bookings 0.52.2 → 0.52.4

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/README.md CHANGED
@@ -34,6 +34,22 @@ Session reads now include first-class persisted wizard state, and repricing
34
34
  supports both preview mode and `applyToSession` mode for committing the priced
35
35
  room/unit selection back onto the booking session totals.
36
36
 
37
+ ## Action-ledger approvals
38
+
39
+ Agent/workflow booking status mutations that require approval return `202` with
40
+ the requested action and approval ids. These approval-required requests must
41
+ send `Idempotency-Key`; the key is fingerprinted with the command input and
42
+ approval policy inputs, so replaying the key with different input returns a
43
+ conflict.
44
+
45
+ After an approval is approved, execute the same status mutation again with the
46
+ `ACTION_LEDGER_APPROVAL_ID_HEADER` header from `@voyantjs/action-ledger`. The
47
+ route validates that the approval is approved, unexpired, linked to the same
48
+ requested action and current principal, and command-equivalent to the original
49
+ request before it mutates the booking. Approved execution ledger fields are
50
+ stamped through `buildActionLedgerApprovedExecutionFields(...)` so execution
51
+ entries consistently link back to the requested action and approval.
52
+
37
53
  ## Entities
38
54
 
39
55
  - **Bookings** (`book`)
@@ -0,0 +1,306 @@
1
+ export declare const BOOKING_PII_READ_CAPABILITY: {
2
+ readonly id: "bookings-pii:read";
3
+ readonly version: "v1";
4
+ readonly resource: "booking_traveler";
5
+ readonly action: "read";
6
+ readonly risk: "high";
7
+ readonly ledgerPolicy: "required";
8
+ readonly approvalPolicy: "none";
9
+ readonly reversible: false;
10
+ readonly allowedActorTypes: readonly ["staff", "system"];
11
+ readonly requiredGrants: readonly [{
12
+ readonly resource: "bookings-pii";
13
+ readonly action: "read";
14
+ }];
15
+ };
16
+ export declare const BOOKING_STATUS_CAPABILITIES: {
17
+ readonly confirm: {
18
+ readonly id: "bookings:status:confirm";
19
+ readonly version: "v1";
20
+ readonly resource: "booking";
21
+ readonly action: "confirm";
22
+ readonly risk: "medium";
23
+ readonly ledgerPolicy: "required";
24
+ readonly approvalPolicy: "none";
25
+ readonly reversible: false;
26
+ readonly allowedActorTypes: readonly ["staff", "system"];
27
+ readonly requiredGrants: readonly [{
28
+ readonly resource: "bookings";
29
+ readonly action: "write";
30
+ }];
31
+ };
32
+ readonly expire: {
33
+ readonly id: "bookings:status:expire";
34
+ readonly version: "v1";
35
+ readonly resource: "booking";
36
+ readonly action: "expire";
37
+ readonly risk: "medium";
38
+ readonly ledgerPolicy: "required";
39
+ readonly approvalPolicy: "none";
40
+ readonly reversible: false;
41
+ readonly allowedActorTypes: readonly ["staff", "system"];
42
+ readonly requiredGrants: readonly [{
43
+ readonly resource: "bookings";
44
+ readonly action: "write";
45
+ }];
46
+ };
47
+ readonly cancel: {
48
+ readonly id: "bookings:status:cancel";
49
+ readonly version: "v1";
50
+ readonly resource: "booking";
51
+ readonly action: "cancel";
52
+ readonly risk: "high";
53
+ readonly ledgerPolicy: "required";
54
+ readonly approvalPolicy: "conditional";
55
+ readonly reversible: false;
56
+ readonly allowedActorTypes: readonly ["staff", "system"];
57
+ readonly requiredGrants: readonly [{
58
+ readonly resource: "bookings";
59
+ readonly action: "write";
60
+ }];
61
+ };
62
+ readonly start: {
63
+ readonly id: "bookings:status:start";
64
+ readonly version: "v1";
65
+ readonly resource: "booking";
66
+ readonly action: "start";
67
+ readonly risk: "medium";
68
+ readonly ledgerPolicy: "required";
69
+ readonly approvalPolicy: "none";
70
+ readonly reversible: false;
71
+ readonly allowedActorTypes: readonly ["staff", "system"];
72
+ readonly requiredGrants: readonly [{
73
+ readonly resource: "bookings";
74
+ readonly action: "write";
75
+ }];
76
+ };
77
+ readonly complete: {
78
+ readonly id: "bookings:status:complete";
79
+ readonly version: "v1";
80
+ readonly resource: "booking";
81
+ readonly action: "complete";
82
+ readonly risk: "medium";
83
+ readonly ledgerPolicy: "required";
84
+ readonly approvalPolicy: "none";
85
+ readonly reversible: false;
86
+ readonly allowedActorTypes: readonly ["staff", "system"];
87
+ readonly requiredGrants: readonly [{
88
+ readonly resource: "bookings";
89
+ readonly action: "write";
90
+ }];
91
+ };
92
+ readonly override: {
93
+ readonly id: "bookings:status:override";
94
+ readonly version: "v1";
95
+ readonly resource: "booking";
96
+ readonly action: "override_status";
97
+ readonly risk: "high";
98
+ readonly ledgerPolicy: "required";
99
+ readonly approvalPolicy: "conditional";
100
+ readonly reversible: false;
101
+ readonly allowedActorTypes: readonly ["staff", "system"];
102
+ readonly requiredGrants: readonly [{
103
+ readonly resource: "bookings";
104
+ readonly action: "write";
105
+ }];
106
+ };
107
+ };
108
+ export declare const BOOKING_ACTION_LEDGER_CAPABILITIES: readonly [{
109
+ readonly id: "bookings-pii:read";
110
+ readonly version: "v1";
111
+ readonly resource: "booking_traveler";
112
+ readonly action: "read";
113
+ readonly risk: "high";
114
+ readonly ledgerPolicy: "required";
115
+ readonly approvalPolicy: "none";
116
+ readonly reversible: false;
117
+ readonly allowedActorTypes: readonly ["staff", "system"];
118
+ readonly requiredGrants: readonly [{
119
+ readonly resource: "bookings-pii";
120
+ readonly action: "read";
121
+ }];
122
+ }, ...({
123
+ readonly id: "bookings:status:confirm";
124
+ readonly version: "v1";
125
+ readonly resource: "booking";
126
+ readonly action: "confirm";
127
+ readonly risk: "medium";
128
+ readonly ledgerPolicy: "required";
129
+ readonly approvalPolicy: "none";
130
+ readonly reversible: false;
131
+ readonly allowedActorTypes: readonly ["staff", "system"];
132
+ readonly requiredGrants: readonly [{
133
+ readonly resource: "bookings";
134
+ readonly action: "write";
135
+ }];
136
+ } | {
137
+ readonly id: "bookings:status:expire";
138
+ readonly version: "v1";
139
+ readonly resource: "booking";
140
+ readonly action: "expire";
141
+ readonly risk: "medium";
142
+ readonly ledgerPolicy: "required";
143
+ readonly approvalPolicy: "none";
144
+ readonly reversible: false;
145
+ readonly allowedActorTypes: readonly ["staff", "system"];
146
+ readonly requiredGrants: readonly [{
147
+ readonly resource: "bookings";
148
+ readonly action: "write";
149
+ }];
150
+ } | {
151
+ readonly id: "bookings:status:cancel";
152
+ readonly version: "v1";
153
+ readonly resource: "booking";
154
+ readonly action: "cancel";
155
+ readonly risk: "high";
156
+ readonly ledgerPolicy: "required";
157
+ readonly approvalPolicy: "conditional";
158
+ readonly reversible: false;
159
+ readonly allowedActorTypes: readonly ["staff", "system"];
160
+ readonly requiredGrants: readonly [{
161
+ readonly resource: "bookings";
162
+ readonly action: "write";
163
+ }];
164
+ } | {
165
+ readonly id: "bookings:status:start";
166
+ readonly version: "v1";
167
+ readonly resource: "booking";
168
+ readonly action: "start";
169
+ readonly risk: "medium";
170
+ readonly ledgerPolicy: "required";
171
+ readonly approvalPolicy: "none";
172
+ readonly reversible: false;
173
+ readonly allowedActorTypes: readonly ["staff", "system"];
174
+ readonly requiredGrants: readonly [{
175
+ readonly resource: "bookings";
176
+ readonly action: "write";
177
+ }];
178
+ } | {
179
+ readonly id: "bookings:status:complete";
180
+ readonly version: "v1";
181
+ readonly resource: "booking";
182
+ readonly action: "complete";
183
+ readonly risk: "medium";
184
+ readonly ledgerPolicy: "required";
185
+ readonly approvalPolicy: "none";
186
+ readonly reversible: false;
187
+ readonly allowedActorTypes: readonly ["staff", "system"];
188
+ readonly requiredGrants: readonly [{
189
+ readonly resource: "bookings";
190
+ readonly action: "write";
191
+ }];
192
+ } | {
193
+ readonly id: "bookings:status:override";
194
+ readonly version: "v1";
195
+ readonly resource: "booking";
196
+ readonly action: "override_status";
197
+ readonly risk: "high";
198
+ readonly ledgerPolicy: "required";
199
+ readonly approvalPolicy: "conditional";
200
+ readonly reversible: false;
201
+ readonly allowedActorTypes: readonly ["staff", "system"];
202
+ readonly requiredGrants: readonly [{
203
+ readonly resource: "bookings";
204
+ readonly action: "write";
205
+ }];
206
+ })[]];
207
+ export declare const bookingActionLedgerCapabilityRegistry: import("@voyantjs/action-ledger").ActionLedgerCapabilityRegistry<{
208
+ readonly id: "bookings-pii:read";
209
+ readonly version: "v1";
210
+ readonly resource: "booking_traveler";
211
+ readonly action: "read";
212
+ readonly risk: "high";
213
+ readonly ledgerPolicy: "required";
214
+ readonly approvalPolicy: "none";
215
+ readonly reversible: false;
216
+ readonly allowedActorTypes: readonly ["staff", "system"];
217
+ readonly requiredGrants: readonly [{
218
+ readonly resource: "bookings-pii";
219
+ readonly action: "read";
220
+ }];
221
+ } | {
222
+ readonly id: "bookings:status:confirm";
223
+ readonly version: "v1";
224
+ readonly resource: "booking";
225
+ readonly action: "confirm";
226
+ readonly risk: "medium";
227
+ readonly ledgerPolicy: "required";
228
+ readonly approvalPolicy: "none";
229
+ readonly reversible: false;
230
+ readonly allowedActorTypes: readonly ["staff", "system"];
231
+ readonly requiredGrants: readonly [{
232
+ readonly resource: "bookings";
233
+ readonly action: "write";
234
+ }];
235
+ } | {
236
+ readonly id: "bookings:status:expire";
237
+ readonly version: "v1";
238
+ readonly resource: "booking";
239
+ readonly action: "expire";
240
+ readonly risk: "medium";
241
+ readonly ledgerPolicy: "required";
242
+ readonly approvalPolicy: "none";
243
+ readonly reversible: false;
244
+ readonly allowedActorTypes: readonly ["staff", "system"];
245
+ readonly requiredGrants: readonly [{
246
+ readonly resource: "bookings";
247
+ readonly action: "write";
248
+ }];
249
+ } | {
250
+ readonly id: "bookings:status:cancel";
251
+ readonly version: "v1";
252
+ readonly resource: "booking";
253
+ readonly action: "cancel";
254
+ readonly risk: "high";
255
+ readonly ledgerPolicy: "required";
256
+ readonly approvalPolicy: "conditional";
257
+ readonly reversible: false;
258
+ readonly allowedActorTypes: readonly ["staff", "system"];
259
+ readonly requiredGrants: readonly [{
260
+ readonly resource: "bookings";
261
+ readonly action: "write";
262
+ }];
263
+ } | {
264
+ readonly id: "bookings:status:start";
265
+ readonly version: "v1";
266
+ readonly resource: "booking";
267
+ readonly action: "start";
268
+ readonly risk: "medium";
269
+ readonly ledgerPolicy: "required";
270
+ readonly approvalPolicy: "none";
271
+ readonly reversible: false;
272
+ readonly allowedActorTypes: readonly ["staff", "system"];
273
+ readonly requiredGrants: readonly [{
274
+ readonly resource: "bookings";
275
+ readonly action: "write";
276
+ }];
277
+ } | {
278
+ readonly id: "bookings:status:complete";
279
+ readonly version: "v1";
280
+ readonly resource: "booking";
281
+ readonly action: "complete";
282
+ readonly risk: "medium";
283
+ readonly ledgerPolicy: "required";
284
+ readonly approvalPolicy: "none";
285
+ readonly reversible: false;
286
+ readonly allowedActorTypes: readonly ["staff", "system"];
287
+ readonly requiredGrants: readonly [{
288
+ readonly resource: "bookings";
289
+ readonly action: "write";
290
+ }];
291
+ } | {
292
+ readonly id: "bookings:status:override";
293
+ readonly version: "v1";
294
+ readonly resource: "booking";
295
+ readonly action: "override_status";
296
+ readonly risk: "high";
297
+ readonly ledgerPolicy: "required";
298
+ readonly approvalPolicy: "conditional";
299
+ readonly reversible: false;
300
+ readonly allowedActorTypes: readonly ["staff", "system"];
301
+ readonly requiredGrants: readonly [{
302
+ readonly resource: "bookings";
303
+ readonly action: "write";
304
+ }];
305
+ }>;
306
+ //# sourceMappingURL=action-ledger-capabilities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-ledger-capabilities.d.ts","sourceRoot":"","sources":["../src/action-ledger-capabilities.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;CAWa,CAAA;AAErD,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyE6B,CAAA;AAErE,eAAO,MAAM,kCAAkC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAGrC,CAAA;AAEV,eAAO,MAAM,qCAAqC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAEjD,CAAA"}
@@ -0,0 +1,92 @@
1
+ import { createActionLedgerCapabilityRegistry, } from "@voyantjs/action-ledger";
2
+ export const BOOKING_PII_READ_CAPABILITY = {
3
+ id: "bookings-pii:read",
4
+ version: "v1",
5
+ resource: "booking_traveler",
6
+ action: "read",
7
+ risk: "high",
8
+ ledgerPolicy: "required",
9
+ approvalPolicy: "none",
10
+ reversible: false,
11
+ allowedActorTypes: ["staff", "system"],
12
+ requiredGrants: [{ resource: "bookings-pii", action: "read" }],
13
+ };
14
+ export const BOOKING_STATUS_CAPABILITIES = {
15
+ confirm: {
16
+ id: "bookings:status:confirm",
17
+ version: "v1",
18
+ resource: "booking",
19
+ action: "confirm",
20
+ risk: "medium",
21
+ ledgerPolicy: "required",
22
+ approvalPolicy: "none",
23
+ reversible: false,
24
+ allowedActorTypes: ["staff", "system"],
25
+ requiredGrants: [{ resource: "bookings", action: "write" }],
26
+ },
27
+ expire: {
28
+ id: "bookings:status:expire",
29
+ version: "v1",
30
+ resource: "booking",
31
+ action: "expire",
32
+ risk: "medium",
33
+ ledgerPolicy: "required",
34
+ approvalPolicy: "none",
35
+ reversible: false,
36
+ allowedActorTypes: ["staff", "system"],
37
+ requiredGrants: [{ resource: "bookings", action: "write" }],
38
+ },
39
+ cancel: {
40
+ id: "bookings:status:cancel",
41
+ version: "v1",
42
+ resource: "booking",
43
+ action: "cancel",
44
+ risk: "high",
45
+ ledgerPolicy: "required",
46
+ approvalPolicy: "conditional",
47
+ reversible: false,
48
+ allowedActorTypes: ["staff", "system"],
49
+ requiredGrants: [{ resource: "bookings", action: "write" }],
50
+ },
51
+ start: {
52
+ id: "bookings:status:start",
53
+ version: "v1",
54
+ resource: "booking",
55
+ action: "start",
56
+ risk: "medium",
57
+ ledgerPolicy: "required",
58
+ approvalPolicy: "none",
59
+ reversible: false,
60
+ allowedActorTypes: ["staff", "system"],
61
+ requiredGrants: [{ resource: "bookings", action: "write" }],
62
+ },
63
+ complete: {
64
+ id: "bookings:status:complete",
65
+ version: "v1",
66
+ resource: "booking",
67
+ action: "complete",
68
+ risk: "medium",
69
+ ledgerPolicy: "required",
70
+ approvalPolicy: "none",
71
+ reversible: false,
72
+ allowedActorTypes: ["staff", "system"],
73
+ requiredGrants: [{ resource: "bookings", action: "write" }],
74
+ },
75
+ override: {
76
+ id: "bookings:status:override",
77
+ version: "v1",
78
+ resource: "booking",
79
+ action: "override_status",
80
+ risk: "high",
81
+ ledgerPolicy: "required",
82
+ approvalPolicy: "conditional",
83
+ reversible: false,
84
+ allowedActorTypes: ["staff", "system"],
85
+ requiredGrants: [{ resource: "bookings", action: "write" }],
86
+ },
87
+ };
88
+ export const BOOKING_ACTION_LEDGER_CAPABILITIES = [
89
+ BOOKING_PII_READ_CAPABILITY,
90
+ ...Object.values(BOOKING_STATUS_CAPABILITIES),
91
+ ];
92
+ export const bookingActionLedgerCapabilityRegistry = createActionLedgerCapabilityRegistry(BOOKING_ACTION_LEDGER_CAPABILITIES);
@@ -0,0 +1,30 @@
1
+ import type { AnyDrizzleDb } from "@voyantjs/db";
2
+ import type { BookingActionLedgerDriftCheck, CheckBookingActionLedgerDriftInput, CheckBookingActionLedgerDriftResult } from "./action-ledger-drift.js";
3
+ export interface BookingActionLedgerDriftRemediationItem {
4
+ check: BookingActionLedgerDriftCheck;
5
+ missingCount: number;
6
+ sampleTargetIds: string[];
7
+ sampleTruncated: boolean;
8
+ recommendedBackfillActionName: string;
9
+ targetType: string;
10
+ targetIdKind: string;
11
+ mode: "dry_run";
12
+ note: string;
13
+ }
14
+ export interface BookingActionLedgerDriftRemediationPlan {
15
+ mode: "dry_run";
16
+ generatedAt: string;
17
+ createdAtFrom: string | null;
18
+ sampleLimit: number | null;
19
+ totalMissingCount: number;
20
+ items: BookingActionLedgerDriftRemediationItem[];
21
+ }
22
+ export interface BuildBookingActionLedgerDriftRemediationPlanInput {
23
+ drift: CheckBookingActionLedgerDriftResult;
24
+ createdAtFrom?: CheckBookingActionLedgerDriftInput["createdAtFrom"];
25
+ sampleLimit?: number | null;
26
+ generatedAt?: Date | string;
27
+ }
28
+ export declare function planBookingActionLedgerDriftRemediation(db: AnyDrizzleDb, input?: CheckBookingActionLedgerDriftInput): Promise<BookingActionLedgerDriftRemediationPlan>;
29
+ export declare function buildBookingActionLedgerDriftRemediationPlan({ drift, createdAtFrom, sampleLimit, generatedAt, }: BuildBookingActionLedgerDriftRemediationPlanInput): BookingActionLedgerDriftRemediationPlan;
30
+ //# sourceMappingURL=action-ledger-drift-remediation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-ledger-drift-remediation.d.ts","sourceRoot":"","sources":["../src/action-ledger-drift-remediation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,KAAK,EACV,6BAA6B,EAC7B,kCAAkC,EAClC,mCAAmC,EACpC,MAAM,0BAA0B,CAAA;AAgDjC,MAAM,WAAW,uCAAuC;IACtD,KAAK,EAAE,6BAA6B,CAAA;IACpC,YAAY,EAAE,MAAM,CAAA;IACpB,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,eAAe,EAAE,OAAO,CAAA;IACxB,6BAA6B,EAAE,MAAM,CAAA;IACrC,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,SAAS,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,uCAAuC;IACtD,IAAI,EAAE,SAAS,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,iBAAiB,EAAE,MAAM,CAAA;IACzB,KAAK,EAAE,uCAAuC,EAAE,CAAA;CACjD;AAED,MAAM,WAAW,iDAAiD;IAChE,KAAK,EAAE,mCAAmC,CAAA;IAC1C,aAAa,CAAC,EAAE,kCAAkC,CAAC,eAAe,CAAC,CAAA;IACnE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,WAAW,CAAC,EAAE,IAAI,GAAG,MAAM,CAAA;CAC5B;AAED,wBAAsB,uCAAuC,CAC3D,EAAE,EAAE,YAAY,EAChB,KAAK,GAAE,kCAAuC,GAC7C,OAAO,CAAC,uCAAuC,CAAC,CAOlD;AAED,wBAAgB,4CAA4C,CAAC,EAC3D,KAAK,EACL,aAAa,EACb,WAAW,EACX,WAAwB,GACzB,EAAE,iDAAiD,GAAG,uCAAuC,CA+B7F"}
@@ -0,0 +1,85 @@
1
+ import { checkBookingActionLedgerDrift } from "./action-ledger-drift.js";
2
+ const BACKFILL_ACTION_BY_CHECK = {
3
+ booking_confirmed: {
4
+ actionName: "booking.status.confirm",
5
+ targetType: "booking",
6
+ targetIdKind: "booking_id",
7
+ },
8
+ booking_expired: {
9
+ actionName: "booking.status.expire",
10
+ targetType: "booking",
11
+ targetIdKind: "booking_id",
12
+ },
13
+ booking_cancelled: {
14
+ actionName: "booking.status.cancel",
15
+ targetType: "booking",
16
+ targetIdKind: "booking_id",
17
+ },
18
+ booking_completed: {
19
+ actionName: "booking.status.complete",
20
+ targetType: "booking",
21
+ targetIdKind: "booking_id",
22
+ },
23
+ booking_item: {
24
+ actionName: "booking.item.create",
25
+ targetType: "booking_item",
26
+ targetIdKind: "booking_item_id",
27
+ },
28
+ booking_traveler: {
29
+ actionName: "booking.traveler.create",
30
+ targetType: "booking_traveler",
31
+ targetIdKind: "booking_traveler_id",
32
+ },
33
+ booking_traveler_travel_details: {
34
+ actionName: "booking.traveler_travel_details.update",
35
+ targetType: "booking_traveler",
36
+ targetIdKind: "booking_traveler_id",
37
+ },
38
+ };
39
+ export async function planBookingActionLedgerDriftRemediation(db, input = {}) {
40
+ const drift = await checkBookingActionLedgerDrift(db, input);
41
+ return buildBookingActionLedgerDriftRemediationPlan({
42
+ drift,
43
+ createdAtFrom: input.createdAtFrom,
44
+ sampleLimit: input.sampleLimit,
45
+ });
46
+ }
47
+ export function buildBookingActionLedgerDriftRemediationPlan({ drift, createdAtFrom, sampleLimit, generatedAt = new Date(), }) {
48
+ const generatedAtDate = generatedAt instanceof Date ? generatedAt : new Date(generatedAt);
49
+ if (Number.isNaN(generatedAtDate.getTime())) {
50
+ throw new Error("generatedAt must be a valid date");
51
+ }
52
+ const items = drift.rows
53
+ .filter((row) => row.missingCount > 0)
54
+ .map((row) => {
55
+ const action = BACKFILL_ACTION_BY_CHECK[row.check];
56
+ return {
57
+ check: row.check,
58
+ missingCount: row.missingCount,
59
+ sampleTargetIds: row.sampleIds,
60
+ sampleTruncated: row.missingCount > row.sampleIds.length,
61
+ recommendedBackfillActionName: action.actionName,
62
+ targetType: action.targetType,
63
+ targetIdKind: action.targetIdKind,
64
+ mode: "dry_run",
65
+ note: "Dry run only. Review source rows and choose an explicit historical actor before writing backfill ledger entries.",
66
+ };
67
+ });
68
+ return {
69
+ mode: "dry_run",
70
+ generatedAt: generatedAtDate.toISOString(),
71
+ createdAtFrom: normalizeNullableDate(createdAtFrom),
72
+ sampleLimit: sampleLimit ?? null,
73
+ totalMissingCount: items.reduce((sum, item) => sum + item.missingCount, 0),
74
+ items,
75
+ };
76
+ }
77
+ function normalizeNullableDate(value) {
78
+ if (!value)
79
+ return null;
80
+ const date = value instanceof Date ? value : new Date(value);
81
+ if (Number.isNaN(date.getTime())) {
82
+ throw new Error("createdAtFrom must be a valid date");
83
+ }
84
+ return date.toISOString();
85
+ }
@@ -0,0 +1,29 @@
1
+ import type { AnyDrizzleDb } from "@voyantjs/db";
2
+ import { type SQL } from "drizzle-orm";
3
+ export type BookingActionLedgerDriftCheck = "booking_confirmed" | "booking_expired" | "booking_cancelled" | "booking_completed" | "booking_item" | "booking_traveler" | "booking_traveler_travel_details";
4
+ export interface CheckBookingActionLedgerDriftInput {
5
+ createdAtFrom?: Date | string | null;
6
+ sampleLimit?: number | null;
7
+ }
8
+ export interface BookingActionLedgerDriftRow {
9
+ check: BookingActionLedgerDriftCheck;
10
+ missingCount: number;
11
+ sampleIds: string[];
12
+ }
13
+ export interface CheckBookingActionLedgerDriftResult {
14
+ ok: boolean;
15
+ rows: BookingActionLedgerDriftRow[];
16
+ }
17
+ interface BookingActionLedgerDriftQueryRow extends Record<string, unknown> {
18
+ check: BookingActionLedgerDriftCheck;
19
+ missing_count: number | string;
20
+ sample_ids: string[] | null;
21
+ }
22
+ export declare function buildBookingActionLedgerDriftQueries(input?: CheckBookingActionLedgerDriftInput): Record<BookingActionLedgerDriftCheck, SQL<BookingActionLedgerDriftQueryRow>>;
23
+ export declare function checkBookingActionLedgerDrift(db: AnyDrizzleDb, input?: CheckBookingActionLedgerDriftInput): Promise<CheckBookingActionLedgerDriftResult>;
24
+ declare function normalizeRow(row: BookingActionLedgerDriftQueryRow): BookingActionLedgerDriftRow;
25
+ export declare const __test__: {
26
+ normalizeRow: typeof normalizeRow;
27
+ };
28
+ export {};
29
+ //# sourceMappingURL=action-ledger-drift.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-ledger-drift.d.ts","sourceRoot":"","sources":["../src/action-ledger-drift.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,EAAE,KAAK,GAAG,EAAwB,MAAM,aAAa,CAAA;AAsB5D,MAAM,MAAM,6BAA6B,GACrC,mBAAmB,GACnB,iBAAiB,GACjB,mBAAmB,GACnB,mBAAmB,GACnB,cAAc,GACd,kBAAkB,GAClB,iCAAiC,CAAA;AAErC,MAAM,WAAW,kCAAkC;IACjD,aAAa,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAAA;IACpC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AAED,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,6BAA6B,CAAA;IACpC,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,EAAE,CAAA;CACpB;AAED,MAAM,WAAW,mCAAmC;IAClD,EAAE,EAAE,OAAO,CAAA;IACX,IAAI,EAAE,2BAA2B,EAAE,CAAA;CACpC;AAED,UAAU,gCAAiC,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACxE,KAAK,EAAE,6BAA6B,CAAA;IACpC,aAAa,EAAE,MAAM,GAAG,MAAM,CAAA;IAC9B,UAAU,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;CAC5B;AAED,wBAAgB,oCAAoC,CAClD,KAAK,GAAE,kCAAuC,GAC7C,MAAM,CAAC,6BAA6B,EAAE,GAAG,CAAC,gCAAgC,CAAC,CAAC,CA4H9E;AAED,wBAAsB,6BAA6B,CACjD,EAAE,EAAE,YAAY,EAChB,KAAK,GAAE,kCAAuC,GAC7C,OAAO,CAAC,mCAAmC,CAAC,CAmB9C;AA8DD,iBAAS,YAAY,CAAC,GAAG,EAAE,gCAAgC,GAAG,2BAA2B,CAMxF;AAED,eAAO,MAAM,QAAQ;;CAEpB,CAAA"}