@luzzle/core 0.0.62 → 0.0.63

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.md +38 -8
  2. package/dist/src/index.d.ts +2 -2
  3. package/dist/src/index.js +2 -2
  4. package/dist/src/index.js.map +1 -1
  5. package/dist/src/pieces/Piece.js +2 -2
  6. package/dist/src/pieces/Piece.js.map +1 -1
  7. package/dist/src/pieces/index.d.ts +1 -0
  8. package/dist/src/pieces/index.js +1 -0
  9. package/dist/src/pieces/index.js.map +1 -1
  10. package/dist/src/pieces/utils/piece.d.ts +3 -2
  11. package/dist/src/pieces/utils/piece.js +17 -14
  12. package/dist/src/pieces/utils/piece.js.map +1 -1
  13. package/dist/tsconfig.build.tsbuildinfo +1 -0
  14. package/package.json +3 -3
  15. package/dist/src/database/NodeSqliteDialect.test.d.ts +0 -1
  16. package/dist/src/database/NodeSqliteDialect.test.js +0 -104
  17. package/dist/src/database/NodeSqliteDialect.test.js.map +0 -1
  18. package/dist/src/database/client.test.d.ts +0 -1
  19. package/dist/src/database/client.test.js +0 -36
  20. package/dist/src/database/client.test.js.map +0 -1
  21. package/dist/src/database/migrations.test.d.ts +0 -1
  22. package/dist/src/database/migrations.test.js +0 -19
  23. package/dist/src/database/migrations.test.js.map +0 -1
  24. package/dist/src/database/utils.test.d.ts +0 -1
  25. package/dist/src/database/utils.test.js +0 -9
  26. package/dist/src/database/utils.test.js.map +0 -1
  27. package/dist/src/index.test.d.ts +0 -1
  28. package/dist/src/index.test.js +0 -9
  29. package/dist/src/index.test.js.map +0 -1
  30. package/dist/src/lib/ajv.test.d.ts +0 -1
  31. package/dist/src/lib/ajv.test.js +0 -49
  32. package/dist/src/lib/ajv.test.js.map +0 -1
  33. package/dist/src/lib/frontmatter.test.d.ts +0 -1
  34. package/dist/src/lib/frontmatter.test.js +0 -37
  35. package/dist/src/lib/frontmatter.test.js.map +0 -1
  36. package/dist/src/lib/markdown.test.d.ts +0 -1
  37. package/dist/src/lib/markdown.test.js +0 -34
  38. package/dist/src/lib/markdown.test.js.map +0 -1
  39. package/dist/src/llm/google.test.d.ts +0 -1
  40. package/dist/src/llm/google.test.js +0 -253
  41. package/dist/src/llm/google.test.js.map +0 -1
  42. package/dist/src/pieces/Piece.test.d.ts +0 -1
  43. package/dist/src/pieces/Piece.test.js +0 -628
  44. package/dist/src/pieces/Piece.test.js.map +0 -1
  45. package/dist/src/pieces/Pieces.test.d.ts +0 -1
  46. package/dist/src/pieces/Pieces.test.js +0 -325
  47. package/dist/src/pieces/Pieces.test.js.map +0 -1
  48. package/dist/src/pieces/cache.test.d.ts +0 -1
  49. package/dist/src/pieces/cache.test.js +0 -72
  50. package/dist/src/pieces/cache.test.js.map +0 -1
  51. package/dist/src/pieces/item.test.d.ts +0 -1
  52. package/dist/src/pieces/item.test.js +0 -243
  53. package/dist/src/pieces/item.test.js.map +0 -1
  54. package/dist/src/pieces/items.test.d.ts +0 -1
  55. package/dist/src/pieces/items.test.js +0 -103
  56. package/dist/src/pieces/items.test.js.map +0 -1
  57. package/dist/src/pieces/json.schema.test.d.ts +0 -1
  58. package/dist/src/pieces/json.schema.test.js +0 -27
  59. package/dist/src/pieces/json.schema.test.js.map +0 -1
  60. package/dist/src/pieces/manager.test.d.ts +0 -1
  61. package/dist/src/pieces/manager.test.js +0 -55
  62. package/dist/src/pieces/manager.test.js.map +0 -1
  63. package/dist/src/pieces/utils/frontmatter.path.test.d.ts +0 -1
  64. package/dist/src/pieces/utils/frontmatter.path.test.js +0 -319
  65. package/dist/src/pieces/utils/frontmatter.path.test.js.map +0 -1
  66. package/dist/src/pieces/utils/frontmatter.test.d.ts +0 -1
  67. package/dist/src/pieces/utils/frontmatter.test.js +0 -335
  68. package/dist/src/pieces/utils/frontmatter.test.js.map +0 -1
  69. package/dist/src/pieces/utils/markdown.test.d.ts +0 -1
  70. package/dist/src/pieces/utils/markdown.test.js +0 -38
  71. package/dist/src/pieces/utils/markdown.test.js.map +0 -1
  72. package/dist/src/pieces/utils/piece.test.d.ts +0 -1
  73. package/dist/src/pieces/utils/piece.test.js +0 -348
  74. package/dist/src/pieces/utils/piece.test.js.map +0 -1
  75. package/dist/src/storage/fs.test.d.ts +0 -1
  76. package/dist/src/storage/fs.test.js +0 -212
  77. package/dist/src/storage/fs.test.js.map +0 -1
  78. package/dist/test/db.d.ts +0 -3
  79. package/dist/test/db.js +0 -19
  80. package/dist/test/db.js.map +0 -1
  81. package/dist/tsconfig.tsbuildinfo +0 -1
package/README.md CHANGED
@@ -1,14 +1,44 @@
1
1
  # @luzzle/core 🫀
2
2
 
3
- The foundational implementation of the Luzzle specification. It solves the inherent challenges of managing large-scale digital records using plain text.
3
+ TypeScript implementation of the Luzzle specification.
4
4
 
5
- ## Challenges Solved 🏗️
5
+ Luzzle is a specification designed to solve the challenges of managing digital
6
+ records using plain text files instead of proprietary databases or spreadsheets.
7
+ `@luzzle/core` provides the tooling to define, parse, and validate these text
8
+ records ("pieces") and attachments so they can be easily queried, indexed, and
9
+ synced to a database.
6
10
 
7
- * **Consistency**: Enforces structure across thousands of records using JSON schemas.
8
- * **Organization**: Standardizes where files and attachments (`.assets/`) live within an archive.
9
- * **Scale**: Maps thousands of text files into a high-performance SQLite index, enabling complex queries and fast searching without slow filesystem traversal.
10
- * **Portability**: Provides a unified Storage abstraction so your data remains accessible anywhere.
11
+ ---
11
12
 
12
- ## How it works 🚂
13
+ ## Core Concepts 🏗️
13
14
 
14
- Core treats your filesystem as the primary database. It parses Markdown, validates frontmatter, and maintains a derivative SQLite cache for application-layer performance.
15
+ ### 1. Pieces & Schemas
16
+
17
+ The core of the Luzzle spec is the **Piece**: a standard Markdown file with
18
+ structured YAML frontmatter. `@luzzle/core` validates these pieces using
19
+ standard JSON schemas (typically defined in your archive under
20
+ `.luzzle/schemas/`). This gives you uniform, type-safe records without holding
21
+ your data hostage.
22
+
23
+ ### 2. Assets & Attachments
24
+
25
+ A digital garden is not just text. `@luzzle/core` defines conventions for how
26
+ non-text media (like images or PDF attachments) are stored within the
27
+ `.assets/` directory and referenced in a piece's metadata.
28
+
29
+ ### 3. File Naming Convention
30
+
31
+ To associate a piece with its schema, Luzzle relies on a specific file naming
32
+ convention: `name.[piece-type].md` (e.g., `dune.books.md`). This naming
33
+ convention solves the problem of quickly identifying a piece's type to map it
34
+ to the correct validator. _Note: This convention might be evolved or removed
35
+ in the future, but remains the current way piece types are discovered._
36
+
37
+ ### 4. Simple Filesystem Backend
38
+
39
+ To adhere to the Unix philosophy, `@luzzle/core` **only** implements a simple
40
+ local filesystem backend. It reads Markdown files, validates frontmatter, and
41
+ updates a derivative SQLite index for query performance.
42
+
43
+ Upstream apps (such as `@luzzle/web` or custom deploy scripts) are responsible
44
+ for handling remote storage backends (like WebDAV or cloud storage syncing).
@@ -4,9 +4,9 @@ import { sql } from 'kysely';
4
4
  import { extractFullMarkdown } from './lib/markdown.js';
5
5
  import { addFrontMatter } from './lib/frontmatter.js';
6
6
  import { getDatabaseClient } from './database/client.js';
7
- import { filterFrontmatterFields, findFrontmatterField, getFrontmatterValue, getFrontmatterValues, resolveFieldPaths, setFrontmatterValue, unsetFrontmatterValue } from './pieces/index.js';
7
+ import { filterFrontmatterFields, findFrontmatterField, getFrontmatterValue, getFrontmatterValues, resolveFieldPaths, setFrontmatterValue, unsetFrontmatterValue, savePieceAsset } from './pieces/index.js';
8
8
  export * from './database/tables/index.js';
9
9
  export * from './pieces/index.js';
10
10
  export * from './llm/google.js';
11
11
  export * from './storage/index.js';
12
- export { getDatabaseClient, migrate, sql, compile, extractFullMarkdown, addFrontMatter, filterFrontmatterFields, findFrontmatterField, getFrontmatterValue, getFrontmatterValues, resolveFieldPaths, setFrontmatterValue, unsetFrontmatterValue };
12
+ export { getDatabaseClient, migrate, sql, compile, extractFullMarkdown, addFrontMatter, filterFrontmatterFields, findFrontmatterField, getFrontmatterValue, getFrontmatterValues, resolveFieldPaths, setFrontmatterValue, unsetFrontmatterValue, savePieceAsset, };
package/dist/src/index.js CHANGED
@@ -4,10 +4,10 @@ import { sql } from 'kysely';
4
4
  import { extractFullMarkdown } from './lib/markdown.js';
5
5
  import { addFrontMatter } from './lib/frontmatter.js';
6
6
  import { getDatabaseClient } from './database/client.js';
7
- import { filterFrontmatterFields, findFrontmatterField, getFrontmatterValue, getFrontmatterValues, resolveFieldPaths, setFrontmatterValue, unsetFrontmatterValue } from './pieces/index.js';
7
+ import { filterFrontmatterFields, findFrontmatterField, getFrontmatterValue, getFrontmatterValues, resolveFieldPaths, setFrontmatterValue, unsetFrontmatterValue, savePieceAsset, } from './pieces/index.js';
8
8
  export * from './database/tables/index.js';
9
9
  export * from './pieces/index.js';
10
10
  export * from './llm/google.js';
11
11
  export * from './storage/index.js';
12
- export { getDatabaseClient, migrate, sql, compile, extractFullMarkdown, addFrontMatter, filterFrontmatterFields, findFrontmatterField, getFrontmatterValue, getFrontmatterValues, resolveFieldPaths, setFrontmatterValue, unsetFrontmatterValue };
12
+ export { getDatabaseClient, migrate, sql, compile, extractFullMarkdown, addFrontMatter, filterFrontmatterFields, findFrontmatterField, getFrontmatterValue, getFrontmatterValues, resolveFieldPaths, setFrontmatterValue, unsetFrontmatterValue, savePieceAsset, };
13
13
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,0BAA0B,CAAA;AAC9C,OAAO,OAAO,MAAM,cAAc,CAAA;AAClC,OAAO,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAA;AAC5B,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AAE3L,cAAc,4BAA4B,CAAA;AAC1C,cAAc,mBAAmB,CAAA;AACjC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAElC,OAAO,EACN,iBAAiB,EACjB,OAAO,EACP,GAAG,EACH,OAAO,EACP,mBAAmB,EACnB,cAAc,EACd,uBAAuB,EACvB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,EACrB,CAAA","sourcesContent":["import migrate from './database/migrations.js'\nimport compile from './lib/ajv.js'\nimport { sql } from 'kysely'\nimport { extractFullMarkdown } from './lib/markdown.js'\nimport { addFrontMatter } from './lib/frontmatter.js'\nimport { getDatabaseClient } from './database/client.js'\nimport { filterFrontmatterFields, findFrontmatterField, getFrontmatterValue, getFrontmatterValues, resolveFieldPaths, setFrontmatterValue, unsetFrontmatterValue } from './pieces/index.js'\n\nexport * from './database/tables/index.js'\nexport * from './pieces/index.js'\nexport * from './llm/google.js'\nexport * from './storage/index.js'\n\nexport {\n\tgetDatabaseClient,\n\tmigrate,\n\tsql,\n\tcompile,\n\textractFullMarkdown,\n\taddFrontMatter,\n\tfilterFrontmatterFields,\n\tfindFrontmatterField,\n\tgetFrontmatterValue,\n\tgetFrontmatterValues,\n\tresolveFieldPaths,\n\tsetFrontmatterValue,\n\tunsetFrontmatterValue\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,0BAA0B,CAAA;AAC9C,OAAO,OAAO,MAAM,cAAc,CAAA;AAClC,OAAO,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAA;AAC5B,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,EACN,uBAAuB,EACvB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,GACd,MAAM,mBAAmB,CAAA;AAE1B,cAAc,4BAA4B,CAAA;AAC1C,cAAc,mBAAmB,CAAA;AACjC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAElC,OAAO,EACN,iBAAiB,EACjB,OAAO,EACP,GAAG,EACH,OAAO,EACP,mBAAmB,EACnB,cAAc,EACd,uBAAuB,EACvB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,GACd,CAAA","sourcesContent":["import migrate from './database/migrations.js'\nimport compile from './lib/ajv.js'\nimport { sql } from 'kysely'\nimport { extractFullMarkdown } from './lib/markdown.js'\nimport { addFrontMatter } from './lib/frontmatter.js'\nimport { getDatabaseClient } from './database/client.js'\nimport {\n\tfilterFrontmatterFields,\n\tfindFrontmatterField,\n\tgetFrontmatterValue,\n\tgetFrontmatterValues,\n\tresolveFieldPaths,\n\tsetFrontmatterValue,\n\tunsetFrontmatterValue,\n\tsavePieceAsset,\n} from './pieces/index.js'\n\nexport * from './database/tables/index.js'\nexport * from './pieces/index.js'\nexport * from './llm/google.js'\nexport * from './storage/index.js'\n\nexport {\n\tgetDatabaseClient,\n\tmigrate,\n\tsql,\n\tcompile,\n\textractFullMarkdown,\n\taddFrontMatter,\n\tfilterFrontmatterFields,\n\tfindFrontmatterField,\n\tgetFrontmatterValue,\n\tgetFrontmatterValues,\n\tresolveFieldPaths,\n\tsetFrontmatterValue,\n\tunsetFrontmatterValue,\n\tsavePieceAsset,\n}\n"]}
@@ -6,7 +6,7 @@ import { Readable } from 'stream';
6
6
  import { databaseValueToPieceFrontmatterValue, getPieceFrontmatterSchemaFields, initializePieceFrontMatter, } from './utils/frontmatter.js';
7
7
  import { findFrontmatterField, setFrontmatterValue, unsetFrontmatterValue, getFrontmatterValue, } from './utils/frontmatter.path.js';
8
8
  import { makePieceMarkdown, makePieceMarkdownString } from './utils/markdown.js';
9
- import { isAttachableStream, calculateHashFromFile, makePieceAttachment, makePieceValue, } from './utils/piece.js';
9
+ import { isAttachableStream, calculateHashFromFile, savePieceFieldAsset, makePieceValue, } from './utils/piece.js';
10
10
  import compile from '../lib/ajv.js';
11
11
  import { getValidatePieceItemErrors, makePieceItemInsertable, makePieceItemUpdatable, validatePieceItem, } from './item.js';
12
12
  import { extractFullMarkdown } from '../lib/markdown.js';
@@ -221,7 +221,7 @@ class Piece {
221
221
  for (const one of values) {
222
222
  const pieceValue = await makePieceValue(itemField, one);
223
223
  const val = isAttachableStream(pieceValue)
224
- ? await makePieceAttachment(markdown.filePath, itemField, pieceValue, this._storage)
224
+ ? await savePieceFieldAsset(markdown.filePath, itemField, pieceValue, this._storage)
225
225
  : pieceValue;
226
226
  setFrontmatterValue(updatedFrontmatter, fieldPath, val);
227
227
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Piece.js","sourceRoot":"","sources":["../../../src/pieces/Piece.ts"],"names":[],"mappings":"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","sourcesContent":["import { updateCache, addCache, getCache } from './cache.js'\nimport { cpus } from 'os'\nimport path from 'path'\nimport slugify from '@sindresorhus/slugify'\nimport { Readable } from 'stream'\nimport {\n\tdatabaseValueToPieceFrontmatterValue,\n\tgetPieceFrontmatterSchemaFields,\n\tinitializePieceFrontMatter,\n\tPieceFrontmatter,\n\tPieceFrontmatterSchema,\n\tPieceFrontmatterSchemaField,\n\tPieceFrontMatterValue,\n} from './utils/frontmatter.js'\nimport {\n\tfindFrontmatterField,\n\tsetFrontmatterValue,\n\tunsetFrontmatterValue,\n\tgetFrontmatterValue,\n} from './utils/frontmatter.path.js'\nimport LuzzleStorage from '../storage/abstract.js'\nimport { makePieceMarkdown, makePieceMarkdownString, PieceMarkdown } from './utils/markdown.js'\nimport {\n\tisAttachableStream,\n\tcalculateHashFromFile,\n\tmakePieceAttachment,\n\tmakePieceValue,\n} from './utils/piece.js'\nimport { LuzzleDatabase, LuzzleSelectable } from '../database/tables/index.js'\nimport compile from '../lib/ajv.js'\nimport {\n\tgetValidatePieceItemErrors,\n\tmakePieceItemInsertable,\n\tmakePieceItemUpdatable,\n\tvalidatePieceItem,\n} from './item.js'\nimport { extractFullMarkdown } from '../lib/markdown.js'\nimport { deleteItem, insertItem, selectItem, selectItems, updateItem } from './items.js'\nimport { LUZZLE_PIECE_FILE_EXTENSION } from './assets.js'\n\nexport interface InterfacePiece<F extends PieceFrontmatter> {\n\tnew(directory: string, pieceName: string, schemaOverride?: PieceFrontmatterSchema<F>): Piece<F>\n}\n\nexport type PiecePruneResult =\n\t| {\n\t\taction: 'pruned'\n\t\tfile: string\n\t\terror?: false\n\t}\n\t| {\n\t\tfile: string\n\t\terror: true\n\t\tmessage: string\n\t}\n\nexport type PieceSyncResult =\n\t| {\n\t\taction: 'added' | 'updated' | 'skipped'\n\t\tfile: string\n\t\terror?: false\n\t}\n\t| {\n\t\tfile: string\n\t\terror: true\n\t\tmessage: string\n\t}\n\nclass Piece<F extends PieceFrontmatter> {\n\tprivate _validator?: ReturnType<typeof compile<F>>\n\tprivate _schema: PieceFrontmatterSchema<F>\n\tprivate _storage: LuzzleStorage\n\tprivate _pieceName: string\n\tprivate _fields?: Array<PieceFrontmatterSchemaField>\n\n\tconstructor(pieceName: string, storage: LuzzleStorage, schema: PieceFrontmatterSchema<F>) {\n\t\tthis._storage = storage\n\t\tthis._schema = schema\n\t\tthis._pieceName = pieceName\n\n\t\tif (this._pieceName !== this._schema.title) {\n\t\t\tthrow new Error(`${pieceName} does not match the schema title: ${this._schema.title}`)\n\t\t}\n\t}\n\n\tasync create(directory: string, name: string): Promise<PieceMarkdown<F>> {\n\t\tconst slug = slugify(name)\n\t\tconst filename = `${slug}.${this.type}.${LUZZLE_PIECE_FILE_EXTENSION}`\n\t\tconst file = path.join(directory, filename)\n\t\tconst exists = await this._storage.exists(file)\n\n\t\tif (exists) {\n\t\t\tthrow new Error(`file already exists: ${file}`)\n\t\t}\n\n\t\tconst frontmatter = initializePieceFrontMatter(this._schema, true) as F\n\t\treturn makePieceMarkdown(file, this._pieceName, undefined, frontmatter)\n\t}\n\n\tasync delete(file: string) {\n\t\tconst exists = await this._storage.exists(file)\n\n\t\tif (exists) {\n\t\t\tawait this._storage.delete(file)\n\t\t\treturn\n\t\t}\n\n\t\tthrow new Error(`${file} does not exist`)\n\t}\n\n\tget type() {\n\t\treturn this._pieceName\n\t}\n\n\tget schema() {\n\t\treturn this._schema\n\t}\n\n\tprotected get validator(): ReturnType<typeof compile<F>> {\n\t\tthis._validator = this._validator || compile<F>(this._schema)\n\t\treturn this._validator\n\t}\n\n\tget fields() {\n\t\tthis._fields = this._fields || getPieceFrontmatterSchemaFields(this._schema)\n\t\treturn this._fields\n\t}\n\n\tasync isOutdated(file: string, db: LuzzleDatabase): Promise<boolean> {\n\t\tconst fileStat = await this._storage.stat(file).catch(() => null)\n\n\t\tif (fileStat) {\n\t\t\tconst cache = await getCache(db, file)\n\t\t\tconst cachedDate = cache?.date_updated || cache?.date_added\n\n\t\t\treturn !cachedDate || fileStat.last_modified.getTime() > cachedDate\n\t\t}\n\n\t\tthrow new Error(`${file} does not exist`)\n\t}\n\n\tvalidate(markdown: PieceMarkdown<F>): { isValid: true } | { isValid: false; errors: string[] } {\n\t\tconst valid = validatePieceItem(markdown, this.validator)\n\n\t\tif (valid) {\n\t\t\treturn { isValid: true }\n\t\t} else {\n\t\t\tconst errors = getValidatePieceItemErrors(this.validator)\n\t\t\treturn { isValid: false, errors }\n\t\t}\n\t}\n\n\tasync get(file: string): Promise<PieceMarkdown<F>> {\n\t\tconst exists = await this._storage.exists(file)\n\n\t\tif (exists) {\n\t\t\tconst contents = await this._storage.readFile(file, 'text')\n\t\t\tconst data = await extractFullMarkdown(contents)\n\n\t\t\tif (!/^\\//.test(file)) {\n\t\t\t\treturn makePieceMarkdown(file, this._pieceName, data.markdown, data.frontmatter as F)\n\t\t\t}\n\t\t}\n\n\t\tthrow new Error(`${file} does not exist`)\n\t}\n\n\tasync write(markdown: PieceMarkdown<F>): Promise<void> {\n\t\tconst validated = this.validate(markdown)\n\n\t\tif (validated.isValid) {\n\t\t\tconst markdownString = makePieceMarkdownString(markdown)\n\t\t\tawait this._storage.writeFile(markdown.filePath, markdownString)\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t`Could not write ${markdown.filePath} due to\\n\\n: ${validated.errors.join('\\n')}`\n\t\t\t)\n\t\t}\n\t}\n\n\tasync prune(db: LuzzleDatabase, files: string[], options?: { dryRun: boolean }) {\n\t\tconst dbPieces = await selectItems(db, { type: this._pieceName })\n\t\tconst diskPiecesSet = new Set<string>(files)\n\t\tconst missingPieces = dbPieces.filter((piece) => !diskPiecesSet.has(piece.file_path))\n\t\tconst missingFiles = missingPieces.map((piece) => piece.file_path)\n\t\tconst stream = Readable.from(missingFiles)\n\n\t\treturn stream.map(\n\t\t\tasync (file: string): Promise<PiecePruneResult> => {\n\t\t\t\ttry {\n\t\t\t\t\tif (!options?.dryRun) {\n\t\t\t\t\t\tawait deleteItem(db, file)\n\t\t\t\t\t}\n\t\t\t\t\treturn { action: 'pruned', file }\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn { file, error: true, message: `error pruning piece: ${error}` }\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ concurrency: cpus().length }\n\t\t) as Readable & AsyncIterable<PiecePruneResult>\n\t}\n\n\tasync sync(db: LuzzleDatabase, files: string[], options?: { dryRun?: boolean; force?: boolean }) {\n\t\tconst stream = Readable.from(files)\n\n\t\treturn stream.map(\n\t\t\tasync (file: string): Promise<PieceSyncResult> => {\n\t\t\t\ttry {\n\t\t\t\t\tconst markdown = await this.get(file)\n\t\t\t\t\tconst dbPiece = await selectItem(db, markdown.filePath)\n\n\t\t\t\t\tif (dbPiece) {\n\t\t\t\t\t\tconst readStream = this._storage.createReadStream(markdown.filePath)\n\t\t\t\t\t\tconst newHash = await calculateHashFromFile(readStream)\n\t\t\t\t\t\tconst cache = await getCache(db, markdown.filePath)\n\t\t\t\t\t\tif (options?.force || cache?.content_hash !== newHash) {\n\t\t\t\t\t\t\tif (!options?.dryRun) {\n\t\t\t\t\t\t\t\tawait this.syncMarkdownUpdate(db, markdown, dbPiece)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn { action: 'updated', file }\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!options?.dryRun) {\n\t\t\t\t\t\t\tawait updateCache(db, markdown.filePath, newHash)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn { action: 'skipped', file }\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (!options?.dryRun) {\n\t\t\t\t\t\t\tawait this.syncMarkdownAdd(db, markdown)\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn { action: 'added', file }\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn { file, error: true, message: `error syncing piece: ${error}` }\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ concurrency: cpus().length }\n\t\t) as Readable & AsyncIterable<PieceSyncResult>\n\t}\n\n\tasync syncMarkdownAdd(db: LuzzleDatabase, markdown: PieceMarkdown<F>): Promise<void> {\n\t\tconst createInput = makePieceItemInsertable(this._pieceName, markdown, this._schema)\n\t\tconst readStream = this._storage.createReadStream(markdown.filePath)\n\t\tconst hash = await calculateHashFromFile(readStream)\n\n\t\tawait insertItem(db, createInput)\n\t\tawait addCache(db, markdown.filePath, hash)\n\t}\n\n\tasync syncMarkdown(db: LuzzleDatabase, markdown: PieceMarkdown<F>): Promise<void> {\n\t\tconst dbPiece = await selectItem(db, markdown.filePath)\n\n\t\tif (dbPiece) {\n\t\t\tawait this.syncMarkdownUpdate(db, markdown, dbPiece)\n\t\t} else {\n\t\t\tawait this.syncMarkdownAdd(db, markdown)\n\t\t}\n\t}\n\n\tasync syncMarkdownUpdate(\n\t\tdb: LuzzleDatabase,\n\t\tmarkdown: PieceMarkdown<F>,\n\t\tdata: LuzzleSelectable<'pieces_items'>\n\t): Promise<void> {\n\t\tconst updateInput = makePieceItemUpdatable(markdown, this._schema, data, false)\n\t\tawait updateItem(db, markdown.filePath, updateInput)\n\t\tconst readStream = this._storage.createReadStream(markdown.filePath)\n\t\tconst hash = await calculateHashFromFile(readStream)\n\n\t\tawait updateCache(db, data.file_path, hash)\n\t}\n\n\ttoMarkdown(data: LuzzleSelectable<'pieces_items'>): PieceMarkdown<F> {\n\t\tconst frontmatter = JSON.parse(data.frontmatter_json)\n\t\tconst frontmatterJson: Record<string, unknown> = {}\n\t\tconst dataKeys = Object.keys(frontmatter)\n\t\tconst fields = getPieceFrontmatterSchemaFields(this._schema).filter(\n\t\t\t(f): f is PieceFrontmatterSchemaField & { name: string } =>\n\t\t\t\t!!f.name && dataKeys.includes(f.name)\n\t\t)\n\n\t\tfields.forEach((field) => {\n\t\t\tconst name = field.name\n\t\t\tconst value = frontmatter[name]\n\n\t\t\tfrontmatterJson[name] = databaseValueToPieceFrontmatterValue(value, field)\n\t\t})\n\n\t\treturn makePieceMarkdown(data.file_path, data.type, data.note_markdown, frontmatterJson as F)\n\t}\n\n\tgetField(markdown: PieceMarkdown<F>, fieldPath: string): PieceFrontMatterValue | undefined {\n\t\treturn getFrontmatterValue(markdown.frontmatter, fieldPath)\n\t}\n\n\tasync setFields(\n\t\tmarkdown: PieceMarkdown<F>,\n\t\tfields: Record<string, unknown>\n\t): Promise<PieceMarkdown<F>> {\n\t\tlet updatedMarkdown = markdown\n\n\t\tfor (const fieldname in fields) {\n\t\t\tupdatedMarkdown = await this.setField(updatedMarkdown, fieldname, fields[fieldname])\n\t\t}\n\n\t\treturn updatedMarkdown\n\t}\n\n\tasync removeFields(\n\t\tmarkdown: PieceMarkdown<F>,\n\t\tfields: string[]\n\t): Promise<PieceMarkdown<Omit<F, keyof F>>> {\n\t\tlet updatedMarkdown = markdown as unknown as PieceMarkdown<Omit<F, keyof F>>\n\n\t\tfor (const field of fields) {\n\t\t\tupdatedMarkdown = (await this.removeField(\n\t\t\t\tupdatedMarkdown as unknown as PieceMarkdown<F>,\n\t\t\t\tfield\n\t\t\t)) as unknown as PieceMarkdown<Omit<F, keyof F>>\n\t\t}\n\n\t\treturn updatedMarkdown\n\t}\n\n\tasync setField(\n\t\tmarkdown: PieceMarkdown<F>,\n\t\tfieldPath: string,\n\t\tvalue: unknown\n\t): Promise<PieceMarkdown<F>> {\n\t\tconst pieceField = findFrontmatterField(this.fields, fieldPath)\n\n\t\tif (!pieceField) {\n\t\t\tthrow new Error(`${fieldPath} is not a field in ${this._pieceName} ${markdown.filePath}`)\n\t\t}\n\n\t\tconst isArray = pieceField.type === 'array'\n\t\tconst itemField = isArray ? { ...pieceField.items, name: pieceField.name } : pieceField\n\t\tconst values = Array.isArray(value) ? value : [value]\n\n\t\tconst updatedFrontmatter = structuredClone(markdown.frontmatter)\n\n\t\ttry {\n\t\t\tif (isArray) {\n\t\t\t\tconst current = getFrontmatterValue(updatedFrontmatter, fieldPath)\n\t\t\t\tif (!Array.isArray(current)) {\n\t\t\t\t\tsetFrontmatterValue(updatedFrontmatter, fieldPath, [] as unknown as PieceFrontMatterValue)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const one of values) {\n\t\t\t\tconst pieceValue = await makePieceValue(itemField, one)\n\n\t\t\t\tconst val = isAttachableStream(pieceValue)\n\t\t\t\t\t? await makePieceAttachment(\n\t\t\t\t\t\tmarkdown.filePath,\n\t\t\t\t\t\titemField as PieceFrontmatterSchemaField,\n\t\t\t\t\t\tpieceValue,\n\t\t\t\t\t\tthis._storage\n\t\t\t\t\t)\n\t\t\t\t\t: (pieceValue as PieceFrontMatterValue)\n\n\t\t\t\tsetFrontmatterValue(updatedFrontmatter, fieldPath, val)\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconst error = e as Error\n\t\t\tconsole.error(`could not set field ${fieldPath}: ${error.message}`)\n\t\t\treturn markdown\n\t\t}\n\n\t\treturn makePieceMarkdown(markdown.filePath, markdown.piece, markdown.note, updatedFrontmatter)\n\t}\n\n\tasync removeField(\n\t\tmarkdown: PieceMarkdown<F>,\n\t\tfieldPath: string,\n\t\tvalue?: number | string | boolean\n\t): Promise<PieceMarkdown<F>> {\n\t\tconst pieceField = findFrontmatterField(this.fields, fieldPath)\n\n\t\tif (!pieceField) {\n\t\t\tthrow new Error(`${fieldPath} is not a field in ${this._pieceName} ${markdown.filePath}`)\n\t\t}\n\n\t\tif (pieceField.nullable !== true) {\n\t\t\tthrow new Error(`${fieldPath} is a required field in ${this._pieceName} ${markdown.filePath}`)\n\t\t}\n\n\t\tconst updatedFrontmatter = structuredClone(markdown.frontmatter)\n\n\t\tif (value === undefined) {\n\t\t\tunsetFrontmatterValue(updatedFrontmatter, fieldPath)\n\t\t} else {\n\t\t\tconst pieceValue = await makePieceValue(pieceField, value)\n\t\t\tconst current = getFrontmatterValue(updatedFrontmatter, fieldPath)\n\n\t\t\tif (Array.isArray(current) && !isAttachableStream(pieceValue)) {\n\t\t\t\tconst index = current.indexOf(pieceValue as PieceFrontMatterValue)\n\t\t\t\tif (index !== -1) {\n\t\t\t\t\tunsetFrontmatterValue(updatedFrontmatter, `${fieldPath}.${index}`)\n\t\t\t\t} else {\n\t\t\t\t\treturn markdown\n\t\t\t\t}\n\t\t\t} else if (current === pieceValue) {\n\t\t\t\tunsetFrontmatterValue(updatedFrontmatter, fieldPath)\n\t\t\t}\n\t\t}\n\n\t\treturn makePieceMarkdown(markdown.filePath, markdown.piece, markdown.note, updatedFrontmatter)\n\t}\n}\n\nexport default Piece\n"]}
1
+ {"version":3,"file":"Piece.js","sourceRoot":"","sources":["../../../src/pieces/Piece.ts"],"names":[],"mappings":"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","sourcesContent":["import { updateCache, addCache, getCache } from './cache.js'\nimport { cpus } from 'os'\nimport path from 'path'\nimport slugify from '@sindresorhus/slugify'\nimport { Readable } from 'stream'\nimport {\n\tdatabaseValueToPieceFrontmatterValue,\n\tgetPieceFrontmatterSchemaFields,\n\tinitializePieceFrontMatter,\n\tPieceFrontmatter,\n\tPieceFrontmatterSchema,\n\tPieceFrontmatterSchemaField,\n\tPieceFrontMatterValue,\n} from './utils/frontmatter.js'\nimport {\n\tfindFrontmatterField,\n\tsetFrontmatterValue,\n\tunsetFrontmatterValue,\n\tgetFrontmatterValue,\n} from './utils/frontmatter.path.js'\nimport LuzzleStorage from '../storage/abstract.js'\nimport { makePieceMarkdown, makePieceMarkdownString, PieceMarkdown } from './utils/markdown.js'\nimport {\n\tisAttachableStream,\n\tcalculateHashFromFile,\n\tsavePieceFieldAsset,\n\tmakePieceValue,\n} from './utils/piece.js'\nimport { LuzzleDatabase, LuzzleSelectable } from '../database/tables/index.js'\nimport compile from '../lib/ajv.js'\nimport {\n\tgetValidatePieceItemErrors,\n\tmakePieceItemInsertable,\n\tmakePieceItemUpdatable,\n\tvalidatePieceItem,\n} from './item.js'\nimport { extractFullMarkdown } from '../lib/markdown.js'\nimport { deleteItem, insertItem, selectItem, selectItems, updateItem } from './items.js'\nimport { LUZZLE_PIECE_FILE_EXTENSION } from './assets.js'\n\nexport interface InterfacePiece<F extends PieceFrontmatter> {\n\tnew(directory: string, pieceName: string, schemaOverride?: PieceFrontmatterSchema<F>): Piece<F>\n}\n\nexport type PiecePruneResult =\n\t| {\n\t\taction: 'pruned'\n\t\tfile: string\n\t\terror?: false\n\t}\n\t| {\n\t\tfile: string\n\t\terror: true\n\t\tmessage: string\n\t}\n\nexport type PieceSyncResult =\n\t| {\n\t\taction: 'added' | 'updated' | 'skipped'\n\t\tfile: string\n\t\terror?: false\n\t}\n\t| {\n\t\tfile: string\n\t\terror: true\n\t\tmessage: string\n\t}\n\nclass Piece<F extends PieceFrontmatter> {\n\tprivate _validator?: ReturnType<typeof compile<F>>\n\tprivate _schema: PieceFrontmatterSchema<F>\n\tprivate _storage: LuzzleStorage\n\tprivate _pieceName: string\n\tprivate _fields?: Array<PieceFrontmatterSchemaField>\n\n\tconstructor(pieceName: string, storage: LuzzleStorage, schema: PieceFrontmatterSchema<F>) {\n\t\tthis._storage = storage\n\t\tthis._schema = schema\n\t\tthis._pieceName = pieceName\n\n\t\tif (this._pieceName !== this._schema.title) {\n\t\t\tthrow new Error(`${pieceName} does not match the schema title: ${this._schema.title}`)\n\t\t}\n\t}\n\n\tasync create(directory: string, name: string): Promise<PieceMarkdown<F>> {\n\t\tconst slug = slugify(name)\n\t\tconst filename = `${slug}.${this.type}.${LUZZLE_PIECE_FILE_EXTENSION}`\n\t\tconst file = path.join(directory, filename)\n\t\tconst exists = await this._storage.exists(file)\n\n\t\tif (exists) {\n\t\t\tthrow new Error(`file already exists: ${file}`)\n\t\t}\n\n\t\tconst frontmatter = initializePieceFrontMatter(this._schema, true) as F\n\t\treturn makePieceMarkdown(file, this._pieceName, undefined, frontmatter)\n\t}\n\n\tasync delete(file: string) {\n\t\tconst exists = await this._storage.exists(file)\n\n\t\tif (exists) {\n\t\t\tawait this._storage.delete(file)\n\t\t\treturn\n\t\t}\n\n\t\tthrow new Error(`${file} does not exist`)\n\t}\n\n\tget type() {\n\t\treturn this._pieceName\n\t}\n\n\tget schema() {\n\t\treturn this._schema\n\t}\n\n\tprotected get validator(): ReturnType<typeof compile<F>> {\n\t\tthis._validator = this._validator || compile<F>(this._schema)\n\t\treturn this._validator\n\t}\n\n\tget fields() {\n\t\tthis._fields = this._fields || getPieceFrontmatterSchemaFields(this._schema)\n\t\treturn this._fields\n\t}\n\n\tasync isOutdated(file: string, db: LuzzleDatabase): Promise<boolean> {\n\t\tconst fileStat = await this._storage.stat(file).catch(() => null)\n\n\t\tif (fileStat) {\n\t\t\tconst cache = await getCache(db, file)\n\t\t\tconst cachedDate = cache?.date_updated || cache?.date_added\n\n\t\t\treturn !cachedDate || fileStat.last_modified.getTime() > cachedDate\n\t\t}\n\n\t\tthrow new Error(`${file} does not exist`)\n\t}\n\n\tvalidate(markdown: PieceMarkdown<F>): { isValid: true } | { isValid: false; errors: string[] } {\n\t\tconst valid = validatePieceItem(markdown, this.validator)\n\n\t\tif (valid) {\n\t\t\treturn { isValid: true }\n\t\t} else {\n\t\t\tconst errors = getValidatePieceItemErrors(this.validator)\n\t\t\treturn { isValid: false, errors }\n\t\t}\n\t}\n\n\tasync get(file: string): Promise<PieceMarkdown<F>> {\n\t\tconst exists = await this._storage.exists(file)\n\n\t\tif (exists) {\n\t\t\tconst contents = await this._storage.readFile(file, 'text')\n\t\t\tconst data = await extractFullMarkdown(contents)\n\n\t\t\tif (!/^\\//.test(file)) {\n\t\t\t\treturn makePieceMarkdown(file, this._pieceName, data.markdown, data.frontmatter as F)\n\t\t\t}\n\t\t}\n\n\t\tthrow new Error(`${file} does not exist`)\n\t}\n\n\tasync write(markdown: PieceMarkdown<F>): Promise<void> {\n\t\tconst validated = this.validate(markdown)\n\n\t\tif (validated.isValid) {\n\t\t\tconst markdownString = makePieceMarkdownString(markdown)\n\t\t\tawait this._storage.writeFile(markdown.filePath, markdownString)\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t`Could not write ${markdown.filePath} due to\\n\\n: ${validated.errors.join('\\n')}`\n\t\t\t)\n\t\t}\n\t}\n\n\tasync prune(db: LuzzleDatabase, files: string[], options?: { dryRun: boolean }) {\n\t\tconst dbPieces = await selectItems(db, { type: this._pieceName })\n\t\tconst diskPiecesSet = new Set<string>(files)\n\t\tconst missingPieces = dbPieces.filter((piece) => !diskPiecesSet.has(piece.file_path))\n\t\tconst missingFiles = missingPieces.map((piece) => piece.file_path)\n\t\tconst stream = Readable.from(missingFiles)\n\n\t\treturn stream.map(\n\t\t\tasync (file: string): Promise<PiecePruneResult> => {\n\t\t\t\ttry {\n\t\t\t\t\tif (!options?.dryRun) {\n\t\t\t\t\t\tawait deleteItem(db, file)\n\t\t\t\t\t}\n\t\t\t\t\treturn { action: 'pruned', file }\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn { file, error: true, message: `error pruning piece: ${error}` }\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ concurrency: cpus().length }\n\t\t) as Readable & AsyncIterable<PiecePruneResult>\n\t}\n\n\tasync sync(db: LuzzleDatabase, files: string[], options?: { dryRun?: boolean; force?: boolean }) {\n\t\tconst stream = Readable.from(files)\n\n\t\treturn stream.map(\n\t\t\tasync (file: string): Promise<PieceSyncResult> => {\n\t\t\t\ttry {\n\t\t\t\t\tconst markdown = await this.get(file)\n\t\t\t\t\tconst dbPiece = await selectItem(db, markdown.filePath)\n\n\t\t\t\t\tif (dbPiece) {\n\t\t\t\t\t\tconst readStream = this._storage.createReadStream(markdown.filePath)\n\t\t\t\t\t\tconst newHash = await calculateHashFromFile(readStream)\n\t\t\t\t\t\tconst cache = await getCache(db, markdown.filePath)\n\t\t\t\t\t\tif (options?.force || cache?.content_hash !== newHash) {\n\t\t\t\t\t\t\tif (!options?.dryRun) {\n\t\t\t\t\t\t\t\tawait this.syncMarkdownUpdate(db, markdown, dbPiece)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn { action: 'updated', file }\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!options?.dryRun) {\n\t\t\t\t\t\t\tawait updateCache(db, markdown.filePath, newHash)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn { action: 'skipped', file }\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (!options?.dryRun) {\n\t\t\t\t\t\t\tawait this.syncMarkdownAdd(db, markdown)\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn { action: 'added', file }\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn { file, error: true, message: `error syncing piece: ${error}` }\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ concurrency: cpus().length }\n\t\t) as Readable & AsyncIterable<PieceSyncResult>\n\t}\n\n\tasync syncMarkdownAdd(db: LuzzleDatabase, markdown: PieceMarkdown<F>): Promise<void> {\n\t\tconst createInput = makePieceItemInsertable(this._pieceName, markdown, this._schema)\n\t\tconst readStream = this._storage.createReadStream(markdown.filePath)\n\t\tconst hash = await calculateHashFromFile(readStream)\n\n\t\tawait insertItem(db, createInput)\n\t\tawait addCache(db, markdown.filePath, hash)\n\t}\n\n\tasync syncMarkdown(db: LuzzleDatabase, markdown: PieceMarkdown<F>): Promise<void> {\n\t\tconst dbPiece = await selectItem(db, markdown.filePath)\n\n\t\tif (dbPiece) {\n\t\t\tawait this.syncMarkdownUpdate(db, markdown, dbPiece)\n\t\t} else {\n\t\t\tawait this.syncMarkdownAdd(db, markdown)\n\t\t}\n\t}\n\n\tasync syncMarkdownUpdate(\n\t\tdb: LuzzleDatabase,\n\t\tmarkdown: PieceMarkdown<F>,\n\t\tdata: LuzzleSelectable<'pieces_items'>\n\t): Promise<void> {\n\t\tconst updateInput = makePieceItemUpdatable(markdown, this._schema, data, false)\n\t\tawait updateItem(db, markdown.filePath, updateInput)\n\t\tconst readStream = this._storage.createReadStream(markdown.filePath)\n\t\tconst hash = await calculateHashFromFile(readStream)\n\n\t\tawait updateCache(db, data.file_path, hash)\n\t}\n\n\ttoMarkdown(data: LuzzleSelectable<'pieces_items'>): PieceMarkdown<F> {\n\t\tconst frontmatter = JSON.parse(data.frontmatter_json)\n\t\tconst frontmatterJson: Record<string, unknown> = {}\n\t\tconst dataKeys = Object.keys(frontmatter)\n\t\tconst fields = getPieceFrontmatterSchemaFields(this._schema).filter(\n\t\t\t(f): f is PieceFrontmatterSchemaField & { name: string } =>\n\t\t\t\t!!f.name && dataKeys.includes(f.name)\n\t\t)\n\n\t\tfields.forEach((field) => {\n\t\t\tconst name = field.name\n\t\t\tconst value = frontmatter[name]\n\n\t\t\tfrontmatterJson[name] = databaseValueToPieceFrontmatterValue(value, field)\n\t\t})\n\n\t\treturn makePieceMarkdown(data.file_path, data.type, data.note_markdown, frontmatterJson as F)\n\t}\n\n\tgetField(markdown: PieceMarkdown<F>, fieldPath: string): PieceFrontMatterValue | undefined {\n\t\treturn getFrontmatterValue(markdown.frontmatter, fieldPath)\n\t}\n\n\tasync setFields(\n\t\tmarkdown: PieceMarkdown<F>,\n\t\tfields: Record<string, unknown>\n\t): Promise<PieceMarkdown<F>> {\n\t\tlet updatedMarkdown = markdown\n\n\t\tfor (const fieldname in fields) {\n\t\t\tupdatedMarkdown = await this.setField(updatedMarkdown, fieldname, fields[fieldname])\n\t\t}\n\n\t\treturn updatedMarkdown\n\t}\n\n\tasync removeFields(\n\t\tmarkdown: PieceMarkdown<F>,\n\t\tfields: string[]\n\t): Promise<PieceMarkdown<Omit<F, keyof F>>> {\n\t\tlet updatedMarkdown = markdown as unknown as PieceMarkdown<Omit<F, keyof F>>\n\n\t\tfor (const field of fields) {\n\t\t\tupdatedMarkdown = (await this.removeField(\n\t\t\t\tupdatedMarkdown as unknown as PieceMarkdown<F>,\n\t\t\t\tfield\n\t\t\t)) as unknown as PieceMarkdown<Omit<F, keyof F>>\n\t\t}\n\n\t\treturn updatedMarkdown\n\t}\n\n\tasync setField(\n\t\tmarkdown: PieceMarkdown<F>,\n\t\tfieldPath: string,\n\t\tvalue: unknown\n\t): Promise<PieceMarkdown<F>> {\n\t\tconst pieceField = findFrontmatterField(this.fields, fieldPath)\n\n\t\tif (!pieceField) {\n\t\t\tthrow new Error(`${fieldPath} is not a field in ${this._pieceName} ${markdown.filePath}`)\n\t\t}\n\n\t\tconst isArray = pieceField.type === 'array'\n\t\tconst itemField = isArray ? { ...pieceField.items, name: pieceField.name } : pieceField\n\t\tconst values = Array.isArray(value) ? value : [value]\n\n\t\tconst updatedFrontmatter = structuredClone(markdown.frontmatter)\n\n\t\ttry {\n\t\t\tif (isArray) {\n\t\t\t\tconst current = getFrontmatterValue(updatedFrontmatter, fieldPath)\n\t\t\t\tif (!Array.isArray(current)) {\n\t\t\t\t\tsetFrontmatterValue(updatedFrontmatter, fieldPath, [] as unknown as PieceFrontMatterValue)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const one of values) {\n\t\t\t\tconst pieceValue = await makePieceValue(itemField, one)\n\n\t\t\t\tconst val = isAttachableStream(pieceValue)\n\t\t\t\t\t? await savePieceFieldAsset(\n\t\t\t\t\t\tmarkdown.filePath,\n\t\t\t\t\t\titemField as PieceFrontmatterSchemaField,\n\t\t\t\t\t\tpieceValue,\n\t\t\t\t\t\tthis._storage\n\t\t\t\t\t)\n\t\t\t\t\t: (pieceValue as PieceFrontMatterValue)\n\n\t\t\t\tsetFrontmatterValue(updatedFrontmatter, fieldPath, val)\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconst error = e as Error\n\t\t\tconsole.error(`could not set field ${fieldPath}: ${error.message}`)\n\t\t\treturn markdown\n\t\t}\n\n\t\treturn makePieceMarkdown(markdown.filePath, markdown.piece, markdown.note, updatedFrontmatter)\n\t}\n\n\tasync removeField(\n\t\tmarkdown: PieceMarkdown<F>,\n\t\tfieldPath: string,\n\t\tvalue?: number | string | boolean\n\t): Promise<PieceMarkdown<F>> {\n\t\tconst pieceField = findFrontmatterField(this.fields, fieldPath)\n\n\t\tif (!pieceField) {\n\t\t\tthrow new Error(`${fieldPath} is not a field in ${this._pieceName} ${markdown.filePath}`)\n\t\t}\n\n\t\tif (pieceField.nullable !== true) {\n\t\t\tthrow new Error(`${fieldPath} is a required field in ${this._pieceName} ${markdown.filePath}`)\n\t\t}\n\n\t\tconst updatedFrontmatter = structuredClone(markdown.frontmatter)\n\n\t\tif (value === undefined) {\n\t\t\tunsetFrontmatterValue(updatedFrontmatter, fieldPath)\n\t\t} else {\n\t\t\tconst pieceValue = await makePieceValue(pieceField, value)\n\t\t\tconst current = getFrontmatterValue(updatedFrontmatter, fieldPath)\n\n\t\t\tif (Array.isArray(current) && !isAttachableStream(pieceValue)) {\n\t\t\t\tconst index = current.indexOf(pieceValue as PieceFrontMatterValue)\n\t\t\t\tif (index !== -1) {\n\t\t\t\t\tunsetFrontmatterValue(updatedFrontmatter, `${fieldPath}.${index}`)\n\t\t\t\t} else {\n\t\t\t\t\treturn markdown\n\t\t\t\t}\n\t\t\t} else if (current === pieceValue) {\n\t\t\t\tunsetFrontmatterValue(updatedFrontmatter, fieldPath)\n\t\t\t}\n\t\t}\n\n\t\treturn makePieceMarkdown(markdown.filePath, markdown.piece, markdown.note, updatedFrontmatter)\n\t}\n}\n\nexport default Piece\n"]}
@@ -1,6 +1,7 @@
1
1
  export * from './utils/markdown.js';
2
2
  export * from './utils/frontmatter.js';
3
3
  export * from './utils/frontmatter.path.js';
4
+ export * from './utils/piece.js';
4
5
  export * from './json.schema.js';
5
6
  export * from './items.js';
6
7
  export * from './item.js';
@@ -1,6 +1,7 @@
1
1
  export * from './utils/markdown.js';
2
2
  export * from './utils/frontmatter.js';
3
3
  export * from './utils/frontmatter.path.js';
4
+ export * from './utils/piece.js';
4
5
  export * from './json.schema.js';
5
6
  export * from './items.js';
6
7
  export * from './item.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/pieces/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAA;AACnC,cAAc,wBAAwB,CAAA;AACtC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,kBAAkB,CAAA;AAChC,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,OAAO,EAAE,OAAO,IAAI,KAAK,EAA+C,MAAM,YAAY,CAAA;AAC1F,OAAO,EAAE,OAAO,IAAI,MAAM,EAAiD,MAAM,aAAa,CAAA","sourcesContent":["export * from './utils/markdown.js'\nexport * from './utils/frontmatter.js'\nexport * from './utils/frontmatter.path.js'\nexport * from './json.schema.js'\nexport * from './items.js'\nexport * from './item.js'\nexport * from './manager.js'\nexport { default as Piece, type PieceSyncResult, type PiecePruneResult } from './Piece.js'\nexport { default as Pieces, type PiecesSyncResult, type PiecesPruneResult } from './Pieces.js'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/pieces/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAA;AACnC,cAAc,wBAAwB,CAAA;AACtC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,OAAO,EAAE,OAAO,IAAI,KAAK,EAA+C,MAAM,YAAY,CAAA;AAC1F,OAAO,EAAE,OAAO,IAAI,MAAM,EAAiD,MAAM,aAAa,CAAA","sourcesContent":["export * from './utils/markdown.js'\nexport * from './utils/frontmatter.js'\nexport * from './utils/frontmatter.path.js'\nexport * from './utils/piece.js'\nexport * from './json.schema.js'\nexport * from './items.js'\nexport * from './item.js'\nexport * from './manager.js'\nexport { default as Piece, type PieceSyncResult, type PiecePruneResult } from './Piece.js'\nexport { default as Pieces, type PiecesSyncResult, type PiecesPruneResult } from './Pieces.js'\n"]}
@@ -10,7 +10,8 @@ declare function detectStreamFileType(stream: Readable, maxBytes?: number): Prom
10
10
  type: import("file-type").FileTypeResult | undefined;
11
11
  stream: Readable;
12
12
  }>;
13
- declare function makePieceAttachment(file: string, field: PieceFrontmatterSchemaField, stream: AttachableStream, storage: LuzzleStorage): Promise<string>;
13
+ declare function savePieceAsset(file: string, filename: string, stream: Readable, storage: LuzzleStorage): Promise<string>;
14
+ declare function savePieceFieldAsset(file: string, field: PieceFrontmatterSchemaField, stream: AttachableStream, storage: LuzzleStorage): Promise<string>;
14
15
  declare function isAttachableStream(value: unknown): value is AttachableStream;
15
16
  declare function makePieceValue(field: PieceFrontmatterSchemaField, value: PieceFrontMatterValue | AttachableStream): Promise<PieceFrontMatterValue | AttachableStream>;
16
- export { calculateHashFromFile, isAttachableStream, makePieceAttachment, makePieceValue, detectStreamFileType, type AttachableStream, };
17
+ export { calculateHashFromFile, isAttachableStream, savePieceFieldAsset, makePieceValue, detectStreamFileType, savePieceAsset, type AttachableStream, };
@@ -100,27 +100,21 @@ async function detectStreamFileType(stream, maxBytes = 4100) {
100
100
  stream: Readable.from(gen()),
101
101
  };
102
102
  }
103
- async function makePieceAttachment(file, field, stream, storage) {
104
- const format = field.type === 'array' ? field.items.format : field.format;
105
- /* c8 ignore next 3 */
106
- if (format !== 'asset') {
107
- throw new Error(`${field} is not an attachable field for ${file}`);
108
- }
103
+ async function savePieceAsset(file, filename, stream, storage) {
109
104
  const pieceDir = file.replace(/\.[^.]+$/, '');
110
105
  const attachDir = path.join(ASSETS_DIRECTORY, pieceDir);
111
106
  const exists = await storage.exists(attachDir);
112
- const sourceInfo = stream.filename;
113
107
  if (!exists) {
114
108
  await storage.makeDirectory(attachDir);
115
109
  }
116
- const { type: detectedType, stream: finalStream } = await detectStreamFileType(stream.stream);
117
- const sourceBasename = sourceInfo
118
- ? path.basename(sourceInfo, path.extname(sourceInfo))
119
- : field.name;
110
+ const { type: detectedType, stream: finalStream } = await detectStreamFileType(stream);
111
+ const sourceBasename = filename
112
+ ? path.basename(filename, path.extname(filename))
113
+ : 'attachment';
120
114
  const sourceExt = detectedType
121
115
  ? '.' + detectedType.ext
122
- : sourceInfo
123
- ? path.extname(sourceInfo)
116
+ : filename
117
+ ? path.extname(filename)
124
118
  : '';
125
119
  let relPath = path.join(attachDir, sourceBasename + sourceExt);
126
120
  let counter = 2;
@@ -131,6 +125,15 @@ async function makePieceAttachment(file, field, stream, storage) {
131
125
  await pipeline(finalStream, storage.createWriteStream(relPath));
132
126
  return relPath;
133
127
  }
128
+ async function savePieceFieldAsset(file, field, stream, storage) {
129
+ const format = field.type === 'array' ? field.items.format : field.format;
130
+ /* c8 ignore next 3 */
131
+ if (format !== 'asset') {
132
+ throw new Error(`${field} is not an attachable field for ${file}`);
133
+ }
134
+ const filename = stream.filename || field.name;
135
+ return savePieceAsset(file, filename, stream.stream, storage);
136
+ }
134
137
  function isAttachableStream(value) {
135
138
  return (typeof value === 'object' &&
136
139
  value !== null &&
@@ -163,5 +166,5 @@ async function makePieceValue(field, value) {
163
166
  }
164
167
  return value;
165
168
  }
166
- export { calculateHashFromFile, isAttachableStream, makePieceAttachment, makePieceValue, detectStreamFileType, };
169
+ export { calculateHashFromFile, isAttachableStream, savePieceFieldAsset, makePieceValue, detectStreamFileType, savePieceAsset, };
167
170
  //# sourceMappingURL=piece.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"piece.js","sourceRoot":"","sources":["../../../../src/pieces/utils/piece.ts"],"names":[],"mappings":"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","sourcesContent":["import { stat } from 'fs/promises'\nimport { createHash } from 'crypto'\nimport { Readable } from 'stream'\nimport { createReadStream } from 'fs'\nimport { pipeline } from 'stream/promises'\nimport path from 'path'\nimport { fileTypeFromBuffer } from 'file-type'\nimport got from 'got'\nimport { PieceFrontmatterSchemaField, PieceFrontMatterValue } from './frontmatter.js'\nimport LuzzleStorage from '../../storage/abstract.js'\nimport { ASSETS_DIRECTORY } from '../assets.js'\n\ntype AttachableStream = { stream: Readable; filename?: string }\n\nasync function downloadToStream(fileOrUrl: string): Promise<AttachableStream> {\n\tif (/https?:\\/\\//i.test(fileOrUrl)) {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst download = got.stream(fileOrUrl, {\n\t\t\t\tthrowHttpErrors: false,\n\t\t\t\theaders: {\n\t\t\t\t\t'user-agent': 'luzzle/core (https://github.com/eleith/luzzle)',\n\t\t\t\t},\n\t\t\t\tretry: {\n\t\t\t\t\tlimit: 3,\n\t\t\t\t\tmethods: ['GET'],\n\t\t\t\t},\n\t\t\t\ttimeout: {\n\t\t\t\t\trequest: 10000,\n\t\t\t\t},\n\t\t\t})\n\t\t\tdownload.on('error', (err) => {\n\t\t\t\tconsole.error(`Error downloading file from ${fileOrUrl}: ${err.message}`)\n\t\t\t\treject(err)\n\t\t\t})\n\t\t\tdownload.on('response', (response) => {\n\t\t\t\tif (response.statusCode >= 400) {\n\t\t\t\t\tconsole.error(`Error downloading file from ${fileOrUrl}: http ${response.statusCode}`)\n\t\t\t\t\treject(new Error(`HTTP Error: ${response.statusCode}`))\n\t\t\t\t} else {\n\t\t\t\t\tconst filename = path.basename(new URL(fileOrUrl).pathname)\n\t\t\t\t\tresolve({ stream: download, filename })\n\t\t\t\t}\n\t\t\t})\n\t\t})\n\t}\n\n\tconst file = fileOrUrl\n\tconst fileStat = await stat(file).catch(() => null)\n\n\tif (fileStat && fileStat.isFile()) {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst stream = createReadStream(file)\n\t\t\tstream.on('error', (err) => {\n\t\t\t\tconsole.error(`Error reading file from path: ${err.message}`)\n\t\t\t\treject(err)\n\t\t\t})\n\t\t\tstream.on('open', () => {\n\t\t\t\tconst filename = path.basename(file)\n\t\t\t\tresolve({ stream, filename })\n\t\t\t})\n\t\t})\n\t}\n\n\tthrow new Error(`${fileOrUrl} is not a valid file`)\n}\n\nfunction calculateHashFromFile(stream: Readable): Promise<string> {\n\tconst hash = createHash('md5')\n\n\treturn new Promise((resolve, reject) => {\n\t\tstream.on('error', (err) => {\n\t\t\tconsole.error(`Error calculating hash from stream: ${err.message}`)\n\t\t\treject(err)\n\t\t})\n\t\tstream.on('data', (data) => hash.update(data))\n\t\tstream.on('end', () => resolve(hash.digest('hex')))\n\t})\n}\n\nasync function detectStreamFileType(stream: Readable, maxBytes = 4100) {\n\tconst iterator = stream[Symbol.asyncIterator]()\n\tconst chunks: Buffer[] = []\n\tlet length = 0\n\tlet done = false\n\n\twhile (length < maxBytes) {\n\t\tconst next = await iterator.next()\n\t\tif (next.done) {\n\t\t\tdone = true\n\t\t\tbreak\n\t\t}\n\t\tconst chunk = Buffer.isBuffer(next.value) ? next.value : Buffer.from(next.value)\n\t\tchunks.push(chunk)\n\t\tlength += chunk.length\n\t}\n\n\tconst buffer = Buffer.concat(chunks)\n\tconst type = await fileTypeFromBuffer(buffer)\n\n\tasync function* gen() {\n\t\tif (length > 0) yield buffer\n\t\tif (done) return\n\n\t\tlet next = await iterator.next()\n\t\twhile (!next.done) {\n\t\t\tyield next.value\n\t\t\tnext = await iterator.next()\n\t\t}\n\t}\n\n\treturn {\n\t\ttype,\n\t\tstream: Readable.from(gen()),\n\t}\n}\n\nasync function makePieceAttachment(\n\tfile: string,\n\tfield: PieceFrontmatterSchemaField,\n\tstream: AttachableStream,\n\tstorage: LuzzleStorage\n): Promise<string> {\n\tconst format = field.type === 'array' ? field.items.format : field.format\n\n\t/* c8 ignore next 3 */\n\tif (format !== 'asset') {\n\t\tthrow new Error(`${field} is not an attachable field for ${file}`)\n\t}\n\n\tconst pieceDir = file.replace(/\\.[^.]+$/, '')\n\tconst attachDir = path.join(ASSETS_DIRECTORY, pieceDir)\n\tconst exists = await storage.exists(attachDir)\n\tconst sourceInfo = stream.filename\n\n\tif (!exists) {\n\t\tawait storage.makeDirectory(attachDir)\n\t}\n\n\tconst { type: detectedType, stream: finalStream } = await detectStreamFileType(stream.stream)\n\n\tconst sourceBasename = sourceInfo\n\t\t? path.basename(sourceInfo, path.extname(sourceInfo))\n\t\t: field.name\n\n\tconst sourceExt = detectedType\n\t\t? '.' + detectedType.ext\n\t\t: sourceInfo\n\t\t\t? path.extname(sourceInfo)\n\t\t\t: ''\n\n\tlet relPath = path.join(attachDir, sourceBasename + sourceExt)\n\tlet counter = 2\n\n\twhile (await storage.exists(relPath)) {\n\t\trelPath = path.join(attachDir, sourceBasename + '-' + counter + sourceExt)\n\t\tcounter++\n\t}\n\n\tawait pipeline(finalStream, storage.createWriteStream(relPath))\n\n\treturn relPath\n}\n\nfunction isAttachableStream(value: unknown): value is AttachableStream {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\t'stream' in value &&\n\t\ttypeof (value as AttachableStream).stream?.pipe === 'function'\n\t)\n}\n\nasync function makePieceValue(\n\tfield: PieceFrontmatterSchemaField,\n\tvalue: PieceFrontMatterValue | AttachableStream\n): Promise<PieceFrontMatterValue | AttachableStream> {\n\tconst isArray = field.type === 'array'\n\tconst format = isArray ? field.items.format : field.format\n\tconst type = isArray ? field.items.type : field.type\n\n\tif (format === 'asset') {\n\t\tif (typeof value === 'string') {\n\t\t\tif (value.startsWith(ASSETS_DIRECTORY)) {\n\t\t\t\treturn value\n\t\t\t}\n\t\t\treturn downloadToStream(value)\n\t\t} else if (typeof value === 'number' || typeof value === 'boolean' || Array.isArray(value)) {\n\t\t\tthrow new Error(`${field} must be a string or stream`)\n\t\t} else {\n\t\t\treturn value\n\t\t}\n\t} else if (type === 'boolean') {\n\t\treturn /1|true|yes/.test(value as string)\n\t} else if (type === 'integer') {\n\t\treturn parseInt(value as string)\n\t}\n\n\treturn value\n}\n\nexport {\n\tcalculateHashFromFile,\n\tisAttachableStream,\n\tmakePieceAttachment,\n\tmakePieceValue,\n\tdetectStreamFileType,\n\ttype AttachableStream,\n}\n"]}
1
+ {"version":3,"file":"piece.js","sourceRoot":"","sources":["../../../../src/pieces/utils/piece.ts"],"names":[],"mappings":"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","sourcesContent":["import { stat } from 'fs/promises'\nimport { createHash } from 'crypto'\nimport { Readable } from 'stream'\nimport { createReadStream } from 'fs'\nimport { pipeline } from 'stream/promises'\nimport path from 'path'\nimport { fileTypeFromBuffer } from 'file-type'\nimport got from 'got'\nimport { PieceFrontmatterSchemaField, PieceFrontMatterValue } from './frontmatter.js'\nimport LuzzleStorage from '../../storage/abstract.js'\nimport { ASSETS_DIRECTORY } from '../assets.js'\n\ntype AttachableStream = { stream: Readable; filename?: string }\n\nasync function downloadToStream(fileOrUrl: string): Promise<AttachableStream> {\n\tif (/https?:\\/\\//i.test(fileOrUrl)) {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst download = got.stream(fileOrUrl, {\n\t\t\t\tthrowHttpErrors: false,\n\t\t\t\theaders: {\n\t\t\t\t\t'user-agent': 'luzzle/core (https://github.com/eleith/luzzle)',\n\t\t\t\t},\n\t\t\t\tretry: {\n\t\t\t\t\tlimit: 3,\n\t\t\t\t\tmethods: ['GET'],\n\t\t\t\t},\n\t\t\t\ttimeout: {\n\t\t\t\t\trequest: 10000,\n\t\t\t\t},\n\t\t\t})\n\t\t\tdownload.on('error', (err) => {\n\t\t\t\tconsole.error(`Error downloading file from ${fileOrUrl}: ${err.message}`)\n\t\t\t\treject(err)\n\t\t\t})\n\t\t\tdownload.on('response', (response) => {\n\t\t\t\tif (response.statusCode >= 400) {\n\t\t\t\t\tconsole.error(`Error downloading file from ${fileOrUrl}: http ${response.statusCode}`)\n\t\t\t\t\treject(new Error(`HTTP Error: ${response.statusCode}`))\n\t\t\t\t} else {\n\t\t\t\t\tconst filename = path.basename(new URL(fileOrUrl).pathname)\n\t\t\t\t\tresolve({ stream: download, filename })\n\t\t\t\t}\n\t\t\t})\n\t\t})\n\t}\n\n\tconst file = fileOrUrl\n\tconst fileStat = await stat(file).catch(() => null)\n\n\tif (fileStat && fileStat.isFile()) {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst stream = createReadStream(file)\n\t\t\tstream.on('error', (err) => {\n\t\t\t\tconsole.error(`Error reading file from path: ${err.message}`)\n\t\t\t\treject(err)\n\t\t\t})\n\t\t\tstream.on('open', () => {\n\t\t\t\tconst filename = path.basename(file)\n\t\t\t\tresolve({ stream, filename })\n\t\t\t})\n\t\t})\n\t}\n\n\tthrow new Error(`${fileOrUrl} is not a valid file`)\n}\n\nfunction calculateHashFromFile(stream: Readable): Promise<string> {\n\tconst hash = createHash('md5')\n\n\treturn new Promise((resolve, reject) => {\n\t\tstream.on('error', (err) => {\n\t\t\tconsole.error(`Error calculating hash from stream: ${err.message}`)\n\t\t\treject(err)\n\t\t})\n\t\tstream.on('data', (data) => hash.update(data))\n\t\tstream.on('end', () => resolve(hash.digest('hex')))\n\t})\n}\n\nasync function detectStreamFileType(stream: Readable, maxBytes = 4100) {\n\tconst iterator = stream[Symbol.asyncIterator]()\n\tconst chunks: Buffer[] = []\n\tlet length = 0\n\tlet done = false\n\n\twhile (length < maxBytes) {\n\t\tconst next = await iterator.next()\n\t\tif (next.done) {\n\t\t\tdone = true\n\t\t\tbreak\n\t\t}\n\t\tconst chunk = Buffer.isBuffer(next.value) ? next.value : Buffer.from(next.value)\n\t\tchunks.push(chunk)\n\t\tlength += chunk.length\n\t}\n\n\tconst buffer = Buffer.concat(chunks)\n\tconst type = await fileTypeFromBuffer(buffer)\n\n\tasync function* gen() {\n\t\tif (length > 0) yield buffer\n\t\tif (done) return\n\n\t\tlet next = await iterator.next()\n\t\twhile (!next.done) {\n\t\t\tyield next.value\n\t\t\tnext = await iterator.next()\n\t\t}\n\t}\n\n\treturn {\n\t\ttype,\n\t\tstream: Readable.from(gen()),\n\t}\n}\n\nasync function savePieceAsset(\n\tfile: string,\n\tfilename: string,\n\tstream: Readable,\n\tstorage: LuzzleStorage\n): Promise<string> {\n\tconst pieceDir = file.replace(/\\.[^.]+$/, '')\n\tconst attachDir = path.join(ASSETS_DIRECTORY, pieceDir)\n\tconst exists = await storage.exists(attachDir)\n\n\tif (!exists) {\n\t\tawait storage.makeDirectory(attachDir)\n\t}\n\n\tconst { type: detectedType, stream: finalStream } = await detectStreamFileType(stream)\n\n\tconst sourceBasename = filename\n\t\t? path.basename(filename, path.extname(filename))\n\t\t: 'attachment'\n\n\tconst sourceExt = detectedType\n\t\t? '.' + detectedType.ext\n\t\t: filename\n\t\t\t? path.extname(filename)\n\t\t\t: ''\n\n\tlet relPath = path.join(attachDir, sourceBasename + sourceExt)\n\tlet counter = 2\n\n\twhile (await storage.exists(relPath)) {\n\t\trelPath = path.join(attachDir, sourceBasename + '-' + counter + sourceExt)\n\t\tcounter++\n\t}\n\n\tawait pipeline(finalStream, storage.createWriteStream(relPath))\n\n\treturn relPath\n}\n\nasync function savePieceFieldAsset(\n\tfile: string,\n\tfield: PieceFrontmatterSchemaField,\n\tstream: AttachableStream,\n\tstorage: LuzzleStorage\n): Promise<string> {\n\tconst format = field.type === 'array' ? field.items.format : field.format\n\n\t/* c8 ignore next 3 */\n\tif (format !== 'asset') {\n\t\tthrow new Error(`${field} is not an attachable field for ${file}`)\n\t}\n\n\tconst filename = stream.filename || field.name\n\treturn savePieceAsset(file, filename, stream.stream, storage)\n}\n\nfunction isAttachableStream(value: unknown): value is AttachableStream {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\t'stream' in value &&\n\t\ttypeof (value as AttachableStream).stream?.pipe === 'function'\n\t)\n}\n\nasync function makePieceValue(\n\tfield: PieceFrontmatterSchemaField,\n\tvalue: PieceFrontMatterValue | AttachableStream\n): Promise<PieceFrontMatterValue | AttachableStream> {\n\tconst isArray = field.type === 'array'\n\tconst format = isArray ? field.items.format : field.format\n\tconst type = isArray ? field.items.type : field.type\n\n\tif (format === 'asset') {\n\t\tif (typeof value === 'string') {\n\t\t\tif (value.startsWith(ASSETS_DIRECTORY)) {\n\t\t\t\treturn value\n\t\t\t}\n\t\t\treturn downloadToStream(value)\n\t\t} else if (typeof value === 'number' || typeof value === 'boolean' || Array.isArray(value)) {\n\t\t\tthrow new Error(`${field} must be a string or stream`)\n\t\t} else {\n\t\t\treturn value\n\t\t}\n\t} else if (type === 'boolean') {\n\t\treturn /1|true|yes/.test(value as string)\n\t} else if (type === 'integer') {\n\t\treturn parseInt(value as string)\n\t}\n\n\treturn value\n}\n\nexport {\n\tcalculateHashFromFile,\n\tisAttachableStream,\n\tsavePieceFieldAsset,\n\tmakePieceValue,\n\tdetectStreamFileType,\n\tsavePieceAsset,\n\ttype AttachableStream,\n}\n"]}