hyperstack-typescript 0.3.14 → 0.3.15

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