diff --git a/.env.example b/.env.example index cc0ccd5..5a5732f 100644 --- a/.env.example +++ b/.env.example @@ -6,6 +6,9 @@ INITIAL_ADMIN_PASSWORD= INITIAL_SELLER_NAME= MFA_ENCRYPTION_KEY= PRICING_FIXTURE_PROVIDER_ENABLED=false +PRICING_HTTP_PROVIDER_ID=http-provider +PRICING_HTTP_PROVIDER_ENDPOINT= +PRICING_HTTP_PROVIDER_TOKEN= PASSWORD_RESET_URL=http://localhost:5173/reset-password SMTP_FROM=no-reply@example.test SMTP_URL=smtp://localhost:1025 diff --git a/apps/api/src/modules/pricing/providers/http-pricing-provider.js b/apps/api/src/modules/pricing/providers/http-pricing-provider.js new file mode 100644 index 0000000..654ef3a --- /dev/null +++ b/apps/api/src/modules/pricing/providers/http-pricing-provider.js @@ -0,0 +1,28 @@ +import { createPricingProvider } from './pricing-provider.js'; + +export function createHttpPricingProvider({ + id, + endpoint, + token, + fetchImplementation = fetch, +}) { + if (typeof endpoint !== 'string' || endpoint.trim().length === 0) { + throw new Error('Pricing provider endpoint is required.'); + } + + return createPricingProvider({ + id, + async observe(input) { + const url = new URL(endpoint); + for (const [key, value] of Object.entries(input)) { + if (value) url.searchParams.set(key, value); + } + const response = await fetchImplementation(url, { + headers: token ? { authorization: `Bearer ${token}` } : {}, + }); + if (!response.ok) throw new Error(`Pricing provider returned HTTP ${response.status}.`); + const payload = await response.json(); + return payload?.observations ?? payload; + }, + }); +} diff --git a/database/migrations/0020_pricing_job_mapping_context.sql b/database/migrations/0020_pricing_job_mapping_context.sql new file mode 100644 index 0000000..8dc43e9 --- /dev/null +++ b/database/migrations/0020_pricing_job_mapping_context.sql @@ -0,0 +1,2 @@ +ALTER TABLE "pricing_refresh_jobs" ADD COLUMN "external_identifier" text; +ALTER TABLE "pricing_refresh_jobs" ADD COLUMN "search_query" text; \ No newline at end of file