velocious 1.0.488 → 1.0.492
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/README.md +2 -0
- package/build/application.js +3 -0
- package/build/cli/commands/db/tenants/create.js +7 -5
- package/build/cli/commands/db/tenants/drop.js +6 -6
- package/build/configuration-types.js +9 -0
- package/build/configuration.js +58 -0
- package/build/database/query/index.js +30 -0
- package/build/database/query/model-class-query.js +17 -0
- package/build/database/record/index.js +16 -0
- package/build/environment-handlers/node.js +22 -6
- package/build/src/application.d.ts.map +1 -1
- package/build/src/application.js +3 -1
- package/build/src/cli/commands/db/tenants/create.d.ts.map +1 -1
- package/build/src/cli/commands/db/tenants/create.js +8 -5
- package/build/src/cli/commands/db/tenants/drop.d.ts +1 -1
- package/build/src/cli/commands/db/tenants/drop.d.ts.map +1 -1
- package/build/src/cli/commands/db/tenants/drop.js +7 -6
- package/build/src/configuration-types.d.ts +29 -0
- package/build/src/configuration-types.d.ts.map +1 -1
- package/build/src/configuration-types.js +9 -1
- package/build/src/configuration.d.ts +17 -0
- package/build/src/configuration.d.ts.map +1 -1
- package/build/src/configuration.js +52 -1
- package/build/src/database/query/index.d.ts +25 -0
- package/build/src/database/query/index.d.ts.map +1 -1
- package/build/src/database/query/index.js +26 -1
- package/build/src/database/query/model-class-query.d.ts +10 -0
- package/build/src/database/query/model-class-query.d.ts.map +1 -1
- package/build/src/database/query/model-class-query.js +16 -1
- package/build/src/database/record/index.d.ts +7 -0
- package/build/src/database/record/index.d.ts.map +1 -1
- package/build/src/database/record/index.js +15 -1
- package/build/src/environment-handlers/node.d.ts.map +1 -1
- package/build/src/environment-handlers/node.js +20 -8
- package/build/src/sync/query-scope.d.ts +18 -0
- package/build/src/sync/query-scope.d.ts.map +1 -0
- package/build/src/sync/query-scope.js +77 -0
- package/build/src/sync/server-change-feed.d.ts.map +1 -1
- package/build/src/sync/server-change-feed.js +2 -24
- package/build/src/sync/stable-json.d.ts +9 -0
- package/build/src/sync/stable-json.d.ts.map +1 -0
- package/build/src/sync/stable-json.js +27 -0
- package/build/src/sync/sync-api-client.d.ts +185 -5
- package/build/src/sync/sync-api-client.d.ts.map +1 -1
- package/build/src/sync/sync-api-client.js +309 -17
- package/build/src/sync/sync-api-controller.d.ts +8 -0
- package/build/src/sync/sync-api-controller.d.ts.map +1 -1
- package/build/src/sync/sync-api-controller.js +17 -1
- package/build/src/sync/sync-client-registry.d.ts +12 -0
- package/build/src/sync/sync-client-registry.d.ts.map +1 -0
- package/build/src/sync/sync-client-registry.js +27 -0
- package/build/src/sync/sync-client-types.d.ts +127 -0
- package/build/src/sync/sync-client-types.d.ts.map +1 -0
- package/build/src/sync/sync-client-types.js +3 -0
- package/build/src/sync/sync-client.d.ts +176 -0
- package/build/src/sync/sync-client.d.ts.map +1 -0
- package/build/src/sync/sync-client.js +380 -0
- package/build/src/sync/sync-envelope-replay-service.d.ts +38 -4
- package/build/src/sync/sync-envelope-replay-service.d.ts.map +1 -1
- package/build/src/sync/sync-envelope-replay-service.js +73 -6
- package/build/src/sync/sync-resource-base.d.ts +98 -0
- package/build/src/sync/sync-resource-base.d.ts.map +1 -0
- package/build/src/sync/sync-resource-base.js +122 -0
- package/build/src/sync/sync-scope-store.d.ts +128 -0
- package/build/src/sync/sync-scope-store.d.ts.map +1 -0
- package/build/src/sync/sync-scope-store.js +282 -0
- package/build/src/tenants/default-tenant-database-provisioning.d.ts +21 -0
- package/build/src/tenants/default-tenant-database-provisioning.d.ts.map +1 -0
- package/build/src/tenants/default-tenant-database-provisioning.js +106 -0
- package/build/src/tenants/tenant.d.ts.map +1 -1
- package/build/src/tenants/tenant.js +6 -5
- package/build/sync/query-scope.js +84 -0
- package/build/sync/server-change-feed.js +1 -25
- package/build/sync/stable-json.js +28 -0
- package/build/sync/sync-api-client.js +331 -17
- package/build/sync/sync-api-controller.js +20 -0
- package/build/sync/sync-client-registry.js +30 -0
- package/build/sync/sync-client-types.js +41 -0
- package/build/sync/sync-client.js +433 -0
- package/build/sync/sync-envelope-replay-service.js +77 -5
- package/build/sync/sync-resource-base.js +143 -0
- package/build/sync/sync-scope-store.js +327 -0
- package/build/tenants/default-tenant-database-provisioning.js +124 -0
- package/build/tenants/tenant.js +5 -5
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/application.js +3 -0
- package/src/cli/commands/db/tenants/create.js +7 -5
- package/src/cli/commands/db/tenants/drop.js +6 -6
- package/src/configuration-types.js +9 -0
- package/src/configuration.js +58 -0
- package/src/database/query/index.js +30 -0
- package/src/database/query/model-class-query.js +17 -0
- package/src/database/record/index.js +16 -0
- package/src/environment-handlers/node.js +22 -6
- package/src/sync/query-scope.js +84 -0
- package/src/sync/server-change-feed.js +1 -25
- package/src/sync/stable-json.js +28 -0
- package/src/sync/sync-api-client.js +331 -17
- package/src/sync/sync-api-controller.js +20 -0
- package/src/sync/sync-client-registry.js +30 -0
- package/src/sync/sync-client-types.js +41 -0
- package/src/sync/sync-client.js +433 -0
- package/src/sync/sync-envelope-replay-service.js +77 -5
- package/src/sync/sync-resource-base.js +143 -0
- package/src/sync/sync-scope-store.js +327 -0
- package/src/tenants/default-tenant-database-provisioning.js +124 -0
- package/src/tenants/tenant.js +5 -5
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import { forcedFunction } from "typanic";
|
|
3
|
+
import Configuration from "../configuration.js";
|
|
4
|
+
import { serializedScopeFromQuery } from "./query-scope.js";
|
|
5
|
+
import SyncApiClient from "./sync-api-client.js";
|
|
6
|
+
import SyncScopeStore from "./sync-scope-store.js";
|
|
7
|
+
import { currentSyncClient, setCurrentSyncClient } from "./sync-client-registry.js";
|
|
8
|
+
let clientCounter = 0;
|
|
9
|
+
/** @type {{create: "afterCreate", update: "afterUpdate", destroy: "afterDestroy"}} */
|
|
10
|
+
const TRACKED_CALLBACK_NAMES = { create: "afterCreate", destroy: "afterDestroy", update: "afterUpdate" };
|
|
11
|
+
/**
|
|
12
|
+
* Declarative client-side sync driver.
|
|
13
|
+
*
|
|
14
|
+
* Apps configure resources, transport, auth, and connectivity once; Velocious
|
|
15
|
+
* owns scope persistence, per-scope cursors, pull paging/apply, local queueing,
|
|
16
|
+
* and online-gated replay. Declare sync interest from queries:
|
|
17
|
+
*
|
|
18
|
+
* const syncClient = new SyncClient({...})
|
|
19
|
+
* syncClient.setCurrent()
|
|
20
|
+
* await syncClient.sync(Event.where({partnerId}))
|
|
21
|
+
*/
|
|
22
|
+
export default class SyncClient {
|
|
23
|
+
/**
|
|
24
|
+
* Creates a declarative sync client.
|
|
25
|
+
* @param {import("./sync-client-types.js").SyncClientConfig} config - Sync client configuration.
|
|
26
|
+
*/
|
|
27
|
+
constructor(config) {
|
|
28
|
+
if (!config || typeof config !== "object")
|
|
29
|
+
throw new Error("SyncClient requires a configuration object");
|
|
30
|
+
forcedFunction(config.postChanges, "SyncClient config.postChanges");
|
|
31
|
+
forcedFunction(config.postReplay, "SyncClient config.postReplay");
|
|
32
|
+
forcedFunction(config.authenticationToken, "SyncClient config.authenticationToken");
|
|
33
|
+
if (!config.syncModel)
|
|
34
|
+
throw new Error("SyncClient requires config.syncModel");
|
|
35
|
+
if (!config.resources || typeof config.resources !== "object" || Object.keys(config.resources).length === 0) {
|
|
36
|
+
throw new Error("SyncClient requires at least one entry in config.resources");
|
|
37
|
+
}
|
|
38
|
+
for (const [resourceType, resource] of Object.entries(config.resources)) {
|
|
39
|
+
if (!resource || typeof resource !== "object" || !resource.modelClass) {
|
|
40
|
+
throw new Error(`SyncClient resource ${resourceType} must declare a modelClass`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
this.config = config;
|
|
44
|
+
this._clientNumber = ++clientCounter;
|
|
45
|
+
/** @type {import("./sync-scope-store.js").default | null} */
|
|
46
|
+
this._scopeStore = config.scopeStore || null;
|
|
47
|
+
/** @type {Promise<void> | null} */
|
|
48
|
+
this._scheduledReplay = null;
|
|
49
|
+
/** @type {Record<string, import("./sync-api-client-types.js").SyncResourceConfig> | null} */
|
|
50
|
+
this._pullResourceConfigs = null;
|
|
51
|
+
/** @type {Array<{callback: (record: ?) => Promise<void>, callbackName: "afterCreate" | "afterUpdate" | "afterDestroy", modelClass: ?}>} */
|
|
52
|
+
this._trackedCallbacks = [];
|
|
53
|
+
/** @type {WeakSet<object>} */
|
|
54
|
+
this._remoteApplyRecords = new WeakSet();
|
|
55
|
+
this._started = false;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Registers automatic mutation tracking for every resource with `track` enabled:
|
|
59
|
+
* local model creates/updates/destroys queue pending sync rows and schedule an
|
|
60
|
+
* immediate replay attempt, without app-side queue calls.
|
|
61
|
+
* @returns {Promise<void>}
|
|
62
|
+
*/
|
|
63
|
+
async start() {
|
|
64
|
+
if (this._started)
|
|
65
|
+
return;
|
|
66
|
+
this._started = true;
|
|
67
|
+
for (const [resourceType, resourceConfig] of Object.entries(this.config.resources)) {
|
|
68
|
+
const operations = this.trackedOperations({ resourceConfig, resourceType });
|
|
69
|
+
for (const operation of operations) {
|
|
70
|
+
const callbackName = TRACKED_CALLBACK_NAMES[operation];
|
|
71
|
+
const callback = this.trackedMutationCallback({ operation, resourceConfig });
|
|
72
|
+
resourceConfig.modelClass[callbackName](callback);
|
|
73
|
+
this._trackedCallbacks.push({ callback, callbackName, modelClass: resourceConfig.modelClass });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Unregisters all tracking callbacks (tests, sign-out, hot reload).
|
|
79
|
+
* @returns {void}
|
|
80
|
+
*/
|
|
81
|
+
stop() {
|
|
82
|
+
for (const { callback, callbackName, modelClass } of this._trackedCallbacks) {
|
|
83
|
+
modelClass.unregisterLifecycleCallback(callbackName, callback);
|
|
84
|
+
}
|
|
85
|
+
this._trackedCallbacks = [];
|
|
86
|
+
this._started = false;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Resolves and validates the tracked operations for a resource config.
|
|
90
|
+
* @param {{resourceConfig: import("./sync-client-types.js").SyncClientResourceConfig, resourceType: string}} args - Resource config and name.
|
|
91
|
+
* @returns {Array<"create" | "update" | "destroy">} Tracked operations.
|
|
92
|
+
*/
|
|
93
|
+
trackedOperations({ resourceConfig, resourceType }) {
|
|
94
|
+
const track = resourceConfig.track;
|
|
95
|
+
if (track === undefined || track === false)
|
|
96
|
+
return [];
|
|
97
|
+
if (track === true)
|
|
98
|
+
return ["create", "update", "destroy"];
|
|
99
|
+
if (!track || typeof track !== "object" || !Array.isArray(track.operations) || track.operations.length === 0) {
|
|
100
|
+
throw new Error(`SyncClient resource ${resourceType} track must be true or {operations: [...]}`);
|
|
101
|
+
}
|
|
102
|
+
for (const operation of track.operations) {
|
|
103
|
+
if (!(operation in TRACKED_CALLBACK_NAMES)) {
|
|
104
|
+
throw new Error(`SyncClient resource ${resourceType} track.operations must be create/update/destroy, got: ${String(operation)}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return track.operations;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Builds the lifecycle callback queueing one tracked mutation.
|
|
111
|
+
* @param {{operation: "create" | "update" | "destroy", resourceConfig: import("./sync-client-types.js").SyncClientResourceConfig}} args - Operation and resource config.
|
|
112
|
+
* @returns {(record: ?) => Promise<void>} Lifecycle callback.
|
|
113
|
+
*/
|
|
114
|
+
trackedMutationCallback({ operation, resourceConfig }) {
|
|
115
|
+
return async (record) => {
|
|
116
|
+
if (this.isRemoteApply(record))
|
|
117
|
+
return;
|
|
118
|
+
await SyncApiClient.queueLocalSync({
|
|
119
|
+
booleanAttributes: resourceConfig.booleanAttributes || [],
|
|
120
|
+
data: resourceConfig.trackedData ? resourceConfig.trackedData({ operation, record }) : undefined,
|
|
121
|
+
localOnlyAttributes: resourceConfig.localOnlyAttributes || [],
|
|
122
|
+
resource: record,
|
|
123
|
+
syncModel: this.config.syncModel,
|
|
124
|
+
syncType: this.defaultSyncType({ operation, record, resourceConfig })
|
|
125
|
+
});
|
|
126
|
+
this.scheduleReplay();
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Whether a record is currently being written by pull-apply (echo suppression).
|
|
131
|
+
* @param {?} record - Local model record.
|
|
132
|
+
* @returns {boolean} Whether the record write originates from a remote change.
|
|
133
|
+
*/
|
|
134
|
+
isRemoteApply(record) {
|
|
135
|
+
return this._remoteApplyRecords.has(record);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Registers this client as the app's current sync client.
|
|
139
|
+
* @returns {void}
|
|
140
|
+
*/
|
|
141
|
+
setCurrent() {
|
|
142
|
+
setCurrentSyncClient(this);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Returns the app's current sync client.
|
|
146
|
+
* @returns {SyncClient} Current sync client.
|
|
147
|
+
*/
|
|
148
|
+
static current() {
|
|
149
|
+
return /** @type {SyncClient} */ (currentSyncClient());
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Declares (or re-activates) a sync scope from a model query and pulls it when online.
|
|
153
|
+
* @param {import("../database/query/model-class-query.js").default<?>} query - Query declaring the sync scope.
|
|
154
|
+
* @returns {Promise<{scope: import("./sync-client-types.js").SerializedSyncScope, pulled: import("./sync-api-client-types.js").SyncChangesResult | null}>} Declared scope and pull result (null while offline).
|
|
155
|
+
*/
|
|
156
|
+
async sync(query) {
|
|
157
|
+
const scope = serializedScopeFromQuery(query);
|
|
158
|
+
const scopeStore = this.scopeStore();
|
|
159
|
+
const scopeRow = await scopeStore.findOrCreateScope(scope);
|
|
160
|
+
if (!scopeRow.cursorPayload && this.config.legacyCursor) {
|
|
161
|
+
const legacyCursorPayload = await this.config.legacyCursor({ scope });
|
|
162
|
+
const legacyCursor = SyncApiClient.syncCursorFromPayload(legacyCursorPayload);
|
|
163
|
+
if (legacyCursor)
|
|
164
|
+
await scopeStore.saveCursor(scopeRow, legacyCursor);
|
|
165
|
+
}
|
|
166
|
+
return { pulled: await this.pull(), scope };
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Deactivates the sync scope declared by a model query.
|
|
170
|
+
* @param {import("../database/query/model-class-query.js").default<?>} query - Query whose scope should stop syncing.
|
|
171
|
+
* @returns {Promise<void>}
|
|
172
|
+
*/
|
|
173
|
+
async unsync(query) {
|
|
174
|
+
await this.scopeStore().deactivate(serializedScopeFromQuery(query));
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Pulls changes for every active scope with per-scope cursors (single-flighted, online-gated).
|
|
178
|
+
* @returns {Promise<import("./sync-api-client-types.js").SyncChangesResult | null>} Combined pull result, or null while offline.
|
|
179
|
+
*/
|
|
180
|
+
async pull() {
|
|
181
|
+
if (!(await this.isOnline()))
|
|
182
|
+
return null;
|
|
183
|
+
/** @type {import("./sync-api-client-types.js").SyncChangesResult | null} */
|
|
184
|
+
let combinedResult = null;
|
|
185
|
+
await SyncApiClient.singleFlight(`velocious-sync-client-pull-${this._clientNumber}`, async () => {
|
|
186
|
+
const authenticationToken = await this.config.authenticationToken();
|
|
187
|
+
const scopeStore = this.scopeStore();
|
|
188
|
+
const pullResourceConfigs = this.pullResourceConfigs();
|
|
189
|
+
const applier = SyncApiClient.resourceApplier(pullResourceConfigs, (record) => {
|
|
190
|
+
this._remoteApplyRecords.add(record);
|
|
191
|
+
return () => this._remoteApplyRecords.delete(record);
|
|
192
|
+
});
|
|
193
|
+
/**
|
|
194
|
+
* Applies one pulled change, failing loudly instead of silently skipping unconfigured resources.
|
|
195
|
+
* @param {import("./sync-api-client-types.js").SyncChangeEnvelope} sync - Pulled change.
|
|
196
|
+
* @returns {Promise<import("./sync-api-client-types.js").SyncChangeApplyResult>} Apply result.
|
|
197
|
+
*/
|
|
198
|
+
const applySync = async (sync) => {
|
|
199
|
+
const resourceType = sync.resourceType();
|
|
200
|
+
if (!resourceType || !pullResourceConfigs[resourceType]) {
|
|
201
|
+
throw new Error(`No sync resource with pull attributes configured for pulled change: ${String(resourceType)}`);
|
|
202
|
+
}
|
|
203
|
+
return await applier(sync);
|
|
204
|
+
};
|
|
205
|
+
const result = {
|
|
206
|
+
changed: false,
|
|
207
|
+
pages: 0,
|
|
208
|
+
resourceChanged: /** @type {Record<string, boolean>} */ ({}),
|
|
209
|
+
resourceCounts: /** @type {Record<string, number>} */ ({}),
|
|
210
|
+
syncedCount: 0
|
|
211
|
+
};
|
|
212
|
+
for (const scopeRow of await scopeStore.activeScopes()) {
|
|
213
|
+
const scopeResult = await SyncApiClient.pullChanges({
|
|
214
|
+
applySync,
|
|
215
|
+
authenticationToken,
|
|
216
|
+
batchSize: this.config.batchSize,
|
|
217
|
+
loadCursor: async () => await scopeStore.loadCursor(scopeRow),
|
|
218
|
+
postChanges: async (payload) => await this.config.postChanges({
|
|
219
|
+
...payload,
|
|
220
|
+
scope: { conditions: scopeRow.conditions, resourceType: scopeRow.resourceType }
|
|
221
|
+
}),
|
|
222
|
+
saveCursor: async (cursor) => await scopeStore.saveCursor(scopeRow, cursor)
|
|
223
|
+
});
|
|
224
|
+
result.changed ||= scopeResult.changed;
|
|
225
|
+
result.pages += scopeResult.pages;
|
|
226
|
+
result.syncedCount += scopeResult.syncedCount;
|
|
227
|
+
for (const [resourceType, count] of Object.entries(scopeResult.resourceCounts)) {
|
|
228
|
+
result.resourceCounts[resourceType] = (result.resourceCounts[resourceType] || 0) + count;
|
|
229
|
+
}
|
|
230
|
+
for (const [resourceType, changed] of Object.entries(scopeResult.resourceChanged)) {
|
|
231
|
+
result.resourceChanged[resourceType] ||= changed;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
combinedResult = result;
|
|
235
|
+
});
|
|
236
|
+
return combinedResult;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Queues a local model change as a pending sync row and schedules an immediate
|
|
240
|
+
* replay attempt (kept pending while offline or when the backend rejects it).
|
|
241
|
+
* @param {{resource: ?, data?: Record<string, ?>, syncType?: string}} args - Queue args.
|
|
242
|
+
* @returns {Promise<?>} Pending local sync row.
|
|
243
|
+
*/
|
|
244
|
+
async queue({ data, resource, syncType }) {
|
|
245
|
+
const resourceConfig = this.resourceConfigFor(resource);
|
|
246
|
+
const syncRow = await SyncApiClient.queueLocalSync({
|
|
247
|
+
booleanAttributes: resourceConfig.booleanAttributes || [],
|
|
248
|
+
data,
|
|
249
|
+
localOnlyAttributes: resourceConfig.localOnlyAttributes || [],
|
|
250
|
+
resource,
|
|
251
|
+
syncModel: this.config.syncModel,
|
|
252
|
+
syncType: syncType ?? this.defaultSyncType({ operation: "update", record: resource, resourceConfig })
|
|
253
|
+
});
|
|
254
|
+
this.scheduleReplay();
|
|
255
|
+
return syncRow;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Drains pending local sync rows to the backend (single-flighted, online-gated).
|
|
259
|
+
* Rows are only marked successful after the backend acknowledges them.
|
|
260
|
+
* @returns {Promise<void>}
|
|
261
|
+
*/
|
|
262
|
+
async replayPending() {
|
|
263
|
+
if (!(await this.isOnline()))
|
|
264
|
+
return;
|
|
265
|
+
await SyncApiClient.singleFlight(`velocious-sync-client-replay-${this._clientNumber}`, async () => {
|
|
266
|
+
await SyncApiClient.replayLocalSyncs({
|
|
267
|
+
authenticationToken: await this.config.authenticationToken(),
|
|
268
|
+
batchSize: this.config.batchSize,
|
|
269
|
+
postReplay: this.config.postReplay,
|
|
270
|
+
syncModel: this.config.syncModel
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Schedules a background replay attempt without blocking the caller.
|
|
276
|
+
* Failures go to config.onError (or rethrow when none is configured).
|
|
277
|
+
* @returns {void}
|
|
278
|
+
*/
|
|
279
|
+
scheduleReplay() {
|
|
280
|
+
this._scheduledReplay = (async () => {
|
|
281
|
+
try {
|
|
282
|
+
await this.replayPending();
|
|
283
|
+
}
|
|
284
|
+
catch (error) {
|
|
285
|
+
this.reportError(/** @type {Error} */ (error));
|
|
286
|
+
}
|
|
287
|
+
})();
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Awaits the last scheduled background replay (useful in tests and shutdown flows).
|
|
291
|
+
* @returns {Promise<void>}
|
|
292
|
+
*/
|
|
293
|
+
async waitForScheduledReplay() {
|
|
294
|
+
if (this._scheduledReplay)
|
|
295
|
+
await this._scheduledReplay;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Reports a background sync failure.
|
|
299
|
+
* @param {Error} error - Background failure.
|
|
300
|
+
* @returns {void}
|
|
301
|
+
*/
|
|
302
|
+
reportError(error) {
|
|
303
|
+
if (this.config.onError) {
|
|
304
|
+
this.config.onError(error);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
throw error;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Resolves connectivity through the configured gate.
|
|
311
|
+
* @returns {Promise<boolean>} Whether the backend is considered reachable.
|
|
312
|
+
*/
|
|
313
|
+
async isOnline() {
|
|
314
|
+
if (!this.config.isOnline)
|
|
315
|
+
return true;
|
|
316
|
+
return (await this.config.isOnline()) !== false;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Returns the scope store backing declared scopes and cursors.
|
|
320
|
+
* @returns {import("./sync-scope-store.js").default} Scope store.
|
|
321
|
+
*/
|
|
322
|
+
scopeStore() {
|
|
323
|
+
this._scopeStore ||= new SyncScopeStore({ configuration: this.config.configuration || Configuration.current() });
|
|
324
|
+
return this._scopeStore;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Resolves the declared resource config for a local record.
|
|
328
|
+
* @param {?} resource - Local model record.
|
|
329
|
+
* @returns {import("./sync-client-types.js").SyncClientResourceConfig} Declared resource config.
|
|
330
|
+
*/
|
|
331
|
+
resourceConfigFor(resource) {
|
|
332
|
+
const modelClass = resource?.constructor;
|
|
333
|
+
if (typeof modelClass?.getModelName !== "function") {
|
|
334
|
+
throw new Error(`Sync resources must be model records with a static getModelName(), got: ${String(resource)}`);
|
|
335
|
+
}
|
|
336
|
+
const resourceType = modelClass.getModelName();
|
|
337
|
+
const resourceConfig = this.config.resources[resourceType];
|
|
338
|
+
if (!resourceConfig)
|
|
339
|
+
throw new Error(`No sync resource configured for: ${resourceType}`);
|
|
340
|
+
return resourceConfig;
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Resolves the sync type for a mutation through the resource config.
|
|
344
|
+
* @param {{operation: "create" | "update" | "destroy", record: ?, resourceConfig: import("./sync-client-types.js").SyncClientResourceConfig}} args - Mutation args.
|
|
345
|
+
* @returns {string} Sync type.
|
|
346
|
+
*/
|
|
347
|
+
defaultSyncType({ operation, record, resourceConfig }) {
|
|
348
|
+
if (resourceConfig.syncType)
|
|
349
|
+
return resourceConfig.syncType({ operation, record });
|
|
350
|
+
if (operation === "destroy")
|
|
351
|
+
return "delete";
|
|
352
|
+
return operation;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Derives the pull-apply resource configs from the declared resources.
|
|
356
|
+
* @returns {Record<string, import("./sync-api-client-types.js").SyncResourceConfig>} Pull-apply resource configs.
|
|
357
|
+
*/
|
|
358
|
+
pullResourceConfigs() {
|
|
359
|
+
this._pullResourceConfigs ||= /** @type {Record<string, import("./sync-api-client-types.js").SyncResourceConfig>} */ (Object.fromEntries(Object.entries(this.config.resources)
|
|
360
|
+
.filter(([, resource]) => Boolean(resource.attributes))
|
|
361
|
+
.map(([resourceType, resource]) => [resourceType, {
|
|
362
|
+
afterApply: resource.afterApply,
|
|
363
|
+
attributes: /** @type {import("./sync-api-client-types.js").SyncResourceConfig["attributes"]} */ (resource.attributes),
|
|
364
|
+
enabled: true,
|
|
365
|
+
findRecord: resource.findRecord,
|
|
366
|
+
findRecordForDelete: resource.findRecordForDelete,
|
|
367
|
+
modelClass: resource.modelClass
|
|
368
|
+
}])));
|
|
369
|
+
return this._pullResourceConfigs;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Declares a sync scope on the current sync client.
|
|
374
|
+
* @param {import("../database/query/model-class-query.js").default<?>} query - Query declaring the sync scope.
|
|
375
|
+
* @returns {Promise<{scope: import("./sync-client-types.js").SerializedSyncScope, pulled: import("./sync-api-client-types.js").SyncChangesResult | null}>} Declared scope and pull result.
|
|
376
|
+
*/
|
|
377
|
+
export async function sync(query) {
|
|
378
|
+
return await SyncClient.current().sync(query);
|
|
379
|
+
}
|
|
380
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luYy1jbGllbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc3luYy9zeW5jLWNsaWVudC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosT0FBTyxFQUFDLGNBQWMsRUFBQyxNQUFNLFNBQVMsQ0FBQTtBQUV0QyxPQUFPLGFBQWEsTUFBTSxxQkFBcUIsQ0FBQTtBQUUvQyxPQUFPLEVBQUMsd0JBQXdCLEVBQUMsTUFBTSxrQkFBa0IsQ0FBQTtBQUN6RCxPQUFPLGFBQWEsTUFBTSxzQkFBc0IsQ0FBQTtBQUNoRCxPQUFPLGNBQWMsTUFBTSx1QkFBdUIsQ0FBQTtBQUNsRCxPQUFPLEVBQUMsaUJBQWlCLEVBQUUsb0JBQW9CLEVBQUMsTUFBTSwyQkFBMkIsQ0FBQTtBQUVqRixJQUFJLGFBQWEsR0FBRyxDQUFDLENBQUE7QUFFckIsc0ZBQXNGO0FBQ3RGLE1BQU0sc0JBQXNCLEdBQUcsRUFBQyxNQUFNLEVBQUUsYUFBYSxFQUFFLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxFQUFFLGFBQWEsRUFBQyxDQUFBO0FBRXRHOzs7Ozs7Ozs7O0dBVUc7QUFDSCxNQUFNLENBQUMsT0FBTyxPQUFPLFVBQVU7SUFDN0I7OztPQUdHO0lBQ0gsWUFBWSxNQUFNO1FBQ2hCLElBQUksQ0FBQyxNQUFNLElBQUksT0FBTyxNQUFNLEtBQUssUUFBUTtZQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsNENBQTRDLENBQUMsQ0FBQTtRQUV4RyxjQUFjLENBQUMsTUFBTSxDQUFDLFdBQVcsRUFBRSwrQkFBK0IsQ0FBQyxDQUFBO1FBQ25FLGNBQWMsQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFLDhCQUE4QixDQUFDLENBQUE7UUFDakUsY0FBYyxDQUFDLE1BQU0sQ0FBQyxtQkFBbUIsRUFBRSx1Q0FBdUMsQ0FBQyxDQUFBO1FBRW5GLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUztZQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsc0NBQXND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VSxDQUFDLENBQUM7YUFDdEQsR0FBRyxDQUFDLENBQUMsQ0FBQyxZQUFZLEVBQUUsUUFBUSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsWUFBWSxFQUFFO2dCQUNoRCxVQUFVLEVBQUUsUUFBUSxDQUFDLFVBQVU7Z0JBQy9CLFVBQVUsRUFBRSxvRkFBb0YsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUM7Z0JBQ3RILE9BQU8sRUFBRSxJQUFJO2dCQUNiLFVBQVUsRUFBRSxRQUFRLENBQUMsVUFBVTtnQkFDL0IsbUJBQW1CLEVBQUUsUUFBUSxDQUFDLG1CQUFtQjtnQkFDakQsVUFBVSxFQUFFLFFBQVEsQ0FBQyxVQUFVO2FBQ2hDLENBQUMsQ0FBQyxDQUNOLENBQUMsQ0FBQTtRQUVGLE9BQU8sSUFBSSxDQUFDLG9CQUFvQixDQUFBO0lBQ2xDLENBQUM7Q0FDRjtBQUVEOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLElBQUksQ0FBQyxLQUFLO0lBQzlCLE9BQU8sTUFBTSxVQUFVLENBQUMsT0FBTyxFQUFFLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFBO0FBQy9DLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBAdHMtY2hlY2tcblxuaW1wb3J0IHtmb3JjZWRGdW5jdGlvbn0gZnJvbSBcInR5cGFuaWNcIlxuXG5pbXBvcnQgQ29uZmlndXJhdGlvbiBmcm9tIFwiLi4vY29uZmlndXJhdGlvbi5qc1wiXG5cbmltcG9ydCB7c2VyaWFsaXplZFNjb3BlRnJvbVF1ZXJ5fSBmcm9tIFwiLi9xdWVyeS1zY29wZS5qc1wiXG5pbXBvcnQgU3luY0FwaUNsaWVudCBmcm9tIFwiLi9zeW5jLWFwaS1jbGllbnQuanNcIlxuaW1wb3J0IFN5bmNTY29wZVN0b3JlIGZyb20gXCIuL3N5bmMtc2NvcGUtc3RvcmUuanNcIlxuaW1wb3J0IHtjdXJyZW50U3luY0NsaWVudCwgc2V0Q3VycmVudFN5bmNDbGllbnR9IGZyb20gXCIuL3N5bmMtY2xpZW50LXJlZ2lzdHJ5LmpzXCJcblxubGV0IGNsaWVudENvdW50ZXIgPSAwXG5cbi8qKiBAdHlwZSB7e2NyZWF0ZTogXCJhZnRlckNyZWF0ZVwiLCB1cGRhdGU6IFwiYWZ0ZXJVcGRhdGVcIiwgZGVzdHJveTogXCJhZnRlckRlc3Ryb3lcIn19ICovXG5jb25zdCBUUkFDS0VEX0NBTExCQUNLX05BTUVTID0ge2NyZWF0ZTogXCJhZnRlckNyZWF0ZVwiLCBkZXN0cm95OiBcImFmdGVyRGVzdHJveVwiLCB1cGRhdGU6IFwiYWZ0ZXJVcGRhdGVcIn1cblxuLyoqXG4gKiBEZWNsYXJhdGl2ZSBjbGllbnQtc2lkZSBzeW5jIGRyaXZlci5cbiAqXG4gKiBBcHBzIGNvbmZpZ3VyZSByZXNvdXJjZXMsIHRyYW5zcG9ydCwgYXV0aCwgYW5kIGNvbm5lY3Rpdml0eSBvbmNlOyBWZWxvY2lvdXNcbiAqIG93bnMgc2NvcGUgcGVyc2lzdGVuY2UsIHBlci1zY29wZSBjdXJzb3JzLCBwdWxsIHBhZ2luZy9hcHBseSwgbG9jYWwgcXVldWVpbmcsXG4gKiBhbmQgb25saW5lLWdhdGVkIHJlcGxheS4gRGVjbGFyZSBzeW5jIGludGVyZXN0IGZyb20gcXVlcmllczpcbiAqXG4gKiAgICAgY29uc3Qgc3luY0NsaWVudCA9IG5ldyBTeW5jQ2xpZW50KHsuLi59KVxuICogICAgIHN5bmNDbGllbnQuc2V0Q3VycmVudCgpXG4gKiAgICAgYXdhaXQgc3luY0NsaWVudC5zeW5jKEV2ZW50LndoZXJlKHtwYXJ0bmVySWR9KSlcbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgU3luY0NsaWVudCB7XG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgZGVjbGFyYXRpdmUgc3luYyBjbGllbnQuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi9zeW5jLWNsaWVudC10eXBlcy5qc1wiKS5TeW5jQ2xpZW50Q29uZmlnfSBjb25maWcgLSBTeW5jIGNsaWVudCBjb25maWd1cmF0aW9uLlxuICAgKi9cbiAgY29uc3RydWN0b3IoY29uZmlnKSB7XG4gICAgaWYgKCFjb25maWcgfHwgdHlwZW9mIGNvbmZpZyAhPT0gXCJvYmplY3RcIikgdGhyb3cgbmV3IEVycm9yKFwiU3luY0NsaWVudCByZXF1aXJlcyBhIGNvbmZpZ3VyYXRpb24gb2JqZWN0XCIpXG5cbiAgICBmb3JjZWRGdW5jdGlvbihjb25maWcucG9zdENoYW5nZXMsIFwiU3luY0NsaWVudCBjb25maWcucG9zdENoYW5nZXNcIilcbiAgICBmb3JjZWRGdW5jdGlvbihjb25maWcucG9zdFJlcGxheSwgXCJTeW5jQ2xpZW50IGNvbmZpZy5wb3N0UmVwbGF5XCIpXG4gICAgZm9yY2VkRnVuY3Rpb24oY29uZmlnLmF1dGhlbnRpY2F0aW9uVG9rZW4sIFwiU3luY0NsaWVudCBjb25maWcuYXV0aGVudGljYXRpb25Ub2tlblwiKVxuXG4gICAgaWYgKCFjb25maWcuc3luY01vZGVsKSB0aHJvdyBuZXcgRXJyb3IoXCJTeW5jQ2xpZW50IHJlcXVpcmVzIGNvbmZpZy5zeW5jTW9kZWxcIilcbiAgICBpZiAoIWNvbmZpZy5yZXNvdXJjZXMgfHwgdHlwZW9mIGNvbmZpZy5yZXNvdXJjZXMgIT09IFwib2JqZWN0XCIgfHwgT2JqZWN0LmtleXMoY29uZmlnLnJlc291cmNlcykubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJTeW5jQ2xpZW50IHJlcXVpcmVzIGF0IGxlYXN0IG9uZSBlbnRyeSBpbiBjb25maWcucmVzb3VyY2VzXCIpXG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBbcmVzb3VyY2VUeXBlLCByZXNvdXJjZV0gb2YgT2JqZWN0LmVudHJpZXMoY29uZmlnLnJlc291cmNlcykpIHtcbiAgICAgIGlmICghcmVzb3VyY2UgfHwgdHlwZW9mIHJlc291cmNlICE9PSBcIm9iamVjdFwiIHx8ICFyZXNvdXJjZS5tb2RlbENsYXNzKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgU3luY0NsaWVudCByZXNvdXJjZSAke3Jlc291cmNlVHlwZX0gbXVzdCBkZWNsYXJlIGEgbW9kZWxDbGFzc2ApXG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5jb25maWcgPSBjb25maWdcbiAgICB0aGlzLl9jbGllbnROdW1iZXIgPSArK2NsaWVudENvdW50ZXJcbiAgICAvKiogQHR5cGUge2ltcG9ydChcIi4vc3luYy1zY29wZS1zdG9yZS5qc1wiKS5kZWZhdWx0IHwgbnVsbH0gKi9cbiAgICB0aGlzLl9zY29wZVN0b3JlID0gY29uZmlnLnNjb3BlU3RvcmUgfHwgbnVsbFxuICAgIC8qKiBAdHlwZSB7UHJvbWlzZTx2b2lkPiB8IG51bGx9ICovXG4gICAgdGhpcy5fc2NoZWR1bGVkUmVwbGF5ID0gbnVsbFxuICAgIC8qKiBAdHlwZSB7UmVjb3JkPHN0cmluZywgaW1wb3J0KFwiLi9zeW5jLWFwaS1jbGllbnQtdHlwZXMuanNcIikuU3luY1Jlc291cmNlQ29uZmlnPiB8IG51bGx9ICovXG4gICAgdGhpcy5fcHVsbFJlc291cmNlQ29uZmlncyA9IG51bGxcbiAgICAvKiogQHR5cGUge0FycmF5PHtjYWxsYmFjazogKHJlY29yZDogPykgPT4gUHJvbWlzZTx2b2lkPiwgY2FsbGJhY2tOYW1lOiBcImFmdGVyQ3JlYXRlXCIgfCBcImFmdGVyVXBkYXRlXCIgfCBcImFmdGVyRGVzdHJveVwiLCBtb2RlbENsYXNzOiA/fT59ICovXG4gICAgdGhpcy5fdHJhY2tlZENhbGxiYWNrcyA9IFtdXG4gICAgLyoqIEB0eXBlIHtXZWFrU2V0PG9iamVjdD59ICovXG4gICAgdGhpcy5fcmVtb3RlQXBwbHlSZWNvcmRzID0gbmV3IFdlYWtTZXQoKVxuICAgIHRoaXMuX3N0YXJ0ZWQgPSBmYWxzZVxuICB9XG5cbiAgLyoqXG4gICAqIFJlZ2lzdGVycyBhdXRvbWF0aWMgbXV0YXRpb24gdHJhY2tpbmcgZm9yIGV2ZXJ5IHJlc291cmNlIHdpdGggYHRyYWNrYCBlbmFibGVkOlxuICAgKiBsb2NhbCBtb2RlbCBjcmVhdGVzL3VwZGF0ZXMvZGVzdHJveXMgcXVldWUgcGVuZGluZyBzeW5jIHJvd3MgYW5kIHNjaGVkdWxlIGFuXG4gICAqIGltbWVkaWF0ZSByZXBsYXkgYXR0ZW1wdCwgd2l0aG91dCBhcHAtc2lkZSBxdWV1ZSBjYWxscy5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBzdGFydCgpIHtcbiAgICBpZiAodGhpcy5fc3RhcnRlZCkgcmV0dXJuXG5cbiAgICB0aGlzLl9zdGFydGVkID0gdHJ1ZVxuXG4gICAgZm9yIChjb25zdCBbcmVzb3VyY2VUeXBlLCByZXNvdXJjZUNvbmZpZ10gb2YgT2JqZWN0LmVudHJpZXModGhpcy5jb25maWcucmVzb3VyY2VzKSkge1xuICAgICAgY29uc3Qgb3BlcmF0aW9ucyA9IHRoaXMudHJhY2tlZE9wZXJhdGlvbnMoe3Jlc291cmNlQ29uZmlnLCByZXNvdXJjZVR5cGV9KVxuXG4gICAgICBmb3IgKGNvbnN0IG9wZXJhdGlvbiBvZiBvcGVyYXRpb25zKSB7XG4gICAgICAgIGNvbnN0IGNhbGxiYWNrTmFtZSA9IFRSQUNLRURfQ0FMTEJBQ0tfTkFNRVNbb3BlcmF0aW9uXVxuICAgICAgICBjb25zdCBjYWxsYmFjayA9IHRoaXMudHJhY2tlZE11dGF0aW9uQ2FsbGJhY2soe29wZXJhdGlvbiwgcmVzb3VyY2VDb25maWd9KVxuXG4gICAgICAgIHJlc291cmNlQ29uZmlnLm1vZGVsQ2xhc3NbY2FsbGJhY2tOYW1lXShjYWxsYmFjaylcbiAgICAgICAgdGhpcy5fdHJhY2tlZENhbGxiYWNrcy5wdXNoKHtjYWxsYmFjaywgY2FsbGJhY2tOYW1lLCBtb2RlbENsYXNzOiByZXNvdXJjZUNvbmZpZy5tb2RlbENsYXNzfSlcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVW5yZWdpc3RlcnMgYWxsIHRyYWNraW5nIGNhbGxiYWNrcyAodGVzdHMsIHNpZ24tb3V0LCBob3QgcmVsb2FkKS5cbiAgICogQHJldHVybnMge3ZvaWR9XG4gICAqL1xuICBzdG9wKCkge1xuICAgIGZvciAoY29uc3Qge2NhbGxiYWNrLCBjYWxsYmFja05hbWUsIG1vZGVsQ2xhc3N9IG9mIHRoaXMuX3RyYWNrZWRDYWxsYmFja3MpIHtcbiAgICAgIG1vZGVsQ2xhc3MudW5yZWdpc3RlckxpZmVjeWNsZUNhbGxiYWNrKGNhbGxiYWNrTmFtZSwgY2FsbGJhY2spXG4gICAgfVxuXG4gICAgdGhpcy5fdHJhY2tlZENhbGxiYWNrcyA9IFtdXG4gICAgdGhpcy5fc3RhcnRlZCA9IGZhbHNlXG4gIH1cblxuICAvKipcbiAgICogUmVzb2x2ZXMgYW5kIHZhbGlkYXRlcyB0aGUgdHJhY2tlZCBvcGVyYXRpb25zIGZvciBhIHJlc291cmNlIGNvbmZpZy5cbiAgICogQHBhcmFtIHt7cmVzb3VyY2VDb25maWc6IGltcG9ydChcIi4vc3luYy1jbGllbnQtdHlwZXMuanNcIikuU3luY0NsaWVudFJlc291cmNlQ29uZmlnLCByZXNvdXJjZVR5cGU6IHN0cmluZ319IGFyZ3MgLSBSZXNvdXJjZSBjb25maWcgYW5kIG5hbWUuXG4gICAqIEByZXR1cm5zIHtBcnJheTxcImNyZWF0ZVwiIHwgXCJ1cGRhdGVcIiB8IFwiZGVzdHJveVwiPn0gVHJhY2tlZCBvcGVyYXRpb25zLlxuICAgKi9cbiAgdHJhY2tlZE9wZXJhdGlvbnMoe3Jlc291cmNlQ29uZmlnLCByZXNvdXJjZVR5cGV9KSB7XG4gICAgY29uc3QgdHJhY2sgPSByZXNvdXJjZUNvbmZpZy50cmFja1xuXG4gICAgaWYgKHRyYWNrID09PSB1bmRlZmluZWQgfHwgdHJhY2sgPT09IGZhbHNlKSByZXR1cm4gW11cbiAgICBpZiAodHJhY2sgPT09IHRydWUpIHJldHVybiBbXCJjcmVhdGVcIiwgXCJ1cGRhdGVcIiwgXCJkZXN0cm95XCJdXG5cbiAgICBpZiAoIXRyYWNrIHx8IHR5cGVvZiB0cmFjayAhPT0gXCJvYmplY3RcIiB8fCAhQXJyYXkuaXNBcnJheSh0cmFjay5vcGVyYXRpb25zKSB8fCB0cmFjay5vcGVyYXRpb25zLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBTeW5jQ2xpZW50IHJlc291cmNlICR7cmVzb3VyY2VUeXBlfSB0cmFjayBtdXN0IGJlIHRydWUgb3Ige29wZXJhdGlvbnM6IFsuLi5dfWApXG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBvcGVyYXRpb24gb2YgdHJhY2sub3BlcmF0aW9ucykge1xuICAgICAgaWYgKCEob3BlcmF0aW9uIGluIFRSQUNLRURfQ0FMTEJBQ0tfTkFNRVMpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgU3luY0NsaWVudCByZXNvdXJjZSAke3Jlc291cmNlVHlwZX0gdHJhY2sub3BlcmF0aW9ucyBtdXN0IGJlIGNyZWF0ZS91cGRhdGUvZGVzdHJveSwgZ290OiAke1N0cmluZyhvcGVyYXRpb24pfWApXG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRyYWNrLm9wZXJhdGlvbnNcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZHMgdGhlIGxpZmVjeWNsZSBjYWxsYmFjayBxdWV1ZWluZyBvbmUgdHJhY2tlZCBtdXRhdGlvbi5cbiAgICogQHBhcmFtIHt7b3BlcmF0aW9uOiBcImNyZWF0ZVwiIHwgXCJ1cGRhdGVcIiB8IFwiZGVzdHJveVwiLCByZXNvdXJjZUNvbmZpZzogaW1wb3J0KFwiLi9zeW5jLWNsaWVudC10eXBlcy5qc1wiKS5TeW5jQ2xpZW50UmVzb3VyY2VDb25maWd9fSBhcmdzIC0gT3BlcmF0aW9uIGFuZCByZXNvdXJjZSBjb25maWcuXG4gICAqIEByZXR1cm5zIHsocmVjb3JkOiA/KSA9PiBQcm9taXNlPHZvaWQ+fSBMaWZlY3ljbGUgY2FsbGJhY2suXG4gICAqL1xuICB0cmFja2VkTXV0YXRpb25DYWxsYmFjayh7b3BlcmF0aW9uLCByZXNvdXJjZUNvbmZpZ30pIHtcbiAgICByZXR1cm4gYXN5bmMgKHJlY29yZCkgPT4ge1xuICAgICAgaWYgKHRoaXMuaXNSZW1vdGVBcHBseShyZWNvcmQpKSByZXR1cm5cblxuICAgICAgYXdhaXQgU3luY0FwaUNsaWVudC5xdWV1ZUxvY2FsU3luYyh7XG4gICAgICAgIGJvb2xlYW5BdHRyaWJ1dGVzOiByZXNvdXJjZUNvbmZpZy5ib29sZWFuQXR0cmlidXRlcyB8fCBbXSxcbiAgICAgICAgZGF0YTogcmVzb3VyY2VDb25maWcudHJhY2tlZERhdGEgPyByZXNvdXJjZUNvbmZpZy50cmFja2VkRGF0YSh7b3BlcmF0aW9uLCByZWNvcmR9KSA6IHVuZGVmaW5lZCxcbiAgICAgICAgbG9jYWxPbmx5QXR0cmlidXRlczogcmVzb3VyY2VDb25maWcubG9jYWxPbmx5QXR0cmlidXRlcyB8fCBbXSxcbiAgICAgICAgcmVzb3VyY2U6IHJlY29yZCxcbiAgICAgICAgc3luY01vZGVsOiB0aGlzLmNvbmZpZy5zeW5jTW9kZWwsXG4gICAgICAgIHN5bmNUeXBlOiB0aGlzLmRlZmF1bHRTeW5jVHlwZSh7b3BlcmF0aW9uLCByZWNvcmQsIHJlc291cmNlQ29uZmlnfSlcbiAgICAgIH0pXG5cbiAgICAgIHRoaXMuc2NoZWR1bGVSZXBsYXkoKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBXaGV0aGVyIGEgcmVjb3JkIGlzIGN1cnJlbnRseSBiZWluZyB3cml0dGVuIGJ5IHB1bGwtYXBwbHkgKGVjaG8gc3VwcHJlc3Npb24pLlxuICAgKiBAcGFyYW0gez99IHJlY29yZCAtIExvY2FsIG1vZGVsIHJlY29yZC5cbiAgICogQHJldHVybnMge2Jvb2xlYW59IFdoZXRoZXIgdGhlIHJlY29yZCB3cml0ZSBvcmlnaW5hdGVzIGZyb20gYSByZW1vdGUgY2hhbmdlLlxuICAgKi9cbiAgaXNSZW1vdGVBcHBseShyZWNvcmQpIHtcbiAgICByZXR1cm4gdGhpcy5fcmVtb3RlQXBwbHlSZWNvcmRzLmhhcyhyZWNvcmQpXG4gIH1cblxuICAvKipcbiAgICogUmVnaXN0ZXJzIHRoaXMgY2xpZW50IGFzIHRoZSBhcHAncyBjdXJyZW50IHN5bmMgY2xpZW50LlxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICovXG4gIHNldEN1cnJlbnQoKSB7XG4gICAgc2V0Q3VycmVudFN5bmNDbGllbnQodGhpcylcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBhcHAncyBjdXJyZW50IHN5bmMgY2xpZW50LlxuICAgKiBAcmV0dXJucyB7U3luY0NsaWVudH0gQ3VycmVudCBzeW5jIGNsaWVudC5cbiAgICovXG4gIHN0YXRpYyBjdXJyZW50KCkge1xuICAgIHJldHVybiAvKiogQHR5cGUge1N5bmNDbGllbnR9ICovIChjdXJyZW50U3luY0NsaWVudCgpKVxuICB9XG5cbiAgLyoqXG4gICAqIERlY2xhcmVzIChvciByZS1hY3RpdmF0ZXMpIGEgc3luYyBzY29wZSBmcm9tIGEgbW9kZWwgcXVlcnkgYW5kIHB1bGxzIGl0IHdoZW4gb25saW5lLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4uL2RhdGFiYXNlL3F1ZXJ5L21vZGVsLWNsYXNzLXF1ZXJ5LmpzXCIpLmRlZmF1bHQ8Pz59IHF1ZXJ5IC0gUXVlcnkgZGVjbGFyaW5nIHRoZSBzeW5jIHNjb3BlLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx7c2NvcGU6IGltcG9ydChcIi4vc3luYy1jbGllbnQtdHlwZXMuanNcIikuU2VyaWFsaXplZFN5bmNTY29wZSwgcHVsbGVkOiBpbXBvcnQoXCIuL3N5bmMtYXBpLWNsaWVudC10eXBlcy5qc1wiKS5TeW5jQ2hhbmdlc1Jlc3VsdCB8IG51bGx9Pn0gRGVjbGFyZWQgc2NvcGUgYW5kIHB1bGwgcmVzdWx0IChudWxsIHdoaWxlIG9mZmxpbmUpLlxuICAgKi9cbiAgYXN5bmMgc3luYyhxdWVyeSkge1xuICAgIGNvbnN0IHNjb3BlID0gc2VyaWFsaXplZFNjb3BlRnJvbVF1ZXJ5KHF1ZXJ5KVxuICAgIGNvbnN0IHNjb3BlU3RvcmUgPSB0aGlzLnNjb3BlU3RvcmUoKVxuICAgIGNvbnN0IHNjb3BlUm93ID0gYXdhaXQgc2NvcGVTdG9yZS5maW5kT3JDcmVhdGVTY29wZShzY29wZSlcblxuICAgIGlmICghc2NvcGVSb3cuY3Vyc29yUGF5bG9hZCAmJiB0aGlzLmNvbmZpZy5sZWdhY3lDdXJzb3IpIHtcbiAgICAgIGNvbnN0IGxlZ2FjeUN1cnNvclBheWxvYWQgPSBhd2FpdCB0aGlzLmNvbmZpZy5sZWdhY3lDdXJzb3Ioe3Njb3BlfSlcbiAgICAgIGNvbnN0IGxlZ2FjeUN1cnNvciA9IFN5bmNBcGlDbGllbnQuc3luY0N1cnNvckZyb21QYXlsb2FkKGxlZ2FjeUN1cnNvclBheWxvYWQpXG5cbiAgICAgIGlmIChsZWdhY3lDdXJzb3IpIGF3YWl0IHNjb3BlU3RvcmUuc2F2ZUN1cnNvcihzY29wZVJvdywgbGVnYWN5Q3Vyc29yKVxuICAgIH1cblxuICAgIHJldHVybiB7cHVsbGVkOiBhd2FpdCB0aGlzLnB1bGwoKSwgc2NvcGV9XG4gIH1cblxuICAvKipcbiAgICogRGVhY3RpdmF0ZXMgdGhlIHN5bmMgc2NvcGUgZGVjbGFyZWQgYnkgYSBtb2RlbCBxdWVyeS5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuLi9kYXRhYmFzZS9xdWVyeS9tb2RlbC1jbGFzcy1xdWVyeS5qc1wiKS5kZWZhdWx0PD8+fSBxdWVyeSAtIFF1ZXJ5IHdob3NlIHNjb3BlIHNob3VsZCBzdG9wIHN5bmNpbmcuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgdW5zeW5jKHF1ZXJ5KSB7XG4gICAgYXdhaXQgdGhpcy5zY29wZVN0b3JlKCkuZGVhY3RpdmF0ZShzZXJpYWxpemVkU2NvcGVGcm9tUXVlcnkocXVlcnkpKVxuICB9XG5cbiAgLyoqXG4gICAqIFB1bGxzIGNoYW5nZXMgZm9yIGV2ZXJ5IGFjdGl2ZSBzY29wZSB3aXRoIHBlci1zY29wZSBjdXJzb3JzIChzaW5nbGUtZmxpZ2h0ZWQsIG9ubGluZS1nYXRlZCkuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPGltcG9ydChcIi4vc3luYy1hcGktY2xpZW50LXR5cGVzLmpzXCIpLlN5bmNDaGFuZ2VzUmVzdWx0IHwgbnVsbD59IENvbWJpbmVkIHB1bGwgcmVzdWx0LCBvciBudWxsIHdoaWxlIG9mZmxpbmUuXG4gICAqL1xuICBhc3luYyBwdWxsKCkge1xuICAgIGlmICghKGF3YWl0IHRoaXMuaXNPbmxpbmUoKSkpIHJldHVybiBudWxsXG5cbiAgICAvKiogQHR5cGUge2ltcG9ydChcIi4vc3luYy1hcGktY2xpZW50LXR5cGVzLmpzXCIpLlN5bmNDaGFuZ2VzUmVzdWx0IHwgbnVsbH0gKi9cbiAgICBsZXQgY29tYmluZWRSZXN1bHQgPSBudWxsXG5cbiAgICBhd2FpdCBTeW5jQXBpQ2xpZW50LnNpbmdsZUZsaWdodChgdmVsb2Npb3VzLXN5bmMtY2xpZW50LXB1bGwtJHt0aGlzLl9jbGllbnROdW1iZXJ9YCwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgYXV0aGVudGljYXRpb25Ub2tlbiA9IGF3YWl0IHRoaXMuY29uZmlnLmF1dGhlbnRpY2F0aW9uVG9rZW4oKVxuICAgICAgY29uc3Qgc2NvcGVTdG9yZSA9IHRoaXMuc2NvcGVTdG9yZSgpXG4gICAgICBjb25zdCBwdWxsUmVzb3VyY2VDb25maWdzID0gdGhpcy5wdWxsUmVzb3VyY2VDb25maWdzKClcbiAgICAgIGNvbnN0IGFwcGxpZXIgPSBTeW5jQXBpQ2xpZW50LnJlc291cmNlQXBwbGllcihwdWxsUmVzb3VyY2VDb25maWdzLCAocmVjb3JkKSA9PiB7XG4gICAgICAgIHRoaXMuX3JlbW90ZUFwcGx5UmVjb3Jkcy5hZGQocmVjb3JkKVxuXG4gICAgICAgIHJldHVybiAoKSA9PiB0aGlzLl9yZW1vdGVBcHBseVJlY29yZHMuZGVsZXRlKHJlY29yZClcbiAgICAgIH0pXG4gICAgICAvKipcbiAgICAgICAqIEFwcGxpZXMgb25lIHB1bGxlZCBjaGFuZ2UsIGZhaWxpbmcgbG91ZGx5IGluc3RlYWQgb2Ygc2lsZW50bHkgc2tpcHBpbmcgdW5jb25maWd1cmVkIHJlc291cmNlcy5cbiAgICAgICAqIEBwYXJhbSB7aW1wb3J0KFwiLi9zeW5jLWFwaS1jbGllbnQtdHlwZXMuanNcIikuU3luY0NoYW5nZUVudmVsb3BlfSBzeW5jIC0gUHVsbGVkIGNoYW5nZS5cbiAgICAgICAqIEByZXR1cm5zIHtQcm9taXNlPGltcG9ydChcIi4vc3luYy1hcGktY2xpZW50LXR5cGVzLmpzXCIpLlN5bmNDaGFuZ2VBcHBseVJlc3VsdD59IEFwcGx5IHJlc3VsdC5cbiAgICAgICAqL1xuICAgICAgY29uc3QgYXBwbHlTeW5jID0gYXN5bmMgKHN5bmMpID0+IHtcbiAgICAgICAgY29uc3QgcmVzb3VyY2VUeXBlID0gc3luYy5yZXNvdXJjZVR5cGUoKVxuXG4gICAgICAgIGlmICghcmVzb3VyY2VUeXBlIHx8ICFwdWxsUmVzb3VyY2VDb25maWdzW3Jlc291cmNlVHlwZV0pIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIHN5bmMgcmVzb3VyY2Ugd2l0aCBwdWxsIGF0dHJpYnV0ZXMgY29uZmlndXJlZCBmb3IgcHVsbGVkIGNoYW5nZTogJHtTdHJpbmcocmVzb3VyY2VUeXBlKX1gKVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGF3YWl0IGFwcGxpZXIoc3luYylcbiAgICAgIH1cbiAgICAgIGNvbnN0IHJlc3VsdCA9IHtcbiAgICAgICAgY2hhbmdlZDogZmFsc2UsXG4gICAgICAgIHBhZ2VzOiAwLFxuICAgICAgICByZXNvdXJjZUNoYW5nZWQ6IC8qKiBAdHlwZSB7UmVjb3JkPHN0cmluZywgYm9vbGVhbj59ICovICh7fSksXG4gICAgICAgIHJlc291cmNlQ291bnRzOiAvKiogQHR5cGUge1JlY29yZDxzdHJpbmcsIG51bWJlcj59ICovICh7fSksXG4gICAgICAgIHN5bmNlZENvdW50OiAwXG4gICAgICB9XG5cbiAgICAgIGZvciAoY29uc3Qgc2NvcGVSb3cgb2YgYXdhaXQgc2NvcGVTdG9yZS5hY3RpdmVTY29wZXMoKSkge1xuICAgICAgICBjb25zdCBzY29wZVJlc3VsdCA9IGF3YWl0IFN5bmNBcGlDbGllbnQucHVsbENoYW5nZXMoe1xuICAgICAgICAgIGFwcGx5U3luYyxcbiAgICAgICAgICBhdXRoZW50aWNhdGlvblRva2VuLFxuICAgICAgICAgIGJhdGNoU2l6ZTogdGhpcy5jb25maWcuYmF0Y2hTaXplLFxuICAgICAgICAgIGxvYWRDdXJzb3I6IGFzeW5jICgpID0+IGF3YWl0IHNjb3BlU3RvcmUubG9hZEN1cnNvcihzY29wZVJvdyksXG4gICAgICAgICAgcG9zdENoYW5nZXM6IGFzeW5jIChwYXlsb2FkKSA9PiBhd2FpdCB0aGlzLmNvbmZpZy5wb3N0Q2hhbmdlcyh7XG4gICAgICAgICAgICAuLi5wYXlsb2FkLFxuICAgICAgICAgICAgc2NvcGU6IHtjb25kaXRpb25zOiBzY29wZVJvdy5jb25kaXRpb25zLCByZXNvdXJjZVR5cGU6IHNjb3BlUm93LnJlc291cmNlVHlwZX1cbiAgICAgICAgICB9KSxcbiAgICAgICAgICBzYXZlQ3Vyc29yOiBhc3luYyAoY3Vyc29yKSA9PiBhd2FpdCBzY29wZVN0b3JlLnNhdmVDdXJzb3Ioc2NvcGVSb3csIGN1cnNvcilcbiAgICAgICAgfSlcblxuICAgICAgICByZXN1bHQuY2hhbmdlZCB8fD0gc2NvcGVSZXN1bHQuY2hhbmdlZFxuICAgICAgICByZXN1bHQucGFnZXMgKz0gc2NvcGVSZXN1bHQucGFnZXNcbiAgICAgICAgcmVzdWx0LnN5bmNlZENvdW50ICs9IHNjb3BlUmVzdWx0LnN5bmNlZENvdW50XG5cbiAgICAgICAgZm9yIChjb25zdCBbcmVzb3VyY2VUeXBlLCBjb3VudF0gb2YgT2JqZWN0LmVudHJpZXMoc2NvcGVSZXN1bHQucmVzb3VyY2VDb3VudHMpKSB7XG4gICAgICAgICAgcmVzdWx0LnJlc291cmNlQ291bnRzW3Jlc291cmNlVHlwZV0gPSAocmVzdWx0LnJlc291cmNlQ291bnRzW3Jlc291cmNlVHlwZV0gfHwgMCkgKyBjb3VudFxuICAgICAgICB9XG4gICAgICAgIGZvciAoY29uc3QgW3Jlc291cmNlVHlwZSwgY2hhbmdlZF0gb2YgT2JqZWN0LmVudHJpZXMoc2NvcGVSZXN1bHQucmVzb3VyY2VDaGFuZ2VkKSkge1xuICAgICAgICAgIHJlc3VsdC5yZXNvdXJjZUNoYW5nZWRbcmVzb3VyY2VUeXBlXSB8fD0gY2hhbmdlZFxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbWJpbmVkUmVzdWx0ID0gcmVzdWx0XG4gICAgfSlcblxuICAgIHJldHVybiBjb21iaW5lZFJlc3VsdFxuICB9XG5cbiAgLyoqXG4gICAqIFF1ZXVlcyBhIGxvY2FsIG1vZGVsIGNoYW5nZSBhcyBhIHBlbmRpbmcgc3luYyByb3cgYW5kIHNjaGVkdWxlcyBhbiBpbW1lZGlhdGVcbiAgICogcmVwbGF5IGF0dGVtcHQgKGtlcHQgcGVuZGluZyB3aGlsZSBvZmZsaW5lIG9yIHdoZW4gdGhlIGJhY2tlbmQgcmVqZWN0cyBpdCkuXG4gICAqIEBwYXJhbSB7e3Jlc291cmNlOiA/LCBkYXRhPzogUmVjb3JkPHN0cmluZywgPz4sIHN5bmNUeXBlPzogc3RyaW5nfX0gYXJncyAtIFF1ZXVlIGFyZ3MuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPD8+fSBQZW5kaW5nIGxvY2FsIHN5bmMgcm93LlxuICAgKi9cbiAgYXN5bmMgcXVldWUoe2RhdGEsIHJlc291cmNlLCBzeW5jVHlwZX0pIHtcbiAgICBjb25zdCByZXNvdXJjZUNvbmZpZyA9IHRoaXMucmVzb3VyY2VDb25maWdGb3IocmVzb3VyY2UpXG4gICAgY29uc3Qgc3luY1JvdyA9IGF3YWl0IFN5bmNBcGlDbGllbnQucXVldWVMb2NhbFN5bmMoe1xuICAgICAgYm9vbGVhbkF0dHJpYnV0ZXM6IHJlc291cmNlQ29uZmlnLmJvb2xlYW5BdHRyaWJ1dGVzIHx8IFtdLFxuICAgICAgZGF0YSxcbiAgICAgIGxvY2FsT25seUF0dHJpYnV0ZXM6IHJlc291cmNlQ29uZmlnLmxvY2FsT25seUF0dHJpYnV0ZXMgfHwgW10sXG4gICAgICByZXNvdXJjZSxcbiAgICAgIHN5bmNNb2RlbDogdGhpcy5jb25maWcuc3luY01vZGVsLFxuICAgICAgc3luY1R5cGU6IHN5bmNUeXBlID8/IHRoaXMuZGVmYXVsdFN5bmNUeXBlKHtvcGVyYXRpb246IFwidXBkYXRlXCIsIHJlY29yZDogcmVzb3VyY2UsIHJlc291cmNlQ29uZmlnfSlcbiAgICB9KVxuXG4gICAgdGhpcy5zY2hlZHVsZVJlcGxheSgpXG5cbiAgICByZXR1cm4gc3luY1Jvd1xuICB9XG5cbiAgLyoqXG4gICAqIERyYWlucyBwZW5kaW5nIGxvY2FsIHN5bmMgcm93cyB0byB0aGUgYmFja2VuZCAoc2luZ2xlLWZsaWdodGVkLCBvbmxpbmUtZ2F0ZWQpLlxuICAgKiBSb3dzIGFyZSBvbmx5IG1hcmtlZCBzdWNjZXNzZnVsIGFmdGVyIHRoZSBiYWNrZW5kIGFja25vd2xlZGdlcyB0aGVtLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIHJlcGxheVBlbmRpbmcoKSB7XG4gICAgaWYgKCEoYXdhaXQgdGhpcy5pc09ubGluZSgpKSkgcmV0dXJuXG5cbiAgICBhd2FpdCBTeW5jQXBpQ2xpZW50LnNpbmdsZUZsaWdodChgdmVsb2Npb3VzLXN5bmMtY2xpZW50LXJlcGxheS0ke3RoaXMuX2NsaWVudE51bWJlcn1gLCBhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCBTeW5jQXBpQ2xpZW50LnJlcGxheUxvY2FsU3luY3Moe1xuICAgICAgICBhdXRoZW50aWNhdGlvblRva2VuOiBhd2FpdCB0aGlzLmNvbmZpZy5hdXRoZW50aWNhdGlvblRva2VuKCksXG4gICAgICAgIGJhdGNoU2l6ZTogdGhpcy5jb25maWcuYmF0Y2hTaXplLFxuICAgICAgICBwb3N0UmVwbGF5OiB0aGlzLmNvbmZpZy5wb3N0UmVwbGF5LFxuICAgICAgICBzeW5jTW9kZWw6IHRoaXMuY29uZmlnLnN5bmNNb2RlbFxuICAgICAgfSlcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIFNjaGVkdWxlcyBhIGJhY2tncm91bmQgcmVwbGF5IGF0dGVtcHQgd2l0aG91dCBibG9ja2luZyB0aGUgY2FsbGVyLlxuICAgKiBGYWlsdXJlcyBnbyB0byBjb25maWcub25FcnJvciAob3IgcmV0aHJvdyB3aGVuIG5vbmUgaXMgY29uZmlndXJlZCkuXG4gICAqIEByZXR1cm5zIHt2b2lkfVxuICAgKi9cbiAgc2NoZWR1bGVSZXBsYXkoKSB7XG4gICAgdGhpcy5fc2NoZWR1bGVkUmVwbGF5ID0gKGFzeW5jICgpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRoaXMucmVwbGF5UGVuZGluZygpXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICB0aGlzLnJlcG9ydEVycm9yKC8qKiBAdHlwZSB7RXJyb3J9ICovIChlcnJvcikpXG4gICAgICB9XG4gICAgfSkoKVxuICB9XG5cbiAgLyoqXG4gICAqIEF3YWl0cyB0aGUgbGFzdCBzY2hlZHVsZWQgYmFja2dyb3VuZCByZXBsYXkgKHVzZWZ1bCBpbiB0ZXN0cyBhbmQgc2h1dGRvd24gZmxvd3MpLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIHdhaXRGb3JTY2hlZHVsZWRSZXBsYXkoKSB7XG4gICAgaWYgKHRoaXMuX3NjaGVkdWxlZFJlcGxheSkgYXdhaXQgdGhpcy5fc2NoZWR1bGVkUmVwbGF5XG4gIH1cblxuICAvKipcbiAgICogUmVwb3J0cyBhIGJhY2tncm91bmQgc3luYyBmYWlsdXJlLlxuICAgKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIEJhY2tncm91bmQgZmFpbHVyZS5cbiAgICogQHJldHVybnMge3ZvaWR9XG4gICAqL1xuICByZXBvcnRFcnJvcihlcnJvcikge1xuICAgIGlmICh0aGlzLmNvbmZpZy5vbkVycm9yKSB7XG4gICAgICB0aGlzLmNvbmZpZy5vbkVycm9yKGVycm9yKVxuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgdGhyb3cgZXJyb3JcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNvbHZlcyBjb25uZWN0aXZpdHkgdGhyb3VnaCB0aGUgY29uZmlndXJlZCBnYXRlLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gV2hldGhlciB0aGUgYmFja2VuZCBpcyBjb25zaWRlcmVkIHJlYWNoYWJsZS5cbiAgICovXG4gIGFzeW5jIGlzT25saW5lKCkge1xuICAgIGlmICghdGhpcy5jb25maWcuaXNPbmxpbmUpIHJldHVybiB0cnVlXG5cbiAgICByZXR1cm4gKGF3YWl0IHRoaXMuY29uZmlnLmlzT25saW5lKCkpICE9PSBmYWxzZVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIHNjb3BlIHN0b3JlIGJhY2tpbmcgZGVjbGFyZWQgc2NvcGVzIGFuZCBjdXJzb3JzLlxuICAgKiBAcmV0dXJucyB7aW1wb3J0KFwiLi9zeW5jLXNjb3BlLXN0b3JlLmpzXCIpLmRlZmF1bHR9IFNjb3BlIHN0b3JlLlxuICAgKi9cbiAgc2NvcGVTdG9yZSgpIHtcbiAgICB0aGlzLl9zY29wZVN0b3JlIHx8PSBuZXcgU3luY1Njb3BlU3RvcmUoe2NvbmZpZ3VyYXRpb246IHRoaXMuY29uZmlnLmNvbmZpZ3VyYXRpb24gfHwgQ29uZmlndXJhdGlvbi5jdXJyZW50KCl9KVxuXG4gICAgcmV0dXJuIHRoaXMuX3Njb3BlU3RvcmVcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNvbHZlcyB0aGUgZGVjbGFyZWQgcmVzb3VyY2UgY29uZmlnIGZvciBhIGxvY2FsIHJlY29yZC5cbiAgICogQHBhcmFtIHs/fSByZXNvdXJjZSAtIExvY2FsIG1vZGVsIHJlY29yZC5cbiAgICogQHJldHVybnMge2ltcG9ydChcIi4vc3luYy1jbGllbnQtdHlwZXMuanNcIikuU3luY0NsaWVudFJlc291cmNlQ29uZmlnfSBEZWNsYXJlZCByZXNvdXJjZSBjb25maWcuXG4gICAqL1xuICByZXNvdXJjZUNvbmZpZ0ZvcihyZXNvdXJjZSkge1xuICAgIGNvbnN0IG1vZGVsQ2xhc3MgPSByZXNvdXJjZT8uY29uc3RydWN0b3JcblxuICAgIGlmICh0eXBlb2YgbW9kZWxDbGFzcz8uZ2V0TW9kZWxOYW1lICE9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgU3luYyByZXNvdXJjZXMgbXVzdCBiZSBtb2RlbCByZWNvcmRzIHdpdGggYSBzdGF0aWMgZ2V0TW9kZWxOYW1lKCksIGdvdDogJHtTdHJpbmcocmVzb3VyY2UpfWApXG4gICAgfVxuXG4gICAgY29uc3QgcmVzb3VyY2VUeXBlID0gbW9kZWxDbGFzcy5nZXRNb2RlbE5hbWUoKVxuICAgIGNvbnN0IHJlc291cmNlQ29uZmlnID0gdGhpcy5jb25maWcucmVzb3VyY2VzW3Jlc291cmNlVHlwZV1cblxuICAgIGlmICghcmVzb3VyY2VDb25maWcpIHRocm93IG5ldyBFcnJvcihgTm8gc3luYyByZXNvdXJjZSBjb25maWd1cmVkIGZvcjogJHtyZXNvdXJjZVR5cGV9YClcblxuICAgIHJldHVybiByZXNvdXJjZUNvbmZpZ1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc29sdmVzIHRoZSBzeW5jIHR5cGUgZm9yIGEgbXV0YXRpb24gdGhyb3VnaCB0aGUgcmVzb3VyY2UgY29uZmlnLlxuICAgKiBAcGFyYW0ge3tvcGVyYXRpb246IFwiY3JlYXRlXCIgfCBcInVwZGF0ZVwiIHwgXCJkZXN0cm95XCIsIHJlY29yZDogPywgcmVzb3VyY2VDb25maWc6IGltcG9ydChcIi4vc3luYy1jbGllbnQtdHlwZXMuanNcIikuU3luY0NsaWVudFJlc291cmNlQ29uZmlnfX0gYXJncyAtIE11dGF0aW9uIGFyZ3MuXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IFN5bmMgdHlwZS5cbiAgICovXG4gIGRlZmF1bHRTeW5jVHlwZSh7b3BlcmF0aW9uLCByZWNvcmQsIHJlc291cmNlQ29uZmlnfSkge1xuICAgIGlmIChyZXNvdXJjZUNvbmZpZy5zeW5jVHlwZSkgcmV0dXJuIHJlc291cmNlQ29uZmlnLnN5bmNUeXBlKHtvcGVyYXRpb24sIHJlY29yZH0pXG4gICAgaWYgKG9wZXJhdGlvbiA9PT0gXCJkZXN0cm95XCIpIHJldHVybiBcImRlbGV0ZVwiXG5cbiAgICByZXR1cm4gb3BlcmF0aW9uXG4gIH1cblxuICAvKipcbiAgICogRGVyaXZlcyB0aGUgcHVsbC1hcHBseSByZXNvdXJjZSBjb25maWdzIGZyb20gdGhlIGRlY2xhcmVkIHJlc291cmNlcy5cbiAgICogQHJldHVybnMge1JlY29yZDxzdHJpbmcsIGltcG9ydChcIi4vc3luYy1hcGktY2xpZW50LXR5cGVzLmpzXCIpLlN5bmNSZXNvdXJjZUNvbmZpZz59IFB1bGwtYXBwbHkgcmVzb3VyY2UgY29uZmlncy5cbiAgICovXG4gIHB1bGxSZXNvdXJjZUNvbmZpZ3MoKSB7XG4gICAgdGhpcy5fcHVsbFJlc291cmNlQ29uZmlncyB8fD0gLyoqIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCBpbXBvcnQoXCIuL3N5bmMtYXBpLWNsaWVudC10eXBlcy5qc1wiKS5TeW5jUmVzb3VyY2VDb25maWc+fSAqLyAoT2JqZWN0LmZyb21FbnRyaWVzKFxuICAgICAgT2JqZWN0LmVudHJpZXModGhpcy5jb25maWcucmVzb3VyY2VzKVxuICAgICAgICAuZmlsdGVyKChbLCByZXNvdXJjZV0pID0+IEJvb2xlYW4ocmVzb3VyY2UuYXR0cmlidXRlcykpXG4gICAgICAgIC5tYXAoKFtyZXNvdXJjZVR5cGUsIHJlc291cmNlXSkgPT4gW3Jlc291cmNlVHlwZSwge1xuICAgICAgICAgIGFmdGVyQXBwbHk6IHJlc291cmNlLmFmdGVyQXBwbHksXG4gICAgICAgICAgYXR0cmlidXRlczogLyoqIEB0eXBlIHtpbXBvcnQoXCIuL3N5bmMtYXBpLWNsaWVudC10eXBlcy5qc1wiKS5TeW5jUmVzb3VyY2VDb25maWdbXCJhdHRyaWJ1dGVzXCJdfSAqLyAocmVzb3VyY2UuYXR0cmlidXRlcyksXG4gICAgICAgICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAgICAgICBmaW5kUmVjb3JkOiByZXNvdXJjZS5maW5kUmVjb3JkLFxuICAgICAgICAgIGZpbmRSZWNvcmRGb3JEZWxldGU6IHJlc291cmNlLmZpbmRSZWNvcmRGb3JEZWxldGUsXG4gICAgICAgICAgbW9kZWxDbGFzczogcmVzb3VyY2UubW9kZWxDbGFzc1xuICAgICAgICB9XSlcbiAgICApKVxuXG4gICAgcmV0dXJuIHRoaXMuX3B1bGxSZXNvdXJjZUNvbmZpZ3NcbiAgfVxufVxuXG4vKipcbiAqIERlY2xhcmVzIGEgc3luYyBzY29wZSBvbiB0aGUgY3VycmVudCBzeW5jIGNsaWVudC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vZGF0YWJhc2UvcXVlcnkvbW9kZWwtY2xhc3MtcXVlcnkuanNcIikuZGVmYXVsdDw/Pn0gcXVlcnkgLSBRdWVyeSBkZWNsYXJpbmcgdGhlIHN5bmMgc2NvcGUuXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx7c2NvcGU6IGltcG9ydChcIi4vc3luYy1jbGllbnQtdHlwZXMuanNcIikuU2VyaWFsaXplZFN5bmNTY29wZSwgcHVsbGVkOiBpbXBvcnQoXCIuL3N5bmMtYXBpLWNsaWVudC10eXBlcy5qc1wiKS5TeW5jQ2hhbmdlc1Jlc3VsdCB8IG51bGx9Pn0gRGVjbGFyZWQgc2NvcGUgYW5kIHB1bGwgcmVzdWx0LlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3luYyhxdWVyeSkge1xuICByZXR1cm4gYXdhaXQgU3luY0NsaWVudC5jdXJyZW50KCkuc3luYyhxdWVyeSlcbn1cbiJdfQ==
|
|
@@ -10,19 +10,32 @@
|
|
|
10
10
|
export default class SyncEnvelopeReplayService {
|
|
11
11
|
/**
|
|
12
12
|
* Creates a sync envelope replay service.
|
|
13
|
+
*
|
|
14
|
+
* When a sync model is given, `findExistingReplaySync` and
|
|
15
|
+
* `persistReplayMutation` get model-backed default implementations. The sync
|
|
16
|
+
* model must expose `findBy`/`create` statics plus instance
|
|
17
|
+
* `assign`/`save`/`clientUpdatedAt` and `advanceServerSequence` (the
|
|
18
|
+
* change-feed sequence contract), and the actor returned from
|
|
19
|
+
* `authenticateReplay` must expose an `id()` method.
|
|
13
20
|
* @param {object} [args] - Constructor arguments.
|
|
14
21
|
* @param {{debug?: (...args: Array<unknown>) => void, warn?: (...args: Array<unknown>) => void}} [args.logger] - Logger used for normalization warnings.
|
|
22
|
+
* @param {?} [args.syncModel] - Sync/change model enabling model-backed default hooks.
|
|
23
|
+
* @param {string} [args.actorForeignKeyColumn] - Sync model column linking rows to the replay actor.
|
|
15
24
|
*/
|
|
16
25
|
constructor(args?: {
|
|
17
26
|
logger?: {
|
|
18
27
|
debug?: (...args: Array<unknown>) => void;
|
|
19
28
|
warn?: (...args: Array<unknown>) => void;
|
|
20
29
|
} | undefined;
|
|
30
|
+
syncModel?: unknown;
|
|
31
|
+
actorForeignKeyColumn?: string | undefined;
|
|
21
32
|
});
|
|
22
33
|
logger: {
|
|
23
34
|
debug?: (...args: Array<unknown>) => void;
|
|
24
35
|
warn?: (...args: Array<unknown>) => void;
|
|
25
36
|
};
|
|
37
|
+
syncModel: any;
|
|
38
|
+
actorForeignKeyColumn: string;
|
|
26
39
|
/**
|
|
27
40
|
* Replays a sync batch.
|
|
28
41
|
* @param {Record<string, ?>} params - Request params carrying authentication and syncs.
|
|
@@ -106,14 +119,23 @@ export default class SyncEnvelopeReplayService {
|
|
|
106
119
|
}>;
|
|
107
120
|
/**
|
|
108
121
|
* Loads the previously stored sync/change row for stale-client comparison.
|
|
109
|
-
*
|
|
122
|
+
*
|
|
123
|
+
* Defaults to a sync-model lookup by actor and resource identity when a sync
|
|
124
|
+
* model is configured; otherwise apps override this hook.
|
|
125
|
+
* @param {{actor: ?, context: Record<string, ?>, mutation: import("./sync-envelope-replay-service.js").SyncReplayMutation}} args - Actor, batch context, and mutation.
|
|
110
126
|
* @returns {Promise<?>} Existing sync row.
|
|
111
127
|
*/
|
|
112
|
-
findExistingReplaySync(
|
|
128
|
+
findExistingReplaySync({ actor, mutation }: {
|
|
113
129
|
actor: unknown;
|
|
114
130
|
context: Record<string, unknown>;
|
|
115
131
|
mutation: import("./sync-envelope-replay-service.js").SyncReplayMutation;
|
|
116
132
|
}): Promise<unknown>;
|
|
133
|
+
/**
|
|
134
|
+
* Resolves the persisted actor id used by model-backed default hooks.
|
|
135
|
+
* @param {?} actor - Actor returned from authenticateReplay.
|
|
136
|
+
* @returns {?} Actor id.
|
|
137
|
+
*/
|
|
138
|
+
replayActorId(actor: unknown): unknown;
|
|
117
139
|
/**
|
|
118
140
|
* Returns whether a normalized mutation should be applied to domain models.
|
|
119
141
|
* @param {{actor: ?, context: Record<string, ?>, existingSync: ?, mutation: import("./sync-envelope-replay-service.js").SyncReplayMutation}} args - Actor, batch context, existing sync row, and mutation.
|
|
@@ -155,10 +177,13 @@ export default class SyncEnvelopeReplayService {
|
|
|
155
177
|
}): Promise<unknown>;
|
|
156
178
|
/**
|
|
157
179
|
* Persists one normalized mutation into the app sync/change store.
|
|
158
|
-
*
|
|
180
|
+
*
|
|
181
|
+
* Defaults to a stale-guarded sync-model upsert (with server re-sequencing on
|
|
182
|
+
* updates) when a sync model is configured; otherwise apps override this hook.
|
|
183
|
+
* @param {{actor: ?, context: Record<string, ?>, existingSync: ?, applyResult: ?, mutation: import("./sync-envelope-replay-service.js").SyncReplayMutation, shouldApply: boolean}} args - Replay persistence arguments.
|
|
159
184
|
* @returns {Promise<void>}
|
|
160
185
|
*/
|
|
161
|
-
persistReplayMutation(
|
|
186
|
+
persistReplayMutation({ actor, existingSync, mutation }: {
|
|
162
187
|
actor: unknown;
|
|
163
188
|
context: Record<string, unknown>;
|
|
164
189
|
existingSync: unknown;
|
|
@@ -166,6 +191,15 @@ export default class SyncEnvelopeReplayService {
|
|
|
166
191
|
mutation: import("./sync-envelope-replay-service.js").SyncReplayMutation;
|
|
167
192
|
shouldApply: boolean;
|
|
168
193
|
}): Promise<void>;
|
|
194
|
+
/**
|
|
195
|
+
* Builds the sync-model attributes persisted by the model-backed default.
|
|
196
|
+
* @param {{actor: ?, mutation: import("./sync-envelope-replay-service.js").SyncReplayMutation}} args - Actor and mutation.
|
|
197
|
+
* @returns {Record<string, ?>} Sync row attributes.
|
|
198
|
+
*/
|
|
199
|
+
replayPersistAttributes({ actor, mutation }: {
|
|
200
|
+
actor: unknown;
|
|
201
|
+
mutation: import("./sync-envelope-replay-service.js").SyncReplayMutation;
|
|
202
|
+
}): Record<string, unknown>;
|
|
169
203
|
/**
|
|
170
204
|
* Runs side effects after a successful mutation replay and persistence.
|
|
171
205
|
* @param {{actor: ?, context: Record<string, ?>, existingSync: ?, applyResult: ?, mutation: import("./sync-envelope-replay-service.js").SyncReplayMutation, shouldApply: boolean}} _args - Replay side-effect arguments.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-envelope-replay-service.d.ts","sourceRoot":"","sources":["../../../src/sync/sync-envelope-replay-service.js"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH;IACE
|
|
1
|
+
{"version":3,"file":"sync-envelope-replay-service.d.ts","sourceRoot":"","sources":["../../../src/sync/sync-envelope-replay-service.js"],"names":[],"mappings":"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"}
|