@objectstack/runtime 7.0.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 +162 -14
- 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 +162 -14
- 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
|
@@ -1686,7 +1686,8 @@ var init_app_plugin = __esm({
|
|
|
1686
1686
|
"translations",
|
|
1687
1687
|
"sharingRules",
|
|
1688
1688
|
"ragPipelines",
|
|
1689
|
-
"data"
|
|
1689
|
+
"data",
|
|
1690
|
+
"emailTemplates"
|
|
1690
1691
|
];
|
|
1691
1692
|
const hasAppPayload = APP_CATEGORY_KEYS.some((k) => {
|
|
1692
1693
|
const v = (bundle && bundle[k]) ?? (sys && sys[k]);
|
|
@@ -8393,6 +8394,36 @@ function resolveCloudUrl(explicit) {
|
|
|
8393
8394
|
return picked.replace(/\/+$/, "");
|
|
8394
8395
|
}
|
|
8395
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
|
+
|
|
8396
8427
|
// src/cloud/marketplace-proxy-plugin.ts
|
|
8397
8428
|
var MARKETPLACE_PREFIX = "/api/v1/marketplace";
|
|
8398
8429
|
var DEFAULT_LRU_MAX = 200;
|
|
@@ -8432,7 +8463,7 @@ var LruTtlCache = class {
|
|
|
8432
8463
|
var MarketplaceProxyPlugin = class _MarketplaceProxyPlugin {
|
|
8433
8464
|
constructor(config = {}) {
|
|
8434
8465
|
this.name = "com.objectstack.runtime.marketplace-proxy";
|
|
8435
|
-
this.version = "1.
|
|
8466
|
+
this.version = "1.1.0";
|
|
8436
8467
|
this.init = async (_ctx) => {
|
|
8437
8468
|
};
|
|
8438
8469
|
this.start = async (ctx) => {
|
|
@@ -8450,7 +8481,11 @@ var MarketplaceProxyPlugin = class _MarketplaceProxyPlugin {
|
|
|
8450
8481
|
}
|
|
8451
8482
|
const rawApp = httpServer.getRawApp();
|
|
8452
8483
|
const cloudUrl = this.cloudUrl;
|
|
8484
|
+
const publicBaseUrl = this.publicBaseUrl;
|
|
8453
8485
|
const cache = this.cache;
|
|
8486
|
+
if (publicBaseUrl) {
|
|
8487
|
+
ctx.logger?.info?.(`[MarketplaceProxyPlugin] public R2 fast-path enabled \u2192 ${publicBaseUrl}`);
|
|
8488
|
+
}
|
|
8454
8489
|
const handler = async (c, next) => {
|
|
8455
8490
|
if (!cloudUrl) {
|
|
8456
8491
|
return c.json({
|
|
@@ -8466,8 +8501,18 @@ var MarketplaceProxyPlugin = class _MarketplaceProxyPlugin {
|
|
|
8466
8501
|
if (incomingUrl.pathname.startsWith(`${MARKETPLACE_PREFIX}/install-local`)) {
|
|
8467
8502
|
return next();
|
|
8468
8503
|
}
|
|
8469
|
-
const target = `${cloudUrl}${incomingUrl.pathname}${incomingUrl.search}`;
|
|
8470
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}`;
|
|
8471
8516
|
if (method !== "GET" && method !== "HEAD") {
|
|
8472
8517
|
return c.json({
|
|
8473
8518
|
success: false,
|
|
@@ -8548,12 +8593,82 @@ var MarketplaceProxyPlugin = class _MarketplaceProxyPlugin {
|
|
|
8548
8593
|
});
|
|
8549
8594
|
};
|
|
8550
8595
|
this.cloudUrl = resolveCloudUrl(config.controlPlaneUrl);
|
|
8596
|
+
this.publicBaseUrl = resolveMarketplacePublicBaseUrl(config.publicMarketplaceBaseUrl);
|
|
8551
8597
|
const envFlag = (process.env.OS_MARKETPLACE_CACHE ?? "").trim().toLowerCase();
|
|
8552
8598
|
const envDisabled = ["off", "false", "0", "no", "disable", "disabled"].includes(envFlag);
|
|
8553
8599
|
const disabled = config.cacheDisabled ?? envDisabled;
|
|
8554
8600
|
this.cache = disabled ? null : new LruTtlCache(Math.max(8, config.cacheMaxEntries ?? DEFAULT_LRU_MAX));
|
|
8555
8601
|
}
|
|
8556
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
|
+
}
|
|
8557
8672
|
var PASSTHROUGH_HEADERS = ["content-type", "cache-control", "etag", "last-modified", "vary"];
|
|
8558
8673
|
function collectHeaders(src) {
|
|
8559
8674
|
const out = {};
|
|
@@ -9037,22 +9152,55 @@ var MarketplaceInstallLocalPlugin = class {
|
|
|
9037
9152
|
return c.json({ success: false, error: { code: "bad_request", message: "packageId is required." } }, 400);
|
|
9038
9153
|
}
|
|
9039
9154
|
let payload;
|
|
9040
|
-
|
|
9041
|
-
|
|
9042
|
-
|
|
9043
|
-
|
|
9044
|
-
|
|
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
|
+
}
|
|
9045
9193
|
return c.json({
|
|
9046
9194
|
success: false,
|
|
9047
|
-
error: { code: "cloud_fetch_failed", message:
|
|
9048
|
-
},
|
|
9195
|
+
error: { code: "cloud_fetch_failed", message: err?.message ?? String(err) }
|
|
9196
|
+
}, 502);
|
|
9049
9197
|
}
|
|
9050
|
-
|
|
9051
|
-
|
|
9198
|
+
}
|
|
9199
|
+
if (!payload) {
|
|
9052
9200
|
return c.json({
|
|
9053
9201
|
success: false,
|
|
9054
|
-
error: { code: "cloud_fetch_failed", message:
|
|
9055
|
-
}, 502);
|
|
9202
|
+
error: { code: "cloud_fetch_failed", message: `Cloud returned ${lastErrStatus}: ${lastErrText}` }
|
|
9203
|
+
}, lastErrStatus === 404 ? 404 : 502);
|
|
9056
9204
|
}
|
|
9057
9205
|
const data = payload?.data ?? payload;
|
|
9058
9206
|
const manifest = data?.manifest;
|