@tensorix/metahub 0.3.2 → 0.4.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 (178) hide show
  1. package/README.md +23 -10
  2. package/README.zh-CN.md +23 -10
  3. package/dist/cli/edge-worker-script.d.ts +4 -0
  4. package/dist/cli/edge-worker-script.d.ts.map +1 -0
  5. package/dist/cli.js +16882 -8691
  6. package/dist/cli.js.map +109 -59
  7. package/dist/core/access-policy.d.ts +82 -0
  8. package/dist/core/access-policy.d.ts.map +1 -0
  9. package/dist/core/blobs-core.d.ts +19 -0
  10. package/dist/core/blobs-core.d.ts.map +1 -1
  11. package/dist/core/blobs.d.ts.map +1 -1
  12. package/dist/core/compact.d.ts.map +1 -1
  13. package/dist/core/config.d.ts +13 -0
  14. package/dist/core/config.d.ts.map +1 -1
  15. package/dist/core/crdt.d.ts +29 -2
  16. package/dist/core/crdt.d.ts.map +1 -1
  17. package/dist/core/data-map.d.ts +105 -0
  18. package/dist/core/data-map.d.ts.map +1 -0
  19. package/dist/core/db.d.ts +1 -1
  20. package/dist/core/db.d.ts.map +1 -1
  21. package/dist/core/documents.d.ts.map +1 -1
  22. package/dist/core/errors.d.ts +2 -0
  23. package/dist/core/errors.d.ts.map +1 -1
  24. package/dist/core/grants-core.d.ts +132 -0
  25. package/dist/core/grants-core.d.ts.map +1 -0
  26. package/dist/core/guest-intent.d.ts +33 -0
  27. package/dist/core/guest-intent.d.ts.map +1 -0
  28. package/dist/core/hash.d.ts +4 -0
  29. package/dist/core/hash.d.ts.map +1 -0
  30. package/dist/core/history.d.ts.map +1 -1
  31. package/dist/core/hlc.d.ts +5 -0
  32. package/dist/core/hlc.d.ts.map +1 -1
  33. package/dist/core/ids.d.ts +1 -1
  34. package/dist/core/ids.d.ts.map +1 -1
  35. package/dist/core/inject-runtime.d.ts +8 -0
  36. package/dist/core/inject-runtime.d.ts.map +1 -0
  37. package/dist/core/intent-retention.d.ts +23 -0
  38. package/dist/core/intent-retention.d.ts.map +1 -0
  39. package/dist/core/md/inline.d.ts +6 -2
  40. package/dist/core/md/inline.d.ts.map +1 -1
  41. package/dist/core/node.d.ts +13 -0
  42. package/dist/core/node.d.ts.map +1 -1
  43. package/dist/core/records.d.ts +31 -0
  44. package/dist/core/records.d.ts.map +1 -1
  45. package/dist/core/schema-init.d.ts +19 -2
  46. package/dist/core/schema-init.d.ts.map +1 -1
  47. package/dist/core/schema.d.ts +1 -1
  48. package/dist/core/schema.d.ts.map +1 -1
  49. package/dist/core/shares.d.ts +15 -0
  50. package/dist/core/shares.d.ts.map +1 -1
  51. package/dist/core/site-channel-lifecycle.d.ts +10 -0
  52. package/dist/core/site-channel-lifecycle.d.ts.map +1 -0
  53. package/dist/core/site-channel-store.d.ts +120 -0
  54. package/dist/core/site-channel-store.d.ts.map +1 -0
  55. package/dist/core/site-channels.d.ts +65 -0
  56. package/dist/core/site-channels.d.ts.map +1 -0
  57. package/dist/core/sites-core.d.ts +100 -7
  58. package/dist/core/sites-core.d.ts.map +1 -1
  59. package/dist/core/sites.d.ts +65 -2
  60. package/dist/core/sites.d.ts.map +1 -1
  61. package/dist/core/sync/anti-abuse.d.ts +26 -0
  62. package/dist/core/sync/anti-abuse.d.ts.map +1 -0
  63. package/dist/core/sync/auth.d.ts +30 -2
  64. package/dist/core/sync/auth.d.ts.map +1 -1
  65. package/dist/core/sync/blob-routes.d.ts.map +1 -1
  66. package/dist/core/sync/cf-api.d.ts +54 -0
  67. package/dist/core/sync/cf-api.d.ts.map +1 -0
  68. package/dist/core/sync/cf-oauth.d.ts +91 -0
  69. package/dist/core/sync/cf-oauth.d.ts.map +1 -0
  70. package/dist/core/sync/client.d.ts +12 -0
  71. package/dist/core/sync/client.d.ts.map +1 -1
  72. package/dist/core/sync/data-map-db.d.ts +8 -0
  73. package/dist/core/sync/data-map-db.d.ts.map +1 -0
  74. package/dist/core/sync/devices.d.ts +65 -0
  75. package/dist/core/sync/devices.d.ts.map +1 -0
  76. package/dist/core/sync/drop-host.d.ts +40 -0
  77. package/dist/core/sync/drop-host.d.ts.map +1 -0
  78. package/dist/core/sync/drop-keys.d.ts +64 -0
  79. package/dist/core/sync/drop-keys.d.ts.map +1 -0
  80. package/dist/core/sync/drop-protocol.d.ts +94 -0
  81. package/dist/core/sync/drop-protocol.d.ts.map +1 -0
  82. package/dist/core/sync/drop-pull.d.ts +67 -0
  83. package/dist/core/sync/drop-pull.d.ts.map +1 -0
  84. package/dist/core/sync/drop-wire.d.ts +39 -0
  85. package/dist/core/sync/drop-wire.d.ts.map +1 -0
  86. package/dist/core/sync/e2ee.d.ts +3 -0
  87. package/dist/core/sync/e2ee.d.ts.map +1 -1
  88. package/dist/core/sync/edge-config.d.ts +77 -0
  89. package/dist/core/sync/edge-config.d.ts.map +1 -0
  90. package/dist/core/sync/edge-connect.d.ts +13 -0
  91. package/dist/core/sync/edge-connect.d.ts.map +1 -0
  92. package/dist/core/sync/edge-service.d.ts +100 -0
  93. package/dist/core/sync/edge-service.d.ts.map +1 -0
  94. package/dist/core/sync/grants-routes.d.ts +46 -0
  95. package/dist/core/sync/grants-routes.d.ts.map +1 -0
  96. package/dist/core/sync/guest-session.d.ts +29 -0
  97. package/dist/core/sync/guest-session.d.ts.map +1 -0
  98. package/dist/core/sync/html-escape.d.ts +2 -0
  99. package/dist/core/sync/html-escape.d.ts.map +1 -0
  100. package/dist/core/sync/http-status.d.ts +14 -0
  101. package/dist/core/sync/http-status.d.ts.map +1 -0
  102. package/dist/core/sync/http-util.d.ts +6 -0
  103. package/dist/core/sync/http-util.d.ts.map +1 -0
  104. package/dist/core/sync/pairing.d.ts +9 -9
  105. package/dist/core/sync/pairing.d.ts.map +1 -1
  106. package/dist/core/sync/partition.d.ts +77 -0
  107. package/dist/core/sync/partition.d.ts.map +1 -0
  108. package/dist/core/sync/peers-routes.d.ts.map +1 -1
  109. package/dist/core/sync/peers.d.ts +77 -0
  110. package/dist/core/sync/peers.d.ts.map +1 -1
  111. package/dist/core/sync/protocol.d.ts +2 -0
  112. package/dist/core/sync/protocol.d.ts.map +1 -1
  113. package/dist/core/sync/rate-limit.d.ts +20 -0
  114. package/dist/core/sync/rate-limit.d.ts.map +1 -0
  115. package/dist/core/sync/recovery.d.ts +9 -0
  116. package/dist/core/sync/recovery.d.ts.map +1 -0
  117. package/dist/core/sync/room-client.d.ts +50 -0
  118. package/dist/core/sync/room-client.d.ts.map +1 -0
  119. package/dist/core/sync/room-peer.d.ts +62 -0
  120. package/dist/core/sync/room-peer.d.ts.map +1 -0
  121. package/dist/core/sync/room-protocol.d.ts +130 -0
  122. package/dist/core/sync/room-protocol.d.ts.map +1 -0
  123. package/dist/core/sync/room-serve.d.ts +38 -0
  124. package/dist/core/sync/room-serve.d.ts.map +1 -0
  125. package/dist/core/sync/room-url.d.ts +4 -0
  126. package/dist/core/sync/room-url.d.ts.map +1 -0
  127. package/dist/core/sync/routes.d.ts +4 -1
  128. package/dist/core/sync/routes.d.ts.map +1 -1
  129. package/dist/core/sync/seal.d.ts +22 -0
  130. package/dist/core/sync/seal.d.ts.map +1 -0
  131. package/dist/core/sync/server.d.ts +7 -0
  132. package/dist/core/sync/server.d.ts.map +1 -1
  133. package/dist/core/sync/share-actions.d.ts +55 -6
  134. package/dist/core/sync/share-actions.d.ts.map +1 -1
  135. package/dist/core/sync/share-export.d.ts +14 -0
  136. package/dist/core/sync/share-export.d.ts.map +1 -1
  137. package/dist/core/sync/share-render.d.ts +9 -1
  138. package/dist/core/sync/share-render.d.ts.map +1 -1
  139. package/dist/core/sync/share-serve.d.ts +5 -1
  140. package/dist/core/sync/share-serve.d.ts.map +1 -1
  141. package/dist/core/sync/site-channel-reconcile.d.ts +26 -0
  142. package/dist/core/sync/site-channel-reconcile.d.ts.map +1 -0
  143. package/dist/core/sync/site-publish-recovery.d.ts +32 -0
  144. package/dist/core/sync/site-publish-recovery.d.ts.map +1 -0
  145. package/dist/core/sync/site-reachability.d.ts +13 -0
  146. package/dist/core/sync/site-reachability.d.ts.map +1 -0
  147. package/dist/core/sync/sites-routes.d.ts.map +1 -1
  148. package/dist/core/sync/sites-serve.d.ts +24 -1
  149. package/dist/core/sync/sites-serve.d.ts.map +1 -1
  150. package/dist/core/sync/storage-s3-bun.d.ts +1 -24
  151. package/dist/core/sync/storage-s3-bun.d.ts.map +1 -1
  152. package/dist/core/sync/storage-s3-sign.d.ts +43 -0
  153. package/dist/core/sync/storage-s3-sign.d.ts.map +1 -0
  154. package/dist/core/sync/storage.d.ts +59 -0
  155. package/dist/core/sync/storage.d.ts.map +1 -1
  156. package/dist/db-worker.js +206 -76
  157. package/dist/edge-worker.js +3960 -0
  158. package/dist/index.js +13175 -6670
  159. package/dist/index.js.map +87 -41
  160. package/dist/metahub-sdk.js +10 -1
  161. package/dist/mh-runtime.js +1 -1
  162. package/dist/room/do-driver.d.ts +30 -0
  163. package/dist/room/do-driver.d.ts.map +1 -0
  164. package/dist/sw.js +10 -1
  165. package/dist/webui/server/edge-routes.d.ts +3 -0
  166. package/dist/webui/server/edge-routes.d.ts.map +1 -0
  167. package/dist/webui/server/json-handler.d.ts +4 -0
  168. package/dist/webui/server/json-handler.d.ts.map +1 -0
  169. package/dist/webui/server/routes.d.ts.map +1 -1
  170. package/dist/webui/server/share-routes.d.ts.map +1 -1
  171. package/dist/webui/server/site-hosting-routes.d.ts +7 -0
  172. package/dist/webui/server/site-hosting-routes.d.ts.map +1 -0
  173. package/dist/webui.js +192 -137
  174. package/dist/workers/edge-worker.d.ts +66 -0
  175. package/dist/workers/edge-worker.d.ts.map +1 -0
  176. package/dist/workers/room.d.ts +34 -0
  177. package/dist/workers/room.d.ts.map +1 -0
  178. package/package.json +1 -1
@@ -1,11 +1,21 @@
1
1
  import type { DbDriver } from "./driver.ts";
2
+ import { type GrantSet } from "./grants-core.ts";
2
3
  export interface SiteRow {
3
4
  id: string;
4
5
  name: string;
5
6
  title: string | null;
6
7
  created_hlc: string;
8
+ /** Access register: exactly "public" = served without a token. Synced, so a
9
+ * peer can write ANY string here — never read it directly, go through
10
+ * isSitePublic (default-deny). */
11
+ visibility: string | null;
12
+ /** 1 = SPA fallback: extension-less misses serve index.html (status 200). */
13
+ spa: number;
14
+ /** Serialized GrantSet for the anonymous /sites/<name>/api/* surface. Synced
15
+ * register — never read raw, always through parseGrantSet (default-deny). */
16
+ public_grants: string | null;
7
17
  }
8
- export declare const SITE_COLS: readonly ["id", "name", "title", "created_hlc"];
18
+ export declare const SITE_COLS: readonly ["id", "name", "title", "created_hlc", "visibility", "spa", "public_grants"];
9
19
  export type FileEncoding = "utf8" | "base64" | "blob";
10
20
  export interface SiteFileRow {
11
21
  id: string;
@@ -16,8 +26,14 @@ export interface SiteFileRow {
16
26
  /** Inline text/base64, or a blob hash when encoding === "blob". */
17
27
  content: string | null;
18
28
  }
19
- /** Manifest entry — file metadata without the (potentially large) content. */
20
- export type SiteFileSummary = Omit<SiteFileRow, "content">;
29
+ /** Manifest entry — file metadata without the (potentially large) content.
30
+ * `size` is derived at query time (see listFiles), never stored. */
31
+ export type SiteFileSummary = Omit<SiteFileRow, "content"> & {
32
+ /** Served byte size: exact for utf8, ~exact for base64 (padding ignored),
33
+ * blob_cache lookup for blobs — null when the blob bytes aren't held
34
+ * locally (e.g. a browser replica, or an evicted cache entry). */
35
+ size: number | null;
36
+ };
21
37
  export declare const SITE_FILE_COLS: readonly ["id", "site_id", "path", "content_type", "encoding", "content"];
22
38
  export declare const SITE_FILE_SELECT: string;
23
39
  /** Guess a content type from a file path's extension; default octet-stream. */
@@ -38,7 +54,23 @@ export declare function normalizeSiteName(raw: string): string;
38
54
  * matter how the path was typed or percent-encoded. May return "" (caller decides).
39
55
  */
40
56
  export declare function normalizeSitePath(raw: string): string;
57
+ /**
58
+ * THE public/private decision point — every serve surface must route through
59
+ * here (default-deny). `visibility` is a synced CRDT register: any peer
60
+ * (including a malicious or future-versioned one) can write arbitrary strings
61
+ * into it, so only the exact string "public" opens the site; "PUBLIC", "true",
62
+ * garbage, and NULL all mean private.
63
+ */
64
+ export declare function isSitePublic(site: Pick<SiteRow, "visibility">): boolean;
41
65
  export declare function getSite(db: DbDriver, id: string): SiteRow | null;
66
+ export type SiteLifecycle = "live" | "tombstoned" | "absent";
67
+ /** Three-state existence probe. Repair/reconcile logic must act on positive
68
+ * tombstone evidence only: `absent` can mean the row simply has not replicated
69
+ * to this node yet, so destructive reactions to it would tear down state that
70
+ * is alive elsewhere. A half-materialized row (columns still NULL from
71
+ * out-of-order ingest) reads as `live` — the conservative answer for
72
+ * revocation decisions. */
73
+ export declare function siteLifecycle(db: DbDriver, id: string): SiteLifecycle;
42
74
  /** Most recently created live site with this name (URL routing). */
43
75
  export declare function getSiteByName(db: DbDriver, name: string): SiteRow | null;
44
76
  export declare function listSites(db: DbDriver): SiteRow[];
@@ -56,7 +88,32 @@ export declare function getFileRow(db: DbDriver, siteId: string, path: string):
56
88
  encoding: FileEncoding;
57
89
  content: string | null;
58
90
  } | null;
91
+ /**
92
+ * Resolve a request path to the row that should be served, GitHub-Pages style:
93
+ * "" / trailing "/" → index.html (same order as getFileRow: index resolution
94
+ * first, then normalization); a miss falls back to the site's own `404.html`
95
+ * (served with status 404) when it exists; a pure miss returns null (caller
96
+ * renders its built-in 404). Shared by every serve surface — server, share,
97
+ * browser replica (db-worker siteFile op), and the service worker — so online
98
+ * and offline 404 behavior stay identical.
99
+ *
100
+ * `opts.spa` (the sites.spa column): a miss on a path whose last segment has no
101
+ * extension falls back to index.html with status 200 — client-side routes like
102
+ * /sites/app/settings/profile render the app shell, while a missing asset
103
+ * (app.js, logo.png) still 404s honestly instead of serving HTML to a <script>.
104
+ * The SPA fallback runs before the 404.html fallback.
105
+ */
106
+ export declare function resolveSiteFileRow(db: DbDriver, siteId: string, path: string, opts?: {
107
+ spa?: boolean;
108
+ }): {
109
+ row: Pick<SiteFileRow, "content_type" | "encoding" | "content">;
110
+ status: 200 | 404;
111
+ } | null;
59
112
  export declare function listFiles(db: DbDriver, siteId: string): SiteFileSummary[];
113
+ /** The listFiles size derivation for one already-loaded row (the upload route
114
+ * returns the row it just wrote and must report the same size the manifest
115
+ * will). Kept in lockstep with the SQL CASE above. */
116
+ export declare function fileSizeOf(db: DbDriver, row: Pick<SiteFileRow, "encoding" | "content">): number | null;
60
117
  /** Binaries at or below this size store inline (base64); larger need a blob. */
61
118
  export declare const INLINE_LIMIT: number;
62
119
  /** Text-ish types store as readable utf8; everything else is binary. */
@@ -66,20 +123,50 @@ export declare function isTextType(contentType: string): boolean;
66
123
  * into the oplog, keeping replicas lean. */
67
124
  export declare function isImageType(contentType: string): boolean;
68
125
  export declare function toBytes(data: string | Uint8Array | ArrayBuffer): Uint8Array;
126
+ /** Portable base64 (no Buffer): for inline small-binary file content. */
127
+ export declare function bytesToBase64(bytes: Uint8Array): string;
128
+ /** Portable base64 decode (no Buffer) — inverse of bytesToBase64. */
129
+ export declare function base64ToBytes(b64: string): Uint8Array;
69
130
  export declare const createSite: (db: DbDriver, opts: {
70
131
  name: string;
71
132
  title?: string;
133
+ visibility?: "public" | "private";
72
134
  }) => SiteRow;
73
- /** Rename a site and/or change its title. Guards against duplicate names. */
135
+ /** Rename a site, change its title, and/or set visibility / SPA mode.
136
+ * Guards against duplicate names; visibility only accepts public|private. */
74
137
  export declare const updateSite: (db: DbDriver, id: string, opts: {
75
138
  name?: string;
76
139
  title?: string;
140
+ visibility?: "public" | "private";
141
+ spa?: boolean;
77
142
  }) => SiteRow;
143
+ /**
144
+ * Set (or clear, with null) a site's public data grants. The set is validated
145
+ * loudly here (this is the LOCAL write path — a peer can still sync junk, which
146
+ * readers default-deny via parseGrantSet) and stored in canonical serialized
147
+ * form. Grants only take effect while the site is visibility:public; setting
148
+ * them on a private site is allowed (they arm when the site goes public).
149
+ */
150
+ export declare const setSitePublicGrants: (db: DbDriver, siteId: string, grants: GrantSet | null) => SiteRow;
78
151
  export declare const deleteSite: (db: DbDriver, id: string) => boolean;
79
152
  /** Stable id for a (site, path) pair so re-uploads merge instead of duplicate. */
80
153
  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;
154
+ /**
155
+ * The live row at (site, path) when it already stores exactly this
156
+ * content_type/encoding/content triple — the skip-unchanged probe. Tombstoned
157
+ * rows never match (re-uploading the same bytes must still un-delete). putFile's
158
+ * blob branch also calls this with the content hash *before* touching the blob
159
+ * store, so an unchanged re-publish never re-marks a flushed blob as pending.
160
+ */
161
+ export declare function liveFileRowIfSame(db: DbDriver, siteId: string, cleanPath: string, contentType: string, encoding: FileEncoding, content: string): SiteFileRow | null;
162
+ /** Emit the register writes for one file (shared by inline + blob put paths).
163
+ * Skip-unchanged: when a live row already stores exactly this triple, nothing
164
+ * is emitted and the row returns with `changed: false` — an idempotent
165
+ * re-publish adds zero oplog rows on every peer. A tombstoned row always
166
+ * rewrites (`changed: true`) so same-byte re-uploads still un-delete. */
167
+ export declare function writeFileRow(db: DbDriver, siteId: string, cleanPath: string, contentType: string, encoding: FileEncoding, content: string): SiteFileRow & {
168
+ changed: boolean;
169
+ };
83
170
  /**
84
171
  * Upload/replace one file inline (utf8 text or small base64 binary) — portable,
85
172
  * so the browser replica authors sites offline. Binaries over INLINE_LIMIT need
@@ -88,8 +175,14 @@ export declare function writeFileRow(db: DbDriver, siteId: string, cleanPath: st
88
175
  export declare function putFileInline(db: DbDriver, siteId: string, path: string, opts: {
89
176
  data: string | Uint8Array | ArrayBuffer;
90
177
  contentType?: string;
91
- }): SiteFileRow;
178
+ }): SiteFileRow & {
179
+ changed: boolean;
180
+ };
92
181
  export declare const deleteFile: (db: DbDriver, siteId: string, path: string) => boolean;
182
+ /** Live-file counts for ALL sites in one GROUP BY (walks idx_site_files_site) —
183
+ * the site list uses this instead of a per-site fileCount N+1. Sites with no
184
+ * live files have no entry; callers default to 0. */
185
+ export declare function fileCounts(db: DbDriver): Map<string, number>;
93
186
  /** Count of live files per site (for the management list's file_count). */
94
187
  export declare function fileCount(db: DbDriver, siteId: string): number;
95
188
  //# 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":"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"}
1
+ {"version":3,"file":"sites-core.d.ts","sourceRoot":"","sources":["../../src/core/sites-core.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import type { DbDriver } from "./driver.ts";
2
- import { type SiteFileRow } from "./sites-core.ts";
2
+ import { type SiteFileRow, type FileEncoding } from "./sites-core.ts";
3
3
  export * from "./sites-core.ts";
4
4
  /** Upload or replace one file. utf8 text and small binaries ride the oplog via
5
5
  * putFileInline (portable); binaries over the inline limit offload to the
@@ -7,10 +7,73 @@ export * from "./sites-core.ts";
7
7
  export declare function putFile(db: DbDriver, siteId: string, path: string, opts: {
8
8
  data: string | Uint8Array | ArrayBuffer;
9
9
  contentType?: string;
10
- }): Promise<SiteFileRow>;
10
+ }): Promise<SiteFileRow & {
11
+ changed: boolean;
12
+ }>;
13
+ export interface PublishResult {
14
+ uploaded: string[];
15
+ unchanged: string[];
16
+ pruned: string[];
17
+ }
18
+ /**
19
+ * Publish a local directory into a site: every file under `dir` uploads via
20
+ * putFile, whose skip-unchanged probe makes a re-publish idempotent (zero
21
+ * oplog rows for files whose bytes didn't change). With `prune`, live remote
22
+ * paths that no longer exist locally are deleted afterwards (mirror mode) —
23
+ * opt-in because deletes are destructive, and reported in full as evidence.
24
+ *
25
+ * Uploads run through a small worker pool (default 8). This is safe because
26
+ * putFile's oplog writes happen synchronously inside withChangeGroup — its
27
+ * await points are only file reads and blob-store writes — so change groups
28
+ * from concurrent workers never interleave. Result arrays are path-sorted for
29
+ * stable output.
30
+ */
31
+ export declare function publishDirectory(db: DbDriver, siteId: string, dir: string, opts?: {
32
+ prune?: boolean;
33
+ concurrency?: number;
34
+ }): Promise<PublishResult>;
35
+ /** Decode a file row to its served bytes. utf8/base64 decode inline; a blob
36
+ * hash resolves on demand (local cache → HTTP peer → bucket) so a published
37
+ * asset whose local bytes were cache-evicted still serves from a bucket/peer
38
+ * instead of 404ing, consistent with /blob. resolveBlob touches the LRU on a
39
+ * local hit and caches any remote fetch. Bounded so a slow source can't hang
40
+ * the serve path (null on timeout; an in-flight fetch still finishes and
41
+ * populates the cache for the next request). */
42
+ export declare function decodeFileRow(db: DbDriver, row: Pick<SiteFileRow, "encoding" | "content">): Promise<Uint8Array | null>;
11
43
  /** Resolve a file to served bytes + content type. "" / trailing "/" → index.html. */
12
44
  export declare function getFileForServe(db: DbDriver, siteId: string, path: string): Promise<{
13
45
  contentType: string;
14
46
  bytes: Uint8Array;
15
47
  } | null>;
48
+ /**
49
+ * HTTP-serve metadata for one request path: the resolved row (index.html /
50
+ * 404.html rules from resolveSiteFileRow), its serve status, and a weak ETag —
51
+ * WITHOUT decoding content. The ETag comes from what the register already
52
+ * holds, so an If-None-Match hit can 304 before resolveBlob's (worst-case 5s)
53
+ * peer/bucket fan-out ever runs:
54
+ * - blob rows: the content field IS the content hash — use it directly;
55
+ * - utf8/base64 rows: Bun.hash over encoding + content (the encoding prefix
56
+ * keeps a text file and a base64 file with equal stored strings distinct).
57
+ * Weak (W/) because the same content may be re-encoded across
58
+ * representations, and we never serve byte-range requests off it.
59
+ */
60
+ export declare function getFileMetaForServe(db: DbDriver, siteId: string, path: string, opts?: {
61
+ spa?: boolean;
62
+ }): {
63
+ row: Pick<SiteFileRow, "content_type" | "encoding" | "content">;
64
+ status: 200 | 404;
65
+ etag: string;
66
+ } | null;
67
+ /**
68
+ * Cache-Control for a served site file. Everything is `private` today (every
69
+ * caller passes isPublic=false — served pages sit behind the master token or a
70
+ * capability slug, neither of which may enter a shared cache); the isPublic
71
+ * branch is pre-wired for Batch 4's visibility:public sites, where a CDN /
72
+ * reverse proxy may cache.
73
+ * - HTML: no-cache — always revalidate (ETag/304) so a republish shows up on
74
+ * the next navigation;
75
+ * - inline text assets (css/js/json…): short TTL + stale-while-revalidate;
76
+ * - blob assets: content-addressed and big — cache a while.
77
+ */
78
+ export declare function siteCacheControl(contentType: string, encoding: FileEncoding, isPublic: boolean): string;
16
79
  //# sourceMappingURL=sites.d.ts.map
@@ -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;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"}
1
+ {"version":3,"file":"sites.d.ts","sourceRoot":"","sources":["../../src/core/sites.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAG5C,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,YAAY,EAelB,MAAM,iBAAiB,CAAC;AAezB,cAAc,iBAAiB,CAAC;AAQhC;;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,GAAG;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAyB7C;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GACnD,OAAO,CAAC,aAAa,CAAC,CA8CxB;AASD;;;;;;iDAMiD;AACjD,wBAAsB,aAAa,CACjC,EAAE,EAAE,QAAQ,EACZ,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,UAAU,GAAG,SAAS,CAAC,GAC7C,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAQ5B;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,CAM5D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE;IAAE,GAAG,CAAC,EAAE,OAAO,CAAA;CAAO,GAC3B;IACD,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,cAAc,GAAG,UAAU,GAAG,SAAS,CAAC,CAAC;IAChE,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,IAAI,CAYP;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,OAAO,GAChB,MAAM,CAWR"}
@@ -0,0 +1,26 @@
1
+ /** Constant-time string equality (length leaks, content never). Shared by the
2
+ * edge owner-token check and the password-verifier compare. */
3
+ export declare function timingSafeEq(a: string, b: string): boolean;
4
+ export type VerifyTurnstile = (secret: string, token: string, ip: string | null) => Promise<boolean>;
5
+ /** Cloudflare Turnstile siteverify. Fails closed on any network/parse error —
6
+ * including the 5s timeout: this runs on the guest-write request path, so a
7
+ * hung siteverify endpoint must 401 fast, not pile up handlers/sockets. */
8
+ export declare const siteverify: VerifyTurnstile;
9
+ /** The per-grant anti-abuse secrets (a subset of edge-config's DropKnobs and the
10
+ * edge D1 `drops` row — structurally compatible with both). */
11
+ export interface AntiAbuseKnobs {
12
+ turnstileSecret?: string | null;
13
+ passwordVerifier?: string | null;
14
+ }
15
+ /**
16
+ * Throw MhError("auth") if the request fails the grant's configured anti-abuse
17
+ * knobs; no knobs → no-op (open submission). Reads the same headers the drop SDK
18
+ * sends: `x-turnstile-token` (verified via siteverify) and `x-drop-pass` (the
19
+ * PBKDF2 verifier the page derived from (password, published salt), compared
20
+ * constant-time — the password itself never travels).
21
+ */
22
+ export declare function assertAntiAbuse(knobs: AntiAbuseKnobs | null | undefined, req: Request, opts?: {
23
+ verifyTurnstile?: VerifyTurnstile;
24
+ ip?: string | null;
25
+ }): Promise<void>;
26
+ //# sourceMappingURL=anti-abuse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anti-abuse.d.ts","sourceRoot":"","sources":["../../../src/core/sync/anti-abuse.ts"],"names":[],"mappings":"AAWA;gEACgE;AAChE,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAO1D;AAED,MAAM,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAErG;;4EAE4E;AAC5E,eAAO,MAAM,UAAU,EAAE,eAaxB,CAAC;AAEF;gEACgE;AAChE,MAAM,WAAW,cAAc;IAC7B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,EACxC,GAAG,EAAE,OAAO,EACZ,IAAI,GAAE;IAAE,eAAe,CAAC,EAAE,eAAe,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAO,GACnE,OAAO,CAAC,IAAI,CAAC,CAaf"}
@@ -1,4 +1,5 @@
1
1
  import type { Database } from "bun:sqlite";
2
+ import { injectRuntimeTag } from "../inject-runtime.ts";
2
3
  export interface AuthConfig {
3
4
  debug: boolean;
4
5
  staticToken: string | null;
@@ -16,6 +17,13 @@ export interface AuthConfig {
16
17
  */
17
18
  export declare function queryTokenCookie(req: Request, url: URL, cfg: AuthConfig): string | null;
18
19
  export declare function extractToken(req: Request, url: URL): string | null;
20
+ /** An EXPLICITLY presented credential (Bearer header or ?token=) — never the
21
+ * ambient cookie. State-changing /api requests require this: /sites/ pages
22
+ * run same-origin, so their fetches ride the owner's mh_token cookie
23
+ * automatically; requiring an explicit token closes that ambient-authority
24
+ * write path without touching cookie-only GET sub-resources (img,
25
+ * EventSource) that cannot carry headers. */
26
+ export declare function explicitToken(req: Request, url: URL): string | null;
19
27
  /** Whether auth is on at all (so the gate runs and the fetch shim is injected). */
20
28
  export declare function authActive(cfg: AuthConfig): boolean;
21
29
  /** The currently-valid token and its expiry, or null when auth is off. */
@@ -42,13 +50,23 @@ export declare function renewToken(req: Request, url: URL, cfg: AuthConfig): {
42
50
  export declare function wantsHtml(req: Request): boolean;
43
51
  declare const HTML_HEADERS: {
44
52
  "content-type": string;
53
+ "referrer-policy": string;
45
54
  };
46
55
  /** Self-contained token gate: themed to match the WebUI (light/dark, metahub
47
56
  * mark), validates the token before entering, and stores it to localStorage +
48
57
  * cookie on success. No stylesheet/bundle — it runs inside the auth gate. */
49
58
  export declare function unlockPage(): string;
50
- /** Insert the runtime into an HTML document (right after <head>, else prepend). */
51
- export declare function injectShim(html: string): string;
59
+ /**
60
+ * The injected page runtime (built from src/webui/runtime.ts, served at
61
+ * /mh-runtime.js). Carries what the old inline fetch shim did — same-origin
62
+ * Bearer attach + transparent 401 renewal — plus the offline machinery:
63
+ * service-worker registration and the local-replica RPC bridge that lets
64
+ * hosted site pages read/write hub data with no network. Loaded synchronously
65
+ * (classic script, head-first) so fetch is wrapped before page code runs.
66
+ * The tag + insertion rule live in core/inject-runtime.ts, shared with the
67
+ * service worker's and offline bootstrap's injectors.
68
+ */
69
+ export { injectRuntimeTag as injectShim };
52
70
  /** Inject the page runtime into HTML responses. Unconditional (unlike the old
53
71
  * token-only shim): the offline bridge matters even in --debug mode where
54
72
  * auth is off — the token half simply no-ops without a stored token.
@@ -57,6 +75,16 @@ export declare function injectShim(html: string): string;
57
75
  * query param, persist that token as the mh_token cookie on this HTML response
58
76
  * so the browser's follow-up asset requests (/webui.css, /webui.js) carry it. */
59
77
  export declare function withShim(res: Response, cfg: AuthConfig, req?: Request, url?: URL): Promise<Response>;
78
+ /** A `?token=` navigation must not leave the credential in the address bar
79
+ * (bookmarks, screenshots, same-origin Referer, logs): persist the cookie,
80
+ * then 302 to the same URL with the token stripped. Only HTML navigations —
81
+ * API calls carrying ?token= are left alone. Returns null when not applicable. */
82
+ export declare function tokenStripRedirect(req: Request, url: URL, cfg: AuthConfig): Response | null;
83
+ /** Cookie ambient authority is READ-ONLY: a state-changing /api request must
84
+ * present its credential explicitly (Bearer/query). Same-origin site pages
85
+ * otherwise mutate the workspace on the owner's cookie without ever holding
86
+ * the token. Returns the 401 to serve, or null to continue. */
87
+ export declare function cookieMutationRejection(req: Request, url: URL, cfg: AuthConfig): Response | null;
60
88
  export declare function unauthorized(): Response;
61
89
  export { HTML_HEADERS };
62
90
  //# 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;;;;;;;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;AA0FpE;;8EAE8E;AAC9E,wBAAgB,UAAU,IAAI,MAAM,CAoHnC;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"}
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;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AASxD,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;;;;;8CAK8C;AAC9C,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,IAAI,CAInE;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;AAKD,QAAA,MAAM,YAAY;;;CAGjB,CAAC;AA0FF;;8EAE8E;AAC9E,wBAAgB,UAAU,IAAI,MAAM,CAoHnC;AAED;;;;;;;;;GASG;AACH,OAAO,EAAE,gBAAgB,IAAI,UAAU,EAAE,CAAC;AAE1C;;;;;;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,CAenB;AAED;;;mFAGmF;AACnF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,UAAU,GAAG,QAAQ,GAAG,IAAI,CAW3F;AAED;;;gEAGgE;AAChE,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,UAAU,GACd,QAAQ,GAAG,IAAI,CAMjB;AAED,wBAAgB,YAAY,IAAI,QAAQ,CAEvC;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -1 +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"}
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;AAmDvE;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAwBrF;AAgBD,eAAO,MAAM,UAAU,EAAE,KAAK,EAoE7B,CAAC"}
@@ -0,0 +1,54 @@
1
+ import type { CfApiTarget } from "./edge-config.ts";
2
+ /** Does the named Worker script exist? Used to prevent adopting or overwriting
3
+ * a same-name script that this deployment did not create. */
4
+ export declare function workerDeployment(cfg: CfApiTarget): Promise<{
5
+ exists: boolean;
6
+ deploymentId: string | null;
7
+ }>;
8
+ export declare function workerExists(cfg: CfApiTarget): Promise<boolean>;
9
+ /** Does the named D1 database exist? */
10
+ export declare function d1Exists(cfg: CfApiTarget): Promise<boolean>;
11
+ export interface D1DatabaseSummary {
12
+ id: string;
13
+ name: string;
14
+ createdAt: string | null;
15
+ }
16
+ /** Exact-name lookup used only by the crash-resume path. D1's API accepts a
17
+ * name filter but we still filter the result exactly before adopting it. */
18
+ export declare function d1DatabasesByName(cfg: Pick<CfApiTarget, "accountId" | "apiToken">, name: string): Promise<D1DatabaseSummary[]>;
19
+ /** Does the named R2 bucket exist? */
20
+ export declare function r2BucketExists(cfg: Pick<CfApiTarget, "accountId" | "apiToken">, name: string): Promise<boolean>;
21
+ /** Create the named R2 bucket. Mirrors createD1Database's stance: a same-name
22
+ * bucket that already exists is refused, never silently adopted (mh only
23
+ * touches resources this flow itself named and created; the resume path in
24
+ * edge-service tolerates its OWN half-finished creation via the persisted
25
+ * progress record, not here). */
26
+ export declare function createR2Bucket(cfg: Pick<CfApiTarget, "accountId" | "apiToken">, name: string): Promise<void>;
27
+ /** The account's S3 endpoint for R2 (path-style; isVirtualHostedStyle
28
+ * auto-detects false for it). */
29
+ export declare function r2Endpoint(accountId: string): string;
30
+ /** Run SQL against the D1 database (schema migration). Statements are sent one
31
+ * at a time so a mid-script failure reports the exact statement. */
32
+ export declare function d1Exec(cfg: CfApiTarget, sqlScript: string): Promise<void>;
33
+ /** Upload the edge worker module (multipart metadata + script). Declarative
34
+ * `exports` + `keep_bindings:["secret_text"]` so a re-deploy never wipes the
35
+ * OWNER_TOKEN secret set separately below. */
36
+ export declare function uploadEdgeWorker(cfg: CfApiTarget, script: string, deploymentId: string): Promise<void>;
37
+ /** Set a secret on the worker via the dedicated secrets endpoint (spike ⑥
38
+ * recommendation: script re-deploys then never carry the secret in metadata). */
39
+ export declare function putWorkerSecret(cfg: CfApiTarget, name: string, text: string): Promise<void>;
40
+ /** The account's workers.dev subdomain — derives the worker's default endpoint. */
41
+ export declare function workersDevSubdomain(cfg: CfApiTarget): Promise<string>;
42
+ /** Create a dedicated D1 database and return its stable UUID. Cloudflare's
43
+ * conflict response is surfaced loudly; callers never adopt a same-name DB. */
44
+ export declare function createD1Database(cfg: Pick<CfApiTarget, "accountId" | "apiToken">, name: string): Promise<{
45
+ id: string;
46
+ name: string;
47
+ }>;
48
+ /** Return the account workers.dev subdomain, or null when none exists yet. */
49
+ export declare function maybeWorkersDevSubdomain(cfg: CfApiTarget): Promise<string | null>;
50
+ /** Create the account-level workers.dev subdomain. */
51
+ export declare function createWorkersDevSubdomain(cfg: CfApiTarget, subdomain: string): Promise<string>;
52
+ /** Publish a script on the account's workers.dev domain. */
53
+ export declare function enableWorkerSubdomain(cfg: CfApiTarget): Promise<void>;
54
+ //# sourceMappingURL=cf-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cf-api.d.ts","sourceRoot":"","sources":["../../../src/core/sync/cf-api.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAqCpD;8DAC8D;AAC9D,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,WAAW,GACf,OAAO,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAc3D;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAErE;AAED,wCAAwC;AACxC,wBAAsB,QAAQ,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAKjE;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;4EAC4E;AAC5E,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,UAAU,CAAC,EAChD,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAgB9B;AAQD,sCAAsC;AACtC,wBAAsB,cAAc,CAClC,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,UAAU,CAAC,EAChD,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,CAAC,CASlB;AAED;;;;kCAIkC;AAClC,wBAAsB,cAAc,CAClC,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,UAAU,CAAC,EAChD,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAWf;AAED;kCACkC;AAClC,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;qEACqE;AACrE,wBAAsB,MAAM,CAAC,GAAG,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAY/E;AAED;;+CAE+C;AAC/C,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CA2Bf;AAED;kFACkF;AAClF,wBAAsB,eAAe,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWjG;AAED,mFAAmF;AACnF,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ3E;AAED;gFACgF;AAChF,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,UAAU,CAAC,EAChD,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAkBvC;AAED,8EAA8E;AAC9E,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CASvF;AAED,sDAAsD;AACtD,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,WAAW,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CAgBjB;AAED,4DAA4D;AAC5D,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAW3E"}
@@ -0,0 +1,91 @@
1
+ /** Registered OAuth client id, resolved from two layers in order:
2
+ *
3
+ * 1. `METAHUB_CF_OAUTH_CLIENT_ID` — a *runtime* env var. Self-hosters who
4
+ * register their own private client set this on the machine; it works on
5
+ * any install, shipped binaries included, and always wins.
6
+ * 2. `MH_BUILD_CF_OAUTH_CLIENT_ID` — *baked in at build time*. The bundler
7
+ * inlines every `MH_BUILD_*` reference as a string literal (`--env
8
+ * 'MH_BUILD_*'` in scripts/build.ts, scripts/compile-binaries.ts and
9
+ * apps/desktop/scripts/build-sidecars.ts), so official builds carry the id
10
+ * even though the end user's machine has no such variable. It is a
11
+ * deliberately *different* name from (1) — sharing one name would let the
12
+ * inliner freeze the override into a constant and kill layer 1.
13
+ *
14
+ * Both empty (a from-source run, or a fork that never registered a client) →
15
+ * OAuth login is unavailable and callers fall back to manual token entry. */
16
+ export declare const CF_OAUTH_CLIENT_ID: string;
17
+ /** Minimal scopes the Edge deploy needs, using Cloudflare's self-managed OAuth
18
+ * scope identifiers (dotted, e.g. `d1.write` — NOT the wrangler `d1:write`
19
+ * style). Both read + write are requested for Workers Scripts and D1 because
20
+ * the deploy pipeline does GETs (existence checks, workers.dev subdomain
21
+ * lookup) as well as writes. `account-settings.read` backs account discovery.
22
+ * NOTE: the account-level /workers/subdomain PUT is assumed covered by
23
+ * workers-scripts.write (no dedicated subdomain scope exists); if a deploy
24
+ * fails there with a permission error, add the missing scope here + in the
25
+ * registered client. */
26
+ export declare const CF_OAUTH_SCOPES: string[];
27
+ export interface CfToken {
28
+ accessToken: string;
29
+ refreshToken: string | null;
30
+ expiresIn: number | null;
31
+ }
32
+ export interface CfAccount {
33
+ id: string;
34
+ name: string;
35
+ }
36
+ /** Is OAuth login available (a client id is configured)? */
37
+ export declare function cfOAuthConfigured(clientId?: string): boolean;
38
+ /** Generate a PKCE verifier + S256 challenge. verifier is 32 random bytes
39
+ * base64url-encoded (43 chars, ~256 bits); challenge = base64url(SHA-256(verifier)). */
40
+ export declare function pkce(): Promise<{
41
+ verifier: string;
42
+ challenge: string;
43
+ }>;
44
+ export declare function buildAuthUrl(p: {
45
+ clientId: string;
46
+ redirectUri: string;
47
+ challenge: string;
48
+ state: string;
49
+ scopes: string[];
50
+ authEndpoint?: string;
51
+ }): string;
52
+ export declare function buildTokenRequestBody(p: {
53
+ clientId: string;
54
+ code: string;
55
+ verifier: string;
56
+ redirectUri: string;
57
+ }): string;
58
+ /** Parse the token endpoint's JSON response into a CfToken. */
59
+ export declare function parseTokenResponse(data: unknown): CfToken;
60
+ /** Parse a Cloudflare /accounts result into id/name pairs. */
61
+ export declare function parseAccounts(data: unknown): CfAccount[];
62
+ /** Discover the accounts the token can act on, so the user need not paste an
63
+ * Account ID. Single account → auto-select; multiple → caller prompts. */
64
+ export declare function discoverAccounts(accessToken: string): Promise<CfAccount[]>;
65
+ /** Open a URL in the user's default browser (best-effort; caller should also
66
+ * print the URL as a fallback). */
67
+ export declare function openBrowser(url: string): void;
68
+ export interface CfLoginHandle {
69
+ /** Consent URL to open in a browser. */
70
+ authUrl: string;
71
+ /** The loopback redirect the temporary listener is bound to. */
72
+ redirectUri: string;
73
+ /** Resolves once the browser redirect is caught and the code is exchanged.
74
+ * Rejects on state mismatch, user-denied consent, timeout, or exchange error.
75
+ * Always tears down the listener. */
76
+ waitForToken(): Promise<CfToken>;
77
+ /** Tear down the listener without waiting (e.g. modal closed). */
78
+ cancel(): void;
79
+ }
80
+ /** Start an OAuth login: bind a temporary loopback listener, build the consent
81
+ * URL. The caller opens `authUrl` (CLI/desktop) or hands it to the browser
82
+ * (WebUI), then awaits `waitForToken()`. Endpoints/clientId are injectable for
83
+ * tests. */
84
+ export declare function startCfLogin(opts?: {
85
+ clientId?: string;
86
+ scopes?: string[];
87
+ authEndpoint?: string;
88
+ tokenEndpoint?: string;
89
+ timeoutMs?: number;
90
+ }): Promise<CfLoginHandle>;
91
+ //# sourceMappingURL=cf-oauth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cf-oauth.d.ts","sourceRoot":"","sources":["../../../src/core/sync/cf-oauth.ts"],"names":[],"mappings":"AAiBA;;;;;;;;;;;;;;8EAc8E;AAC9E,eAAO,MAAM,kBAAkB,QAC0D,CAAC;AAM1F;;;;;;;;yBAQyB;AACzB,eAAO,MAAM,eAAe,UAW3B,CAAC;AAKF,MAAM,WAAW,OAAO;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED,4DAA4D;AAC5D,wBAAgB,iBAAiB,CAAC,QAAQ,SAAqB,GAAG,OAAO,CAExE;AAID;yFACyF;AACzF,wBAAsB,IAAI,IAAI,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAM7E;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,MAAM,CAYT;AAED,wBAAgB,qBAAqB,CAAC,CAAC,EAAE;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,MAAM,CAQT;AAED,+DAA+D;AAC/D,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAezD;AAED,8DAA8D;AAC9D,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,EAAE,CAKxD;AA2BD;2EAC2E;AAC3E,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAYhF;AAED;oCACoC;AACpC,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAY7C;AAED,MAAM,WAAW,aAAa;IAC5B,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB;;0CAEsC;IACtC,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IACjC,kEAAkE;IAClE,MAAM,IAAI,IAAI,CAAC;CAChB;AAED;;;aAGa;AACb,wBAAsB,YAAY,CAAC,IAAI,GAAE;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC,aAAa,CAAC,CAyE9B"}
@@ -1,4 +1,5 @@
1
1
  import type { DbDriver } from "../driver.ts";
2
+ import { type Change } from "../crdt.ts";
2
3
  export interface SyncResult {
3
4
  pushed: number;
4
5
  pulled: number;
@@ -17,7 +18,18 @@ export interface SyncOpts {
17
18
  pullLimit?: number;
18
19
  /** Datasets this replica opts out of (partial replica, e.g. site_files). */
19
20
  excludeDatasets?: string[];
21
+ /** Hard transport budget. Every sync is bounded even when the peer accepts
22
+ * the TCP connection but never replies. */
23
+ timeoutMs?: number;
20
24
  }
25
+ /** After a pull, advance the push cursor across the CONTIGUOUS prefix of
26
+ * newly-appended oplog rows that came out of this round's response: the peer
27
+ * obviously holds what it just sent us, so those rows must not count as
28
+ * "unpushed" (they made status surfaces flash BEHIND after every successful
29
+ * pull, until the next round skipped them). The walk stops at the first row
30
+ * NOT in the response — e.g. a concurrent local write — which genuinely is
31
+ * unpushed and must keep the peer looking behind. Exported for tests. */
32
+ export declare function advanceAckedPrefix(db: DbDriver, fromSeq: number, received: Change[]): number;
21
33
  /**
22
34
  * Run one push/pull round against a peer server. A single round is bidirectional
23
35
  * (pushes local changes, pulls remote ones). The token defaults to the credential
@@ -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;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"}
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;AAE7C,OAAO,EAA2B,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AAuBlE,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;IAC3B;+CAC2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAKD;;;;;;yEAMyE;AACzE,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAgB5F;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,EAAE,EAAE,QAAQ,EACZ,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,QAAQ,GAAG,MAAW,GAC3B,OAAO,CAAC,UAAU,CAAC,CA2CrB"}
@@ -0,0 +1,8 @@
1
+ import type { DbDriver } from "../driver.ts";
2
+ import { type DataPlace, type DataMapState } from "../data-map.ts";
3
+ export interface DataMap {
4
+ state: DataMapState;
5
+ places: DataPlace[];
6
+ }
7
+ export declare function dataMap(db: DbDriver): DataMap;
8
+ //# sourceMappingURL=data-map-db.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-map-db.d.ts","sourceRoot":"","sources":["../../../src/core/sync/data-map-db.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAKL,KAAK,SAAS,EACd,KAAK,YAAY,EAClB,MAAM,gBAAgB,CAAC;AAMxB,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,SAAS,EAAE,CAAC;CACrB;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CAwD7C"}