Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .planning/STATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ See: .planning/PROJECT.md (updated 2026-05-24 after v0.31.0 archive)

Phase: 163 (nap-gamepad-across-repositories) — implementation verified
Plan: 3 of 3
Status: Completing prerequisite publication for CLI follow-up #243
Last activity: 2026-10-14 - Integrated the merged icon skill with the GAMEPAD release branch
Status: Verified; [draft PR #224](https://github.com/napplet/web/pull/224) open, hzrd149 requested
Comment thread
dskvr marked this conversation as resolved.
Resolved
Last activity: 2026-10-14 - Completed quick task 261014-fuc: Replace blossom:sha256 URIs with BUD-10 form

See phase 163 VERIFICATION.md and COVERAGE.md for evidence and disclosed release/specification/baseline limits. Earlier phase and quick-task records below are historical.

Expand Down Expand Up @@ -539,6 +539,7 @@ Full decision log in PROJECT.md Key Decisions table. Recent decisions affecting

| Quick ID | Task | Date | Commit | Artifacts |
|----------|------|------|--------|-----------|
| 261014-fuc | Replace blossom:sha256 URIs with BUD-10 blossom:<sha256>.<ext> | 2026-10-14 | 48782cd0 | [261014-fuc-replace-blossom-sha256-uris-with-bud-10-](./quick/261014-fuc-replace-blossom-sha256-uris-with-bud-10-/) |
| 261013-vo3 | Add a skill for icon design, generation, refinement, and NIP-5D integration | 2026-10-13 | b5757eec | [261013-vo3-add-a-napplet-skill-for-icon-design-imag](./quick/261013-vo3-add-a-napplet-skill-for-icon-design-imag/) |
| 261009-ur6 | Remove commit-title gating from JSR publication | 2026-10-09 | d798a91f | [261009-ur6-remove-commit-title-gating-from-jsr-publ](./quick/261009-ur6-remove-commit-title-gating-from-jsr-publ/) |
| 261006-ij3 | Fix verified PR #224 review findings (conformance x-hash panel, deploy/plugin dropped-asset guards, CLI R/O overlap, debug crash) | 2026-10-06 | a4f1c8b4 | [261006-ij3-fix-verified-pr-224-review-findings-conf](./quick/261006-ij3-fix-verified-pr-224-review-findings-conf/) |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ These drafts will be copy-pasted into PRs against napplet/nubs. Treat them as if

`### https:` — Shell performs the network fetch. Subject to the full Default Resource Policy below: private-IP block list MUST at DNS-resolution time, MIME byte-sniffing MUST, redirect chain cap SHOULD, response size cap SHOULD, fetch timeout SHOULD, per-napplet rate limit SHOULD. The `mime` returned to the napplet is the shell's byte-sniffed classification — never the upstream `Content-Type`.

`### blossom:` — Blossom hash → bytes resolution. Canonical URL form: `blossom:sha256:<hex>` where `<hex>` is the lowercase 64-character SHA-256 hex digest. Shells MAY consult any number of Blossom servers per their server-selection policy. The shell MUST verify the returned bytes hash against the URL's declared digest before delivering to the napplet; mismatch MUST result in `code: "decode-failed"`. The `mime` is byte-sniffed by the shell after hash verification.
`### blossom:` — Blossom hash → bytes resolution. Canonical URL form: `blossom:<sha256>.<ext>` as defined by [BUD-10](https://github.com/hzrd149/blossom/blob/master/buds/10.md), where `<sha256>` is the lowercase 64-character SHA-256 hex digest and `<ext>` is a file extension (`.bin` when unknown), optionally followed by BUD-10 discovery hints (`xs`, `as`, `sz`). Shells MAY consult any number of Blossom servers per their server-selection policy. The shell MUST verify the returned bytes hash against the URL's declared digest before delivering to the napplet; mismatch MUST result in `code: "decode-failed"`. The `mime` is byte-sniffed by the shell after hash verification.

`### nostr:` — NIP-19 bech32 input form (e.g., `nostr:nprofile1...`, `nostr:naddr1...`). **Single-hop resolution semantics:** the shell resolves the bech32 to its referenced Nostr resource (profile metadata, addressable event content) and returns those bytes as a Blob with `mime: "application/json"` (or another shell-classified MIME if the resource is byte-typed). Shells MUST NOT recursively follow URLs *within* the resolved bytes — that is the napplet's job via subsequent `resource.bytes()` calls. Single-hop semantics prevent shell-side fan-out attacks.

Expand Down Expand Up @@ -378,7 +378,7 @@ These drafts will be copy-pasted into PRs against napplet/nubs. Treat them as if
| Byte-sniff MIME | Never honor upstream `Content-Type`. |
| Rasterize SVG in a sandboxed Worker with no network | Per the SVG Handling section. |
| Single-Blob delivery | Result envelope contains exactly one Blob; no streaming, no chunked, no range. |
| Verify Blossom hash before delivery | For `blossom:sha256:<hex>` URLs, the returned bytes MUST hash to the declared digest. |
| Verify Blossom hash before delivery | For [BUD-10](https://github.com/hzrd149/blossom/blob/master/buds/10.md) `blossom:<sha256>.<ext>` URLs, the returned bytes MUST hash to the declared digest. |
| Single-hop `nostr:` resolution | Do NOT recursively follow URLs within resolved Nostr resources. |
| Scope cache per `(dTag, aggregateHash)` | Per NIP-5D identity binding; napplets MUST NOT see another napplet's cached resources. |

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ completed: 2026-04-20
- Scheme Protocol Surfaces (4 subsections — covers SCH-02, SCH-03, SCH-04 plus references SCH-01 done in Phase 126):
- `data:` per RFC 2397, in-shim or shell-handled, no network, no SSRF policy
- `https:` with full Default Resource Policy applied; explicit ban on `http:` cleartext as default
- `blossom:` with canonical `blossom:sha256:<hex>` form, hash verification before delivery, same `https:` policy on upstream Blossom-host fetches
- `blossom:` with canonical [BUD-10](https://github.com/hzrd149/blossom/blob/master/buds/10.md) `blossom:<sha256>.<ext>` form, hash verification before delivery, same `https:` policy on upstream Blossom-host fetches
- `nostr:` with NIP-19 bech32 input and **single-hop resolution semantics** (anti-fan-out)
- Default Resource Policy section with grep-anchor MUST language for Pitfall 6 mitigation:
- Private-IP block list as MUST at DNS-resolution time covering all 6 categories (10/8, 172.16/12, 192.168/16, 127/8, ::1, 169.254/16, fe80::/10, fc00::/7, 169.254.169.254)
Expand Down Expand Up @@ -277,7 +277,7 @@ Exit 0 across all 14 workspace packages. DEF-125-01 stays closed.
| SPEC-05 | NUB-MEDIA-AMENDMENT.md (entire file) | Documentation Clarification with artwork.url -> resource.bytes() prose |
| SPEC-06 | All 4 drafts | grep -c '@napplet/' returns 0 across all 4 files |
| SCH-02 | NUB-RESOURCE.md § Scheme Protocol Surfaces / `https:` | Shell-side network fetch with full Default Resource Policy; `http:` not default |
| SCH-03 | NUB-RESOURCE.md § Scheme Protocol Surfaces / `blossom:` | Canonical `blossom:sha256:<hex>` form; hash verification before delivery |
| SCH-03 | NUB-RESOURCE.md § Scheme Protocol Surfaces / `blossom:` | Canonical [BUD-10](https://github.com/hzrd149/blossom/blob/master/buds/10.md) `blossom:<sha256>.<ext>` form; hash verification before delivery |
| SCH-04 | NUB-RESOURCE.md § Scheme Protocol Surfaces / `nostr:` | NIP-19 bech32 input; single-hop resolution semantics |
| POL-01 | NUB-RESOURCE.md § Default Resource Policy / Private-IP block list (MUST, at DNS-resolution time) | Full 6-category IP block list; DNS-pinning per redirect hop |
| POL-02 | NUB-RESOURCE.md § Default Resource Policy / Response size cap (SHOULD, ~10 MiB) | Excess -> `code: "too-large"` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ napplet: napplet.resource.bytes('data:image/png;base64,iVBORw0KGgo...')

**Successful `blossom:` fetch:**
```
-> { "type": "resource.bytes", "id": "r2", "url": "blossom:sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }
-> { "type": "resource.bytes", "id": "r2", "url": "blossom:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.bin" }
<- { "type": "resource.bytes.result", "id": "r2", "blob": <Blob 9001 bytes>, "mime": "image/webp" }
```

Expand Down Expand Up @@ -110,7 +110,7 @@ The shell performs the network fetch. This scheme is subject to the **full Defau

### `blossom:`

Blossom hash → bytes resolution. Canonical URL form: `blossom:sha256:<hex>` where `<hex>` is the lowercase 64-character SHA-256 hex digest of the resource bytes. Shells MAY consult any number of Blossom servers per their server-selection policy (typically a user-configured list of preferred Blossom hosts). The shell MUST verify the returned bytes hash against the URL's declared digest **before** delivering them to the napplet; mismatch MUST result in `error: "decode-failed"`. The `mime` field is byte-sniffed by the shell after hash verification, not before.
Blossom hash → bytes resolution. Canonical URL form: `blossom:<sha256>.<ext>` as defined by [BUD-10](https://github.com/hzrd149/blossom/blob/master/buds/10.md), where `<sha256>` is the lowercase 64-character SHA-256 hex digest of the resource bytes and `<ext>` is a file extension (`.bin` when unknown), optionally followed by BUD-10 discovery hints (`xs`, `as`, `sz`). Shells MAY consult any number of Blossom servers per their server-selection policy (typically a user-configured list of preferred Blossom hosts). The shell MUST verify the returned bytes hash against the URL's declared digest **before** delivering them to the napplet; mismatch MUST result in `error: "decode-failed"`. The `mime` field is byte-sniffed by the shell after hash verification, not before.

When fetching from upstream Blossom hosts, shells MUST apply the same `https:` policy (private-IP block list at DNS-resolution time, etc.) to each candidate host. Blossom-host selection MUST NOT bypass DNS-pinning.

Expand Down Expand Up @@ -221,7 +221,7 @@ The key words MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY in this document are t
| Byte-sniff MIME | Never honor upstream `Content-Type` for the value delivered to the napplet. Sniffed MIME drives scheme-appropriate allowlist enforcement. |
| Rasterize SVG in a sandboxed Worker with no network | Per the SVG Handling section. `image/svg+xml` MUST NOT be delivered to napplets. |
| Single-Blob delivery | Result envelope contains exactly one `Blob`; no streaming, no chunked, no range, no progress. |
| Verify Blossom hash before delivery | For `blossom:sha256:<hex>` URLs, the returned bytes MUST hash to the declared digest. Mismatch MUST result in `error: "decode-failed"`. |
| Verify Blossom hash before delivery | For [BUD-10](https://github.com/hzrd149/blossom/blob/master/buds/10.md) `blossom:<sha256>.<ext>` URLs, the returned bytes MUST hash to the declared digest. Mismatch MUST result in `error: "decode-failed"`. |
| Single-hop `nostr:` resolution | Do NOT recursively follow URLs found within resolved Nostr resources. |
| Scope cache per `(dTag, aggregateHash)` | Per NIP-5D identity binding. Napplets MUST NOT see another napplet's cached resources. |
| Drop late envelopes after cancel | After receiving `resource.cancel` for an `id`, shells SHOULD NOT emit a terminal envelope for that `id`; if one is emitted (race), conformant napplet shims MUST silently drop it. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ e. Add a new section after the Theme Exception section, before Migration, titled
const blob: Blob = await bytes('https://example.com/avatar.png');

// Synchronous handle for <img src> use; revoke when done.
const handle = bytesAsObjectURL('blossom:sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855');
const handle = bytesAsObjectURL('blossom:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.bin');
imgEl.src = handle.url;
// later
handle.revoke();
Expand All @@ -286,7 +286,7 @@ e. Add a new section after the Theme Exception section, before Migration, titled
Four canonical schemes are defined in the spec:
- `data:` — RFC 2397, decoded inside the napplet shim with zero shell round-trip
- `https:` — shell-side network fetch under the default resource policy (private-IP block list at DNS time, MIME byte-sniffing, size cap, timeout, rate limit, redirect cap)
- `blossom:sha256:<hex>` — Blossom hash → bytes; shell verifies hash before delivery
- `blossom:<sha256>.<ext>` — [BUD-10](https://github.com/hzrd149/blossom/blob/master/buds/10.md) Blossom URI → bytes; shell verifies hash before delivery
- `nostr:<bech32>` — single-hop NIP-19 resolution against the shell's relay pool

Errors arrive as one of 8 typed codes: `not-found`, `blocked-by-policy`, `timeout`,
Expand All @@ -310,7 +310,7 @@ b. In the Quick Start code block, ADD a new pair of lines before `// Clean up`:
```ts
// Fetch external bytes via the shell (CSP blocks direct <img src=externalUrl> / fetch())
const avatarBlob = await window.napplet.resource.bytes('https://example.com/avatar.png');
const handle = window.napplet.resource.bytesAsObjectURL('blossom:sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855');
const handle = window.napplet.resource.bytesAsObjectURL('blossom:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.bin');
imgEl.src = handle.url;
// later: handle.revoke();
```
Expand Down Expand Up @@ -346,7 +346,7 @@ f. Add a new subsection after `### window.napplet.config` and before `### window
| `bytes(url, opts?)` | `Promise<Blob>` | Fetch bytes for a URL via the shell. `opts.signal` accepts an `AbortSignal` for cancellation. |
| `bytesAsObjectURL(url)` | `{ url: string; revoke: () => void }` | Synchronous handle whose `url` resolves to a blob URL once the underlying fetch completes. Caller MUST `revoke()` when done. |

Four canonical schemes: `data:` (decoded in-shim), `https:` (shell-side network with policy), `blossom:sha256:<hex>` (hash-verified), `nostr:<bech32>` (single-hop NIP-19 resolution).
Four canonical schemes: `data:` (decoded in-shim), `https:` (shell-side network with policy), `blossom:<sha256>.<ext>` ([BUD-10](https://github.com/hzrd149/blossom/blob/master/buds/10.md), hash-verified), `nostr:<bech32>` (single-hop NIP-19 resolution).

Errors reject the Promise with one of 8 codes: `not-found`, `blocked-by-policy`, `timeout`, `too-large`, `unsupported-scheme`, `decode-failed`, `network-error`, `quota-exceeded`.

Expand All @@ -371,7 +371,7 @@ b. ADD a usage block in Quick Start after the `// Deep-link settings UI` block,
```ts
// Fetch external bytes via the shell (the iframe sandbox + strict CSP block direct fetch)
const avatarBlob = await resource.bytes('https://example.com/avatar.png');
const handle = resource.bytesAsObjectURL('blossom:sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855');
const handle = resource.bytesAsObjectURL('blossom:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.bin');
imgEl.src = handle.url;
// handle.revoke() when done
```
Expand All @@ -388,7 +388,7 @@ c. ADD a new section after `### config` and before `### keys` titled `### resour
| `bytes(url, opts?)` | `Promise<Blob>` | Fetch bytes through the shell. `opts.signal` accepts an `AbortSignal`. |
| `bytesAsObjectURL(url)` | `{ url: string; revoke: () => void }` | Synchronous handle whose `url` resolves to a blob URL once the fetch completes. |

Four canonical schemes: `data:` (in-shim), `https:` (shell-side under policy), `blossom:sha256:<hex>` (hash-verified), `nostr:<bech32>` (single-hop NIP-19).
Four canonical schemes: `data:` (in-shim), `https:` (shell-side under policy), `blossom:<sha256>.<ext>` ([BUD-10](https://github.com/hzrd149/blossom/blob/master/buds/10.md), hash-verified), `nostr:<bech32>` (single-hop NIP-19).
```

d. In the NUB Domain Constants section, update the import line to include `RESOURCE_DOMAIN`:
Expand Down Expand Up @@ -500,7 +500,7 @@ a. Add a new section after the existing `## Architecture` block and before `## O

v0.28.0 converts napplet iframe security from ambient trust ("napplets shouldn't fetch directly") to browser-enforced isolation ("napplets cannot fetch directly — the browser blocks it"):

- **New NUB:** `@napplet/nub/resource` ships a single scheme-pluggable primitive — `napplet.resource.bytes(url) → Blob`. URL space is scheme-pluggable: `https:` (shell-side network under policy), `blossom:sha256:<hex>` (hash-verified), `nostr:<bech32>` (single-hop NIP-19), `data:` (RFC 2397, decoded in-shim).
- **New NUB:** `@napplet/nub/resource` ships a single scheme-pluggable primitive — `napplet.resource.bytes(url) → Blob`. URL space is scheme-pluggable: `https:` (shell-side network under policy), `blossom:<sha256>.<ext>` ([BUD-10](https://github.com/hzrd149/blossom/blob/master/buds/10.md), hash-verified), `nostr:<bech32>` (single-hop NIP-19), `data:` (RFC 2397, decoded in-shim).
- **Strict CSP:** `@napplet/vite-plugin` ships a `strictCsp` option that emits a 10-directive baseline (`default-src 'none'` + `connect-src 'none'` in prod) as the first child of `<head>`. The browser blocks every `fetch()`, `<img src=externalUrl>`, `XMLHttpRequest`, and direct WebSocket; everything network-sourced flows through the resource NUB.
- **Optional sidecar:** Shells MAY pre-resolve resources referenced by `relay.event` envelopes via an opt-in (default-OFF) `resources?` field; napplet-side `resource.bytes(sidecarUrl)` calls then resolve from cache without a postMessage round-trip.
- **SVG rasterization:** Shells MUST rasterize SVG to PNG/WebP in a sandboxed Worker with no network — napplets never receive parseable XML.
Expand Down Expand Up @@ -606,7 +606,7 @@ imgEl.src = objectUrl;
// remember to URL.revokeObjectURL(objectUrl) when done

// Or use the synchronous handle helper:
const handle = window.napplet.resource.bytesAsObjectURL('blossom:sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855');
const handle = window.napplet.resource.bytesAsObjectURL('blossom:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.bin');
imgEl.src = handle.url; // populated once the underlying fetch resolves
// later
handle.revoke();
Expand All @@ -618,7 +618,7 @@ Four canonical schemes are supported:
|--------|---------|------------|
| `data:` | `data:image/png;base64,iVBORw0KGgo...` | Decoded in the napplet shim — zero shell round-trip |
| `https:` | `https://example.com/avatar.png` | Shell-side network fetch under policy (private-IP block at DNS time, MIME byte-sniffing, size cap, timeout, rate limit, redirect cap) |
| `blossom:sha256:<hex>` | `blossom:sha256:e3b0c44...` | Blossom hash → bytes; shell verifies hash before delivery |
| `blossom:<sha256>.<ext>` | `blossom:e3b0c44…b855.bin` | [BUD-10](https://github.com/hzrd149/blossom/blob/master/buds/10.md) Blossom URI → bytes; shell verifies hash before delivery |
| `nostr:<bech32>` | `nostr:nprofile1...` | Single-hop NIP-19 resolution against the shell's relay pool |

**Cancellation:** Pass an `AbortSignal` to cancel an in-flight fetch:
Expand Down Expand Up @@ -858,7 +858,7 @@ Only the canonical schemes plus shell-administrator opt-ins are dispatched. Smug

- [ ] `data:` (RFC 2397) — decoded in-shim with zero shell round-trip; size cap still applies on the decoded `Blob`
- [ ] `https:` — full Default Resource Policy applies
- [ ] `blossom:sha256:<hex>` — shell verifies hash against the URL's declared digest **before** delivery; mismatch → `code: "decode-failed"`
- [ ] `blossom:<sha256>.<ext>` ([BUD-10](https://github.com/hzrd149/blossom/blob/master/buds/10.md)) — shell verifies hash against the URL's declared digest **before** delivery; mismatch → `code: "decode-failed"`
- [ ] `nostr:<bech32>` — single-hop NIP-19 resolution; recursive resolution is **not** the shell's job

### Never enable by default
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
quick_id: 261014-fuc
type: quick
---

# Replace blossom:sha256 URIs with BUD-10 form

1. Replace every `blossom:sha256:<hex>` occurrence (packages, docs, specs, skills, tests, archived planning) with the BUD-10 `blossom:<sha256>.<ext>` form (`.bin` when the extension is unknown).
2. Link BUD-10 (https://github.com/hzrd149/blossom/blob/master/buds/10.md) from scheme descriptions and add `@see` tags to resource JSDoc.
3. Verify with type-check, unit tests, build; flag that canonical NAP-RESOURCE (napplet/naps#80) still names `blossom:sha256:<hex>`.
Loading
Loading