From fb8975ccb076aa25e6bf6d13f360392e3af4521c Mon Sep 17 00:00:00 2001 From: August Cayzer Date: Mon, 26 Oct 2026 01:31:47 +0000 Subject: [PATCH] docs(catalog): add the Collection type page --- content/docs/(overview)/glossary.mdx | 2 +- .../catalog/(types)/(core)/collection.mdx | 32 +++++++++++++++++++ content/docs/catalog/(types)/(core)/meta.json | 1 + src/generated/GLOSSARY.md | 2 +- src/generated/catalog/builtin-catalog.json | 27 ++++++++++++++++ src/generated/catalog/core.collection.md | 15 +++++++++ src/generated/catalog/types.md | 23 ++++++------- src/generated/contract-index.json | 5 +-- src/lib/docs-map.test.ts | 2 +- 9 files changed, 93 insertions(+), 16 deletions(-) create mode 100644 content/docs/catalog/(types)/(core)/collection.mdx create mode 100644 src/generated/catalog/core.collection.md diff --git a/content/docs/(overview)/glossary.mdx b/content/docs/(overview)/glossary.mdx index a6e16203..2d060240 100644 --- a/content/docs/(overview)/glossary.mdx +++ b/content/docs/(overview)/glossary.mdx @@ -20,7 +20,7 @@ Marfa uses each word below in one sense only, in its code, its API and these doc | [**reverse name**](/properties-metadata-and-edges#edges) | An edge's name read from its target: `child-of` for `parent-of`. | | [**label**](/properties-metadata-and-edges#edges) | The heading a type or an edge type shows for itself. An edge type's label heads the source's end of an edge, such as `Children` for `parent-of`. | | [**reverse label**](/properties-metadata-and-edges#edges) | The heading an edge type shows for the target's end, such as `Parent`. Where an edge type names none, its label names both ends. | -| [**collection**](/catalog/edges) | A flat container of items. An item joins one through an `in-collection` edge to an item whose type has the `container` role, such as an album. An item can be in many, a container can't itself be a member, and deleting the container leaves its members. | +| [**collection**](/catalog/edges) | A flat container of items. An item joins one through an `in-collection` edge to an item whose type has the `container` role, such as a [`core.collection`](/catalog/collection) or an album. An item can be in many, a container can't itself be a member, and deleting the container leaves its members. | | [**view**](/build/save-a-view) | A saved query with one sort and one grouping, kept on the instance as a `system.view` and shared by every app. How an app draws the items is the app's own. | | [**file**](/files) | An item that names its bytes. | | [**blob**](/files) | A file's bytes, stored once under a hash of their content. | diff --git a/content/docs/catalog/(types)/(core)/collection.mdx b/content/docs/catalog/(types)/(core)/collection.mdx new file mode 100644 index 00000000..fb0c5425 --- /dev/null +++ b/content/docs/catalog/(types)/(core)/collection.mdx @@ -0,0 +1,32 @@ +--- +title: Collection +description: "Items of any type that you gather together. Members join it through the in-collection edge, and it can hold any item but another container." +identifier: core.collection +--- + +src/generated/catalog/core.collection.md + +## Example + +```json +{ + "type": "core.collection", + "properties": { + "title": "Kitchen renovation", + "description": "Quotes, sketches and the tasks still to book." + } +} +``` + +An item joins the collection through an [`in-collection`](/catalog/edges#in-collection) edge from the item to the collection, with an optional `position`: + +```json +{ + "source_id": "01a12313-ad0e-71cd-99b4-7a176c5a9f18", + "target_id": "01a12314-0b52-7c41-8e0f-2d6f1a3b9c07", + "edge_type": "in-collection", + "properties": { "position": 1 } +} +``` + +A container, such as another collection or an album, can't be a member. An item can be in any number of collections, and deleting a collection leaves its members in place. diff --git a/content/docs/catalog/(types)/(core)/meta.json b/content/docs/catalog/(types)/(core)/meta.json index 29341cd0..af69d297 100644 --- a/content/docs/catalog/(types)/(core)/meta.json +++ b/content/docs/catalog/(types)/(core)/meta.json @@ -3,6 +3,7 @@ "defaultOpen": false, "pages": [ "bookmark", + "collection", "entity", "event", "file", diff --git a/src/generated/GLOSSARY.md b/src/generated/GLOSSARY.md index 7c676fa0..bee225a7 100644 --- a/src/generated/GLOSSARY.md +++ b/src/generated/GLOSSARY.md @@ -141,7 +141,7 @@ Access is read the same way wherever a person sees it: on the pages where they a | **placement** | Where an item's file sits in a folder: its `in-folder` edge to the folder's `system.folder`, whose `path` names the file from the folder's root. It never decides what a folder holds, and it is never written in a file. | | **registry** | The folder registry: one file on a machine listing its folders, each by its directory and the `system.folder` it follows, so each folder can find the others and a file moved or copied between two of them is told apart. It is never a folder's store, and `MARFA_FOLDER_REGISTRY` names another file in its place. The type registry is the server's catalog of types (`types.md`). | | **embed** | A file an item's body shows inside it, `![](path)` or `![[file]]`: that file item's `attached-to` edge to the item, in a folder's Markdown file and in a body written through a working copy alike. In a folder, the file's `has-attachment` line lists only what the body does not embed, and an embedded file is put where the link says, any other attachment beside the document. It names a file where a file answers to it or its extension names a MIME type; anything else, `![[A note]]` say, is an embed of a note, text in the body and neither a link nor an edge. | -| **collection** | A container and its members: an item whose type declares the `container` role, such as an album or a series, and the items joined to it by an `in-collection` edge, each with an optional `position`. Flat: a container is never a member, `parent-of` is what hierarchy is for, and deleting the container leaves its members. Not a folder and not a view. | +| **collection** | A container and its members: an item whose type declares the `container` role, such as `core.collection`, an album or a series, and the items joined to it by an `in-collection` edge, each with an optional `position`. Flat: a container is never a member, `parent-of` is what hierarchy is for, and deleting the container leaves its members. Not a folder and not a view. | | **frontmatter** | The block of `key: value` lines a Markdown file in a folder opens with between `---` fences. Its `type`, `tier`, `tags`, `state` and `occurred_at` lines are the item's own fields; `marfa_id` and `marfa_version` name the item and the version the file was written from; a line named for an edge type or a reverse name is an edge's, written in the one file at the end the type names and naming its targets as `"[[name]]"` or `"[[]]"`; every other line is a property. The file's body is the property its type's `body_field` names. Never "header". | ### Connectors diff --git a/src/generated/catalog/builtin-catalog.json b/src/generated/catalog/builtin-catalog.json index d03ba4e0..6f120498 100644 --- a/src/generated/catalog/builtin-catalog.json +++ b/src/generated/catalog/builtin-catalog.json @@ -64,6 +64,33 @@ "default": "last_writer_wins" } }, + { + "id": "core.collection", + "label": "Collection", + "description": "Items of any type that you gather together. Members join it through the in-collection edge, and it can hold any item but another container.", + "version": 0, + "fields": { + "title": { + "type": "string", + "description": "Name of the collection", + "required": true + }, + "description": { + "type": "string", + "description": "What the collection gathers" + } + }, + "display_hints": { + "title_field": "title", + "body_field": "description" + }, + "merge_policy": { + "default": "last_writer_wins" + }, + "roles": [ + "container" + ] + }, { "id": "core.entity", "label": "Entity", diff --git a/src/generated/catalog/core.collection.md b/src/generated/catalog/core.collection.md new file mode 100644 index 00000000..f9638f4e --- /dev/null +++ b/src/generated/catalog/core.collection.md @@ -0,0 +1,15 @@ +## Fields + +| Field | Kind | Required | Description | +| ------------- | -------- | -------- | --------------------------- | +| `title` | `string` | Yes | Name of the collection | +| `description` | `string` | No | What the collection gathers | + +## Settings + +| Setting | Value | +| ------------------------------------------------------ | ---------------------------------- | +| [`title_field`](/catalog/your-own-types#fields) | `title` | +| [`body_field`](/catalog/your-own-types#fields) | `description` | +| [`merge_policy`](/catalog/your-own-types#merge-policy) | `last_writer_wins` for every field | +| [`roles`](/catalog/your-own-types#roles) | `container` | diff --git a/src/generated/catalog/types.md b/src/generated/catalog/types.md index 3af02f8c..f5e6cfe4 100644 --- a/src/generated/catalog/types.md +++ b/src/generated/catalog/types.md @@ -1,16 +1,17 @@ ## Core types -| Type | Description | Subtypes | -| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [`core.bookmark`](/catalog/bookmark) | Content you captured from elsewhere: a saved URL, a highlight, an excerpt, a clipped paragraph. | | -| [`core.entity`](/catalog/entity) | Any named entity: a person, a company, a band, a team, a charity, a brand, a school or a place. `core.entity.person` and `core.entity.place` narrow it. | [`person`](/catalog/entity#core-entity-person), [`place`](/catalog/entity#core-entity-place) | -| [`core.event`](/catalog/event) | Something that happens at a time. | | -| [`core.file`](/catalog/file) | A file or binary reference: the generic fallback for any file that has no more specific type. | [`audio`](/catalog/file#core-file-audio), [`image`](/catalog/file#core-file-image), [`video`](/catalog/file#core-file-video) | -| [`core.highlight`](/catalog/highlight) | A user's engagement with content: the highlighted passage plus optional annotation. The canonical relationship (what was highlighted) is carried by a references edge; the moment of highlighting is the item's own `occurred_at`. | | -| [`core.media`](/catalog/media) | Content produced by someone that the user engages with: a film, podcast, book, article, song, show. | [`album`](/catalog/media#core-media-album), [`article`](/catalog/media#core-media-article), [`book`](/catalog/media#core-media-book), [`episode`](/catalog/media#core-media-episode), [`film`](/catalog/media#core-media-film), [`series`](/catalog/media#core-media-series), [`song`](/catalog/media#core-media-song) | -| [`core.message`](/catalog/message) | A light, cross-platform message. Threading is edge-based via in-thread; reply trees via parent-of. Tool-specific richness lives in app namespaces. | | -| [`core.note`](/catalog/note) | Text content you created. | | -| [`core.task`](/catalog/task) | Something to be done. | | +| Type | Description | Subtypes | +| ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [`core.bookmark`](/catalog/bookmark) | Content you captured from elsewhere: a saved URL, a highlight, an excerpt, a clipped paragraph. | | +| [`core.collection`](/catalog/collection) | Items of any type that you gather together. Members join it through the in-collection edge, and it can hold any item but another container. | | +| [`core.entity`](/catalog/entity) | Any named entity: a person, a company, a band, a team, a charity, a brand, a school or a place. `core.entity.person` and `core.entity.place` narrow it. | [`person`](/catalog/entity#core-entity-person), [`place`](/catalog/entity#core-entity-place) | +| [`core.event`](/catalog/event) | Something that happens at a time. | | +| [`core.file`](/catalog/file) | A file or binary reference: the generic fallback for any file that has no more specific type. | [`audio`](/catalog/file#core-file-audio), [`image`](/catalog/file#core-file-image), [`video`](/catalog/file#core-file-video) | +| [`core.highlight`](/catalog/highlight) | A user's engagement with content: the highlighted passage plus optional annotation. The canonical relationship (what was highlighted) is carried by a references edge; the moment of highlighting is the item's own `occurred_at`. | | +| [`core.media`](/catalog/media) | Content produced by someone that the user engages with: a film, podcast, book, article, song, show. | [`album`](/catalog/media#core-media-album), [`article`](/catalog/media#core-media-article), [`book`](/catalog/media#core-media-book), [`episode`](/catalog/media#core-media-episode), [`film`](/catalog/media#core-media-film), [`series`](/catalog/media#core-media-series), [`song`](/catalog/media#core-media-song) | +| [`core.message`](/catalog/message) | A light, cross-platform message. Threading is edge-based via in-thread; reply trees via parent-of. Tool-specific richness lives in app namespaces. | | +| [`core.note`](/catalog/note) | Text content you created. | | +| [`core.task`](/catalog/task) | Something to be done. | | ## System types diff --git a/src/generated/contract-index.json b/src/generated/contract-index.json index 1a8fbbd9..9507eb66 100644 --- a/src/generated/contract-index.json +++ b/src/generated/contract-index.json @@ -1385,7 +1385,7 @@ "edges/folder-revoked-keeps": "a966fa8e996ecd70", "edges/folder-place": "b4c7a00e6469018b", "edges/folder-blind": "bff04a27c6aed303", - "edges/collection-target": "b25dcc6ec5dff1ba", + "edges/collection-target": "9f825815a5cf2672", "edges/collection-no-nesting": "11e27fb49df9d0d0", "edges/collection-no-nesting-others": "c26b7617cbec51ad", "edges/cascade-parent-of": "5f8cce4a86abc3c7", @@ -5294,9 +5294,10 @@ "types/source-filter": "4cb80605ef5eb54c", "types/source-filter-missing-source": "ffaa4dc35611173f", "types/source-filter-by-id": "6617d24512e658f0", - "types/shipped": "a3d618d635c669ae", + "types/shipped": "d329bfef050dc7d6", "types/shipped-system": "aa1b148e069da6e4", "types/message": "b7749ce97bb970c1", + "types/collection": "9b963e89e951391b", "types/body-optional": "6dcf4daee3e74bd6", "types/highlight": "14a1b11a8d1a648f", "types/entity": "699d3bbbab2cdc19", diff --git a/src/lib/docs-map.test.ts b/src/lib/docs-map.test.ts index 702250dc..efd245e2 100644 --- a/src/lib/docs-map.test.ts +++ b/src/lib/docs-map.test.ts @@ -48,7 +48,7 @@ describe('buildDocsMap', () => { '- Items]', '- Types]', ' - Core types', - ...['Bookmark', 'Entity', 'Event', 'File', 'Highlight', 'Media', 'Message', 'Note', 'Task'].map((title) => ` - ${title}]`), + ...['Bookmark', 'Collection', 'Entity', 'Event', 'File', 'Highlight', 'Media', 'Message', 'Note', 'Task'].map((title) => ` - ${title}]`), ' - System types', ...['Connection', 'Folder', 'View'].map((title) => ` - ${title}]`), ' - Type rules]',