@gitsheets/core-napi 0.4.0 → 0.6.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.
package/binding.cjs CHANGED
@@ -149,6 +149,10 @@ module.exports = {
149
149
  // the filter (equality / nested / `$pred` engine snippets) runs in the core.
150
150
  recordQuery: wrap(addon.recordQuery),
151
151
  recordQueryCandidates: wrap(addon.recordQueryCandidates),
152
+ treeReadBlob: wrap(addon.treeReadBlob),
153
+ treeEntryHash: wrap(addon.treeEntryHash),
154
+ blobRead: wrap(addon.blobRead),
155
+ blobHeader: wrap(addon.blobHeader),
152
156
  templateFieldNames: wrap(addon.templateFieldNames),
153
157
  // Secondary indexing (lazy, in-memory). A unique conflict surfaces as a typed
154
158
  // IndexError(index_unique_conflict).
@@ -166,7 +170,12 @@ module.exports = {
166
170
  // `mapCoreError` where a typed instance is wanted.
167
171
  CoreTransaction: addon.CoreTransaction,
168
172
  coreDiscoverSheets: wrap(addon.coreDiscoverSheets),
173
+ syncBranch: wrap(addon.syncBranch),
174
+ isAncestor: wrap(addon.isAncestor),
175
+ mergeSheets: wrap(addon.mergeSheets),
176
+ mergeRecordTexts: wrap(addon.mergeRecordTexts),
169
177
  coreCheckValidators: wrap(addon.coreCheckValidators),
178
+ sheetConfigCheck: wrap(addon.sheetConfigCheck),
170
179
  // Consumer-side contract verification — the two-rung ladder behind
171
180
  // `openSheet(name, { contract })` (specs/behaviors/contracts.md "Consumer
172
181
  // verification"). A verification failure raises a typed
package/index.d.ts CHANGED
@@ -235,15 +235,61 @@ export declare function substrateReset(): void
235
235
  /**
236
236
  * Query records under `base` in the tree `treeRef`, returning each matched
237
237
  * `{ path, record }` in sorted path order. The template prunes the walk; the
238
- * filter (equality / nested / `$pred` snippets) is applied to each candidate.
239
- * Batch-first: the whole query crosses the FFI once.
238
+ * filter (equality / nested / `$pred` snippets / `{ $gt, $gte, $lt, $lte }` ranges)
239
+ * is applied to each candidate; a range on a date-bucket path field prunes
240
+ * the walk to the bounded span of partitions. Batch-first: the whole query
241
+ * crosses the FFI once.
242
+ *
243
+ * Format-aware: pass `bodyField` (and optionally `titleField`) for a
244
+ * markdown/mdx sheet (the kind follows `extension`: `.mdx` → mdx, else
245
+ * markdown) and the core decodes each candidate through the frontmatter
246
+ * codec — `withBody: false` is the lazy-body switch (default `true`). Without
247
+ * `bodyField` records are canonical TOML. The binding never fetches record
248
+ * bytes itself (spec: `rust-core.md` "Query traversal + filtering").
249
+ */
250
+ export declare function recordQuery(gitDir: string, treeRef: string, base: string, template: string, filter: object, extension?: string | undefined | null, bodyField?: string | undefined | null, titleField?: string | undefined | null, withBody?: boolean | undefined | null): Array<JsRecordEntry>
251
+ /**
252
+ * A blob read by `treeRef:path` — the bytes plus the blob's object id, or
253
+ * `null` when nothing (or a subtree) lives at `path`. Backs sheet-config
254
+ * loading and lazy-body hydration without a `git cat-file` subprocess
255
+ * (spec: `rust-core.md` "Blob reads").
240
256
  */
241
- export declare function recordQuery(gitDir: string, treeRef: string, base: string, template: string, filter: object, extension?: string | undefined | null): Array<JsRecordEntry>
257
+ export declare function treeReadBlob(gitDir: string, treeRef: string, path: string): JsBlobEntry | null
258
+ /**
259
+ * The object id of the blob at `treeRef:path`, or `null` when absent or not
260
+ * a blob. The hash-only lookup (attachment handles, cache keys).
261
+ */
262
+ export declare function treeEntryHash(gitDir: string, treeRef: string, path: string): string | null
263
+ /**
264
+ * A blob's bytes by object id, or `null` when no object has that id. Backs
265
+ * attachment content reads and diff-side record reads.
266
+ */
267
+ export declare function blobRead(gitDir: string, hash: string): Buffer | null
268
+ /**
269
+ * An object header: `kind` (`blob` / `tree` / `commit` / `tag`) and `size` in
270
+ * bytes, read without inflating the object.
271
+ */
272
+ export interface JsBlobHeader {
273
+ kind: string
274
+ size: number
275
+ }
276
+ /**
277
+ * The object header for `hash`, or `null` when no object has that id. The
278
+ * metadata behind a host `BlobHandle`'s `size` (specs/behaviors/attachments.md
279
+ * "Blob metadata and bounded buffering").
280
+ */
281
+ export declare function blobHeader(gitDir: string, hash: string): JsBlobHeader | null
282
+ /** A blob read by `treeRef:path`: its object id and bytes. */
283
+ export interface JsBlobEntry {
284
+ hash: string
285
+ content: Buffer
286
+ }
242
287
  /**
243
288
  * The pruning candidate set alone (no content filter applied) — the direct
244
289
  * parity target for the host `Template.queryTree`. `query` is a (partial)
245
- * record of the path-template input fields. Returns candidate record paths
246
- * (relative to `base`, no extension) in sorted order.
290
+ * record of the path-template input fields; a date-bucket field may carry a
291
+ * `{ $gte, $lt, … }` range object, which bounds the walk. Returns candidate
292
+ * record paths (relative to `base`, no extension) in sorted order.
247
293
  */
248
294
  export declare function recordQueryCandidates(gitDir: string, treeRef: string, base: string, template: string, query: JsValue, extension?: string | undefined | null): Array<string>
249
295
  /**
@@ -313,6 +359,12 @@ export interface JsTrailer {
313
359
  */
314
360
  export interface JsTransactionOptions {
315
361
  parent?: string
362
+ /**
363
+ * `transact({ parent: null })`: an orphan root commit — empty starting
364
+ * tree, no parents, always commits; `branch` is created (and must not
365
+ * already exist). `parent` is ignored when set.
366
+ */
367
+ orphan?: boolean
316
368
  branch?: string
317
369
  author?: JsAuthor
318
370
  committer?: JsAuthor
@@ -344,11 +396,100 @@ export interface JsAttachmentEntry {
344
396
  name: string
345
397
  hash: string
346
398
  }
399
+ /** Options for [`sync_branch`]. */
400
+ export interface JsSyncOptions {
401
+ /** Local branch (bare name or qualified ref). */
402
+ branch: string
403
+ /** Remote-tracking ref (or any commit-ish), e.g. `refs/remotes/origin/main`. */
404
+ remoteRef: string
405
+ /** `'fail'` (default) or `'preserve-branch'`. */
406
+ onConflict?: string
407
+ /** Prefix for the preserved branch; default `conflicts/`. */
408
+ conflictBranchPrefix?: string
409
+ /** Committer for replayed commits; default: the repository's identity. */
410
+ committer?: JsAuthor
411
+ timeSeconds: number
412
+ offsetMinutes: number
413
+ }
414
+ /** The result of [`sync_branch`]. */
415
+ export interface JsSyncResult {
416
+ outcome: string
417
+ oldCommit: string
418
+ newCommit: string
419
+ ahead: number
420
+ behind: number
421
+ conflictCommit?: string
422
+ conflictBranch?: string
423
+ }
424
+ /**
425
+ * Classify the local branch against the remote-tracking tip and move it
426
+ * (fast-forward, replay, or preserve-on-conflict). The host fetches first
427
+ * and holds the write lock. See specs/behaviors/push-sync.md "Sync".
428
+ */
429
+ export declare function syncBranch(gitDir: string, opts: JsSyncOptions): JsSyncResult
430
+ /** Whether commit `a` is reachable from commit `b` (or equal). */
431
+ export declare function isAncestor(gitDir: string, a: string, b: string): boolean
432
+ export interface JsMergeOptions {
433
+ ours: string
434
+ theirs: string
435
+ openRoot?: string
436
+ /** `fail` (default) | `ours` | `theirs`. */
437
+ prefer?: string
438
+ /** Default true; false writes the tree and moves nothing. */
439
+ commit?: boolean
440
+ message?: string
441
+ author?: JsAuthor
442
+ committer?: JsAuthor
443
+ timeSeconds: number
444
+ offsetMinutes: number
445
+ }
446
+ export interface JsMergeConflict {
447
+ path: string
448
+ kind: string
449
+ field?: string
450
+ ours?: string
451
+ theirs?: string
452
+ }
453
+ export interface JsMergeResult {
454
+ outcome: string
455
+ oursCommit: string
456
+ theirsCommit: string
457
+ base?: string
458
+ tree?: string
459
+ commit?: string
460
+ mergedRecords: Array<string>
461
+ conflicts: Array<JsMergeConflict>
462
+ }
463
+ /**
464
+ * Sheet-aware merge of `theirs` into `ours` — record files changed on both
465
+ * sides are field-merged and written canonically; conflicts follow `prefer`
466
+ * or are reported. The host holds the write lock.
467
+ */
468
+ export declare function mergeSheets(gitDir: string, opts: JsMergeOptions): JsMergeResult
469
+ export interface JsRecordMergeOutcome {
470
+ text?: string
471
+ conflicts: Array<string>
472
+ }
473
+ /**
474
+ * Field-merge one record's base / ours / theirs texts through the sheet at
475
+ * `treeRef` (the merge-driver primitive): canonical text, or the conflicting
476
+ * field paths.
477
+ */
478
+ export declare function mergeRecordTexts(gitDir: string, treeRef: string, sheetName: string, configPath: string, openRoot: string, base: string | undefined | null, ours: string, theirs: string, prefer?: string | undefined | null): JsRecordMergeOutcome
347
479
  /**
348
480
  * Discover every sheet declared in `<openRoot>/.gitsheets/*.toml` in the tree
349
481
  * `treeRef`. Sorted bare names. The `Store` discovery half (`openStore`).
350
482
  */
351
483
  export declare function coreDiscoverSheets(gitDir: string, treeRef: string, openRoot: string): Array<string>
484
+ /**
485
+ * Open the sheet whose config blob lives at `configPath` in the tree `treeRef`
486
+ * and discard it — the full open-time validation the core performs
487
+ * (config parse, contract load/compile, template coherence per
488
+ * specs/behaviors/path-templates.md "Template fields must be
489
+ * schema-required") surfaced to the host as typed errors. The host calls it
490
+ * once per distinct config blob from `repo.openSheet`.
491
+ */
492
+ export declare function sheetConfigCheck(gitDir: string, treeRef: string, sheetName: string, configPath: string, openRoot: string): void
352
493
  /**
353
494
  * The `openStore` `config_missing` check: every validator must name a declared
354
495
  * sheet. Throws `ConfigError(config_missing)` otherwise.
@@ -470,12 +611,13 @@ export declare class CoreTransaction {
470
611
  /** Stage a single attachment *(mutating)* — sugar over [`Self::set_attachments`]. */
471
612
  setAttachment(name: string, recordPath: string, attachmentName: string, blobHash: string): void
472
613
  /**
473
- * Stage a raw text file at `path` in this transaction's private tree
474
- * *(mutating)* — the generic file write the CLI uses to commit sheet-config
475
- * edits (`init` / `infer` / `migrate-config`) atomically alongside nothing
476
- * else. `path` is repo-root-relative. Returns the written blob hash.
614
+ * Stage a raw file at `path` in this transaction's private tree
615
+ * *(mutating)* — the public `tx.writeFile` (specs/api/transaction.md
616
+ * "Raw files"): a sheet config, a contract, a fixture, committed with the
617
+ * record changes it belongs with. `path` is repo-root-relative; `content`
618
+ * is UTF-8 text or raw bytes. Returns the written blob hash.
477
619
  */
478
- writeFile(path: string, content: string): string
620
+ writeFile(path: string, content: string | Buffer): string
479
621
  /**
480
622
  * Delete a raw file at `path` (repo-root-relative) in this transaction's
481
623
  * private tree *(mutating)* — `write_file`'s inverse. Returns whether a
@@ -510,6 +652,22 @@ export declare class CoreTransaction {
510
652
  * Read-only — does not mark the transaction mutated.
511
653
  */
512
654
  list(name: string, withBody: boolean): Array<JsRecordEntry>
655
+ /**
656
+ * Query the sheet's records in the transaction's private tree — pruned by
657
+ * the path template exactly like a committed-ref query, decoded through
658
+ * the format codec, `withBody` the lazy-body switch (spec:
659
+ * `api/transaction.md` "Read isolation"). The filter takes the same forms
660
+ * as `recordQuery` (equality / nested / `$pred` / ranges). Read-only —
661
+ * does not mark the transaction mutated.
662
+ */
663
+ query(name: string, filter: object, withBody: boolean): Array<JsRecordEntry>
664
+ /**
665
+ * Read the one record at `recordPath` (relative to the sheet's base, no
666
+ * extension) in the transaction's private tree, decoded through the format
667
+ * codec — the tx-bound `Sheet.get`. `null` when absent; `withBody` is the
668
+ * lazy-body switch. Read-only.
669
+ */
670
+ readRecord(name: string, recordPath: string, withBody: boolean): JsValue | null
513
671
  /** The parent commit hash captured at open (null on a fresh repo). */
514
672
  parentCommitHash(): string | null
515
673
  /**
package/index.js CHANGED
@@ -310,7 +310,7 @@ if (!nativeBinding) {
310
310
  throw new Error(`Failed to load native binding`)
311
311
  }
312
312
 
313
- const { roundtrip, parseRecords, serializeRecords, renderPathsBatch, validateBatch, canonicalContractHash, validateContractName, contractPath, checkContractDocument, contractLoad, verifySheetContract, runComparator, collatorSort, CompiledDefinition, recordRead, recordWrite, recordDelete, recordList, writeBlob, substrateStats, substrateReset, recordQuery, recordQueryCandidates, templateFieldNames, recordIndexUnique, recordIndexMulti, createPatch, applyMergePatch, diffRecords, simulateCoreError, CoreTransaction, coreDiscoverSheets, coreCheckValidators, markdownSerialize, markdownNormalizeBody, markdownParse, markdownParseHeaderOnly, markdownExtractH1, markdownRewriteH1 } = nativeBinding
313
+ const { roundtrip, parseRecords, serializeRecords, renderPathsBatch, validateBatch, canonicalContractHash, validateContractName, contractPath, checkContractDocument, contractLoad, verifySheetContract, runComparator, collatorSort, CompiledDefinition, recordRead, recordWrite, recordDelete, recordList, writeBlob, substrateStats, substrateReset, recordQuery, treeReadBlob, treeEntryHash, blobRead, blobHeader, recordQueryCandidates, templateFieldNames, recordIndexUnique, recordIndexMulti, createPatch, applyMergePatch, diffRecords, simulateCoreError, CoreTransaction, syncBranch, isAncestor, mergeSheets, mergeRecordTexts, coreDiscoverSheets, sheetConfigCheck, coreCheckValidators, markdownSerialize, markdownNormalizeBody, markdownParse, markdownParseHeaderOnly, markdownExtractH1, markdownRewriteH1 } = nativeBinding
314
314
 
315
315
  module.exports.roundtrip = roundtrip
316
316
  module.exports.parseRecords = parseRecords
@@ -334,6 +334,10 @@ module.exports.writeBlob = writeBlob
334
334
  module.exports.substrateStats = substrateStats
335
335
  module.exports.substrateReset = substrateReset
336
336
  module.exports.recordQuery = recordQuery
337
+ module.exports.treeReadBlob = treeReadBlob
338
+ module.exports.treeEntryHash = treeEntryHash
339
+ module.exports.blobRead = blobRead
340
+ module.exports.blobHeader = blobHeader
337
341
  module.exports.recordQueryCandidates = recordQueryCandidates
338
342
  module.exports.templateFieldNames = templateFieldNames
339
343
  module.exports.recordIndexUnique = recordIndexUnique
@@ -343,7 +347,12 @@ module.exports.applyMergePatch = applyMergePatch
343
347
  module.exports.diffRecords = diffRecords
344
348
  module.exports.simulateCoreError = simulateCoreError
345
349
  module.exports.CoreTransaction = CoreTransaction
350
+ module.exports.syncBranch = syncBranch
351
+ module.exports.isAncestor = isAncestor
352
+ module.exports.mergeSheets = mergeSheets
353
+ module.exports.mergeRecordTexts = mergeRecordTexts
346
354
  module.exports.coreDiscoverSheets = coreDiscoverSheets
355
+ module.exports.sheetConfigCheck = sheetConfigCheck
347
356
  module.exports.coreCheckValidators = coreCheckValidators
348
357
  module.exports.markdownSerialize = markdownSerialize
349
358
  module.exports.markdownNormalizeBody = markdownNormalizeBody
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitsheets/core-napi",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "Node.js native binding for gitsheets-core — the FFI marshalling boundary.",
5
5
  "main": "binding.cjs",
6
6
  "types": "index.d.ts",
@@ -33,19 +33,19 @@
33
33
  "index.d.ts"
34
34
  ],
35
35
  "optionalDependencies": {
36
- "@gitsheets/core-napi-linux-x64-gnu": "0.4.0",
37
- "@gitsheets/core-napi-linux-arm64-gnu": "0.4.0",
38
- "@gitsheets/core-napi-linux-x64-musl": "0.4.0",
39
- "@gitsheets/core-napi-darwin-arm64": "0.4.0",
40
- "@gitsheets/core-napi-darwin-x64": "0.4.0",
41
- "@gitsheets/core-napi-win32-x64-msvc": "0.4.0"
36
+ "@gitsheets/core-napi-linux-x64-gnu": "0.6.0",
37
+ "@gitsheets/core-napi-linux-arm64-gnu": "0.6.0",
38
+ "@gitsheets/core-napi-linux-x64-musl": "0.6.0",
39
+ "@gitsheets/core-napi-darwin-arm64": "0.6.0",
40
+ "@gitsheets/core-napi-darwin-x64": "0.6.0",
41
+ "@gitsheets/core-napi-win32-x64-msvc": "0.6.0"
42
42
  },
43
43
  "scripts": {
44
44
  "artifacts": "napi artifacts",
45
45
  "build": "napi build --platform --release",
46
46
  "build:debug": "napi build --platform",
47
47
  "prepublishOnly": "napi prepublish -t npm --skip-gh-release",
48
- "test": "node --test test/roundtrip.mjs test/errors.mjs test/canonical.mjs test/path-template.mjs test/validation-parity.mjs test/engine-parity.mjs test/collator-parity.mjs test/record-crud.mjs test/record-query.mjs test/record-index.mjs test/sheet-store.mjs test/sheet-markdown.mjs test/sheet-attachments.mjs test/contracts.mjs",
48
+ "test": "node --test test/roundtrip.mjs test/errors.mjs test/canonical.mjs test/path-template.mjs test/validation-parity.mjs test/engine-parity.mjs test/collator-parity.mjs test/record-crud.mjs test/record-query.mjs test/record-index.mjs test/sheet-store.mjs test/sheet-markdown.mjs test/sheet-attachments.mjs test/contracts.mjs test/sheet-config-check.mjs test/orphan-and-files.mjs",
49
49
  "bench": "node bench/query-bench.mjs",
50
50
  "version": "napi version"
51
51
  },
@@ -54,6 +54,6 @@
54
54
  "ajv": "^8.20.0",
55
55
  "ajv-formats": "^3.0.1",
56
56
  "rfc6902": "^5.2.0",
57
- "smol-toml": "^1.7.0"
57
+ "smol-toml": "^1.8.0"
58
58
  }
59
59
  }