import assert from "node:assert/strict"; import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { execFile } from "node:child_process"; import { promisify } from "node:util"; import test from "node:test"; process.env.AUTH_MODE = "demo"; process.env.STORAGE_MODE = "local"; process.env.PUBLIC_BASE_URL = "http://localhost:4000"; process.env.WEB_ORIGIN = "http://localhost:3000"; process.env.LOCAL_STORAGE_DIR = ".data/test-storage"; process.env.PROCESS_INLINE = "true"; delete process.env.DATABASE_URL; const { createServer } = await import("../apps/api/src/server.ts"); const runtime = await createServer(); const app = runtime.app; test.after(async () => { await app.close(); }); test("creates a source and returns a dashboard in demo mode", async () => { const sourceResponse = await app.inject({ method: "POST", url: "/api/v1/sources", headers: { "x-demo-user": "test@example.com", "content-type": "application/json" }, payload: { name: "Test Source", subtitle: "Test apps", visibility: "draft" }, }); assert.equal(sourceResponse.statusCode, 201); const source = sourceResponse.json().source; assert.equal(source.visibility, "draft"); const dashboardResponse = await app.inject({ method: "GET", url: "/api/v1/dashboard", headers: { "x-demo-user": "test@example.com" } }); assert.equal(dashboardResponse.statusCode, 200); const dashboard = dashboardResponse.json(); assert.ok(dashboard.sources.some((entry) => entry.source.id === source.id)); }); test("does not expose draft sources publicly", async () => { const response = await app.inject({ method: "GET", url: "/sources/test-source/source.json" }); assert.equal(response.statusCode, 404); }); test("validates, stores, publishes, and serves an ADP package", async () => { const root = await mkdtemp(join(tmpdir(), "altdock-test-adp-")); const fixtureRoot = join(root, "fixture"); await (await import("node:fs/promises")).mkdir(join(fixtureRoot, "variant"), { recursive: true }); const manifest = Buffer.from(JSON.stringify({ distributionPackageRevision: 1, appleItemId: "123456789", bundleId: "com.example.fixture", shortVersionString: "1.0", bundleVersion: "1", platforms: ["ios"], minimumSystemVersions: { ios: "17.4" }, variants: [{ assetPath: "variant/fixture.ipa", installTargets: [] }], deltas: [], })); const signature = Buffer.from("signed-fixture"); const ipa = Buffer.from("not-an-installable-ipa-fixture"); await writeFile(join(fixtureRoot, "manifest.json"), manifest); await writeFile(join(fixtureRoot, "signature"), signature); await writeFile(join(fixtureRoot, "variant/fixture.ipa"), ipa); const archivePath = join(root, "fixture.zip"); await promisify(execFile)("zip", ["-q", "-r", archivePath, "manifest.json", "signature", "variant"], { cwd: fixtureRoot }); const archive = await readFile(archivePath); const sourceResponse = await app.inject({ method: "POST", url: "/api/v1/sources", headers: { "x-demo-user": "fixture@example.com", "content-type": "application/json" }, payload: { name: "Fixture Source", visibility: "public" } }); const source = sourceResponse.json().source; const uploadResponse = await app.inject({ method: "POST", url: "/api/v1/uploads", headers: { "x-demo-user": "fixture@example.com", "content-type": "application/json" }, payload: { sourceId: source.id, filename: "fixture.zip", sizeBytes: archive.length } }); assert.equal(uploadResponse.statusCode, 201); const upload = uploadResponse.json(); const putResponse = await app.inject({ method: "PUT", url: new URL(upload.uploadPlan.uploadUrl).pathname, headers: { "content-type": "application/zip" }, payload: archive }); assert.equal(putResponse.statusCode, 200, putResponse.body); const completeResponse = await app.inject({ method: "POST", url: `/api/v1/uploads/${upload.upload.id}/complete`, headers: { "x-demo-user": "fixture@example.com", "content-type": "application/json" }, payload: {} }); assert.equal(completeResponse.statusCode, 202, completeResponse.body); const release = completeResponse.json().release; assert.equal(release.status, "ready"); const publishResponse = await app.inject({ method: "POST", url: `/api/v1/releases/${release.id}/publish`, headers: { "x-demo-user": "fixture@example.com" } }); assert.equal(publishResponse.statusCode, 200, publishResponse.body); const sourceJsonResponse = await app.inject({ method: "GET", url: `/sources/${source.slug}/source.json` }); assert.equal(sourceJsonResponse.statusCode, 200, sourceJsonResponse.body); const sourceJson = sourceJsonResponse.json(); assert.equal(sourceJson.apps[0].bundleIdentifier, "com.example.fixture"); assert.match(sourceJson.apps[0].versions[0].downloadURL, new RegExp(`/artifacts/${release.id}/manifest\\.json$`)); const artifactResponse = await app.inject({ method: "GET", url: `/artifacts/${release.id}/manifest.json` }); assert.equal(artifactResponse.statusCode, 200, artifactResponse.body); assert.deepEqual(artifactResponse.rawPayload, manifest); await rm(root, { recursive: true, force: true }); });