Skip to content

NAP-UPLOAD: shell-mediated file and blob upload - #33

Open
dskvr wants to merge 5 commits into
masterfrom
nap-upload
Open

NAP-UPLOAD: shell-mediated file and blob upload#33
dskvr wants to merge 5 commits into
masterfrom
nap-upload

Conversation

@dskvr

@dskvr dskvr commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds NAP-UPLOAD, a shell-mediated upload interface for napplets. Napplets can inspect coarse upload rail support with optional upload.info, then hand the shell raw bytes plus upload intent. The shell selects or validates a rail, signs rail authorization, performs the upload, reports progress/status, and returns URL plus integrity metadata for attaching the result to Nostr events.

The interface is named around uploading rather than any single protocol so shells can support multiple storage rails without changing the napplet API. NIP-96 HTTP file storage and Blossom blob storage are the first concrete backends; result metadata follows NIP-94 so a napplet can publish a file event or build an imeta tag through NAP-RELAY.

Namespace

window.napplet.upload

Status

draft

Changes

  • Defines upload.info, upload.upload, upload.status, and shell-pushed upload.status.changed.
  • Keeps upload.info advisory; it is not a required preflight before upload.upload.
  • Models rails as nip96, blossom, or runtime-defined strings.
  • Returns sha256 / originalSha256, URL/fallback URLs, MIME, dimensions, blurhash, and ready-to-attach NIP-94 tags when available.
  • Keeps server selection, credentials, NIP-98/BUD authorization signing, quota/MIME policy, progress, and consent runtime-owned.

Downstream

Napplets submit file bytes and intent, not signing keys, server credentials, or direct HTTP access. Runtimes can expose coarse rail availability for UI adaptation while preserving the direct upload path for callers that skip introspection.

Reference

  • NIP-5D napplet transport and shell boundary
  • NIP-96 (HTTP file storage), Blossom (blob storage), NIP-94 (file metadata), NIP-98 (HTTP auth)

Changelog

  • 5dd8458 - Introduced NAP-UPLOAD for shell-mediated file and blob upload.
  • ef147c9 - Added upload.info rail introspection for supported upload rails and policy limits.

@dskvr

dskvr commented Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

fix code smell upload.upload

Rebased onto current master; spec only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Upload operations, request data, result metadata, status records, and rail/status enums now use operation tables plus CDDL-style schemas instead of TypeScript declarations.

Constraint: Keep this branch scoped to NAP-UPLOAD.
Confidence: high
Scope-risk: narrow
Tested: git diff --check
Tested: rg found no TypeScript code fences or declarations in naps/NAP-UPLOAD.md
@hzrd149

hzrd149 commented Jun 25, 2026

Copy link
Copy Markdown

I think NAP-UPLOAD is missing a small introspection endpoint.

Suggested addition:

upload.info() -> UploadInfo

Purpose: let napplets optionally inspect which upload rails the runtime supports, without making rail selection mandatory.

Example shape:

UploadInfo = {
  rails: [* UploadRailInfo],
  ? maxBytes: uint,
  ? mimeTypes: [* tstr],
}

UploadRailInfo = {
  rail: tstr,          ; "nip96" / "blossom" / ...
  enabled: bool,
  ? returns: [* tstr], ; URI/result forms, e.g. "https" / "blossom"
}

Important semantics:

  • Napplets MAY call upload.info() to adapt UI or intentionally choose a rail.
  • Napplets MUST NOT be required to call info() before upload().
  • upload({ data, ... }) with no rail should remain the simple/default path: the runtime selects the best configured rail according to user/runtime policy.
  • If rail is supplied, the runtime SHOULD honor it when supported and allowed; otherwise return unsupported rail.

This preserves runtime-owned defaults while giving advanced napplets a clean way to discover supported protocols and expected returned URI forms.

NAP-UPLOAD needs a way for napplets to inspect supported upload rails and coarse limits without making rail choice mandatory. The new info operation is advisory, keeps default rail selection in the shell when request.rail is omitted, and lets explicit rail requests fail through the existing policy boundary.

Constraint: Upload rail selection and credentials remain runtime-owned.
Rejected: Require info() before upload(request) | would make introspection part of the default flow and weaken runtime-owned defaults.
Rejected: Expose server URLs or credentials | would leak shell configuration across the seam.
Confidence: high
Scope-risk: narrow
Directive: Keep upload.info advisory; do not turn it into a mandatory capability negotiation step.
Tested: git diff --check; targeted rg consistency check for upload.info, UploadInfo, request.rail, unsupported rail, and policy denied wording.
Not-tested: Runtime implementation; spec-only change.

Co-authored-by: sandwich <dskvr@users.noreply.github.com>
@dskvr dskvr removed the NEEDS WORK label Jun 28, 2026
@dskvr
dskvr marked this pull request as ready for review June 28, 2026 12:21
dskvr added 2 commits July 3, 2026 13:14
The upload rail, info, request, result, status, and dimension shapes now use Markdown tables instead of a CDDL-style block. Rail introspection and NIP-94 metadata semantics remain unchanged.

Constraint: PR #33 owns NAP-UPLOAD; keep this change scoped to that spec file.

Confidence: high

Scope-risk: narrow

Tested: rg for cddl/typescript schema fences and type assignment patterns in NAP-UPLOAD

Tested: git diff --check -- naps/NAP-UPLOAD.md
Open NAP proposal branches need reader-visible changelogs that track semantic spec changes without recording formatting-only migrations.

Constraint: Changelog entries are one bullet per semantic commit-change.
Rejected: Include schema-table or formatting-only commits | they do not change the spec contract or boundary.
Confidence: high
Scope-risk: narrow
Directive: Keep future changelog entries semantic; omit changelog-only and formatting-only commits.
Tested: git diff --check
Not-tested: Rendered Markdown
@jodobear

Copy link
Copy Markdown
Collaborator

While implementing Blossom uploads in Kehto/Paja, we added ordered replication across configured servers. The first verified upload is returned as url, with later verified copies in fallbackUrls. Failures for individual servers remain internal to the host.

The current NAP-UPLOAD result cannot describe what happened for each attempted server when some replicas fail and others succeed. Would per-attempt outcomes or machine-readable error codes be useful here, while keeping url and fallbackUrls backward compatible?

This is implementation feedback, not a proposed schema. Kehto has not added any custom wire fields.

@hzrd149

hzrd149 commented Aug 1, 2026

Copy link
Copy Markdown

The current NAP-UPLOAD result cannot describe what happened for each attempted server when some replicas fail and others succeed. Would per-attempt outcomes or machine-readable error codes be useful here, while keeping url and fallbackUrls backward compatible?

The napplet that is using this api shouldn't care or be aware of what protocol is being used. IMO the intent with this api is to upload bytes from a napplet and return a single publicly accessible URL

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants