@tensorix/metahub 0.3.2 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) 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 +16716 -8375
  6. package/dist/cli.js.map +110 -60
  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/properties.d.ts +8 -0
  44. package/dist/core/properties.d.ts.map +1 -1
  45. package/dist/core/records.d.ts +31 -0
  46. package/dist/core/records.d.ts.map +1 -1
  47. package/dist/core/schema-init.d.ts +19 -2
  48. package/dist/core/schema-init.d.ts.map +1 -1
  49. package/dist/core/schema.d.ts +1 -1
  50. package/dist/core/schema.d.ts.map +1 -1
  51. package/dist/core/shares.d.ts +15 -0
  52. package/dist/core/shares.d.ts.map +1 -1
  53. package/dist/core/site-channel-lifecycle.d.ts +10 -0
  54. package/dist/core/site-channel-lifecycle.d.ts.map +1 -0
  55. package/dist/core/site-channel-store.d.ts +120 -0
  56. package/dist/core/site-channel-store.d.ts.map +1 -0
  57. package/dist/core/site-channels.d.ts +65 -0
  58. package/dist/core/site-channels.d.ts.map +1 -0
  59. package/dist/core/sites-core.d.ts +100 -7
  60. package/dist/core/sites-core.d.ts.map +1 -1
  61. package/dist/core/sites.d.ts +65 -2
  62. package/dist/core/sites.d.ts.map +1 -1
  63. package/dist/core/sync/anti-abuse.d.ts +26 -0
  64. package/dist/core/sync/anti-abuse.d.ts.map +1 -0
  65. package/dist/core/sync/auth.d.ts +30 -2
  66. package/dist/core/sync/auth.d.ts.map +1 -1
  67. package/dist/core/sync/blob-routes.d.ts.map +1 -1
  68. package/dist/core/sync/cf-api.d.ts +54 -0
  69. package/dist/core/sync/cf-api.d.ts.map +1 -0
  70. package/dist/core/sync/cf-oauth.d.ts +91 -0
  71. package/dist/core/sync/cf-oauth.d.ts.map +1 -0
  72. package/dist/core/sync/client.d.ts +12 -0
  73. package/dist/core/sync/client.d.ts.map +1 -1
  74. package/dist/core/sync/data-map-db.d.ts +8 -0
  75. package/dist/core/sync/data-map-db.d.ts.map +1 -0
  76. package/dist/core/sync/devices.d.ts +65 -0
  77. package/dist/core/sync/devices.d.ts.map +1 -0
  78. package/dist/core/sync/drop-host.d.ts +40 -0
  79. package/dist/core/sync/drop-host.d.ts.map +1 -0
  80. package/dist/core/sync/drop-keys.d.ts +64 -0
  81. package/dist/core/sync/drop-keys.d.ts.map +1 -0
  82. package/dist/core/sync/drop-protocol.d.ts +94 -0
  83. package/dist/core/sync/drop-protocol.d.ts.map +1 -0
  84. package/dist/core/sync/drop-pull.d.ts +67 -0
  85. package/dist/core/sync/drop-pull.d.ts.map +1 -0
  86. package/dist/core/sync/drop-wire.d.ts +39 -0
  87. package/dist/core/sync/drop-wire.d.ts.map +1 -0
  88. package/dist/core/sync/e2ee.d.ts +3 -0
  89. package/dist/core/sync/e2ee.d.ts.map +1 -1
  90. package/dist/core/sync/edge-config.d.ts +77 -0
  91. package/dist/core/sync/edge-config.d.ts.map +1 -0
  92. package/dist/core/sync/edge-connect.d.ts +13 -0
  93. package/dist/core/sync/edge-connect.d.ts.map +1 -0
  94. package/dist/core/sync/edge-service.d.ts +100 -0
  95. package/dist/core/sync/edge-service.d.ts.map +1 -0
  96. package/dist/core/sync/grants-routes.d.ts +46 -0
  97. package/dist/core/sync/grants-routes.d.ts.map +1 -0
  98. package/dist/core/sync/guest-session.d.ts +29 -0
  99. package/dist/core/sync/guest-session.d.ts.map +1 -0
  100. package/dist/core/sync/html-escape.d.ts +2 -0
  101. package/dist/core/sync/html-escape.d.ts.map +1 -0
  102. package/dist/core/sync/http-status.d.ts +14 -0
  103. package/dist/core/sync/http-status.d.ts.map +1 -0
  104. package/dist/core/sync/http-util.d.ts +6 -0
  105. package/dist/core/sync/http-util.d.ts.map +1 -0
  106. package/dist/core/sync/pairing.d.ts +9 -9
  107. package/dist/core/sync/pairing.d.ts.map +1 -1
  108. package/dist/core/sync/partition.d.ts +77 -0
  109. package/dist/core/sync/partition.d.ts.map +1 -0
  110. package/dist/core/sync/peers-routes.d.ts.map +1 -1
  111. package/dist/core/sync/peers.d.ts +77 -0
  112. package/dist/core/sync/peers.d.ts.map +1 -1
  113. package/dist/core/sync/protocol.d.ts +2 -0
  114. package/dist/core/sync/protocol.d.ts.map +1 -1
  115. package/dist/core/sync/rate-limit.d.ts +20 -0
  116. package/dist/core/sync/rate-limit.d.ts.map +1 -0
  117. package/dist/core/sync/recovery.d.ts +9 -0
  118. package/dist/core/sync/recovery.d.ts.map +1 -0
  119. package/dist/core/sync/room-client.d.ts +50 -0
  120. package/dist/core/sync/room-client.d.ts.map +1 -0
  121. package/dist/core/sync/room-peer.d.ts +62 -0
  122. package/dist/core/sync/room-peer.d.ts.map +1 -0
  123. package/dist/core/sync/room-protocol.d.ts +130 -0
  124. package/dist/core/sync/room-protocol.d.ts.map +1 -0
  125. package/dist/core/sync/room-serve.d.ts +38 -0
  126. package/dist/core/sync/room-serve.d.ts.map +1 -0
  127. package/dist/core/sync/room-url.d.ts +4 -0
  128. package/dist/core/sync/room-url.d.ts.map +1 -0
  129. package/dist/core/sync/routes.d.ts +4 -1
  130. package/dist/core/sync/routes.d.ts.map +1 -1
  131. package/dist/core/sync/seal.d.ts +22 -0
  132. package/dist/core/sync/seal.d.ts.map +1 -0
  133. package/dist/core/sync/server.d.ts +7 -0
  134. package/dist/core/sync/server.d.ts.map +1 -1
  135. package/dist/core/sync/share-actions.d.ts +55 -6
  136. package/dist/core/sync/share-actions.d.ts.map +1 -1
  137. package/dist/core/sync/share-export.d.ts +14 -0
  138. package/dist/core/sync/share-export.d.ts.map +1 -1
  139. package/dist/core/sync/share-render.d.ts +9 -1
  140. package/dist/core/sync/share-render.d.ts.map +1 -1
  141. package/dist/core/sync/share-serve.d.ts +5 -1
  142. package/dist/core/sync/share-serve.d.ts.map +1 -1
  143. package/dist/core/sync/site-channel-reconcile.d.ts +26 -0
  144. package/dist/core/sync/site-channel-reconcile.d.ts.map +1 -0
  145. package/dist/core/sync/site-publish-recovery.d.ts +32 -0
  146. package/dist/core/sync/site-publish-recovery.d.ts.map +1 -0
  147. package/dist/core/sync/site-reachability.d.ts +13 -0
  148. package/dist/core/sync/site-reachability.d.ts.map +1 -0
  149. package/dist/core/sync/sites-routes.d.ts.map +1 -1
  150. package/dist/core/sync/sites-serve.d.ts +24 -1
  151. package/dist/core/sync/sites-serve.d.ts.map +1 -1
  152. package/dist/core/sync/storage-s3-bun.d.ts +1 -24
  153. package/dist/core/sync/storage-s3-bun.d.ts.map +1 -1
  154. package/dist/core/sync/storage-s3-sign.d.ts +43 -0
  155. package/dist/core/sync/storage-s3-sign.d.ts.map +1 -0
  156. package/dist/core/sync/storage.d.ts +59 -0
  157. package/dist/core/sync/storage.d.ts.map +1 -1
  158. package/dist/db-worker.js +206 -76
  159. package/dist/edge-worker.js +4038 -0
  160. package/dist/index.js +13715 -7064
  161. package/dist/index.js.map +88 -42
  162. package/dist/metahub-sdk.js +10 -1
  163. package/dist/mh-runtime.js +1 -1
  164. package/dist/room/do-driver.d.ts +30 -0
  165. package/dist/room/do-driver.d.ts.map +1 -0
  166. package/dist/sw.js +10 -1
  167. package/dist/webui/server/edge-routes.d.ts +3 -0
  168. package/dist/webui/server/edge-routes.d.ts.map +1 -0
  169. package/dist/webui/server/json-handler.d.ts +4 -0
  170. package/dist/webui/server/json-handler.d.ts.map +1 -0
  171. package/dist/webui/server/routes.d.ts.map +1 -1
  172. package/dist/webui/server/share-routes.d.ts.map +1 -1
  173. package/dist/webui/server/site-hosting-routes.d.ts +7 -0
  174. package/dist/webui/server/site-hosting-routes.d.ts.map +1 -0
  175. package/dist/webui.js +208 -147
  176. package/dist/workers/edge-worker.d.ts +66 -0
  177. package/dist/workers/edge-worker.d.ts.map +1 -0
  178. package/dist/workers/room.d.ts +34 -0
  179. package/dist/workers/room.d.ts.map +1 -0
  180. package/package.json +2 -2
@@ -0,0 +1,130 @@
1
+ import type { DbDriver } from "../driver.ts";
2
+ import { type Change } from "../crdt.ts";
3
+ import type { RecordRow } from "../records.ts";
4
+ import { type RowKey } from "./partition.ts";
5
+ export declare const ROOM_PROTOCOL_VERSION = 1;
6
+ export type ShareState = "active" | "expired";
7
+ /** Owner → room, one sync round. `changes` is the partition increment plus
8
+ * full-row winner baselines for rows that just entered (overlap is fine —
9
+ * the room oplog's UNIQUE dedups). `since` is the room-side seq cursor for
10
+ * the guest-op pull AND the ack that lets the room GC deferred guest oplog
11
+ * rows of evicted rows. `members`, when present, is the authoritative member
12
+ * key set (digest-mismatch reconciliation): the room locally deletes every
13
+ * partition row not listed. */
14
+ export interface OwnerSyncRequest {
15
+ protocol: number;
16
+ mh_version?: string;
17
+ node_id: string;
18
+ since: number;
19
+ changes: Change[];
20
+ evict: RowKey[];
21
+ members?: RowKey[];
22
+ digest?: string;
23
+ }
24
+ /** Room → owner. `changes` are guest-authored ops after `since` (never any
25
+ * other author), paged — `more` says the page was truncated and the owner
26
+ * should sync again promptly. `need_baseline` lists rows the room holds
27
+ * incompletely (orphaned by a shadow split) for the owner to re-judge.
28
+ * `need_blobs` lists site-file blob hashes the room lacks (chunked upload
29
+ * channel, /owner/blob). */
30
+ export interface OwnerSyncResponse {
31
+ protocol: number;
32
+ node_id: string;
33
+ changes: Change[];
34
+ cursor: number;
35
+ /** The guest pull was truncated at the page limit — more rows are queued. */
36
+ more?: boolean;
37
+ need_baseline: RowKey[];
38
+ need_blobs: string[];
39
+ digest?: string;
40
+ share_state: ShareState;
41
+ }
42
+ export interface RoomConfig {
43
+ slug: string;
44
+ /** The room's own node identity (meta.node_id) — clock owner, never an author. */
45
+ roomNode: string;
46
+ /** The share's base guest node id; per-visitor sub ids are `<base>-<rand6>`. */
47
+ guestBase: string;
48
+ /** Serialized GrantSet snapshot (read through parseGrantSet, default-deny). */
49
+ grants: string;
50
+ pwHash?: string | null;
51
+ pwSalt?: string | null;
52
+ expiresAt?: number | null;
53
+ state: ShareState;
54
+ }
55
+ export interface RoomProvision {
56
+ slug: string;
57
+ guestBase: string;
58
+ grants: string;
59
+ pwHash?: string | null;
60
+ pwSalt?: string | null;
61
+ expiresAt?: number | null;
62
+ /** Defaults to `room-<slug>`. */
63
+ roomNode?: string;
64
+ }
65
+ /** Bring a fresh (or reopened) room database to shape and store its config.
66
+ * Idempotent; re-provisioning updates the config but keeps the node identity
67
+ * and clock (HLCs already issued must stay monotonic). */
68
+ export declare function initRoomDb(db: DbDriver, prov: RoomProvision): RoomConfig;
69
+ export declare function readRoomConfig(db: DbDriver): RoomConfig;
70
+ /** Flip the share state (revocation propagates as "expired"; the physical
71
+ * destroy — DO deleteAll — is the C2 host's job). */
72
+ export declare function setRoomState(db: DbDriver, state: ShareState): void;
73
+ /** Refresh the grants snapshot (owner re-granted; takes effect immediately
74
+ * for guest writes — pulls/pushes are unaffected, the owner re-scopes those). */
75
+ export declare function setRoomGrants(db: DbDriver, grants: string): void;
76
+ export declare function roomExpired(cfg: RoomConfig, now?: number): boolean;
77
+ /** Chunk size cap enforced at the upload endpoint (DO row limit is ~2MB). */
78
+ export declare const ROOM_BLOB_CHUNK_LIMIT: number;
79
+ /** Blob hashes referenced by live site_files rows with no complete chunk set. */
80
+ export declare function roomMissingBlobs(db: DbDriver, limit?: number): string[];
81
+ /** Store one uploaded chunk. Chunk 0 resets the hash (a re-upload with a
82
+ * different chunking never leaves a stale mixed set behind). */
83
+ export declare function roomPutBlobChunk(db: DbDriver, hash: string, idx: number, total: number, bytes: Uint8Array): void;
84
+ /** Reassemble a blob's bytes, or null while the chunk set is incomplete. */
85
+ export declare function roomBlobBytes(db: DbDriver, hash: string): Uint8Array | null;
86
+ /**
87
+ * One owner sync round, room side. Order matters:
88
+ * 1. ingest the owner's changes (idempotent — baseline/increment overlap and
89
+ * retried requests dedup on the oplog UNIQUE);
90
+ * 2. compute the guest-op pull BEFORE any eviction GC, so an evict racing an
91
+ * undelivered guest op still delivers it this round;
92
+ * 3. membership reset (when `members` rides along) then explicit evicts —
93
+ * local physical deletion, deferred for unacked guest ops;
94
+ * 4. sweep deferred evictions now covered by `since`;
95
+ * 5. orphan detection → need_baseline;
96
+ * 6. digest, echoed only when the owner attached one (anti-entropy rounds).
97
+ */
98
+ export declare function handleOwnerSync(roomDb: DbDriver, req: OwnerSyncRequest, cfg?: RoomConfig): OwnerSyncResponse;
99
+ /** A guest write intent (final decision 1: intents, not pre-signed ops — the
100
+ * room's clock is the time authority; the write shape mirrors share-serve).
101
+ * The wire form the room WS accepts; mapped to the shared GuestIntent in
102
+ * handleGuestWrite. `intentId`/`submittedAt` are optional (new SDK sends them
103
+ * for retry-idempotency; older clients omit and the server synthesizes). */
104
+ export interface GuestWriteIntent {
105
+ op: "createRecord" | "updateRecord";
106
+ /** Database ref (id or granted name) — createRecord. */
107
+ db?: string;
108
+ /** Record id — updateRecord (or client-minted id on createRecord). */
109
+ record?: string;
110
+ values: Record<string, unknown>;
111
+ intentId?: string;
112
+ submittedAt?: number;
113
+ }
114
+ export interface RoomGuestSession {
115
+ /** Per-visitor guest sub id, minted at unlock (mintRoomGuestSub). */
116
+ sub: string;
117
+ }
118
+ /** Mint a per-visitor guest sub id (`<base>-<rand6>`) — same shape as
119
+ * share-serve's session subs, so per-visitor rollback and the base-prefix
120
+ * bulk predicate work identically for room-authored writes. */
121
+ export declare function mintRoomGuestSub(cfg: RoomConfig): string;
122
+ /**
123
+ * Apply one guest intent inside the room. Access gating (expiry + guest-node
124
+ * validity) is enforced here; authorization, guardrails and the write itself go
125
+ * through the shared applyGuestIntent executor (the same one the server share
126
+ * endpoints and — from Stage 4 — drop replay use). Authority clock: the room's
127
+ * persisted clock stamps the HLC, with the session's sub id as the author node.
128
+ */
129
+ export declare function handleGuestWrite(roomDb: DbDriver, cfg: RoomConfig, session: RoomGuestSession, intent: GuestWriteIntent): RecordRow;
130
+ //# sourceMappingURL=room-protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"room-protocol.d.ts","sourceRoot":"","sources":["../../../src/core/sync/room-protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import type { DbDriver } from "../driver.ts";
2
+ import { type RoomConfig } from "./room-protocol.ts";
3
+ export interface RoomHostDeps {
4
+ db: DbDriver;
5
+ /** The edge owner secret ("drt_…"); empty/undefined denies every owner route. */
6
+ ownerToken: string | undefined;
7
+ /** Broadcast a data-changed poke to connected guests (WS fan-out). */
8
+ poke?: (seq: number) => void;
9
+ /** Physical destruction — DO: deleteAll + close sockets; tests: drop the db. */
10
+ destroy: () => void | Promise<void>;
11
+ /** Schedule (epoch ms) / clear (null) the expiry self-destruct alarm. */
12
+ setAlarm?: (at: number | null) => void | Promise<void>;
13
+ /** Cede CPU so a frozen workerd clock can advance (HLC counter headroom —
14
+ * DO shell passes scheduler.wait(1)). Optional belt-and-braces: hlc.ts's
15
+ * carry-into-millis already keeps overflow correct without it. */
16
+ yieldClock?: () => Promise<void>;
17
+ }
18
+ /** Session context for a WebSocket upgrade: null = refuse (unprovisioned /
19
+ * expired / password-locked without a session). A cookieless connection to an
20
+ * unlocked room gets a fresh per-connection sub (P2 WS writes attribute to it). */
21
+ export declare function roomWsSession(db: DbDriver, req: Request): Promise<{
22
+ cfg: RoomConfig;
23
+ sub: string;
24
+ } | null>;
25
+ export interface RoomWsOutcome {
26
+ /** JSON reply for THIS socket, or null (nothing to say). */
27
+ reply: string | null;
28
+ /** Broadcast a poke to every connected guest. */
29
+ poke: boolean;
30
+ seq: number;
31
+ }
32
+ /** Handle one guest WS message: `{type:"write", intent, id?}` applies a write
33
+ * intent through handleGuestWrite (grants + guardrails + room-stamped HLC)
34
+ * and answers `{type:"result"|"error", id, …}`. Ping/pong is the host's
35
+ * auto-response pair and never reaches here. */
36
+ export declare function roomWsMessage(db: DbDriver, sub: string, raw: string): Promise<RoomWsOutcome>;
37
+ export declare function createRoomFetch(deps: RoomHostDeps): (req: Request) => Promise<Response>;
38
+ //# sourceMappingURL=room-serve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"room-serve.d.ts","sourceRoot":"","sources":["../../../src/core/sync/room-serve.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAiB7C,OAAO,EAWL,KAAK,UAAU,EAChB,MAAM,oBAAoB,CAAC;AAM5B,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,QAAQ,CAAC;IACb,iFAAiF;IACjF,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,sEAAsE;IACtE,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,gFAAgF;IAChF,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,yEAAyE;IACzE,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD;;uEAEmE;IACnE,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAClC;AAkHD;;oFAEoF;AACpF,wBAAsB,aAAa,CACjC,EAAE,EAAE,QAAQ,EACZ,GAAG,EAAE,OAAO,GACX,OAAO,CAAC;IAAE,GAAG,EAAE,UAAU,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAMlD;AAID,MAAM,WAAW,aAAa;IAC5B,4DAA4D;IAC5D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,iDAAiD;IACjD,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;iDAGiD;AACjD,wBAAsB,aAAa,CACjC,EAAE,EAAE,QAAQ,EACZ,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,aAAa,CAAC,CA4CxB;AAID,wBAAgB,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAyIvF"}
@@ -0,0 +1,4 @@
1
+ import type { RoomPeerConfig } from "./peers.ts";
2
+ /** Guest-facing Room URL shared by Bun services and the browser worker. */
3
+ export declare function roomUrlOf(config: Pick<RoomPeerConfig, "base" | "slug">): string;
4
+ //# sourceMappingURL=room-url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"room-url.d.ts","sourceRoot":"","sources":["../../../src/core/sync/room-url.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,2EAA2E;AAC3E,wBAAgB,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,CAE/E"}
@@ -4,6 +4,9 @@ import type { Database } from "bun:sqlite";
4
4
  export interface RouteCtx {
5
5
  db: Database;
6
6
  node: string;
7
+ /** Desktop's unauthenticated loopback sidecar may preview locally but must
8
+ * never be accepted as a LAN/public hosting origin. */
9
+ allowRemoteSiteHosting?: boolean;
7
10
  }
8
11
  /** Turn a thrown handler error into a JSON response: `{error, code?}` with a
9
12
  * semantic status, so HTTP clients can dispatch on `code` like CLI users
@@ -15,7 +18,7 @@ export declare function errorResponse(e: unknown): Response;
15
18
  * in /docs automatically — no generate step, no separate spec file.
16
19
  */
17
20
  export interface Route {
18
- method: "GET" | "POST" | "PATCH" | "DELETE";
21
+ method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
19
22
  path: string;
20
23
  summary: string;
21
24
  request?: ZodType;
@@ -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;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
+ {"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;AAgB3C,yEAAyE;AACzE,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,QAAQ,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb;4DACwD;IACxD,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAgBD;;8BAE8B;AAC9B,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,QAAQ,CAMlD;AAED;;;;GAIG;AACH,MAAM,WAAW,KAAK;IACpB,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;IACpD,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;AAsCD,eAAO,MAAM,MAAM,EAAE,KAAK,EAAmE,CAAC"}
@@ -0,0 +1,22 @@
1
+ export declare const SEAL_ENC = "sealed-p256";
2
+ export interface SealKeypair {
3
+ /** Raw uncompressed public point (65 bytes) — what mh-drop.json publishes. */
4
+ publicKey: Uint8Array;
5
+ /** PKCS#8 private key — wrapped with the master key before it leaves the device. */
6
+ privateKey: Uint8Array;
7
+ }
8
+ /** A fresh P-256 keypair for a drop recipient. Independent generation is a
9
+ * design decision, not a shortcut: WebCrypto cannot derive a P-256 keypair
10
+ * from a seed, so "derive from the master key" is technically impossible. */
11
+ export declare function generateSealKeypair(): Promise<SealKeypair>;
12
+ /** Seal plaintext to a recipient's raw P-256 public key (anonymous sender). */
13
+ export declare function seal(recipientPkRaw: Uint8Array, plaintext: Uint8Array): Promise<Uint8Array>;
14
+ /**
15
+ * Open a sealed box with the recipient's PKCS#8 private key (+ its raw public
16
+ * key, which the keyring stores alongside — needed to rebuild the KDF info).
17
+ * EVERY failure mode — truncated input, bad ephemeral point, wrong key,
18
+ * tampered ciphertext — answers with the same MhError("auth"), so a caller
19
+ * can't distinguish "wrong key" from "corrupted": both mean "not for you".
20
+ */
21
+ export declare function openSealed(privateKeyPkcs8: Uint8Array, recipientPkRaw: Uint8Array, sealed: Uint8Array): Promise<Uint8Array>;
22
+ //# sourceMappingURL=seal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seal.d.ts","sourceRoot":"","sources":["../../../src/core/sync/seal.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,QAAQ,gBAAgB,CAAC;AAyBtC,MAAM,WAAW,WAAW;IAC1B,8EAA8E;IAC9E,SAAS,EAAE,UAAU,CAAC;IACtB,oFAAoF;IACpF,UAAU,EAAE,UAAU,CAAC;CACxB;AAED;;8EAE8E;AAC9E,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,WAAW,CAAC,CAMhE;AAqBD,+EAA+E;AAC/E,wBAAsB,IAAI,CAAC,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CASjG;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,eAAe,EAAE,UAAU,EAC3B,cAAc,EAAE,UAAU,EAC1B,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,UAAU,CAAC,CAerB"}
@@ -40,6 +40,12 @@ export interface ServerOptions {
40
40
  syncIntervalMs?: number;
41
41
  /** Master switch for the auto-sync timer. Falls back to stored config. */
42
42
  autoSync?: boolean;
43
+ /** Disable LAN/public site-base verification for an unauthenticated
44
+ * loopback-only shell such as the Desktop sidecar. */
45
+ allowRemoteSiteHosting?: boolean;
46
+ /** Desktop's debug sidecar: reject DNS-rebinding hosts and cross-site
47
+ * mutations even though the token gate is intentionally disabled. */
48
+ loopbackUiOnly?: boolean;
43
49
  /** Browser UI plug-in point. Core ships no UI; callers (CLI, desktop
44
50
  * sidecar) inject the WebUI's asset handler + data API routes here.
45
51
  * Omitted = a headless sync/sites server. */
@@ -60,6 +66,7 @@ export interface UiHandler {
60
66
  /** The UI's data API routes, merged into the route registry (and /docs). */
61
67
  routes: Route[];
62
68
  }
69
+ export declare function loopbackUiRejection(req: Request, port: number): Response | null;
63
70
  /** Start the CRDT sync server. It is just another node backed by ~/.metahub. */
64
71
  export declare function startServer(opts?: ServerOptions): RunningServer;
65
72
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/core/sync/server.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAIvC,OAAO,EAAU,KAAK,KAAK,EAAiB,MAAM,aAAa,CAAC;AAmBhE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,UAAU,CAAC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,qFAAqF;IACrF,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,wFAAwF;IACxF,QAAQ,EAAE,SAAS,GAAG,QAAQ,GAAG,UAAU,CAAC;IAC5C,oEAAoE;IACpE,GAAG,EAAE,OAAO,CAAC;IACb,8CAA8C;IAC9C,QAAQ,EAAE,OAAO,CAAC;IAClB,qEAAqE;IACrE,cAAc,EAAE,MAAM,CAAC;IACvB,+CAA+C;IAC/C,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,6EAA6E;AAC7E,qBAAa,cAAe,SAAQ,OAAO;IAEvC,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM;gBADZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM;CASxB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oFAAoF;IACpF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;kDAE8C;IAC9C,EAAE,CAAC,EAAE,SAAS,CAAC;IACf;;;mEAG+D;IAC/D,GAAG,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C;AAED,oEAAoE;AACpE,MAAM,WAAW,SAAS;IACxB,8EAA8E;IAC9E,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IACpD,4EAA4E;IAC5E,MAAM,EAAE,KAAK,EAAE,CAAC;CACjB;AAYD,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,IAAI,GAAE,aAAkB,GAAG,aAAa,CAqPnE"}
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;AAuBhE,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;2DACuD;IACvD,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC;yEACqE;IACrE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;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;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAe/E;AAYD,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,IAAI,GAAE,aAAkB,GAAG,aAAa,CAsUnE"}
@@ -5,6 +5,8 @@ export interface CreateShareRequest {
5
5
  ref: string;
6
6
  permission?: SharePermission;
7
7
  transport?: "server" | "s3";
8
+ /** Hosting surface for server shares. room provisions an always-on Edge room. */
9
+ hosting?: "server" | "room";
8
10
  password?: string | null;
9
11
  /** Server: any duration (ms); null = never. s3: clamped to ≤7d; default 7d. */
10
12
  expiresMs?: number | null;
@@ -16,12 +18,18 @@ export interface CreateShareRequest {
16
18
  bucketUrl?: string | null;
17
19
  /** s3 only: the static viewer base for the link. */
18
20
  viewerBase?: string;
21
+ /** Serialized GrantSet enabling /share/<slug>/api/* (server transport only —
22
+ * a presigned static export has no API surface). */
23
+ grants?: string | null;
24
+ /** Idempotency key used when a paired node creates the share remotely. */
25
+ requestId?: string | null;
19
26
  }
20
27
  export interface CreatedShare {
21
28
  slug: string;
22
29
  kind: ShareKind;
23
30
  permission: SharePermission;
24
31
  transport: "server" | "s3";
32
+ hosting: "server" | "room" | "s3";
25
33
  /** Full link to copy (server: served_base/share/slug; s3: viewer link). */
26
34
  url: string;
27
35
  expiresAt: number | null;
@@ -38,32 +46,73 @@ export interface ShareListItem {
38
46
  permission: string;
39
47
  transport: "server" | "s3";
40
48
  source: string;
41
- sourceKind: "server" | "peer" | "bucket";
49
+ sourceKind: "server" | "peer" | "room" | "bucket";
50
+ /** Paired node that owns this share; present only in aggregated listings so
51
+ * management actions can be routed back to the correct device. */
52
+ sourceUrl?: string;
53
+ /** Where the share is actually served from: this/a server, an always-on DO
54
+ * room (server share + kind='room' peer), or a bucket export. */
55
+ hosting?: "server" | "room" | "s3";
42
56
  expiresAt: number | null;
43
57
  hasPassword: boolean;
44
58
  /** server: ready-to-copy link; s3: omitted (use renew to mint a fresh one). */
45
59
  url?: string;
60
+ lifecycle?: "active" | "provisioning" | "cleanup_pending";
61
+ /** s3 only: when the snapshot content was last exported (≠ link expiry). */
62
+ contentUpdatedAt?: number;
46
63
  }
47
64
  /** s3 bucket peers (no secrets) for a transport picker. */
48
65
  export declare function listShareBuckets(db: DbDriver): {
49
66
  url: string;
50
67
  label: string;
51
68
  }[];
52
- /** Paired HTTP peer servers (a share can be created on / served by them). */
69
+ /** Paired HTTP peer servers (a share can be created on / served by them).
70
+ * Room peers are deliberately excluded: they are Edge destinations, not
71
+ * devices a user can select as a hosting node. */
53
72
  export declare function listShareServers(db: DbDriver): {
54
73
  url: string;
55
74
  label: string;
75
+ enabled: boolean;
76
+ lastStatus: string | null;
77
+ lastSuccessAt: number | null;
56
78
  }[];
79
+ /** The legal-combination matrix in ONE place. Every rule names the conflict and
80
+ * the way out, so surfaces (CLI flags, WebUI selects, remote peers) fail the
81
+ * same way instead of each scattering its own throws. */
82
+ export declare function assertShareCombo(req: {
83
+ kind: ShareKind;
84
+ transport: "server" | "s3";
85
+ hosting: "server" | "room";
86
+ permission: SharePermission;
87
+ hasGrants: boolean;
88
+ }): void;
57
89
  /** Resolve, validate, and create (server local / server remote / s3 bucket) a share. */
58
90
  export declare function createShareAction(db: DbDriver, req: CreateShareRequest): Promise<CreatedShare>;
91
+ /** This node's server-share rows only (sync, no network) — the bucket-free
92
+ * subset of listSharesLocal. Site reachability and CLI listings use it so a
93
+ * local derivation never waits on an S3 scan. */
94
+ export declare function listServerSharesLocal(db: DbDriver, targetId?: string): ShareListItem[];
59
95
  /** Local listing (server rows + each attached bucket) — NO peer fan-out (so the
60
96
  * /api/shares endpoint a peer calls can't recurse). Optional target filter. */
61
97
  export declare function listSharesLocal(db: DbDriver, targetId?: string): Promise<ShareListItem[]>;
98
+ export declare function createdShareByRequestId(db: DbDriver, requestId: string): CreatedShare | null;
99
+ export declare function revokeShareByRequestId(db: DbDriver, requestId: string): Promise<RevokeShareResult>;
62
100
  /** Aggregated listing for CLI/WebUI: local ∪ each paired peer's /api/shares
63
101
  * (best-effort, bounded), deduped by slug. Optional target filter. */
64
102
  export declare function listSharesAggregated(db: DbDriver, targetId?: string): Promise<ShareListItem[]>;
65
- /** Revoke: local server row → delete it; else a bucket holds it → delete objects. */
66
- export declare function revokeShareAction(db: DbDriver, slug: string): Promise<boolean>;
67
- /** Renew an s3 share (re-presign, mint a fresh ≤7d link). */
68
- export declare function renewShareAction(db: DbDriver, slug: string, viewerBaseOverride?: string): Promise<CreatedShare>;
103
+ /** Revoke: local server row → delete it (cascading the share's room, if one is
104
+ * provisioned — final decision 3: the room's lifecycle is the share's); else a
105
+ * bucket holds it → delete objects. */
106
+ export interface RevokeShareResult {
107
+ ok: boolean;
108
+ status: "revoked" | "cleanup_pending" | "not_found";
109
+ }
110
+ export declare function revokeShareAction(db: DbDriver, slug: string): Promise<RevokeShareResult>;
111
+ /** Renew an s3 share's LINK. Default is re-presign only — the snapshot content
112
+ * is untouched, so "renew" means exactly what it says. Pass
113
+ * `refreshContent: true` for the explicit "update the snapshot from current
114
+ * data AND renew" action (the old implicit behavior). */
115
+ export declare function renewShareAction(db: DbDriver, slug: string, viewerBaseOverride?: string, opts?: {
116
+ refreshContent?: boolean;
117
+ }): Promise<CreatedShare>;
69
118
  //# sourceMappingURL=share-actions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"share-actions.d.ts","sourceRoot":"","sources":["../../../src/core/sync/share-actions.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAQ7C,OAAO,EAOL,KAAK,SAAS,EACd,KAAK,eAAe,EACrB,MAAM,cAAc,CAAC;AActB,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,SAAS,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,SAAS,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,+EAA+E;IAC/E,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;6EAEyE;IACzE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,EAAE,eAAe,CAAC;IAC5B,SAAS,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3B,2EAA2E;IAC3E,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wEAAwE;AACxE,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;IACzC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;IACrB,+EAA+E;IAC/E,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAiCD,2DAA2D;AAC3D,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAI/E;AAED,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAI/E;AAiCD,wFAAwF;AACxF,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,kBAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CA0FpG;AAED;gFACgF;AAChF,wBAAsB,eAAe,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAsC/F;AAED;uEACuE;AACvE,wBAAsB,oBAAoB,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAepG;AAYD,qFAAqF;AACrF,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAWpF;AAED,6DAA6D;AAC7D,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,kBAAkB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAmBrH"}
1
+ {"version":3,"file":"share-actions.d.ts","sourceRoot":"","sources":["../../../src/core/sync/share-actions.ts"],"names":[],"mappings":"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"}
@@ -38,6 +38,10 @@ export interface BucketShareMeta {
38
38
  key: string;
39
39
  /** base64 salt (password shares); the link carries this, viewer derives the key. */
40
40
  salt?: string;
41
+ /** epoch ms the snapshot CONTENT was last (re-)exported. Distinct from
42
+ * presign_exp: re-signing the link does not touch this. Older metas lack the
43
+ * field — readers fall back to created_at. */
44
+ content_updated_at?: number;
41
45
  }
42
46
  export interface BucketShareLink {
43
47
  manifestUrl: string;
@@ -64,6 +68,16 @@ export declare function createBucketShare(db: DbDriver, opts: {
64
68
  * stored per-share key, re-upload + re-presign, refresh meta.json. Works for
65
69
  * password shares too (the key is stored master-encrypted). */
66
70
  export declare function renewBucketShare(db: DbDriver, config: S3Config, slug: string, expiresSec?: number): Promise<BucketShareLink>;
71
+ /** Rewrite ONLY the presigned blob URLs inside a decrypted manifest — content
72
+ * untouched. Pure over the presign callback (unit-testable). */
73
+ export declare function refreshManifestUrls(manifest: ShareManifest, presign: (hash: string) => Promise<string>): Promise<ShareManifest>;
74
+ /** Re-presign an object-storage share WITHOUT touching its content: decrypt
75
+ * the stored manifest, refresh the embedded blob URLs, re-encrypt in place.
76
+ * No live data is read and no blob bytes are re-uploaded — recipients keep
77
+ * seeing the same snapshot (content_updated_at stays put). This is what
78
+ * "renew the link" means; re-exporting current data is a separate, explicit
79
+ * action (renewBucketShare). */
80
+ export declare function represignBucketShare(config: S3Config, slug: string, expiresSec?: number): Promise<BucketShareLink>;
67
81
  /** List all object-storage shares in a bucket (decrypts each meta.json). */
68
82
  export declare function listBucketShares(config: S3Config): Promise<BucketShareMeta[]>;
69
83
  /** Delete a bucket share's objects. meta.json is deleted FIRST so the share
@@ -1 +1 @@
1
- {"version":3,"file":"share-export.d.ts","sourceRoot":"","sources":["../../../src/core/sync/share-export.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAO7C,OAAO,EAAoB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAW/D,MAAM,WAAW,aAAa;IAC5B,CAAC,EAAE,CAAC,CAAC;IACL,IAAI,EAAE,KAAK,GAAG,UAAU,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC1D,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,EAAE,CAAC;IAC/C,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrD;AAED;4CAC4C;AAC5C,MAAM,WAAW,eAAe;IAC9B,CAAC,EAAE,CAAC,CAAC;IACL,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,KAAK,GAAG,UAAU,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,oFAAoF;IACpF,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,oFAAoF;IACpF,GAAG,EAAE,MAAM,CAAC;IACZ,oFAAoF;IACpF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAyGD;;uEAEuE;AACvE,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,QAAQ,EACZ,IAAI,EAAE;IACJ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,KAAK,GAAG,UAAU,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,QAAQ,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GACA,OAAO,CAAC,eAAe,CAAC,CA0C1B;AAED;;gEAEgE;AAChE,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,QAAQ,EAChB,IAAI,EAAE,MAAM,EACZ,UAAU,SAAsB,GAC/B,OAAO,CAAC,eAAe,CAAC,CAmB1B;AAED,4EAA4E;AAC5E,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAanF;AAED;qEACqE;AACrE,wBAAsB,wBAAwB,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAO5F"}
1
+ {"version":3,"file":"share-export.d.ts","sourceRoot":"","sources":["../../../src/core/sync/share-export.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,15 @@
1
- export declare function escapeHtml(s: string): string;
1
+ import { escapeHtml } from "./html-escape.ts";
2
+ export { escapeHtml };
2
3
  export interface RenderOpts {
3
4
  /** Rewrite a `/blob/<hash>` URL to a reachable one (scoped endpoint or data URL). */
4
5
  rewriteBlob?: (url: string) => string;
6
+ /** Resolve a `[[doc_x]]` internal reference to its current title. Absent (or
7
+ * returning null) the reference renders as its alias/id. Share pages render
8
+ * doclinks as inert text either way: auto-linking to the target's own share
9
+ * would extend one share's capability with another's. */
10
+ resolveDocLink?: (id: string) => {
11
+ title: string;
12
+ } | null;
5
13
  }
6
14
  /** Inline Markdown → HTML: a pure function of the shared tokenizer. Gaps are
7
15
  * escaped text; each token maps to one tag shape (the parity test's oracle
@@ -1 +1 @@
1
- {"version":3,"file":"share-render.d.ts","sourceRoot":"","sources":["../../../src/core/sync/share-render.ts"],"names":[],"mappings":"AA6BA,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAM5C;AAED,MAAM,WAAW,UAAU;IACzB,qFAAqF;IACrF,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;CACvC;AAED;;mCAEmC;AACnC,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,UAAe,GAAG,MAAM,CAuCvE;AAyBD,8DAA8D;AAC9D,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,GAAE,UAAe,GAAG,MAAM,CA+JxE"}
1
+ {"version":3,"file":"share-render.d.ts","sourceRoot":"","sources":["../../../src/core/sync/share-render.ts"],"names":[],"mappings":"AA4BA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG9C,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,MAAM,WAAW,UAAU;IACzB,qFAAqF;IACrF,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC;;;8DAG0D;IAC1D,cAAc,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAC3D;AAED;;mCAEmC;AACnC,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,UAAe,GAAG,MAAM,CA8CvE;AAyBD,8DAA8D;AAC9D,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,GAAE,UAAe,GAAG,MAAM,CA+JxE"}
@@ -1,3 +1,7 @@
1
1
  import type { RouteCtx } from "./routes.ts";
2
- export declare function serveShare(req: Request, ctx: RouteCtx): Promise<Response | null>;
2
+ export interface ServeShareOpts {
3
+ /** Client IP — rate-limit fallback key for cookieless callers. */
4
+ ip?: string | null;
5
+ }
6
+ export declare function serveShare(req: Request, ctx: RouteCtx, opts?: ServeShareOpts): Promise<Response | null>;
3
7
  //# sourceMappingURL=share-serve.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"share-serve.d.ts","sourceRoot":"","sources":["../../../src/core/sync/share-serve.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAmC5C,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAkCtF"}
1
+ {"version":3,"file":"share-serve.d.ts","sourceRoot":"","sources":["../../../src/core/sync/share-serve.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAwC5C,MAAM,WAAW,cAAc;IAC7B,kEAAkE;IAClE,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AAED,wBAAsB,UAAU,CAC9B,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAmC1B"}
@@ -0,0 +1,26 @@
1
+ import type { DbDriver } from "../driver.ts";
2
+ /** Prefix marking an observation written because the controller's node-local
3
+ * share row (the capability secret) is missing. The reconciler clears it once
4
+ * the row reappears; surfaces show the channel as errored, never as revoked. */
5
+ export declare const CONTROLLER_STATE_MISSING = "controller_state_missing";
6
+ /** Apply synced desired-state changes whose node-local secret is owned here.
7
+ * Other devices may revoke an Edge link without receiving the account token:
8
+ * they sync desired_state=revoked; the controller performs teardown when it
9
+ * next comes online and records a local observation.
10
+ *
11
+ * Revocations are emitted on POSITIVE evidence only:
12
+ * - a replicated site tombstone (older clients delete sites without knowing
13
+ * about channels) revokes the orphaned channels;
14
+ * - an ABSENT site row means "not replicated here yet" and is left untouched;
15
+ * - a missing node-local share row is an error observation, not a revocation;
16
+ * - share expiry never revokes or deletes — serving refuses expired links,
17
+ * but the share stays manageable (renewable) per the status contract.
18
+ * The "revoked" observation likewise requires teardown evidence: an absent
19
+ * Room record is cleanup_pending, never a fabricated destroy confirmation. */
20
+ /** Reconcile without ever throwing: channel maintenance is LOCAL housekeeping
21
+ * and must not turn an otherwise-successful data sync (or an already-committed
22
+ * delete) into a reported failure. Returns the error message for callers that
23
+ * surface warnings, null on success. */
24
+ export declare function reconcileSiteChannelsQuietly(db: DbDriver): Promise<string | null>;
25
+ export declare function reconcileSiteChannels(db: DbDriver): Promise<void>;
26
+ //# sourceMappingURL=site-channel-reconcile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"site-channel-reconcile.d.ts","sourceRoot":"","sources":["../../../src/core/sync/site-channel-reconcile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAa7C;;gFAEgF;AAChF,eAAO,MAAM,wBAAwB,6BAA6B,CAAC;AAEnE;;;;;;;;;;;;;8EAa8E;AAC9E;;;wCAGwC;AACxC,wBAAsB,4BAA4B,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CASvF;AAED,wBAAsB,qBAAqB,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA2FvE"}
@@ -0,0 +1,32 @@
1
+ import type { DbDriver } from "../driver.ts";
2
+ export interface SitePublishState {
3
+ siteId: string;
4
+ targetBase: string;
5
+ url: string;
6
+ status: "ready" | "syncing";
7
+ updatedAt: number;
8
+ }
9
+ /** Node-local safety record: a private rollback has been emitted locally but
10
+ * the target peer has not yet acknowledged a cursor that includes it. */
11
+ export interface PendingSiteRollback {
12
+ siteId: string;
13
+ peerUrl: string;
14
+ targetUrl: string;
15
+ requiredSeq: number;
16
+ createdAt: number;
17
+ lastError: string;
18
+ }
19
+ export declare function listPendingSiteRollbacks(db: DbDriver): PendingSiteRollback[];
20
+ export declare function getPendingSiteRollback(db: DbDriver, siteId: string, peerUrl: string): PendingSiteRollback | null;
21
+ export declare function putPendingSiteRollback(db: DbDriver, pending: PendingSiteRollback): PendingSiteRollback;
22
+ export declare function updatePendingSiteRollbackError(db: DbDriver, siteId: string, peerUrl: string, error: string): PendingSiteRollback | null;
23
+ export declare function removePendingSiteRollback(db: DbDriver, siteId: string, peerUrl: string): boolean;
24
+ /** A successful HTTP-peer sync advances push_cursor to the highest local CRDT
25
+ * sequence included in the request. That cursor is the durable proof that the
26
+ * compensating private write reached the target. */
27
+ export declare function clearCoveredSiteRollbacks(db: DbDriver, peerUrl: string): number;
28
+ export declare function latestLocalSeq(db: DbDriver): number;
29
+ export declare function listSitePublishStates(db: DbDriver): SitePublishState[];
30
+ export declare function putSitePublishState(db: DbDriver, state: SitePublishState): SitePublishState;
31
+ export declare function removeSitePublishStates(db: DbDriver, siteId: string): number;
32
+ //# sourceMappingURL=site-publish-recovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"site-publish-recovery.d.ts","sourceRoot":"","sources":["../../../src/core/sync/site-publish-recovery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAK7C,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;yEACyE;AACzE,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAmCD,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,QAAQ,GAAG,mBAAmB,EAAE,CAE5E;AAED,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,mBAAmB,GAAG,IAAI,CAE5B;AAED,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,QAAQ,EACZ,OAAO,EAAE,mBAAmB,GAC3B,mBAAmB,CAOrB;AAED,wBAAgB,8BAA8B,CAC5C,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,mBAAmB,GAAG,IAAI,CAO5B;AAED,wBAAgB,yBAAyB,CACvC,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,OAAO,CAMT;AAED;;oDAEoD;AACpD,wBAAgB,yBAAyB,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAW/E;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,GAAG,MAAM,CAKnD;AAkCD,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,QAAQ,GAAG,gBAAgB,EAAE,CAEtE;AAED,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,QAAQ,EACZ,KAAK,EAAE,gBAAgB,GACtB,gBAAgB,CAOlB;AAED,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAK5E"}
@@ -0,0 +1,13 @@
1
+ import type { DbDriver } from "../driver.ts";
2
+ import { type SiteChannel, type SiteState } from "../site-channels.ts";
3
+ import { type SitePublicAccessState } from "../site-channel-store.ts";
4
+ export interface SiteReachability {
5
+ siteId: string;
6
+ visibility: "public" | "private";
7
+ state: SiteState;
8
+ channels: SiteChannel[];
9
+ /** Unified public-access decision (serve/config/anomaly) for this node. */
10
+ publicAccess: SitePublicAccessState;
11
+ }
12
+ export declare function siteReachability(db: DbDriver, siteId: string): SiteReachability;
13
+ //# sourceMappingURL=site-reachability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"site-reachability.d.ts","sourceRoot":"","sources":["../../../src/core/sync/site-reachability.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAG7C,OAAO,EAGL,KAAK,WAAW,EAEhB,KAAK,SAAS,EACf,MAAM,qBAAqB,CAAC;AAM7B,OAAO,EAGL,KAAK,qBAAqB,EAC3B,MAAM,0BAA0B,CAAC;AAElC,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,QAAQ,GAAG,SAAS,CAAC;IACjC,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,2EAA2E;IAC3E,YAAY,EAAE,qBAAqB,CAAC;CACrC;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAkB/E"}
@@ -1 +1 @@
1
- {"version":3,"file":"sites-routes.d.ts","sourceRoot":"","sources":["../../../src/core/sync/sites-routes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,KAAK,EAAiB,MAAM,aAAa,CAAC;AAqDvE,eAAO,MAAM,WAAW,EAAE,KAAK,EAwE9B,CAAC"}
1
+ {"version":3,"file":"sites-routes.d.ts","sourceRoot":"","sources":["../../../src/core/sync/sites-routes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,KAAK,EAAiB,MAAM,aAAa,CAAC;AAoHvE,eAAO,MAAM,WAAW,EAAE,KAAK,EAmH9B,CAAC"}
@@ -1,3 +1,26 @@
1
+ import type { DbDriver } from "../driver.ts";
1
2
  import type { RouteCtx } from "./routes.ts";
2
- export declare function serveSite(req: Request, ctx: RouteCtx): Promise<Response | null>;
3
+ import { type AuthConfig } from "./auth.ts";
4
+ /** Host wiring serveSite can't do itself: the request's client IP (rate-limit
5
+ * key material) and an in-process forwarder into the main /api route table
6
+ * (token-holders under /sites/<name>/api/* get the FULL API). */
7
+ export interface ServeSiteOpts {
8
+ ip?: string | null;
9
+ forwardApi?: (req: Request) => Promise<Response>;
10
+ }
11
+ export declare function serveSite(req: Request, ctx: RouteCtx, auth: AuthConfig, opts?: ServeSiteOpts): Promise<Response | null>;
12
+ /**
13
+ * Serve one file of a resolved site: ETag/304 negotiation → decode → response
14
+ * with content-type + cache headers. Shared by /sites/<name>/ (above) and the
15
+ * token-exempt /share/<slug>/ site path (share-serve.ts) so both surfaces agree
16
+ * on caching and 404 behavior. This function never injects the runtime — the
17
+ * /sites/ caller adds it (withShim) only on the authenticated private branch.
18
+ * `isPublic` selects the Cache-Control scope: only a visibility:public site may
19
+ * pass true (share responses stay `private` always — the slug IS the
20
+ * capability and must never enter a shared cache).
21
+ */
22
+ export declare function serveSiteFile(req: Request, db: DbDriver, siteId: string, path: string, opts?: {
23
+ spa?: boolean;
24
+ isPublic?: boolean;
25
+ }): Promise<Response>;
3
26
  //# sourceMappingURL=sites-serve.d.ts.map
@@ -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,CAyBrF"}
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,cAAc,CAAC;AAC7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAmB5C,OAAO,EACL,KAAK,UAAU,EAShB,MAAM,WAAW,CAAC;AAwBnB;;kEAEkE;AAClE,MAAM,WAAW,aAAa;IAC5B,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CAClD;AAED,wBAAsB,SAAS,CAC7B,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,UAAU,EAChB,IAAI,GAAE,aAAkB,GACvB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CA0G1B;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,OAAO,EACZ,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE;IAAE,GAAG,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAO,GAC/C,OAAO,CAAC,QAAQ,CAAC,CA8BnB"}