@tensorix/metahub 0.1.10 → 0.2.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.
Files changed (95) hide show
  1. package/README.md +19 -6
  2. package/README.zh-CN.md +7 -2
  3. package/dist/cli.js +22843 -18308
  4. package/dist/cli.js.map +87 -66
  5. package/dist/core/blobs-core.d.ts +106 -0
  6. package/dist/core/blobs-core.d.ts.map +1 -0
  7. package/dist/core/blobs.d.ts +100 -0
  8. package/dist/core/blobs.d.ts.map +1 -0
  9. package/dist/core/cache.d.ts +18 -1
  10. package/dist/core/cache.d.ts.map +1 -1
  11. package/dist/core/compact.d.ts +43 -0
  12. package/dist/core/compact.d.ts.map +1 -0
  13. package/dist/core/config.d.ts +6 -3
  14. package/dist/core/config.d.ts.map +1 -1
  15. package/dist/core/context.d.ts +4 -4
  16. package/dist/core/context.d.ts.map +1 -1
  17. package/dist/core/crdt.d.ts +54 -8
  18. package/dist/core/crdt.d.ts.map +1 -1
  19. package/dist/core/databases.d.ts +22 -8
  20. package/dist/core/databases.d.ts.map +1 -1
  21. package/dist/core/db.d.ts +1 -27
  22. package/dist/core/db.d.ts.map +1 -1
  23. package/dist/core/documents.d.ts +28 -15
  24. package/dist/core/documents.d.ts.map +1 -1
  25. package/dist/core/driver.d.ts +25 -0
  26. package/dist/core/driver.d.ts.map +1 -0
  27. package/dist/core/history.d.ts +99 -11
  28. package/dist/core/history.d.ts.map +1 -1
  29. package/dist/core/hlc.d.ts +3 -3
  30. package/dist/core/hlc.d.ts.map +1 -1
  31. package/dist/core/index.d.ts +1 -0
  32. package/dist/core/index.d.ts.map +1 -1
  33. package/dist/core/indexing.d.ts +4 -4
  34. package/dist/core/indexing.d.ts.map +1 -1
  35. package/dist/core/integrity.d.ts +1 -1
  36. package/dist/core/integrity.d.ts.map +1 -1
  37. package/dist/core/node.d.ts +2 -2
  38. package/dist/core/node.d.ts.map +1 -1
  39. package/dist/core/properties.d.ts +10 -9
  40. package/dist/core/properties.d.ts.map +1 -1
  41. package/dist/core/records.d.ts +13 -8
  42. package/dist/core/records.d.ts.map +1 -1
  43. package/dist/core/resolve.d.ts +4 -4
  44. package/dist/core/resolve.d.ts.map +1 -1
  45. package/dist/core/schema-init.d.ts +68 -0
  46. package/dist/core/schema-init.d.ts.map +1 -0
  47. package/dist/core/schema.d.ts +1 -1
  48. package/dist/core/schema.d.ts.map +1 -1
  49. package/dist/core/search.d.ts +3 -3
  50. package/dist/core/search.d.ts.map +1 -1
  51. package/dist/core/sites-core.d.ts +95 -0
  52. package/dist/core/sites-core.d.ts.map +1 -0
  53. package/dist/core/sites.d.ts +8 -58
  54. package/dist/core/sites.d.ts.map +1 -1
  55. package/dist/core/sqlcols.d.ts +4 -0
  56. package/dist/core/sqlcols.d.ts.map +1 -0
  57. package/dist/core/sync/auth.d.ts +5 -3
  58. package/dist/core/sync/auth.d.ts.map +1 -1
  59. package/dist/core/sync/blob-routes.d.ts +12 -0
  60. package/dist/core/sync/blob-routes.d.ts.map +1 -0
  61. package/dist/core/sync/client.d.ts +13 -3
  62. package/dist/core/sync/client.d.ts.map +1 -1
  63. package/dist/core/sync/e2ee.d.ts +24 -0
  64. package/dist/core/sync/e2ee.d.ts.map +1 -0
  65. package/dist/core/sync/enroll.d.ts +21 -0
  66. package/dist/core/sync/enroll.d.ts.map +1 -0
  67. package/dist/core/sync/peers-routes.d.ts.map +1 -1
  68. package/dist/core/sync/peers.d.ts +84 -11
  69. package/dist/core/sync/peers.d.ts.map +1 -1
  70. package/dist/core/sync/protocol.d.ts +5 -0
  71. package/dist/core/sync/protocol.d.ts.map +1 -1
  72. package/dist/core/sync/publisher-lease.d.ts +8 -0
  73. package/dist/core/sync/publisher-lease.d.ts.map +1 -0
  74. package/dist/core/sync/routes.d.ts.map +1 -1
  75. package/dist/core/sync/server.d.ts +11 -0
  76. package/dist/core/sync/server.d.ts.map +1 -1
  77. package/dist/core/sync/sites-serve.d.ts.map +1 -1
  78. package/dist/core/sync/storage-s3-bun.d.ts +26 -0
  79. package/dist/core/sync/storage-s3-bun.d.ts.map +1 -0
  80. package/dist/core/sync/storage.d.ts +170 -0
  81. package/dist/core/sync/storage.d.ts.map +1 -0
  82. package/dist/db-worker.js +384 -0
  83. package/dist/index.js +17250 -13920
  84. package/dist/index.js.map +47 -32
  85. package/dist/metahub-sdk.js +1 -0
  86. package/dist/mh-runtime.js +1 -0
  87. package/dist/sqlite3.wasm +0 -0
  88. package/dist/sw.js +1 -0
  89. package/dist/webui/server/assets.d.ts +8 -1
  90. package/dist/webui/server/assets.d.ts.map +1 -1
  91. package/dist/webui/server/icons.d.ts +4 -0
  92. package/dist/webui/server/icons.d.ts.map +1 -0
  93. package/dist/webui/server/routes.d.ts.map +1 -1
  94. package/dist/webui.js +68 -62
  95. package/package.json +6 -1
@@ -0,0 +1,95 @@
1
+ import type { DbDriver } from "./driver.ts";
2
+ export interface SiteRow {
3
+ id: string;
4
+ name: string;
5
+ title: string | null;
6
+ created_hlc: string;
7
+ }
8
+ export declare const SITE_COLS: readonly ["id", "name", "title", "created_hlc"];
9
+ export type FileEncoding = "utf8" | "base64" | "blob";
10
+ export interface SiteFileRow {
11
+ id: string;
12
+ site_id: string;
13
+ path: string;
14
+ content_type: string;
15
+ encoding: FileEncoding;
16
+ /** Inline text/base64, or a blob hash when encoding === "blob". */
17
+ content: string | null;
18
+ }
19
+ /** Manifest entry — file metadata without the (potentially large) content. */
20
+ export type SiteFileSummary = Omit<SiteFileRow, "content">;
21
+ export declare const SITE_FILE_COLS: readonly ["id", "site_id", "path", "content_type", "encoding", "content"];
22
+ export declare const SITE_FILE_SELECT: string;
23
+ /** Guess a content type from a file path's extension; default octet-stream. */
24
+ export declare function inferContentType(path: string): string;
25
+ /**
26
+ * Canonical site slug: lowercase, [a-z0-9-] only, no leading/trailing/repeated
27
+ * dashes. Applied at every write and lookup so the served URL (/sites/<name>/),
28
+ * duplicate detection, and sync replication all agree on one form regardless of
29
+ * how the name was typed (CLI, API, or browser). Throws when nothing usable
30
+ * remains (empty, or all-punctuation). Matches the WebUI's slugify exactly.
31
+ */
32
+ export declare function normalizeSiteName(raw: string): string;
33
+ /**
34
+ * Canonical in-site file path: drop empty / "." segments, resolve ".." within
35
+ * the bucket, strip leading and duplicate slashes. Files live in SQLite keyed by
36
+ * this exact string (there is no filesystem behind them), so normalizing at the
37
+ * write/serve boundary keeps storage, URL routing, and deletes consistent no
38
+ * matter how the path was typed or percent-encoded. May return "" (caller decides).
39
+ */
40
+ export declare function normalizeSitePath(raw: string): string;
41
+ export declare function getSite(db: DbDriver, id: string): SiteRow | null;
42
+ /** Most recently created live site with this name (URL routing). */
43
+ export declare function getSiteByName(db: DbDriver, name: string): SiteRow | null;
44
+ export declare function listSites(db: DbDriver): SiteRow[];
45
+ /** Resolve a site ref (`site_…` id or name) to its row, or throw. */
46
+ export declare function resolveSite(db: DbDriver, ref: string): SiteRow;
47
+ /**
48
+ * Portable half of file serving: canonical path resolution ("" / trailing "/"
49
+ * → index.html, same normalization putFile stored under) + the raw row. Used
50
+ * directly by the browser replica's worker, which must decode utf8/base64
51
+ * itself and cannot reach "blob" content at all (blob bytes live in the
52
+ * server's on-disk store, not the oplog — they don't replicate).
53
+ */
54
+ export declare function getFileRow(db: DbDriver, siteId: string, path: string): {
55
+ content_type: string;
56
+ encoding: FileEncoding;
57
+ content: string | null;
58
+ } | null;
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;
95
+ //# sourceMappingURL=sites-core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sites-core.d.ts","sourceRoot":"","sources":["../../src/core/sites-core.ts"],"names":[],"mappings":"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"}
@@ -1,65 +1,15 @@
1
- import type { Database } from "bun:sqlite";
2
- export interface SiteRow {
3
- id: string;
4
- name: string;
5
- title: string | null;
6
- created_hlc: string;
7
- }
8
- export type FileEncoding = "utf8" | "base64" | "blob";
9
- export interface SiteFileRow {
10
- id: string;
11
- site_id: string;
12
- path: string;
13
- content_type: string;
14
- encoding: FileEncoding;
15
- /** Inline text/base64, or a blob hash when encoding === "blob". */
16
- content: string | null;
17
- }
18
- /** Manifest entry — file metadata without the (potentially large) content. */
19
- export type SiteFileSummary = Omit<SiteFileRow, "content">;
20
- /** Guess a content type from a file path's extension; default octet-stream. */
21
- export declare function inferContentType(path: string): string;
22
- /**
23
- * Canonical site slug: lowercase, [a-z0-9-] only, no leading/trailing/repeated
24
- * dashes. Applied at every write and lookup so the served URL (/sites/<name>/),
25
- * duplicate detection, and sync replication all agree on one form regardless of
26
- * how the name was typed (CLI, API, or browser). Throws when nothing usable
27
- * remains (empty, or all-punctuation). Matches the WebUI's slugify exactly.
28
- */
29
- export declare function normalizeSiteName(raw: string): string;
30
- /**
31
- * Canonical in-site file path: drop empty / "." segments, resolve ".." within
32
- * the bucket, strip leading and duplicate slashes. Files live in SQLite keyed by
33
- * this exact string (there is no filesystem behind them), so normalizing at the
34
- * write/serve boundary keeps storage, URL routing, and deletes consistent no
35
- * matter how the path was typed or percent-encoded. May return "" (caller decides).
36
- */
37
- export declare function normalizeSitePath(raw: string): string;
38
- export declare function createSite(db: Database, opts: {
39
- name: string;
40
- title?: string;
41
- }): SiteRow;
42
- export declare function getSite(db: Database, id: string): SiteRow | null;
43
- /** Most recently created live site with this name (URL routing). */
44
- export declare function getSiteByName(db: Database, name: string): SiteRow | null;
45
- export declare function listSites(db: Database): SiteRow[];
46
- /** Resolve a site ref (`site_…` id or name) to its row, or throw. */
47
- export declare function resolveSite(db: Database, ref: string): SiteRow;
48
- /** Rename a site and/or change its title. Guards against duplicate names. */
49
- export declare function updateSite(db: Database, id: string, opts: {
50
- name?: string;
51
- title?: string;
52
- }): SiteRow;
53
- export declare function deleteSite(db: Database, id: string): boolean;
54
- /** Upload or replace one file. Picks utf8 / base64 / blob storage automatically. */
55
- export declare function putFile(db: Database, siteId: string, path: string, opts: {
1
+ import type { DbDriver } from "./driver.ts";
2
+ import { type SiteFileRow } from "./sites-core.ts";
3
+ export * from "./sites-core.ts";
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). */
7
+ export declare function putFile(db: DbDriver, siteId: string, path: string, opts: {
56
8
  data: string | Uint8Array | ArrayBuffer;
57
9
  contentType?: string;
58
10
  }): Promise<SiteFileRow>;
59
- export declare function listFiles(db: Database, siteId: string): SiteFileSummary[];
60
- export declare function deleteFile(db: Database, siteId: string, path: string): boolean;
61
11
  /** Resolve a file to served bytes + content type. "" / trailing "/" → index.html. */
62
- export declare function getFileForServe(db: Database, siteId: string, path: string): Promise<{
12
+ export declare function getFileForServe(db: DbDriver, siteId: string, path: string): Promise<{
63
13
  contentType: string;
64
14
  bytes: Uint8Array;
65
15
  } | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"sites.d.ts","sourceRoot":"","sources":["../../src/core/sites.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAY3C,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEtD,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,YAAY,CAAC;IACvB,mEAAmE;IACnE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,8EAA8E;AAC9E,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;AAkC3D,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGrD;AAID;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAQrD;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAQrD;AAuBD,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAQxF;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAIhE;AAED,oEAAoE;AACpE,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAcxE;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,EAAE,CAIjD;AAED,qEAAqE;AACrE,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAK9D;AAED,6EAA6E;AAC7E,wBAAgB,UAAU,CACxB,EAAE,EAAE,QAAQ,EACZ,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACtC,OAAO,CAUT;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAQ5D;AAYD,oFAAoF;AACpF,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,CAoCtB;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,eAAe,EAAE,CAMzE;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAS9E;AAED,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,CAsB5D"}
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;AAczB,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;AAED,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,CAe5D"}
@@ -0,0 +1,4 @@
1
+ export type ColumnsOf<Row, L extends readonly (keyof Row & string)[]> = [
2
+ Exclude<keyof Row, L[number]>
3
+ ] extends [never] ? readonly (keyof Row & string)[] : ["missing column:", Exclude<keyof Row, L[number]>];
4
+ //# sourceMappingURL=sqlcols.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlcols.d.ts","sourceRoot":"","sources":["../../src/core/sqlcols.ts"],"names":[],"mappings":"AAgBA,MAAM,MAAM,SAAS,CAAC,GAAG,EAAE,CAAC,SAAS,SAAS,CAAC,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,IAClE;IAAC,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;CAAC,SAAS,CAAC,KAAK,CAAC,GAC3C,SAAS,CAAC,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,GAC/B,CAAC,iBAAiB,EAAE,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC"}
@@ -36,10 +36,12 @@ declare const HTML_HEADERS: {
36
36
  };
37
37
  /** Self-contained password prompt: stores token to localStorage + cookie, reloads. */
38
38
  export declare function unlockPage(): string;
39
- /** Insert the fetch shim into an HTML document (right after <head>, else prepend). */
39
+ /** Insert the runtime into an HTML document (right after <head>, else prepend). */
40
40
  export declare function injectShim(html: string): string;
41
- /** For HTML responses when auth is active, inject the shim; otherwise pass through. */
42
- export declare function withShim(res: Response, cfg: AuthConfig): Promise<Response>;
41
+ /** Inject the page runtime into HTML responses. Unconditional (unlike the old
42
+ * 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
+ export declare function withShim(res: Response, _cfg: AuthConfig): Promise<Response>;
43
45
  export declare function unauthorized(): Response;
44
46
  export { HTML_HEADERS };
45
47
  //# 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,CAoDnC;AA2CD,sFAAsF;AACtF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED,uFAAuF;AACvF,wBAAsB,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAOhF;AAED,wBAAgB,YAAY,IAAI,QAAQ,CAEvC;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
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,CAoDnC;AAYD,mFAAmF;AACnF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED;;yEAEyE;AACzE,wBAAsB,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAMjF;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;AAyBvE;;;;;;;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,EAkD7B,CAAC"}
@@ -1,13 +1,23 @@
1
- import type { Database } from "bun:sqlite";
1
+ import type { DbDriver } from "../driver.ts";
2
2
  export interface SyncResult {
3
3
  pushed: number;
4
4
  pulled: number;
5
+ /** Storage-sync only: local own ops exist but were deferred by push batching. */
6
+ pendingPush?: boolean;
7
+ }
8
+ export interface SyncOpts {
9
+ /** Bearer credential; defaults to the one stored for this peer (pairing). */
10
+ token?: string;
11
+ /** Max changes to pull this round — chunked initial hydration. */
12
+ pullLimit?: number;
13
+ /** Datasets this replica opts out of (partial replica, e.g. site_files). */
14
+ excludeDatasets?: string[];
5
15
  }
6
16
  /**
7
17
  * Run one push/pull round against a peer server. A single round is bidirectional
8
- * (pushes local changes, pulls remote ones). `token` defaults to the credential
18
+ * (pushes local changes, pulls remote ones). The token defaults to the credential
9
19
  * stored for this peer (set during pairing) and is sent as a Bearer header so a
10
20
  * token-gated /sync accepts the request.
11
21
  */
12
- export declare function syncWithPeer(db: Database, url: string, token?: string): Promise<SyncResult>;
22
+ export declare function syncWithPeer(db: DbDriver, url: string, opts?: SyncOpts | string): Promise<SyncResult>;
13
23
  //# sourceMappingURL=client.d.ts.map
@@ -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,YAAY,CAAC;AAyB3C,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,EAAE,EAAE,QAAQ,EACZ,GAAG,EAAE,MAAM,EACX,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,CAAC,CAyBrB"}
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,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,CAmCrB"}
@@ -0,0 +1,24 @@
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
+ /** Encrypt arbitrary bytes (a compressed segment/snapshot) → iv ‖ ciphertext. */
21
+ export declare function encryptBytes(rawKey: Uint8Array, plaintext: Uint8Array): Promise<Uint8Array>;
22
+ /** Inverse of encryptBytes. Throws `auth` if the key is wrong or data tampered. */
23
+ export declare function decryptBytes(rawKey: Uint8Array, payload: Uint8Array): Promise<Uint8Array>;
24
+ //# 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;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;AA6FvE,eAAO,MAAM,WAAW,EAAE,KAAK,EA+E9B,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
- import type { Database } from "bun:sqlite";
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,12 +8,19 @@ 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
- export declare function listPeers(db: Database): PeerRow[];
15
- export declare function getPeer(db: Database, url: string): PeerRow | null;
22
+ export declare function listPeers(db: DbDriver): PeerRow[];
23
+ export declare function getPeer(db: DbDriver, url: string): PeerRow | null;
16
24
  export interface AddPeerInput {
17
25
  url: string;
18
26
  token?: string | null;
@@ -20,26 +28,91 @@ export interface AddPeerInput {
20
28
  node_id?: string | null;
21
29
  }
22
30
  /** Upsert a peer, preserving replication cursors on conflict. */
23
- export declare function addPeer(db: Database, input: AddPeerInput): void;
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
+ /** Synthetic peer key for a storage peer: one per bucket+prefix. */
41
+ export declare const storageUrl: (bucket: string, prefix: string) => string;
42
+ export interface StoragePeerSpec {
43
+ endpoint: string;
44
+ region?: string;
45
+ bucket: string;
46
+ prefix?: string;
47
+ accessKeyId: string;
48
+ secretAccessKey: string;
49
+ /** Virtual-hosted (COS) vs path-style addressing; undefined → auto-detect.
50
+ * Carried by enroll codes so COS buckets join correctly. */
51
+ virtualHostedStyle?: boolean;
52
+ /** Default true; pass false for `--no-encrypt` plaintext buckets. */
53
+ encrypt?: boolean;
54
+ /** Required when encrypt — provisions/adopts the bucket's wrapped master key. */
55
+ passphrase?: string;
56
+ /** Mark this node the bucket's publisher (writes whole-hub snapshots). */
57
+ publish?: boolean;
58
+ priority?: number;
59
+ label?: string | null;
60
+ }
61
+ /**
62
+ * Resolve + persist an S3 storage peer and run one sync so a bad endpoint /
63
+ * credentials / missing CORS fail fast at the call site. Shared by the CLI
64
+ * (`mh config peer add --s3`) and the WebUI server endpoint (`POST /api/peer/s3`)
65
+ * so both go through the exact same provisioning + first-sync path. Returns the
66
+ * resolved config (incl. the wrapped master key) and the first sync outcome.
67
+ */
68
+ export declare function addAndSyncStoragePeer(db: DbDriver, spec: StoragePeerSpec): Promise<{
69
+ url: string;
70
+ config: S3Config;
71
+ sync: PeerSyncOutcome;
72
+ }>;
24
73
  /**
25
74
  * Remove a peer AND revoke the credential we issued to it during pairing, so
26
75
  * disconnecting is mutual: we stop syncing out to it (peers row) and it can no
27
76
  * longer sync in to us (peer_grants row, keyed by peer_url). Grants minted for a
28
77
  * peer that never sent a self_url have a null peer_url and can't be revoked here.
29
78
  */
30
- export declare function removePeer(db: Database, url: string): boolean;
31
- export declare function setPeerEnabled(db: Database, url: string, enabled: boolean): boolean;
32
- export declare function setPeerLabel(db: Database, url: string, label: string): boolean;
33
- export declare function updatePeerStatus(db: Database, url: string, status: string, error?: string | null): void;
79
+ export declare function removePeer(db: DbDriver, url: string): boolean;
80
+ export declare function setPeerEnabled(db: DbDriver, url: string, enabled: boolean): boolean;
81
+ export declare function setPeerLabel(db: DbDriver, url: string, label: string): boolean;
82
+ export declare function updatePeerStatus(db: DbDriver, url: string, status: string, error?: string | null): void;
34
83
  export interface PeerSyncOutcome {
35
84
  url: string;
36
85
  ok: boolean;
37
86
  pushed?: number;
38
87
  pulled?: number;
88
+ pendingPush?: boolean;
39
89
  error?: string;
40
90
  }
41
- /** Sync once with a single peer, recording status. Errors are captured, not thrown. */
42
- export declare function syncPeer(db: Database, url: string): Promise<PeerSyncOutcome>;
91
+ /** Sync once with a single peer, recording status. Errors are captured, not
92
+ * thrown. Dispatches on transport: 's3' peers go through the bucket
93
+ * store-and-forward client, everything else POSTs /sync. */
94
+ export declare function syncPeer(db: DbDriver, url: string, opts?: {
95
+ storage?: StorageSyncOpts;
96
+ }): Promise<PeerSyncOutcome>;
43
97
  /** Sync once with every enabled peer. Used by the auto-sync timer. */
44
- export declare function syncAllPeers(db: Database): Promise<PeerSyncOutcome[]>;
98
+ export declare function syncAllPeers(db: DbDriver): Promise<PeerSyncOutcome[]>;
99
+ /**
100
+ * Freshness gate for *non-reactive* consumers — CLI reads and the PWA's served
101
+ * site pages (②b). Their local DB is only as fresh as the last sync, and unlike
102
+ * the reactive WebUI they have no background poll and no `synced` revalidate. So
103
+ * if the newest successful peer sync is older than `maxAgeMs`, block on one
104
+ * bounded sync round before the caller reads; otherwise return immediately
105
+ * (read local).
106
+ *
107
+ * No enabled peers → no-op. A running daemon keeps `last_success_at` recent, so
108
+ * this is a near-instant no-op there and only does real work on a daemon-less node
109
+ * that hasn't synced successfully in a while. Failed attempts update
110
+ * `last_sync_at`, but never make local data fresh. Env overrides: MH_OFFLINE=1
111
+ * skips; MH_FRESH=1 forces; MH_SYNC_MAX_AGE=<ms> tunes the threshold.
112
+ */
113
+ export declare function ensureFresh(db: DbDriver, opts?: {
114
+ maxAgeMs?: number;
115
+ force?: boolean;
116
+ offline?: boolean;
117
+ }): Promise<void>;
45
118
  //# 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,YAAY,CAAC;AAG3C,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,EAAE,CAMjD;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAMjE;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,iEAAiE;AACjE,wBAAgB,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI,CAU/D;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAO7D;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAInF;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAE9E;AAED,wBAAgB,gBAAgB,CAC9B,EAAE,EAAE,QAAQ,EACZ,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACpB,IAAI,CAIN;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,uFAAuF;AACvF,wBAAsB,QAAQ,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAUlF;AAED,sEAAsE;AACtE,wBAAsB,YAAY,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAK3E"}
1
+ {"version":3,"file":"peers.d.ts","sourceRoot":"","sources":["../../../src/core/sync/peers.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,7 @@ export declare const ChangeSchema: z.ZodObject<{
7
7
  row_id: z.ZodString;
8
8
  col: z.ZodString;
9
9
  value: z.ZodNullable<z.ZodString>;
10
+ txn: z.ZodOptional<z.ZodNullable<z.ZodString>>;
10
11
  }, z.core.$strip>;
11
12
  export declare const SyncRequestSchema: z.ZodObject<{
12
13
  node_id: z.ZodString;
@@ -18,7 +19,10 @@ export declare const SyncRequestSchema: z.ZodObject<{
18
19
  row_id: z.ZodString;
19
20
  col: z.ZodString;
20
21
  value: z.ZodNullable<z.ZodString>;
22
+ txn: z.ZodOptional<z.ZodNullable<z.ZodString>>;
21
23
  }, z.core.$strip>>;
24
+ limit: z.ZodOptional<z.ZodNumber>;
25
+ exclude_datasets: z.ZodOptional<z.ZodArray<z.ZodString>>;
22
26
  }, z.core.$strip>;
23
27
  export declare const SyncResponseSchema: z.ZodObject<{
24
28
  node_id: z.ZodString;
@@ -29,6 +33,7 @@ export declare const SyncResponseSchema: z.ZodObject<{
29
33
  row_id: z.ZodString;
30
34
  col: z.ZodString;
31
35
  value: z.ZodNullable<z.ZodString>;
36
+ txn: z.ZodOptional<z.ZodNullable<z.ZodString>>;
32
37
  }, z.core.$strip>>;
33
38
  cursor: z.ZodNumber;
34
39
  }, z.core.$strip>;
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../../src/core/sync/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,YAAY,CAAC;AAMvD,eAAO,MAAM,YAAY;;;;;;;iBAOvB,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;;;;;;;;iBAI5B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;;iBAI7B,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;iBAG/B,CAAC;AAKH,eAAO,MAAM,iBAAiB;;;;;iBAK5B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;iBAG7B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC5D,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAI9D,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,GAAG;IAAE,OAAO,EAAE,UAAU,EAAE,CAAA;CAAE,CAAC;AACxF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,GAAG;IAAE,OAAO,EAAE,UAAU,EAAE,CAAA;CAAE,CAAC;AAC1F,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,eAAO,MAAM,SAAS,UAAU,CAAC;AACjC,eAAO,MAAM,WAAW,YAAY,CAAC;AAGrC,eAAO,MAAM,UAAU,gBAAgB,CAAC;AAGxC,eAAO,MAAM,SAAS,cAAc,CAAC"}
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../../src/core/sync/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,YAAY,CAAC;AAMvD,eAAO,MAAM,YAAY;;;;;;;;iBAUvB,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;iBAa5B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;iBAI7B,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;iBAG/B,CAAC;AAKH,eAAO,MAAM,iBAAiB;;;;;iBAK5B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;iBAG7B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC5D,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAI9D,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,GAAG;IAAE,OAAO,EAAE,UAAU,EAAE,CAAA;CAAE,CAAC;AACxF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,GAAG;IAAE,OAAO,EAAE,UAAU,EAAE,CAAA;CAAE,CAAC;AAC1F,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,eAAO,MAAM,SAAS,UAAU,CAAC;AACjC,eAAO,MAAM,WAAW,YAAY,CAAC;AAGrC,eAAO,MAAM,UAAU,gBAAgB,CAAC;AAGxC,eAAO,MAAM,SAAS,cAAc,CAAC"}
@@ -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;AAc3C,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;AA8BD,eAAO,MAAM,MAAM,EAAE,KAAK,EAAoD,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,3 +1,4 @@
1
+ import "./storage-s3-bun.ts";
1
2
  import { MhError } from "../errors.ts";
2
3
  import { type Route } from "./routes.ts";
3
4
  export interface RunningServer {
@@ -12,6 +13,8 @@ export interface RunningServer {
12
13
  exp: number | null;
13
14
  /** How the token was sourced: rotating (managed), fixed (static), or off (disabled). */
14
15
  authMode: "managed" | "static" | "disabled";
16
+ /** Whether the server terminates TLS itself (URLs are https://). */
17
+ tls: boolean;
15
18
  /** Whether the auto-sync timer is running. */
16
19
  autoSync: boolean;
17
20
  /** Auto-sync poll interval in ms (meaningful only when autoSync). */
@@ -41,6 +44,14 @@ export interface ServerOptions {
41
44
  * sidecar) inject the WebUI's asset handler + data API routes here.
42
45
  * Omitted = a headless sync/sites server. */
43
46
  ui?: UiHandler;
47
+ /** Optional TLS (PEM file paths). When set the server terminates TLS itself
48
+ * and serves https — service workers/PWA need a secure context off
49
+ * localhost. A reverse proxy (Caddy, Tailscale Serve) in front is the
50
+ * recommended alternative; this is for setups without one. */
51
+ tls?: {
52
+ certPath: string;
53
+ keyPath: string;
54
+ };
44
55
  }
45
56
  /** What a pluggable browser UI provides (see src/webui/server/). */
46
57
  export interface UiHandler {
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/core/sync/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAIvC,OAAO,EAAU,KAAK,KAAK,EAAiB,MAAM,aAAa,CAAC;AAkBhE,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,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;CAChB;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,CAkJnE"}
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,CA+NnE"}
@@ -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,CAuBrF"}
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,26 @@
1
+ import { type S3Config } from "./storage.ts";
2
+ /** Read the bucket's current CORS config (raw XML), or null if none is set. */
3
+ export declare function getBucketCors(config: S3Config): Promise<string | null>;
4
+ /**
5
+ * Build the PutBucketCors XML body from the bucket's current config. PutBucketCors
6
+ * replaces the whole config, so we keep every rule that isn't ours and re-emit our
7
+ * managed rule (id=metahub-pwa). `merge` decides our rule's origins:
8
+ * - false (CLI `peer cors`): SET — exactly `origins` (lets the user shrink/reset).
9
+ * - true (auto-open on bucket-attach): UNION with the managed rule's existing
10
+ * origins, so attaching the same bucket from a second shell/origin (a homelab
11
+ * server origin alongside the official PWA shell) adds to the allow-list
12
+ * instead of clobbering it.
13
+ * A wildcard `*` collapses the set. Pure (no I/O) so it's unit-testable.
14
+ */
15
+ export declare function buildCorsXml(existing: string | null, origins: string[], merge: boolean): string;
16
+ /**
17
+ * Allow a browser shell served from `origins` to talk to the bucket directly
18
+ * (GET/PUT/HEAD/DELETE) via GET-merge-PUT (see buildCorsXml). `opts.merge` unions
19
+ * with existing managed origins instead of replacing them — used when a second
20
+ * origin attaches the same bucket. Content-MD5 is required by the CORS API
21
+ * (S3 and COS both).
22
+ */
23
+ export declare function putBucketCors(config: S3Config, origins: string[], opts?: {
24
+ merge?: boolean;
25
+ }): Promise<void>;
26
+ //# sourceMappingURL=storage-s3-bun.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-s3-bun.d.ts","sourceRoot":"","sources":["../../../src/core/sync/storage-s3-bun.ts"],"names":[],"mappings":"AAUA,OAAO,EAML,KAAK,QAAQ,EACd,MAAM,cAAc,CAAC;AAiHtB,+EAA+E;AAC/E,wBAAsB,aAAa,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAS5E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAoB/F;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,QAAQ,EAChB,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAC7B,OAAO,CAAC,IAAI,CAAC,CAmBf"}