Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
54 changes: 54 additions & 0 deletions api-extractor.json
Original file line number Diff line number Diff line change
@@ -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": "<projectFolder>/zudb.d.cts",

"compiler": {
"tsconfigFilePath": "<projectFolder>/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": "<projectFolder>/etc/",
"reportTempFolder": "<projectFolder>/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" }
}
}
}
282 changes: 282 additions & 0 deletions etc/zudb.api.md
Original file line number Diff line number Diff line change
@@ -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<Connection>

// @public
export class Connection {
close(): void
cursor(statement: string, params?: Record<string, ZuParam> | null, options?: ZuStreamOptions | null): ZuCursor
dispose(): Promise<void>
exec(statement: string, params?: Record<string, ZuParam> | null, options?: ZuStatementOptions | null): Promise<void>
get open(): boolean
get path(): string
query<Row = Record<string, ZuValue>>(statement: string, params?: Record<string, ZuParam> | null, options?: ZuStatementOptions | null): Promise<ZuRows<Row>>
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<Row = Record<string, ZuValue>> extends Array<Row> {
// (undocumented)
readonly columns: string[]
}

// @public
export type ZuBigIntMode = 'bigint' | 'number'

// @public
export class ZuCursor {
cancel(): Promise<void>
next(): Promise<ZuBatch | null>
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<Row = Record<string, ZuValue>> extends Array<Row> {
// (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<Row = Record<string, ZuValue>> implements AsyncIterable<Row>, AsyncDisposable {
// (undocumented)
[Symbol.asyncDispose](): Promise<void>
// (undocumented)
[Symbol.asyncIterator](): AsyncIterableIterator<Row>
batches(): AsyncIterableIterator<ZuBatch<Row>>
cancel(): Promise<void>
readonly columns: string[] | null
readonly summary: ZuSummary | null
toReadableStream(): ReadableStream<Row>
}

// @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)

```
Loading
Loading