tranfi 0.1.2 → 0.2.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.
Files changed (132) hide show
  1. package/LICENSE +177 -0
  2. package/NOTICE +8 -0
  3. package/README.md +272 -40
  4. package/app/assets/{index-pDFMluyz.js → index-BIAIKnrp.js} +1 -1
  5. package/app/index.html +1 -1
  6. package/binding.gyp +55 -3
  7. package/csrc/arena.c +7 -5
  8. package/csrc/batch.c +818 -71
  9. package/csrc/buffer.c +84 -8
  10. package/csrc/cJSON.c +262 -19
  11. package/csrc/cJSON.h +17 -1
  12. package/csrc/codec_csv.c +1074 -181
  13. package/csrc/codec_jsonl.c +830 -118
  14. package/csrc/codec_table.c +108 -78
  15. package/csrc/codec_text.c +286 -68
  16. package/csrc/compiler.c +31 -3
  17. package/csrc/config.h +21 -0
  18. package/csrc/dsl.c +4722 -485
  19. package/csrc/expr.c +363 -55
  20. package/csrc/expr.h +2 -0
  21. package/csrc/internal.h +316 -27
  22. package/csrc/ir.c +65 -18
  23. package/csrc/ir.h +41 -0
  24. package/csrc/ir_schema.c +20 -5
  25. package/csrc/ir_serialize.c +68 -6
  26. package/csrc/ir_sql.c +796 -185
  27. package/csrc/ir_validate.c +462 -6
  28. package/csrc/json_path.c +210 -0
  29. package/csrc/main.c +879 -30
  30. package/csrc/memory_estimate.c +477 -0
  31. package/csrc/op_acf.c +171 -21
  32. package/csrc/op_across.c +477 -0
  33. package/csrc/op_anomaly.c +167 -32
  34. package/csrc/op_assert.c +761 -0
  35. package/csrc/op_bin.c +168 -29
  36. package/csrc/op_cast.c +383 -55
  37. package/csrc/op_clip.c +30 -19
  38. package/csrc/op_date_trunc.c +208 -34
  39. package/csrc/op_datetime.c +259 -77
  40. package/csrc/op_derive.c +65 -97
  41. package/csrc/op_diff.c +146 -30
  42. package/csrc/op_ewma.c +149 -30
  43. package/csrc/op_explode.c +124 -26
  44. package/csrc/op_fill_down.c +125 -53
  45. package/csrc/op_fill_null.c +176 -31
  46. package/csrc/op_filter.c +89 -40
  47. package/csrc/op_frequency.c +571 -43
  48. package/csrc/op_grep.c +36 -18
  49. package/csrc/op_group_agg.c +1790 -119
  50. package/csrc/op_hash.c +48 -15
  51. package/csrc/op_head.c +21 -86
  52. package/csrc/op_interpolate.c +268 -62
  53. package/csrc/op_join.c +2700 -182
  54. package/csrc/op_json_extract.c +227 -0
  55. package/csrc/op_json_filter.c +384 -0
  56. package/csrc/op_json_flatten.c +293 -0
  57. package/csrc/op_json_schema.c +503 -0
  58. package/csrc/op_label_encode.c +328 -53
  59. package/csrc/op_lag.c +181 -0
  60. package/csrc/op_lead.c +141 -89
  61. package/csrc/op_normalize.c +363 -79
  62. package/csrc/op_onehot.c +345 -73
  63. package/csrc/op_pivot.c +1546 -162
  64. package/csrc/op_quarantine.c +189 -0
  65. package/csrc/op_registry.c +2062 -166
  66. package/csrc/op_rename.c +41 -50
  67. package/csrc/op_replace.c +270 -118
  68. package/csrc/op_rleid.c +297 -0
  69. package/csrc/op_rowid.c +559 -0
  70. package/csrc/op_sample.c +80 -23
  71. package/csrc/op_schema.c +1341 -0
  72. package/csrc/op_schema_infer.c +252 -0
  73. package/csrc/op_select.c +265 -65
  74. package/csrc/op_set.c +3449 -0
  75. package/csrc/op_skip.c +30 -87
  76. package/csrc/op_sort.c +670 -124
  77. package/csrc/op_source_name.c +120 -0
  78. package/csrc/op_split.c +65 -28
  79. package/csrc/op_split_data.c +41 -9
  80. package/csrc/op_stack.c +178 -222
  81. package/csrc/op_stats.c +206 -110
  82. package/csrc/op_step.c +217 -55
  83. package/csrc/op_tail.c +21 -12
  84. package/csrc/op_tee.c +338 -0
  85. package/csrc/op_top.c +260 -53
  86. package/csrc/op_trim.c +48 -19
  87. package/csrc/op_unique.c +1193 -150
  88. package/csrc/op_unpivot.c +100 -66
  89. package/csrc/op_validate.c +601 -24
  90. package/csrc/op_window.c +492 -51
  91. package/csrc/path_policy.c +85 -0
  92. package/csrc/pipeline.c +872 -99
  93. package/csrc/recipes.c +3 -1
  94. package/csrc/report.c +73 -30
  95. package/csrc/selector.c +1097 -0
  96. package/csrc/size_utils.c +348 -0
  97. package/csrc/spill.c +317 -0
  98. package/csrc/spill.h +21 -0
  99. package/csrc/tranfi.h +169 -1
  100. package/csrc/transform.h +209 -0
  101. package/csrc/transform_api.c +2237 -0
  102. package/csrc/transform_categorical.c +923 -0
  103. package/csrc/transform_internal.h +472 -0
  104. package/csrc/transform_json.c +3812 -0
  105. package/csrc/transform_numeric.c +1966 -0
  106. package/csrc/transform_sha256.c +154 -0
  107. package/csrc/transform_wasm.h +162 -0
  108. package/csrc/transform_wasm_api.c +1373 -0
  109. package/csrc/wasm_api.c +70 -9
  110. package/napi_api.c +219 -11
  111. package/napi_transform.c +1648 -0
  112. package/napi_transform.h +8 -0
  113. package/package.json +27 -11
  114. package/scripts/install-native.js +76 -0
  115. package/scripts/prepack.js +64 -0
  116. package/scripts/sync-csrc.js +23 -0
  117. package/src/cli.js +8 -11
  118. package/src/engines/duckdb.js +45 -12
  119. package/src/index.js +661 -42
  120. package/src/memory_policy.js +411 -0
  121. package/src/native.js +1 -5
  122. package/src/pipeline.js +454 -31
  123. package/src/recipe_json.js +80 -0
  124. package/src/server.js +10 -8
  125. package/src/transform.js +403 -0
  126. package/src/transform_error.js +10 -0
  127. package/src/wasm.js +6 -4
  128. package/wasm/index.js +498 -10
  129. package/wasm/tranfi_core.js +0 -0
  130. package/wasm/transform.js +1156 -0
  131. package/wasm/worker.js +786 -0
  132. package/csrc/plan.c +0 -206
package/src/server.js CHANGED
@@ -6,12 +6,12 @@
6
6
  * built-in http, fs, path, url modules only.
7
7
  */
8
8
 
9
- import { createServer } from 'http'
10
- import { readFileSync, readdirSync, statSync, readFile as readFileCb, existsSync } from 'fs'
11
- import { join, extname, resolve, basename } from 'path'
12
- import { URL } from 'url'
13
- import { pipeline, recipes } from './index.js'
14
- import nativeBinding from './native.js'
9
+ const { createServer } = require('http')
10
+ const { readFileSync, readdirSync, statSync, readFile: readFileCb, existsSync } = require('fs')
11
+ const { join, extname, resolve, basename } = require('path')
12
+ const { URL } = require('url')
13
+ const { pipeline, recipes } = require('./index.js')
14
+ const nativeBinding = require('./native.js')
15
15
 
16
16
  const MIME_TYPES = {
17
17
  '.html': 'text/html; charset=utf-8',
@@ -101,7 +101,7 @@ function isSafeName (name) {
101
101
  return name && !name.includes('..') && !name.includes('/') && !name.includes('\\')
102
102
  }
103
103
 
104
- export function startServer ({ port = 3000, dataDir, appDir }) {
104
+ function startServer ({ port = 3000, dataDir, appDir }) {
105
105
  dataDir = resolve(dataDir)
106
106
  appDir = resolve(appDir)
107
107
 
@@ -214,7 +214,7 @@ async function handleRun (res, dataDir, body) {
214
214
  if (!existsSync(filePath)) return sendError(res, `File not found: ${file}`, 404)
215
215
 
216
216
  const p = pipeline(dsl)
217
- const result = await p.run({ inputFile: filePath })
217
+ const result = await p.run({ inputFile: filePath, hostedAuditDefaults: true })
218
218
 
219
219
  const output = result.outputText
220
220
  const stats = result.statsText
@@ -275,3 +275,5 @@ function serveStatic (res, appDir, pathname, indexHtml) {
275
275
  res.end(data)
276
276
  })
277
277
  }
278
+
279
+ module.exports = { startServer }
@@ -0,0 +1,403 @@
1
+ /**
2
+ * Prepared, reusable typed transforms backed by Tranfi's C engine.
3
+ *
4
+ * These objects are separate from the byte-stream Pipeline API. Recipes analyze
5
+ * one or more typed batches, finalize an immutable plan, and apply that plan to
6
+ * a second pass over the reference data or to later compatible batches.
7
+ */
8
+
9
+ const { stringifyRecipe } = require('./recipe_json.js')
10
+ const nativeBinding = require('./native.js')
11
+ const { TranfiTransformError } = require('./transform_error.js')
12
+
13
+ const SCHEMA_INPUT = 1
14
+ const SCHEMA_OUTPUT = 2
15
+
16
+ const LIMIT_FIELDS = new Set([
17
+ 'maxRecipeBytes',
18
+ 'maxPlanBytes',
19
+ 'maxJsonDepth',
20
+ 'maxObjectKeys',
21
+ 'maxSteps',
22
+ 'maxInputColumns',
23
+ 'maxOutputColumns',
24
+ 'maxCategoriesPerColumn',
25
+ 'maxTotalCategories',
26
+ 'maxStringBytes',
27
+ 'maxDecodedStringBytes',
28
+ 'maxAnalyzerRows',
29
+ 'maxAnalyzerInputBytes',
30
+ 'maxResidentStateBytes',
31
+ 'maxSpillBytes',
32
+ 'maxApplyRows',
33
+ 'maxApplyInputBytes',
34
+ 'maxOutputElementsPerCall',
35
+ 'maxAllocationBytes',
36
+ 'maxAllocationsPerSession',
37
+ 'maxLiveHandles',
38
+ 'maxRetiredHandleSlots'
39
+ ])
40
+ const RUNTIME_OPTION_FIELDS = new Set([
41
+ 'limits', 'cancelFlag', 'hostPolicy', 'spillDir'
42
+ ])
43
+
44
+ function requireNative() {
45
+ if (!nativeBinding || typeof nativeBinding.transformRecipeFromJson !== 'function') {
46
+ throw new Error('prepared transforms require the Tranfi native addon; WASM support is not available in this build')
47
+ }
48
+ return nativeBinding
49
+ }
50
+
51
+ function callNative(name, ...args) {
52
+ const binding = requireNative()
53
+ try {
54
+ return binding[name](...args)
55
+ } catch (error) {
56
+ if (error && error.name === 'TranfiTransformError' && Number.isInteger(error.code)) {
57
+ throw new TranfiTransformError(error.code, error.message, error)
58
+ }
59
+ throw error
60
+ }
61
+ }
62
+
63
+ function assertPlainObject(value, label) {
64
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
65
+ throw new TypeError(`${label} must be an object`)
66
+ }
67
+ }
68
+
69
+ function assertWellFormedUnicode(value, label, runtime, rejectNul = false) {
70
+ for (let index = 0; index < value.length; index++) {
71
+ if (index % 4096 === 0) throwIfCancelled(runtime)
72
+ const unit = value.charCodeAt(index)
73
+ if (rejectNul && unit === 0) {
74
+ throw new TypeError(`${label} must not contain NUL`)
75
+ }
76
+ if (unit >= 0xd800 && unit <= 0xdbff) {
77
+ const next = index + 1 < value.length ? value.charCodeAt(index + 1) : 0
78
+ if (next < 0xdc00 || next > 0xdfff) {
79
+ throw new TypeError(`${label} must not contain an unpaired UTF-16 surrogate`)
80
+ }
81
+ index++
82
+ } else if (unit >= 0xdc00 && unit <= 0xdfff) {
83
+ throw new TypeError(`${label} must not contain an unpaired UTF-16 surrogate`)
84
+ }
85
+ }
86
+ throwIfCancelled(runtime)
87
+ return value
88
+ }
89
+
90
+ function utf8ByteLength(value, label, runtime, rejectNul = false, maxBytes = null) {
91
+ let bytes = 0
92
+ for (let index = 0; index < value.length; index++) {
93
+ if (index % 4096 === 0) throwIfCancelled(runtime)
94
+ const unit = value.charCodeAt(index)
95
+ if (rejectNul && unit === 0) {
96
+ throw new TypeError(`${label} must not contain NUL`)
97
+ }
98
+ if (unit <= 0x7f) {
99
+ bytes += 1
100
+ } else if (unit <= 0x7ff) {
101
+ bytes += 2
102
+ } else if (unit >= 0xd800 && unit <= 0xdbff) {
103
+ const next = index + 1 < value.length ? value.charCodeAt(index + 1) : 0
104
+ if (next < 0xdc00 || next > 0xdfff) {
105
+ throw new TypeError(`${label} must not contain an unpaired UTF-16 surrogate`)
106
+ }
107
+ bytes += 4
108
+ index++
109
+ } else if (unit >= 0xdc00 && unit <= 0xdfff) {
110
+ throw new TypeError(`${label} must not contain an unpaired UTF-16 surrogate`)
111
+ } else {
112
+ bytes += 3
113
+ }
114
+ if (maxBytes !== null && bytes > maxBytes) {
115
+ throw new TranfiTransformError(104, `${label} exceeds its configured byte limit`)
116
+ }
117
+ }
118
+ throwIfCancelled(runtime)
119
+ return bytes
120
+ }
121
+
122
+ function normalizeLimits(limits) {
123
+ if (limits === undefined || limits === null) return undefined
124
+ assertPlainObject(limits, 'limits')
125
+ const normalized = {}
126
+ for (const [name, value] of Object.entries(limits)) {
127
+ if (!LIMIT_FIELDS.has(name)) throw new TypeError(`unknown transform limit field: ${name}`)
128
+ if (!Number.isSafeInteger(value) || value <= 0) {
129
+ throw new TranfiTransformError(100, `${name} must be a positive safe integer`)
130
+ }
131
+ normalized[name] = value
132
+ }
133
+ return normalized
134
+ }
135
+
136
+ function safeTransformLimits(overrides = {}) {
137
+ const normalized = normalizeLimits(overrides) || {}
138
+ return { ...callNative('transformSafeLimits'), ...normalized }
139
+ }
140
+
141
+ function normalizeCancelFlag(cancelFlag) {
142
+ if (cancelFlag === undefined || cancelFlag === null) return undefined
143
+ const shared = typeof SharedArrayBuffer !== 'undefined'
144
+ && cancelFlag instanceof Int32Array
145
+ && Object.prototype.toString.call(cancelFlag.buffer) === '[object SharedArrayBuffer]'
146
+ if (!shared || cancelFlag.length < 1) {
147
+ throw new TypeError('cancelFlag must be a nonempty SharedArrayBuffer-backed Int32Array')
148
+ }
149
+ return cancelFlag
150
+ }
151
+
152
+ function normalizeRuntimeOptions(options = {}) {
153
+ if (!options || typeof options !== 'object' || Array.isArray(options)) {
154
+ throw new TypeError('transform runtime options must be an object')
155
+ }
156
+ for (const name of Object.keys(options)) {
157
+ if (!RUNTIME_OPTION_FIELDS.has(name)) {
158
+ throw new TypeError(`unknown transform runtime option: ${name}`)
159
+ }
160
+ }
161
+ if (options.hostPolicy !== undefined && options.hostPolicy !== null) {
162
+ throw new TranfiTransformError(
163
+ 113, 'prepared-transform hostPolicy is reserved but not implemented'
164
+ )
165
+ }
166
+ if (options.spillDir !== undefined && options.spillDir !== null &&
167
+ options.spillDir !== '') {
168
+ throw new TranfiTransformError(
169
+ 113, 'prepared-transform spillDir is reserved but not implemented'
170
+ )
171
+ }
172
+ const limits = normalizeLimits(options.limits)
173
+ const cancelFlag = normalizeCancelFlag(options.cancelFlag)
174
+ if (limits === undefined && cancelFlag === undefined) return undefined
175
+ return { limits, cancelFlag }
176
+ }
177
+
178
+ function throwIfCancelled(runtime) {
179
+ if (runtime && runtime.cancelFlag
180
+ && Atomics.load(runtime.cancelFlag, 0) !== 0) {
181
+ throw new TranfiTransformError(109, 'prepared transform cancelled')
182
+ }
183
+ }
184
+
185
+ function encodeUtf8(value, label, runtime, maxBytes, knownLength = null) {
186
+ const total = knownLength === null
187
+ ? utf8ByteLength(value, label, runtime, true, maxBytes)
188
+ : knownLength
189
+ const encoded = Buffer.allocUnsafe(total)
190
+ let destination = 0
191
+ for (let offset = 0; offset < value.length;) {
192
+ throwIfCancelled(runtime)
193
+ let end = Math.min(offset + 4096, value.length)
194
+ if (end < value.length) {
195
+ const last = value.charCodeAt(end - 1)
196
+ if (last >= 0xd800 && last <= 0xdbff) end--
197
+ }
198
+ destination += encoded.write(
199
+ value.slice(offset, end), destination, total - destination, 'utf8'
200
+ )
201
+ offset = end
202
+ }
203
+ throwIfCancelled(runtime)
204
+ if (destination !== total) {
205
+ throw new Error(`internal UTF-8 length mismatch for ${label}`)
206
+ }
207
+ return encoded
208
+ }
209
+
210
+ function normalizeSchema(schema, runtime, limits) {
211
+ const fields = Array.isArray(schema)
212
+ ? schema
213
+ : schema && typeof schema === 'object' && Array.isArray(schema.fields)
214
+ ? schema.fields
215
+ : null
216
+ if (!fields || fields.length === 0) {
217
+ throw new TypeError('schema must be a nonempty array or { fields } object')
218
+ }
219
+ if (fields.length > limits.maxInputColumns) {
220
+ throw new TranfiTransformError(104, 'prepared-transform input column limit exceeded')
221
+ }
222
+ const prepared = []
223
+ let decodedBytes = 0
224
+ for (let index = 0; index < fields.length; index++) {
225
+ if (index % 4096 === 0) throwIfCancelled(runtime)
226
+ const field = fields[index]
227
+ assertPlainObject(field, `schema field ${index}`)
228
+ const id = field.id
229
+ const name = field.name === undefined ? id : field.name
230
+ const dtype = field.dtype
231
+ if (typeof id !== 'string' || id.length === 0) {
232
+ throw new TypeError(`schema field ${index} id must be a nonempty string`)
233
+ }
234
+ if (typeof name !== 'string' || name.length === 0) {
235
+ throw new TypeError(`schema field ${index} name must be a nonempty string`)
236
+ }
237
+ if (dtype !== 'float32' && dtype !== 'float64') {
238
+ throw new TypeError(`schema field ${index} dtype must be float32 or float64`)
239
+ }
240
+ const maxEncodedBytes = Math.min(
241
+ limits.maxStringBytes, limits.maxAllocationBytes - 1
242
+ )
243
+ const idLength = utf8ByteLength(
244
+ id, `schema field ${index} id`, runtime, true, maxEncodedBytes
245
+ )
246
+ const nameLength = utf8ByteLength(
247
+ name, `schema field ${index} name`, runtime, true, maxEncodedBytes
248
+ )
249
+ if (decodedBytes + idLength + nameLength > limits.maxDecodedStringBytes) {
250
+ throw new TranfiTransformError(104, 'prepared-transform decoded string limit exceeded')
251
+ }
252
+ decodedBytes += idLength + nameLength
253
+ prepared.push({ id, name, dtype, idLength, nameLength })
254
+ }
255
+ throwIfCancelled(runtime)
256
+
257
+ const normalized = []
258
+ for (let index = 0; index < prepared.length; index++) {
259
+ if (index % 4096 === 0) throwIfCancelled(runtime)
260
+ const { id, name, dtype, idLength, nameLength } = prepared[index]
261
+ const maxEncodedBytes = Math.min(
262
+ limits.maxStringBytes, limits.maxAllocationBytes - 1
263
+ )
264
+ const idBytes = encodeUtf8(
265
+ id, `schema field ${index} id`, runtime, maxEncodedBytes, idLength
266
+ )
267
+ const nameBytes = encodeUtf8(
268
+ name, `schema field ${index} name`, runtime, maxEncodedBytes, nameLength
269
+ )
270
+ normalized.push({ id: idBytes, name: nameBytes, dtype })
271
+ }
272
+ throwIfCancelled(runtime)
273
+ return {
274
+ fields: normalized
275
+ }
276
+ }
277
+
278
+ function normalizeRecipeJSON(recipe, limits) {
279
+ if (typeof recipe === 'string') {
280
+ return assertWellFormedUnicode(recipe, 'recipe')
281
+ }
282
+ if (Buffer.isBuffer(recipe) || recipe instanceof Uint8Array) {
283
+ return recipe
284
+ }
285
+ assertPlainObject(recipe, 'recipe')
286
+ return stringifyRecipe(recipe, limits)
287
+ }
288
+
289
+ class OwnedTransform {
290
+ constructor(handle) {
291
+ this._handle = handle
292
+ }
293
+
294
+ _requireOpen() {
295
+ if (this._handle === null) {
296
+ throw new TranfiTransformError(112, 'prepared transform object is closed')
297
+ }
298
+ return this._handle
299
+ }
300
+
301
+ close() {
302
+ if (this._handle !== null) {
303
+ callNative('transformDispose', this._handle)
304
+ this._handle = null
305
+ }
306
+ }
307
+
308
+ dispose() {
309
+ this.close()
310
+ }
311
+ }
312
+
313
+ class TransformRecipe extends OwnedTransform {
314
+ static fromJSON(recipe, { limits } = {}) {
315
+ const normalized = normalizeLimits(limits)
316
+ const effective = safeTransformLimits(normalized)
317
+ return new TransformRecipe(callNative(
318
+ 'transformRecipeFromJson', normalizeRecipeJSON(recipe, effective), normalized
319
+ ))
320
+ }
321
+
322
+ analyzer(schema, options = {}) {
323
+ const recipeHandle = this._requireOpen()
324
+ const runtime = normalizeRuntimeOptions(options)
325
+ throwIfCancelled(runtime)
326
+ const effectiveLimits = safeTransformLimits(runtime && runtime.limits)
327
+ throwIfCancelled(runtime)
328
+ const normalizedSchema = normalizeSchema(schema, runtime, effectiveLimits)
329
+ throwIfCancelled(runtime)
330
+ return new TransformAnalyzer(callNative(
331
+ 'transformAnalyzerCreate', recipeHandle, normalizedSchema, runtime
332
+ ))
333
+ }
334
+ }
335
+
336
+ class TransformAnalyzer extends OwnedTransform {
337
+ push(table) {
338
+ callNative('transformAnalyzerPush', this._requireOpen(), table)
339
+ return this
340
+ }
341
+
342
+ finalize() {
343
+ return new TransformPlan(callNative('transformAnalyzerFinalize', this._requireOpen()))
344
+ }
345
+ }
346
+
347
+ class TransformPlan extends OwnedTransform {
348
+ static fromBytes(bytes, options = {}) {
349
+ return new TransformPlan(callNative(
350
+ 'transformPlanImport', bytes, normalizeRuntimeOptions(options)
351
+ ))
352
+ }
353
+
354
+ toBytes({ limits } = {}) {
355
+ return callNative('transformPlanExport', this._requireOpen(), normalizeLimits(limits))
356
+ }
357
+
358
+ schemaJSON(which = 'output', { limits } = {}) {
359
+ const selector = which === 'input'
360
+ ? SCHEMA_INPUT
361
+ : which === 'output'
362
+ ? SCHEMA_OUTPUT
363
+ : null
364
+ if (selector === null) throw new TypeError("which must be 'input' or 'output'")
365
+ return callNative(
366
+ 'transformPlanSchemaJson', this._requireOpen(), selector, normalizeLimits(limits)
367
+ )
368
+ }
369
+
370
+ recipeSha256({ limits } = {}) {
371
+ return callNative(
372
+ 'transformPlanRecipeSha256', this._requireOpen(), normalizeLimits(limits)
373
+ )
374
+ }
375
+
376
+ apply(schema, options = {}) {
377
+ const planHandle = this._requireOpen()
378
+ const runtime = normalizeRuntimeOptions(options)
379
+ throwIfCancelled(runtime)
380
+ const effectiveLimits = safeTransformLimits(runtime && runtime.limits)
381
+ throwIfCancelled(runtime)
382
+ const normalizedSchema = normalizeSchema(schema, runtime, effectiveLimits)
383
+ throwIfCancelled(runtime)
384
+ return new TransformApply(callNative(
385
+ 'transformApplyCreate', planHandle, normalizedSchema, runtime
386
+ ))
387
+ }
388
+ }
389
+
390
+ class TransformApply extends OwnedTransform {
391
+ run(table) {
392
+ return callNative('transformApplyRun', this._requireOpen(), table)
393
+ }
394
+ }
395
+
396
+ module.exports = {
397
+ TranfiTransformError,
398
+ TransformRecipe,
399
+ TransformAnalyzer,
400
+ TransformPlan,
401
+ TransformApply,
402
+ safeTransformLimits
403
+ }
@@ -0,0 +1,10 @@
1
+ class TranfiTransformError extends Error {
2
+ constructor(code, message, cause) {
3
+ super(message)
4
+ this.name = 'TranfiTransformError'
5
+ this.code = Number(code)
6
+ if (cause !== undefined) this.cause = cause
7
+ }
8
+ }
9
+
10
+ module.exports = { TranfiTransformError }
package/src/wasm.js CHANGED
@@ -5,15 +5,17 @@
5
5
 
6
6
  let instance = null
7
7
 
8
- export async function loadWasm() {
8
+ async function loadWasm() {
9
9
  if (instance) return instance
10
10
 
11
- // Try to load the WASM module
12
- const { default: createTranfi } = await import('../wasm/tranfi_core.js')
11
+ // Load the WASM module
12
+ const createTranfi = require('../wasm/tranfi_core.js')
13
13
  instance = await createTranfi()
14
14
  return instance
15
15
  }
16
16
 
17
- export function getWasm() {
17
+ function getWasm() {
18
18
  return instance
19
19
  }
20
+
21
+ module.exports = { loadWasm, getWasm }