@voyant-travel/storefront 0.121.2 → 0.122.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/dist/index.d.ts CHANGED
@@ -3,6 +3,8 @@ import type { HonoModule } from "@voyant-travel/hono/module";
3
3
  import { createStorefrontPublicRoutes } from "./routes-public.js";
4
4
  export type { GuestBookingGuardOptions, GuestBookingGuardRequest, GuestBookingLookupInput, } from "./guest-booking-guard.js";
5
5
  export { createGuestBookingGuard } from "./guest-booking-guard.js";
6
+ export type { PaymentLinkBankTransferDetails, PaymentLinkRoutesOptions, PaymentLinkSessionInput, PaymentLinkTripComponent, PaymentLinkTripData, } from "./payment-link/routes.js";
7
+ export { createPaymentLinkRoutes } from "./payment-link/routes.js";
6
8
  export type { StorefrontAdminRoutes } from "./routes-admin.js";
7
9
  export { createStorefrontAdminRoutes } from "./routes-admin.js";
8
10
  export type { StorefrontPublicRoutes } from "./routes-public.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAQ5D,OAAO,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAA;AAGjE,YAAY,EACV,wBAAwB,EACxB,wBAAwB,EACxB,uBAAuB,GACxB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AAClE,YAAY,EACV,8BAA8B,EAC9B,wBAAwB,EACxB,uBAAuB,EACvB,wBAAwB,EACxB,mBAAmB,GACpB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AAClE,YAAY,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AAC9D,OAAO,EAAE,2BAA2B,EAAE,MAAM,mBAAmB,CAAA;AAC/D,YAAY,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAChE,OAAO,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAA;AACjE,YAAY,EACV,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,uBAAuB,EACvB,4BAA4B,EAC5B,yBAAyB,GAC1B,MAAM,cAAc,CAAA;AACrB,YAAY,EAAE,wCAAwC,EAAE,MAAM,wCAAwC,CAAA;AACtG,YAAY,EACV,oCAAoC,EACpC,qBAAqB,EACrB,6BAA6B,EAC7B,uBAAuB,EACvB,2BAA2B,EAC3B,mCAAmC,EACnC,sBAAsB,EACtB,sBAAsB,EACtB,mCAAmC,GACpC,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,6BAA6B,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAA;AAC9F,OAAO,EAAE,sCAAsC,EAAE,MAAM,oCAAoC,CAAA;AAC3F,YAAY,EACV,sBAAsB,EACtB,sBAAsB,EACtB,6BAA6B,EAC7B,kCAAkC,EAClC,2BAA2B,EAC3B,iCAAiC,EACjC,sCAAsC,EACtC,yBAAyB,EACzB,4BAA4B,EAC5B,+BAA+B,EAC/B,mBAAmB,EACnB,wBAAwB,EACxB,uBAAuB,EACvB,wBAAwB,EACxB,qBAAqB,EACrB,yBAAyB,EACzB,kCAAkC,EAClC,qCAAqC,EACrC,yBAAyB,EACzB,6BAA6B,EAC7B,0BAA0B,EAC1B,6BAA6B,EAC7B,uBAAuB,EACvB,2BAA2B,EAC3B,4BAA4B,EAC5B,yBAAyB,EACzB,8BAA8B,EAC9B,mCAAmC,EACnC,8BAA8B,EAC9B,0BAA0B,EAC1B,yCAAyC,EACzC,0BAA0B,EAC1B,kBAAkB,EAClB,uBAAuB,EACvB,4BAA4B,EAC5B,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,4BAA4B,EAC5B,wCAAwC,EACxC,mCAAmC,EACnC,iCAAiC,EACjC,4BAA4B,EAC5B,kDAAkD,EAClD,4CAA4C,EAC5C,uCAAuC,EACvC,yCAAyC,EACzC,mCAAmC,EACnC,+CAA+C,EAC/C,+BAA+B,EAC/B,kCAAkC,EAClC,kCAAkC,EAClC,qCAAqC,EACrC,wCAAwC,EACxC,yCAAyC,EACzC,sCAAsC,EACtC,yCAAyC,EACzC,oCAAoC,EACpC,iCAAiC,EACjC,0CAA0C,EAC1C,qCAAqC,EACrC,4CAA4C,EAC5C,qCAAqC,EACrC,kCAAkC,EAClC,oCAAoC,EACpC,qCAAqC,EACrC,yBAAyB,EACzB,8BAA8B,EAC9B,+BAA+B,EAC/B,yBAAyB,EACzB,6BAA6B,EAC7B,6BAA6B,EAC7B,8BAA8B,EAC9B,2BAA2B,EAC3B,+BAA+B,EAC/B,wCAAwC,EACxC,2CAA2C,EAC3C,+BAA+B,EAC/B,6BAA6B,EAC7B,6BAA6B,EAC7B,mCAAmC,EACnC,qCAAqC,EACrC,mCAAmC,EACnC,mCAAmC,EACnC,gCAAgC,EAChC,mCAAmC,EACnC,iCAAiC,EACjC,kCAAkC,EAClC,6BAA6B,EAC7B,yCAAyC,EACzC,oCAAoC,EACpC,oCAAoC,EACpC,+BAA+B,EAC/B,gCAAgC,EAChC,uCAAuC,EACvC,wCAAwC,EACxC,+CAA+C,EAC/C,kDAAkD,EAClD,0CAA0C,EAC1C,sCAAsC,EACtC,yCAAyC,EACzC,yCAAyC,EACzC,4CAA4C,EAC5C,wCAAwC,EACxC,gCAAgC,EAChC,6BAA6B,EAC7B,6BAA6B,EAC7B,wBAAwB,EACxB,gCAAgC,EAChC,2BAA2B,GAC5B,MAAM,iBAAiB,CAAA;AACxB,YAAY,EACV,mCAAmC,EACnC,mCAAmC,EACnC,oCAAoC,EACpC,kCAAkC,EAClC,uCAAuC,GACxC,MAAM,uCAAuC,CAAA;AAC9C,OAAO,EACL,oCAAoC,EACpC,iDAAiD,EACjD,yCAAyC,EACzC,6CAA6C,EAC7C,yCAAyC,EACzC,0CAA0C,EAC1C,wCAAwC,EACxC,4CAA4C,EAC5C,iDAAiD,EACjD,kDAAkD,EAClD,kCAAkC,GACnC,MAAM,uCAAuC,CAAA;AAE9C,eAAO,MAAM,gBAAgB,EAAE,MAE9B,CAAA;AAED,wBAAgB,0BAA0B,CACxC,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,4BAA4B,CAAC,CAAC,CAAC,CAAC,GAC3D,UAAU,CA2BZ;AACD,OAAO,EACL,8BAA8B,EAC9B,6BAA6B,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,6BAA6B,EAClC,mCAAmC,GACpC,MAAM,sBAAsB,CAAA"}
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ import { BOOKING_BOOTSTRAP_INTENT_EVENT, createBookingBootstrapIntentHandler, }
2
2
  import { createStorefrontAdminRoutes } from "./routes-admin.js";
3
3
  import { createStorefrontPublicRoutes } from "./routes-public.js";
4
4
  export { createGuestBookingGuard } from "./guest-booking-guard.js";
5
+ export { createPaymentLinkRoutes } from "./payment-link/routes.js";
5
6
  export { createStorefrontAdminRoutes } from "./routes-admin.js";
6
7
  export { createStorefrontPublicRoutes } from "./routes-public.js";
7
8
  export { createStorefrontService, mergeStorefrontSettingsPatch, resolveStorefrontSettings, } from "./service.js";
@@ -0,0 +1,97 @@
1
+ import type { Context } from "hono";
2
+ import { Hono } from "hono";
3
+ /** Resolved bank-transfer beneficiary details from operator settings + env. */
4
+ export interface PaymentLinkBankTransferDetails {
5
+ beneficiary: string;
6
+ iban: string;
7
+ bankName?: string | null;
8
+ }
9
+ /** A resolved trip component, with optional product enrichment. */
10
+ export interface PaymentLinkTripComponent {
11
+ id: string;
12
+ kind: string;
13
+ entityModule: string | null;
14
+ entityId: string | null;
15
+ description: string | null;
16
+ status: string | null;
17
+ sequence: number | null;
18
+ componentTotalAmountCents: number | null;
19
+ componentCurrency: string | null;
20
+ metadata: Record<string, unknown> | null;
21
+ }
22
+ /** A resolved trip envelope + its visible components and product enrichment. */
23
+ export interface PaymentLinkTripData {
24
+ envelope: {
25
+ id: string;
26
+ status: string | null;
27
+ };
28
+ /**
29
+ * Visible (non-removed, non-cancelled) components, already ordered by
30
+ * sequence then createdAt.
31
+ */
32
+ components: PaymentLinkTripComponent[];
33
+ /** product id → display name (from the inventory product record). */
34
+ productNameById: Map<string, string>;
35
+ /** product id → cover image (from inventory product media). */
36
+ mediaByProductId: Map<string, {
37
+ url: string;
38
+ altText: string | null;
39
+ }>;
40
+ }
41
+ /** The payment-session record fields the handlers read across routes. */
42
+ export interface PaymentLinkSessionInput {
43
+ invoiceId: string | null;
44
+ amountCents: number;
45
+ currency: string;
46
+ }
47
+ /**
48
+ * Deployment-supplied access the payment-link handlers need. Everything here
49
+ * encapsulates a module storefront does not statically depend on, so the
50
+ * package stays free of inventory / trips / netopia / operator-settings
51
+ * imports.
52
+ */
53
+ export interface PaymentLinkRoutesOptions {
54
+ /**
55
+ * Resolve the bank-transfer beneficiary details (operator settings merged
56
+ * with deploy-wide env defaults), or `null` when not configured.
57
+ */
58
+ resolveBankTransferDetails(c: Context): Promise<PaymentLinkBankTransferDetails | null>;
59
+ /** Resolve the public checkout base URL from the deployment bindings. */
60
+ resolvePublicCheckoutBaseUrl(c: Context): string | null;
61
+ /**
62
+ * Best-effort: ensure a fresh payment session can be started on the card
63
+ * provider, returning the redirect URL (or null). Returns `{ configured:
64
+ * false }` when no card processor is wired so the handler can 503. May throw
65
+ * — the handler maps the error to a 502.
66
+ */
67
+ startCardPayment(c: Context, session: {
68
+ id: string;
69
+ payerName: string | null;
70
+ payerEmail: string | null;
71
+ notes: string | null;
72
+ redirectUrl: string | null;
73
+ }): Promise<{
74
+ configured: true;
75
+ redirectUrl: string | null;
76
+ } | {
77
+ configured: false;
78
+ }>;
79
+ /**
80
+ * Resolve a trip envelope (+ reconcile a paid checkout) and its visible
81
+ * components with product-media enrichment, or `null` when the envelope is
82
+ * gone. Encapsulates the trips + inventory schema reads.
83
+ */
84
+ resolveTripData(c: Context, tripEnvelopeId: string, session: {
85
+ id: string;
86
+ status: string | null;
87
+ amountCents: number;
88
+ currency: string;
89
+ provider: string | null;
90
+ }): Promise<PaymentLinkTripData | null>;
91
+ }
92
+ /**
93
+ * Build the public payment-link routes. Paths are ABSOLUTE so the deployment
94
+ * can lazy-mount the returned app directly via `lazyRoutes.paths`.
95
+ */
96
+ export declare function createPaymentLinkRoutes(options: PaymentLinkRoutesOptions): Hono;
97
+ //# sourceMappingURL=routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/payment-link/routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,473 @@
1
+ /**
2
+ * Public payment-link + checkout-status routes — owned by
3
+ * `@voyant-travel/storefront`.
4
+ *
5
+ * agent-quality: file-size exception -- the public payment-link surface
6
+ * (config, retry, resolve, start-card, trip/booking summary, checkout-status)
7
+ * is one cohesive route family backed by the finance payment-session record;
8
+ * splitting it would scatter a single checkout contract.
9
+ *
10
+ * GET /v1/public/payment-link-config
11
+ * POST /v1/public/payment-link/:sessionId/retry
12
+ * GET /v1/public/payment-link/resolve
13
+ * POST /v1/public/payment-link/:sessionId/start-card
14
+ * GET /v1/public/payment-link/:sessionId/trip-summary
15
+ * GET /v1/public/payment-link/:sessionId/booking-summary
16
+ * GET /v1/public/bookings/:bookingId/checkout-status
17
+ *
18
+ * The routes are mounted at their ABSOLUTE public paths so the deployment can
19
+ * lazy-mount them via `lazyRoutes.paths`. All cross-module access that
20
+ * storefront does not already depend on (inventory product media, trip
21
+ * envelopes/components reconciliation, the card-payment provider, and the
22
+ * operator settings + checkout base URL) is INJECTED via `options` — the
23
+ * package never statically imports inventory / trips / the netopia plugin /
24
+ * the operator settings module.
25
+ *
26
+ * Storefront already depends acyclically on `@voyant-travel/bookings` and
27
+ * `@voyant-travel/finance`, so the booking / invoice / payment-session reads
28
+ * use those schemas directly.
29
+ */
30
+ import { bookingItems, bookings } from "@voyant-travel/bookings/schema";
31
+ import { financeService } from "@voyant-travel/finance";
32
+ import { invoices, paymentSessions } from "@voyant-travel/finance/schema";
33
+ import { and, asc, desc, eq, or } from "drizzle-orm";
34
+ import { Hono } from "hono";
35
+ const PUBLIC_PAYMENT_LINK_CONFIG_CACHE_CONTROL = "public, s-maxage=300, stale-while-revalidate=600";
36
+ // ─────────────────────────────────────────────────────────────────
37
+ // Local helpers
38
+ // ─────────────────────────────────────────────────────────────────
39
+ function cachePublicPaymentLinkConfig(c) {
40
+ c.header("Cache-Control", PUBLIC_PAYMENT_LINK_CONFIG_CACHE_CONTROL);
41
+ }
42
+ function requireRouteParam(c, name) {
43
+ const value = c.req.param(name);
44
+ return value ? value : c.json({ error: `${name} route param is required` }, 400);
45
+ }
46
+ function getDb(c) {
47
+ return c.get("db");
48
+ }
49
+ async function buildPublicBankTransferInstructions(c, options, bookingNumber, session) {
50
+ const db = getDb(c);
51
+ const details = await options.resolveBankTransferDetails(c);
52
+ if (!details)
53
+ return null;
54
+ const [invoice] = session.invoiceId
55
+ ? await db
56
+ .select({
57
+ invoiceNumber: invoices.invoiceNumber,
58
+ dueDate: invoices.dueDate,
59
+ balanceDueCents: invoices.balanceDueCents,
60
+ currency: invoices.currency,
61
+ })
62
+ .from(invoices)
63
+ .where(eq(invoices.id, session.invoiceId))
64
+ .limit(1)
65
+ : [];
66
+ return {
67
+ beneficiary: details.beneficiary,
68
+ iban: details.iban,
69
+ bankName: details.bankName ?? "-",
70
+ reference: `BOOK-${bookingNumber}`,
71
+ amountCents: invoice?.balanceDueCents ?? session.amountCents,
72
+ currency: invoice?.currency ?? session.currency,
73
+ dueAt: invoice?.dueDate ?? null,
74
+ proformaNumber: invoice?.invoiceNumber ?? null,
75
+ };
76
+ }
77
+ // ─────────────────────────────────────────────────────────────────
78
+ // Routes
79
+ // ─────────────────────────────────────────────────────────────────
80
+ /**
81
+ * Build the public payment-link routes. Paths are ABSOLUTE so the deployment
82
+ * can lazy-mount the returned app directly via `lazyRoutes.paths`.
83
+ */
84
+ export function createPaymentLinkRoutes(options) {
85
+ const hono = new Hono();
86
+ hono.get("/v1/public/payment-link-config", async (c) => {
87
+ const bankTransfer = await options.resolveBankTransferDetails(c);
88
+ cachePublicPaymentLinkConfig(c);
89
+ return c.json({
90
+ data: {
91
+ publicCheckoutBaseUrl: options.resolvePublicCheckoutBaseUrl(c),
92
+ bankTransfer,
93
+ },
94
+ });
95
+ });
96
+ hono.post("/v1/public/payment-link/:sessionId/retry", async (c) => {
97
+ const sessionId = requireRouteParam(c, "sessionId");
98
+ if (sessionId instanceof Response)
99
+ return sessionId;
100
+ const db = getDb(c);
101
+ const [original] = await db
102
+ .select()
103
+ .from(paymentSessions)
104
+ .where(eq(paymentSessions.id, sessionId))
105
+ .limit(1);
106
+ if (!original)
107
+ return c.json({ error: "Session not found" }, 404);
108
+ if (original.status === "paid" || original.status === "authorized") {
109
+ return c.json({ data: { sessionId: original.id, alreadyPaid: true } });
110
+ }
111
+ const dbCast = db;
112
+ const fresh = await financeService.createPaymentSession(dbCast, {
113
+ targetType: original.targetType,
114
+ targetId: original.targetId ?? undefined,
115
+ bookingId: original.bookingId ?? undefined,
116
+ invoiceId: original.invoiceId ?? undefined,
117
+ bookingPaymentScheduleId: original.bookingPaymentScheduleId ?? undefined,
118
+ bookingGuaranteeId: original.bookingGuaranteeId ?? undefined,
119
+ currency: original.currency,
120
+ amountCents: original.amountCents,
121
+ status: "pending",
122
+ provider: original.provider ?? undefined,
123
+ paymentMethod: original.paymentMethod ?? undefined,
124
+ payerEmail: original.payerEmail ?? undefined,
125
+ payerName: original.payerName ?? undefined,
126
+ notes: original.notes ?? undefined,
127
+ });
128
+ if (!fresh)
129
+ return c.json({ error: "Failed to create payment session" }, 500);
130
+ return c.json({ data: { sessionId: fresh.id } });
131
+ });
132
+ hono.get("/v1/public/payment-link/resolve", async (c) => {
133
+ const ref = c.req.query("ref");
134
+ if (!ref)
135
+ return c.json({ error: "ref query param is required" }, 400);
136
+ const db = getDb(c);
137
+ const [session] = await db
138
+ .select({ id: paymentSessions.id })
139
+ .from(paymentSessions)
140
+ .where(or(eq(paymentSessions.id, ref), eq(paymentSessions.clientReference, ref), eq(paymentSessions.externalReference, ref)))
141
+ .limit(1);
142
+ if (!session)
143
+ return c.json({ error: "Payment session not found" }, 404);
144
+ return c.json({ data: { sessionId: session.id } });
145
+ });
146
+ hono.post("/v1/public/payment-link/:sessionId/start-card", async (c) => {
147
+ const sessionId = requireRouteParam(c, "sessionId");
148
+ if (sessionId instanceof Response)
149
+ return sessionId;
150
+ const db = getDb(c);
151
+ const [session] = await db
152
+ .select()
153
+ .from(paymentSessions)
154
+ .where(eq(paymentSessions.id, sessionId))
155
+ .limit(1);
156
+ if (!session)
157
+ return c.json({ error: "Session not found" }, 404);
158
+ if (session.redirectUrl) {
159
+ return c.json({ data: { redirectUrl: session.redirectUrl } });
160
+ }
161
+ try {
162
+ const started = await options.startCardPayment(c, {
163
+ id: session.id,
164
+ payerName: session.payerName,
165
+ payerEmail: session.payerEmail,
166
+ notes: session.notes,
167
+ redirectUrl: session.redirectUrl,
168
+ });
169
+ if (!started.configured) {
170
+ return c.json({ error: "Card processor not configured" }, 503);
171
+ }
172
+ return c.json({ data: { redirectUrl: started.redirectUrl } });
173
+ }
174
+ catch (err) {
175
+ const message = err instanceof Error ? err.message : "Failed to start card payment";
176
+ return c.json({ error: message }, 502);
177
+ }
178
+ });
179
+ hono.get("/v1/public/payment-link/:sessionId/trip-summary", async (c) => {
180
+ const sessionId = requireRouteParam(c, "sessionId");
181
+ if (sessionId instanceof Response)
182
+ return sessionId;
183
+ const db = getDb(c);
184
+ const [session] = await db
185
+ .select()
186
+ .from(paymentSessions)
187
+ .where(eq(paymentSessions.id, sessionId))
188
+ .limit(1);
189
+ if (!session)
190
+ return c.json({ error: "Session not found" }, 404);
191
+ const metadata = (session.metadata ?? {});
192
+ const tripEnvelopeId = typeof metadata.tripEnvelopeId === "string" ? metadata.tripEnvelopeId : null;
193
+ if (!tripEnvelopeId)
194
+ return c.json({ data: null });
195
+ const tripData = await options.resolveTripData(c, tripEnvelopeId, {
196
+ id: session.id,
197
+ status: session.status,
198
+ amountCents: session.amountCents,
199
+ currency: session.currency,
200
+ provider: session.provider,
201
+ });
202
+ if (!tripData)
203
+ return c.json({ data: null });
204
+ const { envelope, components: visibleComponents, productNameById, mediaByProductId } = tripData;
205
+ const allocationsRaw = Array.isArray(metadata.componentAllocations)
206
+ ? metadata.componentAllocations
207
+ : [];
208
+ const allocationByComponentId = new Map();
209
+ for (const allocation of allocationsRaw) {
210
+ if (allocation.componentId)
211
+ allocationByComponentId.set(allocation.componentId, allocation);
212
+ }
213
+ const trip = {
214
+ envelopeId: envelope.id,
215
+ currency: session.currency,
216
+ totalAmountCents: session.amountCents,
217
+ components: visibleComponents.map((component) => {
218
+ const metadataRecord = (component.metadata ?? {});
219
+ const catalogItem = (metadataRecord.catalogItem ?? null);
220
+ const flightDraft = (metadataRecord.flightDraft ?? null);
221
+ const schedule = resolvePublicTripComponentSchedule(metadataRecord);
222
+ const fallbackName = catalogItem?.name ??
223
+ (component.entityId ? productNameById.get(component.entityId) : null) ??
224
+ (flightDraft?.origin && flightDraft?.destination
225
+ ? `${flightDraft.origin} -> ${flightDraft.destination}`
226
+ : null) ??
227
+ component.description ??
228
+ component.kind.replaceAll("_", " ");
229
+ const thumbnail = component.entityId
230
+ ? (mediaByProductId.get(component.entityId) ?? null)
231
+ : null;
232
+ const catalogThumbnailUrl = publicStringValue(readPublicRecord(metadataRecord.catalogItem)?.thumbnailUrl);
233
+ const allocation = allocationByComponentId.get(component.id);
234
+ return {
235
+ id: component.id,
236
+ kind: component.kind,
237
+ entityModule: component.entityModule,
238
+ title: fallbackName,
239
+ thumbnailUrl: thumbnail?.url ?? catalogThumbnailUrl ?? null,
240
+ thumbnailAlt: thumbnail?.altText ?? null,
241
+ scheduledStartsAt: schedule.start,
242
+ scheduledEndsAt: schedule.end,
243
+ sourceAmountCents: allocation?.sourceAmountCents ?? component.componentTotalAmountCents ?? null,
244
+ sourceCurrency: allocation?.sourceCurrency ?? component.componentCurrency ?? session.currency,
245
+ targetAmountCents: allocation?.targetAmountCents ?? component.componentTotalAmountCents ?? null,
246
+ targetCurrency: allocation?.targetCurrency ?? session.currency,
247
+ fx: allocation?.fx ?? null,
248
+ };
249
+ }),
250
+ };
251
+ return c.json({ data: trip });
252
+ });
253
+ hono.get("/v1/public/payment-link/:sessionId/booking-summary", async (c) => {
254
+ const sessionId = requireRouteParam(c, "sessionId");
255
+ if (sessionId instanceof Response)
256
+ return sessionId;
257
+ const db = getDb(c);
258
+ const [session] = await db
259
+ .select({
260
+ id: paymentSessions.id,
261
+ bookingId: paymentSessions.bookingId,
262
+ amountCents: paymentSessions.amountCents,
263
+ currency: paymentSessions.currency,
264
+ metadata: paymentSessions.metadata,
265
+ })
266
+ .from(paymentSessions)
267
+ .where(eq(paymentSessions.id, sessionId))
268
+ .limit(1);
269
+ if (!session)
270
+ return c.json({ error: "Session not found" }, 404);
271
+ const metadata = (session.metadata ?? {});
272
+ if (typeof metadata.tripEnvelopeId === "string" && metadata.tripEnvelopeId.length > 0) {
273
+ return c.json({ data: null });
274
+ }
275
+ if (!session.bookingId)
276
+ return c.json({ data: null });
277
+ const [booking] = await db
278
+ .select({
279
+ id: bookings.id,
280
+ bookingNumber: bookings.bookingNumber,
281
+ status: bookings.status,
282
+ sellCurrency: bookings.sellCurrency,
283
+ sellAmountCents: bookings.sellAmountCents,
284
+ pax: bookings.pax,
285
+ startDate: bookings.startDate,
286
+ endDate: bookings.endDate,
287
+ })
288
+ .from(bookings)
289
+ .where(eq(bookings.id, session.bookingId))
290
+ .limit(1);
291
+ if (!booking)
292
+ return c.json({ data: null });
293
+ const items = await db
294
+ .select({
295
+ id: bookingItems.id,
296
+ title: bookingItems.title,
297
+ itemType: bookingItems.itemType,
298
+ quantity: bookingItems.quantity,
299
+ totalSellAmountCents: bookingItems.totalSellAmountCents,
300
+ sellCurrency: bookingItems.sellCurrency,
301
+ startsAt: bookingItems.startsAt,
302
+ endsAt: bookingItems.endsAt,
303
+ serviceDate: bookingItems.serviceDate,
304
+ productNameSnapshot: bookingItems.productNameSnapshot,
305
+ optionNameSnapshot: bookingItems.optionNameSnapshot,
306
+ unitNameSnapshot: bookingItems.unitNameSnapshot,
307
+ departureLabelSnapshot: bookingItems.departureLabelSnapshot,
308
+ })
309
+ .from(bookingItems)
310
+ .where(eq(bookingItems.bookingId, booking.id))
311
+ .orderBy(asc(bookingItems.createdAt));
312
+ return c.json({
313
+ data: {
314
+ bookingId: booking.id,
315
+ bookingNumber: booking.bookingNumber,
316
+ status: booking.status,
317
+ pax: booking.pax,
318
+ startDate: booking.startDate,
319
+ endDate: booking.endDate,
320
+ chargeAmountCents: session.amountCents,
321
+ currency: session.currency ?? booking.sellCurrency,
322
+ bookingTotalAmountCents: booking.sellAmountCents,
323
+ bookingCurrency: booking.sellCurrency,
324
+ items: items.map((item) => ({
325
+ id: item.id,
326
+ productName: item.productNameSnapshot ?? item.title,
327
+ optionName: item.optionNameSnapshot,
328
+ unitName: item.unitNameSnapshot,
329
+ departureLabel: item.departureLabelSnapshot,
330
+ startsAt: item.startsAt instanceof Date ? item.startsAt.toISOString() : item.startsAt,
331
+ endsAt: item.endsAt instanceof Date ? item.endsAt.toISOString() : item.endsAt,
332
+ serviceDate: item.serviceDate,
333
+ quantity: item.quantity,
334
+ itemType: item.itemType,
335
+ amountCents: item.totalSellAmountCents,
336
+ currency: item.sellCurrency,
337
+ })),
338
+ },
339
+ });
340
+ });
341
+ hono.get("/v1/public/bookings/:bookingId/checkout-status", async (c) => {
342
+ const bookingId = requireRouteParam(c, "bookingId");
343
+ if (bookingId instanceof Response)
344
+ return bookingId;
345
+ const ref = c.req.query("session") ?? c.req.query("orderId") ?? c.req.query("ref") ?? null;
346
+ const db = getDb(c);
347
+ const [booking] = await db
348
+ .select({
349
+ id: bookings.id,
350
+ bookingNumber: bookings.bookingNumber,
351
+ status: bookings.status,
352
+ updatedAt: bookings.updatedAt,
353
+ })
354
+ .from(bookings)
355
+ .where(eq(bookings.id, bookingId))
356
+ .limit(1);
357
+ if (!booking)
358
+ return c.json({ error: "Booking not found" }, 404);
359
+ const sessionRefFilter = ref
360
+ ? or(eq(paymentSessions.id, ref), eq(paymentSessions.clientReference, ref), eq(paymentSessions.externalReference, ref), eq(paymentSessions.providerSessionId, ref), eq(paymentSessions.providerPaymentId, ref))
361
+ : undefined;
362
+ const sessionWhere = sessionRefFilter
363
+ ? and(eq(paymentSessions.bookingId, bookingId), sessionRefFilter)
364
+ : eq(paymentSessions.bookingId, bookingId);
365
+ let sessions = await db
366
+ .select({
367
+ id: paymentSessions.id,
368
+ status: paymentSessions.status,
369
+ amountCents: paymentSessions.amountCents,
370
+ currency: paymentSessions.currency,
371
+ invoiceId: paymentSessions.invoiceId,
372
+ paymentMethod: paymentSessions.paymentMethod,
373
+ completedAt: paymentSessions.completedAt,
374
+ failedAt: paymentSessions.failedAt,
375
+ updatedAt: paymentSessions.updatedAt,
376
+ })
377
+ .from(paymentSessions)
378
+ .where(sessionWhere)
379
+ .orderBy(desc(paymentSessions.createdAt))
380
+ .limit(5);
381
+ if (sessions.length === 0 && ref) {
382
+ sessions = await db
383
+ .select({
384
+ id: paymentSessions.id,
385
+ status: paymentSessions.status,
386
+ amountCents: paymentSessions.amountCents,
387
+ currency: paymentSessions.currency,
388
+ invoiceId: paymentSessions.invoiceId,
389
+ paymentMethod: paymentSessions.paymentMethod,
390
+ completedAt: paymentSessions.completedAt,
391
+ failedAt: paymentSessions.failedAt,
392
+ updatedAt: paymentSessions.updatedAt,
393
+ })
394
+ .from(paymentSessions)
395
+ .where(eq(paymentSessions.bookingId, bookingId))
396
+ .orderBy(desc(paymentSessions.createdAt))
397
+ .limit(5);
398
+ }
399
+ const paidSession = sessions.find((session) => session.status === "paid" || session.status === "authorized");
400
+ const latestSession = paidSession ?? sessions[0] ?? null;
401
+ const isBankTransferSession = latestSession?.paymentMethod === "bank_transfer" ||
402
+ (booking.status === "awaiting_payment" && Boolean(latestSession?.invoiceId));
403
+ const bankTransferInstructions = isBankTransferSession && latestSession
404
+ ? await buildPublicBankTransferInstructions(c, options, booking.bookingNumber, latestSession)
405
+ : null;
406
+ const failedStatuses = new Set(["failed", "cancelled", "expired"]);
407
+ const paymentStatus = booking.status === "confirmed" || paidSession
408
+ ? "paid"
409
+ : sessions.length > 0 && sessions.every((session) => failedStatuses.has(session.status))
410
+ ? "failed"
411
+ : "pending";
412
+ return c.json({
413
+ data: {
414
+ bookingId: booking.id,
415
+ bookingNumber: booking.bookingNumber,
416
+ bookingStatus: booking.status,
417
+ paymentStatus,
418
+ session: latestSession,
419
+ bankTransferInstructions,
420
+ updatedAt: (latestSession?.updatedAt ?? booking.updatedAt)?.toISOString?.() ?? null,
421
+ },
422
+ });
423
+ });
424
+ return hono;
425
+ }
426
+ // ─────────────────────────────────────────────────────────────────
427
+ // Pure schedule resolution helpers
428
+ // ─────────────────────────────────────────────────────────────────
429
+ function resolvePublicTripComponentSchedule(metadata) {
430
+ const scheduledStart = publicStringValue(metadata.scheduledStartsAt);
431
+ const scheduledEnd = publicStringValue(metadata.scheduledEndsAt);
432
+ if (scheduledStart)
433
+ return { start: scheduledStart, end: scheduledEnd };
434
+ const flightDraft = readPublicRecord(metadata.flightDraft);
435
+ if (flightDraft) {
436
+ const selectedOffer = readPublicRecord(flightDraft.selectedOffer);
437
+ const itineraries = Array.isArray(selectedOffer?.itineraries) ? selectedOffer.itineraries : [];
438
+ const firstItinerary = readPublicRecord(itineraries[0]);
439
+ const lastItinerary = readPublicRecord(itineraries[itineraries.length - 1]);
440
+ const firstSegments = Array.isArray(firstItinerary?.segments) ? firstItinerary.segments : [];
441
+ const lastSegments = Array.isArray(lastItinerary?.segments) ? lastItinerary.segments : [];
442
+ const firstSegment = readPublicRecord(firstSegments[0]);
443
+ const lastSegment = readPublicRecord(lastSegments[lastSegments.length - 1]);
444
+ const departure = readPublicRecord(firstSegment?.departure);
445
+ const arrival = readPublicRecord(lastSegment?.arrival);
446
+ return {
447
+ start: publicStringValue(departure?.at) ?? publicStringValue(flightDraft.departDate),
448
+ end: publicStringValue(arrival?.at) ?? publicStringValue(flightDraft.returnDate),
449
+ };
450
+ }
451
+ const bookingDraft = readPublicRecord(metadata.bookingDraftV1);
452
+ const configure = readPublicRecord(bookingDraft?.configure);
453
+ const dateRange = readPublicRecord(configure?.dateRange);
454
+ const departureDate = publicStringValue(configure?.departureDate);
455
+ const checkIn = publicStringValue(dateRange?.checkIn);
456
+ const checkOut = publicStringValue(dateRange?.checkOut);
457
+ if (departureDate || checkIn) {
458
+ return { start: departureDate ?? checkIn, end: checkOut };
459
+ }
460
+ const cruiseDraft = readPublicRecord(metadata.cruiseDraft);
461
+ const embarkationDate = publicStringValue(cruiseDraft?.embarkationDate);
462
+ if (embarkationDate)
463
+ return { start: embarkationDate, end: null };
464
+ return { start: null, end: null };
465
+ }
466
+ function readPublicRecord(value) {
467
+ return value && typeof value === "object" && !Array.isArray(value)
468
+ ? value
469
+ : null;
470
+ }
471
+ function publicStringValue(value) {
472
+ return typeof value === "string" && value.trim() ? value.trim() : null;
473
+ }
@@ -126,7 +126,7 @@ export declare function createStorefrontPublicRoutes(options?: StorefrontService
126
126
  error: string;
127
127
  };
128
128
  outputFormat: "json";
129
- status: 429 | 400 | 403;
129
+ status: 400 | 403 | 429;
130
130
  } | {
131
131
  input: {};
132
132
  output: {
@@ -134,7 +134,7 @@ export declare function createStorefrontPublicRoutes(options?: StorefrontService
134
134
  id: string;
135
135
  personId: string;
136
136
  kind: "notify" | "wishlist" | "inquiry" | "request_offer" | "referral";
137
- source: "admin" | "phone" | "booking" | "form" | "website" | "abandoned_cart";
137
+ source: "admin" | "form" | "phone" | "booking" | "website" | "abandoned_cart";
138
138
  status: "expired" | "new" | "contacted" | "qualified" | "converted" | "lost";
139
139
  duplicate: boolean;
140
140
  };
@@ -151,7 +151,7 @@ export declare function createStorefrontPublicRoutes(options?: StorefrontService
151
151
  error: string;
152
152
  };
153
153
  outputFormat: "json";
154
- status: 429 | 400 | 403;
154
+ status: 400 | 403 | 429;
155
155
  } | {
156
156
  input: {};
157
157
  output: {
@@ -159,7 +159,7 @@ export declare function createStorefrontPublicRoutes(options?: StorefrontService
159
159
  id: string;
160
160
  personId: string;
161
161
  kind: "notify" | "wishlist" | "inquiry" | "request_offer" | "referral";
162
- source: "admin" | "phone" | "booking" | "form" | "website" | "abandoned_cart";
162
+ source: "admin" | "form" | "phone" | "booking" | "website" | "abandoned_cart";
163
163
  status: "expired" | "new" | "contacted" | "qualified" | "converted" | "lost";
164
164
  duplicate: boolean;
165
165
  doubleOptIn: "requested" | "not_configured";
package/dist/service.d.ts CHANGED
@@ -1041,7 +1041,7 @@ export declare function createStorefrontService(options?: StorefrontServiceOptio
1041
1041
  id: string;
1042
1042
  personId: string;
1043
1043
  kind: "notify" | "wishlist" | "inquiry" | "request_offer" | "referral";
1044
- source: "admin" | "phone" | "booking" | "form" | "website" | "abandoned_cart";
1044
+ source: "admin" | "form" | "phone" | "booking" | "website" | "abandoned_cart";
1045
1045
  status: "expired" | "new" | "contacted" | "qualified" | "converted" | "lost";
1046
1046
  duplicate: boolean;
1047
1047
  }>;
@@ -1052,7 +1052,7 @@ export declare function createStorefrontService(options?: StorefrontServiceOptio
1052
1052
  id: string;
1053
1053
  personId: string;
1054
1054
  kind: "notify" | "wishlist" | "inquiry" | "request_offer" | "referral";
1055
- source: "admin" | "phone" | "booking" | "form" | "website" | "abandoned_cart";
1055
+ source: "admin" | "form" | "phone" | "booking" | "website" | "abandoned_cart";
1056
1056
  status: "expired" | "new" | "contacted" | "qualified" | "converted" | "lost";
1057
1057
  duplicate: boolean;
1058
1058
  doubleOptIn: "requested" | "not_configured";
@@ -23,9 +23,9 @@ export declare const storefrontLeadIntakeInputSchema: z.ZodObject<{
23
23
  }>>;
24
24
  source: z.ZodDefault<z.ZodEnum<{
25
25
  admin: "admin";
26
+ form: "form";
26
27
  phone: "phone";
27
28
  booking: "booking";
28
- form: "form";
29
29
  website: "website";
30
30
  abandoned_cart: "abandoned_cart";
31
31
  }>>;
@@ -59,9 +59,9 @@ export declare const storefrontNewsletterSubscribeInputSchema: z.ZodObject<{
59
59
  lastName: z.ZodOptional<z.ZodString>;
60
60
  source: z.ZodDefault<z.ZodEnum<{
61
61
  admin: "admin";
62
+ form: "form";
62
63
  phone: "phone";
63
64
  booking: "booking";
64
- form: "form";
65
65
  website: "website";
66
66
  abandoned_cart: "abandoned_cart";
67
67
  }>>;
@@ -90,9 +90,9 @@ export declare const storefrontIntakeResponseSchema: z.ZodObject<{
90
90
  }>;
91
91
  source: z.ZodEnum<{
92
92
  admin: "admin";
93
+ form: "form";
93
94
  phone: "phone";
94
95
  booking: "booking";
95
- form: "form";
96
96
  website: "website";
97
97
  abandoned_cart: "abandoned_cart";
98
98
  }>;
@@ -118,9 +118,9 @@ export declare const storefrontNewsletterSubscribeResponseSchema: z.ZodObject<{
118
118
  }>;
119
119
  source: z.ZodEnum<{
120
120
  admin: "admin";
121
+ form: "form";
121
122
  phone: "phone";
122
123
  booking: "booking";
123
- form: "form";
124
124
  website: "website";
125
125
  abandoned_cart: "abandoned_cart";
126
126
  }>;
@@ -46,7 +46,7 @@ export declare function createStorefrontVerificationPublicRoutes(options?: Store
46
46
  error: string;
47
47
  };
48
48
  outputFormat: "json";
49
- status: 404 | 400 | 409 | 410 | 501;
49
+ status: 400 | 404 | 409 | 410 | 501;
50
50
  } | {
51
51
  input: {};
52
52
  output: {
@@ -95,7 +95,7 @@ export declare function createStorefrontVerificationPublicRoutes(options?: Store
95
95
  error: string;
96
96
  };
97
97
  outputFormat: "json";
98
- status: 404 | 400 | 409 | 410 | 501;
98
+ status: 400 | 404 | 409 | 410 | 501;
99
99
  } | {
100
100
  input: {};
101
101
  output: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyant-travel/storefront",
3
- "version": "0.121.2",
3
+ "version": "0.122.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "exports": {
@@ -34,6 +34,11 @@
34
34
  "import": "./dist/customer-portal/routes.js",
35
35
  "default": "./dist/customer-portal/routes.js"
36
36
  },
37
+ "./payment-link": {
38
+ "types": "./dist/payment-link/routes.d.ts",
39
+ "import": "./dist/payment-link/routes.js",
40
+ "default": "./dist/payment-link/routes.js"
41
+ },
37
42
  "./public-routes": {
38
43
  "types": "./dist/routes-public.d.ts",
39
44
  "import": "./dist/routes-public.js",
@@ -90,19 +95,19 @@
90
95
  "drizzle-orm": "^0.45.2",
91
96
  "hono": "^4.12.10",
92
97
  "zod": "^4.3.6",
93
- "@voyant-travel/bookings": "^0.120.2",
94
- "@voyant-travel/commerce": "^0.2.3",
95
98
  "@voyant-travel/core": "^0.109.0",
99
+ "@voyant-travel/bookings": "^0.121.0",
96
100
  "@voyant-travel/db": "^0.108.1",
97
- "@voyant-travel/finance": "^0.120.1",
98
- "@voyant-travel/hono": "^0.110.3",
99
- "@voyant-travel/relationships-contracts": "^0.107.0",
100
- "@voyant-travel/utils": "^0.105.2"
101
+ "@voyant-travel/commerce": "^0.3.0",
102
+ "@voyant-travel/finance": "^0.121.0",
103
+ "@voyant-travel/hono": "^0.111.0",
104
+ "@voyant-travel/utils": "^0.105.2",
105
+ "@voyant-travel/relationships-contracts": "^0.107.0"
101
106
  },
102
107
  "peerDependencies": {
103
- "@voyant-travel/identity": "^0.120.1",
104
- "@voyant-travel/legal": "^0.120.2",
105
- "@voyant-travel/relationships": "^0.119.3"
108
+ "@voyant-travel/legal": "^0.121.0",
109
+ "@voyant-travel/relationships": "^0.119.4",
110
+ "@voyant-travel/identity": "^0.121.0"
106
111
  },
107
112
  "peerDependenciesMeta": {
108
113
  "@voyant-travel/identity": {
@@ -118,12 +123,12 @@
118
123
  "devDependencies": {
119
124
  "typescript": "^6.0.2",
120
125
  "vitest": "^4.1.2",
121
- "@voyant-travel/identity": "^0.120.1",
122
- "@voyant-travel/inventory": "^0.2.0",
123
- "@voyant-travel/legal": "^0.120.2",
124
- "@voyant-travel/relationships": "^0.119.3",
125
- "@voyant-travel/operations": "^0.1.0",
126
- "@voyant-travel/voyant-typescript-config": "^0.1.0"
126
+ "@voyant-travel/identity": "^0.121.0",
127
+ "@voyant-travel/operations": "^0.1.1",
128
+ "@voyant-travel/legal": "^0.121.0",
129
+ "@voyant-travel/voyant-typescript-config": "^0.1.0",
130
+ "@voyant-travel/relationships": "^0.119.4",
131
+ "@voyant-travel/inventory": "^0.3.0"
127
132
  },
128
133
  "files": [
129
134
  "dist"