@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.
Files changed (51) hide show
  1. package/dist/index.cjs +2819 -1186
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +378 -142
  4. package/dist/index.d.ts +378 -142
  5. package/dist/index.iife.js +22799 -20747
  6. package/dist/index.iife.js.map +1 -1
  7. package/dist/index.js +2817 -1185
  8. package/dist/index.js.map +1 -1
  9. package/package.json +12 -6
  10. package/src/AuthToken.ts +8 -2
  11. package/src/KnishIOClient.ts +367 -118
  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 +582 -140
  17. package/src/core/Wallet.ts +19 -24
  18. package/src/index.ts +9 -10
  19. package/src/instance/rules/Rule.ts +128 -19
  20. package/src/libraries/CheckMolecule.ts +88 -1
  21. package/src/libraries/GraphQLClient.ts +17 -22
  22. package/src/libraries/crypto.ts +14 -30
  23. package/src/libraries/strings.ts +26 -25
  24. package/src/mutation/MutationAppendRequest.ts +52 -0
  25. package/src/mutation/MutationCreateRule.ts +2 -2
  26. package/src/mutation/MutationPeering.ts +37 -0
  27. package/src/mutation/MutationRequestAuthorization.ts +3 -3
  28. package/src/query/Query.ts +6 -6
  29. package/src/query/QueryActiveSession.ts +0 -1
  30. package/src/query/QueryAtom.ts +27 -27
  31. package/src/query/QueryContinuId.ts +8 -0
  32. package/src/query/QueryMetaType.ts +1 -1
  33. package/src/query/QueryMetaTypeViaMolecule.ts +221 -0
  34. package/src/query/QueryWalletList.ts +2 -2
  35. package/src/response/Response.ts +17 -1
  36. package/src/response/ResponseAppendRequest.ts +17 -0
  37. package/src/response/ResponseBalance.ts +8 -3
  38. package/src/response/ResponseContinuId.ts +1 -1
  39. package/src/response/ResponseMetaType.ts +32 -19
  40. package/src/response/ResponseMetaTypeViaMolecule.ts +224 -0
  41. package/src/response/ResponsePeering.ts +17 -0
  42. package/src/response/ResponsePolicy.ts +2 -3
  43. package/src/response/ResponseProposeMolecule.ts +0 -1
  44. package/src/response/ResponseRequestAuthorization.ts +32 -2
  45. package/src/response/ResponseRequestAuthorizationGuest.ts +25 -1
  46. package/src/response/ResponseWalletList.ts +1 -1
  47. package/src/schemas/index.ts +12 -1
  48. package/src/types/client.ts +3 -2
  49. package/src/types/graphql.ts +3 -2
  50. package/src/types/guards.ts +18 -5
  51. package/src/types/index.ts +19 -4
@@ -0,0 +1,224 @@
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 type Query from '../query/Query'
50
+ import Response from './Response'
51
+ import CheckMolecule from '../libraries/CheckMolecule'
52
+
53
+ /**
54
+ * Response for MetaType queries via Molecule data.
55
+ *
56
+ * Instead of relying solely on the instance-level `metas` field,
57
+ * this response can extract metadata from molecule atoms' `metasJson`,
58
+ * and provides cryptographic integrity verification via `verifyIntegrity()`.
59
+ */
60
+ export default class ResponseMetaTypeViaMolecule extends Response {
61
+ /**
62
+ * Class constructor
63
+ */
64
+ constructor({
65
+ query,
66
+ json
67
+ }: {
68
+ query: Query
69
+ json: any
70
+ }) {
71
+ super({
72
+ query,
73
+ json,
74
+ dataKey: 'data.MetaTypeViaAtom'
75
+ })
76
+ }
77
+
78
+ /**
79
+ * Extracts metas from a molecule's atoms' metasJson for a specific instance.
80
+ * Filters atoms by matching metaType and metaId, then parses metasJson.
81
+ */
82
+ static extractMetasFromMolecule(
83
+ molecule: any,
84
+ metaType: string,
85
+ metaId: string
86
+ ): Array<{
87
+ molecularHash: string
88
+ position: string
89
+ key: string
90
+ value: string
91
+ createdAt: string
92
+ }> {
93
+ if (!molecule || !molecule.atoms) {
94
+ return []
95
+ }
96
+
97
+ const metas: Array<{
98
+ molecularHash: string
99
+ position: string
100
+ key: string
101
+ value: string
102
+ createdAt: string
103
+ }> = []
104
+
105
+ for (const atom of molecule.atoms) {
106
+ if (atom.metaType !== metaType || atom.metaId !== metaId) {
107
+ continue
108
+ }
109
+
110
+ if (!atom.metasJson) {
111
+ continue
112
+ }
113
+
114
+ let parsed: any
115
+ try {
116
+ parsed = JSON.parse(atom.metasJson)
117
+ if (!Array.isArray(parsed)) {
118
+ continue
119
+ }
120
+ } catch (e) {
121
+ continue
122
+ }
123
+
124
+ for (const entry of parsed) {
125
+ metas.push({
126
+ molecularHash: molecule.molecularHash,
127
+ position: atom.position,
128
+ key: entry.key,
129
+ value: entry.value,
130
+ createdAt: atom.createdAt
131
+ })
132
+ }
133
+ }
134
+
135
+ return metas
136
+ }
137
+
138
+ /**
139
+ * Returns meta type instance results with metas synthesized from molecule data.
140
+ * Produces the same payload format as ResponseMetaType and ResponseMetaTypeViaAtom:
141
+ * { instances, instanceCount, paginatorInfo }
142
+ */
143
+ override payload(): any | null {
144
+ const metaTypeData = this.data()
145
+
146
+ if (!metaTypeData || metaTypeData.length === 0) {
147
+ return null
148
+ }
149
+
150
+ const response: any = {
151
+ instances: {},
152
+ instanceCount: {},
153
+ paginatorInfo: {}
154
+ }
155
+
156
+ const metaData = metaTypeData.pop()
157
+
158
+ if (metaData.instances) {
159
+ response.instances = metaData.instances.map((instance: any) => {
160
+ // Prefer server-filtered metas when available
161
+ let metas = instance.metas
162
+ if (!metas || metas.length === 0) {
163
+ // Fallback: synthesize from molecule atoms' metasJson
164
+ metas = ResponseMetaTypeViaMolecule.extractMetasFromMolecule(
165
+ instance.molecule,
166
+ instance.metaType,
167
+ instance.metaId
168
+ )
169
+ }
170
+
171
+ return {
172
+ ...instance,
173
+ metas
174
+ }
175
+ })
176
+ }
177
+
178
+ if (metaData.instanceCount) {
179
+ response.instanceCount = metaData.instanceCount
180
+ }
181
+
182
+ if (metaData.paginatorInfo) {
183
+ response.paginatorInfo = metaData.paginatorInfo
184
+ }
185
+
186
+ return response
187
+ }
188
+
189
+ /**
190
+ * Verifies the cryptographic integrity of all molecules associated
191
+ * with meta instances in this response.
192
+ */
193
+ verifyIntegrity(): {
194
+ verified: boolean
195
+ molecules: Array<{
196
+ molecularHash: string | null
197
+ verified: boolean
198
+ error: string | null
199
+ }>
200
+ } {
201
+ const results: Array<{
202
+ molecularHash: string | null
203
+ verified: boolean
204
+ error: string | null
205
+ }> = []
206
+ const metaTypeData = this.data()
207
+
208
+ if (!metaTypeData || metaTypeData.length === 0) {
209
+ return { verified: true, molecules: results }
210
+ }
211
+
212
+ const instances = metaTypeData[metaTypeData.length - 1]?.instances || []
213
+
214
+ for (const instance of instances) {
215
+ if (!instance.molecule) continue
216
+ results.push(CheckMolecule.verifyFromServerData(instance.molecule))
217
+ }
218
+
219
+ return {
220
+ verified: results.length === 0 || results.every((r: any) => r.verified),
221
+ molecules: results
222
+ }
223
+ }
224
+ }
@@ -0,0 +1,17 @@
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 ResponseProposeMolecule from './ResponseProposeMolecule'
10
+
11
+ /**
12
+ * Response for peer registration via P-isotope
13
+ * Matches JavaScript SDK ResponsePeering implementation exactly
14
+ */
15
+ export default class ResponsePeering extends ResponseProposeMolecule {
16
+
17
+ }
@@ -65,10 +65,9 @@ export default class ResponsePolicy extends Response {
65
65
  }) {
66
66
  super({
67
67
  query,
68
- json
68
+ json,
69
+ dataKey: 'data.Policy'
69
70
  })
70
- this.dataKey = 'data.Policy'
71
- this.init()
72
71
  }
73
72
 
74
73
  /**
@@ -74,7 +74,6 @@ export default class ResponseProposeMolecule extends Response {
74
74
  dataKey: 'data.ProposeMolecule'
75
75
  })
76
76
  this.$__clientMolecule = (query as any).molecule()
77
- this.init()
78
77
  }
79
78
 
80
79
  /**
@@ -75,13 +75,43 @@ export default class ResponseRequestAuthorization extends ResponseProposeMolecul
75
75
  }
76
76
 
77
77
  /**
78
- * Returns timestamp
79
- * Matches JavaScript SDK time method exactly
78
+ * Returns raw time value from payload
80
79
  */
81
80
  time(): string {
82
81
  return this.payloadKey('time')
83
82
  }
84
83
 
84
+ /**
85
+ * Returns the expiration timestamp as Unix seconds.
86
+ * Handles both server formats:
87
+ * - PHP server: time = lifetime in ms, expiresAt = Unix timestamp in payload
88
+ * - Rust server: time = Unix timestamp in seconds
89
+ */
90
+ expiresAt(): number {
91
+ // Try the explicit expiresAt payload key first (PHP server provides this)
92
+ try {
93
+ const ea = this.payloadKey('expiresAt')
94
+ if (ea) {
95
+ return Number(ea)
96
+ }
97
+ } catch (_e) {
98
+ // Not available in payload, fall back
99
+ }
100
+
101
+ // Use time field with heuristic detection
102
+ const timeValue = Number(this.time())
103
+
104
+ // If timeValue looks like a valid Unix timestamp (>= year 2020), use directly
105
+ // Rust server sets time = Unix timestamp in seconds
106
+ if (timeValue >= 1577836800) {
107
+ return timeValue
108
+ }
109
+
110
+ // Otherwise, time is a lifetime in milliseconds (PHP server format)
111
+ // Convert to Unix timestamp: now_seconds + lifetime_seconds
112
+ return Math.floor(Date.now() / 1000) + Math.floor(timeValue / 1000)
113
+ }
114
+
85
115
  /**
86
116
  * Returns encryption info
87
117
  * Matches JavaScript SDK encrypt method exactly
@@ -111,12 +111,36 @@ export default class ResponseRequestAuthorizationGuest extends Response {
111
111
  }
112
112
 
113
113
  /**
114
- * Returns timestamp
114
+ * Returns raw time value from payload
115
115
  */
116
116
  time(): any {
117
117
  return this.payloadKey('time')
118
118
  }
119
119
 
120
+ /**
121
+ * Returns the expiration timestamp as Unix seconds.
122
+ * Handles both server formats:
123
+ * - PHP server: time = lifetime in ms, expiresAt = Unix timestamp in payload
124
+ * - Rust server: time = Unix timestamp in seconds
125
+ */
126
+ expiresAt(): number {
127
+ try {
128
+ const ea = this.payloadKey('expiresAt')
129
+ if (ea) {
130
+ return Number(ea)
131
+ }
132
+ } catch (_e) {
133
+ // Not available in payload, fall back
134
+ }
135
+
136
+ const timeValue = Number(this.time())
137
+ if (timeValue >= 1577836800) {
138
+ return timeValue
139
+ }
140
+
141
+ return Math.floor(Date.now() / 1000) + Math.floor(timeValue / 1000)
142
+ }
143
+
120
144
  /**
121
145
  * Returns public key
122
146
  */
@@ -125,7 +125,7 @@ export default class ResponseWalletList extends Response {
125
125
  }
126
126
  }
127
127
 
128
- wallet.balance = Number(data.amount)
128
+ wallet.balance = String(data.amount != null ? data.amount : 0)
129
129
  wallet.pubkey = data.pubkey
130
130
  wallet.createdAt = data.createdAt
131
131
 
@@ -248,6 +248,17 @@ export const RequestTokensParamsSchema = z.object({
248
248
  meta: z.union([MetaDataSchema, z.null()]).optional()
249
249
  }).strict()
250
250
 
251
+ // =============================================================================
252
+ // FILTER SCHEMAS
253
+ // =============================================================================
254
+
255
+ export const MetaFilterSchema = z.object({
256
+ key: z.string(),
257
+ value: z.string(),
258
+ comparison: z.string().optional(),
259
+ criterion: z.string().optional()
260
+ }).strict()
261
+
251
262
  // =============================================================================
252
263
  // QUERY PARAMETER SCHEMAS
253
264
  // =============================================================================
@@ -265,7 +276,7 @@ export const MetaQueryParamsSchema = z.object({
265
276
  key: z.union([z.string(), z.null()]).optional(),
266
277
  value: z.union([z.string(), z.null()]).optional(),
267
278
  latest: z.union([z.boolean(), z.null()]).optional(),
268
- filter: z.union([z.string(), z.null()]).optional(),
279
+ filter: z.union([z.array(MetaFilterSchema), z.null()]).optional(),
269
280
  queryArgs: z.union([z.record(z.unknown()), z.null()]).optional(),
270
281
  count: z.union([z.number().int().min(1), z.null()]).optional(),
271
282
  countBy: z.union([z.string(), z.null()]).optional(),
@@ -58,7 +58,8 @@ import type {
58
58
  MetaId,
59
59
  CellSlug,
60
60
  MetaData,
61
- BaseResponse
61
+ BaseResponse,
62
+ MetaFilter
62
63
  } from './index'
63
64
 
64
65
  // =============================================================================
@@ -237,7 +238,7 @@ export interface MetaQueryOptions {
237
238
  key?: string | null
238
239
  value?: string | null
239
240
  latest?: boolean | null
240
- filter?: string | null
241
+ filter?: MetaFilter[] | null
241
242
  queryArgs?: Record<string, unknown> | null
242
243
  count?: number | null
243
244
  countBy?: string | null
@@ -59,7 +59,8 @@ import type {
59
59
  MetaId,
60
60
  CellSlug,
61
61
  AtomIsotope,
62
- MetaData
62
+ MetaData,
63
+ MetaFilter
63
64
  } from './index'
64
65
 
65
66
  // =============================================================================
@@ -173,7 +174,7 @@ export interface QueryMetaTypeVariables {
173
174
  key?: string | null
174
175
  value?: string | null
175
176
  latest?: boolean | null
176
- filter?: string | null
177
+ filter?: MetaFilter[] | null
177
178
  queryArgs?: Record<string, unknown> | null
178
179
  count?: number | null
179
180
  countBy?: string | null
@@ -115,8 +115,8 @@ export function assertExhaustive<T>(
115
115
  * Exhaustive isotope type guard with compile-time checking
116
116
  */
117
117
  export function isAtomIsotope(value: unknown): value is AtomIsotope {
118
- return typeof value === 'string' &&
119
- (['C', 'V', 'U', 'T', 'M', 'I', 'R', 'B', 'F'] as const).includes(value as AtomIsotope)
118
+ return typeof value === 'string' &&
119
+ (['C', 'V', 'U', 'T', 'M', 'I', 'R', 'B', 'F', 'P', 'A'] as const).includes(value as AtomIsotope)
120
120
  }
121
121
 
122
122
  /**
@@ -158,6 +158,14 @@ export function isFuseIsotope(value: unknown): value is 'F' {
158
158
  return value === 'F'
159
159
  }
160
160
 
161
+ export function isPeerIsotope(value: unknown): value is 'P' {
162
+ return value === 'P'
163
+ }
164
+
165
+ export function isAppendIsotope(value: unknown): value is 'A' {
166
+ return value === 'A'
167
+ }
168
+
161
169
  /**
162
170
  * Exhaustive isotope handler with compile-time completeness
163
171
  */
@@ -173,6 +181,8 @@ export function handleIsotope<T>(
173
181
  readonly R: () => T
174
182
  readonly B: () => T
175
183
  readonly F: () => T
184
+ readonly P: () => T
185
+ readonly A: () => T
176
186
  }
177
187
  ): T {
178
188
  switch (isotope) {
@@ -185,6 +195,8 @@ export function handleIsotope<T>(
185
195
  case 'R': return handlers.R()
186
196
  case 'B': return handlers.B()
187
197
  case 'F': return handlers.F()
198
+ case 'P': return handlers.P()
199
+ case 'A': return handlers.A()
188
200
  default: return assertNever(isotope)
189
201
  }
190
202
  }
@@ -378,11 +390,10 @@ export function isCellSlug(value: unknown): value is CellSlug {
378
390
  }
379
391
 
380
392
  /**
381
- * Batch ID validation (UUID format)
393
+ * Batch ID validation (64-char hex string, matching JS SDK)
382
394
  */
383
395
  export function isBatchId(value: unknown): value is BatchId {
384
- return typeof value === 'string' &&
385
- /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value)
396
+ return typeof value === 'string' && /^[a-f0-9]{64}$/i.test(value)
386
397
  }
387
398
 
388
399
  // =============================================================================
@@ -594,6 +605,8 @@ export const Guards = {
594
605
  rule: isRuleIsotope,
595
606
  buffer: isBufferIsotope,
596
607
  fuse: isFuseIsotope,
608
+ peer: isPeerIsotope,
609
+ append: isAppendIsotope,
597
610
  handle: handleIsotope
598
611
  },
599
612
 
@@ -172,8 +172,8 @@ export interface AtomMetaData extends MetaData {
172
172
  export interface AtomParams {
173
173
  position?: string | null
174
174
  walletAddress?: WalletAddress | null
175
- isotope?: AtomIsotope
176
- token?: TokenSlug | string
175
+ isotope?: AtomIsotope | null
176
+ token?: TokenSlug | string | null
177
177
  value?: string | number | null
178
178
  batchId?: BatchId | string | null
179
179
  metaType?: MetaType | string | null
@@ -182,7 +182,7 @@ export interface AtomParams {
182
182
  otsFragment?: string | null
183
183
  index?: number | null
184
184
  createdAt?: string | null
185
- version?: number | null
185
+ version?: string | number | null | undefined
186
186
  }
187
187
 
188
188
  export interface WalletParams {
@@ -284,6 +284,21 @@ export interface RequestTokensParams {
284
284
  meta?: MetaData | null
285
285
  }
286
286
 
287
+ // =============================================================================
288
+ // FILTER TYPES
289
+ // =============================================================================
290
+
291
+ /**
292
+ * MetaFilter interface for filtering meta queries
293
+ * Matches the GraphQL MetaFilter input type from the server
294
+ */
295
+ export interface MetaFilter {
296
+ key: string
297
+ value: string
298
+ comparison?: string // '=', '<', '>', '<=', '>=', '!='
299
+ criterion?: string
300
+ }
301
+
287
302
  // =============================================================================
288
303
  // QUERY PARAMETER TYPES
289
304
  // =============================================================================
@@ -301,7 +316,7 @@ export interface MetaQueryParams {
301
316
  key?: string | null
302
317
  value?: string | null
303
318
  latest?: boolean | null
304
- filter?: string | null
319
+ filter?: MetaFilter[] | null
305
320
  queryArgs?: Record<string, unknown> | null
306
321
  count?: number | null
307
322
  countBy?: string | null