From d687f20ca251637304017ced0e75d8ae5d602795 Mon Sep 17 00:00:00 2001 From: Tam Nguyen Duc <1218621+tamnd@users.noreply.github.com> Date: Wed, 19 Aug 2026 08:14:33 +0700 Subject: [PATCH] hold the public surface to a report, and the report to the Rust Two links of one chain, both in the package job because it already paid for the build they need. The first asks whether binding.d.cts still says what the Rust says: that file is generated and committed, and a committed generated file can go stale, which ships types describing a function that is no longer there. The second asks whether etc/zudb.api.md still says what binding.d.cts says, so a change to what this package exports arrives as a diff in one small file somebody reads rather than as a line buried in six hundred generated ones. What the report leaves out is written into the workflow beside it. api-extractor reads declarations rather than the type checker's merged view, so it does not follow the module augmentation in zudb.d.cts and misses stream and Symbol.asyncDispose on Connection. Those two are held from the other side, by the fixtures under test/types that call both and are compiled under the settings a user's compiler would use. The gate is validated the way the leak gates are: a renamed export has to fail it. --- .github/workflows/ci.yml | 35 ++ .gitignore | 4 + api-extractor.json | 54 +++ etc/zudb.api.md | 282 ++++++++++++++++ package-lock.json | 538 ++++++++++++++++++++++++++++++ package.json | 3 + tools/api-extractor.tsconfig.json | 23 ++ 7 files changed, 939 insertions(+) create mode 100644 api-extractor.json create mode 100644 etc/zudb.api.md create mode 100644 tools/api-extractor.tsconfig.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 476b4f1..aded997 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,6 +42,25 @@ jobs: # exists and every condition is beside the last. What breaks a # published package is the resolution instead, and only tsc and attw # read a package that way. + # + # The same job holds the API gate, because the gate needs the build + # this job already paid for. It is two links of one chain. The first + # asks whether binding.d.cts still says what the Rust says, since that + # file is generated and a committed generated file is a file that can + # go stale: change a signature, forget to rebuild, and the types ship + # describing a function that no longer exists. The second asks whether + # etc/zudb.api.md still says what binding.d.cts says, so that a change + # to what this package exports arrives as a diff in one small file + # somebody has to read rather than as a line buried in six hundred + # generated ones. + # + # What the report leaves out, said out loud: api-extractor reads + # declarations rather than the checker's merged view, so it does not + # follow the `declare module './binding.cjs'` augmentation in + # zudb.d.cts, and `stream` and `Symbol.asyncDispose` are missing from + # Connection there. Those two are held from the other side, by the + # fixtures under test/types that call both and are compiled by + # check:types under the settings a user's compiler would use. package: runs-on: ubuntu-latest steps: @@ -54,8 +73,24 @@ jobs: # The declarations are generated by the build, so there is nothing # to type-check until it has run. - run: npm run build:debug + - name: The generated declarations, still generated from this Rust + run: git diff --exit-code -- binding.d.cts - run: npm run check:types - run: npm run check:package + # The gate is validated the only way a gate can be: a change to + # the surface has to fail it. Renaming an exported function is the + # cheapest change that is unambiguously one, and the tree is put + # back before anything else looks at it. + - name: A surface change the gate is meant to catch, caught + run: | + sed -i 's/export declare function version(): string/export declare function versionRenamed(): string/' binding.d.cts + set +e + npm run check:api + rc=$? + set -e + git checkout -- binding.d.cts + test $rc -ne 0 || { echo "the api gate did not fire on a renamed export"; exit 1; } + - run: npm run check:api test: strategy: diff --git a/.gitignore b/.gitignore index 2148910..d123f53 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,10 @@ target/ node_modules/ dist/ +# Where api-extractor writes the report it just produced, before it is +# compared against the one in etc/ that is committed. +temp/ + # The built addon, which napi drops into the source tree so that the # tests load the same file a published package would. *.node diff --git a/api-extractor.json b/api-extractor.json new file mode 100644 index 0000000..12a92e1 --- /dev/null +++ b/api-extractor.json @@ -0,0 +1,54 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + + // projectFolder is said out loud because there is no tsconfig.json at + // the root to find it by. This package is Rust with a JavaScript face + // on it, and the only TypeScript configs it has are the two under + // tools and test. + "projectFolder": ".", + + // The CommonJS declarations, which are the ones written: the ESM file + // re-exports them so that a public API cannot exist in two copies and + // drift between them. + "mainEntryPointFilePath": "/zudb.d.cts", + + "compiler": { + "tsconfigFilePath": "/tools/api-extractor.tsconfig.json" + }, + + // The report is the point of running this at all. etc/zudb.api.md is + // committed, CI regenerates it and fails if it moved, and so every + // change to what this package exports arrives as a diff somebody has + // to read rather than as a line buried in six hundred generated ones. + "apiReport": { + "enabled": true, + "reportFileName": "zudb.api.md", + "reportFolder": "/etc/", + "reportTempFolder": "/temp/" + }, + + "docModel": { "enabled": false }, + "dtsRollup": { "enabled": false }, + "tsdocMetadata": { "enabled": false }, + + "messages": { + "compilerMessageReporting": { + "default": { "logLevel": "warning" } + }, + + // Release tags and doc comments are not how this package marks what + // is public: the exports map is, and everything reachable through + // it is public. So the two rules that ask for tags are off and the + // one that catches a type leaking out untyped is on. + "extractorMessageReporting": { + "default": { "logLevel": "warning" }, + "ae-missing-release-tag": { "logLevel": "none" }, + "ae-undocumented": { "logLevel": "none" }, + "ae-forgotten-export": { "logLevel": "error", "addToApiReportFile": true } + }, + + "tsdocMessageReporting": { + "default": { "logLevel": "none" } + } + } +} diff --git a/etc/zudb.api.md b/etc/zudb.api.md new file mode 100644 index 0000000..3672031 --- /dev/null +++ b/etc/zudb.api.md @@ -0,0 +1,282 @@ +## API Report File for "zudb" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @public +export function abiVersion(): string + +// @public +export function connect(path: string, options?: ConnectOptions | undefined | null): Promise + +// @public +export class Connection { + close(): void + cursor(statement: string, params?: Record | null, options?: ZuStreamOptions | null): ZuCursor + dispose(): Promise + exec(statement: string, params?: Record | null, options?: ZuStatementOptions | null): Promise + get open(): boolean + get path(): string + query>(statement: string, params?: Record | null, options?: ZuStatementOptions | null): Promise> + get readOnly(): boolean +} + +// @public +export interface ConnectOptions { + bigIntMode?: ZuBigIntMode + memoryLimit?: bigint + readOnly?: boolean + temporal?: boolean + threads?: number +} + +// @public +export function isZuError(value: unknown): value is ZuError + +// @public +export function version(): string + +// @public +export interface ZuBatch> extends Array { + // (undocumented) + readonly columns: string[] +} + +// @public +export type ZuBigIntMode = 'bigint' | 'number' + +// @public +export class ZuCursor { + cancel(): Promise + next(): Promise + get summary(): ZuSummary | null +} + +// @public +export class ZuDate { + constructor(days: number) + // (undocumented) + days: number + toJSON(): object + toTemporal(): ZuPlainDate +} + +// @public +export class ZuDuration { + get kind(): string + get months(): bigint + get nanos(): bigint + static ofMonths(months: bigint): ZuDuration + static ofNanos(nanos: bigint): ZuDuration + toJSON(): object + toTemporal(): ZuTemporalDuration +} + +// @public +export interface ZuError extends Error { + readonly code?: string + // (undocumented) + readonly column?: number + readonly condition?: string + // (undocumented) + readonly docUrl?: string + readonly excerpt?: string + readonly line?: number + readonly name: string + // (undocumented) + readonly offset?: number + readonly retryable: boolean + // (undocumented) + readonly severity?: 'success' | 'noData' | 'warning' | 'informational' | 'exception' +} + +// @public +export class ZuNode { + // (undocumented) + get offset(): bigint + // (undocumented) + get table(): string + toJSON(): object +} + +// @public +export interface ZuNotice { + // (undocumented) + readonly code: string + // (undocumented) + readonly condition: string + // (undocumented) + readonly docUrl: string + // (undocumented) + readonly message: string +} + +// @public +export type ZuParam = +| null +| undefined +| boolean +| number +| bigint +| string +| ZuDate +| ZuTime +| ZuTimestamp +| ZuDuration +| ZuTemporalValue +| ZuParam[] +| { [field: string]: ZuParam } + +// @public +export interface ZuPath { + // (undocumented) + readonly nodes: ZuNode[] + // (undocumented) + readonly rels: ZuRel[] +} + +// @public +export type ZuPlainDate = typeof globalThis extends { + Temporal: { PlainDate: new (...args: any[]) => infer Value } +} +? Value +: unknown + +// @public +export type ZuPlainDateTime = typeof globalThis extends { + Temporal: { PlainDateTime: new (...args: any[]) => infer Value } +} +? Value +: unknown + +// @public +export type ZuPlainTime = typeof globalThis extends { + Temporal: { PlainTime: new (...args: any[]) => infer Value } +} +? Value +: unknown + +// @public +export class ZuRel { + // (undocumented) + get dst(): bigint + // (undocumented) + get ord(): bigint + // (undocumented) + get src(): bigint + // (undocumented) + get table(): string + toJSON(): object +} + +// @public +export interface ZuRows> extends Array { + // (undocumented) + readonly columns: string[] + // (undocumented) + readonly gqlstatus: string + // (undocumented) + readonly notices: ZuNotice[] +} + +// @public +export interface ZuStatementOptions { + readonly bigIntMode?: ZuBigIntMode + readonly signal?: AbortSignal +} + +// @public +export class ZuStream> implements AsyncIterable, AsyncDisposable { + // (undocumented) + [Symbol.asyncDispose](): Promise + // (undocumented) + [Symbol.asyncIterator](): AsyncIterableIterator + batches(): AsyncIterableIterator> + cancel(): Promise + readonly columns: string[] | null + readonly summary: ZuSummary | null + toReadableStream(): ReadableStream +} + +// @public +export interface ZuStreamOptions extends ZuStatementOptions { + readonly batchRows?: number +} + +// @public +export interface ZuSummary { + // (undocumented) + readonly columns: string[] + // (undocumented) + readonly notices: ZuNotice[] + readonly rows: number + // (undocumented) + readonly stopped: boolean + readonly streamed: boolean +} + +// @public +export type ZuTemporalDuration = typeof globalThis extends { + Temporal: { Duration: new (...args: any[]) => infer Value } +} +? Value +: unknown + +// @public +export type ZuTemporalValue = typeof globalThis extends { + Temporal: { Instant: new (...args: any[]) => infer Instant } +} +? Instant | ZuPlainDate | ZuPlainTime | ZuPlainDateTime | ZuZonedDateTime | ZuTemporalDuration +: never + +// @public +export class ZuTime { + constructor(nanos: bigint, offset?: number | undefined | null) + // (undocumented) + get nanos(): bigint + // (undocumented) + offset?: number + toJSON(): object + toTemporal(): ZuPlainTime +} + +// @public +export class ZuTimestamp { + constructor(nanos: bigint, offset?: number | undefined | null) + // (undocumented) + get nanos(): bigint + // (undocumented) + offset?: number + toJSON(): object + toTemporal(): ZuPlainDateTime | ZuZonedDateTime +} + +// @public +export type ZuValue = +| null +| boolean +| number +| bigint +| string +| ZuNode +| ZuRel +| ZuPath +| ZuDate +| ZuTime +| ZuTimestamp +| ZuDuration +| ZuTemporalValue +| ZuValue[] +| { [field: string]: ZuValue } + +// @public +export type ZuZonedDateTime = typeof globalThis extends { + Temporal: { ZonedDateTime: new (...args: any[]) => infer Value } +} +? Value +: unknown + +// (No @packageDocumentation comment for this package) + +``` diff --git a/package-lock.json b/package-lock.json index 3448996..0d63c9b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "Apache-2.0", "devDependencies": { "@arethetypeswrong/cli": "^0.18.2", + "@microsoft/api-extractor": "^7.58.12", "@napi-rs/cli": "^3.8.6", "@types/node": "^26.2.0", "typescript": "^5.9.3" @@ -487,6 +488,76 @@ "@braidai/lang": "^1.0.0" } }, + "node_modules/@microsoft/api-extractor": { + "version": "7.58.12", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.58.12.tgz", + "integrity": "sha512-VNpgC/1LaroLbn+UKmwDYspq+9r3EHyj4vJ3qUy/g8vB0rKt+1Wgs7WFj/JGpgxhG8SNyXs1XwYwe7nqkk8IDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/api-extractor-model": "7.33.10", + "@microsoft/tsdoc": "~0.16.0", + "@microsoft/tsdoc-config": "~0.18.1", + "@rushstack/node-core-library": "5.23.3", + "@rushstack/rig-package": "0.7.3", + "@rushstack/terminal": "0.24.2", + "@rushstack/ts-command-line": "5.3.12", + "diff": "~8.0.2", + "minimatch": "10.2.3", + "resolve": "~1.22.1", + "semver": "~7.7.4", + "source-map": "~0.6.1", + "typescript": "5.9.3" + }, + "bin": { + "api-extractor": "bin/api-extractor" + } + }, + "node_modules/@microsoft/api-extractor-model": { + "version": "7.33.10", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.33.10.tgz", + "integrity": "sha512-uPUK17xGxeQ3av6TN7awp+dTTSTvx8fZC0XFL1gyt7hFapYuxND3XLXH8vkmI7UjfW92oogzFAFqHSifmJROaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "~0.16.0", + "@microsoft/tsdoc-config": "~0.18.1", + "@rushstack/node-core-library": "5.23.3" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@microsoft/tsdoc": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.16.0.tgz", + "integrity": "sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@microsoft/tsdoc-config": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.18.1.tgz", + "integrity": "sha512-9brPoVdfN9k9g0dcWkFeA7IH9bbcttzDJlXvkf8b2OBzd5MueR1V2wkKBL0abn0otvmkHJC6aapBOTJDDeMCZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "0.16.0", + "ajv": "~8.18.0", + "jju": "~1.4.0", + "resolve": "~1.22.2" + } + }, "node_modules/@napi-rs/cli": { "version": "3.8.6", "resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-3.8.6.tgz", @@ -1792,6 +1863,146 @@ "@octokit/openapi-types": "^28.0.0" } }, + "node_modules/@rushstack/node-core-library": { + "version": "5.23.3", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.23.3.tgz", + "integrity": "sha512-f6uuza7Um65bwsIJgf0MRs7IPA5IG+A+zs1AYGQvpZmLjtTGdfHowhQw4kwF0pPhJCrU4UHNhK8Qa6tLygYZCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "~8.20.0", + "ajv-draft-04": "~1.0.0", + "ajv-formats": "~3.0.1", + "fs-extra": "~11.3.0", + "import-lazy": "~4.0.0", + "jju": "~1.4.0", + "resolve": "~1.22.1", + "semver": "~7.7.4" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/node-core-library/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@rushstack/node-core-library/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@rushstack/problem-matcher": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@rushstack/problem-matcher/-/problem-matcher-0.2.1.tgz", + "integrity": "sha512-gulfhBs6n+I5b7DvjKRfhMGyUejtSgOHTclF/eONr8hcgF1APEDjhxIsfdUYYMzC3rvLwGluqLjbwCFZ8nxrog==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/rig-package": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.7.3.tgz", + "integrity": "sha512-aAA518n6wxxjCfnTAOjQnm7ngNE0FVHxHAw2pxKlIhxrMn0XQjGcXKF0oKWpjBgJOmsaJpVob/v+zr3zxgPWuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jju": "~1.4.0", + "resolve": "~1.22.1" + } + }, + "node_modules/@rushstack/terminal": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.24.2.tgz", + "integrity": "sha512-KB7PpvzDyKMw/RGU3TxOwxTs3OwZ4gq6+WHlTJN/JfQH4ezliNtWIqver78jTaAJyz/ZAAlJGH7a/M1WyFLFSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rushstack/node-core-library": "5.23.3", + "@rushstack/problem-matcher": "0.2.1", + "supports-color": "~8.1.1" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/terminal/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@rushstack/ts-command-line": { + "version": "5.3.12", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-5.3.12.tgz", + "integrity": "sha512-Vg2n24arSf7JvUNga2DMHYTbxnVq9L5OtVCp4Gfr8YC/kmL/bmdR8FQhGcpMzMYNY9Vdw3+TaimG11Sf+z1Tpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rushstack/terminal": "0.24.2", + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "string-argv": "~0.3.1" + } + }, + "node_modules/@rushstack/ts-command-line/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, "node_modules/@sindresorhus/is": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", @@ -1816,6 +2027,13 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/argparse": { + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz", + "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { "version": "26.2.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-26.2.0.tgz", @@ -1826,6 +2044,56 @@ "undici-types": "~8.3.0" } }, + "node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^8.5.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, "node_modules/ansi-escapes": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", @@ -1885,6 +2153,16 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/before-after-hook": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", @@ -1892,6 +2170,19 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/brace-expansion": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -2078,6 +2369,16 @@ } } }, + "node_modules/diff": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -2105,6 +2406,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-toolkit": { "version": "1.51.0", "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.51.0.tgz", @@ -2128,6 +2439,13 @@ "node": ">=6" } }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-string-truncated-width": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", @@ -2145,6 +2463,23 @@ "fast-string-truncated-width": "^3.0.2" } }, + "node_modules/fast-uri": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", + "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/fast-wrap-ansi": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", @@ -2162,6 +2497,31 @@ "dev": true, "license": "MIT" }, + "node_modules/fs-extra": { + "version": "11.3.6", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", + "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -2172,6 +2532,13 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2182,6 +2549,19 @@ "node": ">=8" } }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/highlight.js": { "version": "10.7.3", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", @@ -2209,6 +2589,32 @@ "url": "https://opencollective.com/express" } }, + "node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -2219,6 +2625,13 @@ "node": ">=8" } }, + "node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "dev": true, + "license": "MIT" + }, "node_modules/js-yaml": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", @@ -2242,6 +2655,13 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, "node_modules/json-with-bigint": { "version": "3.5.12", "resolved": "https://registry.npmjs.org/json-with-bigint/-/json-with-bigint-3.5.12.tgz", @@ -2249,6 +2669,19 @@ "dev": true, "license": "MIT" }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/lru-cache": { "version": "11.5.2", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", @@ -2307,6 +2740,22 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/minimatch": { + "version": "10.2.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.3.tgz", + "integrity": "sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -2400,6 +2849,13 @@ "dev": true, "license": "MIT" }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -2410,6 +2866,38 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -2456,6 +2944,33 @@ "node": ">=8" } }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -2524,6 +3039,19 @@ "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -2603,6 +3131,16 @@ "dev": true, "license": "ISC" }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/validate-npm-package-name": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", diff --git a/package.json b/package.json index 051aff6..105ccb1 100644 --- a/package.json +++ b/package.json @@ -67,11 +67,14 @@ "test:deno": "deno test --no-check --allow-read --allow-write --allow-env --allow-ffi \"test/*.test.mjs\"", "check:types": "tsc --noEmit --project test/types/tsconfig.json", "check:package": "attw --pack .", + "check:api": "api-extractor run --verbose", + "check:api:update": "api-extractor run --local", "bench": "node bench/query.mjs", "bench:temporal": "node --harmony-temporal bench/query.mjs" }, "devDependencies": { "@arethetypeswrong/cli": "^0.18.2", + "@microsoft/api-extractor": "^7.58.12", "@napi-rs/cli": "^3.8.6", "@types/node": "^26.2.0", "typescript": "^5.9.3" diff --git a/tools/api-extractor.tsconfig.json b/tools/api-extractor.tsconfig.json new file mode 100644 index 0000000..84b0c66 --- /dev/null +++ b/tools/api-extractor.tsconfig.json @@ -0,0 +1,23 @@ +{ + "//": [ + "The compiler settings api-extractor reads the public types with.", + "They are the ones in test/types/tsconfig.json, because the report", + "is meant to say what a TypeScript user sees and that file is what", + "a TypeScript user's compiler does. skipLibCheck is on here and off", + "there: this run is a reader rather than a checker, and the checking", + "is what the other one is for." + ], + "compilerOptions": { + "module": "node16", + "moduleResolution": "node16", + "target": "es2023", + "lib": ["ES2023", "ESNext.Disposable"], + "types": ["node"], + "strict": true, + "noEmit": true, + "skipLibCheck": true, + "exactOptionalPropertyTypes": true, + "noUncheckedIndexedAccess": true + }, + "files": ["../zudb.d.cts"] +}