@objectstack/runtime 7.1.0 → 7.2.0
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/dist/index.cjs +160 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +160 -13
- package/dist/index.js.map +1 -1
- package/package.json +18 -18
package/dist/index.cjs
CHANGED
|
@@ -8475,6 +8475,36 @@ function resolveCloudUrl(explicit) {
|
|
|
8475
8475
|
return picked.replace(/\/+$/, "");
|
|
8476
8476
|
}
|
|
8477
8477
|
|
|
8478
|
+
// src/cloud/marketplace-public-url.ts
|
|
8479
|
+
function resolveMarketplacePublicBaseUrl(explicit) {
|
|
8480
|
+
const raw = (explicit ?? process.env.OS_MARKETPLACE_PUBLIC_BASE_URL ?? "").trim();
|
|
8481
|
+
const lower = raw.toLowerCase();
|
|
8482
|
+
if (!raw || lower === "off" || lower === "none" || lower === "disabled" || lower === "false") {
|
|
8483
|
+
return "";
|
|
8484
|
+
}
|
|
8485
|
+
return raw.replace(/\/+$/, "");
|
|
8486
|
+
}
|
|
8487
|
+
function publicMarketplaceKeyForApiPath(pathname) {
|
|
8488
|
+
const prefix = "/api/v1/marketplace/packages";
|
|
8489
|
+
if (pathname === prefix) return "packages.json";
|
|
8490
|
+
if (!pathname.startsWith(`${prefix}/`)) return null;
|
|
8491
|
+
const tail = pathname.slice(prefix.length + 1);
|
|
8492
|
+
if (!tail) return null;
|
|
8493
|
+
const parts = tail.split("/");
|
|
8494
|
+
if (parts.length === 1) {
|
|
8495
|
+
const id = decodeURIComponent(parts[0] ?? "");
|
|
8496
|
+
if (!id) return null;
|
|
8497
|
+
return `packages/${encodeURIComponent(id)}.json`;
|
|
8498
|
+
}
|
|
8499
|
+
if (parts.length === 4 && parts[1] === "versions" && parts[3] === "manifest") {
|
|
8500
|
+
const id = decodeURIComponent(parts[0] ?? "");
|
|
8501
|
+
const versionId = decodeURIComponent(parts[2] ?? "");
|
|
8502
|
+
if (!id || !versionId) return null;
|
|
8503
|
+
return `packages/${encodeURIComponent(id)}/versions/${encodeURIComponent(versionId)}/manifest.json`;
|
|
8504
|
+
}
|
|
8505
|
+
return null;
|
|
8506
|
+
}
|
|
8507
|
+
|
|
8478
8508
|
// src/cloud/marketplace-proxy-plugin.ts
|
|
8479
8509
|
var MARKETPLACE_PREFIX = "/api/v1/marketplace";
|
|
8480
8510
|
var DEFAULT_LRU_MAX = 200;
|
|
@@ -8514,7 +8544,7 @@ var LruTtlCache = class {
|
|
|
8514
8544
|
var MarketplaceProxyPlugin = class _MarketplaceProxyPlugin {
|
|
8515
8545
|
constructor(config = {}) {
|
|
8516
8546
|
this.name = "com.objectstack.runtime.marketplace-proxy";
|
|
8517
|
-
this.version = "1.
|
|
8547
|
+
this.version = "1.1.0";
|
|
8518
8548
|
this.init = async (_ctx) => {
|
|
8519
8549
|
};
|
|
8520
8550
|
this.start = async (ctx) => {
|
|
@@ -8532,7 +8562,11 @@ var MarketplaceProxyPlugin = class _MarketplaceProxyPlugin {
|
|
|
8532
8562
|
}
|
|
8533
8563
|
const rawApp = httpServer.getRawApp();
|
|
8534
8564
|
const cloudUrl = this.cloudUrl;
|
|
8565
|
+
const publicBaseUrl = this.publicBaseUrl;
|
|
8535
8566
|
const cache = this.cache;
|
|
8567
|
+
if (publicBaseUrl) {
|
|
8568
|
+
ctx.logger?.info?.(`[MarketplaceProxyPlugin] public R2 fast-path enabled \u2192 ${publicBaseUrl}`);
|
|
8569
|
+
}
|
|
8536
8570
|
const handler = async (c, next) => {
|
|
8537
8571
|
if (!cloudUrl) {
|
|
8538
8572
|
return c.json({
|
|
@@ -8548,8 +8582,18 @@ var MarketplaceProxyPlugin = class _MarketplaceProxyPlugin {
|
|
|
8548
8582
|
if (incomingUrl.pathname.startsWith(`${MARKETPLACE_PREFIX}/install-local`)) {
|
|
8549
8583
|
return next();
|
|
8550
8584
|
}
|
|
8551
|
-
const target = `${cloudUrl}${incomingUrl.pathname}${incomingUrl.search}`;
|
|
8552
8585
|
const method = String(c.req.method ?? "GET").toUpperCase();
|
|
8586
|
+
if (publicBaseUrl && (method === "GET" || method === "HEAD")) {
|
|
8587
|
+
const r2Resp = await tryPublicMarketplaceFetch(
|
|
8588
|
+
publicBaseUrl,
|
|
8589
|
+
incomingUrl,
|
|
8590
|
+
method,
|
|
8591
|
+
c.req.header("accept"),
|
|
8592
|
+
ctx.logger
|
|
8593
|
+
);
|
|
8594
|
+
if (r2Resp) return r2Resp;
|
|
8595
|
+
}
|
|
8596
|
+
const target = `${cloudUrl}${incomingUrl.pathname}${incomingUrl.search}`;
|
|
8553
8597
|
if (method !== "GET" && method !== "HEAD") {
|
|
8554
8598
|
return c.json({
|
|
8555
8599
|
success: false,
|
|
@@ -8630,12 +8674,82 @@ var MarketplaceProxyPlugin = class _MarketplaceProxyPlugin {
|
|
|
8630
8674
|
});
|
|
8631
8675
|
};
|
|
8632
8676
|
this.cloudUrl = resolveCloudUrl(config.controlPlaneUrl);
|
|
8677
|
+
this.publicBaseUrl = resolveMarketplacePublicBaseUrl(config.publicMarketplaceBaseUrl);
|
|
8633
8678
|
const envFlag = (process.env.OS_MARKETPLACE_CACHE ?? "").trim().toLowerCase();
|
|
8634
8679
|
const envDisabled = ["off", "false", "0", "no", "disable", "disabled"].includes(envFlag);
|
|
8635
8680
|
const disabled = config.cacheDisabled ?? envDisabled;
|
|
8636
8681
|
this.cache = disabled ? null : new LruTtlCache(Math.max(8, config.cacheMaxEntries ?? DEFAULT_LRU_MAX));
|
|
8637
8682
|
}
|
|
8638
8683
|
};
|
|
8684
|
+
async function tryPublicMarketplaceFetch(publicBaseUrl, incomingUrl, method, acceptHeader, logger) {
|
|
8685
|
+
const key = publicMarketplaceKeyForApiPath(incomingUrl.pathname);
|
|
8686
|
+
if (!key) return null;
|
|
8687
|
+
const target = `${publicBaseUrl}/${key}`;
|
|
8688
|
+
let resp;
|
|
8689
|
+
try {
|
|
8690
|
+
resp = await fetch(target, {
|
|
8691
|
+
method: "GET",
|
|
8692
|
+
headers: {
|
|
8693
|
+
"Accept": acceptHeader || "application/json",
|
|
8694
|
+
"User-Agent": `objectos-marketplace-proxy/public-r2`
|
|
8695
|
+
}
|
|
8696
|
+
});
|
|
8697
|
+
} catch (err) {
|
|
8698
|
+
logger?.warn?.(`[MarketplaceProxyPlugin] public R2 fetch failed (${target}): ${err?.message ?? err}`);
|
|
8699
|
+
return null;
|
|
8700
|
+
}
|
|
8701
|
+
if (resp.status === 404) return null;
|
|
8702
|
+
if (!resp.ok) {
|
|
8703
|
+
logger?.warn?.(`[MarketplaceProxyPlugin] public R2 ${target} returned ${resp.status} \u2014 falling back to cloud`);
|
|
8704
|
+
return null;
|
|
8705
|
+
}
|
|
8706
|
+
const isList = key === "packages.json";
|
|
8707
|
+
const hasFilters = isList && (incomingUrl.searchParams.has("q") || incomingUrl.searchParams.has("category") || incomingUrl.searchParams.has("limit") || incomingUrl.searchParams.has("offset"));
|
|
8708
|
+
if (!hasFilters) {
|
|
8709
|
+
const headers2 = new Headers();
|
|
8710
|
+
const ct = resp.headers.get("content-type") ?? "application/json; charset=utf-8";
|
|
8711
|
+
headers2.set("content-type", ct);
|
|
8712
|
+
const cc = resp.headers.get("cache-control");
|
|
8713
|
+
if (cc) headers2.set("cache-control", cc);
|
|
8714
|
+
const etag = resp.headers.get("etag");
|
|
8715
|
+
if (etag) headers2.set("etag", etag);
|
|
8716
|
+
headers2.set("x-cache", "PUBLIC-R2");
|
|
8717
|
+
const body2 = method === "HEAD" ? null : resp.body;
|
|
8718
|
+
return new Response(body2, { status: 200, headers: headers2 });
|
|
8719
|
+
}
|
|
8720
|
+
let snapshot;
|
|
8721
|
+
try {
|
|
8722
|
+
snapshot = await resp.json();
|
|
8723
|
+
} catch (err) {
|
|
8724
|
+
logger?.warn?.(`[MarketplaceProxyPlugin] public R2 list snapshot parse failed: ${err?.message ?? err}`);
|
|
8725
|
+
return null;
|
|
8726
|
+
}
|
|
8727
|
+
const items = Array.isArray(snapshot?.data?.items) ? snapshot.data.items : [];
|
|
8728
|
+
const q = (incomingUrl.searchParams.get("q") ?? "").trim().toLowerCase();
|
|
8729
|
+
const category = (incomingUrl.searchParams.get("category") ?? "").trim();
|
|
8730
|
+
const limit = Math.min(Math.max(Number(incomingUrl.searchParams.get("limit") ?? 50), 1), 100);
|
|
8731
|
+
const offset = Math.max(Number(incomingUrl.searchParams.get("offset") ?? 0), 0);
|
|
8732
|
+
let filtered = items;
|
|
8733
|
+
if (q) {
|
|
8734
|
+
filtered = filtered.filter((r) => {
|
|
8735
|
+
const dn = String(r?.display_name ?? "").toLowerCase();
|
|
8736
|
+
const mid = String(r?.manifest_id ?? "").toLowerCase();
|
|
8737
|
+
return dn.includes(q) || mid.includes(q);
|
|
8738
|
+
});
|
|
8739
|
+
}
|
|
8740
|
+
if (category) {
|
|
8741
|
+
filtered = filtered.filter((r) => String(r?.category ?? "") === category);
|
|
8742
|
+
}
|
|
8743
|
+
const total = filtered.length;
|
|
8744
|
+
const page = filtered.slice(offset, offset + limit);
|
|
8745
|
+
const body = JSON.stringify({ success: true, data: { items: page, total, limit, offset } });
|
|
8746
|
+
const headers = new Headers({
|
|
8747
|
+
"content-type": "application/json; charset=utf-8",
|
|
8748
|
+
"cache-control": "public, max-age=30",
|
|
8749
|
+
"x-cache": "PUBLIC-R2-FILTERED"
|
|
8750
|
+
});
|
|
8751
|
+
return new Response(method === "HEAD" ? null : body, { status: 200, headers });
|
|
8752
|
+
}
|
|
8639
8753
|
var PASSTHROUGH_HEADERS = ["content-type", "cache-control", "etag", "last-modified", "vary"];
|
|
8640
8754
|
function collectHeaders(src) {
|
|
8641
8755
|
const out = {};
|
|
@@ -9119,22 +9233,55 @@ var MarketplaceInstallLocalPlugin = class {
|
|
|
9119
9233
|
return c.json({ success: false, error: { code: "bad_request", message: "packageId is required." } }, 400);
|
|
9120
9234
|
}
|
|
9121
9235
|
let payload;
|
|
9122
|
-
|
|
9123
|
-
|
|
9124
|
-
|
|
9125
|
-
|
|
9126
|
-
|
|
9236
|
+
const publicBase = resolveMarketplacePublicBaseUrl();
|
|
9237
|
+
const fetchAttempts = [];
|
|
9238
|
+
if (publicBase) {
|
|
9239
|
+
fetchAttempts.push({
|
|
9240
|
+
label: "public-r2",
|
|
9241
|
+
url: `${publicBase}/packages/${encodeURIComponent(packageId)}/versions/${encodeURIComponent(versionId)}/manifest.json`
|
|
9242
|
+
});
|
|
9243
|
+
}
|
|
9244
|
+
fetchAttempts.push({
|
|
9245
|
+
label: "cloud",
|
|
9246
|
+
url: `${this.cloudUrl}/api/v1/marketplace/packages/${encodeURIComponent(packageId)}/versions/${encodeURIComponent(versionId)}/manifest`
|
|
9247
|
+
});
|
|
9248
|
+
let lastErrStatus = 0;
|
|
9249
|
+
let lastErrText = "";
|
|
9250
|
+
for (const attempt of fetchAttempts) {
|
|
9251
|
+
try {
|
|
9252
|
+
const resp = await fetch(attempt.url, { headers: { "Accept": "application/json" } });
|
|
9253
|
+
if (!resp.ok) {
|
|
9254
|
+
lastErrStatus = resp.status;
|
|
9255
|
+
lastErrText = (await resp.text().catch(() => "")).slice(0, 200);
|
|
9256
|
+
if (attempt.label === "public-r2" && resp.status === 404) {
|
|
9257
|
+
ctx.logger?.info?.(`[MarketplaceInstallLocal] public-r2 miss for ${packageId}@${versionId}, falling back to cloud`);
|
|
9258
|
+
continue;
|
|
9259
|
+
}
|
|
9260
|
+
if (attempt.label === "public-r2" && resp.status >= 500) {
|
|
9261
|
+
ctx.logger?.warn?.(`[MarketplaceInstallLocal] public-r2 ${resp.status}, falling back to cloud`);
|
|
9262
|
+
continue;
|
|
9263
|
+
}
|
|
9264
|
+
break;
|
|
9265
|
+
}
|
|
9266
|
+
payload = await resp.json();
|
|
9267
|
+
lastErrStatus = 0;
|
|
9268
|
+
break;
|
|
9269
|
+
} catch (err) {
|
|
9270
|
+
if (attempt.label === "public-r2") {
|
|
9271
|
+
ctx.logger?.warn?.(`[MarketplaceInstallLocal] public-r2 fetch error: ${err?.message ?? err}, falling back to cloud`);
|
|
9272
|
+
continue;
|
|
9273
|
+
}
|
|
9127
9274
|
return c.json({
|
|
9128
9275
|
success: false,
|
|
9129
|
-
error: { code: "cloud_fetch_failed", message:
|
|
9130
|
-
},
|
|
9276
|
+
error: { code: "cloud_fetch_failed", message: err?.message ?? String(err) }
|
|
9277
|
+
}, 502);
|
|
9131
9278
|
}
|
|
9132
|
-
|
|
9133
|
-
|
|
9279
|
+
}
|
|
9280
|
+
if (!payload) {
|
|
9134
9281
|
return c.json({
|
|
9135
9282
|
success: false,
|
|
9136
|
-
error: { code: "cloud_fetch_failed", message:
|
|
9137
|
-
}, 502);
|
|
9283
|
+
error: { code: "cloud_fetch_failed", message: `Cloud returned ${lastErrStatus}: ${lastErrText}` }
|
|
9284
|
+
}, lastErrStatus === 404 ? 404 : 502);
|
|
9138
9285
|
}
|
|
9139
9286
|
const data = payload?.data ?? payload;
|
|
9140
9287
|
const manifest = data?.manifest;
|