@atlaskit/editor-synced-block-provider 3.12.1 → 3.13.0

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.
Files changed (41) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cjs/clients/block-service/blockSubscription.js +124 -0
  3. package/dist/cjs/clients/jira/sourceInfo.js +152 -0
  4. package/dist/cjs/providers/block-service/blockServiceAPI.js +43 -6
  5. package/dist/cjs/providers/syncBlockProvider.js +40 -8
  6. package/dist/cjs/store-manager/referenceSyncBlockStoreManager.js +347 -114
  7. package/dist/cjs/store-manager/syncBlockStoreManager.js +2 -2
  8. package/dist/cjs/utils/resolveSyncBlockInstance.js +1 -1
  9. package/dist/es2019/clients/block-service/blockSubscription.js +125 -0
  10. package/dist/es2019/clients/jira/sourceInfo.js +87 -0
  11. package/dist/es2019/providers/block-service/blockServiceAPI.js +40 -5
  12. package/dist/es2019/providers/syncBlockProvider.js +26 -2
  13. package/dist/es2019/store-manager/referenceSyncBlockStoreManager.js +233 -45
  14. package/dist/es2019/store-manager/syncBlockStoreManager.js +2 -2
  15. package/dist/es2019/utils/resolveSyncBlockInstance.js +1 -1
  16. package/dist/esm/clients/block-service/blockSubscription.js +118 -0
  17. package/dist/esm/clients/jira/sourceInfo.js +147 -0
  18. package/dist/esm/providers/block-service/blockServiceAPI.js +43 -6
  19. package/dist/esm/providers/syncBlockProvider.js +38 -6
  20. package/dist/esm/store-manager/referenceSyncBlockStoreManager.js +347 -114
  21. package/dist/esm/store-manager/syncBlockStoreManager.js +2 -2
  22. package/dist/esm/utils/resolveSyncBlockInstance.js +1 -1
  23. package/dist/types/clients/block-service/blockService.d.ts +2 -2
  24. package/dist/types/clients/block-service/blockSubscription.d.ts +38 -0
  25. package/dist/types/clients/jira/sourceInfo.d.ts +2 -0
  26. package/dist/types/common/types.d.ts +4 -2
  27. package/dist/types/index.d.ts +2 -2
  28. package/dist/types/providers/block-service/blockServiceAPI.d.ts +8 -0
  29. package/dist/types/providers/syncBlockProvider.d.ts +9 -1
  30. package/dist/types/providers/types.d.ts +22 -6
  31. package/dist/types/store-manager/referenceSyncBlockStoreManager.d.ts +59 -0
  32. package/dist/types-ts4.5/clients/block-service/blockService.d.ts +2 -2
  33. package/dist/types-ts4.5/clients/block-service/blockSubscription.d.ts +38 -0
  34. package/dist/types-ts4.5/clients/jira/sourceInfo.d.ts +2 -0
  35. package/dist/types-ts4.5/common/types.d.ts +4 -2
  36. package/dist/types-ts4.5/index.d.ts +2 -2
  37. package/dist/types-ts4.5/providers/block-service/blockServiceAPI.d.ts +8 -0
  38. package/dist/types-ts4.5/providers/syncBlockProvider.d.ts +9 -1
  39. package/dist/types-ts4.5/providers/types.d.ts +22 -6
  40. package/dist/types-ts4.5/store-manager/referenceSyncBlockStoreManager.d.ts +59 -0
  41. package/package.json +2 -1
@@ -83,7 +83,7 @@ export var SyncBlockStoreManager = /*#__PURE__*/function () {
83
83
  return _context.abrupt("return", undefined);
84
84
  case 5:
85
85
  return _context.abrupt("return", _objectSpread(_objectSpread({}, sourceInfo), {}, {
86
- onSamePage: reference.onSamePage,
86
+ onSameDocument: reference.onSameDocument,
87
87
  hasAccess: reference.hasAccess,
88
88
  productType: sourceInfo.productType
89
89
  }));
@@ -107,7 +107,7 @@ export var SyncBlockStoreManager = /*#__PURE__*/function () {
107
107
  sourceSyncBlockData = _context2.sent;
108
108
  if (sourceSyncBlockData) {
109
109
  sourceInfos.push(_objectSpread(_objectSpread({}, sourceSyncBlockData), {}, {
110
- onSamePage: Boolean(sourceSyncBlockData === null || sourceSyncBlockData === void 0 ? void 0 : sourceSyncBlockData.onSamePage),
110
+ onSameDocument: Boolean(sourceSyncBlockData === null || sourceSyncBlockData === void 0 ? void 0 : sourceSyncBlockData.onSameDocument),
111
111
  hasAccess: true,
112
112
  isSource: true,
113
113
  productType: sourceSyncBlockData === null || sourceSyncBlockData === void 0 ? void 0 : sourceSyncBlockData.productType
@@ -34,7 +34,7 @@ export var resolveSyncBlockInstance = function resolveSyncBlockInstance(oldResul
34
34
  sourceTitle: ((_newResult$data2 = newResult.data) === null || _newResult$data2 === void 0 ? void 0 : _newResult$data2.sourceTitle) || ((_oldResult$data2 = oldResult.data) === null || _oldResult$data2 === void 0 ? void 0 : _oldResult$data2.sourceTitle) || undefined
35
35
  }, fg('platform_synced_block_dogfooding') && {
36
36
  sourceSubType: ((_newResult$data3 = newResult.data) === null || _newResult$data3 === void 0 ? void 0 : _newResult$data3.sourceSubType) || ((_oldResult$data3 = oldResult.data) === null || _oldResult$data3 === void 0 ? void 0 : _oldResult$data3.sourceSubType) || undefined,
37
- onSamePage: ((_newResult$data4 = newResult.data) === null || _newResult$data4 === void 0 ? void 0 : _newResult$data4.onSamePage) || ((_oldResult$data4 = oldResult.data) === null || _oldResult$data4 === void 0 ? void 0 : _oldResult$data4.onSamePage) || undefined
37
+ onSameDocument: ((_newResult$data4 = newResult.data) === null || _newResult$data4 === void 0 ? void 0 : _newResult$data4.onSameDocument) || ((_oldResult$data4 = oldResult.data) === null || _oldResult$data4 === void 0 ? void 0 : _oldResult$data4.onSameDocument) || undefined
38
38
  })
39
39
  });
40
40
  };
@@ -1,4 +1,4 @@
1
- import type { ReferenceSyncBlockResponse, SyncBlockProduct } from '../../common/types';
1
+ import type { ReferenceSyncBlockResponse, SyncBlockProduct, SyncBlockStatus } from '../../common/types';
2
2
  export type BlockContentResponse = {
3
3
  blockAri: string;
4
4
  blockInstanceId: string;
@@ -7,7 +7,7 @@ export type BlockContentResponse = {
7
7
  createdBy: string;
8
8
  product: SyncBlockProduct;
9
9
  sourceAri: string;
10
- status: 'active' | 'deleted';
10
+ status: SyncBlockStatus;
11
11
  version: number;
12
12
  };
13
13
  export type ErrorResponse = {
@@ -0,0 +1,38 @@
1
+ import type { ADFEntity } from '@atlaskit/adf-utils/types';
2
+ import type { SyncBlockProduct } from '../../common/types';
3
+ export type BlockSubscriptionPayload = {
4
+ blockAri: string;
5
+ blockInstanceId: string;
6
+ content: string;
7
+ contentUpdatedAt?: number;
8
+ createdAt: number;
9
+ createdBy: string;
10
+ deletionReason?: string;
11
+ product: string;
12
+ sourceAri: string;
13
+ status: string;
14
+ };
15
+ export type ParsedBlockSubscriptionData = {
16
+ blockAri: string;
17
+ blockInstanceId: string;
18
+ content: ADFEntity[];
19
+ createdAt?: string;
20
+ createdBy: string;
21
+ product: SyncBlockProduct;
22
+ resourceId: string;
23
+ sourceAri: string;
24
+ status: string;
25
+ };
26
+ type SubscriptionCallback = (data: ParsedBlockSubscriptionData) => void;
27
+ type ErrorCallback = (error: Error) => void;
28
+ type Unsubscribe = () => void;
29
+ /**
30
+ * Creates a GraphQL subscription to block updates using the shared graphql-ws client.
31
+ *
32
+ * @param blockAri - The full block ARI to subscribe to (ari:cloud:blocks:{cloudId}:synced-block/{resourceId})
33
+ * @param onData - Callback function invoked when block data is updated
34
+ * @param onError - Optional callback function invoked on subscription errors
35
+ * @returns Unsubscribe function to close the subscription
36
+ */
37
+ export declare const subscribeToBlockUpdates: (blockAri: string, onData: SubscriptionCallback, onError?: ErrorCallback) => Unsubscribe;
38
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { SyncBlockSourceInfo } from '../../providers/types';
2
+ export declare const fetchJiraWorkItemInfo: (workItemAri: string, hasAccess: boolean) => Promise<SyncBlockSourceInfo | undefined>;
@@ -5,6 +5,7 @@ import type { SYNC_BLOCK_PRODUCTS } from './consts';
5
5
  export type BlockInstanceId = string;
6
6
  export type ResourceId = string;
7
7
  export type SyncBlockProduct = (typeof SYNC_BLOCK_PRODUCTS)[number];
8
+ export type SyncBlockStatus = 'active' | 'deleted' | 'unpublished';
8
9
  export type SyncBlockAttrs = {
9
10
  localId: BlockInstanceId;
10
11
  resourceId: ResourceId;
@@ -34,7 +35,7 @@ export interface SyncBlockData {
34
35
  /**
35
36
  * Whether the block is on the same page as the source block
36
37
  */
37
- onSamePage?: boolean;
38
+ onSameDocument?: boolean;
38
39
  product?: SyncBlockProduct;
39
40
  /**
40
41
  * The ARI of the block. E.G ari:cloud:blocks:<cloudId>:synced-block/<product>/<pageId>/<resourceId>
@@ -45,6 +46,7 @@ export interface SyncBlockData {
45
46
  sourceTitle?: string;
46
47
  sourceURL?: string;
47
48
  updatedAt?: string;
49
+ status?: SyncBlockStatus;
48
50
  }
49
51
  export interface ReferenceSyncBlockResponse {
50
52
  blockAri: string;
@@ -55,7 +57,7 @@ export interface ReferenceSyncBlockResponse {
55
57
  }
56
58
  export interface ReferenceSyncBlock extends ReferenceSyncBlockResponse {
57
59
  hasAccess: boolean;
58
- onSamePage: boolean;
60
+ onSameDocument: boolean;
59
61
  }
60
62
  export type ReferenceSyncBlockData = {
61
63
  error?: SyncBlockError;
@@ -1,6 +1,6 @@
1
1
  export { rebaseTransaction } from './common/rebase-transaction';
2
2
  export { SyncBlockError } from './common/types';
3
- export type { SyncBlockData, SyncBlockNode, SyncBlockProduct, BlockInstanceId, SyncBlockAttrs, ReferenceSyncBlockData, ReferencesSourceInfo } from './common/types';
3
+ export type { ResourceId, SyncBlockData, SyncBlockNode, SyncBlockProduct, SyncBlockStatus, BlockInstanceId, SyncBlockAttrs, ReferenceSyncBlockData, ReferencesSourceInfo } from './common/types';
4
4
  export { useFetchSyncBlockData, type UseFetchSyncBlockDataResult, } from './hooks/useFetchSyncBlockData';
5
5
  export { useFetchSyncBlockTitle } from './hooks/useFetchSyncBlockTitle';
6
6
  export { useHandleContentChanges } from './hooks/useHandleContentChanges';
@@ -11,7 +11,7 @@ export { getJiraWorkItemAri, getJiraWorkItemIdFromAri } from './clients/jira/ari
11
11
  export { useMemoizedBlockServiceAPIProviders, useMemoizedBlockServiceFetchOnlyAPIProvider, } from './providers/block-service/blockServiceAPI';
12
12
  export { fetchConfluencePageInfo } from './clients/confluence/sourceInfo';
13
13
  export { SyncBlockProvider as SyncedBlockProvider, useMemoizedSyncedBlockProvider, } from './providers/syncBlockProvider';
14
- export type { ADFFetchProvider, ADFWriteProvider, BlockNodeIdentifiers, SyncBlockDataProvider, SyncBlockInstance, MediaEmojiProviderOptions, SyncedBlockRendererProviderOptions, SyncBlockRendererProviderCreator, SyncedBlockRendererDataProviders, UpdateReferenceSyncBlockResult, WriteSyncBlockResult, SyncBlockParentInfo, SyncBlockSourceInfo, } from './providers/types';
14
+ export type { ADFFetchProvider, ADFWriteProvider, BlockNodeIdentifiers, BlockSubscriptionErrorCallback, BlockUpdateCallback, SyncBlockDataProvider, SyncBlockInstance, MediaEmojiProviderOptions, SyncedBlockRendererProviderOptions, SyncBlockRendererProviderCreator, SyncedBlockRendererDataProviders, Unsubscribe, UpdateReferenceSyncBlockResult, WriteSyncBlockResult, SyncBlockParentInfo, SyncBlockSourceInfo, } from './providers/types';
15
15
  export { type ReferenceSyncBlockStoreManager } from './store-manager/referenceSyncBlockStoreManager';
16
16
  export { SyncBlockStoreManager, useMemoizedSyncBlockStoreManager, } from './store-manager/syncBlockStoreManager';
17
17
  export { resolveSyncBlockInstance } from './utils/resolveSyncBlockInstance';
@@ -44,6 +44,14 @@ declare class BlockServiceADFFetchProvider implements ADFFetchProvider {
44
44
  * @returns Array of SyncBlockInstance results
45
45
  */
46
46
  batchFetchData(blockNodeIdentifiers: BlockNodeIdentifiers[]): Promise<SyncBlockInstance[]>;
47
+ /**
48
+ * Subscribes to real-time updates for a specific block using GraphQL WebSocket subscriptions.
49
+ * @param resourceId - The resource ID of the block to subscribe to
50
+ * @param onUpdate - Callback function invoked when the block is updated
51
+ * @param onError - Optional callback function invoked on subscription errors
52
+ * @returns Unsubscribe function to stop receiving updates
53
+ */
54
+ subscribeToBlockUpdates(resourceId: ResourceId, onUpdate: (data: SyncBlockInstance) => void, onError?: (error: Error) => void): () => void;
47
55
  }
48
56
  interface BlockServiceADFWriteProviderProps {
49
57
  cloudId: string;
@@ -1,7 +1,7 @@
1
1
  import type { RendererSyncBlockEventPayload } from '@atlaskit/editor-common/analytics';
2
2
  import type { JSONNode } from '@atlaskit/editor-json-transformer/types';
3
3
  import { type BlockInstanceId, type ReferenceSyncBlockData, type ResourceId, type SyncBlockAttrs, type SyncBlockData, type SyncBlockNode, type SyncBlockProduct } from '../common/types';
4
- import { SyncBlockDataProvider, type ADFFetchProvider, type ADFWriteProvider, type DeleteSyncBlockResult, type SyncBlockInstance, type SyncBlockParentInfo, type SyncBlockSourceInfo, type SyncedBlockRendererProviderOptions, type UpdateReferenceSyncBlockResult, type WriteSyncBlockResult } from './types';
4
+ import { SyncBlockDataProvider, type ADFFetchProvider, type ADFWriteProvider, type BlockSubscriptionErrorCallback, type BlockUpdateCallback, type DeleteSyncBlockResult, type SyncBlockInstance, type SyncBlockParentInfo, type SyncBlockSourceInfo, type SyncedBlockRendererProviderOptions, type Unsubscribe, type UpdateReferenceSyncBlockResult, type WriteSyncBlockResult } from './types';
5
5
  export declare class SyncBlockProvider extends SyncBlockDataProvider {
6
6
  name: string;
7
7
  private fetchProvider;
@@ -91,6 +91,14 @@ export declare class SyncBlockProvider extends SyncBlockDataProvider {
91
91
  retrieveSyncBlockParentInfo(sourceAri: string, sourceProduct: SyncBlockProduct): SyncBlockParentInfo | undefined;
92
92
  updateReferenceData(blocks: SyncBlockAttrs[], noContent?: boolean): Promise<UpdateReferenceSyncBlockResult>;
93
93
  fetchReferences(resourceId: string, isSource: boolean): Promise<ReferenceSyncBlockData>;
94
+ /**
95
+ * Subscribes to real-time updates for a specific block.
96
+ * @param resourceId - The resource ID of the block to subscribe to
97
+ * @param onUpdate - Callback function invoked when the block is updated
98
+ * @param onError - Optional callback function invoked on subscription errors
99
+ * @returns Unsubscribe function to stop receiving updates, or undefined if not supported
100
+ */
101
+ subscribeToBlockUpdates(resourceId: string, onUpdate: BlockUpdateCallback, onError?: BlockSubscriptionErrorCallback): Unsubscribe | undefined;
94
102
  }
95
103
  type UseMemoizedSyncedBlockProviderProps = {
96
104
  fetchProvider: ADFFetchProvider;
@@ -5,10 +5,6 @@ import type { MentionProvider } from '@atlaskit/mention/types';
5
5
  import { NodeDataProvider } from '@atlaskit/node-data-provider';
6
6
  import type { TaskDecisionProvider } from '@atlaskit/task-decision/types';
7
7
  import type { SyncBlockData, ResourceId, SyncBlockError, SyncBlockNode, SyncBlockProduct, BlockInstanceId, SyncBlockAttrs, ReferenceSyncBlockData } from '../common/types';
8
- export type BlockNodeIdentifiers = {
9
- blockInstanceId: string;
10
- resourceId: string;
11
- };
12
8
  /**
13
9
  * The instance of a sync block, containing its data and metadata.
14
10
  * Mainly used for representing the state of a sync block after fetching from a data provider.
@@ -33,7 +29,7 @@ export type SyncBlockSourceInfo = {
33
29
  * Whether the source info is for a source synced block
34
30
  */
35
31
  isSource?: boolean;
36
- onSamePage?: boolean;
32
+ onSameDocument?: boolean;
37
33
  productType?: SyncBlockProduct;
38
34
  sourceAri: string;
39
35
  subType?: string | null;
@@ -56,10 +52,21 @@ export type UpdateReferenceSyncBlockResult = {
56
52
  error?: string;
57
53
  success: boolean;
58
54
  };
55
+ export type BlockNodeIdentifiers = {
56
+ blockInstanceId: string;
57
+ resourceId: string;
58
+ };
59
+ export type BlockUpdateCallback = (data: SyncBlockInstance) => void;
60
+ export type BlockSubscriptionErrorCallback = (error: Error) => void;
61
+ export type Unsubscribe = () => void;
59
62
  export interface ADFFetchProvider {
60
63
  batchFetchData: (blockNodeIdentifiers: BlockNodeIdentifiers[]) => Promise<SyncBlockInstance[]>;
61
64
  fetchData: (resourceId: ResourceId) => Promise<SyncBlockInstance>;
62
65
  fetchReferences: (referenceResourceId: string) => Promise<ReferenceSyncBlockData>;
66
+ /**
67
+ * Subscribes to real-time updates for a specific block.
68
+ */
69
+ subscribeToBlockUpdates?: (resourceId: ResourceId, onUpdate: BlockUpdateCallback, onError?: BlockSubscriptionErrorCallback) => Unsubscribe;
63
70
  }
64
71
  export interface ADFWriteProvider {
65
72
  createData: (data: SyncBlockData) => Promise<WriteSyncBlockResult>;
@@ -88,8 +95,8 @@ export type SyncedBlockRendererDataProviders = {
88
95
  export type SyncBlockRendererProviderCreator = {
89
96
  createEmojiProvider: ((options: MediaEmojiProviderOptions) => Promise<EmojiProvider> | undefined) | undefined;
90
97
  createMediaProvider: ((options: MediaEmojiProviderOptions) => Promise<MediaProvider> | undefined) | undefined;
91
- createSSRMediaProvider?: ((options: MediaEmojiProviderOptions) => MediaProvider | undefined) | undefined;
92
98
  createSmartLinkProvider: (() => Promise<CardProvider>) | undefined;
99
+ createSSRMediaProvider?: ((options: MediaEmojiProviderOptions) => MediaProvider | undefined) | undefined;
93
100
  };
94
101
  export type SyncedBlockRendererProviderOptions = {
95
102
  parentDataProviders?: SyncedBlockRendererDataProviders;
@@ -119,6 +126,15 @@ export declare abstract class SyncBlockDataProvider extends NodeDataProvider<Syn
119
126
  abstract generateResourceIdForReference(sourceId: ResourceId): ResourceId;
120
127
  abstract updateReferenceData(blocks: SyncBlockAttrs[], noContent?: boolean): Promise<UpdateReferenceSyncBlockResult>;
121
128
  abstract fetchReferences(resourceId: string, isSource: boolean): Promise<ReferenceSyncBlockData>;
129
+ /**
130
+ * Subscribes to real-time updates for a specific block.
131
+ * Returns undefined if subscriptions are not supported.
132
+ * @param resourceId - The resource ID of the block to subscribe to
133
+ * @param onUpdate - Callback function invoked when the block is updated
134
+ * @param onError - Optional callback function invoked on subscription errors
135
+ * @returns Unsubscribe function to stop receiving updates, or undefined if not supported
136
+ */
137
+ subscribeToBlockUpdates?(resourceId: ResourceId, onUpdate: BlockUpdateCallback, onError?: BlockSubscriptionErrorCallback): Unsubscribe | undefined;
122
138
  }
123
139
  export type SubscriptionCallback = (data: SyncBlockInstance) => void;
124
140
  export type TitleSubscriptionCallback = (title: string) => void;
@@ -17,19 +17,78 @@ export declare class ReferenceSyncBlockStoreManager {
17
17
  private syncBlockSourceInfoRequests;
18
18
  private isRefreshingSubscriptions;
19
19
  private pendingCacheDeletions;
20
+ private graphqlSubscriptions;
21
+ private useRealTimeSubscriptions;
22
+ private subscriptionChangeListeners;
20
23
  fetchExperience: Experience | undefined;
21
24
  private fetchSourceInfoExperience;
22
25
  private saveExperience;
23
26
  constructor(dataProvider?: SyncBlockDataProvider);
27
+ /**
28
+ * Enables or disables real-time GraphQL subscriptions for block updates.
29
+ * When enabled, the store manager will subscribe to real-time updates
30
+ * instead of relying on polling.
31
+ * @param enabled - Whether to enable real-time subscriptions
32
+ */
33
+ setRealTimeSubscriptionsEnabled(enabled: boolean): void;
34
+ /**
35
+ * Checks if real-time subscriptions are currently enabled.
36
+ */
37
+ isRealTimeSubscriptionsEnabled(): boolean;
38
+ /**
39
+ * Returns all resource IDs that are currently subscribed to.
40
+ * Used by React components to render subscription components.
41
+ */
42
+ getSubscribedResourceIds(): ResourceId[];
43
+ /**
44
+ * Registers a listener that will be called when subscriptions change.
45
+ * @param listener - Callback function to invoke when subscriptions change
46
+ * @returns Unsubscribe function to remove the listener
47
+ */
48
+ onSubscriptionsChanged(listener: () => void): () => void;
49
+ /**
50
+ * Notifies all subscription change listeners.
51
+ */
52
+ private notifySubscriptionChangeListeners;
53
+ /**
54
+ * Handles incoming data from a GraphQL subscription.
55
+ * Called by React subscription components when they receive updates.
56
+ * @param syncBlockInstance - The updated sync block instance
57
+ */
58
+ handleSubscriptionUpdate(syncBlockInstance: SyncBlockInstance): void;
24
59
  setFireAnalyticsEvent(fireAnalyticsEvent?: (payload: RendererSyncBlockEventPayload) => void): void;
25
60
  generateResourceIdForReference(sourceId: ResourceId): ResourceId;
26
61
  updateFireAnalyticsEvent(fireAnalyticsEvent?: (payload: RendererSyncBlockEventPayload) => void): void;
27
62
  getInitialSyncBlockData(resourceId: ResourceId): SyncBlockInstance | undefined;
28
63
  /**
29
64
  * Refreshes the subscriptions for all sync blocks.
65
+ * This is a fallback polling mechanism when real-time subscriptions are not enabled.
30
66
  * @returns {Promise<void>}
31
67
  */
32
68
  refreshSubscriptions(): Promise<void>;
69
+ /**
70
+ * Sets up a GraphQL subscription for a specific block.
71
+ * @param resourceId - The resource ID of the block to subscribe to
72
+ */
73
+ private setupGraphQLSubscription;
74
+ /**
75
+ * Handles updates received from GraphQL subscriptions.
76
+ * @param syncBlockInstance - The updated sync block instance
77
+ */
78
+ private handleGraphQLSubscriptionUpdate;
79
+ /**
80
+ * Cleans up the GraphQL subscription for a specific block.
81
+ * @param resourceId - The resource ID of the block to unsubscribe from
82
+ */
83
+ private cleanupGraphQLSubscription;
84
+ /**
85
+ * Sets up GraphQL subscriptions for all currently subscribed blocks.
86
+ */
87
+ private setupGraphQLSubscriptionsForAllBlocks;
88
+ /**
89
+ * Cleans up all GraphQL subscriptions.
90
+ */
91
+ private cleanupAllGraphQLSubscriptions;
33
92
  fetchSyncBlockSourceInfo(resourceId: ResourceId): Promise<SyncBlockSourceInfo | undefined>;
34
93
  /**
35
94
  * Fetch sync block data for a given array of sync block nodes.
@@ -1,4 +1,4 @@
1
- import type { ReferenceSyncBlockResponse, SyncBlockProduct } from '../../common/types';
1
+ import type { ReferenceSyncBlockResponse, SyncBlockProduct, SyncBlockStatus } from '../../common/types';
2
2
  export type BlockContentResponse = {
3
3
  blockAri: string;
4
4
  blockInstanceId: string;
@@ -7,7 +7,7 @@ export type BlockContentResponse = {
7
7
  createdBy: string;
8
8
  product: SyncBlockProduct;
9
9
  sourceAri: string;
10
- status: 'active' | 'deleted';
10
+ status: SyncBlockStatus;
11
11
  version: number;
12
12
  };
13
13
  export type ErrorResponse = {
@@ -0,0 +1,38 @@
1
+ import type { ADFEntity } from '@atlaskit/adf-utils/types';
2
+ import type { SyncBlockProduct } from '../../common/types';
3
+ export type BlockSubscriptionPayload = {
4
+ blockAri: string;
5
+ blockInstanceId: string;
6
+ content: string;
7
+ contentUpdatedAt?: number;
8
+ createdAt: number;
9
+ createdBy: string;
10
+ deletionReason?: string;
11
+ product: string;
12
+ sourceAri: string;
13
+ status: string;
14
+ };
15
+ export type ParsedBlockSubscriptionData = {
16
+ blockAri: string;
17
+ blockInstanceId: string;
18
+ content: ADFEntity[];
19
+ createdAt?: string;
20
+ createdBy: string;
21
+ product: SyncBlockProduct;
22
+ resourceId: string;
23
+ sourceAri: string;
24
+ status: string;
25
+ };
26
+ type SubscriptionCallback = (data: ParsedBlockSubscriptionData) => void;
27
+ type ErrorCallback = (error: Error) => void;
28
+ type Unsubscribe = () => void;
29
+ /**
30
+ * Creates a GraphQL subscription to block updates using the shared graphql-ws client.
31
+ *
32
+ * @param blockAri - The full block ARI to subscribe to (ari:cloud:blocks:{cloudId}:synced-block/{resourceId})
33
+ * @param onData - Callback function invoked when block data is updated
34
+ * @param onError - Optional callback function invoked on subscription errors
35
+ * @returns Unsubscribe function to close the subscription
36
+ */
37
+ export declare const subscribeToBlockUpdates: (blockAri: string, onData: SubscriptionCallback, onError?: ErrorCallback) => Unsubscribe;
38
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { SyncBlockSourceInfo } from '../../providers/types';
2
+ export declare const fetchJiraWorkItemInfo: (workItemAri: string, hasAccess: boolean) => Promise<SyncBlockSourceInfo | undefined>;
@@ -5,6 +5,7 @@ import type { SYNC_BLOCK_PRODUCTS } from './consts';
5
5
  export type BlockInstanceId = string;
6
6
  export type ResourceId = string;
7
7
  export type SyncBlockProduct = (typeof SYNC_BLOCK_PRODUCTS)[number];
8
+ export type SyncBlockStatus = 'active' | 'deleted' | 'unpublished';
8
9
  export type SyncBlockAttrs = {
9
10
  localId: BlockInstanceId;
10
11
  resourceId: ResourceId;
@@ -34,7 +35,7 @@ export interface SyncBlockData {
34
35
  /**
35
36
  * Whether the block is on the same page as the source block
36
37
  */
37
- onSamePage?: boolean;
38
+ onSameDocument?: boolean;
38
39
  product?: SyncBlockProduct;
39
40
  /**
40
41
  * The ARI of the block. E.G ari:cloud:blocks:<cloudId>:synced-block/<product>/<pageId>/<resourceId>
@@ -45,6 +46,7 @@ export interface SyncBlockData {
45
46
  sourceTitle?: string;
46
47
  sourceURL?: string;
47
48
  updatedAt?: string;
49
+ status?: SyncBlockStatus;
48
50
  }
49
51
  export interface ReferenceSyncBlockResponse {
50
52
  blockAri: string;
@@ -55,7 +57,7 @@ export interface ReferenceSyncBlockResponse {
55
57
  }
56
58
  export interface ReferenceSyncBlock extends ReferenceSyncBlockResponse {
57
59
  hasAccess: boolean;
58
- onSamePage: boolean;
60
+ onSameDocument: boolean;
59
61
  }
60
62
  export type ReferenceSyncBlockData = {
61
63
  error?: SyncBlockError;
@@ -1,6 +1,6 @@
1
1
  export { rebaseTransaction } from './common/rebase-transaction';
2
2
  export { SyncBlockError } from './common/types';
3
- export type { SyncBlockData, SyncBlockNode, SyncBlockProduct, BlockInstanceId, SyncBlockAttrs, ReferenceSyncBlockData, ReferencesSourceInfo } from './common/types';
3
+ export type { ResourceId, SyncBlockData, SyncBlockNode, SyncBlockProduct, SyncBlockStatus, BlockInstanceId, SyncBlockAttrs, ReferenceSyncBlockData, ReferencesSourceInfo } from './common/types';
4
4
  export { useFetchSyncBlockData, type UseFetchSyncBlockDataResult, } from './hooks/useFetchSyncBlockData';
5
5
  export { useFetchSyncBlockTitle } from './hooks/useFetchSyncBlockTitle';
6
6
  export { useHandleContentChanges } from './hooks/useHandleContentChanges';
@@ -11,7 +11,7 @@ export { getJiraWorkItemAri, getJiraWorkItemIdFromAri } from './clients/jira/ari
11
11
  export { useMemoizedBlockServiceAPIProviders, useMemoizedBlockServiceFetchOnlyAPIProvider, } from './providers/block-service/blockServiceAPI';
12
12
  export { fetchConfluencePageInfo } from './clients/confluence/sourceInfo';
13
13
  export { SyncBlockProvider as SyncedBlockProvider, useMemoizedSyncedBlockProvider, } from './providers/syncBlockProvider';
14
- export type { ADFFetchProvider, ADFWriteProvider, BlockNodeIdentifiers, SyncBlockDataProvider, SyncBlockInstance, MediaEmojiProviderOptions, SyncedBlockRendererProviderOptions, SyncBlockRendererProviderCreator, SyncedBlockRendererDataProviders, UpdateReferenceSyncBlockResult, WriteSyncBlockResult, SyncBlockParentInfo, SyncBlockSourceInfo, } from './providers/types';
14
+ export type { ADFFetchProvider, ADFWriteProvider, BlockNodeIdentifiers, BlockSubscriptionErrorCallback, BlockUpdateCallback, SyncBlockDataProvider, SyncBlockInstance, MediaEmojiProviderOptions, SyncedBlockRendererProviderOptions, SyncBlockRendererProviderCreator, SyncedBlockRendererDataProviders, Unsubscribe, UpdateReferenceSyncBlockResult, WriteSyncBlockResult, SyncBlockParentInfo, SyncBlockSourceInfo, } from './providers/types';
15
15
  export { type ReferenceSyncBlockStoreManager } from './store-manager/referenceSyncBlockStoreManager';
16
16
  export { SyncBlockStoreManager, useMemoizedSyncBlockStoreManager, } from './store-manager/syncBlockStoreManager';
17
17
  export { resolveSyncBlockInstance } from './utils/resolveSyncBlockInstance';
@@ -44,6 +44,14 @@ declare class BlockServiceADFFetchProvider implements ADFFetchProvider {
44
44
  * @returns Array of SyncBlockInstance results
45
45
  */
46
46
  batchFetchData(blockNodeIdentifiers: BlockNodeIdentifiers[]): Promise<SyncBlockInstance[]>;
47
+ /**
48
+ * Subscribes to real-time updates for a specific block using GraphQL WebSocket subscriptions.
49
+ * @param resourceId - The resource ID of the block to subscribe to
50
+ * @param onUpdate - Callback function invoked when the block is updated
51
+ * @param onError - Optional callback function invoked on subscription errors
52
+ * @returns Unsubscribe function to stop receiving updates
53
+ */
54
+ subscribeToBlockUpdates(resourceId: ResourceId, onUpdate: (data: SyncBlockInstance) => void, onError?: (error: Error) => void): () => void;
47
55
  }
48
56
  interface BlockServiceADFWriteProviderProps {
49
57
  cloudId: string;
@@ -1,7 +1,7 @@
1
1
  import type { RendererSyncBlockEventPayload } from '@atlaskit/editor-common/analytics';
2
2
  import type { JSONNode } from '@atlaskit/editor-json-transformer/types';
3
3
  import { type BlockInstanceId, type ReferenceSyncBlockData, type ResourceId, type SyncBlockAttrs, type SyncBlockData, type SyncBlockNode, type SyncBlockProduct } from '../common/types';
4
- import { SyncBlockDataProvider, type ADFFetchProvider, type ADFWriteProvider, type DeleteSyncBlockResult, type SyncBlockInstance, type SyncBlockParentInfo, type SyncBlockSourceInfo, type SyncedBlockRendererProviderOptions, type UpdateReferenceSyncBlockResult, type WriteSyncBlockResult } from './types';
4
+ import { SyncBlockDataProvider, type ADFFetchProvider, type ADFWriteProvider, type BlockSubscriptionErrorCallback, type BlockUpdateCallback, type DeleteSyncBlockResult, type SyncBlockInstance, type SyncBlockParentInfo, type SyncBlockSourceInfo, type SyncedBlockRendererProviderOptions, type Unsubscribe, type UpdateReferenceSyncBlockResult, type WriteSyncBlockResult } from './types';
5
5
  export declare class SyncBlockProvider extends SyncBlockDataProvider {
6
6
  name: string;
7
7
  private fetchProvider;
@@ -91,6 +91,14 @@ export declare class SyncBlockProvider extends SyncBlockDataProvider {
91
91
  retrieveSyncBlockParentInfo(sourceAri: string, sourceProduct: SyncBlockProduct): SyncBlockParentInfo | undefined;
92
92
  updateReferenceData(blocks: SyncBlockAttrs[], noContent?: boolean): Promise<UpdateReferenceSyncBlockResult>;
93
93
  fetchReferences(resourceId: string, isSource: boolean): Promise<ReferenceSyncBlockData>;
94
+ /**
95
+ * Subscribes to real-time updates for a specific block.
96
+ * @param resourceId - The resource ID of the block to subscribe to
97
+ * @param onUpdate - Callback function invoked when the block is updated
98
+ * @param onError - Optional callback function invoked on subscription errors
99
+ * @returns Unsubscribe function to stop receiving updates, or undefined if not supported
100
+ */
101
+ subscribeToBlockUpdates(resourceId: string, onUpdate: BlockUpdateCallback, onError?: BlockSubscriptionErrorCallback): Unsubscribe | undefined;
94
102
  }
95
103
  type UseMemoizedSyncedBlockProviderProps = {
96
104
  fetchProvider: ADFFetchProvider;
@@ -5,10 +5,6 @@ import type { MentionProvider } from '@atlaskit/mention/types';
5
5
  import { NodeDataProvider } from '@atlaskit/node-data-provider';
6
6
  import type { TaskDecisionProvider } from '@atlaskit/task-decision/types';
7
7
  import type { SyncBlockData, ResourceId, SyncBlockError, SyncBlockNode, SyncBlockProduct, BlockInstanceId, SyncBlockAttrs, ReferenceSyncBlockData } from '../common/types';
8
- export type BlockNodeIdentifiers = {
9
- blockInstanceId: string;
10
- resourceId: string;
11
- };
12
8
  /**
13
9
  * The instance of a sync block, containing its data and metadata.
14
10
  * Mainly used for representing the state of a sync block after fetching from a data provider.
@@ -33,7 +29,7 @@ export type SyncBlockSourceInfo = {
33
29
  * Whether the source info is for a source synced block
34
30
  */
35
31
  isSource?: boolean;
36
- onSamePage?: boolean;
32
+ onSameDocument?: boolean;
37
33
  productType?: SyncBlockProduct;
38
34
  sourceAri: string;
39
35
  subType?: string | null;
@@ -56,10 +52,21 @@ export type UpdateReferenceSyncBlockResult = {
56
52
  error?: string;
57
53
  success: boolean;
58
54
  };
55
+ export type BlockNodeIdentifiers = {
56
+ blockInstanceId: string;
57
+ resourceId: string;
58
+ };
59
+ export type BlockUpdateCallback = (data: SyncBlockInstance) => void;
60
+ export type BlockSubscriptionErrorCallback = (error: Error) => void;
61
+ export type Unsubscribe = () => void;
59
62
  export interface ADFFetchProvider {
60
63
  batchFetchData: (blockNodeIdentifiers: BlockNodeIdentifiers[]) => Promise<SyncBlockInstance[]>;
61
64
  fetchData: (resourceId: ResourceId) => Promise<SyncBlockInstance>;
62
65
  fetchReferences: (referenceResourceId: string) => Promise<ReferenceSyncBlockData>;
66
+ /**
67
+ * Subscribes to real-time updates for a specific block.
68
+ */
69
+ subscribeToBlockUpdates?: (resourceId: ResourceId, onUpdate: BlockUpdateCallback, onError?: BlockSubscriptionErrorCallback) => Unsubscribe;
63
70
  }
64
71
  export interface ADFWriteProvider {
65
72
  createData: (data: SyncBlockData) => Promise<WriteSyncBlockResult>;
@@ -88,8 +95,8 @@ export type SyncedBlockRendererDataProviders = {
88
95
  export type SyncBlockRendererProviderCreator = {
89
96
  createEmojiProvider: ((options: MediaEmojiProviderOptions) => Promise<EmojiProvider> | undefined) | undefined;
90
97
  createMediaProvider: ((options: MediaEmojiProviderOptions) => Promise<MediaProvider> | undefined) | undefined;
91
- createSSRMediaProvider?: ((options: MediaEmojiProviderOptions) => MediaProvider | undefined) | undefined;
92
98
  createSmartLinkProvider: (() => Promise<CardProvider>) | undefined;
99
+ createSSRMediaProvider?: ((options: MediaEmojiProviderOptions) => MediaProvider | undefined) | undefined;
93
100
  };
94
101
  export type SyncedBlockRendererProviderOptions = {
95
102
  parentDataProviders?: SyncedBlockRendererDataProviders;
@@ -119,6 +126,15 @@ export declare abstract class SyncBlockDataProvider extends NodeDataProvider<Syn
119
126
  abstract generateResourceIdForReference(sourceId: ResourceId): ResourceId;
120
127
  abstract updateReferenceData(blocks: SyncBlockAttrs[], noContent?: boolean): Promise<UpdateReferenceSyncBlockResult>;
121
128
  abstract fetchReferences(resourceId: string, isSource: boolean): Promise<ReferenceSyncBlockData>;
129
+ /**
130
+ * Subscribes to real-time updates for a specific block.
131
+ * Returns undefined if subscriptions are not supported.
132
+ * @param resourceId - The resource ID of the block to subscribe to
133
+ * @param onUpdate - Callback function invoked when the block is updated
134
+ * @param onError - Optional callback function invoked on subscription errors
135
+ * @returns Unsubscribe function to stop receiving updates, or undefined if not supported
136
+ */
137
+ subscribeToBlockUpdates?(resourceId: ResourceId, onUpdate: BlockUpdateCallback, onError?: BlockSubscriptionErrorCallback): Unsubscribe | undefined;
122
138
  }
123
139
  export type SubscriptionCallback = (data: SyncBlockInstance) => void;
124
140
  export type TitleSubscriptionCallback = (title: string) => void;
@@ -17,19 +17,78 @@ export declare class ReferenceSyncBlockStoreManager {
17
17
  private syncBlockSourceInfoRequests;
18
18
  private isRefreshingSubscriptions;
19
19
  private pendingCacheDeletions;
20
+ private graphqlSubscriptions;
21
+ private useRealTimeSubscriptions;
22
+ private subscriptionChangeListeners;
20
23
  fetchExperience: Experience | undefined;
21
24
  private fetchSourceInfoExperience;
22
25
  private saveExperience;
23
26
  constructor(dataProvider?: SyncBlockDataProvider);
27
+ /**
28
+ * Enables or disables real-time GraphQL subscriptions for block updates.
29
+ * When enabled, the store manager will subscribe to real-time updates
30
+ * instead of relying on polling.
31
+ * @param enabled - Whether to enable real-time subscriptions
32
+ */
33
+ setRealTimeSubscriptionsEnabled(enabled: boolean): void;
34
+ /**
35
+ * Checks if real-time subscriptions are currently enabled.
36
+ */
37
+ isRealTimeSubscriptionsEnabled(): boolean;
38
+ /**
39
+ * Returns all resource IDs that are currently subscribed to.
40
+ * Used by React components to render subscription components.
41
+ */
42
+ getSubscribedResourceIds(): ResourceId[];
43
+ /**
44
+ * Registers a listener that will be called when subscriptions change.
45
+ * @param listener - Callback function to invoke when subscriptions change
46
+ * @returns Unsubscribe function to remove the listener
47
+ */
48
+ onSubscriptionsChanged(listener: () => void): () => void;
49
+ /**
50
+ * Notifies all subscription change listeners.
51
+ */
52
+ private notifySubscriptionChangeListeners;
53
+ /**
54
+ * Handles incoming data from a GraphQL subscription.
55
+ * Called by React subscription components when they receive updates.
56
+ * @param syncBlockInstance - The updated sync block instance
57
+ */
58
+ handleSubscriptionUpdate(syncBlockInstance: SyncBlockInstance): void;
24
59
  setFireAnalyticsEvent(fireAnalyticsEvent?: (payload: RendererSyncBlockEventPayload) => void): void;
25
60
  generateResourceIdForReference(sourceId: ResourceId): ResourceId;
26
61
  updateFireAnalyticsEvent(fireAnalyticsEvent?: (payload: RendererSyncBlockEventPayload) => void): void;
27
62
  getInitialSyncBlockData(resourceId: ResourceId): SyncBlockInstance | undefined;
28
63
  /**
29
64
  * Refreshes the subscriptions for all sync blocks.
65
+ * This is a fallback polling mechanism when real-time subscriptions are not enabled.
30
66
  * @returns {Promise<void>}
31
67
  */
32
68
  refreshSubscriptions(): Promise<void>;
69
+ /**
70
+ * Sets up a GraphQL subscription for a specific block.
71
+ * @param resourceId - The resource ID of the block to subscribe to
72
+ */
73
+ private setupGraphQLSubscription;
74
+ /**
75
+ * Handles updates received from GraphQL subscriptions.
76
+ * @param syncBlockInstance - The updated sync block instance
77
+ */
78
+ private handleGraphQLSubscriptionUpdate;
79
+ /**
80
+ * Cleans up the GraphQL subscription for a specific block.
81
+ * @param resourceId - The resource ID of the block to unsubscribe from
82
+ */
83
+ private cleanupGraphQLSubscription;
84
+ /**
85
+ * Sets up GraphQL subscriptions for all currently subscribed blocks.
86
+ */
87
+ private setupGraphQLSubscriptionsForAllBlocks;
88
+ /**
89
+ * Cleans up all GraphQL subscriptions.
90
+ */
91
+ private cleanupAllGraphQLSubscriptions;
33
92
  fetchSyncBlockSourceInfo(resourceId: ResourceId): Promise<SyncBlockSourceInfo | undefined>;
34
93
  /**
35
94
  * Fetch sync block data for a given array of sync block nodes.
package/package.json CHANGED
@@ -31,6 +31,7 @@
31
31
  "@atlaskit/platform-feature-flags": "^1.1.0",
32
32
  "@babel/runtime": "^7.0.0",
33
33
  "@compiled/react": "^0.18.6",
34
+ "graphql-ws": "^5.14.2",
34
35
  "uuid": "^3.1.0"
35
36
  },
36
37
  "peerDependencies": {
@@ -77,7 +78,7 @@
77
78
  }
78
79
  },
79
80
  "name": "@atlaskit/editor-synced-block-provider",
80
- "version": "3.12.1",
81
+ "version": "3.13.0",
81
82
  "description": "Synced Block Provider for @atlaskit/editor-plugin-synced-block",
82
83
  "author": "Atlassian Pty Ltd",
83
84
  "license": "Apache-2.0",