@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.
- package/README.md +23 -10
- package/README.zh-CN.md +23 -10
- package/dist/cli/edge-worker-script.d.ts +4 -0
- package/dist/cli/edge-worker-script.d.ts.map +1 -0
- package/dist/cli.js +16882 -8691
- package/dist/cli.js.map +109 -59
- package/dist/core/access-policy.d.ts +82 -0
- package/dist/core/access-policy.d.ts.map +1 -0
- package/dist/core/blobs-core.d.ts +19 -0
- package/dist/core/blobs-core.d.ts.map +1 -1
- package/dist/core/blobs.d.ts.map +1 -1
- package/dist/core/compact.d.ts.map +1 -1
- package/dist/core/config.d.ts +13 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/crdt.d.ts +29 -2
- package/dist/core/crdt.d.ts.map +1 -1
- package/dist/core/data-map.d.ts +105 -0
- package/dist/core/data-map.d.ts.map +1 -0
- package/dist/core/db.d.ts +1 -1
- package/dist/core/db.d.ts.map +1 -1
- package/dist/core/documents.d.ts.map +1 -1
- package/dist/core/errors.d.ts +2 -0
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/grants-core.d.ts +132 -0
- package/dist/core/grants-core.d.ts.map +1 -0
- package/dist/core/guest-intent.d.ts +33 -0
- package/dist/core/guest-intent.d.ts.map +1 -0
- package/dist/core/hash.d.ts +4 -0
- package/dist/core/hash.d.ts.map +1 -0
- package/dist/core/history.d.ts.map +1 -1
- package/dist/core/hlc.d.ts +5 -0
- package/dist/core/hlc.d.ts.map +1 -1
- package/dist/core/ids.d.ts +1 -1
- package/dist/core/ids.d.ts.map +1 -1
- package/dist/core/inject-runtime.d.ts +8 -0
- package/dist/core/inject-runtime.d.ts.map +1 -0
- package/dist/core/intent-retention.d.ts +23 -0
- package/dist/core/intent-retention.d.ts.map +1 -0
- package/dist/core/md/inline.d.ts +6 -2
- package/dist/core/md/inline.d.ts.map +1 -1
- package/dist/core/node.d.ts +13 -0
- package/dist/core/node.d.ts.map +1 -1
- package/dist/core/records.d.ts +31 -0
- package/dist/core/records.d.ts.map +1 -1
- package/dist/core/schema-init.d.ts +19 -2
- package/dist/core/schema-init.d.ts.map +1 -1
- package/dist/core/schema.d.ts +1 -1
- package/dist/core/schema.d.ts.map +1 -1
- package/dist/core/shares.d.ts +15 -0
- package/dist/core/shares.d.ts.map +1 -1
- package/dist/core/site-channel-lifecycle.d.ts +10 -0
- package/dist/core/site-channel-lifecycle.d.ts.map +1 -0
- package/dist/core/site-channel-store.d.ts +120 -0
- package/dist/core/site-channel-store.d.ts.map +1 -0
- package/dist/core/site-channels.d.ts +65 -0
- package/dist/core/site-channels.d.ts.map +1 -0
- package/dist/core/sites-core.d.ts +100 -7
- package/dist/core/sites-core.d.ts.map +1 -1
- package/dist/core/sites.d.ts +65 -2
- package/dist/core/sites.d.ts.map +1 -1
- package/dist/core/sync/anti-abuse.d.ts +26 -0
- package/dist/core/sync/anti-abuse.d.ts.map +1 -0
- package/dist/core/sync/auth.d.ts +30 -2
- package/dist/core/sync/auth.d.ts.map +1 -1
- package/dist/core/sync/blob-routes.d.ts.map +1 -1
- package/dist/core/sync/cf-api.d.ts +54 -0
- package/dist/core/sync/cf-api.d.ts.map +1 -0
- package/dist/core/sync/cf-oauth.d.ts +91 -0
- package/dist/core/sync/cf-oauth.d.ts.map +1 -0
- package/dist/core/sync/client.d.ts +12 -0
- package/dist/core/sync/client.d.ts.map +1 -1
- package/dist/core/sync/data-map-db.d.ts +8 -0
- package/dist/core/sync/data-map-db.d.ts.map +1 -0
- package/dist/core/sync/devices.d.ts +65 -0
- package/dist/core/sync/devices.d.ts.map +1 -0
- package/dist/core/sync/drop-host.d.ts +40 -0
- package/dist/core/sync/drop-host.d.ts.map +1 -0
- package/dist/core/sync/drop-keys.d.ts +64 -0
- package/dist/core/sync/drop-keys.d.ts.map +1 -0
- package/dist/core/sync/drop-protocol.d.ts +94 -0
- package/dist/core/sync/drop-protocol.d.ts.map +1 -0
- package/dist/core/sync/drop-pull.d.ts +67 -0
- package/dist/core/sync/drop-pull.d.ts.map +1 -0
- package/dist/core/sync/drop-wire.d.ts +39 -0
- package/dist/core/sync/drop-wire.d.ts.map +1 -0
- package/dist/core/sync/e2ee.d.ts +3 -0
- package/dist/core/sync/e2ee.d.ts.map +1 -1
- package/dist/core/sync/edge-config.d.ts +77 -0
- package/dist/core/sync/edge-config.d.ts.map +1 -0
- package/dist/core/sync/edge-connect.d.ts +13 -0
- package/dist/core/sync/edge-connect.d.ts.map +1 -0
- package/dist/core/sync/edge-service.d.ts +100 -0
- package/dist/core/sync/edge-service.d.ts.map +1 -0
- package/dist/core/sync/grants-routes.d.ts +46 -0
- package/dist/core/sync/grants-routes.d.ts.map +1 -0
- package/dist/core/sync/guest-session.d.ts +29 -0
- package/dist/core/sync/guest-session.d.ts.map +1 -0
- package/dist/core/sync/html-escape.d.ts +2 -0
- package/dist/core/sync/html-escape.d.ts.map +1 -0
- package/dist/core/sync/http-status.d.ts +14 -0
- package/dist/core/sync/http-status.d.ts.map +1 -0
- package/dist/core/sync/http-util.d.ts +6 -0
- package/dist/core/sync/http-util.d.ts.map +1 -0
- package/dist/core/sync/pairing.d.ts +9 -9
- package/dist/core/sync/pairing.d.ts.map +1 -1
- package/dist/core/sync/partition.d.ts +77 -0
- package/dist/core/sync/partition.d.ts.map +1 -0
- package/dist/core/sync/peers-routes.d.ts.map +1 -1
- package/dist/core/sync/peers.d.ts +77 -0
- package/dist/core/sync/peers.d.ts.map +1 -1
- package/dist/core/sync/protocol.d.ts +2 -0
- package/dist/core/sync/protocol.d.ts.map +1 -1
- package/dist/core/sync/rate-limit.d.ts +20 -0
- package/dist/core/sync/rate-limit.d.ts.map +1 -0
- package/dist/core/sync/recovery.d.ts +9 -0
- package/dist/core/sync/recovery.d.ts.map +1 -0
- package/dist/core/sync/room-client.d.ts +50 -0
- package/dist/core/sync/room-client.d.ts.map +1 -0
- package/dist/core/sync/room-peer.d.ts +62 -0
- package/dist/core/sync/room-peer.d.ts.map +1 -0
- package/dist/core/sync/room-protocol.d.ts +130 -0
- package/dist/core/sync/room-protocol.d.ts.map +1 -0
- package/dist/core/sync/room-serve.d.ts +38 -0
- package/dist/core/sync/room-serve.d.ts.map +1 -0
- package/dist/core/sync/room-url.d.ts +4 -0
- package/dist/core/sync/room-url.d.ts.map +1 -0
- package/dist/core/sync/routes.d.ts +4 -1
- package/dist/core/sync/routes.d.ts.map +1 -1
- package/dist/core/sync/seal.d.ts +22 -0
- package/dist/core/sync/seal.d.ts.map +1 -0
- package/dist/core/sync/server.d.ts +7 -0
- package/dist/core/sync/server.d.ts.map +1 -1
- package/dist/core/sync/share-actions.d.ts +55 -6
- package/dist/core/sync/share-actions.d.ts.map +1 -1
- package/dist/core/sync/share-export.d.ts +14 -0
- package/dist/core/sync/share-export.d.ts.map +1 -1
- package/dist/core/sync/share-render.d.ts +9 -1
- package/dist/core/sync/share-render.d.ts.map +1 -1
- package/dist/core/sync/share-serve.d.ts +5 -1
- package/dist/core/sync/share-serve.d.ts.map +1 -1
- package/dist/core/sync/site-channel-reconcile.d.ts +26 -0
- package/dist/core/sync/site-channel-reconcile.d.ts.map +1 -0
- package/dist/core/sync/site-publish-recovery.d.ts +32 -0
- package/dist/core/sync/site-publish-recovery.d.ts.map +1 -0
- package/dist/core/sync/site-reachability.d.ts +13 -0
- package/dist/core/sync/site-reachability.d.ts.map +1 -0
- package/dist/core/sync/sites-routes.d.ts.map +1 -1
- package/dist/core/sync/sites-serve.d.ts +24 -1
- package/dist/core/sync/sites-serve.d.ts.map +1 -1
- package/dist/core/sync/storage-s3-bun.d.ts +1 -24
- package/dist/core/sync/storage-s3-bun.d.ts.map +1 -1
- package/dist/core/sync/storage-s3-sign.d.ts +43 -0
- package/dist/core/sync/storage-s3-sign.d.ts.map +1 -0
- package/dist/core/sync/storage.d.ts +59 -0
- package/dist/core/sync/storage.d.ts.map +1 -1
- package/dist/db-worker.js +206 -76
- package/dist/edge-worker.js +3960 -0
- package/dist/index.js +13175 -6670
- package/dist/index.js.map +87 -41
- package/dist/metahub-sdk.js +10 -1
- package/dist/mh-runtime.js +1 -1
- package/dist/room/do-driver.d.ts +30 -0
- package/dist/room/do-driver.d.ts.map +1 -0
- package/dist/sw.js +10 -1
- package/dist/webui/server/edge-routes.d.ts +3 -0
- package/dist/webui/server/edge-routes.d.ts.map +1 -0
- package/dist/webui/server/json-handler.d.ts +4 -0
- package/dist/webui/server/json-handler.d.ts.map +1 -0
- package/dist/webui/server/routes.d.ts.map +1 -1
- package/dist/webui/server/share-routes.d.ts.map +1 -1
- package/dist/webui/server/site-hosting-routes.d.ts +7 -0
- package/dist/webui/server/site-hosting-routes.d.ts.map +1 -0
- package/dist/webui.js +192 -137
- package/dist/workers/edge-worker.d.ts +66 -0
- package/dist/workers/edge-worker.d.ts.map +1 -0
- package/dist/workers/room.d.ts +34 -0
- package/dist/workers/room.d.ts.map +1 -0
- 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
|
-
|
|
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
|
|
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
|
-
/**
|
|
82
|
-
|
|
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":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"sites-core.d.ts","sourceRoot":"","sources":["../../src/core/sites-core.ts"],"names":[],"mappings":"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"}
|
package/dist/core/sites.d.ts
CHANGED
|
@@ -1,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
|
package/dist/core/sites.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sites.d.ts","sourceRoot":"","sources":["../../src/core/sites.ts"],"names":[],"mappings":"
|
|
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"}
|
package/dist/core/sync/auth.d.ts
CHANGED
|
@@ -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
|
-
/**
|
|
51
|
-
|
|
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;
|
|
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;
|
|
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;
|
|
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"}
|