@tensorix/metahub 0.3.1 → 0.3.2

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.
@@ -76,13 +76,16 @@ export interface EditPair {
76
76
  replaceAll?: boolean;
77
77
  }
78
78
  /**
79
- * Apply several anchored find/replaces in one atomic, single-versioned pass —
80
- * the batch form of {@link editDocument}. Pairs fold left-to-right over the
81
- * evolving body (a later `old` can match an earlier `new`), every pair is
82
- * validated before anything is written, and the whole batch commits as one
83
- * grouped txn (one revision, one version bump). Any failing pair (empty/missing/
84
- * ambiguous anchor) aborts the batch with the document untouched. `ifMatch` is
79
+ * Apply several anchored find/replaces in one single-versioned pass — the batch
80
+ * form of {@link editDocument}. Pairs fold left-to-right over the evolving body
81
+ * (a later `old` can match an earlier `new`), EVERY pair is validated before
82
+ * anything is written (validate-all-before-write), so any failing pair (empty/
83
+ * missing/ambiguous anchor) aborts with the document untouched. The writes then
84
+ * land in one oplog change-group (one revision, one version bump). `ifMatch` is
85
85
  * checked once up front, so callers need only a single `doc read` for N deltas.
86
+ * NB: "one pass" here is validate-before-write + single-version, NOT a DB
87
+ * transaction — like every `grouped` mutator, there is no cross-process lock or
88
+ * rollback; concurrent writers reconcile via the block-level CRDT / LWW.
86
89
  */
87
90
  export declare const editDocumentBatch: (db: DbDriver, id: string, opts: {
88
91
  edits: EditPair[];
@@ -1 +1 @@
1
- {"version":3,"file":"documents.d.ts","sourceRoot":"","sources":["../../src/core/documents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAQ5C,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;AAExD,eAAO,MAAM,aAAa,0FAEhB,CAAC;AAqGX,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAShE;AAID,eAAO,MAAM,cAAc;WAEV,MAAM;WAAS,MAAM;kBAAgB,MAAM;gBAAc,MAAM;iBAa9E,CAAC;AAEH,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAIxE;AAMD,wBAAgB,aAAa,CAC3B,EAAE,EAAE,QAAQ,EACZ,IAAI,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GACtD,eAAe,EAAE,CAWnB;AAgFD,kFAAkF;AAClF,eAAO,MAAM,yBAAyB,wBAOpC,CAAC;AAgDH;;;;GAIG;AACH,eAAO,MAAM,YAAY,iGAevB,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB;YAGZ,MAAM;eAAa,MAAM,GAAG,IAAI;6BAuBhD,CAAC;AAEH,eAAO,MAAM,cAAc;YAGP,MAAM;WAAS,MAAM;kBAAgB,MAAM;gBAAc,MAAM,GAAG,IAAI;;cACtE,MAAM;6BAsBxB,CAAC;AAEH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,eAAO,MAAM,YAAY;SAGV,MAAM;SAAO,MAAM;iBAAe,OAAO;cAAY,MAAM;mBAqCxE,CAAC;AAEH,sGAAsG;AACtG,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB;WAGb,QAAQ,EAAE;cAAY,MAAM;mBAiC3C,CAAC;AAEH,eAAO,MAAM,cAAc,2DAczB,CAAC;AAEH,eAAO,MAAM,eAAe,2DAc1B,CAAC;AAEH,eAAO,MAAM,cAAc,uCAUzB,CAAC"}
1
+ {"version":3,"file":"documents.d.ts","sourceRoot":"","sources":["../../src/core/documents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAQ5C,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;AAExD,eAAO,MAAM,aAAa,0FAEhB,CAAC;AAqGX,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAShE;AAID,eAAO,MAAM,cAAc;WAEV,MAAM;WAAS,MAAM;kBAAgB,MAAM;gBAAc,MAAM;iBAa9E,CAAC;AAEH,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAIxE;AAMD,wBAAgB,aAAa,CAC3B,EAAE,EAAE,QAAQ,EACZ,IAAI,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GACtD,eAAe,EAAE,CAWnB;AAgFD,kFAAkF;AAClF,eAAO,MAAM,yBAAyB,wBAOpC,CAAC;AAgDH;;;;GAIG;AACH,eAAO,MAAM,YAAY,iGAevB,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB;YAGZ,MAAM;eAAa,MAAM,GAAG,IAAI;6BAuBhD,CAAC;AAEH,eAAO,MAAM,cAAc;YAGP,MAAM;WAAS,MAAM;kBAAgB,MAAM;gBAAc,MAAM,GAAG,IAAI;;cACtE,MAAM;6BAsBxB,CAAC;AAEH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,eAAO,MAAM,YAAY;SAGV,MAAM;SAAO,MAAM;iBAAe,OAAO;cAAY,MAAM;mBAiDxE,CAAC;AAEH,sGAAsG;AACtG,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iBAAiB;WAGb,QAAQ,EAAE;cAAY,MAAM;mBAkC3C,CAAC;AAEH,eAAO,MAAM,cAAc,2DAczB,CAAC;AAEH,eAAO,MAAM,eAAe,2DAc1B,CAAC;AAEH,eAAO,MAAM,cAAc,uCAUzB,CAAC"}
@@ -10,6 +10,43 @@ export declare const RE: {
10
10
  quote: RegExp;
11
11
  divider: RegExp;
12
12
  };
13
+ /** URL-scheme whitelist for rendered links/images — the single sanitizer every
14
+ * surface uses before emitting an `href`/`src` or calling `window.open`. Blocks
15
+ * the injection vectors (`javascript:`, `vbscript:`, and — for links — `data:`)
16
+ * while allowing normal web/mail/blob links, relative paths and `#anchors`.
17
+ * Returns "#" for anything rejected, so a hostile URL from synced or shared
18
+ * content can never execute. `allowData` is set for `<img>`, where `data:`
19
+ * image URIs are legitimate and non-executable. */
20
+ export declare function safeUrl(url: string, opts?: {
21
+ allowData?: boolean;
22
+ }): string;
23
+ /** A line that is solely a media/file embed is a block-level void on every
24
+ * surface. The classifier + its helpers live here so the same bytes are a block
25
+ * on all three (editor scan, `blocks.startsLeafBlock`, share renderer) — the
26
+ * divergence that let a media line fold into a paragraph on save only. */
27
+ export type MediaKind = "image" | "video" | "audio" | "file";
28
+ /** Lowercased file extension of a URL (no query/fragment), or "". */
29
+ export declare function extOf(url: string): string;
30
+ /** Which `![](url)` embed a media URL is, by extension. Image syntax never maps
31
+ * to "file": an unknown extension written as `![]()` is treated as an image. */
32
+ export declare function imageSyntaxKind(ext: string): "image" | "video" | "audio";
33
+ /** Split a media URL into its base src and an optional `w=` width, preserving any
34
+ * other query params / fragment (external images may carry signed tokens). */
35
+ export declare function parseMediaUrl(url: string): {
36
+ src: string;
37
+ width?: number;
38
+ };
39
+ export interface MediaLine {
40
+ kind: MediaKind;
41
+ src: string;
42
+ name: string;
43
+ width?: number;
44
+ size?: number;
45
+ }
46
+ /** A line that is solely one embed → its classified parts, else null. Media use
47
+ * `![alt](url)` (kind by extension); a file uses a `[name](/blob/..)` link so a
48
+ * plain standalone hyperlink stays a paragraph. */
49
+ export declare function matchMediaEmbed(line: string): MediaLine | null;
13
50
  /** The single quote-line predicate for all consumers: quote content of `text`
14
51
  * ("" for the serializer's empty form `> `), or null if the line is not a
15
52
  * quote line. `text` must already be indent-stripped. */
@@ -1 +1 @@
1
- {"version":3,"file":"grammar.d.ts","sourceRoot":"","sources":["../../../src/core/md/grammar.ts"],"names":[],"mappings":"AAoBA;mFACmF;AACnF,eAAO,MAAM,UAAU,YAAY,CAAC;AAEpC,eAAO,MAAM,EAAE;;;;;;;;CAQd,CAAC;AAEF;;0DAE0D;AAC1D,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG1D;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,GAAG,UAAU,GAAG,MAAM,CAAC;IACrC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CA+B9E;AAED,0DAA0D;AAC1D,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQlD;AAED,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAUjE;AAED;2DAC2D;AAC3D,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAO7E;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAGD,eAAO,MAAM,aAAa,QAAmB,CAAC;AAE9C;8CAC8C;AAC9C,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAUvF;AAED;kEACkE;AAClE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAqBpD"}
1
+ {"version":3,"file":"grammar.d.ts","sourceRoot":"","sources":["../../../src/core/md/grammar.ts"],"names":[],"mappings":"AAoBA;mFACmF;AACnF,eAAO,MAAM,UAAU,YAAY,CAAC;AAEpC,eAAO,MAAM,EAAE;;;;;;;;CAQd,CAAC;AAEF;;;;;;oDAMoD;AACpD,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,MAAM,CAa/E;AAID;;;2EAG2E;AAC3E,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;AAK7D,qEAAqE;AACrE,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKzC;AAED;iFACiF;AACjF,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAIxE;AAED;+EAC+E;AAC/E,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAe1E;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,SAAS,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;oDAEoD;AACpD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAiB9D;AAED;;0DAE0D;AAC1D,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG1D;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,GAAG,UAAU,GAAG,MAAM,CAAC;IACrC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CA+B9E;AAED,0DAA0D;AAC1D,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQlD;AAED,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAUjE;AAED;2DAC2D;AAC3D,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAO7E;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAGD,eAAO,MAAM,aAAa,QAAmB,CAAC;AAE9C;8CAC8C;AAC9C,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAUvF;AAED;kEACkE;AAClE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAqBpD"}
@@ -1 +1 @@
1
- {"version":3,"file":"heal.d.ts","sourceRoot":"","sources":["../../../src/core/md/heal.ts"],"names":[],"mappings":"AAyDA,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAuBtD"}
1
+ {"version":3,"file":"heal.d.ts","sourceRoot":"","sources":["../../../src/core/md/heal.ts"],"names":[],"mappings":"AAyDA,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAkCtD"}
@@ -1 +1 @@
1
- {"version":3,"file":"share-render.d.ts","sourceRoot":"","sources":["../../../src/core/sync/share-render.ts"],"names":[],"mappings":"AA0BA,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,CA+BvE;AAOD,8DAA8D;AAC9D,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,GAAE,UAAe,GAAG,MAAM,CAwJxE"}
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"}
package/dist/db-worker.js CHANGED
@@ -269,9 +269,9 @@ CREATE VIRTUAL TABLE IF NOT EXISTS search_fts USING fts5(
269
269
  ORDER BY order_key DESC, id DESC LIMIT 1`).get(...G.args,...X?[X]:[])?.order_key??null}function rW($,J){let X=KJ(J);return $.query(`SELECT id, order_key FROM documents WHERE ${X.clause} AND __deleted = 0 ${o1}`).all(...X.args)}function CK($,J){let X=rW($,J),G=Xv(null,null,X.length);X.forEach((U,Q)=>{if(U.order_key!==G[Q])T$($,"documents",U.id,"order_key",G[Q])})}function oW($,J){let X=_K($),G=KJ(J),U=$.query(`SELECT id FROM documents WHERE ${G.clause} AND __deleted = 0 AND order_key IS NULL
270
270
  ORDER BY created_hlc, id`).all(...G.args);if(!U.length)return;let Q=Xv(mW($,J),null,U.length);U.forEach((W,Y)=>{if(X)T$($,"documents",W.id,"order_key",Q[Y]);else $.query("UPDATE documents SET order_key = ? WHERE id = ?").run(Q[Y],W.id)})}var dW=d$(function(J){let X=J.query("SELECT DISTINCT parent_id FROM documents WHERE __deleted = 0 AND order_key IS NULL").all();for(let G of X)oW(J,G.parent_id)});function d1($,J,X,G){let U=X;while(U){if(U===J)throw new V$("invalid_input",`cannot set parent_id: would create a cycle (${J})`);U=z6($,U)?.parent_id??null}let Q=z6($,J);if(Q&&(Q.parent_id??null)!==X)T$($,"documents",J,"parent_id",X);let W;if(!G)W=b6(mW($,X,J),null);else{oW($,X);let Y=()=>{let A=rW($,X).filter((r)=>r.id!==J),M=A.findIndex((r)=>r.id===G.targetId);if(M<0)throw new V$("not_found",`no such target document: ${G.targetId}`);return G.where==="before"?[A[M-1]?.order_key??null,A[M].order_key]:[A[M].order_key,A[M+1]?.order_key??null]},[V,H]=Y();if(V!==null&&H!==null&&V>=H)CK($,X),[V,H]=Y();W=b6(V,H)}T$($,"documents",J,"order_key",W)}var DJ=d$(function(J,X,G,U){let Q=z6(J,X);if(!Q)throw new V$("not_found",`no such document: ${X}`);if(X===G)return Q;let W=z6(J,G);if(!W)throw new V$("not_found",`no such target document: ${G}`);if(U==="into")d1(J,X,G);else d1(J,X,W.parent_id,{targetId:G,where:U});return z6(J,X)}),pW=d$(function(J,X,G={}){let U=z6(J,X);if(!U)throw new V$("not_found",`no such document: ${X}`);sv(J,X);let Q=av(J,X),W=G.parentId!==void 0?G.parentId:U.parent_id,Y=YJ(J,{title:G.title??U.title,database_id:U.database_id??void 0,parent_id:W??void 0});if(Q.length)ev(J,Y.id,Q.map((V)=>({text:V.text,blankAfter:V.blank_after})),null,null);if(W===U.parent_id)DJ(J,Y.id,U.id,"after");return z6(J,Y.id)}),p1=d$(function(J,X,G,U={}){if(!z6(J,X))throw new V$("not_found",`no such document: ${X}`);if(U.ifMatch!==void 0&&R6(J,X)!==U.ifMatch)throw new V$("stale",`stale: document changed since ${U.ifMatch}; re-read first`);if(G.title!==void 0)T$(J,"documents",X,"title",G.title);if(G.database_id!==void 0)T$(J,"documents",X,"database_id",G.database_id);if(G.parent_id!==void 0){let Q=G.parent_id??null;if((z6(J,X).parent_id??null)!==Q)d1(J,X,Q)}if(G.body!==void 0)sv(J,X),jJ(J,X,G.body);return z6(J,X)}),eO=d$(function(J,X,G){if(!z6(J,X))throw new V$("not_found",`no such document: ${X}`);if(G.ifMatch!==void 0&&R6(J,X)!==G.ifMatch)throw new V$("stale",`stale: document changed since ${G.ifMatch}; re-read first`);if(G.old==="")throw new V$("invalid_input","--old must not be empty");sv(J,X);let U=av(J,X),Q=Cv(U.map((V)=>({text:V.text,blankAfter:V.blank_after}))),W=aW(Q,G.old);if(W===0)throw new V$("invalid_input","anchor not found: no match for --old");if(W>1&&!G.replaceAll)throw new V$("ambiguous",`${W} matches for --old; add surrounding context or use --replace-all`);if(!G.old.includes(`
271
271
 
272
- `)){let V=U.filter((A)=>A.text.includes(G.old)),H=V.map((A)=>G.replaceAll?A.text.replaceAll(G.old,G.new):A.text.replace(G.old,G.new));if(H.every((A)=>A.length>0&&!A.includes(`
272
+ `)){let V=U.filter((A)=>A.text.includes(G.old)),H=V.map((A)=>G.replaceAll?A.text.replaceAll(G.old,()=>G.new):A.text.replace(G.old,()=>G.new));if(H.every((A)=>A.length>0&&!A.includes(`
273
273
 
274
- `)))return(G.replaceAll?V:V.slice(0,1)).forEach((M,r)=>T$(J,"doc_blocks",M.id,"text",H[r])),{id:X,changed:!0,replaced:G.replaceAll?W:1,version:R6(J,X)}}let Y=G.replaceAll?Q.replaceAll(G.old,G.new):Q.replace(G.old,G.new);return jJ(J,X,Y),{id:X,changed:Y!==Q,replaced:G.replaceAll?W:1,version:R6(J,X)}}),sO=d$(function(J,X,G){if(!z6(J,X))throw new V$("not_found",`no such document: ${X}`);if(G.edits.length===0)throw new V$("invalid_input","no edits given");if(G.ifMatch!==void 0&&R6(J,X)!==G.ifMatch)throw new V$("stale",`stale: document changed since ${G.ifMatch}; re-read first`);sv(J,X);let U=Cv(av(J,X).map((Y)=>({text:Y.text,blankAfter:Y.blank_after}))),Q=U,W=0;if(G.edits.forEach((Y,V)=>{if(Y.old==="")throw new V$("invalid_input",`edit[${V}]: old must not be empty`);let H=aW(Q,Y.old);if(H===0)throw new V$("invalid_input",`edit[${V}]: anchor not found: no match for old`);if(H>1&&!Y.replaceAll)throw new V$("ambiguous",`edit[${V}]: ${H} matches for old; add surrounding context or set replaceAll`);let A=Y.new??"";Q=Y.replaceAll?Q.replaceAll(Y.old,A):Q.replace(Y.old,A),W+=Y.replaceAll?H:1}),Q!==U)jJ(J,X,Q);return{id:X,changed:Q!==U,replaced:W,version:R6(J,X)}}),$L=d$(function(J,X,G){if(!z6(J,X))throw new V$("not_found",`no such document: ${X}`);sv(J,X);let U=pv(G);if(U.length){let Q=av(J,X),W=Q.length?Q[Q.length-1].order_key:null;ev(J,X,U,W,null)}return{id:X,changed:U.length>0,replaced:U.length,version:R6(J,X)}}),vL=d$(function(J,X,G){if(!z6(J,X))throw new V$("not_found",`no such document: ${X}`);sv(J,X);let U=pv(G);if(U.length){let Q=av(J,X),W=Q.length?Q[0].order_key:null;ev(J,X,U,null,W)}return{id:X,changed:U.length>0,replaced:U.length,version:R6(J,X)}}),tW=d$(function(J,X){if(!z6(J,X))return!1;T$(J,"documents",X,"__deleted",1);for(let G of cW(J,"doc_blocks","doc_id",X))T$(J,"doc_blocks",G,"__deleted",1);for(let G of cW(J,"documents","parent_id",X))T$(J,"documents",G,"parent_id",null);return!0});function cW($,J,X,G){return $.query(`SELECT id FROM ${J} WHERE ${X} = ? AND __deleted = 0`).all(G).map((U)=>U.id)}function aW($,J){if(J==="")return 0;let X=0,G=$.indexOf(J);while(G!==-1)X++,G=$.indexOf(J,G+J.length);return X}var IJ="default";function zJ($){let J=$.query("SELECT full_nodes, redundancy FROM blob_policy WHERE id = ? AND __deleted = 0").get(IJ),X=[];if(J?.full_nodes)try{let U=JSON.parse(J.full_nodes);if(Array.isArray(U))X=U.filter((Q)=>typeof Q==="string")}catch{}let G=J?.redundancy==="any"?"any":"all";return{fullNodes:X,redundancy:G}}var eW=($,J)=>{cU(null,()=>{let X=new Set,G=J.filter((Q)=>Q&&!X.has(Q)&&X.add(Q)!=null);if(T$($,"blob_policy",IJ,"full_nodes",G),zJ($).redundancy==null)T$($,"blob_policy",IJ,"redundancy","all")}),MK($)};function MK($){$.query("UPDATE blob_cache SET anchored = 0").run(),$.query("DELETE FROM meta WHERE key = ?").run(FK)}var FK="blob_verified_at";var uK=/\/blob\/([0-9a-f]{16,64})/g;function EK($){if(!$)return[];let J=[];for(let X of $.matchAll(uK))J.push(X[1]);return J}function sW($){let J=new Set,X=$.query("SELECT content FROM site_files WHERE encoding = 'blob' AND __deleted = 0").all();for(let U of X)if(U.content)J.add(U.content);let G=$.query("SELECT text FROM doc_blocks WHERE __deleted = 0 AND text LIKE '%/blob/%'").all();for(let U of G)for(let Q of EK(U.text))J.add(Q);return J}var SK={"https:":"443","http:":"80"};function $j($){try{let J=new URL($),X=J.port&&J.port!==SK[J.protocol]?`:${J.port}`:"";return J.hostname+X}catch{return $.trim().replace(/^[a-z]+:\/\//i,"").replace(/\/.*$/,"").replace(/:(80|443)$/,"")}}function $U($,J,X){let G=X?.trim()||"metahub";return`s3://${$j($)}/${J}/${G}`}function gK($){$.exec(WW);try{$.exec(jW)}catch{}}function vj($){return $.query("SELECT 1 AS ok FROM sqlite_master WHERE name = 'search_fts'").get()!=null}function i6($,J,X){return $.query(`PRAGMA table_info(${J})`).all().some((U)=>U.name===X)}function vU($,J){return $.query("SELECT 1 AS ok FROM sqlite_master WHERE type = 'table' AND name = ?").get(J)!=null}function wK($){if(!i6($,"records","data"))$.exec("ALTER TABLE records ADD COLUMN data TEXT NOT NULL DEFAULT '{}'");if(!i6($,"records","order_key"))$.exec("ALTER TABLE records ADD COLUMN order_key TEXT");if(!vU($,"record_values"))return;$.transaction(()=>{$.exec(`
274
+ `))){let A=G.replaceAll?V:V.slice(0,1),M=!1;return A.forEach((r,e)=>{if(H[e]!==r.text)T$(J,"doc_blocks",r.id,"text",H[e]),M=!0}),{id:X,changed:M,replaced:G.replaceAll?W:1,version:R6(J,X)}}}let Y=G.replaceAll?Q.replaceAll(G.old,()=>G.new):Q.replace(G.old,()=>G.new);return jJ(J,X,Y),{id:X,changed:Y!==Q,replaced:G.replaceAll?W:1,version:R6(J,X)}}),sO=d$(function(J,X,G){if(!z6(J,X))throw new V$("not_found",`no such document: ${X}`);if(G.edits.length===0)throw new V$("invalid_input","no edits given");if(G.ifMatch!==void 0&&R6(J,X)!==G.ifMatch)throw new V$("stale",`stale: document changed since ${G.ifMatch}; re-read first`);sv(J,X);let U=Cv(av(J,X).map((Y)=>({text:Y.text,blankAfter:Y.blank_after}))),Q=U,W=0;if(G.edits.forEach((Y,V)=>{if(Y.old==="")throw new V$("invalid_input",`edit[${V}]: old must not be empty`);let H=aW(Q,Y.old);if(H===0)throw new V$("invalid_input",`edit[${V}]: anchor not found: no match for old`);if(H>1&&!Y.replaceAll)throw new V$("ambiguous",`edit[${V}]: ${H} matches for old; add surrounding context or set replaceAll`);let A=Y.new??"";Q=Y.replaceAll?Q.replaceAll(Y.old,()=>A):Q.replace(Y.old,()=>A),W+=Y.replaceAll?H:1}),Q!==U)jJ(J,X,Q);return{id:X,changed:Q!==U,replaced:W,version:R6(J,X)}}),$L=d$(function(J,X,G){if(!z6(J,X))throw new V$("not_found",`no such document: ${X}`);sv(J,X);let U=pv(G);if(U.length){let Q=av(J,X),W=Q.length?Q[Q.length-1].order_key:null;ev(J,X,U,W,null)}return{id:X,changed:U.length>0,replaced:U.length,version:R6(J,X)}}),vL=d$(function(J,X,G){if(!z6(J,X))throw new V$("not_found",`no such document: ${X}`);sv(J,X);let U=pv(G);if(U.length){let Q=av(J,X),W=Q.length?Q[0].order_key:null;ev(J,X,U,null,W)}return{id:X,changed:U.length>0,replaced:U.length,version:R6(J,X)}}),tW=d$(function(J,X){if(!z6(J,X))return!1;T$(J,"documents",X,"__deleted",1);for(let G of cW(J,"doc_blocks","doc_id",X))T$(J,"doc_blocks",G,"__deleted",1);for(let G of cW(J,"documents","parent_id",X))T$(J,"documents",G,"parent_id",null);return!0});function cW($,J,X,G){return $.query(`SELECT id FROM ${J} WHERE ${X} = ? AND __deleted = 0`).all(G).map((U)=>U.id)}function aW($,J){if(J==="")return 0;let X=0,G=$.indexOf(J);while(G!==-1)X++,G=$.indexOf(J,G+J.length);return X}var IJ="default";function zJ($){let J=$.query("SELECT full_nodes, redundancy FROM blob_policy WHERE id = ? AND __deleted = 0").get(IJ),X=[];if(J?.full_nodes)try{let U=JSON.parse(J.full_nodes);if(Array.isArray(U))X=U.filter((Q)=>typeof Q==="string")}catch{}let G=J?.redundancy==="any"?"any":"all";return{fullNodes:X,redundancy:G}}var eW=($,J)=>{cU(null,()=>{let X=new Set,G=J.filter((Q)=>Q&&!X.has(Q)&&X.add(Q)!=null);if(T$($,"blob_policy",IJ,"full_nodes",G),zJ($).redundancy==null)T$($,"blob_policy",IJ,"redundancy","all")}),MK($)};function MK($){$.query("UPDATE blob_cache SET anchored = 0").run(),$.query("DELETE FROM meta WHERE key = ?").run(FK)}var FK="blob_verified_at";var uK=/\/blob\/([0-9a-f]{16,64})/g;function EK($){if(!$)return[];let J=[];for(let X of $.matchAll(uK))J.push(X[1]);return J}function sW($){let J=new Set,X=$.query("SELECT content FROM site_files WHERE encoding = 'blob' AND __deleted = 0").all();for(let U of X)if(U.content)J.add(U.content);let G=$.query("SELECT text FROM doc_blocks WHERE __deleted = 0 AND text LIKE '%/blob/%'").all();for(let U of G)for(let Q of EK(U.text))J.add(Q);return J}var SK={"https:":"443","http:":"80"};function $j($){try{let J=new URL($),X=J.port&&J.port!==SK[J.protocol]?`:${J.port}`:"";return J.hostname+X}catch{return $.trim().replace(/^[a-z]+:\/\//i,"").replace(/\/.*$/,"").replace(/:(80|443)$/,"")}}function $U($,J,X){let G=X?.trim()||"metahub";return`s3://${$j($)}/${J}/${G}`}function gK($){$.exec(WW);try{$.exec(jW)}catch{}}function vj($){return $.query("SELECT 1 AS ok FROM sqlite_master WHERE name = 'search_fts'").get()!=null}function i6($,J,X){return $.query(`PRAGMA table_info(${J})`).all().some((U)=>U.name===X)}function vU($,J){return $.query("SELECT 1 AS ok FROM sqlite_master WHERE type = 'table' AND name = ?").get(J)!=null}function wK($){if(!i6($,"records","data"))$.exec("ALTER TABLE records ADD COLUMN data TEXT NOT NULL DEFAULT '{}'");if(!i6($,"records","order_key"))$.exec("ALTER TABLE records ADD COLUMN order_key TEXT");if(!vU($,"record_values"))return;$.transaction(()=>{$.exec(`
275
275
  UPDATE records SET data = coalesce((
276
276
  SELECT json_group_object(rv.property_id, json(rv.value))
277
277
  FROM record_values rv WHERE rv.record_id = records.id
package/dist/index.js CHANGED
@@ -1392,16 +1392,22 @@ var init_documents = __esm(() => {
1392
1392
 
1393
1393
  `)) {
1394
1394
  const affected = blocks.filter((b) => b.text.includes(opts.old));
1395
- const next = affected.map((b) => opts.replaceAll ? b.text.replaceAll(opts.old, opts.new) : b.text.replace(opts.old, opts.new));
1395
+ const next = affected.map((b) => opts.replaceAll ? b.text.replaceAll(opts.old, () => opts.new) : b.text.replace(opts.old, () => opts.new));
1396
1396
  if (next.every((t) => t.length > 0 && !t.includes(`
1397
1397
 
1398
1398
  `))) {
1399
1399
  const targets = opts.replaceAll ? affected : affected.slice(0, 1);
1400
- targets.forEach((b, i) => emit(db, "doc_blocks", b.id, "text", next[i]));
1401
- return { id, changed: true, replaced: opts.replaceAll ? count : 1, version: documentVersion(db, id) };
1400
+ let wrote = false;
1401
+ targets.forEach((b, i) => {
1402
+ if (next[i] !== b.text) {
1403
+ emit(db, "doc_blocks", b.id, "text", next[i]);
1404
+ wrote = true;
1405
+ }
1406
+ });
1407
+ return { id, changed: wrote, replaced: opts.replaceAll ? count : 1, version: documentVersion(db, id) };
1402
1408
  }
1403
1409
  }
1404
- const newBody = opts.replaceAll ? body.replaceAll(opts.old, opts.new) : body.replace(opts.old, opts.new);
1410
+ const newBody = opts.replaceAll ? body.replaceAll(opts.old, () => opts.new) : body.replace(opts.old, () => opts.new);
1405
1411
  reconcileBody(db, id, newBody);
1406
1412
  return { id, changed: newBody !== body, replaced: opts.replaceAll ? count : 1, version: documentVersion(db, id) };
1407
1413
  });
@@ -1425,7 +1431,7 @@ var init_documents = __esm(() => {
1425
1431
  if (count > 1 && !e.replaceAll)
1426
1432
  throw new MhError("ambiguous", `edit[${i}]: ${count} matches for old; add surrounding context or set replaceAll`);
1427
1433
  const repl = e.new ?? "";
1428
- body = e.replaceAll ? body.replaceAll(e.old, repl) : body.replace(e.old, repl);
1434
+ body = e.replaceAll ? body.replaceAll(e.old, () => repl) : body.replace(e.old, () => repl);
1429
1435
  total += e.replaceAll ? count : 1;
1430
1436
  });
1431
1437
  if (body !== orig)
@@ -18803,6 +18809,70 @@ var init_shares = __esm(() => {
18803
18809
  });
18804
18810
 
18805
18811
  // src/core/md/grammar.ts
18812
+ function safeUrl(url2, opts = {}) {
18813
+ const probe = url2.replace(/[\u0000-\u0020]+/g, "");
18814
+ const m = /^([a-z][a-z0-9+.-]*):/i.exec(probe);
18815
+ if (!m)
18816
+ return url2;
18817
+ const scheme = m[1].toLowerCase();
18818
+ if (scheme === "http" || scheme === "https" || scheme === "mailto" || scheme === "blob")
18819
+ return url2;
18820
+ if (scheme === "data" && opts.allowData)
18821
+ return url2;
18822
+ return "#";
18823
+ }
18824
+ function extOf(url2) {
18825
+ const clean = url2.split(/[?#]/, 1)[0] ?? url2;
18826
+ const base = clean.slice(clean.lastIndexOf("/") + 1);
18827
+ const dot = base.lastIndexOf(".");
18828
+ return dot >= 0 ? base.slice(dot + 1).toLowerCase() : "";
18829
+ }
18830
+ function imageSyntaxKind(ext2) {
18831
+ if (VIDEO_EXTS.has(ext2))
18832
+ return "video";
18833
+ if (AUDIO_EXTS.has(ext2))
18834
+ return "audio";
18835
+ return "image";
18836
+ }
18837
+ function parseMediaUrl(url2) {
18838
+ const hash3 = url2.indexOf("#");
18839
+ const frag = hash3 >= 0 ? url2.slice(hash3) : "";
18840
+ const noFrag = hash3 >= 0 ? url2.slice(0, hash3) : url2;
18841
+ const q = noFrag.indexOf("?");
18842
+ if (q < 0)
18843
+ return { src: url2 };
18844
+ const base = noFrag.slice(0, q);
18845
+ let width;
18846
+ const kept = [];
18847
+ for (const p of noFrag.slice(q + 1).split("&").filter(Boolean)) {
18848
+ const m = p.match(/^w=(\d+)$/);
18849
+ if (m)
18850
+ width = parseInt(m[1], 10);
18851
+ else
18852
+ kept.push(p);
18853
+ }
18854
+ return { src: base + (kept.length ? "?" + kept.join("&") : "") + frag, width };
18855
+ }
18856
+ function matchMediaEmbed(line) {
18857
+ const t = line.trim();
18858
+ let m = t.match(/^!\[([^\]]*)\]\(([^\s)]+)\)$/);
18859
+ if (m) {
18860
+ const { src, width } = parseMediaUrl(m[2]);
18861
+ const kind = imageSyntaxKind(extOf(src));
18862
+ const r = { kind, src, name: m[1] };
18863
+ if (kind === "image" && width)
18864
+ r.width = width;
18865
+ return r;
18866
+ }
18867
+ m = t.match(/^\[([^\]]*)\]\(([^\s)]+)(?:\s+"([^"]*)")?\)$/);
18868
+ if (m && m[2].startsWith("/blob/")) {
18869
+ const r = { kind: "file", src: m[2], name: m[1] };
18870
+ if (m[3] != null && /^\d+$/.test(m[3]))
18871
+ r.size = parseInt(m[3], 10);
18872
+ return r;
18873
+ }
18874
+ return null;
18875
+ }
18806
18876
  function matchQuoteLine(text) {
18807
18877
  const m = text.match(RE.quote);
18808
18878
  return m ? m[1] : null;
@@ -18906,7 +18976,7 @@ function splitTableRow(line) {
18906
18976
  cells.pop();
18907
18977
  return cells.map((c) => c.trim());
18908
18978
  }
18909
- var HTML_FENCE = "mh-html", RE, RE_DELIM_CELL;
18979
+ var HTML_FENCE = "mh-html", RE, VIDEO_EXTS, AUDIO_EXTS, RE_DELIM_CELL;
18910
18980
  var init_grammar = __esm(() => {
18911
18981
  RE = {
18912
18982
  fenceOpen: /^\s*(`{3,}|~{3,})\s*([^\s`]*)?.*$/,
@@ -18917,6 +18987,8 @@ var init_grammar = __esm(() => {
18917
18987
  quote: /^>[ \t](.*)$/,
18918
18988
  divider: /^\s*(?:-{3,}|\*{3,}|_{3,})\s*$/
18919
18989
  };
18990
+ VIDEO_EXTS = new Set(["mp4", "webm", "mov", "m4v", "ogv", "mkv", "ogg"]);
18991
+ AUDIO_EXTS = new Set(["mp3", "wav", "m4a", "aac", "flac", "opus", "oga", "weba"]);
18920
18992
  RE_DELIM_CELL = /^\s*:?-+:?\s*$/;
18921
18993
  });
18922
18994
 
@@ -19030,6 +19102,15 @@ function healLegacyMarkdown(src) {
19030
19102
  changed = true;
19031
19103
  }
19032
19104
  }
19105
+ for (let i = lines.length - 1;i >= 0; i--) {
19106
+ if (inFence[i])
19107
+ continue;
19108
+ const line = lines[i];
19109
+ if (BARE_QUOTE.test(line) && (quoteish(i - 1) || quoteish(i + 1))) {
19110
+ lines[i] = line + " ";
19111
+ changed = true;
19112
+ }
19113
+ }
19033
19114
  return changed ? lines.join(`
19034
19115
  `) : src;
19035
19116
  }
@@ -19052,7 +19133,7 @@ function renderInline(src, opts = {}) {
19052
19133
  for (const t of tokens) {
19053
19134
  out += escapeHtml(src.slice(pos, t.start));
19054
19135
  const inner = src.slice(t.innerFrom, t.innerTo);
19055
- const url2 = rewrite(t.url ?? "", opts).replace(/"/g, "&quot;");
19136
+ const rawUrl = rewrite(t.url ?? "", opts);
19056
19137
  switch (t.kind) {
19057
19138
  case "code":
19058
19139
  out += `<code>${escapeHtml(inner)}</code>`;
@@ -19066,12 +19147,16 @@ function renderInline(src, opts = {}) {
19066
19147
  case "del":
19067
19148
  out += `<del>${escapeHtml(inner)}</del>`;
19068
19149
  break;
19069
- case "link":
19070
- out += `<a href="${url2}" target="_blank" rel="noreferrer noopener">${escapeHtml(inner)}</a>`;
19150
+ case "link": {
19151
+ const href = escapeHtml(safeUrl(rawUrl));
19152
+ out += `<a href="${href}" target="_blank" rel="noreferrer noopener">${escapeHtml(inner)}</a>`;
19071
19153
  break;
19072
- case "image":
19073
- out += `<img src="${url2}" alt="${escapeHtml(t.alt ?? "")}" loading="lazy">`;
19154
+ }
19155
+ case "image": {
19156
+ const imgSrc = escapeHtml(safeUrl(rawUrl, { allowData: true }));
19157
+ out += `<img src="${imgSrc}" alt="${escapeHtml(t.alt ?? "")}" loading="lazy">`;
19074
19158
  break;
19159
+ }
19075
19160
  }
19076
19161
  pos = t.end;
19077
19162
  }
@@ -19082,6 +19167,19 @@ function rewrite(url2, opts) {
19082
19167
  return opts.rewriteBlob(url2);
19083
19168
  return url2;
19084
19169
  }
19170
+ function renderMedia(m, opts) {
19171
+ const raw = rewrite(m.src, opts);
19172
+ if (m.kind === "video") {
19173
+ const src = escapeHtml(safeUrl(raw, { allowData: true }));
19174
+ return `<p class="mh-media"><video src="${src}" controls preload="metadata"></video></p>`;
19175
+ }
19176
+ if (m.kind === "audio") {
19177
+ const src = escapeHtml(safeUrl(raw, { allowData: true }));
19178
+ return `<p class="mh-media"><audio src="${src}" controls preload="metadata"></audio></p>`;
19179
+ }
19180
+ const href = escapeHtml(safeUrl(raw));
19181
+ return `<p class="mh-file"><a href="${href}" download>${escapeHtml(m.name || "file")}</a></p>`;
19182
+ }
19085
19183
  function renderMarkdown(md, opts = {}) {
19086
19184
  const healed = healLegacyMarkdown((md ?? "").replace(/\r\n?/g, `
19087
19185
  `));
@@ -19193,9 +19291,10 @@ function renderMarkdown(md, opts = {}) {
19193
19291
  out.push(ordered ? `<ol>${lis.join("")}</ol>` : `<ul>${lis.join("")}</ul>`);
19194
19292
  continue;
19195
19293
  }
19196
- if (/^\s*!\[[^\]]*\]\([^)\s]+\)\s*$/.test(line)) {
19294
+ const media = matchMediaEmbed(line);
19295
+ if (media) {
19197
19296
  flushPara();
19198
- out.push(`<p class="mh-img">${renderInline(line.trim(), opts)}</p>`);
19297
+ out.push(media.kind === "image" ? `<p class="mh-img">${renderInline(line.trim(), opts)}</p>` : renderMedia(media, opts));
19199
19298
  i++;
19200
19299
  continue;
19201
19300
  }
@@ -19630,6 +19729,8 @@ function pageShell(title, inner, opts = {}) {
19630
19729
  td[contenteditable]{outline:none} td.saving{opacity:.5} td.saved{background:rgba(46,160,67,.18)}
19631
19730
  .tag{display:inline-block;background:var(--card);border:1px solid var(--line);border-radius:999px;padding:1px 9px;font-size:12px}
19632
19731
  .muted{color:var(--muted)} .mh-img{text-align:center}
19732
+ .mh-media{text-align:center} .mh-media video,.mh-media audio{max-width:100%}
19733
+ .mh-file a{display:inline-block;background:var(--card);border:1px solid var(--line);border-radius:8px;padding:8px 14px;color:var(--accent);text-decoration:none}
19633
19734
  iframe.mh-embed{width:100%;border:1px solid var(--line);border-radius:8px;min-height:240px}
19634
19735
  textarea.mh-raw{width:100%;min-height:60vh;font:14px/1.6 ui-monospace,SFMono-Regular,Menlo,monospace;padding:14px;border:1px solid var(--line);border-radius:8px;background:var(--card);color:var(--fg)}
19635
19736
  ul.files{list-style:none;padding:0} ul.files li{padding:4px 0} button.file{background:none;border:0;color:var(--accent);cursor:pointer;font-size:15px;padding:0}
@@ -20348,7 +20449,7 @@ init_config();
20348
20449
  // package.json
20349
20450
  var package_default = {
20350
20451
  name: "@tensorix/metahub",
20351
- version: "0.3.1",
20452
+ version: "0.3.2",
20352
20453
  description: "Metahub core library and CLI",
20353
20454
  license: "AGPL-3.0-only",
20354
20455
  type: "module",
@@ -25262,4 +25363,4 @@ export {
25262
25363
  BLOB_HASH_HEX
25263
25364
  };
25264
25365
 
25265
- //# debugId=F05E548741611AE364756E2164756E21
25366
+ //# debugId=6391E3807369E20264756E2164756E21