@voyant-travel/storefront 0.120.1

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.
Files changed (126) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +231 -0
  3. package/dist/booking-intents.d.ts +42 -0
  4. package/dist/booking-intents.d.ts.map +1 -0
  5. package/dist/booking-intents.js +83 -0
  6. package/dist/customer-portal/index.d.ts +16 -0
  7. package/dist/customer-portal/index.d.ts.map +1 -0
  8. package/dist/customer-portal/index.js +23 -0
  9. package/dist/customer-portal/route-runtime.d.ts +16 -0
  10. package/dist/customer-portal/route-runtime.d.ts.map +1 -0
  11. package/dist/customer-portal/route-runtime.js +27 -0
  12. package/dist/customer-portal/routes-public.d.ts +1936 -0
  13. package/dist/customer-portal/routes-public.d.ts.map +1 -0
  14. package/dist/customer-portal/routes-public.js +165 -0
  15. package/dist/customer-portal/routes.d.ts +43 -0
  16. package/dist/customer-portal/routes.d.ts.map +1 -0
  17. package/dist/customer-portal/routes.js +17 -0
  18. package/dist/customer-portal/service-public-impl.d.ts +138 -0
  19. package/dist/customer-portal/service-public-impl.d.ts.map +1 -0
  20. package/dist/customer-portal/service-public-impl.js +1808 -0
  21. package/dist/customer-portal/service-public.d.ts +2 -0
  22. package/dist/customer-portal/service-public.d.ts.map +1 -0
  23. package/dist/customer-portal/service-public.js +1 -0
  24. package/dist/customer-portal/validation-public/bookings.d.ts +551 -0
  25. package/dist/customer-portal/validation-public/bookings.d.ts.map +1 -0
  26. package/dist/customer-portal/validation-public/bookings.js +132 -0
  27. package/dist/customer-portal/validation-public/common.d.ts +162 -0
  28. package/dist/customer-portal/validation-public/common.d.ts.map +1 -0
  29. package/dist/customer-portal/validation-public/common.js +139 -0
  30. package/dist/customer-portal/validation-public/profile.d.ts +749 -0
  31. package/dist/customer-portal/validation-public/profile.d.ts.map +1 -0
  32. package/dist/customer-portal/validation-public/profile.js +308 -0
  33. package/dist/customer-portal/validation-public.d.ts +3 -0
  34. package/dist/customer-portal/validation-public.d.ts.map +1 -0
  35. package/dist/customer-portal/validation-public.js +2 -0
  36. package/dist/guest-booking-guard.d.ts +24 -0
  37. package/dist/guest-booking-guard.d.ts.map +1 -0
  38. package/dist/guest-booking-guard.js +55 -0
  39. package/dist/index.d.ts +23 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +41 -0
  42. package/dist/product-extra-ref.d.ts +238 -0
  43. package/dist/product-extra-ref.d.ts.map +1 -0
  44. package/dist/product-extra-ref.js +22 -0
  45. package/dist/routes-admin.d.ts +220 -0
  46. package/dist/routes-admin.d.ts.map +1 -0
  47. package/dist/routes-admin.js +28 -0
  48. package/dist/routes-public.d.ts +1475 -0
  49. package/dist/routes-public.d.ts.map +1 -0
  50. package/dist/routes-public.js +362 -0
  51. package/dist/service-booking-session-bootstrap.d.ts +227 -0
  52. package/dist/service-booking-session-bootstrap.d.ts.map +1 -0
  53. package/dist/service-booking-session-bootstrap.js +287 -0
  54. package/dist/service-boundary-resource-sql.d.ts +18 -0
  55. package/dist/service-boundary-resource-sql.d.ts.map +1 -0
  56. package/dist/service-boundary-resource-sql.js +73 -0
  57. package/dist/service-boundary-sql.d.ts +103 -0
  58. package/dist/service-boundary-sql.d.ts.map +1 -0
  59. package/dist/service-boundary-sql.js +307 -0
  60. package/dist/service-departures-core.d.ts +41 -0
  61. package/dist/service-departures-core.d.ts.map +1 -0
  62. package/dist/service-departures-core.js +92 -0
  63. package/dist/service-departures-extensions.d.ts +46 -0
  64. package/dist/service-departures-extensions.d.ts.map +1 -0
  65. package/dist/service-departures-extensions.js +81 -0
  66. package/dist/service-departures-offers.d.ts +220 -0
  67. package/dist/service-departures-offers.d.ts.map +1 -0
  68. package/dist/service-departures-offers.js +177 -0
  69. package/dist/service-departures-price-preview.d.ts +306 -0
  70. package/dist/service-departures-price-preview.d.ts.map +1 -0
  71. package/dist/service-departures-price-preview.js +383 -0
  72. package/dist/service-departures-pricing-context.d.ts +115 -0
  73. package/dist/service-departures-pricing-context.d.ts.map +1 -0
  74. package/dist/service-departures-pricing-context.js +237 -0
  75. package/dist/service-departures-pricing.d.ts +5 -0
  76. package/dist/service-departures-pricing.d.ts.map +1 -0
  77. package/dist/service-departures-pricing.js +4 -0
  78. package/dist/service-departures.d.ts +192 -0
  79. package/dist/service-departures.d.ts.map +1 -0
  80. package/dist/service-departures.js +213 -0
  81. package/dist/service-intake.d.ts +130 -0
  82. package/dist/service-intake.d.ts.map +1 -0
  83. package/dist/service-intake.js +274 -0
  84. package/dist/service-transport-eligibility.d.ts +10 -0
  85. package/dist/service-transport-eligibility.d.ts.map +1 -0
  86. package/dist/service-transport-eligibility.js +198 -0
  87. package/dist/service.d.ts +1062 -0
  88. package/dist/service.d.ts.map +1 -0
  89. package/dist/service.js +332 -0
  90. package/dist/transport-eligibility.d.ts +4 -0
  91. package/dist/transport-eligibility.d.ts.map +1 -0
  92. package/dist/transport-eligibility.js +2 -0
  93. package/dist/validation/departures.d.ts +1669 -0
  94. package/dist/validation/departures.d.ts.map +1 -0
  95. package/dist/validation/departures.js +397 -0
  96. package/dist/validation/intake.d.ts +147 -0
  97. package/dist/validation/intake.d.ts.map +1 -0
  98. package/dist/validation/intake.js +69 -0
  99. package/dist/validation/offers.d.ts +340 -0
  100. package/dist/validation/offers.d.ts.map +1 -0
  101. package/dist/validation/offers.js +117 -0
  102. package/dist/validation-settings.d.ts +609 -0
  103. package/dist/validation-settings.d.ts.map +1 -0
  104. package/dist/validation-settings.js +235 -0
  105. package/dist/validation-transport-eligibility.d.ts +314 -0
  106. package/dist/validation-transport-eligibility.d.ts.map +1 -0
  107. package/dist/validation-transport-eligibility.js +97 -0
  108. package/dist/validation.d.ts +6 -0
  109. package/dist/validation.d.ts.map +1 -0
  110. package/dist/validation.js +4 -0
  111. package/dist/verification/index.d.ts +12 -0
  112. package/dist/verification/index.d.ts.map +1 -0
  113. package/dist/verification/index.js +18 -0
  114. package/dist/verification/routes-public.d.ts +121 -0
  115. package/dist/verification/routes-public.d.ts.map +1 -0
  116. package/dist/verification/routes-public.js +125 -0
  117. package/dist/verification/schema.d.ts +273 -0
  118. package/dist/verification/schema.d.ts.map +1 -0
  119. package/dist/verification/schema.js +50 -0
  120. package/dist/verification/service.d.ts +114 -0
  121. package/dist/verification/service.d.ts.map +1 -0
  122. package/dist/verification/service.js +283 -0
  123. package/dist/verification/validation.d.ts +98 -0
  124. package/dist/verification/validation.d.ts.map +1 -0
  125. package/dist/verification/validation.js +54 -0
  126. package/package.json +148 -0
@@ -0,0 +1,12 @@
1
+ import type { HonoModule } from "@voyant-travel/hono/module";
2
+ import { type StorefrontVerificationRoutesOptions } from "./routes-public.js";
3
+ export type { StorefrontVerificationPublicRoutes, StorefrontVerificationRoutesOptions, } from "./routes-public.js";
4
+ export { buildStorefrontVerificationSenders, createStorefrontVerificationPublicRoutes, STOREFRONT_VERIFICATION_SENDERS_CONTAINER_KEY, } from "./routes-public.js";
5
+ export type { NewStorefrontVerificationChallenge, StorefrontVerificationChallenge, } from "./schema.js";
6
+ export { storefrontVerificationChallenges, storefrontVerificationChannelEnum, storefrontVerificationLinkable, storefrontVerificationModule, storefrontVerificationStatusEnum, } from "./schema.js";
7
+ export type { StorefrontVerificationDeliveryResult, StorefrontVerificationEmailSendInput, StorefrontVerificationNotificationChannel, StorefrontVerificationNotificationPayload, StorefrontVerificationNotificationProvider, StorefrontVerificationNotificationResult, StorefrontVerificationProviderOptions, StorefrontVerificationSenders, StorefrontVerificationServiceOptions, StorefrontVerificationSmsSendInput, } from "./service.js";
8
+ export { createStorefrontVerificationSendersFromProviders, createStorefrontVerificationService, StorefrontVerificationError, } from "./service.js";
9
+ export type { ConfirmEmailVerificationChallengeInput, ConfirmSmsVerificationChallengeInput, StartEmailVerificationChallengeInput, StartSmsVerificationChallengeInput, StorefrontVerificationChallengeRecord, StorefrontVerificationChannel, StorefrontVerificationConfirmResult, StorefrontVerificationStartResult, StorefrontVerificationStatus, } from "./validation.js";
10
+ export { confirmEmailVerificationChallengeSchema, confirmSmsVerificationChallengeSchema, startEmailVerificationChallengeSchema, startSmsVerificationChallengeSchema, storefrontVerificationChallengeRecordSchema, storefrontVerificationChannelSchema, storefrontVerificationConfirmResultSchema, storefrontVerificationStartResultSchema, storefrontVerificationStatusSchema, } from "./validation.js";
11
+ export declare function createStorefrontVerificationHonoModule(options?: StorefrontVerificationRoutesOptions): HonoModule;
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/verification/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAC5D,OAAO,EAIL,KAAK,mCAAmC,EACzC,MAAM,oBAAoB,CAAA;AAG3B,YAAY,EACV,kCAAkC,EAClC,mCAAmC,GACpC,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACL,kCAAkC,EAClC,wCAAwC,EACxC,6CAA6C,GAC9C,MAAM,oBAAoB,CAAA;AAC3B,YAAY,EACV,kCAAkC,EAClC,+BAA+B,GAChC,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,gCAAgC,EAChC,iCAAiC,EACjC,8BAA8B,EAC9B,4BAA4B,EAC5B,gCAAgC,GACjC,MAAM,aAAa,CAAA;AACpB,YAAY,EACV,oCAAoC,EACpC,oCAAoC,EACpC,yCAAyC,EACzC,yCAAyC,EACzC,0CAA0C,EAC1C,wCAAwC,EACxC,qCAAqC,EACrC,6BAA6B,EAC7B,oCAAoC,EACpC,kCAAkC,GACnC,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,gDAAgD,EAChD,mCAAmC,EACnC,2BAA2B,GAC5B,MAAM,cAAc,CAAA;AACrB,YAAY,EACV,sCAAsC,EACtC,oCAAoC,EACpC,oCAAoC,EACpC,kCAAkC,EAClC,qCAAqC,EACrC,6BAA6B,EAC7B,mCAAmC,EACnC,iCAAiC,EACjC,4BAA4B,GAC7B,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,uCAAuC,EACvC,qCAAqC,EACrC,qCAAqC,EACrC,mCAAmC,EACnC,2CAA2C,EAC3C,mCAAmC,EACnC,yCAAyC,EACzC,uCAAuC,EACvC,kCAAkC,GACnC,MAAM,iBAAiB,CAAA;AAExB,wBAAgB,sCAAsC,CACpD,OAAO,CAAC,EAAE,mCAAmC,GAC5C,UAAU,CAeZ"}
@@ -0,0 +1,18 @@
1
+ import { buildStorefrontVerificationSenders, createStorefrontVerificationPublicRoutes, STOREFRONT_VERIFICATION_SENDERS_CONTAINER_KEY, } from "./routes-public.js";
2
+ import { storefrontVerificationModule } from "./schema.js";
3
+ export { buildStorefrontVerificationSenders, createStorefrontVerificationPublicRoutes, STOREFRONT_VERIFICATION_SENDERS_CONTAINER_KEY, } from "./routes-public.js";
4
+ export { storefrontVerificationChallenges, storefrontVerificationChannelEnum, storefrontVerificationLinkable, storefrontVerificationModule, storefrontVerificationStatusEnum, } from "./schema.js";
5
+ export { createStorefrontVerificationSendersFromProviders, createStorefrontVerificationService, StorefrontVerificationError, } from "./service.js";
6
+ export { confirmEmailVerificationChallengeSchema, confirmSmsVerificationChallengeSchema, startEmailVerificationChallengeSchema, startSmsVerificationChallengeSchema, storefrontVerificationChallengeRecordSchema, storefrontVerificationChannelSchema, storefrontVerificationConfirmResultSchema, storefrontVerificationStartResultSchema, storefrontVerificationStatusSchema, } from "./validation.js";
7
+ export function createStorefrontVerificationHonoModule(options) {
8
+ const module = {
9
+ ...storefrontVerificationModule,
10
+ bootstrap: ({ bindings, container }) => {
11
+ container.register(STOREFRONT_VERIFICATION_SENDERS_CONTAINER_KEY, buildStorefrontVerificationSenders(bindings, options));
12
+ },
13
+ };
14
+ return {
15
+ module,
16
+ publicRoutes: createStorefrontVerificationPublicRoutes(options),
17
+ };
18
+ }
@@ -0,0 +1,121 @@
1
+ import type { ModuleContainer } from "@voyant-travel/core";
2
+ import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
3
+ import { type StorefrontVerificationNotificationProvider, type StorefrontVerificationProviderOptions, type StorefrontVerificationSenders, type StorefrontVerificationServiceOptions } from "./service.js";
4
+ type Env = {
5
+ Bindings: Record<string, unknown>;
6
+ Variables: {
7
+ container: ModuleContainer;
8
+ db: PostgresJsDatabase;
9
+ userId?: string;
10
+ };
11
+ };
12
+ export interface StorefrontVerificationRoutesOptions extends StorefrontVerificationServiceOptions, StorefrontVerificationProviderOptions {
13
+ sendEmailChallenge?: StorefrontVerificationSenders["sendEmailChallenge"];
14
+ sendSmsChallenge?: StorefrontVerificationSenders["sendSmsChallenge"];
15
+ providers?: ReadonlyArray<StorefrontVerificationNotificationProvider>;
16
+ resolveProviders?: (bindings: Record<string, unknown>) => ReadonlyArray<StorefrontVerificationNotificationProvider>;
17
+ }
18
+ export declare const STOREFRONT_VERIFICATION_SENDERS_CONTAINER_KEY = "providers.storefrontVerification.senders";
19
+ export declare function buildStorefrontVerificationSenders(bindings: Record<string, unknown>, options?: StorefrontVerificationRoutesOptions): StorefrontVerificationSenders;
20
+ export declare function createStorefrontVerificationPublicRoutes(options?: StorefrontVerificationRoutesOptions): import("hono/hono-base").HonoBase<Env, {
21
+ "/email/start": {
22
+ $post: {
23
+ input: {};
24
+ output: {};
25
+ outputFormat: string;
26
+ status: import("hono/utils/http-status").StatusCode;
27
+ };
28
+ };
29
+ } & {
30
+ "/email/confirm": {
31
+ $post: {
32
+ input: {};
33
+ output: {
34
+ error: string;
35
+ code: "sender_not_configured";
36
+ } | {
37
+ error: string;
38
+ code: "challenge_not_found";
39
+ } | {
40
+ error: string;
41
+ code: "challenge_expired";
42
+ } | {
43
+ error: string;
44
+ code: "challenge_invalid" | "challenge_failed";
45
+ } | {
46
+ error: string;
47
+ };
48
+ outputFormat: "json";
49
+ status: 404 | 400 | 409 | 410 | 501;
50
+ } | {
51
+ input: {};
52
+ output: {
53
+ data: {
54
+ id: string;
55
+ channel: "email" | "sms";
56
+ destination: string;
57
+ purpose: string;
58
+ status: "failed" | "pending" | "cancelled" | "expired" | "verified";
59
+ expiresAt: string;
60
+ verifiedAt: string | null;
61
+ createdAt: string;
62
+ updatedAt: string;
63
+ };
64
+ };
65
+ outputFormat: "json";
66
+ status: import("hono/utils/http-status").ContentfulStatusCode;
67
+ };
68
+ };
69
+ } & {
70
+ "/sms/start": {
71
+ $post: {
72
+ input: {};
73
+ output: {};
74
+ outputFormat: string;
75
+ status: import("hono/utils/http-status").StatusCode;
76
+ };
77
+ };
78
+ } & {
79
+ "/sms/confirm": {
80
+ $post: {
81
+ input: {};
82
+ output: {
83
+ error: string;
84
+ code: "sender_not_configured";
85
+ } | {
86
+ error: string;
87
+ code: "challenge_not_found";
88
+ } | {
89
+ error: string;
90
+ code: "challenge_expired";
91
+ } | {
92
+ error: string;
93
+ code: "challenge_invalid" | "challenge_failed";
94
+ } | {
95
+ error: string;
96
+ };
97
+ outputFormat: "json";
98
+ status: 404 | 400 | 409 | 410 | 501;
99
+ } | {
100
+ input: {};
101
+ output: {
102
+ data: {
103
+ id: string;
104
+ channel: "email" | "sms";
105
+ destination: string;
106
+ purpose: string;
107
+ status: "failed" | "pending" | "cancelled" | "expired" | "verified";
108
+ expiresAt: string;
109
+ verifiedAt: string | null;
110
+ createdAt: string;
111
+ updatedAt: string;
112
+ };
113
+ };
114
+ outputFormat: "json";
115
+ status: import("hono/utils/http-status").ContentfulStatusCode;
116
+ };
117
+ };
118
+ }, "/", "/sms/confirm">;
119
+ export type StorefrontVerificationPublicRoutes = ReturnType<typeof createStorefrontVerificationPublicRoutes>;
120
+ export {};
121
+ //# sourceMappingURL=routes-public.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes-public.d.ts","sourceRoot":"","sources":["../../src/verification/routes-public.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAE1D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAEjE,OAAO,EAIL,KAAK,0CAA0C,EAC/C,KAAK,qCAAqC,EAC1C,KAAK,6BAA6B,EAClC,KAAK,oCAAoC,EAC1C,MAAM,cAAc,CAAA;AAQrB,KAAK,GAAG,GAAG;IACT,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACjC,SAAS,EAAE;QACT,SAAS,EAAE,eAAe,CAAA;QAC1B,EAAE,EAAE,kBAAkB,CAAA;QACtB,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,CAAA;CACF,CAAA;AAED,MAAM,WAAW,mCACf,SAAQ,oCAAoC,EAC1C,qCAAqC;IACvC,kBAAkB,CAAC,EAAE,6BAA6B,CAAC,oBAAoB,CAAC,CAAA;IACxE,gBAAgB,CAAC,EAAE,6BAA6B,CAAC,kBAAkB,CAAC,CAAA;IACpE,SAAS,CAAC,EAAE,aAAa,CAAC,0CAA0C,CAAC,CAAA;IACrE,gBAAgB,CAAC,EAAE,CACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC9B,aAAa,CAAC,0CAA0C,CAAC,CAAA;CAC/D;AAED,eAAO,MAAM,6CAA6C,6CACd,CAAA;AAE5C,wBAAgB,kCAAkC,CAChD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,OAAO,CAAC,EAAE,mCAAmC,GAC5C,6BAA6B,CAgB/B;AA2ED,wBAAgB,wCAAwC,CACtD,OAAO,CAAC,EAAE,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA6D9C;AAED,MAAM,MAAM,kCAAkC,GAAG,UAAU,CACzD,OAAO,wCAAwC,CAChD,CAAA"}
@@ -0,0 +1,125 @@
1
+ import { clientIpKey, enforceRateLimit, parseJsonBody } from "@voyant-travel/hono";
2
+ import { Hono } from "hono";
3
+ import { createStorefrontVerificationSendersFromProviders, createStorefrontVerificationService, StorefrontVerificationError, } from "./service.js";
4
+ import { confirmEmailVerificationChallengeSchema, confirmSmsVerificationChallengeSchema, startEmailVerificationChallengeSchema, startSmsVerificationChallengeSchema, } from "./validation.js";
5
+ export const STOREFRONT_VERIFICATION_SENDERS_CONTAINER_KEY = "providers.storefrontVerification.senders";
6
+ export function buildStorefrontVerificationSenders(bindings, options) {
7
+ const senders = {
8
+ sendEmailChallenge: options?.sendEmailChallenge,
9
+ sendSmsChallenge: options?.sendSmsChallenge,
10
+ };
11
+ if (!senders.sendEmailChallenge || !senders.sendSmsChallenge) {
12
+ const providers = options?.resolveProviders?.(bindings) ?? options?.providers;
13
+ if (providers?.length) {
14
+ const providerSenders = createStorefrontVerificationSendersFromProviders(providers, options);
15
+ senders.sendEmailChallenge ??= providerSenders.sendEmailChallenge;
16
+ senders.sendSmsChallenge ??= providerSenders.sendSmsChallenge;
17
+ }
18
+ }
19
+ return senders;
20
+ }
21
+ function getSenders(bindings, options, resolveFromContainer) {
22
+ if (resolveFromContainer) {
23
+ try {
24
+ return resolveFromContainer(STOREFRONT_VERIFICATION_SENDERS_CONTAINER_KEY);
25
+ }
26
+ catch {
27
+ // Fall back to per-request sender construction when bootstrap has not run.
28
+ }
29
+ }
30
+ return buildStorefrontVerificationSenders(bindings, options);
31
+ }
32
+ function errorResponse(error) {
33
+ if (error instanceof StorefrontVerificationError) {
34
+ if (error.code === "sender_not_configured") {
35
+ return { status: 501, body: { error: error.message, code: error.code } };
36
+ }
37
+ if (error.code === "challenge_not_found") {
38
+ return { status: 404, body: { error: error.message, code: error.code } };
39
+ }
40
+ if (error.code === "challenge_expired") {
41
+ return { status: 410, body: { error: error.message, code: error.code } };
42
+ }
43
+ if (error.code === "challenge_invalid" || error.code === "challenge_failed") {
44
+ return { status: 409, body: { error: error.message, code: error.code } };
45
+ }
46
+ }
47
+ const message = error instanceof Error ? error.message : "Verification request failed";
48
+ return { status: 400, body: { error: message } };
49
+ }
50
+ function normalizeDestination(channel, destination) {
51
+ return channel === "email" ? destination.trim().toLowerCase() : destination.trim();
52
+ }
53
+ async function enforceVerificationStartLimits(c, channel, destination) {
54
+ const normalized = normalizeDestination(channel, destination);
55
+ return ((await enforceRateLimit(c, {
56
+ bucket: `storefront-verification:${channel}:destination-cooldown`,
57
+ max: 1,
58
+ windowSeconds: 30,
59
+ clientKey: () => normalized,
60
+ })) ??
61
+ (await enforceRateLimit(c, {
62
+ bucket: `storefront-verification:${channel}:destination-hour`,
63
+ max: channel === "sms" ? 5 : 10,
64
+ windowSeconds: 60 * 60,
65
+ clientKey: () => normalized,
66
+ })) ??
67
+ (await enforceRateLimit(c, {
68
+ bucket: `storefront-verification:${channel}:ip-hour`,
69
+ max: channel === "sms" ? 20 : 40,
70
+ windowSeconds: 60 * 60,
71
+ clientKey: clientIpKey,
72
+ })));
73
+ }
74
+ export function createStorefrontVerificationPublicRoutes(options) {
75
+ const service = createStorefrontVerificationService(options);
76
+ return new Hono()
77
+ .post("/email/start", async (c) => {
78
+ try {
79
+ const body = await parseJsonBody(c, startEmailVerificationChallengeSchema);
80
+ const limited = await enforceVerificationStartLimits(c, "email", body.email);
81
+ if (limited)
82
+ return limited;
83
+ const result = await service.startEmailChallenge(c.get("db"), body, getSenders(c.env, options, (key) => c.var.container.resolve(key)));
84
+ return c.json({ data: result }, 201);
85
+ }
86
+ catch (error) {
87
+ const response = errorResponse(error);
88
+ return c.json(response.body, response.status);
89
+ }
90
+ })
91
+ .post("/email/confirm", async (c) => {
92
+ try {
93
+ const result = await service.confirmEmailChallenge(c.get("db"), await parseJsonBody(c, confirmEmailVerificationChallengeSchema));
94
+ return c.json({ data: result });
95
+ }
96
+ catch (error) {
97
+ const response = errorResponse(error);
98
+ return c.json(response.body, response.status);
99
+ }
100
+ })
101
+ .post("/sms/start", async (c) => {
102
+ try {
103
+ const body = await parseJsonBody(c, startSmsVerificationChallengeSchema);
104
+ const limited = await enforceVerificationStartLimits(c, "sms", body.phone);
105
+ if (limited)
106
+ return limited;
107
+ const result = await service.startSmsChallenge(c.get("db"), body, getSenders(c.env, options, (key) => c.var.container.resolve(key)));
108
+ return c.json({ data: result }, 201);
109
+ }
110
+ catch (error) {
111
+ const response = errorResponse(error);
112
+ return c.json(response.body, response.status);
113
+ }
114
+ })
115
+ .post("/sms/confirm", async (c) => {
116
+ try {
117
+ const result = await service.confirmSmsChallenge(c.get("db"), await parseJsonBody(c, confirmSmsVerificationChallengeSchema));
118
+ return c.json({ data: result });
119
+ }
120
+ catch (error) {
121
+ const response = errorResponse(error);
122
+ return c.json(response.body, response.status);
123
+ }
124
+ });
125
+ }
@@ -0,0 +1,273 @@
1
+ import type { LinkableDefinition, Module } from "@voyant-travel/core";
2
+ export declare const storefrontVerificationChannelEnum: import("drizzle-orm/pg-core").PgEnum<["email", "sms"]>;
3
+ export declare const storefrontVerificationStatusEnum: import("drizzle-orm/pg-core").PgEnum<["pending", "verified", "expired", "failed", "cancelled"]>;
4
+ export declare const storefrontVerificationChallenges: import("drizzle-orm/pg-core").PgTableWithColumns<{
5
+ name: "storefront_verification_challenges";
6
+ schema: undefined;
7
+ columns: {
8
+ id: import("drizzle-orm/pg-core").PgColumn<{
9
+ name: string;
10
+ tableName: "storefront_verification_challenges";
11
+ dataType: "string";
12
+ columnType: "PgText";
13
+ data: string;
14
+ driverParam: string;
15
+ notNull: true;
16
+ hasDefault: true;
17
+ isPrimaryKey: true;
18
+ isAutoincrement: false;
19
+ hasRuntimeDefault: true;
20
+ enumValues: [string, ...string[]];
21
+ baseColumn: never;
22
+ identity: undefined;
23
+ generated: undefined;
24
+ }, {}, {}>;
25
+ channel: import("drizzle-orm/pg-core").PgColumn<{
26
+ name: "channel";
27
+ tableName: "storefront_verification_challenges";
28
+ dataType: "string";
29
+ columnType: "PgEnumColumn";
30
+ data: "email" | "sms";
31
+ driverParam: string;
32
+ notNull: true;
33
+ hasDefault: false;
34
+ isPrimaryKey: false;
35
+ isAutoincrement: false;
36
+ hasRuntimeDefault: false;
37
+ enumValues: ["email", "sms"];
38
+ baseColumn: never;
39
+ identity: undefined;
40
+ generated: undefined;
41
+ }, {}, {}>;
42
+ destination: import("drizzle-orm/pg-core").PgColumn<{
43
+ name: "destination";
44
+ tableName: "storefront_verification_challenges";
45
+ dataType: "string";
46
+ columnType: "PgText";
47
+ data: string;
48
+ driverParam: string;
49
+ notNull: true;
50
+ hasDefault: false;
51
+ isPrimaryKey: false;
52
+ isAutoincrement: false;
53
+ hasRuntimeDefault: false;
54
+ enumValues: [string, ...string[]];
55
+ baseColumn: never;
56
+ identity: undefined;
57
+ generated: undefined;
58
+ }, {}, {}>;
59
+ purpose: import("drizzle-orm/pg-core").PgColumn<{
60
+ name: "purpose";
61
+ tableName: "storefront_verification_challenges";
62
+ dataType: "string";
63
+ columnType: "PgText";
64
+ data: string;
65
+ driverParam: string;
66
+ notNull: true;
67
+ hasDefault: true;
68
+ isPrimaryKey: false;
69
+ isAutoincrement: false;
70
+ hasRuntimeDefault: false;
71
+ enumValues: [string, ...string[]];
72
+ baseColumn: never;
73
+ identity: undefined;
74
+ generated: undefined;
75
+ }, {}, {}>;
76
+ codeHash: import("drizzle-orm/pg-core").PgColumn<{
77
+ name: "code_hash";
78
+ tableName: "storefront_verification_challenges";
79
+ dataType: "string";
80
+ columnType: "PgText";
81
+ data: string;
82
+ driverParam: string;
83
+ notNull: true;
84
+ hasDefault: false;
85
+ isPrimaryKey: false;
86
+ isAutoincrement: false;
87
+ hasRuntimeDefault: false;
88
+ enumValues: [string, ...string[]];
89
+ baseColumn: never;
90
+ identity: undefined;
91
+ generated: undefined;
92
+ }, {}, {}>;
93
+ status: import("drizzle-orm/pg-core").PgColumn<{
94
+ name: "status";
95
+ tableName: "storefront_verification_challenges";
96
+ dataType: "string";
97
+ columnType: "PgEnumColumn";
98
+ data: "failed" | "pending" | "cancelled" | "expired" | "verified";
99
+ driverParam: string;
100
+ notNull: true;
101
+ hasDefault: true;
102
+ isPrimaryKey: false;
103
+ isAutoincrement: false;
104
+ hasRuntimeDefault: false;
105
+ enumValues: ["pending", "verified", "expired", "failed", "cancelled"];
106
+ baseColumn: never;
107
+ identity: undefined;
108
+ generated: undefined;
109
+ }, {}, {}>;
110
+ attemptCount: import("drizzle-orm/pg-core").PgColumn<{
111
+ name: "attempt_count";
112
+ tableName: "storefront_verification_challenges";
113
+ dataType: "number";
114
+ columnType: "PgInteger";
115
+ data: number;
116
+ driverParam: string | number;
117
+ notNull: true;
118
+ hasDefault: true;
119
+ isPrimaryKey: false;
120
+ isAutoincrement: false;
121
+ hasRuntimeDefault: false;
122
+ enumValues: undefined;
123
+ baseColumn: never;
124
+ identity: undefined;
125
+ generated: undefined;
126
+ }, {}, {}>;
127
+ maxAttempts: import("drizzle-orm/pg-core").PgColumn<{
128
+ name: "max_attempts";
129
+ tableName: "storefront_verification_challenges";
130
+ dataType: "number";
131
+ columnType: "PgInteger";
132
+ data: number;
133
+ driverParam: string | number;
134
+ notNull: true;
135
+ hasDefault: true;
136
+ isPrimaryKey: false;
137
+ isAutoincrement: false;
138
+ hasRuntimeDefault: false;
139
+ enumValues: undefined;
140
+ baseColumn: never;
141
+ identity: undefined;
142
+ generated: undefined;
143
+ }, {}, {}>;
144
+ expiresAt: import("drizzle-orm/pg-core").PgColumn<{
145
+ name: "expires_at";
146
+ tableName: "storefront_verification_challenges";
147
+ dataType: "date";
148
+ columnType: "PgTimestamp";
149
+ data: Date;
150
+ driverParam: string;
151
+ notNull: true;
152
+ hasDefault: false;
153
+ isPrimaryKey: false;
154
+ isAutoincrement: false;
155
+ hasRuntimeDefault: false;
156
+ enumValues: undefined;
157
+ baseColumn: never;
158
+ identity: undefined;
159
+ generated: undefined;
160
+ }, {}, {}>;
161
+ lastSentAt: import("drizzle-orm/pg-core").PgColumn<{
162
+ name: "last_sent_at";
163
+ tableName: "storefront_verification_challenges";
164
+ dataType: "date";
165
+ columnType: "PgTimestamp";
166
+ data: Date;
167
+ driverParam: string;
168
+ notNull: true;
169
+ hasDefault: true;
170
+ isPrimaryKey: false;
171
+ isAutoincrement: false;
172
+ hasRuntimeDefault: false;
173
+ enumValues: undefined;
174
+ baseColumn: never;
175
+ identity: undefined;
176
+ generated: undefined;
177
+ }, {}, {}>;
178
+ verifiedAt: import("drizzle-orm/pg-core").PgColumn<{
179
+ name: "verified_at";
180
+ tableName: "storefront_verification_challenges";
181
+ dataType: "date";
182
+ columnType: "PgTimestamp";
183
+ data: Date;
184
+ driverParam: string;
185
+ notNull: false;
186
+ hasDefault: false;
187
+ isPrimaryKey: false;
188
+ isAutoincrement: false;
189
+ hasRuntimeDefault: false;
190
+ enumValues: undefined;
191
+ baseColumn: never;
192
+ identity: undefined;
193
+ generated: undefined;
194
+ }, {}, {}>;
195
+ failedAt: import("drizzle-orm/pg-core").PgColumn<{
196
+ name: "failed_at";
197
+ tableName: "storefront_verification_challenges";
198
+ dataType: "date";
199
+ columnType: "PgTimestamp";
200
+ data: Date;
201
+ driverParam: string;
202
+ notNull: false;
203
+ hasDefault: false;
204
+ isPrimaryKey: false;
205
+ isAutoincrement: false;
206
+ hasRuntimeDefault: false;
207
+ enumValues: undefined;
208
+ baseColumn: never;
209
+ identity: undefined;
210
+ generated: undefined;
211
+ }, {}, {}>;
212
+ metadata: import("drizzle-orm/pg-core").PgColumn<{
213
+ name: "metadata";
214
+ tableName: "storefront_verification_challenges";
215
+ dataType: "json";
216
+ columnType: "PgJsonb";
217
+ data: Record<string, unknown>;
218
+ driverParam: unknown;
219
+ notNull: false;
220
+ hasDefault: false;
221
+ isPrimaryKey: false;
222
+ isAutoincrement: false;
223
+ hasRuntimeDefault: false;
224
+ enumValues: undefined;
225
+ baseColumn: never;
226
+ identity: undefined;
227
+ generated: undefined;
228
+ }, {}, {
229
+ $type: Record<string, unknown>;
230
+ }>;
231
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
232
+ name: "created_at";
233
+ tableName: "storefront_verification_challenges";
234
+ dataType: "date";
235
+ columnType: "PgTimestamp";
236
+ data: Date;
237
+ driverParam: string;
238
+ notNull: true;
239
+ hasDefault: true;
240
+ isPrimaryKey: false;
241
+ isAutoincrement: false;
242
+ hasRuntimeDefault: false;
243
+ enumValues: undefined;
244
+ baseColumn: never;
245
+ identity: undefined;
246
+ generated: undefined;
247
+ }, {}, {}>;
248
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
249
+ name: "updated_at";
250
+ tableName: "storefront_verification_challenges";
251
+ dataType: "date";
252
+ columnType: "PgTimestamp";
253
+ data: Date;
254
+ driverParam: string;
255
+ notNull: true;
256
+ hasDefault: true;
257
+ isPrimaryKey: false;
258
+ isAutoincrement: false;
259
+ hasRuntimeDefault: false;
260
+ enumValues: undefined;
261
+ baseColumn: never;
262
+ identity: undefined;
263
+ generated: undefined;
264
+ }, {}, {}>;
265
+ };
266
+ dialect: "pg";
267
+ }>;
268
+ export declare const storefrontVerificationChallengesRelations: import("drizzle-orm").Relations<"storefront_verification_challenges", {}>;
269
+ export type StorefrontVerificationChallenge = typeof storefrontVerificationChallenges.$inferSelect;
270
+ export type NewStorefrontVerificationChallenge = typeof storefrontVerificationChallenges.$inferInsert;
271
+ export declare const storefrontVerificationLinkable: LinkableDefinition;
272
+ export declare const storefrontVerificationModule: Module;
273
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/verification/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAKrE,eAAO,MAAM,iCAAiC,wDAG5C,CAAA;AAEF,eAAO,MAAM,gCAAgC,iGAM3C,CAAA;AAEF,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgC5C,CAAA;AAED,eAAO,MAAM,yCAAyC,2EAGrD,CAAA;AAED,MAAM,MAAM,+BAA+B,GAAG,OAAO,gCAAgC,CAAC,YAAY,CAAA;AAClG,MAAM,MAAM,kCAAkC,GAC5C,OAAO,gCAAgC,CAAC,YAAY,CAAA;AAEtD,eAAO,MAAM,8BAA8B,EAAE,kBAK5C,CAAA;AAED,eAAO,MAAM,4BAA4B,EAAE,MAK1C,CAAA"}
@@ -0,0 +1,50 @@
1
+ import { typeId } from "@voyant-travel/db/lib/typeid-column";
2
+ import { relations } from "drizzle-orm";
3
+ import { index, integer, jsonb, pgEnum, pgTable, text, timestamp } from "drizzle-orm/pg-core";
4
+ export const storefrontVerificationChannelEnum = pgEnum("storefront_verification_channel", [
5
+ "email",
6
+ "sms",
7
+ ]);
8
+ export const storefrontVerificationStatusEnum = pgEnum("storefront_verification_status", [
9
+ "pending",
10
+ "verified",
11
+ "expired",
12
+ "failed",
13
+ "cancelled",
14
+ ]);
15
+ export const storefrontVerificationChallenges = pgTable("storefront_verification_challenges", {
16
+ id: typeId("storefront_verification_challenges"),
17
+ channel: storefrontVerificationChannelEnum("channel").notNull(),
18
+ destination: text("destination").notNull(),
19
+ purpose: text("purpose").notNull().default("contact_confirmation"),
20
+ codeHash: text("code_hash").notNull(),
21
+ status: storefrontVerificationStatusEnum("status").notNull().default("pending"),
22
+ attemptCount: integer("attempt_count").notNull().default(0),
23
+ maxAttempts: integer("max_attempts").notNull().default(5),
24
+ expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
25
+ lastSentAt: timestamp("last_sent_at", { withTimezone: true }).notNull().defaultNow(),
26
+ verifiedAt: timestamp("verified_at", { withTimezone: true }),
27
+ failedAt: timestamp("failed_at", { withTimezone: true }),
28
+ metadata: jsonb("metadata").$type(),
29
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
30
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
31
+ }, (table) => [
32
+ index("idx_storefront_verification_channel").on(table.channel),
33
+ index("idx_storefront_verification_destination").on(table.destination),
34
+ index("idx_storefront_verification_purpose").on(table.purpose),
35
+ index("idx_storefront_verification_status").on(table.status),
36
+ index("idx_storefront_verification_lookup").on(table.channel, table.destination, table.purpose, table.updatedAt, table.createdAt),
37
+ ]);
38
+ export const storefrontVerificationChallengesRelations = relations(storefrontVerificationChallenges, () => ({}));
39
+ export const storefrontVerificationLinkable = {
40
+ module: "storefront-verification",
41
+ entity: "storefrontVerificationChallenge",
42
+ table: "storefront_verification_challenges",
43
+ idPrefix: "svch",
44
+ };
45
+ export const storefrontVerificationModule = {
46
+ name: "storefront-verification",
47
+ linkable: {
48
+ storefrontVerificationChallenge: storefrontVerificationLinkable,
49
+ },
50
+ };