@nostrify/nostrify 0.47.1 → 0.48.2

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.
@@ -1,15 +1,15 @@
1
- import { z } from 'zod';
1
+ import { z } from "zod";
2
2
 
3
- import { N64 } from '../utils/N64.ts';
4
- import { NIP98 } from '../NIP98.ts';
5
- import type { NostrSigner, NUploader } from '@nostrify/types';
3
+ import { N64 } from "../utils/N64.ts";
4
+ import { NIP98 } from "../NIP98.ts";
5
+ import type { NostrSigner, NUploader } from "@nostrify/types";
6
6
 
7
7
  /** NostrBuildUploader options. */
8
8
  export interface NostrBuildUploaderOpts {
9
9
  /** nostr.build endpoint to use. Default: `https://nostr.build/api/v2/upload/files` */
10
10
  endpoint?: string;
11
11
  /** Signer to authenticate with NIP-98 requests. */
12
- signer?: NostrSigner;
12
+ signer: NostrSigner;
13
13
  /** Custom fetch implementation. */
14
14
  fetch?: typeof fetch;
15
15
  }
@@ -21,7 +21,7 @@ export class NostrBuildUploader implements NUploader {
21
21
  private fetch: typeof fetch;
22
22
 
23
23
  constructor(opts?: NostrBuildUploaderOpts) {
24
- this.endpoint = opts?.endpoint ?? 'https://nostr.build/api/v2/upload/files';
24
+ this.endpoint = opts?.endpoint ?? "https://nostr.build/api/v2/upload/files";
25
25
  this.signer = opts?.signer;
26
26
  this.fetch = opts?.fetch ?? globalThis.fetch.bind(globalThis);
27
27
  }
@@ -29,12 +29,12 @@ export class NostrBuildUploader implements NUploader {
29
29
  async upload(
30
30
  file: File,
31
31
  opts?: { signal?: AbortSignal },
32
- ): Promise<[['url', string], ...string[][]]> {
32
+ ): Promise<[["url", string], ...string[][]]> {
33
33
  const formData = new FormData();
34
- formData.append('fileToUpload', file);
34
+ formData.append("fileToUpload", file);
35
35
 
36
36
  const request = new Request(this.endpoint, {
37
- method: 'POST',
37
+ method: "POST",
38
38
  body: formData,
39
39
  signal: opts?.signal,
40
40
  });
@@ -42,7 +42,7 @@ export class NostrBuildUploader implements NUploader {
42
42
  if (this.signer) {
43
43
  const t = await NIP98.template(request);
44
44
  const event = await this.signer.signEvent(t);
45
- request.headers.set('authorization', `Nostr ${N64.encodeEvent(event)}`);
45
+ request.headers.set("authorization", `Nostr ${N64.encodeEvent(event)}`);
46
46
  }
47
47
 
48
48
  const response = await this.fetch(request);
@@ -50,20 +50,20 @@ export class NostrBuildUploader implements NUploader {
50
50
  console.log(json);
51
51
  const [data] = NostrBuildUploader.schema().parse(json).data;
52
52
 
53
- const tags: [['url', string], ...string[][]] = [
54
- ['url', data.url],
55
- ['m', data.mime],
56
- ['x', data.sha256],
57
- ['ox', data.original_sha256],
58
- ['size', data.size.toString()],
53
+ const tags: [["url", string], ...string[][]] = [
54
+ ["url", data.url],
55
+ ["m", data.mime],
56
+ ["x", data.sha256],
57
+ ["ox", data.original_sha256],
58
+ ["size", data.size.toString()],
59
59
  ];
60
60
 
61
61
  if (data.dimensions) {
62
- tags.push(['dim', `${data.dimensions.width}x${data.dimensions.height}`]);
62
+ tags.push(["dim", `${data.dimensions.width}x${data.dimensions.height}`]);
63
63
  }
64
64
 
65
65
  if (data.blurhash) {
66
- tags.push(['blurhash', data.blurhash]);
66
+ tags.push(["blurhash", data.blurhash]);
67
67
  }
68
68
 
69
69
  return tags;
@@ -1,4 +1,4 @@
1
- import type { NostrEvent } from '@nostrify/types';
1
+ import type { NostrEvent } from "@nostrify/types";
2
2
  /** Nostr base64 helper utilities. */
3
3
  export declare class N64 {
4
4
  /** Encode an event as a base64 string. */
package/dist/utils/N64.js CHANGED
@@ -1,13 +1,13 @@
1
- import { decodeBase64, encodeBase64 } from "@std/encoding/base64";
1
+ import { fromBase64, toBase64 } from "@smithy/util-base64";
2
2
  import { NSchema as n } from "../NSchema.js";
3
3
  class N64 {
4
4
  /** Encode an event as a base64 string. */
5
5
  static encodeEvent(event) {
6
- return encodeBase64(JSON.stringify(event));
6
+ return toBase64(JSON.stringify(event));
7
7
  }
8
8
  /** Decode an event from a base64 string. Validates the event's structure but does not verify its signature. */
9
9
  static decodeEvent(base64) {
10
- const bytes = decodeBase64(base64);
10
+ const bytes = fromBase64(base64);
11
11
  const text = new TextDecoder().decode(bytes);
12
12
  return n.json().pipe(n.event()).parse(text);
13
13
  }
package/dist/utils/N64.ts CHANGED
@@ -1,18 +1,18 @@
1
- import type { NostrEvent } from '@nostrify/types';
2
- import { decodeBase64, encodeBase64 } from '@std/encoding/base64';
1
+ import type { NostrEvent } from "@nostrify/types";
2
+ import { fromBase64, toBase64 } from "@smithy/util-base64";
3
3
 
4
- import { NSchema as n } from '../NSchema.ts';
4
+ import { NSchema as n } from "../NSchema.ts";
5
5
 
6
6
  /** Nostr base64 helper utilities. */
7
7
  export class N64 {
8
8
  /** Encode an event as a base64 string. */
9
9
  static encodeEvent(event: NostrEvent): string {
10
- return encodeBase64(JSON.stringify(event));
10
+ return toBase64(JSON.stringify(event));
11
11
  }
12
12
 
13
13
  /** Decode an event from a base64 string. Validates the event's structure but does not verify its signature. */
14
14
  static decodeEvent(base64: string): NostrEvent {
15
- const bytes = decodeBase64(base64);
15
+ const bytes = fromBase64(base64);
16
16
  const text = new TextDecoder().decode(bytes);
17
17
 
18
18
  return n
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nostrify/nostrify",
3
- "version": "0.47.1",
3
+ "version": "0.48.2",
4
4
  "exports": {
5
5
  ".": "./dist/mod.js",
6
6
  "./ln": "./dist/ln/mod.js",
@@ -12,21 +12,26 @@
12
12
  "types": "dist/mod.d.ts",
13
13
  "type": "module",
14
14
  "dependencies": {
15
- "ws": "^8.18.3",
15
+ "@scure/base": "^2.0.0",
16
+ "@smithy/util-base64": "^4.3.0",
17
+ "@smithy/util-hex-encoding": "^4.2.0",
18
+ "@types/node": "^24.1.0",
16
19
  "lru-cache": "^10.2.0",
17
20
  "nostr-tools": "^2.13.0",
18
21
  "websocket-ts": "^2.2.1",
22
+ "ws": "^8.18.3",
19
23
  "zod": "^3.23.8",
20
- "@types/node": "^24.1.0",
21
- "@scure/base": "^1.2.6",
22
- "@std/encoding": "npm:@jsr/std__encoding@^0.224.1",
23
- "@nostrify/types": "0.36.7"
24
+ "@nostrify/types": "0.36.8"
24
25
  },
25
26
  "publishConfig": {
26
27
  "access": "public"
27
28
  },
29
+ "devDependencies": {
30
+ "@types/ws": "^8.18.1"
31
+ },
28
32
  "scripts": {
29
33
  "build": "npx tsc -p tsconfig.json && node ../../esbuild.config.js --package ./",
34
+ "typecheck": "npx tsc --noEmit",
30
35
  "setup": "pnpm i",
31
36
  "test": "node --test \"**/*.test.ts\""
32
37
  }
@@ -1,13 +1,13 @@
1
- import type { NostrSigner, NUploader } from '@nostrify/types';
2
- import { encodeHex } from '@std/encoding/hex';
3
- import { z } from 'zod';
1
+ import type { NostrSigner, NUploader } from "@nostrify/types";
2
+ import { toHex } from "@smithy/util-hex-encoding";
3
+ import { z } from "zod";
4
4
 
5
- import { N64 } from '../utils/N64.ts';
5
+ import { N64 } from "../utils/N64.ts";
6
6
 
7
7
  /** BlossomUploader options. */
8
8
  export interface BlossomUploaderOpts {
9
9
  /** Blossom servers to use. */
10
- servers: Request['url'][];
10
+ servers: Request["url"][];
11
11
  /** Signer for Blossom authorizations. */
12
12
  signer: NostrSigner;
13
13
  /** Custom fetch implementation. */
@@ -18,7 +18,7 @@ export interface BlossomUploaderOpts {
18
18
 
19
19
  /** Upload files to Blossom servers. */
20
20
  export class BlossomUploader implements NUploader {
21
- private servers: Request['url'][];
21
+ private servers: Request["url"][];
22
22
  private signer: NostrSigner;
23
23
  private fetch: typeof fetch;
24
24
  private expiresIn: number;
@@ -33,10 +33,12 @@ export class BlossomUploader implements NUploader {
33
33
  async upload(
34
34
  file: File,
35
35
  opts?: { signal?: AbortSignal },
36
- ): Promise<[['url', string], ...string[][]]> {
37
- const x = encodeHex(
38
- await crypto.subtle.digest('SHA-256', await file.arrayBuffer()),
36
+ ): Promise<[["url", string], ...string[][]]> {
37
+ const digest = await crypto.subtle.digest(
38
+ "SHA-256",
39
+ await file.arrayBuffer(),
39
40
  );
41
+ const x = toHex(new Uint8Array(digest));
40
42
 
41
43
  const now = Date.now();
42
44
  const expiration = now + this.expiresIn;
@@ -46,24 +48,24 @@ export class BlossomUploader implements NUploader {
46
48
  content: `Upload ${file.name}`,
47
49
  created_at: Math.floor(now / 1000),
48
50
  tags: [
49
- ['t', 'upload'],
50
- ['x', x],
51
- ['size', file.size.toString()],
52
- ['expiration', Math.floor(expiration / 1000).toString()],
51
+ ["t", "upload"],
52
+ ["x", x],
53
+ ["size", file.size.toString()],
54
+ ["expiration", Math.floor(expiration / 1000).toString()],
53
55
  ],
54
56
  });
55
57
 
56
58
  const authorization = `Nostr ${N64.encodeEvent(event)}`;
57
59
 
58
60
  return Promise.any(this.servers.map(async (server) => {
59
- const url = new URL('/upload', server);
61
+ const url = new URL("/upload", server);
60
62
 
61
63
  const response = await this.fetch(url, {
62
- method: 'PUT',
64
+ method: "PUT",
63
65
  body: file,
64
66
  headers: {
65
67
  authorization,
66
- 'content-type': file.type,
68
+ "content-type": file.type,
67
69
  },
68
70
  signal: opts?.signal,
69
71
  });
@@ -71,15 +73,15 @@ export class BlossomUploader implements NUploader {
71
73
  const json = await response.json();
72
74
  const data = BlossomUploader.schema().parse(json);
73
75
 
74
- const tags: [['url', string], ...string[][]] = [
75
- ['url', data.url],
76
- ['x', data.sha256],
77
- ['ox', data.sha256],
78
- ['size', data.size.toString()],
76
+ const tags: [["url", string], ...string[][]] = [
77
+ ["url", data.url],
78
+ ["x", data.sha256],
79
+ ["ox", data.sha256],
80
+ ["size", data.size.toString()],
79
81
  ];
80
82
 
81
83
  if (data.type) {
82
- tags.push(['m', data.type]);
84
+ tags.push(["m", data.type]);
83
85
  }
84
86
 
85
87
  return tags;
@@ -6,6 +6,8 @@ import fs from "node:fs/promises";
6
6
 
7
7
  import { NostrBuildUploader } from "./NostrBuildUploader.ts";
8
8
  import { Readable } from "node:stream";
9
+ import { NSecSigner } from "../NSecSigner.ts";
10
+ import { hexToBytes } from "nostr-tools/utils";
9
11
 
10
12
  await test(
11
13
  "NostrBuildUploader.upload",
@@ -18,7 +20,20 @@ await test(
18
20
  .blob();
19
21
  const file = new File([blob], "voadi.png", { type: "image/png" });
20
22
 
21
- const uploader = new NostrBuildUploader();
23
+ const seckey = process.env.NOSTRIFY_NBU_SECRET_KEY;
24
+ if (!seckey) {
25
+ throw new Error(
26
+ "nostr.build with default uploader requires a secret key to be configured",
27
+ );
28
+ }
29
+
30
+ const uploader = new NostrBuildUploader({
31
+ signer: new NSecSigner(
32
+ hexToBytes(
33
+ seckey,
34
+ ),
35
+ ),
36
+ });
22
37
  const tags = await uploader.upload(file);
23
38
 
24
39
  deepStrictEqual(tags, [
@@ -1,15 +1,15 @@
1
- import { z } from 'zod';
1
+ import { z } from "zod";
2
2
 
3
- import { N64 } from '../utils/N64.ts';
4
- import { NIP98 } from '../NIP98.ts';
5
- import type { NostrSigner, NUploader } from '@nostrify/types';
3
+ import { N64 } from "../utils/N64.ts";
4
+ import { NIP98 } from "../NIP98.ts";
5
+ import type { NostrSigner, NUploader } from "@nostrify/types";
6
6
 
7
7
  /** NostrBuildUploader options. */
8
8
  export interface NostrBuildUploaderOpts {
9
9
  /** nostr.build endpoint to use. Default: `https://nostr.build/api/v2/upload/files` */
10
10
  endpoint?: string;
11
11
  /** Signer to authenticate with NIP-98 requests. */
12
- signer?: NostrSigner;
12
+ signer: NostrSigner;
13
13
  /** Custom fetch implementation. */
14
14
  fetch?: typeof fetch;
15
15
  }
@@ -21,7 +21,7 @@ export class NostrBuildUploader implements NUploader {
21
21
  private fetch: typeof fetch;
22
22
 
23
23
  constructor(opts?: NostrBuildUploaderOpts) {
24
- this.endpoint = opts?.endpoint ?? 'https://nostr.build/api/v2/upload/files';
24
+ this.endpoint = opts?.endpoint ?? "https://nostr.build/api/v2/upload/files";
25
25
  this.signer = opts?.signer;
26
26
  this.fetch = opts?.fetch ?? globalThis.fetch.bind(globalThis);
27
27
  }
@@ -29,12 +29,12 @@ export class NostrBuildUploader implements NUploader {
29
29
  async upload(
30
30
  file: File,
31
31
  opts?: { signal?: AbortSignal },
32
- ): Promise<[['url', string], ...string[][]]> {
32
+ ): Promise<[["url", string], ...string[][]]> {
33
33
  const formData = new FormData();
34
- formData.append('fileToUpload', file);
34
+ formData.append("fileToUpload", file);
35
35
 
36
36
  const request = new Request(this.endpoint, {
37
- method: 'POST',
37
+ method: "POST",
38
38
  body: formData,
39
39
  signal: opts?.signal,
40
40
  });
@@ -42,7 +42,7 @@ export class NostrBuildUploader implements NUploader {
42
42
  if (this.signer) {
43
43
  const t = await NIP98.template(request);
44
44
  const event = await this.signer.signEvent(t);
45
- request.headers.set('authorization', `Nostr ${N64.encodeEvent(event)}`);
45
+ request.headers.set("authorization", `Nostr ${N64.encodeEvent(event)}`);
46
46
  }
47
47
 
48
48
  const response = await this.fetch(request);
@@ -50,20 +50,20 @@ export class NostrBuildUploader implements NUploader {
50
50
  console.log(json);
51
51
  const [data] = NostrBuildUploader.schema().parse(json).data;
52
52
 
53
- const tags: [['url', string], ...string[][]] = [
54
- ['url', data.url],
55
- ['m', data.mime],
56
- ['x', data.sha256],
57
- ['ox', data.original_sha256],
58
- ['size', data.size.toString()],
53
+ const tags: [["url", string], ...string[][]] = [
54
+ ["url", data.url],
55
+ ["m", data.mime],
56
+ ["x", data.sha256],
57
+ ["ox", data.original_sha256],
58
+ ["size", data.size.toString()],
59
59
  ];
60
60
 
61
61
  if (data.dimensions) {
62
- tags.push(['dim', `${data.dimensions.width}x${data.dimensions.height}`]);
62
+ tags.push(["dim", `${data.dimensions.width}x${data.dimensions.height}`]);
63
63
  }
64
64
 
65
65
  if (data.blurhash) {
66
- tags.push(['blurhash', data.blurhash]);
66
+ tags.push(["blurhash", data.blurhash]);
67
67
  }
68
68
 
69
69
  return tags;
package/utils/N64.ts CHANGED
@@ -1,18 +1,18 @@
1
- import type { NostrEvent } from '@nostrify/types';
2
- import { decodeBase64, encodeBase64 } from '@std/encoding/base64';
1
+ import type { NostrEvent } from "@nostrify/types";
2
+ import { fromBase64, toBase64 } from "@smithy/util-base64";
3
3
 
4
- import { NSchema as n } from '../NSchema.ts';
4
+ import { NSchema as n } from "../NSchema.ts";
5
5
 
6
6
  /** Nostr base64 helper utilities. */
7
7
  export class N64 {
8
8
  /** Encode an event as a base64 string. */
9
9
  static encodeEvent(event: NostrEvent): string {
10
- return encodeBase64(JSON.stringify(event));
10
+ return toBase64(JSON.stringify(event));
11
11
  }
12
12
 
13
13
  /** Decode an event from a base64 string. Validates the event's structure but does not verify its signature. */
14
14
  static decodeEvent(base64: string): NostrEvent {
15
- const bytes = decodeBase64(base64);
15
+ const bytes = fromBase64(base64);
16
16
  const text = new TextDecoder().decode(bytes);
17
17
 
18
18
  return n
@@ -1,13 +0,0 @@
1
-
2
-
3
- > @nostrify/nostrify@0.46.7 setup /home/sid/repos/nostrify/packages/nostrify
4
- > pnpm i
5
-
6
- (node:1234099) [DEP0169] DeprecationWarning: `url.parse()` behavior is not standardized and prone to errors that have security implications. Use the WHATWG URL API instead. CVEs are not issued for `url.parse()` vulnerabilities.
7
- (Use `node --trace-deprecation ...` to show where the warning was created)
8
- Scope: all 9 workspace projects
9
- ../.. | Progress: resolved 1, reused 0, downloaded 0, added 0
10
- ../.. | +1 +
11
- ../.. | Progress: resolved 1, reused 0, downloaded 0, added 0
12
- ../.. | Progress: resolved 1, reused 1, downloaded 0, added 0
13
- ../.. | Progress: resolved 1, reused 1, downloaded 0, added 0, done
@@ -1,91 +0,0 @@
1
-
2
-
3
- > @nostrify/nostrify@0.46.8 test /home/sid/repos/nostrify/packages/nostrify
4
- > node --test "**/*.test.ts"
5
-
6
- ✔ BunkerURI (2.901722ms)
7
- ✔ BunkerURI.fromJSON (0.681727ms)
8
- ✔ NBrowserSigner - without extension (2.955361ms)
9
- ✔ NBrowserSigner - with extension polyfill (142.479686ms)
10
- ✔ NBrowserSigner.nip44 - with extension polyfill (63.176698ms)
11
- ✔ NBrowserSigner.nip04 - with extension polyfill (94.046199ms)
12
- ✔ NBrowserSigner.getRelays - with extension polyfill (1.225726ms)
13
- ✔ NBrowserSigner - missing nip44 support (0.470316ms)
14
- ✔ NBrowserSigner - missing nip04 support (0.596869ms)
15
- ✔ NBrowserSigner - feature detection (0.692134ms)
16
- ✔ NCache (4.463457ms)
17
- ✔ NConnectSigner.signEvent with nip04 encryption (264.497854ms)
18
- ✔ NConnectSigner.signEvent with nip44 encryption (151.108865ms)
19
- ✔ NIP05.lookup (82.449297ms)
20
- ✔ NIP05.lookup with invalid values but valid profile pointer (5.343535ms)
21
- ✔ NIP05.lookup with invalid document (5.910931ms)
22
- ✔ NIP50.parseInput (6.388441ms)
23
- ✔ NIP50.parseInput with negated token (0.443007ms)
24
- ✔ NIP98.template (3.769298ms)
25
- ✔ NIP98.template with payload (18.668676ms)
26
- ✔ NIP98.verify (102.562862ms)
27
- ✔ NIP98.verify fails with missing header (4.419038ms)
28
- ✔ NIP98.verify fails with missing token (2.752191ms)
29
- ✔ NIP98.verify fails with invalid token (4.587427ms)
30
- ✔ NIP98.verify fails with invalid event (16.989187ms)
31
- ✔ NIP98.verify fails with wrong event kind (40.621459ms)
32
- ✔ NIP98.verify fails with wrong request URL (41.071101ms)
33
- ✔ NIP98.verify fails with wrong request method (62.625645ms)
34
- ✔ NIP98.verify fails with expired event (20.760162ms)
35
- ✔ NIP98.verify fails with invalid payload (51.97091ms)
36
- ✔ NKinds (3.308412ms)
37
- ✔ NPool.query (368.093259ms)
38
- ✔ NPool.req (266.969001ms)
39
- ✔ NPool.event (232.161184ms)
40
- ✔ NRelay1.query (280.362725ms)
41
- ✔ NRelay1.query mismatched filter (245.542477ms)
42
- ✔ NRelay1.req (247.658198ms)
43
- ✔ NRelay1.event (216.357493ms)
44
- ﹣ NRelay1 backoff (0.334682ms) # SKIP
45
- ▶ NRelay1 idleTimeout
46
- ✔ websocket opens (40.531572ms)
47
- ✔ websocket closes after idleTimeout (150.405626ms)
48
- ✔ websocket wakes up during activity (14.544161ms)
49
- ✔ NRelay1 idleTimeout (209.795356ms)
50
- ✔ NRelay1.count rejects when the server sends CLOSED (6.440892ms)
51
- ✔ NRelay1 closes when it receives a binary message (5.03225ms)
52
- ✔ n.id (3.950608ms)
53
- ✔ n.bech32 (1.817636ms)
54
- ✔ n.filter (10.95275ms)
55
- ✔ n.event (2.561941ms)
56
- ✔ n.metadata (11.862022ms)
57
- ✔ NSecSigner (178.164717ms)
58
- ✔ NSecSigner.nip44 (31.935079ms)
59
- ✔ NSet (19.978352ms)
60
- ✔ NSet.add (replaceable) (0.615308ms)
61
- ✔ NSet.add (parameterized) (0.985888ms)
62
- ✔ NSet.add (deletion) (0.380918ms)
63
- ✔ Construct a RelayError from the reason message (1.717692ms)
64
- ✔ Throw a new RelayError if the OK message is false (0.750801ms)
65
- ✔ LNURL.fromString (7.817616ms)
66
- ✔ LNURL.fromLightningAddress (0.932529ms)
67
- ✔ LNURL.toString (1.933713ms)
68
- ✔ LNURL.getDetails (111.66131ms)
69
- ✔ LNURL.getInvoice (13.562812ms)
70
- ✔ ErrorRelay (112.209428ms)
71
- ✔ MockRelay (3.019126ms)
72
- ﹣ BlossomUploader.upload (1.127947ms) # SKIP
73
- ﹣ NostrBuildUploader.upload (2.842008ms) # SKIP
74
- ✔ CircularSet (2.247513ms)
75
- ✔ push, iterate, & close (103.751782ms)
76
- ✔ close & reopen (0.982257ms)
77
- ✔ aborts with signal (51.656203ms)
78
- ✔ already aborted signal in constructor (1.251916ms)
79
- ✔ push after abort (0.906129ms)
80
- ✔ multiple messages in queue (0.531637ms)
81
- ✔ N64 (8.171994ms)
82
- ✔ N64.encodeEvent (0.513338ms)
83
- ✔ N64.decodeEvent (1.449988ms)
84
- ℹ tests 77
85
- ℹ suites 0
86
- ℹ pass 74
87
- ℹ fail 0
88
- ℹ cancelled 0
89
- ℹ skipped 3
90
- ℹ todo 0
91
- ℹ duration_ms 2192.909865