@spicyapi/proxy 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,51 +1,58 @@
1
1
  /**
2
- * 服务端代理:让客户端应用在**不持有 API 密钥**的前提下调用 SpicyAPI
2
+ * A server-side proxy that lets client applications call SpicyAPI without ever holding an API key.
3
3
  *
4
- * 浏览器里的 JS、iOS / Android 应用、桌面应用——这些地方都放不住密钥。打进包里的
5
- * 密钥等于公开的密钥:攻击者反编译或抓一次包就能拿到,然后一直花到余额见底,而
6
- * 我们这边看到的只是「这个账号今天用得有点多」。
4
+ * JavaScript in a browser, an iOS or Android app, a desktop app - none of these can keep a secret.
5
+ * A key shipped inside a bundle is a public key: an attacker decompiles it, or captures one
6
+ * request, and then spends until the balance is gone, while all we see on our side is "this account
7
+ * is rather busy today".
7
8
  *
8
- * 正确的形状是:客户端把请求打到**调用方自己的服务器**,由那一层补上密钥再转发。
9
- * 这个模块就是那一层,装在调用方的 Next.js / Express / 任意 fetch 运行时里。
9
+ * The right shape is for the client to call the caller's own server, and for that layer to add the
10
+ * key and forward the request. This module is that layer, mounted inside the caller's Next.js,
11
+ * Express or any other fetch runtime.
10
12
  *
11
- * ── 协议 ───────────────────────────────────────────────────────────
13
+ * ## The protocol
12
14
  *
13
- * 客户端把目标地址放进 `x-spicy-target-url` 头,打到自己后端约定的那条路由
14
- * (惯例是 `/api/spicy/proxy`)。代理校验目标、补上 `Authorization`、转发,
15
- * 再把响应原样回给客户端。
15
+ * The client puts the destination in an `x-spicy-target-url` header and calls whichever route its
16
+ * own backend agreed on (`/api/spicy/proxy` by convention). The proxy validates the target, adds
17
+ * `Authorization`, forwards the request and passes the response straight back.
16
18
  *
17
- * ── 为什么目标地址必须白名单,而不是「转发到头里写的任何地址」 ──────
19
+ * ## Why the destination must be allow-listed rather than "forward to whatever the header says"
18
20
  *
19
- * 这是整个设计里唯一会造成灾难的地方。不校验的话,任何人往那个头里填
20
- * `https://attacker.example` 就能让**你的服务器把你的密钥发给他**——一个
21
- * 请求就泄露,而且流量看起来完全正常:是你自己的服务器发出去的。
21
+ * This is the one place in the design where getting it wrong is catastrophic. Without validation,
22
+ * anyone can put `https://attacker.example` in that header and have your server send them your key
23
+ * - one request leaks it, and the traffic looks entirely normal, because your own server sent it.
22
24
  *
23
- * 所以 `allowedOrigins` 默认只有 `https://api.spicyapi.ai`,而且是**精确的
24
- * origin 比较**,不是前缀匹配:`https://api.spicyapi.ai.attacker.example`
25
- * 的前缀也是我们的域名。
25
+ * So `allowedOrigins` defaults to `https://api.spicyapi.ai` alone, and the comparison is on the
26
+ * exact origin rather than a prefix: `https://api.spicyapi.ai.attacker.example` starts with our
27
+ * domain too.
26
28
  */
27
- /** 承载目标地址的请求头。全小写,HTTP/2 只接受小写头名。 */
29
+ /** The header carrying the destination. Lower-case throughout, as HTTP/2 accepts nothing else. */
28
30
  export declare const TARGET_URL_HEADER = "x-spicy-target-url";
29
- /** 惯例路由。不是强制的,但保持一致能让前端的配置可以照抄。 */
31
+ /** The conventional route. Not mandatory, but keeping it consistent lets front-end configuration
32
+ * be copied as-is. */
30
33
  export declare const DEFAULT_PROXY_ROUTE = "/api/spicy/proxy";
31
34
  export interface ProxyOptions {
32
35
  /**
33
- * 密钥。缺省从 `SPICY_API_KEY` 读。
36
+ * The API key. Read from `SPICY_API_KEY` by default.
34
37
  *
35
- * 传函数可以支持轮换:每次请求现取,不必重启进程。
38
+ * Passing a function supports rotation: it is consulted on every request, so no restart is
39
+ * needed.
36
40
  */
37
41
  apiKey?: string | (() => string | undefined);
38
- /** 允许转发到的 origin。默认只有生产入口;本地联调时才需要放宽。 */
42
+ /** Origins this proxy may forward to. The production entry point alone by default; only local
43
+ * development needs it widened. */
39
44
  allowedOrigins?: string[];
40
- /** 转发超时。默认 120 秒——媒体任务的提交是快的,慢的是之后的轮询。 */
45
+ /** Forwarding timeout, 120 seconds by default - submitting a media task is fast; what takes time
46
+ * is the polling afterwards. */
41
47
  timeoutMs?: number;
42
- /** 注入 fetch,用于测试。 */
48
+ /** An injected fetch, for tests. */
43
49
  fetch?: typeof fetch;
44
50
  }
45
51
  export declare class ProxyConfigurationError extends Error {
46
52
  constructor(message: string);
47
53
  }
48
- /** 代理判定的结果:要么放行并给出该发的请求,要么拒绝并给出该回的状态。 */
54
+ /** The proxy's decision: either allow, with the request to send, or refuse, with the status to
55
+ * answer. */
49
56
  export type ProxyDecision = {
50
57
  ok: true;
51
58
  request: Request;
@@ -55,16 +62,17 @@ export type ProxyDecision = {
55
62
  message: string;
56
63
  };
57
64
  /**
58
- * 把一条进来的请求判定成「转发什么」或「拒绝」。
65
+ * Turns an incoming request into either "forward this" or "refuse".
59
66
  *
60
- * 这个函数不碰网络,所以各框架适配器共用它,测试也能直接断言判定结果,
61
- * 不必起一个真的 HTTP 服务。
67
+ * This function never touches the network, so every framework adapter shares it and tests can
68
+ * assert on the decision directly without standing up a real HTTP server.
62
69
  */
63
70
  export declare function decide(incoming: Request, options?: ProxyOptions): ProxyDecision;
64
71
  /**
65
- * 通用处理器:吃一条 `Request`,回一条 `Response`。
72
+ * The generic handler: takes a `Request` and returns a `Response`.
66
73
  *
67
- * 各框架适配器只负责把自己的请求对象转成 `Request`,判定与转发都在这里。
74
+ * Framework adapters are responsible only for converting their own request object into a `Request`;
75
+ * the decision and the forwarding both happen here.
68
76
  */
69
77
  export declare function createProxyHandler(options?: ProxyOptions): (incoming: Request) => Promise<Response>;
70
78
  //# sourceMappingURL=core.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,qCAAqC;AACrC,eAAO,MAAM,iBAAiB,uBAAuB,CAAC;AAEtD,mCAAmC;AACnC,eAAO,MAAM,mBAAmB,qBAAqB,CAAC;AA8BtD,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7C,yCAAyC;IACzC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qBAAqB;IACrB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,OAAO,EAAE,MAAM;CAI5B;AAED,yCAAyC;AACzC,MAAM,MAAM,aAAa,GACvB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAkBlF;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAE,YAAiB,GAAG,aAAa,CAgDnF;AAUD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,YAAiB,IAI9B,UAAU,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CAmBnE"}
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,kGAAkG;AAClG,eAAO,MAAM,iBAAiB,uBAAuB,CAAC;AAEtD;sBACsB;AACtB,eAAO,MAAM,mBAAmB,qBAAqB,CAAC;AAgCtD,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7C;uCACmC;IACnC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B;oCACgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,OAAO,EAAE,MAAM;CAI5B;AAED;aACa;AACb,MAAM,MAAM,aAAa,GACvB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAkBlF;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAE,YAAiB,GAAG,aAAa,CAgDnF;AAWD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,YAAiB,IAI9B,UAAU,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CAmBnE"}
package/dist/src/core.js CHANGED
@@ -1,38 +1,42 @@
1
1
  /**
2
- * 服务端代理:让客户端应用在**不持有 API 密钥**的前提下调用 SpicyAPI
2
+ * A server-side proxy that lets client applications call SpicyAPI without ever holding an API key.
3
3
  *
4
- * 浏览器里的 JS、iOS / Android 应用、桌面应用——这些地方都放不住密钥。打进包里的
5
- * 密钥等于公开的密钥:攻击者反编译或抓一次包就能拿到,然后一直花到余额见底,而
6
- * 我们这边看到的只是「这个账号今天用得有点多」。
4
+ * JavaScript in a browser, an iOS or Android app, a desktop app - none of these can keep a secret.
5
+ * A key shipped inside a bundle is a public key: an attacker decompiles it, or captures one
6
+ * request, and then spends until the balance is gone, while all we see on our side is "this account
7
+ * is rather busy today".
7
8
  *
8
- * 正确的形状是:客户端把请求打到**调用方自己的服务器**,由那一层补上密钥再转发。
9
- * 这个模块就是那一层,装在调用方的 Next.js / Express / 任意 fetch 运行时里。
9
+ * The right shape is for the client to call the caller's own server, and for that layer to add the
10
+ * key and forward the request. This module is that layer, mounted inside the caller's Next.js,
11
+ * Express or any other fetch runtime.
10
12
  *
11
- * ── 协议 ───────────────────────────────────────────────────────────
13
+ * ## The protocol
12
14
  *
13
- * 客户端把目标地址放进 `x-spicy-target-url` 头,打到自己后端约定的那条路由
14
- * (惯例是 `/api/spicy/proxy`)。代理校验目标、补上 `Authorization`、转发,
15
- * 再把响应原样回给客户端。
15
+ * The client puts the destination in an `x-spicy-target-url` header and calls whichever route its
16
+ * own backend agreed on (`/api/spicy/proxy` by convention). The proxy validates the target, adds
17
+ * `Authorization`, forwards the request and passes the response straight back.
16
18
  *
17
- * ── 为什么目标地址必须白名单,而不是「转发到头里写的任何地址」 ──────
19
+ * ## Why the destination must be allow-listed rather than "forward to whatever the header says"
18
20
  *
19
- * 这是整个设计里唯一会造成灾难的地方。不校验的话,任何人往那个头里填
20
- * `https://attacker.example` 就能让**你的服务器把你的密钥发给他**——一个
21
- * 请求就泄露,而且流量看起来完全正常:是你自己的服务器发出去的。
21
+ * This is the one place in the design where getting it wrong is catastrophic. Without validation,
22
+ * anyone can put `https://attacker.example` in that header and have your server send them your key
23
+ * - one request leaks it, and the traffic looks entirely normal, because your own server sent it.
22
24
  *
23
- * 所以 `allowedOrigins` 默认只有 `https://api.spicyapi.ai`,而且是**精确的
24
- * origin 比较**,不是前缀匹配:`https://api.spicyapi.ai.attacker.example`
25
- * 的前缀也是我们的域名。
25
+ * So `allowedOrigins` defaults to `https://api.spicyapi.ai` alone, and the comparison is on the
26
+ * exact origin rather than a prefix: `https://api.spicyapi.ai.attacker.example` starts with our
27
+ * domain too.
26
28
  */
27
- /** 承载目标地址的请求头。全小写,HTTP/2 只接受小写头名。 */
29
+ /** The header carrying the destination. Lower-case throughout, as HTTP/2 accepts nothing else. */
28
30
  export const TARGET_URL_HEADER = "x-spicy-target-url";
29
- /** 惯例路由。不是强制的,但保持一致能让前端的配置可以照抄。 */
31
+ /** The conventional route. Not mandatory, but keeping it consistent lets front-end configuration
32
+ * be copied as-is. */
30
33
  export const DEFAULT_PROXY_ROUTE = "/api/spicy/proxy";
31
- /** 平台唯一的生产入口。 */
34
+ /** The platform's only production entry point. */
32
35
  const DEFAULT_ALLOWED_ORIGIN = "https://api.spicyapi.ai";
33
36
  /**
34
- * 逐跳头:它们描述的是**这一段连接**,不是这条消息,转发出去没有意义且可能有害。
35
- * RFC 9110 §7.6.1。`host` 另算——它必须按目标重新计算,照抄会把源站打糊涂。
37
+ * Hop-by-hop headers: they describe this particular connection rather than the message, so
38
+ * forwarding them is meaningless and possibly harmful. See RFC 9110 section 7.6.1. `host` is a
39
+ * separate case - it has to be recomputed for the destination, and copying it confuses the origin.
36
40
  */
37
41
  const HOP_BY_HOP = new Set([
38
42
  "connection",
@@ -47,10 +51,11 @@ const HOP_BY_HOP = new Set([
47
51
  "content-length",
48
52
  ]);
49
53
  /**
50
- * 客户端送来的这些头一律**丢弃**,不允许它影响我们替它做的鉴权决定。
54
+ * These headers are dropped whatever the client sends, so that it cannot influence the
55
+ * authentication decision made on its behalf.
51
56
  *
52
- * `authorization` 尤其要紧:不丢的话,客户端可以自带一个头覆盖掉我们补的那个,
53
- * 把代理变成一个替任意密钥转发的开放中继。
57
+ * `authorization` matters most: without dropping it, a client could supply its own and override the
58
+ * one we add, turning the proxy into an open relay that forwards on behalf of any key at all.
54
59
  */
55
60
  const CLIENT_CONTROLLED = new Set(["authorization", "cookie", "x-api-key"]);
56
61
  export class ProxyConfigurationError extends Error {
@@ -72,10 +77,10 @@ function allowed(options) {
72
77
  return list;
73
78
  }
74
79
  /**
75
- * 把一条进来的请求判定成「转发什么」或「拒绝」。
80
+ * Turns an incoming request into either "forward this" or "refuse".
76
81
  *
77
- * 这个函数不碰网络,所以各框架适配器共用它,测试也能直接断言判定结果,
78
- * 不必起一个真的 HTTP 服务。
82
+ * This function never touches the network, so every framework adapter shares it and tests can
83
+ * assert on the decision directly without standing up a real HTTP server.
79
84
  */
80
85
  export function decide(incoming, options = {}) {
81
86
  const target = incoming.headers.get(TARGET_URL_HEADER);
@@ -89,13 +94,13 @@ export function decide(incoming, options = {}) {
89
94
  catch {
90
95
  return { ok: false, status: 400, message: `${TARGET_URL_HEADER} is not a valid absolute URL` };
91
96
  }
92
- // 精确 origin 比较。前缀匹配会把 https://api.spicyapi.ai.attacker.example 放进来。
97
+ // Exact origin comparison. A prefix match would admit https://api.spicyapi.ai.attacker.example.
93
98
  if (!allowed(options).includes(url.origin)) {
94
99
  return { ok: false, status: 403, message: `target origin is not allowed: ${url.origin}` };
95
100
  }
96
101
  const key = resolveKey(options);
97
102
  if (!key) {
98
- // 这是部署问题,不是调用方的错,所以不要把它说成 4xx
103
+ // This is a deployment problem rather than the caller's mistake, so it must not be a 4xx.
99
104
  return { ok: false, status: 500, message: "the proxy has no SpicyAPI key configured" };
100
105
  }
101
106
  const headers = new Headers();
@@ -116,16 +121,17 @@ export function decide(incoming, options = {}) {
116
121
  method: incoming.method,
117
122
  headers,
118
123
  body: incoming.body,
119
- // 转发的是一条新请求,不该继承调用方的重定向策略。
124
+ // What is forwarded is a new request and must not inherit the caller's redirect policy.
120
125
  redirect: "manual",
121
- // Node undici 要求带流式 body 时显式声明 duplex。它不在标准的
122
- // RequestInit 里,所以单独断言这一小块,而不是把整个字面量断言成
123
- // RequestInit——那样会把上面每个字段的类型检查一起关掉。
126
+ // Node's undici requires duplex to be declared explicitly for a streaming body. It is not
127
+ // part of the standard RequestInit, so only this fragment is asserted rather than the whole
128
+ // literal - asserting the literal would switch off type checking for every field above.
124
129
  ...(incoming.body ? { duplex: "half" } : {}),
125
130
  }),
126
131
  };
127
132
  }
128
- /** 回一条拒绝响应。形状与平台的错误信封一致,客户端不必为代理另写一套解析。 */
133
+ /** Answers with a refusal shaped like the platform's error envelope, so a client needs no separate
134
+ * parsing path for the proxy. */
129
135
  function refuse(status, message) {
130
136
  return new Response(JSON.stringify({ code: status, msg: message, request_id: null }), {
131
137
  status,
@@ -133,9 +139,10 @@ function refuse(status, message) {
133
139
  });
134
140
  }
135
141
  /**
136
- * 通用处理器:吃一条 `Request`,回一条 `Response`。
142
+ * The generic handler: takes a `Request` and returns a `Response`.
137
143
  *
138
- * 各框架适配器只负责把自己的请求对象转成 `Request`,判定与转发都在这里。
144
+ * Framework adapters are responsible only for converting their own request object into a `Request`;
145
+ * the decision and the forwarding both happen here.
139
146
  */
140
147
  export function createProxyHandler(options = {}) {
141
148
  const doFetch = options.fetch ?? globalThis.fetch;
@@ -149,7 +156,7 @@ export function createProxyHandler(options = {}) {
149
156
  upstream = await doFetch(decision.request, { signal: AbortSignal.timeout(timeoutMs) });
150
157
  }
151
158
  catch {
152
- // 不把上游的原始错误回给客户端:它可能带着内部主机名。
159
+ // Do not return the upstream error verbatim: it may carry an internal hostname.
153
160
  return refuse(504, "the upstream request did not complete in time");
154
161
  }
155
162
  const headers = new Headers();
@@ -1 +1 @@
1
- {"version":3,"file":"core.js","sourceRoot":"","sources":["../../src/core.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../../src/core.ts"],"names":[],"mappings":"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"}
@@ -1,16 +1,17 @@
1
1
  /**
2
- * Express 适配器。
2
+ * The Express adapter.
3
3
  *
4
4
  * ```ts
5
5
  * app.all("/api/spicy/proxy", createExpressHandler());
6
6
  * ```
7
7
  *
8
- * Express req/res Node 的流,不是 fetch `Request`/`Response`,
9
- * 所以这一层做的全部事情就是两边互转,判定与转发仍在 core 里。
8
+ * Express req/res are Node streams rather than fetch's `Request` and `Response`, so all this layer
9
+ * does is convert between the two; the decision and the forwarding stay in core.
10
10
  *
11
- * **不要在这条路由前面挂 body 解析中间件**(`express.json()` 之类):那会把
12
- * 请求体读干净,转发出去的就是一条空 body 的请求,而错误发生在上游——表现是
13
- * 「参数缺失」,指不到中间件顺序上。要么把代理挂在解析器之前,要么对这条路径跳过。
11
+ * Do not mount body-parsing middleware ahead of this route (`express.json()` and friends): it
12
+ * consumes the request body, so what gets forwarded is a request with an empty body, and the error
13
+ * surfaces upstream as "missing parameter" - which points nowhere near middleware ordering. Either
14
+ * mount the proxy before the parser, or skip the parser for this path.
14
15
  */
15
16
  import type { IncomingMessage, ServerResponse } from "node:http";
16
17
  import { type ProxyOptions } from "./core.js";
@@ -1 +1 @@
1
- {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/express.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGjE,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAElE,KAAK,WAAW,GAAG,eAAe,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAE9E,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,YAAiB,IAI3D,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,OAAO,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,KAC/B,OAAO,CAAC,IAAI,CAAC,CAmCjB"}
1
+ {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/express.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGjE,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAElE,KAAK,WAAW,GAAG,eAAe,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAE9E,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,YAAiB,IAI3D,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,OAAO,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,KAC/B,OAAO,CAAC,IAAI,CAAC,CAmCjB"}
@@ -1 +1 @@
1
- {"version":3,"file":"express.js","sourceRoot":"","sources":["../../src/express.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,OAAO,EAAE,kBAAkB,EAAqB,MAAM,WAAW,CAAC;AAIlE,MAAM,UAAU,oBAAoB,CAAC,UAAwB,EAAE;IAC7D,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAE3C,OAAO,KAAK,UAAU,UAAU,CAC9B,GAAgB,EAChB,GAAmB,EACnB,IAAgC;QAEhC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;YAC9B,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;gBACxD,IAAI,KAAK,KAAK,SAAS;oBAAE,SAAS;gBAClC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACrE,CAAC;YAED,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC;YAC9D,MAAM,QAAQ,GAAG,MAAM,MAAM,CAC3B,IAAI,OAAO,CAAC,uBAAuB,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,EAAE;gBACtE,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,OAAO;gBACP,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAmB,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACrE,CAAC,CAClB,CAAC;YAEF,GAAG,CAAC,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC;YACjC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;YACtE,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;gBAClB,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CACjC,QAAQ,CAAC,IAA8C,CACxD,CAAC;gBACF,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACvB,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,GAAG,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,IAAI;gBAAE,IAAI,CAAC,KAAK,CAAC,CAAC;iBACjB,CAAC;gBACJ,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;gBACrB,GAAG,CAAC,GAAG,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"express.js","sourceRoot":"","sources":["../../src/express.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,OAAO,EAAE,kBAAkB,EAAqB,MAAM,WAAW,CAAC;AAIlE,MAAM,UAAU,oBAAoB,CAAC,UAAwB,EAAE;IAC7D,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAE3C,OAAO,KAAK,UAAU,UAAU,CAC9B,GAAgB,EAChB,GAAmB,EACnB,IAAgC;QAEhC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;YAC9B,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;gBACxD,IAAI,KAAK,KAAK,SAAS;oBAAE,SAAS;gBAClC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACrE,CAAC;YAED,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC;YAC9D,MAAM,QAAQ,GAAG,MAAM,MAAM,CAC3B,IAAI,OAAO,CAAC,uBAAuB,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,EAAE;gBACtE,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,OAAO;gBACP,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAmB,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACrE,CAAC,CAClB,CAAC;YAEF,GAAG,CAAC,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC;YACjC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;YACtE,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;gBAClB,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CACjC,QAAQ,CAAC,IAA8C,CACxD,CAAC;gBACF,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACvB,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,GAAG,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,IAAI;gBAAE,IAAI,CAAC,KAAK,CAAC,CAAC;iBACjB,CAAC;gBACJ,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;gBACrB,GAAG,CAAC,GAAG,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
@@ -1,20 +1,21 @@
1
1
  /**
2
- * Next.js 适配器。
2
+ * The Next.js adapter.
3
3
  *
4
- * App Router:把 `route` 原样导出成路由的方法处理器即可。
4
+ * App Router: export `route` as the route's method handlers, unchanged.
5
5
  *
6
6
  * ```ts
7
7
  * // app/api/spicy/proxy/route.ts
8
8
  * export const { GET, POST, PUT, DELETE } = route;
9
- * export const runtime = "nodejs"; // 见下
9
+ * export const runtime = "nodejs"; // see below
10
10
  * ```
11
11
  *
12
- * **`runtime` 要显式写 `nodejs`**:边缘运行时读不到 `process.env` 里那些只在
13
- * 服务端配置的值,而密钥恰恰住在那里。默认跑在边缘的项目会在部署之后才发现
14
- * 这一点——那时表现是代理回 500「没有配置密钥」,而本地一切正常。
12
+ * `runtime` must be set to `nodejs` explicitly: the edge runtime cannot read the server-only
13
+ * values in `process.env`, and the key lives precisely there. A project that defaults to the edge
14
+ * discovers this only after deploying - at which point the proxy answers 500 "no key configured"
15
+ * while everything works locally.
15
16
  */
16
17
  import { type ProxyOptions } from "./core.js";
17
- /** App Router:`export const { POST } = route` 就能用。 */
18
+ /** App Router: `export const { POST } = route` is all it takes. */
18
19
  export declare function createRoute(options?: ProxyOptions): {
19
20
  GET: (incoming: Request) => Promise<Response>;
20
21
  POST: (incoming: Request) => Promise<Response>;
@@ -22,7 +23,7 @@ export declare function createRoute(options?: ProxyOptions): {
22
23
  PATCH: (incoming: Request) => Promise<Response>;
23
24
  DELETE: (incoming: Request) => Promise<Response>;
24
25
  };
25
- /** 默认配置的 App Router 路由,密钥取自 `SPICY_API_KEY`。 */
26
+ /** An App Router route with default configuration, taking its key from `SPICY_API_KEY`. */
26
27
  export declare const route: {
27
28
  GET: (incoming: Request) => Promise<Response>;
28
29
  POST: (incoming: Request) => Promise<Response>;
@@ -1 +1 @@
1
- {"version":3,"file":"nextjs.d.ts","sourceRoot":"","sources":["../../src/nextjs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAElE,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,OAAO,GAAE,YAAiB;;;;;;EAGrD;AAED,gDAAgD;AAChD,eAAO,MAAM,KAAK;;;;;;CAAgB,CAAC"}
1
+ {"version":3,"file":"nextjs.d.ts","sourceRoot":"","sources":["../../src/nextjs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAElE,mEAAmE;AACnE,wBAAgB,WAAW,CAAC,OAAO,GAAE,YAAiB;;;;;;EAGrD;AAED,2FAA2F;AAC3F,eAAO,MAAM,KAAK;;;;;;CAAgB,CAAC"}
@@ -1,24 +1,25 @@
1
1
  /**
2
- * Next.js 适配器。
2
+ * The Next.js adapter.
3
3
  *
4
- * App Router:把 `route` 原样导出成路由的方法处理器即可。
4
+ * App Router: export `route` as the route's method handlers, unchanged.
5
5
  *
6
6
  * ```ts
7
7
  * // app/api/spicy/proxy/route.ts
8
8
  * export const { GET, POST, PUT, DELETE } = route;
9
- * export const runtime = "nodejs"; // 见下
9
+ * export const runtime = "nodejs"; // see below
10
10
  * ```
11
11
  *
12
- * **`runtime` 要显式写 `nodejs`**:边缘运行时读不到 `process.env` 里那些只在
13
- * 服务端配置的值,而密钥恰恰住在那里。默认跑在边缘的项目会在部署之后才发现
14
- * 这一点——那时表现是代理回 500「没有配置密钥」,而本地一切正常。
12
+ * `runtime` must be set to `nodejs` explicitly: the edge runtime cannot read the server-only
13
+ * values in `process.env`, and the key lives precisely there. A project that defaults to the edge
14
+ * discovers this only after deploying - at which point the proxy answers 500 "no key configured"
15
+ * while everything works locally.
15
16
  */
16
17
  import { createProxyHandler } from "./core.js";
17
- /** App Router:`export const { POST } = route` 就能用。 */
18
+ /** App Router: `export const { POST } = route` is all it takes. */
18
19
  export function createRoute(options = {}) {
19
20
  const handle = createProxyHandler(options);
20
21
  return { GET: handle, POST: handle, PUT: handle, PATCH: handle, DELETE: handle };
21
22
  }
22
- /** 默认配置的 App Router 路由,密钥取自 `SPICY_API_KEY`。 */
23
+ /** An App Router route with default configuration, taking its key from `SPICY_API_KEY`. */
23
24
  export const route = createRoute();
24
25
  //# sourceMappingURL=nextjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"nextjs.js","sourceRoot":"","sources":["../../src/nextjs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,kBAAkB,EAAqB,MAAM,WAAW,CAAC;AAElE,sDAAsD;AACtD,MAAM,UAAU,WAAW,CAAC,UAAwB,EAAE;IACpD,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC3C,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AACnF,CAAC;AAED,gDAAgD;AAChD,MAAM,CAAC,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC"}
1
+ {"version":3,"file":"nextjs.js","sourceRoot":"","sources":["../../src/nextjs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,kBAAkB,EAAqB,MAAM,WAAW,CAAC;AAElE,mEAAmE;AACnE,MAAM,UAAU,WAAW,CAAC,UAAwB,EAAE;IACpD,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC3C,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AACnF,CAAC;AAED,2FAA2F;AAC3F,MAAM,CAAC,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spicyapi/proxy",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Server-side proxy for SpicyAPI: let browser, mobile and desktop apps call the API without ever holding an API key.",
5
5
  "type": "module",
6
6
  "license": "MIT",