@supernova-studio/client 1.16.0 → 1.16.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/dist/index.mjs CHANGED
@@ -5265,7 +5265,8 @@ var ForgeProjectRoomUpdate = z183.object({
5265
5265
  artifacts: z183.array(ForgeProjectArtifact).optional(),
5266
5266
  artifactIdsToDelete: z183.array(z183.string()).optional(),
5267
5267
  features: z183.array(ProjectFeature).optional(),
5268
- featureIdsToDelete: z183.array(z183.string()).optional()
5268
+ featureIdsToDelete: z183.array(z183.string()).optional(),
5269
+ executedTransactionIds: z183.string().array().optional()
5269
5270
  });
5270
5271
  var RoomTypeEnum = /* @__PURE__ */ ((RoomTypeEnum2) => {
5271
5272
  RoomTypeEnum2["DocumentationPageOld"] = "documentation-page";
@@ -9085,22 +9086,17 @@ var DTOForgeSectionItemMoveInput = z310.object({
9085
9086
  });
9086
9087
 
9087
9088
  // src/api/dto/forge/project-artifact.ts
9088
- var omitProps = {
9089
- projectId: true,
9090
- createdByUserId: true,
9091
- createdAt: true,
9092
- updatedAt: true,
9093
- sortOrder: true
9094
- };
9095
9089
  var DTOForgeProjectArtifact = ForgeProjectArtifact;
9096
- var DTOForgeProjectArtifactUpdateInput = DTOForgeProjectArtifact.omit({
9097
- ...omitProps,
9098
- iterationId: true
9099
- }).partial().extend({
9100
- id: ForgeProjectArtifact.shape.id
9101
- // explicitly reintroduce required id
9102
- });
9103
- var DTOForgeProjectArtifactCreateInput = DTOForgeProjectArtifact.omit(omitProps);
9090
+ var DTOForgeProjectArtifactUpdateInput = z311.object({
9091
+ id: z311.string(),
9092
+ title: z311.string().optional()
9093
+ });
9094
+ var DTOForgeProjectArtifactCreateInput = z311.object({
9095
+ id: z311.string(),
9096
+ title: z311.string(),
9097
+ sectionId: z311.string().optional(),
9098
+ afterArtifactId: z311.string().optional().nullable()
9099
+ });
9104
9100
  var DTOForgeProjectArtifactDeleteInput = z311.object({
9105
9101
  id: Id
9106
9102
  });
@@ -9158,7 +9154,7 @@ var DTOForgeProjectActionFeatureCreate = z313.object({
9158
9154
  });
9159
9155
  var DTOForgeProjectActionFeatureUpdate = z313.object({
9160
9156
  type: z313.literal("FeatureUpdate"),
9161
- input: DTOForgeProjectFeatureCreateInput
9157
+ input: DTOForgeProjectFeatureUpdateInput
9162
9158
  });
9163
9159
  var DTOForgeProjectActionFeatureMove = z313.object({
9164
9160
  type: z313.literal("FeatureMove"),
@@ -9216,7 +9212,11 @@ var DTOForgeProjectAction = z313.discriminatedUnion("type", [
9216
9212
  DTOForgeProjectActionSectionUpdate,
9217
9213
  DTOForgeProjectActionSectionDelete,
9218
9214
  DTOForgeProjectActionSectionMove
9219
- ]);
9215
+ ]).and(
9216
+ z313.object({
9217
+ tId: z313.string().optional()
9218
+ })
9219
+ );
9220
9220
 
9221
9221
  // src/api/dto/forge/project-artifact-room.ts
9222
9222
  import { z as z314 } from "zod";
@@ -11534,110 +11534,400 @@ var DTOEventDataSourcesImported = z342.object({
11534
11534
  import { z as z343 } from "zod";
11535
11535
  var DTOEvent = z343.discriminatedUnion("type", [DTOEventDataSourcesImported, DTOEventFigmaNodesRendered]);
11536
11536
 
11537
- // src/sync/docs-structure-repo.ts
11538
- import PQueue from "p-queue";
11539
-
11540
- // src/yjs/design-system-content/documentation-hierarchy.ts
11541
- import { z as z344 } from "zod";
11542
-
11543
- // src/yjs/version-room/base.ts
11544
- var VersionRoomBaseYDoc = class {
11545
- constructor(yDoc) {
11546
- __publicField(this, "yDoc");
11547
- this.yDoc = yDoc;
11537
+ // src/sync/docs-local-action-executor.ts
11538
+ function applyActionsLocally(input) {
11539
+ const actionExecutor = new LocalDocsElementActionExecutor(input);
11540
+ actionExecutor.applyActions(input.actions);
11541
+ return actionExecutor.localState;
11542
+ }
11543
+ var LocalDocsElementActionExecutor = class {
11544
+ constructor(config) {
11545
+ __publicField(this, "userId");
11546
+ __publicField(this, "designSystemVersionId");
11547
+ __publicField(this, "pages");
11548
+ __publicField(this, "groups");
11549
+ __publicField(this, "approvalStates");
11550
+ __publicField(this, "pageLiveblockRoomIds");
11551
+ const { designSystemVersionId, remoteState, userId } = config;
11552
+ this.userId = userId;
11553
+ this.designSystemVersionId = designSystemVersionId;
11554
+ this.pages = mapByUnique(remoteState.pages, (p) => p.persistentId);
11555
+ this.groups = mapByUnique(remoteState.groups, (p) => p.persistentId);
11556
+ this.approvalStates = mapByUnique(remoteState.approvals, (a) => a.pagePersistentId);
11557
+ this.pageLiveblockRoomIds = { ...remoteState.pageLiveblockRoomIds };
11548
11558
  }
11549
- getState() {
11550
- const groups = this.getGroups();
11551
- const isLoaded = !!groups.length;
11559
+ get localState() {
11552
11560
  return {
11553
- isLoaded,
11554
- groups,
11555
- pages: this.getPages(),
11556
- approvals: this.getApprovals(),
11557
- groupSnapshots: this.getGroupSnapshots(),
11558
- pageContentHashes: this.getDocumentationPageContentHashes(),
11559
- pageSnapshots: this.getPageSnapshots(),
11560
- settings: this.getDocumentationInternalSettings(),
11561
- pageLiveblockRoomIds: this.getDocumentationPageLiveblocksRoomIds(),
11562
- executedTransactionIds: this.getExecutedTransactionIds()
11561
+ pages: Array.from(this.pages.values()),
11562
+ groups: Array.from(this.groups.values()),
11563
+ approvals: Array.from(this.approvalStates.values()),
11564
+ pageLiveblockRoomIds: this.pageLiveblockRoomIds
11563
11565
  };
11564
11566
  }
11565
- //
11566
- // Pages
11567
- //
11568
- getPages() {
11569
- return this.getObjects(this.pagesYMap, DocumentationPageV2);
11570
- }
11571
- updatePages(pages) {
11572
- pages = pages.map((page) => {
11573
- return {
11574
- ...page,
11575
- data: {
11576
- configuration: page.data.configuration
11577
- }
11578
- };
11579
- });
11580
- this.setObjects(this.pagesYMap, pages);
11581
- }
11582
- deletePages(ids) {
11583
- this.deleteObjects(this.pagesYMap, ids);
11567
+ applyActions(trx) {
11568
+ trx.forEach((trx2) => this.applyTransaction(trx2));
11584
11569
  }
11585
- get pagesYMap() {
11586
- return this.yDoc.getMap("documentationPages");
11570
+ applyTransaction(trx) {
11571
+ switch (trx.type) {
11572
+ // Groups
11573
+ case "DocumentationGroupCreate":
11574
+ return this.documentationGroupCreate(trx);
11575
+ case "DocumentationGroupUpdate":
11576
+ return this.documentationGroupUpdate(trx);
11577
+ case "DocumentationGroupMove":
11578
+ return this.documentationGroupMove(trx);
11579
+ // Groups - unsupported
11580
+ case "DocumentationGroupDelete":
11581
+ case "DocumentationGroupDuplicate":
11582
+ case "DocumentationGroupRestore":
11583
+ throw new Error(`Transaction type ${trx.type} is not yet implemented`);
11584
+ // Pages
11585
+ case "DocumentationPageCreate":
11586
+ return this.documentationPageCreate(trx);
11587
+ case "DocumentationPageUpdate":
11588
+ return this.documentationPageUpdate(trx);
11589
+ case "DocumentationPageMove":
11590
+ return this.documentationPageMove(trx);
11591
+ case "DocumentationPageDelete":
11592
+ return this.documentationPageDelete(trx);
11593
+ // Pages - unsupported
11594
+ case "DocumentationPageApprovalStateChange":
11595
+ return this.documentationApprovalStateUpdate(trx);
11596
+ case "DocumentationPageDuplicate":
11597
+ case "DocumentationPageRestore":
11598
+ throw new Error(`Transaction type ${trx.type} is not yet implemented`);
11599
+ // Tabs
11600
+ case "DocumentationTabCreate":
11601
+ return this.documentationTabCreate(trx);
11602
+ case "DocumentationTabGroupDelete":
11603
+ throw new Error(`Transaction type ${trx.type} is not yet implemented`);
11604
+ // Won't ever be supported
11605
+ case "FigmaNodeRender":
11606
+ case "FigmaNodeRenderAsync":
11607
+ throw new Error(`Transaction type ${trx.type} is not a documentation element action`);
11608
+ }
11587
11609
  }
11588
11610
  //
11589
- // Groups
11611
+ // Pages
11590
11612
  //
11591
- getGroups() {
11592
- return this.getObjects(this.groupsYMap, ElementGroup);
11613
+ documentationPageCreate(trx) {
11614
+ const { input } = trx;
11615
+ const { persistentId } = input;
11616
+ if (this.pages.has(input.persistentId)) {
11617
+ return;
11618
+ }
11619
+ if (!this.groups.has(input.parentPersistentId)) {
11620
+ throw new Error(`Cannot create page: parent persistent id ${input.parentPersistentId} was not found`);
11621
+ }
11622
+ const localPage = {
11623
+ persistentId,
11624
+ createdAt: /* @__PURE__ */ new Date(),
11625
+ parentPersistentId: input.parentPersistentId,
11626
+ shortPersistentId: generateShortPersistentId(),
11627
+ slug: slugify(input.title),
11628
+ meta: { name: input.title },
11629
+ updatedAt: /* @__PURE__ */ new Date(),
11630
+ data: {
11631
+ // TODO Artem: move somewhere reusable
11632
+ configuration: input.configuration ? { ...defaultDocumentationItemConfigurationV2, ...input.configuration } : input.configuration
11633
+ },
11634
+ sortOrder: this.calculateSortOrder(input.parentPersistentId, input.afterPersistentId),
11635
+ designSystemVersionId: this.designSystemVersionId
11636
+ };
11637
+ this.pages.set(persistentId, localPage);
11638
+ const roomId = `${RoomType.DocumentationPage}:${this.designSystemVersionId}:${persistentId}`;
11639
+ this.pageLiveblockRoomIds[persistentId] = roomId;
11593
11640
  }
11594
- updateGroups(groups) {
11595
- this.setObjects(this.groupsYMap, groups);
11641
+ documentationPageUpdate(trx) {
11642
+ const { input } = trx;
11643
+ const existingPage = this.pages.get(input.id);
11644
+ if (!existingPage) {
11645
+ throw new Error(`Cannot update page: page id ${input.id} was not found`);
11646
+ }
11647
+ const localPage = {
11648
+ ...existingPage,
11649
+ userSlug: void 0,
11650
+ meta: {
11651
+ ...existingPage.meta,
11652
+ name: input.title ?? existingPage.meta.name
11653
+ },
11654
+ data: {
11655
+ // TODO Artem: move somewhere reusable
11656
+ configuration: input.configuration ? { ...existingPage.data.configuration ?? defaultDocumentationItemConfigurationV2, ...input.configuration } : existingPage.data.configuration
11657
+ }
11658
+ };
11659
+ this.pages.set(localPage.persistentId, localPage);
11596
11660
  }
11597
- deleteGroups(ids) {
11598
- this.deleteObjects(this.groupsYMap, ids);
11661
+ documentationPageMove(trx) {
11662
+ const { input } = trx;
11663
+ if (!this.groups.has(input.parentPersistentId)) {
11664
+ throw new Error(`Cannot move page: page parent id ${input.parentPersistentId} was not found`);
11665
+ }
11666
+ const existingPage = this.pages.get(input.id);
11667
+ if (!existingPage) {
11668
+ throw new Error(`Cannot update page: page id ${input.id} was not found`);
11669
+ }
11670
+ const localPage = {
11671
+ ...existingPage,
11672
+ userSlug: void 0,
11673
+ sortOrder: this.calculateSortOrder(input.parentPersistentId, input.afterPersistentId),
11674
+ parentPersistentId: input.parentPersistentId
11675
+ };
11676
+ this.pages.set(localPage.persistentId, localPage);
11599
11677
  }
11600
- get groupsYMap() {
11601
- return this.yDoc.getMap("documentationGroups");
11678
+ documentationPageDelete(trx) {
11679
+ const { input } = trx;
11680
+ if (!this.pages.delete(trx.input.id)) {
11681
+ throw new Error(`Cannot delete page: page id ${input.id} was not found`);
11682
+ }
11683
+ delete this.pageLiveblockRoomIds[trx.input.id];
11602
11684
  }
11603
11685
  //
11604
- // Documentation internal settings
11686
+ // Group
11605
11687
  //
11606
- getDocumentationInternalSettings() {
11607
- const map = this.internalSettingsYMap;
11608
- const rawSettings = {
11609
- routingVersion: map.get("routingVersion"),
11610
- isDraftFeatureAdopted: map.get("isDraftFeatureAdopted") ?? false,
11611
- isApprovalFeatureEnabled: map.get("isApprovalFeatureEnabled") ?? false,
11612
- approvalRequiredForPublishing: map.get("approvalRequiredForPublishing") ?? false
11613
- };
11614
- const settingsParseResult = DocumentationHierarchySettings.safeParse(rawSettings);
11615
- if (!settingsParseResult.success) {
11616
- return {
11617
- routingVersion: "2",
11618
- isDraftFeatureAdopted: false,
11619
- isApprovalFeatureEnabled: false,
11620
- approvalRequiredForPublishing: false
11621
- };
11688
+ documentationGroupCreate(trx) {
11689
+ const { input } = trx;
11690
+ if (this.groups.has(input.persistentId)) {
11691
+ return;
11622
11692
  }
11623
- return settingsParseResult.data;
11624
- }
11625
- updateDocumentationInternalSettings(settings) {
11626
- const map = this.internalSettingsYMap;
11627
- map.set("routingVersion", settings.routingVersion ?? map.get("routingVersion"));
11628
- map.set("isDraftFeatureAdopted", settings.isDraftFeatureAdopted ?? map.get("isDraftFeatureAdopted"));
11629
- map.set("isApprovalFeatureEnabled", settings.isApprovalFeatureEnabled ?? map.get("isApprovalFeatureEnabled"));
11630
- map.set(
11631
- "approvalRequiredForPublishing",
11632
- settings.approvalRequiredForPublishing ?? map.get("approvalRequiredForPublishing")
11633
- );
11634
- }
11635
- get internalSettingsYMap() {
11636
- return this.yDoc.getMap("documentationInternalSettings");
11693
+ const localGroup = {
11694
+ parentPersistentId: input.parentPersistentId,
11695
+ persistentId: input.persistentId,
11696
+ shortPersistentId: generateShortPersistentId(),
11697
+ slug: slugify(input.title),
11698
+ meta: { name: input.title },
11699
+ createdAt: /* @__PURE__ */ new Date(),
11700
+ updatedAt: /* @__PURE__ */ new Date(),
11701
+ data: {
11702
+ // TODO Artem: move somewhere reusable
11703
+ configuration: input.configuration ? { ...defaultDocumentationItemConfigurationV2, ...input.configuration } : input.configuration
11704
+ },
11705
+ sortOrder: this.calculateSortOrder(input.parentPersistentId, input.afterPersistentId),
11706
+ designSystemVersionId: this.designSystemVersionId
11707
+ };
11708
+ this.groups.set(localGroup.persistentId, localGroup);
11637
11709
  }
11638
- //
11639
- // Documentation page snapshot
11640
- //
11710
+ documentationGroupUpdate(trx) {
11711
+ const { input } = trx;
11712
+ const existingGroup = this.groups.get(input.id);
11713
+ if (!existingGroup) {
11714
+ throw new Error(`Cannot update group: group id ${input.id} was not found`);
11715
+ }
11716
+ const localGroup = {
11717
+ ...existingGroup,
11718
+ userSlug: void 0,
11719
+ meta: {
11720
+ ...existingGroup.meta,
11721
+ name: input.title ?? existingGroup.meta.name
11722
+ },
11723
+ data: {
11724
+ ...existingGroup.data,
11725
+ // TODO Artem: move somewhere reusable
11726
+ configuration: input.configuration ? {
11727
+ ...existingGroup.data?.configuration ?? defaultDocumentationItemConfigurationV2,
11728
+ ...input.configuration
11729
+ } : existingGroup.data?.configuration
11730
+ }
11731
+ };
11732
+ this.groups.set(localGroup.persistentId, localGroup);
11733
+ }
11734
+ documentationGroupMove(trx) {
11735
+ const { input } = trx;
11736
+ if (!this.groups.has(input.parentPersistentId)) {
11737
+ throw new Error(`Cannot move group: group parent id ${input.parentPersistentId} was not found`);
11738
+ }
11739
+ const existingGroup = this.groups.get(input.id);
11740
+ if (!existingGroup) {
11741
+ throw new Error(`Cannot update group: group id ${input.id} was not found`);
11742
+ }
11743
+ const localGroup = {
11744
+ ...existingGroup,
11745
+ userSlug: void 0,
11746
+ sortOrder: this.calculateSortOrder(input.parentPersistentId, input.afterPersistentId),
11747
+ parentPersistentId: input.parentPersistentId
11748
+ };
11749
+ this.groups.set(localGroup.persistentId, localGroup);
11750
+ }
11751
+ //
11752
+ // Tabs
11753
+ //
11754
+ documentationTabCreate(trx) {
11755
+ const { input } = trx;
11756
+ const page = this.pages.get(input.fromItemPersistentId);
11757
+ if (!page) {
11758
+ throw new Error(`Cannot create tab: page id ${input.fromItemPersistentId} was not found`);
11759
+ }
11760
+ const tabGroup = {
11761
+ parentPersistentId: page.parentPersistentId,
11762
+ persistentId: input.persistentId,
11763
+ shortPersistentId: generateShortPersistentId(),
11764
+ slug: page.slug,
11765
+ meta: page.meta,
11766
+ createdAt: /* @__PURE__ */ new Date(),
11767
+ updatedAt: /* @__PURE__ */ new Date(),
11768
+ data: {
11769
+ behavior: "Tabs",
11770
+ configuration: page?.data.configuration
11771
+ },
11772
+ sortOrder: page.sortOrder,
11773
+ designSystemVersionId: this.designSystemVersionId
11774
+ };
11775
+ this.groups.set(input.persistentId, tabGroup);
11776
+ const newLocalPage = {
11777
+ ...page,
11778
+ userSlug: void 0,
11779
+ sortOrder: 0,
11780
+ parentPersistentId: input.persistentId,
11781
+ meta: { name: input.tabName }
11782
+ };
11783
+ this.pages.set(newLocalPage.persistentId, newLocalPage);
11784
+ }
11785
+ //
11786
+ // Approval states
11787
+ //
11788
+ documentationApprovalStateUpdate(trx) {
11789
+ const { input } = trx;
11790
+ const existingApproval = this.approvalStates.get(input.persistentId);
11791
+ if (input.approvalState) {
11792
+ this.approvalStates.set(input.persistentId, {
11793
+ approvalState: input.approvalState,
11794
+ createdAt: existingApproval?.createdAt ?? /* @__PURE__ */ new Date(),
11795
+ designSystemVersionId: this.designSystemVersionId,
11796
+ pagePersistentId: input.persistentId,
11797
+ updatedAt: /* @__PURE__ */ new Date(),
11798
+ updatedByUserId: this.userId
11799
+ });
11800
+ } else {
11801
+ this.approvalStates.delete(input.persistentId);
11802
+ }
11803
+ }
11804
+ //
11805
+ // Utils
11806
+ //
11807
+ calculateSortOrder(parentPersistentId, afterPersistentId) {
11808
+ const sortOrderStep = Math.pow(2, 16);
11809
+ const neighbours = [
11810
+ ...Array.from(this.pages.values()).filter((p) => p.parentPersistentId === parentPersistentId),
11811
+ ...Array.from(this.groups.values()).filter((g) => g.parentPersistentId === parentPersistentId)
11812
+ ];
11813
+ if (!neighbours.length) return 0;
11814
+ neighbours.sort((lhs, rhs) => lhs.sortOrder - rhs.sortOrder);
11815
+ if (afterPersistentId === null) return neighbours[0].sortOrder - sortOrderStep;
11816
+ if (!afterPersistentId) return neighbours[neighbours.length - 1].sortOrder + sortOrderStep;
11817
+ const index = neighbours.findIndex((e) => e.persistentId === afterPersistentId);
11818
+ if (index < 0 || index === neighbours.length - 1) {
11819
+ return neighbours[neighbours.length - 1].sortOrder + sortOrderStep;
11820
+ }
11821
+ const left = neighbours[index].sortOrder;
11822
+ const right = neighbours[index + 1]?.sortOrder ?? left + sortOrderStep * 2;
11823
+ return (right + left) / 2;
11824
+ }
11825
+ };
11826
+
11827
+ // src/sync/docs-structure-repo.ts
11828
+ import PQueue from "p-queue";
11829
+
11830
+ // src/yjs/design-system-content/documentation-hierarchy.ts
11831
+ import { z as z344 } from "zod";
11832
+
11833
+ // src/yjs/version-room/base.ts
11834
+ var VersionRoomBaseYDoc = class {
11835
+ constructor(yDoc) {
11836
+ __publicField(this, "yDoc");
11837
+ this.yDoc = yDoc;
11838
+ }
11839
+ getState() {
11840
+ const groups = this.getGroups();
11841
+ const isLoaded = !!groups.length;
11842
+ return {
11843
+ isLoaded,
11844
+ groups,
11845
+ pages: this.getPages(),
11846
+ approvals: this.getApprovals(),
11847
+ groupSnapshots: this.getGroupSnapshots(),
11848
+ pageContentHashes: this.getDocumentationPageContentHashes(),
11849
+ pageSnapshots: this.getPageSnapshots(),
11850
+ settings: this.getDocumentationInternalSettings(),
11851
+ pageLiveblockRoomIds: this.getDocumentationPageLiveblocksRoomIds(),
11852
+ executedTransactionIds: this.getExecutedTransactionIds()
11853
+ };
11854
+ }
11855
+ //
11856
+ // Pages
11857
+ //
11858
+ getPages() {
11859
+ return this.getObjects(this.pagesYMap, DocumentationPageV2);
11860
+ }
11861
+ updatePages(pages) {
11862
+ pages = pages.map((page) => {
11863
+ return {
11864
+ ...page,
11865
+ data: {
11866
+ configuration: page.data.configuration
11867
+ }
11868
+ };
11869
+ });
11870
+ this.setObjects(this.pagesYMap, pages);
11871
+ }
11872
+ deletePages(ids) {
11873
+ this.deleteObjects(this.pagesYMap, ids);
11874
+ }
11875
+ get pagesYMap() {
11876
+ return this.yDoc.getMap("documentationPages");
11877
+ }
11878
+ //
11879
+ // Groups
11880
+ //
11881
+ getGroups() {
11882
+ return this.getObjects(this.groupsYMap, ElementGroup);
11883
+ }
11884
+ updateGroups(groups) {
11885
+ this.setObjects(this.groupsYMap, groups);
11886
+ }
11887
+ deleteGroups(ids) {
11888
+ this.deleteObjects(this.groupsYMap, ids);
11889
+ }
11890
+ get groupsYMap() {
11891
+ return this.yDoc.getMap("documentationGroups");
11892
+ }
11893
+ //
11894
+ // Documentation internal settings
11895
+ //
11896
+ getDocumentationInternalSettings() {
11897
+ const map = this.internalSettingsYMap;
11898
+ const rawSettings = {
11899
+ routingVersion: map.get("routingVersion"),
11900
+ isDraftFeatureAdopted: map.get("isDraftFeatureAdopted") ?? false,
11901
+ isApprovalFeatureEnabled: map.get("isApprovalFeatureEnabled") ?? false,
11902
+ approvalRequiredForPublishing: map.get("approvalRequiredForPublishing") ?? false
11903
+ };
11904
+ const settingsParseResult = DocumentationHierarchySettings.safeParse(rawSettings);
11905
+ if (!settingsParseResult.success) {
11906
+ return {
11907
+ routingVersion: "2",
11908
+ isDraftFeatureAdopted: false,
11909
+ isApprovalFeatureEnabled: false,
11910
+ approvalRequiredForPublishing: false
11911
+ };
11912
+ }
11913
+ return settingsParseResult.data;
11914
+ }
11915
+ updateDocumentationInternalSettings(settings) {
11916
+ const map = this.internalSettingsYMap;
11917
+ map.set("routingVersion", settings.routingVersion ?? map.get("routingVersion"));
11918
+ map.set("isDraftFeatureAdopted", settings.isDraftFeatureAdopted ?? map.get("isDraftFeatureAdopted"));
11919
+ map.set("isApprovalFeatureEnabled", settings.isApprovalFeatureEnabled ?? map.get("isApprovalFeatureEnabled"));
11920
+ map.set(
11921
+ "approvalRequiredForPublishing",
11922
+ settings.approvalRequiredForPublishing ?? map.get("approvalRequiredForPublishing")
11923
+ );
11924
+ }
11925
+ get internalSettingsYMap() {
11926
+ return this.yDoc.getMap("documentationInternalSettings");
11927
+ }
11928
+ //
11929
+ // Documentation page snapshot
11930
+ //
11641
11931
  getPageSnapshots() {
11642
11932
  return this.getObjects(this.documentationPagePublishedStatesYMap, DocumentationPageSnapshot);
11643
11933
  }
@@ -16488,11 +16778,13 @@ var ForgeProjectRoomBaseYDoc = class {
16488
16778
  getState() {
16489
16779
  const artifacts = this.getArtifacts();
16490
16780
  const features = this.getFeatures();
16781
+ const executedTransactionIds = this.getExecutedTransactionIds();
16491
16782
  const isLoaded = true;
16492
16783
  return {
16493
16784
  isLoaded,
16494
16785
  artifacts,
16495
- features
16786
+ features,
16787
+ executedTransactionIds
16496
16788
  };
16497
16789
  }
16498
16790
  //
@@ -16526,6 +16818,27 @@ var ForgeProjectRoomBaseYDoc = class {
16526
16818
  return this.yDoc.getMap("forgeProjectFeatures");
16527
16819
  }
16528
16820
  //
16821
+ // Executed transactions
16822
+ //
16823
+ updateExecutedTransactionIds(transactionIds) {
16824
+ transactionIds = Array.from(new Set(transactionIds));
16825
+ if (!transactionIds.length) return;
16826
+ const array = this.executedTransactionIdsArray;
16827
+ array.push(transactionIds);
16828
+ if (array.length > 100) {
16829
+ array.delete(0, array.length - 100);
16830
+ }
16831
+ }
16832
+ getExecutedTransactionIds() {
16833
+ const array = this.executedTransactionIdsArray;
16834
+ const transactionIds = [];
16835
+ array.forEach((e) => typeof e === "string" && transactionIds.push(e));
16836
+ return transactionIds;
16837
+ }
16838
+ get executedTransactionIdsArray() {
16839
+ return this.yDoc.getArray("executedTransactionIds");
16840
+ }
16841
+ //
16529
16842
  // Utility methods
16530
16843
  //
16531
16844
  getObjects(map, schema) {
@@ -16554,6 +16867,7 @@ var BackendForgeProjectRoomYDoc = class {
16554
16867
  transaction.artifacts && yDoc.updateArtifacts(transaction.artifacts);
16555
16868
  transaction.featureIdsToDelete && yDoc.deleteFeatures(transaction.featureIdsToDelete);
16556
16869
  transaction.features && yDoc.updateFeatures(transaction.features);
16870
+ transaction.executedTransactionIds && yDoc.updateExecutedTransactionIds(transaction.executedTransactionIds);
16557
16871
  });
16558
16872
  }
16559
16873
  };
@@ -16591,298 +16905,8 @@ var BackendVersionRoomYDoc = class {
16591
16905
  }
16592
16906
  };
16593
16907
 
16594
- // src/sync/local-action-executor.ts
16595
- function applyActionsLocally(input) {
16596
- const actionExecutor = new LocalDocsElementActionExecutor(input);
16597
- actionExecutor.applyActions(input.actions);
16598
- return actionExecutor.localState;
16599
- }
16600
- var LocalDocsElementActionExecutor = class {
16601
- constructor(config) {
16602
- __publicField(this, "userId");
16603
- __publicField(this, "designSystemVersionId");
16604
- __publicField(this, "pages");
16605
- __publicField(this, "groups");
16606
- __publicField(this, "approvalStates");
16607
- __publicField(this, "pageLiveblockRoomIds");
16608
- const { designSystemVersionId, remoteState, userId } = config;
16609
- this.userId = userId;
16610
- this.designSystemVersionId = designSystemVersionId;
16611
- this.pages = mapByUnique(remoteState.pages, (p) => p.persistentId);
16612
- this.groups = mapByUnique(remoteState.groups, (p) => p.persistentId);
16613
- this.approvalStates = mapByUnique(remoteState.approvals, (a) => a.pagePersistentId);
16614
- this.pageLiveblockRoomIds = { ...remoteState.pageLiveblockRoomIds };
16615
- }
16616
- get localState() {
16617
- return {
16618
- pages: Array.from(this.pages.values()),
16619
- groups: Array.from(this.groups.values()),
16620
- approvals: Array.from(this.approvalStates.values()),
16621
- pageLiveblockRoomIds: this.pageLiveblockRoomIds
16622
- };
16623
- }
16624
- applyActions(trx) {
16625
- trx.forEach((trx2) => this.applyTransaction(trx2));
16626
- }
16627
- applyTransaction(trx) {
16628
- switch (trx.type) {
16629
- // Groups
16630
- case "DocumentationGroupCreate":
16631
- return this.documentationGroupCreate(trx);
16632
- case "DocumentationGroupUpdate":
16633
- return this.documentationGroupUpdate(trx);
16634
- case "DocumentationGroupMove":
16635
- return this.documentationGroupMove(trx);
16636
- // Groups - unsupported
16637
- case "DocumentationGroupDelete":
16638
- case "DocumentationGroupDuplicate":
16639
- case "DocumentationGroupRestore":
16640
- throw new Error(`Transaction type ${trx.type} is not yet implemented`);
16641
- // Pages
16642
- case "DocumentationPageCreate":
16643
- return this.documentationPageCreate(trx);
16644
- case "DocumentationPageUpdate":
16645
- return this.documentationPageUpdate(trx);
16646
- case "DocumentationPageMove":
16647
- return this.documentationPageMove(trx);
16648
- case "DocumentationPageDelete":
16649
- return this.documentationPageDelete(trx);
16650
- // Pages - unsupported
16651
- case "DocumentationPageApprovalStateChange":
16652
- return this.documentationApprovalStateUpdate(trx);
16653
- case "DocumentationPageDuplicate":
16654
- case "DocumentationPageRestore":
16655
- throw new Error(`Transaction type ${trx.type} is not yet implemented`);
16656
- // Tabs
16657
- case "DocumentationTabCreate":
16658
- return this.documentationTabCreate(trx);
16659
- case "DocumentationTabGroupDelete":
16660
- throw new Error(`Transaction type ${trx.type} is not yet implemented`);
16661
- // Won't ever be supported
16662
- case "FigmaNodeRender":
16663
- case "FigmaNodeRenderAsync":
16664
- throw new Error(`Transaction type ${trx.type} is not a documentation element action`);
16665
- }
16666
- }
16667
- //
16668
- // Pages
16669
- //
16670
- documentationPageCreate(trx) {
16671
- const { input } = trx;
16672
- const { persistentId } = input;
16673
- if (this.pages.has(input.persistentId)) {
16674
- return;
16675
- }
16676
- if (!this.groups.has(input.parentPersistentId)) {
16677
- throw new Error(`Cannot create page: parent persistent id ${input.parentPersistentId} was not found`);
16678
- }
16679
- const localPage = {
16680
- persistentId,
16681
- createdAt: /* @__PURE__ */ new Date(),
16682
- parentPersistentId: input.parentPersistentId,
16683
- shortPersistentId: generateShortPersistentId(),
16684
- slug: slugify(input.title),
16685
- meta: { name: input.title },
16686
- updatedAt: /* @__PURE__ */ new Date(),
16687
- data: {
16688
- // TODO Artem: move somewhere reusable
16689
- configuration: input.configuration ? { ...defaultDocumentationItemConfigurationV2, ...input.configuration } : input.configuration
16690
- },
16691
- sortOrder: this.calculateSortOrder(input.parentPersistentId, input.afterPersistentId),
16692
- designSystemVersionId: this.designSystemVersionId
16693
- };
16694
- this.pages.set(persistentId, localPage);
16695
- const roomId = `${RoomType.DocumentationPage}:${this.designSystemVersionId}:${persistentId}`;
16696
- this.pageLiveblockRoomIds[persistentId] = roomId;
16697
- }
16698
- documentationPageUpdate(trx) {
16699
- const { input } = trx;
16700
- const existingPage = this.pages.get(input.id);
16701
- if (!existingPage) {
16702
- throw new Error(`Cannot update page: page id ${input.id} was not found`);
16703
- }
16704
- const localPage = {
16705
- ...existingPage,
16706
- userSlug: void 0,
16707
- meta: {
16708
- ...existingPage.meta,
16709
- name: input.title ?? existingPage.meta.name
16710
- },
16711
- data: {
16712
- // TODO Artem: move somewhere reusable
16713
- configuration: input.configuration ? { ...existingPage.data.configuration ?? defaultDocumentationItemConfigurationV2, ...input.configuration } : existingPage.data.configuration
16714
- }
16715
- };
16716
- this.pages.set(localPage.persistentId, localPage);
16717
- }
16718
- documentationPageMove(trx) {
16719
- const { input } = trx;
16720
- if (!this.groups.has(input.parentPersistentId)) {
16721
- throw new Error(`Cannot move page: page parent id ${input.parentPersistentId} was not found`);
16722
- }
16723
- const existingPage = this.pages.get(input.id);
16724
- if (!existingPage) {
16725
- throw new Error(`Cannot update page: page id ${input.id} was not found`);
16726
- }
16727
- const localPage = {
16728
- ...existingPage,
16729
- userSlug: void 0,
16730
- sortOrder: this.calculateSortOrder(input.parentPersistentId, input.afterPersistentId),
16731
- parentPersistentId: input.parentPersistentId
16732
- };
16733
- this.pages.set(localPage.persistentId, localPage);
16734
- }
16735
- documentationPageDelete(trx) {
16736
- const { input } = trx;
16737
- if (!this.pages.delete(trx.input.id)) {
16738
- throw new Error(`Cannot delete page: page id ${input.id} was not found`);
16739
- }
16740
- delete this.pageLiveblockRoomIds[trx.input.id];
16741
- }
16742
- //
16743
- // Group
16744
- //
16745
- documentationGroupCreate(trx) {
16746
- const { input } = trx;
16747
- if (this.groups.has(input.persistentId)) {
16748
- return;
16749
- }
16750
- const localGroup = {
16751
- parentPersistentId: input.parentPersistentId,
16752
- persistentId: input.persistentId,
16753
- shortPersistentId: generateShortPersistentId(),
16754
- slug: slugify(input.title),
16755
- meta: { name: input.title },
16756
- createdAt: /* @__PURE__ */ new Date(),
16757
- updatedAt: /* @__PURE__ */ new Date(),
16758
- data: {
16759
- // TODO Artem: move somewhere reusable
16760
- configuration: input.configuration ? { ...defaultDocumentationItemConfigurationV2, ...input.configuration } : input.configuration
16761
- },
16762
- sortOrder: this.calculateSortOrder(input.parentPersistentId, input.afterPersistentId),
16763
- designSystemVersionId: this.designSystemVersionId
16764
- };
16765
- this.groups.set(localGroup.persistentId, localGroup);
16766
- }
16767
- documentationGroupUpdate(trx) {
16768
- const { input } = trx;
16769
- const existingGroup = this.groups.get(input.id);
16770
- if (!existingGroup) {
16771
- throw new Error(`Cannot update group: group id ${input.id} was not found`);
16772
- }
16773
- const localGroup = {
16774
- ...existingGroup,
16775
- userSlug: void 0,
16776
- meta: {
16777
- ...existingGroup.meta,
16778
- name: input.title ?? existingGroup.meta.name
16779
- },
16780
- data: {
16781
- ...existingGroup.data,
16782
- // TODO Artem: move somewhere reusable
16783
- configuration: input.configuration ? {
16784
- ...existingGroup.data?.configuration ?? defaultDocumentationItemConfigurationV2,
16785
- ...input.configuration
16786
- } : existingGroup.data?.configuration
16787
- }
16788
- };
16789
- this.groups.set(localGroup.persistentId, localGroup);
16790
- }
16791
- documentationGroupMove(trx) {
16792
- const { input } = trx;
16793
- if (!this.groups.has(input.parentPersistentId)) {
16794
- throw new Error(`Cannot move group: group parent id ${input.parentPersistentId} was not found`);
16795
- }
16796
- const existingGroup = this.groups.get(input.id);
16797
- if (!existingGroup) {
16798
- throw new Error(`Cannot update group: group id ${input.id} was not found`);
16799
- }
16800
- const localGroup = {
16801
- ...existingGroup,
16802
- userSlug: void 0,
16803
- sortOrder: this.calculateSortOrder(input.parentPersistentId, input.afterPersistentId),
16804
- parentPersistentId: input.parentPersistentId
16805
- };
16806
- this.groups.set(localGroup.persistentId, localGroup);
16807
- }
16808
- //
16809
- // Tabs
16810
- //
16811
- documentationTabCreate(trx) {
16812
- const { input } = trx;
16813
- const page = this.pages.get(input.fromItemPersistentId);
16814
- if (!page) {
16815
- throw new Error(`Cannot create tab: page id ${input.fromItemPersistentId} was not found`);
16816
- }
16817
- const tabGroup = {
16818
- parentPersistentId: page.parentPersistentId,
16819
- persistentId: input.persistentId,
16820
- shortPersistentId: generateShortPersistentId(),
16821
- slug: page.slug,
16822
- meta: page.meta,
16823
- createdAt: /* @__PURE__ */ new Date(),
16824
- updatedAt: /* @__PURE__ */ new Date(),
16825
- data: {
16826
- behavior: "Tabs",
16827
- configuration: page?.data.configuration
16828
- },
16829
- sortOrder: page.sortOrder,
16830
- designSystemVersionId: this.designSystemVersionId
16831
- };
16832
- this.groups.set(input.persistentId, tabGroup);
16833
- const newLocalPage = {
16834
- ...page,
16835
- userSlug: void 0,
16836
- sortOrder: 0,
16837
- parentPersistentId: input.persistentId,
16838
- meta: { name: input.tabName }
16839
- };
16840
- this.pages.set(newLocalPage.persistentId, newLocalPage);
16841
- }
16842
- //
16843
- // Approval states
16844
- //
16845
- documentationApprovalStateUpdate(trx) {
16846
- const { input } = trx;
16847
- const existingApproval = this.approvalStates.get(input.persistentId);
16848
- if (input.approvalState) {
16849
- this.approvalStates.set(input.persistentId, {
16850
- approvalState: input.approvalState,
16851
- createdAt: existingApproval?.createdAt ?? /* @__PURE__ */ new Date(),
16852
- designSystemVersionId: this.designSystemVersionId,
16853
- pagePersistentId: input.persistentId,
16854
- updatedAt: /* @__PURE__ */ new Date(),
16855
- updatedByUserId: this.userId
16856
- });
16857
- } else {
16858
- this.approvalStates.delete(input.persistentId);
16859
- }
16860
- }
16861
- //
16862
- // Utils
16863
- //
16864
- calculateSortOrder(parentPersistentId, afterPersistentId) {
16865
- const sortOrderStep = Math.pow(2, 16);
16866
- const neighbours = [
16867
- ...Array.from(this.pages.values()).filter((p) => p.parentPersistentId === parentPersistentId),
16868
- ...Array.from(this.groups.values()).filter((g) => g.parentPersistentId === parentPersistentId)
16869
- ];
16870
- if (!neighbours.length) return 0;
16871
- neighbours.sort((lhs, rhs) => lhs.sortOrder - rhs.sortOrder);
16872
- if (afterPersistentId === null) return neighbours[0].sortOrder - sortOrderStep;
16873
- if (!afterPersistentId) return neighbours[neighbours.length - 1].sortOrder + sortOrderStep;
16874
- const index = neighbours.findIndex((e) => e.persistentId === afterPersistentId);
16875
- if (index < 0 || index === neighbours.length - 1) {
16876
- return neighbours[neighbours.length - 1].sortOrder + sortOrderStep;
16877
- }
16878
- const left = neighbours[index].sortOrder;
16879
- const right = neighbours[index + 1]?.sortOrder ?? left + sortOrderStep * 2;
16880
- return (right + left) / 2;
16881
- }
16882
- };
16883
-
16884
- // src/sync/docs-structure-repo.ts
16885
- var DocsStructureRepository = class {
16908
+ // src/sync/docs-structure-repo.ts
16909
+ var DocsStructureRepository = class {
16886
16910
  constructor(config) {
16887
16911
  __publicField(this, "userId");
16888
16912
  __publicField(this, "designSystemVersionId");
@@ -17065,6 +17089,276 @@ var TransactionQueue = class {
17065
17089
  this.queue.clear();
17066
17090
  }
17067
17091
  };
17092
+
17093
+ // src/sync/project-content-repo.ts
17094
+ import PQueue2 from "p-queue";
17095
+
17096
+ // src/sync/project-local-action-executor.ts
17097
+ function applyProjectActionsLocally(input) {
17098
+ const actionExecutor = new LocalProjectActionExecutor(input);
17099
+ actionExecutor.applyActions(input.actions);
17100
+ return actionExecutor.localState;
17101
+ }
17102
+ var LocalProjectActionExecutor = class {
17103
+ constructor(config) {
17104
+ __publicField(this, "userId");
17105
+ __publicField(this, "projectId");
17106
+ __publicField(this, "artifacts");
17107
+ __publicField(this, "features");
17108
+ const { projectId, remoteState, userId } = config;
17109
+ this.userId = userId;
17110
+ this.projectId = projectId;
17111
+ this.artifacts = mapByUnique(remoteState.artifacts, (p) => p.id);
17112
+ this.features = mapByUnique(remoteState.features, (p) => p.id);
17113
+ }
17114
+ get localState() {
17115
+ return {
17116
+ artifacts: Array.from(this.artifacts.values()),
17117
+ features: Array.from(this.features.values())
17118
+ };
17119
+ }
17120
+ applyActions(trx) {
17121
+ trx.forEach((trx2) => this.applyTransaction(trx2));
17122
+ }
17123
+ applyTransaction(trx) {
17124
+ switch (trx.type) {
17125
+ case "ArtifactCreate":
17126
+ return this.artifactCreate(trx);
17127
+ case "ArtifactUpdate":
17128
+ return this.artifactUpdate(trx);
17129
+ case "ArtifactDelete":
17130
+ return this.artifactDelete(trx);
17131
+ case "FeatureCreate":
17132
+ return this.featureCreate(trx);
17133
+ case "FeatureDelete":
17134
+ return this.featureDelete(trx);
17135
+ case "FeatureUpdate":
17136
+ return this.featureUpdate(trx);
17137
+ }
17138
+ }
17139
+ //
17140
+ // Artifacts
17141
+ //
17142
+ artifactCreate(trx) {
17143
+ const { input } = trx;
17144
+ const { id } = input;
17145
+ this.artifacts.set(id, {
17146
+ id,
17147
+ projectId: this.projectId,
17148
+ sortOrder: 0,
17149
+ title: input.title,
17150
+ updatedAt: /* @__PURE__ */ new Date(),
17151
+ createdAt: /* @__PURE__ */ new Date(),
17152
+ createdByUserId: this.userId
17153
+ });
17154
+ }
17155
+ artifactUpdate(trx) {
17156
+ const { input } = trx;
17157
+ const { id } = input;
17158
+ const existingArtifact = this.artifacts.get(id);
17159
+ if (!existingArtifact) {
17160
+ throw new Error(`Cannot update artifact: artifact ${id} was not found in local storage`);
17161
+ }
17162
+ const mergedArtifact = {
17163
+ ...existingArtifact,
17164
+ title: input.title ?? existingArtifact.title,
17165
+ updatedAt: /* @__PURE__ */ new Date()
17166
+ };
17167
+ this.artifacts.set(id, mergedArtifact);
17168
+ }
17169
+ artifactDelete(trx) {
17170
+ const { input } = trx;
17171
+ const { id } = input;
17172
+ if (!this.artifacts.delete(id)) {
17173
+ throw new Error(`Cannot delete artifact: artifact ${id} was not found in local storage`);
17174
+ }
17175
+ }
17176
+ //
17177
+ // Feature
17178
+ //
17179
+ featureCreate(trx) {
17180
+ const { input } = trx;
17181
+ const { id } = input;
17182
+ this.features.set(id, {
17183
+ id,
17184
+ projectId: this.projectId,
17185
+ description: input.description,
17186
+ isArchived: false,
17187
+ sectionId: input.sectionId,
17188
+ sortOrder: 0,
17189
+ name: input.name,
17190
+ updatedAt: /* @__PURE__ */ new Date(),
17191
+ createdAt: /* @__PURE__ */ new Date(),
17192
+ createdByUserId: this.userId
17193
+ });
17194
+ }
17195
+ featureUpdate(trx) {
17196
+ const { input } = trx;
17197
+ const { id } = input;
17198
+ const existingFeature = this.features.get(id);
17199
+ if (!existingFeature) {
17200
+ throw new Error(`Cannot update feature: feature ${id} was not found in local storage`);
17201
+ }
17202
+ const mergedFeature = {
17203
+ ...existingFeature,
17204
+ name: input.name ?? existingFeature.name,
17205
+ description: input.description ?? existingFeature.description,
17206
+ isArchived: input.isArchived ?? existingFeature.isArchived,
17207
+ updatedAt: /* @__PURE__ */ new Date()
17208
+ };
17209
+ this.features.set(id, mergedFeature);
17210
+ }
17211
+ featureDelete(trx) {
17212
+ const { input } = trx;
17213
+ const { id } = input;
17214
+ if (!this.features.delete(id)) {
17215
+ throw new Error(`Cannot delete feature: feature ${id} was not found in local storage`);
17216
+ }
17217
+ }
17218
+ };
17219
+
17220
+ // src/sync/project-content-repo.ts
17221
+ var ForgeProjectContentRepository = class {
17222
+ constructor(config) {
17223
+ __publicField(this, "userId");
17224
+ __publicField(this, "projectId");
17225
+ __publicField(this, "yDoc");
17226
+ __publicField(this, "yObserver");
17227
+ __publicField(this, "_yState");
17228
+ __publicField(this, "_currentProjectContent");
17229
+ __publicField(this, "localActions", []);
17230
+ __publicField(this, "actionQueue");
17231
+ __publicField(this, "projectContentObservers", /* @__PURE__ */ new Set());
17232
+ __publicField(this, "errorObservers", /* @__PURE__ */ new Set());
17233
+ __publicField(this, "initCallbacks", /* @__PURE__ */ new Set());
17234
+ __publicField(this, "transactionIdGenerator");
17235
+ __publicField(this, "transactionExecutor");
17236
+ this.userId = config.userId;
17237
+ this.projectId = config.projectId;
17238
+ this.yDoc = config.yDoc;
17239
+ this.yObserver = this.yDoc.on("update", () => this.onYUpdate());
17240
+ this.onYUpdate();
17241
+ this.transactionExecutor = config.transactionExecutor;
17242
+ this.transactionIdGenerator = config.transactionIdGenerator;
17243
+ this.actionQueue = new TransactionQueue2((action) => this.executeInternalAction(action));
17244
+ }
17245
+ //
17246
+ // Lifecycle
17247
+ //
17248
+ get isInitialized() {
17249
+ return !!this._currentProjectContent;
17250
+ }
17251
+ onInitialized() {
17252
+ if (this.isInitialized) return Promise.resolve();
17253
+ return new Promise((resolve) => {
17254
+ this.initCallbacks.add(resolve);
17255
+ });
17256
+ }
17257
+ addProjectContentObserver(observer) {
17258
+ this.projectContentObservers.add(observer);
17259
+ if (this._currentProjectContent) observer(this._currentProjectContent);
17260
+ }
17261
+ removeProjectContentObserver(observer) {
17262
+ this.projectContentObservers.delete(observer);
17263
+ }
17264
+ addErrorObserver(observer) {
17265
+ this.errorObservers.add(observer);
17266
+ }
17267
+ removeErrorObserver(observer) {
17268
+ this.errorObservers.delete(observer);
17269
+ }
17270
+ dispose() {
17271
+ this.yDoc.off("update", this.yObserver);
17272
+ this.projectContentObservers.clear();
17273
+ this.errorObservers.clear();
17274
+ this.actionQueue.clear();
17275
+ }
17276
+ //
17277
+ // Accessors
17278
+ //
17279
+ get currentProjectContent() {
17280
+ const projectContent = this._currentProjectContent;
17281
+ if (!projectContent) throw new Error(`Project content cannot be accessed while it's still loading`);
17282
+ return projectContent;
17283
+ }
17284
+ //
17285
+ // Actions
17286
+ //
17287
+ executeAction(action, metadata) {
17288
+ void this.executeActionPromise(action, metadata);
17289
+ }
17290
+ executeActionPromise(action, metadata) {
17291
+ const fullAction = { ...action, tId: this.transactionIdGenerator() };
17292
+ this.localActions.push(fullAction);
17293
+ this.refreshProjectContent();
17294
+ return this.actionQueue.enqueue({ action: fullAction, metadata });
17295
+ }
17296
+ async executeInternalAction(action) {
17297
+ try {
17298
+ return await this.transactionExecutor(action.action);
17299
+ } catch (e) {
17300
+ this.localActions = this.localActions.filter((a) => a.tId !== action.action.tId);
17301
+ this.refreshProjectContent();
17302
+ this.errorObservers.forEach((o) => o(e, action.metadata));
17303
+ }
17304
+ }
17305
+ //
17306
+ // Reactions
17307
+ //
17308
+ refreshState() {
17309
+ this.refreshProjectContent();
17310
+ }
17311
+ refreshProjectContent() {
17312
+ const yState = this._yState;
17313
+ if (!yState) return;
17314
+ const projectContent = this.calculateProjectState(yState);
17315
+ if (!projectContent) return;
17316
+ this._currentProjectContent = projectContent;
17317
+ this.projectContentObservers.forEach((o) => o(projectContent));
17318
+ }
17319
+ calculateProjectState(yState) {
17320
+ const executedTransactionIds = new Set(yState.executedTransactionIds);
17321
+ const localActions = this.localActions.filter((a) => a.tId && !executedTransactionIds.has(a.tId));
17322
+ this.localActions = localActions;
17323
+ const state = applyProjectActionsLocally({
17324
+ userId: this.userId,
17325
+ projectId: this.projectId,
17326
+ remoteState: yState,
17327
+ actions: localActions
17328
+ });
17329
+ return {
17330
+ artifacts: state.artifacts,
17331
+ features: state.features
17332
+ };
17333
+ }
17334
+ onYUpdate() {
17335
+ const newState = new ForgeProjectRoomBaseYDoc(this.yDoc).getState();
17336
+ if (newState.isLoaded) {
17337
+ this._yState = newState;
17338
+ this.refreshState();
17339
+ this.initCallbacks.forEach((f) => f());
17340
+ this.initCallbacks.clear();
17341
+ }
17342
+ }
17343
+ };
17344
+ var TransactionQueue2 = class {
17345
+ constructor(executor) {
17346
+ __publicField(this, "executor");
17347
+ __publicField(this, "queue", new PQueue2({
17348
+ concurrency: 1
17349
+ }));
17350
+ this.executor = executor;
17351
+ }
17352
+ enqueue(trx) {
17353
+ return this.queue.add(() => this.executor(trx));
17354
+ }
17355
+ onEmpty() {
17356
+ return this.queue.onEmpty();
17357
+ }
17358
+ clear() {
17359
+ this.queue.clear();
17360
+ }
17361
+ };
17068
17362
  export {
17069
17363
  BackendForgeProjectRoomYDoc,
17070
17364
  BackendVersionRoomYDoc,
@@ -17660,6 +17954,7 @@ export {
17660
17954
  ForgeFeaturesEndpoint,
17661
17955
  ForgeIterationMessagesEndpoint,
17662
17956
  ForgeParticipantsEndpoint,
17957
+ ForgeProjectContentRepository,
17663
17958
  ForgeProjectContextsEndpoint,
17664
17959
  ForgeProjectFeaturesEndpoint,
17665
17960
  ForgeProjectInvitationsEndpoint,