@toolpath/tool-scraper 0.1.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/LICENSE +21 -0
- package/README.md +98 -0
- package/dist/conventions.d.ts +124 -0
- package/dist/conventions.js +143 -0
- package/dist/errors.d.ts +46 -0
- package/dist/errors.js +53 -0
- package/dist/families/destinytool.d.ts +49 -0
- package/dist/families/destinytool.js +55 -0
- package/dist/families/index.d.ts +59 -0
- package/dist/families/index.js +91 -0
- package/dist/families/kennametal.d.ts +757 -0
- package/dist/families/kennametal.js +660 -0
- package/dist/families/regofix.d.ts +185 -0
- package/dist/families/regofix.js +250 -0
- package/dist/family.d.ts +130 -0
- package/dist/family.js +38 -0
- package/dist/fetch.d.ts +98 -0
- package/dist/fetch.js +116 -0
- package/dist/identity.d.ts +133 -0
- package/dist/identity.js +118 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +31 -0
- package/dist/node/cad-mirror.d.ts +55 -0
- package/dist/node/cad-mirror.js +89 -0
- package/dist/node/cli.d.ts +35 -0
- package/dist/node/cli.js +340 -0
- package/dist/node/csv.d.ts +47 -0
- package/dist/node/csv.js +123 -0
- package/dist/node/index.d.ts +16 -0
- package/dist/node/index.js +16 -0
- package/dist/node/main.d.ts +13 -0
- package/dist/node/main.js +14 -0
- package/dist/node/paths.d.ts +60 -0
- package/dist/node/paths.js +80 -0
- package/dist/node/receipts.d.ts +100 -0
- package/dist/node/receipts.js +107 -0
- package/dist/order.d.ts +10 -0
- package/dist/order.js +12 -0
- package/dist/provenance.d.ts +125 -0
- package/dist/provenance.js +133 -0
- package/dist/records.d.ts +305 -0
- package/dist/records.js +297 -0
- package/dist/registry.d.ts +63 -0
- package/dist/registry.js +145 -0
- package/dist/scrape.d.ts +70 -0
- package/dist/scrape.js +37 -0
- package/dist/thread.d.ts +48 -0
- package/dist/thread.js +98 -0
- package/dist/uuid5.d.ts +31 -0
- package/dist/uuid5.js +64 -0
- package/dist/vendors/destinytool/index.d.ts +11 -0
- package/dist/vendors/destinytool/index.js +11 -0
- package/dist/vendors/destinytool/records.d.ts +118 -0
- package/dist/vendors/destinytool/records.js +266 -0
- package/dist/vendors/destinytool/scrape.d.ts +108 -0
- package/dist/vendors/destinytool/scrape.js +192 -0
- package/dist/vendors/kennametal/cad.d.ts +87 -0
- package/dist/vendors/kennametal/cad.js +119 -0
- package/dist/vendors/kennametal/index.d.ts +21 -0
- package/dist/vendors/kennametal/index.js +21 -0
- package/dist/vendors/kennametal/materials.d.ts +143 -0
- package/dist/vendors/kennametal/materials.js +200 -0
- package/dist/vendors/kennametal/records.d.ts +88 -0
- package/dist/vendors/kennametal/records.js +241 -0
- package/dist/vendors/kennametal/scrape.d.ts +111 -0
- package/dist/vendors/kennametal/scrape.js +226 -0
- package/dist/vendors/kennametal/thread-column.d.ts +28 -0
- package/dist/vendors/kennametal/thread-column.js +41 -0
- package/dist/vendors/regofix/index.d.ts +8 -0
- package/dist/vendors/regofix/index.js +8 -0
- package/dist/vendors/regofix/scrape.d.ts +237 -0
- package/dist/vendors/regofix/scrape.js +521 -0
- package/package.json +76 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* REGO-FIX powRgrip product index -> toolholding rows.
|
|
3
|
+
*
|
|
4
|
+
* Nothing here is shared with any other adapter beyond `conventions` —
|
|
5
|
+
* REGO-FIX is a Drupal site, not Kennametal's AEM platform, so the transport,
|
|
6
|
+
* the identity fields and the dimension source are all different. See
|
|
7
|
+
* `docs/REGOFIX_PRODUCTFINDER_API.md` for how the endpoint was found.
|
|
8
|
+
*
|
|
9
|
+
* ## Two sources, and both are needed
|
|
10
|
+
*
|
|
11
|
+
* **The roster** comes from the ProductFinder's Elasticsearch proxy: one POST
|
|
12
|
+
* returns every variant of a group with its part number, its designation, its
|
|
13
|
+
* PG series and its CAD links. It carries no geometry beyond the projection
|
|
14
|
+
* length.
|
|
15
|
+
*
|
|
16
|
+
* **The geometry** comes from a per-part DIN 4000 XML on the vendor's CDN,
|
|
17
|
+
* linked from each hit. Three of its codes are pinned to a meaning by
|
|
18
|
+
* REGO-FIX's own published tables and the rest are not:
|
|
19
|
+
*
|
|
20
|
+
* - **`B3`** — projection from the flange face. The `L` column of the BT/PG
|
|
21
|
+
* table in the PG product catalog, row for row.
|
|
22
|
+
* - **`B4`** — gage length. `B4 - B3 == 48.4` on every row, and 48.4 mm is
|
|
23
|
+
* BT 30's gauge-line-to-flange distance in the vendor's own standards table.
|
|
24
|
+
* - **`A1`** — diameter at the collet end. The `D` column of that same BT/PG
|
|
25
|
+
* table, row for row.
|
|
26
|
+
*
|
|
27
|
+
* `A2`, `B1`, `B2` and `B3_WOA` are carried into the CSV verbatim under their
|
|
28
|
+
* raw DIN codes and are **not** promoted onto a record. Nothing available here
|
|
29
|
+
* says what they measure, and the standing rule is to leave a vendor code
|
|
30
|
+
* unlabelled rather than guess at it (JG 2026-08-07). `conventions.DIN_PREFIX`
|
|
31
|
+
* is what keeps them from reading as promoted dimensions: a column named
|
|
32
|
+
* `A2_mm` would sit in the CSV looking exactly like `L1_mm`, which is mapped.
|
|
33
|
+
*
|
|
34
|
+
* There is a lead on pinning them honestly. REGO-FIX publishes
|
|
35
|
+
* `DXF_ISO13399/DXF` and `DXF_ISO13399/PDF` beside the `XML_DIN4000/XML` this
|
|
36
|
+
* module reads, so the standard this package's canonical names come from is
|
|
37
|
+
* already in the vendor's own source material.
|
|
38
|
+
*
|
|
39
|
+
* `A4` is 46 on every BT 30 holder — the flange diameter, a property of the
|
|
40
|
+
* taper and not of the part — so it is checked rather than stored.
|
|
41
|
+
*
|
|
42
|
+
* ## What the vendor gets wrong
|
|
43
|
+
*
|
|
44
|
+
* Three faults found on 2026-08-07, all reported as warnings rather than
|
|
45
|
+
* fixed: two disagreeing vendor cells cannot say which one is wrong, and a
|
|
46
|
+
* scraper that corrects one becomes a place tool data is authored by hand.
|
|
47
|
+
*
|
|
48
|
+
* 1. `4130.70646`'s XML states its own part number as `4130.71646`.
|
|
49
|
+
* 2. `J22`, the XML's own product-line label, says "PG-SG secuRgrip
|
|
50
|
+
* Werkzeughalter" on several plain BT 30 holders that are not secuRgrip
|
|
51
|
+
* parts. It is never read.
|
|
52
|
+
* 3. `o_mm` on a tapping collet repeats the previous row's value twice
|
|
53
|
+
* (`1715.08215` and `1725.08215`). This is why the nominal size is parsed
|
|
54
|
+
* from the vendor's own designation and `o_mm` is only ever a cross-check.
|
|
55
|
+
*/
|
|
56
|
+
import { type Fetcher } from '../../fetch.js';
|
|
57
|
+
import { type ScrapeResult, type ScrapedRow, type Warn } from '../../scrape.js';
|
|
58
|
+
export declare const MM_PER_INCH = 25.4;
|
|
59
|
+
/**
|
|
60
|
+
* The Searchkit proxy the ProductFinder posts its Elasticsearch queries to.
|
|
61
|
+
* Discovered by reading the app bundle, which constructs
|
|
62
|
+
* `SearchkitManager(origin + '/' + lang, {searchUrlPath: '/elastic/post'})`.
|
|
63
|
+
*/
|
|
64
|
+
export declare const SEARCH_URL = "https://us.rego-fix.com/en/elastic/post";
|
|
65
|
+
/**
|
|
66
|
+
* Where a part's DIN 4000 XML lives. The filename is the part number with its
|
|
67
|
+
* dot removed, which is also `field_sku_ngram`.
|
|
68
|
+
*/
|
|
69
|
+
export declare const DIN4000_URL: string;
|
|
70
|
+
/**
|
|
71
|
+
* Gauge line to flange face, JIS B 6339 / MAS 403 size 30, as published in the
|
|
72
|
+
* vendor's own interface table (PG product catalog, "BT MAS 403":
|
|
73
|
+
* `BT 30 | 31.75 | 46 | 2 | 48.4 | 20 | M 12`). Used to *verify* that `B4` is
|
|
74
|
+
* the gage length rather than to compute one — both numbers are scraped, and
|
|
75
|
+
* their difference is what identifies the code.
|
|
76
|
+
*/
|
|
77
|
+
export declare const BT30_GAUGE_TO_FLANGE = 48.4;
|
|
78
|
+
/** Flange diameter of a BT 30 taper, from the same row. `A4` on every holder. */
|
|
79
|
+
export declare const BT30_FLANGE_DIAMETER = 46;
|
|
80
|
+
/**
|
|
81
|
+
* DIN 4000 codes carried into the CSV verbatim because nothing here says what
|
|
82
|
+
* they measure. Written out rather than "everything else" so that a code the
|
|
83
|
+
* vendor adds later shows up as an unhandled key instead of silently appearing
|
|
84
|
+
* as a column.
|
|
85
|
+
*/
|
|
86
|
+
export declare const UNPINNED_DIN_CODES: readonly ["A2", "B1", "B2", "B3_WOA"];
|
|
87
|
+
/**
|
|
88
|
+
* `form_name`, the vendor's own field, mapped to this catalog's `contact`
|
|
89
|
+
* axis. `Plus +` is REGO-FIX's designation for the dual-contact shank that
|
|
90
|
+
* seats on the spindle face as well as the cone — the same distinction
|
|
91
|
+
* Kennametal sells as BTKV. It is a **scraped fact here**, not family config,
|
|
92
|
+
* because REGO-FIX publishes both forms in one product group:
|
|
93
|
+
* `BT 30 / PG 25 x 080 H` and `BT+ 30 / PG 25 x 080 H` are two rows of one
|
|
94
|
+
* table.
|
|
95
|
+
*
|
|
96
|
+
* There is no default. A third form is a stop-and-ask, and `BT-OM 30` is
|
|
97
|
+
* already sitting in that table undefined — nothing on the vendor's site or in
|
|
98
|
+
* its catalog says what OM designates, so its three parts are deliberately not
|
|
99
|
+
* scraped (JG 2026-08-07).
|
|
100
|
+
*/
|
|
101
|
+
export declare const CONTACT_BY_FORM: Record<string, string>;
|
|
102
|
+
/**
|
|
103
|
+
* The taper designations this package scrapes, and what they mean.
|
|
104
|
+
*
|
|
105
|
+
* `BT-OM 30` is published in the same product group and is **not** here: the
|
|
106
|
+
* family page, the product catalog and the ProductFinder all print the token
|
|
107
|
+
* and none of them says what OM designates, so recording a spindle interface
|
|
108
|
+
* for it would be a guess about which machine a holder fits (JG 2026-08-07).
|
|
109
|
+
* Its three parts are a stop-and-ask, not an omission to fix silently.
|
|
110
|
+
*/
|
|
111
|
+
export declare const SCRAPED_TAPERS: readonly ["BT 30", "BT+ 30"];
|
|
112
|
+
/** One Elasticsearch `_source`: every value is a list, even a single one. */
|
|
113
|
+
export type Source = Record<string, unknown>;
|
|
114
|
+
/**
|
|
115
|
+
* Every `_source` matching an AND of term filters, newest index first.
|
|
116
|
+
*
|
|
117
|
+
* One request: the index holds 4142 products in total and the largest group
|
|
118
|
+
* asked for here is 321, so there is nothing to page. `size` is an explicit
|
|
119
|
+
* ceiling rather than a page length, and going over it throws — a silently
|
|
120
|
+
* truncated roster is the failure this whole package is built to notice.
|
|
121
|
+
*/
|
|
122
|
+
export declare function search(fetcher: Fetcher, filters: Record<string, string>, size?: number): Promise<Source[]>;
|
|
123
|
+
/**
|
|
124
|
+
* A field of an Elasticsearch `_source`, which stores every value as a list
|
|
125
|
+
* even when there is exactly one.
|
|
126
|
+
*
|
|
127
|
+
* Missing and empty are both null: `o_inch` is absent on a metric collet,
|
|
128
|
+
* which is the vendor saying it is metric rather than a gap.
|
|
129
|
+
*/
|
|
130
|
+
export declare function one(source: Source, field: string): string | number | null;
|
|
131
|
+
/**
|
|
132
|
+
* DIN 4000 property codes to their values, empty ones dropped.
|
|
133
|
+
*
|
|
134
|
+
* The document repeats a `<PropertyName>`/`<Value>` pair per property and
|
|
135
|
+
* states most of them empty, so dropping blanks is what makes "the vendor
|
|
136
|
+
* published this" and "the vendor published a hole" different states.
|
|
137
|
+
*
|
|
138
|
+
* Throws on a document with no properties at all rather than returning an
|
|
139
|
+
* empty map, for the reason `kennametal.parseVariantTable` throws on an
|
|
140
|
+
* unparseable response: reporting a changed format as no data looks exactly
|
|
141
|
+
* like a discontinued part.
|
|
142
|
+
*/
|
|
143
|
+
export declare function parseDin4000(xml: string): Record<string, string>;
|
|
144
|
+
/**
|
|
145
|
+
* One part's DIN 4000 properties, or null when the vendor publishes none.
|
|
146
|
+
*
|
|
147
|
+
* Null is a real state — two of the BT+ 30 holders have DXF and PDF but no XML
|
|
148
|
+
* — and it is distinguished from a failed request, which throws. A holder with
|
|
149
|
+
* no XML has no gage length and cannot be converted, so it is the caller that
|
|
150
|
+
* decides what to do about it.
|
|
151
|
+
*/
|
|
152
|
+
export declare function fetchDin4000(fetcher: Fetcher, sku: string): Promise<Record<string, string> | null>;
|
|
153
|
+
/**
|
|
154
|
+
* A number as the vendor would print it: no trailing `.0` on an integer.
|
|
155
|
+
*
|
|
156
|
+
* The CSV is read back as a number, so this only decides what a human and a
|
|
157
|
+
* git diff see — and `10` rather than `10.0` is what the vendor's own
|
|
158
|
+
* designation says.
|
|
159
|
+
*/
|
|
160
|
+
export declare function plain(value: string | number | null | undefined): string;
|
|
161
|
+
/** `1/4` or `3.5` — the vendor prints both, and both are exact here. */
|
|
162
|
+
export declare function parseSize(size: string): number;
|
|
163
|
+
/**
|
|
164
|
+
* The part's STEP model, absolute, or empty when none is published.
|
|
165
|
+
*
|
|
166
|
+
* The index gives protocol-relative CDN URLs, and `conventions.CAD_COLUMN`
|
|
167
|
+
* holds a URL a consumer can fetch — so the scheme is added here rather than
|
|
168
|
+
* left for every reader to guess at.
|
|
169
|
+
*/
|
|
170
|
+
export declare function cadUrl(source: Source): string;
|
|
171
|
+
/**
|
|
172
|
+
* One search hit plus its DIN 4000 properties -> one row.
|
|
173
|
+
*
|
|
174
|
+
* Column names are the shared toolholding vocabulary rather than REGO-FIX's
|
|
175
|
+
* own, so a consumer reads a REGO-FIX holder exactly as it reads a Kennametal
|
|
176
|
+
* one — `L1` is the gage length whoever published it. The DIN codes those came
|
|
177
|
+
* from are in this module's docstring; the ones that stay unmapped keep their
|
|
178
|
+
* raw code behind `conventions.DIN_PREFIX`.
|
|
179
|
+
*
|
|
180
|
+
* **This is the one place a REGO-FIX label is rewritten, and it is a
|
|
181
|
+
* holder-geometry label rather than an identity or a dimension code.** The
|
|
182
|
+
* identity columns are Kennametal's, adopted here because this vendor came
|
|
183
|
+
* second — see `conventions.IDENTITY_COLUMNS`.
|
|
184
|
+
*
|
|
185
|
+
* `D1` is deliberately absent. A powRgrip holder clamps through a collet, and
|
|
186
|
+
* a collet-clamping holder that also carried a bore would be claiming two ways
|
|
187
|
+
* of gripping one tool.
|
|
188
|
+
*/
|
|
189
|
+
export declare function holderRow(source: Source, properties: Record<string, string>, warn?: Warn): ScrapedRow;
|
|
190
|
+
/**
|
|
191
|
+
* One search hit -> one row, with the nominal size read off the vendor's own
|
|
192
|
+
* designation.
|
|
193
|
+
*
|
|
194
|
+
* **The size comes from the title, not from `o_mm`.** `o_mm` is rounded to two
|
|
195
|
+
* decimals, which puts a 1/8 in collet at 3.18 mm where the part is 3.175 —
|
|
196
|
+
* five microns out, against the two-micron tolerance a fit test sizes its
|
|
197
|
+
* equality to, so every inch collet would have failed to match its own shank
|
|
198
|
+
* size. It is also wrong outright on two tapping collets, where it repeats the
|
|
199
|
+
* previous row's value. The title states the vendor's designation exactly
|
|
200
|
+
* (`Ø 1/4"`, `Ø 3.5 mm`) and says which unit system it is in, so it is both
|
|
201
|
+
* more precise and the only source here that carries a unit at all.
|
|
202
|
+
*
|
|
203
|
+
* `o_mm` is kept as a cross-check column rather than dropped, the same way
|
|
204
|
+
* Kennametal's contradictory unit cells are kept: it is what the vendor said.
|
|
205
|
+
*/
|
|
206
|
+
export declare function colletRow(source: Source, warn?: Warn): ScrapedRow;
|
|
207
|
+
/**
|
|
208
|
+
* Rows to a result whose header is the union of their keys, in first-seen
|
|
209
|
+
* order.
|
|
210
|
+
*
|
|
211
|
+
* A union rather than the first row's keys: a mixed-unit collet family has
|
|
212
|
+
* `D1_mm` on its metric rows and `D1_in` on its inch ones, and keying off row
|
|
213
|
+
* one would drop whichever came second.
|
|
214
|
+
*/
|
|
215
|
+
export declare function unionHeader(rows: readonly ScrapedRow[]): string[];
|
|
216
|
+
/** Options every REGO-FIX scrape accepts. */
|
|
217
|
+
export interface RegofixOptions {
|
|
218
|
+
warn?: Warn;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Every powRgrip holder of `group` whose taper is in {@link SCRAPED_TAPERS}.
|
|
222
|
+
*
|
|
223
|
+
* Two requests' worth of work per part — the roster is one POST, then one DIN
|
|
224
|
+
* 4000 document each. A part the vendor publishes no XML for is dropped with a
|
|
225
|
+
* message rather than written with holes: a gage length is required, and a
|
|
226
|
+
* holder without one fails conversion anyway.
|
|
227
|
+
*/
|
|
228
|
+
export declare function scrapeHolders(fetcher: Fetcher, group?: string, category?: string, options?: RegofixOptions): Promise<ScrapeResult>;
|
|
229
|
+
/**
|
|
230
|
+
* Every powRgrip collet of one product group, in the given PG sizes.
|
|
231
|
+
*
|
|
232
|
+
* `sizes` are the vendor's `norm_size` values — the PG series numbers a BT 30
|
|
233
|
+
* holder can take. It is an argument rather than "all of them" because the
|
|
234
|
+
* sizes are what tie a collet family to the holders in this catalog: PG 32 and
|
|
235
|
+
* PG 48 collets exist and no BT 30 holder accepts one.
|
|
236
|
+
*/
|
|
237
|
+
export declare function scrapeCollets(fetcher: Fetcher, group: string, sizes: readonly string[], options?: RegofixOptions): Promise<ScrapeResult>;
|