@hachej/boring-agent 0.4.2 → 0.4.3

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,13 +1,15 @@
1
+ import { SNIFF_BYTES } from '@hachej/boring-files/file-types';
1
2
  export type FileKind = 'text' | 'pdf' | 'office' | 'image' | 'archive' | 'binary';
2
3
  /** The media type of a native image (png, jpeg, gif, webp) by extension, or undefined. */
3
4
  export declare const nativeImageType: (path: string) => string | undefined;
4
- /** How many leading bytes `fileKind` looks at. */
5
- export declare const SNIFF_BYTES = 16;
5
+ /** How many leading bytes `fileKind` looks at: the file-types table's own. */
6
+ export { SNIFF_BYTES };
6
7
  /** The kind of `path`, from its extension and, when given, its leading bytes (the magic number wins). Unknown extensions are text unless a NUL byte says otherwise. */
7
8
  export declare function fileKind(path: string, head?: Uint8Array): FileKind;
8
9
  /**
9
10
  * The media type a converter should be told. A signature in the leading bytes wins over everything (a PDF named `.txt` is
10
11
  * `application/pdf`, whatever the provider derived from the name); then the provider's type unless it is generic; then the table's.
12
+ * Sniffed `text/plain` is not a signature: it never overrides a name.
11
13
  */
12
14
  export declare function mediaTypeFor(path: string, kind: FileKind, provided: string | undefined, head?: Uint8Array): string;
13
15
  //# sourceMappingURL=file-types.d.ts.map
@@ -11,7 +11,7 @@
11
11
  * A file is classified by its extension AND its leading bytes: a PDF or an image is recognised by its magic number even under a
12
12
  * wrong name.
13
13
  */
14
- import { MEDIA_TYPES, extensionOf, sniffMediaType } from '@hachej/boring-files/file-types';
14
+ import { MEDIA_TYPES, SNIFF_BYTES, extensionOf, sniffMediaType } from '@hachej/boring-files/file-types';
15
15
  const TEXT = ['md', 'markdown', 'txt', 'csv', 'tsv', 'json', 'jsonl', 'html', 'htm', 'svg', 'xml', 'js', 'mjs', 'cjs', 'ts', 'tsx', 'jsx', 'css', 'py', 'sql', 'yaml', 'yml', 'sh', 'toml', 'ini', 'log', 'rst', 'tex'];
16
16
  const OFFICE = ['doc', 'docx', 'odt', 'rtf', 'xls', 'xlsx', 'ods', 'ppt', 'pptx', 'odp', 'epub'];
17
17
  /** Image extensions; `native` ones a model reads as an image part without conversion. Their media types are `MEDIA_TYPES`. */
@@ -24,16 +24,24 @@ const BY_EXTENSION = new Map([
24
24
  ]);
25
25
  /** The media type of a native image (png, jpeg, gif, webp) by extension, or undefined. */
26
26
  export const nativeImageType = (path) => IMAGES[extensionOf(path)] === true ? MEDIA_TYPES[extensionOf(path)] : undefined;
27
- /** How many leading bytes `fileKind` looks at. */
28
- export const SNIFF_BYTES = 16;
27
+ /** How many leading bytes `fileKind` looks at: the file-types table's own. */
28
+ export { SNIFF_BYTES };
29
+ /** The signatures this file routes as an image or an office document, as `sniffMediaType` names them. */
30
+ const SNIFFED_IMAGES = new Set(['image/png', 'image/jpeg', 'image/gif', 'image/webp']);
31
+ const SNIFFED_OFFICE = new Set(OFFICE.map(extension => MEDIA_TYPES[extension]));
29
32
  const startsWith = (bytes, signature, at = 0) => signature.every((byte, index) => bytes[at + index] === byte);
30
- /** The kind a magic number names, or undefined. A ZIP signature is an office document only under an office extension. */
33
+ /**
34
+ * The kind a magic number names, or undefined. `sniffMediaType` names the signatures (an office document by its zip entries); a zip
35
+ * it cannot name is an office document only under an office extension, and an OLE container (legacy doc, xls, ppt) is one.
36
+ */
31
37
  function kindByMagic(bytes, extension) {
32
38
  const sniffed = sniffMediaType(bytes);
33
39
  if (sniffed === 'application/pdf')
34
40
  return 'pdf';
35
- if (sniffed?.startsWith('image/') || (startsWith(bytes, [0x42, 0x4d]) && extension === 'bmp'))
41
+ if ((sniffed !== undefined && SNIFFED_IMAGES.has(sniffed)) || (startsWith(bytes, [0x42, 0x4d]) && extension === 'bmp'))
36
42
  return 'image';
43
+ if (sniffed !== undefined && SNIFFED_OFFICE.has(sniffed))
44
+ return 'office';
37
45
  if (startsWith(bytes, [0x50, 0x4b, 0x03, 0x04]))
38
46
  return OFFICE.includes(extension) ? 'office' : 'archive';
39
47
  if (startsWith(bytes, [0xd0, 0xcf, 0x11, 0xe0]))
@@ -56,10 +64,11 @@ export function fileKind(path, head) {
56
64
  /**
57
65
  * The media type a converter should be told. A signature in the leading bytes wins over everything (a PDF named `.txt` is
58
66
  * `application/pdf`, whatever the provider derived from the name); then the provider's type unless it is generic; then the table's.
67
+ * Sniffed `text/plain` is not a signature: it never overrides a name.
59
68
  */
60
69
  export function mediaTypeFor(path, kind, provided, head) {
61
70
  const sniffed = head === undefined ? undefined : sniffMediaType(head);
62
- if (sniffed !== undefined)
71
+ if (sniffed !== undefined && sniffed !== 'text/plain')
63
72
  return sniffed;
64
73
  const extension = extensionOf(path);
65
74
  const table = kind === 'pdf' ? MEDIA_TYPES.pdf : kind === 'image' && IMAGES[extension] !== undefined ? MEDIA_TYPES[extension] : kind === 'office' && OFFICE.includes(extension) ? MEDIA_TYPES[extension] : undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hachej/boring-agent",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "license": "MIT",
5
5
  "private": false,
6
6
  "type": "module",
@@ -143,8 +143,8 @@
143
143
  "@earendil-works/pi-durable": "~1.2.0",
144
144
  "@earendil-works/pi-ai": "~1.2.0",
145
145
  "@earendil-works/chord": "~1.2.0",
146
- "@hachej/boring-files": "^0.4.2",
147
- "@hachej/boring-ui-kit": "^0.4.2"
146
+ "@hachej/boring-files": "^0.4.3",
147
+ "@hachej/boring-ui-kit": "^0.4.3"
148
148
  },
149
149
  "peerDependenciesMeta": {
150
150
  "@hachej/boring-files": {