@wishknish/knishio-client-ts 0.8.2 → 0.9.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.cjs +425 -263
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +44 -17
- package/dist/index.d.ts +44 -17
- package/dist/index.iife.js +425 -265
- package/dist/index.iife.js.map +1 -1
- package/dist/index.js +447 -285
- package/dist/index.js.map +1 -1
- package/package.json +6 -9
- package/src/KnishIOClient.ts +180 -57
- package/src/constants.ts +1 -2
- package/src/core/Molecule.ts +53 -0
- package/src/core/Wallet.ts +84 -3
- package/src/libraries/Decimal.ts +1 -1
- package/src/libraries/GraphQLClient.ts +83 -0
- package/src/libraries/Hex.ts +4 -3
- package/src/libraries/UrqlClientWrapper.ts +13 -13
- package/src/libraries/crypto.ts +4 -4
- package/src/mutation/MutationClaimShadowWallet.ts +3 -1
- package/src/mutation/MutationTransferTokens.ts +18 -0
- package/src/query/QueryActiveSession.ts +0 -1
- package/src/query/QueryPolicy.ts +0 -1
- package/src/response/ResponseAuthorizationGuest.ts +2 -2
- package/src/response/ResponseBalance.ts +9 -6
- package/src/response/ResponseLinkIdentifier.ts +1 -1
- package/src/response/ResponseRequestAuthorizationGuest.ts +2 -2
- package/src/schemas/index.ts +2 -1
- package/src/subscribe/Subscribe.ts +3 -2
- package/src/types/assertions.ts +1 -6
- package/src/types/client.ts +12 -19
- package/src/types/guards.ts +2 -3
- package/src/types/index.ts +6 -0
- package/src/validation/UNIVERSAL_CONFIGURATION_INTERFACES.ts +3 -5
- package/src/validation/ValidationService.ts +6 -15
- package/src/validation/schemas.ts +5 -1
- package/src/versions/HashAtom.ts +11 -9
- package/src/query/QueryUserActivity.ts +0 -153
- package/src/response/ResponseQueryUserActivity.ts +0 -89
|
@@ -62,6 +62,22 @@ import type {
|
|
|
62
62
|
} from '@/types'
|
|
63
63
|
import type Wallet from '@/core/Wallet'
|
|
64
64
|
|
|
65
|
+
const CIPHER_HASH_QUERY = 'query ( $Hash: String! ) { CipherHash ( Hash: $Hash ) { hash } }'
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Light parse of a GraphQL request body's operation type + root field name, for the CipherHash
|
|
69
|
+
* bypass decision (no full GraphQL parse needed). Operation type = the first query/mutation/
|
|
70
|
+
* subscription keyword (default 'query' for an anonymous `{ ... }`); root field = the first
|
|
71
|
+
* identifier inside the top-level selection set.
|
|
72
|
+
*/
|
|
73
|
+
function parseOperation(query: string): { type: string; name: string } {
|
|
74
|
+
const typeMatch = (query || '').match(/\b(query|mutation|subscription)\b/i)
|
|
75
|
+
const type = typeMatch?.[1]?.toLowerCase() ?? 'query'
|
|
76
|
+
const braceIdx = (query || '').indexOf('{')
|
|
77
|
+
const nameMatch = braceIdx >= 0 ? query.slice(braceIdx + 1).match(/[A-Za-z_][A-Za-z0-9_]*/) : null
|
|
78
|
+
return { type, name: nameMatch?.[0] ?? '' }
|
|
79
|
+
}
|
|
80
|
+
|
|
65
81
|
/**
|
|
66
82
|
* GraphQL client wrapper for KnishIO SDK
|
|
67
83
|
* Provides a unified interface for GraphQL operations
|
|
@@ -125,6 +141,10 @@ export default class GraphQLClient implements IGraphQLClient {
|
|
|
125
141
|
return createClient({
|
|
126
142
|
url: serverUri,
|
|
127
143
|
exchanges,
|
|
144
|
+
// PQ-transport Phase E: when encryption is on, route fetch through the CipherHash wrapper
|
|
145
|
+
// (encrypt the request body to the validator's ML-KEM pubkey, decrypt the response).
|
|
146
|
+
// Omitted → urql uses the global fetch (plaintext).
|
|
147
|
+
...(this.cipherLink ? { fetch: ((input: any, init: any) => this.cipherFetch(input, init)) as typeof fetch } : {}),
|
|
128
148
|
fetchOptions: () => ({
|
|
129
149
|
headers: {
|
|
130
150
|
'X-Auth-Token': this.$__authToken
|
|
@@ -135,6 +155,69 @@ export default class GraphQLClient implements IGraphQLClient {
|
|
|
135
155
|
})
|
|
136
156
|
}
|
|
137
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Whether an outgoing GraphQL request body should be wrapped in CipherHash. Bypass (plaintext):
|
|
160
|
+
* introspection `__schema`, `ContinuId`, the `AccessToken` mutation, and the U-isotope
|
|
161
|
+
* `ProposeMolecule` (auth bootstrap — the key exchange itself can't be encrypted). Mirrors the
|
|
162
|
+
* Kotlin/PHP/validator bypass set.
|
|
163
|
+
*/
|
|
164
|
+
private shouldEncrypt(body: string): boolean {
|
|
165
|
+
let parsed: any
|
|
166
|
+
try {
|
|
167
|
+
parsed = JSON.parse(body)
|
|
168
|
+
} catch (e) {
|
|
169
|
+
return false
|
|
170
|
+
}
|
|
171
|
+
const { type, name } = parseOperation(parsed.query)
|
|
172
|
+
if (type === 'query' && (name === '__schema' || name === 'ContinuId')) return false
|
|
173
|
+
if (type === 'mutation' && name === 'AccessToken') return false
|
|
174
|
+
if (type === 'mutation' && name === 'ProposeMolecule') {
|
|
175
|
+
const isotope = parsed.variables?.molecule?.atoms?.[0]?.isotope
|
|
176
|
+
if (isotope === 'U') return false
|
|
177
|
+
}
|
|
178
|
+
return true
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Custom `fetch` that wraps a GraphQL request in the ML-KEM CipherHash envelope and decrypts the
|
|
183
|
+
* response (PQ-transport Phase E). Operates on the raw POST body (mirrors the JS/Kotlin transform).
|
|
184
|
+
* Reads the CURRENT client wallet + validator pubkey from auth.
|
|
185
|
+
*/
|
|
186
|
+
private async cipherFetch(input: any, init: any): Promise<Response> {
|
|
187
|
+
const wallet = this.$__wallet
|
|
188
|
+
const serverPubkey = this.$__pubkey
|
|
189
|
+
let encryptedRequest = false
|
|
190
|
+
let requestInit = init
|
|
191
|
+
|
|
192
|
+
if (wallet && serverPubkey && init && typeof init.body === 'string' && this.shouldEncrypt(init.body)) {
|
|
193
|
+
const hashVar = await wallet.encryptStringML768(init.body, serverPubkey)
|
|
194
|
+
requestInit = { ...init, body: JSON.stringify({ query: CIPHER_HASH_QUERY, variables: { Hash: hashVar } }) }
|
|
195
|
+
encryptedRequest = true
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const response = await fetch(input, requestInit)
|
|
199
|
+
if (!encryptedRequest) {
|
|
200
|
+
return response
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Decrypt the CipherHash response back to the inner GraphQL response JSON.
|
|
204
|
+
const text = await response.text()
|
|
205
|
+
const init2 = { status: response.status, statusText: response.statusText, headers: response.headers }
|
|
206
|
+
let parsed: any
|
|
207
|
+
try {
|
|
208
|
+
parsed = JSON.parse(text)
|
|
209
|
+
} catch (e) {
|
|
210
|
+
return new Response(text, init2)
|
|
211
|
+
}
|
|
212
|
+
const hash = parsed?.data?.CipherHash?.hash
|
|
213
|
+
if (typeof hash !== 'string') {
|
|
214
|
+
// Plaintext (e.g. a validator-side error response) — pass through unchanged.
|
|
215
|
+
return new Response(text, init2)
|
|
216
|
+
}
|
|
217
|
+
const decrypted = await wallet!.decryptMyMessageML768(JSON.parse(hash))
|
|
218
|
+
return new Response(decrypted != null ? decrypted : text, init2)
|
|
219
|
+
}
|
|
220
|
+
|
|
138
221
|
setAuthData({
|
|
139
222
|
token,
|
|
140
223
|
pubkey,
|
package/src/libraries/Hex.ts
CHANGED
|
@@ -72,7 +72,8 @@ export default class Hex {
|
|
|
72
72
|
? ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F']
|
|
73
73
|
: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
// indices are provably in-range (val is a byte; /16 and %16 are 0..15 for a 16-elem set)
|
|
76
|
+
return set[Math.floor(val / 16)]! + set[val % 16]!
|
|
76
77
|
}
|
|
77
78
|
|
|
78
79
|
const opts: Required<HexOptions> = Object.assign(
|
|
@@ -97,7 +98,7 @@ export default class Hex {
|
|
|
97
98
|
let column = 0
|
|
98
99
|
|
|
99
100
|
for (let i = 0; i < arrayLike.length; ++i) {
|
|
100
|
-
str += numberToHex(arrayLike[i]
|
|
101
|
+
str += numberToHex(arrayLike[i]!, opts.uppercase)
|
|
101
102
|
|
|
102
103
|
if (i === arrayLike.length - 1) {
|
|
103
104
|
break
|
|
@@ -135,7 +136,7 @@ export default class Hex {
|
|
|
135
136
|
let curr = -1
|
|
136
137
|
|
|
137
138
|
for (let i = 0; i < target.length; ++i) {
|
|
138
|
-
const c = target[i]
|
|
139
|
+
const c = target[i]!
|
|
139
140
|
const val = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'].indexOf(c)
|
|
140
141
|
|
|
141
142
|
if (val === -1) {
|
|
@@ -54,11 +54,10 @@ import {
|
|
|
54
54
|
Client,
|
|
55
55
|
OperationResult
|
|
56
56
|
} from '@urql/core'
|
|
57
|
-
import { createClient as createWSClient, Client as WSClient } from 'graphql-ws'
|
|
58
|
-
import { pipe, map,
|
|
57
|
+
import { createClient as createWSClient, Client as WSClient, type SubscribePayload } from 'graphql-ws'
|
|
58
|
+
import { pipe, map, subscribe, type Subscription } from 'wonka'
|
|
59
59
|
import type { DocumentNode } from 'graphql'
|
|
60
60
|
import type Wallet from '@/core/Wallet'
|
|
61
|
-
import { GraphQLRequestSchema, GraphQLResponseSchema, parseWithSchema } from '@/schemas'
|
|
62
61
|
|
|
63
62
|
// Enhanced type definitions with proper constraints
|
|
64
63
|
interface SocketConfig {
|
|
@@ -110,7 +109,7 @@ class UrqlClientWrapper {
|
|
|
110
109
|
private $__authToken: string = ''
|
|
111
110
|
private $__pubkey: string | null = null
|
|
112
111
|
private $__wallet: Wallet | null = null
|
|
113
|
-
private
|
|
112
|
+
private serverUri: string
|
|
114
113
|
private soketi: SocketConfig | null
|
|
115
114
|
private cipherLink: boolean
|
|
116
115
|
private readonly $__subscriptionManager: Map<string, SubscriptionManager> = new Map()
|
|
@@ -126,8 +125,7 @@ class UrqlClientWrapper {
|
|
|
126
125
|
|
|
127
126
|
private createUrqlClient({
|
|
128
127
|
serverUri,
|
|
129
|
-
socket
|
|
130
|
-
encrypt
|
|
128
|
+
socket
|
|
131
129
|
}: {
|
|
132
130
|
serverUri: string
|
|
133
131
|
socket?: SocketConfig | null
|
|
@@ -147,7 +145,7 @@ class UrqlClientWrapper {
|
|
|
147
145
|
exchanges.push(subscriptionExchange({
|
|
148
146
|
forwardSubscription: operation => ({
|
|
149
147
|
subscribe: sink => {
|
|
150
|
-
const disposable = wsClient.subscribe(operation, sink)
|
|
148
|
+
const disposable = wsClient.subscribe(operation as unknown as SubscribePayload, sink)
|
|
151
149
|
return { unsubscribe: disposable }
|
|
152
150
|
}
|
|
153
151
|
})
|
|
@@ -209,12 +207,14 @@ class UrqlClientWrapper {
|
|
|
209
207
|
throw new Error('Query is required for subscription')
|
|
210
208
|
}
|
|
211
209
|
|
|
212
|
-
|
|
210
|
+
// wonka v6: subscribe is a pipe operator (no `.subscribe()` method on Source) → pipe(src, ..., subscribe(h))
|
|
211
|
+
const subscription: Subscription = pipe(
|
|
213
212
|
this.$__client.subscription(query, variables),
|
|
214
213
|
map(result => {
|
|
215
214
|
closure(this.formatResponse<TData>(result))
|
|
216
|
-
})
|
|
217
|
-
|
|
215
|
+
}),
|
|
216
|
+
subscribe(() => {})
|
|
217
|
+
)
|
|
218
218
|
|
|
219
219
|
// Store subscription for later cleanup
|
|
220
220
|
if (operationName) {
|
|
@@ -238,8 +238,8 @@ class UrqlClientWrapper {
|
|
|
238
238
|
if (result.error) {
|
|
239
239
|
response.errors = [{
|
|
240
240
|
message: result.error.message,
|
|
241
|
-
locations: result.error.graphQLErrors?.[0]?.locations,
|
|
242
|
-
path: result.error.graphQLErrors?.[0]?.path,
|
|
241
|
+
locations: result.error.graphQLErrors?.[0]?.locations as { line: number; column: number }[] | undefined,
|
|
242
|
+
path: result.error.graphQLErrors?.[0]?.path as (string | number)[] | undefined,
|
|
243
243
|
extensions: result.error.graphQLErrors?.[0]?.extensions
|
|
244
244
|
}]
|
|
245
245
|
}
|
|
@@ -263,7 +263,7 @@ class UrqlClientWrapper {
|
|
|
263
263
|
}
|
|
264
264
|
|
|
265
265
|
unsubscribeAll(): void {
|
|
266
|
-
this.$__subscriptionManager.forEach((
|
|
266
|
+
this.$__subscriptionManager.forEach((_subscription, operationName) => {
|
|
267
267
|
this.unsubscribe(operationName)
|
|
268
268
|
})
|
|
269
269
|
}
|
package/src/libraries/crypto.ts
CHANGED
|
@@ -178,10 +178,10 @@ export function generateSecretEnhanced(options: SecretGenerationOptions): string
|
|
|
178
178
|
* Uses SHAKE256 with 256-bit output (64 hex characters)
|
|
179
179
|
*/
|
|
180
180
|
export function generateBundleHash(secret: string, _source: string | null = null): BundleHash {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
181
|
+
// Cross-SDK parity (c142): an empty secret hashes to shake256("") = 46b9dd2b… — matching
|
|
182
|
+
// JS/PHP/Kotlin/Rust/Python + the committed `empty_secret` vector. (Previously threw;
|
|
183
|
+
// no real caller passes an empty secret.)
|
|
184
|
+
//
|
|
185
185
|
// CRITICAL: source parameter must be IGNORED to match JS SDK behavior.
|
|
186
186
|
// JS SDK's generateBundleHash() accepts source but never uses it.
|
|
187
187
|
// The bundle hash is an identity anchor and must be deterministic from secret alone.
|
|
@@ -71,9 +71,11 @@ export default class MutationClaimShadowWallet extends MutationProposeMolecule {
|
|
|
71
71
|
bundle: this.$__molecule.bundle,
|
|
72
72
|
token,
|
|
73
73
|
batchId
|
|
74
|
-
})
|
|
74
|
+
});
|
|
75
75
|
|
|
76
76
|
// Initialize shadow wallet claim on the molecule
|
|
77
|
+
// (leading-paren statements REQUIRE the preceding semicolon — without it ASI parses
|
|
78
|
+
// `Wallet.create({...})(this.$__molecule)` and throws "Wallet.create(...) is not a function")
|
|
77
79
|
(this.$__molecule as any).initShadowWalletClaim(wallet)
|
|
78
80
|
this.$__molecule.sign({})
|
|
79
81
|
this.$__molecule.check()
|
|
@@ -74,6 +74,24 @@ export default class MutationTransferTokens extends MutationProposeMolecule {
|
|
|
74
74
|
(this.$__molecule as any).check((this.$__molecule as any).sourceWallet)
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Fills the Molecule for a MULTI-recipient transfer (one source funds N recipients)
|
|
79
|
+
*/
|
|
80
|
+
fillMoleculeMulti({
|
|
81
|
+
recipientWallets,
|
|
82
|
+
amounts
|
|
83
|
+
}: {
|
|
84
|
+
recipientWallets: Wallet[]
|
|
85
|
+
amounts: number[]
|
|
86
|
+
}): void {
|
|
87
|
+
(this.$__molecule as any).initValues({
|
|
88
|
+
recipientWallets,
|
|
89
|
+
amounts
|
|
90
|
+
});
|
|
91
|
+
(this.$__molecule as any).sign({});
|
|
92
|
+
(this.$__molecule as any).check((this.$__molecule as any).sourceWallet)
|
|
93
|
+
}
|
|
94
|
+
|
|
77
95
|
/**
|
|
78
96
|
* Builds a Response object out of a JSON object
|
|
79
97
|
* Matches JavaScript SDK createResponse method signature exactly
|
|
@@ -51,7 +51,6 @@ import ResponseQueryActiveSession from '@/response/ResponseQueryActiveSession'
|
|
|
51
51
|
import { gql } from '@urql/core'
|
|
52
52
|
import type { GraphQLClient as IGraphQLClient } from '@/types'
|
|
53
53
|
import type KnishIOClient from '@/KnishIOClient'
|
|
54
|
-
import type { BundleHash, MetaType, MetaId } from '@/types'
|
|
55
54
|
|
|
56
55
|
/**
|
|
57
56
|
* Query for retrieving a list of active User Sessions
|
package/src/query/QueryPolicy.ts
CHANGED
|
@@ -51,7 +51,6 @@ import ResponsePolicy from '@/response/ResponsePolicy'
|
|
|
51
51
|
import { gql } from '@urql/core'
|
|
52
52
|
import type { GraphQLClient as IGraphQLClient } from '@/types'
|
|
53
53
|
import type KnishIOClient from '@/KnishIOClient'
|
|
54
|
-
import type { MetaType, MetaId } from '@/types'
|
|
55
54
|
|
|
56
55
|
/**
|
|
57
56
|
* Query for retrieving Policy information
|
|
@@ -75,14 +75,14 @@ export default class ResponseAuthorizationGuest extends Response {
|
|
|
75
75
|
/**
|
|
76
76
|
* Returns the reason for rejection
|
|
77
77
|
*/
|
|
78
|
-
reason(): string {
|
|
78
|
+
override reason(): string {
|
|
79
79
|
return 'Invalid response from server'
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
/**
|
|
83
83
|
* Returns whether molecule was accepted or not
|
|
84
84
|
*/
|
|
85
|
-
success(): boolean {
|
|
85
|
+
override success(): boolean {
|
|
86
86
|
return this.payload() !== null
|
|
87
87
|
}
|
|
88
88
|
|
|
@@ -48,6 +48,7 @@ License: https://github.com/WishKnish/KnishIO-Client-TS/blob/master/LICENSE
|
|
|
48
48
|
|
|
49
49
|
import Response from './Response'
|
|
50
50
|
import Wallet from '../core/Wallet'
|
|
51
|
+
import TokenUnit from '../core/TokenUnit'
|
|
51
52
|
import type Query from '../query/Query'
|
|
52
53
|
|
|
53
54
|
/**
|
|
@@ -134,12 +135,14 @@ export default class ResponseBalance extends Response {
|
|
|
134
135
|
wallet.tokenFungibility = data.token.fungibility
|
|
135
136
|
}
|
|
136
137
|
|
|
137
|
-
//
|
|
138
|
-
//
|
|
139
|
-
//
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
138
|
+
// Stackable (NFT) token units — the validator serves Wallet.tokenUnits and QueryBalance
|
|
139
|
+
// selects them; parse them so a queried source wallet carries its units (otherwise every
|
|
140
|
+
// stackable transfer silently degrades to fungible). Mirrors ResponseWalletList.toClientWallet.
|
|
141
|
+
if (data.tokenUnits && data.tokenUnits.length) {
|
|
142
|
+
for (const tokenUnitData of data.tokenUnits) {
|
|
143
|
+
wallet.tokenUnits.push(TokenUnit.createFromGraphQL(tokenUnitData))
|
|
144
|
+
}
|
|
145
|
+
}
|
|
143
146
|
|
|
144
147
|
// Set trade rates if available
|
|
145
148
|
if (data.tradeRates && data.tradeRates.length) {
|
|
@@ -75,14 +75,14 @@ export default class ResponseRequestAuthorizationGuest extends Response {
|
|
|
75
75
|
/**
|
|
76
76
|
* Returns the reason for rejection
|
|
77
77
|
*/
|
|
78
|
-
reason(): string {
|
|
78
|
+
override reason(): string {
|
|
79
79
|
return 'Invalid response from server'
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
/**
|
|
83
83
|
* Returns whether authorization was successful
|
|
84
84
|
*/
|
|
85
|
-
success(): boolean {
|
|
85
|
+
override success(): boolean {
|
|
86
86
|
return this.payload() !== null
|
|
87
87
|
}
|
|
88
88
|
|
package/src/schemas/index.ts
CHANGED
|
@@ -191,7 +191,8 @@ export const KnishIOClientConfigSchema = z.object({
|
|
|
191
191
|
client: z.unknown().optional(),
|
|
192
192
|
socket: z.unknown().optional(),
|
|
193
193
|
serverSdkVersion: z.number().int().min(1).optional(),
|
|
194
|
-
logging: z.boolean().optional()
|
|
194
|
+
logging: z.boolean().optional(),
|
|
195
|
+
defaultRequestPolicy: z.enum(['cache-first', 'cache-only', 'network-only', 'cache-and-network']).nullable().optional()
|
|
195
196
|
}).strict()
|
|
196
197
|
|
|
197
198
|
// =============================================================================
|
|
@@ -49,7 +49,6 @@ License: https://github.com/WishKnish/KnishIO-Client-TS/blob/master/LICENSE
|
|
|
49
49
|
import type { GraphQLClient as IGraphQLClient } from '@/types'
|
|
50
50
|
import { CodeException } from '@/exception'
|
|
51
51
|
import type { DocumentNode } from 'graphql'
|
|
52
|
-
import { GraphQLRequestSchema, parseWithSchema } from '@/schemas'
|
|
53
52
|
|
|
54
53
|
// Define subscription-specific types for better type safety
|
|
55
54
|
interface SubscriptionRequest {
|
|
@@ -72,7 +71,9 @@ interface SubscriptionCreateParams {
|
|
|
72
71
|
}
|
|
73
72
|
|
|
74
73
|
// Type for GraphQL client with subscription support
|
|
75
|
-
|
|
74
|
+
// Omit the base's required subscribe/getUri, then re-add as OPTIONAL variants (a passed client may
|
|
75
|
+
// not implement them) — avoids TS2430 (an optional member can't override a required base member).
|
|
76
|
+
interface GraphQLSubscriptionClient extends Omit<IGraphQLClient, 'subscribe' | 'getUri'> {
|
|
76
77
|
subscribe?: (request: SubscriptionRequest, closure: (result: unknown) => void) => Promise<string>
|
|
77
78
|
getUri?: () => string | null
|
|
78
79
|
}
|
package/src/types/assertions.ts
CHANGED
|
@@ -58,19 +58,14 @@ License: https://github.com/WishKnish/KnishIO-Client-TS/blob/master/LICENSE
|
|
|
58
58
|
|
|
59
59
|
import type {
|
|
60
60
|
AtomIsotope,
|
|
61
|
-
KnishIOErrorType
|
|
62
|
-
QueryType,
|
|
63
|
-
MutationType,
|
|
64
|
-
SubscriptionType
|
|
61
|
+
KnishIOErrorType
|
|
65
62
|
} from '../constants'
|
|
66
63
|
|
|
67
64
|
import type {
|
|
68
65
|
WalletAddress,
|
|
69
66
|
BundleHash,
|
|
70
67
|
TokenSlug,
|
|
71
|
-
Position,
|
|
72
68
|
MolecularHash,
|
|
73
|
-
CellSlug,
|
|
74
69
|
BatchId,
|
|
75
70
|
AtomParams,
|
|
76
71
|
WalletParams,
|
package/src/types/client.ts
CHANGED
|
@@ -129,6 +129,18 @@ export interface TransferTokenOptions {
|
|
|
129
129
|
callbackUrl?: string | null
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
/**
|
|
133
|
+
* One destination of a multi-recipient transfer (see KnishIOClient.transferTokens).
|
|
134
|
+
* Provide EITHER units (stackable/NFT: amount = units.length) OR amount (fungible), not both.
|
|
135
|
+
* batchId makes the recipient a claimable shadow under that batch.
|
|
136
|
+
*/
|
|
137
|
+
export interface TransferRecipientInput {
|
|
138
|
+
bundleHash: BundleHash | string
|
|
139
|
+
units?: string[]
|
|
140
|
+
amount?: number | null
|
|
141
|
+
batchId?: string | null
|
|
142
|
+
}
|
|
143
|
+
|
|
132
144
|
export interface RequestTokensOptions {
|
|
133
145
|
to: WalletAddress | string
|
|
134
146
|
amount: number | string
|
|
@@ -269,16 +281,6 @@ export interface ActiveSessionOptions {
|
|
|
269
281
|
metaId?: MetaId | string | null
|
|
270
282
|
}
|
|
271
283
|
|
|
272
|
-
export interface UserActivityOptions {
|
|
273
|
-
bundleHash?: BundleHash | string | null
|
|
274
|
-
metaType?: MetaType | string | null
|
|
275
|
-
metaId?: MetaId | string | null
|
|
276
|
-
dateFrom?: string | null
|
|
277
|
-
dateTo?: string | null
|
|
278
|
-
limit?: number | null
|
|
279
|
-
offset?: number | null
|
|
280
|
-
}
|
|
281
|
-
|
|
282
284
|
export interface PolicyQueryOptions {
|
|
283
285
|
metaType?: MetaType | string | null
|
|
284
286
|
metaId?: MetaId | string | null
|
|
@@ -478,15 +480,6 @@ export interface ResponseQueryActiveSession extends BaseResponse<{
|
|
|
478
480
|
expiresAt: string
|
|
479
481
|
}> {}
|
|
480
482
|
|
|
481
|
-
export interface ResponseQueryUserActivity extends BaseResponse<{
|
|
482
|
-
activities: Array<{
|
|
483
|
-
type: string
|
|
484
|
-
description: string
|
|
485
|
-
data: Record<string, unknown>
|
|
486
|
-
createdAt: string
|
|
487
|
-
}>
|
|
488
|
-
}> {}
|
|
489
|
-
|
|
490
483
|
export interface ResponsePolicy extends BaseResponse<{
|
|
491
484
|
policy: Record<string, unknown>
|
|
492
485
|
metaType: MetaType | null
|
package/src/types/guards.ts
CHANGED
|
@@ -239,7 +239,7 @@ export function isKnishIOErrorType(value: unknown): value is KnishIOErrorType {
|
|
|
239
239
|
'WRONG_TOKEN_TYPE_ERROR'
|
|
240
240
|
] as const
|
|
241
241
|
|
|
242
|
-
return typeof value === 'string' && errorTypes.includes(value
|
|
242
|
+
return typeof value === 'string' && (errorTypes as readonly string[]).includes(value)
|
|
243
243
|
}
|
|
244
244
|
|
|
245
245
|
/**
|
|
@@ -282,8 +282,7 @@ export function isQueryType(value: unknown): value is QueryType {
|
|
|
282
282
|
'Batch',
|
|
283
283
|
'ActiveSession',
|
|
284
284
|
'Policy',
|
|
285
|
-
'Token'
|
|
286
|
-
'UserActivity'
|
|
285
|
+
'Token'
|
|
287
286
|
] as const
|
|
288
287
|
|
|
289
288
|
return typeof value === 'string' && queryTypes.includes(value as QueryType)
|
package/src/types/index.ts
CHANGED
|
@@ -371,6 +371,12 @@ export interface SignatureResult {
|
|
|
371
371
|
// GRAPHQL OPERATION TYPES
|
|
372
372
|
// =============================================================================
|
|
373
373
|
|
|
374
|
+
/**
|
|
375
|
+
* urql request policy (mirrors @urql/core's RequestPolicy). Controls whether a
|
|
376
|
+
* read hits the client's in-memory cache. 'network-only' bypasses it entirely.
|
|
377
|
+
*/
|
|
378
|
+
export type RequestPolicy = 'cache-first' | 'cache-only' | 'network-only' | 'cache-and-network'
|
|
379
|
+
|
|
374
380
|
export interface GraphQLRequest {
|
|
375
381
|
query: string
|
|
376
382
|
variables?: Record<string, unknown>
|
|
@@ -61,8 +61,6 @@ License: https://github.com/WishKnish/KnishIO-Client-TS/blob/master/LICENSE
|
|
|
61
61
|
* - Performance optimization hints
|
|
62
62
|
*/
|
|
63
63
|
|
|
64
|
-
import { z } from 'zod'
|
|
65
|
-
import type { ValidationResult } from './ValidationService'
|
|
66
64
|
|
|
67
65
|
// =============================================================================
|
|
68
66
|
// UNIVERSAL CONFIGURATION TYPES
|
|
@@ -227,16 +225,16 @@ export class ConfigValidator {
|
|
|
227
225
|
|
|
228
226
|
// Enhanced validations
|
|
229
227
|
if (options.includeWarnings !== false) {
|
|
230
|
-
result.warnings.push(...this.generateWarnings(result.data))
|
|
228
|
+
result.warnings.push(...this.generateWarnings(result.data!))
|
|
231
229
|
}
|
|
232
230
|
|
|
233
231
|
if (options.includeRecommendations !== false) {
|
|
234
|
-
result.recommendations.push(...this.generateRecommendations(result.data
|
|
232
|
+
result.recommendations.push(...this.generateRecommendations(result.data!, options))
|
|
235
233
|
}
|
|
236
234
|
|
|
237
235
|
// Performance validation
|
|
238
236
|
if (options.includePerformanceHints !== false) {
|
|
239
|
-
result.warnings.push(...this.generatePerformanceWarnings(result.data))
|
|
237
|
+
result.warnings.push(...this.generatePerformanceWarnings(result.data!))
|
|
240
238
|
}
|
|
241
239
|
|
|
242
240
|
} catch (error) {
|
|
@@ -57,20 +57,9 @@ License: https://github.com/WishKnish/KnishIO-Client-TS/blob/master/LICENSE
|
|
|
57
57
|
*/
|
|
58
58
|
|
|
59
59
|
import { z } from 'zod'
|
|
60
|
-
import type {
|
|
61
|
-
KnishIOClientConfig,
|
|
62
|
-
TransferParams,
|
|
63
|
-
CreateTokenParams,
|
|
64
|
-
RequestTokensParams,
|
|
65
|
-
BalanceQueryParams,
|
|
66
|
-
MetaQueryParams,
|
|
67
|
-
WalletQueryParams
|
|
68
|
-
} from '@/types'
|
|
69
60
|
import {
|
|
70
61
|
Schemas,
|
|
71
62
|
safeParse,
|
|
72
|
-
validateStrict,
|
|
73
|
-
validateWithDefaults,
|
|
74
63
|
createTypeGuard,
|
|
75
64
|
type ValidatedClientConfig,
|
|
76
65
|
type ValidatedTransferParams,
|
|
@@ -164,8 +153,8 @@ export class ValidationService {
|
|
|
164
153
|
this.logValidation('ClientConfig', true)
|
|
165
154
|
return {
|
|
166
155
|
success: true,
|
|
167
|
-
data: parseResult.data,
|
|
168
|
-
warnings: this.generateConfigWarnings(parseResult.data)
|
|
156
|
+
data: parseResult.data as ValidatedClientConfig,
|
|
157
|
+
warnings: this.generateConfigWarnings(parseResult.data as ValidatedClientConfig)
|
|
169
158
|
}
|
|
170
159
|
} catch (error) {
|
|
171
160
|
this.logValidation('ClientConfig', false, String(error))
|
|
@@ -193,7 +182,9 @@ export class ValidationService {
|
|
|
193
182
|
KNISHIO_SERVER_SDK_VERSION: process.env.KNISHIO_SERVER_SDK_VERSION
|
|
194
183
|
}
|
|
195
184
|
|
|
196
|
-
|
|
185
|
+
// cast: EnvironmentConfig uses .default()/.optional() so its inferred input≠output type and
|
|
186
|
+
// doesn't structurally match safeParse's ZodType<T> param; ZodTypeAny sidesteps the mismatch.
|
|
187
|
+
const parseResult = safeParse(Schemas.EnvironmentConfig as z.ZodTypeAny, env)
|
|
197
188
|
|
|
198
189
|
if (!parseResult.success) {
|
|
199
190
|
return {
|
|
@@ -320,7 +311,7 @@ export class ValidationService {
|
|
|
320
311
|
received: 'error',
|
|
321
312
|
path: [],
|
|
322
313
|
message: err.message
|
|
323
|
-
} as z.ZodIssue)),
|
|
314
|
+
} as unknown as z.ZodIssue)),
|
|
324
315
|
context: 'GraphQLResponse'
|
|
325
316
|
}
|
|
326
317
|
}
|
|
@@ -206,7 +206,11 @@ export const KnishIOClientConfigSchema = z.object({
|
|
|
206
206
|
client: z.unknown().optional(),
|
|
207
207
|
socket: z.unknown().optional(),
|
|
208
208
|
serverSdkVersion: z.number().int().min(1).max(10).default(4),
|
|
209
|
-
logging: z.boolean().default(false)
|
|
209
|
+
logging: z.boolean().default(false),
|
|
210
|
+
// Optional default urql request policy for reads (server/sync clients pass
|
|
211
|
+
// 'network-only'). Permitted by the strict schema so the constructor option
|
|
212
|
+
// isn't rejected.
|
|
213
|
+
defaultRequestPolicy: z.enum(['cache-first', 'cache-only', 'network-only', 'cache-and-network']).nullable().optional()
|
|
210
214
|
}).strict()
|
|
211
215
|
|
|
212
216
|
// Environment configuration with validation
|
package/src/versions/HashAtom.ts
CHANGED
|
@@ -49,17 +49,19 @@ License: https://github.com/WishKnish/KnishIO-Client-TS/blob/master/LICENSE
|
|
|
49
49
|
import type Atom from '@/core/Atom'
|
|
50
50
|
|
|
51
51
|
// Define structured value types for better type safety
|
|
52
|
-
type StructuredValue =
|
|
53
|
-
| string
|
|
54
|
-
| number
|
|
55
|
-
| boolean
|
|
56
|
-
| null
|
|
52
|
+
type StructuredValue =
|
|
53
|
+
| string
|
|
54
|
+
| number
|
|
55
|
+
| boolean
|
|
56
|
+
| null
|
|
57
57
|
| undefined
|
|
58
58
|
| StructuredObject
|
|
59
59
|
| StructuredArray
|
|
60
60
|
|
|
61
|
-
type
|
|
62
|
-
type
|
|
61
|
+
// interfaces (not type aliases) so the recursion goes alias->interface->alias, which TS permits
|
|
62
|
+
// (an all-type-alias cycle triggers TS2456 "circularly references itself").
|
|
63
|
+
interface StructuredObject { [key: string]: StructuredValue }
|
|
64
|
+
interface StructuredArray extends Array<StructuredValue> {}
|
|
63
65
|
|
|
64
66
|
// Define types for hashable values
|
|
65
67
|
type HashableValue =
|
|
@@ -95,7 +97,7 @@ export default class HashAtom {
|
|
|
95
97
|
// Extract atom properties with type safety
|
|
96
98
|
for (const key of Object.keys(atom)) {
|
|
97
99
|
if (Object.prototype.hasOwnProperty.call(atom, key)) {
|
|
98
|
-
parameters[key] = (atom as Record<string, unknown>)[key]
|
|
100
|
+
parameters[key] = (atom as unknown as Record<string, unknown>)[key]
|
|
99
101
|
}
|
|
100
102
|
}
|
|
101
103
|
|
|
@@ -113,7 +115,7 @@ export default class HashAtom {
|
|
|
113
115
|
|
|
114
116
|
if (isArray(object)) {
|
|
115
117
|
const result: StructuredArray = []
|
|
116
|
-
for (const value of object) {
|
|
118
|
+
for (const value of (object as unknown[])) {
|
|
117
119
|
result.push(HashAtom.isStructure(value) ? HashAtom.structure(value) : value as StructuredValue)
|
|
118
120
|
}
|
|
119
121
|
return result
|