@sendwavehub/flowdoc
v1.1.4
Published
Fast multilanguage serialization format - Node.js WASM binding
Maintainers
Readme
flowdoc
Node.js binding (via wasm-bindgen) for FlowDoc — a fast serialization format: indent-delimited key: value records, parsed by a shared Rust core compiled to WASM.
const { parse_flow_json, parse_flow_wasm } = require('flowdoc');
const records = JSON.parse(parse_flow_json(`
Record
id: 1
name: Test
`));
// [{ id: '1', name: 'Test' }]Two entry points, both returning the same shape for the same input:
parse_flow_json(data)— returns a JSON string.parse_flow_wasm(data)— returns the parsed value directly (plain JS objects, notMaps).
.flowc (compact text)
.flowc is a denser text sibling of .flow — no Record header line, no
indentation, key:value (no space), and a blank line separates records
instead of .flow's indent-zero boundary rule. Same flat string-to-string
record data model as .flow, just terser syntax — see
docs/FORMAT_FLOWC.md for the full spec.
const { parse_flow_compact_json, write_flow_compact_from_json } = require('flowdoc');
const records = JSON.parse(parse_flow_compact_json('id:1\nname:Test\n\nid:2\nname:Test2'));
// [{ id: '1', name: 'Test' }, { id: '2', name: 'Test2' }]
write_flow_compact_from_json(JSON.stringify(records));
// 'id:1\nname:Test\n\nid:2\nname:Test2' (field order not guaranteed)Only the JSON-string-bridge shape is exposed for .flowc — no
parse_flow_wasm-style direct-value sibling. That shape was measured
slower than the JSON-string round trip for .flow (see CLAUDE.md's
Node.js performance section), and nothing about .flowc's grammar changes
that boundary-cost tradeoff.
.flowb (binary)
.flowb is the binary counterpart to .flow text — the same parsed shape
(an array of objects, each string key -> string value) that parse_flow_json/
parse_flow_wasm produce, MessagePack-encoded
instead of key: value lines. Implemented entirely in JS (via
@msgpack/msgpack),
independent of the wasm core:
const { saveFlowb, loadFlowb } = require('flowdoc');
saveFlowb('data.flowb', [{ id: '1', name: 'Test' }]);
loadFlowb('data.flowb');
// [{ id: '1', name: 'Test' }]loadFlowb(saveFlowb(x)) round-trips exactly for any records parse_flow_json/
parse_flow_wasm can produce, including multi-byte UTF-8 values and empty
records/arrays.
Licensing (soft gate)
parse_flow_json/parse_flow_wasm work identically whether or not a
license key is configured — there is no Pro-exclusive capability gated by
this yet. If FLOWDOC_LICENSE_KEY is set, this package validates it once
per process against FLOWDOC_LICENSE_SERVER + /api/licenses/validate (no
default server — validation is skipped entirely if this isn't set too),
asynchronously, and logs a warning on an invalid key or an unreachable
server. Query the result yourself with:
const { licenseStatus } = require('flowdoc');
const status = await licenseStatus();
// { checked: true, valid: true | false | null, error: string | null }valid is null when there was nothing to check (no key configured) or
nothing could be checked (no server configured, or unreachable) — see
index.js for the full behavior.
In production, set FLOWDOC_LICENSE_SERVER=https://license-admin.sendwavehub.tech/api
(the trailing /api is required — see RELEASING.md's "Production
license server" section for why). There is no default; validation is
skipped entirely without it.
Activation
activateLicense(activatedBy, options) is a separate, explicit call —
unlike licenseStatus(), it never runs automatically, since it's a
mutating call (it flips the license to "Activated" server-side, unlike
/validate's read-only check). Call it once, e.g. on first run/install:
const { activateLicense } = require('flowdoc');
const result = await activateLicense('install-script', { activationIp: '1.2.3.4', metadata: { os: 'linux' } });
// { success: true, error: null, message, tier, seats, expiresAt, customerId, signedLicenseArtifact }
// or, on failure: { success: false, error: string, ...other fields null }Posts to FLOWDOC_LICENSE_SERVER + /licenses/<FLOWDOC_LICENSE_KEY>/activate
(a single /api/ segment, since FLOWDOC_LICENSE_SERVER is expected to
already carry one — see /validate's doubled /api/api/ above).
options.activationIp/options.metadata are both optional. Cache
signedLicenseArtifact yourself if you need it later; this function
doesn't persist anything.
See the FlowDoc project for the format overview, benchmark numbers, and links to every other language binding (Rust, Go, Python, C#, PHP, C++).
