@wishknish/knishio-client-ts 0.7.6 → 0.7.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wishknish/knishio-client-ts",
3
- "version": "0.7.6",
3
+ "version": "0.7.8",
4
4
  "productName": "Knish.IO TypeScript SDK Client",
5
5
  "description": "TypeScript implementation of the Knish.IO SDK to consume Knish.IO GraphQL APIs with enhanced type safety.",
6
6
  "license": "GPL-3.0-or-later",
@@ -84,6 +84,7 @@ import QueryUserActivity from '@/query/QueryUserActivity'
84
84
  import QueryToken from '@/query/QueryToken'
85
85
  import QueryMetaTypeViaAtom from '@/query/QueryMetaTypeViaAtom'
86
86
  import QueryMetaTypeViaMolecule from '@/query/QueryMetaTypeViaMolecule'
87
+ import QueryEmbeddingStatus from '@/query/QueryEmbeddingStatus'
87
88
 
88
89
  // Mutation imports
89
90
  import MutationCreateToken from '@/mutation/MutationCreateToken'
@@ -102,6 +103,10 @@ import MutationRequestAuthorizationGuest from '@/mutation/MutationRequestAuthori
102
103
  import MutationLinkIdentifier from '@/mutation/MutationLinkIdentifier'
103
104
  import MutationPeering from '@/mutation/MutationPeering'
104
105
  import MutationAppendRequest from '@/mutation/MutationAppendRequest'
106
+ import MutationProposeMolecule from '@/mutation/MutationProposeMolecule'
107
+
108
+ // Response imports
109
+ import ResponseProposeMolecule from '@/response/ResponseProposeMolecule'
105
110
 
106
111
  // Subscribe imports
107
112
  import CreateMoleculeSubscribe from '@/subscribe/CreateMoleculeSubscribe'
@@ -116,7 +121,10 @@ import {
116
121
  TransferBalanceException,
117
122
  WalletShadowException,
118
123
  StackableUnitAmountException,
119
- AuthorizationRejectedException
124
+ AuthorizationRejectedException,
125
+ MolecularHashMismatchException,
126
+ SignatureMismatchException,
127
+ AtomIndexException
120
128
  } from '@/exception'
121
129
 
122
130
  // Type imports
@@ -150,6 +158,13 @@ export default class KnishIOClient {
150
158
  private $__remainderWallet: Wallet | null = null
151
159
  private lastMoleculeQuery: Mutation | null = null
152
160
  private abortControllers: Map<string, AbortController> = new Map()
161
+ private $__capabilityCache: Record<string, boolean> = {}
162
+ // Promise-chain mutex serializing MutationProposeMolecule submissions on this
163
+ // client. Without it, concurrent createMolecule() calls both query the same
164
+ // ContinuID position and both sign with it — the second is rejected with
165
+ // OTS position reuse. Auth-token flow (MutationRequestAuthorization) inherits
166
+ // from MutationProposeMolecule so it's covered by the same lock.
167
+ private $__moleculeChain: Promise<unknown> = Promise.resolve()
153
168
 
154
169
  /**
155
170
  * Enhanced constructor with standardized configuration validation (Phase 2 Enhancement)
@@ -320,6 +335,7 @@ export default class KnishIOClient {
320
335
  this.$__authToken = null
321
336
  this.$__remainderWallet = null
322
337
  this.lastMoleculeQuery = null
338
+ this.$__capabilityCache = {}
323
339
  }
324
340
 
325
341
  /**
@@ -344,6 +360,20 @@ export default class KnishIOClient {
344
360
  }
345
361
  }
346
362
 
363
+ /**
364
+ * Sets the WebSocket (subscription) endpoint for this session.
365
+ *
366
+ * F-8a (cross-SDK parity, 2026-06-03): `setUri` only updates the HTTP endpoint; the
367
+ * subscription socket is built once from the `socket.socketUri` passed at
368
+ * construction. This lets a caller re-point the socket when the endpoint changes
369
+ * (mirrors the JS SDK's `setSocketUri`).
370
+ */
371
+ setSocketUri(socketUri: string): void {
372
+ if (this.$__client && 'setSocketUri' in this.$__client) {
373
+ (this.$__client as any).setSocketUri(socketUri)
374
+ }
375
+ }
376
+
347
377
  /**
348
378
  * Gets the Knish.IO server URIs
349
379
  */
@@ -433,6 +463,28 @@ export default class KnishIOClient {
433
463
  secret = secret || this.getSecret()
434
464
  bundle = bundle || this.getBundle()
435
465
 
466
+ // For non-USER source wallets (V/B isotopes), capture the current USER
467
+ // ContinuID position BEFORE overwriting the client's remainder wallet.
468
+ // This position is needed by addContinuIdAtom() for previousPosition metadata.
469
+ let continuIdPosition: string | null = null
470
+ if (sourceWallet && sourceWallet.token !== 'USER') {
471
+ if (this.lastMoleculeQuery &&
472
+ this.getRemainderWallet() &&
473
+ this.getRemainderWallet()?.token === 'USER' &&
474
+ this.lastMoleculeQuery.response() &&
475
+ this.lastMoleculeQuery.response()?.success()
476
+ ) {
477
+ // Carry-forward: use last successful USER remainder wallet position
478
+ continuIdPosition = this.getRemainderWallet()?.position || null
479
+ this.log('info', `KnishIOClient::createMolecule() - Captured USER ContinuID position ${continuIdPosition?.substring(0, 16)}... for non-USER source wallet`)
480
+ } else {
481
+ // Query server for current ContinuID position
482
+ const userWallet = await this.getSourceWallet()
483
+ continuIdPosition = userWallet?.position || null
484
+ this.log('info', `KnishIOClient::createMolecule() - Queried USER ContinuID position ${continuIdPosition?.substring(0, 16)}... for non-USER source wallet`)
485
+ }
486
+ }
487
+
436
488
  // Sets the source wallet as the last remainder wallet (to maintain ContinuID)
437
489
  if (!sourceWallet &&
438
490
  this.lastMoleculeQuery &&
@@ -463,7 +515,8 @@ export default class KnishIOClient {
463
515
  sourceWallet,
464
516
  remainderWallet: this.getRemainderWallet()!,
465
517
  cellSlug: this.getCellSlug(),
466
- version: this.getServerSdkVersion()
518
+ version: this.getServerSdkVersion(),
519
+ continuIdPosition
467
520
  })
468
521
  }
469
522
 
@@ -494,6 +547,24 @@ export default class KnishIOClient {
494
547
  return mutation
495
548
  }
496
549
 
550
+ /**
551
+ * Serializes the given async work behind a per-client promise chain. Used to
552
+ * guarantee that at most one MutationProposeMolecule submission runs at a
553
+ * time on this client — query position, sign, submit, observe response must
554
+ * complete before the next one starts, or two callers race for the same OTS
555
+ * position and the second gets rejected.
556
+ *
557
+ * `.then(fn, fn)` runs fn whether the previous holder resolved or rejected;
558
+ * the queue's `.catch` swallows the rejection so a single failure doesn't
559
+ * poison every subsequent caller, while the rejection still propagates to
560
+ * the caller whose fn threw.
561
+ */
562
+ private withMoleculeLock<T>(fn: () => Promise<T>): Promise<T> {
563
+ const result = (this.$__moleculeChain as Promise<unknown>).then(fn, fn) as Promise<T>
564
+ this.$__moleculeChain = result.catch(() => undefined)
565
+ return result
566
+ }
567
+
497
568
  /**
498
569
  * Executes a query or mutation
499
570
  */
@@ -509,10 +580,42 @@ export default class KnishIOClient {
509
580
  })
510
581
  }
511
582
 
583
+ if (query instanceof MutationProposeMolecule) {
584
+ return await this.withMoleculeLock(async () => {
585
+ const response = await query.execute({ variables: variables || {} })
586
+ this.handlePositionDrift(response)
587
+ return response
588
+ })
589
+ }
590
+
512
591
  // Execute the query
513
592
  return await query.execute({ variables: variables || {} })
514
593
  }
515
594
 
595
+ /**
596
+ * When a ProposeMolecule submission is rejected for a position-related
597
+ * reason (OTS reuse, ContinuID chain violation, molecular hash mismatch),
598
+ * the cached remainder wallet and lastMoleculeQuery are stale — the
599
+ * validator's chain has advanced past what we know. Clear them so the next
600
+ * createMolecule call re-queries queryContinuId for the authoritative
601
+ * position. Other failure modes (network, malformed meta, bad signature
602
+ * bytes) don't imply drift; leave cached state alone.
603
+ */
604
+ private handlePositionDrift(response: Response | null): void {
605
+ if (!(response instanceof ResponseProposeMolecule)) return
606
+ const exc = response.toException()
607
+ if (!exc) return
608
+ if (
609
+ exc instanceof MolecularHashMismatchException ||
610
+ exc instanceof AtomIndexException ||
611
+ (exc instanceof SignatureMismatchException && exc.code === 'OTS_VERIFICATION_FAILED')
612
+ ) {
613
+ this.$__remainderWallet = null
614
+ this.lastMoleculeQuery = null
615
+ this.log('warn', `KnishIOClient::executeQuery() - position drift detected (${exc.name}/${exc.code}); cleared cached remainder wallet`)
616
+ }
617
+ }
618
+
516
619
  /**
517
620
  * Sets the secret for this session
518
621
  */
@@ -1037,6 +1140,76 @@ export default class KnishIOClient {
1037
1140
  return response
1038
1141
  }
1039
1142
 
1143
+ /**
1144
+ * Probes the connected server to check whether it supports a named root query field.
1145
+ * Result is cached per URI so the network round-trip happens at most once per URI.
1146
+ *
1147
+ * Uses GraphQL introspection which is universally supported by spec-compliant servers.
1148
+ *
1149
+ * @param fieldName - The root Query field name to check (e.g. 'embeddingStatus')
1150
+ * @returns true if the server schema includes the field, false otherwise
1151
+ */
1152
+ async hasQueryField(fieldName: string): Promise<boolean> {
1153
+ const uri = this.$__client.getUri()
1154
+ const cacheKey = `${uri}::${fieldName}`
1155
+
1156
+ if (typeof this.$__capabilityCache[cacheKey] === 'boolean') {
1157
+ return this.$__capabilityCache[cacheKey]!
1158
+ }
1159
+
1160
+ try {
1161
+ const result = await this.$__client.query({
1162
+ query: '{ __schema { queryType { fields { name } } } }',
1163
+ variables: {}
1164
+ })
1165
+
1166
+ const data = result?.data as Record<string, any> | undefined
1167
+ const fields: Array<{ name: string }> = data?.__schema?.queryType?.fields || []
1168
+ const supported = fields.some((f: { name: string }) => f.name === fieldName)
1169
+ this.$__capabilityCache[cacheKey] = supported
1170
+ return supported
1171
+ } catch (err: any) {
1172
+ this.log('warn', `KnishIOClient::hasQueryField() - Capability probe for '${fieldName}' failed: ${err.message}`)
1173
+ this.$__capabilityCache[cacheKey] = false
1174
+ return false
1175
+ }
1176
+ }
1177
+
1178
+ /**
1179
+ * Queries embedding status for one or more meta instances (DataBraid observability).
1180
+ *
1181
+ * If the connected server does not support the embeddingStatus query,
1182
+ * returns null without throwing an error (graceful degradation).
1183
+ *
1184
+ * Single mode: queryEmbeddingStatus({ metaType: 'product', metaId: 'SKU-001' })
1185
+ * Bulk mode: queryEmbeddingStatus({ instances: [{ metaType: 'product', metaId: 'SKU-001' }, ...] })
1186
+ *
1187
+ * @returns Response with payload(), or null if the server does not support this query
1188
+ */
1189
+ async queryEmbeddingStatus({
1190
+ metaType = null,
1191
+ metaId = null,
1192
+ instances = null
1193
+ }: {
1194
+ metaType?: string | null
1195
+ metaId?: string | null
1196
+ instances?: Array<{ metaType: string; metaId: string }> | null
1197
+ }): Promise<Response | null> {
1198
+ this.log('info', `KnishIOClient::queryEmbeddingStatus() - Checking embedding status for metaType: ${metaType || '(bulk)'}...`)
1199
+
1200
+ const supported = await this.hasQueryField('embeddingStatus')
1201
+
1202
+ if (!supported) {
1203
+ this.log('warn', 'KnishIOClient::queryEmbeddingStatus() - Server does not support embeddingStatus query. Returning null.')
1204
+ return null
1205
+ }
1206
+
1207
+ const query = this.createQuery(QueryEmbeddingStatus)
1208
+ const variables = QueryEmbeddingStatus.createVariables({ metaType, metaId, instances })
1209
+
1210
+ return this.executeQuery(query, variables)
1211
+ }
1212
+
1040
1213
  /**
1041
1214
  * Query cascading meta instances for batchId
1042
1215
  */
@@ -1496,9 +1669,13 @@ export default class KnishIOClient {
1496
1669
  })
1497
1670
  }
1498
1671
 
1499
- // Create molecule with the source wallet (same pattern as transferToken)
1672
+ // Create remainder wallet from source (must be same token for V-isotope conservation)
1673
+ const remainderWallet = sourceWallet.createRemainder(this.getSecret())
1674
+
1675
+ // Create molecule with the token-specific source and remainder wallets
1500
1676
  const molecule = await this.createMolecule({
1501
- sourceWallet
1677
+ sourceWallet,
1678
+ remainderWallet
1502
1679
  })
1503
1680
 
1504
1681
  // Create a transfer to null address (burn)
@@ -1955,8 +2132,20 @@ export default class KnishIOClient {
1955
2132
  })
1956
2133
  }
1957
2134
 
2135
+ // Create remainder wallet from source (must be same token)
2136
+ const remainderWallet = sourceWallet.createRemainder(this.getSecret())
2137
+
2138
+ // Build the molecule with the token-specific source and remainder wallets
2139
+ const molecule = await this.createMolecule({
2140
+ sourceWallet,
2141
+ remainderWallet
2142
+ })
2143
+
1958
2144
  // Create the molecule mutation
1959
- const mutation = await this.createMoleculeMutation({ mutationClass: MutationDepositBufferToken })
2145
+ const mutation = await this.createMoleculeMutation({
2146
+ mutationClass: MutationDepositBufferToken,
2147
+ molecule
2148
+ })
1960
2149
 
1961
2150
  // Initialize the deposit buffer token mutation
1962
2151
  await mutation.fillMolecule({
@@ -78,6 +78,7 @@ export default class Molecule {
78
78
  public remainderWallet: Wallet | null
79
79
  public atoms: Atom[]
80
80
  public version: string | null | undefined
81
+ public continuIdPosition: string | null
81
82
  public parentHashes: string[]
82
83
  public local?: number
83
84
 
@@ -91,7 +92,8 @@ export default class Molecule {
91
92
  sourceWallet = null,
92
93
  remainderWallet = null,
93
94
  cellSlug = null,
94
- version = null
95
+ version = null,
96
+ continuIdPosition = null
95
97
  }: {
96
98
  secret?: string | null
97
99
  bundle?: string | null
@@ -99,6 +101,7 @@ export default class Molecule {
99
101
  remainderWallet?: Wallet | null
100
102
  cellSlug?: string | null
101
103
  version?: string | number | null
104
+ continuIdPosition?: string | null
102
105
  } = {}) {
103
106
  this.status = null
104
107
  this.molecularHash = null
@@ -107,6 +110,7 @@ export default class Molecule {
107
110
  this.secret = secret
108
111
  this.bundle = bundle
109
112
  this.sourceWallet = sourceWallet
113
+ this.continuIdPosition = continuIdPosition
110
114
  this.atoms = []
111
115
  this.parentHashes = []
112
116
 
@@ -209,8 +213,12 @@ export default class Molecule {
209
213
  // ContinuID metadata for chain integrity validation
210
214
  const continuIdMeta: Record<string, any> = {}
211
215
 
212
- // previousPosition: the source wallet's position being consumed
213
- if (this.sourceWallet && this.sourceWallet.position) {
216
+ // previousPosition: the current USER ContinuID position being consumed.
217
+ // For non-USER source wallets (V/B isotopes), use the explicitly passed
218
+ // continuIdPosition from createMolecule() instead of the TOKEN wallet position.
219
+ if (this.continuIdPosition) {
220
+ continuIdMeta.previousPosition = this.continuIdPosition
221
+ } else if (this.sourceWallet && this.sourceWallet.position) {
214
222
  continuIdMeta.previousPosition = this.sourceWallet.position
215
223
  }
216
224
 
@@ -251,14 +259,13 @@ export default class Molecule {
251
259
  const atomMeta = new AtomMeta(meta)
252
260
  atomMeta.addPolicy(policy)
253
261
 
254
- const wallet = Wallet.create({
255
- secret: this.secret!,
256
- bundle: this.sourceWallet!.bundle!,
257
- token: 'USER'
258
- })
259
-
262
+ // F-3 (cross-SDK parity, 2026-06-03): sign the policy (R-isotope) atom from the
263
+ // established ContinuID source wallet, NOT a freshly-derived Wallet.create() at a
264
+ // random position. As the signing atom in createPolicy(), a fresh-wallet position
265
+ // is unknown to the validator → "ContinuID chain validation failed: signing
266
+ // position … not found as wallet". Mirrors createRule(), which uses this.sourceWallet.
260
267
  this.addAtom(Atom.create({
261
- wallet,
268
+ wallet: this.sourceWallet!,
262
269
  isotope: 'R',
263
270
  metaType,
264
271
  metaId,
@@ -661,13 +668,29 @@ export default class Molecule {
661
668
  throw new BalanceInsufficientException()
662
669
  }
663
670
 
664
- // Burn tokens by removing from source (matching JS SDK)
671
+ // Create burn address wallet (null bundle = token destruction)
672
+ const burnWallet = new Wallet({
673
+ bundle: '0000000000000000000000000000000000000000000000000000000000000000',
674
+ token: this.sourceWallet.token
675
+ })
676
+
677
+ // V-atom 1: Debit full balance from source
665
678
  this.addAtom(Atom.create({
666
679
  isotope: 'V',
667
680
  wallet: this.sourceWallet,
668
- value: -amount
681
+ value: -Number(this.sourceWallet.balance)
669
682
  }))
670
- // Remainder atom (matching JS SDK)
683
+
684
+ // V-atom 2: Credit burn amount to burn address
685
+ this.addAtom(Atom.create({
686
+ isotope: 'V',
687
+ wallet: burnWallet,
688
+ value: amount,
689
+ metaType: 'walletBundle',
690
+ metaId: burnWallet.bundle!
691
+ }))
692
+
693
+ // V-atom 3: Remainder back to source identity
671
694
  this.addAtom(Atom.create({
672
695
  isotope: 'V',
673
696
  wallet: this.remainderWallet!,
package/src/index.ts CHANGED
@@ -94,6 +94,9 @@ export { default as QueryAtom } from './query/QueryAtom'
94
94
  export { default as QueryMetaType } from './query/QueryMetaType'
95
95
  export { default as QueryMetaTypeViaAtom } from './query/QueryMetaTypeViaAtom'
96
96
 
97
+ // DataBraid Embedding Observability
98
+ export { default as QueryEmbeddingStatus } from './query/QueryEmbeddingStatus'
99
+
97
100
  // Phase 2 Tier 2 Priority 3: Essential Query Operations
98
101
  export { default as QueryContinuId } from './query/QueryContinuId'
99
102
  export { default as QueryBatch } from './query/QueryBatch'
@@ -134,6 +137,10 @@ export { default as ResponseCreateMeta } from './response/ResponseCreateMeta'
134
137
  export { default as ResponseMetaType } from './response/ResponseMetaType'
135
138
  export { default as ResponseMetaTypeViaAtom } from './response/ResponseMetaTypeViaAtom'
136
139
 
140
+ // DataBraid Embedding Observability
141
+ export { default as ResponseEmbeddingStatus } from './response/ResponseEmbeddingStatus'
142
+ export type { EmbeddingStatusItem } from './response/ResponseEmbeddingStatus'
143
+
137
144
  // Phase 2 Tier 2 Priority 2: Token Operations
138
145
  export { default as ResponseCreateToken } from './response/ResponseCreateToken'
139
146
  export { default as ResponseRequestTokens } from './response/ResponseRequestTokens'
@@ -301,6 +301,21 @@ export default class GraphQLClient implements IGraphQLClient {
301
301
  })
302
302
  }
303
303
 
304
+ /**
305
+ * F-8a (cross-SDK parity, 2026-06-03): re-point the GraphQL-subscription WebSocket
306
+ * without changing the HTTP endpoint. `setUri` only updates `serverUri`, leaving the
307
+ * subscription socket pinned to whatever was passed at construction; this lets a
308
+ * caller re-derive the socket when the endpoint changes.
309
+ */
310
+ setSocketUri(socketUri: string): void {
311
+ this.socketUri = socketUri
312
+ this.$__client = this.createUrqlClient({
313
+ serverUri: this.serverUri,
314
+ socket: { socketUri },
315
+ encrypt: this.cipherLink
316
+ })
317
+ }
318
+
304
319
  socketDisconnect(): void {
305
320
  if (this.socketUri) {
306
321
  this.unsubscribeAll()
@@ -0,0 +1,130 @@
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 Query from './Query'
50
+ import ResponseEmbeddingStatus from '../response/ResponseEmbeddingStatus'
51
+ import { gql } from '@urql/core'
52
+ import type { GraphQLClient } from '../types/graphql'
53
+ import type KnishIOClient from '../KnishIOClient'
54
+
55
+ /**
56
+ * QueryEmbeddingStatus - Query for retrieving DataBraid embedding status.
57
+ *
58
+ * Supports both single-instance and bulk modes:
59
+ * - Single: { metaType: 'product', metaId: 'SKU-001' }
60
+ * - Bulk: { instances: [{ metaType: 'product', metaId: 'SKU-001' }, ...] }
61
+ *
62
+ * Returns embedding state (PENDING, STALE, COMPLETE) for each instance,
63
+ * allowing apps to render spinner badges and completion indicators.
64
+ *
65
+ * NOTE: Only available on servers with EMBEDDING_ENABLED=true.
66
+ * Use KnishIOClient.queryEmbeddingStatus() which handles capability
67
+ * detection and returns null for unsupported servers.
68
+ */
69
+ export default class QueryEmbeddingStatus extends Query {
70
+ /**
71
+ * Create new QueryEmbeddingStatus instance
72
+ */
73
+ constructor(graphQLClient: GraphQLClient, knishIOClient: KnishIOClient) {
74
+ super(graphQLClient, knishIOClient)
75
+
76
+ this.$__query = gql`query( $metaType: String, $metaId: String, $instances: [EmbeddingStatusInput!] ) {
77
+ embeddingStatus( metaType: $metaType, metaId: $metaId, instances: $instances ) {
78
+ metaType,
79
+ metaId,
80
+ state,
81
+ totalMetas,
82
+ embeddedCount,
83
+ embeddedAt,
84
+ model
85
+ }
86
+ }`
87
+ }
88
+
89
+ /**
90
+ * Builds a GraphQL-friendly variables object for embedding status queries.
91
+ *
92
+ * Single mode: createVariables({ metaType: 'product', metaId: 'SKU-001' })
93
+ * Bulk mode: createVariables({ instances: [{ metaType: 'product', metaId: 'SKU-001' }, ...] })
94
+ */
95
+ static createVariables({
96
+ metaType = null,
97
+ metaId = null,
98
+ instances = null
99
+ }: {
100
+ metaType?: string | null
101
+ metaId?: string | null
102
+ instances?: Array<{ metaType: string; metaId: string }> | null
103
+ } = {}): Record<string, any> {
104
+ const variables: Record<string, any> = {}
105
+
106
+ if (instances && instances.length > 0) {
107
+ variables.instances = instances
108
+ }
109
+
110
+ if (metaType) {
111
+ variables.metaType = metaType
112
+ }
113
+
114
+ if (metaId) {
115
+ variables.metaId = metaId
116
+ }
117
+
118
+ return variables
119
+ }
120
+
121
+ /**
122
+ * Returns a Response object
123
+ */
124
+ override createResponse(json: any): ResponseEmbeddingStatus {
125
+ return new ResponseEmbeddingStatus({
126
+ query: this,
127
+ json
128
+ })
129
+ }
130
+ }
@@ -0,0 +1,107 @@
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
+
52
+ /**
53
+ * EmbeddingStatusItem shape returned by the server.
54
+ */
55
+ export interface EmbeddingStatusItem {
56
+ /** Metadata type (echoed from input) */
57
+ metaType: string
58
+ /** Instance identifier (echoed from input) */
59
+ metaId: string
60
+ /** Embedding state: 'PENDING' | 'STALE' | 'COMPLETE' */
61
+ state: 'PENDING' | 'STALE' | 'COMPLETE'
62
+ /** Total meta rows for this instance */
63
+ totalMetas: number
64
+ /** Rows with current-model embeddings */
65
+ embeddedCount: number
66
+ /** Unix epoch of most recent embedding, or null */
67
+ embeddedAt: number | null
68
+ /** Model name used for embeddings, or null */
69
+ model: string | null
70
+ }
71
+
72
+ /**
73
+ * ResponseEmbeddingStatus - Response for EmbeddingStatus Query
74
+ *
75
+ * Payload is an array of EmbeddingStatusItem objects.
76
+ */
77
+ export default class ResponseEmbeddingStatus extends Response {
78
+ /**
79
+ * Class constructor
80
+ */
81
+ constructor({
82
+ query,
83
+ json
84
+ }: {
85
+ query: Query
86
+ json: any
87
+ }) {
88
+ super({
89
+ query,
90
+ json,
91
+ dataKey: 'data.embeddingStatus'
92
+ })
93
+ }
94
+
95
+ /**
96
+ * Returns the array of embedding status items, or null if empty.
97
+ */
98
+ override payload(): EmbeddingStatusItem[] | null {
99
+ const items = this.data()
100
+
101
+ if (!items || !Array.isArray(items) || items.length === 0) {
102
+ return null
103
+ }
104
+
105
+ return items as EmbeddingStatusItem[]
106
+ }
107
+ }