@elisym/sdk 0.25.1 → 0.25.3

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.cts CHANGED
@@ -227,6 +227,70 @@ declare const JobPayloadEnvelopeSchema: z.ZodObject<{
227
227
  transports: unknown[];
228
228
  seedingExpiresAt?: number | undefined;
229
229
  }>>;
230
+ attachments: z.ZodOptional<z.ZodArray<z.ZodObject<{
231
+ /** Display name only. Never used to derive a filesystem path (callers sanitize). */
232
+ name: z.ZodString;
233
+ /** Declared size in bytes (display/hint only; enforcement is on actual streamed bytes). */
234
+ size: z.ZodNumber;
235
+ mime: z.ZodString;
236
+ /**
237
+ * Ordered by sender preference; at least one KNOWN transport. Parsed leniently: unknown
238
+ * transport `kind`s are dropped (not rejected) so adding a new transport never makes an older
239
+ * decoder throw away the whole envelope - it just ignores the kinds it doesn't know and uses
240
+ * the ones it does. At least one known transport must survive, else the attachment is invalid.
241
+ */
242
+ transports: z.ZodEffects<z.ZodEffects<z.ZodArray<z.ZodUnknown, "many">, ({
243
+ kind: "iroh";
244
+ ticket: string;
245
+ } | {
246
+ kind: "blossom";
247
+ url: string;
248
+ sha256: string;
249
+ enc: {
250
+ alg: "AES-256-GCM";
251
+ iv: string;
252
+ key: string;
253
+ };
254
+ })[], unknown[]>, ({
255
+ kind: "iroh";
256
+ ticket: string;
257
+ } | {
258
+ kind: "blossom";
259
+ url: string;
260
+ sha256: string;
261
+ enc: {
262
+ alg: "AES-256-GCM";
263
+ iv: string;
264
+ key: string;
265
+ };
266
+ })[], unknown[]>;
267
+ /** Optional provider hint (unix seconds) for when seeding may stop. */
268
+ seedingExpiresAt: z.ZodOptional<z.ZodNumber>;
269
+ }, "strip", z.ZodTypeAny, {
270
+ name: string;
271
+ size: number;
272
+ mime: string;
273
+ transports: ({
274
+ kind: "iroh";
275
+ ticket: string;
276
+ } | {
277
+ kind: "blossom";
278
+ url: string;
279
+ sha256: string;
280
+ enc: {
281
+ alg: "AES-256-GCM";
282
+ iv: string;
283
+ key: string;
284
+ };
285
+ })[];
286
+ seedingExpiresAt?: number | undefined;
287
+ }, {
288
+ name: string;
289
+ size: number;
290
+ mime: string;
291
+ transports: unknown[];
292
+ seedingExpiresAt?: number | undefined;
293
+ }>, "many">>;
230
294
  }, "strip", z.ZodTypeAny, {
231
295
  v: "elisym-job/1";
232
296
  text?: string | undefined;
@@ -249,6 +313,25 @@ declare const JobPayloadEnvelopeSchema: z.ZodObject<{
249
313
  })[];
250
314
  seedingExpiresAt?: number | undefined;
251
315
  } | undefined;
316
+ attachments?: {
317
+ name: string;
318
+ size: number;
319
+ mime: string;
320
+ transports: ({
321
+ kind: "iroh";
322
+ ticket: string;
323
+ } | {
324
+ kind: "blossom";
325
+ url: string;
326
+ sha256: string;
327
+ enc: {
328
+ alg: "AES-256-GCM";
329
+ iv: string;
330
+ key: string;
331
+ };
332
+ })[];
333
+ seedingExpiresAt?: number | undefined;
334
+ }[] | undefined;
252
335
  }, {
253
336
  v: "elisym-job/1";
254
337
  text?: string | undefined;
@@ -259,6 +342,13 @@ declare const JobPayloadEnvelopeSchema: z.ZodObject<{
259
342
  transports: unknown[];
260
343
  seedingExpiresAt?: number | undefined;
261
344
  } | undefined;
345
+ attachments?: {
346
+ name: string;
347
+ size: number;
348
+ mime: string;
349
+ transports: unknown[];
350
+ seedingExpiresAt?: number | undefined;
351
+ }[] | undefined;
262
352
  }>;
263
353
  type FileTransport = z.infer<typeof FileTransportSchema>;
264
354
  type FileAttachment = z.infer<typeof FileAttachmentSchema>;
@@ -279,11 +369,20 @@ declare function buildAcceptTransportsTag(kinds: TransportKind[]): string[];
279
369
  * so this never strands a job.
280
370
  */
281
371
  declare function readAcceptedTransports(tags: string[][]): TransportKind[] | undefined;
282
- /** Decoded job payload: a free-text note and/or a file attachment. */
372
+ /** Decoded job payload: a free-text note and/or file attachment(s). */
283
373
  interface DecodedJobPayload {
284
374
  text?: string;
375
+ /** Legacy single attachment (also mirrors `attachments[0]`). */
285
376
  attachment?: FileAttachment;
377
+ /** All attachments when a job carries multiple files. */
378
+ attachments?: FileAttachment[];
286
379
  }
380
+ /**
381
+ * Normalize a decoded payload to the full attachment list, treating the legacy
382
+ * single `attachment` as a 1-element list. Use this everywhere instead of reading
383
+ * `.attachment`/`.attachments` directly, so single- and multi-file are uniform.
384
+ */
385
+ declare function attachmentsOf(decoded: DecodedJobPayload): FileAttachment[];
287
386
  /**
288
387
  * Serialize a job payload into the envelope string that goes (encrypted) into a
289
388
  * Nostr event's `content`. Used only when an attachment is present; plain-text
@@ -325,6 +424,13 @@ interface CapabilityCard {
325
424
  inputMime?: string;
326
425
  /** MIME of a file result the capability produces (from `output_mime`). */
327
426
  outputMime?: string;
427
+ /**
428
+ * Whether a file-input capability ALSO accepts a text prompt (from `input_text`):
429
+ * `'none'` = file only, `'optional'` = file + optional note, `'required'` = both.
430
+ * Discovery hint; the web app shows/hides its text box accordingly. Only meaningful
431
+ * with `inputMime`. Untrusted - gate on it, never render the raw value.
432
+ */
433
+ inputText?: 'required' | 'optional' | 'none';
328
434
  }
329
435
  /** Payment info embedded in capability card (legacy format for on-network events). */
330
436
  interface PaymentInfo {
@@ -457,11 +563,12 @@ interface JobUpdateCallbacks {
457
563
  onFeedback?: (status: string, amount?: number, paymentRequest?: string, senderPubkey?: string) => void;
458
564
  /**
459
565
  * Fired on a job result. `content` is the result text (for a file result, the
460
- * envelope's text note, or `''`); `attachment` is the file descriptor when the
461
- * result carries a file. The file is fetched separately (P2P via iroh), never
462
- * inlined here.
566
+ * envelope's text note, or `''`); `attachment` is the FIRST file descriptor
567
+ * (= `attachments[0]`, kept for back-compat); `attachments` is the full list for
568
+ * a multi-file result. Files are fetched separately (P2P via iroh / Blossom),
569
+ * never inlined here.
463
570
  */
464
- onResult?: (content: string, eventId: string, attachment?: FileAttachment) => void;
571
+ onResult?: (content: string, eventId: string, attachment?: FileAttachment, attachments?: FileAttachment[]) => void;
465
572
  onError?: (error: string) => void;
466
573
  /**
467
574
  * Fired when the result wait window expires without a result - a distinct,
@@ -676,6 +783,15 @@ declare class BlossomService {
676
783
  private serverUrl;
677
784
  private fallback?;
678
785
  constructor(serverUrl?: string, fallback?: BlossomUploadFallback | undefined);
786
+ /**
787
+ * The content-addressed GET URL for a blob, derivable from its sha256 BEFORE
788
+ * upload (BUD-01: `<serverUrl>/<sha256>`, no extension for our octet-stream
789
+ * ciphertext uploads - same form `delete` addresses by). Lets a caller build a
790
+ * complete attachment descriptor and defer the actual byte upload (the descriptor
791
+ * is submitted first, the bytes PUT later). `upload()` re-verifies the server
792
+ * returns this exact url.
793
+ */
794
+ contentUrl(sha256: string): string;
679
795
  /**
680
796
  * Upload a file to the Blossom server, returning its descriptor. On any failure, falls
681
797
  * back to the configured uploader (if any) and returns a normalized descriptor with
@@ -895,14 +1011,14 @@ declare class MarketplaceService {
895
1011
  */
896
1012
  subscribeToJobRequests(identity: ElisymIdentity, kinds: number[], onRequest: (event: Event) => void): SubCloser;
897
1013
  /** Submit a job result with NIP-44 encrypted content. Result kind is derived from the request kind. */
898
- submitJobResult(identity: ElisymIdentity, requestEvent: Event, content: string, amount?: number, attachment?: FileAttachment): Promise<string>;
1014
+ submitJobResult(identity: ElisymIdentity, requestEvent: Event, content: string, amount?: number, attachments?: FileAttachment[]): Promise<string>;
899
1015
  /**
900
1016
  * Submit a job result with retry and exponential backoff.
901
1017
  * Retries on publish failures (e.g. relay disconnects).
902
1018
  * With maxAttempts=3: try, ~1s, try, ~2s, try, throw.
903
1019
  * Jitter: 0.5x-1.0x of calculated delay.
904
1020
  */
905
- submitJobResultWithRetry(identity: ElisymIdentity, requestEvent: Event, content: string, amount?: number, maxAttempts?: number, baseDelayMs?: number, attachment?: FileAttachment): Promise<string>;
1021
+ submitJobResultWithRetry(identity: ElisymIdentity, requestEvent: Event, content: string, amount?: number, maxAttempts?: number, baseDelayMs?: number, attachments?: FileAttachment[]): Promise<string>;
906
1022
  /** Submit payment-required feedback with a payment request. */
907
1023
  submitPaymentRequiredFeedback(identity: ElisymIdentity, requestEvent: Event, amount: number, paymentRequestJson: string): Promise<void>;
908
1024
  /** Submit processing feedback to notify customer that work has started. */
@@ -1063,17 +1179,29 @@ declare function createBlossomTransport(opts: {
1063
1179
  }): BlossomBlobTransport;
1064
1180
 
1065
1181
  /**
1066
- * Customer-side helpers to send/receive ENCRYPTED file jobs over Blossom with no iroh/Node dependency
1067
- * (browser-safe). These are the seams a web app calls.
1182
+ * Encrypt `file` to `providerPubkey` and build a complete `FileAttachment` WITHOUT uploading the bytes
1183
+ * yet. Because Blossom is content-addressed, the blob URL is derivable from the ciphertext sha256, so the
1184
+ * caller can submit the job request with this descriptor and DEFER the byte upload (via the returned
1185
+ * `upload()`) until the customer commits - e.g. after the provider quotes a price, so an unresponsive
1186
+ * provider never costs a wasted upload. TARGETED jobs only (a recipient pubkey is required to encrypt).
1068
1187
  *
1069
- * Encrypted-Blossom needs a recipient pubkey, so a file INPUT is only meaningful on a TARGETED job (a
1070
- * chosen provider) - hence `buildEncryptedFileInput` requires `providerPubkey`. Broadcast file inputs
1071
- * are not supported here (no recipient to encrypt to); those stay on iroh.
1188
+ * `upload()` PUTs the ciphertext and verifies the server returns the precomputed url/sha256 (the request
1189
+ * already carries them, so a mismatch must fail loudly - pre-commit - rather than 404 the provider).
1072
1190
  */
1073
-
1191
+ declare function prepareEncryptedFileInput(args: {
1192
+ file: Blob & {
1193
+ name?: string;
1194
+ };
1195
+ providerPubkey: string;
1196
+ identity: ElisymIdentity;
1197
+ blossom: BlossomService;
1198
+ }): Promise<{
1199
+ attachment: FileAttachment;
1200
+ upload: () => Promise<void>;
1201
+ }>;
1074
1202
  /**
1075
- * Encrypt `file` to `providerPubkey` and upload the ciphertext to Blossom, returning a `FileAttachment`
1076
- * with a single `blossom` transport. TARGETED jobs only (a recipient pubkey is required to encrypt).
1203
+ * Encrypt `file` to `providerPubkey` AND upload it immediately, returning the `FileAttachment`
1204
+ * (prepare + upload in one step). Use `prepareEncryptedFileInput` when you want to defer the upload.
1077
1205
  */
1078
1206
  declare function buildEncryptedFileInput(args: {
1079
1207
  file: Blob & {
@@ -1725,6 +1853,7 @@ declare const DEFAULTS: {
1725
1853
  readonly QUERY_MAX_CONCURRENCY: 6;
1726
1854
  readonly VERIFY_SIGNATURE_LIMIT: 25;
1727
1855
  readonly IROH_FETCH_TIMEOUT_MS: 300000;
1856
+ readonly IROH_SEED_TIMEOUT_MS: 120000;
1728
1857
  readonly BLOSSOM_UPLOAD_TIMEOUT_MS: 300000;
1729
1858
  readonly BLOSSOM_FETCH_TIMEOUT_MS: 300000;
1730
1859
  };
@@ -1756,4 +1885,4 @@ declare const LIMITS: {
1756
1885
  */
1757
1886
  declare function utf8ByteLength(value: string): number;
1758
1887
 
1759
- export { ACCEPT_TRANSPORTS_TAG, type Agent, type AgentPolicy, type AggregateNetworkStatsOptions, Asset, type BlobDescriptor, type BlossomBlobTransport, BlossomService, type BlossomUploadFallback, BoundedSet, type BuildTransactionOptions, type CapabilityCard, DEFAULTS, DEFAULT_KIND_OFFSET, DEFAULT_REDACT_PATHS, type DecodedJobPayload, DiscoveryService, ELISYM_PROTOCOL_TAG, ENVELOPE_VERSION, ElisymClient, type ElisymClientConfig, type ElisymClientFullConfig, ElisymIdentity, type EncryptedBytes, type EstimatePriorityFeeOptions, type EstimateSolFeeOptions, type FileAttachment, type FileTransport, type GetProtocolConfigOptions, INPUT_REDACT_PATHS, type Job, type JobErrorKind, type JobPayloadEnvelope, type JobStatus, type JobSubscriptionOptions, type JobUpdateCallbacks, JobWaitTimeoutError, KIND_APP_HANDLER, KIND_JOB_FEEDBACK, KIND_JOB_REQUEST, KIND_JOB_REQUEST_BASE, KIND_JOB_RESULT, KIND_JOB_RESULT_BASE, KIND_LONG_FORM_ARTICLE, KIND_PING, KIND_PONG, LAMPORTS_PER_SOL, LIMITS, MarketplaceService, MediaService, type Network, type NetworkBaselineEstimate, type NetworkBaselineOptions, type NetworkStats, type NetworkStatsResult, NostrPool, type OnchainNetworkStats, POLICY_D_TAG_PREFIX, POLICY_TYPE_REGEX, POLICY_T_TAG, PROTOCOL_PROGRAM_ID_DEVNET, type ParseOptions, type ParseResult, type ParsedPaymentRequest, type PaymentAssetRef, type PaymentInfo, type PaymentRequestData, PaymentRequestSchema, type PaymentStrategy, type PaymentValidationCode, type PaymentValidationError, type PingResult, PingService, PoliciesService, type PolicyInput, type ProtocolCluster, type ProtocolConfig, type ProtocolConfigInput, type QuickVerifyReason, type QuickVerifyResult, RELAYS, type RankKey, SECRET_REDACT_PATHS, type Signer, type SolFeeEstimate, SolanaPaymentStrategy, type SubCloser, type SubmitJobOptions, type TransportKind, type VerifyOptions, type VerifyResult, aggregateNetworkStats, assertExpiry, assertLamports, buildAcceptTransportsTag, buildEncryptedFileInput, buildPaymentInstructions, calculateProtocolFee, classifyJobError, clearPriorityFeeCache, clearProtocolConfigCache, clearQuickVerifyCache, compareAgentsByRank, computeRankKey, createBlossomTransport, createPaymentRequestWithOnchainConfig, decodeJobPayload, decryptBytesFromSender, encodeJobPayload, encryptBytesForRecipient, estimateNetworkBaseline, estimatePriorityFeeMicroLamports, estimateSolFeeLamports, fetchEncryptedFileOutput, formatFeeBreakdown, formatNetworkBaseline, formatSol, getNetworkStats, getProtocolConfig, getProtocolProgramId, jobRequestKind, jobResultKind, makeCensor, nip44Decrypt, nip44Encrypt, parsePaymentRequest, pickPercentileFee, readAcceptedTransports, timeAgo, toDTag, truncateKey, utf8ByteLength, validateAgentName, validateExpiry, verifyJobPaymentQuick };
1888
+ export { ACCEPT_TRANSPORTS_TAG, type Agent, type AgentPolicy, type AggregateNetworkStatsOptions, Asset, type BlobDescriptor, type BlossomBlobTransport, BlossomService, type BlossomUploadFallback, BoundedSet, type BuildTransactionOptions, type CapabilityCard, DEFAULTS, DEFAULT_KIND_OFFSET, DEFAULT_REDACT_PATHS, type DecodedJobPayload, DiscoveryService, ELISYM_PROTOCOL_TAG, ENVELOPE_VERSION, ElisymClient, type ElisymClientConfig, type ElisymClientFullConfig, ElisymIdentity, type EncryptedBytes, type EstimatePriorityFeeOptions, type EstimateSolFeeOptions, type FileAttachment, type FileTransport, type GetProtocolConfigOptions, INPUT_REDACT_PATHS, type Job, type JobErrorKind, type JobPayloadEnvelope, type JobStatus, type JobSubscriptionOptions, type JobUpdateCallbacks, JobWaitTimeoutError, KIND_APP_HANDLER, KIND_JOB_FEEDBACK, KIND_JOB_REQUEST, KIND_JOB_REQUEST_BASE, KIND_JOB_RESULT, KIND_JOB_RESULT_BASE, KIND_LONG_FORM_ARTICLE, KIND_PING, KIND_PONG, LAMPORTS_PER_SOL, LIMITS, MarketplaceService, MediaService, type Network, type NetworkBaselineEstimate, type NetworkBaselineOptions, type NetworkStats, type NetworkStatsResult, NostrPool, type OnchainNetworkStats, POLICY_D_TAG_PREFIX, POLICY_TYPE_REGEX, POLICY_T_TAG, PROTOCOL_PROGRAM_ID_DEVNET, type ParseOptions, type ParseResult, type ParsedPaymentRequest, type PaymentAssetRef, type PaymentInfo, type PaymentRequestData, PaymentRequestSchema, type PaymentStrategy, type PaymentValidationCode, type PaymentValidationError, type PingResult, PingService, PoliciesService, type PolicyInput, type ProtocolCluster, type ProtocolConfig, type ProtocolConfigInput, type QuickVerifyReason, type QuickVerifyResult, RELAYS, type RankKey, SECRET_REDACT_PATHS, type Signer, type SolFeeEstimate, SolanaPaymentStrategy, type SubCloser, type SubmitJobOptions, type TransportKind, type VerifyOptions, type VerifyResult, aggregateNetworkStats, assertExpiry, assertLamports, attachmentsOf, buildAcceptTransportsTag, buildEncryptedFileInput, buildPaymentInstructions, calculateProtocolFee, classifyJobError, clearPriorityFeeCache, clearProtocolConfigCache, clearQuickVerifyCache, compareAgentsByRank, computeRankKey, createBlossomTransport, createPaymentRequestWithOnchainConfig, decodeJobPayload, decryptBytesFromSender, encodeJobPayload, encryptBytesForRecipient, estimateNetworkBaseline, estimatePriorityFeeMicroLamports, estimateSolFeeLamports, fetchEncryptedFileOutput, formatFeeBreakdown, formatNetworkBaseline, formatSol, getNetworkStats, getProtocolConfig, getProtocolProgramId, jobRequestKind, jobResultKind, makeCensor, nip44Decrypt, nip44Encrypt, parsePaymentRequest, pickPercentileFee, prepareEncryptedFileInput, readAcceptedTransports, timeAgo, toDTag, truncateKey, utf8ByteLength, validateAgentName, validateExpiry, verifyJobPaymentQuick };
package/dist/index.d.ts CHANGED
@@ -227,6 +227,70 @@ declare const JobPayloadEnvelopeSchema: z.ZodObject<{
227
227
  transports: unknown[];
228
228
  seedingExpiresAt?: number | undefined;
229
229
  }>>;
230
+ attachments: z.ZodOptional<z.ZodArray<z.ZodObject<{
231
+ /** Display name only. Never used to derive a filesystem path (callers sanitize). */
232
+ name: z.ZodString;
233
+ /** Declared size in bytes (display/hint only; enforcement is on actual streamed bytes). */
234
+ size: z.ZodNumber;
235
+ mime: z.ZodString;
236
+ /**
237
+ * Ordered by sender preference; at least one KNOWN transport. Parsed leniently: unknown
238
+ * transport `kind`s are dropped (not rejected) so adding a new transport never makes an older
239
+ * decoder throw away the whole envelope - it just ignores the kinds it doesn't know and uses
240
+ * the ones it does. At least one known transport must survive, else the attachment is invalid.
241
+ */
242
+ transports: z.ZodEffects<z.ZodEffects<z.ZodArray<z.ZodUnknown, "many">, ({
243
+ kind: "iroh";
244
+ ticket: string;
245
+ } | {
246
+ kind: "blossom";
247
+ url: string;
248
+ sha256: string;
249
+ enc: {
250
+ alg: "AES-256-GCM";
251
+ iv: string;
252
+ key: string;
253
+ };
254
+ })[], unknown[]>, ({
255
+ kind: "iroh";
256
+ ticket: string;
257
+ } | {
258
+ kind: "blossom";
259
+ url: string;
260
+ sha256: string;
261
+ enc: {
262
+ alg: "AES-256-GCM";
263
+ iv: string;
264
+ key: string;
265
+ };
266
+ })[], unknown[]>;
267
+ /** Optional provider hint (unix seconds) for when seeding may stop. */
268
+ seedingExpiresAt: z.ZodOptional<z.ZodNumber>;
269
+ }, "strip", z.ZodTypeAny, {
270
+ name: string;
271
+ size: number;
272
+ mime: string;
273
+ transports: ({
274
+ kind: "iroh";
275
+ ticket: string;
276
+ } | {
277
+ kind: "blossom";
278
+ url: string;
279
+ sha256: string;
280
+ enc: {
281
+ alg: "AES-256-GCM";
282
+ iv: string;
283
+ key: string;
284
+ };
285
+ })[];
286
+ seedingExpiresAt?: number | undefined;
287
+ }, {
288
+ name: string;
289
+ size: number;
290
+ mime: string;
291
+ transports: unknown[];
292
+ seedingExpiresAt?: number | undefined;
293
+ }>, "many">>;
230
294
  }, "strip", z.ZodTypeAny, {
231
295
  v: "elisym-job/1";
232
296
  text?: string | undefined;
@@ -249,6 +313,25 @@ declare const JobPayloadEnvelopeSchema: z.ZodObject<{
249
313
  })[];
250
314
  seedingExpiresAt?: number | undefined;
251
315
  } | undefined;
316
+ attachments?: {
317
+ name: string;
318
+ size: number;
319
+ mime: string;
320
+ transports: ({
321
+ kind: "iroh";
322
+ ticket: string;
323
+ } | {
324
+ kind: "blossom";
325
+ url: string;
326
+ sha256: string;
327
+ enc: {
328
+ alg: "AES-256-GCM";
329
+ iv: string;
330
+ key: string;
331
+ };
332
+ })[];
333
+ seedingExpiresAt?: number | undefined;
334
+ }[] | undefined;
252
335
  }, {
253
336
  v: "elisym-job/1";
254
337
  text?: string | undefined;
@@ -259,6 +342,13 @@ declare const JobPayloadEnvelopeSchema: z.ZodObject<{
259
342
  transports: unknown[];
260
343
  seedingExpiresAt?: number | undefined;
261
344
  } | undefined;
345
+ attachments?: {
346
+ name: string;
347
+ size: number;
348
+ mime: string;
349
+ transports: unknown[];
350
+ seedingExpiresAt?: number | undefined;
351
+ }[] | undefined;
262
352
  }>;
263
353
  type FileTransport = z.infer<typeof FileTransportSchema>;
264
354
  type FileAttachment = z.infer<typeof FileAttachmentSchema>;
@@ -279,11 +369,20 @@ declare function buildAcceptTransportsTag(kinds: TransportKind[]): string[];
279
369
  * so this never strands a job.
280
370
  */
281
371
  declare function readAcceptedTransports(tags: string[][]): TransportKind[] | undefined;
282
- /** Decoded job payload: a free-text note and/or a file attachment. */
372
+ /** Decoded job payload: a free-text note and/or file attachment(s). */
283
373
  interface DecodedJobPayload {
284
374
  text?: string;
375
+ /** Legacy single attachment (also mirrors `attachments[0]`). */
285
376
  attachment?: FileAttachment;
377
+ /** All attachments when a job carries multiple files. */
378
+ attachments?: FileAttachment[];
286
379
  }
380
+ /**
381
+ * Normalize a decoded payload to the full attachment list, treating the legacy
382
+ * single `attachment` as a 1-element list. Use this everywhere instead of reading
383
+ * `.attachment`/`.attachments` directly, so single- and multi-file are uniform.
384
+ */
385
+ declare function attachmentsOf(decoded: DecodedJobPayload): FileAttachment[];
287
386
  /**
288
387
  * Serialize a job payload into the envelope string that goes (encrypted) into a
289
388
  * Nostr event's `content`. Used only when an attachment is present; plain-text
@@ -325,6 +424,13 @@ interface CapabilityCard {
325
424
  inputMime?: string;
326
425
  /** MIME of a file result the capability produces (from `output_mime`). */
327
426
  outputMime?: string;
427
+ /**
428
+ * Whether a file-input capability ALSO accepts a text prompt (from `input_text`):
429
+ * `'none'` = file only, `'optional'` = file + optional note, `'required'` = both.
430
+ * Discovery hint; the web app shows/hides its text box accordingly. Only meaningful
431
+ * with `inputMime`. Untrusted - gate on it, never render the raw value.
432
+ */
433
+ inputText?: 'required' | 'optional' | 'none';
328
434
  }
329
435
  /** Payment info embedded in capability card (legacy format for on-network events). */
330
436
  interface PaymentInfo {
@@ -457,11 +563,12 @@ interface JobUpdateCallbacks {
457
563
  onFeedback?: (status: string, amount?: number, paymentRequest?: string, senderPubkey?: string) => void;
458
564
  /**
459
565
  * Fired on a job result. `content` is the result text (for a file result, the
460
- * envelope's text note, or `''`); `attachment` is the file descriptor when the
461
- * result carries a file. The file is fetched separately (P2P via iroh), never
462
- * inlined here.
566
+ * envelope's text note, or `''`); `attachment` is the FIRST file descriptor
567
+ * (= `attachments[0]`, kept for back-compat); `attachments` is the full list for
568
+ * a multi-file result. Files are fetched separately (P2P via iroh / Blossom),
569
+ * never inlined here.
463
570
  */
464
- onResult?: (content: string, eventId: string, attachment?: FileAttachment) => void;
571
+ onResult?: (content: string, eventId: string, attachment?: FileAttachment, attachments?: FileAttachment[]) => void;
465
572
  onError?: (error: string) => void;
466
573
  /**
467
574
  * Fired when the result wait window expires without a result - a distinct,
@@ -676,6 +783,15 @@ declare class BlossomService {
676
783
  private serverUrl;
677
784
  private fallback?;
678
785
  constructor(serverUrl?: string, fallback?: BlossomUploadFallback | undefined);
786
+ /**
787
+ * The content-addressed GET URL for a blob, derivable from its sha256 BEFORE
788
+ * upload (BUD-01: `<serverUrl>/<sha256>`, no extension for our octet-stream
789
+ * ciphertext uploads - same form `delete` addresses by). Lets a caller build a
790
+ * complete attachment descriptor and defer the actual byte upload (the descriptor
791
+ * is submitted first, the bytes PUT later). `upload()` re-verifies the server
792
+ * returns this exact url.
793
+ */
794
+ contentUrl(sha256: string): string;
679
795
  /**
680
796
  * Upload a file to the Blossom server, returning its descriptor. On any failure, falls
681
797
  * back to the configured uploader (if any) and returns a normalized descriptor with
@@ -895,14 +1011,14 @@ declare class MarketplaceService {
895
1011
  */
896
1012
  subscribeToJobRequests(identity: ElisymIdentity, kinds: number[], onRequest: (event: Event) => void): SubCloser;
897
1013
  /** Submit a job result with NIP-44 encrypted content. Result kind is derived from the request kind. */
898
- submitJobResult(identity: ElisymIdentity, requestEvent: Event, content: string, amount?: number, attachment?: FileAttachment): Promise<string>;
1014
+ submitJobResult(identity: ElisymIdentity, requestEvent: Event, content: string, amount?: number, attachments?: FileAttachment[]): Promise<string>;
899
1015
  /**
900
1016
  * Submit a job result with retry and exponential backoff.
901
1017
  * Retries on publish failures (e.g. relay disconnects).
902
1018
  * With maxAttempts=3: try, ~1s, try, ~2s, try, throw.
903
1019
  * Jitter: 0.5x-1.0x of calculated delay.
904
1020
  */
905
- submitJobResultWithRetry(identity: ElisymIdentity, requestEvent: Event, content: string, amount?: number, maxAttempts?: number, baseDelayMs?: number, attachment?: FileAttachment): Promise<string>;
1021
+ submitJobResultWithRetry(identity: ElisymIdentity, requestEvent: Event, content: string, amount?: number, maxAttempts?: number, baseDelayMs?: number, attachments?: FileAttachment[]): Promise<string>;
906
1022
  /** Submit payment-required feedback with a payment request. */
907
1023
  submitPaymentRequiredFeedback(identity: ElisymIdentity, requestEvent: Event, amount: number, paymentRequestJson: string): Promise<void>;
908
1024
  /** Submit processing feedback to notify customer that work has started. */
@@ -1063,17 +1179,29 @@ declare function createBlossomTransport(opts: {
1063
1179
  }): BlossomBlobTransport;
1064
1180
 
1065
1181
  /**
1066
- * Customer-side helpers to send/receive ENCRYPTED file jobs over Blossom with no iroh/Node dependency
1067
- * (browser-safe). These are the seams a web app calls.
1182
+ * Encrypt `file` to `providerPubkey` and build a complete `FileAttachment` WITHOUT uploading the bytes
1183
+ * yet. Because Blossom is content-addressed, the blob URL is derivable from the ciphertext sha256, so the
1184
+ * caller can submit the job request with this descriptor and DEFER the byte upload (via the returned
1185
+ * `upload()`) until the customer commits - e.g. after the provider quotes a price, so an unresponsive
1186
+ * provider never costs a wasted upload. TARGETED jobs only (a recipient pubkey is required to encrypt).
1068
1187
  *
1069
- * Encrypted-Blossom needs a recipient pubkey, so a file INPUT is only meaningful on a TARGETED job (a
1070
- * chosen provider) - hence `buildEncryptedFileInput` requires `providerPubkey`. Broadcast file inputs
1071
- * are not supported here (no recipient to encrypt to); those stay on iroh.
1188
+ * `upload()` PUTs the ciphertext and verifies the server returns the precomputed url/sha256 (the request
1189
+ * already carries them, so a mismatch must fail loudly - pre-commit - rather than 404 the provider).
1072
1190
  */
1073
-
1191
+ declare function prepareEncryptedFileInput(args: {
1192
+ file: Blob & {
1193
+ name?: string;
1194
+ };
1195
+ providerPubkey: string;
1196
+ identity: ElisymIdentity;
1197
+ blossom: BlossomService;
1198
+ }): Promise<{
1199
+ attachment: FileAttachment;
1200
+ upload: () => Promise<void>;
1201
+ }>;
1074
1202
  /**
1075
- * Encrypt `file` to `providerPubkey` and upload the ciphertext to Blossom, returning a `FileAttachment`
1076
- * with a single `blossom` transport. TARGETED jobs only (a recipient pubkey is required to encrypt).
1203
+ * Encrypt `file` to `providerPubkey` AND upload it immediately, returning the `FileAttachment`
1204
+ * (prepare + upload in one step). Use `prepareEncryptedFileInput` when you want to defer the upload.
1077
1205
  */
1078
1206
  declare function buildEncryptedFileInput(args: {
1079
1207
  file: Blob & {
@@ -1725,6 +1853,7 @@ declare const DEFAULTS: {
1725
1853
  readonly QUERY_MAX_CONCURRENCY: 6;
1726
1854
  readonly VERIFY_SIGNATURE_LIMIT: 25;
1727
1855
  readonly IROH_FETCH_TIMEOUT_MS: 300000;
1856
+ readonly IROH_SEED_TIMEOUT_MS: 120000;
1728
1857
  readonly BLOSSOM_UPLOAD_TIMEOUT_MS: 300000;
1729
1858
  readonly BLOSSOM_FETCH_TIMEOUT_MS: 300000;
1730
1859
  };
@@ -1756,4 +1885,4 @@ declare const LIMITS: {
1756
1885
  */
1757
1886
  declare function utf8ByteLength(value: string): number;
1758
1887
 
1759
- export { ACCEPT_TRANSPORTS_TAG, type Agent, type AgentPolicy, type AggregateNetworkStatsOptions, Asset, type BlobDescriptor, type BlossomBlobTransport, BlossomService, type BlossomUploadFallback, BoundedSet, type BuildTransactionOptions, type CapabilityCard, DEFAULTS, DEFAULT_KIND_OFFSET, DEFAULT_REDACT_PATHS, type DecodedJobPayload, DiscoveryService, ELISYM_PROTOCOL_TAG, ENVELOPE_VERSION, ElisymClient, type ElisymClientConfig, type ElisymClientFullConfig, ElisymIdentity, type EncryptedBytes, type EstimatePriorityFeeOptions, type EstimateSolFeeOptions, type FileAttachment, type FileTransport, type GetProtocolConfigOptions, INPUT_REDACT_PATHS, type Job, type JobErrorKind, type JobPayloadEnvelope, type JobStatus, type JobSubscriptionOptions, type JobUpdateCallbacks, JobWaitTimeoutError, KIND_APP_HANDLER, KIND_JOB_FEEDBACK, KIND_JOB_REQUEST, KIND_JOB_REQUEST_BASE, KIND_JOB_RESULT, KIND_JOB_RESULT_BASE, KIND_LONG_FORM_ARTICLE, KIND_PING, KIND_PONG, LAMPORTS_PER_SOL, LIMITS, MarketplaceService, MediaService, type Network, type NetworkBaselineEstimate, type NetworkBaselineOptions, type NetworkStats, type NetworkStatsResult, NostrPool, type OnchainNetworkStats, POLICY_D_TAG_PREFIX, POLICY_TYPE_REGEX, POLICY_T_TAG, PROTOCOL_PROGRAM_ID_DEVNET, type ParseOptions, type ParseResult, type ParsedPaymentRequest, type PaymentAssetRef, type PaymentInfo, type PaymentRequestData, PaymentRequestSchema, type PaymentStrategy, type PaymentValidationCode, type PaymentValidationError, type PingResult, PingService, PoliciesService, type PolicyInput, type ProtocolCluster, type ProtocolConfig, type ProtocolConfigInput, type QuickVerifyReason, type QuickVerifyResult, RELAYS, type RankKey, SECRET_REDACT_PATHS, type Signer, type SolFeeEstimate, SolanaPaymentStrategy, type SubCloser, type SubmitJobOptions, type TransportKind, type VerifyOptions, type VerifyResult, aggregateNetworkStats, assertExpiry, assertLamports, buildAcceptTransportsTag, buildEncryptedFileInput, buildPaymentInstructions, calculateProtocolFee, classifyJobError, clearPriorityFeeCache, clearProtocolConfigCache, clearQuickVerifyCache, compareAgentsByRank, computeRankKey, createBlossomTransport, createPaymentRequestWithOnchainConfig, decodeJobPayload, decryptBytesFromSender, encodeJobPayload, encryptBytesForRecipient, estimateNetworkBaseline, estimatePriorityFeeMicroLamports, estimateSolFeeLamports, fetchEncryptedFileOutput, formatFeeBreakdown, formatNetworkBaseline, formatSol, getNetworkStats, getProtocolConfig, getProtocolProgramId, jobRequestKind, jobResultKind, makeCensor, nip44Decrypt, nip44Encrypt, parsePaymentRequest, pickPercentileFee, readAcceptedTransports, timeAgo, toDTag, truncateKey, utf8ByteLength, validateAgentName, validateExpiry, verifyJobPaymentQuick };
1888
+ export { ACCEPT_TRANSPORTS_TAG, type Agent, type AgentPolicy, type AggregateNetworkStatsOptions, Asset, type BlobDescriptor, type BlossomBlobTransport, BlossomService, type BlossomUploadFallback, BoundedSet, type BuildTransactionOptions, type CapabilityCard, DEFAULTS, DEFAULT_KIND_OFFSET, DEFAULT_REDACT_PATHS, type DecodedJobPayload, DiscoveryService, ELISYM_PROTOCOL_TAG, ENVELOPE_VERSION, ElisymClient, type ElisymClientConfig, type ElisymClientFullConfig, ElisymIdentity, type EncryptedBytes, type EstimatePriorityFeeOptions, type EstimateSolFeeOptions, type FileAttachment, type FileTransport, type GetProtocolConfigOptions, INPUT_REDACT_PATHS, type Job, type JobErrorKind, type JobPayloadEnvelope, type JobStatus, type JobSubscriptionOptions, type JobUpdateCallbacks, JobWaitTimeoutError, KIND_APP_HANDLER, KIND_JOB_FEEDBACK, KIND_JOB_REQUEST, KIND_JOB_REQUEST_BASE, KIND_JOB_RESULT, KIND_JOB_RESULT_BASE, KIND_LONG_FORM_ARTICLE, KIND_PING, KIND_PONG, LAMPORTS_PER_SOL, LIMITS, MarketplaceService, MediaService, type Network, type NetworkBaselineEstimate, type NetworkBaselineOptions, type NetworkStats, type NetworkStatsResult, NostrPool, type OnchainNetworkStats, POLICY_D_TAG_PREFIX, POLICY_TYPE_REGEX, POLICY_T_TAG, PROTOCOL_PROGRAM_ID_DEVNET, type ParseOptions, type ParseResult, type ParsedPaymentRequest, type PaymentAssetRef, type PaymentInfo, type PaymentRequestData, PaymentRequestSchema, type PaymentStrategy, type PaymentValidationCode, type PaymentValidationError, type PingResult, PingService, PoliciesService, type PolicyInput, type ProtocolCluster, type ProtocolConfig, type ProtocolConfigInput, type QuickVerifyReason, type QuickVerifyResult, RELAYS, type RankKey, SECRET_REDACT_PATHS, type Signer, type SolFeeEstimate, SolanaPaymentStrategy, type SubCloser, type SubmitJobOptions, type TransportKind, type VerifyOptions, type VerifyResult, aggregateNetworkStats, assertExpiry, assertLamports, attachmentsOf, buildAcceptTransportsTag, buildEncryptedFileInput, buildPaymentInstructions, calculateProtocolFee, classifyJobError, clearPriorityFeeCache, clearProtocolConfigCache, clearQuickVerifyCache, compareAgentsByRank, computeRankKey, createBlossomTransport, createPaymentRequestWithOnchainConfig, decodeJobPayload, decryptBytesFromSender, encodeJobPayload, encryptBytesForRecipient, estimateNetworkBaseline, estimatePriorityFeeMicroLamports, estimateSolFeeLamports, fetchEncryptedFileOutput, formatFeeBreakdown, formatNetworkBaseline, formatSol, getNetworkStats, getProtocolConfig, getProtocolProgramId, jobRequestKind, jobResultKind, makeCensor, nip44Decrypt, nip44Encrypt, parsePaymentRequest, pickPercentileFee, prepareEncryptedFileInput, readAcceptedTransports, timeAgo, toDTag, truncateKey, utf8ByteLength, validateAgentName, validateExpiry, verifyJobPaymentQuick };