SOURCE / PINNED RELEASE
Made of little things.
Pickle Rustlers
- Release
- 039e51f55e34…
- Author-recorded commit
- 40608586a8a1…
- License
- LICENSE
- Author’s source reference
- nostr://npub12lm3rxsva8kfempyjkxupt09e02n3fezurkyadyqfejdc5e0r2kscqty6r/wss%3A%2F%2Fgit.napplet.soy%2F/n-bad44e7ab35
Archive hash verified: f38e99afa0992052…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
// Optional score-card sharing: offered only to a signed-in viewer when the runtime
// injects identity, upload and outbox. Missing or denied domains just hide it.
import { identity, upload } from '@napplet/sdk';
import { runtimeHasDomain } from '../domain-availability.js';
import { postScoreCard } from './post.js';
import { CARD_H, CARD_W, drawScoreCard, toPng } from './scorecard.js';
import type { ScoreShare } from './types.js';
const REQUIRED = ['identity', 'upload', 'outbox'] as const;
async function viewerName(): Promise<string> {
const fallback = 'A lone cowboy';
try {
const profile = await Promise.race([
identity.getProfile(),
new Promise<null>((resolve) => window.setTimeout(() => resolve(null), 1500)),
]);
const name = (profile?.displayName || profile?.name || '').trim();
return name ? Array.from(name).slice(0, 24).join('') : fallback;
} catch {
return fallback;
}
}
/** Upload info is advisory; only a clear "no PNG uploads" answer hides sharing. */
async function canUploadPng(): Promise<boolean> {
try {
const info = await upload.info();
if (info.rails.length > 0 && !info.rails.some((r) => r.enabled)) return false;
if (info.maxBytes !== undefined && info.maxBytes < 256 * 1024) return false;
return !info.mimeTypes?.length || info.mimeTypes.some((m) => m === 'image/png' || m === 'image/*' || m === '*/*');
} catch {
return false;
}
}
export function createScoreShare(): ScoreShare | null {
if (!REQUIRED.every((domain) => runtimeHasDomain(domain))) return null;
let pubkey = '';
let uploadOk = false;
const listeners = new Set<() => void>();
const notify = () => listeners.forEach((fn) => fn());
const setPubkey = (next: string) => {
if (next === pubkey) return;
pubkey = next;
notify();
};
try {
const sub = identity.onChanged((next) => setPubkey(next || ''));
window.addEventListener('pagehide', () => sub.close(), { once: true });
} catch {
// An identity domain that cannot subscribe still answers getPublicKey below.
}
identity
.getPublicKey()
.then((next) => setPubkey(next || ''))
.catch(() => undefined);
void canUploadPng().then((ok) => {
uploadOk = ok;
if (ok) notify();
});
return {
get available() {
return uploadOk && pubkey !== '';
},
onChange(listener) {
listeners.add(listener);
},
async makeCard(run, scene) {
const preview = drawScoreCard(run, scene, await viewerName());
return { preview, png: await toPng(preview) };
},
post(png, text, onStatus) {
return postScoreCard(png, text, { width: CARD_W, height: CARD_H }, onStatus);
},
};
}
