@atlaskit/editor-synced-block-provider 8.5.7 → 8.6.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/CHANGELOG.md +24 -0
- package/dist/cjs/store-manager/referenceSyncBlockStoreManager.js +1 -1
- package/dist/cjs/store-manager/sourceSyncBlockStoreManager.js +72 -13
- package/dist/cjs/store-manager/syncBlockSubscriptionManager.js +216 -66
- package/dist/cjs/utils/errorHandling.js +47 -9
- package/dist/es2019/store-manager/referenceSyncBlockStoreManager.js +1 -1
- package/dist/es2019/store-manager/sourceSyncBlockStoreManager.js +79 -22
- package/dist/es2019/store-manager/syncBlockSubscriptionManager.js +133 -7
- package/dist/es2019/utils/errorHandling.js +50 -6
- package/dist/esm/store-manager/referenceSyncBlockStoreManager.js +1 -1
- package/dist/esm/store-manager/sourceSyncBlockStoreManager.js +73 -14
- package/dist/esm/store-manager/syncBlockSubscriptionManager.js +216 -66
- package/dist/esm/utils/errorHandling.js +46 -8
- package/dist/types/entry-points/errorHandling.d.ts +1 -0
- package/dist/types/store-manager/sourceSyncBlockStoreManager.d.ts +27 -1
- package/dist/types/store-manager/syncBlockSubscriptionManager.d.ts +28 -0
- package/dist/types/utils/errorHandling.d.ts +31 -6
- package/package.json +5 -6
|
@@ -3,6 +3,7 @@ import type { ViewMode } from '@atlaskit/editor-plugin-editor-viewmode';
|
|
|
3
3
|
import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
|
|
4
4
|
import type { ResourceId, SyncBlockAttrs, BlockInstanceId, DeletionReason, DeletionMechanism, ReferenceSyncBlockData } from '../common/types';
|
|
5
5
|
import type { SyncBlockDataProviderInterface, SyncBlockSourceInfo } from '../providers/types';
|
|
6
|
+
import type { CreateSuccessEnrichment } from '../utils/errorHandling';
|
|
6
7
|
export type ConfirmationCallback = (syncBlockIds: SyncBlockAttrs[], deleteReason: DeletionReason | undefined) => Promise<boolean>;
|
|
7
8
|
type OnDelete = () => void;
|
|
8
9
|
type OnCompletion = (success: boolean) => void;
|
|
@@ -35,6 +36,20 @@ export declare class SourceSyncBlockStoreManager {
|
|
|
35
36
|
* multiple blocks are created concurrently. See EDITOR-7112.
|
|
36
37
|
*/
|
|
37
38
|
private creationsTimedOutDuringFlush;
|
|
39
|
+
/**
|
|
40
|
+
* Creation-type signals captured at `createBodiedSyncBlockNode` time and read
|
|
41
|
+
* back in `commitPendingCreation` to enrich the `syncedBlockCreate` event.
|
|
42
|
+
* Kept out of the flushed cache record so it never leaks into Block Service /
|
|
43
|
+
* ADF; removed once consumed.
|
|
44
|
+
*/
|
|
45
|
+
private creationEnrichment;
|
|
46
|
+
/**
|
|
47
|
+
* Resource IDs of blocks created empty this session that have not yet fired
|
|
48
|
+
* the first-content-added event. Added on empty creation, removed when the
|
|
49
|
+
* block first gains content (the event fires once). Blocks created with
|
|
50
|
+
* content or not created this session are never tracked.
|
|
51
|
+
*/
|
|
52
|
+
private awaitingFirstContent;
|
|
38
53
|
private createExperience;
|
|
39
54
|
private saveExperience;
|
|
40
55
|
private deleteExperience;
|
|
@@ -86,6 +101,13 @@ export declare class SourceSyncBlockStoreManager {
|
|
|
86
101
|
* @param success
|
|
87
102
|
*/
|
|
88
103
|
commitPendingCreation(success: boolean, resourceId: ResourceId): void;
|
|
104
|
+
/**
|
|
105
|
+
* Fire the first-content-added event once when a block created empty this
|
|
106
|
+
* session first gains content. The caller detects the in-block edit; this owns
|
|
107
|
+
* dedupe + emission (fires at most once per block, only for empty→content).
|
|
108
|
+
* Gated behind `platform_editor_blocks_patch_4`.
|
|
109
|
+
*/
|
|
110
|
+
maybeEmitFirstContentAdded(resourceId: ResourceId, blockInstanceId?: BlockInstanceId): void;
|
|
89
111
|
registerConfirmationCallback(callback: ConfirmationCallback): () => void;
|
|
90
112
|
requireConfirmationBeforeDelete(): boolean;
|
|
91
113
|
/**
|
|
@@ -97,8 +119,12 @@ export declare class SourceSyncBlockStoreManager {
|
|
|
97
119
|
* @param attrs attributes Ids of the node
|
|
98
120
|
* @param node the ProseMirror node to cache
|
|
99
121
|
* @param onCompletion callback invoked when creation completes
|
|
122
|
+
* @param enrichment optional creation-type signals stashed and attached to the
|
|
123
|
+
* `syncedBlockCreate` event when the async create resolves. When
|
|
124
|
+
* `createdEmpty` is true the block is also registered for the
|
|
125
|
+
* first-content-added event.
|
|
100
126
|
*/
|
|
101
|
-
createBodiedSyncBlockNode(attrs: SyncBlockAttrs, node: PMNode, onCompletion: OnCompletion): void;
|
|
127
|
+
createBodiedSyncBlockNode(attrs: SyncBlockAttrs, node: PMNode, onCompletion: OnCompletion, enrichment?: CreateSuccessEnrichment): void;
|
|
102
128
|
private setPendingDeletion;
|
|
103
129
|
/**
|
|
104
130
|
* Drop dedupe entries older than {@link DELETE_DEDUPE_WINDOW_MS} so
|
|
@@ -37,6 +37,12 @@ export declare class SyncBlockSubscriptionManager {
|
|
|
37
37
|
private static readonly MAX_RETRY_DELAY_MS;
|
|
38
38
|
private retryAttempts;
|
|
39
39
|
private pendingRetries;
|
|
40
|
+
private deferredExhausted;
|
|
41
|
+
private static readonly WAKE_DEBOUNCE_MS;
|
|
42
|
+
private wakeDebounceTimer;
|
|
43
|
+
private readonly onOnline;
|
|
44
|
+
private readonly onVisibilityChange;
|
|
45
|
+
private wakeListenerCleanups;
|
|
40
46
|
private getMaxRetryAttempts;
|
|
41
47
|
private getReconnectionDelay;
|
|
42
48
|
constructor(deps: SyncBlockSubscriptionManagerDeps);
|
|
@@ -72,6 +78,28 @@ export declare class SyncBlockSubscriptionManager {
|
|
|
72
78
|
* update is received, indicating the subscription is healthy.
|
|
73
79
|
*/
|
|
74
80
|
private resetRetryCount;
|
|
81
|
+
/**
|
|
82
|
+
* Whether the tab is currently hidden. SSR/non-browser is treated as "not hidden" so
|
|
83
|
+
* we never defer where wake events can't fire (realtime never subscribes there anyway).
|
|
84
|
+
*/
|
|
85
|
+
private isDocumentHidden;
|
|
86
|
+
/**
|
|
87
|
+
* Lazily register shared `online` / `visibilitychange` listeners on first deferral.
|
|
88
|
+
* Torn down by `unregisterWakeListeners` (via `handleWake`). No-op in SSR / non-browser.
|
|
89
|
+
*/
|
|
90
|
+
private registerWakeListeners;
|
|
91
|
+
private unregisterWakeListeners;
|
|
92
|
+
/**
|
|
93
|
+
* Coalesce a burst of wake events into one debounced re-arm sweep. Callers decide
|
|
94
|
+
* eligibility: `onOnline` always sweeps; `onVisibilityChange` only sweeps when visible.
|
|
95
|
+
*/
|
|
96
|
+
private scheduleWakeSweep;
|
|
97
|
+
/**
|
|
98
|
+
* Re-arm every deferred resource: full reset (attempts→0) + immediate reconnect now
|
|
99
|
+
* the tab is visible / online. Healthy subscriptions are untouched. A re-armed cycle
|
|
100
|
+
* that later exhausts while visible fires the terminal error normally.
|
|
101
|
+
*/
|
|
102
|
+
private handleWake;
|
|
75
103
|
private cancelPendingRetry;
|
|
76
104
|
private cancelAllPendingRetries;
|
|
77
105
|
cleanupSubscription(resourceId: ResourceId): void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics';
|
|
2
|
-
import type { RendererSyncBlockEventPayload, OperationalAEP, SyncBlockEventPayload } from '@atlaskit/editor-common/analytics';
|
|
2
|
+
import type { INPUT_METHOD, RendererSyncBlockEventPayload, OperationalAEP, SyncBlockEventPayload } from '@atlaskit/editor-common/analytics';
|
|
3
3
|
import { SyncBlockError } from '../common/types';
|
|
4
4
|
import type { DeletionMechanism, DeletionReason } from '../common/types';
|
|
5
5
|
export declare const stringifyError: (error: unknown) => string | undefined;
|
|
@@ -111,6 +111,13 @@ export type FetchErrorAttributionAttributes = {
|
|
|
111
111
|
* always sets it, so requiring it costs nothing.
|
|
112
112
|
*/
|
|
113
113
|
benign: boolean;
|
|
114
|
+
/**
|
|
115
|
+
* Set when a `websocket_exhausted` outcome was deferred (tab hidden at exhaustion, so
|
|
116
|
+
* the subscription re-arms on online/visibilitychange) rather than surfaced as a
|
|
117
|
+
* terminal failure. Auditable on the dashboard but counted benign — the user isn't
|
|
118
|
+
* experiencing a failure while hidden. Spread only when true, never `undefined`.
|
|
119
|
+
*/
|
|
120
|
+
deferred?: boolean;
|
|
114
121
|
};
|
|
115
122
|
/**
|
|
116
123
|
* Builds the {@link FetchErrorAttributionAttributes} for a failed fetch/subscribe
|
|
@@ -122,7 +129,7 @@ export type FetchErrorAttributionAttributes = {
|
|
|
122
129
|
* `gateEnabled` is injected by the caller (the store managers evaluate `fg(...)`) so this
|
|
123
130
|
* helper stays pure and trivially unit-testable for both gate states.
|
|
124
131
|
*/
|
|
125
|
-
export declare const buildFetchErrorAttribution: (gateEnabled: boolean, error?: string, statusCode?: number) => FetchErrorAttributionAttributes | undefined;
|
|
132
|
+
export declare const buildFetchErrorAttribution: (gateEnabled: boolean, error?: string, statusCode?: number, deferred?: boolean) => FetchErrorAttributionAttributes | undefined;
|
|
126
133
|
/**
|
|
127
134
|
* Shared operational ERROR payload builder for synced-block events.
|
|
128
135
|
*
|
|
@@ -141,6 +148,7 @@ export declare function getErrorPayload<T extends ACTION_SUBJECT_ID>(actionSubje
|
|
|
141
148
|
reason?: SyncBlockFetchErrorReason;
|
|
142
149
|
statusCode?: number;
|
|
143
150
|
benign?: boolean;
|
|
151
|
+
deferred?: boolean;
|
|
144
152
|
}>;
|
|
145
153
|
export declare function getErrorPayload<T extends ACTION_SUBJECT_ID>(actionSubjectId: T, error: string, resourceId?: string, sourceProduct?: string, attribution?: ErrorAttributionAttributes): OperationalAEP<ACTION.ERROR, ACTION_SUBJECT.SYNCED_BLOCK, T, {
|
|
146
154
|
error: string;
|
|
@@ -175,11 +183,28 @@ export declare const fetchReferencesErrorPayload: (error: string, resourceId?: s
|
|
|
175
183
|
export declare const fetchSuccessPayload: (resourceId: string, blockInstanceId?: string, sourceProduct?: string) => RendererSyncBlockEventPayload;
|
|
176
184
|
export declare const createSuccessPayload: (resourceId: string, sourceProduct?: string) => SyncBlockEventPayload;
|
|
177
185
|
/**
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
186
|
+
* Optional enrichment for the `syncedBlockCreate` success event. All fields
|
|
187
|
+
* optional so gate-off/legacy payloads are unchanged. `inputMethod`: creating
|
|
188
|
+
* surface (enum, PII-safe). `createdEmpty`: true from an empty selection, false
|
|
189
|
+
* when content was converted.
|
|
190
|
+
*/
|
|
191
|
+
export type CreateSuccessEnrichment = {
|
|
192
|
+
createdEmpty?: boolean;
|
|
193
|
+
inputMethod?: INPUT_METHOD;
|
|
194
|
+
};
|
|
195
|
+
/**
|
|
196
|
+
* Operational `syncedBlockCreate` success event, behind
|
|
197
|
+
* `platform_editor_blocks_patch_4`, with the `blockInstanceId` join key and,
|
|
198
|
+
* when available, the `inputMethod` + `createdEmpty` creation-type signals.
|
|
199
|
+
*/
|
|
200
|
+
export declare const createSuccessOperationalPayload: (resourceId: string, blockInstanceId?: string, sourceProduct?: string, enrichment?: CreateSuccessEnrichment) => SyncBlockEventPayload;
|
|
201
|
+
/**
|
|
202
|
+
* Operational first-content-added event, behind
|
|
203
|
+
* `platform_editor_blocks_patch_4`. Fired once when a block created empty first
|
|
204
|
+
* gains user content. Join keys only (`resourceId` + `blockInstanceId`), no user
|
|
205
|
+
* content (PII-safe).
|
|
181
206
|
*/
|
|
182
|
-
export declare const
|
|
207
|
+
export declare const addContentSuccessPayload: (resourceId: string, blockInstanceId?: string, sourceProduct?: string) => SyncBlockEventPayload;
|
|
183
208
|
export declare const updateSuccessPayload: (resourceId: string, hasReference?: boolean, sourceProduct?: string) => SyncBlockEventPayload;
|
|
184
209
|
/**
|
|
185
210
|
* Optional enrichment for the `syncedBlockDelete` success event behind
|
package/package.json
CHANGED
|
@@ -17,20 +17,22 @@
|
|
|
17
17
|
"atlaskit:src": "src/index.ts",
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@atlaskit/adf-utils": "^20.3.0",
|
|
20
|
+
"@atlaskit/browser-apis": "^1.1.0",
|
|
20
21
|
"@atlaskit/editor-json-transformer": "^9.0.0",
|
|
21
22
|
"@atlaskit/editor-prosemirror": "^8.0.0",
|
|
22
23
|
"@atlaskit/node-data-provider": "^13.0.0",
|
|
23
24
|
"@atlaskit/platform-feature-flags": "^2.0.0",
|
|
24
|
-
"@atlaskit/tmp-editor-statsig": "^124.
|
|
25
|
+
"@atlaskit/tmp-editor-statsig": "^124.2.0",
|
|
25
26
|
"@babel/runtime": "^7.0.0",
|
|
26
27
|
"@compiled/react": "^0.20.0",
|
|
28
|
+
"bind-event-listener": "^3.0.0",
|
|
27
29
|
"graphql-ws": "^5.14.2",
|
|
28
30
|
"lodash": "^4.17.21",
|
|
29
31
|
"raf-schd": "^4.0.3",
|
|
30
32
|
"uuid": "^3.1.0"
|
|
31
33
|
},
|
|
32
34
|
"peerDependencies": {
|
|
33
|
-
"@atlaskit/editor-common": "^116.
|
|
35
|
+
"@atlaskit/editor-common": "^116.27.0",
|
|
34
36
|
"react": "^18.2.0"
|
|
35
37
|
},
|
|
36
38
|
"devDependencies": {
|
|
@@ -74,7 +76,7 @@
|
|
|
74
76
|
}
|
|
75
77
|
},
|
|
76
78
|
"name": "@atlaskit/editor-synced-block-provider",
|
|
77
|
-
"version": "8.
|
|
79
|
+
"version": "8.6.1",
|
|
78
80
|
"description": "Synced Block Provider for @atlaskit/editor-plugin-synced-block",
|
|
79
81
|
"author": "Atlassian Pty Ltd",
|
|
80
82
|
"license": "Apache-2.0",
|
|
@@ -82,9 +84,6 @@
|
|
|
82
84
|
"registry": "https://registry.npmjs.org/"
|
|
83
85
|
},
|
|
84
86
|
"platform-feature-flags": {
|
|
85
|
-
"platform_editor_blocks_patch_2": {
|
|
86
|
-
"type": "boolean"
|
|
87
|
-
},
|
|
88
87
|
"platform_editor_blocks_patch_3": {
|
|
89
88
|
"type": "boolean"
|
|
90
89
|
},
|