@magicblock-console/core 0.1.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 (57) hide show
  1. package/dist/client.d.ts +98 -0
  2. package/dist/client.d.ts.map +1 -0
  3. package/dist/client.js +96 -0
  4. package/dist/client.js.map +1 -0
  5. package/dist/config.d.ts +41 -0
  6. package/dist/config.d.ts.map +1 -0
  7. package/dist/config.js +94 -0
  8. package/dist/config.js.map +1 -0
  9. package/dist/connection.d.ts +42 -0
  10. package/dist/connection.d.ts.map +1 -0
  11. package/dist/connection.js +82 -0
  12. package/dist/connection.js.map +1 -0
  13. package/dist/cranks.d.ts +14 -0
  14. package/dist/cranks.d.ts.map +1 -0
  15. package/dist/cranks.js +128 -0
  16. package/dist/cranks.js.map +1 -0
  17. package/dist/er.d.ts +17 -0
  18. package/dist/er.d.ts.map +1 -0
  19. package/dist/er.js +314 -0
  20. package/dist/er.js.map +1 -0
  21. package/dist/index.d.ts +17 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +14 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/monitor.d.ts +21 -0
  26. package/dist/monitor.d.ts.map +1 -0
  27. package/dist/monitor.js +170 -0
  28. package/dist/monitor.js.map +1 -0
  29. package/dist/oracle.d.ts +13 -0
  30. package/dist/oracle.d.ts.map +1 -0
  31. package/dist/oracle.js +215 -0
  32. package/dist/oracle.js.map +1 -0
  33. package/dist/privacy.d.ts +14 -0
  34. package/dist/privacy.d.ts.map +1 -0
  35. package/dist/privacy.js +177 -0
  36. package/dist/privacy.js.map +1 -0
  37. package/dist/projects.d.ts +9 -0
  38. package/dist/projects.d.ts.map +1 -0
  39. package/dist/projects.js +94 -0
  40. package/dist/projects.js.map +1 -0
  41. package/dist/storage.d.ts +37 -0
  42. package/dist/storage.d.ts.map +1 -0
  43. package/dist/storage.js +150 -0
  44. package/dist/storage.js.map +1 -0
  45. package/dist/types.d.ts +180 -0
  46. package/dist/types.d.ts.map +1 -0
  47. package/dist/types.js +5 -0
  48. package/dist/types.js.map +1 -0
  49. package/dist/utils.d.ts +18 -0
  50. package/dist/utils.d.ts.map +1 -0
  51. package/dist/utils.js +43 -0
  52. package/dist/utils.js.map +1 -0
  53. package/dist/vrf.d.ts +42 -0
  54. package/dist/vrf.d.ts.map +1 -0
  55. package/dist/vrf.js +117 -0
  56. package/dist/vrf.js.map +1 -0
  57. package/package.json +30 -0
package/dist/oracle.js ADDED
@@ -0,0 +1,215 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Pyth Feed IDs (hex-encoded, 32 bytes)
3
+ // ---------------------------------------------------------------------------
4
+ const PYTH_FEED_IDS = {
5
+ 'SOL/USD': 'ef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d',
6
+ 'BTC/USD': 'e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43',
7
+ 'ETH/USD': 'ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace',
8
+ 'USDC/USD': 'eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a',
9
+ };
10
+ /**
11
+ * Pyth Solana Receiver program — owns PriceUpdateV2 accounts on devnet/mainnet.
12
+ */
13
+ const PYTH_RECEIVER_PROGRAM = 'rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ';
14
+ /**
15
+ * PriceUpdateV2 account layout:
16
+ * [0..8) Anchor discriminator
17
+ * [8..40) write_authority (Pubkey)
18
+ * [40] verification_level (u8)
19
+ * [41..73) feed_id (32 bytes)
20
+ * [73..81) price (i64 LE)
21
+ * [81..89) confidence (u64 LE)
22
+ * [89..93) exponent (i32 LE)
23
+ * [93..101) publish_time (i64 LE)
24
+ * [101..109) prev_publish_time (i64 LE)
25
+ * [109..117) ema_price (i64 LE)
26
+ * [117..125) ema_conf (u64 LE)
27
+ * [125..133) posted_slot (u64 LE)
28
+ * Total: 134 bytes (with 1 byte padding)
29
+ */
30
+ const PRICE_UPDATE_SIZE = 134;
31
+ const FEED_ID_OFFSET = 41;
32
+ // ---------------------------------------------------------------------------
33
+ // Simulated Price Data
34
+ // ---------------------------------------------------------------------------
35
+ /**
36
+ * Simulated price feeds for common trading pairs.
37
+ * Used as fallback when no blockchain connection is available.
38
+ */
39
+ const SIMULATED_PRICES = {
40
+ 'SOL/USD': { price: 142.85, confidence: 0.12 },
41
+ 'BTC/USD': { price: 67420.5, confidence: 15.3 },
42
+ 'ETH/USD': { price: 3520.75, confidence: 2.1 },
43
+ 'USDC/USD': { price: 1.0001, confidence: 0.0002 },
44
+ };
45
+ // ---------------------------------------------------------------------------
46
+ // Helpers
47
+ // ---------------------------------------------------------------------------
48
+ /**
49
+ * Load a project from storage and validate that the oracle feature is enabled.
50
+ */
51
+ async function requireOracleEnabled(storage, project) {
52
+ const data = await storage.get(`project:${project}`);
53
+ if (!data) {
54
+ throw new Error(`Project "${project}" not found`);
55
+ }
56
+ const parsed = JSON.parse(data);
57
+ if (!parsed.features.oracle) {
58
+ throw new Error(`Feature "oracle" is not enabled for project "${project}". ` +
59
+ `Enable it with: client.projects.configure("${project}", { features: { oracle: true } })`);
60
+ }
61
+ return parsed;
62
+ }
63
+ /**
64
+ * Apply slight randomization to a price to simulate realistic market movement.
65
+ * Varies the price by +/- 0.5%.
66
+ */
67
+ function jitterPrice(basePrice) {
68
+ const factor = 1 + (Math.random() - 0.5) * 0.01; // +/- 0.5%
69
+ return Math.round(basePrice * factor * 100) / 100;
70
+ }
71
+ /**
72
+ * Convert a hex string to a Uint8Array.
73
+ */
74
+ function hexToBytes(hex) {
75
+ const bytes = new Uint8Array(hex.length / 2);
76
+ for (let i = 0; i < hex.length; i += 2) {
77
+ bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);
78
+ }
79
+ return bytes;
80
+ }
81
+ /**
82
+ * Read a signed 64-bit little-endian integer from a buffer at the given offset.
83
+ */
84
+ function readInt64LE(data, offset) {
85
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
86
+ return view.getBigInt64(offset, true);
87
+ }
88
+ /**
89
+ * Read an unsigned 64-bit little-endian integer from a buffer at the given offset.
90
+ */
91
+ function readUint64LE(data, offset) {
92
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
93
+ return view.getBigUint64(offset, true);
94
+ }
95
+ /**
96
+ * Read a signed 32-bit little-endian integer from a buffer at the given offset.
97
+ */
98
+ function readInt32LE(data, offset) {
99
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
100
+ return view.getInt32(offset, true);
101
+ }
102
+ /**
103
+ * Encode a Uint8Array to base64 string (works in both Node.js and browser).
104
+ */
105
+ function bytesToBase64(bytes) {
106
+ // Use Buffer in Node.js, btoa in browser
107
+ if (typeof Buffer !== 'undefined' && typeof Buffer.from === 'function') {
108
+ return Buffer.from(bytes).toString('base64');
109
+ }
110
+ let binary = '';
111
+ for (let i = 0; i < bytes.length; i++) {
112
+ binary += String.fromCharCode(bytes[i]);
113
+ }
114
+ return btoa(binary);
115
+ }
116
+ // ---------------------------------------------------------------------------
117
+ // Factory
118
+ // ---------------------------------------------------------------------------
119
+ /**
120
+ * Create a fully-functional `OracleNamespace` backed by the given Storage.
121
+ *
122
+ * When a `getConnection` callback returns a valid `BlockchainConnection`,
123
+ * attempts to read real Pyth Lazer price data from on-chain PDAs.
124
+ * Falls back to simulated prices on any error or missing connection.
125
+ */
126
+ export function createOracleNamespace(storage, _network, getConnection) {
127
+ return {
128
+ async getPrice(options) {
129
+ await requireOracleEnabled(storage, options.project);
130
+ const feedData = SIMULATED_PRICES[options.feed];
131
+ if (!feedData) {
132
+ const supported = Object.keys(SIMULATED_PRICES).join(', ');
133
+ throw new Error(`Unknown price feed: ${options.feed}. Supported feeds: ${supported}`);
134
+ }
135
+ // Attempt real on-chain Pyth price read via Pyth Solana Receiver
136
+ const conn = getConnection?.();
137
+ const feedIdHex = PYTH_FEED_IDS[options.feed];
138
+ if (conn && feedIdHex) {
139
+ try {
140
+ const { PublicKey } = await import('@solana/web3.js');
141
+ const receiverProgramId = new PublicKey(PYTH_RECEIVER_PROGRAM);
142
+ const feedIdBytes = hexToBytes(feedIdHex);
143
+ // Find a PriceUpdateV2 account matching this feed ID via memcmp filter
144
+ const accounts = await conn.baseConnection.getProgramAccounts(receiverProgramId, {
145
+ filters: [
146
+ { dataSize: PRICE_UPDATE_SIZE },
147
+ { memcmp: { offset: FEED_ID_OFFSET, bytes: bytesToBase64(feedIdBytes), encoding: 'base64' } },
148
+ ],
149
+ dataSlice: { offset: 73, length: 28 },
150
+ });
151
+ if (accounts.length > 0) {
152
+ // Pick the account with the most recent publish_time
153
+ let bestIdx = 0;
154
+ if (accounts.length > 1) {
155
+ let bestTime = readInt64LE(new Uint8Array(accounts[0].account.data), 20);
156
+ for (let i = 1; i < accounts.length; i++) {
157
+ const t = readInt64LE(new Uint8Array(accounts[i].account.data), 20);
158
+ if (t > bestTime) {
159
+ bestTime = t;
160
+ bestIdx = i;
161
+ }
162
+ }
163
+ }
164
+ const sliceData = new Uint8Array(accounts[bestIdx].account.data);
165
+ // Slice layout (relative to offset 73):
166
+ // [0..8) price (i64 LE)
167
+ // [8..16) confidence (u64 LE)
168
+ // [16..20) exponent (i32 LE)
169
+ // [20..28) publish_time (i64 LE)
170
+ const rawPrice = readInt64LE(sliceData, 0);
171
+ const rawConfidence = readUint64LE(sliceData, 8);
172
+ const rawExponent = readInt32LE(sliceData, 16);
173
+ const rawTimestamp = readInt64LE(sliceData, 20);
174
+ // Check staleness — reject data older than 120 seconds
175
+ const ageSeconds = Math.floor(Date.now() / 1000) - Number(rawTimestamp);
176
+ if (ageSeconds > 120) {
177
+ console.warn(`[mb-console] Pyth price data for ${options.feed} is ${ageSeconds}s old, using simulated mode`);
178
+ }
179
+ else {
180
+ // Pyth exponents are typically negative (e.g. -8).
181
+ // Use multiplication with 10^exponent which works for any sign.
182
+ const scale = Math.pow(10, rawExponent);
183
+ const price = Number(rawPrice) * scale;
184
+ const confidence = Number(rawConfidence) * scale;
185
+ const timestamp = new Date(Number(rawTimestamp) * 1000);
186
+ return {
187
+ feed: options.feed,
188
+ price,
189
+ confidence,
190
+ timestamp,
191
+ // getProgramAccounts doesn't expose context.slot;
192
+ // approximate from wall clock (~400ms per slot)
193
+ slot: Math.floor(Date.now() / 400),
194
+ simulated: false,
195
+ };
196
+ }
197
+ }
198
+ }
199
+ catch (err) {
200
+ console.warn(`[mb-console] Real Pyth price read failed, using simulated mode: ${err instanceof Error ? err.message : String(err)}`);
201
+ }
202
+ }
203
+ // Simulated fallback
204
+ return {
205
+ feed: options.feed,
206
+ price: jitterPrice(feedData.price),
207
+ confidence: feedData.confidence,
208
+ timestamp: new Date(),
209
+ slot: Math.floor(Date.now() / 400),
210
+ simulated: true,
211
+ };
212
+ },
213
+ };
214
+ }
215
+ //# sourceMappingURL=oracle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oracle.js","sourceRoot":"","sources":["../src/oracle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { Storage } from './storage.js';
2
+ import type { Network } from './types.js';
3
+ import type { PrivacyNamespace } from './client.js';
4
+ import type { BlockchainConnection } from './connection.js';
5
+ /**
6
+ * Create a fully-functional `PrivacyNamespace` backed by the given Storage.
7
+ *
8
+ * When a `getConnection` callback returns a valid `BlockchainConnection`
9
+ * with a signer, real TEE delegation / withdrawal / transfer operations
10
+ * are attempted via the MagicBlock SDK. Falls back to simulated behavior
11
+ * on any error or missing connection.
12
+ */
13
+ export declare function createPrivacyNamespace(storage: Storage, _network: Network, getConnection?: () => BlockchainConnection | undefined): PrivacyNamespace;
14
+ //# sourceMappingURL=privacy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"privacy.d.ts","sourceRoot":"","sources":["../src/privacy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EACV,OAAO,EAMR,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAgD5D;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,OAAO,EACjB,aAAa,CAAC,EAAE,MAAM,oBAAoB,GAAG,SAAS,GACrD,gBAAgB,CAoPlB"}
@@ -0,0 +1,177 @@
1
+ import { generateSignature, assertPubkey } from './utils.js';
2
+ import { VALIDATORS } from './config.js';
3
+ // ---------------------------------------------------------------------------
4
+ // Known devnet SPL token mints
5
+ // ---------------------------------------------------------------------------
6
+ const KNOWN_MINTS = {
7
+ 'SOL': 'So11111111111111111111111111111111111111112',
8
+ 'USDC': '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',
9
+ };
10
+ // ---------------------------------------------------------------------------
11
+ // Helpers
12
+ // ---------------------------------------------------------------------------
13
+ /**
14
+ * Load a project from storage and validate that the privacy feature is enabled.
15
+ */
16
+ async function requirePrivacyEnabled(storage, project) {
17
+ const data = await storage.get(`project:${project}`);
18
+ if (!data) {
19
+ throw new Error(`Project "${project}" not found`);
20
+ }
21
+ const parsed = JSON.parse(data);
22
+ if (!parsed.features.privacy) {
23
+ throw new Error(`Feature "privacy" is not enabled for project "${project}". ` +
24
+ `Enable it with: client.projects.configure("${project}", { features: { privacy: true } })`);
25
+ }
26
+ return parsed;
27
+ }
28
+ /**
29
+ * Resolve a mint address from either an explicit `mint` option or
30
+ * a well-known token symbol (SOL, USDC).
31
+ */
32
+ function resolveMint(token, mint) {
33
+ if (mint)
34
+ return mint;
35
+ return KNOWN_MINTS[token.toUpperCase()];
36
+ }
37
+ // ---------------------------------------------------------------------------
38
+ // Factory
39
+ // ---------------------------------------------------------------------------
40
+ /**
41
+ * Create a fully-functional `PrivacyNamespace` backed by the given Storage.
42
+ *
43
+ * When a `getConnection` callback returns a valid `BlockchainConnection`
44
+ * with a signer, real TEE delegation / withdrawal / transfer operations
45
+ * are attempted via the MagicBlock SDK. Falls back to simulated behavior
46
+ * on any error or missing connection.
47
+ */
48
+ export function createPrivacyNamespace(storage, _network, getConnection) {
49
+ return {
50
+ async deposit(options) {
51
+ await requirePrivacyEnabled(storage, options.project);
52
+ if (options.amount <= 0) {
53
+ throw new Error('Deposit amount must be greater than 0');
54
+ }
55
+ // Real blockchain: delegate SPL tokens to TEE validator
56
+ const conn = getConnection?.();
57
+ const mintAddress = resolveMint(options.token, options.mint);
58
+ if (conn?.signer && mintAddress) {
59
+ try {
60
+ const { PublicKey, Transaction, SystemProgram } = await import('@solana/web3.js');
61
+ const { getAssociatedTokenAddress, createAssociatedTokenAccountInstruction, createSyncNativeInstruction, NATIVE_MINT, } = await import('@solana/spl-token');
62
+ const { delegatePrivateSpl } = await import('@magicblock-labs/ephemeral-rollups-sdk');
63
+ const mintPk = new PublicKey(mintAddress);
64
+ const teeValidator = new PublicKey(VALIDATORS[conn.network].tee);
65
+ const lamports = BigInt(Math.round(options.amount * 1e9));
66
+ const tx = new Transaction();
67
+ // For native SOL: wrap into wSOL before delegating
68
+ const isNativeSol = mintPk.equals(NATIVE_MINT);
69
+ if (isNativeSol) {
70
+ const wsolAta = await getAssociatedTokenAddress(NATIVE_MINT, conn.signer.publicKey);
71
+ // Create wSOL ATA if it doesn't exist
72
+ const ataInfo = await conn.baseConnection.getAccountInfo(wsolAta);
73
+ if (!ataInfo) {
74
+ tx.add(createAssociatedTokenAccountInstruction(conn.signer.publicKey, wsolAta, conn.signer.publicKey, NATIVE_MINT));
75
+ }
76
+ // Transfer native SOL to wSOL ATA
77
+ tx.add(SystemProgram.transfer({
78
+ fromPubkey: conn.signer.publicKey,
79
+ toPubkey: wsolAta,
80
+ lamports,
81
+ }));
82
+ // Sync native balance so SPL token program sees it
83
+ tx.add(createSyncNativeInstruction(wsolAta));
84
+ }
85
+ const instructions = await delegatePrivateSpl(conn.signer.publicKey, mintPk, lamports, { validator: teeValidator, delegatePermission: true });
86
+ for (const ix of instructions) {
87
+ tx.add(ix);
88
+ }
89
+ tx.feePayer = conn.signer.publicKey;
90
+ // Delegation happens on the base Solana chain, not the Magic Router
91
+ tx.recentBlockhash = (await conn.baseConnection.getLatestBlockhash()).blockhash;
92
+ const signed = await conn.signer.signTransaction(tx);
93
+ const signature = await conn.baseConnection.sendRawTransaction(signed.serialize());
94
+ return { signature, simulated: false };
95
+ }
96
+ catch (err) {
97
+ console.warn(`[mb-console] Real privacy deposit failed, using simulated mode: ${err instanceof Error ? err.message : String(err)}`);
98
+ }
99
+ }
100
+ return { signature: generateSignature(), simulated: true };
101
+ },
102
+ async transfer(options) {
103
+ await requirePrivacyEnabled(storage, options.project);
104
+ if (options.amount <= 0) {
105
+ throw new Error('Transfer amount must be greater than 0');
106
+ }
107
+ if (!options.to) {
108
+ throw new Error('Transfer recipient address is required');
109
+ }
110
+ assertPubkey(options.to, 'recipient');
111
+ // Real blockchain: SPL transfer via TEE ER connection
112
+ const conn = getConnection?.();
113
+ const mintAddress = resolveMint(options.token, options.mint);
114
+ if (conn?.signer && mintAddress) {
115
+ try {
116
+ const { PublicKey, Transaction } = await import('@solana/web3.js');
117
+ const { createAssociatedTokenAccountInstruction, createTransferInstruction, getAssociatedTokenAddress, } = await import('@solana/spl-token');
118
+ const mintPk = new PublicKey(mintAddress);
119
+ const recipientPk = new PublicKey(options.to);
120
+ const lamports = BigInt(Math.round(options.amount * 1e9));
121
+ // Get/create associated token accounts
122
+ const senderAta = await getAssociatedTokenAddress(mintPk, conn.signer.publicKey);
123
+ const recipientAta = await getAssociatedTokenAddress(mintPk, recipientPk);
124
+ const tx = new Transaction();
125
+ // Create recipient ATA if needed
126
+ const recipientAtaInfo = await conn.routerConnection.getAccountInfo(recipientAta);
127
+ if (!recipientAtaInfo) {
128
+ tx.add(createAssociatedTokenAccountInstruction(conn.signer.publicKey, recipientAta, recipientPk, mintPk));
129
+ }
130
+ tx.add(createTransferInstruction(senderAta, recipientAta, conn.signer.publicKey, lamports));
131
+ tx.feePayer = conn.signer.publicKey;
132
+ tx.recentBlockhash = (await conn.baseConnection.getLatestBlockhash()).blockhash;
133
+ const signed = await conn.signer.signTransaction(tx);
134
+ const signature = await conn.baseConnection.sendRawTransaction(signed.serialize());
135
+ return { signature, simulated: false };
136
+ }
137
+ catch (err) {
138
+ console.warn(`[mb-console] Real privacy transfer failed, using simulated mode: ${err instanceof Error ? err.message : String(err)}`);
139
+ }
140
+ }
141
+ return { signature: generateSignature(), simulated: true };
142
+ },
143
+ async withdraw(options) {
144
+ await requirePrivacyEnabled(storage, options.project);
145
+ if (options.amount <= 0) {
146
+ throw new Error('Withdraw amount must be greater than 0');
147
+ }
148
+ // Real blockchain: withdraw SPL + undelegate from TEE
149
+ const conn = getConnection?.();
150
+ const mintAddress = resolveMint(options.token, options.mint);
151
+ if (conn?.signer && mintAddress) {
152
+ try {
153
+ const { PublicKey, Transaction } = await import('@solana/web3.js');
154
+ const { withdrawSplIx, undelegateIx } = await import('@magicblock-labs/ephemeral-rollups-sdk');
155
+ const mintPk = new PublicKey(mintAddress);
156
+ const lamports = BigInt(Math.round(options.amount * 1e9));
157
+ const withdrawInstruction = withdrawSplIx(conn.signer.publicKey, mintPk, lamports);
158
+ const undelegateInstruction = undelegateIx(conn.signer.publicKey, mintPk);
159
+ const tx = new Transaction()
160
+ .add(withdrawInstruction)
161
+ .add(undelegateInstruction);
162
+ tx.feePayer = conn.signer.publicKey;
163
+ // Undelegation returns to the base Solana chain
164
+ tx.recentBlockhash = (await conn.baseConnection.getLatestBlockhash()).blockhash;
165
+ const signed = await conn.signer.signTransaction(tx);
166
+ const signature = await conn.baseConnection.sendRawTransaction(signed.serialize());
167
+ return { signature, simulated: false };
168
+ }
169
+ catch (err) {
170
+ console.warn(`[mb-console] Real privacy withdraw failed, using simulated mode: ${err instanceof Error ? err.message : String(err)}`);
171
+ }
172
+ }
173
+ return { signature: generateSignature(), simulated: true };
174
+ },
175
+ };
176
+ }
177
+ //# sourceMappingURL=privacy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"privacy.js","sourceRoot":"","sources":["../src/privacy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { Storage } from './storage.js';
2
+ import type { ProjectsNamespace } from './client.js';
3
+ /**
4
+ * Create a fully-functional `ProjectsNamespace` backed by the given Storage.
5
+ *
6
+ * Each project is persisted as a JSON string under the key `project:<name>`.
7
+ */
8
+ export declare function createProjectsNamespace(storage: Storage): ProjectsNamespace;
9
+ //# sourceMappingURL=projects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../src/projects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAM5C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AA0CrD;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,iBAAiB,CAqE3E"}
@@ -0,0 +1,94 @@
1
+ import { DEFAULT_FEATURES } from './config.js';
2
+ // ---------------------------------------------------------------------------
3
+ // Key helpers
4
+ // ---------------------------------------------------------------------------
5
+ const PROJECT_PREFIX = 'project:';
6
+ function projectKey(name) {
7
+ return `${PROJECT_PREFIX}${name}`;
8
+ }
9
+ // ---------------------------------------------------------------------------
10
+ // Serialization (handles Date fields)
11
+ // ---------------------------------------------------------------------------
12
+ function serialize(project) {
13
+ return JSON.stringify(project);
14
+ }
15
+ function deserialize(json) {
16
+ const raw = JSON.parse(json);
17
+ return { ...raw, createdAt: new Date(raw.createdAt) };
18
+ }
19
+ // ---------------------------------------------------------------------------
20
+ // Factory
21
+ // ---------------------------------------------------------------------------
22
+ // Valid project name: alphanumeric, hyphens, underscores, 1-64 characters
23
+ const PROJECT_NAME_RE = /^[a-zA-Z0-9_-]{1,64}$/;
24
+ function validateProjectName(name) {
25
+ if (!PROJECT_NAME_RE.test(name)) {
26
+ throw new Error(`Invalid project name "${name}". ` +
27
+ 'Use 1-64 characters: letters, numbers, hyphens, underscores.');
28
+ }
29
+ }
30
+ /**
31
+ * Create a fully-functional `ProjectsNamespace` backed by the given Storage.
32
+ *
33
+ * Each project is persisted as a JSON string under the key `project:<name>`.
34
+ */
35
+ export function createProjectsNamespace(storage) {
36
+ return {
37
+ async create(options) {
38
+ validateProjectName(options.name);
39
+ const existing = await storage.get(projectKey(options.name));
40
+ if (existing) {
41
+ throw new Error(`Project "${options.name}" already exists`);
42
+ }
43
+ const project = {
44
+ name: options.name,
45
+ region: options.region ?? 'us',
46
+ features: { ...DEFAULT_FEATURES, ...options.features },
47
+ createdAt: new Date(),
48
+ };
49
+ await storage.set(projectKey(options.name), serialize(project));
50
+ return project;
51
+ },
52
+ async get(name) {
53
+ const data = await storage.get(projectKey(name));
54
+ if (!data) {
55
+ throw new Error(`Project "${name}" not found`);
56
+ }
57
+ return deserialize(data);
58
+ },
59
+ async list() {
60
+ const keys = await storage.list(PROJECT_PREFIX);
61
+ const projects = [];
62
+ for (const key of keys) {
63
+ const data = await storage.get(key);
64
+ if (data) {
65
+ projects.push(deserialize(data));
66
+ }
67
+ }
68
+ return projects.sort((a, b) => a.name.localeCompare(b.name));
69
+ },
70
+ async configure(name, options) {
71
+ const data = await storage.get(projectKey(name));
72
+ if (!data) {
73
+ throw new Error(`Project "${name}" not found`);
74
+ }
75
+ const project = deserialize(data);
76
+ if (options.features) {
77
+ project.features = { ...project.features, ...options.features };
78
+ }
79
+ if (options.region) {
80
+ project.region = options.region;
81
+ }
82
+ await storage.set(projectKey(name), serialize(project));
83
+ return project;
84
+ },
85
+ async delete(name) {
86
+ const data = await storage.get(projectKey(name));
87
+ if (!data) {
88
+ throw new Error(`Project "${name}" not found`);
89
+ }
90
+ await storage.delete(projectKey(name));
91
+ },
92
+ };
93
+ }
94
+ //# sourceMappingURL=projects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.js","sourceRoot":"","sources":["../src/projects.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /** Key-value storage abstraction for persisting project data. */
2
+ export interface Storage {
3
+ get(key: string): Promise<string | null>;
4
+ set(key: string, value: string): Promise<void>;
5
+ delete(key: string): Promise<void>;
6
+ list(prefix: string): Promise<string[]>;
7
+ }
8
+ export declare class MemoryStorage implements Storage {
9
+ private readonly data;
10
+ get(key: string): Promise<string | null>;
11
+ set(key: string, value: string): Promise<void>;
12
+ delete(key: string): Promise<void>;
13
+ list(prefix: string): Promise<string[]>;
14
+ }
15
+ export declare class FileStorage implements Storage {
16
+ private readonly baseDir;
17
+ constructor(baseDir?: string);
18
+ private fs;
19
+ private path;
20
+ /** Encode a key to a safe filename. */
21
+ private encodeKey;
22
+ private decodeKey;
23
+ private filePath;
24
+ private ensureDir;
25
+ get(key: string): Promise<string | null>;
26
+ set(key: string, value: string): Promise<void>;
27
+ delete(key: string): Promise<void>;
28
+ list(prefix: string): Promise<string[]>;
29
+ }
30
+ export declare class BrowserStorage implements Storage {
31
+ private getLocalStorage;
32
+ get(key: string): Promise<string | null>;
33
+ set(key: string, value: string): Promise<void>;
34
+ delete(key: string): Promise<void>;
35
+ list(prefix: string): Promise<string[]>;
36
+ }
37
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAIA,iEAAiE;AACjE,MAAM,WAAW,OAAO;IACtB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CACzC;AAMD,qBAAa,aAAc,YAAW,OAAO;IAC3C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA6B;IAE5C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAIxC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlC,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAG9C;AAMD,qBAAa,WAAY,YAAW,OAAO;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,CAAC,EAAE,MAAM;YAYd,EAAE;YAIF,IAAI;IAIlB,uCAAuC;IACvC,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,SAAS;YAIH,QAAQ;YAUR,SAAS;IAKjB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAWxC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO9C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWlC,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAa9C;AAQD,qBAAa,cAAe,YAAW,OAAO;IAC5C,OAAO,CAAC,eAAe;IAOjB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAKxC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK9C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKlC,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAa9C"}