@kehto/services 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +243 -58
- package/dist/index.js +279 -159
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ServiceHandler, Signer } from '@kehto/runtime';
|
|
2
|
-
import {
|
|
2
|
+
import { NostrFilter, NostrEvent, EventTemplate } from '@napplet/core';
|
|
3
3
|
import { MediaMetadata, MediaAction } from '@napplet/nub/media/types';
|
|
4
4
|
export { MediaAction } from '@napplet/nub/media/types';
|
|
5
5
|
import { NotifySendMessage } from '@napplet/nub/notify/types';
|
|
@@ -181,53 +181,19 @@ declare function createNotificationService(options?: NotificationServiceOptions)
|
|
|
181
181
|
* - signer.nip04.encrypt/decrypt -> DELETED
|
|
182
182
|
* - signer.nip44.encrypt/decrypt -> DELETED (shell encrypts internally
|
|
183
183
|
* inside relay.publishEncrypted)
|
|
184
|
-
* - identity.decrypt -> ADDED in v1.8 as a shell-mediated decrypt request
|
|
185
|
-
* with class gate + typed error union.
|
|
186
184
|
*
|
|
187
|
-
*
|
|
185
|
+
* Identity is strictly read-only per NAP-IDENTITY: napplets learn *about* the
|
|
186
|
+
* user but cannot act *as* the user — no signing, encryption, or decryption.
|
|
187
|
+
* (An `identity.decrypt` capability was briefly added in v1.8 and removed as a
|
|
188
|
+
* spec violation; decryption belongs to the runtime, inline over the wire.)
|
|
188
189
|
*
|
|
189
|
-
* Handles
|
|
190
|
+
* Handles 9 identity.* request types from @napplet/nub/identity. getPublicKey
|
|
190
191
|
* and getRelays return real values sourced from hooks.auth.getSigner(); the
|
|
191
192
|
* remaining 7 (getProfile/getFollows/getList/getZaps/getMutes/getBlocked/
|
|
192
|
-
* getBadges) are stub-level
|
|
193
|
-
*
|
|
193
|
+
* getBadges) are stub-level. Host apps plug real backends via
|
|
194
|
+
* runtime.registerService('identity', realHandler).
|
|
194
195
|
*/
|
|
195
196
|
|
|
196
|
-
type IdentityDecryptErrorCode = 'class-forbidden' | 'signer-denied' | 'signer-unavailable' | 'decrypt-failed' | 'malformed-wrap' | 'impersonation' | 'unsupported-encryption' | 'policy-denied';
|
|
197
|
-
interface Rumor {
|
|
198
|
-
id: string;
|
|
199
|
-
pubkey: string;
|
|
200
|
-
created_at: number;
|
|
201
|
-
kind: number;
|
|
202
|
-
tags: string[][];
|
|
203
|
-
content: string;
|
|
204
|
-
}
|
|
205
|
-
interface IdentityDecryptMessage extends NappletMessage {
|
|
206
|
-
type: 'identity.decrypt';
|
|
207
|
-
id: string;
|
|
208
|
-
event: NostrEvent;
|
|
209
|
-
}
|
|
210
|
-
interface IdentityDecryptResultMessage extends NappletMessage {
|
|
211
|
-
type: 'identity.decrypt.result';
|
|
212
|
-
id: string;
|
|
213
|
-
rumor: Rumor;
|
|
214
|
-
sender: string;
|
|
215
|
-
}
|
|
216
|
-
interface IdentityDecryptErrorMessage extends NappletMessage {
|
|
217
|
-
type: 'identity.decrypt.error';
|
|
218
|
-
id: string;
|
|
219
|
-
error: IdentityDecryptErrorCode;
|
|
220
|
-
}
|
|
221
|
-
interface GiftWrapDecryptResult {
|
|
222
|
-
seal: NostrEvent;
|
|
223
|
-
rumor: Rumor;
|
|
224
|
-
}
|
|
225
|
-
interface HostDecryptBridge {
|
|
226
|
-
nip04Decrypt(senderPubkey: string, ciphertext: string): Promise<string>;
|
|
227
|
-
nip44Decrypt(senderPubkey: string, ciphertext: string): Promise<string>;
|
|
228
|
-
unwrapGiftWrap(wrap: NostrEvent): Promise<GiftWrapDecryptResult>;
|
|
229
|
-
}
|
|
230
|
-
type VerifyEvent = (event: NostrEvent) => boolean | Promise<boolean>;
|
|
231
197
|
/**
|
|
232
198
|
* Options for creating the identity service.
|
|
233
199
|
*
|
|
@@ -246,27 +212,14 @@ interface IdentityServiceOptions {
|
|
|
246
212
|
* availability can change dynamically.
|
|
247
213
|
*/
|
|
248
214
|
getSigner: () => Signer | null;
|
|
249
|
-
/**
|
|
250
|
-
* Return the host decrypt bridge. Called only after outer event signature
|
|
251
|
-
* verification and encryption-mode detection succeed. Null means decrypt is
|
|
252
|
-
* unavailable while the rest of the identity service remains usable.
|
|
253
|
-
*/
|
|
254
|
-
getDecryptor?: () => HostDecryptBridge | null;
|
|
255
|
-
/**
|
|
256
|
-
* Verify a received event before any decrypt attempt. Host shells should
|
|
257
|
-
* wire this to their canonical Nostr event verifier; tests and old hosts
|
|
258
|
-
* default to true for backward compatibility with the 9 read-only actions.
|
|
259
|
-
*/
|
|
260
|
-
verifyEvent?: VerifyEvent;
|
|
261
215
|
}
|
|
262
216
|
/**
|
|
263
217
|
* Create an identity service that handles NIP-5D identity.* envelope messages.
|
|
264
218
|
*
|
|
265
|
-
* Supports
|
|
266
|
-
*
|
|
219
|
+
* Supports the 9 read-only identity.* request types from @napplet/nub/identity.
|
|
220
|
+
* The two nostr-info queries (getPublicKey, getRelays) resolve through the
|
|
267
221
|
* caller-supplied signer; the remaining 7 return default/empty payloads with
|
|
268
222
|
* spec-correct envelope shapes so napplets always receive a result envelope.
|
|
269
|
-
* identity.decrypt delegates to the host decrypt bridge.
|
|
270
223
|
*
|
|
271
224
|
* @param options - Identity service configuration (getSigner)
|
|
272
225
|
* @returns A ServiceHandler ready for runtime.registerService('identity', handler)
|
|
@@ -1796,4 +1749,236 @@ interface RelayPoolOutboxRouterOptions {
|
|
|
1796
1749
|
*/
|
|
1797
1750
|
declare function createRelayPoolOutboxRouter(options: RelayPoolOutboxRouterOptions): OutboxRouter;
|
|
1798
1751
|
|
|
1799
|
-
|
|
1752
|
+
/**
|
|
1753
|
+
* upload-service.ts — NAP-UPLOAD (shell-mediated file/blob upload) reference service.
|
|
1754
|
+
*
|
|
1755
|
+
* Shell-side handler for the NAP-UPLOAD wire protocol. It is a pure envelope
|
|
1756
|
+
* router: it validates `upload.*` envelopes, delegates the actual byte transfer
|
|
1757
|
+
* (server selection, rail authorization signing, the HTTP upload) to an injected
|
|
1758
|
+
* {@link Uploader}, and posts the correlated result / status messages back to the
|
|
1759
|
+
* napplet.
|
|
1760
|
+
*
|
|
1761
|
+
* The uploader is injected (options-as-bridge) so this service has no transport
|
|
1762
|
+
* or Nostr dependency and is fully unit-testable. NAP-UPLOAD is deliberately
|
|
1763
|
+
* abstract over the backend — the runtime decides *how* it uploads (NIP-96,
|
|
1764
|
+
* Blossom, …). A concrete HTTP-backed uploader ships alongside as
|
|
1765
|
+
* {@link createHttpUploader}.
|
|
1766
|
+
*
|
|
1767
|
+
* ──────────────────────────── Responsibilities ────────────────────────────
|
|
1768
|
+
* Inbound: upload.upload, upload.status
|
|
1769
|
+
* Outbound: upload.upload.result, upload.status.result, upload.status.changed
|
|
1770
|
+
*
|
|
1771
|
+
* The service owns the `uploadId` (generated per request, scoped to the
|
|
1772
|
+
* requesting napplet), tracks the latest {@link UploadStatus} per upload for
|
|
1773
|
+
* `upload.status` queries, and cleans up on window teardown. The shell owns
|
|
1774
|
+
* consent, policy, server selection, signing, and the HTTP upload — all behind
|
|
1775
|
+
* the {@link Uploader}.
|
|
1776
|
+
*
|
|
1777
|
+
* @example
|
|
1778
|
+
* ```ts
|
|
1779
|
+
* import { createUploadService, createHttpUploader } from '@kehto/services';
|
|
1780
|
+
*
|
|
1781
|
+
* const uploader = createHttpUploader({ rails: { nip96: { servers } }, signEvent });
|
|
1782
|
+
* runtime.registerService('upload', createUploadService({ uploader }));
|
|
1783
|
+
* ```
|
|
1784
|
+
*
|
|
1785
|
+
* @packageDocumentation
|
|
1786
|
+
*/
|
|
1787
|
+
|
|
1788
|
+
/**
|
|
1789
|
+
* Storage rail. `nip96` (NIP-96 HTTP file storage) and `blossom` (Blossom blob
|
|
1790
|
+
* storage) are the first concrete backends; the open string keeps the API
|
|
1791
|
+
* stable as shells add rails (torrents, usenet, …).
|
|
1792
|
+
*/
|
|
1793
|
+
type UploadRail = 'nip96' | 'blossom' | (string & {});
|
|
1794
|
+
/** Lifecycle state of an upload. */
|
|
1795
|
+
type UploadState = 'pending' | 'uploading' | 'complete' | 'failed' | 'cancelled';
|
|
1796
|
+
/** Pixel dimensions of an uploaded image/video. */
|
|
1797
|
+
interface UploadDimensions {
|
|
1798
|
+
width: number;
|
|
1799
|
+
height: number;
|
|
1800
|
+
}
|
|
1801
|
+
/**
|
|
1802
|
+
* A napplet's upload request. `data` crosses the postMessage boundary by
|
|
1803
|
+
* structured clone — shells never require base64 encoding.
|
|
1804
|
+
*/
|
|
1805
|
+
interface UploadRequest {
|
|
1806
|
+
/** Storage rail; omit to let the shell pick a configured default. */
|
|
1807
|
+
rail?: UploadRail;
|
|
1808
|
+
/** The bytes to upload. */
|
|
1809
|
+
data: ArrayBuffer | Blob;
|
|
1810
|
+
/** MIME type; inferred from `data` when omitted. */
|
|
1811
|
+
mimeType?: string;
|
|
1812
|
+
/** Suggested filename. */
|
|
1813
|
+
filename?: string;
|
|
1814
|
+
/** Alt text / description for the file event. */
|
|
1815
|
+
caption?: string;
|
|
1816
|
+
/** Request the server not re-encode the file (NIP-96 `no_transform`). */
|
|
1817
|
+
noTransform?: boolean;
|
|
1818
|
+
/** Rail-specific or shell-specific extra metadata. */
|
|
1819
|
+
metadata?: Record<string, unknown>;
|
|
1820
|
+
}
|
|
1821
|
+
/** A single Nostr tag (NIP-94 / imeta entries are arrays of strings). */
|
|
1822
|
+
type NostrTag = string[];
|
|
1823
|
+
/** The result of an upload. */
|
|
1824
|
+
interface UploadResult {
|
|
1825
|
+
/** Whether the upload succeeded (or is progressing) vs failed/cancelled. */
|
|
1826
|
+
ok: boolean;
|
|
1827
|
+
/** Shell-generated id, scoped to the requesting napplet. */
|
|
1828
|
+
uploadId: string;
|
|
1829
|
+
/** Current lifecycle state. */
|
|
1830
|
+
status: UploadState;
|
|
1831
|
+
/** The rail the shell used. */
|
|
1832
|
+
rail: UploadRail;
|
|
1833
|
+
/** Primary download URL. */
|
|
1834
|
+
url?: string;
|
|
1835
|
+
/** Mirrors / alternative server URLs. */
|
|
1836
|
+
fallbackUrls?: string[];
|
|
1837
|
+
/** Hash of the stored blob (NIP-94 `x`). */
|
|
1838
|
+
sha256?: string;
|
|
1839
|
+
/** Hash before server transforms (NIP-94 `ox`). */
|
|
1840
|
+
originalSha256?: string;
|
|
1841
|
+
/** Size in bytes. */
|
|
1842
|
+
size?: number;
|
|
1843
|
+
/** Stored MIME type. */
|
|
1844
|
+
mimeType?: string;
|
|
1845
|
+
/** Image/video dimensions when known. */
|
|
1846
|
+
dimensions?: UploadDimensions;
|
|
1847
|
+
/** Blurhash placeholder when known. */
|
|
1848
|
+
blurhash?: string;
|
|
1849
|
+
/** Ready-to-attach NIP-94 / imeta tags. */
|
|
1850
|
+
nip94?: NostrTag[];
|
|
1851
|
+
/** Error reason when the upload failed or was cancelled. */
|
|
1852
|
+
error?: string;
|
|
1853
|
+
}
|
|
1854
|
+
/** A status snapshot for an upload, including progress counters. */
|
|
1855
|
+
interface UploadStatus extends UploadResult {
|
|
1856
|
+
/** Bytes sent so far (while uploading). */
|
|
1857
|
+
bytesSent?: number;
|
|
1858
|
+
/** Total bytes to send. */
|
|
1859
|
+
bytesTotal?: number;
|
|
1860
|
+
/** Unix ms timestamp of this status. */
|
|
1861
|
+
updatedAt: number;
|
|
1862
|
+
}
|
|
1863
|
+
/**
|
|
1864
|
+
* Context handed to an {@link Uploader} for a single upload. Carries the
|
|
1865
|
+
* service-owned `uploadId` and a sink for streaming progress / state changes.
|
|
1866
|
+
*/
|
|
1867
|
+
interface UploaderContext {
|
|
1868
|
+
/** The service-generated upload id (authoritative; scoped to the napplet). */
|
|
1869
|
+
uploadId: string;
|
|
1870
|
+
/** The napplet window that requested the upload. */
|
|
1871
|
+
windowId: string;
|
|
1872
|
+
/**
|
|
1873
|
+
* Push a status update (progress, or a transition to complete/failed). The
|
|
1874
|
+
* service stamps `uploadId` and `updatedAt` before forwarding to the napplet
|
|
1875
|
+
* as `upload.status.changed`, and records it as the latest tracked status.
|
|
1876
|
+
*/
|
|
1877
|
+
onStatus(status: UploadStatus): void;
|
|
1878
|
+
}
|
|
1879
|
+
/**
|
|
1880
|
+
* Abstract upload backend. Implementors own server selection, rail
|
|
1881
|
+
* authorization signing (NIP-98 for NIP-96, kind 24242 for Blossom), the HTTP
|
|
1882
|
+
* upload, and integrity-hash reporting. The service translates wire envelopes
|
|
1883
|
+
* into these calls and back. A concrete reference implementation ships as
|
|
1884
|
+
* {@link createHttpUploader}.
|
|
1885
|
+
*/
|
|
1886
|
+
interface Uploader {
|
|
1887
|
+
/** Upload `request.data`, streaming progress through `ctx.onStatus`. */
|
|
1888
|
+
upload(request: UploadRequest, ctx: UploaderContext): Promise<UploadResult>;
|
|
1889
|
+
/** Optional: resolve the latest status for an upload the service is not tracking. */
|
|
1890
|
+
status?(uploadId: string): Promise<UploadStatus | undefined>;
|
|
1891
|
+
/** Optional: abort an in-flight upload (called on window teardown). */
|
|
1892
|
+
cancel?(uploadId: string): void;
|
|
1893
|
+
}
|
|
1894
|
+
/** Options for {@link createUploadService}. */
|
|
1895
|
+
interface UploadServiceOptions {
|
|
1896
|
+
/** The upload backend the shell uses. Required. */
|
|
1897
|
+
uploader: Uploader;
|
|
1898
|
+
/** Generate an upload id; defaults to `crypto.randomUUID()`. */
|
|
1899
|
+
generateId?: () => string;
|
|
1900
|
+
/** Current time in unix ms; defaults to `Date.now()`. */
|
|
1901
|
+
now?: () => number;
|
|
1902
|
+
}
|
|
1903
|
+
/**
|
|
1904
|
+
* Create the NAP-UPLOAD service handler.
|
|
1905
|
+
*
|
|
1906
|
+
* @param options - Must provide an {@link Uploader}.
|
|
1907
|
+
* @returns A `ServiceHandler` ready for `runtime.registerService('upload', handler)`.
|
|
1908
|
+
* @throws If `options.uploader` is missing.
|
|
1909
|
+
*/
|
|
1910
|
+
declare function createUploadService(options: UploadServiceOptions): ServiceHandler;
|
|
1911
|
+
|
|
1912
|
+
/**
|
|
1913
|
+
* http-uploader.ts — NAP-UPLOAD concrete HTTP-backed {@link Uploader}.
|
|
1914
|
+
*
|
|
1915
|
+
* The reference upload backend for {@link createUploadService}. Implements two
|
|
1916
|
+
* storage rails over HTTP:
|
|
1917
|
+
*
|
|
1918
|
+
* - **NIP-96** — signs a NIP-98 (kind 27235) HTTP-auth event, POSTs the file as
|
|
1919
|
+
* `multipart/form-data`, and maps the returned NIP-94 event tags into an
|
|
1920
|
+
* {@link UploadResult}.
|
|
1921
|
+
* - **Blossom** — signs a kind 24242 authorization event, PUTs the raw bytes to
|
|
1922
|
+
* `<server>/upload`, and maps the returned blob descriptor.
|
|
1923
|
+
*
|
|
1924
|
+
* Signing (`signEvent`) and transport (`fetch`) are injected so the uploader
|
|
1925
|
+
* carries no Nostr or network dependency and is fully unit-testable. The shell
|
|
1926
|
+
* holds the signing key and never exposes it to napplets — the uploader only
|
|
1927
|
+
* receives a signing callback. Server URLs are shell configuration, not napplet
|
|
1928
|
+
* input: a napplet may *hint* a rail, but never a server.
|
|
1929
|
+
*
|
|
1930
|
+
* The configured server URL is used directly as the upload endpoint (the
|
|
1931
|
+
* NIP-96 `api_url` / Blossom base). Hosts that need `.well-known` discovery can
|
|
1932
|
+
* resolve it before constructing the uploader.
|
|
1933
|
+
*
|
|
1934
|
+
* @example
|
|
1935
|
+
* ```ts
|
|
1936
|
+
* const uploader = createHttpUploader({
|
|
1937
|
+
* rails: { nip96: { servers: ['https://nostr.build/api/v2/nip96/upload'] } },
|
|
1938
|
+
* signEvent: (tmpl) => signer.signEvent(tmpl),
|
|
1939
|
+
* });
|
|
1940
|
+
* runtime.registerService('upload', createUploadService({ uploader }));
|
|
1941
|
+
* ```
|
|
1942
|
+
*
|
|
1943
|
+
* @packageDocumentation
|
|
1944
|
+
*/
|
|
1945
|
+
|
|
1946
|
+
/** Per-rail server configuration. The first server is the primary endpoint. */
|
|
1947
|
+
interface RailServerConfig {
|
|
1948
|
+
/** Ordered server endpoint URLs; index 0 is primary. */
|
|
1949
|
+
servers: string[];
|
|
1950
|
+
}
|
|
1951
|
+
/** Storage rails this uploader can serve. */
|
|
1952
|
+
interface HttpUploaderRails {
|
|
1953
|
+
/** NIP-96 HTTP file storage. */
|
|
1954
|
+
nip96?: RailServerConfig;
|
|
1955
|
+
/** Blossom blob storage. */
|
|
1956
|
+
blossom?: RailServerConfig;
|
|
1957
|
+
}
|
|
1958
|
+
/** Signs an event template on the user's behalf (shell holds the key). */
|
|
1959
|
+
type SignEvent = (template: EventTemplate) => Promise<NostrEvent>;
|
|
1960
|
+
/** Options for {@link createHttpUploader}. */
|
|
1961
|
+
interface HttpUploaderOptions {
|
|
1962
|
+
/** Configured rails + their servers. */
|
|
1963
|
+
rails: HttpUploaderRails;
|
|
1964
|
+
/** Rail to use when a request omits one; defaults to the first configured rail. */
|
|
1965
|
+
defaultRail?: UploadRail;
|
|
1966
|
+
/** Signs NIP-98 / Blossom auth events. Required. */
|
|
1967
|
+
signEvent: SignEvent;
|
|
1968
|
+
/** Fetch implementation; defaults to the global `fetch`. */
|
|
1969
|
+
fetch?: typeof fetch;
|
|
1970
|
+
/** Hex SHA-256 of the payload bytes; defaults to Web Crypto. */
|
|
1971
|
+
digestSha256?: (bytes: Uint8Array) => Promise<string>;
|
|
1972
|
+
/** Unix *seconds* clock for event timestamps; defaults to `Date.now()/1000`. */
|
|
1973
|
+
now?: () => number;
|
|
1974
|
+
}
|
|
1975
|
+
/**
|
|
1976
|
+
* Create the reference HTTP {@link Uploader} (NIP-96 + Blossom rails).
|
|
1977
|
+
*
|
|
1978
|
+
* @param options - Rails, server config, and the injected `signEvent`.
|
|
1979
|
+
* @returns An {@link Uploader} for `createUploadService({ uploader })`.
|
|
1980
|
+
* @throws If `options.signEvent` is missing.
|
|
1981
|
+
*/
|
|
1982
|
+
declare function createHttpUploader(options: HttpUploaderOptions): Uploader;
|
|
1983
|
+
|
|
1984
|
+
export { type AudioServiceOptions, type AudioSource, type CacheServiceOptions, type ConfigSchemaValidation, type ConfigService, type ConfigServiceOptions, type CoordinatedRelayOptions, type HostCacheBridge, type HostKeyEvent, type HostKeysBridge, type HostMediaBridge, type HttpUploaderOptions, type HttpUploaderRails, type IdentityServiceOptions, type KeysServiceOptions, type MediaMetadataLike, type MediaPlaybackOwner, type MediaServiceOptions, type MediaSessionCreateOptions, type MediaSessionTarget, type MediaSourceRef, type NostrTag, type Notification, type NotificationServiceOptions, type NotifyServiceOptions, type OutboxPublishOptions, type OutboxPublishResult, type OutboxQueryOptions, type OutboxRelayPlan, type OutboxRelayPool, type OutboxResult, type OutboxRouter, type OutboxRouterSubscription, type OutboxServiceOptions, type OutboxStrategy, type OutboxSubscribeOptions, type OutboxSubscriptionSink, type OutboxTarget, type RailServerConfig, type RelayListEntry, type RelayPoolOutboxRouterOptions, type RelayPoolServiceOptions, type ResourceService, type ResourceServiceOptions, type SignEvent, type ThemeService, type ThemeServiceOptions, type UploadDimensions, type UploadRail, type UploadRequest, type UploadResult, type UploadServiceOptions, type UploadState, type UploadStatus, type Uploader, type UploaderContext, createAudioService, createBrowserMediaBridge, createCacheService, createConfigService, createCoordinatedRelay, createHttpUploader, createIdentityService, createKeysService, createMediaService, createNotificationService, createNotifyService, createOutboxService, createRelayPoolOutboxRouter, createRelayPoolService, createResourceService, createThemeService, createUploadService };
|