@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.
@@ -1,3 +1,4 @@
1
+ import { ProjectDocuments } from './documents';
1
2
  import { ProjectHistory } from './history';
2
3
  import { Recipes } from './recipes';
3
4
  import { ExecutionEntity, ExecutionSuscriptionReturnType } from '../types/execution';
@@ -631,6 +632,12 @@ export declare class EngineServicesClient {
631
632
  * @param onUpdateCallback - Callback invoked on each progress/result event.
632
633
  */
633
634
  onExecutionProgress(executionId: string, onUpdateCallback: (data: ExecutionSuscriptionReturnType) => void): Promise<void>;
635
+ /**
636
+ * A project's documents. Every document is a FOLDER holding its files plus
637
+ * a `document.json` descriptor naming the document, its native form and its
638
+ * renderable views. See `src/core/documents.ts` for the model and schema.
639
+ */
640
+ documents(projectId: string): ProjectDocuments;
634
641
  /**
635
642
  * A project's history of connected documents (Revit models, AutoCAD
636
643
  * drawings…): their version timelines and their change requests. See
@@ -0,0 +1,59 @@
1
+ import { EngineServicesClient } from './client';
2
+
3
+ /** One renderable representation of a document. */
4
+ export interface DocumentView {
5
+ /** The view file's item id — ids survive renames, names do not. */
6
+ fileId: string;
7
+ /** Lowercase format name: 'frag', 'ifc', 'potree', 'pdf'… */
8
+ format: string;
9
+ }
10
+ /** The wire shape of `document.json`, schema `thatopen/document@1`. */
11
+ export interface DocumentDescriptor {
12
+ schema: typeof DOCUMENT_SCHEMA;
13
+ /** The document's own name — what a row shows. Not any file's name. */
14
+ name: string;
15
+ /**
16
+ * The native form, when the document has one (a .rvt, a .3dm). A document
17
+ * born on the platform (a loose .frag) may not.
18
+ */
19
+ native?: {
20
+ fileId: string;
21
+ format: string;
22
+ };
23
+ /** The renderable representations, in no particular order. */
24
+ views: DocumentView[];
25
+ }
26
+ export declare const DOCUMENT_SCHEMA = "thatopen/document@1";
27
+ export declare const DOCUMENT_FILE = "document.json";
28
+ /**
29
+ * Documents of one project. Get it from {@link EngineServicesClient.documents}.
30
+ * Every method takes the document's FOLDER id — the id interfaces know the
31
+ * document by.
32
+ */
33
+ export declare class ProjectDocuments {
34
+ #private;
35
+ private readonly client;
36
+ readonly projectId: string;
37
+ constructor(client: EngineServicesClient, projectId: string);
38
+ /**
39
+ * The document's descriptor, read and validated, or null when the folder
40
+ * has none yet (an old folder, or a plain folder that is not a document).
41
+ */
42
+ descriptor(folderId: string): Promise<DocumentDescriptor | null>;
43
+ /**
44
+ * The first view whose format appears in `formats` — searched in the ORDER
45
+ * OF THE LIST, so the caller's preference wins (ask `['frag', 'ifc']` and a
46
+ * document carrying both answers the frag). Null when none matches: that is
47
+ * where an interface offers "Process".
48
+ */
49
+ view(folderId: string, formats: string[]): Promise<DocumentView | null>;
50
+ /**
51
+ * Registers a renderable representation — a processor's last act. One view
52
+ * per format: an existing view of the same format is replaced (a re-run
53
+ * processor updates, it does not accumulate). The descriptor must exist;
54
+ * create it first with {@link setDescriptor}.
55
+ */
56
+ addView(folderId: string, view: DocumentView): Promise<void>;
57
+ /** Writes the descriptor, creating or replacing `document.json`. */
58
+ setDescriptor(folderId: string, descriptor: Omit<DocumentDescriptor, 'schema'> & Partial<Pick<DocumentDescriptor, 'schema'>>): Promise<void>;
59
+ }
@@ -1,4 +1,5 @@
1
1
  import { EngineServicesClient } from './client';
2
+ import { DocumentDescriptor, DocumentView } from './documents';
2
3
 
3
4
  /** One element mutation inside a version. Wire-compatible with the plugins. */
4
5
  export interface FlowChange {
@@ -53,6 +54,13 @@ export interface FlowVersion {
53
54
  */
54
55
  export interface FlowSuggestion {
55
56
  opId: string;
57
+ /**
58
+ * The application that receives and executes it: 'revit', 'autocad', or a
59
+ * platform app like 'designer'. A suggestion without a recipient is not a
60
+ * suggestion; absent only in entries written before this field existed,
61
+ * where the recipient is the document's own source.
62
+ */
63
+ to?: string;
56
64
  /** Groups the suggestions one authored action produced across several docs. */
57
65
  batchId?: string;
58
66
  /** Hidden-file id of the payload .frag (envelope `revitflow/op@2`). */
@@ -81,6 +89,11 @@ export interface FlowDocInfo {
81
89
  source: string;
82
90
  /** The document's own id within that application. */
83
91
  docId: string;
92
+ /**
93
+ * The document folder's item id — the id the CDE and the documents API
94
+ * ({@link EngineServicesClient.documents}) know this document by.
95
+ */
96
+ folderId: string;
84
97
  /** The visible model file's name, when one exists yet. */
85
98
  modelName?: string;
86
99
  /**
@@ -91,6 +104,19 @@ export interface FlowDocInfo {
91
104
  */
92
105
  empty?: boolean;
93
106
  }
107
+ /**
108
+ * One person's current hold on a document's elements, read from the lock
109
+ * registry the native plugins arbitrate through. Element keys are the native
110
+ * application's own ids (Revit UniqueIds). Workset-level ownership lives in
111
+ * Revit's own binary worksharing files (the ownership mirror) and is not
112
+ * readable here — what IS here is every element-level claim.
113
+ */
114
+ export interface FlowOwner {
115
+ /** The native application's user name, as the plugin claimed with. */
116
+ owner: string;
117
+ /** The element keys this person currently holds, arbitration applied. */
118
+ elements: string[];
119
+ }
94
120
  /** What `sync` needs: the change list plus whatever the writer knows. */
95
121
  export interface SyncInput {
96
122
  author: string;
@@ -114,6 +140,11 @@ export interface SyncInput {
114
140
  }
115
141
  /** What `suggest` needs. */
116
142
  export interface SuggestInput {
143
+ /**
144
+ * The application that receives and executes it. Defaults to the document's
145
+ * own source — the native app that owns the document.
146
+ */
147
+ to?: string;
117
148
  /**
118
149
  * The suggestion's id, when the caller minted it up front — a payload
119
150
  * (envelope `revitflow/op@2`) carries the opId INSIDE, so whoever builds
@@ -178,6 +209,33 @@ export declare class FlowDoc {
178
209
  delta(version: FlowVersion): Promise<Blob>;
179
210
  /** The visible model .frag as last fully exported. */
180
211
  model(): Promise<Blob>;
212
+ /** The document folder's item id — the id the CDE knows this document by. */
213
+ folderId(): Promise<string>;
214
+ /**
215
+ * The document descriptor (`document.json`), or null when the folder does
216
+ * not carry one yet — an old folder from before descriptors existed.
217
+ */
218
+ descriptor(): Promise<DocumentDescriptor | null>;
219
+ /**
220
+ * The first view whose format appears in `formats`, searched in the order
221
+ * of the list (the caller's preference wins). Falls back to the visible
222
+ * model .frag on a descriptor-less folder, so old documents keep viewing.
223
+ */
224
+ view(formats: string[]): Promise<DocumentView | null>;
225
+ /**
226
+ * Registers a renderable representation, creating the descriptor when the
227
+ * folder predates them (named after the model file, or the folder itself).
228
+ * One view per format: a same-format view is replaced, not accumulated.
229
+ */
230
+ addView(view: DocumentView): Promise<void>;
231
+ /**
232
+ * Who currently holds which elements, read from the lock registry the
233
+ * native plugins arbitrate through. Read-only: claiming and releasing stay
234
+ * with the plugins. Empty when nobody holds anything (or the document has
235
+ * no lock anchor yet). Arbitration is applied: a key contested by two
236
+ * claims counts only for the earliest one, matching the plugins' rule.
237
+ */
238
+ ownership(): Promise<FlowOwner[]>;
181
239
  /**
182
240
  * Appends one version: uploads the geometry it carries, then the updated
183
241
  * history. Give `expectedLatestGuid` whenever you built on a head you read,
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Authors an interoperability OPERATION — a set of deferred edits for one
3
+ * document — and hands back the bytes to upload as a suggestion's payload.
4
+ *
5
+ * WHY THIS EXISTS AND WHY IT LOOKS LIKE THIS. An operation is carried as a
6
+ * .frag with no geometry at all: the envelope in `Model.metadata`, and one
7
+ * geometry-less item per change whose attributes ARE the change. That was
8
+ * cheap on the C# side, which already had a writer, and it is the reason a
9
+ * converter had to be a console tool once: nothing in the browser could
10
+ * produce one. So the format stayed, and this builds it here instead.
11
+ *
12
+ * Nothing above this class needs to know any of that. You say add / set /
13
+ * remove and get bytes for {@link FlowDoc.suggest} or a recipe's result.
14
+ *
15
+ * WHAT IT DOES NOT DO. It does not translate. Attributes are written exactly
16
+ * as given, in the TARGET application's own terms and units, because data
17
+ * that gets translated on the way in has to be untranslated on the way out
18
+ * and the day somebody forgets a field nothing complains. Deciding what a
19
+ * Rhino layer means in Revit is the recipe's job; this only carries the
20
+ * answer.
21
+ *
22
+ * DEPENDENCIES, loaded at build() time and declared as OPTIONAL PEERS:
23
+ * `@thatopen/fragments` (the .frag schema) and `flatbuffers`. An app that
24
+ * authors operations has both already; everything else in this package works
25
+ * without them.
26
+ */
27
+ /** The schema this writes. An applier that speaks a different one must refuse rather than guess. */
28
+ export declare const OP_SCHEMA = "revitflow/op@2";
29
+ export interface OperationTarget {
30
+ /** Platform project id. */
31
+ project: string;
32
+ /** Document name within the project — the model these edits are for. */
33
+ document: string;
34
+ /**
35
+ * The commit this was authored against. The elements named here existed
36
+ * then; by the time somebody applies it they may not, and the applier
37
+ * reports what it could not resolve.
38
+ */
39
+ baseCommit: number;
40
+ /** Who authored it, for the history. */
41
+ author?: string;
42
+ /** Platform user id, so the same person is not two names depending on which tool wrote it. */
43
+ userId?: string;
44
+ /** Groups the operations one authored action produced across several models. */
45
+ batchId?: string;
46
+ title?: string;
47
+ }
48
+ /** Where an added item goes, and how it is turned, in the target's own terms. */
49
+ export interface Placement {
50
+ /** [x, y, z] in the TARGET model's own units and axes. Not converted here. */
51
+ position?: [number, number, number];
52
+ /** Degrees about Z, in the target's convention. */
53
+ rotationDeg?: number;
54
+ /**
55
+ * The id of the object that caused this change, in the AUTHOR's own terms —
56
+ * a Rhino guid, a row of a spreadsheet, whatever proposed it. Optional, and
57
+ * only useful to whoever wrote it: pass it when you expect to come back and
58
+ * find what you created.
59
+ */
60
+ source?: string;
61
+ }
62
+ export declare class OperationBuilder {
63
+ private readonly target;
64
+ private readonly changes;
65
+ constructor(target: OperationTarget);
66
+ /** How many changes are queued. An operation with none is refused by `build`. */
67
+ get length(): number;
68
+ get batchId(): string | undefined;
69
+ get title(): string;
70
+ get author(): string;
71
+ get userId(): string | undefined;
72
+ get baseCommit(): number;
73
+ /**
74
+ * Create something. There is no id yet: the attributes describe what it is,
75
+ * the placement says where it goes, and the operation answers with the id
76
+ * it got.
77
+ */
78
+ add(attrs: Record<string, string>, placement?: Placement): this;
79
+ /** Write attributes onto an item that already exists, named by the id the target published. */
80
+ set(item: string, attrs: Record<string, string>, placement?: Placement): this;
81
+ /** Delete an item. Whatever the target cascades along with it is reported, not guessed at here. */
82
+ remove(item: string): this;
83
+ /**
84
+ * A label for what this operation mostly does. Derived, never read to
85
+ * decide anything: one operation may add, set and remove at once and still
86
+ * be atomic, so what each change does is written on the change.
87
+ */
88
+ get summary(): 'add' | 'set' | 'remove' | 'mixed';
89
+ /**
90
+ * The .frag bytes, zlib-deflated, ready to upload as the operation's
91
+ * payload.
92
+ *
93
+ * `opId` is taken rather than generated so the caller can put the same id
94
+ * in the queue entry it writes next ({@link Recipes} mints it before the
95
+ * run); an id this class invented and did not return would have to be dug
96
+ * back out of the bytes.
97
+ */
98
+ build(opId: string): Promise<Uint8Array>;
99
+ /** Placement rides in the attributes, in the same string form the target published. */
100
+ private pack;
101
+ private requireId;
102
+ /**
103
+ * The buffer itself.
104
+ *
105
+ * Laid out exactly as the C# writer lays it out, because the add-in's
106
+ * reader is the one that has to accept both: items first and the container
107
+ * after, ids handed out by one monotonic counter, attributes as
108
+ * `[name, value, type]` JSON triples, and a Meshes table that exists but is
109
+ * empty.
110
+ *
111
+ * Empty rather than absent: the reader asks for it unconditionally, and a
112
+ * model that draws nothing is still a model. Nothing here gets a sample —
113
+ * an item with no triangles must not have one, because a sample's bounding
114
+ * box would then have no size and the reader turns a box into a "dimension"
115
+ * and rejects a falsy one.
116
+ */
117
+ private flatbuffer;
118
+ }