nostr-arena 0.1.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/LICENSE +21 -0
- package/README.md +188 -0
- package/dist/__tests__/callbacks.test.d.ts +28 -0
- package/dist/__tests__/callbacks.test.d.ts.map +1 -0
- package/dist/__tests__/callbacks.test.js +140 -0
- package/dist/__tests__/callbacks.test.js.map +1 -0
- package/dist/__tests__/config.test.d.ts +18 -0
- package/dist/__tests__/config.test.d.ts.map +1 -0
- package/dist/__tests__/config.test.js +43 -0
- package/dist/__tests__/config.test.js.map +1 -0
- package/dist/__tests__/error-handling.test.d.ts +14 -0
- package/dist/__tests__/error-handling.test.d.ts.map +1 -0
- package/dist/__tests__/error-handling.test.js +199 -0
- package/dist/__tests__/error-handling.test.js.map +1 -0
- package/dist/__tests__/protocol.test.d.ts +7 -0
- package/dist/__tests__/protocol.test.d.ts.map +1 -0
- package/dist/__tests__/protocol.test.js +257 -0
- package/dist/__tests__/protocol.test.js.map +1 -0
- package/dist/__tests__/state-flow.test.d.ts +37 -0
- package/dist/__tests__/state-flow.test.d.ts.map +1 -0
- package/dist/__tests__/state-flow.test.js +160 -0
- package/dist/__tests__/state-flow.test.js.map +1 -0
- package/dist/__tests__/timing.test.d.ts +20 -0
- package/dist/__tests__/timing.test.d.ts.map +1 -0
- package/dist/__tests__/timing.test.js +73 -0
- package/dist/__tests__/timing.test.js.map +1 -0
- package/dist/core/Arena.d.ts +164 -0
- package/dist/core/Arena.d.ts.map +1 -0
- package/dist/core/Arena.js +634 -0
- package/dist/core/Arena.js.map +1 -0
- package/dist/core/NostrClient.d.ts +108 -0
- package/dist/core/NostrClient.d.ts.map +1 -0
- package/dist/core/NostrClient.js +225 -0
- package/dist/core/NostrClient.js.map +1 -0
- package/dist/core/index.d.ts +8 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +7 -0
- package/dist/core/index.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/proxy.d.ts +36 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.js +98 -0
- package/dist/proxy.js.map +1 -0
- package/dist/react/index.d.ts +7 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +6 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/useArena.d.ts +74 -0
- package/dist/react/useArena.d.ts.map +1 -0
- package/dist/react/useArena.js +224 -0
- package/dist/react/useArena.js.map +1 -0
- package/dist/retry.d.ts +54 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +82 -0
- package/dist/retry.js.map +1 -0
- package/dist/testing/MockArena.d.ts +84 -0
- package/dist/testing/MockArena.d.ts.map +1 -0
- package/dist/testing/MockArena.js +156 -0
- package/dist/testing/MockArena.js.map +1 -0
- package/dist/testing/index.d.ts +6 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +6 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/types.d.ts +183 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +55 -0
- package/dist/types.js.map +1 -0
- package/package.json +84 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* nostr-battle-room - NostrClient
|
|
3
|
+
* Framework-agnostic Nostr connection management
|
|
4
|
+
*/
|
|
5
|
+
import type { Filter } from 'nostr-tools';
|
|
6
|
+
import type { NostrEvent, Unsubscribe } from '../types';
|
|
7
|
+
import { type RetryOptions } from '../retry';
|
|
8
|
+
export type { Filter as NostrFilter } from 'nostr-tools';
|
|
9
|
+
/**
|
|
10
|
+
* Options for NostrClient
|
|
11
|
+
*/
|
|
12
|
+
export interface NostrClientOptions {
|
|
13
|
+
/** Nostr relay URLs */
|
|
14
|
+
relays?: string[];
|
|
15
|
+
/** Storage key prefix for persisting keys */
|
|
16
|
+
storageKeyPrefix?: string;
|
|
17
|
+
/** Custom storage (defaults to localStorage) */
|
|
18
|
+
storage?: {
|
|
19
|
+
getItem: (key: string) => string | null;
|
|
20
|
+
setItem: (key: string, value: string) => void;
|
|
21
|
+
};
|
|
22
|
+
/** Retry options for publish operations */
|
|
23
|
+
publishRetry?: RetryOptions;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* NostrClient - Manages Nostr connection, publishing, and subscriptions
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* const client = new NostrClient({ relays: ['wss://relay.damus.io'] });
|
|
31
|
+
* await client.connect();
|
|
32
|
+
*
|
|
33
|
+
* // Publish an event
|
|
34
|
+
* await client.publish({
|
|
35
|
+
* kind: 25000,
|
|
36
|
+
* tags: [['d', 'my-room']],
|
|
37
|
+
* content: JSON.stringify({ type: 'state', data: {} }),
|
|
38
|
+
* });
|
|
39
|
+
*
|
|
40
|
+
* // Subscribe to events
|
|
41
|
+
* const unsubscribe = client.subscribe(
|
|
42
|
+
* [{ kinds: [25000], '#d': ['my-room'] }],
|
|
43
|
+
* (event) => console.log('Received:', event)
|
|
44
|
+
* );
|
|
45
|
+
*
|
|
46
|
+
* // Later: cleanup
|
|
47
|
+
* unsubscribe();
|
|
48
|
+
* client.disconnect();
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare class NostrClient {
|
|
52
|
+
private pool;
|
|
53
|
+
private secretKey;
|
|
54
|
+
private _publicKey;
|
|
55
|
+
private _isConnected;
|
|
56
|
+
private relays;
|
|
57
|
+
private storageKeyPrefix;
|
|
58
|
+
private storage;
|
|
59
|
+
private publishRetry;
|
|
60
|
+
constructor(options?: NostrClientOptions);
|
|
61
|
+
/**
|
|
62
|
+
* Whether the client is connected to relays
|
|
63
|
+
*/
|
|
64
|
+
get isConnected(): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* The public key of this client (Nostr identity)
|
|
67
|
+
*/
|
|
68
|
+
get publicKey(): string;
|
|
69
|
+
/**
|
|
70
|
+
* Get the connection status of each relay
|
|
71
|
+
* @returns Map of relay URL to connection status (true = connected)
|
|
72
|
+
*/
|
|
73
|
+
getRelayStatus(): Map<string, boolean>;
|
|
74
|
+
/**
|
|
75
|
+
* Check if at least one relay is connected
|
|
76
|
+
*/
|
|
77
|
+
get hasConnectedRelay(): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Connect to Nostr relays
|
|
80
|
+
* Generates or retrieves a key pair from storage
|
|
81
|
+
*/
|
|
82
|
+
connect(): void;
|
|
83
|
+
/**
|
|
84
|
+
* Safely set storage item, ignoring quota errors
|
|
85
|
+
*/
|
|
86
|
+
private safeStorageSet;
|
|
87
|
+
/**
|
|
88
|
+
* Disconnect from all relays
|
|
89
|
+
*/
|
|
90
|
+
disconnect(): void;
|
|
91
|
+
/**
|
|
92
|
+
* Publish an event to all relays with retry logic
|
|
93
|
+
*
|
|
94
|
+
* Retries with exponential backoff if all relays fail.
|
|
95
|
+
* Succeeds if at least one relay accepts the event.
|
|
96
|
+
*/
|
|
97
|
+
publish(eventTemplate: Omit<NostrEvent, 'id' | 'pubkey' | 'created_at' | 'sig'>): Promise<void>;
|
|
98
|
+
/**
|
|
99
|
+
* Subscribe to events matching the given filters
|
|
100
|
+
* @returns Unsubscribe function
|
|
101
|
+
*/
|
|
102
|
+
subscribe(filters: Filter[], onEvent: (event: NostrEvent) => void): Unsubscribe;
|
|
103
|
+
/**
|
|
104
|
+
* Fetch events matching the given filter (one-time query)
|
|
105
|
+
*/
|
|
106
|
+
fetch(filter: Filter, timeoutMs?: number): Promise<NostrEvent[]>;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=NostrClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NostrClient.d.ts","sourceRoot":"","sources":["../../src/core/NostrClient.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAExD,OAAO,EAAa,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAGxD,YAAY,EAAE,MAAM,IAAI,WAAW,EAAE,MAAM,aAAa,CAAC;AAEzD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,uBAAuB;IACvB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,6CAA6C;IAC7C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gDAAgD;IAChD,OAAO,CAAC,EAAE;QACR,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;QACxC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;KAC/C,CAAC;IACF,2CAA2C;IAC3C,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,IAAI,CAA2B;IACvC,OAAO,CAAC,SAAS,CAA2B;IAC5C,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,YAAY,CAAkB;IACtC,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,OAAO,CAA6C;IAC5D,OAAO,CAAC,YAAY,CAAe;gBAEvB,OAAO,GAAE,kBAAuB;IAc5C;;OAEG;IACH,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED;;OAEG;IACH,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED;;;OAGG;IACH,cAAc,IAAI,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;IAOtC;;OAEG;IACH,IAAI,iBAAiB,IAAI,OAAO,CAG/B;IAED;;;OAGG;IACH,OAAO,IAAI,IAAI;IA+Bf;;OAEG;IACH,OAAO,CAAC,cAAc;IAQtB;;OAEG;IACH,UAAU,IAAI,IAAI;IAQlB;;;;;OAKG;IACG,OAAO,CACX,aAAa,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,GAAG,QAAQ,GAAG,YAAY,GAAG,KAAK,CAAC,GACtE,OAAO,CAAC,IAAI,CAAC;IAkBhB;;;OAGG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,GAAG,WAAW;IAuB/E;;OAEG;IACG,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,GAAE,MAAa,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;CA2C7E"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* nostr-battle-room - NostrClient
|
|
3
|
+
* Framework-agnostic Nostr connection management
|
|
4
|
+
*/
|
|
5
|
+
import { SimplePool, finalizeEvent, generateSecretKey, getPublicKey } from 'nostr-tools';
|
|
6
|
+
import { DEFAULT_CONFIG } from '../types';
|
|
7
|
+
import { withRetry } from '../retry';
|
|
8
|
+
/**
|
|
9
|
+
* NostrClient - Manages Nostr connection, publishing, and subscriptions
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const client = new NostrClient({ relays: ['wss://relay.damus.io'] });
|
|
14
|
+
* await client.connect();
|
|
15
|
+
*
|
|
16
|
+
* // Publish an event
|
|
17
|
+
* await client.publish({
|
|
18
|
+
* kind: 25000,
|
|
19
|
+
* tags: [['d', 'my-room']],
|
|
20
|
+
* content: JSON.stringify({ type: 'state', data: {} }),
|
|
21
|
+
* });
|
|
22
|
+
*
|
|
23
|
+
* // Subscribe to events
|
|
24
|
+
* const unsubscribe = client.subscribe(
|
|
25
|
+
* [{ kinds: [25000], '#d': ['my-room'] }],
|
|
26
|
+
* (event) => console.log('Received:', event)
|
|
27
|
+
* );
|
|
28
|
+
*
|
|
29
|
+
* // Later: cleanup
|
|
30
|
+
* unsubscribe();
|
|
31
|
+
* client.disconnect();
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export class NostrClient {
|
|
35
|
+
constructor(options = {}) {
|
|
36
|
+
this.pool = null;
|
|
37
|
+
this.secretKey = null;
|
|
38
|
+
this._publicKey = '';
|
|
39
|
+
this._isConnected = false;
|
|
40
|
+
this.relays = options.relays ?? DEFAULT_CONFIG.relays;
|
|
41
|
+
this.storageKeyPrefix = options.storageKeyPrefix ?? 'nostr-battle';
|
|
42
|
+
this.storage = options.storage ?? {
|
|
43
|
+
getItem: (key) => localStorage.getItem(key),
|
|
44
|
+
setItem: (key, value) => localStorage.setItem(key, value),
|
|
45
|
+
};
|
|
46
|
+
this.publishRetry = options.publishRetry ?? {
|
|
47
|
+
maxAttempts: 3,
|
|
48
|
+
initialDelay: 1000,
|
|
49
|
+
maxDelay: 5000,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Whether the client is connected to relays
|
|
54
|
+
*/
|
|
55
|
+
get isConnected() {
|
|
56
|
+
return this._isConnected;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The public key of this client (Nostr identity)
|
|
60
|
+
*/
|
|
61
|
+
get publicKey() {
|
|
62
|
+
return this._publicKey;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Get the connection status of each relay
|
|
66
|
+
* @returns Map of relay URL to connection status (true = connected)
|
|
67
|
+
*/
|
|
68
|
+
getRelayStatus() {
|
|
69
|
+
if (!this.pool) {
|
|
70
|
+
return new Map();
|
|
71
|
+
}
|
|
72
|
+
return this.pool.listConnectionStatus();
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Check if at least one relay is connected
|
|
76
|
+
*/
|
|
77
|
+
get hasConnectedRelay() {
|
|
78
|
+
const status = this.getRelayStatus();
|
|
79
|
+
return Array.from(status.values()).some((connected) => connected);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Connect to Nostr relays
|
|
83
|
+
* Generates or retrieves a key pair from storage
|
|
84
|
+
*/
|
|
85
|
+
connect() {
|
|
86
|
+
if (this._isConnected)
|
|
87
|
+
return;
|
|
88
|
+
// Generate or retrieve key pair
|
|
89
|
+
const storageKey = `${this.storageKeyPrefix}-key`;
|
|
90
|
+
try {
|
|
91
|
+
const storedKey = this.storage.getItem(storageKey);
|
|
92
|
+
if (storedKey) {
|
|
93
|
+
try {
|
|
94
|
+
this.secretKey = new Uint8Array(JSON.parse(storedKey));
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// Invalid stored key, generate new one
|
|
98
|
+
this.secretKey = generateSecretKey();
|
|
99
|
+
this.safeStorageSet(storageKey, JSON.stringify(Array.from(this.secretKey)));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
this.secretKey = generateSecretKey();
|
|
104
|
+
this.safeStorageSet(storageKey, JSON.stringify(Array.from(this.secretKey)));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// Storage not available, generate ephemeral key
|
|
109
|
+
this.secretKey = generateSecretKey();
|
|
110
|
+
}
|
|
111
|
+
this._publicKey = getPublicKey(this.secretKey);
|
|
112
|
+
this.pool = new SimplePool();
|
|
113
|
+
this._isConnected = true;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Safely set storage item, ignoring quota errors
|
|
117
|
+
*/
|
|
118
|
+
safeStorageSet(key, value) {
|
|
119
|
+
try {
|
|
120
|
+
this.storage.setItem(key, value);
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// Ignore storage errors (quota exceeded, etc.)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Disconnect from all relays
|
|
128
|
+
*/
|
|
129
|
+
disconnect() {
|
|
130
|
+
if (this.pool) {
|
|
131
|
+
this.pool.close(this.relays);
|
|
132
|
+
this.pool = null;
|
|
133
|
+
}
|
|
134
|
+
this._isConnected = false;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Publish an event to all relays with retry logic
|
|
138
|
+
*
|
|
139
|
+
* Retries with exponential backoff if all relays fail.
|
|
140
|
+
* Succeeds if at least one relay accepts the event.
|
|
141
|
+
*/
|
|
142
|
+
async publish(eventTemplate) {
|
|
143
|
+
if (!this.pool || !this.secretKey) {
|
|
144
|
+
throw new Error('NostrClient not connected. Call connect() first.');
|
|
145
|
+
}
|
|
146
|
+
const event = finalizeEvent({
|
|
147
|
+
kind: eventTemplate.kind,
|
|
148
|
+
tags: eventTemplate.tags,
|
|
149
|
+
content: eventTemplate.content,
|
|
150
|
+
created_at: Math.floor(Date.now() / 1000),
|
|
151
|
+
}, this.secretKey);
|
|
152
|
+
await withRetry(() => Promise.any(this.pool.publish(this.relays, event)), this.publishRetry);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Subscribe to events matching the given filters
|
|
156
|
+
* @returns Unsubscribe function
|
|
157
|
+
*/
|
|
158
|
+
subscribe(filters, onEvent) {
|
|
159
|
+
if (!this.pool) {
|
|
160
|
+
console.warn('NostrClient not connected. Call connect() first.');
|
|
161
|
+
return () => { };
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
// nostr-tools types show Filter (singular) but implementation accepts Filter[]
|
|
165
|
+
const sub = this.pool.subscribeMany(this.relays, filters, {
|
|
166
|
+
onevent(event) {
|
|
167
|
+
onEvent(event);
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
return () => {
|
|
171
|
+
sub.close();
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
console.error('Failed to subscribe:', error);
|
|
176
|
+
return () => { };
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Fetch events matching the given filter (one-time query)
|
|
181
|
+
*/
|
|
182
|
+
async fetch(filter, timeoutMs = 5000) {
|
|
183
|
+
if (!this.pool) {
|
|
184
|
+
throw new Error('NostrClient not connected. Call connect() first.');
|
|
185
|
+
}
|
|
186
|
+
return new Promise((resolve, reject) => {
|
|
187
|
+
const events = [];
|
|
188
|
+
let resolved = false;
|
|
189
|
+
const finish = (success, error) => {
|
|
190
|
+
if (resolved)
|
|
191
|
+
return;
|
|
192
|
+
resolved = true;
|
|
193
|
+
sub.close();
|
|
194
|
+
if (success) {
|
|
195
|
+
resolve(events);
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
reject(error);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
const sub = this.pool.subscribeManyEose(this.relays, filter, {
|
|
202
|
+
onevent: (event) => {
|
|
203
|
+
events.push(event);
|
|
204
|
+
},
|
|
205
|
+
onclose: (reasons) => {
|
|
206
|
+
// Check if at least one relay sent EOSE (successful response)
|
|
207
|
+
const hasEose = reasons.some((r) => r === 'EOSE');
|
|
208
|
+
if (hasEose) {
|
|
209
|
+
// Valid response (may have 0 events, but relay responded)
|
|
210
|
+
finish(true);
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
// All relays failed without sending EOSE
|
|
214
|
+
finish(false, new Error('No relay response: ' + reasons.join(', ')));
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
// Timeout fallback
|
|
219
|
+
setTimeout(() => {
|
|
220
|
+
finish(false, new Error('No relay response: timeout'));
|
|
221
|
+
}, timeoutMs);
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=NostrClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NostrClient.js","sourceRoot":"","sources":["../../src/core/NostrClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* nostr-battle-room - Core exports
|
|
3
|
+
* Framework-agnostic classes for Nostr battle rooms
|
|
4
|
+
*/
|
|
5
|
+
export { NostrClient } from './NostrClient';
|
|
6
|
+
export type { NostrClientOptions } from './NostrClient';
|
|
7
|
+
export { Arena } from './Arena';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAG5C,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* nostr-battle-room
|
|
3
|
+
* Nostr-based real-time battle room for multiplayer games
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* // Using the core Arena class (framework-agnostic)
|
|
8
|
+
* import { Arena } from 'nostr-battle-room';
|
|
9
|
+
*
|
|
10
|
+
* const room = new Arena<MyGameState>({ gameId: 'my-game' });
|
|
11
|
+
* room.onOpponentState((state) => console.log(state));
|
|
12
|
+
* await room.create();
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* // Using the React hook
|
|
18
|
+
* import { useArena } from 'nostr-battle-room/react';
|
|
19
|
+
*
|
|
20
|
+
* function Game() {
|
|
21
|
+
* const { roomState, opponent, createRoom } = useArena<MyGameState>({
|
|
22
|
+
* gameId: 'my-game',
|
|
23
|
+
* });
|
|
24
|
+
* // ...
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export { Arena } from './core/Arena';
|
|
29
|
+
export { NostrClient } from './core/NostrClient';
|
|
30
|
+
export type { NostrClientOptions, NostrFilter } from './core/NostrClient';
|
|
31
|
+
export type { ArenaConfig, ArenaCallbacks, ArenaEventName, RoomState, RoomStatus, OpponentBase, OpponentState, NostrEvent, StoredRoomData, Unsubscribe, RoomEventContent, JoinEventContent, StateEventContent, GameOverEventContent, RematchEventContent, HeartbeatEventContent, BattleEventContent, } from './types';
|
|
32
|
+
export { DEFAULT_CONFIG, INITIAL_ROOM_STATE, NOSTR_KINDS, createRoomTag, generateSeed, generateRoomId, } from './types';
|
|
33
|
+
export { configureProxy, resetProxyConfiguration } from './proxy';
|
|
34
|
+
export { withRetry, withTimeout, timeout, type RetryOptions } from './retry';
|
|
35
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,YAAY,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAG1E,YAAY,EACV,WAAW,EACX,cAAc,EACd,cAAc,EACd,SAAS,EACT,UAAU,EACV,YAAY,EACZ,aAAa,EACb,UAAU,EACV,cAAc,EACd,WAAW,EAEX,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,SAAS,CAAC;AAGjB,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,YAAY,EACZ,cAAc,GACf,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAGlE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* nostr-battle-room
|
|
3
|
+
* Nostr-based real-time battle room for multiplayer games
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* // Using the core Arena class (framework-agnostic)
|
|
8
|
+
* import { Arena } from 'nostr-battle-room';
|
|
9
|
+
*
|
|
10
|
+
* const room = new Arena<MyGameState>({ gameId: 'my-game' });
|
|
11
|
+
* room.onOpponentState((state) => console.log(state));
|
|
12
|
+
* await room.create();
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* // Using the React hook
|
|
18
|
+
* import { useArena } from 'nostr-battle-room/react';
|
|
19
|
+
*
|
|
20
|
+
* function Game() {
|
|
21
|
+
* const { roomState, opponent, createRoom } = useArena<MyGameState>({
|
|
22
|
+
* gameId: 'my-game',
|
|
23
|
+
* });
|
|
24
|
+
* // ...
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
// Core exports
|
|
29
|
+
export { Arena } from './core/Arena';
|
|
30
|
+
export { NostrClient } from './core/NostrClient';
|
|
31
|
+
// Constants and utilities
|
|
32
|
+
export { DEFAULT_CONFIG, INITIAL_ROOM_STATE, NOSTR_KINDS, createRoomTag, generateSeed, generateRoomId, } from './types';
|
|
33
|
+
// Proxy support (Node.js)
|
|
34
|
+
export { configureProxy, resetProxyConfiguration } from './proxy';
|
|
35
|
+
// Retry utilities
|
|
36
|
+
export { withRetry, withTimeout, timeout } from './retry';
|
|
37
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,eAAe;AACf,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAyBjD,0BAA0B;AAC1B,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,YAAY,EACZ,cAAc,GACf,MAAM,SAAS,CAAC;AAEjB,0BAA0B;AAC1B,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAElE,kBAAkB;AAClB,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC"}
|
package/dist/proxy.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* nostr-battle-room - Proxy Support
|
|
3
|
+
* Configure WebSocket to work through HTTP/HTTPS proxies
|
|
4
|
+
*
|
|
5
|
+
* Call configureProxy() before creating any Arena instances.
|
|
6
|
+
* Reads proxy URL from environment variables:
|
|
7
|
+
* - HTTPS_PROXY
|
|
8
|
+
* - HTTP_PROXY
|
|
9
|
+
* - ALL_PROXY
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { configureProxy } from 'nostr-battle-room';
|
|
14
|
+
*
|
|
15
|
+
* // Call once at startup (Node.js only)
|
|
16
|
+
* configureProxy();
|
|
17
|
+
*
|
|
18
|
+
* // Now create rooms as usual
|
|
19
|
+
* const room = new Arena({ gameId: 'my-game' });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Configure WebSocket to use proxy from environment variables.
|
|
24
|
+
* Must be called before connecting to any relays.
|
|
25
|
+
*
|
|
26
|
+
* In Node.js: Sets up proxy-aware WebSocket if HTTPS_PROXY/HTTP_PROXY is set
|
|
27
|
+
* In browser: No-op (browsers handle proxies at OS/network level)
|
|
28
|
+
*
|
|
29
|
+
* @returns true if proxy was configured, false otherwise
|
|
30
|
+
*/
|
|
31
|
+
export declare function configureProxy(): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Reset proxy configuration (mainly for testing)
|
|
34
|
+
*/
|
|
35
|
+
export declare function resetProxyConfiguration(): void;
|
|
36
|
+
//# sourceMappingURL=proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAyBH;;;;;;;;GAQG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAmDxC;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C"}
|
package/dist/proxy.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* nostr-battle-room - Proxy Support
|
|
3
|
+
* Configure WebSocket to work through HTTP/HTTPS proxies
|
|
4
|
+
*
|
|
5
|
+
* Call configureProxy() before creating any Arena instances.
|
|
6
|
+
* Reads proxy URL from environment variables:
|
|
7
|
+
* - HTTPS_PROXY
|
|
8
|
+
* - HTTP_PROXY
|
|
9
|
+
* - ALL_PROXY
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { configureProxy } from 'nostr-battle-room';
|
|
14
|
+
*
|
|
15
|
+
* // Call once at startup (Node.js only)
|
|
16
|
+
* configureProxy();
|
|
17
|
+
*
|
|
18
|
+
* // Now create rooms as usual
|
|
19
|
+
* const room = new Arena({ gameId: 'my-game' });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
import { useWebSocketImplementation } from 'nostr-tools/pool';
|
|
23
|
+
let proxyConfigured = false;
|
|
24
|
+
/**
|
|
25
|
+
* Get proxy URL from environment variables
|
|
26
|
+
*/
|
|
27
|
+
function getProxyUrl() {
|
|
28
|
+
if (typeof process === 'undefined' || !process.env) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
return process.env.HTTPS_PROXY || process.env.HTTP_PROXY || process.env.ALL_PROXY;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Check if running in Node.js environment
|
|
35
|
+
*/
|
|
36
|
+
function isNode() {
|
|
37
|
+
return (typeof process !== 'undefined' && process.versions != null && process.versions.node != null);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Configure WebSocket to use proxy from environment variables.
|
|
41
|
+
* Must be called before connecting to any relays.
|
|
42
|
+
*
|
|
43
|
+
* In Node.js: Sets up proxy-aware WebSocket if HTTPS_PROXY/HTTP_PROXY is set
|
|
44
|
+
* In browser: No-op (browsers handle proxies at OS/network level)
|
|
45
|
+
*
|
|
46
|
+
* @returns true if proxy was configured, false otherwise
|
|
47
|
+
*/
|
|
48
|
+
export function configureProxy() {
|
|
49
|
+
if (proxyConfigured) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
if (!isNode()) {
|
|
53
|
+
// Browser environment - no action needed
|
|
54
|
+
proxyConfigured = true;
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
const proxyUrl = getProxyUrl();
|
|
58
|
+
// Always configure ws for Node.js, even without proxy
|
|
59
|
+
// This ensures WebSocket works in Node.js environment
|
|
60
|
+
try {
|
|
61
|
+
// Dynamic import to avoid bundling issues in browser
|
|
62
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
63
|
+
const WebSocket = require('ws');
|
|
64
|
+
if (proxyUrl) {
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
66
|
+
const { HttpsProxyAgent } = require('https-proxy-agent');
|
|
67
|
+
const agent = new HttpsProxyAgent(proxyUrl);
|
|
68
|
+
// Create a WebSocket class that uses the proxy agent
|
|
69
|
+
class ProxyWebSocket extends WebSocket {
|
|
70
|
+
constructor(url, protocols) {
|
|
71
|
+
super(url, protocols, { agent });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
useWebSocketImplementation(ProxyWebSocket);
|
|
75
|
+
proxyConfigured = true;
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// No proxy, but still need ws for Node.js
|
|
80
|
+
useWebSocketImplementation(WebSocket);
|
|
81
|
+
proxyConfigured = true;
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// ws or https-proxy-agent not installed
|
|
87
|
+
console.warn('nostr-battle-room: Could not configure WebSocket for Node.js.', 'Install "ws" package for Node.js support.', proxyUrl ? 'Install "https-proxy-agent" for proxy support.' : '');
|
|
88
|
+
proxyConfigured = true;
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Reset proxy configuration (mainly for testing)
|
|
94
|
+
*/
|
|
95
|
+
export function resetProxyConfiguration() {
|
|
96
|
+
proxyConfigured = false;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAE9D,IAAI,eAAe,GAAG,KAAK,CAAC;AAE5B;;GAEG;AACH,SAAS,WAAW;IAClB,IAAI,OAAO,OAAO,KAAK,WAAW,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;QACnD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;AACpF,CAAC;AAED;;GAEG;AACH,SAAS,MAAM;IACb,OAAO,CACL,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,QAAQ,IAAI,IAAI,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,IAAI,IAAI,CAC5F,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc;IAC5B,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;QACd,yCAAyC;QACzC,eAAe,GAAG,IAAI,CAAC;QACvB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAE/B,sDAAsD;IACtD,sDAAsD;IACtD,IAAI,CAAC;QACH,qDAAqD;QACrD,iEAAiE;QACjE,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAEhC,IAAI,QAAQ,EAAE,CAAC;YACb,iEAAiE;YACjE,MAAM,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;YACzD,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,QAAQ,CAAC,CAAC;YAE5C,qDAAqD;YACrD,MAAM,cAAe,SAAQ,SAAS;gBACpC,YAAY,GAAW,EAAE,SAA6B;oBACpD,KAAK,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;gBACnC,CAAC;aACF;YAED,0BAA0B,CAAC,cAAc,CAAC,CAAC;YAC3C,eAAe,GAAG,IAAI,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;aAAM,CAAC;YACN,0CAA0C;YAC1C,0BAA0B,CAAC,SAAS,CAAC,CAAC;YACtC,eAAe,GAAG,IAAI,CAAC;YACvB,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,wCAAwC;QACxC,OAAO,CAAC,IAAI,CACV,+DAA+D,EAC/D,2CAA2C,EAC3C,QAAQ,CAAC,CAAC,CAAC,gDAAgD,CAAC,CAAC,CAAC,EAAE,CACjE,CAAC;QACF,eAAe,GAAG,IAAI,CAAC;QACvB,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB;IACrC,eAAe,GAAG,KAAK,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
|