@wishknish/knishio-client-ts 0.7.2 → 0.7.6
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.cjs +2819 -1186
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +378 -142
- package/dist/index.d.ts +378 -142
- package/dist/index.iife.js +22799 -20747
- package/dist/index.iife.js.map +1 -1
- package/dist/index.js +2817 -1185
- package/dist/index.js.map +1 -1
- package/package.json +12 -6
- package/src/AuthToken.ts +8 -2
- package/src/KnishIOClient.ts +367 -118
- package/src/constants.ts +5 -3
- package/src/core/Atom.ts +167 -100
- package/src/core/AtomMeta.ts +11 -28
- package/src/core/Meta.ts +18 -15
- package/src/core/Molecule.ts +582 -140
- package/src/core/Wallet.ts +19 -24
- package/src/index.ts +9 -10
- package/src/instance/rules/Rule.ts +128 -19
- package/src/libraries/CheckMolecule.ts +88 -1
- package/src/libraries/GraphQLClient.ts +17 -22
- package/src/libraries/crypto.ts +14 -30
- package/src/libraries/strings.ts +26 -25
- package/src/mutation/MutationAppendRequest.ts +52 -0
- package/src/mutation/MutationCreateRule.ts +2 -2
- package/src/mutation/MutationPeering.ts +37 -0
- package/src/mutation/MutationRequestAuthorization.ts +3 -3
- package/src/query/Query.ts +6 -6
- package/src/query/QueryActiveSession.ts +0 -1
- package/src/query/QueryAtom.ts +27 -27
- package/src/query/QueryContinuId.ts +8 -0
- package/src/query/QueryMetaType.ts +1 -1
- package/src/query/QueryMetaTypeViaMolecule.ts +221 -0
- package/src/query/QueryWalletList.ts +2 -2
- package/src/response/Response.ts +17 -1
- package/src/response/ResponseAppendRequest.ts +17 -0
- package/src/response/ResponseBalance.ts +8 -3
- package/src/response/ResponseContinuId.ts +1 -1
- package/src/response/ResponseMetaType.ts +32 -19
- package/src/response/ResponseMetaTypeViaMolecule.ts +224 -0
- package/src/response/ResponsePeering.ts +17 -0
- package/src/response/ResponsePolicy.ts +2 -3
- package/src/response/ResponseProposeMolecule.ts +0 -1
- package/src/response/ResponseRequestAuthorization.ts +32 -2
- package/src/response/ResponseRequestAuthorizationGuest.ts +25 -1
- package/src/response/ResponseWalletList.ts +1 -1
- package/src/schemas/index.ts +12 -1
- package/src/types/client.ts +3 -2
- package/src/types/graphql.ts +3 -2
- package/src/types/guards.ts +18 -5
- package/src/types/index.ts +19 -4
package/src/core/Wallet.ts
CHANGED
|
@@ -47,10 +47,10 @@ License: https://github.com/WishKnish/KnishIO-Client-TS/blob/master/LICENSE
|
|
|
47
47
|
*/
|
|
48
48
|
|
|
49
49
|
import JsSHA from 'jssha'
|
|
50
|
-
import { randomString, chunkSubstr } from '@/libraries/strings'
|
|
50
|
+
import { randomString, chunkSubstr, isHex } from '@/libraries/strings'
|
|
51
51
|
import { generateBundleHash, generateSecret, shake256, generateBatchId } from '@/libraries/crypto'
|
|
52
52
|
import WalletCredentialException from '@/exception/WalletCredentialException'
|
|
53
|
-
import {
|
|
53
|
+
import { isBundleHash } from '@/types'
|
|
54
54
|
// Post-quantum cryptography for ML-KEM768 key encapsulation
|
|
55
55
|
import { ml_kem768 } from '@noble/post-quantum/ml-kem.js'
|
|
56
56
|
|
|
@@ -60,7 +60,7 @@ import { ml_kem768 } from '@noble/post-quantum/ml-kem.js'
|
|
|
60
60
|
*/
|
|
61
61
|
export default class Wallet {
|
|
62
62
|
public token: string
|
|
63
|
-
public balance:
|
|
63
|
+
public balance: string
|
|
64
64
|
public address: string | null
|
|
65
65
|
public position: string | null
|
|
66
66
|
public bundle: string | null
|
|
@@ -97,18 +97,8 @@ export default class Wallet {
|
|
|
97
97
|
batchId?: string | null
|
|
98
98
|
characters?: string | null
|
|
99
99
|
} = {}) {
|
|
100
|
-
// TypeScript 2025: Exhaustive validation with type guards
|
|
101
|
-
if (address !== null && !isWalletAddress(address)) {
|
|
102
|
-
throw new WalletCredentialException('Invalid wallet address format')
|
|
103
|
-
}
|
|
104
|
-
if (bundle !== null && !isBundleHash(bundle)) {
|
|
105
|
-
throw new WalletCredentialException('Invalid bundle hash format')
|
|
106
|
-
}
|
|
107
|
-
if (position !== null && !isPosition(position)) {
|
|
108
|
-
throw new WalletCredentialException('Invalid position format')
|
|
109
|
-
}
|
|
110
100
|
this.token = token
|
|
111
|
-
this.balance = 0
|
|
101
|
+
this.balance = '0'
|
|
112
102
|
this.molecules = {}
|
|
113
103
|
|
|
114
104
|
// Empty values
|
|
@@ -164,20 +154,21 @@ export default class Wallet {
|
|
|
164
154
|
batchId?: string | null
|
|
165
155
|
characters?: string | null
|
|
166
156
|
}): Wallet {
|
|
167
|
-
let position = null
|
|
168
|
-
|
|
157
|
+
let position: string | null = null
|
|
158
|
+
|
|
169
159
|
// No credentials parameters provided?
|
|
170
160
|
if (!secret && !bundle) {
|
|
171
161
|
throw new WalletCredentialException()
|
|
172
162
|
}
|
|
173
|
-
|
|
163
|
+
|
|
174
164
|
// Secret, but no bundle?
|
|
175
165
|
if (secret && !bundle) {
|
|
176
166
|
position = Wallet.generatePosition()
|
|
177
167
|
bundle = generateBundleHash(secret, 'Wallet::create')
|
|
178
168
|
}
|
|
179
|
-
|
|
180
|
-
// Wallet initialization
|
|
169
|
+
|
|
170
|
+
// Wallet initialization (matching JS SDK exactly)
|
|
171
|
+
// Bundle-only wallets (shadow) get no position/address generation
|
|
181
172
|
return new Wallet({
|
|
182
173
|
secret,
|
|
183
174
|
bundle,
|
|
@@ -202,11 +193,15 @@ export default class Wallet {
|
|
|
202
193
|
token: string
|
|
203
194
|
position: string
|
|
204
195
|
}): string {
|
|
196
|
+
// Normalize non-hex secret/position via SHAKE256 (matching JS/Rust SDKs)
|
|
197
|
+
const secretHex = isHex(secret) ? secret : shake256(secret, 1024)
|
|
198
|
+
const positionHex = isHex(position) ? position : shake256(position, 256)
|
|
199
|
+
|
|
205
200
|
// Converting secret to bigInt
|
|
206
|
-
const bigIntSecret = BigInt(`0x${
|
|
207
|
-
|
|
201
|
+
const bigIntSecret = BigInt(`0x${secretHex}`)
|
|
202
|
+
|
|
208
203
|
// Adding new position to the user secret to produce the indexed key
|
|
209
|
-
const indexedKey = bigIntSecret + BigInt(`0x${
|
|
204
|
+
const indexedKey = bigIntSecret + BigInt(`0x${positionHex}`)
|
|
210
205
|
|
|
211
206
|
// Hashing the indexed key to produce the intermediate key
|
|
212
207
|
// CRITICAL FIX: Use sponge pattern exactly like JavaScript SDK
|
|
@@ -383,8 +378,8 @@ export default class Wallet {
|
|
|
383
378
|
*/
|
|
384
379
|
initializeMLKEM(): void {
|
|
385
380
|
// Generate a 64-byte (512-bit) seed from the Knish.IO private key
|
|
386
|
-
// Use deterministic approach: generateSecret(key,
|
|
387
|
-
const seedHex = generateSecret(this.key!,
|
|
381
|
+
// Use deterministic approach: generateSecret(key, 128) → 128 hex chars = 64 bytes
|
|
382
|
+
const seedHex = generateSecret(this.key!, 128) // 128 hex chars = 64 bytes, matches JS SDK
|
|
388
383
|
|
|
389
384
|
// Convert the hex string to a Uint8Array
|
|
390
385
|
const seed = new Uint8Array(64)
|
package/src/index.ts
CHANGED
|
@@ -113,6 +113,10 @@ export { default as MutationCreateMeta } from './mutation/MutationCreateMeta'
|
|
|
113
113
|
export { default as MutationCreateToken } from './mutation/MutationCreateToken'
|
|
114
114
|
export { default as MutationRequestTokens } from './mutation/MutationRequestTokens'
|
|
115
115
|
|
|
116
|
+
// P-isotope and A-isotope Mutation classes
|
|
117
|
+
export { default as MutationPeering } from './mutation/MutationPeering'
|
|
118
|
+
export { default as MutationAppendRequest } from './mutation/MutationAppendRequest'
|
|
119
|
+
|
|
116
120
|
// Essential Response classes (Phase 1)
|
|
117
121
|
export { default as ResponseBalance } from './response/ResponseBalance'
|
|
118
122
|
export { default as ResponseWalletBundle } from './response/ResponseWalletBundle'
|
|
@@ -134,6 +138,10 @@ export { default as ResponseMetaTypeViaAtom } from './response/ResponseMetaTypeV
|
|
|
134
138
|
export { default as ResponseCreateToken } from './response/ResponseCreateToken'
|
|
135
139
|
export { default as ResponseRequestTokens } from './response/ResponseRequestTokens'
|
|
136
140
|
|
|
141
|
+
// P-isotope and A-isotope Response classes
|
|
142
|
+
export { default as ResponsePeering } from './response/ResponsePeering'
|
|
143
|
+
export { default as ResponseAppendRequest } from './response/ResponseAppendRequest'
|
|
144
|
+
|
|
137
145
|
// Phase 2 Tier 2 Priority 3: Essential Query Operations
|
|
138
146
|
export { default as ResponseContinuId } from './response/ResponseContinuId'
|
|
139
147
|
// QueryBatch uses base Response class directly
|
|
@@ -479,16 +487,7 @@ export const DevUtils = process.env.NODE_ENV === 'development' ? {
|
|
|
479
487
|
// COMPATIBILITY WITH JAVASCRIPT SDK
|
|
480
488
|
// =============================================================================
|
|
481
489
|
|
|
482
|
-
|
|
483
|
-
* Legacy export names for compatibility with JavaScript SDK
|
|
484
|
-
* These maintain the exact same naming convention
|
|
485
|
-
*/
|
|
486
|
-
export {
|
|
487
|
-
// Core exports (matching JS SDK exactly)
|
|
488
|
-
shake256 as default, // The JS SDK doesn't export a default, but this maintains compatibility
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
// Maintain exact export structure as JS SDK index.js
|
|
490
|
+
// Maintain exact export structure as JS SDK index.js (named exports only)
|
|
492
491
|
export const KnishIO = {
|
|
493
492
|
shake256,
|
|
494
493
|
generateSecret,
|
|
@@ -1,29 +1,138 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
/*
|
|
2
|
+
(
|
|
3
|
+
(/(
|
|
4
|
+
(//(
|
|
5
|
+
(///(
|
|
6
|
+
(/////(
|
|
7
|
+
(//////( )
|
|
8
|
+
(////////( (/)
|
|
9
|
+
(////////( (///)
|
|
10
|
+
(//////////( (////)
|
|
11
|
+
(//////////( (//////)
|
|
12
|
+
(////////////( (///////)
|
|
13
|
+
(/////////////( (/////////)
|
|
14
|
+
(//////////////( (///////////)
|
|
15
|
+
(///////////////( (/////////////)
|
|
16
|
+
(////////////////( (//////////////)
|
|
17
|
+
((((((((((((((((((( (((((((((((((((
|
|
18
|
+
((((((((((((((((((( ((((((((((((((
|
|
19
|
+
((((((((((((((((((( ((((((((((((((
|
|
20
|
+
(((((((((((((((((((( (((((((((((((
|
|
21
|
+
(((((((((((((((((((( ((((((((((((
|
|
22
|
+
((((((((((((((((((( ((((((((((((
|
|
23
|
+
((((((((((((((((((( ((((((((((
|
|
24
|
+
((((((((((((((((((/ (((((((((
|
|
25
|
+
(((((((((((((((((( ((((((((
|
|
26
|
+
((((((((((((((((( (((((((
|
|
27
|
+
(((((((((((((((((( (((((
|
|
28
|
+
################# ##
|
|
29
|
+
################ #
|
|
30
|
+
################# ##
|
|
31
|
+
%################ ###
|
|
32
|
+
###############( ####
|
|
33
|
+
############### ####
|
|
34
|
+
############### ######
|
|
35
|
+
%#############( (#######
|
|
36
|
+
%############# #########
|
|
37
|
+
############( ##########
|
|
38
|
+
########### #############
|
|
39
|
+
######### ##############
|
|
40
|
+
%######
|
|
41
|
+
|
|
42
|
+
Powered by Knish.IO: Connecting a Decentralized World
|
|
43
|
+
|
|
44
|
+
Please visit https://github.com/WishKnish/KnishIO-Client-TS for information.
|
|
45
|
+
|
|
46
|
+
License: https://github.com/WishKnish/KnishIO-Client-TS/blob/master/LICENSE
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
import Callback from './Callback'
|
|
50
|
+
import Condition from './Condition'
|
|
51
|
+
import RuleArgumentException from './exception/RuleArgumentException'
|
|
52
|
+
import { MetaMissingException } from '@/exception'
|
|
53
|
+
|
|
54
|
+
interface RuleParams {
|
|
55
|
+
condition?: Condition[]
|
|
56
|
+
callback?: Callback[]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
interface RuleJSON {
|
|
60
|
+
condition: Condition[]
|
|
61
|
+
callback: Callback[]
|
|
62
|
+
}
|
|
63
|
+
|
|
5
64
|
export default class Rule {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
65
|
+
private __condition: Condition[]
|
|
66
|
+
private __callback: Callback[]
|
|
67
|
+
|
|
68
|
+
constructor({ condition = [], callback = [] }: RuleParams) {
|
|
69
|
+
for (const element of condition) {
|
|
70
|
+
if (!(element instanceof Condition)) {
|
|
71
|
+
throw new RuleArgumentException()
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
for (const element of callback) {
|
|
76
|
+
if (!(element instanceof Callback)) {
|
|
77
|
+
throw new RuleArgumentException()
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
this.__condition = condition
|
|
82
|
+
this.__callback = callback
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Adds a condition to this rule
|
|
87
|
+
*/
|
|
88
|
+
set comparison(condition: Condition | Record<string, any>) {
|
|
89
|
+
this.__condition.push(
|
|
90
|
+
condition instanceof Condition ? condition : Condition.toObject(condition as any)
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Adds a callback to this rule
|
|
96
|
+
*/
|
|
97
|
+
set callback(callback: Callback | Record<string, any>) {
|
|
98
|
+
this.__callback.push(
|
|
99
|
+
callback instanceof Callback ? callback : Callback.toObject(callback as any)
|
|
100
|
+
)
|
|
14
101
|
}
|
|
15
102
|
|
|
16
103
|
/**
|
|
17
104
|
* Convert rule data to Rule object
|
|
18
|
-
* @param
|
|
105
|
+
* @param object - Rule data to convert
|
|
19
106
|
* @return Rule instance
|
|
20
107
|
*/
|
|
21
|
-
static toObject(
|
|
22
|
-
if (
|
|
23
|
-
|
|
108
|
+
static toObject(object: any): Rule {
|
|
109
|
+
if (!object.condition) {
|
|
110
|
+
throw new MetaMissingException('Rule::toObject() - Incorrect rule format! There is no condition field.')
|
|
111
|
+
}
|
|
112
|
+
if (!object.callback) {
|
|
113
|
+
throw new MetaMissingException('Rule::toObject() - Incorrect rule format! There is no callback field.')
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const rule = new Rule({})
|
|
117
|
+
|
|
118
|
+
for (const condition of object.condition) {
|
|
119
|
+
rule.comparison = condition
|
|
24
120
|
}
|
|
25
|
-
|
|
121
|
+
|
|
122
|
+
for (const callback of object.callback) {
|
|
123
|
+
rule.callback = callback
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return rule
|
|
26
127
|
}
|
|
27
128
|
|
|
28
|
-
|
|
29
|
-
|
|
129
|
+
/**
|
|
130
|
+
* Converts to JSON representation
|
|
131
|
+
*/
|
|
132
|
+
toJSON(): RuleJSON {
|
|
133
|
+
return {
|
|
134
|
+
condition: this.__condition,
|
|
135
|
+
callback: this.__callback
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -71,6 +71,7 @@ import Rule from '@/instance/rules/Rule'
|
|
|
71
71
|
import { base64ToHex, chunkSubstr } from '@/libraries/strings'
|
|
72
72
|
import { shake256 } from '@/libraries/crypto'
|
|
73
73
|
import Dot from '@/libraries/Dot'
|
|
74
|
+
import Molecule from '@/core/Molecule'
|
|
74
75
|
|
|
75
76
|
// Type definitions for Molecule structure
|
|
76
77
|
interface MoleculeStructure {
|
|
@@ -461,7 +462,7 @@ export default class CheckMolecule {
|
|
|
461
462
|
throw new TypeError('Invalid isotope "V" values')
|
|
462
463
|
}
|
|
463
464
|
|
|
464
|
-
const remainder = senderWallet.balance + firstValue
|
|
465
|
+
const remainder = Number(senderWallet.balance) + firstValue
|
|
465
466
|
|
|
466
467
|
// Is there enough balance to send?
|
|
467
468
|
if (remainder < 0) {
|
|
@@ -578,4 +579,90 @@ export default class CheckMolecule {
|
|
|
578
579
|
// Looks like we passed all the tests!
|
|
579
580
|
return true
|
|
580
581
|
}
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* Reconstructs a Molecule instance from server-side GraphQL data.
|
|
585
|
+
* Maps server atom field names to SDK-expected format and parses metasJson.
|
|
586
|
+
*/
|
|
587
|
+
static fromServerData({
|
|
588
|
+
molecularHash,
|
|
589
|
+
bundleHash,
|
|
590
|
+
cellSlug = null,
|
|
591
|
+
status = null,
|
|
592
|
+
createdAt = null,
|
|
593
|
+
atoms = []
|
|
594
|
+
}: {
|
|
595
|
+
molecularHash: string
|
|
596
|
+
bundleHash: string
|
|
597
|
+
cellSlug?: string | null
|
|
598
|
+
status?: string | null
|
|
599
|
+
createdAt?: string | null
|
|
600
|
+
atoms?: any[]
|
|
601
|
+
}): Molecule {
|
|
602
|
+
const mappedAtoms = atoms.map((serverAtom: any) => {
|
|
603
|
+
let meta: Array<{ key: string; value: string }> = []
|
|
604
|
+
if (serverAtom.metasJson) {
|
|
605
|
+
try {
|
|
606
|
+
const parsed = JSON.parse(serverAtom.metasJson)
|
|
607
|
+
if (Array.isArray(parsed)) {
|
|
608
|
+
meta = parsed
|
|
609
|
+
} else if (parsed && typeof parsed === 'object') {
|
|
610
|
+
meta = Object.entries(parsed).map(([key, value]) => ({ key, value: String(value) }))
|
|
611
|
+
}
|
|
612
|
+
} catch (e) {
|
|
613
|
+
meta = []
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
return {
|
|
618
|
+
position: serverAtom.position || null,
|
|
619
|
+
walletAddress: serverAtom.walletAddress || null,
|
|
620
|
+
isotope: serverAtom.isotope || null,
|
|
621
|
+
token: serverAtom.tokenSlug || serverAtom.token || null,
|
|
622
|
+
value: serverAtom.value != null ? String(serverAtom.value) : null,
|
|
623
|
+
batchId: serverAtom.batchId || null,
|
|
624
|
+
metaType: serverAtom.metaType || null,
|
|
625
|
+
metaId: serverAtom.metaId || null,
|
|
626
|
+
meta,
|
|
627
|
+
index: serverAtom.index != null ? serverAtom.index : null,
|
|
628
|
+
otsFragment: serverAtom.otsFragment || null,
|
|
629
|
+
createdAt: serverAtom.createdAt || null
|
|
630
|
+
}
|
|
631
|
+
})
|
|
632
|
+
|
|
633
|
+
return Molecule.fromJSON({
|
|
634
|
+
molecularHash,
|
|
635
|
+
bundle: bundleHash,
|
|
636
|
+
cellSlug,
|
|
637
|
+
status,
|
|
638
|
+
createdAt,
|
|
639
|
+
atoms: mappedAtoms
|
|
640
|
+
})
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Verifies a molecule reconstructed from server-side GraphQL data.
|
|
645
|
+
* Returns an object with verification result and any error details.
|
|
646
|
+
*/
|
|
647
|
+
static verifyFromServerData(moleculeData: any): {
|
|
648
|
+
molecularHash: string | null
|
|
649
|
+
verified: boolean
|
|
650
|
+
error: string | null
|
|
651
|
+
} {
|
|
652
|
+
try {
|
|
653
|
+
const molecule = CheckMolecule.fromServerData(moleculeData)
|
|
654
|
+
new CheckMolecule(molecule as unknown as MoleculeStructure).verify()
|
|
655
|
+
return {
|
|
656
|
+
molecularHash: moleculeData.molecularHash,
|
|
657
|
+
verified: true,
|
|
658
|
+
error: null
|
|
659
|
+
}
|
|
660
|
+
} catch (error) {
|
|
661
|
+
return {
|
|
662
|
+
molecularHash: moleculeData.molecularHash || null,
|
|
663
|
+
verified: false,
|
|
664
|
+
error: (error as Error).message || String(error)
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
}
|
|
581
668
|
}
|
|
@@ -58,8 +58,7 @@ import { pipe, subscribe } from 'wonka'
|
|
|
58
58
|
import type {
|
|
59
59
|
GraphQLClient as IGraphQLClient,
|
|
60
60
|
GraphQLRequest,
|
|
61
|
-
GraphQLResponse
|
|
62
|
-
GraphQLVariables
|
|
61
|
+
GraphQLResponse
|
|
63
62
|
} from '@/types'
|
|
64
63
|
import type Wallet from '@/core/Wallet'
|
|
65
64
|
|
|
@@ -157,42 +156,38 @@ export default class GraphQLClient implements IGraphQLClient {
|
|
|
157
156
|
})
|
|
158
157
|
}
|
|
159
158
|
|
|
160
|
-
async query<TResult = unknown
|
|
161
|
-
request: GraphQLRequest
|
|
162
|
-
variables?: TVariables
|
|
159
|
+
async query<TResult = unknown>(
|
|
160
|
+
request: GraphQLRequest
|
|
163
161
|
): Promise<GraphQLResponse<TResult>> {
|
|
164
|
-
const
|
|
165
|
-
const result = await this.$__client.query(
|
|
162
|
+
const { query, variables } = request
|
|
163
|
+
const result = await this.$__client.query(query, variables || {}).toPromise()
|
|
166
164
|
return this.formatResponse<TResult>(result)
|
|
167
165
|
}
|
|
168
166
|
|
|
169
|
-
async mutation<TResult = unknown
|
|
170
|
-
request: GraphQLRequest
|
|
171
|
-
variables?: TVariables
|
|
167
|
+
async mutation<TResult = unknown>(
|
|
168
|
+
request: GraphQLRequest
|
|
172
169
|
): Promise<GraphQLResponse<TResult>> {
|
|
173
|
-
const
|
|
170
|
+
const { query, variables } = request
|
|
174
171
|
// Support both query and mutation properties for backward compatibility
|
|
175
|
-
const mutationString = (request as any).mutation ||
|
|
176
|
-
const result = await this.$__client.mutation(mutationString,
|
|
172
|
+
const mutationString = (request as any).mutation || query
|
|
173
|
+
const result = await this.$__client.mutation(mutationString, variables || {}).toPromise()
|
|
177
174
|
return this.formatResponse<TResult>(result)
|
|
178
175
|
}
|
|
179
176
|
|
|
180
177
|
// Alias for mutation() to match JS SDK interface
|
|
181
|
-
async mutate<TResult = unknown
|
|
182
|
-
request: GraphQLRequest
|
|
183
|
-
variables?: TVariables
|
|
178
|
+
async mutate<TResult = unknown>(
|
|
179
|
+
request: GraphQLRequest
|
|
184
180
|
): Promise<GraphQLResponse<TResult>> {
|
|
185
|
-
return this.mutation<TResult
|
|
181
|
+
return this.mutation<TResult>(request)
|
|
186
182
|
}
|
|
187
183
|
|
|
188
|
-
async *subscription<TResult = unknown
|
|
189
|
-
request: GraphQLRequest
|
|
190
|
-
variables?: TVariables
|
|
184
|
+
async *subscription<TResult = unknown>(
|
|
185
|
+
request: GraphQLRequest
|
|
191
186
|
): AsyncIterableIterator<GraphQLResponse<TResult>> {
|
|
192
|
-
const
|
|
187
|
+
const { query, variables } = request
|
|
193
188
|
|
|
194
189
|
// Create subscription stream
|
|
195
|
-
const subscription = this.$__client.subscription(
|
|
190
|
+
const subscription = this.$__client.subscription(query, variables || {})
|
|
196
191
|
|
|
197
192
|
// Convert wonka stream to async iterator
|
|
198
193
|
const results: GraphQLResponse<TResult>[] = []
|
package/src/libraries/crypto.ts
CHANGED
|
@@ -176,19 +176,15 @@ export function generateSecretEnhanced(options: SecretGenerationOptions): string
|
|
|
176
176
|
* Generate bundle hash from secret - MUST produce identical results to JS SDK
|
|
177
177
|
* Uses SHAKE256 with 256-bit output (64 hex characters)
|
|
178
178
|
*/
|
|
179
|
-
export function generateBundleHash(secret: string,
|
|
179
|
+
export function generateBundleHash(secret: string, _source: string | null = null): BundleHash {
|
|
180
180
|
if (!secret || secret.length === 0) {
|
|
181
181
|
throw new Error('Secret is required for bundle hash generation')
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
// Fix: BUNDLE_HASH_LENGTH is 64 (hex chars), but shake256 expects bits
|
|
190
|
-
// So we multiply by 4: 64 hex chars * 4 = 256 bits (matching JS SDK)
|
|
191
|
-
const hash = shake256(input, CRYPTO_CONSTANTS.BUNDLE_HASH_LENGTH * 4)
|
|
184
|
+
// CRITICAL: source parameter must be IGNORED to match JS SDK behavior.
|
|
185
|
+
// JS SDK's generateBundleHash() accepts source but never uses it.
|
|
186
|
+
// The bundle hash is an identity anchor and must be deterministic from secret alone.
|
|
187
|
+
const hash = shake256(secret, CRYPTO_CONSTANTS.BUNDLE_HASH_LENGTH * 4)
|
|
192
188
|
return hash as BundleHash
|
|
193
189
|
}
|
|
194
190
|
|
|
@@ -251,30 +247,18 @@ export function generatePositionEnhanced(options: PositionGenerationOptions = {}
|
|
|
251
247
|
* Generate batch ID from molecular hash and index
|
|
252
248
|
* Uses SHAKE256 to create deterministic batch identifiers
|
|
253
249
|
*/
|
|
254
|
-
export function generateBatchId({
|
|
255
|
-
molecularHash = null,
|
|
256
|
-
index = null
|
|
257
|
-
}: {
|
|
250
|
+
export function generateBatchId({
|
|
251
|
+
molecularHash = null,
|
|
252
|
+
index = null
|
|
253
|
+
}: {
|
|
258
254
|
molecularHash?: string | null
|
|
259
|
-
index?: number | null
|
|
255
|
+
index?: number | null
|
|
260
256
|
} = {}): string {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
input += molecularHash
|
|
257
|
+
// Match JS SDK: require BOTH molecularHash AND index for deterministic batch ID
|
|
258
|
+
if (molecularHash && index !== null) {
|
|
259
|
+
return shake256(molecularHash + index, 256) // 256 bits = 64 hex chars
|
|
265
260
|
}
|
|
266
|
-
|
|
267
|
-
if (index !== null) {
|
|
268
|
-
input += index.toString()
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// If no input provided, generate random batch ID
|
|
272
|
-
if (input === '') {
|
|
273
|
-
input = randomString(32)
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// Use SHAKE256 to generate 64-character batch ID
|
|
277
|
-
return shake256(input, 64)
|
|
261
|
+
return randomString(64)
|
|
278
262
|
}
|
|
279
263
|
|
|
280
264
|
// =============================================================================
|
package/src/libraries/strings.ts
CHANGED
|
@@ -78,7 +78,7 @@ export function chunkSubstr(str: string, size: number): string[] {
|
|
|
78
78
|
*/
|
|
79
79
|
export function randomString(
|
|
80
80
|
length = 32,
|
|
81
|
-
alphabet = '
|
|
81
|
+
alphabet = 'abcdef0123456789'
|
|
82
82
|
): string {
|
|
83
83
|
if (length <= 0) return ''
|
|
84
84
|
|
|
@@ -108,7 +108,8 @@ export function randomString(
|
|
|
108
108
|
|
|
109
109
|
/**
|
|
110
110
|
* Convert between different character sets/bases
|
|
111
|
-
*
|
|
111
|
+
* Uses BigInt for arbitrary-precision arithmetic to handle 256-bit hashes
|
|
112
|
+
* MUST match JavaScript SDK charsetBaseConvert exactly
|
|
112
113
|
*/
|
|
113
114
|
export function charsetBaseConvert(
|
|
114
115
|
src: string,
|
|
@@ -120,37 +121,37 @@ export function charsetBaseConvert(
|
|
|
120
121
|
if (!src || fromBase < 2 || toBase < 2 || fromBase > srcSymbolTable.length || toBase > destSymbolTable.length) {
|
|
121
122
|
return false
|
|
122
123
|
}
|
|
123
|
-
|
|
124
|
+
|
|
124
125
|
try {
|
|
125
|
-
// Convert from source base to
|
|
126
|
-
let
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
for (let
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if (charIndex === -1) {
|
|
126
|
+
// Convert from source base to BigInt (arbitrary precision)
|
|
127
|
+
let val = BigInt(0)
|
|
128
|
+
const bigFromBase = BigInt(fromBase)
|
|
129
|
+
|
|
130
|
+
for (let charIndex = 0; charIndex < src.length; charIndex++) {
|
|
131
|
+
const symbolIndex = srcSymbolTable.indexOf(src.charAt(charIndex))
|
|
132
|
+
|
|
133
|
+
if (symbolIndex === -1) {
|
|
134
134
|
return false // Invalid character for source base
|
|
135
135
|
}
|
|
136
|
-
|
|
137
|
-
|
|
136
|
+
|
|
137
|
+
val = val * bigFromBase + BigInt(symbolIndex)
|
|
138
138
|
}
|
|
139
|
-
|
|
140
|
-
// Convert from
|
|
141
|
-
if (
|
|
139
|
+
|
|
140
|
+
// Convert from BigInt to destination base
|
|
141
|
+
if (val === BigInt(0)) {
|
|
142
142
|
return destSymbolTable.charAt(0)
|
|
143
143
|
}
|
|
144
|
-
|
|
144
|
+
|
|
145
|
+
const bigToBase = BigInt(toBase)
|
|
145
146
|
let result = ''
|
|
146
|
-
while (
|
|
147
|
-
const remainder =
|
|
148
|
-
result = destSymbolTable.charAt(remainder) + result
|
|
149
|
-
|
|
147
|
+
while (val > BigInt(0)) {
|
|
148
|
+
const remainder = val % bigToBase
|
|
149
|
+
result = destSymbolTable.charAt(Number(remainder)) + result
|
|
150
|
+
val = val / bigToBase
|
|
150
151
|
}
|
|
151
|
-
|
|
152
|
-
return result
|
|
153
|
-
|
|
152
|
+
|
|
153
|
+
return result || '0'
|
|
154
|
+
|
|
154
155
|
} catch (error) {
|
|
155
156
|
return false
|
|
156
157
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Powered by Knish.IO: Connecting a Decentralized World
|
|
3
|
+
|
|
4
|
+
Please visit https://github.com/WishKnish/KnishIO-Client-TS for information.
|
|
5
|
+
|
|
6
|
+
License: https://github.com/WishKnish/KnishIO-Client-TS/blob/master/LICENSE
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import MutationProposeMolecule from './MutationProposeMolecule'
|
|
10
|
+
import ResponseAppendRequest from '../response/ResponseAppendRequest'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Mutation for submitting an append request via the A-isotope
|
|
14
|
+
* Matches JavaScript SDK MutationAppendRequest implementation exactly
|
|
15
|
+
*/
|
|
16
|
+
export default class MutationAppendRequest extends MutationProposeMolecule {
|
|
17
|
+
/**
|
|
18
|
+
* Fills a molecule with an A-isotope append request atom
|
|
19
|
+
* Matches JavaScript SDK fillMolecule method exactly
|
|
20
|
+
*/
|
|
21
|
+
override fillMolecule({
|
|
22
|
+
metaType,
|
|
23
|
+
metaId,
|
|
24
|
+
action,
|
|
25
|
+
meta = {}
|
|
26
|
+
}: {
|
|
27
|
+
metaType: string
|
|
28
|
+
metaId: string
|
|
29
|
+
action: string
|
|
30
|
+
meta?: Record<string, any>
|
|
31
|
+
}): void {
|
|
32
|
+
(this.$__molecule as any).initAppendRequest({
|
|
33
|
+
metaType,
|
|
34
|
+
metaId,
|
|
35
|
+
action,
|
|
36
|
+
meta
|
|
37
|
+
});
|
|
38
|
+
(this.$__molecule as any).sign({});
|
|
39
|
+
(this.$__molecule as any).check()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Builds a Response object out of a JSON object
|
|
44
|
+
* Matches JavaScript SDK createResponse method exactly
|
|
45
|
+
*/
|
|
46
|
+
override createResponse(json: any): ResponseAppendRequest {
|
|
47
|
+
return new ResponseAppendRequest({
|
|
48
|
+
query: this,
|
|
49
|
+
json
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
}
|