@tensorix/metahub 0.1.11 → 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 (50) hide show
  1. package/dist/cli.js +21342 -17813
  2. package/dist/cli.js.map +76 -60
  3. package/dist/core/blobs-core.d.ts +106 -0
  4. package/dist/core/blobs-core.d.ts.map +1 -0
  5. package/dist/core/blobs.d.ts +100 -0
  6. package/dist/core/blobs.d.ts.map +1 -0
  7. package/dist/core/cache.d.ts +18 -1
  8. package/dist/core/cache.d.ts.map +1 -1
  9. package/dist/core/compact.d.ts +4 -3
  10. package/dist/core/compact.d.ts.map +1 -1
  11. package/dist/core/config.d.ts +3 -0
  12. package/dist/core/config.d.ts.map +1 -1
  13. package/dist/core/crdt.d.ts +25 -2
  14. package/dist/core/crdt.d.ts.map +1 -1
  15. package/dist/core/schema-init.d.ts +33 -2
  16. package/dist/core/schema-init.d.ts.map +1 -1
  17. package/dist/core/schema.d.ts +1 -1
  18. package/dist/core/schema.d.ts.map +1 -1
  19. package/dist/core/sites-core.d.ts +35 -0
  20. package/dist/core/sites-core.d.ts.map +1 -1
  21. package/dist/core/sites.d.ts +4 -13
  22. package/dist/core/sites.d.ts.map +1 -1
  23. package/dist/core/sync/blob-routes.d.ts +12 -0
  24. package/dist/core/sync/blob-routes.d.ts.map +1 -0
  25. package/dist/core/sync/client.d.ts +2 -0
  26. package/dist/core/sync/client.d.ts.map +1 -1
  27. package/dist/core/sync/e2ee.d.ts +24 -0
  28. package/dist/core/sync/e2ee.d.ts.map +1 -0
  29. package/dist/core/sync/enroll.d.ts +21 -0
  30. package/dist/core/sync/enroll.d.ts.map +1 -0
  31. package/dist/core/sync/peers-routes.d.ts.map +1 -1
  32. package/dist/core/sync/peers.d.ts +75 -2
  33. package/dist/core/sync/peers.d.ts.map +1 -1
  34. package/dist/core/sync/publisher-lease.d.ts +8 -0
  35. package/dist/core/sync/publisher-lease.d.ts.map +1 -0
  36. package/dist/core/sync/routes.d.ts.map +1 -1
  37. package/dist/core/sync/server.d.ts +1 -0
  38. package/dist/core/sync/server.d.ts.map +1 -1
  39. package/dist/core/sync/sites-serve.d.ts.map +1 -1
  40. package/dist/core/sync/storage-s3-bun.d.ts +26 -0
  41. package/dist/core/sync/storage-s3-bun.d.ts.map +1 -0
  42. package/dist/core/sync/storage.d.ts +170 -0
  43. package/dist/core/sync/storage.d.ts.map +1 -0
  44. package/dist/db-worker.js +181 -65
  45. package/dist/index.js +16519 -13910
  46. package/dist/index.js.map +40 -28
  47. package/dist/sw.js +1 -1
  48. package/dist/webui/server/routes.d.ts.map +1 -1
  49. package/dist/webui.js +67 -61
  50. package/package.json +4 -1
@@ -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
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,47 @@ 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
+ /** 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
@@ -36,10 +85,34 @@ export interface PeerSyncOutcome {
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: DbDriver, 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
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,cAAc,CAAC;AAG7C,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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"}
@@ -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;AAiCD,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 {
@@ -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,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,CA8JnE"}
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"}
@@ -0,0 +1,170 @@
1
+ import type { DbDriver } from "../driver.ts";
2
+ import type { SyncResult } from "./client.ts";
3
+ /** An 's3' peer's bucket settings, stored as JSON in peers.config (local-only). */
4
+ export interface S3Config {
5
+ endpoint: string;
6
+ region: string;
7
+ bucket: string;
8
+ prefix: string;
9
+ accessKeyId: string;
10
+ secretAccessKey: string;
11
+ /** When false (`--no-encrypt`) segments are gzip-only plaintext. */
12
+ encrypt: boolean;
13
+ /** base64 raw 32-byte master key; present iff encrypt. Resolved at peer-add. */
14
+ masterKey?: string;
15
+ /**
16
+ * Address objects as `<bucket>.<host>/<key>` (virtual-hosted) instead of
17
+ * `<host>/<bucket>/<key>` (path-style). Some providers (Tencent COS) reject
18
+ * path-style outright. When undefined, the clients auto-detect: virtual-hosted
19
+ * iff the endpoint host already starts with `<bucket>.` (see
20
+ * isVirtualHostedStyle). R2/MinIO keep using path-style.
21
+ */
22
+ virtualHostedStyle?: boolean;
23
+ /**
24
+ * Node-role hints for this bucket (not bucket settings — safe to omit from
25
+ * shared enroll links). `publish` marks this node as the bucket's publisher
26
+ * (writes whole-hub snapshots; see StorageSyncOpts.publish): true for the data
27
+ * home (a server, or a no-origin PWA which IS the home), false for a replica
28
+ * that only attaches the bucket for its own away-sync. `priority` ranks
29
+ * publisher candidates when several are eligible (higher wins; see
30
+ * publisher-lease.ts) — server > desktop > laptop > phone.
31
+ */
32
+ publish?: boolean;
33
+ priority?: number;
34
+ }
35
+ /** Whether to use virtual-hosted addressing for this bucket: the explicit flag,
36
+ * or — when unset — auto-detected from an endpoint whose host already carries
37
+ * the bucket (e.g. COS's `<bucket>.cos.<region>.myqcloud.com`). */
38
+ export declare function isVirtualHostedStyle(config: S3Config): boolean;
39
+ export interface StorageObject {
40
+ key: string;
41
+ etag?: string;
42
+ }
43
+ /** Options for a conditional/typed put. */
44
+ export interface StoragePutOpts {
45
+ contentType?: string;
46
+ /** Conditional create (S3 `If-None-Match: *`): fail with an MhError("conflict")
47
+ * if the object already exists. Used to make first-time key provisioning a
48
+ * compare-and-set so two devices initializing the same empty bucket can't
49
+ * clobber each other's master key. */
50
+ ifNoneMatch?: boolean;
51
+ }
52
+ /** The minimal object-store surface storage-sync needs. Implemented per runtime:
53
+ * Bun.S3Client on the CLI/desktop (storage-s3-bun.ts), aws4fetch SigV4 + fetch
54
+ * in the browser worker (webui/data/storage-s3-browser.ts). */
55
+ export interface StorageClient {
56
+ /** Keys under `prefix`, ascending, optionally only those strictly after
57
+ * `startAfter`. With `delimiter` ("/"), collapse one level into common
58
+ * prefixes (their keys end in the delimiter) to discover child "folders"
59
+ * cheaply — callers must tolerate a backend that ignores it and returns full
60
+ * keys instead. */
61
+ list(prefix: string, startAfter?: string, delimiter?: string): Promise<StorageObject[]>;
62
+ get(key: string): Promise<Uint8Array | null>;
63
+ put(key: string, body: Uint8Array, opts?: StoragePutOpts): Promise<void>;
64
+ del(key: string): Promise<void>;
65
+ }
66
+ type StorageClientFactory = (config: S3Config) => StorageClient;
67
+ /** Register this runtime's S3 client builder (see the per-runtime impls). */
68
+ export declare function setStorageClientFactory(f: StorageClientFactory): void;
69
+ export declare function storageClientFor(config: S3Config): StorageClient;
70
+ /** Upload a blob's bytes to the bucket (idempotent via If-None-Match). Returns
71
+ * true when actually written, false when the object already existed. */
72
+ export declare function putBucketBlob(config: S3Config, hash: string, bytes: Uint8Array): Promise<boolean>;
73
+ /** Every blob hash the bucket durably holds — one paginated LIST of the `blobs/`
74
+ * namespace (the client loops continuation tokens internally). Used by the
75
+ * on-demand clear-presence verify; keeps the `<base>/blobs/<hash>` key layout
76
+ * encapsulated here. Throws if the bucket is unreachable (caller treats the
77
+ * anchor as unverified). */
78
+ export declare function listBucketBlobHashes(config: S3Config): Promise<Set<string>>;
79
+ /** Fetch a blob's bytes from the bucket, or null if absent. */
80
+ export declare function getBucketBlob(config: S3Config, hash: string): Promise<Uint8Array | null>;
81
+ /**
82
+ * Resolve the master key for a bucket at setup: read keys/main.json and unwrap
83
+ * with the passphrase, or — when absent — generate a key, wrap it, and upload
84
+ * it with `If-None-Match` so a concurrent first-time init can't clobber it.
85
+ * Returns base64(K) to store in peers.config, or null when encryption is off.
86
+ * Wrong passphrase throws `auth` (from unwrapMasterKey).
87
+ */
88
+ export declare function provisionMasterKey(client: StorageClient, config: S3Config, passphrase: string): Promise<string | null>;
89
+ /**
90
+ * Publish a winners-only snapshot and truncate this node's own segments. Every
91
+ * op we've uploaded so far is in the local oplog now, so the snapshot (winners
92
+ * as-of the current max HLC) supersedes all of them — they're safe to delete
93
+ * (compact.ts invariant #1). Ops produced afterwards go into fresh, higher-keyed
94
+ * segments; consumers reach our pre-snapshot state via the snapshot itself.
95
+ *
96
+ * The key is `<maxHlc>~<hash>.snap`: the hash (over the canonical winner set)
97
+ * makes converged nodes collide on one key (deduped) while two nodes that are
98
+ * NOT converged — same max HLC but different extra winners — get distinct keys,
99
+ * so neither overwrites the other. Then old snapshots (strictly lower max-HLC)
100
+ * are GC'd so the bucket stays bounded.
101
+ *
102
+ * Returns the snapshot key + change count, or null when the oplog is empty.
103
+ */
104
+ export declare function publishSnapshot(db: DbDriver, client: StorageClient, config: S3Config, retainSegments?: number): Promise<{
105
+ key: string;
106
+ changes: number;
107
+ } | null>;
108
+ export interface StorageSyncOpts {
109
+ /** Publisher-only: publish a snapshot + truncate once this node's own segment
110
+ * count reaches this. Default 200 — high enough that typical use rarely hits
111
+ * it, low enough to keep the bucket bounded under heavy publisher use. */
112
+ snapshotEverySegments?: number;
113
+ /** Push-batching: defer uploading our pending own ops until there are at least
114
+ * this many (default 1 → push every round). Coalesces a burst of edits into
115
+ * one segment instead of many tiny ones (each is a billed request + a GET for
116
+ * every puller). */
117
+ minPushChanges?: number;
118
+ /** …or until the oldest pending op is at least this old (ms; default 0 → no
119
+ * age bound). Bounds how long a small trailing edit waits. */
120
+ maxPushAgeMs?: number;
121
+ /** Push regardless of the batching thresholds — use on explicit "sync now" and
122
+ * when the app is backgrounding, so edits are never stranded unsynced. */
123
+ forcePush?: boolean;
124
+ /**
125
+ * This node is the bucket's *publisher*: keep the bucket a complete, fresh
126
+ * whole-hub mirror by writing a winners-only snapshot (publishSnapshot) when
127
+ * the bucket has none yet, or when the hub has advanced past the newest
128
+ * snapshot. The snapshot spans the WHOLE db, so it captures data authored by
129
+ * nodes that never push to this bucket themselves (e.g. a server holding the
130
+ * canonical hub while browsers only window onto it) — fixing the "attached a
131
+ * bucket but it stays empty" footgun. Any node holding the full hub can be the
132
+ * publisher; who is one is decided above storage.ts (server by default, else a
133
+ * lease — see publisher-lease.ts). Correctness never depends on a single
134
+ * publisher: concurrent snapshots are content-addressed and idempotent. */
135
+ publish?: boolean;
136
+ /** ⑤d snapshot trigger: publish once the whole-hub delta since the newest
137
+ * snapshot reaches max(`snapshotMinDelta` ops, hub_size × `snapshotDeltaRatio`),
138
+ * or `snapshotMaxIntervalMs` elapsed (safety). Replaces the old 60s timer that
139
+ * re-checkpointed constantly and forced full re-downloads. Defaults:
140
+ * DEFAULT_SNAPSHOT_MIN_DELTA / _DELTA_RATIO / _MAX_INTERVAL_MS. */
141
+ snapshotMinDelta?: number;
142
+ snapshotDeltaRatio?: number;
143
+ snapshotMaxIntervalMs?: number;
144
+ /** ⑤c: keep this many of our most recent own segments alive past a snapshot so
145
+ * slightly-behind consumers catch up incrementally (default DEFAULT_RETAIN_SEGMENTS). */
146
+ snapshotRetainSegments?: number;
147
+ /** This node's publisher priority when contending for the lease (higher wins;
148
+ * see publisher-lease.ts). Only consulted when `publish` is set. */
149
+ priority?: number;
150
+ /**
151
+ * Run the PULL half of the round (snapshots + other nodes' segments). Default
152
+ * true. Set false for *push-only* rounds: an origin-backed replica gets a
153
+ * superset of bucket contents from its origin (HTTP), so it never needs to PULL
154
+ * the bucket — it only PUSHes its own segments here for independent durability
155
+ * (Path B). Skipping PULL drops the two unconditional LISTs (snapshot/, oplog/)
156
+ * that dominate idle bucket cost. A *publisher* must always PULL (it needs the
157
+ * snapshot list to decide what to publish), so callers never combine
158
+ * `publish:true` with `pull:false`.
159
+ */
160
+ pull?: boolean;
161
+ }
162
+ /**
163
+ * One push/pull round against a storage peer. Push uploads this node's pending
164
+ * own ops as a new segment (subject to batching); pull hydrates from snapshots
165
+ * (any not yet ingested) then drains each other node's new segments. Returns
166
+ * { pushed, pulled } like syncWithPeer so peers.ts status writeback is shared.
167
+ */
168
+ export declare function syncWithStorage(db: DbDriver, peerUrl: string, client: StorageClient, config: S3Config, opts?: StorageSyncOpts): Promise<SyncResult>;
169
+ export {};
170
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/core/sync/storage.ts"],"names":[],"mappings":"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"}