ZenAPIServer_hmac.ts.bak34 matches
2/// <reference lib="deno.ns" />
34import { z } from "npm:@hono/zod-openapi";
5import type { Context, Next } from "npm:hono";
6import { createMiddleware } from "npm:hono/factory";
90.describe("HMAC signature for request validation")
91.meta({
92openapi: {
93description: "HMAC-SHA256 signature of the request payload",
94example: "dG9rXzEyMzQ1Njc4OTBhYmNkZWY=",
102.describe("Request timestamp for replay protection")
103.meta({
104openapi: {
105description: "Unix timestamp when the request was created",
106example: "1736999800",
114.describe("Unique request identifier")
115.meta({
116openapi: {
117description: "Unique identifier for the request",
118example: "req_550e8400-e29b-41d4-a716-446655440000",
126.describe("Device identifier")
127.meta({
128openapi: {
129description: "Unique identifier for the client device",
130example: "dev_1234567890abcdef",
138.describe("Application identifier")
139.meta({
140openapi: {
141description: "Identifier for the client application",
142example: "com.example.mobileapp",
150.describe("Application version")
151.meta({
152openapi: {
153description: "Version of the client application",
154example: "1.2.3",
168.describe("Validated request timestamp")
169.meta({
170openapi: {
171description: "Unix timestamp that passed validation",
172example: "1736999800",
178.describe("Validated request identifier")
179.meta({
180openapi: {
181description: "Unique request identifier that passed validation",
182example: "req_550e8400-e29b-41d4-a716-446655440000",
188.describe("Validated device identifier")
189.meta({
190openapi: {
191description: "Device identifier that passed validation",
192example: "dev_1234567890abcdef",
198.describe("Validated application identifier")
199.meta({
200openapi: {
201description: "Application identifier that passed validation",
202example: "com.example.mobileapp",
208.describe("Validated HMAC signature")
209.meta({
210openapi: {
211description: "HMAC signature that passed validation",
212example: "dG9rXzEyMzQ1Njc4OTBhYmNkZWY=",
218.describe("Validated application version")
219.meta({
220openapi: {
221description: "Application version that passed validation",
222example: "1.2.3",
234.describe("Verification success status")
235.meta({
236openapi: {
237description: "Whether the HMAC verification was successful",
238example: true,
244.optional()
245.meta({
246openapi: {
247description: "Validated request headers (only present on success)",
248example: {
261.optional()
262.meta({
263openapi: {
264description: "Original request body content (only present on success)",
265example: '{"amount": 2500, "currency": "USD"}',
271.optional()
272.meta({
273openapi: {
274description: "Reason for verification failure (only present on failure)",
275example: "Request timestamp expired or invalid",
288.describe("Webhook event type")
289.meta({
290openapi: {
291description: "Type of webhook event",
292example: "payment.completed",
302.describe("Payment identifier")
303.meta({
304openapi: {
305description: "Unique identifier for the payment",
306example: "pay_1234567890abcdef",
312.describe("Merchant reference")
313.meta({
314openapi: {
315description: "Merchant's reference for the payment",
316example: "order_12345",
324.describe("Payment amount in cents")
325.meta({
326openapi: {
327description: "Payment amount in cents (e.g., 2500 = $25.00)",
328example: 2500,
335.describe("Payment currency")
336.meta({
337openapi: {
338description: "Three-letter currency code",
339example: "AUD",
347.describe("Event timestamp")
348.meta({
349openapi: {
350description: "ISO 8601 timestamp when the event occurred",
351example: "2024-01-15T10:30:00Z",
358.optional()
359.meta({
360openapi: {
361description: "Additional metadata for the payment",
362example: {
376.describe("Request success status")
377.meta({
378openapi: {
379description: "Always false for HMAC error responses",
380example: false,
385.describe("HMAC error message")
386.meta({
387openapi: {
388description: "Human-readable HMAC error message",
389example: "Invalid HMAC signature",
396.describe("HMAC error code")
397.meta({
398openapi: {
399description: "Machine-readable HMAC error code",
400example: "HMAC_VERIFICATION_FAILED",
414.describe("Error timestamp")
415.meta({
416openapi: {
417description: "ISO 8601 timestamp when the error occurred",
418example: "2024-01-15T10:30:00Z",
642/**
643* Generate Generic HMAC Signature Function
644* @description Creates HMAC-SHA256 signature for any data using Web Crypto API
645*
646* **HMAC Generation Process:**
647* 1. **Text Encoding**: Converts data and secret to UTF-8 bytes
648* 2. **Key Import**: Imports secret as HMAC-SHA256 crypto key
649* 3. **Signature Creation**: Generates HMAC signature using Web Crypto API
650* 4. **Base64 Encoding**: Converts signature bytes to base64 string
651*
652* **Security Features:**
653* - ๐ **Web Crypto API**: Uses browser's native cryptographic functions
654* - ๐ก๏ธ **HMAC-SHA256**: Industry-standard HMAC algorithm
655* - โก **Secure Key Handling**: Proper key import and management
672*
673* > [!note]
674* **Note**: Uses Web Crypto API for optimal performance and security.
675*
676* @type {Utility Function}
795* **Usage Example:**
796* ```typescript
797* app.use("/api/v1/mobile/*", verifyHMACWithHeadersMiddleware);
798* // Later in handlers:
799* const headers = c.get("validatedHeaders");
872* **Usage Example:**
873* ```typescript
874* app.use("/api/v1/webhooks/*", verifyHMACMiddleware);
875* // Later in handlers:
876* const body = c.get("requestBody");
1// /// <reference no-default-lib="true" />
2// /// <reference lib="deno.ns" />
3// /** v2 ExternalAPIRequestOps */
4// import { secureDBv2 } from "./dbCore.ts";
5// import { SQL_TABLES } from "./dbSchema.ts";
6
7// export class ExternalAPIRequestOpsV2 {
8// private static instance: ExternalAPIRequestOpsV2; private constructor() { }
9// static getInstance(): ExternalAPIRequestOpsV2 { if (!ExternalAPIRequestOpsV2.instance) ExternalAPIRequestOpsV2.instance = new ExternalAPIRequestOpsV2(); return ExternalAPIRequestOpsV2.instance; }
10
11// async track(deviceId: string, appId: string, appVersion: string, ipAddress: string, requestId: string, signature: string, responseStatus: number, processingTimeMs: number): Promise<void> {
49// }
50
51// export const externalAPIRequestsV2 = () => ExternalAPIRequestOpsV2.getInstance();
52
ZenAPIServer_crypto.ts.bak15 matches
2/// <reference lib="deno.ns" />
3
4import { z } from "npm:@hono/zod-openapi";
5import type { Context } from "npm:hono";
6import { createMiddleware } from "npm:hono/factory";
39.describe("Original client IP from Cloudflare")
40.meta({
41openapi: {
42description: "Original client IP address as seen by Cloudflare",
43example: "203.0.113.1",
55.describe("Comma-separated list of IP addresses in proxy chain")
56.meta({
57openapi: {
58description: "Comma-separated list of IP addresses: client, proxy1, proxy2, ...",
59example: "203.0.113.1, 10.0.0.1, 172.16.0.1",
76.describe("Real client IP address")
77.meta({
78openapi: {
79description: "Real client IP address as determined by the proxy",
80example: "203.0.113.1",
92.describe("Resolved client IP address")
93.meta({
94openapi: {
95description: "Best available client IP address from headers or connection",
96example: "203.0.113.1",
108.describe("Source of the IP address")
109.meta({
110openapi: {
111description: "Source header or method used to determine the client IP",
112example: "cf-connecting-ip",
126.describe("IP extraction timestamp")
127.meta({
128openapi: {
129description: "Unix timestamp when the IP was extracted",
130example: 1736999800,
142.describe("Request success status")
143.meta({
144openapi: {
145description: "Always false for IP detection error responses",
146example: false,
151.describe("IP detection error message")
152.meta({
153openapi: {
154description: "Human-readable IP detection error message",
155example: "Failed to extract client IP address",
162.describe("IP detection error code")
163.meta({
164openapi: {
165description: "Machine-readable IP detection error code",
166example: "IP_EXTRACTION_FAILED",
177.describe("Fallback IP address used")
178.meta({
179openapi: {
180description: "Fallback IP address used when extraction fails",
181example: "0.0.0.0",
188.describe("Error timestamp")
189.meta({
190openapi: {
191description: "ISO 8601 timestamp when the error occurred",
192example: "2024-01-15T10:30:00Z",
285/**
286* @fileoverview Unified Cryptographic Utilities
287* @description Centralized cryptographic operations using Hono utilities and Web Crypto API
288* @version 1.0.0
289*/
292
293/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
2945) Secure Random Generation (Using Web Crypto API)
295โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
296
297/**
298* Generate Secure UUID Function
299* @description Generates RFC 4122 compliant UUID v4 using Web Crypto API
300* type {Utility Function}
301* @returns {string} RFC 4122 compliant UUID v4 string
ZenAPIServer_cors.ts.bak.bak4 matches
2* @fileoverview Security - CORS (Cross-Origin Resource Sharing) Management
3*
4* Complete CORS implementation for the Hono + Zod + OpenAPI architecture following proper
5* security patterns. Provides configurable CORS policies, origin validation, and comprehensive
6* logging for different application contexts (main, webhook, admin, credentials mode).
469* const adminCORS = createCORSMiddleware(ADMIN_CORS_POLICY);
470*
471* app.use('/api/*', mainCORS);
472* app.use('/admin/*', adminCORS);
473* ```
599* **Usage:**
600* ```typescript
601* app.use("/api/secure/*", corsCredentialsMode);
602* ```
603*
691* ```typescript
692* const customPolicy = createCustomCORSPolicy({
693* name: 'api-v2',
694* allowedOrigins: ['https://app.example.com'],
695* allowedMethods: ['GET', 'POST'],
ZenAPIServer_cors.ts.bak4 matches
2* @fileoverview Security - CORS (Cross-Origin Resource Sharing) Management
3*
4* Complete CORS implementation for the Hono + Zod + OpenAPI architecture following proper
5* security patterns. Provides configurable CORS policies, origin validation, and comprehensive
6* logging for different application contexts (main, webhook, admin, credentials mode).
400* const adminCORS = createCORSMiddleware(ADMIN_CORS_POLICY);
401*
402* app.use('/api/*', mainCORS);
403* app.use('/admin/*', adminCORS);
404* ```
578* **Usage:**
579* ```typescript
580* app.use("/api/secure/*", corsCredentialsMode);
581* ```
582*
685* ```typescript
686* const customPolicy = createCustomCORSPolicy({
687* name: 'api-v2',
688* allowedOrigins: ['https://app.example.com'],
689* allowedMethods: ['GET', 'POST'],
ZenAPIServer_context.ts.bak2 matches
195PAGE_NONCES: 'pageNonces',
196
197// API Key Authentication (set by API key middleware)
198ACCESS_KEY_CONFIG: 'accessKeyConfig',
199
230
231// ZenPay Integration
232ZENPAY_API_KEY: 'ZENPAY_API_KEY',
233ZENPAY_USERNAME: 'ZENPAY_USERNAME',
234ZENPAY_PASSWORD: 'ZENPAY_PASSWORD',
ZenAPIServer_booking.getById.ts.bak48 matches
3*
4* Retrieves a single booking resource using its UUID identifier
5* Following EXACTLY the hono-zod-openapi-correct-usage.md patterns
6*
7* ## Component Category
21*/
2223import { createRoute, z, type RouteHandler } from 'npm:@hono/zod-openapi';
24import type { AppEnv } from '../types/index.ts';
25import { BookingData } from './_booking.create.ts.bak.ts'; // Import from booking.create.ts where it's defined
48INTERNAL_ERROR: 'Internal server error',
49},
50API_EXAMPLES: {
51BOOKING_ID: '550e8400-e29b-41d4-a716-446655440000',
52TOUR_ID: 'tour_reef_001',
67} as const;
6869// Define response envelope schemas with .openapi() - NOT .meta()
70const OkEnvelopeSchema = z.object({
71success: z.literal(true)
72.describe('Always true on successful booking retrieval')
73.openapi({
74example: true,
75description: 'Indicates the request succeeded',
77data: BookingData
78.describe('Booking resource payload')
79.openapi({
80description: 'Full booking record with all fields',
81}),
82}).openapi('BookingResponse');
8384const NotFoundEnvelopeSchema = z.object({
87.max(BOOKING_GET_BY_ID_CONSTANTS.VALIDATION_LIMITS.MAX_MESSAGE_LENGTH)
88.describe('Human readable not found message')
89.openapi({
90example: BOOKING_GET_BY_ID_CONSTANTS.ERROR_MESSAGES.BOOKING_NOT_FOUND,
91minLength: BOOKING_GET_BY_ID_CONSTANTS.VALIDATION_LIMITS.MIN_MESSAGE_LENGTH,
92maxLength: BOOKING_GET_BY_ID_CONSTANTS.VALIDATION_LIMITS.MAX_MESSAGE_LENGTH,
93}),
94}).openapi('BookingNotFound');
9596const BookingErrorSchema = z.object({
97message: z.string()
98.describe('Error message describing the failure')
99.openapi({
100example: BOOKING_GET_BY_ID_CONSTANTS.ERROR_MESSAGES.INTERNAL_ERROR,
101}),
102}).openapi('BookingError');
103104// Define path parameter schema
107.uuid()
108.describe('Booking UUID v4')
109.openapi({
110description: 'Unique booking identifier (UUID v4)',
111example: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.BOOKING_ID,
112format: 'uuid',
113pattern: BOOKING_GET_BY_ID_CONSTANTS.PATTERNS.UUID_SIMPLE,
114}),
115}).openapi('BookingParams');
116117// Create booking retrieval route
118export const getBookingByIdRoute = createRoute({
119method: 'get',
120path: '/api/v1/bookings/:id', // Hono param syntax (colon); OpenAPI generator will convert
121tags: ['Bookings', 'Retrieval'],
122summary: 'Get booking by ID',
141### Usage Example
142\`\`\`bash
143curl -X GET "https://api.example.com/api/v1/bookings/550e8400-e29b-41d4-a716-446655440000" \\
144-H "Accept: application/json"
145\`\`\`
215success: true,
216data: {
217id: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.BOOKING_ID,
218tourId: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.TOUR_ID,
219title: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.TITLE,
220description: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.DESCRIPTION,
221paymentAmount: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.PAYMENT_AMOUNT,
222customerName: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.CUSTOMER_NAME,
223customerEmail: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.CUSTOMER_EMAIL,
224bookingDate: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.BOOKING_DATE,
225numberOfPeople: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.NUMBER_OF_PEOPLE,
226totalAmount: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.TOTAL_AMOUNT,
227status: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.STATUS,
228paymentStatus: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.PAYMENT_STATUS,
229sessionId: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.SESSION_ID,
230createdAt: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.CREATED_AT,
231updatedAt: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.UPDATED_AT,
232},
233},
274* @example
275* ```typescript
276* app.openapi(getBookingByIdRoute, getBookingByIdHandler);
277* ```
278* @since 1.0.0
282// PLACEHOLDER: In real app, this would validate path parameters and query repository
283// Mock parameter validation and booking lookup for testing purposes
284const mockId = BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.BOOKING_ID;
285286// PLACEHOLDER: In real app, this would be: const { id } = c.req.valid("param");
298// Mock booking repository lookup for testing purposes
299const mockBooking = {
300id: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.BOOKING_ID,
301tourId: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.TOUR_ID,
302title: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.TITLE,
303description: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.DESCRIPTION,
304paymentAmount: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.PAYMENT_AMOUNT,
305customerName: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.CUSTOMER_NAME,
306customerEmail: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.CUSTOMER_EMAIL,
307bookingDate: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.BOOKING_DATE,
308numberOfPeople: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.NUMBER_OF_PEOPLE,
309totalAmount: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.TOTAL_AMOUNT,
310status: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.STATUS,
311paymentStatus: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.PAYMENT_STATUS,
312firstName: 'Jane',
313lastName: 'Doe',
319subscribeNewsletter: 1,
320acceptTerms: 1,
321sessionId: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.SESSION_ID,
322createdAt: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.CREATED_AT,
323updatedAt: BOOKING_GET_BY_ID_CONSTANTS.API_EXAMPLES.UPDATED_AT,
324};
325
ZenAPIServer_booking.create.ts.bak136 matches
3*
4* Creates new tour bookings with JWT-CSRF authentication, honeypot validation, and pricing calculation
5* Following EXACTLY the hono-zod-openapi-correct-usage.md patterns
6*
7* ## Component Category
21*/
2223import { createRoute, z, type RouteHandler } from 'npm:@hono/zod-openapi';
24import type { AppEnv } from '../types/index.ts';
2565INVALID_DATE_FORMAT: 'Date must be in YYYY-MM-DD format',
66},
67API_EXAMPLES: {
68TOUR_ID: 'tour-paris-explorer',
69CUSTOMER_NAME: 'Jane Doe',
112} as const;
113114// Define comprehensive request schema with .openapi() - NOT .meta()
115const CreateBookingRequestSchema = z.object({
116tourId: z.string()
119.regex(new RegExp(BOOKING_CREATE_CONSTANTS.PATTERNS.TOUR_ID))
120.describe('Public tour identifier (slug form) from tour catalogue')
121.openapi({
122example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.TOUR_ID,
123pattern: BOOKING_CREATE_CONSTANTS.PATTERNS.TOUR_ID,
124minLength: BOOKING_CREATE_CONSTANTS.VALIDATION_LIMITS.MIN_TOUR_ID_LENGTH,
130.max(BOOKING_CREATE_CONSTANTS.VALIDATION_LIMITS.MAX_NAME_LENGTH)
131.describe('Primary customer full name')
132.openapi({
133example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.CUSTOMER_NAME,
134minLength: BOOKING_CREATE_CONSTANTS.VALIDATION_LIMITS.MIN_NAME_LENGTH,
135maxLength: BOOKING_CREATE_CONSTANTS.VALIDATION_LIMITS.MAX_NAME_LENGTH,
139.max(BOOKING_CREATE_CONSTANTS.VALIDATION_LIMITS.MAX_EMAIL_LENGTH)
140.describe('Customer contact email (honeypot emoji removed server-side)')
141.openapi({
142example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.CUSTOMER_EMAIL,
143format: 'email',
144maxLength: BOOKING_CREATE_CONSTANTS.VALIDATION_LIMITS.MAX_EMAIL_LENGTH,
147.regex(new RegExp(BOOKING_CREATE_CONSTANTS.PATTERNS.DATE_YYYY_MM_DD))
148.describe('Requested tour date (YYYY-MM-DD) must exist in tour\'s datesAvailable array')
149.openapi({
150example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.BOOKING_DATE,
151pattern: BOOKING_CREATE_CONSTANTS.PATTERNS.DATE_YYYY_MM_DD,
152description: 'ISO calendar date, client should select from datesAvailable returned by tour listing',
157.max(BOOKING_CREATE_CONSTANTS.VALIDATION_LIMITS.MAX_PEOPLE)
158.describe('Number of participants included in booking')
159.openapi({
160example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.NUMBER_OF_PEOPLE,
161minimum: BOOKING_CREATE_CONSTANTS.VALIDATION_LIMITS.MIN_PEOPLE,
162maximum: BOOKING_CREATE_CONSTANTS.VALIDATION_LIMITS.MAX_PEOPLE,
168.optional()
169.describe('Client-calculated payment amount override (major units); defaults to tour.price * numberOfPeople if omitted')
170.openapi({
171example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.PAYMENT_AMOUNT,
172minimum: BOOKING_CREATE_CONSTANTS.VALIDATION_LIMITS.MIN_PAYMENT,
173maximum: BOOKING_CREATE_CONSTANTS.VALIDATION_LIMITS.MAX_PAYMENT,
177.optional()
178.describe('Optional free-form special requirements / notes')
179.openapi({
180example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.SPECIAL_REQUESTS,
181maxLength: BOOKING_CREATE_CONSTANTS.VALIDATION_LIMITS.MAX_SPECIAL_REQUESTS_LENGTH,
182}),
186.optional()
187.describe('Primary traveller given name')
188.openapi({
189example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.FIRST_NAME,
190maxLength: BOOKING_CREATE_CONSTANTS.VALIDATION_LIMITS.MAX_FIRST_NAME_LENGTH,
191}),
194.optional()
195.describe('Primary traveller family name')
196.openapi({
197example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.LAST_NAME,
198maxLength: BOOKING_CREATE_CONSTANTS.VALIDATION_LIMITS.MAX_LAST_NAME_LENGTH,
199}),
202.optional()
203.describe('Traveller contact email (may differ from booking contact)')
204.openapi({
205example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.TRAVELLER_EMAIL,
206format: 'email',
207}),
209.optional()
210.describe('Contact phone (E.164 recommended)')
211.openapi({
212example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.PHONE_NUMBER,
213}),
214numberOfTravelers: z.number()
218.optional()
219.describe('Total travellers represented by travellerInfo (fallback to numberOfPeople)')
220.openapi({
221example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.NUMBER_OF_PEOPLE,
222minimum: BOOKING_CREATE_CONSTANTS.VALIDATION_LIMITS.MIN_PEOPLE,
223maximum: BOOKING_CREATE_CONSTANTS.VALIDATION_LIMITS.MAX_PEOPLE,
227.optional()
228.describe('Alternate preferred date (if primary unavailable)')
229.openapi({
230example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.PREFERRED_DATE,
231}),
232dietaryRestrictions: z.string()
233.optional()
234.describe('Dietary needs summary')
235.openapi({
236example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.DIETARY_RESTRICTIONS,
237}),
238emergencyContact: z.string()
239.optional()
240.describe('Emergency contact name')
241.openapi({
242example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.EMERGENCY_CONTACT,
243}),
244emergencyPhone: z.string()
245.optional()
246.describe('Emergency contact phone')
247.openapi({
248example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.EMERGENCY_PHONE,
249}),
250subscribeNewsletter: z.boolean()
251.optional()
252.describe('Whether customer opts into marketing updates')
253.openapi({
254example: true,
255}),
257.optional()
258.describe('Acceptance of booking terms & conditions')
259.openapi({
260example: true,
261}),
262}).optional().describe('Optional extended traveller profile & preferences').openapi({
263description: 'Nested attributes for more detailed traveller information',
264example: {
265firstName: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.FIRST_NAME,
266lastName: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.LAST_NAME,
267email: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.TRAVELLER_EMAIL,
268phoneNumber: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.PHONE_NUMBER,
269numberOfTravelers: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.NUMBER_OF_PEOPLE,
270dietaryRestrictions: '1x vegetarian',
271subscribeNewsletter: true,
273},
274}),
275}).openapi('CreateBookingRequest');
276277// Define comprehensive booking data schema
280.regex(new RegExp(BOOKING_CREATE_CONSTANTS.PATTERNS.UUID_V4))
281.describe('Booking unique identifier (UUID v4)')
282.openapi({
283example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.BOOKING_ID,
284format: 'uuid',
285pattern: BOOKING_CREATE_CONSTANTS.PATTERNS.UUID_V4,
287tourId: z.string()
288.describe('Tour slug identifier')
289.openapi({
290example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.TOUR_ID,
291}),
292title: z.string()
293.describe('Booking title combining tour + customer')
294.openapi({
295example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.BOOKING_TITLE,
296}),
297description: z.string()
298.describe('Human readable booking summary')
299.openapi({
300example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.BOOKING_DESCRIPTION,
301}),
302paymentAmount: z.number()
303.positive()
304.describe('Per-person or total payment amount recorded')
305.openapi({
306example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.TOUR_PRICE,
307minimum: 0.01,
308}),
309customerName: z.string()
310.describe('Primary customer name')
311.openapi({
312example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.CUSTOMER_NAME,
313}),
314customerEmail: z.string()
315.email()
316.describe('Primary contact email')
317.openapi({
318example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.CUSTOMER_EMAIL,
319format: 'email',
320}),
321bookingDate: z.string()
322.describe('Selected tour date (YYYY-MM-DD)')
323.openapi({
324example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.BOOKING_DATE,
325}),
326numberOfPeople: z.number()
328.positive()
329.describe('Number of participants')
330.openapi({
331example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.NUMBER_OF_PEOPLE,
332minimum: 1,
333format: 'int32',
336.positive()
337.describe('Total computed amount (paymentAmount * numberOfPeople)')
338.openapi({
339example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.TOTAL_AMOUNT,
340minimum: 0.01,
341}),
342status: z.enum(['pending', 'confirmed', 'cancelled', 'completed'])
343.describe('Booking status lifecycle')
344.openapi({
345example: BOOKING_CREATE_CONSTANTS.BOOKING_STATUSES.PENDING,
346enum: ['pending', 'confirmed', 'cancelled', 'completed'],
348paymentStatus: z.enum(['pending', 'paid', 'refunded', 'cancelled'])
349.describe('Payment settlement status')
350.openapi({
351example: BOOKING_CREATE_CONSTANTS.PAYMENT_STATUSES.PENDING,
352enum: ['pending', 'paid', 'refunded', 'cancelled'],
355.optional()
356.describe('Special requests text')
357.openapi({
358example: 'Wheelchair access required',
359}),
361.optional()
362.describe('Traveller given name')
363.openapi({
364example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.FIRST_NAME,
365}),
366lastName: z.string()
367.optional()
368.describe('Traveller family name')
369.openapi({
370example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.LAST_NAME,
371}),
372email: z.string()
374.optional()
375.describe('Traveller email')
376.openapi({
377example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.TRAVELLER_EMAIL,
378format: 'email',
379}),
381.optional()
382.describe('Contact phone')
383.openapi({
384example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.PHONE_NUMBER,
385}),
386numberOfTravelers: z.number()
389.optional()
390.describe('Traveller count override')
391.openapi({
392example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.NUMBER_OF_PEOPLE,
393minimum: 1,
394format: 'int32',
397.optional()
398.describe('Alternate preferred date')
399.openapi({
400example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.PREFERRED_DATE,
401}),
402dietaryRestrictions: z.string()
403.optional()
404.describe('Dietary requirements summary')
405.openapi({
406example: '1x vegetarian',
407}),
409.optional()
410.describe('Emergency contact name')
411.openapi({
412example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.EMERGENCY_CONTACT,
413}),
414emergencyPhone: z.string()
415.optional()
416.describe('Emergency contact phone')
417.openapi({
418example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.EMERGENCY_PHONE,
419}),
420subscribeNewsletter: z.number()
424.optional()
425.describe('Newsletter opt-in stored as tinyint (1=yes,0=no)')
426.openapi({
427example: 1,
428minimum: 0,
436.optional()
437.describe('Terms acceptance flag stored as tinyint')
438.openapi({
439example: 1,
440minimum: 0,
446.nullable()
447.describe('Session identifier associated with booking creation')
448.openapi({
449example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.SESSION_ID,
450format: 'uuid',
451pattern: BOOKING_CREATE_CONSTANTS.PATTERNS.UUID_V4,
454.regex(new RegExp(BOOKING_CREATE_CONSTANTS.PATTERNS.ISO_DATETIME))
455.describe('Creation timestamp ISO 8601')
456.openapi({
457example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.CREATED_AT,
458format: 'date-time',
459pattern: BOOKING_CREATE_CONSTANTS.PATTERNS.ISO_DATETIME,
462.regex(new RegExp(BOOKING_CREATE_CONSTANTS.PATTERNS.ISO_DATETIME))
463.describe('Last update timestamp ISO 8601')
464.openapi({
465example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.UPDATED_AT,
466format: 'date-time',
467pattern: BOOKING_CREATE_CONSTANTS.PATTERNS.ISO_DATETIME,
468}),
469}).openapi('BookingData');
470471// Define response schemas
473success: z.literal(true)
474.describe('Indicates booking creation succeeded')
475.openapi({
476example: true,
477}),
480'payment-init': z.string()
481.describe('Nonce for initiating payment flow')
482.openapi({
483example: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.PAYMENT_INIT_NONCE,
484}),
485}).describe('Fresh page nonces for follow-up privileged actions'),
486}).openapi('CreateBookingResponse');
487488const BookingErrorSchema = z.object({
489success: z.literal(false),
490error: z.string().openapi({
491example: BOOKING_CREATE_CONSTANTS.ERROR_MESSAGES.BOOKING_CREATION_FAILED,
492description: 'Error message describing the booking creation failure'
493}),
494}).openapi('BookingError');
495496// Create booking route
497export const createBookingRoute = createRoute({
498method: 'post',
499path: '/api/v1/booking',
500tags: ['Bookings', 'Payments'],
501summary: 'Create Booking',
525### Usage Example
526\`\`\`bash
527curl -X POST "https://api.example.com/api/v1/booking" \\
528-H "Content-Type: application/json" \\
529-H "X-JWT-CSRF-Token: <jwt_csrf_token>" \\
597booking: {
598value: {
599tourId: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.TOUR_ID,
600customerName: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.CUSTOMER_NAME,
601customerEmail: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.CUSTOMER_EMAIL,
602bookingDate: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.BOOKING_DATE,
603numberOfPeople: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.NUMBER_OF_PEOPLE,
604travellerInfo: {
605firstName: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.FIRST_NAME,
606lastName: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.LAST_NAME,
607acceptTerms: true,
608},
625success: true,
626data: {
627id: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.BOOKING_ID,
628tourId: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.TOUR_ID,
629title: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.BOOKING_TITLE,
630description: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.BOOKING_DESCRIPTION,
631paymentAmount: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.TOUR_PRICE,
632customerName: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.CUSTOMER_NAME,
633customerEmail: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.CUSTOMER_EMAIL,
634bookingDate: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.BOOKING_DATE,
635numberOfPeople: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.NUMBER_OF_PEOPLE,
636totalAmount: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.TOTAL_AMOUNT,
637status: BOOKING_CREATE_CONSTANTS.BOOKING_STATUSES.PENDING,
638paymentStatus: BOOKING_CREATE_CONSTANTS.PAYMENT_STATUSES.PENDING,
639sessionId: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.SESSION_ID,
640createdAt: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.CREATED_AT,
641updatedAt: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.UPDATED_AT,
642},
643pageNonces: {
644'payment-init': BOOKING_CREATE_CONSTANTS.API_EXAMPLES.PAYMENT_INIT_NONCE,
645},
646},
671* @example
672* ```typescript
673* app.openapi(createBookingRoute, createBookingHandler);
674* ```
675* @since 1.0.0
680// Mock request data parsing for testing purposes
681const mockRequestData = {
682tourId: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.TOUR_ID,
683customerName: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.CUSTOMER_NAME,
684customerEmail: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.CUSTOMER_EMAIL,
685bookingDate: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.BOOKING_DATE,
686numberOfPeople: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.NUMBER_OF_PEOPLE,
687travellerInfo: {
688firstName: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.FIRST_NAME,
689lastName: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.LAST_NAME,
690acceptTerms: true,
691},
705// Mock tour lookup and pricing calculation for testing purposes
706const mockTour = {
707tourId: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.TOUR_ID,
708title: 'Paris Explorer ๐ผ',
709price: BOOKING_CREATE_CONSTANTS.API_EXAMPLES.TOUR_PRICE,
710};
711721// PLACEHOLDER: In real app, this would generate secure UUIDs and manage sessions
722// Mock UUID generation and session management for testing purposes
723const bookingId = BOOKING_CREATE_CONSTANTS.API_EXAMPLES.BOOKING_ID;
724const sessionId = BOOKING_CREATE_CONSTANTS.API_EXAMPLES.SESSION_ID;
725726// PLACEHOLDER: In real app, this would create the booking record in database
754// PLACEHOLDER: In real app, this would generate fresh page nonces
755// Mock nonce generation for testing purposes
756const paymentInitNonce = BOOKING_CREATE_CONSTANTS.API_EXAMPLES.PAYMENT_INIT_NONCE;
757const pageNoncesPayload = {
758[BOOKING_CREATE_CONSTANTS.NONCE_TYPES.PAYMENT_INIT]: paymentInitNonce,
ZenAPIServer_auth.turnstileVerify.ts.bak29 matches
3*
4* Verifies Cloudflare Turnstile response tokens to prevent automated interactions
5* Following EXACTLY the hono-zod-openapi-correct-usage.md patterns
6*
7* ## Component Category
21*/
2223import { createRoute, z, type RouteHandler } from 'npm:@hono/zod-openapi';
24import type { AppEnv } from '../types/index.ts';
2552INTERNAL_ERROR: 'Internal verification error',
53},
54API_EXAMPLES: {
55TOKEN: '0x4AAAAAAAC2mU1rG7x2q8x1d8P5w3c9L7hK1y_mQshpXz8y1g4nS9XoXxH0bSgX6A',
56CHALLENGE_TS: '2025-08-16T10:22:41.512Z',
61} as const;
6263// Define request schema with .openapi() - NOT .meta()
64const TurnstileVerifyRequestSchema = z.object({
65token: z.string()
68.regex(new RegExp(TURNSTILE_VERIFY_CONSTANTS.PATTERNS.TOKEN_PATTERN))
69.describe('Turnstile response token')
70.openapi({
71description: 'The client-side Turnstile response token obtained after the user passes the challenge',
72example: TURNSTILE_VERIFY_CONSTANTS.API_EXAMPLES.TOKEN,
73minLength: TURNSTILE_VERIFY_CONSTANTS.VALIDATION_LIMITS.MIN_TOKEN_LENGTH,
74maxLength: TURNSTILE_VERIFY_CONSTANTS.VALIDATION_LIMITS.MAX_TOKEN_LENGTH,
75pattern: TURNSTILE_VERIFY_CONSTANTS.PATTERNS.TOKEN_PATTERN,
76}),
77}).openapi('TurnstileVerifyRequest');
7879// Define success response schema with .openapi() - NOT .meta()
80const TurnstileVerifySuccessSchema = z.object({
81valid: z.boolean()
82.describe('Token validation result')
83.openapi({
84description: 'Indicates if token verification succeeded',
85example: true,
89.optional()
90.describe('Challenge timestamp')
91.openapi({
92description: 'ISO 8601 timestamp when the original challenge was solved (server-generated surrogate)',
93example: TURNSTILE_VERIFY_CONSTANTS.API_EXAMPLES.CHALLENGE_TS,
94format: 'date-time',
95pattern: TURNSTILE_VERIFY_CONSTANTS.PATTERNS.DATETIME_ISO,
99.optional()
100.describe('Associated hostname')
101.openapi({
102description: 'Expected hostname associated with the sitekey (if available)',
103example: TURNSTILE_VERIFY_CONSTANTS.API_EXAMPLES.HOSTNAME,
104pattern: TURNSTILE_VERIFY_CONSTANTS.PATTERNS.HOSTNAME_PATTERN,
105}),
106}).openapi('TurnstileVerifySuccess');
107108const TurnstileVerifyErrorSchema = z.object({
109valid: z.literal(false)
110.describe('Validation failed')
111.openapi({
112description: 'Always false when validation fails',
113example: false,
118.max(TURNSTILE_VERIFY_CONSTANTS.VALIDATION_LIMITS.MAX_ERROR_MESSAGE_LENGTH)
119.describe('Error description')
120.openapi({
121description: 'Error description when validation fails',
122example: TURNSTILE_VERIFY_CONSTANTS.API_EXAMPLES.ERROR_INVALID,
123minLength: TURNSTILE_VERIFY_CONSTANTS.VALIDATION_LIMITS.MIN_ERROR_MESSAGE_LENGTH,
124maxLength: TURNSTILE_VERIFY_CONSTANTS.VALIDATION_LIMITS.MAX_ERROR_MESSAGE_LENGTH,
125}),
126}).openapi('TurnstileVerifyError');
127128// Create route with ALL possible response status codes
129export const route = createRoute({
130method: 'post',
131path: '/api/v1/auth/turnstile-verify',
132tags: ['Authentication', 'Security'],
133summary: 'Verify Turnstile Token',
152### Usage Example
153\`\`\`bash
154curl -X POST "https://api.example.com/api/v1/auth/turnstile-verify" \\
155-H "Content-Type: application/json" \\
156-d '{"token":"0x4AAAAAAAC2mU1rG7x2q8x1d8P5w3c9L7hK1y_mQshpXz8y1g4nS9XoXxH0bSgX6A"}'
206value: {
207valid: true,
208challengeTs: TURNSTILE_VERIFY_CONSTANTS.API_EXAMPLES.CHALLENGE_TS,
209hostname: TURNSTILE_VERIFY_CONSTANTS.API_EXAMPLES.HOSTNAME,
210},
211},
223value: {
224valid: false,
225error: TURNSTILE_VERIFY_CONSTANTS.API_EXAMPLES.ERROR_INVALID,
226},
227},
229value: {
230valid: false,
231error: TURNSTILE_VERIFY_CONSTANTS.API_EXAMPLES.ERROR_TIMEOUT,
232},
233},
258* @example
259* ```typescript
260* app.openapi(route, handler);
261* ```
262* @since 1.0.0
268const { token } = TurnstileVerifyRequestSchema.parse(requestBody);
269270// PLACEHOLDER: Mock token validation (in real app: call Cloudflare API)
271if (!token || typeof token !== 'string') {
272return c.json({
281return c.json({
282valid: false as const,
283error: TURNSTILE_VERIFY_CONSTANTS.API_EXAMPLES.ERROR_INVALID
284}, TURNSTILE_VERIFY_CONSTANTS.HTTP_STATUS.UNPROCESSABLE_ENTITY);
285}
288return c.json({
289valid: false as const,
290error: TURNSTILE_VERIFY_CONSTANTS.API_EXAMPLES.ERROR_TIMEOUT
291}, TURNSTILE_VERIFY_CONSTANTS.HTTP_STATUS.UNPROCESSABLE_ENTITY);
292}
296valid: true as const,
297challengeTs: new Date().toISOString(),
298hostname: TURNSTILE_VERIFY_CONSTANTS.API_EXAMPLES.HOSTNAME,
299};
300
ZenAPIServer_auth.tokens.ts.bak24 matches
3*
4* Provides JWT-CSRF tokens and session establishment
5* Following EXACTLY the hono-zod-openapi-correct-usage.md patterns
6*
7* ## Component Category
20*/
2122import { createRoute, z, type RouteHandler } from 'npm:@hono/zod-openapi';
23import type { AppEnv } from '../types/index.ts';
2458HONEYPOT_EMOJI: 'honeypotEmoji',
59},
60API_VERSION: '1.0.0',
61} as const;
6263// Define response schema with .openapi() - NOT .meta()
64const AuthTokensResponseSchema = z.object({
65type: z.enum(['bootstrap', 'refresh'])
66.describe('Token operation type')
67.openapi({
68description: 'Type of token operation being performed',
69example: 'bootstrap',
73token: z.string()
74.describe('JWT-CSRF token')
75.openapi({
76description: 'Secure JWT-CSRF token for authentication',
77example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzZXNzaW9uSWQiOiI1NTBlODQwMC1lMjliLTQxZDQtYTcxNi00NDY2NTU0NDAwMCIsImNzcmZJZCI6IjU1MGU4NDAwLWUyOWItNDFkNC1hNzE2LTQ0NjY1NTQ0MDAwIiwiaWF0IjoxNzM2OTk5ODAwLCJleHAiOjE3MzY5OTk4NjB9.signature',
84headerName: z.string()
85.describe('Header name for token submission')
86.openapi({
87description: 'HTTP header name to use when submitting the token',
88example: 'X-JWT-CSRF-Token',
94.positive()
95.describe('Token expiration time in seconds')
96.openapi({
97description: 'Token expiration time in seconds from now',
98example: 3600,
105.describe('Page-specific nonces for action authorization')
106.optional()
107.openapi({
108description: 'Nonces for specific page actions (booking submit, payment init)',
109example: {
119sessionEstablished: z.boolean()
120.describe('Whether session was created')
121.openapi({
122description: 'Indicates if a new session was successfully established',
123example: true,
128.describe('Session identifier')
129.optional()
130.openapi({
131description: 'Unique session identifier for tracking',
132example: '550e8400-e29b-41d4-a716-446655440000',
138.describe('CSRF correlation identifier')
139.optional()
140.openapi({
141description: 'Opaque UUID linking JWT to CSRF/session context for double-submit mitigation',
142example: '8f5a4d1c-9e32-4f6a-9b75-1d2c3e4f5a6b',
146honeypotEmoji: z.string()
147.describe('Dynamic emoji for honeypot security')
148.openapi({
149description: 'Random emoji used for bot detection and security validation',
150example: '๐ฆ',
157.describe('Timestamp when tokens were generated')
158.optional()
159.openapi({
160description: 'ISO 8601 timestamp of token generation',
161example: '2024-01-15T10:30:00Z',
164165version: z.string()
166.describe('API version')
167.optional()
168.openapi({
169description: 'API version identifier',
170example: '1.0.0',
171pattern: AUTH_TOKENS_CONSTANTS.PATTERNS.VERSION_PATTERN,
172}),
173}).openapi('AuthTokensResponse');
174175const ErrorSchema = z.object({
176success: z.literal(false),
177error: z.string().openapi({
178example: 'Token generation failed',
179description: 'Error message'
180}),
181}).openapi('AuthTokensError');
182183// Create route with ALL possible response status codes
184export const route = createRoute({
185method: 'get',
186path: '/api/v1/auth/tokens',
187tags: ['Authentication', 'Security'],
188summary: 'Get Authentication Tokens',
211### Usage Example
212\`\`\`bash
213curl -X GET "https://api.example.com/api/v1/auth/tokens" \\
214-H "Accept: application/json" \\
215-H "User-Agent: YourApp/1.0"
311* @example
312* ```typescript
313* app.openapi(route, handler);
314* ```
315* @since 1.0.0
350honeypotEmoji,
351generatedAt: new Date().toISOString(),
352version: AUTH_TOKENS_CONSTANTS.API_VERSION,
353csrfId,
354}, AUTH_TOKENS_CONSTANTS.HTTP_STATUS.OK);