@elisym/sdk 0.24.1 → 0.25.1

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.js CHANGED
@@ -4,7 +4,7 @@ import { getTransferSolInstruction } from '@solana-program/system';
4
4
  import { findAssociatedTokenPda, TOKEN_PROGRAM_ADDRESS, getCreateAssociatedTokenIdempotentInstruction, ASSOCIATED_TOKEN_PROGRAM_ADDRESS, getTransferCheckedInstruction } from '@solana-program/token';
5
5
  import Decimal3 from 'decimal.js-light';
6
6
  import { z } from 'zod';
7
- import { verifyEvent, finalizeEvent, getPublicKey, nip19, generateSecretKey, SimplePool } from 'nostr-tools';
7
+ import { finalizeEvent, verifyEvent, getPublicKey, nip19, generateSecretKey, SimplePool } from 'nostr-tools';
8
8
  import * as nip44 from 'nostr-tools/nip44';
9
9
 
10
10
  // src/constants.ts
@@ -72,7 +72,12 @@ var DEFAULTS = {
72
72
  // Default ceiling for a single iroh file transfer (seed/fetch). A tunable
73
73
  // default, not a protocol constant - the transfer is resumable and its own
74
74
  // budget, decoupled from the result-wait window.
75
- IROH_FETCH_TIMEOUT_MS: 3e5
75
+ IROH_FETCH_TIMEOUT_MS: 3e5,
76
+ // Ceiling for a single Blossom blob upload (PUT /upload). Large blobs (up to
77
+ // LIMITS.MAX_FILE_SIZE) need far more than the 30s used for small media images.
78
+ BLOSSOM_UPLOAD_TIMEOUT_MS: 3e5,
79
+ // Ceiling for a single encrypted Blossom blob download (GET). Same budget as upload.
80
+ BLOSSOM_FETCH_TIMEOUT_MS: 3e5
76
81
  };
77
82
  var LIMITS = {
78
83
  MAX_INPUT_LENGTH: 1e5,
@@ -97,6 +102,12 @@ var LIMITS = {
97
102
  // providers may lower it per deployment.
98
103
  MAX_FILE_SIZE: 1073741824,
99
104
  // 1 GiB
105
+ // Cap for the ENCRYPTED Blossom path (web/SDK). The encrypt-then-upload flow is
106
+ // whole-buffer in WebCrypto + BlossomService (~3x file-size peak RAM), so this is
107
+ // deliberately far below MAX_FILE_SIZE to stay safe in a browser tab; larger files
108
+ // use iroh. The relay enforces a ~128 MiB server-side backstop.
109
+ MAX_BLOSSOM_ENCRYPTED_BYTES: 104857600,
110
+ // 100 MiB
100
111
  MAX_TIMEOUT_SECS: 600,
101
112
  // Upper bound for execution budgets (`max_execution_secs` / `execution_timeout_secs`).
102
113
  // Distinct from MAX_TIMEOUT_SECS (the result-wait cap): execution budgets may be
@@ -1175,6 +1186,180 @@ async function createPaymentRequestWithOnchainConfig(rpc, programId, recipient,
1175
1186
  options
1176
1187
  );
1177
1188
  }
1189
+ var KIND_BLOSSOM_AUTH = 24242;
1190
+ var DEFAULT_BLOSSOM_URL = "https://files.elisym.network";
1191
+ var AUTH_TTL_SECS = 600;
1192
+ var BlossomService = class {
1193
+ constructor(serverUrl = DEFAULT_BLOSSOM_URL, fallback) {
1194
+ this.serverUrl = serverUrl;
1195
+ this.fallback = fallback;
1196
+ }
1197
+ /**
1198
+ * Upload a file to the Blossom server, returning its descriptor. On any failure, falls
1199
+ * back to the configured uploader (if any) and returns a normalized descriptor with
1200
+ * `provider: 'fallback'`. Works with browser File objects and Node.js/Bun Blobs.
1201
+ */
1202
+ async upload(identity, file) {
1203
+ const bytes = new Uint8Array(await file.arrayBuffer());
1204
+ if (bytes.byteLength > LIMITS.MAX_FILE_SIZE) {
1205
+ throw new Error(
1206
+ `File too large: ${bytes.byteLength} bytes exceeds limit of ${LIMITS.MAX_FILE_SIZE}.`
1207
+ );
1208
+ }
1209
+ const hashBuffer = await crypto.subtle.digest("SHA-256", bytes);
1210
+ const hashHex = [...new Uint8Array(hashBuffer)].map((b) => b.toString(16).padStart(2, "0")).join("");
1211
+ try {
1212
+ return await this.uploadToBlossom(identity, bytes, hashHex, file.type);
1213
+ } catch (err) {
1214
+ if (!this.fallback) {
1215
+ throw err;
1216
+ }
1217
+ const url = await this.fallback(identity, file);
1218
+ return {
1219
+ url,
1220
+ sha256: hashHex,
1221
+ size: file.size,
1222
+ type: file.type || "application/octet-stream",
1223
+ provider: "fallback"
1224
+ };
1225
+ }
1226
+ }
1227
+ /** Delete a blob by sha256 (BUD-02). Blossom only - there is no fallback for deletes. */
1228
+ async delete(identity, sha256) {
1229
+ if (!/^[0-9a-f]{64}$/.test(sha256)) {
1230
+ throw new Error("sha256 must be 64 lowercase hex chars.");
1231
+ }
1232
+ const authHeader = this.authHeader(identity, "delete", sha256);
1233
+ const controller = new AbortController();
1234
+ const timer = setTimeout(() => controller.abort(), DEFAULTS.BLOSSOM_UPLOAD_TIMEOUT_MS);
1235
+ try {
1236
+ const res = await fetch(`${this.serverUrl}/${sha256}`, {
1237
+ method: "DELETE",
1238
+ headers: { Authorization: authHeader },
1239
+ signal: controller.signal
1240
+ });
1241
+ if (!res.ok) {
1242
+ throw new Error(`Delete failed: ${res.status} ${res.statusText}`);
1243
+ }
1244
+ } finally {
1245
+ clearTimeout(timer);
1246
+ }
1247
+ }
1248
+ /**
1249
+ * Download a public blob (BUD-01 GET, no auth). Bounds memory on the ACTUAL streamed bytes (never
1250
+ * the declared Content-Length) and verifies the sha256 when `expectedSha256` is given. Browser-safe.
1251
+ */
1252
+ async download(url, opts = {}) {
1253
+ const maxBytes = opts.maxBytes ?? LIMITS.MAX_FILE_SIZE;
1254
+ const controller = new AbortController();
1255
+ const timer = setTimeout(
1256
+ () => controller.abort(),
1257
+ opts.timeoutMs ?? DEFAULTS.BLOSSOM_FETCH_TIMEOUT_MS
1258
+ );
1259
+ try {
1260
+ const res = await fetch(url, { signal: controller.signal });
1261
+ if (!res.ok) {
1262
+ throw new Error(`Download failed: ${res.status} ${res.statusText}`);
1263
+ }
1264
+ const declared = Number(res.headers.get("content-length"));
1265
+ if (Number.isFinite(declared) && declared > maxBytes) {
1266
+ throw new Error(`Blob too large: ${declared} bytes exceeds limit of ${maxBytes}.`);
1267
+ }
1268
+ if (!res.body) {
1269
+ throw new Error("Download response has no body.");
1270
+ }
1271
+ const reader = res.body.getReader();
1272
+ const chunks = [];
1273
+ let total = 0;
1274
+ let chunk = await reader.read();
1275
+ while (!chunk.done) {
1276
+ total += chunk.value.byteLength;
1277
+ if (total > maxBytes) {
1278
+ await reader.cancel();
1279
+ throw new Error(`Blob exceeds limit of ${maxBytes} bytes.`);
1280
+ }
1281
+ chunks.push(chunk.value);
1282
+ chunk = await reader.read();
1283
+ }
1284
+ const bytes = new Uint8Array(total);
1285
+ let offset = 0;
1286
+ for (const c of chunks) {
1287
+ bytes.set(c, offset);
1288
+ offset += c.byteLength;
1289
+ }
1290
+ if (opts.expectedSha256 !== void 0) {
1291
+ const digest = await crypto.subtle.digest("SHA-256", bytes);
1292
+ const hashHex = [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, "0")).join("");
1293
+ if (hashHex !== opts.expectedSha256) {
1294
+ throw new Error(
1295
+ `Download integrity check failed: got ${hashHex}, expected ${opts.expectedSha256}.`
1296
+ );
1297
+ }
1298
+ }
1299
+ return bytes;
1300
+ } finally {
1301
+ clearTimeout(timer);
1302
+ }
1303
+ }
1304
+ async uploadToBlossom(identity, bytes, hashHex, mime) {
1305
+ const contentType = mime || "application/octet-stream";
1306
+ const authHeader = this.authHeader(identity, "upload", hashHex);
1307
+ const controller = new AbortController();
1308
+ const timer = setTimeout(() => controller.abort(), DEFAULTS.BLOSSOM_UPLOAD_TIMEOUT_MS);
1309
+ try {
1310
+ const res = await fetch(`${this.serverUrl}/upload`, {
1311
+ method: "PUT",
1312
+ headers: { Authorization: authHeader, "Content-Type": contentType },
1313
+ body: bytes,
1314
+ signal: controller.signal
1315
+ });
1316
+ if (!res.ok) {
1317
+ throw new Error(`Upload failed: ${res.status} ${res.statusText}`);
1318
+ }
1319
+ let data;
1320
+ try {
1321
+ data = await res.json();
1322
+ } catch {
1323
+ throw new Error("Invalid response from Blossom server.");
1324
+ }
1325
+ if (!data.url || !data.sha256) {
1326
+ throw new Error("No descriptor returned from Blossom server.");
1327
+ }
1328
+ if (data.sha256 !== hashHex) {
1329
+ throw new Error(
1330
+ `Blossom upload integrity check failed: server returned ${data.sha256}, expected ${hashHex}.`
1331
+ );
1332
+ }
1333
+ return {
1334
+ url: data.url,
1335
+ sha256: data.sha256,
1336
+ size: data.size ?? bytes.byteLength,
1337
+ type: data.type ?? contentType,
1338
+ uploaded: data.uploaded,
1339
+ provider: "blossom"
1340
+ };
1341
+ } finally {
1342
+ clearTimeout(timer);
1343
+ }
1344
+ }
1345
+ authHeader(identity, verb, sha256) {
1346
+ const now = Math.floor(Date.now() / 1e3);
1347
+ const authEvent = finalizeEvent(
1348
+ {
1349
+ kind: KIND_BLOSSOM_AUTH,
1350
+ created_at: now,
1351
+ tags: [
1352
+ ["t", verb],
1353
+ ["x", sha256],
1354
+ ["expiration", String(now + AUTH_TTL_SECS)]
1355
+ ],
1356
+ content: `${verb} blob via elisym SDK`
1357
+ },
1358
+ identity.secretKey
1359
+ );
1360
+ return "Nostr " + btoa(JSON.stringify(authEvent));
1361
+ }
1362
+ };
1178
1363
  var RANKING_ACTIVITY_WINDOW_SECS = 30 * 24 * 60 * 60;
1179
1364
  var RANKING_BUCKET_SIZE_SECS = 60;
1180
1365
  var COLD_START_BUCKET = -Infinity;
@@ -1831,6 +2016,26 @@ var FileTransportSchema = z.discriminatedUnion("kind", [
1831
2016
  kind: z.literal("iroh"),
1832
2017
  /** Opaque iroh `BlobTicket` string. Parsed into a real ticket only at fetch time. */
1833
2018
  ticket: z.string().min(1).max(MAX_TICKET_LENGTH)
2019
+ }),
2020
+ z.object({
2021
+ kind: z.literal("blossom"),
2022
+ /** Public HTTP(S) URL of the CIPHERTEXT blob on a Blossom relay. */
2023
+ url: z.string().url().max(2048),
2024
+ /** sha256 (lowercase hex) of the ciphertext - what the relay stores and addresses. */
2025
+ sha256: z.string().regex(/^[0-9a-f]{64}$/),
2026
+ /**
2027
+ * Hybrid-encryption parameters. The file bytes are AES-256-GCM encrypted with a random
2028
+ * content key; that key is NIP-44-wrapped to the recipient. `name`/`mime`/`size` on the
2029
+ * attachment describe the PLAINTEXT and live only inside the (encrypted) envelope - never
2030
+ * sent to the relay (the relay only ever sees opaque ciphertext).
2031
+ */
2032
+ enc: z.object({
2033
+ alg: z.literal("AES-256-GCM"),
2034
+ /** base64 12-byte GCM IV (non-secret). */
2035
+ iv: z.string().min(1).max(64),
2036
+ /** NIP-44-wrapped content key. */
2037
+ key: z.string().min(1).max(2048)
2038
+ })
1834
2039
  })
1835
2040
  ]);
1836
2041
  var FileAttachmentSchema = z.object({
@@ -1839,8 +2044,18 @@ var FileAttachmentSchema = z.object({
1839
2044
  /** Declared size in bytes (display/hint only; enforcement is on actual streamed bytes). */
1840
2045
  size: z.number().int().nonnegative(),
1841
2046
  mime: z.string().min(1).max(255),
1842
- /** Ordered by sender preference; at least one. */
1843
- transports: z.array(FileTransportSchema).min(1),
2047
+ /**
2048
+ * Ordered by sender preference; at least one KNOWN transport. Parsed leniently: unknown
2049
+ * transport `kind`s are dropped (not rejected) so adding a new transport never makes an older
2050
+ * decoder throw away the whole envelope - it just ignores the kinds it doesn't know and uses
2051
+ * the ones it does. At least one known transport must survive, else the attachment is invalid.
2052
+ */
2053
+ transports: z.array(z.unknown()).transform(
2054
+ (arr) => arr.flatMap((t) => {
2055
+ const parsed = FileTransportSchema.safeParse(t);
2056
+ return parsed.success ? [parsed.data] : [];
2057
+ })
2058
+ ).refine((arr) => arr.length >= 1, { message: "attachment has no known transport" }),
1844
2059
  /** Optional provider hint (unix seconds) for when seeding may stop. */
1845
2060
  seedingExpiresAt: z.number().int().nonnegative().optional()
1846
2061
  });
@@ -1849,6 +2064,37 @@ var JobPayloadEnvelopeSchema = z.object({
1849
2064
  text: z.string().optional(),
1850
2065
  attachment: FileAttachmentSchema.optional()
1851
2066
  });
2067
+ var ACCEPT_TRANSPORTS_TAG = "accept";
2068
+ var KNOWN_TRANSPORT_KINDS = ["iroh", "blossom"];
2069
+ function isKnownTransportKind(value) {
2070
+ return KNOWN_TRANSPORT_KINDS.includes(value);
2071
+ }
2072
+ function buildAcceptTransportsTag(kinds) {
2073
+ const seen = /* @__PURE__ */ new Set();
2074
+ const out = [ACCEPT_TRANSPORTS_TAG];
2075
+ for (const kind of kinds) {
2076
+ if (isKnownTransportKind(kind) && !seen.has(kind)) {
2077
+ seen.add(kind);
2078
+ out.push(kind);
2079
+ }
2080
+ }
2081
+ return out;
2082
+ }
2083
+ function readAcceptedTransports(tags) {
2084
+ const tag = tags.find((t) => t[0] === ACCEPT_TRANSPORTS_TAG);
2085
+ if (tag === void 0) {
2086
+ return void 0;
2087
+ }
2088
+ const seen = /* @__PURE__ */ new Set();
2089
+ const out = [];
2090
+ for (const value of tag.slice(1)) {
2091
+ if (isKnownTransportKind(value) && !seen.has(value)) {
2092
+ seen.add(value);
2093
+ out.push(value);
2094
+ }
2095
+ }
2096
+ return out.length > 0 ? out : void 0;
2097
+ }
1852
2098
  function encodeJobPayload(payload) {
1853
2099
  const envelope = { v: ENVELOPE_VERSION };
1854
2100
  if (payload.text !== void 0) {
@@ -1951,6 +2197,12 @@ var MarketplaceService = class {
1951
2197
  tags.push(["p", options.providerPubkey]);
1952
2198
  tags.push(["encrypted", "nip44"]);
1953
2199
  }
2200
+ if (options.acceptTransports && options.acceptTransports.length > 0) {
2201
+ const acceptTag = buildAcceptTransportsTag(options.acceptTransports);
2202
+ if (acceptTag.length > 1) {
2203
+ tags.push(acceptTag);
2204
+ }
2205
+ }
1954
2206
  const kind = jobRequestKind(options.kindOffset ?? DEFAULT_KIND_OFFSET);
1955
2207
  const event = finalizeEvent(
1956
2208
  {
@@ -3338,6 +3590,7 @@ var ElisymClient = class {
3338
3590
  marketplace;
3339
3591
  ping;
3340
3592
  media;
3593
+ blossom;
3341
3594
  policies;
3342
3595
  payment;
3343
3596
  constructor(config = {}) {
@@ -3346,6 +3599,10 @@ var ElisymClient = class {
3346
3599
  this.marketplace = new MarketplaceService(this.pool);
3347
3600
  this.ping = new PingService(this.pool);
3348
3601
  this.media = new MediaService(config.uploadUrl);
3602
+ this.blossom = new BlossomService(
3603
+ config.blossomUrl,
3604
+ (identity, file) => this.media.upload(identity, file)
3605
+ );
3349
3606
  this.policies = new PoliciesService(this.pool);
3350
3607
  this.payment = config.payment ?? new SolanaPaymentStrategy();
3351
3608
  }
@@ -3354,6 +3611,147 @@ var ElisymClient = class {
3354
3611
  }
3355
3612
  };
3356
3613
 
3614
+ // src/primitives/file-crypto.ts
3615
+ var KEY_BYTES = 32;
3616
+ var IV_BYTES = 12;
3617
+ function bytesToBase64(bytes) {
3618
+ let bin = "";
3619
+ for (const b of bytes) {
3620
+ bin += String.fromCharCode(b);
3621
+ }
3622
+ return btoa(bin);
3623
+ }
3624
+ function base64ToBytes(b64) {
3625
+ const bin = atob(b64);
3626
+ const out = new Uint8Array(bin.length);
3627
+ for (let i = 0; i < bin.length; i += 1) {
3628
+ out[i] = bin.charCodeAt(i);
3629
+ }
3630
+ return out;
3631
+ }
3632
+ async function encryptBytesForRecipient(bytes, senderSk, recipientPubkey) {
3633
+ const rawKey = crypto.getRandomValues(new Uint8Array(KEY_BYTES));
3634
+ const iv = crypto.getRandomValues(new Uint8Array(IV_BYTES));
3635
+ const key = await crypto.subtle.importKey("raw", rawKey, "AES-GCM", false, ["encrypt"]);
3636
+ const ct = await crypto.subtle.encrypt({ name: "AES-GCM", iv, tagLength: 128 }, key, bytes);
3637
+ const wrappedKey = nip44Encrypt(bytesToBase64(rawKey), senderSk, recipientPubkey);
3638
+ return { ciphertext: new Uint8Array(ct), wrappedKey, iv: bytesToBase64(iv) };
3639
+ }
3640
+ async function decryptBytesFromSender(ciphertext, wrappedKey, iv, receiverSk, senderPubkey) {
3641
+ const rawKey = base64ToBytes(nip44Decrypt(wrappedKey, receiverSk, senderPubkey));
3642
+ const key = await crypto.subtle.importKey("raw", rawKey, "AES-GCM", false, ["decrypt"]);
3643
+ const pt = await crypto.subtle.decrypt(
3644
+ { name: "AES-GCM", iv: base64ToBytes(iv), tagLength: 128 },
3645
+ key,
3646
+ ciphertext
3647
+ );
3648
+ return new Uint8Array(pt);
3649
+ }
3650
+
3651
+ // src/transport/blossom-transport.ts
3652
+ var AES_GCM_TAG_BYTES = 16;
3653
+ function createBlossomTransport(opts) {
3654
+ const { blossom, identity } = opts;
3655
+ return {
3656
+ async seedBytes({ bytes, recipientPubkey }) {
3657
+ if (bytes.byteLength > LIMITS.MAX_BLOSSOM_ENCRYPTED_BYTES) {
3658
+ throw new Error(
3659
+ `File too large for encrypted Blossom: ${bytes.byteLength} bytes exceeds ${LIMITS.MAX_BLOSSOM_ENCRYPTED_BYTES}.`
3660
+ );
3661
+ }
3662
+ const { ciphertext, wrappedKey, iv } = await encryptBytesForRecipient(
3663
+ bytes,
3664
+ identity.secretKey,
3665
+ recipientPubkey
3666
+ );
3667
+ const blob = new Blob([ciphertext], { type: "application/octet-stream" });
3668
+ const descriptor = await blossom.upload(identity, blob);
3669
+ if (descriptor.provider !== "blossom") {
3670
+ throw new Error("Blossom upload fell back to a non-content-addressed provider.");
3671
+ }
3672
+ return {
3673
+ kind: "blossom",
3674
+ url: descriptor.url,
3675
+ sha256: descriptor.sha256,
3676
+ enc: { alg: "AES-256-GCM", iv, key: wrappedKey }
3677
+ };
3678
+ },
3679
+ async fetchToBytes({ transport, senderPubkey, maxBytes }) {
3680
+ const plaintextCap = maxBytes ?? LIMITS.MAX_BLOSSOM_ENCRYPTED_BYTES;
3681
+ const ciphertext = await blossom.download(transport.url, {
3682
+ maxBytes: plaintextCap + AES_GCM_TAG_BYTES,
3683
+ expectedSha256: transport.sha256
3684
+ });
3685
+ return decryptBytesFromSender(
3686
+ ciphertext,
3687
+ transport.enc.key,
3688
+ transport.enc.iv,
3689
+ identity.secretKey,
3690
+ senderPubkey
3691
+ );
3692
+ }
3693
+ };
3694
+ }
3695
+
3696
+ // src/transport/file-jobs.ts
3697
+ var EXECUTABLE_EXTENSIONS = /* @__PURE__ */ new Set([
3698
+ ".exe",
3699
+ ".dll",
3700
+ ".bat",
3701
+ ".cmd",
3702
+ ".com",
3703
+ ".msi",
3704
+ ".sh",
3705
+ ".app",
3706
+ ".scr",
3707
+ ".ps1"
3708
+ ]);
3709
+ var EXECUTABLE_MIMES = /* @__PURE__ */ new Set([
3710
+ "application/x-msdownload",
3711
+ "application/x-msdos-program",
3712
+ "application/x-sh",
3713
+ "application/x-executable",
3714
+ "application/vnd.microsoft.portable-executable",
3715
+ "application/x-mach-binary"
3716
+ ]);
3717
+ function looksExecutable(name, type) {
3718
+ const dot = name.lastIndexOf(".");
3719
+ const ext = dot >= 0 ? name.slice(dot).toLowerCase() : "";
3720
+ return EXECUTABLE_EXTENSIONS.has(ext) || EXECUTABLE_MIMES.has(type);
3721
+ }
3722
+ async function buildEncryptedFileInput(args) {
3723
+ const { file, providerPubkey, identity, blossom } = args;
3724
+ const name = file.name ?? "upload";
3725
+ if (looksExecutable(name, file.type)) {
3726
+ throw new Error("Refusing to upload an executable file.");
3727
+ }
3728
+ const transport = createBlossomTransport({ blossom, identity });
3729
+ const bytes = new Uint8Array(await file.arrayBuffer());
3730
+ const member = await transport.seedBytes({ bytes, recipientPubkey: providerPubkey });
3731
+ return {
3732
+ name,
3733
+ size: bytes.byteLength,
3734
+ mime: file.type || "application/octet-stream",
3735
+ transports: [member]
3736
+ };
3737
+ }
3738
+ async function fetchEncryptedFileOutput(args) {
3739
+ const { attachment, providerPubkey, identity, blossom, maxBytes } = args;
3740
+ const member = attachment.transports.find(
3741
+ (t) => t.kind === "blossom"
3742
+ );
3743
+ if (member === void 0) {
3744
+ throw new Error("Attachment has no blossom transport.");
3745
+ }
3746
+ const transport = createBlossomTransport({ blossom, identity });
3747
+ const bytes = await transport.fetchToBytes({
3748
+ transport: member,
3749
+ senderPubkey: providerPubkey,
3750
+ maxBytes
3751
+ });
3752
+ return { bytes, name: attachment.name, mime: attachment.mime };
3753
+ }
3754
+
3357
3755
  // src/services/jobErrors.ts
3358
3756
  var AGENT_UNAVAILABLE_MARKERS = [
3359
3757
  "agent temporarily unavailable",
@@ -3925,6 +4323,6 @@ function makeCensor() {
3925
4323
  };
3926
4324
  }
3927
4325
 
3928
- export { BoundedSet, DEFAULTS, DEFAULT_KIND_OFFSET, DEFAULT_REDACT_PATHS, DiscoveryService, ELISYM_PROTOCOL_TAG, ENVELOPE_VERSION, ElisymClient, ElisymIdentity, GlobalConfigSchema, INPUT_REDACT_PATHS, 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, KNOWN_ASSETS, LAMPORTS_PER_SOL, LIMITS, MarketplaceService, MediaService, NATIVE_SOL, NostrPool, POLICY_D_TAG_PREFIX, POLICY_TYPE_REGEX, POLICY_T_TAG, PROTOCOL_PROGRAM_ID_DEVNET, PaymentRequestSchema, PingService, PoliciesService, RELAYS, SECRET_REDACT_PATHS, SessionSpendLimitEntrySchema, SolanaPaymentStrategy, USDC_SOLANA_DEVNET, aggregateNetworkStats, assertExpiry, assertLamports, assetByKey, assetKey, buildPaymentInstructions, calculateProtocolFee, classifyJobError, clearPriorityFeeCache, clearProtocolConfigCache, clearQuickVerifyCache, compareAgentsByRank, computeRankKey, createPaymentRequestWithOnchainConfig, createSlidingWindowLimiter, decodeJobPayload, encodeJobPayload, estimateNetworkBaseline, estimatePriorityFeeMicroLamports, estimateSolFeeLamports, formatAssetAmount, formatFeeBreakdown, formatNetworkBaseline, formatSol, getNetworkStats, getProtocolConfig, getProtocolProgramId, jobRequestKind, jobResultKind, makeCensor, nip44Decrypt, nip44Encrypt, parseAssetAmount, parsePaymentRequest, pickPercentileFee, resolveAssetFromPaymentRequest, resolveKnownAsset, timeAgo, toDTag, truncateKey, utf8ByteLength, validateAgentName, validateExpiry, verifyJobPaymentQuick };
4326
+ export { ACCEPT_TRANSPORTS_TAG, BlossomService, BoundedSet, DEFAULTS, DEFAULT_KIND_OFFSET, DEFAULT_REDACT_PATHS, DiscoveryService, ELISYM_PROTOCOL_TAG, ENVELOPE_VERSION, ElisymClient, ElisymIdentity, GlobalConfigSchema, INPUT_REDACT_PATHS, 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, KNOWN_ASSETS, LAMPORTS_PER_SOL, LIMITS, MarketplaceService, MediaService, NATIVE_SOL, NostrPool, POLICY_D_TAG_PREFIX, POLICY_TYPE_REGEX, POLICY_T_TAG, PROTOCOL_PROGRAM_ID_DEVNET, PaymentRequestSchema, PingService, PoliciesService, RELAYS, SECRET_REDACT_PATHS, SessionSpendLimitEntrySchema, SolanaPaymentStrategy, USDC_SOLANA_DEVNET, aggregateNetworkStats, assertExpiry, assertLamports, assetByKey, assetKey, buildAcceptTransportsTag, buildEncryptedFileInput, buildPaymentInstructions, calculateProtocolFee, classifyJobError, clearPriorityFeeCache, clearProtocolConfigCache, clearQuickVerifyCache, compareAgentsByRank, computeRankKey, createBlossomTransport, createPaymentRequestWithOnchainConfig, createSlidingWindowLimiter, decodeJobPayload, decryptBytesFromSender, encodeJobPayload, encryptBytesForRecipient, estimateNetworkBaseline, estimatePriorityFeeMicroLamports, estimateSolFeeLamports, fetchEncryptedFileOutput, formatAssetAmount, formatFeeBreakdown, formatNetworkBaseline, formatSol, getNetworkStats, getProtocolConfig, getProtocolProgramId, jobRequestKind, jobResultKind, makeCensor, nip44Decrypt, nip44Encrypt, parseAssetAmount, parsePaymentRequest, pickPercentileFee, readAcceptedTransports, resolveAssetFromPaymentRequest, resolveKnownAsset, timeAgo, toDTag, truncateKey, utf8ByteLength, validateAgentName, validateExpiry, verifyJobPaymentQuick };
3929
4327
  //# sourceMappingURL=index.js.map
3930
4328
  //# sourceMappingURL=index.js.map