yamlite 0.35.0 → 0.36.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/dist/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { I as isLoopback, L as loopbackHosts, P as createHandler, R as check, a as query, c as exportSite, i as formatTable, n as formatCsv, o as generateConfig, r as formatJson, s as init, t as open } from "./src-DKu7thkC.mjs";
3
- import { n as guide, r as envKeys, t as createWorkspace } from "./workspace-BHg_GGkH.mjs";
2
+ import { I as isLoopback, L as loopbackHosts, P as createHandler, R as check, a as query, c as exportSite, i as formatTable, n as formatCsv, o as generateConfig, r as formatJson, s as init, t as open } from "./src-O1FTGCot.mjs";
3
+ import { n as guide, r as envKeys, t as createWorkspace } from "./workspace-1vCIMAfl.mjs";
4
4
  import { createRequire } from "node:module";
5
5
  import { relative, resolve } from "node:path";
6
6
  import { homedir } from "node:os";
package/dist/core.d.mts CHANGED
@@ -277,8 +277,13 @@ interface GitDriver {
277
277
  afterTreeChange: () => Promise<void>;
278
278
  }): Promise<ReviewOutcome>;
279
279
  readonly namesBranch?: boolean;
280
+ readonly defaultBranchFiles?: DefaultBranchFiles;
280
281
  readonly steps?: StepRunner;
281
282
  }
283
+ interface DefaultBranchFiles {
284
+ changes(): Promise<GitStatus["changes"]>;
285
+ file(rootPath: string): Promise<Uint8Array | null>;
286
+ }
282
287
  interface StepRunner {
283
288
  readonly repo: Repo;
284
289
  validate(raw: unknown): Promise<{
@@ -524,4 +529,4 @@ interface Workspace {
524
529
  }
525
530
  export declare function createWorkspace(o: WorkspaceOptions): Promise<Workspace>;
526
531
  //#endregion
527
- export { type AiOptions, type ApiContext, CONFIG_NAMES, type Capture, type Change, type ChangeOp, type CheckResult, type CheckTable, type ColumnType, type Config, type ConflictInfo, type Credentials, type Decision, type DeclaredTable, type DiffResult, type ExportOptions, type ExportResult, type Extract, type Extracted, type GitDriver, type GitStatus, type GitStep, type HistoryEntry, type HistoryPage, type HistoryTarget, type IndexSpec, type InitOptions, type OpenOptions, type PageSpec, type QueryOptions, type QueryResult, type Repo, type ReviewOutcome, type ReviewRequest, type RunOptions, type SchemaChange, type StepResult, type StepRunner, type TableInput, type TableLocation, type TableResult, type TableSpec, type WatchHandlers, type WatchOptions, type Watcher, type Workspace, type WorkspaceOptions, Yamlite, check, exportSite, formatCsv, formatJson, formatTable, generateConfig, init, open, parseConfig, query, readsFile };
532
+ export { type AiOptions, type ApiContext, CONFIG_NAMES, type Capture, type Change, type ChangeOp, type CheckResult, type CheckTable, type ColumnType, type Config, type ConflictInfo, type Credentials, type Decision, type DeclaredTable, type DefaultBranchFiles, type DiffResult, type ExportOptions, type ExportResult, type Extract, type Extracted, type GitDriver, type GitStatus, type GitStep, type HistoryEntry, type HistoryPage, type HistoryTarget, type IndexSpec, type InitOptions, type OpenOptions, type PageSpec, type QueryOptions, type QueryResult, type Repo, type ReviewOutcome, type ReviewRequest, type RunOptions, type SchemaChange, type StepResult, type StepRunner, type TableInput, type TableLocation, type TableResult, type TableSpec, type WatchHandlers, type WatchOptions, type Watcher, type Workspace, type WorkspaceOptions, Yamlite, check, exportSite, formatCsv, formatJson, formatTable, generateConfig, init, open, parseConfig, query, readsFile };
package/dist/core.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { C as fieldChanges, F as HttpError, H as readsFile, R as check, S as describeChange, V as parseConfig, a as query, c as exportSite, f as ReviewRefused, i as formatTable, n as formatCsv, o as generateConfig, r as formatJson, s as init, t as open, w as worthShowing, z as CONFIG_NAMES } from "./src-DKu7thkC.mjs";
2
- import { t as createWorkspace } from "./workspace-BHg_GGkH.mjs";
1
+ import { C as fieldChanges, F as HttpError, H as readsFile, R as check, S as describeChange, V as parseConfig, a as query, c as exportSite, f as ReviewRefused, i as formatTable, n as formatCsv, o as generateConfig, r as formatJson, s as init, t as open, w as worthShowing, z as CONFIG_NAMES } from "./src-O1FTGCot.mjs";
2
+ import { t as createWorkspace } from "./workspace-1vCIMAfl.mjs";
3
3
  export { CONFIG_NAMES, HttpError, ReviewRefused, check, createWorkspace, describeChange, exportSite, fieldChanges, formatCsv, formatJson, formatTable, generateConfig, init, open, parseConfig, query, readsFile, worthShowing };
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- export { R as check, c as exportSite, n as formatCsv, r as formatJson, i as formatTable, o as generateConfig, s as init, t as open, a as query } from "./src-DKu7thkC.mjs";
1
+ export { R as check, c as exportSite, n as formatCsv, r as formatJson, i as formatTable, o as generateConfig, s as init, t as open, a as query } from "./src-O1FTGCot.mjs";
@@ -6015,6 +6015,12 @@ async function localDriver(root, gh) {
6015
6015
  if (!f) throw new NoRepository();
6016
6016
  return f;
6017
6017
  };
6018
+ const defaultName = async () => {
6019
+ const f = await lookup();
6020
+ if (!f) return null;
6021
+ base ??= await defaultBranch(f.repo);
6022
+ return base;
6023
+ };
6018
6024
  await lookup();
6019
6025
  return {
6020
6026
  namesBranch: true,
@@ -6053,12 +6059,7 @@ async function localDriver(root, gh) {
6053
6059
  changes
6054
6060
  };
6055
6061
  },
6056
- async defaultBranch() {
6057
- const f = await lookup();
6058
- if (!f) return null;
6059
- base ??= await defaultBranch(f.repo);
6060
- return base;
6061
- },
6062
+ defaultBranch: defaultName,
6062
6063
  async baseContent(rootPath) {
6063
6064
  const { repo } = await need();
6064
6065
  const top = insideRoot(repo, rootPath);
@@ -6070,35 +6071,41 @@ async function localDriver(root, gh) {
6070
6071
  }
6071
6072
  },
6072
6073
  async baseFile(rootPath) {
6073
- const { repo } = await need();
6074
- const top = insideRoot(repo, rootPath);
6075
- if (top === null) throw new GitError(`${rootPath} is outside the repository`);
6076
- let entry;
6077
- try {
6078
- entry = await runGit(repo.top, [
6079
- "ls-tree",
6074
+ return blobAt((await need()).repo, "HEAD", rootPath);
6075
+ },
6076
+ defaultBranchFiles: {
6077
+ async changes() {
6078
+ const f = await lookup();
6079
+ if (!f) return [];
6080
+ const [branch, name] = [await currentBranch(f.repo), await defaultName()];
6081
+ if (branch === null || name === null || branch === name) return [];
6082
+ const parts = (await runGit(f.repo.top, [
6083
+ "diff",
6084
+ "--name-status",
6085
+ "--no-renames",
6080
6086
  "-z",
6081
- "HEAD",
6087
+ `${await defaultRef(f.repo, name)}...HEAD`,
6082
6088
  "--",
6083
- top
6084
- ]);
6085
- } catch (e) {
6086
- if (!await runGit(repo.top, [
6087
- "rev-parse",
6088
- "-q",
6089
- "--verify",
6090
- "HEAD"
6091
- ]).then(() => true, () => false)) return null;
6092
- throw e;
6089
+ f.repo.prefix || "."
6090
+ ])).split("\0");
6091
+ const changes = [];
6092
+ for (let i = 0; i + 1 < parts.length; i += 2) {
6093
+ const path = toRoot(f.repo, parts[i + 1]);
6094
+ if (path === null) continue;
6095
+ const code = parts[i];
6096
+ changes.push({
6097
+ path,
6098
+ status: code === "A" ? "added" : code === "D" ? "deleted" : "modified"
6099
+ });
6100
+ }
6101
+ return changes;
6102
+ },
6103
+ async file(rootPath) {
6104
+ const { repo } = await need();
6105
+ const name = await defaultName();
6106
+ if (name === null) throw new GitError("the default branch is not known");
6107
+ return blobAt(repo, await defaultRef(repo, name), rootPath);
6093
6108
  }
6094
- if (entry === "") return null;
6095
- const type = entry.split(" ")[1];
6096
- if (type !== "blob") throw new GitError(`${rootPath} is a ${type === "commit" ? "submodule" : "folder"}`);
6097
- return runGitBytes(repo.top, [
6098
- "cat-file",
6099
- "--filters",
6100
- `HEAD:${top}`
6101
- ], { timeoutMs: SLOW_MS });
6102
6109
  },
6103
6110
  history: (t, extract, o) => recordHistory(t, extract, o),
6104
6111
  fileDiff: (t, rev) => fileDiff(t, rev),
@@ -6112,6 +6119,45 @@ async function localDriver(root, gh) {
6112
6119
  }
6113
6120
  };
6114
6121
  }
6122
+ async function defaultRef(repo, name) {
6123
+ for (const ref of [`refs/remotes/origin/${name}`, `refs/heads/${name}`]) if (await runGit(repo.top, [
6124
+ "rev-parse",
6125
+ "-q",
6126
+ "--verify",
6127
+ `${ref}^{commit}`
6128
+ ]).then(() => true, () => false)) return ref;
6129
+ throw new GitError(`the default branch ${name} is not in this clone`);
6130
+ }
6131
+ async function blobAt(repo, rev, rootPath) {
6132
+ const top = insideRoot(repo, rootPath);
6133
+ if (top === null) throw new GitError(`${rootPath} is outside the repository`);
6134
+ let entry;
6135
+ try {
6136
+ entry = await runGit(repo.top, [
6137
+ "ls-tree",
6138
+ "-z",
6139
+ rev,
6140
+ "--",
6141
+ top
6142
+ ]);
6143
+ } catch (e) {
6144
+ if (!await runGit(repo.top, [
6145
+ "rev-parse",
6146
+ "-q",
6147
+ "--verify",
6148
+ rev
6149
+ ]).then(() => true, () => false)) return null;
6150
+ throw e;
6151
+ }
6152
+ if (entry === "") return null;
6153
+ const type = entry.split(" ")[1];
6154
+ if (type !== "blob") throw new GitError(`${rootPath} is a ${type === "commit" ? "submodule" : "folder"}`);
6155
+ return runGitBytes(repo.top, [
6156
+ "cat-file",
6157
+ "--filters",
6158
+ `${rev}:${top}`
6159
+ ], { timeoutMs: SLOW_MS });
6160
+ }
6115
6161
  //#endregion
6116
6162
  //#region src/serve/gitrecords.ts
6117
6163
  function ownerOf(tables, file) {
@@ -6268,14 +6314,59 @@ const gitRoutes = (router, ctx) => {
6268
6314
  ...summary(await recordChanges(git, ctx.root, ctx.y.tables, c.path))
6269
6315
  })));
6270
6316
  changes.sort((a, b) => a.path.localeCompare(b.path));
6317
+ const defaultBranch = await git.defaultBranch();
6271
6318
  return { git: {
6272
6319
  branch: status.branch,
6273
- defaultBranch: await git.defaultBranch(),
6320
+ defaultBranch,
6274
6321
  upstream: status.upstream,
6275
6322
  namesBranch: git.namesBranch === true,
6323
+ restoresDefault: git.defaultBranchFiles !== void 0 && status.branch !== null && defaultBranch !== null && status.branch !== defaultBranch,
6276
6324
  changes
6277
6325
  } };
6278
6326
  });
6327
+ router.add("GET", "/api/git/default", async () => {
6328
+ const from = ctx.git?.defaultBranchFiles;
6329
+ if (!from) throw new HttpError(404, "this host cannot read the default branch");
6330
+ const [changes, status] = await Promise.all([from.changes().catch(notFound), ctx.git.status()]);
6331
+ const unsent = new Set(status.changes.map((c) => c.path));
6332
+ return { files: changes.map((c) => ({
6333
+ path: c.path,
6334
+ status: c.status,
6335
+ table: ownerOf(ctx.y.tables, join(ctx.root, c.path))?.spec.name ?? null,
6336
+ unsent: unsent.has(c.path)
6337
+ })).sort((a, b) => a.path.localeCompare(b.path)) };
6338
+ });
6339
+ router.add("POST", "/api/git/restore-default", async ({ body }) => {
6340
+ const from = ctx.git?.defaultBranchFiles;
6341
+ if (!from) throw new HttpError(404, "this host cannot read the default branch");
6342
+ const paths = objectBody(body, "body").files;
6343
+ if (!Array.isArray(paths) || paths.length === 0 || paths.some((p) => typeof p !== "string")) throw new HttpError(400, "choose at least one file", { field: "files" });
6344
+ return ctx.proposals.exclusive(async () => {
6345
+ const changed = new Set((await from.changes().catch(notFound)).map((c) => c.path));
6346
+ const files = await Promise.all(paths.map(async (path) => {
6347
+ const file = resolve(ctx.root, path);
6348
+ const rel = relative(ctx.root, file);
6349
+ if (rel === "" || rel.startsWith("..") || isAbsolute(rel)) throw new HttpError(400, `${path} is outside the data folder`);
6350
+ if (!changed.has(path)) throw new HttpError(400, `${path} is the same as on the default branch`);
6351
+ const content = await from.file(path).catch(notFound);
6352
+ if (content === null && existsSync(file) && lstatSync(file).isDirectory()) throw new HttpError(409, `${path} is a folder; remove it with git`);
6353
+ return {
6354
+ path,
6355
+ file,
6356
+ content
6357
+ };
6358
+ }));
6359
+ assertSynced(await ctx.y.sync(), "could not write the latest edits to files for", "; nothing was restored");
6360
+ for (const f of files) if (f.content === null) rmSync(f.file, { force: true });
6361
+ else {
6362
+ mkdirSync(dirname(f.file), { recursive: true });
6363
+ writeAtomic(f.file, f.content);
6364
+ }
6365
+ if (files.some((f) => f.file === resolve(ctx.configFile))) ctx.reloadConfig();
6366
+ assertSynced(await ctx.y.sync({ force: true }), "the database could not follow the files for");
6367
+ return { files: files.map((f) => f.path) };
6368
+ });
6369
+ });
6279
6370
  router.add("GET", "/api/git/diff", async ({ query }) => {
6280
6371
  const git = ctx.git;
6281
6372
  if (!git) throw new HttpError(404, "the data folder is not in a git repository");