@tensorix/metahub 0.1.11 → 0.2.1
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.js +23711 -17899
- package/dist/cli.js.map +84 -59
- package/dist/core/blobs-core.d.ts +106 -0
- package/dist/core/blobs-core.d.ts.map +1 -0
- package/dist/core/blobs.d.ts +110 -0
- package/dist/core/blobs.d.ts.map +1 -0
- package/dist/core/cache.d.ts +23 -1
- package/dist/core/cache.d.ts.map +1 -1
- package/dist/core/compact.d.ts +4 -3
- package/dist/core/compact.d.ts.map +1 -1
- package/dist/core/config.d.ts +7 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/crdt.d.ts +32 -2
- package/dist/core/crdt.d.ts.map +1 -1
- package/dist/core/schema-init.d.ts +62 -2
- package/dist/core/schema-init.d.ts.map +1 -1
- package/dist/core/schema.d.ts +1 -1
- package/dist/core/schema.d.ts.map +1 -1
- package/dist/core/shares.d.ts +60 -0
- package/dist/core/shares.d.ts.map +1 -0
- package/dist/core/sites-core.d.ts +35 -0
- package/dist/core/sites-core.d.ts.map +1 -1
- package/dist/core/sites.d.ts +4 -13
- package/dist/core/sites.d.ts.map +1 -1
- package/dist/core/sync/auth.d.ts +15 -2
- package/dist/core/sync/auth.d.ts.map +1 -1
- package/dist/core/sync/blob-routes.d.ts +12 -0
- package/dist/core/sync/blob-routes.d.ts.map +1 -0
- package/dist/core/sync/client.d.ts +7 -0
- package/dist/core/sync/client.d.ts.map +1 -1
- package/dist/core/sync/e2ee.d.ts +31 -0
- package/dist/core/sync/e2ee.d.ts.map +1 -0
- package/dist/core/sync/enroll.d.ts +21 -0
- package/dist/core/sync/enroll.d.ts.map +1 -0
- package/dist/core/sync/peers-routes.d.ts.map +1 -1
- package/dist/core/sync/peers.d.ts +74 -2
- package/dist/core/sync/peers.d.ts.map +1 -1
- package/dist/core/sync/publisher-lease.d.ts +8 -0
- package/dist/core/sync/publisher-lease.d.ts.map +1 -0
- package/dist/core/sync/routes.d.ts.map +1 -1
- package/dist/core/sync/server.d.ts +1 -0
- package/dist/core/sync/server.d.ts.map +1 -1
- package/dist/core/sync/share-actions.d.ts +69 -0
- package/dist/core/sync/share-actions.d.ts.map +1 -0
- package/dist/core/sync/share-export.d.ts +72 -0
- package/dist/core/sync/share-export.d.ts.map +1 -0
- package/dist/core/sync/share-render.d.ts +10 -0
- package/dist/core/sync/share-render.d.ts.map +1 -0
- package/dist/core/sync/share-serve.d.ts +3 -0
- package/dist/core/sync/share-serve.d.ts.map +1 -0
- package/dist/core/sync/sites-serve.d.ts.map +1 -1
- package/dist/core/sync/storage-s3-bun.d.ts +35 -0
- package/dist/core/sync/storage-s3-bun.d.ts.map +1 -0
- package/dist/core/sync/storage-url.d.ts +18 -0
- package/dist/core/sync/storage-url.d.ts.map +1 -0
- package/dist/core/sync/storage.d.ts +170 -0
- package/dist/core/sync/storage.d.ts.map +1 -0
- package/dist/db-worker.js +212 -66
- package/dist/index.js +13546 -8960
- package/dist/index.js.map +46 -27
- package/dist/sw.js +1 -1
- package/dist/webui/server/assets.d.ts.map +1 -1
- package/dist/webui/server/routes.d.ts.map +1 -1
- package/dist/webui/server/share-routes.d.ts +3 -0
- package/dist/webui/server/share-routes.d.ts.map +1 -0
- package/dist/webui.js +93 -61
- package/package.json +5 -1
|
@@ -57,4 +57,39 @@ export declare function getFileRow(db: DbDriver, siteId: string, path: string):
|
|
|
57
57
|
content: string | null;
|
|
58
58
|
} | null;
|
|
59
59
|
export declare function listFiles(db: DbDriver, siteId: string): SiteFileSummary[];
|
|
60
|
+
/** Binaries at or below this size store inline (base64); larger need a blob. */
|
|
61
|
+
export declare const INLINE_LIMIT: number;
|
|
62
|
+
/** Text-ish types store as readable utf8; everything else is binary. */
|
|
63
|
+
export declare function isTextType(contentType: string): boolean;
|
|
64
|
+
/** Raster image types (svg is text, handled by isTextType). These always store
|
|
65
|
+
* as a content-addressed blob regardless of size — they never base64-inline
|
|
66
|
+
* into the oplog, keeping replicas lean. */
|
|
67
|
+
export declare function isImageType(contentType: string): boolean;
|
|
68
|
+
export declare function toBytes(data: string | Uint8Array | ArrayBuffer): Uint8Array;
|
|
69
|
+
export declare const createSite: (db: DbDriver, opts: {
|
|
70
|
+
name: string;
|
|
71
|
+
title?: string;
|
|
72
|
+
}) => SiteRow;
|
|
73
|
+
/** Rename a site and/or change its title. Guards against duplicate names. */
|
|
74
|
+
export declare const updateSite: (db: DbDriver, id: string, opts: {
|
|
75
|
+
name?: string;
|
|
76
|
+
title?: string;
|
|
77
|
+
}) => SiteRow;
|
|
78
|
+
export declare const deleteSite: (db: DbDriver, id: string) => boolean;
|
|
79
|
+
/** Stable id for a (site, path) pair so re-uploads merge instead of duplicate. */
|
|
80
|
+
export declare function fileIdFor(db: DbDriver, siteId: string, path: string): string | null;
|
|
81
|
+
/** Emit the register writes for one file (shared by inline + blob put paths). */
|
|
82
|
+
export declare function writeFileRow(db: DbDriver, siteId: string, cleanPath: string, contentType: string, encoding: FileEncoding, content: string): SiteFileRow;
|
|
83
|
+
/**
|
|
84
|
+
* Upload/replace one file inline (utf8 text or small base64 binary) — portable,
|
|
85
|
+
* so the browser replica authors sites offline. Binaries over INLINE_LIMIT need
|
|
86
|
+
* the server-only blob store; here they throw (sites.ts putFile handles them).
|
|
87
|
+
*/
|
|
88
|
+
export declare function putFileInline(db: DbDriver, siteId: string, path: string, opts: {
|
|
89
|
+
data: string | Uint8Array | ArrayBuffer;
|
|
90
|
+
contentType?: string;
|
|
91
|
+
}): SiteFileRow;
|
|
92
|
+
export declare const deleteFile: (db: DbDriver, siteId: string, path: string) => boolean;
|
|
93
|
+
/** Count of live files per site (for the management list's file_count). */
|
|
94
|
+
export declare function fileCount(db: DbDriver, siteId: string): number;
|
|
60
95
|
//# sourceMappingURL=sites-core.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sites-core.d.ts","sourceRoot":"","sources":["../../src/core/sites-core.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"sites-core.d.ts","sourceRoot":"","sources":["../../src/core/sites-core.ts"],"names":[],"mappings":"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"}
|
package/dist/core/sites.d.ts
CHANGED
|
@@ -1,22 +1,13 @@
|
|
|
1
1
|
import type { DbDriver } from "./driver.ts";
|
|
2
|
-
import { type
|
|
2
|
+
import { type SiteFileRow } from "./sites-core.ts";
|
|
3
3
|
export * from "./sites-core.ts";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}) => SiteRow;
|
|
8
|
-
/** Rename a site and/or change its title. Guards against duplicate names. */
|
|
9
|
-
export declare const updateSite: (db: DbDriver, id: string, opts: {
|
|
10
|
-
name?: string;
|
|
11
|
-
title?: string;
|
|
12
|
-
}) => SiteRow;
|
|
13
|
-
export declare const deleteSite: (db: DbDriver, id: string) => boolean;
|
|
14
|
-
/** Upload or replace one file. Picks utf8 / base64 / blob storage automatically. */
|
|
4
|
+
/** Upload or replace one file. utf8 text and small binaries ride the oplog via
|
|
5
|
+
* putFileInline (portable); binaries over the inline limit offload to the
|
|
6
|
+
* node-local blob store (server-only — their bytes don't replicate). */
|
|
15
7
|
export declare function putFile(db: DbDriver, siteId: string, path: string, opts: {
|
|
16
8
|
data: string | Uint8Array | ArrayBuffer;
|
|
17
9
|
contentType?: string;
|
|
18
10
|
}): Promise<SiteFileRow>;
|
|
19
|
-
export declare const deleteFile: (db: DbDriver, siteId: string, path: string) => boolean;
|
|
20
11
|
/** Resolve a file to served bytes + content type. "" / trailing "/" → index.html. */
|
|
21
12
|
export declare function getFileForServe(db: DbDriver, siteId: string, path: string): Promise<{
|
|
22
13
|
contentType: string;
|
package/dist/core/sites.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sites.d.ts","sourceRoot":"","sources":["../../src/core/sites.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"sites.d.ts","sourceRoot":"","sources":["../../src/core/sites.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAG5C,OAAO,EACL,KAAK,WAAW,EAUjB,MAAM,iBAAiB,CAAC;AAezB,cAAc,iBAAiB,CAAC;AAEhC;;yEAEyE;AACzE,wBAAsB,OAAO,CAC3B,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,WAAW,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GACtE,OAAO,CAAC,WAAW,CAAC,CAetB;AASD,qFAAqF;AACrF,wBAAsB,eAAe,CACnC,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GAAG,IAAI,CAAC,CAuB5D"}
|
package/dist/core/sync/auth.d.ts
CHANGED
|
@@ -6,6 +6,15 @@ export interface AuthConfig {
|
|
|
6
6
|
ttlMs: number;
|
|
7
7
|
graceMs: number;
|
|
8
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* When a request authenticated via a `?token=` query param and carries no cookie
|
|
11
|
+
* yet, return the `Set-Cookie` to persist it; otherwise null. A `/?token=...`
|
|
12
|
+
* link (QR / "copy login link") authorizes only that one navigation — without
|
|
13
|
+
* this, the browser's follow-up /webui.css, /webui.js etc. carry no credential
|
|
14
|
+
* and 401, serving a broken page. Setting the cookie on the HTML response lets
|
|
15
|
+
* those same-origin sub-requests ride it automatically.
|
|
16
|
+
*/
|
|
17
|
+
export declare function queryTokenCookie(req: Request, url: URL, cfg: AuthConfig): string | null;
|
|
9
18
|
export declare function extractToken(req: Request, url: URL): string | null;
|
|
10
19
|
/** Whether auth is on at all (so the gate runs and the fetch shim is injected). */
|
|
11
20
|
export declare function authActive(cfg: AuthConfig): boolean;
|
|
@@ -40,8 +49,12 @@ export declare function unlockPage(): string;
|
|
|
40
49
|
export declare function injectShim(html: string): string;
|
|
41
50
|
/** Inject the page runtime into HTML responses. Unconditional (unlike the old
|
|
42
51
|
* token-only shim): the offline bridge matters even in --debug mode where
|
|
43
|
-
* auth is off — the token half simply no-ops without a stored token.
|
|
44
|
-
|
|
52
|
+
* auth is off — the token half simply no-ops without a stored token.
|
|
53
|
+
*
|
|
54
|
+
* When `req`/`url` are supplied and the navigation authenticated via a `?token=`
|
|
55
|
+
* query param, persist that token as the mh_token cookie on this HTML response
|
|
56
|
+
* so the browser's follow-up asset requests (/webui.css, /webui.js) carry it. */
|
|
57
|
+
export declare function withShim(res: Response, cfg: AuthConfig, req?: Request, url?: URL): Promise<Response>;
|
|
45
58
|
export declare function unauthorized(): Response;
|
|
46
59
|
export { HTML_HEADERS };
|
|
47
60
|
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/core/sync/auth.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAS3C,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,EAAE,EAAE,QAAQ,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAcD,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,IAAI,CAIlE;AAED,mFAAmF;AACnF,wBAAgB,UAAU,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAEnD;AAED,0EAA0E;AAC1E,wBAAgB,WAAW,CAAC,GAAG,EAAE,UAAU,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAQlF;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAI9E;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,GAAG,OAAO,CAO/F;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,UAAU,GACd;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAUvC;AAED,oFAAoF;AACpF,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAE/C;AAED,QAAA,MAAM,YAAY;;CAAiD,CAAC;AAEpE,sFAAsF;AACtF,wBAAgB,UAAU,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/core/sync/auth.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAS3C,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,EAAE,EAAE,QAAQ,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAcD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAMvF;AAYD,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,IAAI,CAIlE;AAED,mFAAmF;AACnF,wBAAgB,UAAU,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAEnD;AAED,0EAA0E;AAC1E,wBAAgB,WAAW,CAAC,GAAG,EAAE,UAAU,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAQlF;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAI9E;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,GAAG,OAAO,CAO/F;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,UAAU,GACd;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAUvC;AAED,oFAAoF;AACpF,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAE/C;AAED,QAAA,MAAM,YAAY;;CAAiD,CAAC;AAEpE,sFAAsF;AACtF,wBAAgB,UAAU,IAAI,MAAM,CAqDnC;AAYD,mFAAmF;AACnF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED;;;;;;kFAMkF;AAClF,wBAAsB,QAAQ,CAC5B,GAAG,EAAE,QAAQ,EACb,GAAG,EAAE,UAAU,EACf,GAAG,CAAC,EAAE,OAAO,EACb,GAAG,CAAC,EAAE,GAAG,GACR,OAAO,CAAC,QAAQ,CAAC,CAUnB;AAED,wBAAgB,YAAY,IAAI,QAAQ,CAEvC;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Route, type RouteCtx } from "./routes.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Serve `GET /blob/<hash>[.ext]`. Default: resolve on demand (local cache → peers
|
|
4
|
+
* → bucket) so a browser <img> or a far node gets the bytes even if this node
|
|
5
|
+
* hadn't cached them. `?local=1` (used by peer-to-peer resolution) serves only
|
|
6
|
+
* what we already hold, so cross-node fetches can't loop. Content-addressed →
|
|
7
|
+
* immutable cache. Returns null when the path isn't a blob URL (so the caller
|
|
8
|
+
* falls through to the next matcher).
|
|
9
|
+
*/
|
|
10
|
+
export declare function serveBlob(req: Request, ctx: RouteCtx): Promise<Response | null>;
|
|
11
|
+
export declare const blobRoutes: Route[];
|
|
12
|
+
//# sourceMappingURL=blob-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blob-routes.d.ts","sourceRoot":"","sources":["../../../src/core/sync/blob-routes.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,KAAK,KAAK,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAkDvE;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAqBrF;AAgBD,eAAO,MAAM,UAAU,EAAE,KAAK,EAoE7B,CAAC"}
|
|
@@ -2,6 +2,13 @@ import type { DbDriver } from "../driver.ts";
|
|
|
2
2
|
export interface SyncResult {
|
|
3
3
|
pushed: number;
|
|
4
4
|
pulled: number;
|
|
5
|
+
/** Response page size (changes the peer returned this round), independent of
|
|
6
|
+
* how many were new to our oplog. Pagination must break on this, NOT on
|
|
7
|
+
* `pulled`: a page of all-known changes ingests 0 but may not be the last
|
|
8
|
+
* page (e.g. after a cursor reset re-pulls data we already hold). */
|
|
9
|
+
received?: number;
|
|
10
|
+
/** Storage-sync only: local own ops exist but were deferred by push batching. */
|
|
11
|
+
pendingPush?: boolean;
|
|
5
12
|
}
|
|
6
13
|
export interface SyncOpts {
|
|
7
14
|
/** Bearer credential; defaults to the one stored for this peer (pairing). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/core/sync/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAyB7C,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/core/sync/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAyB7C,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf;;;0EAGsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,QAAQ;IACvB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,EAAE,EAAE,QAAQ,EACZ,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,QAAQ,GAAG,MAAW,GAC3B,OAAO,CAAC,UAAU,CAAC,CAqCrB"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** The bucket's keys/main.json: the master key wrapped by the passphrase KEK. */
|
|
2
|
+
export interface KeyEnvelope {
|
|
3
|
+
v: 1;
|
|
4
|
+
kdf: "PBKDF2-SHA256";
|
|
5
|
+
iter: number;
|
|
6
|
+
salt: string;
|
|
7
|
+
wrap: "AES-GCM";
|
|
8
|
+
/** base64(iv ‖ ciphertext) of the raw 32-byte master key. */
|
|
9
|
+
wrapped_key: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function toB64(bytes: Uint8Array): string;
|
|
12
|
+
export declare function fromB64(b64: string): Uint8Array;
|
|
13
|
+
/** A fresh random 256-bit master key (raw bytes). */
|
|
14
|
+
export declare function generateMasterKey(): Uint8Array;
|
|
15
|
+
/** Wrap the master key under a passphrase-derived KEK → bucket keys/main.json. */
|
|
16
|
+
export declare function wrapMasterKey(rawKey: Uint8Array, passphrase: string): Promise<KeyEnvelope>;
|
|
17
|
+
/** Recover the master key from the envelope + passphrase. Throws `auth` on a
|
|
18
|
+
* wrong passphrase (the GCM tag won't verify) or a malformed envelope. */
|
|
19
|
+
export declare function unwrapMasterKey(env: KeyEnvelope, passphrase: string): Promise<Uint8Array>;
|
|
20
|
+
/**
|
|
21
|
+
* Derive a raw 32-byte content key from a share password + salt (same PBKDF2
|
|
22
|
+
* parameters as the bucket KEK). Used by the object-storage share path: the
|
|
23
|
+
* exporter and the in-browser viewer both derive the identical key, so a wrong
|
|
24
|
+
* password simply fails the GCM tag on decrypt — no server-side verifier needed.
|
|
25
|
+
*/
|
|
26
|
+
export declare function deriveShareKey(password: string, salt: Uint8Array): Promise<Uint8Array>;
|
|
27
|
+
/** Encrypt arbitrary bytes (a compressed segment/snapshot) → iv ‖ ciphertext. */
|
|
28
|
+
export declare function encryptBytes(rawKey: Uint8Array, plaintext: Uint8Array): Promise<Uint8Array>;
|
|
29
|
+
/** Inverse of encryptBytes. Throws `auth` if the key is wrong or data tampered. */
|
|
30
|
+
export declare function decryptBytes(rawKey: Uint8Array, payload: Uint8Array): Promise<Uint8Array>;
|
|
31
|
+
//# sourceMappingURL=e2ee.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"e2ee.d.ts","sourceRoot":"","sources":["../../../src/core/sync/e2ee.ts"],"names":[],"mappings":"AAkCA,iFAAiF;AACjF,MAAM,WAAW,WAAW;IAC1B,CAAC,EAAE,CAAC,CAAC;IACL,GAAG,EAAE,eAAe,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;CACrB;AAID,wBAAgB,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAI/C;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAK/C;AAID,qDAAqD;AACrD,wBAAgB,iBAAiB,IAAI,UAAU,CAE9C;AAmBD,kFAAkF;AAClF,wBAAsB,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAkBhG;AAED;2EAC2E;AAC3E,wBAAsB,eAAe,CAAC,GAAG,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAc/F;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAc5F;AAWD,iFAAiF;AACjF,wBAAsB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAUjG;AAED,mFAAmF;AACnF,wBAAsB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAU/F"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** The slim bucket descriptor an enroll token carries. Mirrors the access-only
|
|
2
|
+
* subset of S3Config — no passphrase, no master key, no node-role hints. */
|
|
3
|
+
export interface EnrollPayload {
|
|
4
|
+
endpoint: string;
|
|
5
|
+
region?: string;
|
|
6
|
+
bucket: string;
|
|
7
|
+
prefix?: string;
|
|
8
|
+
accessKeyId: string;
|
|
9
|
+
secretAccessKey: string;
|
|
10
|
+
encrypt?: boolean;
|
|
11
|
+
virtualHostedStyle?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/** Encode the bucket descriptor into a base64url enroll token. Keys are emitted
|
|
14
|
+
* in a fixed order (and undefined fields omitted) so the token is stable. */
|
|
15
|
+
export declare function encodeEnroll(p: EnrollPayload): string;
|
|
16
|
+
/** Decode an enroll token back into a bucket descriptor. Accepts the bare token,
|
|
17
|
+
* an `enroll=<token>` fragment, or a full `…/#enroll=<token>` deep link, so a
|
|
18
|
+
* user can paste whatever they copied. Throws MhError("invalid_input") on a
|
|
19
|
+
* malformed token or a payload missing the fields needed to reach the bucket. */
|
|
20
|
+
export declare function decodeEnroll(tokenOrUrl: string): EnrollPayload;
|
|
21
|
+
//# sourceMappingURL=enroll.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enroll.d.ts","sourceRoot":"","sources":["../../../src/core/sync/enroll.ts"],"names":[],"mappings":"AAaA;6EAC6E;AAC7E,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAmBD;8EAC8E;AAC9E,wBAAgB,YAAY,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM,CAYrD;AAED;;;kFAGkF;AAClF,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,CAoC9D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"peers-routes.d.ts","sourceRoot":"","sources":["../../../src/core/sync/peers-routes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,KAAK,EAAiB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"peers-routes.d.ts","sourceRoot":"","sources":["../../../src/core/sync/peers-routes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,KAAK,EAAiB,MAAM,aAAa,CAAC;AA6KvE,eAAO,MAAM,WAAW,EAAE,KAAK,EA+H9B,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { DbDriver } from "../driver.ts";
|
|
2
|
+
import { type S3Config, type StorageSyncOpts } from "./storage.ts";
|
|
2
3
|
export interface PeerRow {
|
|
3
4
|
url: string;
|
|
4
5
|
pull_cursor: number;
|
|
@@ -7,9 +8,16 @@ export interface PeerRow {
|
|
|
7
8
|
label: string | null;
|
|
8
9
|
node_id: string | null;
|
|
9
10
|
enabled: number;
|
|
11
|
+
/** Last sync attempt, successful or failed. */
|
|
10
12
|
last_sync_at: number | null;
|
|
13
|
+
/** Last successful sync. Freshness gates must use this, not last_sync_at. */
|
|
14
|
+
last_success_at: number | null;
|
|
11
15
|
last_status: string | null;
|
|
12
16
|
last_error: string | null;
|
|
17
|
+
/** Transport: 'http' (POST /sync) or 's3' (bucket store-and-forward). */
|
|
18
|
+
kind: string;
|
|
19
|
+
/** JSON S3Config for 's3' peers; null for 'http'. */
|
|
20
|
+
config: string | null;
|
|
13
21
|
}
|
|
14
22
|
export declare function listPeers(db: DbDriver): PeerRow[];
|
|
15
23
|
export declare function getPeer(db: DbDriver, url: string): PeerRow | null;
|
|
@@ -21,6 +29,46 @@ export interface AddPeerInput {
|
|
|
21
29
|
}
|
|
22
30
|
/** Upsert a peer, preserving replication cursors on conflict. */
|
|
23
31
|
export declare function addPeer(db: DbDriver, input: AddPeerInput): void;
|
|
32
|
+
export interface AddStoragePeerInput {
|
|
33
|
+
/** Synthetic peer key, by convention s3://<bucket>/<prefix>. */
|
|
34
|
+
url: string;
|
|
35
|
+
config: S3Config;
|
|
36
|
+
label?: string | null;
|
|
37
|
+
}
|
|
38
|
+
/** Upsert an 's3' (bucket store-and-forward) peer, preserving cursors on conflict. */
|
|
39
|
+
export declare function addStoragePeer(db: DbDriver, input: AddStoragePeerInput): void;
|
|
40
|
+
export { storageUrl, storageEndpointHost } from "./storage-url.ts";
|
|
41
|
+
export interface StoragePeerSpec {
|
|
42
|
+
endpoint: string;
|
|
43
|
+
region?: string;
|
|
44
|
+
bucket: string;
|
|
45
|
+
prefix?: string;
|
|
46
|
+
accessKeyId: string;
|
|
47
|
+
secretAccessKey: string;
|
|
48
|
+
/** Virtual-hosted (COS) vs path-style addressing; undefined → auto-detect.
|
|
49
|
+
* Carried by enroll codes so COS buckets join correctly. */
|
|
50
|
+
virtualHostedStyle?: boolean;
|
|
51
|
+
/** Default true; pass false for `--no-encrypt` plaintext buckets. */
|
|
52
|
+
encrypt?: boolean;
|
|
53
|
+
/** Required when encrypt — provisions/adopts the bucket's wrapped master key. */
|
|
54
|
+
passphrase?: string;
|
|
55
|
+
/** Mark this node the bucket's publisher (writes whole-hub snapshots). */
|
|
56
|
+
publish?: boolean;
|
|
57
|
+
priority?: number;
|
|
58
|
+
label?: string | null;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Resolve + persist an S3 storage peer and run one sync so a bad endpoint /
|
|
62
|
+
* credentials / missing CORS fail fast at the call site. Shared by the CLI
|
|
63
|
+
* (`mh config peer add --s3`) and the WebUI server endpoint (`POST /api/peer/s3`)
|
|
64
|
+
* so both go through the exact same provisioning + first-sync path. Returns the
|
|
65
|
+
* resolved config (incl. the wrapped master key) and the first sync outcome.
|
|
66
|
+
*/
|
|
67
|
+
export declare function addAndSyncStoragePeer(db: DbDriver, spec: StoragePeerSpec): Promise<{
|
|
68
|
+
url: string;
|
|
69
|
+
config: S3Config;
|
|
70
|
+
sync: PeerSyncOutcome;
|
|
71
|
+
}>;
|
|
24
72
|
/**
|
|
25
73
|
* Remove a peer AND revoke the credential we issued to it during pairing, so
|
|
26
74
|
* disconnecting is mutual: we stop syncing out to it (peers row) and it can no
|
|
@@ -36,10 +84,34 @@ export interface PeerSyncOutcome {
|
|
|
36
84
|
ok: boolean;
|
|
37
85
|
pushed?: number;
|
|
38
86
|
pulled?: number;
|
|
87
|
+
pendingPush?: boolean;
|
|
39
88
|
error?: string;
|
|
40
89
|
}
|
|
41
|
-
/** Sync once with a single peer, recording status. Errors are captured, not
|
|
42
|
-
|
|
90
|
+
/** Sync once with a single peer, recording status. Errors are captured, not
|
|
91
|
+
* thrown. Dispatches on transport: 's3' peers go through the bucket
|
|
92
|
+
* store-and-forward client, everything else POSTs /sync. */
|
|
93
|
+
export declare function syncPeer(db: DbDriver, url: string, opts?: {
|
|
94
|
+
storage?: StorageSyncOpts;
|
|
95
|
+
}): Promise<PeerSyncOutcome>;
|
|
43
96
|
/** Sync once with every enabled peer. Used by the auto-sync timer. */
|
|
44
97
|
export declare function syncAllPeers(db: DbDriver): Promise<PeerSyncOutcome[]>;
|
|
98
|
+
/**
|
|
99
|
+
* Freshness gate for *non-reactive* consumers — CLI reads and the PWA's served
|
|
100
|
+
* site pages (②b). Their local DB is only as fresh as the last sync, and unlike
|
|
101
|
+
* the reactive WebUI they have no background poll and no `synced` revalidate. So
|
|
102
|
+
* if the newest successful peer sync is older than `maxAgeMs`, block on one
|
|
103
|
+
* bounded sync round before the caller reads; otherwise return immediately
|
|
104
|
+
* (read local).
|
|
105
|
+
*
|
|
106
|
+
* No enabled peers → no-op. A running daemon keeps `last_success_at` recent, so
|
|
107
|
+
* this is a near-instant no-op there and only does real work on a daemon-less node
|
|
108
|
+
* that hasn't synced successfully in a while. Failed attempts update
|
|
109
|
+
* `last_sync_at`, but never make local data fresh. Env overrides: MH_OFFLINE=1
|
|
110
|
+
* skips; MH_FRESH=1 forces; MH_SYNC_MAX_AGE=<ms> tunes the threshold.
|
|
111
|
+
*/
|
|
112
|
+
export declare function ensureFresh(db: DbDriver, opts?: {
|
|
113
|
+
maxAgeMs?: number;
|
|
114
|
+
force?: boolean;
|
|
115
|
+
offline?: boolean;
|
|
116
|
+
}): Promise<void>;
|
|
45
117
|
//# sourceMappingURL=peers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"peers.d.ts","sourceRoot":"","sources":["../../../src/core/sync/peers.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"peers.d.ts","sourceRoot":"","sources":["../../../src/core/sync/peers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { StorageClient } from "./storage.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Refresh this node's heartbeat (throttled) and return whether it is the elected
|
|
4
|
+
* publisher among currently-live candidates. Call only when a snapshot is
|
|
5
|
+
* actually due, so the lease LIST/GETs aren't paid on idle rounds.
|
|
6
|
+
*/
|
|
7
|
+
export declare function isElectedPublisher(client: StorageClient, base: string, node: string, priority: number, now?: number): Promise<boolean>;
|
|
8
|
+
//# sourceMappingURL=publisher-lease.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publisher-lease.d.ts","sourceRoot":"","sources":["../../../src/core/sync/publisher-lease.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAmBlD;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,GAAG,GAAE,MAAmB,GACvB,OAAO,CAAC,OAAO,CAAC,CAgDlB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/core/sync/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AACnC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/core/sync/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AACnC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAe3C,yEAAyE;AACzE,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,QAAQ,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAeD;;8BAE8B;AAC9B,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,QAAQ,CAMlD;AAED;;;;GAIG;AACH,MAAM,WAAW,KAAK;IACpB,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC;CACxE;AAiCD,eAAO,MAAM,MAAM,EAAE,KAAK,EAAmE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/core/sync/server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/core/sync/server.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAIvC,OAAO,EAAU,KAAK,KAAK,EAAiB,MAAM,aAAa,CAAC;AAmBhE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,UAAU,CAAC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,qFAAqF;IACrF,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,wFAAwF;IACxF,QAAQ,EAAE,SAAS,GAAG,QAAQ,GAAG,UAAU,CAAC;IAC5C,oEAAoE;IACpE,GAAG,EAAE,OAAO,CAAC;IACb,8CAA8C;IAC9C,QAAQ,EAAE,OAAO,CAAC;IAClB,qEAAqE;IACrE,cAAc,EAAE,MAAM,CAAC;IACvB,+CAA+C;IAC/C,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,6EAA6E;AAC7E,qBAAa,cAAe,SAAQ,OAAO;IAEvC,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM;gBADZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM;CASxB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oFAAoF;IACpF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;kDAE8C;IAC9C,EAAE,CAAC,EAAE,SAAS,CAAC;IACf;;;mEAG+D;IAC/D,GAAG,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C;AAED,oEAAoE;AACpE,MAAM,WAAW,SAAS;IACxB,8EAA8E;IAC9E,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IACpD,4EAA4E;IAC5E,MAAM,EAAE,KAAK,EAAE,CAAC;CACjB;AAYD,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,IAAI,GAAE,aAAkB,GAAG,aAAa,CAqPnE"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { DbDriver } from "../driver.ts";
|
|
2
|
+
import { type ShareKind, type SharePermission } from "../shares.ts";
|
|
3
|
+
export interface CreateShareRequest {
|
|
4
|
+
kind: ShareKind;
|
|
5
|
+
ref: string;
|
|
6
|
+
permission?: SharePermission;
|
|
7
|
+
transport?: "server" | "s3";
|
|
8
|
+
password?: string | null;
|
|
9
|
+
/** Server: any duration (ms); null = never. s3: clamped to ≤7d; default 7d. */
|
|
10
|
+
expiresMs?: number | null;
|
|
11
|
+
/** server transport target: a paired peer url → create remotely on that peer;
|
|
12
|
+
* any other base url (this node's origin / LAN / domain) → create locally and
|
|
13
|
+
* record it as served_base; undefined → local with no recorded base. */
|
|
14
|
+
server?: string | null;
|
|
15
|
+
/** s3: which bucket peer url; default the single s3 peer if exactly one. */
|
|
16
|
+
bucketUrl?: string | null;
|
|
17
|
+
/** s3 only: the static viewer base for the link. */
|
|
18
|
+
viewerBase?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface CreatedShare {
|
|
21
|
+
slug: string;
|
|
22
|
+
kind: ShareKind;
|
|
23
|
+
permission: SharePermission;
|
|
24
|
+
transport: "server" | "s3";
|
|
25
|
+
/** Full link to copy (server: served_base/share/slug; s3: viewer link). */
|
|
26
|
+
url: string;
|
|
27
|
+
expiresAt: number | null;
|
|
28
|
+
/** Human label of where it's served: a server address or a bucket name. */
|
|
29
|
+
source: string;
|
|
30
|
+
}
|
|
31
|
+
/** A row in the aggregated share listing (CLI `list` / WebUI panel). */
|
|
32
|
+
export interface ShareListItem {
|
|
33
|
+
slug: string;
|
|
34
|
+
kind: string;
|
|
35
|
+
target_id: string;
|
|
36
|
+
/** Human title of the shared object (for the management list). */
|
|
37
|
+
title: string;
|
|
38
|
+
permission: string;
|
|
39
|
+
transport: "server" | "s3";
|
|
40
|
+
source: string;
|
|
41
|
+
sourceKind: "server" | "peer" | "bucket";
|
|
42
|
+
expiresAt: number | null;
|
|
43
|
+
hasPassword: boolean;
|
|
44
|
+
/** server: ready-to-copy link; s3: omitted (use renew to mint a fresh one). */
|
|
45
|
+
url?: string;
|
|
46
|
+
}
|
|
47
|
+
/** s3 bucket peers (no secrets) for a transport picker. */
|
|
48
|
+
export declare function listShareBuckets(db: DbDriver): {
|
|
49
|
+
url: string;
|
|
50
|
+
label: string;
|
|
51
|
+
}[];
|
|
52
|
+
/** Paired HTTP peer servers (a share can be created on / served by them). */
|
|
53
|
+
export declare function listShareServers(db: DbDriver): {
|
|
54
|
+
url: string;
|
|
55
|
+
label: string;
|
|
56
|
+
}[];
|
|
57
|
+
/** Resolve, validate, and create (server local / server remote / s3 bucket) a share. */
|
|
58
|
+
export declare function createShareAction(db: DbDriver, req: CreateShareRequest): Promise<CreatedShare>;
|
|
59
|
+
/** Local listing (server rows + each attached bucket) — NO peer fan-out (so the
|
|
60
|
+
* /api/shares endpoint a peer calls can't recurse). Optional target filter. */
|
|
61
|
+
export declare function listSharesLocal(db: DbDriver, targetId?: string): Promise<ShareListItem[]>;
|
|
62
|
+
/** Aggregated listing for CLI/WebUI: local ∪ each paired peer's /api/shares
|
|
63
|
+
* (best-effort, bounded), deduped by slug. Optional target filter. */
|
|
64
|
+
export declare function listSharesAggregated(db: DbDriver, targetId?: string): Promise<ShareListItem[]>;
|
|
65
|
+
/** Revoke: local server row → delete it; else a bucket holds it → delete objects. */
|
|
66
|
+
export declare function revokeShareAction(db: DbDriver, slug: string): Promise<boolean>;
|
|
67
|
+
/** Renew an s3 share (re-presign, mint a fresh ≤7d link). */
|
|
68
|
+
export declare function renewShareAction(db: DbDriver, slug: string, viewerBaseOverride?: string): Promise<CreatedShare>;
|
|
69
|
+
//# sourceMappingURL=share-actions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"share-actions.d.ts","sourceRoot":"","sources":["../../../src/core/sync/share-actions.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAQ7C,OAAO,EAOL,KAAK,SAAS,EACd,KAAK,eAAe,EACrB,MAAM,cAAc,CAAC;AActB,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,SAAS,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,SAAS,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,+EAA+E;IAC/E,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;6EAEyE;IACzE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,EAAE,eAAe,CAAC;IAC5B,SAAS,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3B,2EAA2E;IAC3E,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wEAAwE;AACxE,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;IACzC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;IACrB,+EAA+E;IAC/E,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAiCD,2DAA2D;AAC3D,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAI/E;AAED,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAI/E;AAiCD,wFAAwF;AACxF,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,kBAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CA0FpG;AAED;gFACgF;AAChF,wBAAsB,eAAe,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAsC/F;AAED;uEACuE;AACvE,wBAAsB,oBAAoB,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAepG;AAYD,qFAAqF;AACrF,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAWpF;AAED,6DAA6D;AAC7D,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,kBAAkB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAmBrH"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { DbDriver } from "../driver.ts";
|
|
2
|
+
import { type S3Config } from "./storage.ts";
|
|
3
|
+
export interface ShareManifest {
|
|
4
|
+
v: 1;
|
|
5
|
+
kind: "doc" | "database";
|
|
6
|
+
title: string;
|
|
7
|
+
body?: string;
|
|
8
|
+
properties?: {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
type: string;
|
|
12
|
+
}[];
|
|
13
|
+
records?: {
|
|
14
|
+
cells: Record<string, unknown>;
|
|
15
|
+
}[];
|
|
16
|
+
/** hash → { presigned GET of the (encrypted) blob, original content-type }. */
|
|
17
|
+
blobs?: Record<string, {
|
|
18
|
+
url: string;
|
|
19
|
+
ct: string;
|
|
20
|
+
}>;
|
|
21
|
+
}
|
|
22
|
+
/** Bucket-resident share descriptor (master-key encrypted). The listable source
|
|
23
|
+
* of truth for an object-storage share. */
|
|
24
|
+
export interface BucketShareMeta {
|
|
25
|
+
v: 1;
|
|
26
|
+
slug: string;
|
|
27
|
+
kind: "doc" | "database";
|
|
28
|
+
target_id: string;
|
|
29
|
+
title: string;
|
|
30
|
+
permission: "view";
|
|
31
|
+
created_at: number;
|
|
32
|
+
/** epoch ms the presigned URLs expire (≤ 7 days out). */
|
|
33
|
+
presign_exp: number;
|
|
34
|
+
has_password: boolean;
|
|
35
|
+
/** every object key this share owns (manifest + each blob) — for renew + delete. */
|
|
36
|
+
objects: string[];
|
|
37
|
+
/** base64 per-share content key (lets a bucket-holder renew / re-copy the link). */
|
|
38
|
+
key: string;
|
|
39
|
+
/** base64 salt (password shares); the link carries this, viewer derives the key. */
|
|
40
|
+
salt?: string;
|
|
41
|
+
}
|
|
42
|
+
export interface BucketShareLink {
|
|
43
|
+
manifestUrl: string;
|
|
44
|
+
presignExp: number;
|
|
45
|
+
/** base64 random key (no-password) — goes in the link fragment as #k=. */
|
|
46
|
+
keyB64?: string;
|
|
47
|
+
/** base64 salt (password) — goes in the link fragment as #s=. */
|
|
48
|
+
saltB64?: string;
|
|
49
|
+
title: string;
|
|
50
|
+
}
|
|
51
|
+
/** Create an object-storage share: write manifest+blobs (per-share-key encrypted)
|
|
52
|
+
* then meta.json (master-key encrypted, written LAST so a half-built share is
|
|
53
|
+
* never listed), and allow the viewer origin in the bucket's CORS. */
|
|
54
|
+
export declare function createBucketShare(db: DbDriver, opts: {
|
|
55
|
+
slug: string;
|
|
56
|
+
kind: "doc" | "database";
|
|
57
|
+
targetId: string;
|
|
58
|
+
config: S3Config;
|
|
59
|
+
password?: string | null;
|
|
60
|
+
expiresSec: number;
|
|
61
|
+
viewerOrigin?: string;
|
|
62
|
+
}): Promise<BucketShareLink>;
|
|
63
|
+
/** Renew an object-storage share: re-read the (live) source, re-encrypt with the
|
|
64
|
+
* stored per-share key, re-upload + re-presign, refresh meta.json. Works for
|
|
65
|
+
* password shares too (the key is stored master-encrypted). */
|
|
66
|
+
export declare function renewBucketShare(db: DbDriver, config: S3Config, slug: string, expiresSec?: number): Promise<BucketShareLink>;
|
|
67
|
+
/** List all object-storage shares in a bucket (decrypts each meta.json). */
|
|
68
|
+
export declare function listBucketShares(config: S3Config): Promise<BucketShareMeta[]>;
|
|
69
|
+
/** Delete a bucket share's objects. meta.json is deleted FIRST so the share
|
|
70
|
+
* immediately disappears from listings even if the rest is slow. */
|
|
71
|
+
export declare function deleteBucketShareObjects(config: S3Config, slug: string): Promise<void>;
|
|
72
|
+
//# sourceMappingURL=share-export.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"share-export.d.ts","sourceRoot":"","sources":["../../../src/core/sync/share-export.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAO7C,OAAO,EAAoB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAW/D,MAAM,WAAW,aAAa;IAC5B,CAAC,EAAE,CAAC,CAAC;IACL,IAAI,EAAE,KAAK,GAAG,UAAU,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC1D,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,EAAE,CAAC;IAC/C,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrD;AAED;4CAC4C;AAC5C,MAAM,WAAW,eAAe;IAC9B,CAAC,EAAE,CAAC,CAAC;IACL,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,KAAK,GAAG,UAAU,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,oFAAoF;IACpF,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,oFAAoF;IACpF,GAAG,EAAE,MAAM,CAAC;IACZ,oFAAoF;IACpF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAyGD;;uEAEuE;AACvE,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,QAAQ,EACZ,IAAI,EAAE;IACJ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,KAAK,GAAG,UAAU,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,QAAQ,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GACA,OAAO,CAAC,eAAe,CAAC,CA0C1B;AAED;;gEAEgE;AAChE,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,QAAQ,EAChB,IAAI,EAAE,MAAM,EACZ,UAAU,SAAsB,GAC/B,OAAO,CAAC,eAAe,CAAC,CAmB1B;AAED,4EAA4E;AAC5E,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAanF;AAED;qEACqE;AACrE,wBAAsB,wBAAwB,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAO5F"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare function escapeHtml(s: string): string;
|
|
2
|
+
export interface RenderOpts {
|
|
3
|
+
/** Rewrite a `/blob/<hash>` URL to a reachable one (scoped endpoint or data URL). */
|
|
4
|
+
rewriteBlob?: (url: string) => string;
|
|
5
|
+
}
|
|
6
|
+
/** Inline Markdown → HTML: `code`, **bold**, *italic*, [link](url), . */
|
|
7
|
+
export declare function renderInline(src: string, opts?: RenderOpts): string;
|
|
8
|
+
/** Render a markdown body to an HTML string (block-level). */
|
|
9
|
+
export declare function renderMarkdown(md: string, opts?: RenderOpts): string;
|
|
10
|
+
//# sourceMappingURL=share-render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"share-render.d.ts","sourceRoot":"","sources":["../../../src/core/sync/share-render.ts"],"names":[],"mappings":"AASA,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAM5C;AAED,MAAM,WAAW,UAAU;IACzB,qFAAqF;IACrF,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;CACvC;AAOD,oFAAoF;AACpF,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,UAAe,GAAG,MAAM,CAmBvE;AASD,8DAA8D;AAC9D,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,GAAE,UAAe,GAAG,MAAM,CAkIxE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"share-serve.d.ts","sourceRoot":"","sources":["../../../src/core/sync/share-serve.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAmC5C,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAkCtF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sites-serve.d.ts","sourceRoot":"","sources":["../../../src/core/sync/sites-serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAQ5C,wBAAsB,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"sites-serve.d.ts","sourceRoot":"","sources":["../../../src/core/sync/sites-serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAQ5C,wBAAsB,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAyBrF"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type S3Config } from "./storage.ts";
|
|
2
|
+
/** SigV4 presigned GET cap: 7 days (604800s) is the protocol maximum. */
|
|
3
|
+
export declare const MAX_PRESIGN_SECONDS = 604800;
|
|
4
|
+
/**
|
|
5
|
+
* Build a presigned GET URL for one object (used by the object-storage share
|
|
6
|
+
* path — the recipient fetches the ciphertext directly from the bucket, no
|
|
7
|
+
* credential in the link). Addressing mirrors corsEndpoint (virtual-hosted vs
|
|
8
|
+
* path-style). `expiresSec` is clamped to the 7-day SigV4 maximum.
|
|
9
|
+
*/
|
|
10
|
+
export declare function presignGet(config: S3Config, key: string, expiresSec: number): Promise<string>;
|
|
11
|
+
/** Read the bucket's current CORS config (raw XML), or null if none is set. */
|
|
12
|
+
export declare function getBucketCors(config: S3Config): Promise<string | null>;
|
|
13
|
+
/**
|
|
14
|
+
* Build the PutBucketCors XML body from the bucket's current config. PutBucketCors
|
|
15
|
+
* replaces the whole config, so we keep every rule that isn't ours and re-emit our
|
|
16
|
+
* managed rule (id=metahub-pwa). `merge` decides our rule's origins:
|
|
17
|
+
* - false (CLI `peer cors`): SET — exactly `origins` (lets the user shrink/reset).
|
|
18
|
+
* - true (auto-open on bucket-attach): UNION with the managed rule's existing
|
|
19
|
+
* origins, so attaching the same bucket from a second shell/origin (a homelab
|
|
20
|
+
* server origin alongside the official PWA shell) adds to the allow-list
|
|
21
|
+
* instead of clobbering it.
|
|
22
|
+
* A wildcard `*` collapses the set. Pure (no I/O) so it's unit-testable.
|
|
23
|
+
*/
|
|
24
|
+
export declare function buildCorsXml(existing: string | null, origins: string[], merge: boolean): string;
|
|
25
|
+
/**
|
|
26
|
+
* Allow a browser shell served from `origins` to talk to the bucket directly
|
|
27
|
+
* (GET/PUT/HEAD/DELETE) via GET-merge-PUT (see buildCorsXml). `opts.merge` unions
|
|
28
|
+
* with existing managed origins instead of replacing them — used when a second
|
|
29
|
+
* origin attaches the same bucket. Content-MD5 is required by the CORS API
|
|
30
|
+
* (S3 and COS both).
|
|
31
|
+
*/
|
|
32
|
+
export declare function putBucketCors(config: S3Config, origins: string[], opts?: {
|
|
33
|
+
merge?: boolean;
|
|
34
|
+
}): Promise<void>;
|
|
35
|
+
//# sourceMappingURL=storage-s3-bun.d.ts.map
|