1import { cmdApp } from "./app.ts";23Deno.test("app init reserves the permanent default and writes token-free tracked config", async () => {4 const directory = await Deno.makeTempDir();5 const previousDirectory = Deno.cwd();6 const previousFetch = globalThis.fetch;7 const previousLog = console.log;8 const requests: string[] = [];9 globalThis.fetch = ((input) => {10 const url = String(input);11 requests.push(url);12 if (url.endsWith("/api/status")) {13 return Promise.resolve(14 new Response(JSON.stringify({15 ok: true,16 version: "0.9.0",17 defaultVaults: { temporary: "personal", permanent: "public" },18 globalDefaultTtl: 14,19 vaults: [],20 siteCount: 0,21 expiringSoon: 0,22 })),23 );24 }25 if (url.endsWith("/api/apps")) {26 return Promise.resolve(27 new Response(JSON.stringify({28 address: "f123",29 vault: "public",30 alias: "field-notes",31 url: "https://f123.n.zip/",32 createdAt: 1,33 deployed: false,34 })),35 );36 }37 throw new Error(`unexpected fetch: ${url}`);38 }) as typeof fetch;39 console.log = () => {};40 try {41 Deno.chdir(directory);42 const config = { server: "https://n.zip", token: "owner-secret" };43 await cmdApp(config, ["init", "field-notes"], {});44 await cmdApp(config, ["init"], {});45 const saved = JSON.parse(await Deno.readTextFile("nzip.app.json"));46 if (47 saved.target !== "public:field-notes" || saved.address !== "f123" ||48 saved.origin !== "https://f123.n.zip" || saved.framework !== "lofi"49 ) {50 throw new Error(`unexpected app config: ${JSON.stringify(saved)}`);51 }52 if (JSON.stringify(saved).includes(config.token)) throw new Error("app config leaked token");53 if (requests.filter((url) => url.endsWith("/api/apps")).length !== 2) {54 throw new Error("idempotent init did not verify the server reservation");55 }56 } finally {57 Deno.chdir(previousDirectory);58 globalThis.fetch = previousFetch;59 console.log = previousLog;60 await Deno.remove(directory, { recursive: true });61 }62});6364Deno.test("app deploy builds a root-scoped lofi PWA and commits its CSP", async () => {65 const directory = await Deno.makeTempDir();66 const previousDirectory = Deno.cwd();67 const previousFetch = globalThis.fetch;68 const previousLog = console.log;69 let committed: Record<string, unknown> | undefined;70 globalThis.fetch = ((input, init) => {71 const url = String(input);72 if (url.endsWith("/api/push/prepare")) {73 return Promise.resolve(74 new Response(JSON.stringify({ manifestHash: "a".repeat(64), missing: [] })),75 );76 }77 if (url.endsWith("/api/push/commit")) {78 committed = JSON.parse(String(init?.body));79 return Promise.resolve(80 new Response(JSON.stringify({81 address: "f123",82 url: "https://f123.n.zip/",83 alias: "field-notes",84 manifestHash: "a".repeat(64),85 expiresAt: null,86 ttl: "forever",87 ttlSource: "vault",88 protected: false,89 seq: 1,90 })),91 );92 }93 throw new Error(`unexpected fetch: ${url}`);94 }) as typeof fetch;95 console.log = () => {};96 try {97 Deno.chdir(directory);98 await Deno.mkdir("src");99 await Deno.writeTextFile(100 "src/app.ts",101 'const app = { credentialOrigins: ["https://f123.n.zip"] };\n',102 );103 await Deno.writeTextFile(104 "deno.json",105 JSON.stringify({ tasks: { build: "deno run -A build.ts" } }),106 );107 await Deno.writeTextFile(108 "build.ts",109 `await Deno.mkdir("dist", { recursive: true });110const files = {111 "index.html": "<!doctype html><title>app</title>",112 "manifest.webmanifest": "{}",113 "sw.js": "// worker",114 "lofi-precache.json": "[]",115 "lofi-schema.json": "{}",116 "lofi-build.json": JSON.stringify({117 lofiVersion: "1.0.0",118 sourceHash: "fixture",119 basePath: "/",120 csp: "default-src 'self'",121 }),122};123for (const [name, value] of Object.entries(files)) await Deno.writeTextFile("dist/" + name, value);124`,125 );126 await Deno.writeTextFile(127 "nzip.app.json",128 JSON.stringify({129 v: 1,130 framework: "lofi",131 target: "public:field-notes",132 address: "f123",133 origin: "https://f123.n.zip",134 build: { task: "build", output: "dist" },135 }),136 );137138 await cmdApp(139 { server: "https://n.zip", token: "owner-secret" },140 ["deploy"],141 {},142 );143 if (144 (committed?.target as { vault?: string })?.vault !== "public" ||145 (committed?.app as { contentSecurityPolicy?: string })?.contentSecurityPolicy !==146 "default-src 'self'"147 ) {148 throw new Error(`unexpected app commit: ${JSON.stringify(committed)}`);149 }150 } finally {151 Deno.chdir(previousDirectory);152 globalThis.fetch = previousFetch;153 console.log = previousLog;154 await Deno.remove(directory, { recursive: true });155 }156});