@wishknish/knishio-client-ts 0.7.4 → 0.7.7

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 (43) hide show
  1. package/dist/index.cjs +2702 -1033
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +339 -106
  4. package/dist/index.d.ts +339 -106
  5. package/dist/index.iife.js +22052 -19964
  6. package/dist/index.iife.js.map +1 -1
  7. package/dist/index.js +2699 -1034
  8. package/dist/index.js.map +1 -1
  9. package/package.json +10 -4
  10. package/src/AuthToken.ts +8 -2
  11. package/src/KnishIOClient.ts +346 -51
  12. package/src/constants.ts +5 -3
  13. package/src/core/Atom.ts +167 -100
  14. package/src/core/AtomMeta.ts +11 -28
  15. package/src/core/Meta.ts +18 -15
  16. package/src/core/Molecule.ts +607 -141
  17. package/src/core/Wallet.ts +19 -24
  18. package/src/index.ts +8 -0
  19. package/src/instance/rules/Rule.ts +128 -19
  20. package/src/libraries/CheckMolecule.ts +88 -1
  21. package/src/libraries/crypto.ts +14 -30
  22. package/src/libraries/strings.ts +26 -25
  23. package/src/mutation/MutationAppendRequest.ts +52 -0
  24. package/src/mutation/MutationCreateRule.ts +2 -2
  25. package/src/mutation/MutationPeering.ts +37 -0
  26. package/src/mutation/MutationRequestAuthorization.ts +3 -3
  27. package/src/query/QueryActiveSession.ts +0 -1
  28. package/src/query/QueryContinuId.ts +8 -0
  29. package/src/query/QueryMetaTypeViaMolecule.ts +221 -0
  30. package/src/query/QueryWalletList.ts +2 -2
  31. package/src/response/ResponseAppendRequest.ts +17 -0
  32. package/src/response/ResponseBalance.ts +8 -3
  33. package/src/response/ResponseContinuId.ts +1 -1
  34. package/src/response/ResponseMetaType.ts +32 -19
  35. package/src/response/ResponseMetaTypeViaMolecule.ts +224 -0
  36. package/src/response/ResponsePeering.ts +17 -0
  37. package/src/response/ResponsePolicy.ts +2 -3
  38. package/src/response/ResponseProposeMolecule.ts +0 -1
  39. package/src/response/ResponseRequestAuthorization.ts +32 -2
  40. package/src/response/ResponseRequestAuthorizationGuest.ts +25 -1
  41. package/src/response/ResponseWalletList.ts +1 -1
  42. package/src/types/guards.ts +18 -5
  43. package/src/types/index.ts +3 -3
@@ -49,7 +49,8 @@ License: https://github.com/WishKnish/KnishIO-Client-TS/blob/master/LICENSE
49
49
  import Decimal from '@/libraries/Decimal'
50
50
  import GraphQLClient from '@/libraries/GraphQLClient'
51
51
  import {
52
- generateBundleHash
52
+ generateBundleHash,
53
+ generateSecret
53
54
  } from '@/libraries/crypto'
54
55
  import Molecule from '@/core/Molecule'
55
56
  import Wallet from '@/core/Wallet'
@@ -57,6 +58,7 @@ import AuthToken from '@/AuthToken'
57
58
  import Query from '@/query/Query'
58
59
  import Mutation from '@/mutation/Mutation'
59
60
  import Response from '@/response/Response'
61
+ import ResponseRequestAuthorization from '@/response/ResponseRequestAuthorization'
60
62
 
61
63
  // 2025 TypeScript: Zod validation integration
62
64
  import {
@@ -81,6 +83,7 @@ import QueryActiveSession from '@/query/QueryActiveSession'
81
83
  import QueryUserActivity from '@/query/QueryUserActivity'
82
84
  import QueryToken from '@/query/QueryToken'
83
85
  import QueryMetaTypeViaAtom from '@/query/QueryMetaTypeViaAtom'
86
+ import QueryMetaTypeViaMolecule from '@/query/QueryMetaTypeViaMolecule'
84
87
 
85
88
  // Mutation imports
86
89
  import MutationCreateToken from '@/mutation/MutationCreateToken'
@@ -97,6 +100,8 @@ import MutationWithdrawBufferToken from '@/mutation/MutationWithdrawBufferToken'
97
100
  import MutationRequestAuthorization from '@/mutation/MutationRequestAuthorization'
98
101
  import MutationRequestAuthorizationGuest from '@/mutation/MutationRequestAuthorizationGuest'
99
102
  import MutationLinkIdentifier from '@/mutation/MutationLinkIdentifier'
103
+ import MutationPeering from '@/mutation/MutationPeering'
104
+ import MutationAppendRequest from '@/mutation/MutationAppendRequest'
100
105
 
101
106
  // Subscribe imports
102
107
  import CreateMoleculeSubscribe from '@/subscribe/CreateMoleculeSubscribe'
@@ -110,7 +115,8 @@ import {
110
115
  UnauthenticatedException,
111
116
  TransferBalanceException,
112
117
  WalletShadowException,
113
- StackableUnitAmountException
118
+ StackableUnitAmountException,
119
+ AuthorizationRejectedException
114
120
  } from '@/exception'
115
121
 
116
122
  // Type imports
@@ -140,6 +146,7 @@ export default class KnishIOClient {
140
146
  private $__logging: boolean = false
141
147
  private $__authTokenObjects: Record<string, AuthToken | null> = {}
142
148
  private $__authToken: AuthToken | null = null
149
+ private $__authInProcess: boolean = false
143
150
  private $__remainderWallet: Wallet | null = null
144
151
  private lastMoleculeQuery: Mutation | null = null
145
152
  private abortControllers: Map<string, AbortController> = new Map()
@@ -331,6 +338,10 @@ export default class KnishIOClient {
331
338
  } else {
332
339
  this.$__uris = uri
333
340
  }
341
+ // Update the underlying GraphQL client's URI
342
+ if (this.$__client && 'setUri' in this.$__client) {
343
+ (this.$__client as any).setUri(this.getRandomUri())
344
+ }
334
345
  }
335
346
 
336
347
  /**
@@ -403,7 +414,8 @@ export default class KnishIOClient {
403
414
  }
404
415
 
405
416
  /**
406
- * Creates a new molecule for a transaction
417
+ * Instantiates a new Molecule and prepares this client session to operate on it
418
+ * Matches JavaScript SDK createMolecule implementation
407
419
  */
408
420
  async createMolecule({
409
421
  secret = null,
@@ -421,6 +433,28 @@ export default class KnishIOClient {
421
433
  secret = secret || this.getSecret()
422
434
  bundle = bundle || this.getBundle()
423
435
 
436
+ // For non-USER source wallets (V/B isotopes), capture the current USER
437
+ // ContinuID position BEFORE overwriting the client's remainder wallet.
438
+ // This position is needed by addContinuIdAtom() for previousPosition metadata.
439
+ let continuIdPosition: string | null = null
440
+ if (sourceWallet && sourceWallet.token !== 'USER') {
441
+ if (this.lastMoleculeQuery &&
442
+ this.getRemainderWallet() &&
443
+ this.getRemainderWallet()?.token === 'USER' &&
444
+ this.lastMoleculeQuery.response() &&
445
+ this.lastMoleculeQuery.response()?.success()
446
+ ) {
447
+ // Carry-forward: use last successful USER remainder wallet position
448
+ continuIdPosition = this.getRemainderWallet()?.position || null
449
+ this.log('info', `KnishIOClient::createMolecule() - Captured USER ContinuID position ${continuIdPosition?.substring(0, 16)}... for non-USER source wallet`)
450
+ } else {
451
+ // Query server for current ContinuID position
452
+ const userWallet = await this.getSourceWallet()
453
+ continuIdPosition = userWallet?.position || null
454
+ this.log('info', `KnishIOClient::createMolecule() - Queried USER ContinuID position ${continuIdPosition?.substring(0, 16)}... for non-USER source wallet`)
455
+ }
456
+ }
457
+
424
458
  // Sets the source wallet as the last remainder wallet (to maintain ContinuID)
425
459
  if (!sourceWallet &&
426
460
  this.lastMoleculeQuery &&
@@ -429,19 +463,30 @@ export default class KnishIOClient {
429
463
  this.lastMoleculeQuery.response()?.success()
430
464
  ) {
431
465
  sourceWallet = this.getRemainderWallet()
466
+ this.log('info', `KnishIOClient::createMolecule() - Using carry-forward remainder wallet at position ${sourceWallet?.position?.substring(0, 16)}...`)
432
467
  }
433
468
 
434
469
  // Unable to use last remainder wallet; Figure out what wallet to use:
435
470
  if (!sourceWallet) {
436
- // Get source wallet
437
471
  sourceWallet = await this.getSourceWallet()
438
472
  }
439
473
 
474
+ // Set the remainder wallet for the next transaction (always USER token for ContinuID)
475
+ this.setRemainderWallet(remainderWallet || Wallet.create({
476
+ secret: secret!,
477
+ bundle,
478
+ token: 'USER',
479
+ batchId: sourceWallet!.batchId,
480
+ characters: sourceWallet!.characters
481
+ }))
482
+
440
483
  return new Molecule({
441
484
  secret,
442
- bundle,
443
485
  sourceWallet,
444
- remainderWallet
486
+ remainderWallet: this.getRemainderWallet()!,
487
+ cellSlug: this.getCellSlug(),
488
+ version: this.getServerSdkVersion(),
489
+ continuIdPosition
445
490
  })
446
491
  }
447
492
 
@@ -477,7 +522,8 @@ export default class KnishIOClient {
477
522
  */
478
523
  async executeQuery(query: Query | Mutation, variables: Record<string, any> | null = null): Promise<Response | null> {
479
524
  // Check and refresh authorization token if needed
480
- if (this.$__authToken && this.$__authToken.isExpired()) {
525
+ // Guard with $__authInProcess to prevent recursive auth refresh
526
+ if (this.$__authToken && this.$__authToken.isExpired() && !this.$__authInProcess) {
481
527
  this.log('info', 'KnishIOClient::executeQuery() - Access token is expired. Getting new one...')
482
528
  await this.requestAuthToken({
483
529
  secret: this.$__secret,
@@ -511,16 +557,29 @@ export default class KnishIOClient {
511
557
  }
512
558
 
513
559
  /**
514
- * Gets source wallet - basic implementation
560
+ * Retrieves this session's wallet used for signing the next Molecule
561
+ * Queries ContinuID from the server to get the authoritative position
562
+ * Matches JavaScript SDK getSourceWallet implementation
515
563
  */
516
564
  async getSourceWallet(): Promise<Wallet> {
517
- // For now, create a new wallet with the current secret
518
- // In full implementation, this would query the ledger
519
- return Wallet.create({
520
- secret: this.getSecret(),
521
- bundle: this.getBundle(),
522
- token: 'USER'
523
- })
565
+ // Match JavaScript SDK exactly: no try/catch, errors propagate
566
+ let sourceWallet: Wallet | null = (await this.queryContinuId({
567
+ bundle: this.getBundle()
568
+ }))?.payload() as Wallet | null
569
+
570
+ if (!sourceWallet) {
571
+ sourceWallet = new Wallet({
572
+ secret: this.getSecret()
573
+ })
574
+ } else {
575
+ sourceWallet.key = Wallet.generateKey({
576
+ secret: this.getSecret(),
577
+ token: sourceWallet.token,
578
+ position: sourceWallet.position!
579
+ })
580
+ }
581
+
582
+ return sourceWallet
524
583
  }
525
584
 
526
585
  /**
@@ -566,7 +625,7 @@ export default class KnishIOClient {
566
625
  }
567
626
 
568
627
  // Do you have enough tokens?
569
- if (sourceWallet === null || Decimal.cmp(sourceWallet.balance, amount) < 0) {
628
+ if (sourceWallet === null || Decimal.cmp(Number(sourceWallet.balance), amount) < 0) {
570
629
  throw new TransferBalanceException()
571
630
  }
572
631
 
@@ -615,13 +674,18 @@ export default class KnishIOClient {
615
674
  }
616
675
 
617
676
  /**
618
- * Request authorization token
677
+ * Request authorization token (guest or profile)
678
+ *
679
+ * @param secret - User secret for profile auth (null for guest)
680
+ * @param seed - Seed to generate secret (alternative to secret)
681
+ * @param cellSlug - Cell slug for scoped access
682
+ * @param encrypt - Whether to use encryption
619
683
  */
620
684
  async requestAuthToken({
621
- secret: _secret = null,
622
- seed: _seed = null,
623
- cellSlug: _cellSlug = null,
624
- encrypt: _encrypt = false
685
+ secret = null,
686
+ seed = null,
687
+ cellSlug = null,
688
+ encrypt = false
625
689
  }: {
626
690
  secret?: string | null
627
691
  seed?: string | null
@@ -630,12 +694,52 @@ export default class KnishIOClient {
630
694
  } = {}): Promise<Response | null> {
631
695
  // SDK versions 2 and below do not utilize an authorization token
632
696
  if (this.$__serverSdkVersion < 3) {
633
- this.log('warn', 'KnishIOClient::authorize() - Server SDK version does not require an authorization...')
697
+ this.log('warn', 'KnishIOClient::requestAuthToken() - Server SDK version does not require authorization...')
634
698
  return null
635
699
  }
636
700
 
637
- // For now, return null - full implementation would handle authorization
638
- return null
701
+ // Generate a secret from the seed if provided
702
+ if (secret === null && seed) {
703
+ secret = generateSecret(seed)
704
+ }
705
+
706
+ // Set cell slug if provided
707
+ if (cellSlug) {
708
+ this.setCellSlug(cellSlug)
709
+ }
710
+
711
+ // Auth in process...
712
+ this.$__authInProcess = true
713
+
714
+ // Auth token response
715
+ let response: Response
716
+
717
+ // Authorized user (profile auth with secret)
718
+ if (secret) {
719
+ response = await this.requestProfileAuthToken({
720
+ secret,
721
+ encrypt
722
+ })
723
+ } else {
724
+ // Guest auth (no secret)
725
+ response = await this.requestGuestAuthToken({
726
+ cellSlug: cellSlug || this.getCellSlug(),
727
+ encrypt
728
+ })
729
+ }
730
+
731
+ // Log success
732
+ if (this.$__authToken) {
733
+ this.log('info', `KnishIOClient::requestAuthToken() - Successfully retrieved auth token...`)
734
+ }
735
+
736
+ // Handle encryption if needed
737
+ this.switchEncryption(encrypt)
738
+
739
+ // Auth process is stopped
740
+ this.$__authInProcess = false
741
+
742
+ return response
639
743
  }
640
744
 
641
745
  /**
@@ -756,7 +860,7 @@ export default class KnishIOClient {
756
860
 
757
861
  // Do you have enough tokens?
758
862
  const amountNum = typeof amount === 'string' ? Number(amount) : amount
759
- if (sourceWallet === null || Decimal.cmp(sourceWallet.balance || 0, amountNum) < 0) {
863
+ if (sourceWallet === null || Decimal.cmp(Number(sourceWallet.balance || 0), amountNum) < 0) {
760
864
  throw new TransferBalanceException()
761
865
  }
762
866
 
@@ -786,7 +890,7 @@ export default class KnishIOClient {
786
890
 
787
891
  const response = await this.executeQuery(walletQuery, {
788
892
  bundleHash: bundle || this.getBundle(),
789
- tokenSlug: token,
893
+ token,
790
894
  unspent
791
895
  })
792
896
 
@@ -851,6 +955,7 @@ export default class KnishIOClient {
851
955
  count = null,
852
956
  countBy = null,
853
957
  throughAtom = true,
958
+ throughMolecule = false,
854
959
  values = null,
855
960
  keys = null,
856
961
  atomValues = null
@@ -866,6 +971,7 @@ export default class KnishIOClient {
866
971
  count?: number | null
867
972
  countBy?: string | null
868
973
  throughAtom?: boolean | null
974
+ throughMolecule?: boolean | null
869
975
  values?: any[] | null
870
976
  keys?: string[] | null
871
977
  atomValues?: any[] | null
@@ -875,10 +981,26 @@ export default class KnishIOClient {
875
981
  let query: Query
876
982
  let variables: Record<string, any>
877
983
 
878
- if (throughAtom) {
984
+ if (throughMolecule) {
985
+ query = this.createQuery(QueryMetaTypeViaMolecule)
986
+ variables = QueryMetaTypeViaMolecule.createVariables({
987
+ metaType: metaType,
988
+ metaId,
989
+ key,
990
+ value,
991
+ latest,
992
+ filter,
993
+ queryArgs,
994
+ countBy,
995
+ values,
996
+ keys,
997
+ atomValues,
998
+ cellSlug: this.getCellSlug()
999
+ })
1000
+ } else if (throughAtom) {
879
1001
  query = this.createQuery(QueryMetaTypeViaAtom)
880
1002
  variables = QueryMetaTypeViaAtom.createVariables({
881
- metaType,
1003
+ metaType: metaType,
882
1004
  metaId,
883
1005
  key,
884
1006
  value,
@@ -894,7 +1016,7 @@ export default class KnishIOClient {
894
1016
  } else {
895
1017
  query = this.createQuery(QueryMetaType)
896
1018
  variables = QueryMetaType.createVariables({
897
- metaType,
1019
+ metaType: metaType,
898
1020
  metaId,
899
1021
  key,
900
1022
  value,
@@ -910,6 +1032,34 @@ export default class KnishIOClient {
910
1032
  return this.executeQuery(query, variables) as Promise<Response>
911
1033
  }
912
1034
 
1035
+ /**
1036
+ * Queries meta assets and verifies cryptographic integrity of associated molecules.
1037
+ * Forces throughMolecule=true to ensure molecule data is available for verification.
1038
+ * Returns the same response as queryMeta(), with an additional `integrity` field on the payload.
1039
+ */
1040
+ async queryMetaVerified(params: {
1041
+ metaType: MetaType | string
1042
+ metaId?: MetaId | string | null
1043
+ key?: string | null
1044
+ value?: string | null
1045
+ latest?: boolean | null
1046
+ fields?: string[] | null
1047
+ filter?: MetaFilter[] | null
1048
+ queryArgs?: Record<string, any> | null
1049
+ count?: number | null
1050
+ countBy?: string | null
1051
+ values?: any[] | null
1052
+ keys?: string[] | null
1053
+ atomValues?: any[] | null
1054
+ }): Promise<Response> {
1055
+ const response = await this.queryMeta({ ...params, throughMolecule: true })
1056
+ const payload = response.payload()
1057
+ if (payload && typeof (response as any).verifyIntegrity === 'function') {
1058
+ payload.integrity = (response as any).verifyIntegrity()
1059
+ }
1060
+ return response
1061
+ }
1062
+
913
1063
  /**
914
1064
  * Query cascading meta instances for batchId
915
1065
  */
@@ -1281,7 +1431,7 @@ export default class KnishIOClient {
1281
1431
  const recipientWallet = new Wallet({
1282
1432
  secret: this.getSecret(),
1283
1433
  bundle: this.getBundle(),
1284
- token: token.toUpperCase(),
1434
+ token,
1285
1435
  batchId: batchId as any
1286
1436
  })
1287
1437
 
@@ -1327,7 +1477,7 @@ export default class KnishIOClient {
1327
1477
 
1328
1478
  // Initialize the request tokens mutation
1329
1479
  await mutation.fillMolecule({
1330
- token: token.toUpperCase(),
1480
+ token,
1331
1481
  amount: amount ?? 0,
1332
1482
  metaType: to || '',
1333
1483
  metaId: to || '',
@@ -1369,14 +1519,26 @@ export default class KnishIOClient {
1369
1519
  })
1370
1520
  }
1371
1521
 
1522
+ // Create remainder wallet from source (must be same token for V-isotope conservation)
1523
+ const remainderWallet = sourceWallet.createRemainder(this.getSecret())
1524
+
1525
+ // Create molecule with the token-specific source and remainder wallets
1526
+ const molecule = await this.createMolecule({
1527
+ sourceWallet,
1528
+ remainderWallet
1529
+ })
1530
+
1372
1531
  // Create a transfer to null address (burn)
1373
- const mutation = await this.createMoleculeMutation({ mutationClass: MutationTransferTokens })
1532
+ const mutation = await this.createMoleculeMutation({
1533
+ mutationClass: MutationTransferTokens,
1534
+ molecule
1535
+ })
1374
1536
 
1375
1537
  // Create recipient wallet for burn address
1376
1538
  const recipientWallet = new Wallet({
1377
1539
  secret: this.getSecret(),
1378
1540
  bundle: '0000000000000000000000000000000000000000000000000000000000000000',
1379
- token: token.toUpperCase()
1541
+ token
1380
1542
  })
1381
1543
 
1382
1544
  await mutation.fillMolecule({
@@ -1461,7 +1623,7 @@ export default class KnishIOClient {
1461
1623
  const newWallet = new Wallet({
1462
1624
  secret: this.getSecret(),
1463
1625
  bundle: this.getBundle(),
1464
- token: token.toUpperCase()
1626
+ token
1465
1627
  })
1466
1628
 
1467
1629
  // Initialize the create wallet mutation
@@ -1516,7 +1678,7 @@ export default class KnishIOClient {
1516
1678
 
1517
1679
  // Initialize the claim shadow wallet mutation
1518
1680
  await mutation.fillMolecule({
1519
- token: token.toUpperCase() as TokenSlug,
1681
+ token: token as TokenSlug,
1520
1682
  batchId: shadowWallet.batchId
1521
1683
  })
1522
1684
 
@@ -1587,14 +1749,20 @@ export default class KnishIOClient {
1587
1749
  }): Promise<Response> {
1588
1750
  this.log('info', `KnishIOClient::createMeta() - Creating metadata for ${metaType}:${metaId}...`)
1589
1751
 
1590
- // Create the molecule mutation
1591
- const mutation = await this.createMoleculeMutation({ mutationClass: MutationCreateMeta })
1752
+ // Create the molecule mutation — let createMolecule() handle sourceWallet via
1753
+ // carry-forward (remainder wallet from prior mutation) or server fallback
1754
+ const mutation = await this.createMoleculeMutation({
1755
+ mutationClass: MutationCreateMeta,
1756
+ molecule: await this.createMolecule({
1757
+ secret: this.getSecret()
1758
+ })
1759
+ })
1592
1760
 
1593
1761
  // Initialize the create meta mutation
1594
1762
  await mutation.fillMolecule({
1595
- metaType: metaType.toUpperCase(),
1763
+ metaType,
1596
1764
  metaId,
1597
- meta,
1765
+ meta: meta || {},
1598
1766
  policy
1599
1767
  })
1600
1768
 
@@ -1624,12 +1792,18 @@ export default class KnishIOClient {
1624
1792
  }): Promise<Response> {
1625
1793
  this.log('info', `KnishIOClient::createRule() - Creating rule for ${metaType}:${metaId}...`)
1626
1794
 
1627
- // Create the molecule mutation
1628
- const mutation = await this.createMoleculeMutation({ mutationClass: MutationCreateRule })
1795
+ // Create the molecule mutation — let createMolecule() handle sourceWallet via
1796
+ // carry-forward (remainder wallet from prior mutation) or server fallback
1797
+ const mutation = await this.createMoleculeMutation({
1798
+ mutationClass: MutationCreateRule,
1799
+ molecule: await this.createMolecule({
1800
+ secret: this.getSecret()
1801
+ })
1802
+ })
1629
1803
 
1630
1804
  // Initialize the create rule mutation
1631
1805
  await mutation.fillMolecule({
1632
- metaType: metaType.toUpperCase() as MetaType,
1806
+ metaType: metaType as MetaType,
1633
1807
  metaId: metaId as MetaId,
1634
1808
  rule,
1635
1809
  policy
@@ -1764,10 +1938,10 @@ export default class KnishIOClient {
1764
1938
  // Create the mutation (extends Mutation directly, not MutationProposeMolecule)
1765
1939
  const mutation = this.createQuery(MutationActiveSession)
1766
1940
 
1767
- // Execute with variables
1941
+ // Execute with variables (bundleHash matches GraphQL variable name)
1768
1942
  const response = await this.executeQuery(mutation, {
1769
- bundle: bundle || this.getBundle(),
1770
- metaType: metaType.toUpperCase(),
1943
+ bundleHash: bundle || this.getBundle(),
1944
+ metaType,
1771
1945
  metaId,
1772
1946
  ipAddress,
1773
1947
  browser,
@@ -1808,8 +1982,20 @@ export default class KnishIOClient {
1808
1982
  })
1809
1983
  }
1810
1984
 
1985
+ // Create remainder wallet from source (must be same token)
1986
+ const remainderWallet = sourceWallet.createRemainder(this.getSecret())
1987
+
1988
+ // Build the molecule with the token-specific source and remainder wallets
1989
+ const molecule = await this.createMolecule({
1990
+ sourceWallet,
1991
+ remainderWallet
1992
+ })
1993
+
1811
1994
  // Create the molecule mutation
1812
- const mutation = await this.createMoleculeMutation({ mutationClass: MutationDepositBufferToken })
1995
+ const mutation = await this.createMoleculeMutation({
1996
+ mutationClass: MutationDepositBufferToken,
1997
+ molecule
1998
+ })
1813
1999
 
1814
2000
  // Initialize the deposit buffer token mutation
1815
2001
  await mutation.fillMolecule({
@@ -1909,6 +2095,7 @@ export default class KnishIOClient {
1909
2095
 
1910
2096
  /**
1911
2097
  * Request profile authentication token
2098
+ * Matches JavaScript SDK requestProfileAuthToken implementation
1912
2099
  */
1913
2100
  async requestProfileAuthToken({
1914
2101
  secret,
@@ -1916,27 +2103,58 @@ export default class KnishIOClient {
1916
2103
  }: {
1917
2104
  secret: string
1918
2105
  encrypt?: boolean
1919
- }): Promise<Response> {
2106
+ }): Promise<ResponseRequestAuthorization> {
1920
2107
  this.log('info', 'KnishIOClient::requestProfileAuthToken() - Requesting profile auth token...')
1921
2108
 
1922
2109
  // Set the secret
1923
2110
  this.setSecret(secret)
1924
2111
 
1925
- // Create the molecule mutation
1926
- const mutation = await this.createMoleculeMutation({ mutationClass: MutationRequestAuthorization })
2112
+ // Generate a signing wallet with AUTH token (matching JavaScript SDK)
2113
+ const wallet = new Wallet({
2114
+ secret,
2115
+ token: 'AUTH'
2116
+ })
2117
+
2118
+ // Create a molecule with the AUTH wallet as source
2119
+ const molecule = await this.createMolecule({
2120
+ secret,
2121
+ sourceWallet: wallet
2122
+ })
2123
+
2124
+ // Create the mutation with this specific molecule
2125
+ const mutation = await this.createMoleculeMutation({
2126
+ mutationClass: MutationRequestAuthorization,
2127
+ molecule
2128
+ })
1927
2129
 
1928
2130
  // Initialize the profile auth mutation
1929
- await mutation.fillMolecule({
2131
+ mutation.fillMolecule({
1930
2132
  meta: { encrypt: encrypt ? 'true' : 'false' }
1931
2133
  })
1932
2134
 
1933
2135
  // Execute the mutation
1934
- const response = await this.executeQuery(mutation)
2136
+ const response = await this.executeQuery(mutation) as ResponseRequestAuthorization
1935
2137
 
1936
2138
  if (!response) {
1937
2139
  throw new CodeException('Profile auth token request failed')
1938
2140
  }
1939
2141
 
2142
+ // Did the authorization molecule get accepted?
2143
+ if (response.success()) {
2144
+ // Create & set an auth token from the response data
2145
+ const authToken = AuthToken.create({
2146
+ token: response.token(),
2147
+ expiresAt: response.expiresAt(),
2148
+ encrypt: String(response.encrypt()) === 'true',
2149
+ pubkey: response.pubKey()
2150
+ }, wallet)
2151
+ this.setAuthToken(authToken)
2152
+ } else {
2153
+ throw new AuthorizationRejectedException(
2154
+ `KnishIOClient::requestProfileAuthToken() - Authorization attempt rejected by ledger. Reason: ${response.reason()}`
2155
+ )
2156
+ }
2157
+
1940
2158
  // Handle encryption if needed
1941
2159
  if (encrypt) {
1942
2160
  this.switchEncryption(true)
@@ -1945,6 +2163,83 @@ export default class KnishIOClient {
1945
2163
  return response
1946
2164
  }
1947
2165
 
2166
+ // =============================================================================
2167
+ // MUTATION METHODS - PEERING & APPEND REQUEST
2168
+ // =============================================================================
2169
+
2170
+ /**
2171
+ * Register a peer node via P-isotope
2172
+ * Matches JavaScript SDK registerPeer implementation exactly
2173
+ */
2174
+ async registerPeer({ host }: { host: string }): Promise<Response> {
2175
+ this.log('info', `KnishIOClient::registerPeer() - Registering peer at ${host}...`)
2176
+
2177
+ // Create the molecule mutation — let createMolecule() handle sourceWallet via
2178
+ // carry-forward (remainder wallet from prior mutation) or server fallback
2179
+ const mutation = await this.createMoleculeMutation({
2180
+ mutationClass: MutationPeering,
2181
+ molecule: await this.createMolecule({
2182
+ secret: this.getSecret()
2183
+ })
2184
+ })
2185
+
2186
+ // Fill the molecule with peering data
2187
+ mutation.fillMolecule({ host })
2188
+
2189
+ // Execute the mutation
2190
+ const response = await this.executeQuery(mutation)
2191
+
2192
+ if (!response) {
2193
+ throw new CodeException('Peer registration failed')
2194
+ }
2195
+
2196
+ return response
2197
+ }
2198
+
2199
+ /**
2200
+ * Submit an append request via A-isotope
2201
+ * Matches JavaScript SDK appendRequest implementation exactly
2202
+ */
2203
+ async appendRequest({
2204
+ metaType,
2205
+ metaId,
2206
+ action,
2207
+ meta = {}
2208
+ }: {
2209
+ metaType: string
2210
+ metaId: string
2211
+ action: string
2212
+ meta?: Record<string, any>
2213
+ }): Promise<Response> {
2214
+ this.log('info', `KnishIOClient::appendRequest() - Submitting append request for ${metaType}:${metaId}...`)
2215
+
2216
+ // Create the molecule mutation — let createMolecule() handle sourceWallet via
2217
+ // carry-forward (remainder wallet from prior mutation) or server fallback
2218
+ const mutation = await this.createMoleculeMutation({
2219
+ mutationClass: MutationAppendRequest,
2220
+ molecule: await this.createMolecule({
2221
+ secret: this.getSecret()
2222
+ })
2223
+ })
2224
+
2225
+ // Fill the molecule with append request data
2226
+ mutation.fillMolecule({
2227
+ metaType,
2228
+ metaId,
2229
+ action,
2230
+ meta
2231
+ })
2232
+
2233
+ // Execute the mutation
2234
+ const response = await this.executeQuery(mutation)
2235
+
2236
+ if (!response) {
2237
+ throw new CodeException('Append request failed')
2238
+ }
2239
+
2240
+ return response
2241
+ }
2242
+
1948
2243
  // =============================================================================
1949
2244
  // LEGACY/DEPRECATED METHODS
1950
2245
  // =============================================================================