diff --git a/next/app/(api)/api/order/check/route.ts b/next/app/(api)/api/order/check/route.ts index 4bb8e69..5816dd3 100644 --- a/next/app/(api)/api/order/check/route.ts +++ b/next/app/(api)/api/order/check/route.ts @@ -2,6 +2,7 @@ import { Api } from "@/lib/api"; import { ItemsMemberProduct, ItemsOrders } from "@/lib/api/data-contracts"; import { logError } from "@/lib/loging"; +import fetchPonyfill from "fetch-ponyfill"; import { NextResponse, NextRequest } from "next/server"; // const SAFERPAY_CHECK_QUERY_PARAM = "saferpay_check"; @@ -66,7 +67,7 @@ export async function GET(request) { Token: order.token, }; - let response = await fetch( + let response = await fetchPonyfill().fetch( process.env.SAFERPAY_URL + "/Payment/v1/PaymentPage/Assert", { method: "post", @@ -104,7 +105,7 @@ export async function GET(request) { }, }; - response = await fetch( + response = await fetchPonyfill().fetch( process.env.SAFERPAY_URL + "/Payment/v1/Transaction/Capture", { method: "post", diff --git a/next/app/(api)/api/order/init/route.ts b/next/app/(api)/api/order/init/route.ts index b4e64ac..8ed7932 100644 --- a/next/app/(api)/api/order/init/route.ts +++ b/next/app/(api)/api/order/init/route.ts @@ -2,6 +2,7 @@ import { Api } from "@/lib/api"; import { ItemsMemberProduct, ItemsOrders } from "@/lib/api/data-contracts"; import { logError } from "@/lib/loging"; +import fetchPonyfill from "fetch-ponyfill"; import { NextResponse, NextRequest } from "next/server"; // const SAFERPAY_CHECK_QUERY_PARAM = "saferpay_check"; @@ -180,7 +181,7 @@ export async function POST(request) { console.log("ENCODED_SAFERPAY_CREDENTIALS", ENCODED_SAFERPAY_CREDENTIALS); console.log("requestData", requestData); - const response = await fetch(initPaymentURL, { + const response = await fetchPonyfill().fetch(initPaymentURL, { method: "post", headers: { "Content-Type": "application/json; charset=utf-8", diff --git a/next/app/(main)/[slug]/page.tsx b/next/app/(main)/[slug]/page.tsx index c9b9141..0e3b824 100644 --- a/next/app/(main)/[slug]/page.tsx +++ b/next/app/(main)/[slug]/page.tsx @@ -6,6 +6,7 @@ import { logError } from "@/lib/loging"; import { Show } from "@/lib/Types"; import PageProgram from "./PageProgram"; import Flows from "@/lib/api/Flows"; +import fetchPonyfill from "fetch-ponyfill"; async function getSendung(slug) { console.log("getSendung: ", slug); @@ -58,12 +59,13 @@ async function getSendung(slug) { export async function getNextShowForProgram(slug) { try { - return fetch("https://songticker.rabe.ch/libretime/live-info-v2.json", { - next: { - revalidate: process.env.NODE_ENV === "production" ? 900 : undefined, // in seconds - }, - cache: process.env.NODE_ENV === "production" ? undefined : "no-store", - }) + return fetchPonyfill() + .fetch("https://songticker.rabe.ch/libretime/live-info-v2.json", { + next: { + revalidate: process.env.NODE_ENV === "production" ? 900 : undefined, // in seconds + }, + cache: process.env.NODE_ENV === "production" ? undefined : "no-store", + }) .then((response: any) => response.json()) .then((liveData: any) => { // console.log("liveData", liveData); diff --git a/next/app/(main)/bestellung/Form.tsx b/next/app/(main)/bestellung/Form.tsx index 6657850..750a69e 100644 --- a/next/app/(main)/bestellung/Form.tsx +++ b/next/app/(main)/bestellung/Form.tsx @@ -10,6 +10,7 @@ import StyleSheet from "react-native-media-query"; import Select from "react-select"; import Button from "@/components/Button"; import ButtonText from "@/components/ButtonText"; +import fetchPonyfill from "fetch-ponyfill"; export default function Statement({ id, type, options, defaultValue }) { const [errors, setErrors] = useState([]); @@ -98,10 +99,11 @@ export default function Statement({ id, type, options, defaultValue }) { if (newErrors.length === 0) { // console.log("fetch"); setErrorMessage(""); - fetch("/api/order/init", { - method: "POST", - body: formData, - }) + fetchPonyfill() + .fetch("/api/order/init", { + method: "POST", + body: formData, + }) .then((response) => { // console.log("respons", response); return response.json(); diff --git a/next/app/(main)/programm/[date]/page.tsx b/next/app/(main)/programm/[date]/page.tsx index 96788cd..57c3aa8 100644 --- a/next/app/(main)/programm/[date]/page.tsx +++ b/next/app/(main)/programm/[date]/page.tsx @@ -6,15 +6,17 @@ import moment from "moment"; import { notFound } from "next/navigation"; import PageProgramm from "./PageProgramm"; import Flows from "@/lib/api/Flows"; +import fetchPonyfill from "fetch-ponyfill"; export async function getLiveData() { try { - return fetch("https://songticker.rabe.ch/libretime/live-info-v2.json", { - next: { - revalidate: process.env.NODE_ENV === "production" ? 900 : undefined, // in seconds - }, - cache: process.env.NODE_ENV === "production" ? undefined : "no-store", - }) + return fetchPonyfill() + .fetch("https://songticker.rabe.ch/libretime/live-info-v2.json", { + next: { + revalidate: process.env.NODE_ENV === "production" ? 900 : undefined, // in seconds + }, + cache: process.env.NODE_ENV === "production" ? undefined : "no-store", + }) .then((response: any) => response.json()) .then((liveData: any) => { let todayShows: Show[] = liveData.shows.previous.filter((item) => { diff --git a/next/app/(special)/bestellung/check/page.tsx b/next/app/(special)/bestellung/check/page.tsx index 29f5b91..7bdfa5f 100644 --- a/next/app/(special)/bestellung/check/page.tsx +++ b/next/app/(special)/bestellung/check/page.tsx @@ -7,10 +7,11 @@ import { notFound, useSearchParams } from "next/navigation"; import useSWR from "swr"; import { useEffect } from "react"; +import fetchPonyfill from "fetch-ponyfill"; async function checkOrder([slug, id]) { try { - let response = await fetch(`${slug}?id=${id}`, { + let response = await fetchPonyfill().fetch(`${slug}?id=${id}`, { method: "GET", }); let data = await response.json(); diff --git a/next/components/Header/AudioRabePlayerLabel.tsx b/next/components/Header/AudioRabePlayerLabel.tsx index 5b3f7f4..39077cf 100644 --- a/next/components/Header/AudioRabePlayerLabel.tsx +++ b/next/components/Header/AudioRabePlayerLabel.tsx @@ -8,6 +8,7 @@ import { useAnimate } from "framer-motion"; import Fonts from "@/lib/Fonts"; import Colors from "@/lib/Colors"; import Metrics from "@/lib/Metrics"; +import fetchPonyfill from "fetch-ponyfill"; export interface HoverableProps {} @@ -27,9 +28,10 @@ const AudioRabePlayerLabel = ({}: HoverableProps) => { useEffect(() => { if (refetch) { - fetch("https://songticker.rabe.ch/songticker/0.9.3/current.xml", { - cache: "no-store", - }) + fetchPonyfill() + .fetch("https://songticker.rabe.ch/songticker/0.9.3/current.xml", { + cache: "no-store", + }) .then((res) => res.text()) .then((data) => { if (data && oldData !== data) { diff --git a/next/components/ProgramBox/ProgramBox.tsx b/next/components/ProgramBox/ProgramBox.tsx index ead721c..5ab19a6 100644 --- a/next/components/ProgramBox/ProgramBox.tsx +++ b/next/components/ProgramBox/ProgramBox.tsx @@ -12,15 +12,17 @@ import StyleSheet from "react-native-media-query"; import Button from "../Button"; import PlayList from "./PlayList"; import ShowsList from "./ShowsList"; +import fetchPonyfill from "fetch-ponyfill"; export async function getLiveData() { try { - return fetch("https://songticker.rabe.ch/libretime/live-info-v2.json", { - next: { - revalidate: process.env.NODE_ENV === "production" ? 900 : undefined, // in seconds - }, - cache: process.env.NODE_ENV === "production" ? undefined : "no-store", - }) + return fetchPonyfill() + .fetch("https://songticker.rabe.ch/libretime/live-info-v2.json", { + next: { + revalidate: process.env.NODE_ENV === "production" ? 900 : undefined, // in seconds + }, + cache: process.env.NODE_ENV === "production" ? undefined : "no-store", + }) .then((response: any) => response.json()) .then((liveData: any) => { let todayShows: Show[] = liveData.shows.previous.filter((item) => { @@ -64,15 +66,16 @@ export async function getLiveData() { export async function getPlaylistData(numbers) { try { - return fetch( - `https://archiv.rabe.ch/api/tracks?sort=-started_at&page[size]=${numbers}`, - { - next: { - revalidate: process.env.NODE_ENV === "production" ? 900 : undefined, // in seconds - }, - cache: process.env.NODE_ENV === "production" ? undefined : "no-store", - } - ) + return fetchPonyfill() + .fetch( + `https://archiv.rabe.ch/api/tracks?sort=-started_at&page[size]=${numbers}`, + { + next: { + revalidate: process.env.NODE_ENV === "production" ? 900 : undefined, // in seconds + }, + cache: process.env.NODE_ENV === "production" ? undefined : "no-store", + } + ) .then((response: any) => response.json()) .then((responseData: any) => { // console.log("playlistData", responseData.data); diff --git a/next/lib/api/http-client.ts b/next/lib/api/http-client.ts index effb370..33efcec 100644 --- a/next/lib/api/http-client.ts +++ b/next/lib/api/http-client.ts @@ -11,6 +11,7 @@ export type QueryParamsType = Record; export type ResponseFormat = keyof Omit; +import fetchPonyfill from "fetch-ponyfill"; export interface FullRequestParams extends Omit { /** set parameter to `true` for call `securityWorker` for this request */ @@ -31,16 +32,22 @@ export interface FullRequestParams extends Omit { cancelToken?: CancelToken; } -export type RequestParams = Omit; +export type RequestParams = Omit< + FullRequestParams, + "body" | "method" | "query" | "path" +>; export interface ApiConfig { baseUrl?: string; baseApiParams?: Omit; - securityWorker?: (securityData: SecurityDataType | null) => Promise | RequestParams | void; + securityWorker?: ( + securityData: SecurityDataType | null + ) => Promise | RequestParams | void; customFetch?: typeof fetch; } -export interface HttpResponse extends Response { +export interface HttpResponse + extends Response { data: D; error: E; } @@ -59,7 +66,8 @@ export class HttpClient { private securityData: SecurityDataType | null = null; private securityWorker?: ApiConfig["securityWorker"]; private abortControllers = new Map(); - private customFetch = (...fetchParams: Parameters) => fetch(...fetchParams); + private customFetch = (...fetchParams: Parameters) => + fetchPonyfill().fetch(...fetchParams); private baseApiParams: RequestParams = { credentials: "same-origin", @@ -92,9 +100,15 @@ export class HttpClient { protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; - const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); + const keys = Object.keys(query).filter( + (key) => "undefined" !== typeof query[key] + ); return keys - .map((key) => (Array.isArray(query[key]) ? this.addArrayQueryParam(query, key) : this.addQueryParam(query, key))) + .map((key) => + Array.isArray(query[key]) + ? this.addArrayQueryParam(query, key) + : this.addQueryParam(query, key) + ) .join("&"); } @@ -105,8 +119,13 @@ export class HttpClient { private contentFormatters: Record any> = { [ContentType.Json]: (input: any) => - input !== null && (typeof input === "object" || typeof input === "string") ? JSON.stringify(input) : input, - [ContentType.Text]: (input: any) => (input !== null && typeof input !== "string" ? JSON.stringify(input) : input), + input !== null && (typeof input === "object" || typeof input === "string") + ? JSON.stringify(input) + : input, + [ContentType.Text]: (input: any) => + input !== null && typeof input !== "string" + ? JSON.stringify(input) + : input, [ContentType.FormData]: (input: any) => Object.keys(input || {}).reduce((formData, key) => { const property = input[key]; @@ -116,14 +135,17 @@ export class HttpClient { ? property : typeof property === "object" && property !== null ? JSON.stringify(property) - : `${property}`, + : `${property}` ); return formData; }, new FormData()), [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - protected mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { + protected mergeRequestParams( + params1: RequestParams, + params2?: RequestParams + ): RequestParams { return { ...this.baseApiParams, ...params1, @@ -136,7 +158,9 @@ export class HttpClient { }; } - protected createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + protected createAbortSignal = ( + cancelToken: CancelToken + ): AbortSignal | undefined => { if (this.abortControllers.has(cancelToken)) { const abortController = this.abortControllers.get(cancelToken); if (abortController) { @@ -180,15 +204,26 @@ export class HttpClient { const payloadFormatter = this.contentFormatters[type || ContentType.Json]; const responseFormat = format || requestParams.format; - return this.customFetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { - ...requestParams, - headers: { - ...(requestParams.headers || {}), - ...(type && type !== ContentType.FormData ? { "Content-Type": type } : {}), - }, - signal: (cancelToken ? this.createAbortSignal(cancelToken) : requestParams.signal) || null, - body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), - }).then(async (response) => { + return this.customFetch( + `${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, + { + ...requestParams, + headers: { + ...(requestParams.headers || {}), + ...(type && type !== ContentType.FormData + ? { "Content-Type": type } + : {}), + }, + signal: + (cancelToken + ? this.createAbortSignal(cancelToken) + : requestParams.signal) || null, + body: + typeof body === "undefined" || body === null + ? null + : payloadFormatter(body), + } + ).then(async (response) => { const r = response.clone() as HttpResponse; r.data = null as unknown as T; r.error = null as unknown as E; diff --git a/next/package.json b/next/package.json index 51b1744..ea46535 100644 --- a/next/package.json +++ b/next/package.json @@ -15,6 +15,7 @@ "dompurify": "^3.1.6", "dotenv": "^16.4.5", "fast-xml-parser": "^4.5.1", + "fetch-ponyfill": "^7.1.0", "framer-motion": "^11.11.10", "google-maps-react-markers": "^2.0.11", "jsdom": "^24.1.1", diff --git a/next/yarn.lock b/next/yarn.lock index 99f8a96..609202e 100644 --- a/next/yarn.lock +++ b/next/yarn.lock @@ -2340,6 +2340,13 @@ fbjs@^3.0.4: setimmediate "^1.0.5" ua-parser-js "^1.0.35" +fetch-ponyfill@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/fetch-ponyfill/-/fetch-ponyfill-7.1.0.tgz#4266ed48b4e64663a50ab7f7fcb8e76f990526d0" + integrity sha512-FhbbL55dj/qdVO3YNK7ZEkshvj3eQ7EuIGV2I6ic/2YiocvyWv+7jg2s4AyS0wdRU75s3tA8ZxI/xPigb0v5Aw== + dependencies: + node-fetch "~2.6.1" + fill-range@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" @@ -3460,6 +3467,13 @@ node-fetch@^2.6.1, node-fetch@^2.7.0: dependencies: whatwg-url "^5.0.0" +node-fetch@~2.6.1: + version "2.6.13" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.13.tgz#a20acbbec73c2e09f9007de5cda17104122e0010" + integrity sha512-StxNAxh15zr77QvvkmveSQ8uCQ4+v5FkvNTj0OESmiHu+VRi/gXArXtkWMElOsOUNLtUEvI4yS+rdtOHZTwlQA== + dependencies: + whatwg-url "^5.0.0" + node-forge@^1: version "1.3.1" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3"