SOURCE / PINNED RELEASE
Made of little things.
Supersonic RC Revive
- Release
- 1ba42f1ca1d6…
- Author-recorded commit
- baecad10b1cd…
- License
- LICENSE
- Author’s source reference
- nostr://npub1ye5ptcxfyyxl5vjvdjar2ua3f0hynkjzpx552mu5snj3qmx5pzjscpknpr/wss%3A%2F%2Fgit.napplet.soy%2F/n-143146b0d6f
Archive hash verified: 90d22b206672eba4…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
// Generated by soyLI. Edit napplet.assets.json through soyli assets or the manager.
const assets = {"game-pack": {hash: "9b828ff319aca0630b52864141cf9c3f7a332c78e6db9d4e2cb3e19371de0f39"}};
const blobs = new Map();
const urls = new Map();
function assetEntry(id) {
const entry = Object.hasOwn(assets, id) ? assets[id] : undefined;
if (!entry) throw new Error('Unknown asset: ' + id);
return entry;
}
function embeddedBlob(entry) {
const comma = entry.url.indexOf(',');
if (!entry.url.startsWith('data:') || comma < 0)
throw new Error('Embedded asset is not a data URL. Rebuild with the single-file plugin.');
const data = entry.url.slice(comma + 1);
let bytes;
if (/;base64$/i.test(entry.url.slice(0, comma))) {
bytes = Uint8Array.from(atob(decodeURIComponent(data)), char => char.charCodeAt(0));
} else {
bytes = new TextEncoder().encode(data);
let length = 0;
for (let offset = 0; offset < bytes.length; offset++) {
if (bytes[offset] === 37) {
const hex = String.fromCharCode(bytes[offset + 1], bytes[offset + 2]);
if (!/^[a-f0-9]{2}$/i.test(hex)) throw new Error('Invalid embedded asset data URL.');
bytes[length++] = parseInt(hex, 16);
offset += 2;
} else bytes[length++] = bytes[offset];
}
bytes = bytes.subarray(0, length);
}
return new Blob([bytes], { type: entry.mime });
}
/** @param {string} id */
export async function assetBlob(id) {
const entry = assetEntry(id);
if (!blobs.has(id)) {
const pending = Promise.resolve().then(() => entry.url
? embeddedBlob(entry)
: window.napplet.resource.bytes('blossom:sha256:' + entry.hash));
blobs.set(id, pending);
pending.catch(() => { if (blobs.get(id) === pending) blobs.delete(id); });
}
return blobs.get(id);
}
/** @param {string} id */
export async function assetUrl(id) {
const entry = assetEntry(id);
if (entry.url) return entry.url;
if (!urls.has(id)) {
const pending = assetBlob(id).then(blob => URL.createObjectURL(blob));
urls.set(id, pending);
pending.catch(() => { if (urls.get(id) === pending) urls.delete(id); });
}
return urls.get(id);
}
export function releaseAssetUrls() {
for (const value of urls.values()) value.then(url => URL.revokeObjectURL(url)).catch(() => {});
urls.clear();
blobs.clear();
}
