@wishknish/knishio-client-js 0.7.4 → 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.
@@ -0,0 +1,223 @@
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-JS for information.
45
+
46
+ License: https://github.com/WishKnish/KnishIO-Client-JS/blob/master/LICENSE
47
+ */
48
+ import Query from './Query.js'
49
+ import ResponseMetaTypeViaMolecule from '../response/ResponseMetaTypeViaMolecule.js'
50
+ import { gql } from '@urql/core'
51
+
52
+ /**
53
+ * Query for retrieving Meta Asset information via Molecule data.
54
+ *
55
+ * Unlike QueryMetaTypeViaAtom, this query does NOT request the redundant
56
+ * instance-level `metas` field. Instead, metadata is extracted client-side
57
+ * from molecule atoms' `metasJson`, eliminating duplicate data transfer.
58
+ */
59
+ export default class QueryMetaTypeViaMolecule extends Query {
60
+ /**
61
+ * @param {UrqlClientWrapper} graphQLClient
62
+ * @param {KnishIOClient} knishIOClient
63
+ */
64
+ constructor (graphQLClient, knishIOClient) {
65
+ super(graphQLClient, knishIOClient)
66
+
67
+ this.$__query = gql`query ($metaTypes: [String!], $metaIds: [String!], $values: [String!], $keys: [String!], $latest: Boolean, $filter: [MetaFilter!], $queryArgs: QueryArgs, $countBy: String, $atomValues: [String!], $cellSlugs: [String!] ) {
68
+ MetaTypeViaAtom(
69
+ metaTypes: $metaTypes
70
+ metaIds: $metaIds
71
+ atomValues: $atomValues
72
+ cellSlugs: $cellSlugs
73
+ filter: $filter,
74
+ latest: $latest,
75
+ queryArgs: $queryArgs
76
+ countBy: $countBy
77
+ ) {
78
+ metaType,
79
+ instanceCount {
80
+ key,
81
+ value
82
+ },
83
+ instances {
84
+ metaType,
85
+ metaId,
86
+ createdAt,
87
+ metas( values: $values, keys: $keys ) {
88
+ molecularHash,
89
+ position,
90
+ key,
91
+ value,
92
+ createdAt
93
+ },
94
+ molecule {
95
+ molecularHash,
96
+ bundleHash,
97
+ cellSlug,
98
+ status,
99
+ createdAt,
100
+ atoms {
101
+ position,
102
+ walletAddress,
103
+ isotope,
104
+ tokenSlug,
105
+ value,
106
+ batchId,
107
+ metaType,
108
+ metaId,
109
+ index,
110
+ createdAt,
111
+ otsFragment,
112
+ metasJson
113
+ }
114
+ }
115
+ },
116
+ paginatorInfo {
117
+ currentPage,
118
+ total
119
+ }
120
+ }
121
+ }`
122
+ }
123
+
124
+ /**
125
+ * Builds a GraphQL-friendly variables object based on input fields
126
+ *
127
+ * @param {string|array|null} metaType
128
+ * @param {string|array|null} metaId
129
+ * @param {string|null} key
130
+ * @param {string|null} value
131
+ * @param {array|null} values
132
+ * @param {array|null} keys
133
+ * @param {array|null} atomValues
134
+ * @param {boolean|null} latest
135
+ * @param {array|null} filter
136
+ * @param {object|null} queryArgs
137
+ * @param {string|null} countBy
138
+ * @param {string|null} cellSlug
139
+ * @return {{}}
140
+ */
141
+ static createVariables ({
142
+ metaType = null,
143
+ metaId = null,
144
+ key = null,
145
+ value = null,
146
+ keys = null,
147
+ values = null,
148
+ atomValues = null,
149
+ latest = null,
150
+ filter = null,
151
+ queryArgs = null,
152
+ countBy = null,
153
+ cellSlug = null
154
+ }) {
155
+ const variables = {}
156
+
157
+ if (atomValues) {
158
+ variables.atomValues = atomValues
159
+ }
160
+
161
+ if (keys) {
162
+ variables.keys = keys
163
+ }
164
+
165
+ if (values) {
166
+ variables.values = values
167
+ }
168
+
169
+ if (metaType) {
170
+ variables.metaTypes = typeof metaType === 'string' ? [metaType] : metaType
171
+ }
172
+
173
+ if (metaId) {
174
+ variables.metaIds = typeof metaId === 'string' ? [metaId] : metaId
175
+ }
176
+
177
+ if (cellSlug) {
178
+ variables.cellSlugs = typeof cellSlug === 'string' ? [cellSlug] : cellSlug
179
+ }
180
+
181
+ if (countBy) {
182
+ variables.countBy = countBy
183
+ }
184
+
185
+ if (filter) {
186
+ variables.filter = filter
187
+ }
188
+
189
+ if (key && value) {
190
+ variables.filter = variables.filter || []
191
+ variables.filter.push({
192
+ key,
193
+ value,
194
+ comparison: '='
195
+ })
196
+ }
197
+
198
+ variables.latest = latest === true
199
+
200
+ if (queryArgs) {
201
+ if (typeof queryArgs.limit === 'undefined' || queryArgs.limit === 0) {
202
+ queryArgs.limit = '*'
203
+ }
204
+
205
+ variables.queryArgs = queryArgs
206
+ }
207
+
208
+ return variables
209
+ }
210
+
211
+ /**
212
+ * Returns a Response object
213
+ *
214
+ * @param {object} json
215
+ * @return {ResponseMetaTypeViaMolecule}
216
+ */
217
+ createResponse (json) {
218
+ return new ResponseMetaTypeViaMolecule({
219
+ query: this,
220
+ json
221
+ })
222
+ }
223
+ }
@@ -60,8 +60,8 @@ export default class QueryWalletList extends Query {
60
60
  constructor (graphQLClient, knishIOClient) {
61
61
  super(graphQLClient, knishIOClient)
62
62
 
63
- this.$__query = gql`query( $bundleHash: String, $tokenSlug: String ) {
64
- Wallet( bundleHash: $bundleHash, tokenSlug: $tokenSlug ) {
63
+ this.$__query = gql`query( $bundleHash: String, $token: String ) {
64
+ Wallet( bundleHash: $bundleHash, token: $token ) {
65
65
  address,
66
66
  bundleHash,
67
67
  token {
@@ -91,7 +91,7 @@ export default class ResponseContinuId extends Response {
91
91
  wallet.batchId = continuId.batchId
92
92
  wallet.characters = continuId.characters
93
93
  wallet.pubkey = continuId.pubkey
94
- wallet.balance = continuId.amount * 1.0
94
+ wallet.balance = String(continuId.amount != null ? continuId.amount : 0)
95
95
  }
96
96
 
97
97
  return wallet
@@ -0,0 +1,210 @@
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-JS for information.
45
+
46
+ License: https://github.com/WishKnish/KnishIO-Client-JS/blob/master/LICENSE
47
+ */
48
+
49
+ import Query from '../query/Query.js'
50
+ import Response from './Response.js'
51
+ import CheckMolecule from '../libraries/CheckMolecule.js'
52
+
53
+ /**
54
+ * Response for MetaType queries via Molecule data.
55
+ *
56
+ * Instead of using the redundant instance-level `metas` field,
57
+ * this response extracts metadata from molecule atoms' `metasJson`,
58
+ * producing a payload format compatible with ResponseMetaType and
59
+ * ResponseMetaTypeViaAtom for drop-in replacement usage.
60
+ */
61
+ export default class ResponseMetaTypeViaMolecule extends Response {
62
+ /**
63
+ * Class constructor
64
+ *
65
+ * @param {Query} query
66
+ * @param {object} json
67
+ */
68
+ constructor ({
69
+ query,
70
+ json
71
+ }) {
72
+ super({
73
+ query,
74
+ json,
75
+ dataKey: 'data.MetaTypeViaAtom'
76
+ })
77
+ }
78
+
79
+ /**
80
+ * Extracts metas from a molecule's atoms' metasJson for a specific instance.
81
+ * Filters atoms by matching metaType and metaId, then parses metasJson.
82
+ *
83
+ * @param {object} molecule - Molecule data with atoms array
84
+ * @param {string} metaType - Instance meta type to filter by
85
+ * @param {string} metaId - Instance meta ID to filter by
86
+ * @return {Array<{molecularHash: string, position: string, key: string, value: string, createdAt: string}>}
87
+ */
88
+ static extractMetasFromMolecule (molecule, metaType, metaId) {
89
+ if (!molecule || !molecule.atoms) {
90
+ return []
91
+ }
92
+
93
+ const metas = []
94
+
95
+ for (const atom of molecule.atoms) {
96
+ // Filter atoms to those matching this instance's metaType and metaId
97
+ if (atom.metaType !== metaType || atom.metaId !== metaId) {
98
+ continue
99
+ }
100
+
101
+ if (!atom.metasJson) {
102
+ continue
103
+ }
104
+
105
+ let parsed
106
+ try {
107
+ parsed = JSON.parse(atom.metasJson)
108
+ if (!Array.isArray(parsed)) {
109
+ continue
110
+ }
111
+ } catch (e) {
112
+ continue
113
+ }
114
+
115
+ for (const entry of parsed) {
116
+ metas.push({
117
+ molecularHash: molecule.molecularHash,
118
+ position: atom.position,
119
+ key: entry.key,
120
+ value: entry.value,
121
+ createdAt: atom.createdAt
122
+ })
123
+ }
124
+ }
125
+
126
+ return metas
127
+ }
128
+
129
+ /**
130
+ * Returns meta type instance results with metas synthesized from molecule data.
131
+ * Produces the same payload format as ResponseMetaType and ResponseMetaTypeViaAtom:
132
+ * { instances, instanceCount, paginatorInfo }
133
+ *
134
+ * @return {null|{instances: Array, instanceCount: Array, paginatorInfo: object}}
135
+ */
136
+ payload () {
137
+ const metaTypeData = this.data()
138
+
139
+ if (!metaTypeData || metaTypeData.length === 0) {
140
+ return null
141
+ }
142
+
143
+ const response = {
144
+ instances: {},
145
+ instanceCount: {},
146
+ paginatorInfo: {}
147
+ }
148
+
149
+ const metaData = metaTypeData.pop()
150
+
151
+ if (metaData.instances) {
152
+ response.instances = metaData.instances.map(instance => {
153
+ // Prefer server-filtered metas (from metas sub-field) when available
154
+ let metas = instance.metas
155
+ if (!metas || metas.length === 0) {
156
+ // Fallback: synthesize from molecule atoms' metasJson
157
+ metas = ResponseMetaTypeViaMolecule.extractMetasFromMolecule(
158
+ instance.molecule,
159
+ instance.metaType,
160
+ instance.metaId
161
+ )
162
+ }
163
+
164
+ return {
165
+ ...instance,
166
+ metas
167
+ }
168
+ })
169
+ }
170
+
171
+ if (metaData.instanceCount) {
172
+ response.instanceCount = metaData.instanceCount
173
+ }
174
+
175
+ if (metaData.paginatorInfo) {
176
+ response.paginatorInfo = metaData.paginatorInfo
177
+ }
178
+
179
+ return response
180
+ }
181
+
182
+ /**
183
+ * Verifies the cryptographic integrity of all molecules associated
184
+ * with meta instances in this response. For each instance, reconstructs
185
+ * the molecule from server data and runs CheckMolecule.verify() to validate
186
+ * the molecular hash and OTS signature.
187
+ *
188
+ * @return {{ verified: boolean, molecules: Array<{ molecularHash: string, verified: boolean, error: string|null }> }}
189
+ */
190
+ verifyIntegrity () {
191
+ const results = []
192
+ const metaTypeData = this.data()
193
+
194
+ if (!metaTypeData || metaTypeData.length === 0) {
195
+ return { verified: true, molecules: results }
196
+ }
197
+
198
+ const instances = metaTypeData[metaTypeData.length - 1]?.instances || []
199
+
200
+ for (const instance of instances) {
201
+ if (!instance.molecule) continue
202
+ results.push(CheckMolecule.verifyFromServerData(instance.molecule))
203
+ }
204
+
205
+ return {
206
+ verified: results.length === 0 || results.every(r => r.verified),
207
+ molecules: results
208
+ }
209
+ }
210
+ }
@@ -76,7 +76,7 @@ export default class ResponseRequestAuthorization extends ResponseProposeMolecul
76
76
  }
77
77
 
78
78
  /**
79
- * Returns timestamp
79
+ * Returns raw time value from payload
80
80
  *
81
81
  * @return {string}
82
82
  */
@@ -84,6 +84,39 @@ export default class ResponseRequestAuthorization extends ResponseProposeMolecul
84
84
  return this.payloadKey('time')
85
85
  }
86
86
 
87
+ /**
88
+ * Returns the expiration timestamp as Unix seconds.
89
+ * Handles both server formats:
90
+ * - PHP server: time = lifetime in ms, expiresAt = Unix timestamp in payload
91
+ * - Rust server: time = Unix timestamp in seconds
92
+ *
93
+ * @return {number}
94
+ */
95
+ expiresAt () {
96
+ // Try the explicit expiresAt payload key first (PHP server provides this)
97
+ try {
98
+ const ea = this.payloadKey('expiresAt')
99
+ if (ea) {
100
+ return Number(ea)
101
+ }
102
+ } catch (_e) {
103
+ // Not available in payload, fall back
104
+ }
105
+
106
+ // Use time field with heuristic detection
107
+ const timeValue = Number(this.time())
108
+
109
+ // If timeValue looks like a valid Unix timestamp (>= year 2020), use directly
110
+ // Rust server sets time = Unix timestamp in seconds
111
+ if (timeValue >= 1577836800) {
112
+ return timeValue
113
+ }
114
+
115
+ // Otherwise, time is a lifetime in milliseconds (PHP server format)
116
+ // Convert to Unix timestamp: now_seconds + lifetime_seconds
117
+ return Math.floor(Date.now() / 1000) + Math.floor(timeValue / 1000)
118
+ }
119
+
87
120
  /**
88
121
  *
89
122
  * @return {string}
@@ -120,7 +120,7 @@ export default class ResponseRequestAuthorizationGuest extends Response {
120
120
  }
121
121
 
122
122
  /**
123
- * Returns timestamp
123
+ * Returns raw time value from payload
124
124
  *
125
125
  * @return {*}
126
126
  */
@@ -128,6 +128,37 @@ export default class ResponseRequestAuthorizationGuest extends Response {
128
128
  return this.payloadKey('time')
129
129
  }
130
130
 
131
+ /**
132
+ * Returns the expiration timestamp as Unix seconds.
133
+ * Handles both server formats:
134
+ * - PHP server: time = lifetime in ms, expiresAt = Unix timestamp in payload
135
+ * - Rust server: time = Unix timestamp in seconds
136
+ *
137
+ * @return {number}
138
+ */
139
+ expiresAt () {
140
+ // Try the explicit expiresAt payload key first (PHP server provides this)
141
+ try {
142
+ const ea = this.payloadKey('expiresAt')
143
+ if (ea) {
144
+ return Number(ea)
145
+ }
146
+ } catch (_e) {
147
+ // Not available in payload, fall back
148
+ }
149
+
150
+ // Use time field with heuristic detection
151
+ const timeValue = Number(this.time())
152
+
153
+ // If timeValue looks like a valid Unix timestamp (>= year 2020), use directly
154
+ if (timeValue >= 1577836800) {
155
+ return timeValue
156
+ }
157
+
158
+ // Otherwise, time is a lifetime in milliseconds (PHP server format)
159
+ return Math.floor(Date.now() / 1000) + Math.floor(timeValue / 1000)
160
+ }
161
+
131
162
  /**
132
163
  * Returns timestamp
133
164
  *
@@ -122,7 +122,7 @@ export default class ResponseWalletList extends Response {
122
122
  }
123
123
  }
124
124
 
125
- wallet.balance = Number(data.amount)
125
+ wallet.balance = String(data.amount != null ? data.amount : 0)
126
126
  wallet.pubkey = data.pubkey
127
127
  wallet.createdAt = data.createdAt
128
128