@yydb/yydb 0.0.3 → 0.0.5

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 (48) hide show
  1. package/README.md +82 -45
  2. package/dist/{cli → node/cli}/cli.js +1 -3
  3. package/dist/{database.d.ts → node/database.d.ts} +2 -2
  4. package/dist/{database.js → node/database.js} +1 -9
  5. package/dist/{index.d.ts → node/index.d.ts} +2 -2
  6. package/dist/{index.js → node/index.js} +2 -2
  7. package/dist/{micro.d.ts → shared/micro.d.ts} +2 -0
  8. package/dist/{micro.js → shared/micro.js} +9 -0
  9. package/dist/shared/wasm-envelope.d.ts +37 -0
  10. package/dist/shared/wasm-envelope.js +46 -0
  11. package/dist/wasm/binding.d.ts +1 -0
  12. package/dist/wasm/binding.js +1 -0
  13. package/dist/wasm/database.d.ts +53 -0
  14. package/dist/wasm/database.js +116 -0
  15. package/dist/wasm/index.d.ts +5 -0
  16. package/dist/wasm/index.js +4 -0
  17. package/package.json +26 -20
  18. package/dist/cli/generate-cmd.d.ts +0 -3
  19. package/dist/cli/generate-cmd.js +0 -25
  20. package/dist/generator/emit-typescript.d.ts +0 -3
  21. package/dist/generator/emit-typescript.js +0 -26
  22. package/dist/generator/fixtures/setting.generated.d.ts +0 -13
  23. package/dist/generator/fixtures/setting.generated.js +0 -3
  24. package/dist/generator/index.d.ts +0 -6
  25. package/dist/generator/index.js +0 -10
  26. package/dist/generator/ir.d.ts +0 -20
  27. package/dist/generator/ir.js +0 -12
  28. package/dist/generator/parse-vos.d.ts +0 -6
  29. package/dist/generator/parse-vos.js +0 -149
  30. /package/dist/{cli → node/cli}/cli.d.ts +0 -0
  31. /package/dist/{cli → node/cli}/info-cmd.d.ts +0 -0
  32. /package/dist/{cli → node/cli}/info-cmd.js +0 -0
  33. /package/dist/{cli → node/cli}/init-cmd.d.ts +0 -0
  34. /package/dist/{cli → node/cli}/init-cmd.js +0 -0
  35. /package/dist/{cli → node/cli}/options.d.ts +0 -0
  36. /package/dist/{cli → node/cli}/options.js +0 -0
  37. /package/dist/{cli → node/cli}/serve-cmd.d.ts +0 -0
  38. /package/dist/{cli → node/cli}/serve-cmd.js +0 -0
  39. /package/dist/{cli → node/cli}/version-cmd.d.ts +0 -0
  40. /package/dist/{cli → node/cli}/version-cmd.js +0 -0
  41. /package/dist/{cli.d.ts → node/cli.d.ts} +0 -0
  42. /package/dist/{cli.js → node/cli.js} +0 -0
  43. /package/dist/{native.d.ts → node/native.d.ts} +0 -0
  44. /package/dist/{native.js → node/native.js} +0 -0
  45. /package/dist/{resolve-bin.d.ts → node/resolve-bin.d.ts} +0 -0
  46. /package/dist/{resolve-bin.js → node/resolve-bin.js} +0 -0
  47. /package/dist/{udf-types.d.ts → shared/udf-types.d.ts} +0 -0
  48. /package/dist/{udf-types.js → shared/udf-types.js} +0 -0
package/README.md CHANGED
@@ -1,32 +1,36 @@
1
1
  # `@yydb/yydb`
2
2
 
3
- **All-in-one YYDB for Node.js: CLI, embedded engine, and local `serve`.**
3
+ Node all-in-one and browser wasm core from one package. On Node.js, `Database.open` starts a private loopback `yydb serve`
4
+ process and talks over the YY wire protocol. In browsers, `@yydb/yydb/wasm` loads an in-process wasm session with KV,
5
+ schema, and VOS `query` / `execute` on memory or OPFS paths.
4
6
 
5
- Open a `.yydb` file with one dependency — `@yydb/yydb` spawns a private loopback server and talks to it over the YY
6
- wire protocol. For a **lightweight client only** (browser, renderer, or an app that already runs `yydb serve`), use
7
- [`@yydb/yydb-client`](../yydb-client).
7
+ For a wire client only (renderer or an app that already runs `yydb serve`), use
8
+ [`@yydb/yydb-client`](https://www.npmjs.com/package/@yydb/yydb-client).
8
9
 
9
10
  [![npm](https://img.shields.io/npm/v/@yydb/yydb)](https://www.npmjs.com/package/@yydb/yydb)
10
11
  [![Node.js](https://img.shields.io/node/v/@yydb/yydb)](https://www.npmjs.com/package/@yydb/yydb)
11
- [![Check Rust](https://github.com/yy-database/yydb/actions/workflows/check-rust.yml/badge.svg?branch=dev)](https://github.com/yy-database/yydb/actions/workflows/check-rust.yml)
12
- [![Check TypeScript](https://github.com/yy-database/yydb/actions/workflows/check-typescript.yml/badge.svg?branch=dev)](https://github.com/yy-database/yydb/actions/workflows/check-typescript.yml)
13
12
 
14
- ## Install
13
+ ## Exports
15
14
 
16
- ```bash
17
- npm install @yydb/yydb
18
- ```
15
+ | Import | Runtime | Role |
16
+ |--------|---------|------|
17
+ | `@yydb/yydb` | Node (`node` export condition) | `Database.open`, micro helpers |
18
+ | `@yydb/yydb` | Browser / bundler (`default`) | wasm `Database` |
19
+ | `@yydb/yydb/node` | Node (explicit) | Same as Node default |
20
+ | `@yydb/yydb/wasm` | Browser (explicit) | wasm `Database`, `initWasm`, `checkSchema` |
21
+ | `@yydb/yydb/cli` | Node | CLI (`version`, `init`, `info`, `serve`) |
22
+
23
+ Node.js 18+. Platform `.node` bindings install via optional dependencies.
19
24
 
20
- Node.js 18 or newer is supported. The matching `yydb-napi` binding is installed as an optional platform dependency and
21
- is
22
- started on a private loopback endpoint when `Database.open()` runs.
25
+ Schema truth lives in the `.yydb` file via `ensureSchema` and VOS documents. Wasm sessions mirror KV and schema calls
26
+ and add VOS pipelines directly on the embedded core.
23
27
 
24
- ## Example
28
+ ## Node example
25
29
 
26
30
  ```ts
27
- import {Database} from "@yydb/yydb";
31
+ import { Database } from '@yydb/yydb';
28
32
 
29
- const db = await Database.open("./data/app.yydb");
33
+ const db = await Database.open('./data/app.yydb');
30
34
 
31
35
  await db.ensureSchema(
32
36
  1,
@@ -37,20 +41,41 @@ await db.ensureSchema(
37
41
  }`,
38
42
  );
39
43
 
40
- await db.put("theme", "dark");
41
- const value = await db.get("theme");
42
- console.log(value && new TextDecoder().decode(value));
43
-
44
+ await db.put('theme', 'dark');
45
+ console.log(await db.get('theme'));
44
46
  await db.close();
45
47
  ```
46
48
 
47
- The database file is created if it does not exist. The VOS schema and its version are stored with the data, so reopening
48
- the file does not depend on a separate schema registry.
49
+ The file is created when missing. Schema version and VOS document persist with the data.
50
+
51
+ ## Browser example
52
+
53
+ ```ts
54
+ import { Database } from '@yydb/yydb/wasm';
55
+
56
+ const db = await Database.openInMemory();
57
+
58
+ await db.ensureSchema(
59
+ 1,
60
+ `table Setting {
61
+ @@id: uuid,
62
+ key: utf8,
63
+ value: utf8,
64
+ }`,
65
+ );
66
+
67
+ await db.put('theme', 'dark');
68
+ console.log(await db.get('theme'));
69
+ db.close();
70
+ ```
71
+
72
+ Use `Database.open('app.yydb')` for OPFS-backed paths in supported browsers.
49
73
 
50
- ## API
74
+ ## Wasm API
51
75
 
52
76
  ```ts
53
- const db = await Database.open(path, options ?);
77
+ const db = await Database.openInMemory();
78
+ // or: const db = await Database.open('app.yydb');
54
79
 
55
80
  await db.ensureSchema(version, vosDocument);
56
81
  await db.getSchema();
@@ -58,33 +83,45 @@ await db.put(key, stringOrBytes);
58
83
  await db.get(key);
59
84
  await db.info();
60
85
  await db.serverVersion();
61
- await db.close();
86
+ await db.registerMicro(microDefinition);
87
+ await db.callScalar('double', 1, [21]);
88
+ db.query('User.filter(x => x.active).collect()');
89
+ db.execute('User { name: "Ada" }.insert()');
90
+ db.close();
62
91
  ```
63
92
 
64
- `OpenOptions` supports `cli` (an explicit CLI script path), `port` (a preferred loopback port), and `serveArgs` (extra
65
- arguments forwarded to `yydb serve`). `binary` is a deprecated alias for `cli`.
93
+ ## Node API
94
+
95
+ ```ts
96
+ const db = await Database.open(path, options?);
66
97
 
67
- ## Use a different package when
98
+ await db.ensureSchema(version, vosDocument);
99
+ await db.getSchema();
100
+ await db.put(key, stringOrBytes);
101
+ await db.get(key);
102
+ await db.info();
103
+ await db.serverVersion();
104
+ await db.registerMicro(microDefinition);
105
+ await db.callScalar('double', 1, [21]);
106
+ await db.close();
107
+ ```
68
108
 
69
- | Need | Package |
70
- |----------------------------------------|-------------------------------------------|
71
- | Node all-in-one (CLI + engine + serve) | **`@yydb/yydb`** (this package) |
72
- | Lightweight wire client only | [`@yydb/yydb-client`](../yydb-client) |
73
- | In-process Rust embed | [`yydb`](https://crates.io/crates/yydb) |
74
- | Rust wire server crate (used by N-API) | [`yydb-server`](../../crates/yydb-server) |
75
- | Rust remote client | [`yydb-client`](../../crates/yydb-client) |
109
+ `OpenOptions`: `cli` (explicit CLI script path), `port` (preferred loopback port), `serveArgs` (extra `yydb serve`
110
+ arguments). `binary` is a deprecated alias for `cli`.
76
111
 
77
- For Electron, the main process can use `@yydb/yydb`; renderer code can use
78
- `@yydb/yydb-client` against the main process endpoint.
112
+ ## Related packages
79
113
 
80
- ## Security
114
+ | Need | Package |
115
+ |------|---------|
116
+ | Node all-in-one (this package) | **`@yydb/yydb`** or `@yydb/yydb/node` |
117
+ | Browser wasm entry | **`@yydb/yydb/wasm`** |
118
+ | Wire client only | [`@yydb/yydb-client`](https://www.npmjs.com/package/@yydb/yydb-client) |
119
+ | In-process Rust embed | [`yydb`](https://crates.io/crates/yydb) |
120
+ | Agent skills (wire protocol) | [`@yydb/yydb-skills`](https://www.npmjs.com/package/@yydb/yydb-skills) |
81
121
 
82
- The managed engine listens on `127.0.0.1` and has no authentication layer. Keep the endpoint private and use the
83
- operating system's file permissions for the `.yydb` file.
122
+ Electron: main process can use `@yydb/yydb/node`; renderer code can use `@yydb/yydb-client` against the main-process
123
+ endpoint.
84
124
 
85
- ## Links
125
+ The managed engine listens on `127.0.0.1` with no authentication — keep the endpoint private.
86
126
 
87
- - [YYDB overview](https://github.com/yy-database/yydb.rs)
88
- - [User guides](https://github.com/yy-database/yydb.rs/tree/dev/projects/packages/homepage/documentation/zh-hans)
89
- - [API documentation](https://docs.rs/yydb)
90
- - [License](https://github.com/yy-database/yydb.rs/blob/dev/License.md)
127
+ [YYDB overview](https://github.com/yy-database/yydb.rs) · [User guides](https://github.com/yy-database/yydb.rs/tree/dev/projects/packages/homepage/documentation/zh-hans)
@@ -1,19 +1,17 @@
1
1
  import { dirname, join } from 'node:path';
2
2
  import { fileURLToPath } from 'node:url';
3
3
  import { createCli } from '@vmz/commander';
4
- import { registerGenerateCommand } from './generate-cmd.js';
5
4
  import { registerInfoCommand } from './info-cmd.js';
6
5
  import { registerInitCommand } from './init-cmd.js';
7
6
  import { registerServeCommand } from './serve-cmd.js';
8
7
  import { registerVersionCommand } from './version-cmd.js';
9
8
  function buildYydbCli() {
10
- const localesRoot = join(dirname(fileURLToPath(import.meta.url)), '../../locales');
9
+ const localesRoot = join(dirname(fileURLToPath(import.meta.url)), '../../../locales');
11
10
  const cli = createCli('yydb').locales(localesRoot).intro('cli.intro');
12
11
  registerVersionCommand(cli);
13
12
  registerInitCommand(cli);
14
13
  registerInfoCommand(cli);
15
14
  registerServeCommand(cli);
16
- registerGenerateCommand(cli);
17
15
  return cli;
18
16
  }
19
17
  export async function runCli(argv) {
@@ -1,5 +1,5 @@
1
- import { defineMicro as buildMicro, type DefinedMicro, type MicroHandle } from './micro.js';
2
- import type { UdfTypeDescriptor } from './udf-types.js';
1
+ import { defineMicro as buildMicro, type DefinedMicro, type MicroHandle } from '../shared/micro.js';
2
+ import type { UdfTypeDescriptor } from '../shared/udf-types.js';
3
3
  export type { SchemaVersion } from '@yydb/yydb-client';
4
4
  export interface OpenOptions {
5
5
  /** Override CLI script path (tests / special installs). */
@@ -3,16 +3,8 @@ import fs from 'node:fs';
3
3
  import net from 'node:net';
4
4
  import path from 'node:path';
5
5
  import { connect } from '@yydb/yydb-client/node';
6
- import { defineMicro as buildMicro, MicroSessionRegistry } from './micro.js';
6
+ import { defineMicro as buildMicro, microFingerprint, MicroSessionRegistry } from '../shared/micro.js';
7
7
  import { resolveYydbCli } from './resolve-bin.js';
8
- function microFingerprint(name, version) {
9
- const bytes = new Uint8Array(32);
10
- const seed = `${name}@${version}`;
11
- for (let index = 0; index < bytes.byteLength; index += 1) {
12
- bytes[index] = seed.charCodeAt(index % seed.length) & 0xff;
13
- }
14
- return bytes;
15
- }
16
8
  async function freeLoopbackPort() {
17
9
  return await new Promise((resolve, reject) => {
18
10
  const server = net.createServer();
@@ -1,4 +1,4 @@
1
1
  export { Database, type OpenOptions } from './database.js';
2
- export { defineMicro, type DefinedMicro, type MicroHandle, type TsMicroDefinitionInput, MicroSessionRegistry } from './micro.js';
3
- export { bool, i64, nullType, text, type InferUdfArgs, type InferUdfReturn, type MicroEffect, type MicroInvocationMode, type UdfScalarKind, type UdfTypeDescriptor, } from './udf-types.js';
2
+ export { defineMicro, type DefinedMicro, type MicroHandle, type TsMicroDefinitionInput, MicroSessionRegistry } from '../shared/micro.js';
3
+ export { bool, i64, nullType, text, type InferUdfArgs, type InferUdfReturn, type MicroEffect, type MicroInvocationMode, type UdfScalarKind, type UdfTypeDescriptor, } from '../shared/udf-types.js';
4
4
  export { nativeBindingName, platformKey, resolveYydbBinary, resolveYydbCli } from './resolve-bin.js';
@@ -1,4 +1,4 @@
1
1
  export { Database } from './database.js';
2
- export { defineMicro, MicroSessionRegistry } from './micro.js';
3
- export { bool, i64, nullType, text, } from './udf-types.js';
2
+ export { defineMicro, MicroSessionRegistry } from '../shared/micro.js';
3
+ export { bool, i64, nullType, text, } from '../shared/udf-types.js';
4
4
  export { nativeBindingName, platformKey, resolveYydbBinary, resolveYydbCli } from './resolve-bin.js';
@@ -60,4 +60,6 @@ export declare class MicroSessionRegistry {
60
60
  }
61
61
  /** Builds a session-local micro definition without registering it. */
62
62
  export declare function defineMicro<TArgs extends readonly UdfTypeDescriptor[], TReturn extends UdfTypeDescriptor>(input: TsMicroDefinitionInput<TArgs, TReturn>): DefinedMicro<TArgs, TReturn>;
63
+ /** Stable 32-byte fingerprint for a logical micro name and version. */
64
+ export declare function microFingerprint(name: string, version: number): Uint8Array;
63
65
  export {};
@@ -99,6 +99,15 @@ export function defineMicro(input) {
99
99
  fn: input.fn,
100
100
  };
101
101
  }
102
+ /** Stable 32-byte fingerprint for a logical micro name and version. */
103
+ export function microFingerprint(name, version) {
104
+ const bytes = new Uint8Array(32);
105
+ const seed = `${name}@${version}`;
106
+ for (let index = 0; index < bytes.byteLength; index += 1) {
107
+ bytes[index] = seed.charCodeAt(index % seed.length) & 0xff;
108
+ }
109
+ return bytes;
110
+ }
102
111
  function logicalKey(name, version) {
103
112
  return `${name}@${version}`;
104
113
  }
@@ -0,0 +1,37 @@
1
+ /** Parsed `{ ok, rows, error }` envelope from wasm VOS calls. */
2
+ export type WasmRowsResult = {
3
+ ok: boolean;
4
+ rows: Record<string, unknown>[];
5
+ error: string | null;
6
+ };
7
+ /** Parsed `{ ok, schema, error }` envelope from wasm `getSchema`. */
8
+ export type WasmSchemaResult = {
9
+ ok: boolean;
10
+ schema: {
11
+ version: number;
12
+ document: string;
13
+ } | null;
14
+ error: string | null;
15
+ };
16
+ /** Parsed `{ ok, value, error }` envelope from wasm `get`. */
17
+ export type WasmKvGetResult = {
18
+ ok: boolean;
19
+ value: number[] | null;
20
+ error: string | null;
21
+ };
22
+ /** Parsed `{ ok, value, error }` envelope from wasm `callScalar`. */
23
+ export type WasmScalarResult = {
24
+ ok: boolean;
25
+ value: string | number | boolean | null;
26
+ error: string | null;
27
+ };
28
+ export type WireScalarValue = string | number | boolean | null;
29
+ export type SchemaVersion = {
30
+ version: number;
31
+ document: string;
32
+ };
33
+ export declare function parseWasmRowsResult(payload: string): WasmRowsResult;
34
+ export declare function parseWasmUnitResult(payload: string): void;
35
+ export declare function parseWasmSchemaResult(payload: string): SchemaVersion | null;
36
+ export declare function parseWasmScalarResult(payload: string): WireScalarValue;
37
+ export declare function parseWasmKvGetResult(payload: string): Uint8Array | null;
@@ -0,0 +1,46 @@
1
+ function parseJson(payload, label) {
2
+ try {
3
+ return JSON.parse(payload);
4
+ }
5
+ catch (error) {
6
+ const message = error instanceof Error ? error.message : String(error);
7
+ throw new Error(`${label}: invalid JSON (${message})`);
8
+ }
9
+ }
10
+ export function parseWasmRowsResult(payload) {
11
+ const parsed = parseJson(payload, 'wasm query/execute');
12
+ if (!parsed.ok) {
13
+ throw new Error(parsed.error ?? 'wasm query/execute failed');
14
+ }
15
+ return parsed;
16
+ }
17
+ export function parseWasmUnitResult(payload) {
18
+ const parsed = parseJson(payload, 'wasm unit call');
19
+ if (!parsed.ok) {
20
+ throw new Error(parsed.error ?? 'wasm unit call failed');
21
+ }
22
+ }
23
+ export function parseWasmSchemaResult(payload) {
24
+ const parsed = parseJson(payload, 'wasm getSchema');
25
+ if (!parsed.ok) {
26
+ throw new Error(parsed.error ?? 'wasm getSchema failed');
27
+ }
28
+ return parsed.schema;
29
+ }
30
+ export function parseWasmScalarResult(payload) {
31
+ const parsed = parseJson(payload, 'wasm callScalar');
32
+ if (!parsed.ok) {
33
+ throw new Error(parsed.error ?? 'wasm callScalar failed');
34
+ }
35
+ return parsed.value;
36
+ }
37
+ export function parseWasmKvGetResult(payload) {
38
+ const parsed = parseJson(payload, 'wasm get');
39
+ if (!parsed.ok) {
40
+ throw new Error(parsed.error ?? 'wasm get failed');
41
+ }
42
+ if (parsed.value === null) {
43
+ return null;
44
+ }
45
+ return Uint8Array.from(parsed.value);
46
+ }
@@ -0,0 +1 @@
1
+ export { checkSchema, createMemorySession, initWasm, introspectSchema, openPersistentSession, queryMemory, resetWasmBindingForTests, yydbVersion, type CheckSchemaResult, type InitWasmOptions, type WasmInitInput, type WasmSession, } from '@yydb/yydb-unknown-wasm32';
@@ -0,0 +1 @@
1
+ export { checkSchema, createMemorySession, initWasm, introspectSchema, openPersistentSession, queryMemory, resetWasmBindingForTests, yydbVersion, } from '@yydb/yydb-unknown-wasm32';
@@ -0,0 +1,53 @@
1
+ import { defineMicro as buildMicro, type DefinedMicro, type MicroHandle } from '../shared/micro.js';
2
+ import type { UdfTypeDescriptor } from '../shared/udf-types.js';
3
+ import { type SchemaVersion } from '../shared/wasm-envelope.js';
4
+ import { type CheckSchemaResult, type InitWasmOptions } from './binding.js';
5
+ export type WasmOpenOptions = InitWasmOptions;
6
+ /**
7
+ * Browser-facing YYDB handle backed by an in-process wasm session.
8
+ * Use `open` for OPFS-backed paths and `openInMemory` for ephemeral state.
9
+ */
10
+ export declare class Database {
11
+ readonly path: string;
12
+ private session;
13
+ private readonly kind;
14
+ private readonly microRegistry;
15
+ private constructor();
16
+ /** Open an OPFS-backed database at `path` (for example `app.yydb`). */
17
+ static open(path: string, options?: WasmOpenOptions): Promise<Database>;
18
+ /** Open a stateful in-memory database session. */
19
+ static openInMemory(options?: WasmOpenOptions): Promise<Database>;
20
+ /** Library version from the wasm binding. */
21
+ version(): string;
22
+ /** Engine version string (Node API parity). */
23
+ serverVersion(): Promise<string>;
24
+ /** Database info text (`path=…\\n…`), matching the YY wire `Info` reply. */
25
+ info(): Promise<string>;
26
+ /** Parse and validate a VOS schema document without opening a session. */
27
+ checkSchema(source: string): CheckSchemaResult;
28
+ /** Persist schema document. `version` is accepted for Node API parity; wasm uses the document body. */
29
+ ensureSchema(_version: number, document: string): Promise<void>;
30
+ getSchema(): Promise<SchemaVersion | null>;
31
+ get(key: string): Promise<Uint8Array | null>;
32
+ put(key: string, value: Uint8Array | string): Promise<void>;
33
+ /** VOS read pipeline (for example `User.filter(x => x.active).collect()`). */
34
+ query(source: string): Record<string, unknown>[];
35
+ /** Unit-valued VOS write programs (for example `User { … }.insert()`). */
36
+ execute(source: string): void;
37
+ /**
38
+ * Build a typed session-local micro definition. Does not register it with
39
+ * the engine until `registerMicro` is called.
40
+ */
41
+ defineMicro<TArgs extends readonly UdfTypeDescriptor[], TReturn extends UdfTypeDescriptor>(definition: Parameters<typeof buildMicro<TArgs, TReturn>>[0]): DefinedMicro<TArgs, TReturn>;
42
+ /**
43
+ * Install a `defineMicro` definition into the current session registry and
44
+ * sync metadata to the embedded engine. Host micros are session-local.
45
+ */
46
+ registerMicro<TArgs extends readonly UdfTypeDescriptor[], TReturn extends UdfTypeDescriptor>(definition: DefinedMicro<TArgs, TReturn>): Promise<MicroHandle>;
47
+ /** Invoke a registered scalar UDF on the embedded engine. */
48
+ callScalar(name: string, version: number, args: readonly (string | number | boolean | null)[]): Promise<string | number | boolean | null>;
49
+ /** Whether this handle owns a persistent OPFS session. */
50
+ isPersistent(): boolean;
51
+ close(): void;
52
+ private requireSession;
53
+ }
@@ -0,0 +1,116 @@
1
+ import { encodeMicroRegister, encodeScalarCall } from '@yydb/yydb-client';
2
+ import { defineMicro as buildMicro, microFingerprint, MicroSessionRegistry } from '../shared/micro.js';
3
+ import { parseWasmKvGetResult, parseWasmRowsResult, parseWasmScalarResult, parseWasmSchemaResult, parseWasmUnitResult, } from '../shared/wasm-envelope.js';
4
+ import { checkSchema, createMemorySession, initWasm, openPersistentSession, yydbVersion, } from './binding.js';
5
+ /**
6
+ * Browser-facing YYDB handle backed by an in-process wasm session.
7
+ * Use `open` for OPFS-backed paths and `openInMemory` for ephemeral state.
8
+ */
9
+ export class Database {
10
+ path;
11
+ session;
12
+ kind;
13
+ microRegistry;
14
+ constructor(kind, path, session) {
15
+ this.kind = kind;
16
+ this.path = path;
17
+ this.session = session;
18
+ this.microRegistry = new MicroSessionRegistry();
19
+ session.setMicroHostInvoker((payload) => this.microRegistry.invokeFromWire(payload));
20
+ }
21
+ /** Open an OPFS-backed database at `path` (for example `app.yydb`). */
22
+ static async open(path, options = {}) {
23
+ await initWasm(options);
24
+ const session = openPersistentSession(path);
25
+ return new Database('persistent', session.path ?? path, session);
26
+ }
27
+ /** Open a stateful in-memory database session. */
28
+ static async openInMemory(options = {}) {
29
+ await initWasm(options);
30
+ const session = createMemorySession();
31
+ return new Database('memory', ':memory:', session);
32
+ }
33
+ /** Library version from the wasm binding. */
34
+ version() {
35
+ return yydbVersion();
36
+ }
37
+ /** Engine version string (Node API parity). */
38
+ async serverVersion() {
39
+ return yydbVersion();
40
+ }
41
+ /** Database info text (`path=…\\n…`), matching the YY wire `Info` reply. */
42
+ async info() {
43
+ return this.requireSession().info();
44
+ }
45
+ /** Parse and validate a VOS schema document without opening a session. */
46
+ checkSchema(source) {
47
+ return checkSchema(source);
48
+ }
49
+ /** Persist schema document. `version` is accepted for Node API parity; wasm uses the document body. */
50
+ async ensureSchema(_version, document) {
51
+ parseWasmUnitResult(this.requireSession().ensureSchema(document));
52
+ }
53
+ async getSchema() {
54
+ return parseWasmSchemaResult(this.requireSession().getSchema());
55
+ }
56
+ async get(key) {
57
+ return parseWasmKvGetResult(this.requireSession().get(key));
58
+ }
59
+ async put(key, value) {
60
+ const bytes = typeof value === 'string' ? new TextEncoder().encode(value) : value;
61
+ parseWasmUnitResult(this.requireSession().put(key, bytes));
62
+ }
63
+ /** VOS read pipeline (for example `User.filter(x => x.active).collect()`). */
64
+ query(source) {
65
+ return parseWasmRowsResult(this.requireSession().query(source)).rows;
66
+ }
67
+ /** Unit-valued VOS write programs (for example `User { … }.insert()`). */
68
+ execute(source) {
69
+ parseWasmUnitResult(this.requireSession().execute(source));
70
+ }
71
+ /**
72
+ * Build a typed session-local micro definition. Does not register it with
73
+ * the engine until `registerMicro` is called.
74
+ */
75
+ defineMicro(definition) {
76
+ return buildMicro(definition);
77
+ }
78
+ /**
79
+ * Install a `defineMicro` definition into the current session registry and
80
+ * sync metadata to the embedded engine. Host micros are session-local.
81
+ */
82
+ async registerMicro(definition) {
83
+ const handle = this.microRegistry.register(definition);
84
+ const body = encodeMicroRegister({
85
+ hostId: handle.hostId,
86
+ handleVersion: handle.implementationVersion,
87
+ udfVersion: definition.version,
88
+ name: definition.name,
89
+ functionId: handle.functionId,
90
+ args: definition.args.map((arg) => arg.kind),
91
+ returns: definition.returns.kind,
92
+ fingerprint: microFingerprint(definition.name, definition.version),
93
+ });
94
+ parseWasmUnitResult(this.requireSession().registerMicro(body));
95
+ return handle;
96
+ }
97
+ /** Invoke a registered scalar UDF on the embedded engine. */
98
+ async callScalar(name, version, args) {
99
+ const body = encodeScalarCall(name, version, args);
100
+ return parseWasmScalarResult(this.requireSession().callScalar(body));
101
+ }
102
+ /** Whether this handle owns a persistent OPFS session. */
103
+ isPersistent() {
104
+ return this.kind === 'persistent';
105
+ }
106
+ close() {
107
+ this.session?.close();
108
+ this.session = null;
109
+ }
110
+ requireSession() {
111
+ if (!this.session) {
112
+ throw new Error('@yydb/yydb/wasm: database session is closed');
113
+ }
114
+ return this.session;
115
+ }
116
+ }
@@ -0,0 +1,5 @@
1
+ export { Database, type WasmOpenOptions } from './database.js';
2
+ export { checkSchema, createMemorySession, initWasm, introspectSchema, openPersistentSession, queryMemory, resetWasmBindingForTests, yydbVersion, type CheckSchemaResult, type InitWasmOptions, type WasmInitInput, type WasmSession, } from './binding.js';
3
+ export { defineMicro, type DefinedMicro, type MicroHandle, type TsMicroDefinitionInput, MicroSessionRegistry } from '../shared/micro.js';
4
+ export { bool, i64, nullType, text, type InferUdfArgs, type InferUdfReturn, type MicroEffect, type MicroInvocationMode, type UdfScalarKind, type UdfTypeDescriptor, } from '../shared/udf-types.js';
5
+ export type { SchemaVersion } from '../shared/wasm-envelope.js';
@@ -0,0 +1,4 @@
1
+ export { Database } from './database.js';
2
+ export { checkSchema, createMemorySession, initWasm, introspectSchema, openPersistentSession, queryMemory, resetWasmBindingForTests, yydbVersion, } from './binding.js';
3
+ export { defineMicro, MicroSessionRegistry } from '../shared/micro.js';
4
+ export { bool, i64, nullType, text, } from '../shared/udf-types.js';
package/package.json CHANGED
@@ -1,26 +1,31 @@
1
1
  {
2
2
  "name": "@yydb/yydb",
3
- "version": "0.0.3",
4
- "description": "YYDB all-in-one for Node: embedded engine, CLI, and local serve",
3
+ "version": "0.0.5",
4
+ "description": "YYDB all-in-one: Node embedded engine and CLI, browser wasm core",
5
5
  "license": "MPL-2.0",
6
6
  "type": "module",
7
7
  "bin": {
8
- "yydb": "./dist/cli.js"
8
+ "yydb": "./dist/node/cli.js"
9
9
  },
10
- "main": "./dist/index.js",
11
- "types": "./dist/index.d.ts",
10
+ "main": "./dist/node/index.js",
11
+ "types": "./dist/node/index.d.ts",
12
12
  "exports": {
13
13
  ".": {
14
- "types": "./dist/index.d.ts",
15
- "import": "./dist/index.js"
14
+ "types": "./dist/node/index.d.ts",
15
+ "node": "./dist/node/index.js",
16
+ "default": "./dist/wasm/index.js"
16
17
  },
17
- "./cli": {
18
- "types": "./dist/cli.d.ts",
19
- "import": "./dist/cli.js"
18
+ "./node": {
19
+ "types": "./dist/node/index.d.ts",
20
+ "import": "./dist/node/index.js"
21
+ },
22
+ "./wasm": {
23
+ "types": "./dist/wasm/index.d.ts",
24
+ "import": "./dist/wasm/index.js"
20
25
  },
21
- "./generator": {
22
- "types": "./dist/generator/index.d.ts",
23
- "import": "./dist/generator/index.js"
26
+ "./cli": {
27
+ "types": "./dist/node/cli.d.ts",
28
+ "import": "./dist/node/cli.js"
24
29
  }
25
30
  },
26
31
  "files": [
@@ -28,8 +33,8 @@
28
33
  "README.md"
29
34
  ],
30
35
  "scripts": {
31
- "build": "tsc -p tsconfig.json",
32
- "test": "pnpm run build && node --experimental-strip-types --test src/**/*.test.ts"
36
+ "build": "tsc -p tsconfig.node.json && tsc -p tsconfig.wasm.json",
37
+ "test": "pnpm run build && node --experimental-strip-types --test src/node/**/*.test.ts src/shared/**/*.test.ts"
33
38
  },
34
39
  "repository": {
35
40
  "type": "git",
@@ -52,7 +57,8 @@
52
57
  },
53
58
  "dependencies": {
54
59
  "@vmz/commander": "^0.2.0",
55
- "@yydb/yydb-client": "0.0.3"
60
+ "@yydb/yydb-client": "0.0.5",
61
+ "@yydb/yydb-unknown-wasm32": "0.0.5"
56
62
  },
57
63
  "devDependencies": {
58
64
  "@types/node": "^20.10.0",
@@ -62,9 +68,9 @@
62
68
  "node": ">=18"
63
69
  },
64
70
  "optionalDependencies": {
65
- "@yydb/yydb-win32-x64": "0.0.3",
66
- "@yydb/yydb-linux-x64": "0.0.3",
67
- "@yydb/yydb-darwin-x64": "0.0.3",
68
- "@yydb/yydb-darwin-arm64": "0.0.3"
71
+ "@yydb/yydb-win32-x64": "0.0.5",
72
+ "@yydb/yydb-linux-x64": "0.0.5",
73
+ "@yydb/yydb-darwin-x64": "0.0.5",
74
+ "@yydb/yydb-darwin-arm64": "0.0.5"
69
75
  }
70
76
  }
@@ -1,3 +0,0 @@
1
- import type { Cli, ParsedOptions } from '@vmz/commander';
2
- export declare function registerGenerateCommand(cli: Cli): void;
3
- export declare function cmdGenerate(options: ParsedOptions): number;
@@ -1,25 +0,0 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
- import { generateTypeScript } from '../generator/index.js';
4
- import { requiredPositional, str } from './options.js';
5
- export function registerGenerateCommand(cli) {
6
- cli.command('generate', 'cli.cmd.generate')
7
- .option('-o, --output <path>', 'cli.opt.output')
8
- .option('--schema-version <n>', 'cli.opt.schema-version')
9
- .action((options) => cmdGenerate(options));
10
- }
11
- export function cmdGenerate(options) {
12
- const input = requiredPositional(options, 'generate');
13
- const output = str(options, 'output');
14
- if (!output) {
15
- throw new Error('generate requires --output <path>');
16
- }
17
- const schemaVersion = Number.parseInt(str(options, 'schema-version') ?? '1', 10);
18
- const source = fs.readFileSync(input, 'utf8');
19
- const ts = generateTypeScript(source, schemaVersion);
20
- const outPath = path.resolve(output);
21
- fs.mkdirSync(path.dirname(outPath), { recursive: true });
22
- fs.writeFileSync(outPath, ts);
23
- console.log(`wrote ${outPath}`);
24
- return 0;
25
- }
@@ -1,3 +0,0 @@
1
- import { type TsSchemaIr } from './ir.js';
2
- /** Generate `schema.generated.ts` source from IR. */
3
- export declare function emitTypeScript(ir: TsSchemaIr): string;
@@ -1,26 +0,0 @@
1
- import { scalarToTs } from './ir.js';
2
- const BANNER = '// @generated by `yydb generate`, do not edit!';
3
- /** Generate `schema.generated.ts` source from IR. */
4
- export function emitTypeScript(ir) {
5
- const lines = [BANNER];
6
- lines.push(`export const APP_SCHEMA_VERSION = ${ir.schemaVersion};`);
7
- lines.push(`export const APP_SCHEMA = ${JSON.stringify(ir.vosSource)};`);
8
- for (const table of ir.tables) {
9
- lines.push(emitInterfaceRow(table));
10
- }
11
- lines.push(emitInterfaceAppDb(ir));
12
- lines.push(`export type AppDbTableName = keyof AppDb["tables"];`);
13
- return `${lines.join('\n')}\n`;
14
- }
15
- function emitInterfaceRow(table) {
16
- const lines = [`export interface ${table.name}Row {`];
17
- for (const field of table.fields) {
18
- lines.push(` ${field.name}: ${scalarToTs(field.ty)};`);
19
- }
20
- lines.push('}');
21
- return lines.join('\n');
22
- }
23
- function emitInterfaceAppDb(ir) {
24
- const tableLines = ir.tables.map((table) => ` ${table.name}: ${table.name}Row;`);
25
- return ['export interface AppDb {', ' tables: {', ...tableLines, ' };', '}'].join('\n');
26
- }
@@ -1,13 +0,0 @@
1
- export declare const APP_SCHEMA_VERSION = 1;
2
- export declare const APP_SCHEMA = "table Setting {\n @@id: uuid,\n key: utf8,\n value: utf8,\n}\n";
3
- export interface SettingRow {
4
- id: string;
5
- key: string;
6
- value: string;
7
- }
8
- export interface AppDb {
9
- tables: {
10
- Setting: SettingRow;
11
- };
12
- }
13
- export type AppDbTableName = keyof AppDb["tables"];
@@ -1,3 +0,0 @@
1
- // @generated by `yydb generate`, do not edit!
2
- export const APP_SCHEMA_VERSION = 1;
3
- export const APP_SCHEMA = "table Setting {\n @@id: uuid,\n key: utf8,\n value: utf8,\n}\n";
@@ -1,6 +0,0 @@
1
- export type { SchemaField, SchemaTable, ScalarType, TsSchemaIr } from './ir.js';
2
- export { emitTypeScript } from './emit-typescript.js';
3
- export { parseVosSubset, VosParseError } from './parse-vos.js';
4
- /** Generate TypeScript from a VOS document. */
5
- export declare function generateTypeScript(vosSource: string, schemaVersion: number): string;
6
- export { generateTypeScript as generateTypescript };
@@ -1,10 +0,0 @@
1
- import { emitTypeScript } from './emit-typescript.js';
2
- import { parseVosSubset } from './parse-vos.js';
3
- export { emitTypeScript } from './emit-typescript.js';
4
- export { parseVosSubset, VosParseError } from './parse-vos.js';
5
- /** Generate TypeScript from a VOS document. */
6
- export function generateTypeScript(vosSource, schemaVersion) {
7
- const ir = parseVosSubset(vosSource, schemaVersion);
8
- return emitTypeScript(ir);
9
- }
10
- export { generateTypeScript as generateTypescript };
@@ -1,20 +0,0 @@
1
- /** Scalar types supported by the MVP emitter (expand with `vos-parser`). */
2
- export type ScalarType = 'uuid' | 'utf8' | 'bool' | 'i64' | 'f64';
3
- export interface SchemaField {
4
- readonly name: string;
5
- readonly ty: ScalarType;
6
- /** True when this field is declared via `@@id`. */
7
- readonly isId: boolean;
8
- }
9
- export interface SchemaTable {
10
- readonly name: string;
11
- readonly fields: readonly SchemaField[];
12
- }
13
- /** One schema document ready for TypeScript emission. */
14
- export interface TsSchemaIr {
15
- /** Original VOS source (database truth embedded into generated module). */
16
- readonly vosSource: string;
17
- readonly schemaVersion: number;
18
- readonly tables: readonly SchemaTable[];
19
- }
20
- export declare function scalarToTs(ty: ScalarType): string;
@@ -1,12 +0,0 @@
1
- export function scalarToTs(ty) {
2
- switch (ty) {
3
- case 'uuid':
4
- case 'utf8':
5
- return 'string';
6
- case 'bool':
7
- return 'boolean';
8
- case 'i64':
9
- case 'f64':
10
- return 'number';
11
- }
12
- }
@@ -1,6 +0,0 @@
1
- import type { TsSchemaIr } from './ir.js';
2
- export declare class VosParseError extends Error {
3
- constructor(message: string);
4
- }
5
- /** Interim VOS subset parser for `yydb generate` (MVP). */
6
- export declare function parseVosSubset(source: string, schemaVersion: number): TsSchemaIr;
@@ -1,149 +0,0 @@
1
- export class VosParseError extends Error {
2
- constructor(message) {
3
- super(message);
4
- this.name = 'VosParseError';
5
- }
6
- }
7
- /** Interim VOS subset parser for `yydb generate` (MVP). */
8
- export function parseVosSubset(source, schemaVersion) {
9
- if (source.includes('\0')) {
10
- throw new VosParseError('VOS document must not contain NUL bytes');
11
- }
12
- let normalized = source.startsWith('\uFEFF') ? source.slice(1) : source;
13
- normalized = normalized.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
14
- const lexer = new Lexer(normalized);
15
- const tables = [];
16
- while (!lexer.eof()) {
17
- lexer.skipWsAndComments();
18
- if (lexer.eof()) {
19
- break;
20
- }
21
- tables.push(parseTable(lexer));
22
- }
23
- if (tables.length === 0) {
24
- throw new VosParseError('expected at least one `table` declaration');
25
- }
26
- return {
27
- vosSource: normalized,
28
- schemaVersion,
29
- tables,
30
- };
31
- }
32
- function parseTable(lexer) {
33
- lexer.expectIdent('table');
34
- const name = lexer.expectAnyIdent();
35
- lexer.expectPunct('{');
36
- const fields = [];
37
- while (true) {
38
- lexer.skipWsAndComments();
39
- if (lexer.eatPunct('}')) {
40
- break;
41
- }
42
- if (lexer.eatPunct('@')) {
43
- lexer.expectPunct('@');
44
- const attr = lexer.expectAnyIdent();
45
- if (attr !== 'id') {
46
- throw new VosParseError(`unsupported table attribute \`@@${attr}\` (MVP supports \`@@id\` only)`);
47
- }
48
- lexer.expectPunct(':');
49
- const ty = parseScalar(lexer);
50
- fields.push({ name: 'id', ty, isId: true });
51
- }
52
- else {
53
- const fieldName = lexer.expectAnyIdent();
54
- lexer.expectPunct(':');
55
- const ty = parseScalar(lexer);
56
- fields.push({ name: fieldName, ty, isId: false });
57
- }
58
- lexer.skipWsAndComments();
59
- lexer.eatPunct(',');
60
- }
61
- if (!fields.some((field) => field.isId)) {
62
- throw new VosParseError(`table \`${name}\` requires \`@@id: <type>\``);
63
- }
64
- return { name, fields };
65
- }
66
- function parseScalar(lexer) {
67
- const name = lexer.expectAnyIdent();
68
- switch (name) {
69
- case 'uuid':
70
- return 'uuid';
71
- case 'utf8':
72
- return 'utf8';
73
- case 'bool':
74
- return 'bool';
75
- case 'i64':
76
- return 'i64';
77
- case 'f64':
78
- return 'f64';
79
- default:
80
- throw new VosParseError(`unsupported scalar type \`${name}\` (MVP: uuid, utf8, bool, i64, f64)`);
81
- }
82
- }
83
- class Lexer {
84
- src;
85
- i = 0;
86
- constructor(src) {
87
- this.src = src;
88
- }
89
- eof() {
90
- return this.i >= this.src.length;
91
- }
92
- peek() {
93
- return this.src[this.i];
94
- }
95
- bump() {
96
- const ch = this.peek();
97
- if (ch === undefined) {
98
- return undefined;
99
- }
100
- this.i += 1;
101
- return ch;
102
- }
103
- skipWsAndComments() {
104
- while (true) {
105
- while (this.peek() !== undefined && /\s/.test(this.peek())) {
106
- this.bump();
107
- }
108
- if (this.src.startsWith('//', this.i)) {
109
- while (this.peek() !== undefined && this.peek() !== '\n') {
110
- this.bump();
111
- }
112
- continue;
113
- }
114
- break;
115
- }
116
- }
117
- eatPunct(expected) {
118
- this.skipWsAndComments();
119
- if (this.peek() === expected) {
120
- this.bump();
121
- return true;
122
- }
123
- return false;
124
- }
125
- expectPunct(expected) {
126
- if (!this.eatPunct(expected)) {
127
- throw new VosParseError(`expected \`${expected}\` at byte ${this.i}`);
128
- }
129
- }
130
- expectIdent(expected) {
131
- const got = this.expectAnyIdent();
132
- if (got !== expected) {
133
- throw new VosParseError(`expected \`${expected}\`, found \`${got}\``);
134
- }
135
- }
136
- expectAnyIdent() {
137
- this.skipWsAndComments();
138
- const start = this.i;
139
- const first = this.peek();
140
- if (first === undefined || !/[A-Za-z_]/.test(first)) {
141
- throw new VosParseError(`expected identifier at byte ${this.i}`);
142
- }
143
- this.bump();
144
- while (this.peek() !== undefined && /[A-Za-z0-9_]/.test(this.peek())) {
145
- this.bump();
146
- }
147
- return this.src.slice(start, this.i);
148
- }
149
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes