@thatopen/services 0.22.0 → 0.24.0

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.
@@ -352,14 +352,49 @@ is the reply. The full walkthrough (typed contracts, collaboration events,
352
352
  presence) is `node_modules/@thatopen/services/src/core/examples/channel.ts`,
353
353
  indexed in the client API index you already loaded.
354
354
 
355
- ## 5c. History and recipes: documents, versions, change requests
355
+ ## 5c. Documents: every document is a folder
356
+
357
+ A DOCUMENT is the platform's unit of content — what a person sees as one file
358
+ in the CDE. It is stored as a FOLDER holding its actual files plus a
359
+ `document.json` descriptor (schema `thatopen/document@1`):
360
+
361
+ ```json
362
+ {
363
+ "schema": "thatopen/document@1",
364
+ "name": "Clinic building",
365
+ "native": { "fileId": "<id>", "format": "rvt" },
366
+ "views": [{ "fileId": "<id>", "format": "frag" }]
367
+ }
368
+ ```
369
+
370
+ `name` is the document's own name (what a row shows), `native` its native form
371
+ (optional — a document born on the platform may have none), `views` its
372
+ renderable representations, by fileId so renames do not break them. The ONE
373
+ viewer rule: a document is READY TO VISUALIZE when it has a view in a format
374
+ the viewer renders; otherwise the interface offers to PROCESS it, and the
375
+ processor's last act is `addView`. A format that views itself (a PDF) lists
376
+ the same fileId as `native` and as a view — nothing is ever deduced from
377
+ extensions. The folder is an internal detail: interfaces show one row and
378
+ apply move/rename/delete/permissions to the whole document. Plain files
379
+ uploaded outside this shape still work, with fewer abilities (`descriptor()`
380
+ returns null).
381
+
382
+ ```ts
383
+ const documents = client.documents(projectId);
384
+ const descriptor = await documents.descriptor(folderId); // null on a plain folder
385
+ const view = await documents.view(folderId, ['frag', 'ifc']); // your preference order wins
386
+ await documents.addView(folderId, { fileId, format: 'frag' }); // a processor's last act
387
+ ```
388
+
389
+ ## 5d. History and recipes: versions, change requests
356
390
 
357
391
  Three sentences hold the whole model. Every connected document (a Revit model,
358
392
  an AutoCAD drawing) has its version history: who synced, when, what changed.
359
393
  Nobody writes in somebody else's document: changes arrive as SUGGESTIONS
360
- (create/modify/delete native data) that the owner accepts or dismisses in the
361
- native app. A RECIPE is a script that writes suggestions in an application's
362
- own language, from whatever input.
394
+ (create/modify/delete native data) that a recipient application — named in the
395
+ suggestion's `to`, the document's own app by default — executes when the owner
396
+ accepts. A RECIPE is a script that writes suggestions in an application's own
397
+ language, from whatever input.
363
398
 
364
399
  ```ts
365
400
  const history = client.history(projectId);
@@ -367,6 +402,8 @@ const docs = await history.docs(); // the connected documents
367
402
  const doc = history.doc('revit', docs[0].docId);
368
403
  const timeline = await doc.timeline(); // versions, oldest first
369
404
  const pending = await doc.pendingSuggestions(); // waiting for the owner
405
+ const holders = await doc.ownership(); // who holds which elements
406
+ const view = await doc.view(['frag']); // same rule as any document
370
407
 
371
408
  client.recipes.register(myRecipe); // manifest + one run()
372
409
  await client.recipes.run('my-recipe', { // only QUEUES a suggestion:
@@ -375,13 +412,24 @@ await client.recipes.run('my-recipe', { // only QUEUES a suggestion:
375
412
  });
376
413
  ```
377
414
 
415
+ `docs()` also answers `folderId` — the id the CDE knows that document by, the
416
+ bridge between this section and 5c.
417
+
418
+ To AUTHOR a suggestion's payload, `OperationBuilder` (same import) writes the
419
+ operation .frag: `new OperationBuilder(target).add(attrs, placement)` /
420
+ `.set(id, attrs)` / `.remove(id)`, then `await builder.build(opId)` gives the
421
+ bytes for `suggest({ payload })`. Attributes go in the TARGET app's own terms
422
+ and units, untranslated. It needs the optional peers `flatbuffers` and
423
+ `@thatopen/fragments` installed (loaded only when `build()` runs — nothing
424
+ else in the package needs them).
425
+
378
426
  This surface is the only supported way in: the storage underneath is private
379
427
  and will move. Never list or write the `bimterop` files directly. The full
380
428
  walkthrough (manifest fields, StaleHistoryError on concurrent syncs, payloads)
381
429
  is `node_modules/@thatopen/services/src/core/examples/history.ts`, indexed in
382
430
  the client API index you already loaded.
383
431
 
384
- ## 5d. The desktop MCP server: `thatopen mcp`
432
+ ## 5e. The desktop MCP server: `thatopen mcp`
385
433
 
386
434
  The raw socket above is for tools you write. For an LLM on the desktop (Claude
387
435
  Desktop, Claude Code, anything that speaks MCP), the CLI ships the same bridge
package/package.json CHANGED
@@ -15,7 +15,7 @@
15
15
  "access": "public"
16
16
  },
17
17
  "private": false,
18
- "version": "0.22.0",
18
+ "version": "0.24.0",
19
19
  "main": "dist/index.cjs.js",
20
20
  "module": "dist/index.es.js",
21
21
  "types": "dist/index.d.ts",
@@ -82,16 +82,24 @@
82
82
  },
83
83
  "peerDependencies": {
84
84
  "@thatopen/components": "~3.4.0",
85
+ "@thatopen/fragments": "~3.4.0",
85
86
  "@thatopen/ui": "~3.4.0",
87
+ "flatbuffers": ">=23.0.0",
86
88
  "three": ">=0.182.0"
87
89
  },
88
90
  "peerDependenciesMeta": {
89
91
  "@thatopen/components": {
90
92
  "optional": true
91
93
  },
94
+ "@thatopen/fragments": {
95
+ "optional": true
96
+ },
92
97
  "@thatopen/ui": {
93
98
  "optional": true
94
99
  },
100
+ "flatbuffers": {
101
+ "optional": true
102
+ },
95
103
  "three": {
96
104
  "optional": true
97
105
  }