SOURCE / PINNED RELEASE
Made of little things.
Outbreak: Soycoon City
- Release
- db7750b1d009…
- Author-recorded commit
- 3ee3f5fd27a6…
- License
- LICENSE
- Author’s source reference
- nostr://npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf/wss%3A%2F%2Fgit.napplet.soy%2F/n-b87c04571a9
Archive hash verified: dbebdc772b142a1c…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
import { fs } from '@napplet/sdk';
import { runtimeHasDomain } from './domain-availability.js';
export function base64(bytes: Uint8Array): string {
let out = ''; for (let i = 0; i < bytes.length; i += 8192) out += String.fromCharCode(...bytes.subarray(i, i + 8192)); return btoa(out);
}
export async function exportFile(name: string, content: string, encoded = false): Promise<void> {
if (!runtimeHasDomain('fs')) throw new Error('This host has no file exports. Your map and prompt remain available here.');
const extension = '.' + name.split('.').pop();
const picked = await fs.pickSaveFile({ suggestedName: name, accept: [{ extension }], description: 'Export a Soyindent Evil editor file' });
const path = picked.entries[0]?.path;
if (!path) throw new Error('Export cancelled.');
const data = encoded ? content : base64(new TextEncoder().encode(content));
let first = true;
for (let i = 0; i < data.length; i += 262144) {
await fs.write(path, data.slice(i, i + 262144), { mode: first ? 'replace' : 'append' }); first = false;
}
}
export async function importFile(extensions: string[], maxBytes = 8_000_000): Promise<{ name: string; data: Uint8Array }> {
if (!runtimeHasDomain('fs')) throw new Error('This host has no file imports. Paste map JSON in the map text field instead.');
const picked = await fs.pickFile({ accept: extensions.map(extension => ({ extension })), description: 'Choose a map or a 4:3 background image' });
const entry = picked.entries[0];
if (!entry) throw new Error('Import cancelled.');
const info = await fs.stat(entry.path);
if (info.size !== undefined && info.size > maxBytes) throw new Error(`File is too large (limit ${Math.round(maxBytes / 1e6)} MB).`);
const chunks: Uint8Array[] = []; let offset = 0;
for (;;) {
const result = await fs.read(entry.path, { offset, length: 262144 });
const chunk = Uint8Array.from(atob(result.data), c => c.charCodeAt(0)); chunks.push(chunk); offset += chunk.length;
if (offset > maxBytes) throw new Error('File exceeds the import limit.');
if (result.eof || !chunk.length) break;
}
const data = new Uint8Array(offset); let pos = 0; for (const c of chunks) { data.set(c, pos); pos += c.length; }
return { name: entry.path.split('/').pop() ?? 'import', data };
}
