yamlite 0.39.0 → 0.40.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/README.md +7 -3
- package/dist/browser/chokidar.mjs +1 -1
- package/dist/browser/expose.mjs +10 -17
- package/dist/browser/fs.d.mts +5 -0
- package/dist/browser/fs.mjs +1 -1
- package/dist/cli.mjs +3 -2
- package/dist/core.d.mts +22 -13
- package/dist/core.mjs +3 -3
- package/dist/{fs-DZ4QHM93.mjs → fs-BM30qNPb.mjs} +8 -1
- package/dist/{index-OSyELQEX.d.mts → index-CDLxve55.d.mts} +2 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{src-BMrfSYwa.mjs → src-NOJw_gTE.mjs} +164 -5
- package/dist/ui/assets/{ErdView-D3Q6HCAZ.js → ErdView-Dqs3Ly-E.js} +1 -1
- package/dist/ui/assets/{MarkdownField-Dh4Tn8_S.js → MarkdownField-Bg4zDZM_.js} +1 -1
- package/dist/ui/assets/PageView-D0hs43d8.js +1 -0
- package/dist/ui/assets/access-DSnHSuXB.js +1 -0
- package/dist/ui/assets/{index-nxlI4YiX.js → index-LbUt_Zkt.js} +54 -54
- package/dist/ui/assets/load-ylhnQAWa.js +2 -0
- package/dist/ui/index.html +1 -1
- package/dist/ui-embed/{ErdView-Dk-iexgy.js → ErdView-CgNnAf5I.js} +2 -2
- package/dist/ui-embed/{HintPopover-D5P2UuTa.js → HintPopover-8CeJLQO5.js} +1611 -1605
- package/dist/ui-embed/{PageView-BzCYlXPg.js → PageView-B29tXeqW.js} +158 -141
- package/dist/ui-embed/{activity-letLdXN4.js → activity-DecWPHxS.js} +1 -1
- package/dist/ui-embed/embed.js +36 -36
- package/dist/ui-embed/{pageFrame-CFoU6UjD.js → pageFrame-ClOBfTt9.js} +1 -1
- package/dist/{workspace-gtZ3m7LH.mjs → workspace-Cp5-yHYp.mjs} +7 -3
- package/package.json +1 -1
- package/dist/ui/assets/PageView-9PohkcTy.js +0 -1
- package/dist/ui/assets/load-C3NfhY_i.js +0 -2
package/README.md
CHANGED
|
@@ -255,20 +255,22 @@ pages:
|
|
|
255
255
|
access: { tasks: write, people: read } # tables and views; nothing else is reachable
|
|
256
256
|
sql: false # true allows SELECT over the names in access
|
|
257
257
|
network: [] # origins the page may load scripts, styles, images and fonts from, and connect to
|
|
258
|
+
files: [.images/] # files the page may read with yamlite.file; a folder ends in /
|
|
258
259
|
ai: true # lets the page call the host's AI model; { maxOutputTokens: 2048 } raises the default 1024 (at most 8192)
|
|
259
260
|
```
|
|
260
261
|
|
|
261
|
-
Start from [`examples/pages/kanban.html`](examples/pages/kanban.html): copy it into `.pages/`, set `TABLE`, `KEY`, `GROUP` and `TITLE` at the top, and declare it as above. [`examples/pages/summary.html`](examples/pages/summary.html) shows a page that asks AI to summarize a record.
|
|
262
|
+
Start from [`examples/pages/kanban.html`](examples/pages/kanban.html): copy it into `.pages/`, set `TABLE`, `KEY`, `GROUP` and `TITLE` at the top, and declare it as above. [`examples/pages/summary.html`](examples/pages/summary.html) shows a page that asks AI to summarize a record. [`examples/pages/gallery.html`](examples/pages/gallery.html) lists a table's `image` column and shows each file with `yamlite.file`.
|
|
262
263
|
|
|
263
264
|
To share a page with people who should see only that page, open it and click **Copy app link**. The link ends in `/-/apps/<name>/` and shows the page alone, with its own title and look: no sidebar, tables, SQL console, command menu or links into other records. Once there are edits, a bar at the bottom shows their count and **Send for review**; an embedding host can add its own controls at the left of that bar with the `appFooter` mount option. The part after `#` is where the page stands inside itself, which it sets with `yamlite.history`, so a reload, the back button and a copied address return there; changing it does not leave the app. It leaves the editor out of sight; it does not take it away, so anyone who removes `-/apps/<name>/` from the address can still reach the rest of the UI. With `serve`, the copied link has no token, and the login cookie is not sent when a link is opened from another site such as mail or chat: share `/-/apps/<name>/?token=…` instead, on the origin of the URL `serve` printed and with its token. `serve` is meant for trying an app out; to share one with a team, use a host that gives each viewer their own branch. An `export` has the same entry at `-/apps/<name>/` for each page it includes; open it with the trailing slash (static hosts add it), since without it the page's relative paths resolve one folder too high.
|
|
264
265
|
|
|
265
266
|
| Call | Does |
|
|
266
267
|
| ------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
267
|
-
| `await yamlite.ready` | `{ page, title, access, sql, network, readOnly, ai }`; `ai` is `{ provider, models }` when the page has `ai` and the host holds a key, else `null`
|
|
268
|
+
| `await yamlite.ready` | `{ page, title, access, sql, network, files, readOnly, ai }`; `ai` is `{ provider, models }` when the page has `ai` and the host holds a key, else `null` |
|
|
268
269
|
| `yamlite.rows(table, { filter, sort, search, limit, offset })` | `{ rows, total }`, reads tables and views, same filters and search as the table screen; `limit` ≤ 500 |
|
|
269
270
|
| `yamlite.get(table, key)` | `{ row, file }`; tables only, a view gives 400 |
|
|
270
271
|
| `yamlite.create(table, key, values)` / `update(table, key, values, base)` / `remove(table, key)` | needs `write`; `update` fails with status 409, `extra.stale` (the fields) and `extra.current` (their values now), if a field changed since `base` |
|
|
271
272
|
| `yamlite.sql(select)` | needs `sql: true`; one SELECT over the names in `access` |
|
|
273
|
+
| `await yamlite.file(path)` | needs `path` to match one of the page's `files` and not be a denied path; resolves to a `Blob` typed by extension (`image/png`, `image/jpeg`, `image/webp`, `image/gif`, `image/svg+xml`, `application/pdf`, `text/plain`, otherwise `application/octet-stream`), for `URL.createObjectURL`. Files on the branch or commit the viewer has open, at most 10 MB; 403 when `path` matches no entry, 404 when there is no such file, 413 over the limit |
|
|
272
274
|
| `yamlite.on("change", ({ tables }) => …)` | called after a sync changes a table or view the page can read |
|
|
273
275
|
| `yamlite.theme` / `yamlite.on("theme", ({ theme }) => …)` | the current theme (`light` or `dark`), and a call when it changes |
|
|
274
276
|
| `yamlite.ai.generate({ system, prompt, schema, model, maxOutputTokens })` | needs `ai` (a page without it gets 403); `{ text }`, or `{ object }` matching `schema` (a JSON Schema). `prompt` is a string or a list of `{ role: "user" \| "assistant", content }`; `model` is one of `ready`'s `ai.models`, the first by default; `maxOutputTokens` may lower the page's limit. Runs on the host's key, never one from the page. Fails with 503 and `extra.code: "no_key"` when the host has no key, 429 with `extra.retryAfter` (seconds) when busy, and 502 when the provider fails: `extra.provider` is the provider id and the provider's own text is in `message` |
|
|
@@ -303,7 +305,9 @@ The variable and class names are part of the page API: renaming one is a breakin
|
|
|
303
305
|
- `network` is enforced with a Content Security Policy. It limits what the page loads and where it connects. Declaring an origin lets the page send data, including anything it can read through `access`, off your machine to that origin.
|
|
304
306
|
- `ai` lets the page send anything it can read through `access` to the host's AI provider, billed to the host's key.
|
|
305
307
|
- Every page, even with `network: []`, can leak data by navigating its own frame to another site with the data in the URL. YAMLite then disconnects the page, but the data has already left. Only declare pages you trust, as you would any script you run.
|
|
306
|
-
-
|
|
308
|
+
- `files` is a read grant like `access`: the page can read every file under a declared folder, and anything a page can read can leave through navigation, as for records. An entry ending in `/` is a folder, any other entry one exact file; `..`, absolute paths and entries inside `.yamlite/` or naming `yamlite.yaml` are config errors. A page cannot read YAMLite's state folder, the database (and its `-wal`, `-shm` and `-journal` files) or the config files, whatever `files` says: a broad folder entry still gets 403 for them. Symlinks are followed and must stay inside a granted path.
|
|
309
|
+
- `serve` reads the working tree, so a `files` entry also covers files git does not track, such as a local `.env` or build output. Declare folders that hold only what the page should show.
|
|
310
|
+
- In an [export](#export) pages are read-only, and `access` does not hide data: the exported `db.sqlite` is downloadable, and `sql: true` reads every exported table. Pages whose `access` names a table left out of the export are skipped with a warning. An export also copies the files a page declares into `data/files/`, each stored with a `.bin` suffix so a host serves it as a download rather than as a page; deploying the export makes them public; a file over 10 MB is skipped with a warning.
|
|
307
311
|
|
|
308
312
|
## Check
|
|
309
313
|
|
package/dist/browser/expose.mjs
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
//#region src/browser/expose.ts
|
|
2
|
+
function post(port, id, bytes) {
|
|
3
|
+
const data = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
4
|
+
port.postMessage({
|
|
5
|
+
id,
|
|
6
|
+
kind: "chunk",
|
|
7
|
+
data
|
|
8
|
+
}, [data]);
|
|
9
|
+
}
|
|
2
10
|
function expose(port, dispatch) {
|
|
3
11
|
const open = /* @__PURE__ */ new Map();
|
|
4
12
|
port.onmessage = async (e) => {
|
|
@@ -29,24 +37,13 @@ function expose(port, dispatch) {
|
|
|
29
37
|
});
|
|
30
38
|
headSent = true;
|
|
31
39
|
if (res.body) {
|
|
32
|
-
const decoder = new TextDecoder();
|
|
33
40
|
const reader = res.body.getReader();
|
|
34
41
|
ac.signal.addEventListener("abort", () => void reader.cancel(), { once: true });
|
|
35
42
|
for (;;) {
|
|
36
43
|
const { done, value } = await reader.read();
|
|
37
44
|
if (done) break;
|
|
38
|
-
port.
|
|
39
|
-
id: m.id,
|
|
40
|
-
kind: "chunk",
|
|
41
|
-
data: decoder.decode(value, { stream: true })
|
|
42
|
-
});
|
|
45
|
+
post(port, m.id, value);
|
|
43
46
|
}
|
|
44
|
-
const rest = decoder.decode();
|
|
45
|
-
if (rest) port.postMessage({
|
|
46
|
-
id: m.id,
|
|
47
|
-
kind: "chunk",
|
|
48
|
-
data: rest
|
|
49
|
-
});
|
|
50
47
|
}
|
|
51
48
|
} catch (err) {
|
|
52
49
|
if (!ac.signal.aborted && !headSent) {
|
|
@@ -56,11 +53,7 @@ function expose(port, dispatch) {
|
|
|
56
53
|
status: 500,
|
|
57
54
|
headers: [["content-type", "application/json"]]
|
|
58
55
|
});
|
|
59
|
-
port.
|
|
60
|
-
id: m.id,
|
|
61
|
-
kind: "chunk",
|
|
62
|
-
data: JSON.stringify({ error: String(err) })
|
|
63
|
-
});
|
|
56
|
+
post(port, m.id, new TextEncoder().encode(JSON.stringify({ error: String(err) })));
|
|
64
57
|
}
|
|
65
58
|
} finally {
|
|
66
59
|
open.delete(m.id);
|
package/dist/browser/fs.d.mts
CHANGED
|
@@ -24,6 +24,9 @@ export declare function statSync(p: string, opts?: {
|
|
|
24
24
|
export declare const lstatSync: typeof statSync;
|
|
25
25
|
export declare function accessSync(p: string): void;
|
|
26
26
|
export declare function realpathSync(p: string): string;
|
|
27
|
+
export declare namespace realpathSync {
|
|
28
|
+
export { realpathSync as native };
|
|
29
|
+
}
|
|
27
30
|
export declare function readFileSync(p: string, opts?: string | {
|
|
28
31
|
encoding?: string;
|
|
29
32
|
}): string | Buffer<ArrayBuffer>;
|
|
@@ -51,6 +54,7 @@ export declare function rmSync(p: string, opts?: {
|
|
|
51
54
|
}): void;
|
|
52
55
|
export declare function renameSync(from: string, to: string): void;
|
|
53
56
|
export declare function linkSync(from: string, to: string): void;
|
|
57
|
+
export declare function copyFileSync(from: string, to: string): void;
|
|
54
58
|
export declare function cpSync(from: string, to: string): void;
|
|
55
59
|
export declare function chmodSync(p: string, mode: number): void;
|
|
56
60
|
export declare function mkdtempSync(prefix: string): string;
|
|
@@ -64,6 +68,7 @@ declare const _default: {
|
|
|
64
68
|
W_OK: number;
|
|
65
69
|
X_OK: number;
|
|
66
70
|
};
|
|
71
|
+
copyFileSync: typeof copyFileSync;
|
|
67
72
|
cpSync: typeof cpSync;
|
|
68
73
|
createReadStream: typeof createReadStream;
|
|
69
74
|
existsSync: typeof existsSync;
|
package/dist/browser/fs.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as accessSync, n as chmodSync, r as constants, i as
|
|
1
|
+
export { t as accessSync, n as chmodSync, r as constants, i as copyFileSync, a as cpSync, o as createReadStream, l as default, s as existsSync, c as external, u as linkSync, d as lstatSync, f as mkdirSync, p as mkdtempSync, m as onChange, h as onRemove, g as readFileSync, _ as readdirSync, v as realpathSync, y as renameSync, b as rmSync, x as rmdirSync, S as statSync, C as unlinkSync, w as writeFileSync } from "../fs-BM30qNPb.mjs";
|
package/dist/cli.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { n as guide, r as envKeys, t as createWorkspace } from "./workspace-
|
|
2
|
+
import { B as check, I as createHandler, R as isLoopback, a as query, c as exportSite, i as formatTable, n as formatCsv, o as generateConfig, r as formatJson, s as init, t as open, z as loopbackHosts } from "./src-NOJw_gTE.mjs";
|
|
3
|
+
import { n as guide, r as envKeys, t as createWorkspace } from "./workspace-Cp5-yHYp.mjs";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import { relative, resolve } from "node:path";
|
|
6
6
|
import { homedir } from "node:os";
|
|
@@ -423,6 +423,7 @@ program.command("export").description("write the web UI as a read-only static si
|
|
|
423
423
|
console.log(`${out("green", "✓")} exported ${count} to ${displayPath(r.out)}`);
|
|
424
424
|
for (const [table, warnings] of Object.entries(r.warnings)) for (const w of warnings) console.log(` ${out("yellow", "!")} ${table}: ${w}`);
|
|
425
425
|
for (const [page, reason] of Object.entries(r.skippedPages)) console.log(` ${out("yellow", "!")} page ${page} not exported: ${reason}`);
|
|
426
|
+
for (const [path, reason] of Object.entries(r.skippedFiles)) console.log(` ${out("yellow", "!")} file ${path} not exported: ${reason}`);
|
|
426
427
|
console.log(out("dim", " serve the folder over HTTP to open it; file:// does not work"));
|
|
427
428
|
});
|
|
428
429
|
program.parseAsync().catch((e) => {
|
package/dist/core.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as parseConfig, B as HistoryEntry, C as Decision, D as OpenOptions, E as DeclaredTable, F as ColumnType, G as Rec, H as IndexSpec, I as ConflictInfo, J as ViewRecord, K as SchemaChange, L as DbRow, M as Capture, N as Change, O as TableInput, P as ChangeOp, R as DbValue, S as BaseHashes, T as Config, U as PageAccess, V as HistoryPage, W as PageSpec, _ as check, a as formatCsv, b as Watcher, c as query, d as init, f as ExportOptions, g as CheckTable, h as CheckResult, i as QueryResult, j as readsFile, k as TableLocation, l as InitOptions, m as exportSite, n as open, o as formatJson, p as ExportResult, q as TableSpec, r as QueryOptions, s as formatTable, t as Yamlite, u as generateConfig, v as WatchHandlers, w as CONFIG_NAMES, x as TableResult, y as WatchOptions, z as FieldChange } from "./index-
|
|
1
|
+
import { A as parseConfig, B as HistoryEntry, C as Decision, D as OpenOptions, E as DeclaredTable, F as ColumnType, G as Rec, H as IndexSpec, I as ConflictInfo, J as ViewRecord, K as SchemaChange, L as DbRow, M as Capture, N as Change, O as TableInput, P as ChangeOp, R as DbValue, S as BaseHashes, T as Config, U as PageAccess, V as HistoryPage, W as PageSpec, _ as check, a as formatCsv, b as Watcher, c as query, d as init, f as ExportOptions, g as CheckTable, h as CheckResult, i as QueryResult, j as readsFile, k as TableLocation, l as InitOptions, m as exportSite, n as open, o as formatJson, p as ExportResult, q as TableSpec, r as QueryOptions, s as formatTable, t as Yamlite, u as generateConfig, v as WatchHandlers, w as CONFIG_NAMES, x as TableResult, y as WatchOptions, z as FieldChange } from "./index-CDLxve55.mjs";
|
|
2
2
|
import { DatabaseSync } from "node:sqlite";
|
|
3
3
|
import { LanguageModel, ModelMessage } from "ai";
|
|
4
4
|
//#region src/store.d.ts
|
|
@@ -53,6 +53,22 @@ declare class Store {
|
|
|
53
53
|
dropState(table: string, key: string): void;
|
|
54
54
|
}
|
|
55
55
|
//#endregion
|
|
56
|
+
//#region src/pages/access.d.ts
|
|
57
|
+
interface PageRules {
|
|
58
|
+
name: string;
|
|
59
|
+
access: Record<string, PageAccess>;
|
|
60
|
+
sql: boolean;
|
|
61
|
+
network: string[];
|
|
62
|
+
files: string[];
|
|
63
|
+
ai: {
|
|
64
|
+
maxOutputTokens: number;
|
|
65
|
+
} | null;
|
|
66
|
+
}
|
|
67
|
+
export declare const DENIED_FILES: string[];
|
|
68
|
+
export declare const MAX_PAGE_FILE_BYTES = 10485760;
|
|
69
|
+
export declare function normalizeFilePath(path: string): string | null;
|
|
70
|
+
export declare const fileGranted: (files: string[], path: string) => boolean;
|
|
71
|
+
//#endregion
|
|
56
72
|
//#region src/agent/providers.d.ts
|
|
57
73
|
interface Credentials {
|
|
58
74
|
provider: string;
|
|
@@ -355,17 +371,6 @@ declare class EventHub {
|
|
|
355
371
|
private send;
|
|
356
372
|
}
|
|
357
373
|
//#endregion
|
|
358
|
-
//#region src/pages/access.d.ts
|
|
359
|
-
interface PageRules {
|
|
360
|
-
name: string;
|
|
361
|
-
access: Record<string, PageAccess>;
|
|
362
|
-
sql: boolean;
|
|
363
|
-
network: string[];
|
|
364
|
-
ai: {
|
|
365
|
-
maxOutputTokens: number;
|
|
366
|
-
} | null;
|
|
367
|
-
}
|
|
368
|
-
//#endregion
|
|
369
374
|
//#region src/serve/pagesql.d.ts
|
|
370
375
|
declare class PageSql {
|
|
371
376
|
private readonly path;
|
|
@@ -393,6 +398,8 @@ interface ApiContext {
|
|
|
393
398
|
agent: AgentHost | null;
|
|
394
399
|
git: GitDriver | null;
|
|
395
400
|
reloadConfig: () => void;
|
|
401
|
+
pageFiles: WorkspaceOptions["pageFiles"] | null;
|
|
402
|
+
deniedFiles: string[];
|
|
396
403
|
}
|
|
397
404
|
//#endregion
|
|
398
405
|
//#region src/agent/tools.d.ts
|
|
@@ -523,6 +530,7 @@ declare class Router {
|
|
|
523
530
|
//#endregion
|
|
524
531
|
//#region src/serve/workspace.d.ts
|
|
525
532
|
type AiOptions = Omit<HostOptions, "tools" | "feedback" | "notes">;
|
|
533
|
+
type PageFileResult = Uint8Array<ArrayBuffer> | "missing" | "too-large" | undefined;
|
|
526
534
|
interface WorkspaceOptions {
|
|
527
535
|
root: string;
|
|
528
536
|
db?: string;
|
|
@@ -530,6 +538,7 @@ interface WorkspaceOptions {
|
|
|
530
538
|
ai?: AiOptions | null;
|
|
531
539
|
git?: GitDriver | null;
|
|
532
540
|
gh?: string | null;
|
|
541
|
+
pageFiles?: (path: string, signal: AbortSignal) => Promise<PageFileResult>;
|
|
533
542
|
}
|
|
534
543
|
interface Workspace {
|
|
535
544
|
readonly context: ApiContext;
|
|
@@ -541,4 +550,4 @@ export declare function createWorkspace(o: WorkspaceOptions): Promise<Workspace>
|
|
|
541
550
|
//#region src/git/pr.d.ts
|
|
542
551
|
export declare function templatePath(paths: readonly string[]): string | null;
|
|
543
552
|
//#endregion
|
|
544
|
-
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 };
|
|
553
|
+
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 PageFileResult, 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 { B as
|
|
2
|
-
import { t as createWorkspace } from "./workspace-
|
|
3
|
-
export { CONFIG_NAMES, HttpError, ReviewRefused, check, createWorkspace, describeChange, exportSite, fieldChanges, formatCsv, formatJson, formatTable, generateConfig, init, open, parseConfig, query, readsFile, templatePath, worthShowing };
|
|
1
|
+
import { B as check, C as describeChange, J as fileGranted, K as DENIED_FILES, L as HttpError, T as worthShowing, U as parseConfig, V as CONFIG_NAMES, W as readsFile, Y as normalizeFilePath, a as query, c as exportSite, f as ReviewRefused, h as templatePath, i as formatTable, n as formatCsv, o as generateConfig, q as MAX_PAGE_FILE_BYTES, r as formatJson, s as init, t as open, w as fieldChanges } from "./src-NOJw_gTE.mjs";
|
|
2
|
+
import { t as createWorkspace } from "./workspace-Cp5-yHYp.mjs";
|
|
3
|
+
export { CONFIG_NAMES, DENIED_FILES, HttpError, MAX_PAGE_FILE_BYTES, ReviewRefused, check, createWorkspace, describeChange, exportSite, fieldChanges, fileGranted, formatCsv, formatJson, formatTable, generateConfig, init, normalizeFilePath, open, parseConfig, query, readsFile, templatePath, worthShowing };
|
|
@@ -94,6 +94,7 @@ function realpathSync(p) {
|
|
|
94
94
|
get(abs(p), "realpath");
|
|
95
95
|
return abs(p);
|
|
96
96
|
}
|
|
97
|
+
realpathSync.native = realpathSync;
|
|
97
98
|
function readFileSync(p, opts) {
|
|
98
99
|
const path = abs(p);
|
|
99
100
|
const e = get(path, "open");
|
|
@@ -199,6 +200,11 @@ function linkSync(from, to) {
|
|
|
199
200
|
tree.set(b, e);
|
|
200
201
|
emit("add", b);
|
|
201
202
|
}
|
|
203
|
+
function copyFileSync(from, to) {
|
|
204
|
+
const e = get(abs(from), "copyfile");
|
|
205
|
+
if (e.kind === "dir") fail("EISDIR", "illegal operation on a directory", "copyfile", abs(from));
|
|
206
|
+
writeFileSync(to, e.data);
|
|
207
|
+
}
|
|
202
208
|
function cpSync(from, to) {
|
|
203
209
|
const a = abs(from);
|
|
204
210
|
const b = abs(to);
|
|
@@ -230,6 +236,7 @@ var fs_default = {
|
|
|
230
236
|
accessSync,
|
|
231
237
|
chmodSync,
|
|
232
238
|
constants,
|
|
239
|
+
copyFileSync,
|
|
233
240
|
cpSync,
|
|
234
241
|
createReadStream,
|
|
235
242
|
existsSync,
|
|
@@ -248,4 +255,4 @@ var fs_default = {
|
|
|
248
255
|
writeFileSync
|
|
249
256
|
};
|
|
250
257
|
//#endregion
|
|
251
|
-
export {
|
|
258
|
+
export { unlinkSync as C, statSync as S, readdirSync as _, cpSync as a, rmSync as b, external as c, lstatSync as d, mkdirSync as f, readFileSync as g, onRemove as h, copyFileSync as i, fs_default as l, onChange as m, chmodSync as n, createReadStream as o, mkdtempSync as p, constants as r, existsSync as s, accessSync as t, linkSync as u, realpathSync as v, writeFileSync as w, rmdirSync as x, renameSync as y };
|
|
@@ -81,6 +81,7 @@ interface PageSpec {
|
|
|
81
81
|
access: Record<string, PageAccess>;
|
|
82
82
|
sql: boolean;
|
|
83
83
|
network: string[];
|
|
84
|
+
files: string[];
|
|
84
85
|
ai: {
|
|
85
86
|
maxOutputTokens: number;
|
|
86
87
|
} | null;
|
|
@@ -268,6 +269,7 @@ interface ExportResult {
|
|
|
268
269
|
warnings: Record<string, string[]>;
|
|
269
270
|
pages: string[];
|
|
270
271
|
skippedPages: Record<string, string>;
|
|
272
|
+
skippedFiles: Record<string, string>;
|
|
271
273
|
}
|
|
272
274
|
declare function exportSite(opts: ExportOptions): Promise<ExportResult>;
|
|
273
275
|
//#endregion
|
package/dist/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { C as Decision, D as OpenOptions, F as ColumnType, H as IndexSpec, I as ConflictInfo, K as SchemaChange, N as Change, O as TableInput, P as ChangeOp, W as PageSpec, _ as check, a as formatCsv, b as Watcher, c as query, d as init, f as ExportOptions, g as CheckTable, h as CheckResult, i as QueryResult, l as InitOptions, m as exportSite, n as open, o as formatJson, p as ExportResult, q as TableSpec, r as QueryOptions, s as formatTable, t as Yamlite, u as generateConfig, v as WatchHandlers, x as TableResult, y as WatchOptions } from "./index-
|
|
1
|
+
import { C as Decision, D as OpenOptions, F as ColumnType, H as IndexSpec, I as ConflictInfo, K as SchemaChange, N as Change, O as TableInput, P as ChangeOp, W as PageSpec, _ as check, a as formatCsv, b as Watcher, c as query, d as init, f as ExportOptions, g as CheckTable, h as CheckResult, i as QueryResult, l as InitOptions, m as exportSite, n as open, o as formatJson, p as ExportResult, q as TableSpec, r as QueryOptions, s as formatTable, t as Yamlite, u as generateConfig, v as WatchHandlers, x as TableResult, y as WatchOptions } from "./index-CDLxve55.mjs";
|
|
2
2
|
export { type Change, type ChangeOp, type CheckResult, type CheckTable, type ColumnType, type ConflictInfo, type Decision, type ExportOptions, type ExportResult, type IndexSpec, type InitOptions, type OpenOptions, type PageSpec, type QueryOptions, type QueryResult, type SchemaChange, type TableInput, type TableResult, type TableSpec, type WatchHandlers, type WatchOptions, type Watcher, Yamlite, check, exportSite, formatCsv, formatJson, formatTable, generateConfig, init, open, query };
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { B 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-NOJw_gTE.mjs";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { basename, delimiter, dirname, extname, isAbsolute, join, matchesGlob, normalize, posix, relative, resolve, sep } from "node:path";
|
|
2
|
-
import { accessSync, chmodSync, constants, cpSync, createReadStream, existsSync, linkSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, rmdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { accessSync, chmodSync, constants, copyFileSync, cpSync, createReadStream, existsSync, linkSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, rmdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { homedir, tmpdir } from "node:os";
|
|
4
4
|
import { Document, Scalar, isMap, isNode, isScalar, isSeq, parse, parseDocument, stringify } from "yaml";
|
|
5
5
|
import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
|
|
@@ -1105,6 +1105,12 @@ function reconcileViews(store, spec, apply) {
|
|
|
1105
1105
|
}
|
|
1106
1106
|
//#endregion
|
|
1107
1107
|
//#region src/pages/access.ts
|
|
1108
|
+
const DENIED_FILES = [
|
|
1109
|
+
".yamlite/",
|
|
1110
|
+
"yamlite.yaml",
|
|
1111
|
+
"yamlite.yml"
|
|
1112
|
+
];
|
|
1113
|
+
const MAX_PAGE_FILE_BYTES = 10485760;
|
|
1108
1114
|
const PAGE_AI_DEFAULT_TOKENS = 1024;
|
|
1109
1115
|
const PAGE_AI_MAX_TOKENS = 8192;
|
|
1110
1116
|
const canRead = (page, name) => Object.hasOwn(page.access, name);
|
|
@@ -1115,6 +1121,30 @@ function trustedViews(page, views) {
|
|
|
1115
1121
|
for (const name of Object.keys(page.access)) for (let v = name; v !== void 0 && parentOf.has(v) && !trusted.has(v); v = parentOf.get(v)) trusted.add(v);
|
|
1116
1122
|
return trusted;
|
|
1117
1123
|
}
|
|
1124
|
+
function normalizeFilePath(path) {
|
|
1125
|
+
if (path.startsWith("/") || path.startsWith("\\") || /^[a-z]:/i.test(path)) return null;
|
|
1126
|
+
const parts = path.split(/[\\/]/);
|
|
1127
|
+
if (parts.includes("..")) return null;
|
|
1128
|
+
const kept = parts.filter((p) => p !== "" && p !== ".");
|
|
1129
|
+
if (kept.length === 0) return null;
|
|
1130
|
+
return kept.join("/") + (path.endsWith("/") ? "/" : "");
|
|
1131
|
+
}
|
|
1132
|
+
const fileGranted = (files, path) => files.some((entry) => entry.endsWith("/") ? path.startsWith(entry) : path === entry);
|
|
1133
|
+
const deniedFile = (path, denied) => fileGranted(denied.map((d) => d.toLowerCase()), path.toLowerCase());
|
|
1134
|
+
const CONTENT_TYPES = {
|
|
1135
|
+
png: "image/png",
|
|
1136
|
+
jpg: "image/jpeg",
|
|
1137
|
+
jpeg: "image/jpeg",
|
|
1138
|
+
webp: "image/webp",
|
|
1139
|
+
gif: "image/gif",
|
|
1140
|
+
svg: "image/svg+xml",
|
|
1141
|
+
pdf: "application/pdf",
|
|
1142
|
+
txt: "text/plain"
|
|
1143
|
+
};
|
|
1144
|
+
function contentTypeOf(path) {
|
|
1145
|
+
const ext = path.slice(path.lastIndexOf(".") + 1).toLowerCase();
|
|
1146
|
+
return path.includes(".") && Object.hasOwn(CONTENT_TYPES, ext) ? CONTENT_TYPES[ext] : "application/octet-stream";
|
|
1147
|
+
}
|
|
1118
1148
|
//#endregion
|
|
1119
1149
|
//#region src/config.ts
|
|
1120
1150
|
const CONFIG_NAMES = ["yamlite.yaml", "yamlite.yml"];
|
|
@@ -1639,6 +1669,7 @@ const PAGE_KEYS = [
|
|
|
1639
1669
|
"access",
|
|
1640
1670
|
"sql",
|
|
1641
1671
|
"network",
|
|
1672
|
+
"files",
|
|
1642
1673
|
"ai"
|
|
1643
1674
|
];
|
|
1644
1675
|
const PAGE_NAME = /^[a-z0-9][a-z0-9_-]*$/;
|
|
@@ -1654,6 +1685,16 @@ function toOrigin(where, raw) {
|
|
|
1654
1685
|
if (url.protocol !== "https:" && url.protocol !== "http:" || raw.replace(/\/$/, "") !== url.origin) throw invalid();
|
|
1655
1686
|
return url.origin;
|
|
1656
1687
|
}
|
|
1688
|
+
function toFiles(where, raw) {
|
|
1689
|
+
if (raw === void 0 || raw === null) return [];
|
|
1690
|
+
if (!Array.isArray(raw)) throw new Error(`${where}files must be a list of root-relative files and folders`);
|
|
1691
|
+
return raw.map((entry) => {
|
|
1692
|
+
const invalid = (why) => /* @__PURE__ */ new Error(`${where}files entry ${JSON.stringify(entry)} ${why}`);
|
|
1693
|
+
if (typeof entry !== "string" || normalizeFilePath(entry) !== entry) throw invalid("must be a root-relative path without .., . or empty segments");
|
|
1694
|
+
if (deniedFile(entry, DENIED_FILES)) throw invalid("is YAMLite's own and cannot be granted");
|
|
1695
|
+
return entry;
|
|
1696
|
+
});
|
|
1697
|
+
}
|
|
1657
1698
|
function toPageAi(where, raw) {
|
|
1658
1699
|
if (raw === void 0 || raw === null || raw === false) return null;
|
|
1659
1700
|
if (raw === true) return { maxOutputTokens: PAGE_AI_DEFAULT_TOKENS };
|
|
@@ -1694,6 +1735,7 @@ function toPages(raw, place) {
|
|
|
1694
1735
|
access,
|
|
1695
1736
|
sql: v.sql === true,
|
|
1696
1737
|
network: (v.network ?? []).map((o) => toOrigin(where, o)),
|
|
1738
|
+
files: toFiles(where, v.files),
|
|
1697
1739
|
ai: toPageAi(where, v.ai)
|
|
1698
1740
|
};
|
|
1699
1741
|
});
|
|
@@ -4238,6 +4280,37 @@ var ProposalStore = class {
|
|
|
4238
4280
|
};
|
|
4239
4281
|
//#endregion
|
|
4240
4282
|
//#region src/serve/context.ts
|
|
4283
|
+
function onDisk(path) {
|
|
4284
|
+
try {
|
|
4285
|
+
return realpathSync.native(path);
|
|
4286
|
+
} catch {
|
|
4287
|
+
try {
|
|
4288
|
+
return join(realpathSync.native(dirname(path)), basename(path));
|
|
4289
|
+
} catch {
|
|
4290
|
+
return path;
|
|
4291
|
+
}
|
|
4292
|
+
}
|
|
4293
|
+
}
|
|
4294
|
+
function deniedFiles(root, stateDir, dbPath) {
|
|
4295
|
+
const base = onDisk(root);
|
|
4296
|
+
const inside = (path) => {
|
|
4297
|
+
const rel = relative(base, path);
|
|
4298
|
+
return rel === "" || rel.startsWith("..") || isAbsolute(rel) ? null : rel.split(sep).join("/");
|
|
4299
|
+
};
|
|
4300
|
+
const state = inside(onDisk(stateDir));
|
|
4301
|
+
const given = inside(join(onDisk(dirname(dbPath)), basename(dbPath)));
|
|
4302
|
+
const dbs = [.../* @__PURE__ */ new Set([given, inside(onDisk(dbPath))])].filter((db) => db !== null);
|
|
4303
|
+
return [
|
|
4304
|
+
...DENIED_FILES,
|
|
4305
|
+
...state === null ? [] : [`${state}/`],
|
|
4306
|
+
...dbs.flatMap((db) => [
|
|
4307
|
+
db,
|
|
4308
|
+
`${db}-wal`,
|
|
4309
|
+
`${db}-shm`,
|
|
4310
|
+
`${db}-journal`
|
|
4311
|
+
])
|
|
4312
|
+
];
|
|
4313
|
+
}
|
|
4241
4314
|
function displayPath$1(root, path) {
|
|
4242
4315
|
const rel = relative(root, path);
|
|
4243
4316
|
return rel === "" || rel.startsWith("..") ? path : rel;
|
|
@@ -6520,11 +6593,56 @@ function pageSpec(ctx, name) {
|
|
|
6520
6593
|
if (!page) throw new HttpError(404, `unknown page: ${name}`);
|
|
6521
6594
|
return page;
|
|
6522
6595
|
}
|
|
6596
|
+
const FILE_HEADERS = {
|
|
6597
|
+
"cache-control": "no-store",
|
|
6598
|
+
"x-content-type-options": "nosniff",
|
|
6599
|
+
"content-security-policy": "default-src 'none'; style-src 'unsafe-inline'; sandbox"
|
|
6600
|
+
};
|
|
6601
|
+
const tooLarge = (path) => new HttpError(413, `${path} is larger than 10 MB`);
|
|
6602
|
+
const missing = (path) => new HttpError(404, `file not found: ${path}`);
|
|
6603
|
+
function grantedFile(root, files, denied, path) {
|
|
6604
|
+
let real;
|
|
6605
|
+
let size;
|
|
6606
|
+
try {
|
|
6607
|
+
real = realpathSync.native(join(root, path));
|
|
6608
|
+
const st = statSync(real);
|
|
6609
|
+
if (!st.isFile()) throw missing(path);
|
|
6610
|
+
size = st.size;
|
|
6611
|
+
} catch (e) {
|
|
6612
|
+
if (e instanceof HttpError) throw e;
|
|
6613
|
+
throw missing(path);
|
|
6614
|
+
}
|
|
6615
|
+
const rel = relative(realpathSync.native(root), real);
|
|
6616
|
+
const shown = rel.split(sep).join("/");
|
|
6617
|
+
if (rel.startsWith("..") || isAbsolute(rel) || !fileGranted(files, shown) || deniedFile(shown, denied)) throw new HttpError(403, `${path} leads outside this page's files`);
|
|
6618
|
+
if (size > 10485760) throw tooLarge(path);
|
|
6619
|
+
return {
|
|
6620
|
+
real,
|
|
6621
|
+
size
|
|
6622
|
+
};
|
|
6623
|
+
}
|
|
6624
|
+
const readGranted = (ctx, page, path) => readFileSync(grantedFile(ctx.root, page.files, ctx.deniedFiles, path).real);
|
|
6523
6625
|
const pageRoutes = (router, ctx) => {
|
|
6524
6626
|
router.add("GET", "/api/pages/:page/html", ({ params }) => {
|
|
6525
6627
|
const page = pageSpec(ctx, params.page);
|
|
6526
6628
|
return { html: readPageHtml(page.path, displayPath$1(ctx.root, page.path)) };
|
|
6527
6629
|
});
|
|
6630
|
+
router.add("GET", "/api/pages/:page/file", async ({ params, query, signal }) => {
|
|
6631
|
+
const page = pageSpec(ctx, params.page);
|
|
6632
|
+
const asked = query.get("path");
|
|
6633
|
+
if (!asked) throw new HttpError(400, "path is required");
|
|
6634
|
+
const path = normalizeFilePath(asked);
|
|
6635
|
+
if (path === null || !fileGranted(page.files, path)) throw new HttpError(403, `${asked} is not in this page's files`);
|
|
6636
|
+
if (deniedFile(path, ctx.deniedFiles)) throw new HttpError(403, `${asked} is YAMLite's own and no page may read it`);
|
|
6637
|
+
let bytes = await ctx.pageFiles?.(path, signal);
|
|
6638
|
+
if (bytes === "missing") throw missing(path);
|
|
6639
|
+
if (bytes === "too-large" || bytes !== void 0 && bytes.length > 10485760) throw tooLarge(path);
|
|
6640
|
+
bytes ??= readGranted(ctx, page, path);
|
|
6641
|
+
return new Response(bytes, { headers: {
|
|
6642
|
+
...FILE_HEADERS,
|
|
6643
|
+
"content-type": contentTypeOf(path)
|
|
6644
|
+
} });
|
|
6645
|
+
});
|
|
6528
6646
|
};
|
|
6529
6647
|
//#endregion
|
|
6530
6648
|
//#region src/serve/routes/pageai.ts
|
|
@@ -7077,6 +7195,7 @@ const metaRoutes = (router, ctx) => {
|
|
|
7077
7195
|
access: p.access,
|
|
7078
7196
|
sql: p.sql,
|
|
7079
7197
|
network: p.network,
|
|
7198
|
+
files: p.files,
|
|
7080
7199
|
ai: p.ai
|
|
7081
7200
|
})),
|
|
7082
7201
|
views: ctx.y.tables.flatMap((t) => declaredViews(t).map(({ spec, parent, depth, path }) => {
|
|
@@ -7586,6 +7705,40 @@ function warningScrubber(root, specPaths) {
|
|
|
7586
7705
|
return name === "" ? out : out.split(root).join(name);
|
|
7587
7706
|
};
|
|
7588
7707
|
}
|
|
7708
|
+
function grantedCandidates(root, entries) {
|
|
7709
|
+
const found = [];
|
|
7710
|
+
const walk = (rel) => {
|
|
7711
|
+
let items;
|
|
7712
|
+
try {
|
|
7713
|
+
items = readdirSync(join(root, rel), { withFileTypes: true });
|
|
7714
|
+
} catch {
|
|
7715
|
+
return;
|
|
7716
|
+
}
|
|
7717
|
+
for (const item of items) {
|
|
7718
|
+
const path = `${rel}${item.name}`;
|
|
7719
|
+
if (item.isDirectory()) walk(`${path}/`);
|
|
7720
|
+
else found.push(path);
|
|
7721
|
+
}
|
|
7722
|
+
};
|
|
7723
|
+
for (const entry of entries) if (entry.endsWith("/")) walk(entry);
|
|
7724
|
+
else found.push(entry);
|
|
7725
|
+
return found;
|
|
7726
|
+
}
|
|
7727
|
+
function copyPageFiles(root, dir, grants, denied, skipped) {
|
|
7728
|
+
for (const path of new Set(grantedCandidates(root, grants))) {
|
|
7729
|
+
if (deniedFile(path, denied)) continue;
|
|
7730
|
+
let real;
|
|
7731
|
+
try {
|
|
7732
|
+
real = grantedFile(root, grants, denied, path).real;
|
|
7733
|
+
} catch (e) {
|
|
7734
|
+
if (e instanceof HttpError && e.status === 413) skipped[path] = "is larger than 10 MB";
|
|
7735
|
+
continue;
|
|
7736
|
+
}
|
|
7737
|
+
const dest = join(dir, "data", "files", `${path}.bin`);
|
|
7738
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
7739
|
+
copyFileSync(real, dest);
|
|
7740
|
+
}
|
|
7741
|
+
}
|
|
7589
7742
|
const writeJson = (path, value) => writeFileSync(path, JSON.stringify(value));
|
|
7590
7743
|
async function writeSnapshotData(opts) {
|
|
7591
7744
|
const root = resolve(opts.root);
|
|
@@ -7597,6 +7750,7 @@ async function writeSnapshotData(opts) {
|
|
|
7597
7750
|
const yaml = [];
|
|
7598
7751
|
const pages = [];
|
|
7599
7752
|
const skippedPages = {};
|
|
7753
|
+
const skippedFiles = {};
|
|
7600
7754
|
const all = y.tables.map((t) => t.name);
|
|
7601
7755
|
const unknown = (opts.tables ?? []).filter((n) => !all.includes(n));
|
|
7602
7756
|
if (unknown.length > 0) throw new Error(`unknown table: ${unknown.join(", ")}`);
|
|
@@ -7621,6 +7775,8 @@ async function writeSnapshotData(opts) {
|
|
|
7621
7775
|
agent: null,
|
|
7622
7776
|
git: null,
|
|
7623
7777
|
reloadConfig: () => {},
|
|
7778
|
+
pageFiles: null,
|
|
7779
|
+
deniedFiles: deniedFiles(root, stateDir, dbPath),
|
|
7624
7780
|
proposals: new ProposalStore({
|
|
7625
7781
|
store,
|
|
7626
7782
|
dry: store,
|
|
@@ -7652,6 +7808,7 @@ async function writeSnapshotData(opts) {
|
|
|
7652
7808
|
}
|
|
7653
7809
|
}
|
|
7654
7810
|
const kept = new Set(pages.map(([name]) => name));
|
|
7811
|
+
copyPageFiles(root, opts.dir, y.pages.filter((p) => kept.has(p.name)).flatMap((p) => p.files), ctx.deniedFiles, skippedFiles);
|
|
7655
7812
|
meta = {
|
|
7656
7813
|
...served,
|
|
7657
7814
|
root: basename(root),
|
|
@@ -7722,7 +7879,8 @@ async function writeSnapshotData(opts) {
|
|
|
7722
7879
|
tables: selected,
|
|
7723
7880
|
warnings,
|
|
7724
7881
|
pages: pages.map(([name]) => name),
|
|
7725
|
-
skippedPages
|
|
7882
|
+
skippedPages,
|
|
7883
|
+
skippedFiles
|
|
7726
7884
|
};
|
|
7727
7885
|
});
|
|
7728
7886
|
}
|
|
@@ -7810,7 +7968,7 @@ async function exportSite(opts) {
|
|
|
7810
7968
|
if (!html.includes("<head>")) throw new Error(`${indexPath} has no <head>`);
|
|
7811
7969
|
const index = html.replace("<head>", `<head>\n ${STATIC_META}\n ${FILE_GUARD}`);
|
|
7812
7970
|
writeFileSync(join(staging, "index.html"), index);
|
|
7813
|
-
const { tables, warnings, pages, skippedPages } = await writeSnapshotData({
|
|
7971
|
+
const { tables, warnings, pages, skippedPages, skippedFiles } = await writeSnapshotData({
|
|
7814
7972
|
root: opts.root,
|
|
7815
7973
|
tables: opts.tables,
|
|
7816
7974
|
dir: staging,
|
|
@@ -7839,7 +7997,8 @@ async function exportSite(opts) {
|
|
|
7839
7997
|
tables,
|
|
7840
7998
|
warnings,
|
|
7841
7999
|
pages,
|
|
7842
|
-
skippedPages
|
|
8000
|
+
skippedPages,
|
|
8001
|
+
skippedFiles
|
|
7843
8002
|
};
|
|
7844
8003
|
} catch (e) {
|
|
7845
8004
|
rmSync(staging, {
|
|
@@ -8415,4 +8574,4 @@ async function open(options) {
|
|
|
8415
8574
|
};
|
|
8416
8575
|
}
|
|
8417
8576
|
//#endregion
|
|
8418
|
-
export {
|
|
8577
|
+
export { deniedFiles as A, check as B, describeChange as C, isRead as D, PageSql as E, Router as F, resolveConfig as G, configPath as H, createHandler as I, fileGranted as J, DENIED_FILES as K, HttpError as L, readRecord as M, assertSynced as N, statementCount as O, toWire as P, COLUMN_TYPES as Q, isLoopback as R, which as S, worthShowing as T, parseConfig as U, CONFIG_NAMES as V, readsFile as W, declaredViews as X, normalizeFilePath as Y, Store as Z, ghReady as _, query as a, gitLog as b, exportSite as c, validateNewTable as d, ReviewRefused as f, DIFF_LIMIT as g, templatePath as h, formatTable as i, ProposalStore as j, EventHub as k, ROUTES as l, STEP_KINDS as m, formatCsv as n, generateConfig as o, localDriver as p, MAX_PAGE_FILE_BYTES as q, formatJson as r, init as s, open as t, createTable as u, gitBranches as v, fieldChanges as w, gitStatus as x, gitDiff as y, loopbackHosts as z };
|