hyperstack-typescript 0.3.14 → 0.4.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.
package/dist/index.js CHANGED
@@ -741,6 +741,69 @@ function createUpdateStream(storage, subscriptionRegistry, subscription, keyFilt
741
741
  },
742
742
  };
743
743
  }
744
+ function createEntityStream(storage, subscriptionRegistry, subscription, keyFilter) {
745
+ return {
746
+ [Symbol.asyncIterator]() {
747
+ const queue = [];
748
+ let waitingResolve = null;
749
+ let unsubscribeStorage = null;
750
+ let unsubscribeRegistry = null;
751
+ let done = false;
752
+ const handler = (viewPath, key, update) => {
753
+ if (viewPath !== subscription.view)
754
+ return;
755
+ if (keyFilter !== undefined && key !== keyFilter)
756
+ return;
757
+ if (update.type === 'deleted')
758
+ return;
759
+ const entity = (update.type === 'created' ? update.data : update.after);
760
+ if (waitingResolve) {
761
+ const resolve = waitingResolve;
762
+ waitingResolve = null;
763
+ resolve({ value: entity, done: false });
764
+ }
765
+ else {
766
+ if (queue.length >= MAX_QUEUE_SIZE) {
767
+ queue.shift();
768
+ }
769
+ queue.push(entity);
770
+ }
771
+ };
772
+ const start = () => {
773
+ unsubscribeStorage = storage.onRichUpdate(handler);
774
+ unsubscribeRegistry = subscriptionRegistry.subscribe(subscription);
775
+ };
776
+ const cleanup = () => {
777
+ done = true;
778
+ unsubscribeStorage?.();
779
+ unsubscribeRegistry?.();
780
+ };
781
+ start();
782
+ return {
783
+ async next() {
784
+ if (done) {
785
+ return { value: undefined, done: true };
786
+ }
787
+ const queued = queue.shift();
788
+ if (queued) {
789
+ return { value: queued, done: false };
790
+ }
791
+ return new Promise((resolve) => {
792
+ waitingResolve = resolve;
793
+ });
794
+ },
795
+ async return() {
796
+ cleanup();
797
+ return { value: undefined, done: true };
798
+ },
799
+ async throw(error) {
800
+ cleanup();
801
+ throw error;
802
+ },
803
+ };
804
+ },
805
+ };
806
+ }
744
807
  function createRichUpdateStream(storage, subscriptionRegistry, subscription, keyFilter) {
745
808
  return {
746
809
  [Symbol.asyncIterator]() {
@@ -808,11 +871,14 @@ function createRichUpdateStream(storage, subscriptionRegistry, subscription, key
808
871
 
809
872
  function createTypedStateView(viewDef, storage, subscriptionRegistry) {
810
873
  return {
811
- watch(key) {
812
- return createUpdateStream(storage, subscriptionRegistry, { view: viewDef.view, key }, key);
874
+ use(key, options) {
875
+ return createEntityStream(storage, subscriptionRegistry, { view: viewDef.view, key, ...options }, key);
813
876
  },
814
- watchRich(key) {
815
- return createRichUpdateStream(storage, subscriptionRegistry, { view: viewDef.view, key }, key);
877
+ watch(key, options) {
878
+ return createUpdateStream(storage, subscriptionRegistry, { view: viewDef.view, key, ...options }, key);
879
+ },
880
+ watchRich(key, options) {
881
+ return createRichUpdateStream(storage, subscriptionRegistry, { view: viewDef.view, key, ...options }, key);
816
882
  },
817
883
  async get(key) {
818
884
  return storage.get(viewDef.view, key);
@@ -824,11 +890,14 @@ function createTypedStateView(viewDef, storage, subscriptionRegistry) {
824
890
  }
825
891
  function createTypedListView(viewDef, storage, subscriptionRegistry) {
826
892
  return {
827
- watch() {
828
- return createUpdateStream(storage, subscriptionRegistry, { view: viewDef.view });
893
+ use(options) {
894
+ return createEntityStream(storage, subscriptionRegistry, { view: viewDef.view, ...options });
895
+ },
896
+ watch(options) {
897
+ return createUpdateStream(storage, subscriptionRegistry, { view: viewDef.view, ...options });
829
898
  },
830
- watchRich() {
831
- return createRichUpdateStream(storage, subscriptionRegistry, { view: viewDef.view });
899
+ watchRich(options) {
900
+ return createRichUpdateStream(storage, subscriptionRegistry, { view: viewDef.view, ...options });
832
901
  },
833
902
  async get() {
834
903
  return storage.getAll(viewDef.view);
@@ -840,20 +909,512 @@ function createTypedListView(viewDef, storage, subscriptionRegistry) {
840
909
  }
841
910
  function createTypedViews(stack, storage, subscriptionRegistry) {
842
911
  const views = {};
843
- for (const [viewName, viewGroup] of Object.entries(stack.views)) {
912
+ for (const [entityName, viewGroup] of Object.entries(stack.views)) {
844
913
  const group = viewGroup;
845
914
  const typedGroup = {};
846
- if (group.state) {
847
- typedGroup.state = createTypedStateView(group.state, storage, subscriptionRegistry);
848
- }
849
- if (group.list) {
850
- typedGroup.list = createTypedListView(group.list, storage, subscriptionRegistry);
915
+ for (const [viewName, viewDef] of Object.entries(group)) {
916
+ if (viewDef.mode === 'state') {
917
+ typedGroup[viewName] = createTypedStateView(viewDef, storage, subscriptionRegistry);
918
+ }
919
+ else if (viewDef.mode === 'list') {
920
+ typedGroup[viewName] = createTypedListView(viewDef, storage, subscriptionRegistry);
921
+ }
851
922
  }
852
- views[viewName] = typedGroup;
923
+ views[entityName] = typedGroup;
853
924
  }
854
925
  return views;
855
926
  }
856
927
 
928
+ /**
929
+ * Resolves instruction accounts by categorizing and deriving addresses.
930
+ *
931
+ * @param accountMetas - Account metadata from the instruction definition
932
+ * @param args - Instruction arguments (used for PDA derivation)
933
+ * @param options - Resolution options including wallet and user-provided accounts
934
+ * @returns Resolved accounts and any missing required accounts
935
+ */
936
+ function resolveAccounts(accountMetas, args, options) {
937
+ const resolved = [];
938
+ const missing = [];
939
+ for (const meta of accountMetas) {
940
+ const resolvedAccount = resolveSingleAccount(meta, args, options);
941
+ if (resolvedAccount) {
942
+ resolved.push(resolvedAccount);
943
+ }
944
+ else if (!meta.isOptional) {
945
+ missing.push(meta.name);
946
+ }
947
+ }
948
+ return {
949
+ accounts: resolved,
950
+ missingUserAccounts: missing,
951
+ };
952
+ }
953
+ function resolveSingleAccount(meta, args, options) {
954
+ switch (meta.category) {
955
+ case 'signer':
956
+ return resolveSignerAccount(meta, options.wallet);
957
+ case 'known':
958
+ return resolveKnownAccount(meta);
959
+ case 'pda':
960
+ return resolvePdaAccount(meta);
961
+ case 'userProvided':
962
+ return resolveUserProvidedAccount(meta, options.accounts);
963
+ default:
964
+ return null;
965
+ }
966
+ }
967
+ function resolveSignerAccount(meta, wallet) {
968
+ if (!wallet) {
969
+ return null;
970
+ }
971
+ return {
972
+ name: meta.name,
973
+ address: wallet.publicKey,
974
+ isSigner: true,
975
+ isWritable: meta.isWritable,
976
+ };
977
+ }
978
+ function resolveKnownAccount(meta) {
979
+ if (!meta.knownAddress) {
980
+ return null;
981
+ }
982
+ return {
983
+ name: meta.name,
984
+ address: meta.knownAddress,
985
+ isSigner: meta.isSigner,
986
+ isWritable: meta.isWritable,
987
+ };
988
+ }
989
+ function resolvePdaAccount(meta, args) {
990
+ if (!meta.pdaConfig) {
991
+ return null;
992
+ }
993
+ // PDA derivation will be implemented in pda.ts
994
+ // For now, return a placeholder that will be resolved later
995
+ return {
996
+ name: meta.name,
997
+ address: '', // Will be derived
998
+ isSigner: meta.isSigner,
999
+ isWritable: meta.isWritable,
1000
+ };
1001
+ }
1002
+ function resolveUserProvidedAccount(meta, accounts) {
1003
+ const address = accounts?.[meta.name];
1004
+ if (!address) {
1005
+ return null;
1006
+ }
1007
+ return {
1008
+ name: meta.name,
1009
+ address,
1010
+ isSigner: meta.isSigner,
1011
+ isWritable: meta.isWritable,
1012
+ };
1013
+ }
1014
+ /**
1015
+ * Validates that all required accounts are present.
1016
+ *
1017
+ * @param result - Account resolution result
1018
+ * @throws Error if any required accounts are missing
1019
+ */
1020
+ function validateAccountResolution(result) {
1021
+ if (result.missingUserAccounts.length > 0) {
1022
+ throw new Error(`Missing required accounts: ${result.missingUserAccounts.join(', ')}`);
1023
+ }
1024
+ }
1025
+
1026
+ /**
1027
+ * Derives a Program-Derived Address (PDA) from seeds and program ID.
1028
+ *
1029
+ * This function implements PDA derivation using the Solana algorithm:
1030
+ * 1. Concatenate all seeds
1031
+ * 2. Hash with SHA-256
1032
+ * 3. Check if result is off-curve (valid PDA)
1033
+ *
1034
+ * Note: This is a placeholder implementation. In production, you would use
1035
+ * the actual Solana web3.js library's PDA derivation.
1036
+ *
1037
+ * @param seeds - Array of seed buffers
1038
+ * @param programId - The program ID (as base58 string)
1039
+ * @returns The derived PDA address (base58 string)
1040
+ */
1041
+ async function derivePda(seeds, programId) {
1042
+ // In production, this would use:
1043
+ // PublicKey.findProgramAddressSync(seeds, new PublicKey(programId))
1044
+ // For now, return a placeholder that will be replaced with actual implementation
1045
+ const combined = Buffer.concat(seeds);
1046
+ // Simulate PDA derivation (this is NOT the actual algorithm)
1047
+ const hash = await simulateHash(combined);
1048
+ // Return base58-encoded address
1049
+ return bs58Encode(hash);
1050
+ }
1051
+ /**
1052
+ * Creates a seed buffer from various input types.
1053
+ *
1054
+ * @param value - The value to convert to a seed
1055
+ * @returns Buffer suitable for PDA derivation
1056
+ */
1057
+ function createSeed(value) {
1058
+ if (Buffer.isBuffer(value)) {
1059
+ return value;
1060
+ }
1061
+ if (value instanceof Uint8Array) {
1062
+ return Buffer.from(value);
1063
+ }
1064
+ if (typeof value === 'string') {
1065
+ return Buffer.from(value, 'utf-8');
1066
+ }
1067
+ if (typeof value === 'bigint') {
1068
+ // Convert bigint to 8-byte buffer (u64)
1069
+ const buffer = Buffer.alloc(8);
1070
+ buffer.writeBigUInt64LE(value);
1071
+ return buffer;
1072
+ }
1073
+ throw new Error(`Cannot create seed from type: ${typeof value}`);
1074
+ }
1075
+ /**
1076
+ * Creates a public key seed from a base58-encoded address.
1077
+ *
1078
+ * @param address - Base58-encoded public key
1079
+ * @returns 32-byte buffer
1080
+ */
1081
+ function createPublicKeySeed(address) {
1082
+ // In production, decode base58 to 32-byte buffer
1083
+ // For now, return placeholder
1084
+ return Buffer.alloc(32);
1085
+ }
1086
+ async function simulateHash(data) {
1087
+ // In production, use actual SHA-256
1088
+ // This is a placeholder
1089
+ if (typeof crypto !== 'undefined' && crypto.subtle) {
1090
+ const hashBuffer = await crypto.subtle.digest('SHA-256', data);
1091
+ return Buffer.from(hashBuffer);
1092
+ }
1093
+ // Fallback for Node.js
1094
+ return Buffer.alloc(32, 0);
1095
+ }
1096
+ function bs58Encode(buffer) {
1097
+ // In production, use actual base58 encoding
1098
+ // This is a placeholder
1099
+ return 'P' + buffer.toString('hex').slice(0, 31);
1100
+ }
1101
+
1102
+ /**
1103
+ * Borsh-compatible instruction data serializer.
1104
+ *
1105
+ * This module handles serializing instruction arguments into the binary format
1106
+ * expected by Solana programs using Borsh serialization.
1107
+ */
1108
+ /**
1109
+ * Serializes instruction arguments into a Buffer using Borsh encoding.
1110
+ *
1111
+ * @param discriminator - The 8-byte instruction discriminator
1112
+ * @param args - Arguments to serialize
1113
+ * @param schema - Schema defining argument types
1114
+ * @returns Serialized instruction data
1115
+ */
1116
+ function serializeInstructionData(discriminator, args, schema) {
1117
+ const buffers = [Buffer.from(discriminator)];
1118
+ for (const field of schema) {
1119
+ const value = args[field.name];
1120
+ const serialized = serializeValue(value, field.type);
1121
+ buffers.push(serialized);
1122
+ }
1123
+ return Buffer.concat(buffers);
1124
+ }
1125
+ function serializeValue(value, type) {
1126
+ if (typeof type === 'string') {
1127
+ return serializePrimitive(value, type);
1128
+ }
1129
+ if ('vec' in type) {
1130
+ return serializeVec(value, type.vec);
1131
+ }
1132
+ if ('option' in type) {
1133
+ return serializeOption(value, type.option);
1134
+ }
1135
+ if ('array' in type) {
1136
+ return serializeArray(value, type.array[0], type.array[1]);
1137
+ }
1138
+ throw new Error(`Unknown type: ${JSON.stringify(type)}`);
1139
+ }
1140
+ function serializePrimitive(value, type) {
1141
+ switch (type) {
1142
+ case 'u8':
1143
+ return Buffer.from([value]);
1144
+ case 'u16':
1145
+ const u16 = Buffer.alloc(2);
1146
+ u16.writeUInt16LE(value, 0);
1147
+ return u16;
1148
+ case 'u32':
1149
+ const u32 = Buffer.alloc(4);
1150
+ u32.writeUInt32LE(value, 0);
1151
+ return u32;
1152
+ case 'u64':
1153
+ const u64 = Buffer.alloc(8);
1154
+ u64.writeBigUInt64LE(BigInt(value), 0);
1155
+ return u64;
1156
+ case 'u128':
1157
+ // u128 is 16 bytes, little-endian
1158
+ const u128 = Buffer.alloc(16);
1159
+ const bigU128 = BigInt(value);
1160
+ u128.writeBigUInt64LE(bigU128 & BigInt('0xFFFFFFFFFFFFFFFF'), 0);
1161
+ u128.writeBigUInt64LE(bigU128 >> BigInt(64), 8);
1162
+ return u128;
1163
+ case 'i8':
1164
+ return Buffer.from([value]);
1165
+ case 'i16':
1166
+ const i16 = Buffer.alloc(2);
1167
+ i16.writeInt16LE(value, 0);
1168
+ return i16;
1169
+ case 'i32':
1170
+ const i32 = Buffer.alloc(4);
1171
+ i32.writeInt32LE(value, 0);
1172
+ return i32;
1173
+ case 'i64':
1174
+ const i64 = Buffer.alloc(8);
1175
+ i64.writeBigInt64LE(BigInt(value), 0);
1176
+ return i64;
1177
+ case 'i128':
1178
+ const i128 = Buffer.alloc(16);
1179
+ const bigI128 = BigInt(value);
1180
+ i128.writeBigInt64LE(bigI128 & BigInt('0xFFFFFFFFFFFFFFFF'), 0);
1181
+ i128.writeBigInt64LE(bigI128 >> BigInt(64), 8);
1182
+ return i128;
1183
+ case 'bool':
1184
+ return Buffer.from([value ? 1 : 0]);
1185
+ case 'string':
1186
+ const str = value;
1187
+ const strBytes = Buffer.from(str, 'utf-8');
1188
+ const strLen = Buffer.alloc(4);
1189
+ strLen.writeUInt32LE(strBytes.length, 0);
1190
+ return Buffer.concat([strLen, strBytes]);
1191
+ case 'pubkey':
1192
+ // In production, decode base58 to 32 bytes
1193
+ return Buffer.alloc(32, 0);
1194
+ default:
1195
+ throw new Error(`Unknown primitive type: ${type}`);
1196
+ }
1197
+ }
1198
+ function serializeVec(values, elementType) {
1199
+ const len = Buffer.alloc(4);
1200
+ len.writeUInt32LE(values.length, 0);
1201
+ const elementBuffers = values.map(v => serializeValue(v, elementType));
1202
+ return Buffer.concat([len, ...elementBuffers]);
1203
+ }
1204
+ function serializeOption(value, innerType) {
1205
+ if (value === null || value === undefined) {
1206
+ return Buffer.from([0]); // None
1207
+ }
1208
+ const inner = serializeValue(value, innerType);
1209
+ return Buffer.concat([Buffer.from([1]), inner]); // Some
1210
+ }
1211
+ function serializeArray(values, elementType, length) {
1212
+ if (values.length !== length) {
1213
+ throw new Error(`Array length mismatch: expected ${length}, got ${values.length}`);
1214
+ }
1215
+ const elementBuffers = values.map(v => serializeValue(v, elementType));
1216
+ return Buffer.concat(elementBuffers);
1217
+ }
1218
+
1219
+ /**
1220
+ * Waits for transaction confirmation.
1221
+ *
1222
+ * @param signature - Transaction signature
1223
+ * @param level - Desired confirmation level
1224
+ * @param timeout - Maximum wait time in milliseconds
1225
+ * @returns Confirmation result
1226
+ */
1227
+ async function waitForConfirmation(signature, level = 'confirmed', timeout = 60000) {
1228
+ const startTime = Date.now();
1229
+ while (Date.now() - startTime < timeout) {
1230
+ const status = await checkTransactionStatus();
1231
+ if (status.err) {
1232
+ throw new Error(`Transaction failed: ${JSON.stringify(status.err)}`);
1233
+ }
1234
+ if (isConfirmationLevelSufficient(status.confirmations, level)) {
1235
+ return {
1236
+ level,
1237
+ slot: status.slot,
1238
+ };
1239
+ }
1240
+ await sleep(1000);
1241
+ }
1242
+ throw new Error(`Transaction confirmation timeout after ${timeout}ms`);
1243
+ }
1244
+ async function checkTransactionStatus(signature) {
1245
+ // In production, query the Solana RPC
1246
+ return {
1247
+ err: null,
1248
+ confirmations: 32,
1249
+ slot: 123456789,
1250
+ };
1251
+ }
1252
+ function isConfirmationLevelSufficient(confirmations, level) {
1253
+ if (confirmations === null) {
1254
+ return false;
1255
+ }
1256
+ switch (level) {
1257
+ case 'processed':
1258
+ return confirmations >= 0;
1259
+ case 'confirmed':
1260
+ return confirmations >= 1;
1261
+ case 'finalized':
1262
+ return confirmations >= 32;
1263
+ default:
1264
+ return false;
1265
+ }
1266
+ }
1267
+ function sleep(ms) {
1268
+ return new Promise(resolve => setTimeout(resolve, ms));
1269
+ }
1270
+
1271
+ /**
1272
+ * Parses and handles instruction errors.
1273
+ */
1274
+ /**
1275
+ * Parses an error returned from a Solana transaction.
1276
+ *
1277
+ * @param error - The error from the transaction
1278
+ * @param errorMetadata - Error definitions from the IDL
1279
+ * @returns Parsed program error or null if not a program error
1280
+ */
1281
+ function parseInstructionError(error, errorMetadata) {
1282
+ if (!error) {
1283
+ return null;
1284
+ }
1285
+ const errorCode = extractErrorCode(error);
1286
+ if (errorCode === null) {
1287
+ return null;
1288
+ }
1289
+ const metadata = errorMetadata.find(e => e.code === errorCode);
1290
+ if (metadata) {
1291
+ return {
1292
+ code: metadata.code,
1293
+ name: metadata.name,
1294
+ message: metadata.msg,
1295
+ };
1296
+ }
1297
+ return {
1298
+ code: errorCode,
1299
+ name: `CustomError${errorCode}`,
1300
+ message: `Unknown error with code ${errorCode}`,
1301
+ };
1302
+ }
1303
+ function extractErrorCode(error) {
1304
+ if (typeof error !== 'object' || error === null) {
1305
+ return null;
1306
+ }
1307
+ const errorObj = error;
1308
+ // Check for InstructionError format
1309
+ if (errorObj.InstructionError) {
1310
+ const instructionError = errorObj.InstructionError;
1311
+ if (instructionError[1]?.Custom !== undefined) {
1312
+ return instructionError[1].Custom;
1313
+ }
1314
+ }
1315
+ // Check for direct code
1316
+ if (typeof errorObj.code === 'number') {
1317
+ return errorObj.code;
1318
+ }
1319
+ return null;
1320
+ }
1321
+ /**
1322
+ * Formats an error for display.
1323
+ *
1324
+ * @param error - The program error
1325
+ * @returns Human-readable error message
1326
+ */
1327
+ function formatProgramError(error) {
1328
+ return `${error.name} (${error.code}): ${error.message}`;
1329
+ }
1330
+
1331
+ /**
1332
+ * Converts resolved account array to a map for the builder.
1333
+ */
1334
+ function toResolvedAccountsMap(accounts) {
1335
+ const map = {};
1336
+ for (const account of accounts) {
1337
+ map[account.name] = account.address;
1338
+ }
1339
+ return map;
1340
+ }
1341
+ /**
1342
+ * Executes an instruction handler with the given arguments and options.
1343
+ *
1344
+ * This is the main function for executing Solana instructions. It handles:
1345
+ * 1. Account resolution (signer, PDA, user-provided)
1346
+ * 2. Calling the generated build() function
1347
+ * 3. Transaction signing and sending
1348
+ * 4. Confirmation waiting
1349
+ *
1350
+ * @param handler - Instruction handler from generated SDK
1351
+ * @param args - Instruction arguments
1352
+ * @param options - Execution options
1353
+ * @returns Execution result with signature
1354
+ */
1355
+ async function executeInstruction(handler, args, options = {}) {
1356
+ // Step 1: Resolve accounts using handler's account metadata
1357
+ const resolutionOptions = {
1358
+ accounts: options.accounts,
1359
+ wallet: options.wallet,
1360
+ };
1361
+ const resolution = resolveAccounts(handler.accounts, args, resolutionOptions);
1362
+ validateAccountResolution(resolution);
1363
+ // Step 2: Call generated build() function
1364
+ const resolvedAccountsMap = toResolvedAccountsMap(resolution.accounts);
1365
+ const instruction = handler.build(args, resolvedAccountsMap);
1366
+ // Step 3: Build transaction from the built instruction
1367
+ const transaction = buildTransaction(instruction);
1368
+ // Step 4: Sign and send
1369
+ if (!options.wallet) {
1370
+ throw new Error('Wallet required to sign transaction');
1371
+ }
1372
+ const signature = await options.wallet.signAndSend(transaction);
1373
+ // Step 5: Wait for confirmation
1374
+ const confirmationLevel = options.confirmationLevel ?? 'confirmed';
1375
+ const timeout = options.timeout ?? 60000;
1376
+ const confirmation = await waitForConfirmation(signature, confirmationLevel, timeout);
1377
+ return {
1378
+ signature,
1379
+ confirmationLevel: confirmation.level,
1380
+ slot: confirmation.slot,
1381
+ };
1382
+ }
1383
+ /**
1384
+ * Creates a transaction object from a built instruction.
1385
+ *
1386
+ * @param instruction - Built instruction from handler
1387
+ * @returns Transaction object ready for signing
1388
+ */
1389
+ function buildTransaction(instruction) {
1390
+ // This returns a framework-agnostic transaction representation.
1391
+ // The wallet adapter is responsible for converting this to the
1392
+ // appropriate format (@solana/web3.js Transaction, etc.)
1393
+ return {
1394
+ instructions: [{
1395
+ programId: instruction.programId,
1396
+ keys: instruction.keys,
1397
+ data: Array.from(instruction.data),
1398
+ }],
1399
+ };
1400
+ }
1401
+ /**
1402
+ * Creates an instruction executor bound to a specific wallet.
1403
+ *
1404
+ * @param wallet - Wallet adapter
1405
+ * @returns Bound executor function
1406
+ */
1407
+ function createInstructionExecutor(wallet) {
1408
+ return {
1409
+ execute: async (handler, args, options) => {
1410
+ return executeInstruction(handler, args, {
1411
+ ...options,
1412
+ wallet,
1413
+ });
1414
+ },
1415
+ };
1416
+ }
1417
+
857
1418
  class HyperStack {
858
1419
  constructor(url, options) {
859
1420
  this.stack = options.stack;
@@ -871,16 +1432,34 @@ class HyperStack {
871
1432
  this.processor.handleFrame(frame);
872
1433
  });
873
1434
  this._views = createTypedViews(this.stack, this.storage, this.subscriptionRegistry);
1435
+ this._instructions = this.buildInstructions();
1436
+ }
1437
+ buildInstructions() {
1438
+ const instructions = {};
1439
+ if (this.stack.instructions) {
1440
+ for (const [name, handler] of Object.entries(this.stack.instructions)) {
1441
+ instructions[name] = (args, options) => {
1442
+ return executeInstruction(handler, args, options);
1443
+ };
1444
+ }
1445
+ }
1446
+ return instructions;
874
1447
  }
875
- static async connect(url, options) {
1448
+ static async connect(stack, options) {
1449
+ const url = options?.url ?? stack.url;
876
1450
  if (!url) {
877
- throw new HyperStackError('URL is required', 'INVALID_CONFIG');
878
- }
879
- if (!options.stack) {
880
- throw new HyperStackError('Stack definition is required', 'INVALID_CONFIG');
881
- }
882
- const client = new HyperStack(url, options);
883
- if (options.autoReconnect !== false) {
1451
+ throw new HyperStackError('URL is required (provide url option or define url in stack)', 'INVALID_CONFIG');
1452
+ }
1453
+ const internalOptions = {
1454
+ stack,
1455
+ storage: options?.storage,
1456
+ maxEntriesPerView: options?.maxEntriesPerView,
1457
+ autoReconnect: options?.autoReconnect,
1458
+ reconnectIntervals: options?.reconnectIntervals,
1459
+ maxReconnectAttempts: options?.maxReconnectAttempts,
1460
+ };
1461
+ const client = new HyperStack(url, internalOptions);
1462
+ if (options?.autoReconnect !== false) {
884
1463
  await client.connection.connect();
885
1464
  }
886
1465
  return client;
@@ -888,6 +1467,9 @@ class HyperStack {
888
1467
  get views() {
889
1468
  return this._views;
890
1469
  }
1470
+ get instructions() {
1471
+ return this._instructions;
1472
+ }
891
1473
  get connectionState() {
892
1474
  return this.connection.getState();
893
1475
  }
@@ -1356,15 +1938,27 @@ exports.HyperStack = HyperStack;
1356
1938
  exports.HyperStackError = HyperStackError;
1357
1939
  exports.MemoryAdapter = MemoryAdapter;
1358
1940
  exports.SubscriptionRegistry = SubscriptionRegistry;
1941
+ exports.createEntityStream = createEntityStream;
1942
+ exports.createInstructionExecutor = createInstructionExecutor;
1943
+ exports.createPublicKeySeed = createPublicKeySeed;
1359
1944
  exports.createRichUpdateStream = createRichUpdateStream;
1945
+ exports.createSeed = createSeed;
1360
1946
  exports.createTypedListView = createTypedListView;
1361
1947
  exports.createTypedStateView = createTypedStateView;
1362
1948
  exports.createTypedViews = createTypedViews;
1363
1949
  exports.createUpdateStream = createUpdateStream;
1950
+ exports.derivePda = derivePda;
1951
+ exports.executeInstruction = executeInstruction;
1952
+ exports.formatProgramError = formatProgramError;
1364
1953
  exports.isEntityFrame = isEntityFrame;
1365
1954
  exports.isSnapshotFrame = isSnapshotFrame;
1366
1955
  exports.isSubscribedFrame = isSubscribedFrame;
1367
1956
  exports.isValidFrame = isValidFrame;
1368
1957
  exports.parseFrame = parseFrame;
1369
1958
  exports.parseFrameFromBlob = parseFrameFromBlob;
1959
+ exports.parseInstructionError = parseInstructionError;
1960
+ exports.resolveAccounts = resolveAccounts;
1961
+ exports.serializeInstructionData = serializeInstructionData;
1962
+ exports.validateAccountResolution = validateAccountResolution;
1963
+ exports.waitForConfirmation = waitForConfirmation;
1370
1964
  //# sourceMappingURL=index.js.map