@atlaskit/editor-synced-block-provider 4.3.2 → 4.3.3

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/AGENTS.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # Synced Block Provider — Developer Agent Guide
2
2
 
3
- > **Package**: `@atlaskit/editor-synced-block-provider` **Purpose**: Data layer for synced blocks —
4
- > store managers, block service API client, ARI generation, permissions, media tokens. **Full
5
- > Knowledge Base**:
6
- > [Synced Blocks — Comprehensive Knowledge Base](https://hello.atlassian.net/wiki/spaces/egcuc/pages/6679548384)
3
+ > **Package**: `@atlaskit/editor-synced-block-provider`
4
+ >
5
+ > **For workflow guidance, debugging, and cross-package task guides, load the `synced-blocks` skill:**
6
+ > `get_skill(skill_name_or_path="platform/packages/editor/.rovodev/skills/synced-blocks/SKILL.md")`
7
7
 
8
8
  ---
9
9
 
@@ -19,29 +19,29 @@ plugin and the renderer across Confluence and Jira.
19
19
 
20
20
  ```
21
21
  src/
22
- ├── index.ts Barrel export
22
+ ├── index.ts # Barrel export
23
23
  ├── store-manager/
24
- │ ├── syncBlockStoreManager.ts Parent coordinator for source + reference managers
25
- │ ├── referenceSyncBlockStoreManager.ts Reference block lifecycle, cache, subscriptions, flush
26
- │ └── sourceSyncBlockStoreManager.ts Source block create, update, delete, flush
24
+ │ ├── syncBlockStoreManager.ts # Parent coordinator for source + reference managers
25
+ │ ├── referenceSyncBlockStoreManager.ts # Reference block lifecycle, cache, subscriptions, flush
26
+ │ └── sourceSyncBlockStoreManager.ts # Source block create, update, delete, flush
27
27
  ├── clients/
28
28
  │ ├── block-service/
29
- │ │ ├── blockService.ts Block service API client (fetch, batch, CRUD)
30
- │ │ └── ari.ts Block ARI generation/parsing
29
+ │ │ ├── blockService.ts # Block service API client (fetch, batch, CRUD)
30
+ │ │ └── ari.ts # Block ARI generation/parsing
31
31
  │ ├── confluence/
32
- │ │ ├── ari.ts Confluence page ARI generation/parsing
33
- │ │ └── fetchMediaToken.ts Media token fetching via GraphQL (MediaUploadTokenQuery)
32
+ │ │ ├── ari.ts # Confluence page ARI generation/parsing
33
+ │ │ └── fetchMediaToken.ts # Media token fetching via GraphQL (MediaUploadTokenQuery)
34
34
  │ └── jira/
35
- │ └── ari.ts Jira work item ARI generation/parsing
35
+ │ └── ari.ts # Jira work item ARI generation/parsing
36
36
  ├── providers/
37
37
  │ └── block-service/
38
- │ └── blockServiceAPI.ts Provider factory and API helpers
39
- └── types/ Shared types
38
+ │ └── blockServiceAPI.ts # Provider factory and API helpers
39
+ └── types/ # Shared types
40
40
  ```
41
41
 
42
42
  ---
43
43
 
44
- ## Key Concepts
44
+ ## Key Exports and Types
45
45
 
46
46
  ### Store Manager Hierarchy
47
47
 
@@ -49,81 +49,41 @@ src/
49
49
  SyncBlockStoreManager (parent coordinator)
50
50
  ├── SourceSyncBlockStoreManager
51
51
  │ ├── create(content) → Block Service API → returns resourceId
52
- │ ├── update(resourceId, content) → debounced 3s write
53
- │ ├── delete(resourceId) → soft delete
54
- └── flush() → persist all pending changes on page save
52
+ │ ├── updateSyncBlockData(node) → marks isDirty, caches content
53
+ │ ├── flush() → persist all dirty changes to backend
54
+ ├── hasUnsavedChanges() → checks isDirty + hasReceivedContentChange
55
+ │ └── delete(resourceId) → soft delete with confirmation
55
56
  └── ReferenceSyncBlockStoreManager
56
57
  ├── fetchSyncBlocksData(nodes) → batch fetch with deduplication
57
- ├── subscribeToSyncBlock(resourceId, localId, callback) → AGG WebSocket
58
+ ├── subscribeToSyncBlock(resourceId, callback) → AGG WebSocket
58
59
  ├── fetchSyncBlockSourceInfo(resourceId) → title, URL metadata
59
- ├── getFromCache(resourceId) → retrieve cached data
60
- ├── flush() → save reference changes to backend
61
60
  └── destroy() → cleanup subscriptions and batchers
62
61
  ```
63
62
 
64
- ### ARI Formats & Utilities
63
+ ### ARI Utilities
65
64
 
66
- | Function | ARI Pattern | Example |
67
- | ------------------------------------------------------------ | ------------------------- | --------------------------------------------------------------- |
68
- | `generateBlockAri({cloudId, parentId, product, resourceId})` | Source block ARI | `ari:cloud:block::{cloudId}/confluence-page:{pageId}/{localId}` |
69
- | `generateBlockAriFromReference({cloudId, resourceId})` | Reference block ARI | — |
70
- | `getConfluencePageAri({pageId, cloudId, pageType})` | Confluence page | `ari:cloud:confluence::{cloudId}:page/{pageId}` |
71
- | `getJiraWorkItemAri({cloudId, workItemId})` | Jira issue | `ari:cloud:jira::{cloudId}:work-item/{issueId}` |
72
- | `getJiraWorkItemIdFromAri(ari)` | Extract issue ID from ARI | — |
65
+ | Function | Purpose |
66
+ | ------------------------------------------------------------ | -------------------------- |
67
+ | `generateBlockAri({cloudId, parentId, product, resourceId})` | Generate source block ARI |
68
+ | `generateBlockAriFromReference({cloudId, resourceId})` | Generate reference ARI |
69
+ | `getConfluencePageAri({pageId, cloudId, pageType})` | Confluence page ARI |
70
+ | `getJiraWorkItemAri({cloudId, workItemId})` | Jira issue ARI |
73
71
 
74
72
  ### Block Service API
75
73
 
76
74
  The client in `clients/block-service/blockService.ts` communicates via GraphQL at
77
- `/gateway/api/graphql`:
78
-
79
- - **Fetch**: Single or batch block content retrieval
80
- - **Create**: Register new source block with content
81
- - **Update**: Push content changes (debounced 3s)
82
- - **Delete**: Soft delete a source block
83
- - **Source Info**: Fetch metadata (source page title, URL)
84
- - **References Info**: Fetch list of locations referencing a block
75
+ `/gateway/api/graphql`: Fetch, Create, Update (debounced 3s), Delete, Source Info, References Info.
85
76
 
86
77
  ### Media Token Fetching
87
78
 
88
79
  `fetchMediaToken(contentId)` → GraphQL `MediaUploadTokenQuery` → returns
89
80
  `{token, config: {clientId, fileStoreUrl}, collectionId}`
90
81
 
91
- Used when synced blocks contain media (images, files) — the reference needs a valid token to render
92
- media from the source page.
93
-
94
- ---
95
-
96
- ## Common Tasks
97
-
98
- ### Adding a new API method
99
-
100
- 1. Add the GraphQL query/mutation in `clients/block-service/blockService.ts`
101
- 2. Expose it through the appropriate store manager
102
- 3. Export from `src/index.ts` if needed by product integrations
103
- 4. Add tests in `editor-synced-block-provider-tests`
104
-
105
- ### Debugging data issues
106
-
107
- 1. Check `ReferenceSyncBlockStoreManager` cache state
108
- 2. Verify ARI format matches expected pattern for the product
109
- 3. Check Block Service API responses in network tab (look for `/gateway/api/graphql`)
110
- 4. Use analytics:
111
- [HOW-TO: Debug errors](https://hello.atlassian.net/wiki/spaces/egcuc/pages/6342760320)
112
-
113
- ### Adding support for a new product
114
-
115
- 1. Create ARI utilities in `clients/{product}/ari.ts`
116
- 2. Ensure `generateBlockAri` supports the new product type
117
- 3. Add media token fetching if the product has media content
118
- 4. Update store managers if the product has unique lifecycle requirements
119
-
120
82
  ---
121
83
 
122
84
  ## Related Packages
123
85
 
124
- - **Plugin**: `platform/packages/editor/editor-plugin-synced-block/` — uses store managers
125
- - **Renderer**: `platform/packages/editor/editor-synced-block-renderer/` — uses fetch provider
126
- - **Confluence**: `confluence/next/packages/fabric-providers/src/SyncedBlockProvider.ts` — wraps
127
- this provider
128
- - **Jira**: `jira/src/packages/issue/issue-view-synced-block-provider/` — wraps this provider with
129
- Relay
86
+ - **Plugin**: `platform/packages/editor/editor-plugin-synced-block/`
87
+ - **Renderer**: `platform/packages/editor/editor-synced-block-renderer/`
88
+ - **Confluence**: `confluence/next/packages/fabric-providers/src/SyncedBlockProvider.ts`
89
+ - **Jira**: `jira/src/packages/issue/issue-view-synced-block-provider/`
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # @atlaskit/editor-synced-block-provider
2
2
 
3
+ ## 4.3.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [`15deee785151b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/15deee785151b) -
8
+ EDITOR-6174 Pass node to createBodiedSyncBlockNode to cache content on creation, preventing false
9
+ unsaved changes on page refresh
10
+ - Updated dependencies
11
+
3
12
  ## 4.3.2
4
13
 
5
14
  ### Patch Changes
@@ -339,10 +339,12 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
339
339
  /**
340
340
  * Create a bodiedSyncBlock node with empty content to backend
341
341
  * @param attrs attributes Ids of the node
342
+ * @param node the ProseMirror node to cache
343
+ * @param onCompletion callback invoked when creation completes
342
344
  */
343
345
  }, {
344
346
  key: "createBodiedSyncBlockNode",
345
- value: function createBodiedSyncBlockNode(attrs, onCompletion) {
347
+ value: function createBodiedSyncBlockNode(attrs, node, onCompletion) {
346
348
  var _this4 = this;
347
349
  if (this.viewMode === 'view' && (0, _platformFeatureFlags.fg)('platform_synced_block_patch_8')) {
348
350
  return;
@@ -354,6 +356,10 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
354
356
  if (!this.dataProvider) {
355
357
  throw new Error('Data provider not set');
356
358
  }
359
+ if ((0, _platformFeatureFlags.fg)('platform_synced_block_update_refactor')) {
360
+ // add the node to the cache
361
+ this.updateSyncBlockData(node);
362
+ }
357
363
  this.creationCompletionCallbacks.set(resourceId, onCompletion);
358
364
  (_this$createExperienc = this.createExperience) === null || _this$createExperienc === void 0 || _this$createExperienc.start({});
359
365
  this.dataProvider.createNodeData({
@@ -269,8 +269,10 @@ export class SourceSyncBlockStoreManager {
269
269
  /**
270
270
  * Create a bodiedSyncBlock node with empty content to backend
271
271
  * @param attrs attributes Ids of the node
272
+ * @param node the ProseMirror node to cache
273
+ * @param onCompletion callback invoked when creation completes
272
274
  */
273
- createBodiedSyncBlockNode(attrs, onCompletion) {
275
+ createBodiedSyncBlockNode(attrs, node, onCompletion) {
274
276
  if (this.viewMode === 'view' && fg('platform_synced_block_patch_8')) {
275
277
  return;
276
278
  }
@@ -283,6 +285,10 @@ export class SourceSyncBlockStoreManager {
283
285
  if (!this.dataProvider) {
284
286
  throw new Error('Data provider not set');
285
287
  }
288
+ if (fg('platform_synced_block_update_refactor')) {
289
+ // add the node to the cache
290
+ this.updateSyncBlockData(node);
291
+ }
286
292
  this.creationCompletionCallbacks.set(resourceId, onCompletion);
287
293
  (_this$createExperienc = this.createExperience) === null || _this$createExperienc === void 0 ? void 0 : _this$createExperienc.start({});
288
294
  this.dataProvider.createNodeData({
@@ -332,10 +332,12 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
332
332
  /**
333
333
  * Create a bodiedSyncBlock node with empty content to backend
334
334
  * @param attrs attributes Ids of the node
335
+ * @param node the ProseMirror node to cache
336
+ * @param onCompletion callback invoked when creation completes
335
337
  */
336
338
  }, {
337
339
  key: "createBodiedSyncBlockNode",
338
- value: function createBodiedSyncBlockNode(attrs, onCompletion) {
340
+ value: function createBodiedSyncBlockNode(attrs, node, onCompletion) {
339
341
  var _this4 = this;
340
342
  if (this.viewMode === 'view' && fg('platform_synced_block_patch_8')) {
341
343
  return;
@@ -347,6 +349,10 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
347
349
  if (!this.dataProvider) {
348
350
  throw new Error('Data provider not set');
349
351
  }
352
+ if (fg('platform_synced_block_update_refactor')) {
353
+ // add the node to the cache
354
+ this.updateSyncBlockData(node);
355
+ }
350
356
  this.creationCompletionCallbacks.set(resourceId, onCompletion);
351
357
  (_this$createExperienc = this.createExperience) === null || _this$createExperienc === void 0 || _this$createExperienc.start({});
352
358
  this.dataProvider.createNodeData({
@@ -57,8 +57,10 @@ export declare class SourceSyncBlockStoreManager {
57
57
  /**
58
58
  * Create a bodiedSyncBlock node with empty content to backend
59
59
  * @param attrs attributes Ids of the node
60
+ * @param node the ProseMirror node to cache
61
+ * @param onCompletion callback invoked when creation completes
60
62
  */
61
- createBodiedSyncBlockNode(attrs: SyncBlockAttrs, onCompletion: OnCompletion): void;
63
+ createBodiedSyncBlockNode(attrs: SyncBlockAttrs, node: PMNode, onCompletion: OnCompletion): void;
62
64
  private setPendingDeletion;
63
65
  private delete;
64
66
  isRetryingDeletion(): boolean;
@@ -57,8 +57,10 @@ export declare class SourceSyncBlockStoreManager {
57
57
  /**
58
58
  * Create a bodiedSyncBlock node with empty content to backend
59
59
  * @param attrs attributes Ids of the node
60
+ * @param node the ProseMirror node to cache
61
+ * @param onCompletion callback invoked when creation completes
60
62
  */
61
- createBodiedSyncBlockNode(attrs: SyncBlockAttrs, onCompletion: OnCompletion): void;
63
+ createBodiedSyncBlockNode(attrs: SyncBlockAttrs, node: PMNode, onCompletion: OnCompletion): void;
62
64
  private setPendingDeletion;
63
65
  private delete;
64
66
  isRetryingDeletion(): boolean;
package/package.json CHANGED
@@ -29,7 +29,7 @@
29
29
  "@atlaskit/editor-prosemirror": "^7.3.0",
30
30
  "@atlaskit/node-data-provider": "^9.0.0",
31
31
  "@atlaskit/platform-feature-flags": "^1.1.0",
32
- "@atlaskit/tmp-editor-statsig": "^54.1.0",
32
+ "@atlaskit/tmp-editor-statsig": "^54.4.0",
33
33
  "@babel/runtime": "^7.0.0",
34
34
  "@compiled/react": "^0.20.0",
35
35
  "graphql-ws": "^5.14.2",
@@ -38,7 +38,7 @@
38
38
  "uuid": "^3.1.0"
39
39
  },
40
40
  "peerDependencies": {
41
- "@atlaskit/editor-common": "^112.16.0",
41
+ "@atlaskit/editor-common": "^112.18.0",
42
42
  "react": "^18.2.0"
43
43
  },
44
44
  "devDependencies": {
@@ -81,7 +81,7 @@
81
81
  }
82
82
  },
83
83
  "name": "@atlaskit/editor-synced-block-provider",
84
- "version": "4.3.2",
84
+ "version": "4.3.3",
85
85
  "description": "Synced Block Provider for @atlaskit/editor-plugin-synced-block",
86
86
  "author": "Atlassian Pty Ltd",
87
87
  "license": "Apache-2.0",