@kent-tokyo/chematic 0.8.0 → 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/README.md CHANGED
@@ -30,6 +30,10 @@ npm install @kent-tokyo/chematic
30
30
  - SVG grid layout for multiple molecules
31
31
  - Reaction SMILES/SMIRKS parsing and transform
32
32
  - Add/remove explicit hydrogens
33
+ - `embed_pipeline_v2_json`: torsion-knowledge-aware 3D embedding + stereo
34
+ verification/repair + policy-gated force field, mirroring the Python
35
+ `Mol.embed_pipeline_v2()` binding — opt-in, not a default 3D API
36
+ ([usage](#3d-embedding-embed_pipeline_v2_json))
33
37
 
34
38
  ## Usage
35
39
 
@@ -96,6 +100,43 @@ const ifg = JSON.parse(identify_functional_groups(mol));
96
100
  console.log(ifg); // [{"atoms":[1,2,3],"types":"OC=O"}, ...]
97
101
  ```
98
102
 
103
+ ### 3D embedding (`embed_pipeline_v2_json`)
104
+
105
+ Opt-in — does not change behavior of any existing 3D API (`generate_coords`,
106
+ `generate_and_minimize_*`, etc.), which remain the defaults.
107
+
108
+ ```js
109
+ const response = JSON.parse(embed_pipeline_v2_json(mol, JSON.stringify({
110
+ embedSeed: 7,
111
+ maxAttempts: 8,
112
+ embedTimeoutMs: null,
113
+ useExpTorsions: false,
114
+ useSmallRingTorsions: false,
115
+ useMacrocycleTorsions: false,
116
+ useMacrocycle14Bounds: false,
117
+ includeLegacyTorsionHeuristic: false,
118
+ stereoPolicy: "ignore",
119
+ failOnUnevaluableStereo: false,
120
+ forceFieldPolicy: "none",
121
+ forceFieldMaxIterations: 200,
122
+ gateMmff94TorsionOop: false,
123
+ ringTorsionPolicy: "fail_closed",
124
+ totalTimeoutMs: null,
125
+ })));
126
+ // response.ok, response.result / response.error — same shape as
127
+ // Mol.embed_pipeline_v2() in the Python binding.
128
+ ```
129
+
130
+ Verified working end-to-end under real WASM (both `wasm-pack --target nodejs`
131
+ and `--target web`, the latter being what this package's npm build actually
132
+ uses) — success, typed-failure, and typed-timeout paths all return real
133
+ results. `embedTimeoutMs`/`totalTimeoutMs` use a monotonic clock that's
134
+ portable across native and `wasm32-unknown-unknown`
135
+ ([`web-time`](https://crates.io/crates/web-time), backed by
136
+ `Performance.now()` in the browser); this does not claim identical wall-clock
137
+ precision across every JS engine, only that the value is finite, non-negative,
138
+ and enforced correctly on all of them.
139
+
99
140
  ## Version History
100
141
 
101
142
  **v0.1.94** (2026-06-12):
@@ -790,6 +790,25 @@ export function ecfp6_bitvec_with_chirality(mol: MolHandle, use_chirality: boole
790
790
  */
791
791
  export function ecfp_bitvec_custom(mol: MolHandle, radius: number, nbits: number, use_chirality: boolean): Uint8Array;
792
792
 
793
+ /**
794
+ * Run the opt-in v2 embedding pipeline, applied directly to `mol`'s own atom
795
+ * order (never canonicalizes/reparses -- see the module doc).
796
+ *
797
+ * `config_json` must be an object with exactly the 15 fields `PipelineV2Config`
798
+ * requires (camelCase keys: `embedSeed`, `maxAttempts`, `embedTimeoutMs`,
799
+ * `useExpTorsions`, `useSmallRingTorsions`, `useMacrocycleTorsions`,
800
+ * `useMacrocycle14Bounds`, `includeLegacyTorsionHeuristic`, `stereoPolicy`,
801
+ * `failOnUnevaluableStereo`, `forceFieldPolicy`, `forceFieldMaxIterations`,
802
+ * `gateMmff94TorsionOop`, `ringTorsionPolicy`, `totalTimeoutMs`) -- an unknown
803
+ * field, a missing field, an unknown `stereoPolicy`/`ringTorsionPolicy`/
804
+ * `forceFieldPolicy` string, or a wrong-typed/out-of-range integer all fail
805
+ * closed rather than silently defaulting.
806
+ *
807
+ * Never throws. Always returns a JSON string tagged with `schemaVersion: 1` and
808
+ * `ok: true`/`false` -- see the module doc for both shapes.
809
+ */
810
+ export function embed_pipeline_v2_json(mol: MolHandle, config_json: string): string;
811
+
793
812
  /**
794
813
  * Enumerate a combinatorial library from a SMIRKS template and two fragment sets.
795
814
  *
@@ -1612,6 +1631,32 @@ export function rdkit_ecfp_config_detail_json(mol: MolHandle, radius: number, nb
1612
1631
  */
1613
1632
  export function remove_hydrogens(mol: MolHandle): MolHandle;
1614
1633
 
1634
+ /**
1635
+ * Single-step retrosynthetic disconnection (issue #91).
1636
+ *
1637
+ * Thin wrapper around [`chematic_rxn::retro::retro_disconnect`] -- applies
1638
+ * the same built-in 60-template SMIRKS library and returns identical
1639
+ * disconnections (same templates, same precursor sets, same ordering:
1640
+ * fewest precursors first) as the Rust and Python (`Mol.retro_disconnect()`)
1641
+ * APIs. This function changes nothing about the underlying algorithm; it
1642
+ * only serializes the result to JSON.
1643
+ *
1644
+ * `max_results` -- cap on returned disconnections (0 = unlimited).
1645
+ *
1646
+ * `reaction_class` -- filter to a single reaction class, or `""` for all
1647
+ * classes. Valid values: `"AmideBond"`, `"Ester"`, `"Ether"`, `"CNBond"`,
1648
+ * `"CCBond"`, `"CSBond"`, `"Other"`. An unrecognized non-empty value is a
1649
+ * JS error (not silently ignored).
1650
+ *
1651
+ * JSON schema: array of
1652
+ * `{"template":str,"reaction_class":str,"precursors":[str,...],"sa_scores":[number,...],"max_sa_score":number}`
1653
+ * -- same field names as the Python binding's dict output. Returns `[]`
1654
+ * when no template matches the molecule (e.g. it has no disconnectable
1655
+ * bond the template library recognizes) -- a valid, non-error result,
1656
+ * distinct from the `reaction_class` validation error above.
1657
+ */
1658
+ export function retro_disconnect_json(mol: MolHandle, max_results: number, reaction_class: string): string;
1659
+
1615
1660
  /**
1616
1661
  * Decompose a set of molecules against a core SMARTS, returning R-group SMILES.
1617
1662
  *
@@ -2047,6 +2092,7 @@ export interface InitOutput {
2047
2092
  readonly ecfp6_bitvec: (a: number) => [number, number];
2048
2093
  readonly ecfp6_bitvec_with_chirality: (a: number, b: number) => [number, number];
2049
2094
  readonly ecfp_bitvec_custom: (a: number, b: number, c: number, d: number) => [number, number];
2095
+ readonly embed_pipeline_v2_json: (a: number, b: number, c: number) => [number, number];
2050
2096
  readonly enumerate_library_2way: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number, number];
2051
2097
  readonly enumerate_stereo_isomers_json: (a: number) => [number, number, number, number];
2052
2098
  readonly enumerate_tautomers_json: (a: number) => [number, number];
@@ -2217,6 +2263,7 @@ export interface InitOutput {
2217
2263
  readonly rdkit_ecfp_config_bitvec: (a: number, b: number, c: number) => [number, number, number, number];
2218
2264
  readonly rdkit_ecfp_config_detail_json: (a: number, b: number, c: number) => [number, number, number, number];
2219
2265
  readonly remove_hydrogens: (a: number) => number;
2266
+ readonly retro_disconnect_json: (a: number, b: number, c: number, d: number) => [number, number, number, number];
2220
2267
  readonly rgroup_decompose_json: (a: number, b: number, c: number, d: number) => [number, number, number, number];
2221
2268
  readonly ring_families_json: (a: number) => [number, number, number, number];
2222
2269
  readonly run_reactants: (a: number, b: number, c: number, d: number) => [number, number, number, number];
@@ -2265,6 +2312,7 @@ export interface InitOutput {
2265
2312
  readonly start: () => void;
2266
2313
  readonly __wbindgen_malloc: (a: number, b: number) => number;
2267
2314
  readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
2315
+ readonly __externref_table_alloc: () => number;
2268
2316
  readonly __wbindgen_externrefs: WebAssembly.Table;
2269
2317
  readonly __wbindgen_free: (a: number, b: number, c: number) => void;
2270
2318
  readonly __externref_table_dealloc: (a: number) => void;
package/chematic_wasm.js CHANGED
@@ -1886,6 +1886,42 @@ export function ecfp_bitvec_custom(mol, radius, nbits, use_chirality) {
1886
1886
  return v1;
1887
1887
  }
1888
1888
 
1889
+ /**
1890
+ * Run the opt-in v2 embedding pipeline, applied directly to `mol`'s own atom
1891
+ * order (never canonicalizes/reparses -- see the module doc).
1892
+ *
1893
+ * `config_json` must be an object with exactly the 15 fields `PipelineV2Config`
1894
+ * requires (camelCase keys: `embedSeed`, `maxAttempts`, `embedTimeoutMs`,
1895
+ * `useExpTorsions`, `useSmallRingTorsions`, `useMacrocycleTorsions`,
1896
+ * `useMacrocycle14Bounds`, `includeLegacyTorsionHeuristic`, `stereoPolicy`,
1897
+ * `failOnUnevaluableStereo`, `forceFieldPolicy`, `forceFieldMaxIterations`,
1898
+ * `gateMmff94TorsionOop`, `ringTorsionPolicy`, `totalTimeoutMs`) -- an unknown
1899
+ * field, a missing field, an unknown `stereoPolicy`/`ringTorsionPolicy`/
1900
+ * `forceFieldPolicy` string, or a wrong-typed/out-of-range integer all fail
1901
+ * closed rather than silently defaulting.
1902
+ *
1903
+ * Never throws. Always returns a JSON string tagged with `schemaVersion: 1` and
1904
+ * `ok: true`/`false` -- see the module doc for both shapes.
1905
+ * @param {MolHandle} mol
1906
+ * @param {string} config_json
1907
+ * @returns {string}
1908
+ */
1909
+ export function embed_pipeline_v2_json(mol, config_json) {
1910
+ let deferred2_0;
1911
+ let deferred2_1;
1912
+ try {
1913
+ _assertClass(mol, MolHandle);
1914
+ const ptr0 = passStringToWasm0(config_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1915
+ const len0 = WASM_VECTOR_LEN;
1916
+ const ret = wasm.embed_pipeline_v2_json(mol.__wbg_ptr, ptr0, len0);
1917
+ deferred2_0 = ret[0];
1918
+ deferred2_1 = ret[1];
1919
+ return getStringFromWasm0(ret[0], ret[1]);
1920
+ } finally {
1921
+ wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
1922
+ }
1923
+ }
1924
+
1889
1925
  /**
1890
1926
  * Enumerate a combinatorial library from a SMIRKS template and two fragment sets.
1891
1927
  *
@@ -4058,6 +4094,56 @@ export function remove_hydrogens(mol) {
4058
4094
  return MolHandle.__wrap(ret);
4059
4095
  }
4060
4096
 
4097
+ /**
4098
+ * Single-step retrosynthetic disconnection (issue #91).
4099
+ *
4100
+ * Thin wrapper around [`chematic_rxn::retro::retro_disconnect`] -- applies
4101
+ * the same built-in 60-template SMIRKS library and returns identical
4102
+ * disconnections (same templates, same precursor sets, same ordering:
4103
+ * fewest precursors first) as the Rust and Python (`Mol.retro_disconnect()`)
4104
+ * APIs. This function changes nothing about the underlying algorithm; it
4105
+ * only serializes the result to JSON.
4106
+ *
4107
+ * `max_results` -- cap on returned disconnections (0 = unlimited).
4108
+ *
4109
+ * `reaction_class` -- filter to a single reaction class, or `""` for all
4110
+ * classes. Valid values: `"AmideBond"`, `"Ester"`, `"Ether"`, `"CNBond"`,
4111
+ * `"CCBond"`, `"CSBond"`, `"Other"`. An unrecognized non-empty value is a
4112
+ * JS error (not silently ignored).
4113
+ *
4114
+ * JSON schema: array of
4115
+ * `{"template":str,"reaction_class":str,"precursors":[str,...],"sa_scores":[number,...],"max_sa_score":number}`
4116
+ * -- same field names as the Python binding's dict output. Returns `[]`
4117
+ * when no template matches the molecule (e.g. it has no disconnectable
4118
+ * bond the template library recognizes) -- a valid, non-error result,
4119
+ * distinct from the `reaction_class` validation error above.
4120
+ * @param {MolHandle} mol
4121
+ * @param {number} max_results
4122
+ * @param {string} reaction_class
4123
+ * @returns {string}
4124
+ */
4125
+ export function retro_disconnect_json(mol, max_results, reaction_class) {
4126
+ let deferred3_0;
4127
+ let deferred3_1;
4128
+ try {
4129
+ _assertClass(mol, MolHandle);
4130
+ const ptr0 = passStringToWasm0(reaction_class, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
4131
+ const len0 = WASM_VECTOR_LEN;
4132
+ const ret = wasm.retro_disconnect_json(mol.__wbg_ptr, max_results, ptr0, len0);
4133
+ var ptr2 = ret[0];
4134
+ var len2 = ret[1];
4135
+ if (ret[3]) {
4136
+ ptr2 = 0; len2 = 0;
4137
+ throw takeFromExternrefTable0(ret[2]);
4138
+ }
4139
+ deferred3_0 = ptr2;
4140
+ deferred3_1 = len2;
4141
+ return getStringFromWasm0(ptr2, len2);
4142
+ } finally {
4143
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
4144
+ }
4145
+ }
4146
+
4061
4147
  /**
4062
4148
  * Decompose a set of molecules against a core SMARTS, returning R-group SMILES.
4063
4149
  *
@@ -5108,6 +5194,10 @@ export function xlogp3_per_atom_json(mol) {
5108
5194
  function __wbg_get_imports() {
5109
5195
  const import0 = {
5110
5196
  __proto__: null,
5197
+ __wbg___wbindgen_is_undefined_c05833b95a3cf397: function(arg0) {
5198
+ const ret = arg0 === undefined;
5199
+ return ret;
5200
+ },
5111
5201
  __wbg___wbindgen_string_get_b0ca35b86a603356: function(arg0, arg1) {
5112
5202
  const obj = arg1;
5113
5203
  const ret = typeof(obj) === 'string' ? obj : undefined;
@@ -5122,6 +5212,30 @@ function __wbg_get_imports() {
5122
5212
  __wbg_error_744744ff0c9861e6: function(arg0) {
5123
5213
  console.error(arg0);
5124
5214
  },
5215
+ __wbg_now_e7c6795a7f81e10f: function(arg0) {
5216
+ const ret = arg0.now();
5217
+ return ret;
5218
+ },
5219
+ __wbg_performance_3fcf6e32a7e1ed0a: function(arg0) {
5220
+ const ret = arg0.performance;
5221
+ return ret;
5222
+ },
5223
+ __wbg_static_accessor_GLOBAL_4ef717fb391d88b7: function() {
5224
+ const ret = typeof global === 'undefined' ? null : global;
5225
+ return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
5226
+ },
5227
+ __wbg_static_accessor_GLOBAL_THIS_8d1badc68b5a74f4: function() {
5228
+ const ret = typeof globalThis === 'undefined' ? null : globalThis;
5229
+ return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
5230
+ },
5231
+ __wbg_static_accessor_SELF_146583524fe1469b: function() {
5232
+ const ret = typeof self === 'undefined' ? null : self;
5233
+ return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
5234
+ },
5235
+ __wbg_static_accessor_WINDOW_f2829a2234d7819e: function() {
5236
+ const ret = typeof window === 'undefined' ? null : window;
5237
+ return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
5238
+ },
5125
5239
  __wbindgen_cast_0000000000000001: function(arg0) {
5126
5240
  // Cast intrinsic for `F64 -> Externref`.
5127
5241
  const ret = arg0;
@@ -5161,6 +5275,12 @@ const MolHandleFinalization = (typeof FinalizationRegistry === 'undefined')
5161
5275
  ? { register: () => {}, unregister: () => {} }
5162
5276
  : new FinalizationRegistry(ptr => wasm.__wbg_molhandle_free(ptr, 1));
5163
5277
 
5278
+ function addToExternrefTable0(obj) {
5279
+ const idx = wasm.__externref_table_alloc();
5280
+ wasm.__wbindgen_externrefs.set(idx, obj);
5281
+ return idx;
5282
+ }
5283
+
5164
5284
  function _assertClass(instance, klass) {
5165
5285
  if (!(instance instanceof klass)) {
5166
5286
  throw new Error(`expected instance of ${klass.name}`);
Binary file
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "kent-tokyo <kent-tokyo@users.noreply.github.com>"
6
6
  ],
7
7
  "description": "WebAssembly bindings for chematic — use chematic from JavaScript/TypeScript",
8
- "version": "0.8.0",
8
+ "version": "0.9.0",
9
9
  "license": "MIT OR Apache-2.0",
10
10
  "repository": {
11
11
  "type": "git",