@openfairygui/backend 0.2.0 → 0.3.0-alpha.1

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/README.md CHANGED
@@ -28,6 +28,7 @@ It also provides:
28
28
  - polling runtime events with per-runtime monotonic sequence and bounded retention
29
29
  - `cache.refresh` in-memory jobs with cooperative cancel and terminal retention
30
30
  - revision-bound derived read-only cache snapshots
31
+ - revision-bound project identity outlines for transaction planning
31
32
  - explicit Node bridge boundaries for publish/restore
32
33
 
33
34
  It does **not** redefine transaction grammar or expose `Document`.
@@ -67,6 +68,9 @@ const runtime = new BackendRuntime();
67
68
  const opened = runtime.openProjectSession({ project: uamProject });
68
69
  if (!opened.ok) throw new Error(opened.error.message);
69
70
 
71
+ const outline = runtime.getProjectOutline({ sessionId: opened.data.sessionId });
72
+ if (!outline.ok) throw new Error(outline.error.message);
73
+
70
74
  const applied = await runtime.applyTransaction({
71
75
  sessionId: opened.data.sessionId,
72
76
  expectedRevision: opened.data.revision,
package/dist/index.cjs CHANGED
@@ -1051,6 +1051,48 @@ var JobService = class {
1051
1051
  };
1052
1052
  //#endregion
1053
1053
  //#region src/services/read-service.ts
1054
+ function toProjectOutline(session) {
1055
+ const project = session.project;
1056
+ return {
1057
+ sessionId: session.sessionId,
1058
+ revision: session.revision,
1059
+ projectId: project.projectId,
1060
+ projectType: project.projectType,
1061
+ version: project.version,
1062
+ branches: [...project.branches],
1063
+ packages: project.packages.map((pkg) => ({
1064
+ id: pkg.id,
1065
+ name: pkg.name,
1066
+ branchNames: [...pkg.branchNames],
1067
+ folders: pkg.folders.map((folder) => ({
1068
+ branch: folder.branch,
1069
+ path: folder.path
1070
+ })),
1071
+ resources: pkg.resources.map((resource) => ({
1072
+ id: resource.id,
1073
+ name: resource.name,
1074
+ path: resource.path,
1075
+ kind: resource.kind,
1076
+ branch: resource.branch,
1077
+ ...resource.kind === "component" ? { component: {
1078
+ displayList: resource.component.displayList.map((node) => ({
1079
+ id: node.id,
1080
+ name: node.name,
1081
+ kind: node.kind
1082
+ })),
1083
+ controllers: resource.component.controllers.map((controller) => ({
1084
+ name: controller.name,
1085
+ pages: controller.pages.map((page) => ({
1086
+ id: page.id,
1087
+ name: page.name
1088
+ }))
1089
+ })),
1090
+ transitions: resource.component.transitions.map((transition) => ({ name: transition.name }))
1091
+ } } : {}
1092
+ }))
1093
+ }))
1094
+ };
1095
+ }
1054
1096
  var ReadService = class {
1055
1097
  constructor(context) {
1056
1098
  this.context = context;
@@ -1067,6 +1109,15 @@ var ReadService = class {
1067
1109
  revision: session.revision
1068
1110
  });
1069
1111
  }
1112
+ getProjectOutline(input) {
1113
+ const startedAt = Date.now();
1114
+ const session = this.context.sessions.get(input.sessionId);
1115
+ if (!session || session.closed) return failure("read", startedAt, createSessionNotFoundError(input.sessionId));
1116
+ return success("read", startedAt, toProjectOutline(session), {
1117
+ sessionId: session.sessionId,
1118
+ revision: session.revision
1119
+ });
1120
+ }
1070
1121
  };
1071
1122
  //#endregion
1072
1123
  //#region src/services/runtime-service.ts
@@ -1380,6 +1431,7 @@ const BACKEND_METHODS = [
1380
1431
  "openSession",
1381
1432
  "openProjectSession",
1382
1433
  "getSession",
1434
+ "getProjectOutline",
1383
1435
  "applyTransaction",
1384
1436
  "saveSession",
1385
1437
  "materializeSession",
@@ -1408,7 +1460,8 @@ function createCapabilities() {
1408
1460
  methods: BACKEND_METHODS,
1409
1461
  read: {
1410
1462
  capabilitySnapshot: true,
1411
- sessionSnapshot: true
1463
+ sessionSnapshot: true,
1464
+ projectOutline: true
1412
1465
  },
1413
1466
  authoring: {
1414
1467
  applyTransaction: true,
@@ -1548,6 +1601,9 @@ var BackendRuntime = class {
1548
1601
  getSession(input) {
1549
1602
  return this.readService.getSession(input);
1550
1603
  }
1604
+ getProjectOutline(input) {
1605
+ return this.readService.getProjectOutline(input);
1606
+ }
1551
1607
  async applyTransaction(input) {
1552
1608
  return this.authoringService.applyTransaction(input);
1553
1609
  }
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ApplyUamTransactionAppError } from "@openfairygui/functions/uam";
2
- import { UamProject, UamTransactionOperation } from "@openfairygui/core/uam";
2
+ import { UamDisplayNodeKind, UamProject, UamResource, UamTransactionOperation } from "@openfairygui/core/uam";
3
3
  import { FileSystem } from "@openfairygui/core/project-io";
4
4
 
5
5
  //#region src/contracts.d.ts
@@ -130,10 +130,11 @@ interface BackendCapabilities {
130
130
  transactionKernelOwner: '@openfairygui/core';
131
131
  appSeamOwner: '@openfairygui/functions';
132
132
  runtimeOwner: '@openfairygui/backend';
133
- methods: readonly ['getCapabilities', 'openSession', 'openProjectSession', 'getSession', 'applyTransaction', 'saveSession', 'materializeSession', 'closeSession', 'getEvents', 'getJob', 'listJobs', 'cancelJob', 'getCacheSnapshot', 'refreshCache'];
133
+ methods: readonly ['getCapabilities', 'openSession', 'openProjectSession', 'getSession', 'getProjectOutline', 'applyTransaction', 'saveSession', 'materializeSession', 'closeSession', 'getEvents', 'getJob', 'listJobs', 'cancelJob', 'getCacheSnapshot', 'refreshCache'];
134
134
  read: {
135
135
  capabilitySnapshot: true;
136
136
  sessionSnapshot: true;
137
+ projectOutline: true;
137
138
  };
138
139
  authoring: {
139
140
  applyTransaction: true;
@@ -202,6 +203,49 @@ interface BackendSessionSnapshot {
202
203
  lockHeld: boolean;
203
204
  capabilities: BackendCapabilities;
204
205
  }
206
+ interface BackendProjectOutline {
207
+ sessionId: string;
208
+ revision: number;
209
+ projectId: string;
210
+ projectType: number;
211
+ version: string;
212
+ branches: string[];
213
+ packages: BackendProjectOutlinePackage[];
214
+ }
215
+ interface BackendProjectOutlinePackage {
216
+ id: string;
217
+ name: string;
218
+ branchNames: string[];
219
+ folders: Array<{
220
+ branch: string;
221
+ path: string;
222
+ }>;
223
+ resources: BackendProjectOutlineResource[];
224
+ }
225
+ interface BackendProjectOutlineResource {
226
+ id: string;
227
+ name: string;
228
+ path: string;
229
+ kind: UamResource['kind'];
230
+ branch: string;
231
+ component?: {
232
+ displayList: Array<{
233
+ id: string;
234
+ name: string;
235
+ kind: UamDisplayNodeKind;
236
+ }>;
237
+ controllers: Array<{
238
+ name: string;
239
+ pages: Array<{
240
+ id: string;
241
+ name: string;
242
+ }>;
243
+ }>;
244
+ transitions: Array<{
245
+ name: string;
246
+ }>;
247
+ };
248
+ }
205
249
  interface MaterializeSessionSnapshot extends BackendSessionSnapshot {
206
250
  mode: 'fullProject';
207
251
  reason?: string;
@@ -427,6 +471,9 @@ interface ApplySessionTransactionInput {
427
471
  expectedRevision: number;
428
472
  operations: UamTransactionOperation[];
429
473
  }
474
+ interface GetProjectOutlineInput {
475
+ sessionId: string;
476
+ }
430
477
  interface OpenProjectSessionInput {
431
478
  /** Authoritative UAM project. Use BackendRuntime.openSession() when importing an existing project from storage. */
432
479
  project: UamProject;
@@ -490,6 +537,7 @@ declare class BackendRuntime {
490
537
  getSession(input: {
491
538
  sessionId: string;
492
539
  }): BackendResult<BackendSessionSnapshot, SessionNotFoundError>;
540
+ getProjectOutline(input: GetProjectOutlineInput): BackendResult<BackendProjectOutline, SessionNotFoundError>;
493
541
  applyTransaction(input: ApplySessionTransactionInput): Promise<BackendResult<BackendSessionSnapshot, SessionNotFoundError | SessionStaleWriteError | ApplyUamTransactionAppError>>;
494
542
  saveSession(input: SaveSessionInput): Promise<BackendResult<BackendSessionSnapshot | MaterializeSessionSnapshot, SessionNotFoundError | SessionStaleWriteError | SavePartialFailureError | UamFidelityUnsupportedError | MaterializeValidationFailedError | MaterializeWriteFailedError | PathPolicyViolationError | InProcessLockConflictError | BackendCapabilityUnavailableError>>;
495
543
  materializeSession(input: MaterializeSessionInput): Promise<BackendResult<MaterializeSessionSnapshot, SessionNotFoundError | SessionStaleWriteError | UamFidelityUnsupportedError | MaterializeValidationFailedError | MaterializeWriteFailedError | PathPolicyViolationError | InProcessLockConflictError | BackendCapabilityUnavailableError>>;
@@ -542,4 +590,4 @@ interface BackendAsyncStorageAdapter {
542
590
  type BackendStorageFileSystem = BackendFileSystem & FileSystem;
543
591
  declare function createBackendStorageFileSystem(storage: BackendAsyncStorageAdapter): BackendStorageFileSystem;
544
592
  //#endregion
545
- export { type AdvisoryLockConflictError, type ApplySessionTransactionInput, BACKEND_CAPABILITY_SCHEMA_VERSION, BACKEND_COMPATIBILITY_POLICY, BACKEND_CONTRACT_VERSION, type BackendArtifactBridgeCapability, type BackendAsyncStorageAdapter, type BackendCacheEntry, type BackendCacheSnapshot, type BackendCapabilities, type BackendCapabilityManifest, type BackendCapabilityUnavailableError, type BackendDiagnostic, type BackendError, type BackendEvent, type BackendEventKind, type BackendFailure, type BackendFileStat, type BackendFileSystem, type BackendHostAdapter, type BackendJobErrors, type BackendJobKind, type BackendJobListSnapshot, type BackendJobListStatusFilter, type BackendJobNotCancellableError, type BackendJobNotFoundError, type BackendJobProgress, type BackendJobSnapshot, type BackendJobStatus, type BackendMessage, type BackendProjectSessionStorage, type BackendResponseMeta, type BackendResult, BackendRuntime, type BackendRuntimeOptions, type BackendSessionLock, type BackendSessionSnapshot, type BackendStage, type BackendStorageFileSystem, type BackendStorageStatLike, type BackendSuccess, type CacheRefreshFailedError, type CancelJobInput, type EventCursorInvalidError, type GetCacheSnapshotInput, type GetEventsInput, type GetEventsSnapshot, type GetJobInput, type InProcessLockConflictError, type ListJobsInput, type MaterializeSessionInput, type MaterializeSessionSnapshot, type MaterializeValidationFailedError, type MaterializeWriteFailedError, type OpenProjectSessionInput, type RefreshCacheInput, type SavePartialFailureError, type SaveSessionInput, type SessionNotFoundError, type SessionStaleWriteError, type UamFidelityUnsupportedError, createBackendStorageFileSystem };
593
+ export { type AdvisoryLockConflictError, type ApplySessionTransactionInput, BACKEND_CAPABILITY_SCHEMA_VERSION, BACKEND_COMPATIBILITY_POLICY, BACKEND_CONTRACT_VERSION, type BackendArtifactBridgeCapability, type BackendAsyncStorageAdapter, type BackendCacheEntry, type BackendCacheSnapshot, type BackendCapabilities, type BackendCapabilityManifest, type BackendCapabilityUnavailableError, type BackendDiagnostic, type BackendError, type BackendEvent, type BackendEventKind, type BackendFailure, type BackendFileStat, type BackendFileSystem, type BackendHostAdapter, type BackendJobErrors, type BackendJobKind, type BackendJobListSnapshot, type BackendJobListStatusFilter, type BackendJobNotCancellableError, type BackendJobNotFoundError, type BackendJobProgress, type BackendJobSnapshot, type BackendJobStatus, type BackendMessage, type BackendProjectOutline, type BackendProjectOutlinePackage, type BackendProjectOutlineResource, type BackendProjectSessionStorage, type BackendResponseMeta, type BackendResult, BackendRuntime, type BackendRuntimeOptions, type BackendSessionLock, type BackendSessionSnapshot, type BackendStage, type BackendStorageFileSystem, type BackendStorageStatLike, type BackendSuccess, type CacheRefreshFailedError, type CancelJobInput, type EventCursorInvalidError, type GetCacheSnapshotInput, type GetEventsInput, type GetEventsSnapshot, type GetJobInput, type GetProjectOutlineInput, type InProcessLockConflictError, type ListJobsInput, type MaterializeSessionInput, type MaterializeSessionSnapshot, type MaterializeValidationFailedError, type MaterializeWriteFailedError, type OpenProjectSessionInput, type RefreshCacheInput, type SavePartialFailureError, type SaveSessionInput, type SessionNotFoundError, type SessionStaleWriteError, type UamFidelityUnsupportedError, createBackendStorageFileSystem };
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { UamProject, UamTransactionOperation } from "@openfairygui/core/uam";
1
+ import { UamDisplayNodeKind, UamProject, UamResource, UamTransactionOperation } from "@openfairygui/core/uam";
2
2
  import { ApplyUamTransactionAppError } from "@openfairygui/functions/uam";
3
3
  import { FileSystem } from "@openfairygui/core/project-io";
4
4
 
@@ -130,10 +130,11 @@ interface BackendCapabilities {
130
130
  transactionKernelOwner: '@openfairygui/core';
131
131
  appSeamOwner: '@openfairygui/functions';
132
132
  runtimeOwner: '@openfairygui/backend';
133
- methods: readonly ['getCapabilities', 'openSession', 'openProjectSession', 'getSession', 'applyTransaction', 'saveSession', 'materializeSession', 'closeSession', 'getEvents', 'getJob', 'listJobs', 'cancelJob', 'getCacheSnapshot', 'refreshCache'];
133
+ methods: readonly ['getCapabilities', 'openSession', 'openProjectSession', 'getSession', 'getProjectOutline', 'applyTransaction', 'saveSession', 'materializeSession', 'closeSession', 'getEvents', 'getJob', 'listJobs', 'cancelJob', 'getCacheSnapshot', 'refreshCache'];
134
134
  read: {
135
135
  capabilitySnapshot: true;
136
136
  sessionSnapshot: true;
137
+ projectOutline: true;
137
138
  };
138
139
  authoring: {
139
140
  applyTransaction: true;
@@ -202,6 +203,49 @@ interface BackendSessionSnapshot {
202
203
  lockHeld: boolean;
203
204
  capabilities: BackendCapabilities;
204
205
  }
206
+ interface BackendProjectOutline {
207
+ sessionId: string;
208
+ revision: number;
209
+ projectId: string;
210
+ projectType: number;
211
+ version: string;
212
+ branches: string[];
213
+ packages: BackendProjectOutlinePackage[];
214
+ }
215
+ interface BackendProjectOutlinePackage {
216
+ id: string;
217
+ name: string;
218
+ branchNames: string[];
219
+ folders: Array<{
220
+ branch: string;
221
+ path: string;
222
+ }>;
223
+ resources: BackendProjectOutlineResource[];
224
+ }
225
+ interface BackendProjectOutlineResource {
226
+ id: string;
227
+ name: string;
228
+ path: string;
229
+ kind: UamResource['kind'];
230
+ branch: string;
231
+ component?: {
232
+ displayList: Array<{
233
+ id: string;
234
+ name: string;
235
+ kind: UamDisplayNodeKind;
236
+ }>;
237
+ controllers: Array<{
238
+ name: string;
239
+ pages: Array<{
240
+ id: string;
241
+ name: string;
242
+ }>;
243
+ }>;
244
+ transitions: Array<{
245
+ name: string;
246
+ }>;
247
+ };
248
+ }
205
249
  interface MaterializeSessionSnapshot extends BackendSessionSnapshot {
206
250
  mode: 'fullProject';
207
251
  reason?: string;
@@ -427,6 +471,9 @@ interface ApplySessionTransactionInput {
427
471
  expectedRevision: number;
428
472
  operations: UamTransactionOperation[];
429
473
  }
474
+ interface GetProjectOutlineInput {
475
+ sessionId: string;
476
+ }
430
477
  interface OpenProjectSessionInput {
431
478
  /** Authoritative UAM project. Use BackendRuntime.openSession() when importing an existing project from storage. */
432
479
  project: UamProject;
@@ -490,6 +537,7 @@ declare class BackendRuntime {
490
537
  getSession(input: {
491
538
  sessionId: string;
492
539
  }): BackendResult<BackendSessionSnapshot, SessionNotFoundError>;
540
+ getProjectOutline(input: GetProjectOutlineInput): BackendResult<BackendProjectOutline, SessionNotFoundError>;
493
541
  applyTransaction(input: ApplySessionTransactionInput): Promise<BackendResult<BackendSessionSnapshot, SessionNotFoundError | SessionStaleWriteError | ApplyUamTransactionAppError>>;
494
542
  saveSession(input: SaveSessionInput): Promise<BackendResult<BackendSessionSnapshot | MaterializeSessionSnapshot, SessionNotFoundError | SessionStaleWriteError | SavePartialFailureError | UamFidelityUnsupportedError | MaterializeValidationFailedError | MaterializeWriteFailedError | PathPolicyViolationError | InProcessLockConflictError | BackendCapabilityUnavailableError>>;
495
543
  materializeSession(input: MaterializeSessionInput): Promise<BackendResult<MaterializeSessionSnapshot, SessionNotFoundError | SessionStaleWriteError | UamFidelityUnsupportedError | MaterializeValidationFailedError | MaterializeWriteFailedError | PathPolicyViolationError | InProcessLockConflictError | BackendCapabilityUnavailableError>>;
@@ -542,4 +590,4 @@ interface BackendAsyncStorageAdapter {
542
590
  type BackendStorageFileSystem = BackendFileSystem & FileSystem;
543
591
  declare function createBackendStorageFileSystem(storage: BackendAsyncStorageAdapter): BackendStorageFileSystem;
544
592
  //#endregion
545
- export { type AdvisoryLockConflictError, type ApplySessionTransactionInput, BACKEND_CAPABILITY_SCHEMA_VERSION, BACKEND_COMPATIBILITY_POLICY, BACKEND_CONTRACT_VERSION, type BackendArtifactBridgeCapability, type BackendAsyncStorageAdapter, type BackendCacheEntry, type BackendCacheSnapshot, type BackendCapabilities, type BackendCapabilityManifest, type BackendCapabilityUnavailableError, type BackendDiagnostic, type BackendError, type BackendEvent, type BackendEventKind, type BackendFailure, type BackendFileStat, type BackendFileSystem, type BackendHostAdapter, type BackendJobErrors, type BackendJobKind, type BackendJobListSnapshot, type BackendJobListStatusFilter, type BackendJobNotCancellableError, type BackendJobNotFoundError, type BackendJobProgress, type BackendJobSnapshot, type BackendJobStatus, type BackendMessage, type BackendProjectSessionStorage, type BackendResponseMeta, type BackendResult, BackendRuntime, type BackendRuntimeOptions, type BackendSessionLock, type BackendSessionSnapshot, type BackendStage, type BackendStorageFileSystem, type BackendStorageStatLike, type BackendSuccess, type CacheRefreshFailedError, type CancelJobInput, type EventCursorInvalidError, type GetCacheSnapshotInput, type GetEventsInput, type GetEventsSnapshot, type GetJobInput, type InProcessLockConflictError, type ListJobsInput, type MaterializeSessionInput, type MaterializeSessionSnapshot, type MaterializeValidationFailedError, type MaterializeWriteFailedError, type OpenProjectSessionInput, type RefreshCacheInput, type SavePartialFailureError, type SaveSessionInput, type SessionNotFoundError, type SessionStaleWriteError, type UamFidelityUnsupportedError, createBackendStorageFileSystem };
593
+ export { type AdvisoryLockConflictError, type ApplySessionTransactionInput, BACKEND_CAPABILITY_SCHEMA_VERSION, BACKEND_COMPATIBILITY_POLICY, BACKEND_CONTRACT_VERSION, type BackendArtifactBridgeCapability, type BackendAsyncStorageAdapter, type BackendCacheEntry, type BackendCacheSnapshot, type BackendCapabilities, type BackendCapabilityManifest, type BackendCapabilityUnavailableError, type BackendDiagnostic, type BackendError, type BackendEvent, type BackendEventKind, type BackendFailure, type BackendFileStat, type BackendFileSystem, type BackendHostAdapter, type BackendJobErrors, type BackendJobKind, type BackendJobListSnapshot, type BackendJobListStatusFilter, type BackendJobNotCancellableError, type BackendJobNotFoundError, type BackendJobProgress, type BackendJobSnapshot, type BackendJobStatus, type BackendMessage, type BackendProjectOutline, type BackendProjectOutlinePackage, type BackendProjectOutlineResource, type BackendProjectSessionStorage, type BackendResponseMeta, type BackendResult, BackendRuntime, type BackendRuntimeOptions, type BackendSessionLock, type BackendSessionSnapshot, type BackendStage, type BackendStorageFileSystem, type BackendStorageStatLike, type BackendSuccess, type CacheRefreshFailedError, type CancelJobInput, type EventCursorInvalidError, type GetCacheSnapshotInput, type GetEventsInput, type GetEventsSnapshot, type GetJobInput, type GetProjectOutlineInput, type InProcessLockConflictError, type ListJobsInput, type MaterializeSessionInput, type MaterializeSessionSnapshot, type MaterializeValidationFailedError, type MaterializeWriteFailedError, type OpenProjectSessionInput, type RefreshCacheInput, type SavePartialFailureError, type SaveSessionInput, type SessionNotFoundError, type SessionStaleWriteError, type UamFidelityUnsupportedError, createBackendStorageFileSystem };
package/dist/index.mjs CHANGED
@@ -1050,6 +1050,48 @@ var JobService = class {
1050
1050
  };
1051
1051
  //#endregion
1052
1052
  //#region src/services/read-service.ts
1053
+ function toProjectOutline(session) {
1054
+ const project = session.project;
1055
+ return {
1056
+ sessionId: session.sessionId,
1057
+ revision: session.revision,
1058
+ projectId: project.projectId,
1059
+ projectType: project.projectType,
1060
+ version: project.version,
1061
+ branches: [...project.branches],
1062
+ packages: project.packages.map((pkg) => ({
1063
+ id: pkg.id,
1064
+ name: pkg.name,
1065
+ branchNames: [...pkg.branchNames],
1066
+ folders: pkg.folders.map((folder) => ({
1067
+ branch: folder.branch,
1068
+ path: folder.path
1069
+ })),
1070
+ resources: pkg.resources.map((resource) => ({
1071
+ id: resource.id,
1072
+ name: resource.name,
1073
+ path: resource.path,
1074
+ kind: resource.kind,
1075
+ branch: resource.branch,
1076
+ ...resource.kind === "component" ? { component: {
1077
+ displayList: resource.component.displayList.map((node) => ({
1078
+ id: node.id,
1079
+ name: node.name,
1080
+ kind: node.kind
1081
+ })),
1082
+ controllers: resource.component.controllers.map((controller) => ({
1083
+ name: controller.name,
1084
+ pages: controller.pages.map((page) => ({
1085
+ id: page.id,
1086
+ name: page.name
1087
+ }))
1088
+ })),
1089
+ transitions: resource.component.transitions.map((transition) => ({ name: transition.name }))
1090
+ } } : {}
1091
+ }))
1092
+ }))
1093
+ };
1094
+ }
1053
1095
  var ReadService = class {
1054
1096
  constructor(context) {
1055
1097
  this.context = context;
@@ -1066,6 +1108,15 @@ var ReadService = class {
1066
1108
  revision: session.revision
1067
1109
  });
1068
1110
  }
1111
+ getProjectOutline(input) {
1112
+ const startedAt = Date.now();
1113
+ const session = this.context.sessions.get(input.sessionId);
1114
+ if (!session || session.closed) return failure("read", startedAt, createSessionNotFoundError(input.sessionId));
1115
+ return success("read", startedAt, toProjectOutline(session), {
1116
+ sessionId: session.sessionId,
1117
+ revision: session.revision
1118
+ });
1119
+ }
1069
1120
  };
1070
1121
  //#endregion
1071
1122
  //#region src/services/runtime-service.ts
@@ -1379,6 +1430,7 @@ const BACKEND_METHODS = [
1379
1430
  "openSession",
1380
1431
  "openProjectSession",
1381
1432
  "getSession",
1433
+ "getProjectOutline",
1382
1434
  "applyTransaction",
1383
1435
  "saveSession",
1384
1436
  "materializeSession",
@@ -1407,7 +1459,8 @@ function createCapabilities() {
1407
1459
  methods: BACKEND_METHODS,
1408
1460
  read: {
1409
1461
  capabilitySnapshot: true,
1410
- sessionSnapshot: true
1462
+ sessionSnapshot: true,
1463
+ projectOutline: true
1411
1464
  },
1412
1465
  authoring: {
1413
1466
  applyTransaction: true,
@@ -1547,6 +1600,9 @@ var BackendRuntime = class {
1547
1600
  getSession(input) {
1548
1601
  return this.readService.getSession(input);
1549
1602
  }
1603
+ getProjectOutline(input) {
1604
+ return this.readService.getProjectOutline(input);
1605
+ }
1550
1606
  async applyTransaction(input) {
1551
1607
  return this.authoringService.applyTransaction(input);
1552
1608
  }
package/dist/node.cjs CHANGED
@@ -1076,6 +1076,48 @@ var JobService = class {
1076
1076
  };
1077
1077
  //#endregion
1078
1078
  //#region src/services/read-service.ts
1079
+ function toProjectOutline(session) {
1080
+ const project = session.project;
1081
+ return {
1082
+ sessionId: session.sessionId,
1083
+ revision: session.revision,
1084
+ projectId: project.projectId,
1085
+ projectType: project.projectType,
1086
+ version: project.version,
1087
+ branches: [...project.branches],
1088
+ packages: project.packages.map((pkg) => ({
1089
+ id: pkg.id,
1090
+ name: pkg.name,
1091
+ branchNames: [...pkg.branchNames],
1092
+ folders: pkg.folders.map((folder) => ({
1093
+ branch: folder.branch,
1094
+ path: folder.path
1095
+ })),
1096
+ resources: pkg.resources.map((resource) => ({
1097
+ id: resource.id,
1098
+ name: resource.name,
1099
+ path: resource.path,
1100
+ kind: resource.kind,
1101
+ branch: resource.branch,
1102
+ ...resource.kind === "component" ? { component: {
1103
+ displayList: resource.component.displayList.map((node) => ({
1104
+ id: node.id,
1105
+ name: node.name,
1106
+ kind: node.kind
1107
+ })),
1108
+ controllers: resource.component.controllers.map((controller) => ({
1109
+ name: controller.name,
1110
+ pages: controller.pages.map((page) => ({
1111
+ id: page.id,
1112
+ name: page.name
1113
+ }))
1114
+ })),
1115
+ transitions: resource.component.transitions.map((transition) => ({ name: transition.name }))
1116
+ } } : {}
1117
+ }))
1118
+ }))
1119
+ };
1120
+ }
1079
1121
  var ReadService = class {
1080
1122
  constructor(context) {
1081
1123
  this.context = context;
@@ -1092,6 +1134,15 @@ var ReadService = class {
1092
1134
  revision: session.revision
1093
1135
  });
1094
1136
  }
1137
+ getProjectOutline(input) {
1138
+ const startedAt = Date.now();
1139
+ const session = this.context.sessions.get(input.sessionId);
1140
+ if (!session || session.closed) return failure("read", startedAt, createSessionNotFoundError(input.sessionId));
1141
+ return success("read", startedAt, toProjectOutline(session), {
1142
+ sessionId: session.sessionId,
1143
+ revision: session.revision
1144
+ });
1145
+ }
1095
1146
  };
1096
1147
  //#endregion
1097
1148
  //#region src/services/runtime-service.ts
@@ -1405,6 +1456,7 @@ const BACKEND_METHODS = [
1405
1456
  "openSession",
1406
1457
  "openProjectSession",
1407
1458
  "getSession",
1459
+ "getProjectOutline",
1408
1460
  "applyTransaction",
1409
1461
  "saveSession",
1410
1462
  "materializeSession",
@@ -1433,7 +1485,8 @@ function createCapabilities() {
1433
1485
  methods: BACKEND_METHODS,
1434
1486
  read: {
1435
1487
  capabilitySnapshot: true,
1436
- sessionSnapshot: true
1488
+ sessionSnapshot: true,
1489
+ projectOutline: true
1437
1490
  },
1438
1491
  authoring: {
1439
1492
  applyTransaction: true,
@@ -1573,6 +1626,9 @@ var BackendRuntime = class {
1573
1626
  getSession(input) {
1574
1627
  return this.readService.getSession(input);
1575
1628
  }
1629
+ getProjectOutline(input) {
1630
+ return this.readService.getProjectOutline(input);
1631
+ }
1576
1632
  async applyTransaction(input) {
1577
1633
  return this.authoringService.applyTransaction(input);
1578
1634
  }
package/dist/node.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ApplyUamTransactionAppError } from "@openfairygui/functions/uam";
2
- import { UamProject, UamTransactionOperation } from "@openfairygui/core/uam";
2
+ import { UamDisplayNodeKind, UamProject, UamResource, UamTransactionOperation } from "@openfairygui/core/uam";
3
3
 
4
4
  //#region src/path-policy.d.ts
5
5
  interface PathPolicyViolationError {
@@ -129,10 +129,11 @@ interface BackendCapabilities {
129
129
  transactionKernelOwner: '@openfairygui/core';
130
130
  appSeamOwner: '@openfairygui/functions';
131
131
  runtimeOwner: '@openfairygui/backend';
132
- methods: readonly ['getCapabilities', 'openSession', 'openProjectSession', 'getSession', 'applyTransaction', 'saveSession', 'materializeSession', 'closeSession', 'getEvents', 'getJob', 'listJobs', 'cancelJob', 'getCacheSnapshot', 'refreshCache'];
132
+ methods: readonly ['getCapabilities', 'openSession', 'openProjectSession', 'getSession', 'getProjectOutline', 'applyTransaction', 'saveSession', 'materializeSession', 'closeSession', 'getEvents', 'getJob', 'listJobs', 'cancelJob', 'getCacheSnapshot', 'refreshCache'];
133
133
  read: {
134
134
  capabilitySnapshot: true;
135
135
  sessionSnapshot: true;
136
+ projectOutline: true;
136
137
  };
137
138
  authoring: {
138
139
  applyTransaction: true;
@@ -201,6 +202,49 @@ interface BackendSessionSnapshot {
201
202
  lockHeld: boolean;
202
203
  capabilities: BackendCapabilities;
203
204
  }
205
+ interface BackendProjectOutline {
206
+ sessionId: string;
207
+ revision: number;
208
+ projectId: string;
209
+ projectType: number;
210
+ version: string;
211
+ branches: string[];
212
+ packages: BackendProjectOutlinePackage[];
213
+ }
214
+ interface BackendProjectOutlinePackage {
215
+ id: string;
216
+ name: string;
217
+ branchNames: string[];
218
+ folders: Array<{
219
+ branch: string;
220
+ path: string;
221
+ }>;
222
+ resources: BackendProjectOutlineResource[];
223
+ }
224
+ interface BackendProjectOutlineResource {
225
+ id: string;
226
+ name: string;
227
+ path: string;
228
+ kind: UamResource['kind'];
229
+ branch: string;
230
+ component?: {
231
+ displayList: Array<{
232
+ id: string;
233
+ name: string;
234
+ kind: UamDisplayNodeKind;
235
+ }>;
236
+ controllers: Array<{
237
+ name: string;
238
+ pages: Array<{
239
+ id: string;
240
+ name: string;
241
+ }>;
242
+ }>;
243
+ transitions: Array<{
244
+ name: string;
245
+ }>;
246
+ };
247
+ }
204
248
  interface MaterializeSessionSnapshot extends BackendSessionSnapshot {
205
249
  mode: 'fullProject';
206
250
  reason?: string;
@@ -425,6 +469,9 @@ interface ApplySessionTransactionInput {
425
469
  expectedRevision: number;
426
470
  operations: UamTransactionOperation[];
427
471
  }
472
+ interface GetProjectOutlineInput {
473
+ sessionId: string;
474
+ }
428
475
  interface OpenProjectSessionInput {
429
476
  /** Authoritative UAM project. Use BackendRuntime.openSession() when importing an existing project from storage. */
430
477
  project: UamProject;
@@ -488,6 +535,7 @@ declare class BackendRuntime {
488
535
  getSession(input: {
489
536
  sessionId: string;
490
537
  }): BackendResult<BackendSessionSnapshot, SessionNotFoundError>;
538
+ getProjectOutline(input: GetProjectOutlineInput): BackendResult<BackendProjectOutline, SessionNotFoundError>;
491
539
  applyTransaction(input: ApplySessionTransactionInput): Promise<BackendResult<BackendSessionSnapshot, SessionNotFoundError | SessionStaleWriteError | ApplyUamTransactionAppError>>;
492
540
  saveSession(input: SaveSessionInput): Promise<BackendResult<BackendSessionSnapshot | MaterializeSessionSnapshot, SessionNotFoundError | SessionStaleWriteError | SavePartialFailureError | UamFidelityUnsupportedError | MaterializeValidationFailedError | MaterializeWriteFailedError | PathPolicyViolationError | InProcessLockConflictError | BackendCapabilityUnavailableError>>;
493
541
  materializeSession(input: MaterializeSessionInput): Promise<BackendResult<MaterializeSessionSnapshot, SessionNotFoundError | SessionStaleWriteError | UamFidelityUnsupportedError | MaterializeValidationFailedError | MaterializeWriteFailedError | PathPolicyViolationError | InProcessLockConflictError | BackendCapabilityUnavailableError>>;
package/dist/node.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { UamProject, UamTransactionOperation } from "@openfairygui/core/uam";
1
+ import { UamDisplayNodeKind, UamProject, UamResource, UamTransactionOperation } from "@openfairygui/core/uam";
2
2
  import { ApplyUamTransactionAppError } from "@openfairygui/functions/uam";
3
3
 
4
4
  //#region src/path-policy.d.ts
@@ -129,10 +129,11 @@ interface BackendCapabilities {
129
129
  transactionKernelOwner: '@openfairygui/core';
130
130
  appSeamOwner: '@openfairygui/functions';
131
131
  runtimeOwner: '@openfairygui/backend';
132
- methods: readonly ['getCapabilities', 'openSession', 'openProjectSession', 'getSession', 'applyTransaction', 'saveSession', 'materializeSession', 'closeSession', 'getEvents', 'getJob', 'listJobs', 'cancelJob', 'getCacheSnapshot', 'refreshCache'];
132
+ methods: readonly ['getCapabilities', 'openSession', 'openProjectSession', 'getSession', 'getProjectOutline', 'applyTransaction', 'saveSession', 'materializeSession', 'closeSession', 'getEvents', 'getJob', 'listJobs', 'cancelJob', 'getCacheSnapshot', 'refreshCache'];
133
133
  read: {
134
134
  capabilitySnapshot: true;
135
135
  sessionSnapshot: true;
136
+ projectOutline: true;
136
137
  };
137
138
  authoring: {
138
139
  applyTransaction: true;
@@ -201,6 +202,49 @@ interface BackendSessionSnapshot {
201
202
  lockHeld: boolean;
202
203
  capabilities: BackendCapabilities;
203
204
  }
205
+ interface BackendProjectOutline {
206
+ sessionId: string;
207
+ revision: number;
208
+ projectId: string;
209
+ projectType: number;
210
+ version: string;
211
+ branches: string[];
212
+ packages: BackendProjectOutlinePackage[];
213
+ }
214
+ interface BackendProjectOutlinePackage {
215
+ id: string;
216
+ name: string;
217
+ branchNames: string[];
218
+ folders: Array<{
219
+ branch: string;
220
+ path: string;
221
+ }>;
222
+ resources: BackendProjectOutlineResource[];
223
+ }
224
+ interface BackendProjectOutlineResource {
225
+ id: string;
226
+ name: string;
227
+ path: string;
228
+ kind: UamResource['kind'];
229
+ branch: string;
230
+ component?: {
231
+ displayList: Array<{
232
+ id: string;
233
+ name: string;
234
+ kind: UamDisplayNodeKind;
235
+ }>;
236
+ controllers: Array<{
237
+ name: string;
238
+ pages: Array<{
239
+ id: string;
240
+ name: string;
241
+ }>;
242
+ }>;
243
+ transitions: Array<{
244
+ name: string;
245
+ }>;
246
+ };
247
+ }
204
248
  interface MaterializeSessionSnapshot extends BackendSessionSnapshot {
205
249
  mode: 'fullProject';
206
250
  reason?: string;
@@ -425,6 +469,9 @@ interface ApplySessionTransactionInput {
425
469
  expectedRevision: number;
426
470
  operations: UamTransactionOperation[];
427
471
  }
472
+ interface GetProjectOutlineInput {
473
+ sessionId: string;
474
+ }
428
475
  interface OpenProjectSessionInput {
429
476
  /** Authoritative UAM project. Use BackendRuntime.openSession() when importing an existing project from storage. */
430
477
  project: UamProject;
@@ -488,6 +535,7 @@ declare class BackendRuntime {
488
535
  getSession(input: {
489
536
  sessionId: string;
490
537
  }): BackendResult<BackendSessionSnapshot, SessionNotFoundError>;
538
+ getProjectOutline(input: GetProjectOutlineInput): BackendResult<BackendProjectOutline, SessionNotFoundError>;
491
539
  applyTransaction(input: ApplySessionTransactionInput): Promise<BackendResult<BackendSessionSnapshot, SessionNotFoundError | SessionStaleWriteError | ApplyUamTransactionAppError>>;
492
540
  saveSession(input: SaveSessionInput): Promise<BackendResult<BackendSessionSnapshot | MaterializeSessionSnapshot, SessionNotFoundError | SessionStaleWriteError | SavePartialFailureError | UamFidelityUnsupportedError | MaterializeValidationFailedError | MaterializeWriteFailedError | PathPolicyViolationError | InProcessLockConflictError | BackendCapabilityUnavailableError>>;
493
541
  materializeSession(input: MaterializeSessionInput): Promise<BackendResult<MaterializeSessionSnapshot, SessionNotFoundError | SessionStaleWriteError | UamFidelityUnsupportedError | MaterializeValidationFailedError | MaterializeWriteFailedError | PathPolicyViolationError | InProcessLockConflictError | BackendCapabilityUnavailableError>>;
package/dist/node.mjs CHANGED
@@ -1051,6 +1051,48 @@ var JobService = class {
1051
1051
  };
1052
1052
  //#endregion
1053
1053
  //#region src/services/read-service.ts
1054
+ function toProjectOutline(session) {
1055
+ const project = session.project;
1056
+ return {
1057
+ sessionId: session.sessionId,
1058
+ revision: session.revision,
1059
+ projectId: project.projectId,
1060
+ projectType: project.projectType,
1061
+ version: project.version,
1062
+ branches: [...project.branches],
1063
+ packages: project.packages.map((pkg) => ({
1064
+ id: pkg.id,
1065
+ name: pkg.name,
1066
+ branchNames: [...pkg.branchNames],
1067
+ folders: pkg.folders.map((folder) => ({
1068
+ branch: folder.branch,
1069
+ path: folder.path
1070
+ })),
1071
+ resources: pkg.resources.map((resource) => ({
1072
+ id: resource.id,
1073
+ name: resource.name,
1074
+ path: resource.path,
1075
+ kind: resource.kind,
1076
+ branch: resource.branch,
1077
+ ...resource.kind === "component" ? { component: {
1078
+ displayList: resource.component.displayList.map((node) => ({
1079
+ id: node.id,
1080
+ name: node.name,
1081
+ kind: node.kind
1082
+ })),
1083
+ controllers: resource.component.controllers.map((controller) => ({
1084
+ name: controller.name,
1085
+ pages: controller.pages.map((page) => ({
1086
+ id: page.id,
1087
+ name: page.name
1088
+ }))
1089
+ })),
1090
+ transitions: resource.component.transitions.map((transition) => ({ name: transition.name }))
1091
+ } } : {}
1092
+ }))
1093
+ }))
1094
+ };
1095
+ }
1054
1096
  var ReadService = class {
1055
1097
  constructor(context) {
1056
1098
  this.context = context;
@@ -1067,6 +1109,15 @@ var ReadService = class {
1067
1109
  revision: session.revision
1068
1110
  });
1069
1111
  }
1112
+ getProjectOutline(input) {
1113
+ const startedAt = Date.now();
1114
+ const session = this.context.sessions.get(input.sessionId);
1115
+ if (!session || session.closed) return failure("read", startedAt, createSessionNotFoundError(input.sessionId));
1116
+ return success("read", startedAt, toProjectOutline(session), {
1117
+ sessionId: session.sessionId,
1118
+ revision: session.revision
1119
+ });
1120
+ }
1070
1121
  };
1071
1122
  //#endregion
1072
1123
  //#region src/services/runtime-service.ts
@@ -1380,6 +1431,7 @@ const BACKEND_METHODS = [
1380
1431
  "openSession",
1381
1432
  "openProjectSession",
1382
1433
  "getSession",
1434
+ "getProjectOutline",
1383
1435
  "applyTransaction",
1384
1436
  "saveSession",
1385
1437
  "materializeSession",
@@ -1408,7 +1460,8 @@ function createCapabilities() {
1408
1460
  methods: BACKEND_METHODS,
1409
1461
  read: {
1410
1462
  capabilitySnapshot: true,
1411
- sessionSnapshot: true
1463
+ sessionSnapshot: true,
1464
+ projectOutline: true
1412
1465
  },
1413
1466
  authoring: {
1414
1467
  applyTransaction: true,
@@ -1548,6 +1601,9 @@ var BackendRuntime = class {
1548
1601
  getSession(input) {
1549
1602
  return this.readService.getSession(input);
1550
1603
  }
1604
+ getProjectOutline(input) {
1605
+ return this.readService.getProjectOutline(input);
1606
+ }
1551
1607
  async applyTransaction(input) {
1552
1608
  return this.authoringService.applyTransaction(input);
1553
1609
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfairygui/backend",
3
- "version": "0.2.0",
3
+ "version": "0.3.0-alpha.1",
4
4
  "description": "FairyGUI Headless Authoring SDK — stateful backend runtime and session services.",
5
5
  "author": "OpenFairyGUI Contributors",
6
6
  "license": "MIT",
@@ -52,8 +52,8 @@
52
52
  "runtime"
53
53
  ],
54
54
  "dependencies": {
55
- "@openfairygui/core": "0.2.0",
56
- "@openfairygui/functions": "0.2.0"
55
+ "@openfairygui/functions": "0.3.0-alpha.1",
56
+ "@openfairygui/core": "0.3.0-alpha.1"
57
57
  },
58
58
  "devDependencies": {
59
59
  "ava": "^7.0.0",
package/src/index.ts CHANGED
@@ -32,6 +32,9 @@ export {
32
32
  type BackendJobProgress,
33
33
  type BackendJobSnapshot,
34
34
  type BackendJobStatus,
35
+ type BackendProjectOutline,
36
+ type BackendProjectOutlinePackage,
37
+ type BackendProjectOutlineResource,
35
38
  type BackendProjectSessionStorage,
36
39
  type BackendResult,
37
40
  BackendRuntime,
@@ -46,6 +49,7 @@ export {
46
49
  type GetEventsInput,
47
50
  type GetEventsSnapshot,
48
51
  type GetJobInput,
52
+ type GetProjectOutlineInput,
49
53
  type InProcessLockConflictError,
50
54
  type ListJobsInput,
51
55
  type MaterializeSessionInput,
@@ -16,6 +16,7 @@ const BACKEND_METHODS = [
16
16
  'openSession',
17
17
  'openProjectSession',
18
18
  'getSession',
19
+ 'getProjectOutline',
19
20
  'applyTransaction',
20
21
  'saveSession',
21
22
  'materializeSession',
@@ -47,6 +48,7 @@ export function createCapabilities(): BackendCapabilities {
47
48
  read: {
48
49
  capabilitySnapshot: true,
49
50
  sessionSnapshot: true,
51
+ projectOutline: true,
50
52
  },
51
53
  authoring: {
52
54
  applyTransaction: true,
@@ -1,4 +1,9 @@
1
- import type { UamProject, UamTransactionOperation } from '@openfairygui/core/uam';
1
+ import type {
2
+ UamDisplayNodeKind,
3
+ UamProject,
4
+ UamResource,
5
+ UamTransactionOperation,
6
+ } from '@openfairygui/core/uam';
2
7
  import type { ApplyUamTransactionAppError } from '@openfairygui/functions/uam';
3
8
  import type {
4
9
  BACKEND_CAPABILITY_SCHEMA_VERSION,
@@ -94,6 +99,7 @@ export interface BackendCapabilities {
94
99
  'openSession',
95
100
  'openProjectSession',
96
101
  'getSession',
102
+ 'getProjectOutline',
97
103
  'applyTransaction',
98
104
  'saveSession',
99
105
  'materializeSession',
@@ -108,6 +114,7 @@ export interface BackendCapabilities {
108
114
  read: {
109
115
  capabilitySnapshot: true;
110
116
  sessionSnapshot: true;
117
+ projectOutline: true;
111
118
  };
112
119
  authoring: {
113
120
  applyTransaction: true;
@@ -178,6 +185,37 @@ export interface BackendSessionSnapshot {
178
185
  capabilities: BackendCapabilities;
179
186
  }
180
187
 
188
+ export interface BackendProjectOutline {
189
+ sessionId: string;
190
+ revision: number;
191
+ projectId: string;
192
+ projectType: number;
193
+ version: string;
194
+ branches: string[];
195
+ packages: BackendProjectOutlinePackage[];
196
+ }
197
+
198
+ export interface BackendProjectOutlinePackage {
199
+ id: string;
200
+ name: string;
201
+ branchNames: string[];
202
+ folders: Array<{ branch: string; path: string }>;
203
+ resources: BackendProjectOutlineResource[];
204
+ }
205
+
206
+ export interface BackendProjectOutlineResource {
207
+ id: string;
208
+ name: string;
209
+ path: string;
210
+ kind: UamResource['kind'];
211
+ branch: string;
212
+ component?: {
213
+ displayList: Array<{ id: string; name: string; kind: UamDisplayNodeKind }>;
214
+ controllers: Array<{ name: string; pages: Array<{ id: string; name: string }> }>;
215
+ transitions: Array<{ name: string }>;
216
+ };
217
+ }
218
+
181
219
  export interface MaterializeSessionSnapshot extends BackendSessionSnapshot {
182
220
  mode: 'fullProject';
183
221
  reason?: string;
@@ -476,6 +514,10 @@ export interface ApplySessionTransactionInput {
476
514
  operations: UamTransactionOperation[];
477
515
  }
478
516
 
517
+ export interface GetProjectOutlineInput {
518
+ sessionId: string;
519
+ }
520
+
479
521
  export interface OpenProjectSessionInput {
480
522
  /** Authoritative UAM project. Use BackendRuntime.openSession() when importing an existing project from storage. */
481
523
  project: UamProject;
package/src/runtime.ts CHANGED
@@ -21,6 +21,7 @@ import type {
21
21
  BackendJobNotCancellableError,
22
22
  BackendJobNotFoundError,
23
23
  BackendJobSnapshot,
24
+ BackendProjectOutline,
24
25
  BackendResult,
25
26
  BackendRuntimeOptions,
26
27
  BackendSessionSnapshot,
@@ -31,6 +32,7 @@ import type {
31
32
  GetEventsInput,
32
33
  GetEventsSnapshot,
33
34
  GetJobInput,
35
+ GetProjectOutlineInput,
34
36
  InProcessLockConflictError,
35
37
  ListJobsInput,
36
38
  MaterializeSessionInput,
@@ -113,6 +115,12 @@ export class BackendRuntime {
113
115
  return this.readService.getSession(input);
114
116
  }
115
117
 
118
+ public getProjectOutline(
119
+ input: GetProjectOutlineInput,
120
+ ): BackendResult<BackendProjectOutline, SessionNotFoundError> {
121
+ return this.readService.getProjectOutline(input);
122
+ }
123
+
116
124
  public async applyTransaction(
117
125
  input: ApplySessionTransactionInput,
118
126
  ): Promise<
@@ -1,7 +1,54 @@
1
- import { failure, success, type BackendContext } from './context.js';
2
- import type { BackendCapabilities, BackendResult, BackendSessionSnapshot, SessionNotFoundError } from '../runtime.js';
1
+ import { failure, success, type BackendContext, type BackendSessionState } from './context.js';
2
+ import type {
3
+ BackendCapabilities,
4
+ BackendProjectOutline,
5
+ BackendResult,
6
+ BackendSessionSnapshot,
7
+ GetProjectOutlineInput,
8
+ SessionNotFoundError,
9
+ } from '../runtime.js';
3
10
  import { createSessionNotFoundError, toSessionSnapshot } from './session-utils.js';
4
11
 
12
+ function toProjectOutline(session: BackendSessionState): BackendProjectOutline {
13
+ const project = session.project;
14
+ // ponytail: full outline is O(project size); add filters or pagination only if payload size becomes a measured problem.
15
+ return {
16
+ sessionId: session.sessionId,
17
+ revision: session.revision,
18
+ projectId: project.projectId,
19
+ projectType: project.projectType,
20
+ version: project.version,
21
+ branches: [...project.branches],
22
+ packages: project.packages.map((pkg) => ({
23
+ id: pkg.id,
24
+ name: pkg.name,
25
+ branchNames: [...pkg.branchNames],
26
+ folders: pkg.folders.map((folder) => ({ branch: folder.branch, path: folder.path })),
27
+ resources: pkg.resources.map((resource) => ({
28
+ id: resource.id,
29
+ name: resource.name,
30
+ path: resource.path,
31
+ kind: resource.kind,
32
+ branch: resource.branch,
33
+ ...(resource.kind === 'component' ? {
34
+ component: {
35
+ displayList: resource.component.displayList.map((node) => ({
36
+ id: node.id,
37
+ name: node.name,
38
+ kind: node.kind,
39
+ })),
40
+ controllers: resource.component.controllers.map((controller) => ({
41
+ name: controller.name,
42
+ pages: controller.pages.map((page) => ({ id: page.id, name: page.name })),
43
+ })),
44
+ transitions: resource.component.transitions.map((transition) => ({ name: transition.name })),
45
+ },
46
+ } : {}),
47
+ })),
48
+ })),
49
+ };
50
+ }
51
+
5
52
  export class ReadService {
6
53
  public constructor(private readonly context: BackendContext) {}
7
54
 
@@ -20,4 +67,18 @@ export class ReadService {
20
67
  revision: session.revision,
21
68
  });
22
69
  }
70
+
71
+ public getProjectOutline(
72
+ input: GetProjectOutlineInput,
73
+ ): BackendResult<BackendProjectOutline, SessionNotFoundError> {
74
+ const startedAt = Date.now();
75
+ const session = this.context.sessions.get(input.sessionId);
76
+ if (!session || session.closed) {
77
+ return failure('read', startedAt, createSessionNotFoundError(input.sessionId));
78
+ }
79
+ return success('read', startedAt, toProjectOutline(session), {
80
+ sessionId: session.sessionId,
81
+ revision: session.revision,
82
+ });
83
+ }
23
84
  }