@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.d.cts
CHANGED
|
@@ -1940,11 +1940,21 @@ interface MarketplaceProxyPluginConfig {
|
|
|
1940
1940
|
* Override the LRU upper bound. Defaults to 200 entries.
|
|
1941
1941
|
*/
|
|
1942
1942
|
cacheMaxEntries?: number;
|
|
1943
|
+
/**
|
|
1944
|
+
* Public R2 base URL for marketplace snapshots. When set, GETs for
|
|
1945
|
+
* snapshot-backed paths (`/packages`, `/packages/:id`,
|
|
1946
|
+
* `/packages/:id/versions/:vid/manifest`) are fetched directly from
|
|
1947
|
+
* R2 (CF edge) — bypassing the cloud control plane entirely.
|
|
1948
|
+
* Defaults to the value of OS_MARKETPLACE_PUBLIC_BASE_URL. Empty
|
|
1949
|
+
* string disables the public fast-path (legacy cloud-proxy only).
|
|
1950
|
+
*/
|
|
1951
|
+
publicMarketplaceBaseUrl?: string;
|
|
1943
1952
|
}
|
|
1944
1953
|
declare class MarketplaceProxyPlugin implements Plugin {
|
|
1945
1954
|
readonly name = "com.objectstack.runtime.marketplace-proxy";
|
|
1946
|
-
readonly version = "1.
|
|
1955
|
+
readonly version = "1.1.0";
|
|
1947
1956
|
private readonly cloudUrl;
|
|
1957
|
+
private readonly publicBaseUrl;
|
|
1948
1958
|
private readonly cache;
|
|
1949
1959
|
constructor(config?: MarketplaceProxyPluginConfig);
|
|
1950
1960
|
init: (_ctx: PluginContext) => Promise<void>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1940,11 +1940,21 @@ interface MarketplaceProxyPluginConfig {
|
|
|
1940
1940
|
* Override the LRU upper bound. Defaults to 200 entries.
|
|
1941
1941
|
*/
|
|
1942
1942
|
cacheMaxEntries?: number;
|
|
1943
|
+
/**
|
|
1944
|
+
* Public R2 base URL for marketplace snapshots. When set, GETs for
|
|
1945
|
+
* snapshot-backed paths (`/packages`, `/packages/:id`,
|
|
1946
|
+
* `/packages/:id/versions/:vid/manifest`) are fetched directly from
|
|
1947
|
+
* R2 (CF edge) — bypassing the cloud control plane entirely.
|
|
1948
|
+
* Defaults to the value of OS_MARKETPLACE_PUBLIC_BASE_URL. Empty
|
|
1949
|
+
* string disables the public fast-path (legacy cloud-proxy only).
|
|
1950
|
+
*/
|
|
1951
|
+
publicMarketplaceBaseUrl?: string;
|
|
1943
1952
|
}
|
|
1944
1953
|
declare class MarketplaceProxyPlugin implements Plugin {
|
|
1945
1954
|
readonly name = "com.objectstack.runtime.marketplace-proxy";
|
|
1946
|
-
readonly version = "1.
|
|
1955
|
+
readonly version = "1.1.0";
|
|
1947
1956
|
private readonly cloudUrl;
|
|
1957
|
+
private readonly publicBaseUrl;
|
|
1948
1958
|
private readonly cache;
|
|
1949
1959
|
constructor(config?: MarketplaceProxyPluginConfig);
|
|
1950
1960
|
init: (_ctx: PluginContext) => Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -8394,6 +8394,36 @@ function resolveCloudUrl(explicit) {
|
|
|
8394
8394
|
return picked.replace(/\/+$/, "");
|
|
8395
8395
|
}
|
|
8396
8396
|
|
|
8397
|
+
// src/cloud/marketplace-public-url.ts
|
|
8398
|
+
function resolveMarketplacePublicBaseUrl(explicit) {
|
|
8399
|
+
const raw = (explicit ?? process.env.OS_MARKETPLACE_PUBLIC_BASE_URL ?? "").trim();
|
|
8400
|
+
const lower = raw.toLowerCase();
|
|
8401
|
+
if (!raw || lower === "off" || lower === "none" || lower === "disabled" || lower === "false") {
|
|
8402
|
+
return "";
|
|
8403
|
+
}
|
|
8404
|
+
return raw.replace(/\/+$/, "");
|
|
8405
|
+
}
|
|
8406
|
+
function publicMarketplaceKeyForApiPath(pathname) {
|
|
8407
|
+
const prefix = "/api/v1/marketplace/packages";
|
|
8408
|
+
if (pathname === prefix) return "packages.json";
|
|
8409
|
+
if (!pathname.startsWith(`${prefix}/`)) return null;
|
|
8410
|
+
const tail = pathname.slice(prefix.length + 1);
|
|
8411
|
+
if (!tail) return null;
|
|
8412
|
+
const parts = tail.split("/");
|
|
8413
|
+
if (parts.length === 1) {
|
|
8414
|
+
const id = decodeURIComponent(parts[0] ?? "");
|
|
8415
|
+
if (!id) return null;
|
|
8416
|
+
return `packages/${encodeURIComponent(id)}.json`;
|
|
8417
|
+
}
|
|
8418
|
+
if (parts.length === 4 && parts[1] === "versions" && parts[3] === "manifest") {
|
|
8419
|
+
const id = decodeURIComponent(parts[0] ?? "");
|
|
8420
|
+
const versionId = decodeURIComponent(parts[2] ?? "");
|
|
8421
|
+
if (!id || !versionId) return null;
|
|
8422
|
+
return `packages/${encodeURIComponent(id)}/versions/${encodeURIComponent(versionId)}/manifest.json`;
|
|
8423
|
+
}
|
|
8424
|
+
return null;
|
|
8425
|
+
}
|
|
8426
|
+
|
|
8397
8427
|
// src/cloud/marketplace-proxy-plugin.ts
|
|
8398
8428
|
var MARKETPLACE_PREFIX = "/api/v1/marketplace";
|
|
8399
8429
|
var DEFAULT_LRU_MAX = 200;
|
|
@@ -8433,7 +8463,7 @@ var LruTtlCache = class {
|
|
|
8433
8463
|
var MarketplaceProxyPlugin = class _MarketplaceProxyPlugin {
|
|
8434
8464
|
constructor(config = {}) {
|
|
8435
8465
|
this.name = "com.objectstack.runtime.marketplace-proxy";
|
|
8436
|
-
this.version = "1.
|
|
8466
|
+
this.version = "1.1.0";
|
|
8437
8467
|
this.init = async (_ctx) => {
|
|
8438
8468
|
};
|
|
8439
8469
|
this.start = async (ctx) => {
|
|
@@ -8451,7 +8481,11 @@ var MarketplaceProxyPlugin = class _MarketplaceProxyPlugin {
|
|
|
8451
8481
|
}
|
|
8452
8482
|
const rawApp = httpServer.getRawApp();
|
|
8453
8483
|
const cloudUrl = this.cloudUrl;
|
|
8484
|
+
const publicBaseUrl = this.publicBaseUrl;
|
|
8454
8485
|
const cache = this.cache;
|
|
8486
|
+
if (publicBaseUrl) {
|
|
8487
|
+
ctx.logger?.info?.(`[MarketplaceProxyPlugin] public R2 fast-path enabled \u2192 ${publicBaseUrl}`);
|
|
8488
|
+
}
|
|
8455
8489
|
const handler = async (c, next) => {
|
|
8456
8490
|
if (!cloudUrl) {
|
|
8457
8491
|
return c.json({
|
|
@@ -8467,8 +8501,18 @@ var MarketplaceProxyPlugin = class _MarketplaceProxyPlugin {
|
|
|
8467
8501
|
if (incomingUrl.pathname.startsWith(`${MARKETPLACE_PREFIX}/install-local`)) {
|
|
8468
8502
|
return next();
|
|
8469
8503
|
}
|
|
8470
|
-
const target = `${cloudUrl}${incomingUrl.pathname}${incomingUrl.search}`;
|
|
8471
8504
|
const method = String(c.req.method ?? "GET").toUpperCase();
|
|
8505
|
+
if (publicBaseUrl && (method === "GET" || method === "HEAD")) {
|
|
8506
|
+
const r2Resp = await tryPublicMarketplaceFetch(
|
|
8507
|
+
publicBaseUrl,
|
|
8508
|
+
incomingUrl,
|
|
8509
|
+
method,
|
|
8510
|
+
c.req.header("accept"),
|
|
8511
|
+
ctx.logger
|
|
8512
|
+
);
|
|
8513
|
+
if (r2Resp) return r2Resp;
|
|
8514
|
+
}
|
|
8515
|
+
const target = `${cloudUrl}${incomingUrl.pathname}${incomingUrl.search}`;
|
|
8472
8516
|
if (method !== "GET" && method !== "HEAD") {
|
|
8473
8517
|
return c.json({
|
|
8474
8518
|
success: false,
|
|
@@ -8549,12 +8593,82 @@ var MarketplaceProxyPlugin = class _MarketplaceProxyPlugin {
|
|
|
8549
8593
|
});
|
|
8550
8594
|
};
|
|
8551
8595
|
this.cloudUrl = resolveCloudUrl(config.controlPlaneUrl);
|
|
8596
|
+
this.publicBaseUrl = resolveMarketplacePublicBaseUrl(config.publicMarketplaceBaseUrl);
|
|
8552
8597
|
const envFlag = (process.env.OS_MARKETPLACE_CACHE ?? "").trim().toLowerCase();
|
|
8553
8598
|
const envDisabled = ["off", "false", "0", "no", "disable", "disabled"].includes(envFlag);
|
|
8554
8599
|
const disabled = config.cacheDisabled ?? envDisabled;
|
|
8555
8600
|
this.cache = disabled ? null : new LruTtlCache(Math.max(8, config.cacheMaxEntries ?? DEFAULT_LRU_MAX));
|
|
8556
8601
|
}
|
|
8557
8602
|
};
|
|
8603
|
+
async function tryPublicMarketplaceFetch(publicBaseUrl, incomingUrl, method, acceptHeader, logger) {
|
|
8604
|
+
const key = publicMarketplaceKeyForApiPath(incomingUrl.pathname);
|
|
8605
|
+
if (!key) return null;
|
|
8606
|
+
const target = `${publicBaseUrl}/${key}`;
|
|
8607
|
+
let resp;
|
|
8608
|
+
try {
|
|
8609
|
+
resp = await fetch(target, {
|
|
8610
|
+
method: "GET",
|
|
8611
|
+
headers: {
|
|
8612
|
+
"Accept": acceptHeader || "application/json",
|
|
8613
|
+
"User-Agent": `objectos-marketplace-proxy/public-r2`
|
|
8614
|
+
}
|
|
8615
|
+
});
|
|
8616
|
+
} catch (err) {
|
|
8617
|
+
logger?.warn?.(`[MarketplaceProxyPlugin] public R2 fetch failed (${target}): ${err?.message ?? err}`);
|
|
8618
|
+
return null;
|
|
8619
|
+
}
|
|
8620
|
+
if (resp.status === 404) return null;
|
|
8621
|
+
if (!resp.ok) {
|
|
8622
|
+
logger?.warn?.(`[MarketplaceProxyPlugin] public R2 ${target} returned ${resp.status} \u2014 falling back to cloud`);
|
|
8623
|
+
return null;
|
|
8624
|
+
}
|
|
8625
|
+
const isList = key === "packages.json";
|
|
8626
|
+
const hasFilters = isList && (incomingUrl.searchParams.has("q") || incomingUrl.searchParams.has("category") || incomingUrl.searchParams.has("limit") || incomingUrl.searchParams.has("offset"));
|
|
8627
|
+
if (!hasFilters) {
|
|
8628
|
+
const headers2 = new Headers();
|
|
8629
|
+
const ct = resp.headers.get("content-type") ?? "application/json; charset=utf-8";
|
|
8630
|
+
headers2.set("content-type", ct);
|
|
8631
|
+
const cc = resp.headers.get("cache-control");
|
|
8632
|
+
if (cc) headers2.set("cache-control", cc);
|
|
8633
|
+
const etag = resp.headers.get("etag");
|
|
8634
|
+
if (etag) headers2.set("etag", etag);
|
|
8635
|
+
headers2.set("x-cache", "PUBLIC-R2");
|
|
8636
|
+
const body2 = method === "HEAD" ? null : resp.body;
|
|
8637
|
+
return new Response(body2, { status: 200, headers: headers2 });
|
|
8638
|
+
}
|
|
8639
|
+
let snapshot;
|
|
8640
|
+
try {
|
|
8641
|
+
snapshot = await resp.json();
|
|
8642
|
+
} catch (err) {
|
|
8643
|
+
logger?.warn?.(`[MarketplaceProxyPlugin] public R2 list snapshot parse failed: ${err?.message ?? err}`);
|
|
8644
|
+
return null;
|
|
8645
|
+
}
|
|
8646
|
+
const items = Array.isArray(snapshot?.data?.items) ? snapshot.data.items : [];
|
|
8647
|
+
const q = (incomingUrl.searchParams.get("q") ?? "").trim().toLowerCase();
|
|
8648
|
+
const category = (incomingUrl.searchParams.get("category") ?? "").trim();
|
|
8649
|
+
const limit = Math.min(Math.max(Number(incomingUrl.searchParams.get("limit") ?? 50), 1), 100);
|
|
8650
|
+
const offset = Math.max(Number(incomingUrl.searchParams.get("offset") ?? 0), 0);
|
|
8651
|
+
let filtered = items;
|
|
8652
|
+
if (q) {
|
|
8653
|
+
filtered = filtered.filter((r) => {
|
|
8654
|
+
const dn = String(r?.display_name ?? "").toLowerCase();
|
|
8655
|
+
const mid = String(r?.manifest_id ?? "").toLowerCase();
|
|
8656
|
+
return dn.includes(q) || mid.includes(q);
|
|
8657
|
+
});
|
|
8658
|
+
}
|
|
8659
|
+
if (category) {
|
|
8660
|
+
filtered = filtered.filter((r) => String(r?.category ?? "") === category);
|
|
8661
|
+
}
|
|
8662
|
+
const total = filtered.length;
|
|
8663
|
+
const page = filtered.slice(offset, offset + limit);
|
|
8664
|
+
const body = JSON.stringify({ success: true, data: { items: page, total, limit, offset } });
|
|
8665
|
+
const headers = new Headers({
|
|
8666
|
+
"content-type": "application/json; charset=utf-8",
|
|
8667
|
+
"cache-control": "public, max-age=30",
|
|
8668
|
+
"x-cache": "PUBLIC-R2-FILTERED"
|
|
8669
|
+
});
|
|
8670
|
+
return new Response(method === "HEAD" ? null : body, { status: 200, headers });
|
|
8671
|
+
}
|
|
8558
8672
|
var PASSTHROUGH_HEADERS = ["content-type", "cache-control", "etag", "last-modified", "vary"];
|
|
8559
8673
|
function collectHeaders(src) {
|
|
8560
8674
|
const out = {};
|
|
@@ -9038,22 +9152,55 @@ var MarketplaceInstallLocalPlugin = class {
|
|
|
9038
9152
|
return c.json({ success: false, error: { code: "bad_request", message: "packageId is required." } }, 400);
|
|
9039
9153
|
}
|
|
9040
9154
|
let payload;
|
|
9041
|
-
|
|
9042
|
-
|
|
9043
|
-
|
|
9044
|
-
|
|
9045
|
-
|
|
9155
|
+
const publicBase = resolveMarketplacePublicBaseUrl();
|
|
9156
|
+
const fetchAttempts = [];
|
|
9157
|
+
if (publicBase) {
|
|
9158
|
+
fetchAttempts.push({
|
|
9159
|
+
label: "public-r2",
|
|
9160
|
+
url: `${publicBase}/packages/${encodeURIComponent(packageId)}/versions/${encodeURIComponent(versionId)}/manifest.json`
|
|
9161
|
+
});
|
|
9162
|
+
}
|
|
9163
|
+
fetchAttempts.push({
|
|
9164
|
+
label: "cloud",
|
|
9165
|
+
url: `${this.cloudUrl}/api/v1/marketplace/packages/${encodeURIComponent(packageId)}/versions/${encodeURIComponent(versionId)}/manifest`
|
|
9166
|
+
});
|
|
9167
|
+
let lastErrStatus = 0;
|
|
9168
|
+
let lastErrText = "";
|
|
9169
|
+
for (const attempt of fetchAttempts) {
|
|
9170
|
+
try {
|
|
9171
|
+
const resp = await fetch(attempt.url, { headers: { "Accept": "application/json" } });
|
|
9172
|
+
if (!resp.ok) {
|
|
9173
|
+
lastErrStatus = resp.status;
|
|
9174
|
+
lastErrText = (await resp.text().catch(() => "")).slice(0, 200);
|
|
9175
|
+
if (attempt.label === "public-r2" && resp.status === 404) {
|
|
9176
|
+
ctx.logger?.info?.(`[MarketplaceInstallLocal] public-r2 miss for ${packageId}@${versionId}, falling back to cloud`);
|
|
9177
|
+
continue;
|
|
9178
|
+
}
|
|
9179
|
+
if (attempt.label === "public-r2" && resp.status >= 500) {
|
|
9180
|
+
ctx.logger?.warn?.(`[MarketplaceInstallLocal] public-r2 ${resp.status}, falling back to cloud`);
|
|
9181
|
+
continue;
|
|
9182
|
+
}
|
|
9183
|
+
break;
|
|
9184
|
+
}
|
|
9185
|
+
payload = await resp.json();
|
|
9186
|
+
lastErrStatus = 0;
|
|
9187
|
+
break;
|
|
9188
|
+
} catch (err) {
|
|
9189
|
+
if (attempt.label === "public-r2") {
|
|
9190
|
+
ctx.logger?.warn?.(`[MarketplaceInstallLocal] public-r2 fetch error: ${err?.message ?? err}, falling back to cloud`);
|
|
9191
|
+
continue;
|
|
9192
|
+
}
|
|
9046
9193
|
return c.json({
|
|
9047
9194
|
success: false,
|
|
9048
|
-
error: { code: "cloud_fetch_failed", message:
|
|
9049
|
-
},
|
|
9195
|
+
error: { code: "cloud_fetch_failed", message: err?.message ?? String(err) }
|
|
9196
|
+
}, 502);
|
|
9050
9197
|
}
|
|
9051
|
-
|
|
9052
|
-
|
|
9198
|
+
}
|
|
9199
|
+
if (!payload) {
|
|
9053
9200
|
return c.json({
|
|
9054
9201
|
success: false,
|
|
9055
|
-
error: { code: "cloud_fetch_failed", message:
|
|
9056
|
-
}, 502);
|
|
9202
|
+
error: { code: "cloud_fetch_failed", message: `Cloud returned ${lastErrStatus}: ${lastErrText}` }
|
|
9203
|
+
}, lastErrStatus === 404 ? 404 : 502);
|
|
9057
9204
|
}
|
|
9058
9205
|
const data = payload?.data ?? payload;
|
|
9059
9206
|
const manifest = data?.manifest;
|