api_ianmenethil_comhashService.ts20 matches
31*/
32export const ZenithHashRequestSchema = z.object({
33apiKey: z.string().min(1, "API key cannot be empty"),
34username: z.string().min(1, "Username cannot be empty"),
35password: z.string().min(1, "Password cannot be empty"),
6061export const AuthenticatedZenithHashRequestSchema = z.object({
62apiKey: z.string().min(1, "API key cannot be empty"),
63username: z.string().optional(),
64password: z.string().optional(),
128*
129* This endpoint helps clients generate the required fingerprint
130* for Zenith Payments API integration without exposing credentials.
131*
132* The generated hash should be used as the 'fingerprint' field
456457// Create hash string according to Zenith format
458const { apiKey, mode, paymentAmount, merchantUniquePaymentId, timestamp } = validatedData;
459const hashString =
460`${apiKey}|${username}|${password}|${mode}|${paymentAmount}|${merchantUniquePaymentId}|${timestamp}`;
461462// Get algorithm
530531/**
532* Generate hash using Web Crypto API
533*/
534async function generateHash(data: string, algorithm: string): Promise<string> {
547break;
548case "SHA3-512":
549// SHA3-512 is not natively supported in Web Crypto API
550// Try it first, fallback to SHA-512
551try {
626suggestion =
627'Payment amount must be in cents/pence as whole numbers only. For $12.34, use "1234". For $100.00, use "10000".';
628} else if (field === "apiKey") {
629suggestion = "API key should be provided by Zenith Payments";
630}
631672673return await c.json({
674purpose: "Generate fingerprint hash for Zenith Payments API",
675endpoint: "/v1/hash",
676current_time: currentTime,
699description: "SHA-1 hash of concatenated fields",
700algorithm: "SHA-1",
701use_case: "Zenith API v3 integration",
702warning: "SHA-1 is deprecated for security reasons, use v5",
703example_request: {
704apiKey: "test_api_key",
705username: "merchant_user",
706password: "merchant_pass",
715description: "SHA-512 hash of concatenated fields",
716algorithm: "SHA-512",
717use_case: "Zenith API v4 integration (recommended by Zenith)",
718example_request: {
719apiKey: "test_api_key",
720username: "merchant_user",
721password: "merchant_pass",
732use_case: "Most secure option for future compatibility",
733example_request: {
734apiKey: "test_api_key",
735username: "merchant_user",
736password: "merchant_pass",
745v3_v4_v5_format: {
746description: "Concatenated string format for hashing",
747format: "apiKey|username|password|mode|paymentAmount|merchantUniquePaymentId|timestamp",
748example: "test_api_key|merchant_user|merchant_pass|0|10050|INV-2025-001|2025-06-15T19:42:13Z",
749},
750required_fields: {
755v3_v4_v5: {
756public_access: [
757"apiKey",
758"username",
759"password",
764],
765authenticated_access: [
766"apiKey",
767"username (optional)",
768"password (optional)",
786},
787authenticated_access: {
788description: "Requires API key or session authentication",
789benefit: "Username and password can use environment defaults if not provided in request",
790},
api_ianmenethil_comhash.service.ts20 matches
31*/
32export const ZenithHashRequestSchema = z.object({
33apiKey: z.string().min(1, "API key cannot be empty"),
34username: z.string().min(1, "Username cannot be empty"),
35password: z.string().min(1, "Password cannot be empty"),
6061export const AuthenticatedZenithHashRequestSchema = z.object({
62apiKey: z.string().min(1, "API key cannot be empty"),
63username: z.string().optional(),
64password: z.string().optional(),
128*
129* This endpoint helps clients generate the required fingerprint
130* for Zenith Payments API integration without exposing credentials.
131*
132* The generated hash should be used as the 'fingerprint' field
456457// Create hash string according to Zenith format
458const { apiKey, mode, paymentAmount, merchantUniquePaymentId, timestamp } = validatedData;
459const hashString =
460`${apiKey}|${username}|${password}|${mode}|${paymentAmount}|${merchantUniquePaymentId}|${timestamp}`;
461462// Get algorithm
530531/**
532* Generate hash using Web Crypto API
533*/
534async function generateHash(data: string, algorithm: string): Promise<string> {
547break;
548case "SHA3-512":
549// SHA3-512 is not natively supported in Web Crypto API
550// Try it first, fallback to SHA-512
551try {
626suggestion =
627'Payment amount must be in cents/pence as whole numbers only. For $12.34, use "1234". For $100.00, use "10000".';
628} else if (field === "apiKey") {
629suggestion = "API key should be provided by Zenith Payments";
630}
631672673return await c.json({
674purpose: "Generate fingerprint hash for Zenith Payments API",
675endpoint: "/v1/hash",
676current_time: currentTime,
699description: "SHA-1 hash of concatenated fields",
700algorithm: "SHA-1",
701use_case: "Zenith API v3 integration",
702warning: "SHA-1 is deprecated for security reasons, use v5",
703example_request: {
704apiKey: "test_api_key",
705username: "merchant_user",
706password: "merchant_pass",
715description: "SHA-512 hash of concatenated fields",
716algorithm: "SHA-512",
717use_case: "Zenith API v4 integration (recommended by Zenith)",
718example_request: {
719apiKey: "test_api_key",
720username: "merchant_user",
721password: "merchant_pass",
732use_case: "Most secure option for future compatibility",
733example_request: {
734apiKey: "test_api_key",
735username: "merchant_user",
736password: "merchant_pass",
745v3_v4_v5_format: {
746description: "Concatenated string format for hashing",
747format: "apiKey|username|password|mode|paymentAmount|merchantUniquePaymentId|timestamp",
748example: "test_api_key|merchant_user|merchant_pass|0|10050|INV-2025-001|2025-06-15T19:42:13Z",
749},
750required_fields: {
755v3_v4_v5: {
756public_access: [
757"apiKey",
758"username",
759"password",
764],
765authenticated_access: [
766"apiKey",
767"username (optional)",
768"password (optional)",
786},
787authenticated_access: {
788description: "Requires API key or session authentication",
789benefit: "Username and password can use environment defaults if not provided in request",
790},
2import type { HonoVariables as Variables } from "@/types/index.ts";
3import {
4fetchFromFirecrawlAPI,
5FirecrawlMapInput,
6FirecrawlMapInputSchema,
7performFirecrawlMap,
8ScraperInput,
9ScraperSchema,
10} from "../external-apis/firecrawlClient.ts";
1112// Helper function to get error messages
24* firecrawlScrape operation handler
25* POST /v1/firecrawl/scrape
26* Handles requests to the Firecrawl scrape API for a single URL.
27*/
28export async function firecrawlScrapeHandler(
50const scrapeInput: ScraperInput = validationResult.data;
5152// Call the Firecrawl API through the client function
53const firecrawlResponse = await fetchFromFirecrawlAPI(scrapeInput);
5455// Type assertion to ensure it's a valid JSON value
6162// Handle specific error cases
63if (message.includes("Configuration error: invalid or missing FIRECRAWL_API_KEY")) {
64return c.json({
65success: false,
66error: "Firecrawl API configuration error. Please contact support.",
67}, 503); // Service Unavailable
68}
71return c.json({
72success: false,
73error: "Firecrawl API returned an error during scrape.",
74details: error.message,
75}, 502); // Bad Gateway
87* firecrawlMap operation handler
88* POST /v1/firecrawl/map
89* Handles requests to the Firecrawl map API for discovering URLs on a website.
90*/
91export async function firecrawlMapHandler(c: Context<{ Variables: Variables }>): Promise<Response> {
93const requestBody = await c.req.json();
9495// Validate the request body against the FirecrawlMapInputSchema
96const validationResult = FirecrawlMapInputSchema.safeParse(requestBody);
9798if (!validationResult.success) {
106107// Use the validated data with explicit type
108const mapInput: FirecrawlMapInput = validationResult.data;
109110// Call the dedicated map function with validated input
111const firecrawlResponse = await performFirecrawlMap(mapInput);
112113// Type assertion to ensure it's a valid JSON value
119120// Handle specific error cases
121if (message.includes("Configuration error: invalid or missing FIRECRAWL_API_KEY")) {
122return c.json({
123success: false,
124error: "Firecrawl API configuration error. Please contact support.",
125}, 503); // Service Unavailable
126}
129return c.json({
130success: false,
131error: "Firecrawl API returned an error during map operation.",
132details: error.message,
133}, 502); // Bad Gateway
1// F:\zApps\valtown.servers\APIServer\src\handlers\echo.service.ts
2import { getCurrentDateInSydney } from "@/utils/dateUtils.ts";
3
1/**
2* callbackService.ts — Callback endpoint handlers for managing callback records with CRUD operations.
3* Provides RESTful API for creating, listing, viewing, and deleting callback entries.
4*/
5
api_ianmenethil_comauthService.ts10 matches
263/**
264* Exchange Token - implements exchangeToken operation
265* Converts API keys to JWT tokens for secure service access
266*/
267export async function exchangeToken(c: Context<{ Variables: Variables }>): Promise<Response> {
287// Validate token key against configured keys
288const validKeys = [
289AUTH_CONFIG.methods.API_KEY.keys.internal,
290AUTH_CONFIG.methods.API_KEY.keys.serviceToService,
291];
292315// Determine service type based on token key
316let sourceService = "unknown-service";
317let scope = "api:read";
318319if (tokenKey === AUTH_CONFIG.methods.API_KEY.keys.internal) {
320sourceService = "internal-service";
321scope = "internal-service api:read api:write";
322} else if (tokenKey === AUTH_CONFIG.methods.API_KEY.keys.serviceToService) {
323sourceService = "service-to-service";
324scope = "s2s-service api:read api:write";
325}
326328const jwtToken = await internalJwtService.generateInternalToken(c, {
329sourceService,
330targetEndpoint: "api-access",
331scope,
332expiryMinutes: 60, // 1 hour token
355usage: {
356header: "Authorization: Bearer " + jwtToken,
357description: "Use this JWT token for API authentication",
358},
359},
api_ianmenethil_comrouter.ts18 matches
1/**
2* request-gateway.ts — Hono-based request gateway for the v2 API server.
3* Now properly integrated with middleware chains for consistent request processing.
4*/
4950/**
51* OpenAPI Operation interface
52*/
53interface OpenAPIOperation {
54operationId?: string;
55summary?: string;
174175/**
176* Register a handler for an OpenAPI operation ID
177*/
178registerHandler(operationId: string, handler: RouteHandler): this {
217case GatewayRouteType.BROWSER:
218default:
219return "/api/v1";
220}
221}
222223/**
224* Register OpenAPI routes from specification
225*/
226registerOpenApiRoutes(spec: any): this {
227if (!spec.paths) return this;
228233}
234235const operation = operationData as OpenAPIOperation;
236const operationId = operation.operationId;
237if (!operationId) continue;
243}
244245// Determine route type from OpenAPI extensions or path
246const routeType = this.determineRouteType(path, operation);
247248// Convert OpenAPI path to Hono path format
249const honoPath = path.replace(/\{([^}]+)\}/g, ":$1");
250272* Determine route type from path and operation
273*/
274private determineRouteType(path: string, operation: OpenAPIOperation): GatewayRouteType {
275// Check OpenAPI extensions first
276if (operation["x-route-type"]) {
277return operation["x-route-type"] as GatewayRouteType;
294295/**
296* Extract authentication requirement from OpenAPI operation
297*/
298private extractAuthRequirement(operation: OpenAPIOperation): AuthMethod {
299if (!operation.security || operation.security.length === 0) {
300return "none";
306307if (securitySchemes.includes("bearerAuth")) return "jwt";
308if (securitySchemes.includes("apiKey")) return "apiKey";
309if (securitySchemes.includes("oauth2")) return "oauth";
310if (securitySchemes.includes("basicAuth")) return "basic";
370*/
371serve(port = 8000): void {
372console.log(`🚀 API Gateway starting on port ${port}`);
373console.log(`📚 API Documentation: ${APP_CONFIG.server.BASE_URL}/docs`);
374console.log(`🔗 API Base URL: ${APP_CONFIG.server.BASE_URL}/api/v1`);
375console.log("");
376console.log("Middleware chains configured:");
api_ianmenethil_comtavilyClient.ts42 matches
1/**
2* tavily-client.ts - Tavily API integration client for v2
3*/
45import { z } from "z";
67// --- Tavily Search Schema (based on actual API documentation) ---
8export const TavilySearchSchema = z.object({
9query: z.string().min(1, "Search query cannot be empty"),
31export type TavilySearchInput = z.infer<typeof TavilySearchSchema>;
3233// --- Tavily Extract Schema (based on actual API documentation) ---
34export const TavilyExtractSchema = z.object({
35urls: z.union([
45export type TavilyExtractInput = z.infer<typeof TavilyExtractSchema>;
4647// --- Tavily Crawl Schema (based on actual API documentation) ---
48export const TavilyCrawlInputSchema = z.object({
49url: z.string().url("Root URL to begin crawling is required"),
76export type TavilyCrawlInput = z.infer<typeof TavilyCrawlInputSchema>;
7778// --- Tavily Map Schema (based on actual API documentation) ---
79export const TavilyMapInputSchema = z.object({
80url: z.string().url("Root URL to begin mapping is required"),
81max_depth: z.number().int().min(1).optional().default(1),
101});
102103export type TavilyMapInput = z.infer<typeof TavilyMapInputSchema>;
104105// API configuration
106function getTavilyApiKey(): string {
107const key = Deno.env.get("TAVILY_API_KEY") || "";
108if (!key) {
109throw new Error("Configuration error: invalid or missing TAVILY_API_KEY");
110}
111return key;
112}
113114const TAVILY_API_BASE_URL = "https://api.tavily.com";
115116/**
117* Perform a search using the Tavily API.
118*/
119export async function performTavilySearch(input: TavilySearchInput): Promise<unknown> {
120const apiKey = getTavilyApiKey();
121const options = {
122method: "POST",
123headers: {
124"Authorization": `Bearer ${apiKey}`,
125"Content-Type": "application/json",
126},
128};
129130const response = await fetch(`${TAVILY_API_BASE_URL}/search`, options);
131132if (!response.ok) {
136} catch {
137console.error(
138`Failed to parse error response from Tavily API for search: ${response.status} - ${response.statusText}`,
139);
140}
146147/**
148* Perform an extract using the Tavily API.
149*/
150export async function performTavilyExtract(input: TavilyExtractInput): Promise<unknown> {
151const apiKey = getTavilyApiKey();
152153// Ensure urls is always an array for the API
154const apiInput = {
155...input,
156urls: Array.isArray(input.urls) ? input.urls : [input.urls],
160method: "POST",
161headers: {
162"Authorization": `Bearer ${apiKey}`,
163"Content-Type": "application/json",
164},
165body: JSON.stringify(apiInput),
166};
167168const response = await fetch(`${TAVILY_API_BASE_URL}/extract`, options);
169170if (!response.ok) {
174} catch {
175console.error(
176`Failed to parse error response from Tavily API for extract: ${response.status} - ${response.statusText}`,
177);
178}
184185/**
186* Perform a crawl using the Tavily API (BETA).
187*/
188export async function performTavilyCrawl(input: TavilyCrawlInput): Promise<unknown> {
189const apiKey = getTavilyApiKey();
190191// Convert empty arrays to null as per API documentation
192const apiInput = {
193...input,
194select_paths: input.select_paths?.length ? input.select_paths : null,
202method: "POST",
203headers: {
204"Authorization": `Bearer ${apiKey}`,
205"Content-Type": "application/json",
206},
207body: JSON.stringify(apiInput),
208};
209210const response = await fetch(`${TAVILY_API_BASE_URL}/crawl`, options);
211212if (!response.ok) {
216} catch {
217console.error(
218`Failed to parse error response from Tavily API for crawl: ${response.status} - ${response.statusText}`,
219);
220}
226227/**
228* Perform a site map using the Tavily API (BETA).
229*/
230export async function performTavilyMap(input: TavilyMapInput): Promise<unknown> {
231const apiKey = getTavilyApiKey();
232233// Convert empty arrays to null as per API documentation
234const apiInput = {
235...input,
236select_paths: input.select_paths?.length ? input.select_paths : null,
244method: "POST",
245headers: {
246"Authorization": `Bearer ${apiKey}`,
247"Content-Type": "application/json",
248},
249body: JSON.stringify(apiInput),
250};
251252const response = await fetch(`${TAVILY_API_BASE_URL}/map`, options);
253254if (!response.ok) {
258} catch {
259console.error(
260`Failed to parse error response from Tavily API for map: ${response.status} - ${response.statusText}`,
261);
262}
api_ianmenethil_comopenaiClient.ts2 matches
1// Future implementation of OpenAI client for API calls
2import { OpenAI } from "openai";
34const openai = new OpenAI({
5apiKey: Deno.env.get("OPENAI_API_KEY"),
6});
7
api_ianmenethil_comfirecrawlClient.ts20 matches
1// F:\zApps\valtown.servers\APIServer\src\external-apis\firecrawl-client.ts
23import FirecrawlApp from "firecrawl";
94export type ScraperInput = z.infer<typeof ScraperSchema>;
9596// Map schema - Based on actual Firecrawl API documentation
97export const FirecrawlMapInputSchema = z.object({
98url: z.string().url("Invalid URL format"),
99search: z.string().optional(),
105});
106107export type FirecrawlMapInput = z.infer<typeof FirecrawlMapInputSchema>;
108109function getApiKey(): string {
110const key = Deno.env.get("FIRECRAWL_API_KEY") || "";
111if (!key) {
112throw new Error("Configuration error: invalid or missing FIRECRAWL_API_KEY");
113}
114return key;
116117function getFirecrawlClient(): FirecrawlApp {
118const apiKey = getApiKey();
119return new FirecrawlApp({ apiKey });
120}
121122/**
123* Fetch content via the Firecrawl API scrape endpoint.
124* Handles single page scraping with all supported options.
125*/
126export async function fetchFromFirecrawlAPI(
127input: ScraperInput,
128): Promise<unknown> {
170171/**
172* Perform a map operation using the Firecrawl API.
173* Maps all URLs from a website using Firecrawl's dedicated map endpoint.
174*/
175export async function performFirecrawlMap(
176input: FirecrawlMapInput,
177): Promise<unknown> {
178const firecrawl = getFirecrawlClient();
181// Use the dedicated map method from FirecrawlApp
182// Note: The FirecrawlApp SDK might need to be updated to support the map endpoint
183// If the SDK doesn't have a map method, we'll need to make a direct API call
184185// Check if FirecrawlApp has a map method
195});
196} else {
197// Fallback to direct API call if SDK doesn't support map
198const apiKey = getApiKey();
199const response = await fetch("https://api.firecrawl.dev/v1/map", {
200method: "POST",
201headers: {
202"Authorization": `Bearer ${apiKey}`,
203"Content-Type": "application/json",
204},
212} catch {
213console.error(
214`Failed to parse error response from Firecrawl API for map: ${response.status} - ${response.statusText}`,
215);
216}