@stvor/sdk 2.4.1 → 3.0.0

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.
Files changed (81) hide show
  1. package/dist/facade/app.d.ts +83 -76
  2. package/dist/facade/app.js +330 -195
  3. package/dist/facade/crypto-session.cjs +29 -0
  4. package/dist/facade/crypto-session.d.ts +71 -0
  5. package/dist/facade/crypto-session.js +152 -0
  6. package/dist/facade/errors.d.ts +29 -12
  7. package/dist/facade/errors.js +49 -8
  8. package/dist/facade/index.d.ts +27 -8
  9. package/dist/facade/index.js +23 -3
  10. package/dist/facade/local-storage-identity-store.cjs +29 -0
  11. package/dist/facade/local-storage-identity-store.d.ts +50 -0
  12. package/dist/facade/local-storage-identity-store.js +100 -0
  13. package/dist/facade/metrics-attestation.cjs +29 -0
  14. package/dist/facade/metrics-attestation.d.ts +209 -0
  15. package/dist/facade/metrics-attestation.js +333 -0
  16. package/dist/facade/metrics-engine.cjs +29 -0
  17. package/dist/facade/metrics-engine.d.ts +91 -0
  18. package/dist/facade/metrics-engine.js +170 -0
  19. package/dist/facade/redis-replay-cache.cjs +29 -0
  20. package/dist/facade/redis-replay-cache.d.ts +88 -0
  21. package/dist/facade/redis-replay-cache.js +60 -0
  22. package/dist/facade/relay-client.d.ts +22 -23
  23. package/dist/facade/relay-client.js +107 -128
  24. package/dist/facade/replay-manager.cjs +29 -0
  25. package/dist/facade/replay-manager.d.ts +51 -0
  26. package/dist/facade/replay-manager.js +150 -0
  27. package/dist/facade/sodium-singleton.cjs +29 -0
  28. package/dist/facade/sodium-singleton.d.ts +20 -0
  29. package/dist/facade/sodium-singleton.js +44 -0
  30. package/dist/facade/tofu-manager.cjs +29 -0
  31. package/dist/facade/tofu-manager.d.ts +82 -0
  32. package/dist/facade/tofu-manager.js +166 -0
  33. package/dist/facade/types.d.ts +2 -0
  34. package/dist/index.d.cts +4 -0
  35. package/dist/index.d.ts +4 -0
  36. package/dist/index.js +7 -0
  37. package/dist/legacy.d.ts +31 -1
  38. package/dist/legacy.js +90 -2
  39. package/dist/ratchet/core-production.cjs +29 -0
  40. package/dist/ratchet/core-production.d.ts +95 -0
  41. package/dist/ratchet/core-production.js +286 -0
  42. package/dist/{facade/crypto.cjs → ratchet/index.cjs} +1 -1
  43. package/dist/ratchet/index.d.ts +59 -0
  44. package/dist/ratchet/index.js +343 -0
  45. package/dist/ratchet/key-recovery.cjs +29 -0
  46. package/dist/ratchet/key-recovery.d.ts +45 -0
  47. package/dist/ratchet/key-recovery.js +148 -0
  48. package/dist/ratchet/replay-protection.cjs +29 -0
  49. package/dist/ratchet/replay-protection.d.ts +21 -0
  50. package/dist/ratchet/replay-protection.js +50 -0
  51. package/dist/{mock-relay-server.cjs → ratchet/tofu.cjs} +1 -1
  52. package/dist/ratchet/tofu.d.ts +27 -0
  53. package/dist/ratchet/tofu.js +62 -0
  54. package/dist/src/facade/app.cjs +29 -0
  55. package/dist/src/facade/app.d.ts +105 -0
  56. package/dist/src/facade/app.js +245 -0
  57. package/dist/src/facade/crypto.cjs +29 -0
  58. package/dist/src/facade/errors.cjs +29 -0
  59. package/dist/src/facade/errors.d.ts +19 -0
  60. package/dist/src/facade/errors.js +21 -0
  61. package/dist/src/facade/index.cjs +29 -0
  62. package/dist/src/facade/index.d.ts +8 -0
  63. package/dist/src/facade/index.js +5 -0
  64. package/dist/src/facade/relay-client.cjs +29 -0
  65. package/dist/src/facade/relay-client.d.ts +36 -0
  66. package/dist/src/facade/relay-client.js +154 -0
  67. package/dist/src/facade/types.cjs +29 -0
  68. package/dist/src/facade/types.d.ts +50 -0
  69. package/dist/src/facade/types.js +4 -0
  70. package/dist/src/index.cjs +29 -0
  71. package/dist/src/index.d.ts +2 -0
  72. package/dist/src/index.js +2 -0
  73. package/dist/src/legacy.cjs +29 -0
  74. package/dist/src/legacy.d.ts +0 -0
  75. package/dist/src/legacy.js +1 -0
  76. package/dist/src/mock-relay-server.cjs +29 -0
  77. package/package.json +16 -5
  78. /package/dist/{facade → src/facade}/crypto.d.ts +0 -0
  79. /package/dist/{facade → src/facade}/crypto.js +0 -0
  80. /package/dist/{mock-relay-server.d.ts → src/mock-relay-server.d.ts} +0 -0
  81. /package/dist/{mock-relay-server.js → src/mock-relay-server.js} +0 -0
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Generate a SHA-256 fingerprint for a given public key.
3
+ * @param publicKey - The public key to fingerprint.
4
+ * @returns The fingerprint as a hex string.
5
+ */
6
+ export declare function generateFingerprint(publicKey: Uint8Array): string;
7
+ /**
8
+ * Store the fingerprint in the database.
9
+ * @param userId - The user ID associated with the fingerprint.
10
+ * @param fingerprint - The fingerprint to store.
11
+ */
12
+ export declare function storeFingerprint(userId: string, fingerprint: string): Promise<void>;
13
+ /**
14
+ * Verify the fingerprint against the stored value.
15
+ * @param userId - The user ID associated with the fingerprint.
16
+ * @param fingerprint - The fingerprint to verify.
17
+ * @returns True if the fingerprint matches, false otherwise.
18
+ */
19
+ export declare function verifyFingerprint(userId: string, fingerprint: string): Promise<boolean>;
20
+ /**
21
+ * Honest TOFU Limitations
22
+ *
23
+ * 1. First-session MITM risk: The first connection assumes trust.
24
+ * 2. Fingerprint mismatches result in hard failure.
25
+ * 3. No automatic recovery from key substitution attacks.
26
+ */
27
+ export declare function handleFingerprintMismatch(userId: string): void;
@@ -0,0 +1,62 @@
1
+ import { createHash } from 'crypto';
2
+ import { Pool } from 'pg';
3
+ // PostgreSQL connection pool
4
+ const pool = new Pool({
5
+ connectionString: process.env.DATABASE_URL, // Ensure DATABASE_URL is set in the environment
6
+ });
7
+ /**
8
+ * Generate a SHA-256 fingerprint for a given public key.
9
+ * @param publicKey - The public key to fingerprint.
10
+ * @returns The fingerprint as a hex string.
11
+ */
12
+ export function generateFingerprint(publicKey) {
13
+ const hash = createHash('sha256');
14
+ hash.update(publicKey);
15
+ return hash.digest('hex');
16
+ }
17
+ /**
18
+ * Store the fingerprint in the database.
19
+ * @param userId - The user ID associated with the fingerprint.
20
+ * @param fingerprint - The fingerprint to store.
21
+ */
22
+ export async function storeFingerprint(userId, fingerprint) {
23
+ const client = await pool.connect();
24
+ try {
25
+ await client.query('INSERT INTO fingerprints (user_id, fingerprint) VALUES ($1, $2) ON CONFLICT (user_id) DO UPDATE SET fingerprint = $2', [userId, fingerprint]);
26
+ }
27
+ finally {
28
+ client.release();
29
+ }
30
+ }
31
+ /**
32
+ * Verify the fingerprint against the stored value.
33
+ * @param userId - The user ID associated with the fingerprint.
34
+ * @param fingerprint - The fingerprint to verify.
35
+ * @returns True if the fingerprint matches, false otherwise.
36
+ */
37
+ export async function verifyFingerprint(userId, fingerprint) {
38
+ const client = await pool.connect();
39
+ try {
40
+ const result = await client.query('SELECT fingerprint FROM fingerprints WHERE user_id = $1', [userId]);
41
+ if (result.rows.length === 0) {
42
+ // First use: store the fingerprint
43
+ await storeFingerprint(userId, fingerprint);
44
+ return true;
45
+ }
46
+ return result.rows[0].fingerprint === fingerprint;
47
+ }
48
+ finally {
49
+ client.release();
50
+ }
51
+ }
52
+ /**
53
+ * Honest TOFU Limitations
54
+ *
55
+ * 1. First-session MITM risk: The first connection assumes trust.
56
+ * 2. Fingerprint mismatches result in hard failure.
57
+ * 3. No automatic recovery from key substitution attacks.
58
+ */
59
+ export function handleFingerprintMismatch(userId) {
60
+ console.error(`SECURITY ALERT: Fingerprint mismatch detected for user ${userId}`);
61
+ throw new Error('Fingerprint mismatch detected. Connection aborted.');
62
+ }
@@ -0,0 +1,29 @@
1
+ 'use strict';
2
+
3
+ // Auto-generated CommonJS wrapper for src/facade/app.js
4
+ // This allows `require('@stvor/sdk')` to work alongside ESM `import`.
5
+
6
+ const mod = require('module');
7
+ const url = require('url');
8
+
9
+ // Use dynamic import to load the ESM module
10
+ let _cached;
11
+ async function _load() {
12
+ if (!_cached) {
13
+ _cached = await import(url.pathToFileURL(__filename.replace(/\.cjs$/, '.js')).href);
14
+ }
15
+ return _cached;
16
+ }
17
+
18
+ // For simple CJS usage, expose a promise-based loader
19
+ module.exports = new Proxy({ load: _load }, {
20
+ get(target, prop) {
21
+ if (prop === '__esModule') return true;
22
+ if (prop === 'then') return undefined; // prevent treating as thenable
23
+ if (prop === 'load') return _load;
24
+ if (prop === 'default') {
25
+ return _load().then(m => m.default);
26
+ }
27
+ return _load().then(m => m[prop]);
28
+ }
29
+ });
@@ -0,0 +1,105 @@
1
+ import type { StvorAppConfig, UserId, MessageContent } from './types.js';
2
+ import { RelayClient } from './relay-client.js';
3
+ type MessageHandler = (from: UserId, msg: string | Uint8Array) => void;
4
+ type UserAvailableHandler = (userId: UserId) => void;
5
+ export declare class StvorFacadeClient {
6
+ readonly userId: UserId;
7
+ private readonly relay;
8
+ private readonly defaultTimeout;
9
+ private crypto;
10
+ private handlers;
11
+ private userAvailableHandlers;
12
+ private knownPubKeys;
13
+ private pendingKeyResolvers;
14
+ constructor(userId: UserId, relay: RelayClient, defaultTimeout?: number);
15
+ private handleRelayMessage;
16
+ internalInitialize(): Promise<void>;
17
+ /**
18
+ * Check if a user's public key is available locally
19
+ */
20
+ isUserAvailable(userId: UserId): boolean;
21
+ /**
22
+ * Get list of all known users (whose public keys we have)
23
+ */
24
+ getAvailableUsers(): UserId[];
25
+ /**
26
+ * Wait until a specific user's public key becomes available.
27
+ * This is the recommended way to ensure you can send messages.
28
+ *
29
+ * @param userId - The user to wait for
30
+ * @param timeoutMs - Maximum time to wait (default: 10000ms)
31
+ * @throws StvorError with RECIPIENT_TIMEOUT if timeout expires
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * await alice.waitForUser('bob@example.com');
36
+ * await alice.send('bob@example.com', 'Hello!');
37
+ * ```
38
+ */
39
+ waitForUser(userId: UserId, timeoutMs?: number): Promise<void>;
40
+ /**
41
+ * Send an encrypted message to a recipient.
42
+ *
43
+ * If the recipient's public key is not yet available, this method will
44
+ * automatically wait up to `timeoutMs` for the key to arrive via the relay.
45
+ *
46
+ * @param recipientId - The recipient's user ID
47
+ * @param content - Message content (string or Uint8Array)
48
+ * @param options - Optional: { timeout: number, waitForRecipient: boolean }
49
+ * @throws StvorError with RECIPIENT_TIMEOUT if recipient key doesn't arrive in time
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * // Auto-waits for recipient (recommended)
54
+ * await alice.send('bob@example.com', 'Hello!');
55
+ *
56
+ * // Skip waiting (throws immediately if not available)
57
+ * await alice.send('bob@example.com', 'Hello!', { waitForRecipient: false });
58
+ * ```
59
+ */
60
+ send(recipientId: UserId, content: MessageContent, options?: {
61
+ timeout?: number;
62
+ waitForRecipient?: boolean;
63
+ }): Promise<void>;
64
+ /**
65
+ * Register a handler for incoming messages
66
+ */
67
+ onMessage(handler: MessageHandler): () => void;
68
+ /**
69
+ * Register a handler that fires when a new user becomes available.
70
+ * This is triggered when we receive a user's public key announcement.
71
+ *
72
+ * **Edge-triggered**: Fires only ONCE per user, on first key discovery.
73
+ * Will NOT fire again if user reconnects with same identity.
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * client.onUserAvailable((userId) => {
78
+ * console.log(`${userId} is now available for messaging`);
79
+ * });
80
+ * ```
81
+ */
82
+ onUserAvailable(handler: UserAvailableHandler): () => void;
83
+ }
84
+ export declare class StvorApp {
85
+ private readonly config;
86
+ private clients;
87
+ constructor(config: StvorAppConfig);
88
+ connect(userId: UserId): Promise<StvorFacadeClient>;
89
+ /**
90
+ * Get a connected client by user ID
91
+ */
92
+ getClient(userId: UserId): StvorFacadeClient | undefined;
93
+ /**
94
+ * Check if a user is connected locally
95
+ */
96
+ isConnected(userId: UserId): boolean;
97
+ disconnect(userId?: UserId): Promise<void>;
98
+ }
99
+ export declare function init(config: StvorAppConfig): Promise<StvorApp>;
100
+ export declare const createApp: typeof init;
101
+ export declare const Stvor: {
102
+ init: typeof init;
103
+ createApp: typeof init;
104
+ };
105
+ export {};
@@ -0,0 +1,245 @@
1
+ import { Errors, StvorError } from './errors.js';
2
+ import { RelayClient } from './relay-client.js';
3
+ import { CryptoSession } from './crypto.js';
4
+ /** Default timeout for waiting for recipient keys (ms) */
5
+ const DEFAULT_RECIPIENT_TIMEOUT = 10000;
6
+ /** Polling interval for key resolution (ms) */
7
+ const KEY_POLL_INTERVAL = 100;
8
+ export class StvorFacadeClient {
9
+ constructor(userId, relay, defaultTimeout = DEFAULT_RECIPIENT_TIMEOUT) {
10
+ this.userId = userId;
11
+ this.relay = relay;
12
+ this.defaultTimeout = defaultTimeout;
13
+ this.handlers = [];
14
+ this.userAvailableHandlers = [];
15
+ this.knownPubKeys = new Map();
16
+ this.pendingKeyResolvers = new Map();
17
+ this.crypto = new CryptoSession();
18
+ // listen relay messages
19
+ this.relay.onMessage((m) => this.handleRelayMessage(m));
20
+ // announce our public key
21
+ this.relay.send({ type: 'announce', user: this.userId, pub: this.crypto.exportPublic() });
22
+ }
23
+ async handleRelayMessage(m) {
24
+ if (!m || typeof m !== 'object')
25
+ return;
26
+ if (m.type === 'announce' && m.user && m.pub) {
27
+ const wasKnown = this.knownPubKeys.has(m.user);
28
+ this.knownPubKeys.set(m.user, m.pub);
29
+ // Notify pending resolvers
30
+ const resolvers = this.pendingKeyResolvers.get(m.user);
31
+ if (resolvers) {
32
+ resolvers.forEach(resolve => resolve());
33
+ this.pendingKeyResolvers.delete(m.user);
34
+ }
35
+ // Notify user available handlers (only for new users)
36
+ if (!wasKnown) {
37
+ for (const h of this.userAvailableHandlers) {
38
+ try {
39
+ h(m.user);
40
+ }
41
+ catch { }
42
+ }
43
+ }
44
+ return;
45
+ }
46
+ if (m.type === 'message' && m.to === this.userId && m.payload) {
47
+ const payload = m.payload;
48
+ const sender = m.from;
49
+ try {
50
+ const plain = this.crypto.decrypt(payload, payload.senderPub);
51
+ const text = new TextDecoder().decode(plain);
52
+ for (const h of this.handlers)
53
+ h(sender, text);
54
+ }
55
+ catch (e) {
56
+ // ignore decryption errors
57
+ }
58
+ }
59
+ }
60
+ async internalInitialize() {
61
+ // nothing for now; announce already sent in constructor
62
+ }
63
+ /**
64
+ * Check if a user's public key is available locally
65
+ */
66
+ isUserAvailable(userId) {
67
+ return this.knownPubKeys.has(userId);
68
+ }
69
+ /**
70
+ * Get list of all known users (whose public keys we have)
71
+ */
72
+ getAvailableUsers() {
73
+ return Array.from(this.knownPubKeys.keys()).filter(id => id !== this.userId);
74
+ }
75
+ /**
76
+ * Wait until a specific user's public key becomes available.
77
+ * This is the recommended way to ensure you can send messages.
78
+ *
79
+ * @param userId - The user to wait for
80
+ * @param timeoutMs - Maximum time to wait (default: 10000ms)
81
+ * @throws StvorError with RECIPIENT_TIMEOUT if timeout expires
82
+ *
83
+ * @example
84
+ * ```typescript
85
+ * await alice.waitForUser('bob@example.com');
86
+ * await alice.send('bob@example.com', 'Hello!');
87
+ * ```
88
+ */
89
+ async waitForUser(userId, timeoutMs = this.defaultTimeout) {
90
+ // Already available
91
+ if (this.knownPubKeys.has(userId)) {
92
+ return;
93
+ }
94
+ return new Promise((resolve, reject) => {
95
+ const timeout = setTimeout(() => {
96
+ // Remove from pending
97
+ const resolvers = this.pendingKeyResolvers.get(userId);
98
+ if (resolvers) {
99
+ const idx = resolvers.indexOf(resolveHandler);
100
+ if (idx >= 0)
101
+ resolvers.splice(idx, 1);
102
+ if (resolvers.length === 0)
103
+ this.pendingKeyResolvers.delete(userId);
104
+ }
105
+ reject(new StvorError(Errors.RECIPIENT_TIMEOUT, `Timed out waiting for user "${userId}" after ${timeoutMs}ms. ` +
106
+ `The user may not be connected to the relay. ` +
107
+ `Ensure both parties are online before sending messages.`, 'Verify the recipient is connected, or increase timeout', true));
108
+ }, timeoutMs);
109
+ const resolveHandler = () => {
110
+ clearTimeout(timeout);
111
+ resolve();
112
+ };
113
+ // Add to pending resolvers
114
+ if (!this.pendingKeyResolvers.has(userId)) {
115
+ this.pendingKeyResolvers.set(userId, []);
116
+ }
117
+ this.pendingKeyResolvers.get(userId).push(resolveHandler);
118
+ });
119
+ }
120
+ /**
121
+ * Send an encrypted message to a recipient.
122
+ *
123
+ * If the recipient's public key is not yet available, this method will
124
+ * automatically wait up to `timeoutMs` for the key to arrive via the relay.
125
+ *
126
+ * @param recipientId - The recipient's user ID
127
+ * @param content - Message content (string or Uint8Array)
128
+ * @param options - Optional: { timeout: number, waitForRecipient: boolean }
129
+ * @throws StvorError with RECIPIENT_TIMEOUT if recipient key doesn't arrive in time
130
+ *
131
+ * @example
132
+ * ```typescript
133
+ * // Auto-waits for recipient (recommended)
134
+ * await alice.send('bob@example.com', 'Hello!');
135
+ *
136
+ * // Skip waiting (throws immediately if not available)
137
+ * await alice.send('bob@example.com', 'Hello!', { waitForRecipient: false });
138
+ * ```
139
+ */
140
+ async send(recipientId, content, options) {
141
+ const { timeout = this.defaultTimeout, waitForRecipient = true } = options ?? {};
142
+ // Try to resolve recipient key
143
+ let recipientPub = this.knownPubKeys.get(recipientId);
144
+ if (!recipientPub) {
145
+ if (!waitForRecipient) {
146
+ throw new StvorError(Errors.RECIPIENT_NOT_FOUND, `Recipient "${recipientId}" is not available. ` +
147
+ `Their public key has not been announced to the relay. ` +
148
+ `Use waitForUser() or enable waitForRecipient option.`, 'Call waitForUser(recipientId) before sending, or ensure recipient is connected', false);
149
+ }
150
+ // Wait for recipient key with timeout
151
+ await this.waitForUser(recipientId, timeout);
152
+ recipientPub = this.knownPubKeys.get(recipientId);
153
+ if (!recipientPub) {
154
+ // Should not happen, but safety check
155
+ throw new StvorError(Errors.RECIPIENT_NOT_FOUND, `Recipient "${recipientId}" key resolution failed unexpectedly.`, 'This is an internal error, please report it', false);
156
+ }
157
+ }
158
+ const plain = typeof content === 'string' ? new TextEncoder().encode(content) : content;
159
+ const payload = this.crypto.encrypt(plain, recipientPub);
160
+ const msg = { type: 'message', to: recipientId, from: this.userId, payload };
161
+ this.relay.send(msg);
162
+ }
163
+ /**
164
+ * Register a handler for incoming messages
165
+ */
166
+ onMessage(handler) {
167
+ this.handlers.push(handler);
168
+ return () => {
169
+ const i = this.handlers.indexOf(handler);
170
+ if (i >= 0)
171
+ this.handlers.splice(i, 1);
172
+ };
173
+ }
174
+ /**
175
+ * Register a handler that fires when a new user becomes available.
176
+ * This is triggered when we receive a user's public key announcement.
177
+ *
178
+ * **Edge-triggered**: Fires only ONCE per user, on first key discovery.
179
+ * Will NOT fire again if user reconnects with same identity.
180
+ *
181
+ * @example
182
+ * ```typescript
183
+ * client.onUserAvailable((userId) => {
184
+ * console.log(`${userId} is now available for messaging`);
185
+ * });
186
+ * ```
187
+ */
188
+ onUserAvailable(handler) {
189
+ this.userAvailableHandlers.push(handler);
190
+ return () => {
191
+ const i = this.userAvailableHandlers.indexOf(handler);
192
+ if (i >= 0)
193
+ this.userAvailableHandlers.splice(i, 1);
194
+ };
195
+ }
196
+ }
197
+ export class StvorApp {
198
+ constructor(config) {
199
+ this.config = config;
200
+ this.clients = new Map();
201
+ }
202
+ async connect(userId) {
203
+ const existing = this.clients.get(userId);
204
+ if (existing)
205
+ return existing;
206
+ const relay = new RelayClient(this.config.relayUrl ?? 'wss://stvor.xyz/relay', this.config.appToken, this.config.timeout ?? 10000);
207
+ // Wait for relay handshake - throws if API key is invalid
208
+ await relay.init();
209
+ const client = new StvorFacadeClient(userId, relay, this.config.timeout ?? 10000);
210
+ await client.internalInitialize();
211
+ this.clients.set(userId, client);
212
+ return client;
213
+ }
214
+ /**
215
+ * Get a connected client by user ID
216
+ */
217
+ getClient(userId) {
218
+ return this.clients.get(userId);
219
+ }
220
+ /**
221
+ * Check if a user is connected locally
222
+ */
223
+ isConnected(userId) {
224
+ return this.clients.has(userId);
225
+ }
226
+ async disconnect(userId) {
227
+ if (userId) {
228
+ this.clients.delete(userId);
229
+ return;
230
+ }
231
+ this.clients.clear();
232
+ }
233
+ }
234
+ export async function init(config) {
235
+ if (!config.appToken.startsWith('stvor_')) {
236
+ throw new StvorError(Errors.INVALID_APP_TOKEN, 'Invalid app token');
237
+ }
238
+ return new StvorApp(config);
239
+ }
240
+ // Alias for createApp
241
+ export const createApp = init;
242
+ export const Stvor = {
243
+ init,
244
+ createApp,
245
+ };
@@ -0,0 +1,29 @@
1
+ 'use strict';
2
+
3
+ // Auto-generated CommonJS wrapper for src/facade/crypto.js
4
+ // This allows `require('@stvor/sdk')` to work alongside ESM `import`.
5
+
6
+ const mod = require('module');
7
+ const url = require('url');
8
+
9
+ // Use dynamic import to load the ESM module
10
+ let _cached;
11
+ async function _load() {
12
+ if (!_cached) {
13
+ _cached = await import(url.pathToFileURL(__filename.replace(/\.cjs$/, '.js')).href);
14
+ }
15
+ return _cached;
16
+ }
17
+
18
+ // For simple CJS usage, expose a promise-based loader
19
+ module.exports = new Proxy({ load: _load }, {
20
+ get(target, prop) {
21
+ if (prop === '__esModule') return true;
22
+ if (prop === 'then') return undefined; // prevent treating as thenable
23
+ if (prop === 'load') return _load;
24
+ if (prop === 'default') {
25
+ return _load().then(m => m.default);
26
+ }
27
+ return _load().then(m => m[prop]);
28
+ }
29
+ });
@@ -0,0 +1,29 @@
1
+ 'use strict';
2
+
3
+ // Auto-generated CommonJS wrapper for src/facade/errors.js
4
+ // This allows `require('@stvor/sdk')` to work alongside ESM `import`.
5
+
6
+ const mod = require('module');
7
+ const url = require('url');
8
+
9
+ // Use dynamic import to load the ESM module
10
+ let _cached;
11
+ async function _load() {
12
+ if (!_cached) {
13
+ _cached = await import(url.pathToFileURL(__filename.replace(/\.cjs$/, '.js')).href);
14
+ }
15
+ return _cached;
16
+ }
17
+
18
+ // For simple CJS usage, expose a promise-based loader
19
+ module.exports = new Proxy({ load: _load }, {
20
+ get(target, prop) {
21
+ if (prop === '__esModule') return true;
22
+ if (prop === 'then') return undefined; // prevent treating as thenable
23
+ if (prop === 'load') return _load;
24
+ if (prop === 'default') {
25
+ return _load().then(m => m.default);
26
+ }
27
+ return _load().then(m => m[prop]);
28
+ }
29
+ });
@@ -0,0 +1,19 @@
1
+ export declare const Errors: {
2
+ readonly INVALID_APP_TOKEN: "INVALID_APP_TOKEN";
3
+ readonly INVALID_API_KEY: "INVALID_API_KEY";
4
+ readonly RELAY_UNAVAILABLE: "RELAY_UNAVAILABLE";
5
+ readonly DELIVERY_FAILED: "DELIVERY_FAILED";
6
+ readonly RECIPIENT_NOT_FOUND: "RECIPIENT_NOT_FOUND";
7
+ readonly RECIPIENT_TIMEOUT: "RECIPIENT_TIMEOUT";
8
+ readonly MESSAGE_INTEGRITY_FAILED: "MESSAGE_INTEGRITY_FAILED";
9
+ readonly RECEIVE_TIMEOUT: "RECEIVE_TIMEOUT";
10
+ readonly RECEIVE_IN_PROGRESS: "RECEIVE_IN_PROGRESS";
11
+ readonly NOT_CONNECTED: "NOT_CONNECTED";
12
+ };
13
+ export type ErrorCode = (typeof Errors)[keyof typeof Errors];
14
+ export declare class StvorError extends Error {
15
+ code: ErrorCode;
16
+ action?: string;
17
+ retryable?: boolean;
18
+ constructor(code: ErrorCode, message: string, action?: string, retryable?: boolean);
19
+ }
@@ -0,0 +1,21 @@
1
+ export const Errors = {
2
+ INVALID_APP_TOKEN: 'INVALID_APP_TOKEN',
3
+ INVALID_API_KEY: 'INVALID_API_KEY',
4
+ RELAY_UNAVAILABLE: 'RELAY_UNAVAILABLE',
5
+ DELIVERY_FAILED: 'DELIVERY_FAILED',
6
+ RECIPIENT_NOT_FOUND: 'RECIPIENT_NOT_FOUND',
7
+ RECIPIENT_TIMEOUT: 'RECIPIENT_TIMEOUT',
8
+ MESSAGE_INTEGRITY_FAILED: 'MESSAGE_INTEGRITY_FAILED',
9
+ RECEIVE_TIMEOUT: 'RECEIVE_TIMEOUT',
10
+ RECEIVE_IN_PROGRESS: 'RECEIVE_IN_PROGRESS',
11
+ NOT_CONNECTED: 'NOT_CONNECTED',
12
+ };
13
+ export class StvorError extends Error {
14
+ constructor(code, message, action, retryable) {
15
+ super(message);
16
+ this.code = code;
17
+ this.action = action;
18
+ this.retryable = retryable;
19
+ this.name = 'StvorError';
20
+ }
21
+ }
@@ -0,0 +1,29 @@
1
+ 'use strict';
2
+
3
+ // Auto-generated CommonJS wrapper for src/facade/index.js
4
+ // This allows `require('@stvor/sdk')` to work alongside ESM `import`.
5
+
6
+ const mod = require('module');
7
+ const url = require('url');
8
+
9
+ // Use dynamic import to load the ESM module
10
+ let _cached;
11
+ async function _load() {
12
+ if (!_cached) {
13
+ _cached = await import(url.pathToFileURL(__filename.replace(/\.cjs$/, '.js')).href);
14
+ }
15
+ return _cached;
16
+ }
17
+
18
+ // For simple CJS usage, expose a promise-based loader
19
+ module.exports = new Proxy({ load: _load }, {
20
+ get(target, prop) {
21
+ if (prop === '__esModule') return true;
22
+ if (prop === 'then') return undefined; // prevent treating as thenable
23
+ if (prop === 'load') return _load;
24
+ if (prop === 'default') {
25
+ return _load().then(m => m.default);
26
+ }
27
+ return _load().then(m => m[prop]);
28
+ }
29
+ });
@@ -0,0 +1,8 @@
1
+ export * from './app.js';
2
+ export * from './errors.js';
3
+ export * from './types.js';
4
+ export type { DecryptedMessage, SealedPayload } from './types.js';
5
+ export type { StvorAppConfig, AppToken, UserId, MessageContent } from './types.js';
6
+ export { StvorError } from './errors.js';
7
+ export { StvorApp, StvorFacadeClient, Stvor, init, createApp } from './app.js';
8
+ export { ErrorCode as STVOR_ERRORS } from './errors.js';
@@ -0,0 +1,5 @@
1
+ export * from './app.js';
2
+ export * from './errors.js';
3
+ export * from './types.js';
4
+ export { StvorError } from './errors.js';
5
+ export { StvorApp, StvorFacadeClient, Stvor, init, createApp } from './app.js';
@@ -0,0 +1,29 @@
1
+ 'use strict';
2
+
3
+ // Auto-generated CommonJS wrapper for src/facade/relay-client.js
4
+ // This allows `require('@stvor/sdk')` to work alongside ESM `import`.
5
+
6
+ const mod = require('module');
7
+ const url = require('url');
8
+
9
+ // Use dynamic import to load the ESM module
10
+ let _cached;
11
+ async function _load() {
12
+ if (!_cached) {
13
+ _cached = await import(url.pathToFileURL(__filename.replace(/\.cjs$/, '.js')).href);
14
+ }
15
+ return _cached;
16
+ }
17
+
18
+ // For simple CJS usage, expose a promise-based loader
19
+ module.exports = new Proxy({ load: _load }, {
20
+ get(target, prop) {
21
+ if (prop === '__esModule') return true;
22
+ if (prop === 'then') return undefined; // prevent treating as thenable
23
+ if (prop === 'load') return _load;
24
+ if (prop === 'default') {
25
+ return _load().then(m => m.default);
26
+ }
27
+ return _load().then(m => m[prop]);
28
+ }
29
+ });
@@ -0,0 +1,36 @@
1
+ /**
2
+ * STVOR DX Facade - Relay Client
3
+ */
4
+ type JSONable = Record<string, any>;
5
+ export type RelayHandler = (msg: JSONable) => void;
6
+ export declare class RelayClient {
7
+ private relayUrl;
8
+ private timeout;
9
+ private appToken;
10
+ private ws?;
11
+ private connected;
12
+ private handshakeComplete;
13
+ private backoff;
14
+ private queue;
15
+ private handlers;
16
+ private reconnecting;
17
+ private connectPromise?;
18
+ private connectResolve?;
19
+ private connectReject?;
20
+ private authFailed;
21
+ constructor(relayUrl: string, appToken: string, timeout?: number);
22
+ /**
23
+ * Initialize the connection and wait for handshake.
24
+ * Throws StvorError if API key is rejected.
25
+ */
26
+ init(): Promise<void>;
27
+ private getAuthHeaders;
28
+ private connect;
29
+ private scheduleReconnect;
30
+ private doSend;
31
+ send(obj: JSONable): void;
32
+ onMessage(h: RelayHandler): void;
33
+ isConnected(): boolean;
34
+ isAuthenticated(): boolean;
35
+ }
36
+ export {};