@wishknish/knishio-client-ts 0.7.7 → 0.8.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.js CHANGED
@@ -1917,7 +1917,7 @@ function generateSecret(seed = null, length = CRYPTO_CONSTANTS.SECRET_LENGTH) {
1917
1917
  if (seed) {
1918
1918
  const sponge = new JsSHA("SHAKE256", "TEXT");
1919
1919
  sponge.update(seed);
1920
- return sponge.getHash("HEX", { outputLen: length * 2 }).toLowerCase();
1920
+ return sponge.getHash("HEX", { outputLen: length * 4 }).toLowerCase();
1921
1921
  } else {
1922
1922
  return randomString(length);
1923
1923
  }
@@ -4935,13 +4935,8 @@ var Molecule = class _Molecule {
4935
4935
  }) {
4936
4936
  const atomMeta = new AtomMeta(meta);
4937
4937
  atomMeta.addPolicy(policy);
4938
- const wallet = Wallet.create({
4939
- secret: this.secret,
4940
- bundle: this.sourceWallet.bundle,
4941
- token: "USER"
4942
- });
4943
4938
  this.addAtom(Atom.create({
4944
- wallet,
4939
+ wallet: this.sourceWallet,
4945
4940
  isotope: "R",
4946
4941
  metaType,
4947
4942
  metaId,
@@ -5926,6 +5921,20 @@ var GraphQLClient = class {
5926
5921
  encrypt: this.cipherLink
5927
5922
  });
5928
5923
  }
5924
+ /**
5925
+ * F-8a (cross-SDK parity, 2026-06-03): re-point the GraphQL-subscription WebSocket
5926
+ * without changing the HTTP endpoint. `setUri` only updates `serverUri`, leaving the
5927
+ * subscription socket pinned to whatever was passed at construction; this lets a
5928
+ * caller re-derive the socket when the endpoint changes.
5929
+ */
5930
+ setSocketUri(socketUri) {
5931
+ this.socketUri = socketUri;
5932
+ this.$__client = this.createUrqlClient({
5933
+ serverUri: this.serverUri,
5934
+ socket: { socketUri },
5935
+ encrypt: this.cipherLink
5936
+ });
5937
+ }
5929
5938
  socketDisconnect() {
5930
5939
  if (this.socketUri) {
5931
5940
  this.unsubscribeAll();
@@ -8826,9 +8835,91 @@ var QueryMetaTypeViaMolecule = class extends Query {
8826
8835
  }
8827
8836
  };
8828
8837
 
8838
+ // src/response/ResponseEmbeddingStatus.ts
8839
+ init_Response();
8840
+ var ResponseEmbeddingStatus = class extends Response {
8841
+ /**
8842
+ * Class constructor
8843
+ */
8844
+ constructor({
8845
+ query,
8846
+ json
8847
+ }) {
8848
+ super({
8849
+ query,
8850
+ json,
8851
+ dataKey: "data.embeddingStatus"
8852
+ });
8853
+ }
8854
+ /**
8855
+ * Returns the array of embedding status items, or null if empty.
8856
+ */
8857
+ payload() {
8858
+ const items = this.data();
8859
+ if (!items || !Array.isArray(items) || items.length === 0) {
8860
+ return null;
8861
+ }
8862
+ return items;
8863
+ }
8864
+ };
8865
+ var QueryEmbeddingStatus = class extends Query {
8866
+ /**
8867
+ * Create new QueryEmbeddingStatus instance
8868
+ */
8869
+ constructor(graphQLClient, knishIOClient) {
8870
+ super(graphQLClient, knishIOClient);
8871
+ this.$__query = gql`query( $metaType: String, $metaId: String, $instances: [EmbeddingStatusInput!] ) {
8872
+ embeddingStatus( metaType: $metaType, metaId: $metaId, instances: $instances ) {
8873
+ metaType,
8874
+ metaId,
8875
+ state,
8876
+ totalMetas,
8877
+ embeddedCount,
8878
+ embeddedAt,
8879
+ model
8880
+ }
8881
+ }`;
8882
+ }
8883
+ /**
8884
+ * Builds a GraphQL-friendly variables object for embedding status queries.
8885
+ *
8886
+ * Single mode: createVariables({ metaType: 'product', metaId: 'SKU-001' })
8887
+ * Bulk mode: createVariables({ instances: [{ metaType: 'product', metaId: 'SKU-001' }, ...] })
8888
+ */
8889
+ static createVariables({
8890
+ metaType = null,
8891
+ metaId = null,
8892
+ instances = null
8893
+ } = {}) {
8894
+ const variables = {};
8895
+ if (instances && instances.length > 0) {
8896
+ variables.instances = instances;
8897
+ }
8898
+ if (metaType) {
8899
+ variables.metaType = metaType;
8900
+ }
8901
+ if (metaId) {
8902
+ variables.metaId = metaId;
8903
+ }
8904
+ return variables;
8905
+ }
8906
+ /**
8907
+ * Returns a Response object
8908
+ */
8909
+ createResponse(json) {
8910
+ return new ResponseEmbeddingStatus({
8911
+ query: this,
8912
+ json
8913
+ });
8914
+ }
8915
+ };
8916
+
8829
8917
  // src/response/ResponseProposeMolecule.ts
8830
8918
  init_Response();
8831
8919
  init_Dot();
8920
+ init_MolecularHashMismatchException();
8921
+ init_SignatureMismatchException();
8922
+ init_AtomIndexException();
8832
8923
  var ResponseProposeMolecule = class extends Response {
8833
8924
  $__clientMolecule;
8834
8925
  /**
@@ -8900,6 +8991,47 @@ var ResponseProposeMolecule = class extends Response {
8900
8991
  reason() {
8901
8992
  return Dot.get(this.data(), "reason", "Invalid response from server");
8902
8993
  }
8994
+ /**
8995
+ * Map this rejection to a typed SDK exception when the failure mode is one
8996
+ * we know about. Returns null on success or for rejections we don't have a
8997
+ * typed class for.
8998
+ *
8999
+ * This is the single place pattern-matching against validator reason strings
9000
+ * lives — consumers (KnishIOClient cache invalidation, callers needing to
9001
+ * branch on failure mode) can `instanceof`-switch on the result instead.
9002
+ * Future validator versions can rephrase reasons (or populate a structured
9003
+ * field in the response payload) without breaking callers.
9004
+ */
9005
+ toException() {
9006
+ if (this.success()) return null;
9007
+ const reason = this.reason();
9008
+ const lc = reason.toLowerCase();
9009
+ if (/molecularhashmismatch|hash.*mismatch/.test(lc)) {
9010
+ return new MolecularHashMismatchException(reason, {
9011
+ details: { reason },
9012
+ code: "HASH_MISMATCH"
9013
+ });
9014
+ }
9015
+ if (/ots.*position.*reuse|position.*already.*used|ots.*verification/.test(lc)) {
9016
+ return new SignatureMismatchException(reason, {
9017
+ details: { reason },
9018
+ code: "OTS_VERIFICATION_FAILED"
9019
+ });
9020
+ }
9021
+ if (/continuid.*chain|previousposition|chain.*violation/.test(lc)) {
9022
+ return new AtomIndexException(reason, {
9023
+ details: { reason },
9024
+ code: "INDEX_CONFLICT"
9025
+ });
9026
+ }
9027
+ if (/signature.*verification|signature.*invalid/.test(lc)) {
9028
+ return new SignatureMismatchException(reason, {
9029
+ details: { reason },
9030
+ code: "VERIFICATION_FAILED"
9031
+ });
9032
+ }
9033
+ return null;
9034
+ }
8903
9035
  /**
8904
9036
  * Returns payload object
8905
9037
  * Matches JavaScript SDK payload method exactly
@@ -9937,6 +10069,13 @@ var KnishIOClient = class {
9937
10069
  $__remainderWallet = null;
9938
10070
  lastMoleculeQuery = null;
9939
10071
  abortControllers = /* @__PURE__ */ new Map();
10072
+ $__capabilityCache = {};
10073
+ // Promise-chain mutex serializing MutationProposeMolecule submissions on this
10074
+ // client. Without it, concurrent createMolecule() calls both query the same
10075
+ // ContinuID position and both sign with it — the second is rejected with
10076
+ // OTS position reuse. Auth-token flow (MutationRequestAuthorization) inherits
10077
+ // from MutationProposeMolecule so it's covered by the same lock.
10078
+ $__moleculeChain = Promise.resolve();
9940
10079
  /**
9941
10080
  * Enhanced constructor with standardized configuration validation (Phase 2 Enhancement)
9942
10081
  */
@@ -10061,6 +10200,7 @@ var KnishIOClient = class {
10061
10200
  this.$__authToken = null;
10062
10201
  this.$__remainderWallet = null;
10063
10202
  this.lastMoleculeQuery = null;
10203
+ this.$__capabilityCache = {};
10064
10204
  }
10065
10205
  /**
10066
10206
  * Get the GraphQL client
@@ -10081,6 +10221,19 @@ var KnishIOClient = class {
10081
10221
  this.$__client.setUri(this.getRandomUri());
10082
10222
  }
10083
10223
  }
10224
+ /**
10225
+ * Sets the WebSocket (subscription) endpoint for this session.
10226
+ *
10227
+ * F-8a (cross-SDK parity, 2026-06-03): `setUri` only updates the HTTP endpoint; the
10228
+ * subscription socket is built once from the `socket.socketUri` passed at
10229
+ * construction. This lets a caller re-point the socket when the endpoint changes
10230
+ * (mirrors the JS SDK's `setSocketUri`).
10231
+ */
10232
+ setSocketUri(socketUri) {
10233
+ if (this.$__client && "setSocketUri" in this.$__client) {
10234
+ this.$__client.setSocketUri(socketUri);
10235
+ }
10236
+ }
10084
10237
  /**
10085
10238
  * Gets the Knish.IO server URIs
10086
10239
  */
@@ -10204,6 +10357,23 @@ var KnishIOClient = class {
10204
10357
  this.lastMoleculeQuery = mutation;
10205
10358
  return mutation;
10206
10359
  }
10360
+ /**
10361
+ * Serializes the given async work behind a per-client promise chain. Used to
10362
+ * guarantee that at most one MutationProposeMolecule submission runs at a
10363
+ * time on this client — query position, sign, submit, observe response must
10364
+ * complete before the next one starts, or two callers race for the same OTS
10365
+ * position and the second gets rejected.
10366
+ *
10367
+ * `.then(fn, fn)` runs fn whether the previous holder resolved or rejected;
10368
+ * the queue's `.catch` swallows the rejection so a single failure doesn't
10369
+ * poison every subsequent caller, while the rejection still propagates to
10370
+ * the caller whose fn threw.
10371
+ */
10372
+ withMoleculeLock(fn) {
10373
+ const result = this.$__moleculeChain.then(fn, fn);
10374
+ this.$__moleculeChain = result.catch(() => void 0);
10375
+ return result;
10376
+ }
10207
10377
  /**
10208
10378
  * Executes a query or mutation
10209
10379
  */
@@ -10216,8 +10386,34 @@ var KnishIOClient = class {
10216
10386
  encrypt: this.$__encrypt
10217
10387
  });
10218
10388
  }
10389
+ if (query instanceof MutationProposeMolecule) {
10390
+ return await this.withMoleculeLock(async () => {
10391
+ const response = await query.execute({ variables: variables || {} });
10392
+ this.handlePositionDrift(response);
10393
+ return response;
10394
+ });
10395
+ }
10219
10396
  return await query.execute({ variables: variables || {} });
10220
10397
  }
10398
+ /**
10399
+ * When a ProposeMolecule submission is rejected for a position-related
10400
+ * reason (OTS reuse, ContinuID chain violation, molecular hash mismatch),
10401
+ * the cached remainder wallet and lastMoleculeQuery are stale — the
10402
+ * validator's chain has advanced past what we know. Clear them so the next
10403
+ * createMolecule call re-queries queryContinuId for the authoritative
10404
+ * position. Other failure modes (network, malformed meta, bad signature
10405
+ * bytes) don't imply drift; leave cached state alone.
10406
+ */
10407
+ handlePositionDrift(response) {
10408
+ if (!(response instanceof ResponseProposeMolecule)) return;
10409
+ const exc = response.toException();
10410
+ if (!exc) return;
10411
+ if (exc instanceof MolecularHashMismatchException || exc instanceof AtomIndexException || exc instanceof SignatureMismatchException && exc.code === "OTS_VERIFICATION_FAILED") {
10412
+ this.$__remainderWallet = null;
10413
+ this.lastMoleculeQuery = null;
10414
+ this.log("warn", `KnishIOClient::executeQuery() - position drift detected (${exc.name}/${exc.code}); cleared cached remainder wallet`);
10415
+ }
10416
+ }
10221
10417
  /**
10222
10418
  * Sets the secret for this session
10223
10419
  */
@@ -10597,6 +10793,63 @@ var KnishIOClient = class {
10597
10793
  }
10598
10794
  return response;
10599
10795
  }
10796
+ /**
10797
+ * Probes the connected server to check whether it supports a named root query field.
10798
+ * Result is cached per URI so the network round-trip happens at most once per URI.
10799
+ *
10800
+ * Uses GraphQL introspection which is universally supported by spec-compliant servers.
10801
+ *
10802
+ * @param fieldName - The root Query field name to check (e.g. 'embeddingStatus')
10803
+ * @returns true if the server schema includes the field, false otherwise
10804
+ */
10805
+ async hasQueryField(fieldName) {
10806
+ const uri = this.$__client.getUri();
10807
+ const cacheKey = `${uri}::${fieldName}`;
10808
+ if (typeof this.$__capabilityCache[cacheKey] === "boolean") {
10809
+ return this.$__capabilityCache[cacheKey];
10810
+ }
10811
+ try {
10812
+ const result = await this.$__client.query({
10813
+ query: "{ __schema { queryType { fields { name } } } }",
10814
+ variables: {}
10815
+ });
10816
+ const data = result?.data;
10817
+ const fields = data?.__schema?.queryType?.fields || [];
10818
+ const supported = fields.some((f) => f.name === fieldName);
10819
+ this.$__capabilityCache[cacheKey] = supported;
10820
+ return supported;
10821
+ } catch (err) {
10822
+ this.log("warn", `KnishIOClient::hasQueryField() - Capability probe for '${fieldName}' failed: ${err.message}`);
10823
+ this.$__capabilityCache[cacheKey] = false;
10824
+ return false;
10825
+ }
10826
+ }
10827
+ /**
10828
+ * Queries embedding status for one or more meta instances (DataBraid observability).
10829
+ *
10830
+ * If the connected server does not support the embeddingStatus query,
10831
+ * returns null without throwing an error (graceful degradation).
10832
+ *
10833
+ * Single mode: queryEmbeddingStatus({ metaType: 'product', metaId: 'SKU-001' })
10834
+ * Bulk mode: queryEmbeddingStatus({ instances: [{ metaType: 'product', metaId: 'SKU-001' }, ...] })
10835
+ *
10836
+ * @returns Response with payload(), or null if the server does not support this query
10837
+ */
10838
+ async queryEmbeddingStatus({
10839
+ metaType = null,
10840
+ metaId = null,
10841
+ instances = null
10842
+ }) {
10843
+ this.log("info", `KnishIOClient::queryEmbeddingStatus() - Checking embedding status for metaType: ${metaType || "(bulk)"}...`);
10844
+ const supported = await this.hasQueryField("embeddingStatus");
10845
+ if (!supported) {
10846
+ this.log("warn", "KnishIOClient::queryEmbeddingStatus() - Server does not support embeddingStatus query. Returning null.");
10847
+ return null;
10848
+ }
10849
+ const query = this.createQuery(QueryEmbeddingStatus);
10850
+ const variables = QueryEmbeddingStatus.createVariables({ metaType, metaId, instances });
10851
+ return this.executeQuery(query, variables);
10852
+ }
10600
10853
  /**
10601
10854
  * Query cascading meta instances for batchId
10602
10855
  */
@@ -11559,6 +11812,6 @@ var KnishIO = {
11559
11812
  SDK_INFO
11560
11813
  };
11561
11814
 
11562
- export { Atom, AtomIndexException, AtomMeta, AtomsMissingException, AuthToken, BaseException, COMPATIBLE_SERVER_VERSIONS, CRYPTO_CONSTANTS, CheckMolecule, DevUtils, Dot, EXCEPTION_CODES, EXCEPTION_TYPES, EXTENDED_COMPATIBILITY_TEST_VECTORS, ExceptionFactory, GraphQLClient, InvalidResponseException, KnishIO, KnishIOClient, Meta, MolecularHashMismatchException, Molecule, Mutation, MutationAppendRequest, MutationCreateMeta, MutationCreateToken, MutationCreateWallet, MutationPeering, MutationProposeMolecule, MutationRequestAuthorization, MutationRequestTokens, MutationTransferTokens, PolicyMeta, Query, QueryAtom, QueryBalance, QueryBatch, QueryContinuId, QueryMetaType, QueryMetaTypeViaAtom, QueryWalletBundle, QueryWalletList, Response, ResponseAppendRequest, ResponseAtom, ResponseBalance, ResponseContinuId, ResponseCreateMeta, ResponseCreateToken, ResponseCreateWallet, ResponseMetaType, ResponseMetaTypeViaAtom, ResponsePeering, ResponseProposeMolecule, ResponseRequestAuthorization, ResponseRequestTokens, ResponseTransferTokens, ResponseWalletBundle, ResponseWalletList, SDK_INFO, SDK_NAME, SDK_VERSION, SignatureMismatchException, TokenUnit, TransferBalanceException, Wallet, WalletCredentialException, base64ToHex, bufferToHexString, capitalize, charsetBaseConvert, chunkArray, chunkSubstr, configureSDK, convertToBase17, createBundleHash, createMolecularHash, createPosition, createTokenSlug, createWalletAddress, deepCloning, diff, enumerateMolecularHash, generateBatchId, generateBundleHash, generateOTSSignature, generatePosition, generateSecret, generateWalletAddress, generateWalletKey, getSDKConfig, hexStringToBuffer, hexToBase64, intersect, isAtomIsotope, isBundleHash, isHex, isHexString, isMolecularHash, isNumeric, isPosition2 as isPosition, isWalletAddress2 as isWalletAddress, normalizeMolecularHash, randomString, runCompatibilityTests, runExtendedCompatibilityTests, shake256, toCamelCase, toSnakeCase, truncate, validateBundleHash, validateMolecularHashForSignature, validateOTSSignature, validatePosition, validateSecret, validateWalletAddress, verifyOTSSignature };
11815
+ export { Atom, AtomIndexException, AtomMeta, AtomsMissingException, AuthToken, BaseException, COMPATIBLE_SERVER_VERSIONS, CRYPTO_CONSTANTS, CheckMolecule, DevUtils, Dot, EXCEPTION_CODES, EXCEPTION_TYPES, EXTENDED_COMPATIBILITY_TEST_VECTORS, ExceptionFactory, GraphQLClient, InvalidResponseException, KnishIO, KnishIOClient, Meta, MolecularHashMismatchException, Molecule, Mutation, MutationAppendRequest, MutationCreateMeta, MutationCreateToken, MutationCreateWallet, MutationPeering, MutationProposeMolecule, MutationRequestAuthorization, MutationRequestTokens, MutationTransferTokens, PolicyMeta, Query, QueryAtom, QueryBalance, QueryBatch, QueryContinuId, QueryEmbeddingStatus, QueryMetaType, QueryMetaTypeViaAtom, QueryWalletBundle, QueryWalletList, Response, ResponseAppendRequest, ResponseAtom, ResponseBalance, ResponseContinuId, ResponseCreateMeta, ResponseCreateToken, ResponseCreateWallet, ResponseEmbeddingStatus, ResponseMetaType, ResponseMetaTypeViaAtom, ResponsePeering, ResponseProposeMolecule, ResponseRequestAuthorization, ResponseRequestTokens, ResponseTransferTokens, ResponseWalletBundle, ResponseWalletList, SDK_INFO, SDK_NAME, SDK_VERSION, SignatureMismatchException, TokenUnit, TransferBalanceException, Wallet, WalletCredentialException, base64ToHex, bufferToHexString, capitalize, charsetBaseConvert, chunkArray, chunkSubstr, configureSDK, convertToBase17, createBundleHash, createMolecularHash, createPosition, createTokenSlug, createWalletAddress, deepCloning, diff, enumerateMolecularHash, generateBatchId, generateBundleHash, generateOTSSignature, generatePosition, generateSecret, generateWalletAddress, generateWalletKey, getSDKConfig, hexStringToBuffer, hexToBase64, intersect, isAtomIsotope, isBundleHash, isHex, isHexString, isMolecularHash, isNumeric, isPosition2 as isPosition, isWalletAddress2 as isWalletAddress, normalizeMolecularHash, randomString, runCompatibilityTests, runExtendedCompatibilityTests, shake256, toCamelCase, toSnakeCase, truncate, validateBundleHash, validateMolecularHashForSignature, validateOTSSignature, validatePosition, validateSecret, validateWalletAddress, verifyOTSSignature };
11563
11816
  //# sourceMappingURL=index.js.map
11564
11817
  //# sourceMappingURL=index.js.map