@voyantjs/legal 0.6.9 → 0.8.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.
@@ -0,0 +1,129 @@
1
+ import { bookingsService } from "@voyantjs/bookings";
2
+ import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
3
+ import type { ContractDocumentGenerator } from "./service-documents.js";
4
+ /**
5
+ * Event shape emitted by `@voyantjs/bookings` on confirm. Duplicated here so
6
+ * legal doesn't have to import the bookings service just for the interface —
7
+ * the concrete `bookingsService` lookup happens inside the handler.
8
+ */
9
+ export interface BookingConfirmedLikeEvent {
10
+ bookingId: string;
11
+ bookingNumber: string;
12
+ actorId: string | null;
13
+ }
14
+ /**
15
+ * Variables passed to the contract template at render time. Consumers can
16
+ * augment via `resolveVariables`; the built-in resolver supplies the fields
17
+ * the default contract template expects.
18
+ */
19
+ export interface DefaultContractVariables {
20
+ contract: {
21
+ issuedAt: string;
22
+ date: string;
23
+ };
24
+ booking: {
25
+ id: string;
26
+ number: string;
27
+ status: string;
28
+ currency: string | null;
29
+ startDate: string | null;
30
+ endDate: string | null;
31
+ pax: number | null;
32
+ internalNotes: string | null;
33
+ totalAmountCents: number | null;
34
+ };
35
+ travelers: Array<{
36
+ id: string;
37
+ firstName: string;
38
+ lastName: string;
39
+ email: string | null;
40
+ phone: string | null;
41
+ isPrimary: boolean;
42
+ participantType: string;
43
+ }>;
44
+ leadTraveler: {
45
+ id: string;
46
+ firstName: string;
47
+ lastName: string;
48
+ email: string | null;
49
+ phone: string | null;
50
+ } | null;
51
+ }
52
+ /**
53
+ * Hook point so consumers can extend (or replace) the template variables.
54
+ * Receives the default payload plus the raw booking/travelers so the
55
+ * consumer can fold in product/person/etc. lookups without re-fetching.
56
+ */
57
+ export type ResolveContractVariablesFn = (context: {
58
+ db: PostgresJsDatabase;
59
+ booking: NonNullable<Awaited<ReturnType<typeof bookingsService.getBookingById>>>;
60
+ travelers: Awaited<ReturnType<typeof bookingsService.listTravelers>>;
61
+ defaults: DefaultContractVariables;
62
+ }) => Promise<Record<string, unknown>> | Record<string, unknown>;
63
+ export interface AutoGenerateContractOptions {
64
+ enabled?: boolean;
65
+ /**
66
+ * Slug of the contract template to use. The contract is created against
67
+ * that template's `currentVersionId`. If the template has no current
68
+ * version, the handler logs + bails.
69
+ */
70
+ templateSlug: string;
71
+ /**
72
+ * Scope the contract defaults to when creating. Matches
73
+ * `contractScopeEnum`; the default `"customer"` is right for the common
74
+ * operator-issues-to-traveler case.
75
+ */
76
+ scope?: "customer" | "supplier" | "partner" | "channel" | "other";
77
+ /**
78
+ * When set, the contract tries to allocate a number from the matching
79
+ * active series on issuance. Without it, the contract issues unnumbered.
80
+ */
81
+ seriesName?: string;
82
+ /**
83
+ * Language code written onto the contract row. Used by the PDF
84
+ * renderer to pick the right locale for date/currency filters.
85
+ */
86
+ language?: string;
87
+ /**
88
+ * Optional variable extender — see `ResolveContractVariablesFn`.
89
+ */
90
+ resolveVariables?: ResolveContractVariablesFn;
91
+ }
92
+ export interface AutoGenerateContractRuntime {
93
+ generator: ContractDocumentGenerator;
94
+ eventBus?: import("@voyantjs/core").EventBus;
95
+ }
96
+ /**
97
+ * Core auto-generate handler. Fire this from a `booking.confirmed` subscriber.
98
+ * On success, the booking now has an issued contract with an attachment
99
+ * (the PDF / storage object produced by the configured generator) and a
100
+ * `contract.document.generated` event has been emitted post-commit.
101
+ *
102
+ * Failure modes (all surfaced via the returned status):
103
+ * - `template_not_found` — no active template matches the slug
104
+ * - `template_version_missing` — template exists but has no published version
105
+ * - `booking_not_found` — booking disappeared between confirm + fire
106
+ * - `contract_create_failed` — insert returned null
107
+ * - `document_<…>` — pass-through of generateContractDocument statuses
108
+ *
109
+ * Callers (the subscriber wrapper) log these and move on — per the EventBus
110
+ * contract, handler throws are swallowed anyway; returning a discriminated
111
+ * status keeps tests honest.
112
+ */
113
+ export declare function autoGenerateContractForBooking(db: PostgresJsDatabase, event: BookingConfirmedLikeEvent, options: AutoGenerateContractOptions, runtime: AutoGenerateContractRuntime): Promise<{
114
+ status: "ok";
115
+ contractId: string;
116
+ attachmentId: string;
117
+ } | {
118
+ status: "template_not_found";
119
+ } | {
120
+ status: "template_version_missing";
121
+ } | {
122
+ status: "booking_not_found";
123
+ } | {
124
+ status: "contract_create_failed";
125
+ } | {
126
+ status: "document_failed";
127
+ reason: string;
128
+ }>;
129
+ //# sourceMappingURL=service-auto-generate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-auto-generate.d.ts","sourceRoot":"","sources":["../../src/contracts/service-auto-generate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,122 @@
1
+ import { bookingsService } from "@voyantjs/bookings";
2
+ import { contractRecordsService } from "./service-contracts.js";
3
+ import { contractDocumentsService } from "./service-documents.js";
4
+ import { contractSeriesService } from "./service-series.js";
5
+ import { contractTemplatesService } from "./service-templates.js";
6
+ /**
7
+ * Core auto-generate handler. Fire this from a `booking.confirmed` subscriber.
8
+ * On success, the booking now has an issued contract with an attachment
9
+ * (the PDF / storage object produced by the configured generator) and a
10
+ * `contract.document.generated` event has been emitted post-commit.
11
+ *
12
+ * Failure modes (all surfaced via the returned status):
13
+ * - `template_not_found` — no active template matches the slug
14
+ * - `template_version_missing` — template exists but has no published version
15
+ * - `booking_not_found` — booking disappeared between confirm + fire
16
+ * - `contract_create_failed` — insert returned null
17
+ * - `document_<…>` — pass-through of generateContractDocument statuses
18
+ *
19
+ * Callers (the subscriber wrapper) log these and move on — per the EventBus
20
+ * contract, handler throws are swallowed anyway; returning a discriminated
21
+ * status keeps tests honest.
22
+ */
23
+ export async function autoGenerateContractForBooking(db, event, options, runtime) {
24
+ // Resolve the template + its current version. Consumers configure the slug
25
+ // once at module bootstrap; we look up on every fire so template body
26
+ // edits are picked up without restart.
27
+ const template = await contractTemplatesService.findTemplateBySlug(db, options.templateSlug);
28
+ if (!template) {
29
+ return { status: "template_not_found" };
30
+ }
31
+ if (!template.currentVersionId) {
32
+ return { status: "template_version_missing" };
33
+ }
34
+ const booking = await bookingsService.getBookingById(db, event.bookingId);
35
+ if (!booking) {
36
+ return { status: "booking_not_found" };
37
+ }
38
+ const travelers = await bookingsService.listTravelers(db, event.bookingId);
39
+ const leadTraveler = travelers.find((t) => t.isPrimary) ??
40
+ travelers.find((t) => t.participantType === "traveler") ??
41
+ travelers[0] ??
42
+ null;
43
+ const now = new Date();
44
+ const defaults = {
45
+ contract: {
46
+ issuedAt: now.toISOString(),
47
+ date: now.toISOString().slice(0, 10),
48
+ },
49
+ booking: {
50
+ id: booking.id,
51
+ number: booking.bookingNumber,
52
+ status: booking.status,
53
+ currency: booking.sellCurrency ?? null,
54
+ startDate: booking.startDate,
55
+ endDate: booking.endDate,
56
+ pax: booking.pax,
57
+ internalNotes: booking.internalNotes,
58
+ totalAmountCents: booking.sellAmountCents ?? null,
59
+ },
60
+ travelers: travelers.map((t) => ({
61
+ id: t.id,
62
+ firstName: t.firstName,
63
+ lastName: t.lastName,
64
+ email: t.email,
65
+ phone: t.phone,
66
+ isPrimary: t.isPrimary,
67
+ participantType: t.participantType,
68
+ })),
69
+ leadTraveler: leadTraveler
70
+ ? {
71
+ id: leadTraveler.id,
72
+ firstName: leadTraveler.firstName,
73
+ lastName: leadTraveler.lastName,
74
+ email: leadTraveler.email,
75
+ phone: leadTraveler.phone,
76
+ }
77
+ : null,
78
+ };
79
+ const variables = options.resolveVariables
80
+ ? await options.resolveVariables({ db, booking, travelers, defaults })
81
+ : defaults;
82
+ // Resolve a series id if the consumer gave a name — failure to find is
83
+ // non-fatal since a contract can issue without a number (some operators
84
+ // use templates as standalone records and number externally).
85
+ let seriesId = null;
86
+ if (options.seriesName) {
87
+ const series = await contractSeriesService.findSeriesByName(db, options.seriesName);
88
+ seriesId = series?.id ?? null;
89
+ }
90
+ const contract = await contractRecordsService.createContract(db, {
91
+ scope: options.scope ?? "customer",
92
+ status: "draft",
93
+ title: `${template.name} — ${booking.bookingNumber}`,
94
+ templateVersionId: template.currentVersionId,
95
+ seriesId,
96
+ bookingId: event.bookingId,
97
+ personId: booking.personId ?? null,
98
+ organizationId: booking.organizationId ?? null,
99
+ language: options.language ?? template.language ?? "en",
100
+ variables,
101
+ metadata: {
102
+ autoGenerated: true,
103
+ trigger: "booking.confirmed",
104
+ triggerActorId: event.actorId,
105
+ },
106
+ });
107
+ if (!contract) {
108
+ return { status: "contract_create_failed" };
109
+ }
110
+ const result = await contractDocumentsService.generateContractDocument(db, contract.id, {
111
+ issueIfDraft: true,
112
+ replaceExisting: true,
113
+ kind: "document",
114
+ }, {
115
+ generator: runtime.generator,
116
+ eventBus: runtime.eventBus,
117
+ });
118
+ if (result.status === "generated") {
119
+ return { status: "ok", contractId: contract.id, attachmentId: result.attachment.id };
120
+ }
121
+ return { status: "document_failed", reason: result.status };
122
+ }
@@ -29,6 +29,26 @@ export declare const contractSeriesService: {
29
29
  createdAt: Date;
30
30
  updatedAt: Date;
31
31
  } | null>;
32
+ /**
33
+ * Find the most-recently-updated active series matching a name. Used by
34
+ * the auto-generate subscriber so consumers can pin a named series
35
+ * (`"2026 Customer"`) in config and let operators rename the row via
36
+ * the admin UI without breaking the wiring.
37
+ */
38
+ findSeriesByName(db: PostgresJsDatabase, name: string): Promise<{
39
+ id: string;
40
+ name: string;
41
+ prefix: string;
42
+ separator: string;
43
+ padLength: number;
44
+ currentSequence: number;
45
+ resetStrategy: "never" | "annual" | "monthly";
46
+ resetAt: Date | null;
47
+ scope: "customer" | "partner" | "supplier" | "other" | "channel";
48
+ active: boolean;
49
+ createdAt: Date;
50
+ updatedAt: Date;
51
+ } | null>;
32
52
  createSeries(db: PostgresJsDatabase, data: CreateContractNumberSeriesInput): Promise<{
33
53
  id: string;
34
54
  name: string;
@@ -1 +1 @@
1
- {"version":3,"file":"service-series.d.ts","sourceRoot":"","sources":["../../src/contracts/service-series.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAGjE,OAAO,KAAK,EACV,+BAA+B,EAC/B,+BAA+B,EAChC,MAAM,qBAAqB,CAAA;AAE5B,eAAO,MAAM,qBAAqB;mBACX,kBAAkB;;;;;;;;;;;;;;sBAGf,kBAAkB,MAAM,MAAM;;;;;;;;;;;;;;qBAQ/B,kBAAkB,QAAQ,+BAA+B;;;;;;;;;;;;;;qBAIzD,kBAAkB,MAAM,MAAM,QAAQ,+BAA+B;;;;;;;;;;;;;;qBAQrE,kBAAkB,MAAM,MAAM;;;CAOtD,CAAA"}
1
+ {"version":3,"file":"service-series.d.ts","sourceRoot":"","sources":["../../src/contracts/service-series.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAGjE,OAAO,KAAK,EACV,+BAA+B,EAC/B,+BAA+B,EAChC,MAAM,qBAAqB,CAAA;AAE5B,eAAO,MAAM,qBAAqB;mBACX,kBAAkB;;;;;;;;;;;;;;sBAGf,kBAAkB,MAAM,MAAM;;;;;;;;;;;;;;IAQtD;;;;;OAKG;yBACwB,kBAAkB,QAAQ,MAAM;;;;;;;;;;;;;;qBASpC,kBAAkB,QAAQ,+BAA+B;;;;;;;;;;;;;;qBAIzD,kBAAkB,MAAM,MAAM,QAAQ,+BAA+B;;;;;;;;;;;;;;qBAQrE,kBAAkB,MAAM,MAAM;;;CAOtD,CAAA"}
@@ -1,4 +1,4 @@
1
- import { desc, eq } from "drizzle-orm";
1
+ import { and, desc, eq } from "drizzle-orm";
2
2
  import { contractNumberSeries } from "./schema.js";
3
3
  export const contractSeriesService = {
4
4
  async listSeries(db) {
@@ -12,6 +12,21 @@ export const contractSeriesService = {
12
12
  .limit(1);
13
13
  return row ?? null;
14
14
  },
15
+ /**
16
+ * Find the most-recently-updated active series matching a name. Used by
17
+ * the auto-generate subscriber so consumers can pin a named series
18
+ * (`"2026 Customer"`) in config and let operators rename the row via
19
+ * the admin UI without breaking the wiring.
20
+ */
21
+ async findSeriesByName(db, name) {
22
+ const [row] = await db
23
+ .select()
24
+ .from(contractNumberSeries)
25
+ .where(and(eq(contractNumberSeries.name, name), eq(contractNumberSeries.active, true)))
26
+ .orderBy(desc(contractNumberSeries.updatedAt))
27
+ .limit(1);
28
+ return row ?? null;
29
+ },
15
30
  async createSeries(db, data) {
16
31
  const [row] = await db.insert(contractNumberSeries).values(data).returning();
17
32
  return row ?? null;
@@ -34,6 +34,24 @@ export declare const contractTemplatesService: {
34
34
  createdAt: Date;
35
35
  updatedAt: Date;
36
36
  } | null>;
37
+ /**
38
+ * Slug lookup, used by the auto-generate subscriber. Slug is unique so the
39
+ * result is either the row or null — no disambiguation needed.
40
+ */
41
+ findTemplateBySlug(db: PostgresJsDatabase, slug: string): Promise<{
42
+ id: string;
43
+ name: string;
44
+ slug: string;
45
+ scope: "customer" | "partner" | "supplier" | "other" | "channel";
46
+ language: string;
47
+ description: string | null;
48
+ body: string;
49
+ variableSchema: unknown;
50
+ currentVersionId: string | null;
51
+ active: boolean;
52
+ createdAt: Date;
53
+ updatedAt: Date;
54
+ } | null>;
37
55
  getDefaultTemplate(db: PostgresJsDatabase, query: {
38
56
  scope: "customer" | "supplier" | "partner" | "channel" | "other";
39
57
  language?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"service-templates.d.ts","sourceRoot":"","sources":["../../src/contracts/service-templates.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAGjE,OAAO,EACL,KAAK,yBAAyB,EAC9B,KAAK,2BAA2B,EAChC,KAAK,kCAAkC,EAEvC,KAAK,mBAAmB,EAExB,KAAK,2BAA2B,EACjC,MAAM,qBAAqB,CAAA;AAE5B,eAAO,MAAM,wBAAwB;sBACX,kBAAkB,SAAS,yBAAyB;;;;;;;;;;;;;;;;;;;wBA6BlD,kBAAkB,MAAM,MAAM;;;;;;;;;;;;;;2BASlD,kBAAkB,SACf;QACL,KAAK,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAA;QAChE,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAA;KAC7B;;;;;;;;;;;;;;uBAgCsB,kBAAkB,QAAQ,2BAA2B;;;;;;;;;;;;;;uBAIrD,kBAAkB,MAAM,MAAM,QAAQ,2BAA2B;;;;;;;;;;;;;;uBAQjE,kBAAkB,MAAM,MAAM;;;6BAO9B,kBAAkB,cAAc,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+BAO9B,kBAAkB,MAAM,MAAM;;;;;;;;;;8BASzD,kBAAkB,cACV,MAAM,QACZ,kCAAkC;;;;;;;;;;yBAkCrB,mBAAmB,GAAG,MAAM;CAIlD,CAAA"}
1
+ {"version":3,"file":"service-templates.d.ts","sourceRoot":"","sources":["../../src/contracts/service-templates.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAGjE,OAAO,EACL,KAAK,yBAAyB,EAC9B,KAAK,2BAA2B,EAChC,KAAK,kCAAkC,EAEvC,KAAK,mBAAmB,EAExB,KAAK,2BAA2B,EACjC,MAAM,qBAAqB,CAAA;AAE5B,eAAO,MAAM,wBAAwB;sBACX,kBAAkB,SAAS,yBAAyB;;;;;;;;;;;;;;;;;;;wBA6BlD,kBAAkB,MAAM,MAAM;;;;;;;;;;;;;;IAQxD;;;OAGG;2BAC0B,kBAAkB,QAAQ,MAAM;;;;;;;;;;;;;;2BASvD,kBAAkB,SACf;QACL,KAAK,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAA;QAChE,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAA;KAC7B;;;;;;;;;;;;;;uBAgCsB,kBAAkB,QAAQ,2BAA2B;;;;;;;;;;;;;;uBAIrD,kBAAkB,MAAM,MAAM,QAAQ,2BAA2B;;;;;;;;;;;;;;uBAQjE,kBAAkB,MAAM,MAAM;;;6BAO9B,kBAAkB,cAAc,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+BAO9B,kBAAkB,MAAM,MAAM;;;;;;;;;;8BASzD,kBAAkB,cACV,MAAM,QACZ,kCAAkC;;;;;;;;;;yBAkCrB,mBAAmB,GAAG,MAAM;CAIlD,CAAA"}
@@ -31,6 +31,18 @@ export const contractTemplatesService = {
31
31
  .limit(1);
32
32
  return row ?? null;
33
33
  },
34
+ /**
35
+ * Slug lookup, used by the auto-generate subscriber. Slug is unique so the
36
+ * result is either the row or null — no disambiguation needed.
37
+ */
38
+ async findTemplateBySlug(db, slug) {
39
+ const [row] = await db
40
+ .select()
41
+ .from(contractTemplates)
42
+ .where(eq(contractTemplates.slug, slug))
43
+ .limit(1);
44
+ return row ?? null;
45
+ },
34
46
  async getDefaultTemplate(db, query) {
35
47
  const rows = await db
36
48
  .select()
@@ -1282,6 +1282,20 @@ export declare const contractsService: {
1282
1282
  createdAt: Date;
1283
1283
  updatedAt: Date;
1284
1284
  } | null>;
1285
+ findSeriesByName(db: import("drizzle-orm/postgres-js").PostgresJsDatabase, name: string): Promise<{
1286
+ id: string;
1287
+ name: string;
1288
+ prefix: string;
1289
+ separator: string;
1290
+ padLength: number;
1291
+ currentSequence: number;
1292
+ resetStrategy: "never" | "annual" | "monthly";
1293
+ resetAt: Date | null;
1294
+ scope: "customer" | "partner" | "supplier" | "other" | "channel";
1295
+ active: boolean;
1296
+ createdAt: Date;
1297
+ updatedAt: Date;
1298
+ } | null>;
1285
1299
  createSeries(db: import("drizzle-orm/postgres-js").PostgresJsDatabase, data: import("./service-shared.js").CreateContractNumberSeriesInput): Promise<{
1286
1300
  id: string;
1287
1301
  name: string;
@@ -1346,6 +1360,20 @@ export declare const contractsService: {
1346
1360
  createdAt: Date;
1347
1361
  updatedAt: Date;
1348
1362
  } | null>;
1363
+ findTemplateBySlug(db: import("drizzle-orm/postgres-js").PostgresJsDatabase, slug: string): Promise<{
1364
+ id: string;
1365
+ name: string;
1366
+ slug: string;
1367
+ scope: "customer" | "partner" | "supplier" | "other" | "channel";
1368
+ language: string;
1369
+ description: string | null;
1370
+ body: string;
1371
+ variableSchema: unknown;
1372
+ currentVersionId: string | null;
1373
+ active: boolean;
1374
+ createdAt: Date;
1375
+ updatedAt: Date;
1376
+ } | null>;
1349
1377
  getDefaultTemplate(db: import("drizzle-orm/postgres-js").PostgresJsDatabase, query: {
1350
1378
  scope: "customer" | "supplier" | "partner" | "channel" | "other";
1351
1379
  language?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/contracts/service.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,yBAAyB,EAC1B,MAAM,qBAAqB,CAAA;AAG5B,OAAO,EAAE,sBAAsB,EAAE,cAAc,EAAE,yBAAyB,EAAE,CAAA;AAE5E,eAAO,MAAM,gBAAgB;;mBAMy1S,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBAAlkQ,CAAC;yBAAgC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CADt1C,CAAA"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/contracts/service.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,yBAAyB,EAC1B,MAAM,qBAAqB,CAAA;AAG5B,OAAO,EAAE,sBAAsB,EAAE,cAAc,EAAE,yBAAyB,EAAE,CAAA;AAE5E,eAAO,MAAM,gBAAgB;;mBAMy1S,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBAA9rP,CAAC;yBAAgC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAD1tD,CAAA"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import type { Module } from "@voyantjs/core";
2
2
  import type { HonoModule } from "@voyantjs/hono/module";
3
+ import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
3
4
  import { type ContractsRouteOptions } from "./contracts/routes.js";
5
+ import { type AutoGenerateContractOptions } from "./contracts/service-auto-generate.js";
4
6
  export declare const legalLinkable: {
5
7
  policy: import("@voyantjs/core").LinkableDefinition;
6
8
  policyVersion: import("@voyantjs/core").LinkableDefinition;
@@ -9,10 +11,27 @@ export declare const legalLinkable: {
9
11
  contractTemplate: import("@voyantjs/core").LinkableDefinition;
10
12
  };
11
13
  export declare const legalModule: Module;
12
- export declare function createLegalHonoModule(options?: ContractsRouteOptions): HonoModule;
14
+ export interface CreateLegalHonoModuleOptions extends ContractsRouteOptions {
15
+ /**
16
+ * Required when `autoGenerateContractOnConfirmed.enabled` is true. The
17
+ * `booking.confirmed` subscriber fires outside request scope, so it
18
+ * needs its own db handle from runtime bindings.
19
+ */
20
+ resolveDb?: (bindings: Record<string, unknown>) => PostgresJsDatabase;
21
+ /**
22
+ * Opt-in auto-generate on `booking.confirmed`. When enabled + a
23
+ * `templateSlug` is supplied + a `documentGenerator` is resolvable, every
24
+ * booking.confirmed event creates a contract against the template's
25
+ * current version and generates its attachment via the configured
26
+ * generator (R2-backed PDF, etc.).
27
+ */
28
+ autoGenerateContractOnConfirmed?: AutoGenerateContractOptions;
29
+ }
30
+ export declare function createLegalHonoModule(options?: CreateLegalHonoModuleOptions): HonoModule;
13
31
  export declare const legalHonoModule: HonoModule;
14
32
  export * from "./contracts/index.js";
15
33
  export { buildContractsRouteRuntime, CONTRACTS_ROUTE_RUNTIME_CONTAINER_KEY, type ContractsRouteRuntime, } from "./contracts/route-runtime.js";
16
34
  export type { ContractsRouteOptions } from "./contracts/routes.js";
35
+ export { type AutoGenerateContractOptions, type AutoGenerateContractRuntime, autoGenerateContractForBooking, type BookingConfirmedLikeEvent, type DefaultContractVariables, type ResolveContractVariablesFn, } from "./contracts/service-auto-generate.js";
17
36
  export * from "./policies/index.js";
18
37
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAOvD,OAAO,EACL,KAAK,qBAAqB,EAG3B,MAAM,uBAAuB,CAAA;AAI9B,eAAO,MAAM,aAAa;;;;;;CAGzB,CAAA;AAED,eAAO,MAAM,WAAW,EAAE,MAGzB,CAAA;AAED,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,qBAA0B,GAAG,UAAU,CAwBrF;AAED,eAAO,MAAM,eAAe,EAAE,UAAoC,CAAA;AAElE,cAAc,sBAAsB,CAAA;AACpC,OAAO,EACL,0BAA0B,EAC1B,qCAAqC,EACrC,KAAK,qBAAqB,GAC3B,MAAM,8BAA8B,CAAA;AACrC,YAAY,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAClE,cAAc,qBAAqB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAOjE,OAAO,EACL,KAAK,qBAAqB,EAG3B,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,KAAK,2BAA2B,EAEjC,MAAM,sCAAsC,CAAA;AAI7C,eAAO,MAAM,aAAa;;;;;;CAGzB,CAAA;AAED,eAAO,MAAM,WAAW,EAAE,MAGzB,CAAA;AAED,MAAM,WAAW,4BAA6B,SAAQ,qBAAqB;IACzE;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,kBAAkB,CAAA;IACrE;;;;;;OAMG;IACH,+BAA+B,CAAC,EAAE,2BAA2B,CAAA;CAC9D;AAED,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,4BAAiC,GAAG,UAAU,CAsE5F;AAED,eAAO,MAAM,eAAe,EAAE,UAAoC,CAAA;AAElE,cAAc,sBAAsB,CAAA;AACpC,OAAO,EACL,0BAA0B,EAC1B,qCAAqC,EACrC,KAAK,qBAAqB,GAC3B,MAAM,8BAA8B,CAAA;AACrC,YAAY,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAClE,OAAO,EACL,KAAK,2BAA2B,EAChC,KAAK,2BAA2B,EAChC,8BAA8B,EAC9B,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,GAChC,MAAM,sCAAsC,CAAA;AAC7C,cAAc,qBAAqB,CAAA"}
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ import { Hono } from "hono";
2
2
  import { contractsLinkable } from "./contracts/index.js";
3
3
  import { buildContractsRouteRuntime, CONTRACTS_ROUTE_RUNTIME_CONTAINER_KEY, } from "./contracts/route-runtime.js";
4
4
  import { createContractsAdminRoutes, createContractsPublicRoutes, } from "./contracts/routes.js";
5
+ import { autoGenerateContractForBooking, } from "./contracts/service-auto-generate.js";
5
6
  import { policiesLinkable } from "./policies/index.js";
6
7
  import { policiesAdminRoutes, policiesPublicRoutes } from "./policies/routes.js";
7
8
  export const legalLinkable = {
@@ -21,8 +22,42 @@ export function createLegalHonoModule(options = {}) {
21
22
  .route("/policies", policiesPublicRoutes);
22
23
  const module = {
23
24
  ...legalModule,
24
- bootstrap: ({ bindings, container }) => {
25
+ bootstrap: ({ bindings, container, eventBus }) => {
25
26
  container.register(CONTRACTS_ROUTE_RUNTIME_CONTAINER_KEY, buildContractsRouteRuntime(bindings, options));
27
+ // Auto-generate wiring — opt-in. Mirrors the notifications
28
+ // autoConfirmAndDispatch subscriber pattern. Both fire on the same
29
+ // booking.confirmed event; legal's handler just needs to run first
30
+ // so the contract attachment exists before notifications looks it
31
+ // up via listLegalBookingDocuments. Module-registration order in the
32
+ // template controls this.
33
+ const auto = options.autoGenerateContractOnConfirmed;
34
+ if (auto?.enabled && options.resolveDb) {
35
+ const resolveDb = options.resolveDb;
36
+ const runtime = buildContractsRouteRuntime(bindings, options);
37
+ if (!runtime.documentGenerator) {
38
+ // Mis-configuration — don't silently drop contracts. Log and
39
+ // skip; the template operator will notice on the first confirm.
40
+ console.error("[legal] autoGenerateContractOnConfirmed.enabled=true but no documentGenerator resolved; skipping subscriber.");
41
+ return;
42
+ }
43
+ const generator = runtime.documentGenerator;
44
+ eventBus.subscribe("booking.confirmed", async (event) => {
45
+ try {
46
+ const db = resolveDb(bindings);
47
+ const result = await autoGenerateContractForBooking(db, event.data, auto, {
48
+ generator,
49
+ eventBus,
50
+ });
51
+ if (result.status !== "ok") {
52
+ console.error(`[legal] auto-generate contract skipped for booking ${event.data.bookingId}: ${result.status}`);
53
+ }
54
+ }
55
+ catch (error) {
56
+ const message = error instanceof Error ? error.message : String(error);
57
+ console.error(`[legal] auto-generate contract failed for booking ${event.data.bookingId}: ${message}`);
58
+ }
59
+ });
60
+ }
26
61
  },
27
62
  };
28
63
  return {
@@ -34,4 +69,5 @@ export function createLegalHonoModule(options = {}) {
34
69
  export const legalHonoModule = createLegalHonoModule();
35
70
  export * from "./contracts/index.js";
36
71
  export { buildContractsRouteRuntime, CONTRACTS_ROUTE_RUNTIME_CONTAINER_KEY, } from "./contracts/route-runtime.js";
72
+ export { autoGenerateContractForBooking, } from "./contracts/service-auto-generate.js";
37
73
  export * from "./policies/index.js";
@@ -114,7 +114,7 @@ export declare const policiesAdminRoutes: import("hono/hono-base").HonoBase<Env,
114
114
  label: string | null;
115
115
  daysBeforeDeparture: number | null;
116
116
  refundPercent: number | null;
117
- refundType: "cash" | "credit" | "cash_or_credit" | "none" | null;
117
+ refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
118
118
  flatAmountCents: number | null;
119
119
  currency: string | null;
120
120
  validFrom: string | null;
@@ -380,7 +380,7 @@ export declare const policiesAdminRoutes: import("hono/hono-base").HonoBase<Env,
380
380
  label: string | null;
381
381
  daysBeforeDeparture: number | null;
382
382
  refundPercent: number | null;
383
- refundType: "cash" | "credit" | "cash_or_credit" | "none" | null;
383
+ refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
384
384
  flatAmountCents: number | null;
385
385
  currency: string | null;
386
386
  validFrom: string | null;
@@ -429,7 +429,7 @@ export declare const policiesAdminRoutes: import("hono/hono-base").HonoBase<Env,
429
429
  ruleType: "custom" | "window" | "percentage" | "flat_amount" | "date_range";
430
430
  daysBeforeDeparture: number | null;
431
431
  refundPercent: number | null;
432
- refundType: "cash" | "credit" | "cash_or_credit" | "none" | null;
432
+ refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
433
433
  flatAmountCents: number | null;
434
434
  };
435
435
  };
@@ -464,7 +464,7 @@ export declare const policiesAdminRoutes: import("hono/hono-base").HonoBase<Env,
464
464
  label: string | null;
465
465
  daysBeforeDeparture: number | null;
466
466
  refundPercent: number | null;
467
- refundType: "cash" | "credit" | "cash_or_credit" | "none" | null;
467
+ refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
468
468
  flatAmountCents: number | null;
469
469
  currency: string | null;
470
470
  validFrom: string | null;
@@ -670,9 +670,9 @@ export declare const policiesAdminRoutes: import("hono/hono-base").HonoBase<Env,
670
670
  bookingId: string | null;
671
671
  orderId: string | null;
672
672
  method: "signature" | "implicit" | "explicit_checkbox";
673
- policyVersionId: string;
674
- offerId: string | null;
675
673
  acceptedAt: string;
674
+ offerId: string | null;
675
+ policyVersionId: string;
676
676
  acceptedBy: string | null;
677
677
  } | null;
678
678
  };
@@ -892,9 +892,9 @@ export declare const policiesPublicRoutes: import("hono/hono-base").HonoBase<Env
892
892
  bookingId: string | null;
893
893
  orderId: string | null;
894
894
  method: "signature" | "implicit" | "explicit_checkbox";
895
- policyVersionId: string;
896
- offerId: string | null;
897
895
  acceptedAt: string;
896
+ offerId: string | null;
897
+ policyVersionId: string;
898
898
  acceptedBy: string | null;
899
899
  } | null;
900
900
  };
@@ -507,7 +507,7 @@ export declare const policyRules: import("drizzle-orm/pg-core").PgTableWithColum
507
507
  tableName: "policy_rules";
508
508
  dataType: "string";
509
509
  columnType: "PgEnumColumn";
510
- data: "cash" | "credit" | "cash_or_credit" | "none";
510
+ data: "none" | "cash" | "credit" | "cash_or_credit";
511
511
  driverParam: string;
512
512
  notNull: false;
513
513
  hasDefault: false;
@@ -680,7 +680,7 @@ export declare const policiesCoreService: {
680
680
  tableName: "policy_rules";
681
681
  dataType: "string";
682
682
  columnType: "PgEnumColumn";
683
- data: "cash" | "credit" | "cash_or_credit" | "none";
683
+ data: "none" | "cash" | "credit" | "cash_or_credit";
684
684
  driverParam: string;
685
685
  notNull: false;
686
686
  hasDefault: false;
@@ -835,7 +835,7 @@ export declare const policiesCoreService: {
835
835
  label: string | null;
836
836
  daysBeforeDeparture: number | null;
837
837
  refundPercent: number | null;
838
- refundType: "cash" | "credit" | "cash_or_credit" | "none" | null;
838
+ refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
839
839
  flatAmountCents: number | null;
840
840
  currency: string | null;
841
841
  validFrom: string | null;
@@ -952,7 +952,7 @@ export declare const policiesCoreService: {
952
952
  tableName: "policy_rules";
953
953
  dataType: "string";
954
954
  columnType: "PgEnumColumn";
955
- data: "cash" | "credit" | "cash_or_credit" | "none";
955
+ data: "none" | "cash" | "credit" | "cash_or_credit";
956
956
  driverParam: string;
957
957
  notNull: false;
958
958
  hasDefault: false;
@@ -1115,7 +1115,7 @@ export declare const policiesCoreService: {
1115
1115
  ruleType: "custom" | "window" | "percentage" | "flat_amount" | "date_range";
1116
1116
  daysBeforeDeparture: number | null;
1117
1117
  refundPercent: number | null;
1118
- refundType: "cash" | "credit" | "cash_or_credit" | "none" | null;
1118
+ refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
1119
1119
  flatAmountCents: number | null;
1120
1120
  } | null>;
1121
1121
  updatePolicyRule(db: PostgresJsDatabase, ruleId: string, data: UpdatePolicyRuleInput): Promise<{
@@ -1125,7 +1125,7 @@ export declare const policiesCoreService: {
1125
1125
  label: string | null;
1126
1126
  daysBeforeDeparture: number | null;
1127
1127
  refundPercent: number | null;
1128
- refundType: "cash" | "credit" | "cash_or_credit" | "none" | null;
1128
+ refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
1129
1129
  flatAmountCents: number | null;
1130
1130
  currency: string | null;
1131
1131
  validFrom: string | null;
@@ -1244,7 +1244,7 @@ export declare const policiesCoreService: {
1244
1244
  label: string | null;
1245
1245
  daysBeforeDeparture: number | null;
1246
1246
  refundPercent: number | null;
1247
- refundType: "cash" | "credit" | "cash_or_credit" | "none" | null;
1247
+ refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
1248
1248
  flatAmountCents: number | null;
1249
1249
  currency: string | null;
1250
1250
  validFrom: string | null;
@@ -1286,9 +1286,9 @@ export declare const policiesCoreService: {
1286
1286
  bookingId: string | null;
1287
1287
  orderId: string | null;
1288
1288
  method: "signature" | "implicit" | "explicit_checkbox";
1289
- policyVersionId: string;
1290
- offerId: string | null;
1291
1289
  acceptedAt: Date;
1290
+ offerId: string | null;
1291
+ policyVersionId: string;
1292
1292
  acceptedBy: string | null;
1293
1293
  } | null>;
1294
1294
  };
@@ -680,7 +680,7 @@ export declare const policiesService: {
680
680
  tableName: "policy_rules";
681
681
  dataType: "string";
682
682
  columnType: "PgEnumColumn";
683
- data: "cash" | "credit" | "cash_or_credit" | "none";
683
+ data: "none" | "cash" | "credit" | "cash_or_credit";
684
684
  driverParam: string;
685
685
  notNull: false;
686
686
  hasDefault: false;
@@ -835,7 +835,7 @@ export declare const policiesService: {
835
835
  label: string | null;
836
836
  daysBeforeDeparture: number | null;
837
837
  refundPercent: number | null;
838
- refundType: "cash" | "credit" | "cash_or_credit" | "none" | null;
838
+ refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
839
839
  flatAmountCents: number | null;
840
840
  currency: string | null;
841
841
  validFrom: string | null;
@@ -952,7 +952,7 @@ export declare const policiesService: {
952
952
  tableName: "policy_rules";
953
953
  dataType: "string";
954
954
  columnType: "PgEnumColumn";
955
- data: "cash" | "credit" | "cash_or_credit" | "none";
955
+ data: "none" | "cash" | "credit" | "cash_or_credit";
956
956
  driverParam: string;
957
957
  notNull: false;
958
958
  hasDefault: false;
@@ -1115,7 +1115,7 @@ export declare const policiesService: {
1115
1115
  ruleType: "custom" | "window" | "percentage" | "flat_amount" | "date_range";
1116
1116
  daysBeforeDeparture: number | null;
1117
1117
  refundPercent: number | null;
1118
- refundType: "cash" | "credit" | "cash_or_credit" | "none" | null;
1118
+ refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
1119
1119
  flatAmountCents: number | null;
1120
1120
  } | null>;
1121
1121
  updatePolicyRule(db: import("drizzle-orm/postgres-js").PostgresJsDatabase, ruleId: string, data: import("./service-shared.js").UpdatePolicyRuleInput): Promise<{
@@ -1125,7 +1125,7 @@ export declare const policiesService: {
1125
1125
  label: string | null;
1126
1126
  daysBeforeDeparture: number | null;
1127
1127
  refundPercent: number | null;
1128
- refundType: "cash" | "credit" | "cash_or_credit" | "none" | null;
1128
+ refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
1129
1129
  flatAmountCents: number | null;
1130
1130
  currency: string | null;
1131
1131
  validFrom: string | null;
@@ -1244,7 +1244,7 @@ export declare const policiesService: {
1244
1244
  label: string | null;
1245
1245
  daysBeforeDeparture: number | null;
1246
1246
  refundPercent: number | null;
1247
- refundType: "cash" | "credit" | "cash_or_credit" | "none" | null;
1247
+ refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
1248
1248
  flatAmountCents: number | null;
1249
1249
  currency: string | null;
1250
1250
  validFrom: string | null;
@@ -1286,9 +1286,9 @@ export declare const policiesService: {
1286
1286
  bookingId: string | null;
1287
1287
  orderId: string | null;
1288
1288
  method: "signature" | "implicit" | "explicit_checkbox";
1289
- policyVersionId: string;
1290
- offerId: string | null;
1291
1289
  acceptedAt: Date;
1290
+ offerId: string | null;
1291
+ policyVersionId: string;
1292
1292
  acceptedBy: string | null;
1293
1293
  } | null>;
1294
1294
  };
@@ -22,10 +22,10 @@ export declare const policyRuleTypeSchema: z.ZodEnum<{
22
22
  date_range: "date_range";
23
23
  }>;
24
24
  export declare const policyRefundTypeSchema: z.ZodEnum<{
25
+ none: "none";
25
26
  cash: "cash";
26
27
  credit: "credit";
27
28
  cash_or_credit: "cash_or_credit";
28
- none: "none";
29
29
  }>;
30
30
  export declare const policyAssignmentScopeSchema: z.ZodEnum<{
31
31
  supplier: "supplier";
@@ -114,10 +114,10 @@ export declare const insertPolicyRuleSchema: z.ZodObject<{
114
114
  daysBeforeDeparture: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
115
115
  refundPercent: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
116
116
  refundType: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
117
+ none: "none";
117
118
  cash: "cash";
118
119
  credit: "credit";
119
120
  cash_or_credit: "cash_or_credit";
120
- none: "none";
121
121
  }>>>;
122
122
  flatAmountCents: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
123
123
  currency: z.ZodNullable<z.ZodOptional<z.ZodString>>;
@@ -138,10 +138,10 @@ export declare const updatePolicyRuleSchema: z.ZodObject<{
138
138
  daysBeforeDeparture: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodNumber>>>;
139
139
  refundPercent: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodNumber>>>;
140
140
  refundType: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodEnum<{
141
+ none: "none";
141
142
  cash: "cash";
142
143
  credit: "credit";
143
144
  cash_or_credit: "cash_or_credit";
144
- none: "none";
145
145
  }>>>>;
146
146
  flatAmountCents: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodNumber>>>;
147
147
  currency: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodString>>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/legal",
3
- "version": "0.6.9",
3
+ "version": "0.8.0",
4
4
  "license": "FSL-1.1-Apache-2.0",
5
5
  "type": "module",
6
6
  "exports": {
@@ -53,13 +53,14 @@
53
53
  "drizzle-orm": "^0.45.2",
54
54
  "hono": "^4.12.10",
55
55
  "zod": "^4.3.6",
56
- "@voyantjs/core": "0.6.9",
57
- "@voyantjs/crm": "0.6.9",
58
- "@voyantjs/db": "0.6.9",
59
- "@voyantjs/hono": "0.6.9",
60
- "@voyantjs/suppliers": "0.6.9",
61
- "@voyantjs/utils": "0.6.9",
62
- "@voyantjs/voyant-storage": "0.6.9"
56
+ "@voyantjs/bookings": "0.8.0",
57
+ "@voyantjs/core": "0.8.0",
58
+ "@voyantjs/crm": "0.8.0",
59
+ "@voyantjs/db": "0.8.0",
60
+ "@voyantjs/hono": "0.8.0",
61
+ "@voyantjs/suppliers": "0.8.0",
62
+ "@voyantjs/utils": "0.8.0",
63
+ "@voyantjs/voyant-storage": "0.8.0"
63
64
  },
64
65
  "devDependencies": {
65
66
  "typescript": "^6.0.2",