@deepseek-ai/dsh-api-workspace-controller 0.1.2-alpha.2

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.
package/lib/index.js ADDED
@@ -0,0 +1,726 @@
1
+ import { Remote, RemoteError, TypertRemoteService, remoteErrorOf } from "@deepseek-ai/dsh-typert-protocol";
2
+ import { WorkspaceId, WorkspaceMoveInvalidError, WorkspaceOrderInvalidError, WorkspaceUnknownSessionError, workspaceDomainState, workspaceRecord } from "@deepseek-ai/dsh-workspace";
3
+ import { Deque } from "@deepseek-ai/dsh-deque";
4
+ import { z } from "zod";
5
+ import { DirectoryPickerError } from "@deepseek-ai/dsh-host-directory-picker";
6
+ //#region lib/types/feed.js
7
+ /** Reconnect-safe Workspace baseline and increment producer. */
8
+ /**
9
+ * Project one authoritative Workspace entity into its Remote value.
10
+ * @param workspace - authoritative registry entity.
11
+ * @returns detached Workspace projection for Remote consumers.
12
+ */
13
+ function workspaceView(workspace) {
14
+ return {
15
+ workspaceId: workspace.id,
16
+ path: workspace.path,
17
+ title: workspace.title,
18
+ sessionIds: [...workspace.sessionIds],
19
+ createdAt: workspace.createdAt,
20
+ updatedAt: workspace.updatedAt
21
+ };
22
+ }
23
+ function changedWorkspaceView(workspaceId, value) {
24
+ const record = workspaceRecord.parse(value);
25
+ return {
26
+ workspaceId: WorkspaceId(workspaceId),
27
+ path: record.path,
28
+ title: record.title,
29
+ sessionIds: [...record.sessionIds],
30
+ createdAt: record.createdAt,
31
+ updatedAt: record.updatedAt
32
+ };
33
+ }
34
+ /** Owns Workspace domain observation and all active follow generations. */
35
+ var WorkspaceFeed = class {
36
+ ctx;
37
+ followers = /* @__PURE__ */ new Set();
38
+ knownIds;
39
+ order;
40
+ archived;
41
+ /** @param ctx - Host context containing the authoritative Workspace registry. */
42
+ constructor(ctx) {
43
+ this.ctx = ctx;
44
+ const baseline = ctx.workspaceRegistry.list();
45
+ this.knownIds = new Set(baseline.map((workspace) => String(workspace.id)));
46
+ this.order = baseline.map((workspace) => String(workspace.id));
47
+ this.archived = ctx.workspaceRegistry.archivedSessionIds.map(String);
48
+ ctx.on("domain/changed", (change) => {
49
+ this.changed(change);
50
+ });
51
+ ctx.effect(() => () => {
52
+ for (const follower of this.followers) follower.close();
53
+ this.followers.clear();
54
+ }, "workspace-controller.feed");
55
+ }
56
+ /**
57
+ * Read the complete current projection synchronously.
58
+ * @returns all active Workspaces and archived Session identities.
59
+ */
60
+ baseline() {
61
+ return {
62
+ items: this.ctx.workspaceRegistry.list().map(workspaceView),
63
+ archivedSessionIds: [...this.ctx.workspaceRegistry.archivedSessionIds]
64
+ };
65
+ }
66
+ /**
67
+ * Open one generation beginning with a complete baseline.
68
+ * @param signal - generation cancellation.
69
+ * @returns baseline followed by ordered Workspace increments.
70
+ */
71
+ async *follow(signal) {
72
+ signal.throwIfAborted();
73
+ const follower = new WorkspaceFollower();
74
+ this.followers.add(follower);
75
+ try {
76
+ yield {
77
+ type: "baseline",
78
+ value: this.baseline()
79
+ };
80
+ yield* follower.read(signal);
81
+ } finally {
82
+ this.followers.delete(follower);
83
+ follower.close();
84
+ }
85
+ }
86
+ changed(change) {
87
+ if (change.domain !== "workspace") return;
88
+ if (change.table === "") {
89
+ if (change.operation !== "put") return;
90
+ const state = workspaceDomainState.parse(change.value);
91
+ const nextOrder = state.workspaceIds.map(String);
92
+ const orderChanged = !sameStrings(this.order, nextOrder);
93
+ for (const id of state.workspaceIds) {
94
+ if (this.knownIds.has(id)) continue;
95
+ const workspace = this.ctx.workspaceRegistry.get(id);
96
+ if (workspace === void 0) throw new Error(`committed Workspace registry references missing Workspace "${id}"`);
97
+ this.knownIds.add(id);
98
+ this.publish({
99
+ type: "upsert",
100
+ workspace: workspaceView(workspace)
101
+ });
102
+ }
103
+ this.order = nextOrder;
104
+ if (orderChanged) this.publish({
105
+ type: "order",
106
+ workspaceIds: [...state.workspaceIds]
107
+ });
108
+ const nextArchived = state.archivedSessionIds.map(String);
109
+ if (!sameStrings(this.archived, nextArchived)) {
110
+ this.archived = nextArchived;
111
+ this.publish({
112
+ type: "archived",
113
+ archivedSessionIds: [...state.archivedSessionIds]
114
+ });
115
+ }
116
+ return;
117
+ }
118
+ if (change.table !== "workspaces") return;
119
+ if (change.operation === "deleted") {
120
+ if (!this.knownIds.delete(change.key)) return;
121
+ this.publish({
122
+ type: "remove",
123
+ workspaceId: WorkspaceId(change.key)
124
+ });
125
+ return;
126
+ }
127
+ if (!this.knownIds.has(change.key)) return;
128
+ this.publish({
129
+ type: "upsert",
130
+ workspace: changedWorkspaceView(change.key, change.value)
131
+ });
132
+ }
133
+ publish(frame) {
134
+ for (const follower of this.followers) follower.push(frame);
135
+ }
136
+ };
137
+ function sameStrings(left, right) {
138
+ return left.length === right.length && left.every((value, index) => value === right[index]);
139
+ }
140
+ var WorkspaceFollower = class {
141
+ frames = new Deque();
142
+ waiting;
143
+ closed = false;
144
+ push(frame) {
145
+ /* v8 ignore next -- closed followers are removed before later publication can reach them. */
146
+ if (this.closed) return;
147
+ this.frames.pushBack(frame);
148
+ this.waiting?.();
149
+ }
150
+ close() {
151
+ if (this.closed) return;
152
+ this.closed = true;
153
+ this.waiting?.();
154
+ }
155
+ async *read(signal) {
156
+ while (!this.closed && !signal.aborted) {
157
+ const frame = this.frames.popFront();
158
+ if (frame !== void 0) {
159
+ yield frame;
160
+ continue;
161
+ }
162
+ await this.wait(signal);
163
+ }
164
+ }
165
+ wait(signal) {
166
+ return new Promise((resolve) => {
167
+ const finish = () => {
168
+ signal.removeEventListener("abort", finish);
169
+ /* v8 ignore next -- one read owns the sole installed wait callback. */
170
+ if (this.waiting === finish) this.waiting = void 0;
171
+ resolve();
172
+ };
173
+ this.waiting = finish;
174
+ signal.addEventListener("abort", finish, { once: true });
175
+ /* v8 ignore next -- native signals and the private queue cannot change during this synchronous setup. */
176
+ if (signal.aborted || this.closed || this.frames.size > 0) finish();
177
+ });
178
+ }
179
+ };
180
+ //#endregion
181
+ //#region lib/types/commands.js
182
+ /** Workspace command implementation and stable Remote failure mapping. */
183
+ /** Implements Workspace mutations against the authoritative registry. */
184
+ var WorkspaceCommands = class {
185
+ ctx;
186
+ operationTail = Promise.resolve();
187
+ /** @param ctx - Host context containing the Workspace registry. */
188
+ constructor(ctx) {
189
+ this.ctx = ctx;
190
+ }
191
+ /**
192
+ * Create or resolve one Workspace over an existing directory.
193
+ * @param request - directory path to register.
194
+ * @returns the Workspace and whether this call created it.
195
+ */
196
+ create(request) {
197
+ return this.enqueue(async () => {
198
+ try {
199
+ const existing = await this.ctx.workspaceRegistry.resolveByPath(request.path);
200
+ if (existing !== void 0) return {
201
+ workspace: workspaceView(existing),
202
+ created: false
203
+ };
204
+ return {
205
+ workspace: workspaceView(await this.ctx.workspaceRegistry.create(request.path)),
206
+ created: true
207
+ };
208
+ } catch (error) {
209
+ if (remoteErrorOf(error) !== void 0) throw error;
210
+ throw new RemoteError("workspace/invalid-path", `cannot create a Workspace at "${request.path}": ${errorMessage$1(error)}`, { path: request.path }, { cause: error });
211
+ }
212
+ });
213
+ }
214
+ /**
215
+ * Rename one Workspace after serializing title ownership checks.
216
+ * @param request - Workspace identity and proposed title.
217
+ * @returns the updated Workspace projection.
218
+ */
219
+ rename(request) {
220
+ const title = request.title.trim();
221
+ if (title === "") return Promise.reject(new RemoteError("gateway/bad-request", "Workspace rename requires a non-blank title", {}));
222
+ return this.enqueue(async () => {
223
+ const workspace = this.requireWorkspace(request.workspaceId);
224
+ if (title !== workspace.title) {
225
+ if (this.ctx.workspaceRegistry.list().some((candidate) => candidate.id !== workspace.id && candidate.title === title)) throw new RemoteError("workspace/name-conflict", `Workspace name '${title}' is already in use`, { name: title });
226
+ await workspace.setTitle(title);
227
+ }
228
+ return { workspace: workspaceView(workspace) };
229
+ });
230
+ }
231
+ /**
232
+ * Delete one Workspace registration without deleting its directory or Sessions.
233
+ * @param request - Workspace identity to remove.
234
+ * @returns deletion confirmation.
235
+ */
236
+ delete(request) {
237
+ return this.enqueue(async () => {
238
+ if (!await this.ctx.workspaceRegistry.delete(WorkspaceId(request.workspaceId))) throw workspaceNotFound(request.workspaceId);
239
+ return { deleted: true };
240
+ });
241
+ }
242
+ /**
243
+ * Move one Workspace within the durable registry order.
244
+ * @param request - moved Workspace and optional anchor.
245
+ * @returns the complete resulting Workspace order.
246
+ */
247
+ async insertBefore(request) {
248
+ try {
249
+ return { workspaceIds: [...await this.ctx.workspaceRegistry.insertBefore(WorkspaceId(request.workspaceId), request.beforeWorkspaceId === void 0 ? void 0 : WorkspaceId(request.beforeWorkspaceId))] };
250
+ } catch (error) {
251
+ if (!(error instanceof WorkspaceOrderInvalidError)) throw error;
252
+ throw workspaceNotFound(error.workspaceId);
253
+ }
254
+ }
255
+ /**
256
+ * Move one accounted Session within a Workspace's manual order.
257
+ * @param request - Workspace, Session, and optional anchor identities.
258
+ * @returns the updated Workspace projection.
259
+ */
260
+ async insertSessionBefore(request) {
261
+ const workspace = this.requireWorkspace(request.workspaceId);
262
+ try {
263
+ await workspace.insertSessionBefore(request.sessionId, request.beforeSessionId);
264
+ } catch (error) {
265
+ if (!(error instanceof WorkspaceMoveInvalidError)) throw error;
266
+ throw new RemoteError("workspace/move-invalid", error.message, {
267
+ workspaceId: request.workspaceId,
268
+ sessionId: request.sessionId,
269
+ ...request.beforeSessionId === void 0 ? {} : { beforeSessionId: request.beforeSessionId }
270
+ }, { cause: error });
271
+ }
272
+ return { workspace: workspaceView(workspace) };
273
+ }
274
+ /**
275
+ * Add one known Session to the registry-global archive set.
276
+ * @param request - Session identity to archive.
277
+ * @returns the complete resulting archive set.
278
+ */
279
+ async archiveSession(request) {
280
+ try {
281
+ await this.ctx.workspaceRegistry.archiveSession(request.sessionId);
282
+ } catch (error) {
283
+ if (!(error instanceof WorkspaceUnknownSessionError)) throw error;
284
+ throw new RemoteError("session/not-found", error.message, { sessionId: request.sessionId }, { cause: error });
285
+ }
286
+ return { archivedSessionIds: [...this.ctx.workspaceRegistry.archivedSessionIds] };
287
+ }
288
+ requireWorkspace(workspaceId) {
289
+ const workspace = this.ctx.workspaceRegistry.get(WorkspaceId(workspaceId));
290
+ if (workspace === void 0) throw workspaceNotFound(workspaceId);
291
+ return workspace;
292
+ }
293
+ enqueue(operation) {
294
+ const result = this.operationTail.then(operation);
295
+ this.operationTail = result.then(() => void 0, () => void 0);
296
+ return result;
297
+ }
298
+ };
299
+ function workspaceNotFound(workspaceId) {
300
+ return new RemoteError("workspace/not-found", `Workspace "${workspaceId}" not found`, { workspaceId });
301
+ }
302
+ function errorMessage$1(error) {
303
+ return error instanceof Error ? error.message : String(error);
304
+ }
305
+ //#endregion
306
+ //#region lib/types/directory-picker.js
307
+ /**
308
+ * Host directory-picking Remote owner: capability gating, cancellation, and the
309
+ * stable wire failure vocabulary over the `ctx.directoryPicker` seam.
310
+ */
311
+ var __runInitializers$1 = function(thisArg, initializers, value) {
312
+ var useValue = arguments.length > 2;
313
+ for (var i = 0; i < initializers.length; i++) value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
314
+ return useValue ? value : void 0;
315
+ };
316
+ var __esDecorate$1 = function(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
317
+ function accept(f) {
318
+ if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected");
319
+ return f;
320
+ }
321
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
322
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
323
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
324
+ var _, done = false;
325
+ for (var i = decorators.length - 1; i >= 0; i--) {
326
+ var context = {};
327
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
328
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
329
+ context.addInitializer = function(f) {
330
+ if (done) throw new TypeError("Cannot add initializers after decoration has completed");
331
+ extraInitializers.push(accept(f || null));
332
+ };
333
+ var result = (0, decorators[i])(kind === "accessor" ? {
334
+ get: descriptor.get,
335
+ set: descriptor.set
336
+ } : descriptor[key], context);
337
+ if (kind === "accessor") {
338
+ if (result === void 0) continue;
339
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
340
+ if (_ = accept(result.get)) descriptor.get = _;
341
+ if (_ = accept(result.set)) descriptor.set = _;
342
+ if (_ = accept(result.init)) initializers.unshift(_);
343
+ } else if (_ = accept(result)) if (kind === "field") initializers.unshift(_);
344
+ else descriptor[key] = _;
345
+ }
346
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
347
+ done = true;
348
+ };
349
+ const createDirectoryRequestSchema = z.object({
350
+ path: z.string(),
351
+ name: z.string()
352
+ }).refine((request) => request.name.trim() !== "" && request.name !== "." && request.name !== ".." && !/[/\\]/.test(request.name), { message: "host.createDirectory requires a single non-blank path segment name" });
353
+ /**
354
+ * Host service backing the generated `ctx.remote.directoryPicker` namespace. The
355
+ * seam it exports is abstract and therefore never a Loader entry of its own, so
356
+ * this controller carries the wire verbs: one composed backend serves either the
357
+ * native chooser or the browse primitives, and a verb the composition cannot
358
+ * serve is refused rather than approximated.
359
+ */
360
+ let DirectoryPickerController = (() => {
361
+ let _classSuper = TypertRemoteService;
362
+ let _instanceExtraInitializers = [];
363
+ let _pick_decorators;
364
+ let _list_decorators;
365
+ let _createDirectory_decorators;
366
+ return class DirectoryPickerController extends _classSuper {
367
+ static {
368
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
369
+ _pick_decorators = [Remote("pick")];
370
+ _list_decorators = [Remote("list")];
371
+ _createDirectory_decorators = [Remote("createDirectory")];
372
+ __esDecorate$1(this, null, _pick_decorators, {
373
+ kind: "method",
374
+ name: "pick",
375
+ static: false,
376
+ private: false,
377
+ access: {
378
+ has: (obj) => "pick" in obj,
379
+ get: (obj) => obj.pick
380
+ },
381
+ metadata: _metadata
382
+ }, null, _instanceExtraInitializers);
383
+ __esDecorate$1(this, null, _list_decorators, {
384
+ kind: "method",
385
+ name: "list",
386
+ static: false,
387
+ private: false,
388
+ access: {
389
+ has: (obj) => "list" in obj,
390
+ get: (obj) => obj.list
391
+ },
392
+ metadata: _metadata
393
+ }, null, _instanceExtraInitializers);
394
+ __esDecorate$1(this, null, _createDirectory_decorators, {
395
+ kind: "method",
396
+ name: "createDirectory",
397
+ static: false,
398
+ private: false,
399
+ access: {
400
+ has: (obj) => "createDirectory" in obj,
401
+ get: (obj) => obj.createDirectory
402
+ },
403
+ metadata: _metadata
404
+ }, null, _instanceExtraInitializers);
405
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, {
406
+ enumerable: true,
407
+ configurable: true,
408
+ writable: true,
409
+ value: _metadata
410
+ });
411
+ }
412
+ static inject = ["directoryPicker"];
413
+ /** @param ctx - Host context carrying the composed directory-picking backend. */
414
+ constructor(ctx) {
415
+ super(ctx, "directoryPickerController", { namespace: "directoryPicker" });
416
+ __runInitializers$1(this, _instanceExtraInitializers);
417
+ }
418
+ /**
419
+ * Open the host's OS chooser for a Remote caller.
420
+ * @param signal - caller lifetime; abort terminates the chooser.
421
+ * @returns the chosen absolute path, or null when the operator cancels.
422
+ */
423
+ async pick(signal) {
424
+ const capability = this.requireCapability("native", "pick");
425
+ try {
426
+ return await capability.pick(signal);
427
+ } catch (error) {
428
+ throw cancellableFailure(error, signal, "directory picker was aborted", "directory picker failed");
429
+ }
430
+ }
431
+ /**
432
+ * List one directory level for a Remote caller's in-app browser.
433
+ * @param path - absolute directory to list; absent lists the home directory.
434
+ * @param signal - caller lifetime; abort stops the backend's scan instead of
435
+ * letting it outlive a disconnected caller.
436
+ * @returns the level's listing with its ancestry.
437
+ */
438
+ async list(path, signal) {
439
+ const capability = this.requireCapability("browse", "list");
440
+ try {
441
+ return await capability.list(path, signal);
442
+ } catch (error) {
443
+ throw cancellableFailure(error, signal, "directory listing was aborted");
444
+ }
445
+ }
446
+ /**
447
+ * Create one child directory for a Remote caller's in-app browser.
448
+ * @param path - absolute existing parent directory.
449
+ * @param name - single non-blank path segment.
450
+ * @returns the created directory's absolute path.
451
+ */
452
+ async createDirectory(path, name) {
453
+ const request = createDirectoryRequestSchema.safeParse({
454
+ path,
455
+ name
456
+ });
457
+ if (!request.success) throw new RemoteError("gateway/bad-request", "invalid payload for host.createDirectory", { issues: request.error.issues });
458
+ const capability = this.requireCapability("browse", "createDirectory");
459
+ try {
460
+ return await capability.createDirectory(request.data.path, request.data.name);
461
+ } catch (error) {
462
+ throw browseFailure(error);
463
+ }
464
+ }
465
+ /** Resolve the capability one wire verb needs, or refuse with the kind this backend serves. */
466
+ requireCapability(kind, method) {
467
+ const capability = this.ctx.directoryPicker.capability();
468
+ if (capability.kind !== kind) throw new RemoteError("directory-picker/unavailable", `directoryPicker.${method} needs the ${kind} capability; the composed picker serves "${capability.kind}"`, { capability: capability.kind });
469
+ return capability;
470
+ }
471
+ };
472
+ })();
473
+ /**
474
+ * Wire code answered for each seam browse failure. The seam's closed codes are
475
+ * its own local vocabulary, so this controller owns the projection onto the
476
+ * `directory-picker/*` codes a Remote caller discriminates on.
477
+ */
478
+ const BROWSE_FAILURE_CODES = {
479
+ "directory-unreadable": "directory-picker/unreadable",
480
+ "directory-exists": "directory-picker/exists",
481
+ "directory-create-failed": "directory-picker/create-failed"
482
+ };
483
+ /**
484
+ * Classify a browse-primitive rejection: the seam's own closed codes carry the
485
+ * path they are about, and anything else stays an infrastructure failure.
486
+ * @param error - the primitive's rejection.
487
+ * @returns the failure to throw across the Remote boundary.
488
+ */
489
+ function browseFailure(error) {
490
+ if (error instanceof DirectoryPickerError) return new RemoteError(BROWSE_FAILURE_CODES[error.code], error.message, { path: error.path }, { cause: error });
491
+ return new RemoteError("gateway/internal", errorMessage(error), {}, { cause: error });
492
+ }
493
+ /**
494
+ * Classify a cancellable primitive's rejection. An abort is the caller's own
495
+ * timeout or disconnect, not a backend failure, so it answers `gateway/cancelled`
496
+ * before the business classification runs.
497
+ * @param error - the primitive's rejection.
498
+ * @param signal - the caller lifetime the primitive ran under.
499
+ * @param cancelled - operator-facing text for the abort outcome.
500
+ * @param failed - prefix for a non-seam failure, when the verb has no closed codes.
501
+ * @returns the failure to throw across the Remote boundary.
502
+ */
503
+ function cancellableFailure(error, signal, cancelled, failed) {
504
+ if (signal.aborted) return new RemoteError("gateway/cancelled", cancelled, {}, { cause: error });
505
+ if (failed === void 0) return browseFailure(error);
506
+ return new RemoteError("gateway/internal", `${failed}: ${errorMessage(error)}`, {}, { cause: error });
507
+ }
508
+ function errorMessage(error) {
509
+ return error instanceof Error ? error.message : String(error);
510
+ }
511
+ //#endregion
512
+ //#region lib/types/index.js
513
+ /** Host Workspace Remote owner: explicit commands and reconnect-safe state. */
514
+ var __runInitializers = function(thisArg, initializers, value) {
515
+ var useValue = arguments.length > 2;
516
+ for (var i = 0; i < initializers.length; i++) value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
517
+ return useValue ? value : void 0;
518
+ };
519
+ var __esDecorate = function(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
520
+ function accept(f) {
521
+ if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected");
522
+ return f;
523
+ }
524
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
525
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
526
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
527
+ var _, done = false;
528
+ for (var i = decorators.length - 1; i >= 0; i--) {
529
+ var context = {};
530
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
531
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
532
+ context.addInitializer = function(f) {
533
+ if (done) throw new TypeError("Cannot add initializers after decoration has completed");
534
+ extraInitializers.push(accept(f || null));
535
+ };
536
+ var result = (0, decorators[i])(kind === "accessor" ? {
537
+ get: descriptor.get,
538
+ set: descriptor.set
539
+ } : descriptor[key], context);
540
+ if (kind === "accessor") {
541
+ if (result === void 0) continue;
542
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
543
+ if (_ = accept(result.get)) descriptor.get = _;
544
+ if (_ = accept(result.set)) descriptor.set = _;
545
+ if (_ = accept(result.init)) initializers.unshift(_);
546
+ } else if (_ = accept(result)) if (kind === "field") initializers.unshift(_);
547
+ else descriptor[key] = _;
548
+ }
549
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
550
+ done = true;
551
+ };
552
+ /** Host service backing the generated `ctx.remote.workspace` namespace. */
553
+ let WorkspaceController = (() => {
554
+ let _classSuper = TypertRemoteService;
555
+ let _instanceExtraInitializers = [];
556
+ let _create_decorators;
557
+ let _rename_decorators;
558
+ let _delete_decorators;
559
+ let _insertBefore_decorators;
560
+ let _insertSessionBefore_decorators;
561
+ let _archiveSession_decorators;
562
+ let _follow_decorators;
563
+ return class WorkspaceController extends _classSuper {
564
+ static {
565
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
566
+ _create_decorators = [Remote("create")];
567
+ _rename_decorators = [Remote("rename")];
568
+ _delete_decorators = [Remote("delete")];
569
+ _insertBefore_decorators = [Remote("insertBefore")];
570
+ _insertSessionBefore_decorators = [Remote("insertSessionBefore")];
571
+ _archiveSession_decorators = [Remote("archiveSession")];
572
+ _follow_decorators = [Remote({ mode: "stream" })];
573
+ __esDecorate(this, null, _create_decorators, {
574
+ kind: "method",
575
+ name: "create",
576
+ static: false,
577
+ private: false,
578
+ access: {
579
+ has: (obj) => "create" in obj,
580
+ get: (obj) => obj.create
581
+ },
582
+ metadata: _metadata
583
+ }, null, _instanceExtraInitializers);
584
+ __esDecorate(this, null, _rename_decorators, {
585
+ kind: "method",
586
+ name: "rename",
587
+ static: false,
588
+ private: false,
589
+ access: {
590
+ has: (obj) => "rename" in obj,
591
+ get: (obj) => obj.rename
592
+ },
593
+ metadata: _metadata
594
+ }, null, _instanceExtraInitializers);
595
+ __esDecorate(this, null, _delete_decorators, {
596
+ kind: "method",
597
+ name: "delete",
598
+ static: false,
599
+ private: false,
600
+ access: {
601
+ has: (obj) => "delete" in obj,
602
+ get: (obj) => obj.delete
603
+ },
604
+ metadata: _metadata
605
+ }, null, _instanceExtraInitializers);
606
+ __esDecorate(this, null, _insertBefore_decorators, {
607
+ kind: "method",
608
+ name: "insertBefore",
609
+ static: false,
610
+ private: false,
611
+ access: {
612
+ has: (obj) => "insertBefore" in obj,
613
+ get: (obj) => obj.insertBefore
614
+ },
615
+ metadata: _metadata
616
+ }, null, _instanceExtraInitializers);
617
+ __esDecorate(this, null, _insertSessionBefore_decorators, {
618
+ kind: "method",
619
+ name: "insertSessionBefore",
620
+ static: false,
621
+ private: false,
622
+ access: {
623
+ has: (obj) => "insertSessionBefore" in obj,
624
+ get: (obj) => obj.insertSessionBefore
625
+ },
626
+ metadata: _metadata
627
+ }, null, _instanceExtraInitializers);
628
+ __esDecorate(this, null, _archiveSession_decorators, {
629
+ kind: "method",
630
+ name: "archiveSession",
631
+ static: false,
632
+ private: false,
633
+ access: {
634
+ has: (obj) => "archiveSession" in obj,
635
+ get: (obj) => obj.archiveSession
636
+ },
637
+ metadata: _metadata
638
+ }, null, _instanceExtraInitializers);
639
+ __esDecorate(this, null, _follow_decorators, {
640
+ kind: "method",
641
+ name: "follow",
642
+ static: false,
643
+ private: false,
644
+ access: {
645
+ has: (obj) => "follow" in obj,
646
+ get: (obj) => obj.follow
647
+ },
648
+ metadata: _metadata
649
+ }, null, _instanceExtraInitializers);
650
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, {
651
+ enumerable: true,
652
+ configurable: true,
653
+ writable: true,
654
+ value: _metadata
655
+ });
656
+ }
657
+ static inject = ["typert", "workspaceRegistry"];
658
+ commands = __runInitializers(this, _instanceExtraInitializers);
659
+ feed;
660
+ /** @param ctx - Host context containing the Workspace registry. */
661
+ constructor(ctx) {
662
+ super(ctx, "workspaceController", { namespace: "workspace" });
663
+ this.commands = new WorkspaceCommands(ctx);
664
+ this.feed = new WorkspaceFeed(ctx);
665
+ ctx.plugin(DirectoryPickerController);
666
+ }
667
+ /**
668
+ * Create or idempotently resolve one Workspace over an existing directory.
669
+ * @param request - directory path to register.
670
+ * @returns the Workspace and whether this call created it.
671
+ */
672
+ create(request) {
673
+ return this.commands.create(request);
674
+ }
675
+ /**
676
+ * Rename one Workspace to a unique non-blank title.
677
+ * @param request - Workspace identity and proposed title.
678
+ * @returns the updated Workspace projection.
679
+ */
680
+ rename(request) {
681
+ return this.commands.rename(request);
682
+ }
683
+ /**
684
+ * Remove one Workspace registration while retaining files and Sessions.
685
+ * @param request - Workspace identity to remove.
686
+ * @returns deletion confirmation.
687
+ */
688
+ delete(request) {
689
+ return this.commands.delete(request);
690
+ }
691
+ /**
692
+ * Move one Workspace within the registry display order.
693
+ * @param request - moved Workspace and optional anchor.
694
+ * @returns the complete resulting Workspace order.
695
+ */
696
+ insertBefore(request) {
697
+ return this.commands.insertBefore(request);
698
+ }
699
+ /**
700
+ * Move one accounted Session within a Workspace.
701
+ * @param request - Workspace, Session, and optional anchor identities.
702
+ * @returns the updated Workspace projection.
703
+ */
704
+ insertSessionBefore(request) {
705
+ return this.commands.insertSessionBefore(request);
706
+ }
707
+ /**
708
+ * Hide one known Session from Workspace grouping surfaces.
709
+ * @param request - Session identity to archive.
710
+ * @returns the complete resulting archive set.
711
+ */
712
+ archiveSession(request) {
713
+ return this.commands.archiveSession(request);
714
+ }
715
+ /**
716
+ * Stream a complete Workspace baseline followed by ordered increments.
717
+ * @param signal - generation cancellation.
718
+ * @returns baseline followed by ordered Workspace increments.
719
+ */
720
+ follow(signal) {
721
+ return this.feed.follow(signal);
722
+ }
723
+ };
724
+ })();
725
+ //#endregion
726
+ export { DirectoryPickerController, WorkspaceController, WorkspaceController as default };