@meddleware/nft-gate-gateway 0.0.3 → 0.0.4
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.
- package/package.json +2 -2
- package/src/cors.ts +38 -0
- package/src/index.ts +7 -1
- package/wrangler.toml +5 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
2
|
"name": "@meddleware/nft-gate-gateway",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Cloudflare Workers implementation of the nft-gate gateway: a wire-identical, drop-in sibling of the Rust gateway that gates any HTTP upstream behind an access_gate NFT.",
|
|
6
6
|
"license": "0BSD",
|
package/src/cors.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CORS utilities for the nft-gate Cloudflare Worker.
|
|
3
|
+
*
|
|
4
|
+
* The Worker is accessed from browser origins (e.g. sui-walrus.meddleware.co.uk,
|
|
5
|
+
* sui.meddleware.co.uk) that differ from the Worker's own hostname. Without
|
|
6
|
+
* Access-Control-Allow-Origin headers the browser blocks the response even when
|
|
7
|
+
* the Worker returns 200, and OPTIONS preflights (required before non-simple requests
|
|
8
|
+
* such as PUT uploads with an Authorization header) receive no preflight grant.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const CORS_HEADERS: Record<string, string> = {
|
|
12
|
+
'access-control-allow-origin': '*',
|
|
13
|
+
'access-control-allow-methods': 'GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS',
|
|
14
|
+
'access-control-allow-headers': 'authorization, content-type, x-access-proof',
|
|
15
|
+
'access-control-expose-headers': 'location, upload-offset',
|
|
16
|
+
'access-control-max-age': '86400',
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Clone `res` and add CORS headers. Using `set()` so calling this on an upstream
|
|
21
|
+
* response that already carries CORS headers just overwrites them consistently.
|
|
22
|
+
*/
|
|
23
|
+
export function withCors(res: Response): Response {
|
|
24
|
+
const out = new Response(res.body, res)
|
|
25
|
+
for (const [k, v] of Object.entries(CORS_HEADERS)) {
|
|
26
|
+
out.headers.set(k, v)
|
|
27
|
+
}
|
|
28
|
+
return out
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Return a minimal 204 preflight response for OPTIONS requests.
|
|
33
|
+
* The browser requires this before sending non-simple cross-origin requests
|
|
34
|
+
* (e.g. PUT/POST with Authorization or Content-Type).
|
|
35
|
+
*/
|
|
36
|
+
export function corsPreflightResponse(): Response {
|
|
37
|
+
return new Response(null, { status: 204, headers: CORS_HEADERS })
|
|
38
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { SuiRpc } from './chain.js'
|
|
|
15
15
|
import { verifyAccessRequest, deniedReason } from './verify.js'
|
|
16
16
|
import { forward } from './proxy.js'
|
|
17
17
|
import { runQuotaGuard } from './quota.js'
|
|
18
|
+
import { withCors, corsPreflightResponse } from './cors.js'
|
|
18
19
|
|
|
19
20
|
export { NonceRateState } from './state/durable_object.js'
|
|
20
21
|
|
|
@@ -124,6 +125,11 @@ async function handle(request: Request, env: Env): Promise<Response> {
|
|
|
124
125
|
|
|
125
126
|
if (path === '/healthz') return new Response('ok', { status: 200 })
|
|
126
127
|
|
|
128
|
+
// Handle CORS preflight before any auth check. The browser sends OPTIONS before
|
|
129
|
+
// non-simple cross-origin requests (e.g. PUT/POST with Authorization); responding
|
|
130
|
+
// here avoids the auth path returning 401 and causing the browser to abort.
|
|
131
|
+
if (request.method === 'OPTIONS') return corsPreflightResponse()
|
|
132
|
+
|
|
127
133
|
let state: GatewayState
|
|
128
134
|
try {
|
|
129
135
|
state = await getState(env)
|
|
@@ -163,7 +169,7 @@ async function handle(request: Request, env: Env): Promise<Response> {
|
|
|
163
169
|
*/
|
|
164
170
|
export default {
|
|
165
171
|
fetch(request: Request, env: Env): Promise<Response> {
|
|
166
|
-
return handle(request, env)
|
|
172
|
+
return handle(request, env).then(withCors)
|
|
167
173
|
},
|
|
168
174
|
async scheduled(_controller: ScheduledController, env: Env): Promise<void> {
|
|
169
175
|
if ((env.QUOTA_GUARD_ENABLED ?? 'false').toLowerCase() === 'true') {
|
package/wrangler.toml
CHANGED
|
@@ -73,10 +73,11 @@ new_sqlite_classes = ["NonceRateState"]
|
|
|
73
73
|
# id = "<KV_NAMESPACE_ID>" # create with: wrangler kv namespace create NONCE_KV
|
|
74
74
|
|
|
75
75
|
# ── route: Worker serves as the public NFT-gated relay endpoint ───────────────────────────────
|
|
76
|
-
#
|
|
77
|
-
#
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
# Configured via CF API (route ID 63427e4dbf9b4428ad9c492487953551).
|
|
77
|
+
# wrangler deploy will create/update this automatically.
|
|
78
|
+
[[routes]]
|
|
79
|
+
pattern = "sui-walrus-relay-testnet.meddleware.co.uk/*"
|
|
80
|
+
zone_name = "meddleware.co.uk"
|
|
80
81
|
|
|
81
82
|
# ── optional quota guard (needs QUOTA_GUARD_ENABLED=true + the secrets above) ────────────────
|
|
82
83
|
# [triggers]
|