-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinscription-assets-proxy-middleware.js
More file actions
82 lines (82 loc) · 3.81 KB
/
inscription-assets-proxy-middleware.js
File metadata and controls
82 lines (82 loc) · 3.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createInscriptionAssetsProxyMiddleware = void 0;
const https = __importStar(require("https"));
const logger_1 = __importDefault(require("./logger"));
// HACK --- Ordpool: proxy /resources/inscription-assets/* to the SPA host.
//
// The inscription previews generated by ordpool-parser (text-json, text-code,
// audio, video, model, pdf, markdown, ...) emit HTML that loads small CSS/JS
// helpers via relative paths like /resources/inscription-assets/preview-text.css.
// Inside the iframe at api.ordpool.space/preview/<id> these resolve to
// api.ordpool.space/resources/..., but the static assets only live on the SPA
// host (ordpool.space), where Angular ships them as build artifacts. Without
// this proxy the helper scripts 404 and the iframe renders blank.
//
// We stream the assets through the backend over HTTPS rather than 301-redirect
// because module scripts (`<script type="module">`) require CORS allow-origin
// for cross-origin imports, and Cloudflare Pages doesn't set those headers on
// static assets. Streaming keeps the iframe's view of the world same-origin.
//
// All inscription-assets are immutable build outputs; we keep upstream's
// Cache-Control if present, otherwise fill in a long-lived default.
function createInscriptionAssetsProxyMiddleware(spaHost = 'ordpool.space') {
return (req, res, next) => {
if (req.method !== 'GET' && req.method !== 'HEAD') {
return next();
}
const upstreamPath = `/resources/inscription-assets${req.url}`;
const proxyReq = https.request({
host: spaHost,
port: 443,
path: upstreamPath,
method: req.method,
headers: {
'accept': req.headers.accept || '*/*',
'accept-encoding': req.headers['accept-encoding'] || 'identity',
'user-agent': 'ordpool-backend-asset-proxy',
},
}, (upstreamRes) => {
const headers = { ...upstreamRes.headers };
if (!headers['cache-control']) {
headers['cache-control'] = 'public, max-age=86400, immutable';
}
res.writeHead(upstreamRes.statusCode || 502, headers);
upstreamRes.pipe(res);
});
proxyReq.on('error', (err) => {
logger_1.default.warn(`inscription-assets proxy error for ${req.method} ${upstreamPath}: ${err.message}`);
if (!res.headersSent) {
res.status(502).send('inscription-assets proxy error');
}
});
proxyReq.end();
};
}
exports.createInscriptionAssetsProxyMiddleware = createInscriptionAssetsProxyMiddleware;