@atlaskit/editor-synced-block-provider 4.1.2 → 4.1.4

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 ADDED
@@ -0,0 +1,117 @@
1
+ # Synced Block Provider — Developer Agent Guide
2
+
3
+ > **Package**: `@atlaskit/editor-synced-block-provider`
4
+ > **Purpose**: Data layer for synced blocks — store managers, block service API client, ARI generation, permissions, media tokens.
5
+ > **Full Knowledge Base**: [Synced Blocks — Comprehensive Knowledge Base](https://hello.atlassian.net/wiki/spaces/egcuc/pages/6679548384)
6
+
7
+ ---
8
+
9
+ ## Quick Context
10
+
11
+ This package manages the lifecycle and state of synced blocks for both source and reference nodes.
12
+ It provides the data fetching, caching, subscription, and persistence layer used by the editor plugin
13
+ and the renderer across Confluence and Jira.
14
+
15
+ ---
16
+
17
+ ## Source Structure
18
+
19
+ ```
20
+ src/
21
+ ├── index.ts ← Barrel export
22
+ ├── store-manager/
23
+ │ ├── syncBlockStoreManager.ts ← Parent coordinator for source + reference managers
24
+ │ ├── referenceSyncBlockStoreManager.ts ← Reference block lifecycle, cache, subscriptions, flush
25
+ │ └── sourceSyncBlockStoreManager.ts ← Source block create, update, delete, flush
26
+ ├── clients/
27
+ │ ├── block-service/
28
+ │ │ ├── blockService.ts ← Block service API client (fetch, batch, CRUD)
29
+ │ │ └── ari.ts ← Block ARI generation/parsing
30
+ │ ├── confluence/
31
+ │ │ ├── ari.ts ← Confluence page ARI generation/parsing
32
+ │ │ └── fetchMediaToken.ts ← Media token fetching via GraphQL (MediaUploadTokenQuery)
33
+ │ └── jira/
34
+ │ └── ari.ts ← Jira work item ARI generation/parsing
35
+ ├── providers/
36
+ │ └── block-service/
37
+ │ └── blockServiceAPI.ts ← Provider factory and API helpers
38
+ └── types/ ← Shared types
39
+ ```
40
+
41
+ ---
42
+
43
+ ## Key Concepts
44
+
45
+ ### Store Manager Hierarchy
46
+
47
+ ```
48
+ SyncBlockStoreManager (parent coordinator)
49
+ ├── SourceSyncBlockStoreManager
50
+ │ ├── create(content) → Block Service API → returns resourceId
51
+ │ ├── update(resourceId, content) → debounced 3s write
52
+ │ ├── delete(resourceId) → soft delete
53
+ │ └── flush() → persist all pending changes on page save
54
+ └── ReferenceSyncBlockStoreManager
55
+ ├── fetchSyncBlocksData(nodes) → batch fetch with deduplication
56
+ ├── subscribeToSyncBlock(resourceId, localId, callback) → AGG WebSocket
57
+ ├── fetchSyncBlockSourceInfo(resourceId) → title, URL metadata
58
+ ├── getFromCache(resourceId) → retrieve cached data
59
+ ├── flush() → save reference changes to backend
60
+ └── destroy() → cleanup subscriptions and batchers
61
+ ```
62
+
63
+ ### ARI Formats & Utilities
64
+
65
+ | Function | ARI Pattern | Example |
66
+ |----------|-------------|---------|
67
+ | `generateBlockAri({cloudId, parentId, product, resourceId})` | Source block ARI | `ari:cloud:block::{cloudId}/confluence-page:{pageId}/{localId}` |
68
+ | `generateBlockAriFromReference({cloudId, resourceId})` | Reference block ARI | — |
69
+ | `getConfluencePageAri({pageId, cloudId, pageType})` | Confluence page | `ari:cloud:confluence::{cloudId}:page/{pageId}` |
70
+ | `getJiraWorkItemAri({cloudId, workItemId})` | Jira issue | `ari:cloud:jira::{cloudId}:work-item/{issueId}` |
71
+ | `getJiraWorkItemIdFromAri(ari)` | Extract issue ID from ARI | — |
72
+
73
+ ### Block Service API
74
+
75
+ The client in `clients/block-service/blockService.ts` communicates via GraphQL at `/gateway/api/graphql`:
76
+ - **Fetch**: Single or batch block content retrieval
77
+ - **Create**: Register new source block with content
78
+ - **Update**: Push content changes (debounced 3s)
79
+ - **Delete**: Soft delete a source block
80
+ - **Source Info**: Fetch metadata (source page title, URL)
81
+ - **References Info**: Fetch list of locations referencing a block
82
+
83
+ ### Media Token Fetching
84
+
85
+ `fetchMediaToken(contentId)` → GraphQL `MediaUploadTokenQuery` → returns `{token, config: {clientId, fileStoreUrl}, collectionId}`
86
+
87
+ Used when synced blocks contain media (images, files) — the reference needs a valid token to render media from the source page.
88
+
89
+ ---
90
+
91
+ ## Common Tasks
92
+
93
+ ### Adding a new API method
94
+ 1. Add the GraphQL query/mutation in `clients/block-service/blockService.ts`
95
+ 2. Expose it through the appropriate store manager
96
+ 3. Export from `src/index.ts` if needed by product integrations
97
+ 4. Add tests in `editor-synced-block-provider-tests`
98
+
99
+ ### Debugging data issues
100
+ 1. Check `ReferenceSyncBlockStoreManager` cache state
101
+ 2. Verify ARI format matches expected pattern for the product
102
+ 3. Check Block Service API responses in network tab (look for `/gateway/api/graphql`)
103
+ 4. Use analytics: [HOW-TO: Debug errors](https://hello.atlassian.net/wiki/spaces/egcuc/pages/6342760320)
104
+
105
+ ### Adding support for a new product
106
+ 1. Create ARI utilities in `clients/{product}/ari.ts`
107
+ 2. Ensure `generateBlockAri` supports the new product type
108
+ 3. Add media token fetching if the product has media content
109
+ 4. Update store managers if the product has unique lifecycle requirements
110
+
111
+ ---
112
+
113
+ ## Related Packages
114
+ - **Plugin**: `platform/packages/editor/editor-plugin-synced-block/` — uses store managers
115
+ - **Renderer**: `platform/packages/editor/editor-synced-block-renderer/` — uses fetch provider
116
+ - **Confluence**: `confluence/next/packages/fabric-providers/src/SyncedBlockProvider.ts` — wraps this provider
117
+ - **Jira**: `jira/src/packages/issue/issue-view-synced-block-provider/` — wraps this provider with Relay
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @atlaskit/editor-synced-block-provider
2
2
 
3
+ ## 4.1.4
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+
9
+ ## 4.1.3
10
+
11
+ ### Patch Changes
12
+
13
+ - [`3895f6d32cc49`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/3895f6d32cc49) -
14
+ Set hasReceivedContentChange on successful sync block creation to ensure unsaved changes are
15
+ flushed
16
+ - Updated dependencies
17
+
3
18
  ## 4.1.2
4
19
 
5
20
  ### Patch Changes
@@ -12,6 +12,7 @@ var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/creat
12
12
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
13
13
  var _isEqual = _interopRequireDefault(require("lodash/isEqual"));
14
14
  var _monitoring = require("@atlaskit/editor-common/monitoring");
15
+ var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
15
16
  var _types = require("../common/types");
16
17
  var _errorHandling = require("../utils/errorHandling");
17
18
  var _experienceTracking = require("../utils/experienceTracking");
@@ -227,6 +228,13 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
227
228
  if (onCompletion) {
228
229
  this.creationCompletionCallbacks.delete(resourceId);
229
230
  onCompletion(success);
231
+ if (success && (0, _experiments.editorExperiment)('platform_synced_block_patch_6', true, {
232
+ exposure: true
233
+ })) {
234
+ // If creation is successful, set hasReceivedContentChange to true
235
+ // to indicate that there are unsaved changes in the cache
236
+ this.hasReceivedContentChange = true;
237
+ }
230
238
  } else {
231
239
  var _this$fireAnalyticsEv3;
232
240
  (_this$fireAnalyticsEv3 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv3 === void 0 || _this$fireAnalyticsEv3.call(this, (0, _errorHandling.createErrorPayload)('creation complete callback missing', resourceId));
@@ -1,6 +1,7 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
2
  import isEqual from 'lodash/isEqual';
3
3
  import { logException } from '@atlaskit/editor-common/monitoring';
4
+ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
4
5
  import { SyncBlockError } from '../common/types';
5
6
  import { updateErrorPayload, createErrorPayload, deleteErrorPayload, updateCacheErrorPayload, getSourceInfoErrorPayload, updateSuccessPayload, createSuccessPayload, deleteSuccessPayload, fetchReferencesErrorPayload } from '../utils/errorHandling';
6
7
  import { getCreateSourceExperience, getDeleteSourceExperience, getSaveSourceExperience, getFetchSourceInfoExperience } from '../utils/experienceTracking';
@@ -168,6 +169,13 @@ export class SourceSyncBlockStoreManager {
168
169
  if (onCompletion) {
169
170
  this.creationCompletionCallbacks.delete(resourceId);
170
171
  onCompletion(success);
172
+ if (success && editorExperiment('platform_synced_block_patch_6', true, {
173
+ exposure: true
174
+ })) {
175
+ // If creation is successful, set hasReceivedContentChange to true
176
+ // to indicate that there are unsaved changes in the cache
177
+ this.hasReceivedContentChange = true;
178
+ }
171
179
  } else {
172
180
  var _this$fireAnalyticsEv5;
173
181
  (_this$fireAnalyticsEv5 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv5 === void 0 ? void 0 : _this$fireAnalyticsEv5.call(this, createErrorPayload('creation complete callback missing', resourceId));
@@ -7,6 +7,7 @@ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbol
7
7
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
8
8
  import isEqual from 'lodash/isEqual';
9
9
  import { logException } from '@atlaskit/editor-common/monitoring';
10
+ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
10
11
  import { SyncBlockError } from '../common/types';
11
12
  import { updateErrorPayload, createErrorPayload, deleteErrorPayload, updateCacheErrorPayload, getSourceInfoErrorPayload, updateSuccessPayload, createSuccessPayload, deleteSuccessPayload, fetchReferencesErrorPayload } from '../utils/errorHandling';
12
13
  import { getCreateSourceExperience, getDeleteSourceExperience, getSaveSourceExperience, getFetchSourceInfoExperience } from '../utils/experienceTracking';
@@ -220,6 +221,13 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
220
221
  if (onCompletion) {
221
222
  this.creationCompletionCallbacks.delete(resourceId);
222
223
  onCompletion(success);
224
+ if (success && editorExperiment('platform_synced_block_patch_6', true, {
225
+ exposure: true
226
+ })) {
227
+ // If creation is successful, set hasReceivedContentChange to true
228
+ // to indicate that there are unsaved changes in the cache
229
+ this.hasReceivedContentChange = true;
230
+ }
223
231
  } else {
224
232
  var _this$fireAnalyticsEv3;
225
233
  (_this$fireAnalyticsEv3 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv3 === void 0 || _this$fireAnalyticsEv3.call(this, createErrorPayload('creation complete callback missing', resourceId));
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": "^41.0.0",
32
+ "@atlaskit/tmp-editor-statsig": "^43.0.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.6.0",
41
+ "@atlaskit/editor-common": "^112.7.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.1.2",
84
+ "version": "4.1.4",
85
85
  "description": "Synced Block Provider for @atlaskit/editor-plugin-synced-block",
86
86
  "author": "Atlassian Pty Ltd",
87
87
  "license": "Apache-2.0",