@inkandswitch/patchwork-pkg-base 0.0.97 → 0.0.99

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.
@@ -1 +1 @@
1
- automerge:4EhwfShT9ybL5Tf1rEc7dfNB97Gx
1
+ automerge:25THBJy1ym2cnE4ovaVak8yMjNjT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inkandswitch/patchwork-pkg-base",
3
- "version": "0.0.97",
3
+ "version": "0.0.99",
4
4
  "type": "module",
5
5
  "description": "Base packages for the Patchwork system",
6
6
  "repository": {
@@ -29,7 +29,7 @@ var MarkdownDatatype = {
29
29
  updateText(
30
30
  doc,
31
31
  ["content"],
32
- doc.content.replace(/^#\s+(.*)/gm, () => `# ${title}`)
32
+ doc.content.replace(/^#\s+(.*)/m, () => `# ${title}`)
33
33
  );
34
34
  } else {
35
35
  if (hasFrontmatter) return;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/datatype.ts"],
4
- "sourcesContent": ["import { type DatatypeImplementation } from \"@inkandswitch/patchwork-plugins\";\nimport { updateText } from \"@automerge/automerge/slim\";\n\nexport type MarkdownDoc = {\n content: string;\n};\n\nconst frontmatterRegex = /---\\n([\\s\\S]+?)\\n---/;\n\nexport const MarkdownDatatype: DatatypeImplementation<MarkdownDoc> = {\n init(doc: MarkdownDoc) {\n doc.content = \"# Untitled\";\n },\n getTitle(doc: MarkdownDoc) {\n const content = doc.content;\n\n const frontmatterMatch = content.match(frontmatterRegex);\n const frontmatter = frontmatterMatch ? frontmatterMatch[1] : \"\";\n\n const titleRegex = /title:\\s\"(.+?)\"/;\n const subtitleRegex = /subtitle:\\s\"(.+?)\"/;\n\n const titleMatch = frontmatter.match(titleRegex);\n const subtitleMatch = frontmatter.match(subtitleRegex);\n\n let title = titleMatch ? titleMatch[1] : null;\n const subtitle = subtitleMatch ? subtitleMatch[1] : \"\";\n\n // If title not found in frontmatter, find first markdown heading\n if (!title) {\n const titleFallbackRegex = /(^|\\n)#\\s(.+)/;\n const titleFallbackMatch = content.match(titleFallbackRegex);\n title = titleFallbackMatch ? titleFallbackMatch[2] : \"Untitled\";\n }\n\n return `${title}${subtitle && `: ${subtitle}`}`;\n },\n setTitle(doc: MarkdownDoc, title: string) {\n const hasTitle = doc.content.match(/^#\\s/gm);\n const hasFrontmatter = frontmatterRegex.exec(doc.content);\n\n if (hasTitle) {\n updateText(\n doc,\n [\"content\"],\n doc.content.replace(/^#\\s+(.*)/gm, () => `# ${title}`)\n );\n } else {\n // todo\n if (hasFrontmatter) return;\n updateText(\n doc,\n [\"content\"],\n (doc.content = `# ${title}\\n` + doc.content)\n );\n }\n },\n};\n"],
5
- "mappings": ";AACA,SAAS,kBAAkB;AAM3B,IAAM,mBAAmB;AAElB,IAAM,mBAAwD;AAAA,EACnE,KAAK,KAAkB;AACrB,QAAI,UAAU;AAAA,EAChB;AAAA,EACA,SAAS,KAAkB;AACzB,UAAM,UAAU,IAAI;AAEpB,UAAM,mBAAmB,QAAQ,MAAM,gBAAgB;AACvD,UAAM,cAAc,mBAAmB,iBAAiB,CAAC,IAAI;AAE7D,UAAM,aAAa;AACnB,UAAM,gBAAgB;AAEtB,UAAM,aAAa,YAAY,MAAM,UAAU;AAC/C,UAAM,gBAAgB,YAAY,MAAM,aAAa;AAErD,QAAI,QAAQ,aAAa,WAAW,CAAC,IAAI;AACzC,UAAM,WAAW,gBAAgB,cAAc,CAAC,IAAI;AAGpD,QAAI,CAAC,OAAO;AACV,YAAM,qBAAqB;AAC3B,YAAM,qBAAqB,QAAQ,MAAM,kBAAkB;AAC3D,cAAQ,qBAAqB,mBAAmB,CAAC,IAAI;AAAA,IACvD;AAEA,WAAO,GAAG,KAAK,GAAG,YAAY,KAAK,QAAQ,EAAE;AAAA,EAC/C;AAAA,EACA,SAAS,KAAkB,OAAe;AACxC,UAAM,WAAW,IAAI,QAAQ,MAAM,QAAQ;AAC3C,UAAM,iBAAiB,iBAAiB,KAAK,IAAI,OAAO;AAExD,QAAI,UAAU;AACZ;AAAA,QACE;AAAA,QACA,CAAC,SAAS;AAAA,QACV,IAAI,QAAQ,QAAQ,eAAe,MAAM,KAAK,KAAK,EAAE;AAAA,MACvD;AAAA,IACF,OAAO;AAEL,UAAI,eAAgB;AACpB;AAAA,QACE;AAAA,QACA,CAAC,SAAS;AAAA,QACT,IAAI,UAAU,KAAK,KAAK;AAAA,IAAO,IAAI;AAAA,MACtC;AAAA,IACF;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import { type DatatypeImplementation } from \"@inkandswitch/patchwork-plugins\";\nimport { updateText } from \"@automerge/automerge/slim\";\n\nexport type MarkdownDoc = {\n content: string;\n};\n\nconst frontmatterRegex = /---\\n([\\s\\S]+?)\\n---/;\n\nexport const MarkdownDatatype: DatatypeImplementation<MarkdownDoc> = {\n init(doc: MarkdownDoc) {\n doc.content = \"# Untitled\";\n },\n getTitle(doc: MarkdownDoc) {\n const content = doc.content;\n\n const frontmatterMatch = content.match(frontmatterRegex);\n const frontmatter = frontmatterMatch ? frontmatterMatch[1] : \"\";\n\n const titleRegex = /title:\\s\"(.+?)\"/;\n const subtitleRegex = /subtitle:\\s\"(.+?)\"/;\n\n const titleMatch = frontmatter.match(titleRegex);\n const subtitleMatch = frontmatter.match(subtitleRegex);\n\n let title = titleMatch ? titleMatch[1] : null;\n const subtitle = subtitleMatch ? subtitleMatch[1] : \"\";\n\n // If title not found in frontmatter, find first markdown heading\n if (!title) {\n const titleFallbackRegex = /(^|\\n)#\\s(.+)/;\n const titleFallbackMatch = content.match(titleFallbackRegex);\n title = titleFallbackMatch ? titleFallbackMatch[2] : \"Untitled\";\n }\n\n return `${title}${subtitle && `: ${subtitle}`}`;\n },\n setTitle(doc: MarkdownDoc, title: string) {\n const hasTitle = doc.content.match(/^#\\s/gm);\n const hasFrontmatter = frontmatterRegex.exec(doc.content);\n\n if (hasTitle) {\n updateText(\n doc,\n [\"content\"],\n doc.content.replace(/^#\\s+(.*)/m, () => `# ${title}`)\n );\n } else {\n // todo\n if (hasFrontmatter) return;\n updateText(\n doc,\n [\"content\"],\n (doc.content = `# ${title}\\n` + doc.content)\n );\n }\n },\n};\n"],
5
+ "mappings": ";AACA,SAAS,kBAAkB;AAM3B,IAAM,mBAAmB;AAElB,IAAM,mBAAwD;AAAA,EACnE,KAAK,KAAkB;AACrB,QAAI,UAAU;AAAA,EAChB;AAAA,EACA,SAAS,KAAkB;AACzB,UAAM,UAAU,IAAI;AAEpB,UAAM,mBAAmB,QAAQ,MAAM,gBAAgB;AACvD,UAAM,cAAc,mBAAmB,iBAAiB,CAAC,IAAI;AAE7D,UAAM,aAAa;AACnB,UAAM,gBAAgB;AAEtB,UAAM,aAAa,YAAY,MAAM,UAAU;AAC/C,UAAM,gBAAgB,YAAY,MAAM,aAAa;AAErD,QAAI,QAAQ,aAAa,WAAW,CAAC,IAAI;AACzC,UAAM,WAAW,gBAAgB,cAAc,CAAC,IAAI;AAGpD,QAAI,CAAC,OAAO;AACV,YAAM,qBAAqB;AAC3B,YAAM,qBAAqB,QAAQ,MAAM,kBAAkB;AAC3D,cAAQ,qBAAqB,mBAAmB,CAAC,IAAI;AAAA,IACvD;AAEA,WAAO,GAAG,KAAK,GAAG,YAAY,KAAK,QAAQ,EAAE;AAAA,EAC/C;AAAA,EACA,SAAS,KAAkB,OAAe;AACxC,UAAM,WAAW,IAAI,QAAQ,MAAM,QAAQ;AAC3C,UAAM,iBAAiB,iBAAiB,KAAK,IAAI,OAAO;AAExD,QAAI,UAAU;AACZ;AAAA,QACE;AAAA,QACA,CAAC,SAAS;AAAA,QACV,IAAI,QAAQ,QAAQ,cAAc,MAAM,KAAK,KAAK,EAAE;AAAA,MACtD;AAAA,IACF,OAAO;AAEL,UAAI,eAAgB;AACpB;AAAA,QACE;AAAA,QACA,CAAC,SAAS;AAAA,QACT,IAAI,UAAU,KAAK,KAAK;AAAA,IAAO,IAAI;AAAA,MACtC;AAAA,IACF;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -36,13 +36,13 @@ function F(t, e) {
36
36
  function y(t) {
37
37
  return t.content instanceof Uint8Array;
38
38
  }
39
- function S(t) {
39
+ function U(t) {
40
40
  return typeof t.content == "string";
41
41
  }
42
- const g = (t) => typeof t == "object" && t !== null && !(t instanceof Uint8Array) && typeof t.val == "string", A = (t) => l(t.content) || g(t.content), I = (t) => y(t) && !F(t.content, t.content.length), N = (t) => {
42
+ const g = (t) => typeof t == "object" && t !== null && !(t instanceof Uint8Array) && typeof t.val == "string", E = (t) => l(t.content) || g(t.content), I = (t) => y(t) && !F(t.content, t.content.length), x = (t) => {
43
43
  const e = t == null ? void 0 : t.content;
44
44
  return typeof e == "string" ? e : g(e) ? e.val : l(e) ? e.toString() : e instanceof Uint8Array ? new TextDecoder().decode(e) : "";
45
- }, U = (t) => {
45
+ }, L = (t) => {
46
46
  if (y(t))
47
47
  return t.content;
48
48
  if (typeof t.content == "string")
@@ -50,7 +50,7 @@ const g = (t) => typeof t == "object" && t !== null && !(t instanceof Uint8Array
50
50
  if ("toString" in t.content && typeof t.content.toString == "function")
51
51
  return t.content.toString();
52
52
  throw new Error("Unsupported file content type");
53
- }, T = {
53
+ }, h = {
54
54
  init(t) {
55
55
  t.name = "", t.extension = "", t.mimeType = "", t.content = "";
56
56
  },
@@ -70,7 +70,7 @@ const g = (t) => typeof t == "object" && t !== null && !(t instanceof Uint8Array
70
70
  setTitle(t, e) {
71
71
  t.name = e;
72
72
  }
73
- }, x = 1e5, h = ["mp4", "webm", "ogg"], E = [
73
+ }, T = ["mp4", "webm", "ogg"], S = [
74
74
  "svg",
75
75
  "png",
76
76
  "jpg",
@@ -78,19 +78,19 @@ const g = (t) => typeof t == "object" && t !== null && !(t instanceof Uint8Array
78
78
  "gif",
79
79
  "webp",
80
80
  "bmp"
81
- ], O = (t) => {
81
+ ], N = (t) => {
82
82
  var e;
83
- return E.includes((e = t.extension) == null ? void 0 : e.toLowerCase());
84
- }, _ = (t) => {
83
+ return S.includes((e = t.extension) == null ? void 0 : e.toLowerCase());
84
+ }, b = (t) => {
85
85
  var e;
86
- return h.includes((e = t.extension) == null ? void 0 : e.toLowerCase());
87
- }, b = (t, e) => {
86
+ return T.includes((e = t.extension) == null ? void 0 : e.toLowerCase());
87
+ }, v = (t, e) => {
88
88
  if (t instanceof Uint8Array)
89
89
  return URL.createObjectURL(
90
90
  new Blob([t], e ? { type: e } : {})
91
91
  );
92
92
  };
93
- function v(t, e) {
93
+ function O(t, e) {
94
94
  const i = t instanceof ArrayBuffer ? new Uint8Array(t) : t, o = e instanceof ArrayBuffer ? new Uint8Array(e) : e;
95
95
  if (i.byteLength !== o.byteLength)
96
96
  return !1;
@@ -112,7 +112,7 @@ const k = [
112
112
  icon: "File",
113
113
  unlisted: !0,
114
114
  async load() {
115
- return T;
115
+ return h;
116
116
  }
117
117
  },
118
118
  {
@@ -122,7 +122,7 @@ const k = [
122
122
  icon: "File",
123
123
  supportedDatatypes: ["file"],
124
124
  async load() {
125
- return (await import("./tool-D5jQjo2l.js").then((t) => t.t)).FileTool;
125
+ return (await import("./tool-UKWDK93W.js").then((t) => t.t)).FileTool;
126
126
  }
127
127
  },
128
128
  {
@@ -146,20 +146,19 @@ const k = [
146
146
  }
147
147
  ];
148
148
  export {
149
- T as FileDatatype,
150
- E as IMAGE_EXTENSIONS,
151
- x as LONG_TEXT_FILE_LENGTH_THRESHOLD,
152
- h as VIDEO_EXTENSIONS,
153
- v as compareBuffers,
154
- b as createBinaryUrl,
155
- N as fileText,
156
- U as getFileContents,
149
+ h as FileDatatype,
150
+ S as IMAGE_EXTENSIONS,
151
+ T as VIDEO_EXTENSIONS,
152
+ O as compareBuffers,
153
+ v as createBinaryUrl,
154
+ x as fileText,
155
+ L as getFileContents,
157
156
  y as isBinaryFileDoc,
158
- O as isImageFile,
159
- A as isImmutableStringFileDoc,
157
+ N as isImageFile,
158
+ E as isImmutableStringFileDoc,
160
159
  I as isTextBytesFileDoc,
161
- S as isTextFileDoc,
162
- _ as isVideoFile,
160
+ U as isTextFileDoc,
161
+ b as isVideoFile,
163
162
  k as plugins
164
163
  };
165
164
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/isBinaryFile.ts","../src/datatype.ts","../src/new-file-datatype.ts","../src/types.ts","../src/utils.ts","../src/index.ts"],"sourcesContent":["// This function was extracted from\n// https://github.com/gjtorikian/isBinaryFile/blob/main/src/index.ts#L158\n\nconst MAX_BYTES = 512;\n\nconst PDF_HEADER = [0x25, 0x50, 0x44, 0x46, 0x2d];\n\nexport function isBinaryCheck(\n fileBuffer: Uint8Array,\n bytesRead: number\n): boolean {\n // empty file. no clue what it is.\n if (bytesRead === 0) {\n return false;\n }\n\n let suspiciousBytes = 0;\n const totalBytes = Math.min(bytesRead, MAX_BYTES);\n\n // UTF-8 BOM\n if (\n bytesRead >= 3 &&\n fileBuffer[0] === 0xef &&\n fileBuffer[1] === 0xbb &&\n fileBuffer[2] === 0xbf\n ) {\n return false;\n }\n\n // UTF-32 BOM\n if (\n bytesRead >= 4 &&\n fileBuffer[0] === 0x00 &&\n fileBuffer[1] === 0x00 &&\n fileBuffer[2] === 0xfe &&\n fileBuffer[3] === 0xff\n ) {\n return false;\n }\n\n // UTF-32 LE BOM\n if (\n bytesRead >= 4 &&\n fileBuffer[0] === 0xff &&\n fileBuffer[1] === 0xfe &&\n fileBuffer[2] === 0x00 &&\n fileBuffer[3] === 0x00\n ) {\n return false;\n }\n\n // GB BOM\n if (\n bytesRead >= 4 &&\n fileBuffer[0] === 0x84 &&\n fileBuffer[1] === 0x31 &&\n fileBuffer[2] === 0x95 &&\n fileBuffer[3] === 0x33\n ) {\n return false;\n }\n\n if (totalBytes >= 5 && PDF_HEADER.every((byte, i) => fileBuffer[i] === byte)) {\n /* PDF. This is binary. */\n return true;\n }\n\n // UTF-16 BE BOM\n if (bytesRead >= 2 && fileBuffer[0] === 0xfe && fileBuffer[1] === 0xff) {\n return false;\n }\n\n // UTF-16 LE BOM\n if (bytesRead >= 2 && fileBuffer[0] === 0xff && fileBuffer[1] === 0xfe) {\n return false;\n }\n\n for (let i = 0; i < totalBytes; i++) {\n if (fileBuffer[i] === 0) {\n // NULL byte--it's binary!\n return true;\n } else if (\n (fileBuffer[i] < 7 || fileBuffer[i] > 14) &&\n (fileBuffer[i] < 32 || fileBuffer[i] > 127)\n ) {\n // UTF-8 detection\n if (\n fileBuffer[i] >= 0xc0 &&\n fileBuffer[i] <= 0xdf &&\n i + 1 < totalBytes\n ) {\n i++;\n if (fileBuffer[i] >= 0x80 && fileBuffer[i] <= 0xbf) {\n continue;\n }\n } else if (\n fileBuffer[i] >= 0xe0 &&\n fileBuffer[i] <= 0xef &&\n i + 2 < totalBytes\n ) {\n i++;\n if (\n fileBuffer[i] >= 0x80 &&\n fileBuffer[i] <= 0xbf &&\n fileBuffer[i + 1] >= 0x80 &&\n fileBuffer[i + 1] <= 0xbf\n ) {\n i++;\n continue;\n }\n } else if (\n fileBuffer[i] >= 0xf0 &&\n fileBuffer[i] <= 0xf7 &&\n i + 3 < totalBytes\n ) {\n i++;\n if (\n fileBuffer[i] >= 0x80 &&\n fileBuffer[i] <= 0xbf &&\n fileBuffer[i + 1] >= 0x80 &&\n fileBuffer[i + 1] <= 0xbf &&\n fileBuffer[i + 2] >= 0x80 &&\n fileBuffer[i + 2] <= 0xbf\n ) {\n i += 2;\n continue;\n }\n }\n\n suspiciousBytes++;\n // Read at least 32 fileBuffer before making a decision\n if (i >= 32 && (suspiciousBytes * 100) / totalBytes > 10) {\n return true;\n }\n }\n }\n\n if ((suspiciousBytes * 100) / totalBytes > 10) {\n return true;\n }\n\n return false;\n}\n","// File datatype implementation\n\nimport {isImmutableString} from \"@automerge/automerge-repo/slim\"\nimport {BinaryFileDoc, FileDoc, TextFileDoc} from \"./types\"\nimport {isBinaryCheck} from \"./isBinaryFile\"\n\nexport function isBinaryFileDoc(doc: FileDoc): doc is BinaryFileDoc {\n\treturn doc.content instanceof Uint8Array\n}\n\nexport function isTextFileDoc(doc: FileDoc): doc is TextFileDoc {\n\treturn typeof doc.content === \"string\"\n}\n\n// An ImmutableString that's been through structuredClone (as solid-automerge's\n// document projection does) loses its symbol marker and its prototype and\n// comes out as a plain {val: \"...\"}, so that counts as one too.\nconst isClonedImmutableString = (content: unknown): content is {val: string} =>\n\ttypeof content === \"object\" &&\n\tcontent !== null &&\n\t!(content instanceof Uint8Array) &&\n\ttypeof (content as {val?: unknown}).val === \"string\"\n\nexport const isImmutableStringFileDoc = (doc: FileDoc): boolean => {\n\treturn isImmutableString(doc.content) || isClonedImmutableString(doc.content)\n}\n\n// Text that was stored as bytes (e.g. synced in by a tool that didn't know it\n// was text). It can be shown, but not edited as text.\nexport const isTextBytesFileDoc = (doc: FileDoc): boolean =>\n\tisBinaryFileDoc(doc) && !isBinaryCheck(doc.content, doc.content.length)\n\n// The text of a text file, whichever way it's stored (a string, an\n// ImmutableString, a cloned one, or UTF-8 bytes).\nexport const fileText = (doc: FileDoc | undefined): string => {\n\tconst content = doc?.content as unknown\n\tif (typeof content === \"string\") return content\n\tif (isClonedImmutableString(content)) return content.val\n\tif (isImmutableString(content)) return content.toString()\n\tif (content instanceof Uint8Array) return new TextDecoder().decode(content)\n\treturn \"\"\n}\n\n// Get file contents as string or Uint8Array\nexport const getFileContents = (doc: FileDoc): string | Uint8Array => {\n\tif (isBinaryFileDoc(doc)) {\n\t\treturn doc.content\n\t} else if (typeof doc.content === \"string\") {\n\t\treturn doc.content\n\t} else if (\n\t\t\"toString\" in doc.content &&\n\t\ttypeof doc.content.toString == \"function\"\n\t) {\n\t\tconst content = doc.content\n\t\treturn content.toString()\n\t} else {\n\t\tthrow new Error(\"Unsupported file content type\")\n\t}\n}\n\n// Datatype implementation\nexport const FileDatatype = {\n\tinit(doc: FileDoc) {\n\t\tdoc.name = \"\"\n\t\tdoc.extension = \"\"\n\t\tdoc.mimeType = \"\"\n\t\tdoc.content = \"\"\n\t},\n\n\tsetTitle(doc: FileDoc, title: string) {\n\t\tdoc.name = title\n\t},\n\n\tgetTitle(doc: FileDoc) {\n\t\treturn doc.name || \"Untitled File\"\n\t},\n}\n","// \"New File\" datatype — a listed datatype that acts as a creation prompt.\n// Once the user enters a filename, the doc flips to type \"file\".\n\nimport type {FileDoc} from \"./types\"\n\nexport const NewFileDatatype = {\n\tinit(doc: FileDoc) {\n\t\tdoc.name = \"\"\n\t\tdoc.extension = \"\"\n\t\tdoc.mimeType = \"\"\n\t\tdoc.content = \"\"\n\t},\n\n\tgetTitle(doc: FileDoc) {\n\t\treturn doc.name || \"New File\"\n\t},\n\n\tsetTitle(doc: FileDoc, title: string) {\n\t\tdoc.name = title\n\t},\n}\n","// File document types\n\nimport type {ImmutableString} from \"@automerge/automerge-repo/slim\"\nimport type {UnixFileEntry} from \"@inkandswitch/patchwork-filesystem\"\n\nexport type TextFileDoc = {\n\tname: string\n\textension: string\n\tmimeType: string\n\tcontent: string\n}\n\nexport type BinaryFileDoc = {\n\tname: string\n\textension: string\n\tmimeType: string\n\tcontent: Uint8Array\n}\n\nexport type ImmutableStringFileDoc = {\n\tname: string\n\textension: string\n\tmimeType: string\n\tcontent: ImmutableString\n}\n\nexport type FileDoc = UnixFileEntry\n\n// Conservatively use LongTextFileContent for text files longer than 100KB.\nexport const LONG_TEXT_FILE_LENGTH_THRESHOLD = 100000\n","// Utility functions for file handling\n\nexport const VIDEO_EXTENSIONS = [\"mp4\", \"webm\", \"ogg\"]\nexport const IMAGE_EXTENSIONS = [\n\t\"svg\",\n\t\"png\",\n\t\"jpg\",\n\t\"jpeg\",\n\t\"gif\",\n\t\"webp\",\n\t\"bmp\",\n]\n\nexport const isImageFile = (doc: {extension: string}) => {\n\treturn IMAGE_EXTENSIONS.includes(doc.extension?.toLowerCase())\n}\n\nexport const isVideoFile = (doc: {extension: string}) => {\n\treturn VIDEO_EXTENSIONS.includes(doc.extension?.toLowerCase())\n}\n\n// An object URL carries the blob's type as its Content-Type. Without one the\n// browser resolves the response as text/plain, which is fine for <img> (it\n// sniffs the bytes) but means an <iframe> renders a PDF as source instead of\n// handing it to the built-in viewer.\nexport const createBinaryUrl = (\n\tvalue: Uint8Array | undefined,\n\tmimeType?: string\n): string | undefined => {\n\tif (!(value instanceof Uint8Array)) {\n\t\treturn undefined\n\t}\n\n\treturn URL.createObjectURL(\n\t\tnew Blob([value as BlobPart], mimeType ? {type: mimeType} : {})\n\t)\n}\n\n/**\n * Efficiently compares two array buffers or typed arrays for equality.\n * Optimized for large buffers (10MB+) by comparing in 64-bit chunks.\n * @param {ArrayBuffer|Uint8Array} buf1 First buffer to compare\n * @param {ArrayBuffer|Uint8Array} buf2 Second buffer to compare\n * @returns {boolean} True if buffers are identical, false otherwise\n */\nexport function compareBuffers(\n\tbuf1: ArrayBuffer | Uint8Array,\n\tbuf2: ArrayBuffer | Uint8Array\n): boolean {\n\t// Convert ArrayBuffers to Uint8Arrays if needed\n\tconst a1 = buf1 instanceof ArrayBuffer ? new Uint8Array(buf1) : buf1\n\tconst a2 = buf2 instanceof ArrayBuffer ? new Uint8Array(buf2) : buf2\n\n\tif (a1.byteLength !== a2.byteLength) {\n\t\treturn false\n\t}\n\n\t// Use DataView for fast 64-bit comparisons\n\tconst dv1 = new DataView(a1.buffer, a1.byteOffset, a1.byteLength)\n\tconst dv2 = new DataView(a2.buffer, a2.byteOffset, a2.byteLength)\n\n\tconst len = a1.byteLength\n\tconst remainder = len % 8\n\tconst loops = (len - remainder) / 8\n\n\t// Compare 8 bytes at a time using BigInt64\n\tfor (let i = 0; i < loops; i++) {\n\t\tif (dv1.getBigInt64(i * 8, true) !== dv2.getBigInt64(i * 8, true)) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\t// Compare any remaining bytes individually\n\tconst startByte = len - remainder\n\tfor (let i = 0; i < remainder; i++) {\n\t\tif (a1[startByte + i] !== a2[startByte + i]) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n","// File plugin for Patchwork\n// Bundleless plugin that supports viewing and editing various file types\n\nimport {FileDatatype} from \"./datatype\"\nimport {NewFileDatatype} from \"./new-file-datatype\"\n\nexport * from \"./types\"\nexport * from \"./datatype\"\nexport * from \"./utils\"\n\nexport const plugins = [\n\t{\n\t\ttype: \"patchwork:datatype\",\n\t\tid: \"file\",\n\t\tname: \"File\",\n\t\ticon: \"File\",\n\t\tunlisted: true,\n\t\tasync load() {\n\t\t\treturn FileDatatype\n\t\t},\n\t},\n\t{\n\t\ttype: \"patchwork:tool\",\n\t\tid: \"file\",\n\t\tname: \"File\",\n\t\ticon: \"File\",\n\t\tsupportedDatatypes: [\"file\"],\n\t\tasync load() {\n\t\t\treturn (await import(\"./tool\")).FileTool\n\t\t},\n\t},\n\t{\n\t\ttype: \"patchwork:datatype\",\n\t\tid: \"new-file\",\n\t\tname: \"New File\",\n\t\ticon: \"FilePlus\",\n\t\tasync load() {\n\t\t\treturn NewFileDatatype\n\t\t},\n\t},\n\t{\n\t\ttype: \"patchwork:tool\",\n\t\tid: \"new-file\",\n\t\tname: \"New File\",\n\t\ticon: \"FilePlus\",\n\t\tsupportedDatatypes: [\"new-file\"],\n\t\tasync load() {\n\t\t\treturn (await import(\"./new-file-tool\")).NewFileTool\n\t\t},\n\t},\n]\n"],"names":["MAX_BYTES","PDF_HEADER","isBinaryCheck","fileBuffer","bytesRead","suspiciousBytes","totalBytes","byte","i","isBinaryFileDoc","doc","isTextFileDoc","isClonedImmutableString","content","isImmutableStringFileDoc","isImmutableString","isTextBytesFileDoc","fileText","getFileContents","FileDatatype","title","NewFileDatatype","LONG_TEXT_FILE_LENGTH_THRESHOLD","VIDEO_EXTENSIONS","IMAGE_EXTENSIONS","isImageFile","_a","isVideoFile","createBinaryUrl","value","mimeType","compareBuffers","buf1","buf2","a1","a2","dv1","dv2","len","remainder","loops","startByte","plugins","n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/isBinaryFile.ts","../src/datatype.ts","../src/new-file-datatype.ts","../src/utils.ts","../src/index.ts"],"sourcesContent":["// This function was extracted from\n// https://github.com/gjtorikian/isBinaryFile/blob/main/src/index.ts#L158\n\nconst MAX_BYTES = 512;\n\nconst PDF_HEADER = [0x25, 0x50, 0x44, 0x46, 0x2d];\n\nexport function isBinaryCheck(\n fileBuffer: Uint8Array,\n bytesRead: number\n): boolean {\n // empty file. no clue what it is.\n if (bytesRead === 0) {\n return false;\n }\n\n let suspiciousBytes = 0;\n const totalBytes = Math.min(bytesRead, MAX_BYTES);\n\n // UTF-8 BOM\n if (\n bytesRead >= 3 &&\n fileBuffer[0] === 0xef &&\n fileBuffer[1] === 0xbb &&\n fileBuffer[2] === 0xbf\n ) {\n return false;\n }\n\n // UTF-32 BOM\n if (\n bytesRead >= 4 &&\n fileBuffer[0] === 0x00 &&\n fileBuffer[1] === 0x00 &&\n fileBuffer[2] === 0xfe &&\n fileBuffer[3] === 0xff\n ) {\n return false;\n }\n\n // UTF-32 LE BOM\n if (\n bytesRead >= 4 &&\n fileBuffer[0] === 0xff &&\n fileBuffer[1] === 0xfe &&\n fileBuffer[2] === 0x00 &&\n fileBuffer[3] === 0x00\n ) {\n return false;\n }\n\n // GB BOM\n if (\n bytesRead >= 4 &&\n fileBuffer[0] === 0x84 &&\n fileBuffer[1] === 0x31 &&\n fileBuffer[2] === 0x95 &&\n fileBuffer[3] === 0x33\n ) {\n return false;\n }\n\n if (totalBytes >= 5 && PDF_HEADER.every((byte, i) => fileBuffer[i] === byte)) {\n /* PDF. This is binary. */\n return true;\n }\n\n // UTF-16 BE BOM\n if (bytesRead >= 2 && fileBuffer[0] === 0xfe && fileBuffer[1] === 0xff) {\n return false;\n }\n\n // UTF-16 LE BOM\n if (bytesRead >= 2 && fileBuffer[0] === 0xff && fileBuffer[1] === 0xfe) {\n return false;\n }\n\n for (let i = 0; i < totalBytes; i++) {\n if (fileBuffer[i] === 0) {\n // NULL byte--it's binary!\n return true;\n } else if (\n (fileBuffer[i] < 7 || fileBuffer[i] > 14) &&\n (fileBuffer[i] < 32 || fileBuffer[i] > 127)\n ) {\n // UTF-8 detection\n if (\n fileBuffer[i] >= 0xc0 &&\n fileBuffer[i] <= 0xdf &&\n i + 1 < totalBytes\n ) {\n i++;\n if (fileBuffer[i] >= 0x80 && fileBuffer[i] <= 0xbf) {\n continue;\n }\n } else if (\n fileBuffer[i] >= 0xe0 &&\n fileBuffer[i] <= 0xef &&\n i + 2 < totalBytes\n ) {\n i++;\n if (\n fileBuffer[i] >= 0x80 &&\n fileBuffer[i] <= 0xbf &&\n fileBuffer[i + 1] >= 0x80 &&\n fileBuffer[i + 1] <= 0xbf\n ) {\n i++;\n continue;\n }\n } else if (\n fileBuffer[i] >= 0xf0 &&\n fileBuffer[i] <= 0xf7 &&\n i + 3 < totalBytes\n ) {\n i++;\n if (\n fileBuffer[i] >= 0x80 &&\n fileBuffer[i] <= 0xbf &&\n fileBuffer[i + 1] >= 0x80 &&\n fileBuffer[i + 1] <= 0xbf &&\n fileBuffer[i + 2] >= 0x80 &&\n fileBuffer[i + 2] <= 0xbf\n ) {\n i += 2;\n continue;\n }\n }\n\n suspiciousBytes++;\n // Read at least 32 fileBuffer before making a decision\n if (i >= 32 && (suspiciousBytes * 100) / totalBytes > 10) {\n return true;\n }\n }\n }\n\n if ((suspiciousBytes * 100) / totalBytes > 10) {\n return true;\n }\n\n return false;\n}\n","// File datatype implementation\n\nimport {isImmutableString} from \"@automerge/automerge-repo/slim\"\nimport {BinaryFileDoc, FileDoc, TextFileDoc} from \"./types\"\nimport {isBinaryCheck} from \"./isBinaryFile\"\n\nexport function isBinaryFileDoc(doc: FileDoc): doc is BinaryFileDoc {\n\treturn doc.content instanceof Uint8Array\n}\n\nexport function isTextFileDoc(doc: FileDoc): doc is TextFileDoc {\n\treturn typeof doc.content === \"string\"\n}\n\n// An ImmutableString that's been through structuredClone (as solid-automerge's\n// document projection does) loses its symbol marker and its prototype and\n// comes out as a plain {val: \"...\"}, so that counts as one too.\nconst isClonedImmutableString = (content: unknown): content is {val: string} =>\n\ttypeof content === \"object\" &&\n\tcontent !== null &&\n\t!(content instanceof Uint8Array) &&\n\ttypeof (content as {val?: unknown}).val === \"string\"\n\nexport const isImmutableStringFileDoc = (doc: FileDoc): boolean => {\n\treturn isImmutableString(doc.content) || isClonedImmutableString(doc.content)\n}\n\n// Text that was stored as bytes (e.g. synced in by a tool that didn't know it\n// was text). It can be shown, but not edited as text.\nexport const isTextBytesFileDoc = (doc: FileDoc): boolean =>\n\tisBinaryFileDoc(doc) && !isBinaryCheck(doc.content, doc.content.length)\n\n// The text of a text file, whichever way it's stored (a string, an\n// ImmutableString, a cloned one, or UTF-8 bytes).\nexport const fileText = (doc: FileDoc | undefined): string => {\n\tconst content = doc?.content as unknown\n\tif (typeof content === \"string\") return content\n\tif (isClonedImmutableString(content)) return content.val\n\tif (isImmutableString(content)) return content.toString()\n\tif (content instanceof Uint8Array) return new TextDecoder().decode(content)\n\treturn \"\"\n}\n\n// Get file contents as string or Uint8Array\nexport const getFileContents = (doc: FileDoc): string | Uint8Array => {\n\tif (isBinaryFileDoc(doc)) {\n\t\treturn doc.content\n\t} else if (typeof doc.content === \"string\") {\n\t\treturn doc.content\n\t} else if (\n\t\t\"toString\" in doc.content &&\n\t\ttypeof doc.content.toString == \"function\"\n\t) {\n\t\tconst content = doc.content\n\t\treturn content.toString()\n\t} else {\n\t\tthrow new Error(\"Unsupported file content type\")\n\t}\n}\n\n// Datatype implementation\nexport const FileDatatype = {\n\tinit(doc: FileDoc) {\n\t\tdoc.name = \"\"\n\t\tdoc.extension = \"\"\n\t\tdoc.mimeType = \"\"\n\t\tdoc.content = \"\"\n\t},\n\n\tsetTitle(doc: FileDoc, title: string) {\n\t\tdoc.name = title\n\t},\n\n\tgetTitle(doc: FileDoc) {\n\t\treturn doc.name || \"Untitled File\"\n\t},\n}\n","// \"New File\" datatype — a listed datatype that acts as a creation prompt.\n// Once the user enters a filename, the doc flips to type \"file\".\n\nimport type {FileDoc} from \"./types\"\n\nexport const NewFileDatatype = {\n\tinit(doc: FileDoc) {\n\t\tdoc.name = \"\"\n\t\tdoc.extension = \"\"\n\t\tdoc.mimeType = \"\"\n\t\tdoc.content = \"\"\n\t},\n\n\tgetTitle(doc: FileDoc) {\n\t\treturn doc.name || \"New File\"\n\t},\n\n\tsetTitle(doc: FileDoc, title: string) {\n\t\tdoc.name = title\n\t},\n}\n","// Utility functions for file handling\n\nexport const VIDEO_EXTENSIONS = [\"mp4\", \"webm\", \"ogg\"]\nexport const IMAGE_EXTENSIONS = [\n\t\"svg\",\n\t\"png\",\n\t\"jpg\",\n\t\"jpeg\",\n\t\"gif\",\n\t\"webp\",\n\t\"bmp\",\n]\n\nexport const isImageFile = (doc: {extension: string}) => {\n\treturn IMAGE_EXTENSIONS.includes(doc.extension?.toLowerCase())\n}\n\nexport const isVideoFile = (doc: {extension: string}) => {\n\treturn VIDEO_EXTENSIONS.includes(doc.extension?.toLowerCase())\n}\n\n// An object URL carries the blob's type as its Content-Type. Without one the\n// browser resolves the response as text/plain, which is fine for <img> (it\n// sniffs the bytes) but means an <iframe> renders a PDF as source instead of\n// handing it to the built-in viewer.\nexport const createBinaryUrl = (\n\tvalue: Uint8Array | undefined,\n\tmimeType?: string\n): string | undefined => {\n\tif (!(value instanceof Uint8Array)) {\n\t\treturn undefined\n\t}\n\n\treturn URL.createObjectURL(\n\t\tnew Blob([value as BlobPart], mimeType ? {type: mimeType} : {})\n\t)\n}\n\n/**\n * Efficiently compares two array buffers or typed arrays for equality.\n * Optimized for large buffers (10MB+) by comparing in 64-bit chunks.\n * @param {ArrayBuffer|Uint8Array} buf1 First buffer to compare\n * @param {ArrayBuffer|Uint8Array} buf2 Second buffer to compare\n * @returns {boolean} True if buffers are identical, false otherwise\n */\nexport function compareBuffers(\n\tbuf1: ArrayBuffer | Uint8Array,\n\tbuf2: ArrayBuffer | Uint8Array\n): boolean {\n\t// Convert ArrayBuffers to Uint8Arrays if needed\n\tconst a1 = buf1 instanceof ArrayBuffer ? new Uint8Array(buf1) : buf1\n\tconst a2 = buf2 instanceof ArrayBuffer ? new Uint8Array(buf2) : buf2\n\n\tif (a1.byteLength !== a2.byteLength) {\n\t\treturn false\n\t}\n\n\t// Use DataView for fast 64-bit comparisons\n\tconst dv1 = new DataView(a1.buffer, a1.byteOffset, a1.byteLength)\n\tconst dv2 = new DataView(a2.buffer, a2.byteOffset, a2.byteLength)\n\n\tconst len = a1.byteLength\n\tconst remainder = len % 8\n\tconst loops = (len - remainder) / 8\n\n\t// Compare 8 bytes at a time using BigInt64\n\tfor (let i = 0; i < loops; i++) {\n\t\tif (dv1.getBigInt64(i * 8, true) !== dv2.getBigInt64(i * 8, true)) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\t// Compare any remaining bytes individually\n\tconst startByte = len - remainder\n\tfor (let i = 0; i < remainder; i++) {\n\t\tif (a1[startByte + i] !== a2[startByte + i]) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n","// File plugin for Patchwork\n// Bundleless plugin that supports viewing and editing various file types\n\nimport {FileDatatype} from \"./datatype\"\nimport {NewFileDatatype} from \"./new-file-datatype\"\n\nexport * from \"./types\"\nexport * from \"./datatype\"\nexport * from \"./utils\"\n\nexport const plugins = [\n\t{\n\t\ttype: \"patchwork:datatype\",\n\t\tid: \"file\",\n\t\tname: \"File\",\n\t\ticon: \"File\",\n\t\tunlisted: true,\n\t\tasync load() {\n\t\t\treturn FileDatatype\n\t\t},\n\t},\n\t{\n\t\ttype: \"patchwork:tool\",\n\t\tid: \"file\",\n\t\tname: \"File\",\n\t\ticon: \"File\",\n\t\tsupportedDatatypes: [\"file\"],\n\t\tasync load() {\n\t\t\treturn (await import(\"./tool\")).FileTool\n\t\t},\n\t},\n\t{\n\t\ttype: \"patchwork:datatype\",\n\t\tid: \"new-file\",\n\t\tname: \"New File\",\n\t\ticon: \"FilePlus\",\n\t\tasync load() {\n\t\t\treturn NewFileDatatype\n\t\t},\n\t},\n\t{\n\t\ttype: \"patchwork:tool\",\n\t\tid: \"new-file\",\n\t\tname: \"New File\",\n\t\ticon: \"FilePlus\",\n\t\tsupportedDatatypes: [\"new-file\"],\n\t\tasync load() {\n\t\t\treturn (await import(\"./new-file-tool\")).NewFileTool\n\t\t},\n\t},\n]\n"],"names":["MAX_BYTES","PDF_HEADER","isBinaryCheck","fileBuffer","bytesRead","suspiciousBytes","totalBytes","byte","i","isBinaryFileDoc","doc","isTextFileDoc","isClonedImmutableString","content","isImmutableStringFileDoc","isImmutableString","isTextBytesFileDoc","fileText","getFileContents","FileDatatype","title","NewFileDatatype","VIDEO_EXTENSIONS","IMAGE_EXTENSIONS","isImageFile","_a","isVideoFile","createBinaryUrl","value","mimeType","compareBuffers","buf1","buf2","a1","a2","dv1","dv2","len","remainder","loops","startByte","plugins","n"],"mappings":"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"}