@graview/ship 0.1.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/LICENSE +96 -0
- package/README.md +95 -0
- package/dist/browser-adapter.d.ts +84 -0
- package/dist/browser-adapter.d.ts.map +1 -0
- package/dist/browser-adapter.js +111 -0
- package/dist/browser-adapter.js.map +1 -0
- package/dist/browser.d.ts +26 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +16 -0
- package/dist/browser.js.map +1 -0
- package/dist/cli.d.ts +48 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +170 -0
- package/dist/cli.js.map +1 -0
- package/dist/dev.d.ts +148 -0
- package/dist/dev.d.ts.map +1 -0
- package/dist/dev.js +286 -0
- package/dist/dev.js.map +1 -0
- package/dist/door.d.ts +22 -0
- package/dist/door.d.ts.map +1 -0
- package/dist/door.js +43 -0
- package/dist/door.js.map +1 -0
- package/dist/export.d.ts +25 -0
- package/dist/export.d.ts.map +1 -0
- package/dist/export.js +30 -0
- package/dist/export.js.map +1 -0
- package/dist/file-adapter.d.ts +28 -0
- package/dist/file-adapter.d.ts.map +1 -0
- package/dist/file-adapter.js +50 -0
- package/dist/file-adapter.js.map +1 -0
- package/dist/health.d.ts +19 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +16 -0
- package/dist/health.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/migrations.d.ts +31 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/migrations.js +59 -0
- package/dist/migrations.js.map +1 -0
- package/dist/open-store.d.ts +57 -0
- package/dist/open-store.d.ts.map +1 -0
- package/dist/open-store.js +103 -0
- package/dist/open-store.js.map +1 -0
- package/dist/photos.d.ts +89 -0
- package/dist/photos.d.ts.map +1 -0
- package/dist/photos.js +102 -0
- package/dist/photos.js.map +1 -0
- package/dist/presence.d.ts +33 -0
- package/dist/presence.d.ts.map +1 -0
- package/dist/presence.js +99 -0
- package/dist/presence.js.map +1 -0
- package/dist/remote.d.ts +73 -0
- package/dist/remote.d.ts.map +1 -0
- package/dist/remote.js +271 -0
- package/dist/remote.js.map +1 -0
- package/dist/serve.d.ts +121 -0
- package/dist/serve.d.ts.map +1 -0
- package/dist/serve.js +249 -0
- package/dist/serve.js.map +1 -0
- package/dist/snapshot.d.ts +20 -0
- package/dist/snapshot.d.ts.map +1 -0
- package/dist/snapshot.js +41 -0
- package/dist/snapshot.js.map +1 -0
- package/dist/source-edit.d.ts +52 -0
- package/dist/source-edit.d.ts.map +1 -0
- package/dist/source-edit.js +455 -0
- package/dist/source-edit.js.map +1 -0
- package/dist/steps.d.ts +98 -0
- package/dist/steps.d.ts.map +1 -0
- package/dist/steps.js +189 -0
- package/dist/steps.js.map +1 -0
- package/dist/studio-door.d.ts +36 -0
- package/dist/studio-door.d.ts.map +1 -0
- package/dist/studio-door.js +102 -0
- package/dist/studio-door.js.map +1 -0
- package/dist/sync-seed.d.ts +61 -0
- package/dist/sync-seed.d.ts.map +1 -0
- package/dist/sync-seed.js +95 -0
- package/dist/sync-seed.js.map +1 -0
- package/dist/typecheck.d.ts +15 -0
- package/dist/typecheck.d.ts.map +1 -0
- package/dist/typecheck.js +59 -0
- package/dist/typecheck.js.map +1 -0
- package/package.json +75 -0
package/dist/door.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
/** Same origin, or no origin at all (curl, a test). Anything else is another site. */
|
|
3
|
+
export declare function sameOrigin(headers: {
|
|
4
|
+
readonly origin?: string;
|
|
5
|
+
readonly host?: string;
|
|
6
|
+
}): boolean;
|
|
7
|
+
/** Whether this request came from the page this server serves. */
|
|
8
|
+
export declare function fromThisApp(req: IncomingMessage): boolean;
|
|
9
|
+
/** The request's body, refused past `limit` bytes with a sentence saying what was too much. */
|
|
10
|
+
export declare function readBody(req: IncomingMessage, limit: number, what?: string): Promise<string>;
|
|
11
|
+
export declare function sendJson(res: ServerResponse, status: number, body: unknown): void;
|
|
12
|
+
/** The shape of the Vite plugin object, without importing Vite to say it. */
|
|
13
|
+
export interface DevServerPlugin {
|
|
14
|
+
readonly name: string;
|
|
15
|
+
readonly apply: "serve";
|
|
16
|
+
configureServer(server: {
|
|
17
|
+
middlewares: {
|
|
18
|
+
use(path: string, handler: (req: IncomingMessage, res: ServerResponse) => void): void;
|
|
19
|
+
};
|
|
20
|
+
}): void;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=door.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"door.d.ts","sourceRoot":"","sources":["../src/door.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AASjE,sFAAsF;AACtF,wBAAgB,UAAU,CAAC,OAAO,EAAE;IAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAOjG;AAED,kEAAkE;AAClE,wBAAgB,WAAW,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAGzD;AAED,+FAA+F;AAC/F,wBAAgB,QAAQ,CAAC,GAAG,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,SAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAa/F;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAIjF;AAED,6EAA6E;AAC7E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,eAAe,CAAC,MAAM,EAAE;QACtB,WAAW,EAAE;YAAE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,KAAK,IAAI,GAAG,IAAI,CAAA;SAAE,CAAC;KACxG,GAAG,IAAI,CAAC;CACV"}
|
package/dist/door.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHAT EVERY DEV-SERVER DOOR SHARES: who may knock, how much they may
|
|
3
|
+
* send, and the shape of the plugin that opens it. The local door, the
|
|
4
|
+
* decision door and the studio door each answered these three questions,
|
|
5
|
+
* and they must answer them the same way.
|
|
6
|
+
*/
|
|
7
|
+
/** Same origin, or no origin at all (curl, a test). Anything else is another site. */
|
|
8
|
+
export function sameOrigin(headers) {
|
|
9
|
+
if (headers.origin === undefined)
|
|
10
|
+
return true;
|
|
11
|
+
try {
|
|
12
|
+
return new URL(headers.origin).host === headers.host;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** Whether this request came from the page this server serves. */
|
|
19
|
+
export function fromThisApp(req) {
|
|
20
|
+
const { origin, host } = req.headers;
|
|
21
|
+
return sameOrigin({ ...(origin ? { origin } : {}), ...(host ? { host } : {}) });
|
|
22
|
+
}
|
|
23
|
+
/** The request's body, refused past `limit` bytes with a sentence saying what was too much. */
|
|
24
|
+
export function readBody(req, limit, what = "request") {
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
let body = "";
|
|
27
|
+
req.on("data", (chunk) => {
|
|
28
|
+
body += chunk.toString();
|
|
29
|
+
if (body.length > limit) {
|
|
30
|
+
reject(new Error(`That is more than ${Math.round(limit / 1_000_000)} MB of ${what} — send fewer, or smaller.`));
|
|
31
|
+
req.destroy();
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
req.on("end", () => resolve(body));
|
|
35
|
+
req.on("error", reject);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
export function sendJson(res, status, body) {
|
|
39
|
+
res.statusCode = status;
|
|
40
|
+
res.setHeader("content-type", "application/json");
|
|
41
|
+
res.end(JSON.stringify(body));
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=door.js.map
|
package/dist/door.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"door.js","sourceRoot":"","sources":["../src/door.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH,sFAAsF;AACtF,MAAM,UAAU,UAAU,CAAC,OAA6D;IACtF,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAC9C,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,WAAW,CAAC,GAAoB;IAC9C,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC;IACrC,OAAO,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAClF,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,QAAQ,CAAC,GAAoB,EAAE,KAAa,EAAE,IAAI,GAAG,SAAS;IAC5E,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YAC/B,IAAI,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,MAAM,GAAG,KAAK,EAAE,CAAC;gBACxB,MAAM,CAAC,IAAI,KAAK,CAAC,qBAAqB,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,SAAS,CAAC,UAAU,IAAI,4BAA4B,CAAC,CAAC,CAAC;gBAChH,GAAG,CAAC,OAAO,EAAE,CAAC;YAChB,CAAC;QACH,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACnC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,GAAmB,EAAE,MAAc,EAAE,IAAa;IACzE,GAAG,CAAC,UAAU,GAAG,MAAM,CAAC;IACxB,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;IAClD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,CAAC"}
|
package/dist/export.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { AnySchema, GraviewApp, Operation, Store } from "@graview/core";
|
|
2
|
+
import type { GraphSnapshot } from "./snapshot.js";
|
|
3
|
+
/**
|
|
4
|
+
* THE ANTI-LOCK-IN CLAIM, as a data shape. Everything a deployment is —
|
|
5
|
+
* the graph, its whole attributed history, and the version it stands at —
|
|
6
|
+
* leaves in one JSON-serialisable bundle, and re-imports into any other
|
|
7
|
+
* deployment of the same declaration: hosted to self-hosted and back.
|
|
8
|
+
* A tenant who cannot leave was never a customer, only a hostage.
|
|
9
|
+
*/
|
|
10
|
+
export interface AppBundle {
|
|
11
|
+
readonly format: "graview-bundle";
|
|
12
|
+
readonly bundleVersion: 1;
|
|
13
|
+
readonly app: string;
|
|
14
|
+
readonly version: number;
|
|
15
|
+
readonly exportedAt: string;
|
|
16
|
+
readonly snapshot: GraphSnapshot;
|
|
17
|
+
readonly log: readonly Operation[];
|
|
18
|
+
}
|
|
19
|
+
export declare function exportBundle<S extends AnySchema>(app: GraviewApp<S>, store: Store<S>, options?: {
|
|
20
|
+
readonly log?: readonly Operation[];
|
|
21
|
+
readonly now?: () => string;
|
|
22
|
+
}): AppBundle;
|
|
23
|
+
/** Refuses a bundle for a different app or a newer format, plainly. */
|
|
24
|
+
export declare function assertBundle<S extends AnySchema>(app: GraviewApp<S>, bundle: AppBundle): void;
|
|
25
|
+
//# sourceMappingURL=export.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../src/export.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD;;;;;;GAMG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,GAAG,EAAE,SAAS,SAAS,EAAE,CAAC;CACpC;AAED,wBAAgB,YAAY,CAAC,CAAC,SAAS,SAAS,EAC9C,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,EAClB,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EACf,OAAO,GAAE;IAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAAO,GACjF,SAAS,CAYX;AAED,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,CAAC,SAAS,SAAS,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,GAAG,IAAI,CAkB7F"}
|
package/dist/export.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export function exportBundle(app, store, options = {}) {
|
|
2
|
+
return {
|
|
3
|
+
format: "graview-bundle",
|
|
4
|
+
bundleVersion: 1,
|
|
5
|
+
app: app.name,
|
|
6
|
+
version: app.version ?? 1,
|
|
7
|
+
exportedAt: (options.now ?? (() => new Date().toISOString()))(),
|
|
8
|
+
snapshot: store.snapshot(),
|
|
9
|
+
// The persisted log when the caller has one (it holds migration runs and
|
|
10
|
+
// prior sessions); the in-memory log otherwise.
|
|
11
|
+
log: options.log ?? store.log.all(),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/** Refuses a bundle for a different app or a newer format, plainly. */
|
|
15
|
+
export function assertBundle(app, bundle) {
|
|
16
|
+
if (bundle.format !== "graview-bundle") {
|
|
17
|
+
throw new Error(`Not a graview bundle (format "${bundle.format}")`);
|
|
18
|
+
}
|
|
19
|
+
if (bundle.bundleVersion > 1) {
|
|
20
|
+
throw new Error(`Bundle format ${bundle.bundleVersion} is newer than this ship understands (1). Upgrade @graview/ship, then import.`);
|
|
21
|
+
}
|
|
22
|
+
if (bundle.app !== app.name) {
|
|
23
|
+
throw new Error(`This bundle is for "${bundle.app}", not "${app.name}"`);
|
|
24
|
+
}
|
|
25
|
+
if (bundle.version > (app.version ?? 1)) {
|
|
26
|
+
throw new Error(`Bundle is at version ${bundle.version}; this declaration only reaches ${app.version ?? 1}. ` +
|
|
27
|
+
`Upgrade the app, then import.`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.js","sourceRoot":"","sources":["../src/export.ts"],"names":[],"mappings":"AAoBA,MAAM,UAAU,YAAY,CAC1B,GAAkB,EAClB,KAAe,EACf,UAAgF,EAAE;IAElF,OAAO;QACL,MAAM,EAAE,gBAAgB;QACxB,aAAa,EAAE,CAAC;QAChB,GAAG,EAAE,GAAG,CAAC,IAAI;QACb,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,CAAC;QACzB,UAAU,EAAE,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE;QAC/D,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAmB;QAC3C,yEAAyE;QACzE,gDAAgD;QAChD,GAAG,EAAE,OAAO,CAAC,GAAG,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;KACpC,CAAC;AACJ,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,YAAY,CAAsB,GAAkB,EAAE,MAAiB;IACrF,IAAI,MAAM,CAAC,MAAM,KAAK,gBAAgB,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CAAC,iCAAkC,MAA8B,CAAC,MAAM,IAAI,CAAC,CAAC;IAC/F,CAAC;IACD,IAAI,MAAM,CAAC,aAAa,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,iBAAiB,MAAM,CAAC,aAAa,+EAA+E,CACrH,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,CAAC,GAAG,KAAK,GAAG,CAAC,IAAI,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,uBAAuB,MAAM,CAAC,GAAG,WAAW,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC;IAC3E,CAAC;IACD,IAAI,MAAM,CAAC,OAAO,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CACb,wBAAwB,MAAM,CAAC,OAAO,mCAAmC,GAAG,CAAC,OAAO,IAAI,CAAC,IAAI;YAC3F,+BAA+B,CAClC,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { PersistenceAdapter } from "@graview/core";
|
|
2
|
+
/**
|
|
3
|
+
* Persistence a self-hoster can READ: a directory per scope holding
|
|
4
|
+
* `snapshot.json` (the current graph), `log.jsonl` (one operation per line,
|
|
5
|
+
* append-only — history as plain lines a person can grep), and `meta.json`
|
|
6
|
+
* (the stored schema version the migration engine compares against).
|
|
7
|
+
*
|
|
8
|
+
* Deliberately boring. The core's sqlite adapter exists for scale; this one
|
|
9
|
+
* exists so "where is my data" has an answer anyone can open.
|
|
10
|
+
*/
|
|
11
|
+
export interface FileAdapter extends PersistenceAdapter<string> {
|
|
12
|
+
loadMeta(scope: string): {
|
|
13
|
+
version: number;
|
|
14
|
+
} | null;
|
|
15
|
+
saveMeta(scope: string, meta: {
|
|
16
|
+
version: number;
|
|
17
|
+
}): void;
|
|
18
|
+
/**
|
|
19
|
+
* The directory it writes into.
|
|
20
|
+
*
|
|
21
|
+
* Said out loud because "where is my data" is the question this adapter
|
|
22
|
+
* exists to answer, and a health report that could only repeat the scope
|
|
23
|
+
* name was answering a different one.
|
|
24
|
+
*/
|
|
25
|
+
readonly root: string;
|
|
26
|
+
}
|
|
27
|
+
export declare function createFileAdapter(root: string): FileAdapter;
|
|
28
|
+
//# sourceMappingURL=file-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-adapter.d.ts","sourceRoot":"","sources":["../src/file-adapter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAa,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAGnE;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAY,SAAQ,kBAAkB,CAAC,MAAM,CAAC;IAC7D,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACpD,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACzD;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CA4C3D"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, rmSync, writeFileSync, appendFileSync, existsSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
export function createFileAdapter(root) {
|
|
4
|
+
const place = (scope, file) => join(root, scope, file);
|
|
5
|
+
const read = (path) => {
|
|
6
|
+
if (!existsSync(path))
|
|
7
|
+
return null;
|
|
8
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
9
|
+
};
|
|
10
|
+
const write = (path, value) => {
|
|
11
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
12
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`);
|
|
13
|
+
};
|
|
14
|
+
return {
|
|
15
|
+
name: "file",
|
|
16
|
+
root,
|
|
17
|
+
async load(scope) {
|
|
18
|
+
return read(place(scope, "snapshot.json"));
|
|
19
|
+
},
|
|
20
|
+
async save(scope, snapshot) {
|
|
21
|
+
write(place(scope, "snapshot.json"), snapshot);
|
|
22
|
+
},
|
|
23
|
+
async delete(scope) {
|
|
24
|
+
rmSync(join(root, scope), { recursive: true, force: true });
|
|
25
|
+
},
|
|
26
|
+
async loadLog(scope) {
|
|
27
|
+
const path = place(scope, "log.jsonl");
|
|
28
|
+
if (!existsSync(path))
|
|
29
|
+
return [];
|
|
30
|
+
return readFileSync(path, "utf8")
|
|
31
|
+
.split("\n")
|
|
32
|
+
.filter((line) => line.trim().length > 0)
|
|
33
|
+
.map((line) => JSON.parse(line));
|
|
34
|
+
},
|
|
35
|
+
async appendOps(scope, ops) {
|
|
36
|
+
if (ops.length === 0)
|
|
37
|
+
return;
|
|
38
|
+
const path = place(scope, "log.jsonl");
|
|
39
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
40
|
+
appendFileSync(path, ops.map((op) => JSON.stringify(op)).join("\n") + "\n");
|
|
41
|
+
},
|
|
42
|
+
loadMeta(scope) {
|
|
43
|
+
return read(place(scope, "meta.json"));
|
|
44
|
+
},
|
|
45
|
+
saveMeta(scope, meta) {
|
|
46
|
+
write(place(scope, "meta.json"), meta);
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=file-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-adapter.js","sourceRoot":"","sources":["../src/file-adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/health.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { AnySchema, Store } from "@graview/core";
|
|
2
|
+
/**
|
|
3
|
+
* Whether a deployment is WELL, asked of the store itself. Not liveness —
|
|
4
|
+
* the process answering proves that — but coherence: the graph parses under
|
|
5
|
+
* its schema, no edge dangles, and the rules' standing is a number rather
|
|
6
|
+
* than a surprise. A service polls this per tenant; a self-hoster curls it.
|
|
7
|
+
*/
|
|
8
|
+
export interface HealthReport {
|
|
9
|
+
readonly ok: boolean;
|
|
10
|
+
readonly nodes: number;
|
|
11
|
+
readonly edges: number;
|
|
12
|
+
readonly violations: number;
|
|
13
|
+
readonly danglingEdges: readonly string[];
|
|
14
|
+
readonly at: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function health<S extends AnySchema>(store: Store<S>, options?: {
|
|
17
|
+
readonly now?: () => string;
|
|
18
|
+
}): HealthReport;
|
|
19
|
+
//# sourceMappingURL=health.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEtD;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,MAAM,CAAC,CAAC,SAAS,SAAS,EACxC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EACf,OAAO,GAAE;IAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAAO,GAC5C,YAAY,CAcd"}
|
package/dist/health.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function health(store, options = {}) {
|
|
2
|
+
const ids = new Set([...store.graph.allNodes()].map((node) => node.id));
|
|
3
|
+
const dangling = [...store.graph.allEdges()]
|
|
4
|
+
.filter((edge) => !ids.has(edge.from) || !ids.has(edge.to))
|
|
5
|
+
.map((edge) => `${edge.kind}:${edge.from}->${edge.to}`);
|
|
6
|
+
const violations = store.violations().length;
|
|
7
|
+
return {
|
|
8
|
+
ok: dangling.length === 0,
|
|
9
|
+
nodes: ids.size,
|
|
10
|
+
edges: [...store.graph.allEdges()].length,
|
|
11
|
+
violations,
|
|
12
|
+
danglingEdges: dangling,
|
|
13
|
+
at: (options.now ?? (() => new Date().toISOString()))(),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"AAiBA,MAAM,UAAU,MAAM,CACpB,KAAe,EACf,UAA2C,EAAE;IAE7C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IACxE,MAAM,QAAQ,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;SACzC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;SAC1D,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1D,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC,MAAM,CAAC;IAC7C,OAAO;QACL,EAAE,EAAE,QAAQ,CAAC,MAAM,KAAK,CAAC;QACzB,KAAK,EAAE,GAAG,CAAC,IAAI;QACf,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,MAAM;QACzC,UAAU;QACV,aAAa,EAAE,QAAQ;QACvB,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE;KACxD,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export { createFileAdapter } from "./file-adapter.js";
|
|
2
|
+
export type { FileAdapter } from "./file-adapter.js";
|
|
3
|
+
export { browserStartsFresh, createBrowserAdapter, forgetFreshParam, freshHref, } from "./browser-adapter.js";
|
|
4
|
+
export type { BrowserAdapter, BrowserAdapterOptions, StorageLike } from "./browser-adapter.js";
|
|
5
|
+
export { migrateSnapshot, pendingMigrations } from "./migrations.js";
|
|
6
|
+
export { primitivesFor, primitivesForSteps, sayStep, stepsMigration } from "./steps.js";
|
|
7
|
+
export { applySteps, contentOperation, SEED_SYNC_AUTHOR, seedSteps } from "./sync-seed.js";
|
|
8
|
+
export type { SeedSyncOptions } from "./sync-seed.js";
|
|
9
|
+
export type { MigrationStep } from "./steps.js";
|
|
10
|
+
export type { MigrationRun } from "./migrations.js";
|
|
11
|
+
export { openStore } from "./open-store.js";
|
|
12
|
+
export type { OpenStoreOptions, OpenedStore } from "./open-store.js";
|
|
13
|
+
export { applyToSnapshot } from "./snapshot.js";
|
|
14
|
+
export type { GraphSnapshot } from "./snapshot.js";
|
|
15
|
+
export { assertBundle, exportBundle } from "./export.js";
|
|
16
|
+
export type { AppBundle } from "./export.js";
|
|
17
|
+
export { health } from "./health.js";
|
|
18
|
+
export type { HealthReport } from "./health.js";
|
|
19
|
+
export { openRemote } from "./remote.js";
|
|
20
|
+
export { createBroadcastPresence, presenceChannelName } from "./presence.js";
|
|
21
|
+
export type { BroadcastPresenceOptions, ChannelLike } from "./presence.js";
|
|
22
|
+
export type { RemoteOptions, RemoteStore } from "./remote.js";
|
|
23
|
+
export { SEAT_HEADERS, serveStore, WIRE } from "./serve.js";
|
|
24
|
+
export type { ServeOptions, ServedStore } from "./serve.js";
|
|
25
|
+
export { backendFrom, serve, SERVE_USAGE, syncSeed } from "./cli.js";
|
|
26
|
+
export type { StoreBackend } from "./cli.js";
|
|
27
|
+
export { assertPhotoFits, photosUsed, storageBytes, PhotoTooLarge, PHOTO_BUDGET_BYTES, PHOTO_MAX_BYTES, } from "./photos.js";
|
|
28
|
+
export type { PhotoBudget, PhotoField } from "./photos.js";
|
|
29
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,gBAAgB,EAChB,SAAS,GACV,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC/F,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3F,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACzD,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAC7E,YAAY,EAAE,wBAAwB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC3E,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAC5D,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACrE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EACL,eAAe,EACf,UAAU,EACV,YAAY,EACZ,aAAa,EACb,kBAAkB,EAClB,eAAe,GAChB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { createFileAdapter } from "./file-adapter.js";
|
|
2
|
+
export { browserStartsFresh, createBrowserAdapter, forgetFreshParam, freshHref, } from "./browser-adapter.js";
|
|
3
|
+
export { migrateSnapshot, pendingMigrations } from "./migrations.js";
|
|
4
|
+
export { primitivesFor, primitivesForSteps, sayStep, stepsMigration } from "./steps.js";
|
|
5
|
+
export { applySteps, contentOperation, SEED_SYNC_AUTHOR, seedSteps } from "./sync-seed.js";
|
|
6
|
+
export { openStore } from "./open-store.js";
|
|
7
|
+
export { applyToSnapshot } from "./snapshot.js";
|
|
8
|
+
export { assertBundle, exportBundle } from "./export.js";
|
|
9
|
+
export { health } from "./health.js";
|
|
10
|
+
export { openRemote } from "./remote.js";
|
|
11
|
+
export { createBroadcastPresence, presenceChannelName } from "./presence.js";
|
|
12
|
+
export { SEAT_HEADERS, serveStore, WIRE } from "./serve.js";
|
|
13
|
+
export { backendFrom, serve, SERVE_USAGE, syncSeed } from "./cli.js";
|
|
14
|
+
export { assertPhotoFits, photosUsed, storageBytes, PhotoTooLarge, PHOTO_BUDGET_BYTES, PHOTO_MAX_BYTES, } from "./photos.js";
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,gBAAgB,EAChB,SAAS,GACV,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAI3F,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEzD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAG7E,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAE5D,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAErE,OAAO,EACL,eAAe,EACf,UAAU,EACV,YAAY,EACZ,aAAa,EACb,kBAAkB,EAClB,eAAe,GAChB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type GraviewApp, type AnySchema, type MigrationDeclaration, type Operation } from "@graview/core";
|
|
2
|
+
import type { GraphSnapshot } from "./snapshot.js";
|
|
3
|
+
/**
|
|
4
|
+
* MIGRATIONS SPEAK THE OP LOG'S LANGUAGE.
|
|
5
|
+
*
|
|
6
|
+
* A migration answers with primitives — the same five words every other
|
|
7
|
+
* change is made of — and running one appends ordinary operations: authored
|
|
8
|
+
* (`system · ship:migration`), stating their intent, carrying their inverse
|
|
9
|
+
* because a patch carries its before. Schema evolution is therefore not a
|
|
10
|
+
* special ceremony outside the record; it IS the record, replayable and
|
|
11
|
+
* undoable in the same vocabulary as a person's edit.
|
|
12
|
+
*/
|
|
13
|
+
export interface MigrationRun {
|
|
14
|
+
readonly snapshot: GraphSnapshot;
|
|
15
|
+
readonly version: number;
|
|
16
|
+
/** The operations the run appended — empty when already current. */
|
|
17
|
+
readonly ops: readonly Operation[];
|
|
18
|
+
}
|
|
19
|
+
/** The single-step chain from a stored version to the declaration's. */
|
|
20
|
+
export declare function pendingMigrations<S extends AnySchema>(app: GraviewApp<S>, storedVersion: number): readonly MigrationDeclaration[];
|
|
21
|
+
/**
|
|
22
|
+
* Runs the chain over a stored snapshot, producing the migrated snapshot
|
|
23
|
+
* and the operations that record the run. Pure: nothing is written here —
|
|
24
|
+
* the caller (openStore, a service's fleet upgrader) owns the append and
|
|
25
|
+
* can therefore halt, stage, or roll back.
|
|
26
|
+
*/
|
|
27
|
+
export declare function migrateSnapshot<S extends AnySchema>(app: GraviewApp<S>, stored: GraphSnapshot, storedVersion: number, options?: {
|
|
28
|
+
readonly now?: () => string;
|
|
29
|
+
readonly nextOpId?: (step: string) => string;
|
|
30
|
+
}): MigrationRun;
|
|
31
|
+
//# sourceMappingURL=migrations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,oBAAoB,EACzB,KAAK,SAAS,EAEf,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD;;;;;;;;;GASG;AAEH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,QAAQ,CAAC,GAAG,EAAE,SAAS,SAAS,EAAE,CAAC;CACpC;AAED,wEAAwE;AACxE,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,SAAS,EACnD,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,EAClB,aAAa,EAAE,MAAM,GACpB,SAAS,oBAAoB,EAAE,CAsBjC;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,SAAS,EACjD,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,EAClB,MAAM,EAAE,aAAa,EACrB,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE;IAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;CAAO,GAC1F,YAAY,CA+Bd"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { invert, normalise, writesOf, } from "@graview/core";
|
|
2
|
+
import { applyToSnapshot } from "./snapshot.js";
|
|
3
|
+
/** The single-step chain from a stored version to the declaration's. */
|
|
4
|
+
export function pendingMigrations(app, storedVersion) {
|
|
5
|
+
const target = app.version ?? storedVersion;
|
|
6
|
+
const bySource = new Map((app.migrations ?? []).map((m) => [m.from, m]));
|
|
7
|
+
const chain = [];
|
|
8
|
+
let at = storedVersion;
|
|
9
|
+
while (at < target) {
|
|
10
|
+
const step = bySource.get(at);
|
|
11
|
+
if (step && step.to <= step.from) {
|
|
12
|
+
throw new Error(`Migration ${step.from}→${step.to} does not advance — the chain would never terminate.`);
|
|
13
|
+
}
|
|
14
|
+
if (!step) {
|
|
15
|
+
throw new Error(`No migration from version ${at} — a stored graph there cannot reach ${target}. ` +
|
|
16
|
+
`graview check would have said so.`);
|
|
17
|
+
}
|
|
18
|
+
chain.push(step);
|
|
19
|
+
at = step.to;
|
|
20
|
+
}
|
|
21
|
+
return chain;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Runs the chain over a stored snapshot, producing the migrated snapshot
|
|
25
|
+
* and the operations that record the run. Pure: nothing is written here —
|
|
26
|
+
* the caller (openStore, a service's fleet upgrader) owns the append and
|
|
27
|
+
* can therefore halt, stage, or roll back.
|
|
28
|
+
*/
|
|
29
|
+
export function migrateSnapshot(app, stored, storedVersion, options = {}) {
|
|
30
|
+
const now = options.now ?? (() => new Date().toISOString());
|
|
31
|
+
const nextOpId = options.nextOpId ?? ((step) => `migration:${step}:${now()}`);
|
|
32
|
+
let snapshot = stored;
|
|
33
|
+
const ops = [];
|
|
34
|
+
const batch = `migration:${storedVersion}->${app.version ?? storedVersion}`;
|
|
35
|
+
for (const step of pendingMigrations(app, storedVersion)) {
|
|
36
|
+
/*
|
|
37
|
+
* Normalised, like every other op: a step that clears a field says so
|
|
38
|
+
* with a value rather than with an absence, so the inverse it carries is
|
|
39
|
+
* still there after the log has been through JSON.
|
|
40
|
+
*/
|
|
41
|
+
const primitives = step.apply(snapshot).map(normalise);
|
|
42
|
+
snapshot = applyToSnapshot(snapshot, primitives);
|
|
43
|
+
ops.push({
|
|
44
|
+
id: nextOpId(`${step.from}-${step.to}`),
|
|
45
|
+
seq: -1, // The appender assigns the real position in its log.
|
|
46
|
+
batch,
|
|
47
|
+
author: { kind: "system", id: "ship:migration" },
|
|
48
|
+
intent: `migration ${step.from}→${step.to}: ${step.title}`,
|
|
49
|
+
mutation: null,
|
|
50
|
+
primitives,
|
|
51
|
+
inverse: [...primitives].reverse().map(invert),
|
|
52
|
+
reads: [],
|
|
53
|
+
writes: [...new Set(primitives.flatMap(writesOf))],
|
|
54
|
+
at: now(),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return { snapshot, version: app.version ?? storedVersion, ops };
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=migrations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrations.js","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Store, type AnySchema, type GraviewApp, type Operation, type PersistenceAdapter, type StoreOptions } from "@graview/core";
|
|
2
|
+
import type { GraphSnapshot } from "./snapshot.js";
|
|
3
|
+
/**
|
|
4
|
+
* ONE declaration plus ONE adapter is a running deployment.
|
|
5
|
+
*
|
|
6
|
+
* `openStore` is the lifecycle every deployment repeats and no app should
|
|
7
|
+
* write: load what was stored, migrate it forward (the run recorded as
|
|
8
|
+
* ordinary operations in the persisted log), fold it into a live store, and
|
|
9
|
+
* keep the adapter current — every applied diff appends its operations and
|
|
10
|
+
* rewrites the snapshot, so a crash loses nothing that was ever notified.
|
|
11
|
+
*/
|
|
12
|
+
export interface OpenStoreOptions<S extends AnySchema> {
|
|
13
|
+
readonly app: GraviewApp<S>;
|
|
14
|
+
readonly adapter: PersistenceAdapter<string> & {
|
|
15
|
+
loadMeta?(scope: string): {
|
|
16
|
+
version: number;
|
|
17
|
+
} | null;
|
|
18
|
+
saveMeta?(scope: string, meta: {
|
|
19
|
+
version: number;
|
|
20
|
+
}): void;
|
|
21
|
+
};
|
|
22
|
+
readonly scope?: string;
|
|
23
|
+
/** First-run data when nothing is stored yet. */
|
|
24
|
+
readonly seed?: GraphSnapshot;
|
|
25
|
+
/**
|
|
26
|
+
* The version of a stored graph that predates version metadata. Absent,
|
|
27
|
+
* a metaless store is assumed CURRENT — the conservative reading, since
|
|
28
|
+
* migrating data that is already new-shaped corrupts it.
|
|
29
|
+
*/
|
|
30
|
+
readonly assumeVersion?: number;
|
|
31
|
+
/** Told when a persistence write fails; absent, failures reach the console. */
|
|
32
|
+
readonly onPersistError?: (error: unknown) => void;
|
|
33
|
+
/**
|
|
34
|
+
* Discard what is stored for this scope and start from the seed. The
|
|
35
|
+
* way back to the example for a demo that has been edited into a corner —
|
|
36
|
+
* a graph you cannot leave teaches distrust. Everything stored is deleted
|
|
37
|
+
* first, so the seed really is the first load again.
|
|
38
|
+
*/
|
|
39
|
+
readonly fresh?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Overrides for the store. The declaration's own policy and modules are
|
|
42
|
+
* applied before these, so an app that declares who may do what gets it
|
|
43
|
+
* enforced by the store ship opens without saying so twice.
|
|
44
|
+
*/
|
|
45
|
+
readonly storeOptions?: Partial<StoreOptions<S>>;
|
|
46
|
+
}
|
|
47
|
+
export interface OpenedStore<S extends AnySchema> {
|
|
48
|
+
readonly store: Store<S>;
|
|
49
|
+
/** Operations the opening appended: the migration run, when one happened. */
|
|
50
|
+
readonly migrated: readonly Operation[];
|
|
51
|
+
/** Resolves when every write accepted so far has settled on the adapter. */
|
|
52
|
+
flush(): Promise<void>;
|
|
53
|
+
/** Stops persisting. The store keeps working; nothing further is written. */
|
|
54
|
+
close(): void;
|
|
55
|
+
}
|
|
56
|
+
export declare function openStore<S extends AnySchema>(options: OpenStoreOptions<S>): Promise<OpenedStore<S>>;
|
|
57
|
+
//# sourceMappingURL=open-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open-store.d.ts","sourceRoot":"","sources":["../src/open-store.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,kBAAkB,EACvB,KAAK,YAAY,EAClB,MAAM,eAAe,CAAC;AAEvB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD;;;;;;;;GAQG;AAEH,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,SAAS;IACnD,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC,MAAM,CAAC,GAAG;QAC7C,QAAQ,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAC;QACrD,QAAQ,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAC;KAC3D,CAAC;IACF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,iDAAiD;IACjD,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,+EAA+E;IAC/E,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnD;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;CAClD;AAQD,MAAM,WAAW,WAAW,CAAC,CAAC,SAAS,SAAS;IAC9C,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACzB,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,EAAE,SAAS,SAAS,EAAE,CAAC;IACxC,4EAA4E;IAC5E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,6EAA6E;IAC7E,KAAK,IAAI,IAAI,CAAC;CACf;AAED,wBAAsB,SAAS,CAAC,CAAC,SAAS,SAAS,EACjD,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAC3B,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CA2GzB"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Store, } from "@graview/core";
|
|
2
|
+
import { migrateSnapshot } from "./migrations.js";
|
|
3
|
+
export async function openStore(options) {
|
|
4
|
+
const { app, adapter } = options;
|
|
5
|
+
const scope = options.scope ?? app.name;
|
|
6
|
+
if (options.fresh)
|
|
7
|
+
await adapter.delete(scope);
|
|
8
|
+
const stored = (await adapter.load(scope));
|
|
9
|
+
const persisted = (await adapter.loadLog?.(scope)) ?? [];
|
|
10
|
+
let seq = persisted.length;
|
|
11
|
+
const meta = adapter.loadMeta?.(scope) ?? null;
|
|
12
|
+
const target = app.version ?? 1;
|
|
13
|
+
/*
|
|
14
|
+
* THE LOG OUTRANKS THE META. A crash between writing the migrated
|
|
15
|
+
* snapshot and stamping the version leaves new-shaped data under an old
|
|
16
|
+
* stamp — and re-running a migration over already-migrated data is the
|
|
17
|
+
* exact corruption migrations exist to prevent. The migration ops are in
|
|
18
|
+
* the log before anything else is written, so the log knows the truth.
|
|
19
|
+
*/
|
|
20
|
+
const migratedTo = persisted
|
|
21
|
+
.filter((op) => op.author.kind === "system" && op.author.id === "ship:migration")
|
|
22
|
+
.map((op) => Number(op.intent.match(/migration \d+→(\d+):/)?.[1] ?? 0))
|
|
23
|
+
.reduce((highest, version) => Math.max(highest, version), 0);
|
|
24
|
+
const storedVersion = stored === null
|
|
25
|
+
? target
|
|
26
|
+
: Math.max(meta?.version ?? options.assumeVersion ?? target, migratedTo);
|
|
27
|
+
let snapshot = stored ?? options.seed ?? { nodes: [], edges: [] };
|
|
28
|
+
let migrated = [];
|
|
29
|
+
if (storedVersion < target) {
|
|
30
|
+
const run = migrateSnapshot(app, snapshot, storedVersion);
|
|
31
|
+
snapshot = run.snapshot;
|
|
32
|
+
migrated = run.ops.map((op) => ({ ...op, seq: seq++ }));
|
|
33
|
+
await adapter.appendOps?.(scope, migrated);
|
|
34
|
+
}
|
|
35
|
+
/*
|
|
36
|
+
* The store REOPENS WITH ITS HISTORY. The snapshot is the graph; the
|
|
37
|
+
* persisted log (plus the migration run just appended) is how it got
|
|
38
|
+
* there — and it is handed to the store as the live log rather than
|
|
39
|
+
* folded, because the seed was never an operation. What was done in an
|
|
40
|
+
* earlier session is therefore still attributed, still in the activity,
|
|
41
|
+
* and still undoable, which is what "persistence is the op log" means.
|
|
42
|
+
*/
|
|
43
|
+
const history = [...persisted, ...migrated];
|
|
44
|
+
/*
|
|
45
|
+
* Ids that cannot collide with an earlier session's. The store's default
|
|
46
|
+
* counter restarts at op1 every open, and an undo names its target BY ID —
|
|
47
|
+
* a second "op1" would make the log ambiguous about what was taken back.
|
|
48
|
+
* A supplied `ids` still wins.
|
|
49
|
+
*/
|
|
50
|
+
const taken = new Set(history.map((op) => op.id));
|
|
51
|
+
let n = history.length;
|
|
52
|
+
const ids = () => {
|
|
53
|
+
let id = `op${++n}`;
|
|
54
|
+
while (taken.has(id))
|
|
55
|
+
id = `op${++n}`;
|
|
56
|
+
taken.add(id);
|
|
57
|
+
return id;
|
|
58
|
+
};
|
|
59
|
+
const store = new Store({
|
|
60
|
+
schema: app.schema,
|
|
61
|
+
mutations: app.mutations ?? [],
|
|
62
|
+
invariants: app.invariants ?? [],
|
|
63
|
+
...(app.modules ? { modules: app.modules } : {}),
|
|
64
|
+
...(app.policy ? { policy: app.policy } : {}),
|
|
65
|
+
/* The allowlist travels with the declaration, so a deployment enforces
|
|
66
|
+
what the app said an agent was for without being asked to. */
|
|
67
|
+
...(app.intelligence ? { intelligence: app.intelligence } : {}),
|
|
68
|
+
snapshot,
|
|
69
|
+
log: history,
|
|
70
|
+
ids,
|
|
71
|
+
// A stored history is read back later, so its timestamps are real ones.
|
|
72
|
+
now: () => new Date().toISOString(),
|
|
73
|
+
...(options.storeOptions ?? {}),
|
|
74
|
+
});
|
|
75
|
+
/*
|
|
76
|
+
* Write at open only when opening CHANGED something — a fresh scope or a
|
|
77
|
+
* migration run. Re-saving an untouched store rewrites the snapshot
|
|
78
|
+
* through the current schema's parse, which silently strips any field a
|
|
79
|
+
* rolled-back declaration does not know — data loss with no prior copy.
|
|
80
|
+
*/
|
|
81
|
+
if (stored === null || migrated.length > 0) {
|
|
82
|
+
await adapter.save(scope, store.snapshot());
|
|
83
|
+
}
|
|
84
|
+
adapter.saveMeta?.(scope, { version: target });
|
|
85
|
+
/*
|
|
86
|
+
* Writes are SERIALISED: a second diff's ops never land before the
|
|
87
|
+
* first's snapshot, and a failure is reported rather than swallowed —
|
|
88
|
+
* an app that thinks it persisted and did not is the worst quiet state.
|
|
89
|
+
*/
|
|
90
|
+
const report = options.onPersistError ?? ((error) => console.error("graview ship: persistence failed", error));
|
|
91
|
+
let writing = Promise.resolve();
|
|
92
|
+
const unsubscribe = store.subscribe((_diff, ops) => {
|
|
93
|
+
const stamped = ops.map((op) => ({ ...op, seq: seq++ }));
|
|
94
|
+
writing = writing
|
|
95
|
+
.then(async () => {
|
|
96
|
+
await adapter.appendOps?.(scope, stamped);
|
|
97
|
+
await adapter.save(scope, store.snapshot());
|
|
98
|
+
})
|
|
99
|
+
.catch(report);
|
|
100
|
+
});
|
|
101
|
+
return { store, migrated, flush: () => writing, close: unsubscribe };
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=open-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open-store.js","sourceRoot":"","sources":["../src/open-store.ts"],"names":[],"mappings":"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"}
|