@elisym/sdk 0.25.3 → 0.25.5
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/agent-store.cjs +2 -0
- package/dist/agent-store.cjs.map +1 -1
- package/dist/agent-store.js +2 -0
- package/dist/agent-store.js.map +1 -1
- package/dist/index.cjs +31 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -9
- package/dist/index.d.ts +22 -9
- package/dist/index.js +31 -5
- package/dist/index.js.map +1 -1
- package/dist/node.cjs +47 -28
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +6 -0
- package/dist/node.d.ts +6 -0
- package/dist/node.js +47 -28
- package/dist/node.js.map +1 -1
- package/dist/skills.cjs.map +1 -1
- package/dist/skills.d.cts +9 -7
- package/dist/skills.d.ts +9 -7
- package/dist/skills.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -417,18 +417,20 @@ interface CapabilityCard {
|
|
|
417
417
|
/**
|
|
418
418
|
* MIME the capability expects as a file input (from a dynamic-script skill's
|
|
419
419
|
* `input_mime`). Discovery hint only; the provider still content-sniffs the
|
|
420
|
-
* actual file. Its presence means the capability
|
|
421
|
-
*
|
|
422
|
-
*
|
|
420
|
+
* actual file. Its presence means the capability accepts a file input (the web
|
|
421
|
+
* app sends it over encrypted Blossom; the MCP/CLI over iroh), so clients show a
|
|
422
|
+
* file picker. `*` = any file, `image/*` = any image, `image/png` = exact.
|
|
423
423
|
*/
|
|
424
424
|
inputMime?: string;
|
|
425
425
|
/** MIME of a file result the capability produces (from `output_mime`). */
|
|
426
426
|
outputMime?: string;
|
|
427
427
|
/**
|
|
428
|
-
*
|
|
429
|
-
* `'none'` = file only, `'optional'` = file +
|
|
430
|
-
*
|
|
431
|
-
*
|
|
428
|
+
* How a file-input capability treats the text prompt (from `input_text`):
|
|
429
|
+
* `'none'` = file only, `'optional'` = file optional + instruction required (a
|
|
430
|
+
* generate-or-edit skill), `'required'` = file + text both required. Omitted =
|
|
431
|
+
* file required + optional note. Discovery hint; the web app shows/hides/gates its
|
|
432
|
+
* text box and file picker accordingly. Only meaningful with `inputMime`.
|
|
433
|
+
* Untrusted - gate on it, never render the raw value.
|
|
432
434
|
*/
|
|
433
435
|
inputText?: 'required' | 'optional' | 'none';
|
|
434
436
|
}
|
|
@@ -801,13 +803,22 @@ declare class BlossomService {
|
|
|
801
803
|
/** Delete a blob by sha256 (BUD-02). Blossom only - there is no fallback for deletes. */
|
|
802
804
|
delete(identity: ElisymIdentity, sha256: string): Promise<void>;
|
|
803
805
|
/**
|
|
804
|
-
* Download a
|
|
805
|
-
* the declared Content-Length) and verifies the sha256 when
|
|
806
|
+
* Download a content-addressed blob from THIS Blossom server (BUD-01 GET, no auth). Bounds memory
|
|
807
|
+
* on the ACTUAL streamed bytes (never the declared Content-Length) and verifies the sha256 when
|
|
808
|
+
* `expectedSha256` is given. Browser-safe.
|
|
809
|
+
*
|
|
810
|
+
* SSRF guard: `url` typically arrives inside a remote counterparty's encrypted job envelope, so it
|
|
811
|
+
* is untrusted. elisym blobs are content-addressed on the single configured server (`seedBytes`
|
|
812
|
+
* refuses non-content-addressed fallbacks), so a legitimate URL is always `<serverUrl>/<sha256>`.
|
|
813
|
+
* The origin is pinned to `serverUrl` and redirects are refused, so a crafted url (or a 30x from
|
|
814
|
+
* the host) can't coerce a fetch to loopback, cloud-metadata, or internal addresses. Federation
|
|
815
|
+
* across Blossom servers would replace this single-origin pin with an explicit allowlist.
|
|
806
816
|
*/
|
|
807
817
|
download(url: string, opts?: {
|
|
808
818
|
maxBytes?: number;
|
|
809
819
|
timeoutMs?: number;
|
|
810
820
|
expectedSha256?: string;
|
|
821
|
+
signal?: AbortSignal;
|
|
811
822
|
}): Promise<Uint8Array>;
|
|
812
823
|
private uploadToBlossom;
|
|
813
824
|
private authHeader;
|
|
@@ -1171,6 +1182,8 @@ interface BlossomBlobTransport {
|
|
|
1171
1182
|
transport: BlossomTransport;
|
|
1172
1183
|
senderPubkey: string;
|
|
1173
1184
|
maxBytes?: number;
|
|
1185
|
+
/** Abort the in-flight download (e.g. job stop() / input-fetch budget). */
|
|
1186
|
+
signal?: AbortSignal;
|
|
1174
1187
|
}): Promise<Uint8Array>;
|
|
1175
1188
|
}
|
|
1176
1189
|
declare function createBlossomTransport(opts: {
|
package/dist/index.d.ts
CHANGED
|
@@ -417,18 +417,20 @@ interface CapabilityCard {
|
|
|
417
417
|
/**
|
|
418
418
|
* MIME the capability expects as a file input (from a dynamic-script skill's
|
|
419
419
|
* `input_mime`). Discovery hint only; the provider still content-sniffs the
|
|
420
|
-
* actual file. Its presence means the capability
|
|
421
|
-
*
|
|
422
|
-
*
|
|
420
|
+
* actual file. Its presence means the capability accepts a file input (the web
|
|
421
|
+
* app sends it over encrypted Blossom; the MCP/CLI over iroh), so clients show a
|
|
422
|
+
* file picker. `*` = any file, `image/*` = any image, `image/png` = exact.
|
|
423
423
|
*/
|
|
424
424
|
inputMime?: string;
|
|
425
425
|
/** MIME of a file result the capability produces (from `output_mime`). */
|
|
426
426
|
outputMime?: string;
|
|
427
427
|
/**
|
|
428
|
-
*
|
|
429
|
-
* `'none'` = file only, `'optional'` = file +
|
|
430
|
-
*
|
|
431
|
-
*
|
|
428
|
+
* How a file-input capability treats the text prompt (from `input_text`):
|
|
429
|
+
* `'none'` = file only, `'optional'` = file optional + instruction required (a
|
|
430
|
+
* generate-or-edit skill), `'required'` = file + text both required. Omitted =
|
|
431
|
+
* file required + optional note. Discovery hint; the web app shows/hides/gates its
|
|
432
|
+
* text box and file picker accordingly. Only meaningful with `inputMime`.
|
|
433
|
+
* Untrusted - gate on it, never render the raw value.
|
|
432
434
|
*/
|
|
433
435
|
inputText?: 'required' | 'optional' | 'none';
|
|
434
436
|
}
|
|
@@ -801,13 +803,22 @@ declare class BlossomService {
|
|
|
801
803
|
/** Delete a blob by sha256 (BUD-02). Blossom only - there is no fallback for deletes. */
|
|
802
804
|
delete(identity: ElisymIdentity, sha256: string): Promise<void>;
|
|
803
805
|
/**
|
|
804
|
-
* Download a
|
|
805
|
-
* the declared Content-Length) and verifies the sha256 when
|
|
806
|
+
* Download a content-addressed blob from THIS Blossom server (BUD-01 GET, no auth). Bounds memory
|
|
807
|
+
* on the ACTUAL streamed bytes (never the declared Content-Length) and verifies the sha256 when
|
|
808
|
+
* `expectedSha256` is given. Browser-safe.
|
|
809
|
+
*
|
|
810
|
+
* SSRF guard: `url` typically arrives inside a remote counterparty's encrypted job envelope, so it
|
|
811
|
+
* is untrusted. elisym blobs are content-addressed on the single configured server (`seedBytes`
|
|
812
|
+
* refuses non-content-addressed fallbacks), so a legitimate URL is always `<serverUrl>/<sha256>`.
|
|
813
|
+
* The origin is pinned to `serverUrl` and redirects are refused, so a crafted url (or a 30x from
|
|
814
|
+
* the host) can't coerce a fetch to loopback, cloud-metadata, or internal addresses. Federation
|
|
815
|
+
* across Blossom servers would replace this single-origin pin with an explicit allowlist.
|
|
806
816
|
*/
|
|
807
817
|
download(url: string, opts?: {
|
|
808
818
|
maxBytes?: number;
|
|
809
819
|
timeoutMs?: number;
|
|
810
820
|
expectedSha256?: string;
|
|
821
|
+
signal?: AbortSignal;
|
|
811
822
|
}): Promise<Uint8Array>;
|
|
812
823
|
private uploadToBlossom;
|
|
813
824
|
private authHeader;
|
|
@@ -1171,6 +1182,8 @@ interface BlossomBlobTransport {
|
|
|
1171
1182
|
transport: BlossomTransport;
|
|
1172
1183
|
senderPubkey: string;
|
|
1173
1184
|
maxBytes?: number;
|
|
1185
|
+
/** Abort the in-flight download (e.g. job stop() / input-fetch budget). */
|
|
1186
|
+
signal?: AbortSignal;
|
|
1174
1187
|
}): Promise<Uint8Array>;
|
|
1175
1188
|
}
|
|
1176
1189
|
declare function createBlossomTransport(opts: {
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,8 @@ import * as nip44 from 'nostr-tools/nip44';
|
|
|
9
9
|
|
|
10
10
|
// src/constants.ts
|
|
11
11
|
var RELAYS = [
|
|
12
|
+
// Dedicated elisym relay (self-hosted) first, public relays as fallback.
|
|
13
|
+
"wss://relay.elisym.network",
|
|
12
14
|
"wss://relay.damus.io",
|
|
13
15
|
"wss://nos.lol",
|
|
14
16
|
"wss://relay.nostr.band",
|
|
@@ -1262,18 +1264,38 @@ var BlossomService = class {
|
|
|
1262
1264
|
}
|
|
1263
1265
|
}
|
|
1264
1266
|
/**
|
|
1265
|
-
* Download a
|
|
1266
|
-
* the declared Content-Length) and verifies the sha256 when
|
|
1267
|
+
* Download a content-addressed blob from THIS Blossom server (BUD-01 GET, no auth). Bounds memory
|
|
1268
|
+
* on the ACTUAL streamed bytes (never the declared Content-Length) and verifies the sha256 when
|
|
1269
|
+
* `expectedSha256` is given. Browser-safe.
|
|
1270
|
+
*
|
|
1271
|
+
* SSRF guard: `url` typically arrives inside a remote counterparty's encrypted job envelope, so it
|
|
1272
|
+
* is untrusted. elisym blobs are content-addressed on the single configured server (`seedBytes`
|
|
1273
|
+
* refuses non-content-addressed fallbacks), so a legitimate URL is always `<serverUrl>/<sha256>`.
|
|
1274
|
+
* The origin is pinned to `serverUrl` and redirects are refused, so a crafted url (or a 30x from
|
|
1275
|
+
* the host) can't coerce a fetch to loopback, cloud-metadata, or internal addresses. Federation
|
|
1276
|
+
* across Blossom servers would replace this single-origin pin with an explicit allowlist.
|
|
1267
1277
|
*/
|
|
1268
1278
|
async download(url, opts = {}) {
|
|
1279
|
+
if (new URL(url).origin !== new URL(this.serverUrl).origin) {
|
|
1280
|
+
throw new Error(`Refusing to download from a non-Blossom origin: ${url}`);
|
|
1281
|
+
}
|
|
1269
1282
|
const maxBytes = opts.maxBytes ?? LIMITS.MAX_FILE_SIZE;
|
|
1270
1283
|
const controller = new AbortController();
|
|
1271
1284
|
const timer = setTimeout(
|
|
1272
1285
|
() => controller.abort(),
|
|
1273
1286
|
opts.timeoutMs ?? DEFAULTS.BLOSSOM_FETCH_TIMEOUT_MS
|
|
1274
1287
|
);
|
|
1288
|
+
const externalSignal = opts.signal;
|
|
1289
|
+
const onExternalAbort = () => controller.abort();
|
|
1290
|
+
if (externalSignal !== void 0) {
|
|
1291
|
+
if (externalSignal.aborted) {
|
|
1292
|
+
controller.abort();
|
|
1293
|
+
} else {
|
|
1294
|
+
externalSignal.addEventListener("abort", onExternalAbort, { once: true });
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1275
1297
|
try {
|
|
1276
|
-
const res = await fetch(url, { signal: controller.signal });
|
|
1298
|
+
const res = await fetch(url, { signal: controller.signal, redirect: "error" });
|
|
1277
1299
|
if (!res.ok) {
|
|
1278
1300
|
throw new Error(`Download failed: ${res.status} ${res.statusText}`);
|
|
1279
1301
|
}
|
|
@@ -1315,6 +1337,9 @@ var BlossomService = class {
|
|
|
1315
1337
|
return bytes;
|
|
1316
1338
|
} finally {
|
|
1317
1339
|
clearTimeout(timer);
|
|
1340
|
+
if (externalSignal !== void 0) {
|
|
1341
|
+
externalSignal.removeEventListener("abort", onExternalAbort);
|
|
1342
|
+
}
|
|
1318
1343
|
}
|
|
1319
1344
|
}
|
|
1320
1345
|
async uploadToBlossom(identity, bytes, hashHex, mime) {
|
|
@@ -3712,11 +3737,12 @@ function createBlossomTransport(opts) {
|
|
|
3712
3737
|
enc: { alg: "AES-256-GCM", iv, key: wrappedKey }
|
|
3713
3738
|
};
|
|
3714
3739
|
},
|
|
3715
|
-
async fetchToBytes({ transport, senderPubkey, maxBytes }) {
|
|
3740
|
+
async fetchToBytes({ transport, senderPubkey, maxBytes, signal }) {
|
|
3716
3741
|
const plaintextCap = maxBytes ?? LIMITS.MAX_BLOSSOM_ENCRYPTED_BYTES;
|
|
3717
3742
|
const ciphertext = await blossom.download(transport.url, {
|
|
3718
3743
|
maxBytes: plaintextCap + AES_GCM_TAG_BYTES,
|
|
3719
|
-
expectedSha256: transport.sha256
|
|
3744
|
+
expectedSha256: transport.sha256,
|
|
3745
|
+
signal
|
|
3720
3746
|
});
|
|
3721
3747
|
return decryptBytesFromSender(
|
|
3722
3748
|
ciphertext,
|