@ambasada/village 0.8.2 → 0.8.3
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/cli.mjs +78 -40
- package/dist/index.js +49 -13
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -85,6 +85,7 @@ __export(src_exports, {
|
|
|
85
85
|
parseCheckpoint: () => parseCheckpoint,
|
|
86
86
|
parseVerifierKey: () => parseVerifierKey,
|
|
87
87
|
pngInfo: () => pngInfo,
|
|
88
|
+
probeManifest: () => probeManifest,
|
|
88
89
|
publicJwkOf: () => publicJwkOf,
|
|
89
90
|
randomId: () => randomId,
|
|
90
91
|
rootFromLeafHashes: () => rootFromLeafHashes,
|
|
@@ -1266,6 +1267,34 @@ var USER_AGENT = "ambasada-check/1 (+https://ambasada.id)";
|
|
|
1266
1267
|
async function get(fetchImpl, url) {
|
|
1267
1268
|
return fetchImpl(url, { redirect: "manual", signal: AbortSignal.timeout(FETCH_TIMEOUT_MS), headers: { "user-agent": USER_AGENT, accept: "*/*" } });
|
|
1268
1269
|
}
|
|
1270
|
+
async function probeManifest(origin, fetchImpl = fetch) {
|
|
1271
|
+
try {
|
|
1272
|
+
const res = await get(fetchImpl, new URL(MANIFEST_URL_PATH, origin).toString());
|
|
1273
|
+
if (res.status !== 200) {
|
|
1274
|
+
await res.body?.cancel();
|
|
1275
|
+
return { on: false, entry: null };
|
|
1276
|
+
}
|
|
1277
|
+
const m = JSON.parse(await res.text());
|
|
1278
|
+
if (!m || typeof m !== "object" || m.schema !== MANIFEST_SCHEMA && m.schema !== 1) return { on: false, entry: null };
|
|
1279
|
+
return { on: true, entry: typeof m.entry === "string" && m.entry.startsWith("/") ? m.entry : "/" };
|
|
1280
|
+
} catch {
|
|
1281
|
+
return { on: false, entry: null };
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
async function checkPage(fetchImpl, url, report, html) {
|
|
1285
|
+
try {
|
|
1286
|
+
const started = Date.now();
|
|
1287
|
+
const res = await get(fetchImpl, url);
|
|
1288
|
+
const text = res.status === 200 && html ? await res.text() : "";
|
|
1289
|
+
if (!html) await res.body?.cancel();
|
|
1290
|
+
const ms = Date.now() - started;
|
|
1291
|
+
if (res.status !== 200) report.problems.push({ code: "entry_status", message: `${url} answered ${res.status}${res.headers.get("location") ? ` \u2192 ${res.headers.get("location")}` : ""}; ${html ? "the entry" : "the app"} must answer 200 without redirects` });
|
|
1292
|
+
else if (html) merge(report, checkHtml(text));
|
|
1293
|
+
if (ms > SLOW_ENTRY_MS) report.warnings.push({ code: "slow_entry", message: `${url} took ${ms} ms; aim for under ${SLOW_ENTRY_MS} ms${html ? " (the splash stays until ready())" : ""}` });
|
|
1294
|
+
} catch (error) {
|
|
1295
|
+
report.problems.push({ code: "entry_fetch", message: `could not fetch ${url}: ${error.message}` });
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1269
1298
|
async function checkRemote(url, fetchImpl = fetch, options = {}) {
|
|
1270
1299
|
const report = { ok: true, target: url, problems: [], warnings: [], notes: [] };
|
|
1271
1300
|
let origin;
|
|
@@ -1279,8 +1308,23 @@ async function checkRemote(url, fetchImpl = fetch, options = {}) {
|
|
|
1279
1308
|
if (origin.protocol !== "https:") report.problems.push({ code: "not_https", message: "the app must be served over https" });
|
|
1280
1309
|
let manifest = null;
|
|
1281
1310
|
const manifestUrl = new URL(MANIFEST_URL_PATH, origin).toString();
|
|
1311
|
+
if (options.miniapp === false) {
|
|
1312
|
+
report.miniapp = { on: false, entry: null };
|
|
1313
|
+
report.notes.push("mini app: off");
|
|
1314
|
+
await checkPage(fetchImpl, new URL("/", origin).toString(), report, false);
|
|
1315
|
+
report.ok = report.problems.length === 0;
|
|
1316
|
+
return report;
|
|
1317
|
+
}
|
|
1282
1318
|
try {
|
|
1283
1319
|
let res = await get(fetchImpl, manifestUrl);
|
|
1320
|
+
if (res.status === 404 && options.miniapp === void 0) {
|
|
1321
|
+
await res.body?.cancel();
|
|
1322
|
+
report.miniapp = { on: false, entry: null };
|
|
1323
|
+
report.notes.push(`mini app: off (no ${MANIFEST_URL_PATH})`);
|
|
1324
|
+
await checkPage(fetchImpl, new URL("/", origin).toString(), report, false);
|
|
1325
|
+
report.ok = report.problems.length === 0;
|
|
1326
|
+
return report;
|
|
1327
|
+
}
|
|
1284
1328
|
if (res.status >= 300 && res.status < 400) {
|
|
1285
1329
|
const location = res.headers.get("location") ?? "";
|
|
1286
1330
|
if (res.status === 307 && HOSTED_MANIFEST.test(location)) {
|
|
@@ -1302,18 +1346,8 @@ async function checkRemote(url, fetchImpl = fetch, options = {}) {
|
|
|
1302
1346
|
report.problems.push({ code: "manifest_fetch", message: `could not fetch ${manifestUrl}: ${error.message}` });
|
|
1303
1347
|
}
|
|
1304
1348
|
const entryPath = typeof manifest?.entry === "string" && manifest.entry.startsWith("/") ? manifest.entry : "/";
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
const started = Date.now();
|
|
1308
|
-
const res = await get(fetchImpl, entryUrl);
|
|
1309
|
-
const html = res.status === 200 ? await res.text() : "";
|
|
1310
|
-
const ms = Date.now() - started;
|
|
1311
|
-
if (res.status !== 200) report.problems.push({ code: "entry_status", message: `${entryUrl} answered ${res.status}${res.headers.get("location") ? ` \u2192 ${res.headers.get("location")}` : ""}; the entry must answer 200 without redirects` });
|
|
1312
|
-
else merge(report, checkHtml(html));
|
|
1313
|
-
if (ms > SLOW_ENTRY_MS) report.warnings.push({ code: "slow_entry", message: `${entryUrl} took ${ms} ms; the splash stays until ready(), aim for under ${SLOW_ENTRY_MS} ms` });
|
|
1314
|
-
} catch (error) {
|
|
1315
|
-
report.problems.push({ code: "entry_fetch", message: `could not fetch ${entryUrl}: ${error.message}` });
|
|
1316
|
-
}
|
|
1349
|
+
report.miniapp = { on: true, entry: entryPath };
|
|
1350
|
+
await checkPage(fetchImpl, new URL(entryPath, origin).toString(), report, true);
|
|
1317
1351
|
if (typeof manifest?.icon === "string" && manifest.icon) {
|
|
1318
1352
|
const iconUrl = new URL(manifest.icon, origin).toString();
|
|
1319
1353
|
try {
|
|
@@ -1381,9 +1415,11 @@ function summarizeCheck(report, now = /* @__PURE__ */ new Date()) {
|
|
|
1381
1415
|
...report.warnings.map((w) => ({ ...w, level: "warning", label: findingLabel(w.code) }))
|
|
1382
1416
|
];
|
|
1383
1417
|
const needs = [...new Set(issues.filter((i) => i.level === "problem").map((i) => i.label))];
|
|
1384
|
-
|
|
1418
|
+
const miniapp = report.miniapp ? { miniapp: report.miniapp.on ? "on" : "off", entry: report.miniapp.entry } : {};
|
|
1419
|
+
return { ok: report.ok, issues, needs, checked_at: now.toISOString(), ...miniapp };
|
|
1385
1420
|
}
|
|
1386
1421
|
function listingLine(tier, check) {
|
|
1422
|
+
if (check?.miniapp === "off") return "Mini app: off";
|
|
1387
1423
|
if (tier === "verified") return "Verified";
|
|
1388
1424
|
if (tier === "listed") return "Listed for the event";
|
|
1389
1425
|
if (tier === "unlisted") return check?.needs.length ? `Unlisted \xB7 needs: ${check.needs.join(", ")}` : "Unlisted";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ambasada/village",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"description": "The Hack A Ton add-on for Ambasada apps: TON checkout, receipts, offerings, LLM, the agent, the market; CLI commands and the local bank.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"node": ">=22"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@ambasada/sdk": "^0.8.
|
|
30
|
+
"@ambasada/sdk": "^0.8.3"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/node": "^22.20.5",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"typescript": "~5.9.3",
|
|
36
36
|
"vitest": "^4.1.12",
|
|
37
37
|
"@ambasada/protocol": "0.1.0",
|
|
38
|
-
"@ambasada/cli": "0.8.
|
|
38
|
+
"@ambasada/cli": "0.8.3"
|
|
39
39
|
},
|
|
40
40
|
"author": "CENTYSO (https://centyso.com)",
|
|
41
41
|
"homepage": "https://ambasada.id",
|