TypeScript definitions (#18)

This commit is contained in:
Lennon Day-Reynolds 2022-07-15 11:49:49 -07:00 committed by GitHub
parent 2f7e3f8473
commit 821a8f7895
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 195 additions and 12 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@ dist
yarn.lock
package-lock.json
nostr.js
.envrc

View File

@ -84,6 +84,10 @@ You can import nostr-tools as an ES module. Just add a script tag like this:
And import whatever function you would import from `"nostr-tools"` in a bundler.
## TypeScript
This module has hand-authored TypeScript declarations. `npm run check-ts` will run a lint-check script to ensure the typings can be loaded and call at least a few standard library functions. It's not at all comprehensive and likely to contain bugs. Issues welcome; tag @rcoder as needed.
## License
Public domain.

View File

106
index.d.ts vendored Normal file
View File

@ -0,0 +1,106 @@
import { type Buffer } from 'buffer';
// these should be available from the native @noble/secp256k1 type
// declarations, but they somehow aren't so instead: copypasta
declare type Hex = Uint8Array | string;
declare type PrivKey = Hex | bigint | number;
declare enum EventKind {
Metadata = 0,
Text = 1,
RelayRec = 2,
Contacts = 3,
DM = 4,
Deleted = 5,
}
// event.js
declare type Event = {
kind: EventKind,
pubkey?: string,
content: string,
tags: string[],
created_at: number,
};
declare function getBlankEvent(): Event;
declare function serializeEvent(event: Event): string;
declare function getEventHash(event: Event): string;
declare function validateEvent(event: Event): boolean;
declare function validateSignature(event: Event): boolean;
declare function signEvent(event: Event, key: PrivKey): Promise<[Uint8Array, number]>;
// filter.js
declare type Filter = {
ids: string[],
kinds: EventKind[],
authors: string[],
since: number,
until: number,
"#e": string[],
"#p": string[],
};
declare function matchFilter(filter: Filter, event: Event): boolean;
declare function matchFilters(filters: Filter[], event: Event): boolean;
// general
declare type ClientMessage =
["EVENT", Event] |
["REQ", string, Filter[]] |
["CLOSE", string];
declare type ServerMessage =
["EVENT", string, Event] |
["NOTICE", unknown];
// keys.js
declare function generatePrivateKey(): string;
declare function getPublicKey(privateKey: Buffer): string;
// pool.js
declare type RelayPolicy = {
read: boolean,
write: boolean,
};
declare type SubscriptionCallback = (event: Event, relay: string) => void;
declare type SubscriptionOptions = {
cb: SubscriptionCallback,
filter: Filter,
// TODO: thread through how `beforeSend` actually works before trying to type it
// beforeSend(event: Event):
};
declare type Subscription = {
unsub(): void,
};
declare type PublishCallback = (status: number) => void;
// relay.js
declare type Relay = {
url: string,
sub: SubscriptionCallback,
publish: (event: Event, cb: PublishCallback) => Promise<Event>,
};
declare type PoolPublishCallback = (status: number, relay: string) => void;
declare type RelayPool = {
setPrivateKey(key: string): void,
addRelay(url: string, opts?: RelayPolicy): Relay,
sub(opts: SubscriptionOptions, id?: string): Subscription,
publish(event: Event, cb: PoolPublishCallback): Promise<Event>,
close: () => void,
status: number,
};
declare function relayPool(): RelayPool;
// nip04.js
// nip05.js
// nip06.js

View File

@ -1,6 +1,6 @@
import {generatePrivateKey, getPublicKey} from './keys'
import {relayConnect} from './relay'
import {relayPool} from './pool'
import {generatePrivateKey, getPublicKey} from './keys.js'
import {relayConnect} from './relay.js'
import {relayPool} from './pool.js'
import {
getBlankEvent,
signEvent,
@ -8,8 +8,8 @@ import {
verifySignature,
serializeEvent,
getEventHash
} from './event'
import {matchFilter, matchFilters} from './filter'
} from './event.js'
import {matchFilter, matchFilters} from './filter.js'
export {
generatePrivateKey,

42
index.test-d.ts Normal file
View File

@ -0,0 +1,42 @@
import * as process from 'process';
import {
relayPool,
getBlankEvent,
validateEvent,
RelayPool,
Event as NEvent
} from './index.js';
import { expectType } from 'tsd';
const pool = relayPool();
expectType<RelayPool>(pool);
const privkey = process.env.NOSTR_PRIVATE_KEY;
const pubkey = process.env.NOSTR_PUBLIC_KEY;
const message = {
...getBlankEvent(),
kind: 1,
content: `just saying hi from pid ${process.pid}`,
pubkey,
};
const publishCb = (status: number, url: string) => {
console.log({ status, url });
};
pool.setPrivateKey(privkey!);
const publishF = pool.publish(message, publishCb);
expectType<Promise<NEvent>>(publishF);
publishF.then((event) => {
expectType<NEvent>(event);
console.info({ event });
if (!validateEvent(event)) {
console.error(`event failed to validate!`);
process.exit(1);
}
});

View File

@ -1,4 +1,4 @@
import {wordlist} from 'micro-bip39/wordlists/english'
import {wordlist} from 'micro-bip39/wordlists/english.js'
import {
generateMnemonic,
mnemonicToSeedSync,

View File

@ -6,6 +6,7 @@
"type": "git",
"url": "https://github.com/fiatjaf/nostr-tools.git"
},
"type": "module",
"dependencies": {
"@noble/hashes": "^0.5.7",
"@noble/secp256k1": "^1.5.2",
@ -31,14 +32,18 @@
],
"devDependencies": {
"@esbuild-plugins/node-globals-polyfill": "^0.1.1",
"@types/node": "^18.0.3",
"esbuild": "^0.14.38",
"esbuild-plugin-alias": "^0.2.1",
"eslint": "^8.5.0",
"eslint-plugin-babel": "^5.3.1",
"esm-loader-typescript": "^1.0.1",
"events": "^3.3.0",
"readable-stream": "^3.6.0"
"tsd": "^0.22.0",
"typescript": "^4.7.4"
},
"scripts": {
"prepublish": "node build.js"
"prepublish": "node build.cjs",
"check-ts": "tsd && node --no-warnings --loader=esm-loader-typescript index.test-d.ts"
}
}

View File

@ -1,5 +1,5 @@
import {getEventHash, verifySignature, signEvent} from './event'
import {relayConnect, normalizeRelayURL} from './relay'
import {getEventHash, verifySignature, signEvent} from './event.js'
import {relayConnect, normalizeRelayURL} from './relay.js'
export function relayPool() {
var globalPrivateKey

View File

@ -2,8 +2,8 @@
import 'websocket-polyfill'
import {verifySignature, validateEvent} from './event'
import {matchFilters} from './filter'
import {verifySignature, validateEvent} from './event.js'
import {matchFilters} from './filter.js'
export function normalizeRelayURL(url) {
let [host, ...qs] = url.trim().split('?')

25
tsconfig.json Normal file
View File

@ -0,0 +1,25 @@
{
"compilerOptions": {
"module": "es2020",
"target": "es2020",
"lib": ["dom", "es2020"],
"esModuleInterop": true,
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"declaration": true,
"strict": true,
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"baseUrl": "./",
"typeRoots": ["."],
"types": ["node"],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"t/nostr-tools-tests.ts"
]
}