feat: 更新 API 路径配置并优化环境变量管理
- 修改 .env.example,更新玩家端本地配置说明,新增直连 Laravel 和局域网 IP 访问配置项,提升开发灵活性。 - 更新 middleware.ts,使用新的 LOTTERY_API_V1_BASE 常量构建 API 请求路径,简化代码结构。 - 在 next.config.ts 中引入 parseAllowedDevOrigins 函数,动态解析允许的开发来源,增强安全性。 - 重构多个 API 模块,移除 API_V1_PREFIX,直接使用相对路径,简化 API 调用逻辑,提高可维护性。
This commit is contained in:
19
.env.example
19
.env.example
@@ -1,6 +1,11 @@
|
|||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 前端本地配置示例
|
# 玩家端本地配置示例:复制为 .env.local 后按需修改
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
# 三端联调速查见 lotteryadmin/.env.example;本端默认端口 3800。
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Laravel API(Next rewrites:/api/* → ${API_BASE_URL}/api/*)
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
# 手动切换环境:保留一个生效,另一个注释掉
|
# 手动切换环境:保留一个生效,另一个注释掉
|
||||||
|
|
||||||
# 测试
|
# 测试
|
||||||
@@ -8,6 +13,13 @@ API_BASE_URL=http://127.0.0.1:8000
|
|||||||
# 线上
|
# 线上
|
||||||
# API_BASE_URL=https://api.your-production-domain.com
|
# API_BASE_URL=https://api.your-production-domain.com
|
||||||
|
|
||||||
|
# 可选:直连 Laravel(不经 Next 反代)
|
||||||
|
# NEXT_PUBLIC_LOTTERY_API_BASE_URL=http://127.0.0.1:8000
|
||||||
|
# NEXT_PUBLIC_LOTTERY_API_PROXY_DISABLED=true
|
||||||
|
|
||||||
|
# Next 开发:局域网 IP 访问(逗号分隔 host,无协议)
|
||||||
|
# ALLOWED_DEV_ORIGINS=192.168.0.101
|
||||||
|
|
||||||
# 可选:大厅「玩法与赔率」接口 `/api/v1/play/effective` 的 ?currency=(如 NPR);不设则由后端选默认可下注币种。
|
# 可选:大厅「玩法与赔率」接口 `/api/v1/play/effective` 的 ?currency=(如 NPR);不设则由后端选默认可下注币种。
|
||||||
# NEXT_PUBLIC_LOTTERY_PLAY_CURRENCY=NPR
|
# NEXT_PUBLIC_LOTTERY_PLAY_CURRENCY=NPR
|
||||||
|
|
||||||
@@ -16,9 +28,10 @@ API_BASE_URL=http://127.0.0.1:8000
|
|||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Laravel Reverb(WebSocket)。不配则 Echo 为空,会一直显示「降级模式 / 轮询」。
|
# Laravel Reverb(WebSocket)。不配则 Echo 为空,会一直显示「降级模式 / 轮询」。
|
||||||
|
# 须与 lotterLaravel .env 的 REVERB_APP_KEY / REVERB_HOST / REVERB_PORT / REVERB_SCHEME 一致。
|
||||||
# Laravel 终端另开:`php artisan reverb:start`
|
# Laravel 终端另开:`php artisan reverb:start`
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# NEXT_PUBLIC_REVERB_APP_KEY=与 lotterLaravel .env 的 REVERB_APP_KEY 一致
|
# NEXT_PUBLIC_REVERB_APP_KEY=
|
||||||
# NEXT_PUBLIC_REVERB_HOST=127.0.0.1
|
# NEXT_PUBLIC_REVERB_HOST=127.0.0.1
|
||||||
# NEXT_PUBLIC_REVERB_PORT=8080
|
# NEXT_PUBLIC_REVERB_PORT=8080
|
||||||
# NEXT_PUBLIC_REVERB_SCHEME=http
|
# NEXT_PUBLIC_REVERB_SCHEME=http
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { NextResponse, type NextRequest } from "next/server";
|
import { NextResponse, type NextRequest } from "next/server";
|
||||||
|
|
||||||
|
import { LOTTERY_API_V1_BASE } from "./src/api/paths";
|
||||||
import { generateCSP, nonCspSecurityHeaders } from "./src/lib/csp-config";
|
import { generateCSP, nonCspSecurityHeaders } from "./src/lib/csp-config";
|
||||||
|
|
||||||
type RuntimeOriginsEnvelope = {
|
type RuntimeOriginsEnvelope = {
|
||||||
@@ -11,7 +12,7 @@ type RuntimeOriginsEnvelope = {
|
|||||||
|
|
||||||
async function loadRuntimeOrigins(request: NextRequest): Promise<string[]> {
|
async function loadRuntimeOrigins(request: NextRequest): Promise<string[]> {
|
||||||
try {
|
try {
|
||||||
const url = new URL("/api/v1/integration/runtime-origins", request.url);
|
const url = new URL(`${LOTTERY_API_V1_BASE}/integration/runtime-origins`, request.url);
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
headers: { Accept: "application/json" },
|
headers: { Accept: "application/json" },
|
||||||
cache: "no-store",
|
cache: "no-store",
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import type { NextConfig } from "next";
|
import type { NextConfig } from "next";
|
||||||
|
|
||||||
import { nonCspSecurityHeaders } from "./src/lib/csp-config";
|
import { nonCspSecurityHeaders } from "./src/lib/csp-config";
|
||||||
|
import { parseAllowedDevOrigins } from "./src/lib/next-dev-origins";
|
||||||
|
|
||||||
const lotteryApiProxyTarget =
|
const lotteryApiProxyTarget =
|
||||||
process.env.API_BASE_URL?.trim() || "http://127.0.0.1:8000";
|
process.env.API_BASE_URL?.trim() || "http://127.0.0.1:8000";
|
||||||
|
const allowedDevOrigins = parseAllowedDevOrigins(process.env.ALLOWED_DEV_ORIGINS);
|
||||||
|
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
allowedDevOrigins: ["192.168.0.101"],
|
...(allowedDevOrigins.length > 0 ? { allowedDevOrigins } : {}),
|
||||||
reactCompiler: true,
|
reactCompiler: true,
|
||||||
|
|
||||||
// 非 CSP 安全头;CSP 由 middleware 按后台接入站点白名单动态生成。
|
// 非 CSP 安全头;CSP 由 middleware 按后台接入站点白名单动态生成。
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { API_V1_PREFIX } from "@/api/paths";
|
|
||||||
import { lotteryRequest } from "@/lib/lottery-http";
|
import { lotteryRequest } from "@/lib/lottery-http";
|
||||||
import type { PublicCurrencyListData } from "@/types/api/currency";
|
import type { PublicCurrencyListData } from "@/types/api/currency";
|
||||||
|
|
||||||
/** `GET /api/v1/currencies`(公开) */
|
/** `GET /api/v1/currencies`(公开) */
|
||||||
export function getPublicCurrencies(): Promise<PublicCurrencyListData> {
|
export function getPublicCurrencies(): Promise<PublicCurrencyListData> {
|
||||||
return lotteryRequest.get<PublicCurrencyListData>(`${API_V1_PREFIX}/currencies`);
|
return lotteryRequest.get<PublicCurrencyListData>(`/currencies`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { lotteryRequest } from "@/lib/lottery-http";
|
import { lotteryRequest } from "@/lib/lottery-http";
|
||||||
import { API_V1_PREFIX } from "@/api/paths";
|
|
||||||
import type { DrawCurrentResponse } from "@/types/api/draw-current";
|
import type { DrawCurrentResponse } from "@/types/api/draw-current";
|
||||||
import type {
|
import type {
|
||||||
DrawResultDetailPayload,
|
DrawResultDetailPayload,
|
||||||
@@ -16,7 +15,7 @@ export function getDrawCurrent(
|
|||||||
params?: GetDrawCurrentParams,
|
params?: GetDrawCurrentParams,
|
||||||
): Promise<DrawCurrentResponse> {
|
): Promise<DrawCurrentResponse> {
|
||||||
return lotteryRequest.get<DrawCurrentResponse>(
|
return lotteryRequest.get<DrawCurrentResponse>(
|
||||||
`${API_V1_PREFIX}/draw/current`,
|
`/draw/current`,
|
||||||
{ params: params?.currency ? { currency: params.currency } : undefined },
|
{ params: params?.currency ? { currency: params.currency } : undefined },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -35,7 +34,7 @@ export function getDrawResults(
|
|||||||
params?: GetDrawResultsParams,
|
params?: GetDrawResultsParams,
|
||||||
): Promise<DrawResultsListPayload> {
|
): Promise<DrawResultsListPayload> {
|
||||||
return lotteryRequest.get<DrawResultsListPayload>(
|
return lotteryRequest.get<DrawResultsListPayload>(
|
||||||
`${API_V1_PREFIX}/draw/results`,
|
`/draw/results`,
|
||||||
{
|
{
|
||||||
params: {
|
params: {
|
||||||
page: params?.page,
|
page: params?.page,
|
||||||
@@ -58,7 +57,7 @@ export function getDrawResultByNo(
|
|||||||
): Promise<DrawResultDetailPayload> {
|
): Promise<DrawResultDetailPayload> {
|
||||||
const encoded = encodeURIComponent(drawNo);
|
const encoded = encodeURIComponent(drawNo);
|
||||||
return lotteryRequest.get<DrawResultDetailPayload>(
|
return lotteryRequest.get<DrawResultDetailPayload>(
|
||||||
`${API_V1_PREFIX}/draw/results/${encoded}`,
|
`/draw/results/${encoded}`,
|
||||||
{ params: params?.currency ? { currency: params.currency } : undefined },
|
{ params: params?.currency ? { currency: params.currency } : undefined },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { lotteryRequest } from "@/lib/lottery-http";
|
import { lotteryRequest } from "@/lib/lottery-http";
|
||||||
import type { HealthData } from "@/types/api/health";
|
import type { HealthData } from "@/types/api/health";
|
||||||
|
|
||||||
import { API_V1_PREFIX } from "@/api/paths";
|
|
||||||
|
|
||||||
/** `GET /api/v1/health` */
|
/** `GET /api/v1/health` */
|
||||||
export function getHealth(): Promise<HealthData> {
|
export function getHealth(): Promise<HealthData> {
|
||||||
return lotteryRequest.get<HealthData>(`${API_V1_PREFIX}/health`);
|
return lotteryRequest.get<HealthData>(`/health`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export { API_V1_PREFIX } from "@/api/paths";
|
export { LOTTERY_API_V1_BASE } from "@/api/paths";
|
||||||
export { getHealth } from "@/api/health";
|
export { getHealth } from "@/api/health";
|
||||||
export { getPublicCurrencies } from "@/api/currency";
|
export { getPublicCurrencies } from "@/api/currency";
|
||||||
export { getPlayerPing, getPlayerMe } from "@/api/player";
|
export { getPlayerPing, getPlayerMe } from "@/api/player";
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { lotteryRequest } from "@/lib/lottery-http";
|
import { lotteryRequest } from "@/lib/lottery-http";
|
||||||
import { API_V1_PREFIX } from "@/api/paths";
|
|
||||||
import type { JackpotSummaryData } from "@/types/api/jackpot";
|
import type { JackpotSummaryData } from "@/types/api/jackpot";
|
||||||
|
|
||||||
/** `GET /api/v1/jackpot/summary`(无需登录) */
|
/** `GET /api/v1/jackpot/summary`(无需登录) */
|
||||||
@@ -7,7 +6,7 @@ export function getJackpotSummary(
|
|||||||
currencyCode = "NPR",
|
currencyCode = "NPR",
|
||||||
): Promise<JackpotSummaryData> {
|
): Promise<JackpotSummaryData> {
|
||||||
return lotteryRequest.get<JackpotSummaryData>(
|
return lotteryRequest.get<JackpotSummaryData>(
|
||||||
`${API_V1_PREFIX}/jackpot/summary`,
|
`/jackpot/summary`,
|
||||||
{ params: { currency_code: currencyCode } },
|
{ params: { currency_code: currencyCode } },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
/** Laravel `routes/api.php`:`api` 前缀 + `v1` 分组 */
|
/** Laravel `routes/api.php`:`api` 前缀 + `v1` 分组;与 {@link lotteryHttp} `baseURL` 一致。 */
|
||||||
export const API_V1_PREFIX = "/api/v1";
|
export const LOTTERY_API_V1_BASE = "/api/v1";
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { lotteryRequest } from "@/lib/lottery-http";
|
import { lotteryRequest } from "@/lib/lottery-http";
|
||||||
import { API_V1_PREFIX } from "@/api/paths";
|
|
||||||
import type { PlayEffectivePayload } from "@/types/api/play-effective";
|
import type { PlayEffectivePayload } from "@/types/api/play-effective";
|
||||||
|
|
||||||
export type GetPlayEffectiveParams = {
|
export type GetPlayEffectiveParams = {
|
||||||
@@ -15,7 +14,7 @@ export function getPlayEffective(
|
|||||||
params?: GetPlayEffectiveParams,
|
params?: GetPlayEffectiveParams,
|
||||||
): Promise<PlayEffectivePayload> {
|
): Promise<PlayEffectivePayload> {
|
||||||
return lotteryRequest.get<PlayEffectivePayload>(
|
return lotteryRequest.get<PlayEffectivePayload>(
|
||||||
`${API_V1_PREFIX}/play/effective`,
|
`/play/effective`,
|
||||||
{
|
{
|
||||||
params:
|
params:
|
||||||
params?.currency !== undefined && params.currency !== ""
|
params?.currency !== undefined && params.currency !== ""
|
||||||
|
|||||||
@@ -2,14 +2,13 @@ import { lotteryRequest } from "@/lib/lottery-http";
|
|||||||
import type { PlayerMeData } from "@/types/api/player-me";
|
import type { PlayerMeData } from "@/types/api/player-me";
|
||||||
import type { ScopePingData } from "@/types/api/ping";
|
import type { ScopePingData } from "@/types/api/ping";
|
||||||
|
|
||||||
import { API_V1_PREFIX } from "@/api/paths";
|
|
||||||
|
|
||||||
/** `GET /api/v1/player/ping`(无需登录) */
|
/** `GET /api/v1/player/ping`(无需登录) */
|
||||||
export function getPlayerPing(): Promise<ScopePingData> {
|
export function getPlayerPing(): Promise<ScopePingData> {
|
||||||
return lotteryRequest.get<ScopePingData>(`${API_V1_PREFIX}/player/ping`);
|
return lotteryRequest.get<ScopePingData>(`/player/ping`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** `GET /api/v1/player/me`(需玩家 Token) */
|
/** `GET /api/v1/player/me`(需玩家 Token) */
|
||||||
export function getPlayerMe(): Promise<PlayerMeData> {
|
export function getPlayerMe(): Promise<PlayerMeData> {
|
||||||
return lotteryRequest.get<PlayerMeData>(`${API_V1_PREFIX}/player/me`);
|
return lotteryRequest.get<PlayerMeData>(`/player/me`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { lotteryRequest } from "@/lib/lottery-http";
|
import { lotteryRequest } from "@/lib/lottery-http";
|
||||||
import { API_V1_PREFIX } from "@/api/paths";
|
|
||||||
|
|
||||||
export type SettingItem = {
|
export type SettingItem = {
|
||||||
key: string;
|
key: string;
|
||||||
@@ -13,7 +12,7 @@ export type SettingListResponse = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export async function getPublicSettings(group: string): Promise<SettingListResponse> {
|
export async function getPublicSettings(group: string): Promise<SettingListResponse> {
|
||||||
return lotteryRequest.get<SettingListResponse>(`${API_V1_PREFIX}/settings`, {
|
return lotteryRequest.get<SettingListResponse>(`/settings`, {
|
||||||
params: { group },
|
params: { group },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { lotteryRequest } from "@/lib/lottery-http";
|
import { lotteryRequest } from "@/lib/lottery-http";
|
||||||
import { API_V1_PREFIX } from "@/api/paths";
|
|
||||||
import type {
|
import type {
|
||||||
TicketDrawMyMatchPayload,
|
TicketDrawMyMatchPayload,
|
||||||
TicketItemDetailPayload,
|
TicketItemDetailPayload,
|
||||||
@@ -21,7 +20,7 @@ export function getTicketItems(
|
|||||||
params?: GetTicketItemsParams,
|
params?: GetTicketItemsParams,
|
||||||
): Promise<TicketItemsListPayload> {
|
): Promise<TicketItemsListPayload> {
|
||||||
return lotteryRequest.get<TicketItemsListPayload>(
|
return lotteryRequest.get<TicketItemsListPayload>(
|
||||||
`${API_V1_PREFIX}/ticket/items`,
|
`/ticket/items`,
|
||||||
{
|
{
|
||||||
params: {
|
params: {
|
||||||
page: params?.page,
|
page: params?.page,
|
||||||
@@ -42,7 +41,7 @@ export function getTicketItemDetail(
|
|||||||
): Promise<TicketItemDetailPayload> {
|
): Promise<TicketItemDetailPayload> {
|
||||||
const enc = encodeURIComponent(ticketNo);
|
const enc = encodeURIComponent(ticketNo);
|
||||||
return lotteryRequest.get<TicketItemDetailPayload>(
|
return lotteryRequest.get<TicketItemDetailPayload>(
|
||||||
`${API_V1_PREFIX}/ticket/items/${enc}`,
|
`/ticket/items/${enc}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,6 +51,6 @@ export function getTicketDrawMyMatch(
|
|||||||
): Promise<TicketDrawMyMatchPayload> {
|
): Promise<TicketDrawMyMatchPayload> {
|
||||||
const enc = encodeURIComponent(drawNo);
|
const enc = encodeURIComponent(drawNo);
|
||||||
return lotteryRequest.get<TicketDrawMyMatchPayload>(
|
return lotteryRequest.get<TicketDrawMyMatchPayload>(
|
||||||
`${API_V1_PREFIX}/ticket/draws/${enc}/my-match`,
|
`/ticket/draws/${enc}/my-match`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { lotteryRequest } from "@/lib/lottery-http";
|
import { lotteryRequest } from "@/lib/lottery-http";
|
||||||
import { API_V1_PREFIX } from "@/api/paths";
|
|
||||||
import type {
|
import type {
|
||||||
TicketPlaceData,
|
TicketPlaceData,
|
||||||
TicketPlacePayload,
|
TicketPlacePayload,
|
||||||
@@ -12,7 +11,7 @@ export function postTicketPreview(
|
|||||||
body: TicketPreviewPayload,
|
body: TicketPreviewPayload,
|
||||||
): Promise<TicketPreviewData> {
|
): Promise<TicketPreviewData> {
|
||||||
return lotteryRequest.post<TicketPreviewData>(
|
return lotteryRequest.post<TicketPreviewData>(
|
||||||
`${API_V1_PREFIX}/ticket/preview`,
|
`/ticket/preview`,
|
||||||
body,
|
body,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -20,7 +19,7 @@ export function postTicketPreview(
|
|||||||
/** `POST /api/v1/ticket/place` — 真实下注 */
|
/** `POST /api/v1/ticket/place` — 真实下注 */
|
||||||
export function postTicketPlace(body: TicketPlacePayload): Promise<TicketPlaceData> {
|
export function postTicketPlace(body: TicketPlacePayload): Promise<TicketPlaceData> {
|
||||||
return lotteryRequest.post<TicketPlaceData>(
|
return lotteryRequest.post<TicketPlaceData>(
|
||||||
`${API_V1_PREFIX}/ticket/place`,
|
`/ticket/place`,
|
||||||
body,
|
body,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { lotteryRequest } from "@/lib/lottery-http";
|
import { lotteryRequest } from "@/lib/lottery-http";
|
||||||
import { API_V1_PREFIX } from "@/api/paths";
|
|
||||||
import type { WalletBalanceData } from "@/types/api/wallet-balance";
|
import type { WalletBalanceData } from "@/types/api/wallet-balance";
|
||||||
import type {
|
import type {
|
||||||
WalletTransferBody,
|
WalletTransferBody,
|
||||||
@@ -17,7 +16,7 @@ export function getWalletBalance(
|
|||||||
params?: GetWalletBalanceParams,
|
params?: GetWalletBalanceParams,
|
||||||
): Promise<WalletBalanceData> {
|
): Promise<WalletBalanceData> {
|
||||||
return lotteryRequest.get<WalletBalanceData>(
|
return lotteryRequest.get<WalletBalanceData>(
|
||||||
`${API_V1_PREFIX}/wallet/balance`,
|
`/wallet/balance`,
|
||||||
{ params },
|
{ params },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -27,7 +26,7 @@ export function getWalletLogs(
|
|||||||
params?: GetWalletLogsParams,
|
params?: GetWalletLogsParams,
|
||||||
): Promise<WalletLogsData> {
|
): Promise<WalletLogsData> {
|
||||||
return lotteryRequest.get<WalletLogsData>(
|
return lotteryRequest.get<WalletLogsData>(
|
||||||
`${API_V1_PREFIX}/wallet/logs`,
|
`/wallet/logs`,
|
||||||
{ params },
|
{ params },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -37,7 +36,7 @@ export function postWalletTransferIn(
|
|||||||
body: WalletTransferBody,
|
body: WalletTransferBody,
|
||||||
): Promise<WalletTransferResultData> {
|
): Promise<WalletTransferResultData> {
|
||||||
return lotteryRequest.post<WalletTransferResultData>(
|
return lotteryRequest.post<WalletTransferResultData>(
|
||||||
`${API_V1_PREFIX}/wallet/transfer-in`,
|
`/wallet/transfer-in`,
|
||||||
body,
|
body,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -47,7 +46,7 @@ export function postWalletTransferOut(
|
|||||||
body: WalletTransferBody,
|
body: WalletTransferBody,
|
||||||
): Promise<WalletTransferResultData> {
|
): Promise<WalletTransferResultData> {
|
||||||
return lotteryRequest.post<WalletTransferResultData>(
|
return lotteryRequest.post<WalletTransferResultData>(
|
||||||
`${API_V1_PREFIX}/wallet/transfer-out`,
|
`/wallet/transfer-out`,
|
||||||
body,
|
body,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { lotteryHttp, unwrapData } from "@/lib/lottery-http";
|
import { lotteryHttp, unwrapData } from "@/lib/lottery-http";
|
||||||
import { API_V1_PREFIX } from "@/api/paths";
|
|
||||||
|
|
||||||
type RuntimeOriginsResponse = {
|
type RuntimeOriginsResponse = {
|
||||||
iframe_allowed_origins: string[];
|
iframe_allowed_origins: string[];
|
||||||
@@ -49,7 +48,7 @@ export async function loadIframeAllowedOrigins(): Promise<string[]> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pendingOrigins ??= lotteryHttp
|
pendingOrigins ??= lotteryHttp
|
||||||
.get(`${API_V1_PREFIX}/integration/runtime-origins`)
|
.get("/integration/runtime-origins")
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
const data = unwrapData<RuntimeOriginsResponse>(response.data);
|
const data = unwrapData<RuntimeOriginsResponse>(response.data);
|
||||||
cachedOrigins = data.iframe_allowed_origins
|
cachedOrigins = data.iframe_allowed_origins
|
||||||
|
|||||||
13
src/lib/lottery-api-env.ts
Normal file
13
src/lib/lottery-api-env.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* 玩家端 API 连接方式(与管理端一致):
|
||||||
|
* - 默认:同源 `/api` + Next `rewrites` → Laravel(`API_BASE_URL` 写在 .env.local)。
|
||||||
|
* - 可选:`NEXT_PUBLIC_LOTTERY_API_BASE_URL` 直连。
|
||||||
|
*/
|
||||||
|
export function hasLotteryPlayerApiBaseUrl(): boolean {
|
||||||
|
const direct = process.env.NEXT_PUBLIC_LOTTERY_API_BASE_URL?.trim();
|
||||||
|
if (direct !== undefined && direct !== "") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return process.env.NEXT_PUBLIC_LOTTERY_API_PROXY_DISABLED !== "true";
|
||||||
|
}
|
||||||
@@ -13,13 +13,13 @@ import {
|
|||||||
} from "@/types/api/errors";
|
} from "@/types/api/errors";
|
||||||
import { isApiEnvelope } from "@/types/api/envelope";
|
import { isApiEnvelope } from "@/types/api/envelope";
|
||||||
import { useErrorStore } from "@/stores/error-store";
|
import { useErrorStore } from "@/stores/error-store";
|
||||||
|
import { LOTTERY_API_V1_BASE } from "@/api/paths";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* **第一层**:只挂 `baseURL` / `timeout` / 默认 `Accept`。业务解析、toast 都不在这里。
|
* **第一层**:`baseURL` 对齐 Laravel `api/v1`;各 `api/*.ts` 只写业务 path(如 `/currencies`)。
|
||||||
*/
|
*/
|
||||||
export const lotteryHttp = axios.create({
|
export const lotteryHttp = axios.create({
|
||||||
// 统一走 Next 同源 /api 代理,由 next.config.ts 的 API_BASE_URL 转发到后端。
|
baseURL: LOTTERY_API_V1_BASE,
|
||||||
baseURL: "/api",
|
|
||||||
timeout: 30_000,
|
timeout: 30_000,
|
||||||
headers: { Accept: "application/json" },
|
headers: { Accept: "application/json" },
|
||||||
});
|
});
|
||||||
|
|||||||
11
src/lib/next-dev-origins.ts
Normal file
11
src/lib/next-dev-origins.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/** 解析 `ALLOWED_DEV_ORIGINS`(逗号分隔),供 next.config `allowedDevOrigins` 使用 */
|
||||||
|
export function parseAllowedDevOrigins(envValue: string | undefined): string[] {
|
||||||
|
if (envValue === undefined || envValue.trim() === "") {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return envValue
|
||||||
|
.split(",")
|
||||||
|
.map((origin) => origin.trim())
|
||||||
|
.filter((origin) => origin !== "");
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user