velocious 1.0.503 → 1.0.504

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 (60) hide show
  1. package/build/application.js +2 -0
  2. package/build/configuration-types.js +8 -8
  3. package/build/configuration.js +2 -2
  4. package/build/src/application.d.ts.map +1 -1
  5. package/build/src/application.js +3 -1
  6. package/build/src/configuration-types.d.ts +17 -17
  7. package/build/src/configuration-types.d.ts.map +1 -1
  8. package/build/src/configuration-types.js +9 -9
  9. package/build/src/configuration.d.ts +4 -4
  10. package/build/src/configuration.d.ts.map +1 -1
  11. package/build/src/configuration.js +3 -3
  12. package/build/src/sync/sync-channel-name.d.ts +9 -0
  13. package/build/src/sync/sync-channel-name.d.ts.map +1 -0
  14. package/build/src/sync/sync-channel-name.js +10 -0
  15. package/build/src/sync/sync-client-types.d.ts +10 -7
  16. package/build/src/sync/sync-client-types.d.ts.map +1 -1
  17. package/build/src/sync/sync-client-types.js +1 -1
  18. package/build/src/sync/sync-client.d.ts +1 -1
  19. package/build/src/sync/sync-client.js +2 -2
  20. package/build/src/sync/sync-model-change-feed-service.d.ts +6 -1
  21. package/build/src/sync/sync-model-change-feed-service.d.ts.map +1 -1
  22. package/build/src/sync/sync-model-change-feed-service.js +15 -4
  23. package/build/src/sync/sync-publisher-types.d.ts +53 -21
  24. package/build/src/sync/sync-publisher-types.d.ts.map +1 -1
  25. package/build/src/sync/sync-publisher-types.js +1 -1
  26. package/build/src/sync/sync-publisher.d.ts +32 -9
  27. package/build/src/sync/sync-publisher.d.ts.map +1 -1
  28. package/build/src/sync/sync-publisher.js +170 -37
  29. package/build/src/sync/sync-realtime-bridge.d.ts +33 -10
  30. package/build/src/sync/sync-realtime-bridge.d.ts.map +1 -1
  31. package/build/src/sync/sync-realtime-bridge.js +51 -12
  32. package/build/src/sync/sync-scope-attributes.d.ts +15 -0
  33. package/build/src/sync/sync-scope-attributes.d.ts.map +1 -0
  34. package/build/src/sync/sync-scope-attributes.js +24 -0
  35. package/build/src/sync/sync-websocket-channel.d.ts +58 -0
  36. package/build/src/sync/sync-websocket-channel.d.ts.map +1 -0
  37. package/build/src/sync/sync-websocket-channel.js +131 -0
  38. package/build/sync/sync-channel-name.js +10 -0
  39. package/build/sync/sync-client-types.js +12 -6
  40. package/build/sync/sync-client.js +1 -1
  41. package/build/sync/sync-model-change-feed-service.js +17 -3
  42. package/build/sync/sync-publisher-types.js +32 -12
  43. package/build/sync/sync-publisher.js +192 -41
  44. package/build/sync/sync-realtime-bridge.js +56 -11
  45. package/build/sync/sync-scope-attributes.js +26 -0
  46. package/build/sync/sync-websocket-channel.js +146 -0
  47. package/build/tsconfig.tsbuildinfo +1 -1
  48. package/package.json +1 -1
  49. package/src/application.js +2 -0
  50. package/src/configuration-types.js +8 -8
  51. package/src/configuration.js +2 -2
  52. package/src/sync/sync-channel-name.js +10 -0
  53. package/src/sync/sync-client-types.js +12 -6
  54. package/src/sync/sync-client.js +1 -1
  55. package/src/sync/sync-model-change-feed-service.js +17 -3
  56. package/src/sync/sync-publisher-types.js +32 -12
  57. package/src/sync/sync-publisher.js +192 -41
  58. package/src/sync/sync-realtime-bridge.js +56 -11
  59. package/src/sync/sync-scope-attributes.js +26 -0
  60. package/src/sync/sync-websocket-channel.js +146 -0
@@ -1,14 +1,19 @@
1
1
  // @ts-check
2
2
  import SyncApiClient from "./sync-api-client.js";
3
+ import { VELOCIOUS_SYNC_CHANNEL } from "./sync-channel-name.js";
3
4
  /** @typedef {import("../configuration-types.js").VelociousSyncRealtimeChannelDescriptor} VelociousSyncRealtimeChannelDescriptor */
4
5
  /** @typedef {import("../configuration-types.js").VelociousSyncRealtimeWebsocketClient} VelociousSyncRealtimeWebsocketClient */
5
6
  /**
6
- * Derived realtime push bridge for the sync client. Subscribes the declared
7
- * websocket channels (config `sync.client.realtime.channels` callback plus
8
- * model-level `static sync = {realtime: {channel}}` declarations), applies
9
- * pushed changes through the same derived resource applier as pulls (with echo
10
- * suppression against tracked re-queueing), drops own-device messages by echo
11
- * origin, and fires a coalesced `pull()` when subscriptions become ready or
7
+ * Derived realtime push bridge for the sync client. Subscribes every declared
8
+ * pull scope to the framework sync channel ({@link VELOCIOUS_SYNC_CHANNEL})
9
+ * automatically the subscribe params mirror the scope's
10
+ * `{resourceType, conditions}` so the server authorizes them through the same
11
+ * sync resource authorization as pulls plus any deprecated legacy channels
12
+ * (config `sync.client.realtime.channels` callback and model-level
13
+ * `static sync = {realtime: {channel}}` declarations). Pushed changes apply
14
+ * through the same derived resource applier as pulls (with echo suppression
15
+ * against tracked re-queueing), own-device messages are dropped by echo
16
+ * origin, and a coalesced `pull()` fires when subscriptions become ready or
12
17
  * resume so offline gaps close.
13
18
  */
14
19
  export default class SyncRealtimeBridge {
@@ -37,7 +42,7 @@ export default class SyncRealtimeBridge {
37
42
  * Subscribes the derived realtime channels (idempotent and single-flighted):
38
43
  * an active subscription is kept as-is and a concurrent subscribe awaits the
39
44
  * in-flight attempt. Call `unsubscribe()` first to change the context.
40
- * @param {?} [context] - App context passed to the `sync.client.realtime.channels` callback (runtime values like eventId).
45
+ * @param {?} [context] - App context passed to the deprecated `sync.client.realtime.channels` callback (runtime scope values).
41
46
  * @returns {Promise<void>}
42
47
  */
43
48
  async subscribe(context) {
@@ -175,15 +180,24 @@ export default class SyncRealtimeBridge {
175
180
  return realtime;
176
181
  }
177
182
  /**
178
- * Derives the channel descriptors to subscribe: model-level static realtime
179
- * declarations plus the config channels callback, failing loudly when none exist.
180
- * @param {?} context - App context passed to the channels callback.
183
+ * Derives the channel descriptors to subscribe: one framework sync channel
184
+ * subscription per declared pull scope (the params mirror the scope's
185
+ * `{resourceType, conditions}`), plus the deprecated legacy paths
186
+ * model-level static realtime declarations and the config channels callback.
187
+ * Fails loudly when nothing is subscribable.
188
+ * @param {?} context - App context passed to the deprecated channels callback.
181
189
  * @returns {Promise<Array<VelociousSyncRealtimeChannelDescriptor>>} Channel descriptors.
182
190
  */
183
191
  async channelDescriptors(context) {
184
192
  const realtime = this.realtimeConfiguration();
185
193
  /** @type {Array<VelociousSyncRealtimeChannelDescriptor>} */
186
194
  const channelDescriptors = [];
195
+ for (const scopeRow of await this.syncClient.scopeStore().activeScopes()) {
196
+ channelDescriptors.push({
197
+ channel: VELOCIOUS_SYNC_CHANNEL,
198
+ params: { conditions: this.attributeNamedConditions(scopeRow), resourceType: scopeRow.resourceType }
199
+ });
200
+ }
187
201
  for (const [resourceType, resourceConfig] of Object.entries(this.syncClient.config.resources)) {
188
202
  if (!resourceConfig.realtime)
189
203
  continue;
@@ -193,10 +207,35 @@ export default class SyncRealtimeBridge {
193
207
  channelDescriptors.push(...await realtime.channels(context));
194
208
  }
195
209
  if (channelDescriptors.length === 0) {
196
- throw new Error("subscribeRealtime found no realtime channels - declare sync.client.realtime.channels or static sync = {realtime: {channel}} on a model");
210
+ throw new Error("subscribeRealtime found no channels to subscribe - declare a sync scope (syncClient().sync(query)) so its framework sync channel subscription can be derived, or the deprecated sync.client.realtime.channels callback");
197
211
  }
198
212
  return channelDescriptors;
199
213
  }
214
+ /**
215
+ * Translates a persisted scope's condition keys to the model's attribute
216
+ * names so the framework channel subscription matches the publisher's
217
+ * attribute-named scoping params: `serializedScopeFromQuery` persists the
218
+ * query's model-normalized column names (for example `project_id`), while
219
+ * scope-partition broadcasts carry attribute names (`projectId`). Keys
220
+ * without a column mapping are already attribute names and pass through;
221
+ * scopes on models without a declared sync resource fail loudly because no
222
+ * attribute mapping exists for them.
223
+ * @param {{conditions: Record<string, ?>, resourceType: string}} scopeRow - Active scope row.
224
+ * @returns {Record<string, ?>} Attribute-named scope conditions.
225
+ */
226
+ attributeNamedConditions(scopeRow) {
227
+ const resourceConfig = this.syncClient.config.resources[scopeRow.resourceType];
228
+ if (!resourceConfig) {
229
+ throw new Error(`subscribeRealtime can't derive attribute names for the sync scope declared on ${scopeRow.resourceType} - declare static sync on that model so its resource is registered`);
230
+ }
231
+ const columnNameToAttributeName = resourceConfig.modelClass.getColumnNameToAttributeNameMap();
232
+ /** @type {Record<string, ?>} */
233
+ const conditions = {};
234
+ for (const [conditionName, conditionValue] of Object.entries(scopeRow.conditions)) {
235
+ conditions[columnNameToAttributeName[conditionName] || conditionName] = conditionValue;
236
+ }
237
+ return conditions;
238
+ }
200
239
  /**
201
240
  * Chains one pushed message onto the serialized apply queue so changes apply
202
241
  * in arrival order; failures go to the sync client's error reporting.
@@ -259,4 +298,4 @@ export default class SyncRealtimeBridge {
259
298
  })();
260
299
  }
261
300
  }
262
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luYy1yZWFsdGltZS1icmlkZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc3luYy9zeW5jLXJlYWx0aW1lLWJyaWRnZS5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosT0FBTyxhQUFhLE1BQU0sc0JBQXNCLENBQUE7QUFFaEQsbUlBQW1JO0FBQ25JLCtIQUErSDtBQUUvSDs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sQ0FBQyxPQUFPLE9BQU8sa0JBQWtCO0lBQ3JDOzs7T0FHRztJQUNILFlBQVksRUFBQyxVQUFVLEVBQUM7UUFDdEIsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUE7UUFDNUIseUpBQXlKO1FBQ3pKLElBQUksQ0FBQyxTQUFTLEdBQUcsRUFBRSxDQUFBO1FBQ25CLDBEQUEwRDtRQUMxRCxJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQTtRQUNuQiw0QkFBNEI7UUFDNUIsSUFBSSxDQUFDLGFBQWEsR0FBRyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUE7UUFDdEMsdUhBQXVIO1FBQ3ZILElBQUksQ0FBQyxXQUFXLEdBQUcsQ0FBQyxDQUFBO1FBQ3BCLG1DQUFtQztRQUNuQyxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksQ0FBQTtRQUMxQixtQ0FBbUM7UUFDbkMsSUFBSSxDQUFDLGlCQUFpQixHQUFHLElBQUksQ0FBQTtRQUM3Qiw0REFBNEQ7UUFDNUQsSUFBSSxDQUFDLE1BQU0sR0FBRyxjQUFjLENBQUE7SUFDOUIsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNILEtBQUssQ0FBQyxTQUFTLENBQUMsT0FBTztRQUNyQixJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssWUFBWTtZQUFFLE9BQU07UUFFeEMsSUFBSSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1lBQzVCLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxDQUFD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LEVBQUU7WUFDbEMsSUFBSSxDQUFDO2dCQUNILE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsQ0FBQTtZQUM5QixDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDZixJQUFJLENBQUMsVUFBVSxDQUFDLFdBQVcsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUE7WUFDM0QsQ0FBQztvQkFBUyxDQUFDO2dCQUNULElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFBO1lBQzVCLENBQUM7UUFDSCxDQUFDLENBQUMsRUFBRSxDQUFBO0lBQ04sQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmltcG9ydCBTeW5jQXBpQ2xpZW50IGZyb20gXCIuL3N5bmMtYXBpLWNsaWVudC5qc1wiXG5cbi8qKiBAdHlwZWRlZiB7aW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5WZWxvY2lvdXNTeW5jUmVhbHRpbWVDaGFubmVsRGVzY3JpcHRvcn0gVmVsb2Npb3VzU3luY1JlYWx0aW1lQ2hhbm5lbERlc2NyaXB0b3IgKi9cbi8qKiBAdHlwZWRlZiB7aW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5WZWxvY2lvdXNTeW5jUmVhbHRpbWVXZWJzb2NrZXRDbGllbnR9IFZlbG9jaW91c1N5bmNSZWFsdGltZVdlYnNvY2tldENsaWVudCAqL1xuXG4vKipcbiAqIERlcml2ZWQgcmVhbHRpbWUgcHVzaCBicmlkZ2UgZm9yIHRoZSBzeW5jIGNsaWVudC4gU3Vic2NyaWJlcyB0aGUgZGVjbGFyZWRcbiAqIHdlYnNvY2tldCBjaGFubmVscyAoY29uZmlnIGBzeW5jLmNsaWVudC5yZWFsdGltZS5jaGFubmVsc2AgY2FsbGJhY2sgcGx1c1xuICogbW9kZWwtbGV2ZWwgYHN0YXRpYyBzeW5jID0ge3JlYWx0aW1lOiB7Y2hhbm5lbH19YCBkZWNsYXJhdGlvbnMpLCBhcHBsaWVzXG4gKiBwdXNoZWQgY2hhbmdlcyB0aHJvdWdoIHRoZSBzYW1lIGRlcml2ZWQgcmVzb3VyY2UgYXBwbGllciBhcyBwdWxscyAod2l0aCBlY2hvXG4gKiBzdXBwcmVzc2lvbiBhZ2FpbnN0IHRyYWNrZWQgcmUtcXVldWVpbmcpLCBkcm9wcyBvd24tZGV2aWNlIG1lc3NhZ2VzIGJ5IGVjaG9cbiAqIG9yaWdpbiwgYW5kIGZpcmVzIGEgY29hbGVzY2VkIGBwdWxsKClgIHdoZW4gc3Vic2NyaXB0aW9ucyBiZWNvbWUgcmVhZHkgb3JcbiAqIHJlc3VtZSBzbyBvZmZsaW5lIGdhcHMgY2xvc2UuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFN5bmNSZWFsdGltZUJyaWRnZSB7XG4gIC8qKlxuICAgKiBCdWlsZHMgdGhlIGJyaWRnZSBmb3IgYSBzeW5jIGNsaWVudC5cbiAgICogQHBhcmFtIHt7c3luY0NsaWVudDogaW1wb3J0KFwiLi9zeW5jLWNsaWVudC5qc1wiKS5kZWZhdWx0fX0gYXJncyAtIEJyaWRnZSBhcmdzLlxuICAgKi9cbiAgY29uc3RydWN0b3Ioe3N5bmNDbGllbnR9KSB7XG4gICAgdGhpcy5zeW5jQ2xpZW50ID0gc3luY0NsaWVudFxuICAgIC8qKiBAdHlwZSB7QXJyYXk8e2NoYW5uZWw6IHN0cmluZywgcmVzb3VyY2VUeXBlOiBzdHJpbmcgfCBudWxsLCBzdWJzY3JpcHRpb246IGltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24tdHlwZXMuanNcIikuVmVsb2Npb3VzU3luY1JlYWx0aW1lU3Vic2NyaXB0aW9ufT59ICovXG4gICAgdGhpcy5fY2hhbm5lbHMgPSBbXVxuICAgIC8qKiBAdHlwZSB7VmVsb2Npb3VzU3luY1JlYWx0aW1lV2Vic29ja2V0Q2xpZW50IHwgbnVsbH0gKi9cbiAgICB0aGlzLl9jbGllbnQgPSBudWxsXG4gICAgLyoqIEB0eXBlIHtQcm9taXNlPHZvaWQ+fSAqL1xuICAgIHRoaXMuX2FwcGx5UHJvbWlzZSA9IFByb21pc2UucmVzb2x2ZSgpXG4gICAgLyoqIEB0eXBlIHtudW1iZXJ9IFN1YnNjcmlwdGlvbiBnZW5lcmF0aW9uIC0gYnVtcGVkIGJ5IHVuc3Vic2NyaWJlIHNvIGluLWZsaWdodCBzdWJzY3JpYmVzIGRldGVjdCB0aGV5IGJlY2FtZSBzdGFsZS4gKi9cbiAgICB0aGlzLl9nZW5lcmF0aW9uID0gMFxuICAgIC8qKiBAdHlwZSB7UHJvbWlzZTx2b2lkPiB8IG51bGx9ICovXG4gICAgdGhpcy5fc2NoZWR1bGVkUHVsbCA9IG51bGxcbiAgICAvKiogQHR5cGUge1Byb21pc2U8dm9pZD4gfCBudWxsfSAqL1xuICAgIHRoaXMuX3N1YnNjcmliZVByb21pc2UgPSBudWxsXG4gICAgLyoqIEB0eXBlIHtcInN1YnNjcmliZWRcIiB8IFwic3Vic2NyaWJpbmdcIiB8IFwidW5zdWJzY3JpYmVkXCJ9ICovXG4gICAgdGhpcy5fc3RhdGUgPSBcInVuc3Vic2NyaWJlZFwiXG4gIH1cblxuICAvKipcbiAgICogU3Vic2NyaWJlcyB0aGUgZGVyaXZlZCByZWFsdGltZSBjaGFubmVscyAoaWRlbXBvdGVudCBhbmQgc2luZ2xlLWZsaWdodGVkKTpcbiAgICogYW4gYWN0aXZlIHN1YnNjcmlwdGlvbiBpcyBrZXB0IGFzLWlzIGFuZCBhIGNvbmN1cnJlbnQgc3Vic2NyaWJlIGF3YWl0cyB0aGVcbiAgICogaW4tZmxpZ2h0IGF0dGVtcHQuIENhbGwgYHVuc3Vic2NyaWJlKClgIGZpcnN0IHRvIGNoYW5nZSB0aGUgY29udGV4dC5cbiAgICogQHBhcmFtIHs/fSBbY29udGV4dF0gLSBBcHAgY29udGV4dCBwYXNzZWQgdG8gdGhlIGBzeW5jLmNsaWVudC5yZWFsdGltZS5jaGFubmVsc2AgY2FsbGJhY2sgKHJ1bnRpbWUgdmFsdWVzIGxpa2UgZXZlbnRJZCkuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgc3Vic2NyaWJlKGNvbnRleHQpIHtcbiAgICBpZiAodGhpcy5fc3RhdGUgPT09IFwic3Vic2NyaWJlZFwiKSByZXR1cm5cblxuICAgIGlmICghdGhpcy5fc3Vic2NyaWJlUHJvbWlzZSkge1xuICAgICAgdGhpcy5fc3Vic2NyaWJlUHJvbWlzZSA9IHRoaXMuX3N1YnNjcmliZShjb250ZXh0KS5maW5hbGx5KCgpID0+IHtcbiAgICAgICAgdGhpcy5fc3Vic2NyaWJlUHJvbWlzZSA9IG51bGxcbiAgICAgIH0pXG4gICAgfVxuXG4gICAgYXdhaXQgdGhpcy5fc3Vic2NyaWJlUHJvbWlzZVxuICB9XG5cbiAgLyoqXG4gICAqIENvbm5lY3RzIHRoZSB3ZWJzb2NrZXQgY2xpZW50LCBzdWJzY3JpYmVzIGV2ZXJ5IGRlcml2ZWQgY2hhbm5lbCwgYW5kIHdhaXRzXG4gICAqIGZvciBlYWNoIHN1YnNjcmlwdGlvbidzIHNlcnZlciBhY2tub3dsZWRnZW1lbnQgYmVmb3JlIHRoZSBnYXAtY2xvc2luZyBwdWxsLFxuICAgKiBzbyBubyBjaGFuZ2UgY2FuIGxhbmQgYmV0d2VlbiB0aGUgcHVsbCBhbmQgdGhlIHN1YnNjcmlwdGlvbnMgZ29pbmcgbGl2ZS5cbiAgICogTG9jYWxseSBjcmVhdGVkIHJlc291cmNlcyBhcmUgb25seSBwcm9tb3RlZCB0byB0aGUgYnJpZGdlIG9uY2UgZXZlcnl0aGluZ1xuICAgKiBpcyBsaXZlOyBhbiB1bnN1YnNjcmliZSBhcnJpdmluZyBkdXJpbmcgYW55IGF3YWl0IG1hcmtzIHRoaXMgYXR0ZW1wdCBzdGFsZVxuICAgKiBhbmQgaXQgdGVhcnMgaXRzIG93biByZXNvdXJjZXMgZG93biBpbnN0ZWFkIG9mIHJlc3Vic2NyaWJpbmcuXG4gICAqIEBwYXJhbSB7P30gY29udGV4dCAtIEFwcCBjb250ZXh0IHBhc3NlZCB0byB0aGUgY2hhbm5lbHMgY2FsbGJhY2suXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgX3N1YnNjcmliZShjb250ZXh0KSB7XG4gICAgY29uc3QgZ2VuZXJhdGlvbiA9IHRoaXMuX2dlbmVyYXRpb25cblxuICAgIHRoaXMuX3N0YXRlID0gXCJzdWJzY3JpYmluZ1wiXG5cbiAgICAvKiogQHR5cGUge0FycmF5PHtjaGFubmVsOiBzdHJpbmcsIHJlc291cmNlVHlwZTogc3RyaW5nIHwgbnVsbCwgc3Vic2NyaXB0aW9uOiBpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLlZlbG9jaW91c1N5bmNSZWFsdGltZVN1YnNjcmlwdGlvbn0+fSAqL1xuICAgIGNvbnN0IGNoYW5uZWxzID0gW11cbiAgICAvKiogQHR5cGUge1ZlbG9jaW91c1N5bmNSZWFsdGltZVdlYnNvY2tldENsaWVudCB8IG51bGx9ICovXG4gICAgbGV0IGNsaWVudCA9IG51bGxcbiAgICAvKipcbiAgICAgKiBUZWFycyBkb3duIGV2ZXJ5dGhpbmcgdGhpcyBzdGFsZS9mYWlsZWQgc3Vic2NyaWJlIGF0dGVtcHQgY3JlYXRlZCBpdHNlbGYuXG4gICAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59XG4gICAgICovXG4gICAgY29uc3QgdGVhcmRvd24gPSBhc3luYyAoKSA9PiB7XG4gICAgICBmb3IgKGNvbnN0IHtzdWJzY3JpcHRpb259IG9mIGNoYW5uZWxzKSB7XG4gICAgICAgIHN1YnNjcmlwdGlvbi5jbG9zZSgpXG4gICAgICB9XG5cbiAgICAgIGlmIChjbGllbnQpIGF3YWl0IGNsaWVudC5kaXNjb25uZWN0QW5kU3RvcFJlY29ubmVjdCgpXG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlYWx0aW1lID0gdGhpcy5yZWFsdGltZUNvbmZpZ3VyYXRpb24oKVxuICAgICAgY29uc3QgY2hhbm5lbERlc2NyaXB0b3JzID0gYXdhaXQgdGhpcy5jaGFubmVsRGVzY3JpcHRvcnMoY29udGV4dClcblxuICAgICAgaWYgKGdlbmVyYXRpb24gIT09IHRoaXMuX2dlbmVyYXRpb24pIHJldHVyblxuXG4gICAgICBjbGllbnQgPSBhd2FpdCByZWFsdGltZS5jcmVhdGVDbGllbnQoKVxuXG4gICAgICBpZiAoZ2VuZXJhdGlvbiAhPT0gdGhpcy5fZ2VuZXJhdGlvbikgcmV0dXJuXG5cbiAgICAgIGF3YWl0IGNsaWVudC5jb25uZWN0KClcblxuICAgICAgaWYgKGdlbmVyYXRpb24gIT09IHRoaXMuX2dlbmVyYXRpb24pIHtcbiAgICAgICAgYXdhaXQgdGVhcmRvd24oKVxuICAgICAgICByZXR1cm5cbiAgICAgIH1cblxuICAgICAgY29uc3QgYXV0aGVudGljYXRpb25Ub2tlbiA9IGF3YWl0IHRoaXMuc3luY0NsaWVudC5jb25maWcuYXV0aGVudGljYXRpb25Ub2tlbigpXG5cbiAgICAgIGlmIChnZW5lcmF0aW9uICE9PSB0aGlzLl9nZW5lcmF0aW9uKSB7XG4gICAgICAgIGF3YWl0IHRlYXJkb3duKClcbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIGZvciAoY29uc3QgY2hhbm5lbERlc2NyaXB0b3Igb2YgY2hhbm5lbERlc2NyaXB0b3JzKSB7XG4gICAgICAgIGlmIChjaGFubmVsRGVzY3JpcHRvci5wYXJhbXMgJiYgXCJhdXRoZW50aWNhdGlvblRva2VuXCIgaW4gY2hhbm5lbERlc2NyaXB0b3IucGFyYW1zKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBSZWFsdGltZSBjaGFubmVsIFwiJHtjaGFubmVsRGVzY3JpcHRvci5jaGFubmVsfVwiIHBhcmFtcyBtdXN0IG5vdCBpbmNsdWRlIGF1dGhlbnRpY2F0aW9uVG9rZW4gLSB0aGUgZnJhbWV3b3JrIGluamVjdHMgdGhlIHN5bmMuY2xpZW50IGF1dGhlbnRpY2F0aW9uVG9rZW4gYXV0b21hdGljYWxseWApXG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCByZXNvdXJjZVR5cGUgPSBjaGFubmVsRGVzY3JpcHRvci5yZXNvdXJjZVR5cGUgPz8gbnVsbFxuICAgICAgICBjb25zdCBzdWJzY3JpcHRpb24gPSBjbGllbnQuc3Vic2NyaWJlQ2hhbm5lbChjaGFubmVsRGVzY3JpcHRvci5jaGFubmVsLCB7XG4gICAgICAgICAgb25NZXNzYWdlOiAoYm9keSkgPT4gdGhpcy5lbnF1ZXVlQXBwbHkoe2JvZHksIHJlc291cmNlVHlwZX0pLFxuICAgICAgICAgIG9uUmVzdW1lOiAoKSA9PiB0aGlzLnNjaGVkdWxlUHVsbCgpLFxuICAgICAgICAgIHBhcmFtczogey4uLmNoYW5uZWxEZXNjcmlwdG9yLnBhcmFtcywgYXV0aGVudGljYXRpb25Ub2tlbn1cbiAgICAgICAgfSlcblxuICAgICAgICBjaGFubmVscy5wdXNoKHtjaGFubmVsOiBjaGFubmVsRGVzY3JpcHRvci5jaGFubmVsLCByZXNvdXJjZVR5cGUsIHN1YnNjcmlwdGlvbn0pXG4gICAgICB9XG5cbiAgICAgIGF3YWl0IFByb21pc2UuYWxsKGNoYW5uZWxzLm1hcCgoe3N1YnNjcmlwdGlvbn0pID0+IHN1YnNjcmlwdGlvbi53YWl0Rm9yUmVhZHkoKSkpXG5cbiAgICAgIGlmIChnZW5lcmF0aW9uICE9PSB0aGlzLl9nZW5lcmF0aW9uKSB7XG4gICAgICAgIGF3YWl0IHRlYXJkb3duKClcbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIHRoaXMuX2NoYW5uZWxzID0gY2hhbm5lbHNcbiAgICAgIHRoaXMuX2NsaWVudCA9IGNsaWVudFxuICAgICAgdGhpcy5fc3RhdGUgPSBcInN1YnNjcmliZWRcIlxuICAgICAgdGhpcy5zY2hlZHVsZVB1bGwoKVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBhd2FpdCB0ZWFyZG93bigpXG5cbiAgICAgIGlmIChnZW5lcmF0aW9uID09PSB0aGlzLl9nZW5lcmF0aW9uKSB0aGlzLl9zdGF0ZSA9IFwidW5zdWJzY3JpYmVkXCJcblxuICAgICAgdGhyb3cgZXJyb3JcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ2xvc2VzIGV2ZXJ5IGNoYW5uZWwgc3Vic2NyaXB0aW9uIGFuZCBkaXNjb25uZWN0cyB0aGUgd2Vic29ja2V0IGNsaWVudFxuICAgKiAoaWRlbXBvdGVudCkuIEFsc28gbWFya3MgYW55IGluLWZsaWdodCBzdWJzY3JpYmUgYXR0ZW1wdCBzdGFsZSBzbyBpdCB0ZWFyc1xuICAgKiBpdHNlbGYgZG93biBpbnN0ZWFkIG9mIGZpbmlzaGluZyB0aGUgc3Vic2NyaXB0aW9uIGFmdGVyd2FyZHMuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgdW5zdWJzY3JpYmUoKSB7XG4gICAgdGhpcy5fZ2VuZXJhdGlvbiArPSAxXG5cbiAgICBjb25zdCBjaGFubmVscyA9IHRoaXMuX2NoYW5uZWxzXG4gICAgY29uc3QgY2xpZW50ID0gdGhpcy5fY2xpZW50XG5cbiAgICB0aGlzLl9jaGFubmVscyA9IFtdXG4gICAgdGhpcy5fY2xpZW50ID0gbnVsbFxuICAgIHRoaXMuX3N0YXRlID0gXCJ1bnN1YnNjcmliZWRcIlxuXG4gICAgZm9yIChjb25zdCB7c3Vic2NyaXB0aW9ufSBvZiBjaGFubmVscykge1xuICAgICAgc3Vic2NyaXB0aW9uLmNsb3NlKClcbiAgICB9XG5cbiAgICBpZiAoY2xpZW50KSBhd2FpdCBjbGllbnQuZGlzY29ubmVjdEFuZFN0b3BSZWNvbm5lY3QoKVxuICB9XG5cbiAgLyoqXG4gICAqIFJlcG9ydHMgdGhlIGJyaWRnZSBzdWJzY3JpcHRpb24gc3RhdGUgYW5kIHBlci1jaGFubmVsIHJlYWRpbmVzcy5cbiAgICogQHJldHVybnMge3tjaGFubmVsczogQXJyYXk8e2NoYW5uZWw6IHN0cmluZywgcmVhZHk6IGJvb2xlYW4sIHJlc291cmNlVHlwZTogc3RyaW5nIHwgbnVsbH0+LCBzdGF0ZTogXCJzdWJzY3JpYmVkXCIgfCBcInN1YnNjcmliaW5nXCIgfCBcInVuc3Vic2NyaWJlZFwifX0gUmVhbHRpbWUgc3RhdHVzLlxuICAgKi9cbiAgc3RhdHVzKCkge1xuICAgIHJldHVybiB7XG4gICAgICBjaGFubmVsczogdGhpcy5fY2hhbm5lbHMubWFwKCh7Y2hhbm5lbCwgcmVzb3VyY2VUeXBlLCBzdWJzY3JpcHRpb259KSA9PiAoe2NoYW5uZWwsIHJlYWR5OiBzdWJzY3JpcHRpb24uaXNSZWFkeSgpLCByZXNvdXJjZVR5cGV9KSksXG4gICAgICBzdGF0ZTogdGhpcy5fc3RhdGVcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQXdhaXRzIGFsbCBlbnF1ZXVlZCBtZXNzYWdlIGFwcGxpZXMgYW5kIGFueSBzY2hlZHVsZWQgcHVsbCAodGVzdHMsIHNodXRkb3duIGZsb3dzKS5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyB3YWl0Rm9yQXBwbGllZCgpIHtcbiAgICBhd2FpdCB0aGlzLl9hcHBseVByb21pc2VcbiAgICBpZiAodGhpcy5fc2NoZWR1bGVkUHVsbCkgYXdhaXQgdGhpcy5fc2NoZWR1bGVkUHVsbFxuICB9XG5cbiAgLyoqXG4gICAqIFJlc29sdmVzIHRoZSByZWFsdGltZSBjb25maWd1cmF0aW9uLCBmYWlsaW5nIGxvdWRseSB3aGVuIGl0IGlzIG1pc3NpbmcuXG4gICAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLlZlbG9jaW91c1N5bmNDbGllbnRSZWFsdGltZUNvbmZpZ3VyYXRpb259IFJlYWx0aW1lIGNvbmZpZ3VyYXRpb24uXG4gICAqL1xuICByZWFsdGltZUNvbmZpZ3VyYXRpb24oKSB7XG4gICAgY29uc3QgcmVhbHRpbWUgPSB0aGlzLnN5bmNDbGllbnQuY29uZmlnLnJlYWx0aW1lXG5cbiAgICBpZiAoIXJlYWx0aW1lKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJzdWJzY3JpYmVSZWFsdGltZSByZXF1aXJlcyBhIHN5bmMuY2xpZW50LnJlYWx0aW1lIGNvbmZpZ3VyYXRpb24gYmxvY2sgd2l0aCBhIGNyZWF0ZUNsaWVudCBjYWxsYmFja1wiKVxuICAgIH1cblxuICAgIHJldHVybiByZWFsdGltZVxuICB9XG5cbiAgLyoqXG4gICAqIERlcml2ZXMgdGhlIGNoYW5uZWwgZGVzY3JpcHRvcnMgdG8gc3Vic2NyaWJlOiBtb2RlbC1sZXZlbCBzdGF0aWMgcmVhbHRpbWVcbiAgICogZGVjbGFyYXRpb25zIHBsdXMgdGhlIGNvbmZpZyBjaGFubmVscyBjYWxsYmFjaywgZmFpbGluZyBsb3VkbHkgd2hlbiBub25lIGV4aXN0LlxuICAgKiBAcGFyYW0gez99IGNvbnRleHQgLSBBcHAgY29udGV4dCBwYXNzZWQgdG8gdGhlIGNoYW5uZWxzIGNhbGxiYWNrLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxBcnJheTxWZWxvY2lvdXNTeW5jUmVhbHRpbWVDaGFubmVsRGVzY3JpcHRvcj4+fSBDaGFubmVsIGRlc2NyaXB0b3JzLlxuICAgKi9cbiAgYXN5bmMgY2hhbm5lbERlc2NyaXB0b3JzKGNvbnRleHQpIHtcbiAgICBjb25zdCByZWFsdGltZSA9IHRoaXMucmVhbHRpbWVDb25maWd1cmF0aW9uKClcbiAgICAvKiogQHR5cGUge0FycmF5PFZlbG9jaW91c1N5bmNSZWFsdGltZUNoYW5uZWxEZXNjcmlwdG9yPn0gKi9cbiAgICBjb25zdCBjaGFubmVsRGVzY3JpcHRvcnMgPSBbXVxuXG4gICAgZm9yIChjb25zdCBbcmVzb3VyY2VUeXBlLCByZXNvdXJjZUNvbmZpZ10gb2YgT2JqZWN0LmVudHJpZXModGhpcy5zeW5jQ2xpZW50LmNvbmZpZy5yZXNvdXJjZXMpKSB7XG4gICAgICBpZiAoIXJlc291cmNlQ29uZmlnLnJlYWx0aW1lKSBjb250aW51ZVxuXG4gICAgICBjaGFubmVsRGVzY3JpcHRvcnMucHVzaCh7Y2hhbm5lbDogcmVzb3VyY2VDb25maWcucmVhbHRpbWUuY2hhbm5lbCwgcGFyYW1zOiByZXNvdXJjZUNvbmZpZy5yZWFsdGltZS5wYXJhbXMsIHJlc291cmNlVHlwZX0pXG4gICAgfVxuXG4gICAgaWYgKHJlYWx0aW1lLmNoYW5uZWxzKSB7XG4gICAgICBjaGFubmVsRGVzY3JpcHRvcnMucHVzaCguLi5hd2FpdCByZWFsdGltZS5jaGFubmVscyhjb250ZXh0KSlcbiAgICB9XG5cbiAgICBpZiAoY2hhbm5lbERlc2NyaXB0b3JzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwic3Vic2NyaWJlUmVhbHRpbWUgZm91bmQgbm8gcmVhbHRpbWUgY2hhbm5lbHMgLSBkZWNsYXJlIHN5bmMuY2xpZW50LnJlYWx0aW1lLmNoYW5uZWxzIG9yIHN0YXRpYyBzeW5jID0ge3JlYWx0aW1lOiB7Y2hhbm5lbH19IG9uIGEgbW9kZWxcIilcbiAgICB9XG5cbiAgICByZXR1cm4gY2hhbm5lbERlc2NyaXB0b3JzXG4gIH1cblxuICAvKipcbiAgICogQ2hhaW5zIG9uZSBwdXNoZWQgbWVzc2FnZSBvbnRvIHRoZSBzZXJpYWxpemVkIGFwcGx5IHF1ZXVlIHNvIGNoYW5nZXMgYXBwbHlcbiAgICogaW4gYXJyaXZhbCBvcmRlcjsgZmFpbHVyZXMgZ28gdG8gdGhlIHN5bmMgY2xpZW50J3MgZXJyb3IgcmVwb3J0aW5nLlxuICAgKiBAcGFyYW0ge3tib2R5OiA/LCByZXNvdXJjZVR5cGU6IHN0cmluZyB8IG51bGx9fSBhcmdzIC0gTWVzc2FnZSBhcmdzLlxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICovXG4gIGVucXVldWVBcHBseSh7Ym9keSwgcmVzb3VyY2VUeXBlfSkge1xuICAgIHRoaXMuX2FwcGx5UHJvbWlzZSA9IHRoaXMuX2FwcGx5UHJvbWlzZS50aGVuKGFzeW5jICgpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRoaXMuYXBwbHlNZXNzYWdlKHtib2R5LCByZXNvdXJjZVR5cGV9KVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgdGhpcy5zeW5jQ2xpZW50LnJlcG9ydEVycm9yKC8qKiBAdHlwZSB7RXJyb3J9ICovIChlcnJvcikpXG4gICAgICB9XG4gICAgfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBBcHBsaWVzIG9uZSBwdXNoZWQgbWVzc2FnZSB0aHJvdWdoIHRoZSBkZXJpdmVkIHJlc291cmNlIGFwcGxpZXI6IGRyb3BzXG4gICAqIG93bi1kZXZpY2UgbWVzc2FnZXMgYnkgZWNobyBvcmlnaW4sIGRlZmF1bHRzIHRoZSBjaGFubmVsJ3MgcmVzb3VyY2VUeXBlIG9udG9cbiAgICogZW52ZWxvcGVzIHdpdGhvdXQgb25lLCBhbmQgZmFpbHMgbG91ZGx5IG9uIHVua25vd24gcmVzb3VyY2UgdHlwZXMuXG4gICAqIEBwYXJhbSB7e2JvZHk6ID8sIHJlc291cmNlVHlwZTogc3RyaW5nIHwgbnVsbH19IGFyZ3MgLSBNZXNzYWdlIGFyZ3MuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgYXBwbHlNZXNzYWdlKHtib2R5LCByZXNvdXJjZVR5cGV9KSB7XG4gICAgaWYgKCFib2R5IHx8IHR5cGVvZiBib2R5ICE9PSBcIm9iamVjdFwiIHx8IEFycmF5LmlzQXJyYXkoYm9keSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgUmVhbHRpbWUgc3luYyBtZXNzYWdlcyBtdXN0IGJlIGVudmVsb3BlIG9iamVjdHMsIGdvdDogJHtKU09OLnN0cmluZ2lmeShib2R5KX1gKVxuICAgIH1cblxuICAgIGNvbnN0IHJlYWx0aW1lID0gdGhpcy5yZWFsdGltZUNvbmZpZ3VyYXRpb24oKVxuXG4gICAgaWYgKHJlYWx0aW1lLmxvY2FsT3JpZ2luICYmIGJvZHkuZWNob09yaWdpbiAhPT0gdW5kZWZpbmVkICYmIGJvZHkuZWNob09yaWdpbiAhPT0gbnVsbCkge1xuICAgICAgY29uc3QgbG9jYWxPcmlnaW4gPSBTdHJpbmcoYXdhaXQgcmVhbHRpbWUubG9jYWxPcmlnaW4oKSlcblxuICAgICAgaWYgKFN0cmluZyhib2R5LmVjaG9PcmlnaW4pID09PSBsb2NhbE9yaWdpbikgcmV0dXJuXG4gICAgfVxuXG4gICAgY29uc3Qgc3luY1BheWxvYWRzID0gQXJyYXkuaXNBcnJheShib2R5LnN5bmNzKSA/IGJvZHkuc3luY3MgOiBbYm9keV1cbiAgICBjb25zdCBhcHBseVN5bmMgPSB0aGlzLnN5bmNDbGllbnQucmVtb3RlQXBwbHlTeW5jKHtzb3VyY2U6IFwicmVtb3RlIGNoYW5nZVwifSlcblxuICAgIGZvciAoY29uc3Qgc3luY1BheWxvYWQgb2Ygc3luY1BheWxvYWRzKSB7XG4gICAgICBjb25zdCBzeW5jID0gU3luY0FwaUNsaWVudC5zeW5jRW52ZWxvcGVGcm9tUGF5bG9hZCh7cmVzb3VyY2VUeXBlLCAuLi5zeW5jUGF5bG9hZH0pXG5cbiAgICAgIGF3YWl0IGFwcGx5U3luYyhzeW5jKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTY2hlZHVsZXMgYSBjb2FsZXNjZWQgYmFja2dyb3VuZCBwdWxsIGNsb3Npbmcgb2ZmbGluZSBnYXBzIGFmdGVyXG4gICAqIChyZSlzdWJzY3JpcHRpb24gcmVhZGluZXNzLiBSZXN1bWVzIGFycml2aW5nIHdoaWxlIGEgcHVsbCBpcyBhbHJlYWR5XG4gICAqIHNjaGVkdWxlZCBvciBpbiBmbGlnaHQgY29hbGVzY2UgaW50byB0aGF0IHB1bGwgaW5zdGVhZCBvZiBzdGFja2luZy5cbiAgICogQHJldHVybnMge3ZvaWR9XG4gICAqL1xuICBzY2hlZHVsZVB1bGwoKSB7XG4gICAgaWYgKHRoaXMucmVhbHRpbWVDb25maWd1cmF0aW9uKCkucHVsbE9uUmVjb25uZWN0ID09PSBmYWxzZSkgcmV0dXJuXG5cbiAgICB0aGlzLl9zY2hlZHVsZWRQdWxsIHx8PSAoYXN5bmMgKCkgPT4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgdGhpcy5zeW5jQ2xpZW50LnB1bGwoKVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgdGhpcy5zeW5jQ2xpZW50LnJlcG9ydEVycm9yKC8qKiBAdHlwZSB7RXJyb3J9ICovIChlcnJvcikpXG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICB0aGlzLl9zY2hlZHVsZWRQdWxsID0gbnVsbFxuICAgICAgfVxuICAgIH0pKClcbiAgfVxufVxuIl19
301
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luYy1yZWFsdGltZS1icmlkZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc3luYy9zeW5jLXJlYWx0aW1lLWJyaWRnZS5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosT0FBTyxhQUFhLE1BQU0sc0JBQXNCLENBQUE7QUFDaEQsT0FBTyxFQUFDLHNCQUFzQixFQUFDLE1BQU0sd0JBQXdCLENBQUE7QUFFN0QsbUlBQW1JO0FBQ25JLCtIQUErSDtBQUUvSDs7Ozs7Ozs7Ozs7O0dBWUc7QUFDSCxNQUFNLENBQUMsT0FBTyxPQUFPLGtCQUFrQjtJQUNyQzs7O09BR0c7SUFDSCxZQUFZLEVBQUMsVUFBVSxFQUFDO1FBQ3RCLElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxDQUFBO1FBQzVCLHlKQUF5SjtRQUN6SixJQUFJLENBQUMsU0FBUyxHQUFHLEVBQUUsQ0FBQTtRQUNuQiwwREFBMEQ7UUFDMUQsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUE7UUFDbkIsNEJBQTRCO1FBQzVCLElBQUksQ0FBQyxhQUFhLEdBQUcsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFBO1FBQ3RDLHVIQUF1SDtRQUN2SCxJQUFJLENBQUMsV0FBVyxHQUFHLENBQUMsQ0FBQTtRQUNwQixtQ0FBbUM7UUFDbkMsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUE7UUFDMUIsbUNBQW1DO1FBQ25DLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLENBQUE7UUFDN0IsNERBQTREO1FBQzVELElBQUksQ0FBQyxNQUFNLEdBQUcsY0FBYyxDQUFBO0lBQzlCLENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSCxLQUFLLENBQUMsU0FBUyxDQUFDLE9BQU87UUFDckIsSUFBSSxJQUFJLENBQUMsTUFBTSxLQUFLLFlBQVk7WUFBRSxPQUFNO1FBRXhDLElBQUksQ0FBQyxJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztZQUM1QixJQUFJLENB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LFVBQVUsQ0FBQyxJQUFJLEVBQUUsQ0FBQTtZQUM5QixDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDZixJQUFJLENBQUMsVUFBVSxDQUFDLFdBQVcsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUE7WUFDM0QsQ0FBQztvQkFBUyxDQUFDO2dCQUNULElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFBO1lBQzVCLENBQUM7UUFDSCxDQUFDLENBQUMsRUFBRSxDQUFBO0lBQ04sQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmltcG9ydCBTeW5jQXBpQ2xpZW50IGZyb20gXCIuL3N5bmMtYXBpLWNsaWVudC5qc1wiXG5pbXBvcnQge1ZFTE9DSU9VU19TWU5DX0NIQU5ORUx9IGZyb20gXCIuL3N5bmMtY2hhbm5lbC1uYW1lLmpzXCJcblxuLyoqIEB0eXBlZGVmIHtpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLlZlbG9jaW91c1N5bmNSZWFsdGltZUNoYW5uZWxEZXNjcmlwdG9yfSBWZWxvY2lvdXNTeW5jUmVhbHRpbWVDaGFubmVsRGVzY3JpcHRvciAqL1xuLyoqIEB0eXBlZGVmIHtpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLlZlbG9jaW91c1N5bmNSZWFsdGltZVdlYnNvY2tldENsaWVudH0gVmVsb2Npb3VzU3luY1JlYWx0aW1lV2Vic29ja2V0Q2xpZW50ICovXG5cbi8qKlxuICogRGVyaXZlZCByZWFsdGltZSBwdXNoIGJyaWRnZSBmb3IgdGhlIHN5bmMgY2xpZW50LiBTdWJzY3JpYmVzIGV2ZXJ5IGRlY2xhcmVkXG4gKiBwdWxsIHNjb3BlIHRvIHRoZSBmcmFtZXdvcmsgc3luYyBjaGFubmVsICh7QGxpbmsgVkVMT0NJT1VTX1NZTkNfQ0hBTk5FTH0pXG4gKiBhdXRvbWF0aWNhbGx5IOKAlCB0aGUgc3Vic2NyaWJlIHBhcmFtcyBtaXJyb3IgdGhlIHNjb3BlJ3NcbiAqIGB7cmVzb3VyY2VUeXBlLCBjb25kaXRpb25zfWAgc28gdGhlIHNlcnZlciBhdXRob3JpemVzIHRoZW0gdGhyb3VnaCB0aGUgc2FtZVxuICogc3luYyByZXNvdXJjZSBhdXRob3JpemF0aW9uIGFzIHB1bGxzIOKAlCBwbHVzIGFueSBkZXByZWNhdGVkIGxlZ2FjeSBjaGFubmVsc1xuICogKGNvbmZpZyBgc3luYy5jbGllbnQucmVhbHRpbWUuY2hhbm5lbHNgIGNhbGxiYWNrIGFuZCBtb2RlbC1sZXZlbFxuICogYHN0YXRpYyBzeW5jID0ge3JlYWx0aW1lOiB7Y2hhbm5lbH19YCBkZWNsYXJhdGlvbnMpLiBQdXNoZWQgY2hhbmdlcyBhcHBseVxuICogdGhyb3VnaCB0aGUgc2FtZSBkZXJpdmVkIHJlc291cmNlIGFwcGxpZXIgYXMgcHVsbHMgKHdpdGggZWNobyBzdXBwcmVzc2lvblxuICogYWdhaW5zdCB0cmFja2VkIHJlLXF1ZXVlaW5nKSwgb3duLWRldmljZSBtZXNzYWdlcyBhcmUgZHJvcHBlZCBieSBlY2hvXG4gKiBvcmlnaW4sIGFuZCBhIGNvYWxlc2NlZCBgcHVsbCgpYCBmaXJlcyB3aGVuIHN1YnNjcmlwdGlvbnMgYmVjb21lIHJlYWR5IG9yXG4gKiByZXN1bWUgc28gb2ZmbGluZSBnYXBzIGNsb3NlLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBTeW5jUmVhbHRpbWVCcmlkZ2Uge1xuICAvKipcbiAgICogQnVpbGRzIHRoZSBicmlkZ2UgZm9yIGEgc3luYyBjbGllbnQuXG4gICAqIEBwYXJhbSB7e3N5bmNDbGllbnQ6IGltcG9ydChcIi4vc3luYy1jbGllbnQuanNcIikuZGVmYXVsdH19IGFyZ3MgLSBCcmlkZ2UgYXJncy5cbiAgICovXG4gIGNvbnN0cnVjdG9yKHtzeW5jQ2xpZW50fSkge1xuICAgIHRoaXMuc3luY0NsaWVudCA9IHN5bmNDbGllbnRcbiAgICAvKiogQHR5cGUge0FycmF5PHtjaGFubmVsOiBzdHJpbmcsIHJlc291cmNlVHlwZTogc3RyaW5nIHwgbnVsbCwgc3Vic2NyaXB0aW9uOiBpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLlZlbG9jaW91c1N5bmNSZWFsdGltZVN1YnNjcmlwdGlvbn0+fSAqL1xuICAgIHRoaXMuX2NoYW5uZWxzID0gW11cbiAgICAvKiogQHR5cGUge1ZlbG9jaW91c1N5bmNSZWFsdGltZVdlYnNvY2tldENsaWVudCB8IG51bGx9ICovXG4gICAgdGhpcy5fY2xpZW50ID0gbnVsbFxuICAgIC8qKiBAdHlwZSB7UHJvbWlzZTx2b2lkPn0gKi9cbiAgICB0aGlzLl9hcHBseVByb21pc2UgPSBQcm9taXNlLnJlc29sdmUoKVxuICAgIC8qKiBAdHlwZSB7bnVtYmVyfSBTdWJzY3JpcHRpb24gZ2VuZXJhdGlvbiAtIGJ1bXBlZCBieSB1bnN1YnNjcmliZSBzbyBpbi1mbGlnaHQgc3Vic2NyaWJlcyBkZXRlY3QgdGhleSBiZWNhbWUgc3RhbGUuICovXG4gICAgdGhpcy5fZ2VuZXJhdGlvbiA9IDBcbiAgICAvKiogQHR5cGUge1Byb21pc2U8dm9pZD4gfCBudWxsfSAqL1xuICAgIHRoaXMuX3NjaGVkdWxlZFB1bGwgPSBudWxsXG4gICAgLyoqIEB0eXBlIHtQcm9taXNlPHZvaWQ+IHwgbnVsbH0gKi9cbiAgICB0aGlzLl9zdWJzY3JpYmVQcm9taXNlID0gbnVsbFxuICAgIC8qKiBAdHlwZSB7XCJzdWJzY3JpYmVkXCIgfCBcInN1YnNjcmliaW5nXCIgfCBcInVuc3Vic2NyaWJlZFwifSAqL1xuICAgIHRoaXMuX3N0YXRlID0gXCJ1bnN1YnNjcmliZWRcIlxuICB9XG5cbiAgLyoqXG4gICAqIFN1YnNjcmliZXMgdGhlIGRlcml2ZWQgcmVhbHRpbWUgY2hhbm5lbHMgKGlkZW1wb3RlbnQgYW5kIHNpbmdsZS1mbGlnaHRlZCk6XG4gICAqIGFuIGFjdGl2ZSBzdWJzY3JpcHRpb24gaXMga2VwdCBhcy1pcyBhbmQgYSBjb25jdXJyZW50IHN1YnNjcmliZSBhd2FpdHMgdGhlXG4gICAqIGluLWZsaWdodCBhdHRlbXB0LiBDYWxsIGB1bnN1YnNjcmliZSgpYCBmaXJzdCB0byBjaGFuZ2UgdGhlIGNvbnRleHQuXG4gICAqIEBwYXJhbSB7P30gW2NvbnRleHRdIC0gQXBwIGNvbnRleHQgcGFzc2VkIHRvIHRoZSBkZXByZWNhdGVkIGBzeW5jLmNsaWVudC5yZWFsdGltZS5jaGFubmVsc2AgY2FsbGJhY2sgKHJ1bnRpbWUgc2NvcGUgdmFsdWVzKS5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBzdWJzY3JpYmUoY29udGV4dCkge1xuICAgIGlmICh0aGlzLl9zdGF0ZSA9PT0gXCJzdWJzY3JpYmVkXCIpIHJldHVyblxuXG4gICAgaWYgKCF0aGlzLl9zdWJzY3JpYmVQcm9taXNlKSB7XG4gICAgICB0aGlzLl9zdWJzY3JpYmVQcm9taXNlID0gdGhpcy5fc3Vic2NyaWJlKGNvbnRleHQpLmZpbmFsbHkoKCkgPT4ge1xuICAgICAgICB0aGlzLl9zdWJzY3JpYmVQcm9taXNlID0gbnVsbFxuICAgICAgfSlcbiAgICB9XG5cbiAgICBhd2FpdCB0aGlzLl9zdWJzY3JpYmVQcm9taXNlXG4gIH1cblxuICAvKipcbiAgICogQ29ubmVjdHMgdGhlIHdlYnNvY2tldCBjbGllbnQsIHN1YnNjcmliZXMgZXZlcnkgZGVyaXZlZCBjaGFubmVsLCBhbmQgd2FpdHNcbiAgICogZm9yIGVhY2ggc3Vic2NyaXB0aW9uJ3Mgc2VydmVyIGFja25vd2xlZGdlbWVudCBiZWZvcmUgdGhlIGdhcC1jbG9zaW5nIHB1bGwsXG4gICAqIHNvIG5vIGNoYW5nZSBjYW4gbGFuZCBiZXR3ZWVuIHRoZSBwdWxsIGFuZCB0aGUgc3Vic2NyaXB0aW9ucyBnb2luZyBsaXZlLlxuICAgKiBMb2NhbGx5IGNyZWF0ZWQgcmVzb3VyY2VzIGFyZSBvbmx5IHByb21vdGVkIHRvIHRoZSBicmlkZ2Ugb25jZSBldmVyeXRoaW5nXG4gICAqIGlzIGxpdmU7IGFuIHVuc3Vic2NyaWJlIGFycml2aW5nIGR1cmluZyBhbnkgYXdhaXQgbWFya3MgdGhpcyBhdHRlbXB0IHN0YWxlXG4gICAqIGFuZCBpdCB0ZWFycyBpdHMgb3duIHJlc291cmNlcyBkb3duIGluc3RlYWQgb2YgcmVzdWJzY3JpYmluZy5cbiAgICogQHBhcmFtIHs/fSBjb250ZXh0IC0gQXBwIGNvbnRleHQgcGFzc2VkIHRvIHRoZSBjaGFubmVscyBjYWxsYmFjay5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBfc3Vic2NyaWJlKGNvbnRleHQpIHtcbiAgICBjb25zdCBnZW5lcmF0aW9uID0gdGhpcy5fZ2VuZXJhdGlvblxuXG4gICAgdGhpcy5fc3RhdGUgPSBcInN1YnNjcmliaW5nXCJcblxuICAgIC8qKiBAdHlwZSB7QXJyYXk8e2NoYW5uZWw6IHN0cmluZywgcmVzb3VyY2VUeXBlOiBzdHJpbmcgfCBudWxsLCBzdWJzY3JpcHRpb246IGltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24tdHlwZXMuanNcIikuVmVsb2Npb3VzU3luY1JlYWx0aW1lU3Vic2NyaXB0aW9ufT59ICovXG4gICAgY29uc3QgY2hhbm5lbHMgPSBbXVxuICAgIC8qKiBAdHlwZSB7VmVsb2Npb3VzU3luY1JlYWx0aW1lV2Vic29ja2V0Q2xpZW50IHwgbnVsbH0gKi9cbiAgICBsZXQgY2xpZW50ID0gbnVsbFxuICAgIC8qKlxuICAgICAqIFRlYXJzIGRvd24gZXZlcnl0aGluZyB0aGlzIHN0YWxlL2ZhaWxlZCBzdWJzY3JpYmUgYXR0ZW1wdCBjcmVhdGVkIGl0c2VsZi5cbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn1cbiAgICAgKi9cbiAgICBjb25zdCB0ZWFyZG93biA9IGFzeW5jICgpID0+IHtcbiAgICAgIGZvciAoY29uc3Qge3N1YnNjcmlwdGlvbn0gb2YgY2hhbm5lbHMpIHtcbiAgICAgICAgc3Vic2NyaXB0aW9uLmNsb3NlKClcbiAgICAgIH1cblxuICAgICAgaWYgKGNsaWVudCkgYXdhaXQgY2xpZW50LmRpc2Nvbm5lY3RBbmRTdG9wUmVjb25uZWN0KClcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVhbHRpbWUgPSB0aGlzLnJlYWx0aW1lQ29uZmlndXJhdGlvbigpXG4gICAgICBjb25zdCBjaGFubmVsRGVzY3JpcHRvcnMgPSBhd2FpdCB0aGlzLmNoYW5uZWxEZXNjcmlwdG9ycyhjb250ZXh0KVxuXG4gICAgICBpZiAoZ2VuZXJhdGlvbiAhPT0gdGhpcy5fZ2VuZXJhdGlvbikgcmV0dXJuXG5cbiAgICAgIGNsaWVudCA9IGF3YWl0IHJlYWx0aW1lLmNyZWF0ZUNsaWVudCgpXG5cbiAgICAgIGlmIChnZW5lcmF0aW9uICE9PSB0aGlzLl9nZW5lcmF0aW9uKSByZXR1cm5cblxuICAgICAgYXdhaXQgY2xpZW50LmNvbm5lY3QoKVxuXG4gICAgICBpZiAoZ2VuZXJhdGlvbiAhPT0gdGhpcy5fZ2VuZXJhdGlvbikge1xuICAgICAgICBhd2FpdCB0ZWFyZG93bigpXG4gICAgICAgIHJldHVyblxuICAgICAgfVxuXG4gICAgICBjb25zdCBhdXRoZW50aWNhdGlvblRva2VuID0gYXdhaXQgdGhpcy5zeW5jQ2xpZW50LmNvbmZpZy5hdXRoZW50aWNhdGlvblRva2VuKClcblxuICAgICAgaWYgKGdlbmVyYXRpb24gIT09IHRoaXMuX2dlbmVyYXRpb24pIHtcbiAgICAgICAgYXdhaXQgdGVhcmRvd24oKVxuICAgICAgICByZXR1cm5cbiAgICAgIH1cblxuICAgICAgZm9yIChjb25zdCBjaGFubmVsRGVzY3JpcHRvciBvZiBjaGFubmVsRGVzY3JpcHRvcnMpIHtcbiAgICAgICAgaWYgKGNoYW5uZWxEZXNjcmlwdG9yLnBhcmFtcyAmJiBcImF1dGhlbnRpY2F0aW9uVG9rZW5cIiBpbiBjaGFubmVsRGVzY3JpcHRvci5wYXJhbXMpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFJlYWx0aW1lIGNoYW5uZWwgXCIke2NoYW5uZWxEZXNjcmlwdG9yLmNoYW5uZWx9XCIgcGFyYW1zIG11c3Qgbm90IGluY2x1ZGUgYXV0aGVudGljYXRpb25Ub2tlbiAtIHRoZSBmcmFtZXdvcmsgaW5qZWN0cyB0aGUgc3luYy5jbGllbnQgYXV0aGVudGljYXRpb25Ub2tlbiBhdXRvbWF0aWNhbGx5YClcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHJlc291cmNlVHlwZSA9IGNoYW5uZWxEZXNjcmlwdG9yLnJlc291cmNlVHlwZSA/PyBudWxsXG4gICAgICAgIGNvbnN0IHN1YnNjcmlwdGlvbiA9IGNsaWVudC5zdWJzY3JpYmVDaGFubmVsKGNoYW5uZWxEZXNjcmlwdG9yLmNoYW5uZWwsIHtcbiAgICAgICAgICBvbk1lc3NhZ2U6IChib2R5KSA9PiB0aGlzLmVucXVldWVBcHBseSh7Ym9keSwgcmVzb3VyY2VUeXBlfSksXG4gICAgICAgICAgb25SZXN1bWU6ICgpID0+IHRoaXMuc2NoZWR1bGVQdWxsKCksXG4gICAgICAgICAgcGFyYW1zOiB7Li4uY2hhbm5lbERlc2NyaXB0b3IucGFyYW1zLCBhdXRoZW50aWNhdGlvblRva2VufVxuICAgICAgICB9KVxuXG4gICAgICAgIGNoYW5uZWxzLnB1c2goe2NoYW5uZWw6IGNoYW5uZWxEZXNjcmlwdG9yLmNoYW5uZWwsIHJlc291cmNlVHlwZSwgc3Vic2NyaXB0aW9ufSlcbiAgICAgIH1cblxuICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoY2hhbm5lbHMubWFwKCh7c3Vic2NyaXB0aW9ufSkgPT4gc3Vic2NyaXB0aW9uLndhaXRGb3JSZWFkeSgpKSlcblxuICAgICAgaWYgKGdlbmVyYXRpb24gIT09IHRoaXMuX2dlbmVyYXRpb24pIHtcbiAgICAgICAgYXdhaXQgdGVhcmRvd24oKVxuICAgICAgICByZXR1cm5cbiAgICAgIH1cblxuICAgICAgdGhpcy5fY2hhbm5lbHMgPSBjaGFubmVsc1xuICAgICAgdGhpcy5fY2xpZW50ID0gY2xpZW50XG4gICAgICB0aGlzLl9zdGF0ZSA9IFwic3Vic2NyaWJlZFwiXG4gICAgICB0aGlzLnNjaGVkdWxlUHVsbCgpXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGF3YWl0IHRlYXJkb3duKClcblxuICAgICAgaWYgKGdlbmVyYXRpb24gPT09IHRoaXMuX2dlbmVyYXRpb24pIHRoaXMuX3N0YXRlID0gXCJ1bnN1YnNjcmliZWRcIlxuXG4gICAgICB0aHJvdyBlcnJvclxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDbG9zZXMgZXZlcnkgY2hhbm5lbCBzdWJzY3JpcHRpb24gYW5kIGRpc2Nvbm5lY3RzIHRoZSB3ZWJzb2NrZXQgY2xpZW50XG4gICAqIChpZGVtcG90ZW50KS4gQWxzbyBtYXJrcyBhbnkgaW4tZmxpZ2h0IHN1YnNjcmliZSBhdHRlbXB0IHN0YWxlIHNvIGl0IHRlYXJzXG4gICAqIGl0c2VsZiBkb3duIGluc3RlYWQgb2YgZmluaXNoaW5nIHRoZSBzdWJzY3JpcHRpb24gYWZ0ZXJ3YXJkcy5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyB1bnN1YnNjcmliZSgpIHtcbiAgICB0aGlzLl9nZW5lcmF0aW9uICs9IDFcblxuICAgIGNvbnN0IGNoYW5uZWxzID0gdGhpcy5fY2hhbm5lbHNcbiAgICBjb25zdCBjbGllbnQgPSB0aGlzLl9jbGllbnRcblxuICAgIHRoaXMuX2NoYW5uZWxzID0gW11cbiAgICB0aGlzLl9jbGllbnQgPSBudWxsXG4gICAgdGhpcy5fc3RhdGUgPSBcInVuc3Vic2NyaWJlZFwiXG5cbiAgICBmb3IgKGNvbnN0IHtzdWJzY3JpcHRpb259IG9mIGNoYW5uZWxzKSB7XG4gICAgICBzdWJzY3JpcHRpb24uY2xvc2UoKVxuICAgIH1cblxuICAgIGlmIChjbGllbnQpIGF3YWl0IGNsaWVudC5kaXNjb25uZWN0QW5kU3RvcFJlY29ubmVjdCgpXG4gIH1cblxuICAvKipcbiAgICogUmVwb3J0cyB0aGUgYnJpZGdlIHN1YnNjcmlwdGlvbiBzdGF0ZSBhbmQgcGVyLWNoYW5uZWwgcmVhZGluZXNzLlxuICAgKiBAcmV0dXJucyB7e2NoYW5uZWxzOiBBcnJheTx7Y2hhbm5lbDogc3RyaW5nLCByZWFkeTogYm9vbGVhbiwgcmVzb3VyY2VUeXBlOiBzdHJpbmcgfCBudWxsfT4sIHN0YXRlOiBcInN1YnNjcmliZWRcIiB8IFwic3Vic2NyaWJpbmdcIiB8IFwidW5zdWJzY3JpYmVkXCJ9fSBSZWFsdGltZSBzdGF0dXMuXG4gICAqL1xuICBzdGF0dXMoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGNoYW5uZWxzOiB0aGlzLl9jaGFubmVscy5tYXAoKHtjaGFubmVsLCByZXNvdXJjZVR5cGUsIHN1YnNjcmlwdGlvbn0pID0+ICh7Y2hhbm5lbCwgcmVhZHk6IHN1YnNjcmlwdGlvbi5pc1JlYWR5KCksIHJlc291cmNlVHlwZX0pKSxcbiAgICAgIHN0YXRlOiB0aGlzLl9zdGF0ZVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBBd2FpdHMgYWxsIGVucXVldWVkIG1lc3NhZ2UgYXBwbGllcyBhbmQgYW55IHNjaGVkdWxlZCBwdWxsICh0ZXN0cywgc2h1dGRvd24gZmxvd3MpLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIHdhaXRGb3JBcHBsaWVkKCkge1xuICAgIGF3YWl0IHRoaXMuX2FwcGx5UHJvbWlzZVxuICAgIGlmICh0aGlzLl9zY2hlZHVsZWRQdWxsKSBhd2FpdCB0aGlzLl9zY2hlZHVsZWRQdWxsXG4gIH1cblxuICAvKipcbiAgICogUmVzb2x2ZXMgdGhlIHJlYWx0aW1lIGNvbmZpZ3VyYXRpb24sIGZhaWxpbmcgbG91ZGx5IHdoZW4gaXQgaXMgbWlzc2luZy5cbiAgICogQHJldHVybnMge2ltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24tdHlwZXMuanNcIikuVmVsb2Npb3VzU3luY0NsaWVudFJlYWx0aW1lQ29uZmlndXJhdGlvbn0gUmVhbHRpbWUgY29uZmlndXJhdGlvbi5cbiAgICovXG4gIHJlYWx0aW1lQ29uZmlndXJhdGlvbigpIHtcbiAgICBjb25zdCByZWFsdGltZSA9IHRoaXMuc3luY0NsaWVudC5jb25maWcucmVhbHRpbWVcblxuICAgIGlmICghcmVhbHRpbWUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcInN1YnNjcmliZVJlYWx0aW1lIHJlcXVpcmVzIGEgc3luYy5jbGllbnQucmVhbHRpbWUgY29uZmlndXJhdGlvbiBibG9jayB3aXRoIGEgY3JlYXRlQ2xpZW50IGNhbGxiYWNrXCIpXG4gICAgfVxuXG4gICAgcmV0dXJuIHJlYWx0aW1lXG4gIH1cblxuICAvKipcbiAgICogRGVyaXZlcyB0aGUgY2hhbm5lbCBkZXNjcmlwdG9ycyB0byBzdWJzY3JpYmU6IG9uZSBmcmFtZXdvcmsgc3luYyBjaGFubmVsXG4gICAqIHN1YnNjcmlwdGlvbiBwZXIgZGVjbGFyZWQgcHVsbCBzY29wZSAodGhlIHBhcmFtcyBtaXJyb3IgdGhlIHNjb3BlJ3NcbiAgICogYHtyZXNvdXJjZVR5cGUsIGNvbmRpdGlvbnN9YCksIHBsdXMgdGhlIGRlcHJlY2F0ZWQgbGVnYWN5IHBhdGhzIOKAlFxuICAgKiBtb2RlbC1sZXZlbCBzdGF0aWMgcmVhbHRpbWUgZGVjbGFyYXRpb25zIGFuZCB0aGUgY29uZmlnIGNoYW5uZWxzIGNhbGxiYWNrLlxuICAgKiBGYWlscyBsb3VkbHkgd2hlbiBub3RoaW5nIGlzIHN1YnNjcmliYWJsZS5cbiAgICogQHBhcmFtIHs/fSBjb250ZXh0IC0gQXBwIGNvbnRleHQgcGFzc2VkIHRvIHRoZSBkZXByZWNhdGVkIGNoYW5uZWxzIGNhbGxiYWNrLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxBcnJheTxWZWxvY2lvdXNTeW5jUmVhbHRpbWVDaGFubmVsRGVzY3JpcHRvcj4+fSBDaGFubmVsIGRlc2NyaXB0b3JzLlxuICAgKi9cbiAgYXN5bmMgY2hhbm5lbERlc2NyaXB0b3JzKGNvbnRleHQpIHtcbiAgICBjb25zdCByZWFsdGltZSA9IHRoaXMucmVhbHRpbWVDb25maWd1cmF0aW9uKClcbiAgICAvKiogQHR5cGUge0FycmF5PFZlbG9jaW91c1N5bmNSZWFsdGltZUNoYW5uZWxEZXNjcmlwdG9yPn0gKi9cbiAgICBjb25zdCBjaGFubmVsRGVzY3JpcHRvcnMgPSBbXVxuXG4gICAgZm9yIChjb25zdCBzY29wZVJvdyBvZiBhd2FpdCB0aGlzLnN5bmNDbGllbnQuc2NvcGVTdG9yZSgpLmFjdGl2ZVNjb3BlcygpKSB7XG4gICAgICBjaGFubmVsRGVzY3JpcHRvcnMucHVzaCh7XG4gICAgICAgIGNoYW5uZWw6IFZFTE9DSU9VU19TWU5DX0NIQU5ORUwsXG4gICAgICAgIHBhcmFtczoge2NvbmRpdGlvbnM6IHRoaXMuYXR0cmlidXRlTmFtZWRDb25kaXRpb25zKHNjb3BlUm93KSwgcmVzb3VyY2VUeXBlOiBzY29wZVJvdy5yZXNvdXJjZVR5cGV9XG4gICAgICB9KVxuICAgIH1cblxuICAgIGZvciAoY29uc3QgW3Jlc291cmNlVHlwZSwgcmVzb3VyY2VDb25maWddIG9mIE9iamVjdC5lbnRyaWVzKHRoaXMuc3luY0NsaWVudC5jb25maWcucmVzb3VyY2VzKSkge1xuICAgICAgaWYgKCFyZXNvdXJjZUNvbmZpZy5yZWFsdGltZSkgY29udGludWVcblxuICAgICAgY2hhbm5lbERlc2NyaXB0b3JzLnB1c2goe2NoYW5uZWw6IHJlc291cmNlQ29uZmlnLnJlYWx0aW1lLmNoYW5uZWwsIHBhcmFtczogcmVzb3VyY2VDb25maWcucmVhbHRpbWUucGFyYW1zLCByZXNvdXJjZVR5cGV9KVxuICAgIH1cblxuICAgIGlmIChyZWFsdGltZS5jaGFubmVscykge1xuICAgICAgY2hhbm5lbERlc2NyaXB0b3JzLnB1c2goLi4uYXdhaXQgcmVhbHRpbWUuY2hhbm5lbHMoY29udGV4dCkpXG4gICAgfVxuXG4gICAgaWYgKGNoYW5uZWxEZXNjcmlwdG9ycy5sZW5ndGggPT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcInN1YnNjcmliZVJlYWx0aW1lIGZvdW5kIG5vIGNoYW5uZWxzIHRvIHN1YnNjcmliZSAtIGRlY2xhcmUgYSBzeW5jIHNjb3BlIChzeW5jQ2xpZW50KCkuc3luYyhxdWVyeSkpIHNvIGl0cyBmcmFtZXdvcmsgc3luYyBjaGFubmVsIHN1YnNjcmlwdGlvbiBjYW4gYmUgZGVyaXZlZCwgb3IgdGhlIGRlcHJlY2F0ZWQgc3luYy5jbGllbnQucmVhbHRpbWUuY2hhbm5lbHMgY2FsbGJhY2tcIilcbiAgICB9XG5cbiAgICByZXR1cm4gY2hhbm5lbERlc2NyaXB0b3JzXG4gIH1cblxuICAvKipcbiAgICogVHJhbnNsYXRlcyBhIHBlcnNpc3RlZCBzY29wZSdzIGNvbmRpdGlvbiBrZXlzIHRvIHRoZSBtb2RlbCdzIGF0dHJpYnV0ZVxuICAgKiBuYW1lcyBzbyB0aGUgZnJhbWV3b3JrIGNoYW5uZWwgc3Vic2NyaXB0aW9uIG1hdGNoZXMgdGhlIHB1Ymxpc2hlcidzXG4gICAqIGF0dHJpYnV0ZS1uYW1lZCBzY29waW5nIHBhcmFtczogYHNlcmlhbGl6ZWRTY29wZUZyb21RdWVyeWAgcGVyc2lzdHMgdGhlXG4gICAqIHF1ZXJ5J3MgbW9kZWwtbm9ybWFsaXplZCBjb2x1bW4gbmFtZXMgKGZvciBleGFtcGxlIGBwcm9qZWN0X2lkYCksIHdoaWxlXG4gICAqIHNjb3BlLXBhcnRpdGlvbiBicm9hZGNhc3RzIGNhcnJ5IGF0dHJpYnV0ZSBuYW1lcyAoYHByb2plY3RJZGApLiBLZXlzXG4gICAqIHdpdGhvdXQgYSBjb2x1bW4gbWFwcGluZyBhcmUgYWxyZWFkeSBhdHRyaWJ1dGUgbmFtZXMgYW5kIHBhc3MgdGhyb3VnaDtcbiAgICogc2NvcGVzIG9uIG1vZGVscyB3aXRob3V0IGEgZGVjbGFyZWQgc3luYyByZXNvdXJjZSBmYWlsIGxvdWRseSBiZWNhdXNlIG5vXG4gICAqIGF0dHJpYnV0ZSBtYXBwaW5nIGV4aXN0cyBmb3IgdGhlbS5cbiAgICogQHBhcmFtIHt7Y29uZGl0aW9uczogUmVjb3JkPHN0cmluZywgPz4sIHJlc291cmNlVHlwZTogc3RyaW5nfX0gc2NvcGVSb3cgLSBBY3RpdmUgc2NvcGUgcm93LlxuICAgKiBAcmV0dXJucyB7UmVjb3JkPHN0cmluZywgPz59IEF0dHJpYnV0ZS1uYW1lZCBzY29wZSBjb25kaXRpb25zLlxuICAgKi9cbiAgYXR0cmlidXRlTmFtZWRDb25kaXRpb25zKHNjb3BlUm93KSB7XG4gICAgY29uc3QgcmVzb3VyY2VDb25maWcgPSB0aGlzLnN5bmNDbGllbnQuY29uZmlnLnJlc291cmNlc1tzY29wZVJvdy5yZXNvdXJjZVR5cGVdXG5cbiAgICBpZiAoIXJlc291cmNlQ29uZmlnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYHN1YnNjcmliZVJlYWx0aW1lIGNhbid0IGRlcml2ZSBhdHRyaWJ1dGUgbmFtZXMgZm9yIHRoZSBzeW5jIHNjb3BlIGRlY2xhcmVkIG9uICR7c2NvcGVSb3cucmVzb3VyY2VUeXBlfSAtIGRlY2xhcmUgc3RhdGljIHN5bmMgb24gdGhhdCBtb2RlbCBzbyBpdHMgcmVzb3VyY2UgaXMgcmVnaXN0ZXJlZGApXG4gICAgfVxuXG4gICAgY29uc3QgY29sdW1uTmFtZVRvQXR0cmlidXRlTmFtZSA9IHJlc291cmNlQ29uZmlnLm1vZGVsQ2xhc3MuZ2V0Q29sdW1uTmFtZVRvQXR0cmlidXRlTmFtZU1hcCgpXG4gICAgLyoqIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gKi9cbiAgICBjb25zdCBjb25kaXRpb25zID0ge31cblxuICAgIGZvciAoY29uc3QgW2NvbmRpdGlvbk5hbWUsIGNvbmRpdGlvblZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhzY29wZVJvdy5jb25kaXRpb25zKSkge1xuICAgICAgY29uZGl0aW9uc1tjb2x1bW5OYW1lVG9BdHRyaWJ1dGVOYW1lW2NvbmRpdGlvbk5hbWVdIHx8IGNvbmRpdGlvbk5hbWVdID0gY29uZGl0aW9uVmFsdWVcbiAgICB9XG5cbiAgICByZXR1cm4gY29uZGl0aW9uc1xuICB9XG5cbiAgLyoqXG4gICAqIENoYWlucyBvbmUgcHVzaGVkIG1lc3NhZ2Ugb250byB0aGUgc2VyaWFsaXplZCBhcHBseSBxdWV1ZSBzbyBjaGFuZ2VzIGFwcGx5XG4gICAqIGluIGFycml2YWwgb3JkZXI7IGZhaWx1cmVzIGdvIHRvIHRoZSBzeW5jIGNsaWVudCdzIGVycm9yIHJlcG9ydGluZy5cbiAgICogQHBhcmFtIHt7Ym9keTogPywgcmVzb3VyY2VUeXBlOiBzdHJpbmcgfCBudWxsfX0gYXJncyAtIE1lc3NhZ2UgYXJncy5cbiAgICogQHJldHVybnMge3ZvaWR9XG4gICAqL1xuICBlbnF1ZXVlQXBwbHkoe2JvZHksIHJlc291cmNlVHlwZX0pIHtcbiAgICB0aGlzLl9hcHBseVByb21pc2UgPSB0aGlzLl9hcHBseVByb21pc2UudGhlbihhc3luYyAoKSA9PiB7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCB0aGlzLmFwcGx5TWVzc2FnZSh7Ym9keSwgcmVzb3VyY2VUeXBlfSlcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIHRoaXMuc3luY0NsaWVudC5yZXBvcnRFcnJvcigvKiogQHR5cGUge0Vycm9yfSAqLyAoZXJyb3IpKVxuICAgICAgfVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogQXBwbGllcyBvbmUgcHVzaGVkIG1lc3NhZ2UgdGhyb3VnaCB0aGUgZGVyaXZlZCByZXNvdXJjZSBhcHBsaWVyOiBkcm9wc1xuICAgKiBvd24tZGV2aWNlIG1lc3NhZ2VzIGJ5IGVjaG8gb3JpZ2luLCBkZWZhdWx0cyB0aGUgY2hhbm5lbCdzIHJlc291cmNlVHlwZSBvbnRvXG4gICAqIGVudmVsb3BlcyB3aXRob3V0IG9uZSwgYW5kIGZhaWxzIGxvdWRseSBvbiB1bmtub3duIHJlc291cmNlIHR5cGVzLlxuICAgKiBAcGFyYW0ge3tib2R5OiA/LCByZXNvdXJjZVR5cGU6IHN0cmluZyB8IG51bGx9fSBhcmdzIC0gTWVzc2FnZSBhcmdzLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIGFwcGx5TWVzc2FnZSh7Ym9keSwgcmVzb3VyY2VUeXBlfSkge1xuICAgIGlmICghYm9keSB8fCB0eXBlb2YgYm9keSAhPT0gXCJvYmplY3RcIiB8fCBBcnJheS5pc0FycmF5KGJvZHkpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFJlYWx0aW1lIHN5bmMgbWVzc2FnZXMgbXVzdCBiZSBlbnZlbG9wZSBvYmplY3RzLCBnb3Q6ICR7SlNPTi5zdHJpbmdpZnkoYm9keSl9YClcbiAgICB9XG5cbiAgICBjb25zdCByZWFsdGltZSA9IHRoaXMucmVhbHRpbWVDb25maWd1cmF0aW9uKClcblxuICAgIGlmIChyZWFsdGltZS5sb2NhbE9yaWdpbiAmJiBib2R5LmVjaG9PcmlnaW4gIT09IHVuZGVmaW5lZCAmJiBib2R5LmVjaG9PcmlnaW4gIT09IG51bGwpIHtcbiAgICAgIGNvbnN0IGxvY2FsT3JpZ2luID0gU3RyaW5nKGF3YWl0IHJlYWx0aW1lLmxvY2FsT3JpZ2luKCkpXG5cbiAgICAgIGlmIChTdHJpbmcoYm9keS5lY2hvT3JpZ2luKSA9PT0gbG9jYWxPcmlnaW4pIHJldHVyblxuICAgIH1cblxuICAgIGNvbnN0IHN5bmNQYXlsb2FkcyA9IEFycmF5LmlzQXJyYXkoYm9keS5zeW5jcykgPyBib2R5LnN5bmNzIDogW2JvZHldXG4gICAgY29uc3QgYXBwbHlTeW5jID0gdGhpcy5zeW5jQ2xpZW50LnJlbW90ZUFwcGx5U3luYyh7c291cmNlOiBcInJlbW90ZSBjaGFuZ2VcIn0pXG5cbiAgICBmb3IgKGNvbnN0IHN5bmNQYXlsb2FkIG9mIHN5bmNQYXlsb2Fkcykge1xuICAgICAgY29uc3Qgc3luYyA9IFN5bmNBcGlDbGllbnQuc3luY0VudmVsb3BlRnJvbVBheWxvYWQoe3Jlc291cmNlVHlwZSwgLi4uc3luY1BheWxvYWR9KVxuXG4gICAgICBhd2FpdCBhcHBseVN5bmMoc3luYylcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU2NoZWR1bGVzIGEgY29hbGVzY2VkIGJhY2tncm91bmQgcHVsbCBjbG9zaW5nIG9mZmxpbmUgZ2FwcyBhZnRlclxuICAgKiAocmUpc3Vic2NyaXB0aW9uIHJlYWRpbmVzcy4gUmVzdW1lcyBhcnJpdmluZyB3aGlsZSBhIHB1bGwgaXMgYWxyZWFkeVxuICAgKiBzY2hlZHVsZWQgb3IgaW4gZmxpZ2h0IGNvYWxlc2NlIGludG8gdGhhdCBwdWxsIGluc3RlYWQgb2Ygc3RhY2tpbmcuXG4gICAqIEByZXR1cm5zIHt2b2lkfVxuICAgKi9cbiAgc2NoZWR1bGVQdWxsKCkge1xuICAgIGlmICh0aGlzLnJlYWx0aW1lQ29uZmlndXJhdGlvbigpLnB1bGxPblJlY29ubmVjdCA9PT0gZmFsc2UpIHJldHVyblxuXG4gICAgdGhpcy5fc2NoZWR1bGVkUHVsbCB8fD0gKGFzeW5jICgpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRoaXMuc3luY0NsaWVudC5wdWxsKClcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIHRoaXMuc3luY0NsaWVudC5yZXBvcnRFcnJvcigvKiogQHR5cGUge0Vycm9yfSAqLyAoZXJyb3IpKVxuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgdGhpcy5fc2NoZWR1bGVkUHVsbCA9IG51bGxcbiAgICAgIH1cbiAgICB9KSgpXG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Reads and validates a sync/change model's declared scope-partition
3
+ * attributes (`static syncScopeAttributes`).
4
+ *
5
+ * The declaration names the attribute(s) partitioning the app's sync feed —
6
+ * the same attribute names client pull scopes use as conditions (for example
7
+ * `["eventId"]` or `["accountId"]`). The publisher persists them onto every
8
+ * published sync row and broadcasts them as the framework sync channel's
9
+ * scoping params, and the change feed serializes them onto every changes row
10
+ * under their own names. Velocious itself has no built-in partition name.
11
+ * @param {?} syncModel - Sync/change model class.
12
+ * @returns {string[] | null} Declared scope attributes, or null when the model declares none.
13
+ */
14
+ export function declaredSyncScopeAttributes(syncModel: unknown): string[] | null;
15
+ //# sourceMappingURL=sync-scope-attributes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-scope-attributes.d.ts","sourceRoot":"","sources":["../../../src/sync/sync-scope-attributes.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AACH,uDAHW,OAAC,GACC,MAAM,EAAE,GAAG,IAAI,CAY3B"}
@@ -0,0 +1,24 @@
1
+ // @ts-check
2
+ /**
3
+ * Reads and validates a sync/change model's declared scope-partition
4
+ * attributes (`static syncScopeAttributes`).
5
+ *
6
+ * The declaration names the attribute(s) partitioning the app's sync feed —
7
+ * the same attribute names client pull scopes use as conditions (for example
8
+ * `["eventId"]` or `["accountId"]`). The publisher persists them onto every
9
+ * published sync row and broadcasts them as the framework sync channel's
10
+ * scoping params, and the change feed serializes them onto every changes row
11
+ * under their own names. Velocious itself has no built-in partition name.
12
+ * @param {?} syncModel - Sync/change model class.
13
+ * @returns {string[] | null} Declared scope attributes, or null when the model declares none.
14
+ */
15
+ export function declaredSyncScopeAttributes(syncModel) {
16
+ const declared = syncModel.syncScopeAttributes;
17
+ if (declared === undefined || declared === null)
18
+ return null;
19
+ if (!Array.isArray(declared) || declared.length === 0 || declared.some((attributeName) => typeof attributeName !== "string" || !attributeName)) {
20
+ throw new Error(`${syncModel.name} static syncScopeAttributes must be a non-empty array of attribute-name strings, got: ${String(declared)}`);
21
+ }
22
+ return declared;
23
+ }
24
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luYy1zY29wZS1hdHRyaWJ1dGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3N5bmMvc3luYy1zY29wZS1hdHRyaWJ1dGVzLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWjs7Ozs7Ozs7Ozs7O0dBWUc7QUFDSCxNQUFNLFVBQVUsMkJBQTJCLENBQUMsU0FBUztJQUNuRCxNQUFNLFFBQVEsR0FBRyxTQUFTLENBQUMsbUJBQW1CLENBQUE7SUFFOUMsSUFBSSxRQUFRLEtBQUssU0FBUyxJQUFJLFFBQVEsS0FBSyxJQUFJO1FBQUUsT0FBTyxJQUFJLENBQUE7SUFFNUQsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxDQUFDLElBQUksUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLGFBQWEsRUFBRSxFQUFFLENBQUMsT0FBTyxhQUFhLEtBQUssUUFBUSxJQUFJLENBQUMsYUFBYSxDQUFDLEVBQUUsQ0FBQztRQUMvSSxNQUFNLElBQUksS0FBSyxDQUFDLEdBQUcsU0FBUyxDQUFDLElBQUkseUZBQXlGLE1BQU0sQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUE7SUFDL0ksQ0FBQztJQUVELE9BQU8sUUFBUSxDQUFBO0FBQ2pCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBAdHMtY2hlY2tcblxuLyoqXG4gKiBSZWFkcyBhbmQgdmFsaWRhdGVzIGEgc3luYy9jaGFuZ2UgbW9kZWwncyBkZWNsYXJlZCBzY29wZS1wYXJ0aXRpb25cbiAqIGF0dHJpYnV0ZXMgKGBzdGF0aWMgc3luY1Njb3BlQXR0cmlidXRlc2ApLlxuICpcbiAqIFRoZSBkZWNsYXJhdGlvbiBuYW1lcyB0aGUgYXR0cmlidXRlKHMpIHBhcnRpdGlvbmluZyB0aGUgYXBwJ3Mgc3luYyBmZWVkIOKAlFxuICogdGhlIHNhbWUgYXR0cmlidXRlIG5hbWVzIGNsaWVudCBwdWxsIHNjb3BlcyB1c2UgYXMgY29uZGl0aW9ucyAoZm9yIGV4YW1wbGVcbiAqIGBbXCJldmVudElkXCJdYCBvciBgW1wiYWNjb3VudElkXCJdYCkuIFRoZSBwdWJsaXNoZXIgcGVyc2lzdHMgdGhlbSBvbnRvIGV2ZXJ5XG4gKiBwdWJsaXNoZWQgc3luYyByb3cgYW5kIGJyb2FkY2FzdHMgdGhlbSBhcyB0aGUgZnJhbWV3b3JrIHN5bmMgY2hhbm5lbCdzXG4gKiBzY29waW5nIHBhcmFtcywgYW5kIHRoZSBjaGFuZ2UgZmVlZCBzZXJpYWxpemVzIHRoZW0gb250byBldmVyeSBjaGFuZ2VzIHJvd1xuICogdW5kZXIgdGhlaXIgb3duIG5hbWVzLiBWZWxvY2lvdXMgaXRzZWxmIGhhcyBubyBidWlsdC1pbiBwYXJ0aXRpb24gbmFtZS5cbiAqIEBwYXJhbSB7P30gc3luY01vZGVsIC0gU3luYy9jaGFuZ2UgbW9kZWwgY2xhc3MuXG4gKiBAcmV0dXJucyB7c3RyaW5nW10gfCBudWxsfSBEZWNsYXJlZCBzY29wZSBhdHRyaWJ1dGVzLCBvciBudWxsIHdoZW4gdGhlIG1vZGVsIGRlY2xhcmVzIG5vbmUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkZWNsYXJlZFN5bmNTY29wZUF0dHJpYnV0ZXMoc3luY01vZGVsKSB7XG4gIGNvbnN0IGRlY2xhcmVkID0gc3luY01vZGVsLnN5bmNTY29wZUF0dHJpYnV0ZXNcblxuICBpZiAoZGVjbGFyZWQgPT09IHVuZGVmaW5lZCB8fCBkZWNsYXJlZCA9PT0gbnVsbCkgcmV0dXJuIG51bGxcblxuICBpZiAoIUFycmF5LmlzQXJyYXkoZGVjbGFyZWQpIHx8IGRlY2xhcmVkLmxlbmd0aCA9PT0gMCB8fCBkZWNsYXJlZC5zb21lKChhdHRyaWJ1dGVOYW1lKSA9PiB0eXBlb2YgYXR0cmlidXRlTmFtZSAhPT0gXCJzdHJpbmdcIiB8fCAhYXR0cmlidXRlTmFtZSkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYCR7c3luY01vZGVsLm5hbWV9IHN0YXRpYyBzeW5jU2NvcGVBdHRyaWJ1dGVzIG11c3QgYmUgYSBub24tZW1wdHkgYXJyYXkgb2YgYXR0cmlidXRlLW5hbWUgc3RyaW5ncywgZ290OiAke1N0cmluZyhkZWNsYXJlZCl9YClcbiAgfVxuXG4gIHJldHVybiBkZWNsYXJlZFxufVxuIl19
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Framework-owned websocket channel for synced resources
3
+ * ({@link VELOCIOUS_SYNC_CHANNEL}).
4
+ *
5
+ * Subscribe params mirror a declared pull scope — `{resourceType, conditions}`
6
+ * plus the client-injected `authenticationToken` — and subscribe-time
7
+ * authorization delegates to the app sync resource's existing
8
+ * `authorizeChanges({params, scope})` (the `sync.api.resourceClass`), so apps
9
+ * hook in through the authorization they already declared instead of writing
10
+ * their own channel classes. Broadcast routing matches the publisher's
11
+ * scoping params against the subscription's scope conditions.
12
+ */
13
+ export default class SyncWebsocketChannel extends VelociousWebsocketChannel {
14
+ /**
15
+ * Registers the framework sync channel on a configuration declaring a
16
+ * `sync.api` block (guarded so repeated server boots with the same
17
+ * configuration register it only once). No-op without `sync.api` — the
18
+ * channel authorizes through the app's sync resource class.
19
+ * @param {import("../configuration.js").default} configuration - Configuration instance.
20
+ * @returns {void}
21
+ */
22
+ static registerFromConfiguration(configuration: import("../configuration.js").default): void;
23
+ /**
24
+ * Scope the subscription was authorized for, set by {@link SyncWebsocketChannel#canSubscribe}.
25
+ * @type {import("./sync-resource-base.js").SerializedChangesScope | null}
26
+ */
27
+ _scope: import("./sync-resource-base.js").SerializedChangesScope | null;
28
+ /**
29
+ * Authorizes the subscription through the app sync resource: the subscribe
30
+ * params are parsed into the same serialized scope the changes endpoint
31
+ * consumes and passed to the resource's `authorizeChanges({params, scope})`.
32
+ * Denials and malformed scopes throw, rejecting the subscription.
33
+ * @returns {Promise<boolean>} Whether the subscription is allowed.
34
+ */
35
+ canSubscribe(): Promise<boolean>;
36
+ /**
37
+ * Builds the app sync resource authorizing this subscription, mirroring the
38
+ * sync transport controller's resource construction with the ability
39
+ * resolved from the subscribe params (which carry the client-injected
40
+ * authenticationToken).
41
+ * @returns {Promise<import("./sync-resource-base.js").default>} App sync resource instance.
42
+ */
43
+ buildSyncResource(): Promise<import("./sync-resource-base.js").default>;
44
+ /**
45
+ * Routes a publisher broadcast to this subscription when the published
46
+ * resource type equals the type the subscription was authorized for and the
47
+ * scoping params satisfy every scope condition: each condition key must be
48
+ * present in the broadcast params and match by string comparison (array
49
+ * conditions match by membership). Broadcasts without a resource type and
50
+ * conditions the publisher's scoping params do not carry never match, so a
51
+ * subscription cannot receive changes outside its authorized scope.
52
+ * @param {import("../http-server/websocket-channel.js").WebsocketJsonValue} broadcastParams - Publisher scoping params (the published resourceType plus the change's scope-partition values).
53
+ * @returns {boolean} Whether the broadcast belongs to this subscription's scope.
54
+ */
55
+ matches(broadcastParams: import("../http-server/websocket-channel.js").WebsocketJsonValue): boolean;
56
+ }
57
+ import VelociousWebsocketChannel from "../http-server/websocket-channel.js";
58
+ //# sourceMappingURL=sync-websocket-channel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-websocket-channel.d.ts","sourceRoot":"","sources":["../../../src/sync/sync-websocket-channel.js"],"names":[],"mappings":"AAQA;;;;;;;;;;;GAWG;AACH;IAOE;;;;;;;OAOG;IACH,gDAHW,OAAO,qBAAqB,EAAE,OAAO,GACnC,IAAI,CAOhB;IAnBD;;;OAGG;IACH,QAFU,OAAO,yBAAyB,EAAE,sBAAsB,GAAG,IAAI,CAE5D;IAiBb;;;;;;OAMG;IACH,gBAFa,OAAO,CAAC,OAAO,CAAC,CAW5B;IAED;;;;;;OAMG;IACH,qBAFa,OAAO,CAAC,OAAO,yBAAyB,EAAE,OAAO,CAAC,CAkC9D;IAED;;;;;;;;;;OAUG;IACH,yBAHW,OAAO,qCAAqC,EAAE,kBAAkB,GAC9D,OAAO,CA0BnB;CASF;sCA/IqC,qCAAqC"}
@@ -0,0 +1,131 @@
1
+ // @ts-check
2
+ import VelociousWebsocketChannel from "../http-server/websocket-channel.js";
3
+ import { VELOCIOUS_SYNC_CHANNEL } from "./sync-channel-name.js";
4
+ /** Configurations whose framework sync channel has already been registered. */
5
+ const registeredConfigurations = new WeakSet();
6
+ /**
7
+ * Framework-owned websocket channel for synced resources
8
+ * ({@link VELOCIOUS_SYNC_CHANNEL}).
9
+ *
10
+ * Subscribe params mirror a declared pull scope — `{resourceType, conditions}`
11
+ * plus the client-injected `authenticationToken` — and subscribe-time
12
+ * authorization delegates to the app sync resource's existing
13
+ * `authorizeChanges({params, scope})` (the `sync.api.resourceClass`), so apps
14
+ * hook in through the authorization they already declared instead of writing
15
+ * their own channel classes. Broadcast routing matches the publisher's
16
+ * scoping params against the subscription's scope conditions.
17
+ */
18
+ export default class SyncWebsocketChannel extends VelociousWebsocketChannel {
19
+ /**
20
+ * Scope the subscription was authorized for, set by {@link SyncWebsocketChannel#canSubscribe}.
21
+ * @type {import("./sync-resource-base.js").SerializedChangesScope | null}
22
+ */
23
+ _scope = null;
24
+ /**
25
+ * Registers the framework sync channel on a configuration declaring a
26
+ * `sync.api` block (guarded so repeated server boots with the same
27
+ * configuration register it only once). No-op without `sync.api` — the
28
+ * channel authorizes through the app's sync resource class.
29
+ * @param {import("../configuration.js").default} configuration - Configuration instance.
30
+ * @returns {void}
31
+ */
32
+ static registerFromConfiguration(configuration) {
33
+ if (!configuration.getSyncConfiguration().api || registeredConfigurations.has(configuration))
34
+ return;
35
+ registeredConfigurations.add(configuration);
36
+ configuration.registerWebsocketChannel(VELOCIOUS_SYNC_CHANNEL, this);
37
+ }
38
+ /**
39
+ * Authorizes the subscription through the app sync resource: the subscribe
40
+ * params are parsed into the same serialized scope the changes endpoint
41
+ * consumes and passed to the resource's `authorizeChanges({params, scope})`.
42
+ * Denials and malformed scopes throw, rejecting the subscription.
43
+ * @returns {Promise<boolean>} Whether the subscription is allowed.
44
+ */
45
+ async canSubscribe() {
46
+ const resource = await this.buildSyncResource();
47
+ const scope = resource.changesScope({ scope: { conditions: this.params.conditions, resourceType: this.params.resourceType } });
48
+ await resource.authorizeChanges({ params: this.params, scope });
49
+ this._scope = scope;
50
+ return true;
51
+ }
52
+ /**
53
+ * Builds the app sync resource authorizing this subscription, mirroring the
54
+ * sync transport controller's resource construction with the ability
55
+ * resolved from the subscribe params (which carry the client-injected
56
+ * authenticationToken).
57
+ * @returns {Promise<import("./sync-resource-base.js").default>} App sync resource instance.
58
+ */
59
+ async buildSyncResource() {
60
+ const configuration = this.session.configuration;
61
+ const api = configuration.getSyncConfiguration().api;
62
+ if (!api) {
63
+ throw new Error(`The ${VELOCIOUS_SYNC_CHANNEL} channel requires a sync.api configuration block with the app's sync resource class`);
64
+ }
65
+ // Narrows the configured resource class to the sync resource contract
66
+ // (changesScope/authorizeChanges) the sync.api validation requires.
67
+ const ResourceClass = /** @type {typeof import("./sync-resource-base.js").default} */ (api.resourceClass);
68
+ // Narrows the websocket subscribe params to the resource params contract.
69
+ const params = /** @type {import("../configuration-types.js").VelociousParams} */ ( /** @type {unknown} */(this.params));
70
+ const request = this.session.upgradeRequest;
71
+ const ability = await configuration.resolveAbility({ params, request });
72
+ return new ResourceClass({
73
+ ability,
74
+ context: {
75
+ ...(ability?.getContext() || {}),
76
+ params,
77
+ request
78
+ },
79
+ locals: ability?.getLocals() || {},
80
+ modelClass: ResourceClass.ModelClass,
81
+ modelName: ResourceClass.ModelClass?.name,
82
+ params,
83
+ resourceConfiguration: /** @type {import("../configuration-types.js").FrontendModelResourceConfiguration} */ ({
84
+ attributes: ResourceClass.attributes || {},
85
+ sync: { enabled: true }
86
+ })
87
+ });
88
+ }
89
+ /**
90
+ * Routes a publisher broadcast to this subscription when the published
91
+ * resource type equals the type the subscription was authorized for and the
92
+ * scoping params satisfy every scope condition: each condition key must be
93
+ * present in the broadcast params and match by string comparison (array
94
+ * conditions match by membership). Broadcasts without a resource type and
95
+ * conditions the publisher's scoping params do not carry never match, so a
96
+ * subscription cannot receive changes outside its authorized scope.
97
+ * @param {import("../http-server/websocket-channel.js").WebsocketJsonValue} broadcastParams - Publisher scoping params (the published resourceType plus the change's scope-partition values).
98
+ * @returns {boolean} Whether the broadcast belongs to this subscription's scope.
99
+ */
100
+ matches(broadcastParams) {
101
+ const scope = this._scope;
102
+ if (!scope)
103
+ return false;
104
+ const scopingParams = broadcastParams && typeof broadcastParams === "object" && !Array.isArray(broadcastParams)
105
+ ? /** @type {Record<string, ?>} */ (broadcastParams)
106
+ : {};
107
+ if (!Object.hasOwn(scopingParams, "resourceType") || String(scopingParams.resourceType) !== String(scope.resourceType))
108
+ return false;
109
+ for (const [conditionName, conditionValue] of Object.entries(scope.conditions)) {
110
+ if (!Object.hasOwn(scopingParams, conditionName))
111
+ return false;
112
+ const scopingValue = scopingParams[conditionName];
113
+ if (Array.isArray(conditionValue)) {
114
+ if (!conditionValue.some((value) => String(value) === String(scopingValue)))
115
+ return false;
116
+ }
117
+ else if (String(conditionValue) !== String(scopingValue)) {
118
+ return false;
119
+ }
120
+ }
121
+ return true;
122
+ }
123
+ /**
124
+ * Returns the authorized scope for debug snapshots.
125
+ * @returns {Record<string, ?>} Debug-safe subscription details.
126
+ */
127
+ debugSnapshot() {
128
+ return { scope: this._scope };
129
+ }
130
+ }
131
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luYy13ZWJzb2NrZXQtY2hhbm5lbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zeW5jL3N5bmMtd2Vic29ja2V0LWNoYW5uZWwuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE9BQU8seUJBQXlCLE1BQU0scUNBQXFDLENBQUE7QUFDM0UsT0FBTyxFQUFDLHNCQUFzQixFQUFDLE1BQU0sd0JBQXdCLENBQUE7QUFFN0QsK0VBQStFO0FBQy9FLE1BQU0sd0JBQXdCLEdBQUcsSUFBSSxPQUFPLEVBQUUsQ0FBQTtBQUU5Qzs7Ozs7Ozs7Ozs7R0FXRztBQUNILE1BQU0sQ0FBQyxPQUFPLE9BQU8sb0JBQXFCLFNBQVEseUJBQXlCO0lBQ3pFOzs7T0FHRztJQUNILE1BQU0sR0FBRyxJQUFJLENBQUE7SUFFYjs7Ozs7OztPQU9HO0lBQ0gsTUFBTSxDQUFDLHlCQUF5QixDQUFDLGFBQWE7UUFDNUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxvQkFBb0IsRUFBRSxDQUFDLEdBQUcsSUFBSSx3QkFBd0IsQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDO1lBQUUsT0FBTTtRQUVwRyx3QkFBd0IsQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDLENBQUE7UUFDM0MsYUFBYSxDQUFDLHdCQUF3QixDQUFDLHNCQUFzQixFQUFFLElBQUksQ0FBQyxDQUFBO0lBQ3RFLENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSCxLQUFLLENBQUMsWUFBWTtRQUNoQixNQUFNLFFBQVEsR0FBRyxNQUFNLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFBO1FBQy9DLE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyxZQUFZLENBQUMsRUFBQyxLQUFLLEVBQUUsRUFBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLEVBQUUsWUFBWSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsWUFBWSxFQUFDLEVBQUMsQ0FBQyxDQUFBO1FBRTFILE1BQU0s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QUUsQ0FBQztnQkFDbEMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUM7b0JBQUUsT0FBTyxLQUFLLENBQUE7WUFDM0YsQ0FBQztpQkFBTSxJQUFJLE1BQU0sQ0FBQyxjQUFjLENBQUMsS0FBSyxNQUFNLENBQUMsWUFBWSxDQUFDLEVBQUUsQ0FBQztnQkFDM0QsT0FBTyxLQUFLLENBQUE7WUFDZCxDQUFDO1FBQ0gsQ0FBQztRQUVELE9BQU8sSUFBSSxDQUFBO0lBQ2IsQ0FBQztJQUVEOzs7T0FHRztJQUNILGFBQWE7UUFDWCxPQUFPLEVBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxNQUFNLEVBQUMsQ0FBQTtJQUM3QixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBAdHMtY2hlY2tcblxuaW1wb3J0IFZlbG9jaW91c1dlYnNvY2tldENoYW5uZWwgZnJvbSBcIi4uL2h0dHAtc2VydmVyL3dlYnNvY2tldC1jaGFubmVsLmpzXCJcbmltcG9ydCB7VkVMT0NJT1VTX1NZTkNfQ0hBTk5FTH0gZnJvbSBcIi4vc3luYy1jaGFubmVsLW5hbWUuanNcIlxuXG4vKiogQ29uZmlndXJhdGlvbnMgd2hvc2UgZnJhbWV3b3JrIHN5bmMgY2hhbm5lbCBoYXMgYWxyZWFkeSBiZWVuIHJlZ2lzdGVyZWQuICovXG5jb25zdCByZWdpc3RlcmVkQ29uZmlndXJhdGlvbnMgPSBuZXcgV2Vha1NldCgpXG5cbi8qKlxuICogRnJhbWV3b3JrLW93bmVkIHdlYnNvY2tldCBjaGFubmVsIGZvciBzeW5jZWQgcmVzb3VyY2VzXG4gKiAoe0BsaW5rIFZFTE9DSU9VU19TWU5DX0NIQU5ORUx9KS5cbiAqXG4gKiBTdWJzY3JpYmUgcGFyYW1zIG1pcnJvciBhIGRlY2xhcmVkIHB1bGwgc2NvcGUg4oCUIGB7cmVzb3VyY2VUeXBlLCBjb25kaXRpb25zfWBcbiAqIHBsdXMgdGhlIGNsaWVudC1pbmplY3RlZCBgYXV0aGVudGljYXRpb25Ub2tlbmAg4oCUIGFuZCBzdWJzY3JpYmUtdGltZVxuICogYXV0aG9yaXphdGlvbiBkZWxlZ2F0ZXMgdG8gdGhlIGFwcCBzeW5jIHJlc291cmNlJ3MgZXhpc3RpbmdcbiAqIGBhdXRob3JpemVDaGFuZ2VzKHtwYXJhbXMsIHNjb3BlfSlgICh0aGUgYHN5bmMuYXBpLnJlc291cmNlQ2xhc3NgKSwgc28gYXBwc1xuICogaG9vayBpbiB0aHJvdWdoIHRoZSBhdXRob3JpemF0aW9uIHRoZXkgYWxyZWFkeSBkZWNsYXJlZCBpbnN0ZWFkIG9mIHdyaXRpbmdcbiAqIHRoZWlyIG93biBjaGFubmVsIGNsYXNzZXMuIEJyb2FkY2FzdCByb3V0aW5nIG1hdGNoZXMgdGhlIHB1Ymxpc2hlcidzXG4gKiBzY29waW5nIHBhcmFtcyBhZ2FpbnN0IHRoZSBzdWJzY3JpcHRpb24ncyBzY29wZSBjb25kaXRpb25zLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBTeW5jV2Vic29ja2V0Q2hhbm5lbCBleHRlbmRzIFZlbG9jaW91c1dlYnNvY2tldENoYW5uZWwge1xuICAvKipcbiAgICogU2NvcGUgdGhlIHN1YnNjcmlwdGlvbiB3YXMgYXV0aG9yaXplZCBmb3IsIHNldCBieSB7QGxpbmsgU3luY1dlYnNvY2tldENoYW5uZWwjY2FuU3Vic2NyaWJlfS5cbiAgICogQHR5cGUge2ltcG9ydChcIi4vc3luYy1yZXNvdXJjZS1iYXNlLmpzXCIpLlNlcmlhbGl6ZWRDaGFuZ2VzU2NvcGUgfCBudWxsfVxuICAgKi9cbiAgX3Njb3BlID0gbnVsbFxuXG4gIC8qKlxuICAgKiBSZWdpc3RlcnMgdGhlIGZyYW1ld29yayBzeW5jIGNoYW5uZWwgb24gYSBjb25maWd1cmF0aW9uIGRlY2xhcmluZyBhXG4gICAqIGBzeW5jLmFwaWAgYmxvY2sgKGd1YXJkZWQgc28gcmVwZWF0ZWQgc2VydmVyIGJvb3RzIHdpdGggdGhlIHNhbWVcbiAgICogY29uZmlndXJhdGlvbiByZWdpc3RlciBpdCBvbmx5IG9uY2UpLiBOby1vcCB3aXRob3V0IGBzeW5jLmFwaWAg4oCUIHRoZVxuICAgKiBjaGFubmVsIGF1dGhvcml6ZXMgdGhyb3VnaCB0aGUgYXBwJ3Mgc3luYyByZXNvdXJjZSBjbGFzcy5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLmpzXCIpLmRlZmF1bHR9IGNvbmZpZ3VyYXRpb24gLSBDb25maWd1cmF0aW9uIGluc3RhbmNlLlxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICovXG4gIHN0YXRpYyByZWdpc3RlckZyb21Db25maWd1cmF0aW9uKGNvbmZpZ3VyYXRpb24pIHtcbiAgICBpZiAoIWNvbmZpZ3VyYXRpb24uZ2V0U3luY0NvbmZpZ3VyYXRpb24oKS5hcGkgfHwgcmVnaXN0ZXJlZENvbmZpZ3VyYXRpb25zLmhhcyhjb25maWd1cmF0aW9uKSkgcmV0dXJuXG5cbiAgICByZWdpc3RlcmVkQ29uZmlndXJhdGlvbnMuYWRkKGNvbmZpZ3VyYXRpb24pXG4gICAgY29uZmlndXJhdGlvbi5yZWdpc3RlcldlYnNvY2tldENoYW5uZWwoVkVMT0NJT1VTX1NZTkNfQ0hBTk5FTCwgdGhpcylcbiAgfVxuXG4gIC8qKlxuICAgKiBBdXRob3JpemVzIHRoZSBzdWJzY3JpcHRpb24gdGhyb3VnaCB0aGUgYXBwIHN5bmMgcmVzb3VyY2U6IHRoZSBzdWJzY3JpYmVcbiAgICogcGFyYW1zIGFyZSBwYXJzZWQgaW50byB0aGUgc2FtZSBzZXJpYWxpemVkIHNjb3BlIHRoZSBjaGFuZ2VzIGVuZHBvaW50XG4gICAqIGNvbnN1bWVzIGFuZCBwYXNzZWQgdG8gdGhlIHJlc291cmNlJ3MgYGF1dGhvcml6ZUNoYW5nZXMoe3BhcmFtcywgc2NvcGV9KWAuXG4gICAqIERlbmlhbHMgYW5kIG1hbGZvcm1lZCBzY29wZXMgdGhyb3csIHJlamVjdGluZyB0aGUgc3Vic2NyaXB0aW9uLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gV2hldGhlciB0aGUgc3Vic2NyaXB0aW9uIGlzIGFsbG93ZWQuXG4gICAqL1xuICBhc3luYyBjYW5TdWJzY3JpYmUoKSB7XG4gICAgY29uc3QgcmVzb3VyY2UgPSBhd2FpdCB0aGlzLmJ1aWxkU3luY1Jlc291cmNlKClcbiAgICBjb25zdCBzY29wZSA9IHJlc291cmNlLmNoYW5nZXNTY29wZSh7c2NvcGU6IHtjb25kaXRpb25zOiB0aGlzLnBhcmFtcy5jb25kaXRpb25zLCByZXNvdXJjZVR5cGU6IHRoaXMucGFyYW1zLnJlc291cmNlVHlwZX19KVxuXG4gICAgYXdhaXQgcmVzb3VyY2UuYXV0aG9yaXplQ2hhbmdlcyh7cGFyYW1zOiB0aGlzLnBhcmFtcywgc2NvcGV9KVxuXG4gICAgdGhpcy5fc2NvcGUgPSBzY29wZVxuXG4gICAgcmV0dXJuIHRydWVcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZHMgdGhlIGFwcCBzeW5jIHJlc291cmNlIGF1dGhvcml6aW5nIHRoaXMgc3Vic2NyaXB0aW9uLCBtaXJyb3JpbmcgdGhlXG4gICAqIHN5bmMgdHJhbnNwb3J0IGNvbnRyb2xsZXIncyByZXNvdXJjZSBjb25zdHJ1Y3Rpb24gd2l0aCB0aGUgYWJpbGl0eVxuICAgKiByZXNvbHZlZCBmcm9tIHRoZSBzdWJzY3JpYmUgcGFyYW1zICh3aGljaCBjYXJyeSB0aGUgY2xpZW50LWluamVjdGVkXG4gICAqIGF1dGhlbnRpY2F0aW9uVG9rZW4pLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxpbXBvcnQoXCIuL3N5bmMtcmVzb3VyY2UtYmFzZS5qc1wiKS5kZWZhdWx0Pn0gQXBwIHN5bmMgcmVzb3VyY2UgaW5zdGFuY2UuXG4gICAqL1xuICBhc3luYyBidWlsZFN5bmNSZXNvdXJjZSgpIHtcbiAgICBjb25zdCBjb25maWd1cmF0aW9uID0gdGhpcy5zZXNzaW9uLmNvbmZpZ3VyYXRpb25cbiAgICBjb25zdCBhcGkgPSBjb25maWd1cmF0aW9uLmdldFN5bmNDb25maWd1cmF0aW9uKCkuYXBpXG5cbiAgICBpZiAoIWFwaSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBUaGUgJHtWRUxPQ0lPVVNfU1lOQ19DSEFOTkVMfSBjaGFubmVsIHJlcXVpcmVzIGEgc3luYy5hcGkgY29uZmlndXJhdGlvbiBibG9jayB3aXRoIHRoZSBhcHAncyBzeW5jIHJlc291cmNlIGNsYXNzYClcbiAgICB9XG5cbiAgICAvLyBOYXJyb3dzIHRoZSBjb25maWd1cmVkIHJlc291cmNlIGNsYXNzIHRvIHRoZSBzeW5jIHJlc291cmNlIGNvbnRyYWN0XG4gICAgLy8gKGNoYW5nZXNTY29wZS9hdXRob3JpemVDaGFuZ2VzKSB0aGUgc3luYy5hcGkgdmFsaWRhdGlvbiByZXF1aXJlcy5cbiAgICBjb25zdCBSZXNvdXJjZUNsYXNzID0gLyoqIEB0eXBlIHt0eXBlb2YgaW1wb3J0KFwiLi9zeW5jLXJlc291cmNlLWJhc2UuanNcIikuZGVmYXVsdH0gKi8gKGFwaS5yZXNvdXJjZUNsYXNzKVxuICAgIC8vIE5hcnJvd3MgdGhlIHdlYnNvY2tldCBzdWJzY3JpYmUgcGFyYW1zIHRvIHRoZSByZXNvdXJjZSBwYXJhbXMgY29udHJhY3QuXG4gICAgY29uc3QgcGFyYW1zID0gLyoqIEB0eXBlIHtpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLlZlbG9jaW91c1BhcmFtc30gKi8gKC8qKiBAdHlwZSB7dW5rbm93bn0gKi8gKHRoaXMucGFyYW1zKSlcbiAgICBjb25zdCByZXF1ZXN0ID0gdGhpcy5zZXNzaW9uLnVwZ3JhZGVSZXF1ZXN0XG4gICAgY29uc3QgYWJpbGl0eSA9IGF3YWl0IGNvbmZpZ3VyYXRpb24ucmVzb2x2ZUFiaWxpdHkoe3BhcmFtcywgcmVxdWVzdH0pXG5cbiAgICByZXR1cm4gbmV3IFJlc291cmNlQ2xhc3Moe1xuICAgICAgYWJpbGl0eSxcbiAgICAgIGNvbnRleHQ6IHtcbiAgICAgICAgLi4uKGFiaWxpdHk/LmdldENvbnRleHQoKSB8fCB7fSksXG4gICAgICAgIHBhcmFtcyxcbiAgICAgICAgcmVxdWVzdFxuICAgICAgfSxcbiAgICAgIGxvY2FsczogYWJpbGl0eT8uZ2V0TG9jYWxzKCkgfHwge30sXG4gICAgICBtb2RlbENsYXNzOiBSZXNvdXJjZUNsYXNzLk1vZGVsQ2xhc3MsXG4gICAgICBtb2RlbE5hbWU6IFJlc291cmNlQ2xhc3MuTW9kZWxDbGFzcz8ubmFtZSxcbiAgICAgIHBhcmFtcyxcbiAgICAgIHJlc291cmNlQ29uZmlndXJhdGlvbjogLyoqIEB0eXBlIHtpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLkZyb250ZW5kTW9kZWxSZXNvdXJjZUNvbmZpZ3VyYXRpb259ICovICh7XG4gICAgICAgIGF0dHJpYnV0ZXM6IFJlc291cmNlQ2xhc3MuYXR0cmlidXRlcyB8fCB7fSxcbiAgICAgICAgc3luYzoge2VuYWJsZWQ6IHRydWV9XG4gICAgICB9KVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogUm91dGVzIGEgcHVibGlzaGVyIGJyb2FkY2FzdCB0byB0aGlzIHN1YnNjcmlwdGlvbiB3aGVuIHRoZSBwdWJsaXNoZWRcbiAgICogcmVzb3VyY2UgdHlwZSBlcXVhbHMgdGhlIHR5cGUgdGhlIHN1YnNjcmlwdGlvbiB3YXMgYXV0aG9yaXplZCBmb3IgYW5kIHRoZVxuICAgKiBzY29waW5nIHBhcmFtcyBzYXRpc2Z5IGV2ZXJ5IHNjb3BlIGNvbmRpdGlvbjogZWFjaCBjb25kaXRpb24ga2V5IG11c3QgYmVcbiAgICogcHJlc2VudCBpbiB0aGUgYnJvYWRjYXN0IHBhcmFtcyBhbmQgbWF0Y2ggYnkgc3RyaW5nIGNvbXBhcmlzb24gKGFycmF5XG4gICAqIGNvbmRpdGlvbnMgbWF0Y2ggYnkgbWVtYmVyc2hpcCkuIEJyb2FkY2FzdHMgd2l0aG91dCBhIHJlc291cmNlIHR5cGUgYW5kXG4gICAqIGNvbmRpdGlvbnMgdGhlIHB1Ymxpc2hlcidzIHNjb3BpbmcgcGFyYW1zIGRvIG5vdCBjYXJyeSBuZXZlciBtYXRjaCwgc28gYVxuICAgKiBzdWJzY3JpcHRpb24gY2Fubm90IHJlY2VpdmUgY2hhbmdlcyBvdXRzaWRlIGl0cyBhdXRob3JpemVkIHNjb3BlLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4uL2h0dHAtc2VydmVyL3dlYnNvY2tldC1jaGFubmVsLmpzXCIpLldlYnNvY2tldEpzb25WYWx1ZX0gYnJvYWRjYXN0UGFyYW1zIC0gUHVibGlzaGVyIHNjb3BpbmcgcGFyYW1zICh0aGUgcHVibGlzaGVkIHJlc291cmNlVHlwZSBwbHVzIHRoZSBjaGFuZ2UncyBzY29wZS1wYXJ0aXRpb24gdmFsdWVzKS5cbiAgICogQHJldHVybnMge2Jvb2xlYW59IFdoZXRoZXIgdGhlIGJyb2FkY2FzdCBiZWxvbmdzIHRvIHRoaXMgc3Vic2NyaXB0aW9uJ3Mgc2NvcGUuXG4gICAqL1xuICBtYXRjaGVzKGJyb2FkY2FzdFBhcmFtcykge1xuICAgIGNvbnN0IHNjb3BlID0gdGhpcy5fc2NvcGVcblxuICAgIGlmICghc2NvcGUpIHJldHVybiBmYWxzZVxuXG4gICAgY29uc3Qgc2NvcGluZ1BhcmFtcyA9IGJyb2FkY2FzdFBhcmFtcyAmJiB0eXBlb2YgYnJvYWRjYXN0UGFyYW1zID09PSBcIm9iamVjdFwiICYmICFBcnJheS5pc0FycmF5KGJyb2FkY2FzdFBhcmFtcylcbiAgICAgID8gLyoqIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCA/Pn0gKi8gKGJyb2FkY2FzdFBhcmFtcylcbiAgICAgIDoge31cblxuICAgIGlmICghT2JqZWN0Lmhhc093bihzY29waW5nUGFyYW1zLCBcInJlc291cmNlVHlwZVwiKSB8fCBTdHJpbmcoc2NvcGluZ1BhcmFtcy5yZXNvdXJjZVR5cGUpICE9PSBTdHJpbmcoc2NvcGUucmVzb3VyY2VUeXBlKSkgcmV0dXJuIGZhbHNlXG5cbiAgICBmb3IgKGNvbnN0IFtjb25kaXRpb25OYW1lLCBjb25kaXRpb25WYWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoc2NvcGUuY29uZGl0aW9ucykpIHtcbiAgICAgIGlmICghT2JqZWN0Lmhhc093bihzY29waW5nUGFyYW1zLCBjb25kaXRpb25OYW1lKSkgcmV0dXJuIGZhbHNlXG5cbiAgICAgIGNvbnN0IHNjb3BpbmdWYWx1ZSA9IHNjb3BpbmdQYXJhbXNbY29uZGl0aW9uTmFtZV1cblxuICAgICAgaWYgKEFycmF5LmlzQXJyYXkoY29uZGl0aW9uVmFsdWUpKSB7XG4gICAgICAgIGlmICghY29uZGl0aW9uVmFsdWUuc29tZSgodmFsdWUpID0+IFN0cmluZyh2YWx1ZSkgPT09IFN0cmluZyhzY29waW5nVmFsdWUpKSkgcmV0dXJuIGZhbHNlXG4gICAgICB9IGVsc2UgaWYgKFN0cmluZyhjb25kaXRpb25WYWx1ZSkgIT09IFN0cmluZyhzY29waW5nVmFsdWUpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0cnVlXG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgYXV0aG9yaXplZCBzY29wZSBmb3IgZGVidWcgc25hcHNob3RzLlxuICAgKiBAcmV0dXJucyB7UmVjb3JkPHN0cmluZywgPz59IERlYnVnLXNhZmUgc3Vic2NyaXB0aW9uIGRldGFpbHMuXG4gICAqL1xuICBkZWJ1Z1NuYXBzaG90KCkge1xuICAgIHJldHVybiB7c2NvcGU6IHRoaXMuX3Njb3BlfVxuICB9XG59XG4iXX0=
@@ -0,0 +1,10 @@
1
+ // @ts-check
2
+
3
+ /**
4
+ * Canonical framework-owned websocket channel for synced resources. The server
5
+ * registers it automatically when `sync.api` is configured (subscribe
6
+ * authorization delegates to the app sync resource's `authorizeChanges`), the
7
+ * sync publisher broadcasts standard sync envelopes on it, and the derived
8
+ * sync client subscribes its declared pull scopes to it automatically.
9
+ */
10
+ export const VELOCIOUS_SYNC_CHANNEL = "velocious-sync"
@@ -9,8 +9,8 @@
9
9
 
10
10
  /**
11
11
  * Static realtime channel declaration on a model's `static sync`, for channels
12
- * whose name and params are static. Channels needing runtime params (like
13
- * eventId) belong in the `sync.client.realtime.channels` callback instead.
12
+ * whose name and params are static.
13
+ * @deprecated Declared pull scopes subscribe the framework sync channel automatically; keep this only for legacy app channels.
14
14
  * @typedef {object} ModelSyncRealtimeDeclaration
15
15
  * @property {string} channel - Server channel name to subscribe.
16
16
  * @property {Record<string, ?>} [params] - Static subscribe params. The framework injects `authenticationToken` automatically.
@@ -29,13 +29,14 @@
29
29
  * @property {"upsert" | ((args: {operation: "create" | "update" | "destroy", record: ?}) => string)} [syncType] - Maps a mutation operation to a sync type. The "upsert" flag queues creates and updates as "update" rows (the server upserts by resource id) and destroys as "delete". Defaults to the operation name with destroy mapped to "delete".
30
30
  * @property {(args: {operation: "create" | "update" | "destroy", record: ?}) => Record<string, ?>} [trackedData] - Custom queued-payload builder for tracked mutations.
31
31
  * @property {boolean | {operations: Array<"create" | "update" | "destroy">}} [track] - Automatic mutation tracking policy. On by default (creates and updates queue automatically); `false` opts the resource out, `true` adds destroys, `{operations}` narrows the tracked operations.
32
- * @property {ModelSyncRealtimeDeclaration} [realtime] - Static realtime channel this resource subscribes through `subscribeRealtime(...)`.
32
+ * @property {ModelSyncRealtimeDeclaration} [realtime] - Deprecated: static legacy realtime channel this resource subscribes through `subscribeRealtime(...)`. Declared pull scopes subscribe the framework sync channel automatically.
33
33
  */
34
34
 
35
35
  /**
36
36
  * Model-level client sync declaration read from `static sync` by
37
37
  * `SyncClient.fromConfiguration(...)`. `true` opts the model in with all
38
38
  * defaults; an object customizes the derived resource config.
39
+ * @template [TModel=any]
39
40
  * @typedef {object} ModelSyncDeclarationConfig
40
41
  * @property {import("./sync-api-client-types.js").SyncResourceConfig["afterApply"]} [afterApply] - Post-apply hook.
41
42
  * @property {import("./sync-api-client-types.js").SyncResourceConfig["attributes"]} [attributes] - Pull-apply attribute mapper. Required for resources that receive pulled changes.
@@ -43,14 +44,19 @@
43
44
  * @property {import("./sync-api-client-types.js").SyncResourceConfig["findRecord"]} [findRecord] - Custom pull-apply record resolver.
44
45
  * @property {import("./sync-api-client-types.js").SyncResourceConfig["findRecordForDelete"]} [findRecordForDelete] - Custom pull-apply delete resolver.
45
46
  * @property {string[]} [localOnlyAttributes] - Extra local-only attributes merged with the derived primary key, createdAt/updatedAt, and sync bookkeeping attributes.
46
- * @property {import("./sync-publisher-types.js").SyncPublishDeclaration} [publish] - Server-side publish declaration consumed by `SyncPublisher.fromConfiguration(...)` on the backend; ignored by the client.
47
+ * @property {import("./sync-publisher-types.js").SyncPublishDeclaration<TModel>} [publish] - Server-side publish declaration consumed by `SyncPublisher.fromConfiguration(...)` on the backend; ignored by the client.
47
48
  * @property {"upsert" | ((args: {operation: "create" | "update" | "destroy", record: ?}) => string)} [syncType] - Sync type flag or mapper (see SyncClientResourceConfig).
48
49
  * @property {boolean | Array<"create" | "update" | "destroy"> | {operations: Array<"create" | "update" | "destroy">}} [track] - Automatic mutation tracking policy; an array is shorthand for {operations}. On by default (creates and updates queue automatically); `false` opts the model out (for models written by non-user flows), `true` adds destroys.
49
50
  * @property {(args: {operation: "create" | "update" | "destroy", record: ?}) => Record<string, ?>} [trackedData] - Custom queued-payload builder for tracked mutations.
50
- * @property {ModelSyncRealtimeDeclaration} [realtime] - Static realtime channel this resource subscribes through `subscribeRealtime(...)`; use the `sync.client.realtime.channels` callback for channels needing runtime params.
51
+ * @property {ModelSyncRealtimeDeclaration} [realtime] - Deprecated: static legacy realtime channel this resource subscribes through `subscribeRealtime(...)`. Declared pull scopes subscribe the framework sync channel automatically.
51
52
  */
52
53
 
53
- /** @typedef {boolean | ModelSyncDeclarationConfig} ModelSyncDeclaration */
54
+ /**
55
+ * Model-level sync declaration value: `true` opts in with all defaults, an
56
+ * object customizes the derived resource config.
57
+ * @template [TModel=any]
58
+ * @typedef {boolean | ModelSyncDeclarationConfig<TModel>} ModelSyncDeclaration
59
+ */
54
60
 
55
61
  /**
56
62
  * Options for building a sync client. Everything else — resources, transport
@@ -452,7 +452,7 @@ export default class SyncClient {
452
452
  /**
453
453
  * Subscribes the derived realtime channels so pushed websocket changes apply
454
454
  * through the same derived applier as pulls (idempotent, single-flighted).
455
- * @param {?} [context] - App context passed to the `sync.client.realtime.channels` callback (runtime values like eventId).
455
+ * @param {?} [context] - App context passed to the deprecated `sync.client.realtime.channels` callback (runtime scope values).
456
456
  * @returns {Promise<void>}
457
457
  */
458
458
  async subscribeRealtime(context) {
@@ -2,6 +2,8 @@
2
2
 
3
3
  import VelociousError from "../velocious-error.js"
4
4
 
5
+ import {declaredSyncScopeAttributes} from "./sync-scope-attributes.js"
6
+
5
7
  /**
6
8
  * Generic cursor-paginated change feed over an app-owned sync/change model.
7
9
  *
@@ -173,14 +175,20 @@ export default class SyncModelChangeFeedService {
173
175
  }
174
176
 
175
177
  /**
176
- * Serializes a record using the standard sync envelope shape.
178
+ * Serializes a record using the standard sync envelope shape plus the sync
179
+ * model's declared scope-partition attributes (`static syncScopeAttributes`),
180
+ * each emitted under its own attribute name. Models declaring no scope
181
+ * attributes keep the deprecated 1.0.503 wire and emit `eventId`. Keys are
182
+ * sorted so a declared `["eventId"]` partition stays byte-identical with the
183
+ * 1.0.503 wire.
177
184
  * @param {?} record - Sync/change record.
178
185
  * @returns {Record<string, unknown>} Default serialized row.
179
186
  */
180
187
  defaultSerializeRecord(record) {
181
- return {
188
+ const scopeAttributes = declaredSyncScopeAttributes(this.modelClass)
189
+ /** @type {Record<string, unknown>} */
190
+ const serialized = {
182
191
  data: this.recordData(record),
183
- eventId: this.recordValue(record, "eventId"),
184
192
  id: this.recordValue(record, "id"),
185
193
  resourceId: this.recordValue(record, "resourceId"),
186
194
  resourceType: this.recordValue(record, "resourceType"),
@@ -188,6 +196,12 @@ export default class SyncModelChangeFeedService {
188
196
  syncType: this.recordValue(record, "syncType"),
189
197
  updatedAt: this.isoDate(this.recordValue(record, "updatedAt"))
190
198
  }
199
+
200
+ for (const scopeAttribute of scopeAttributes || ["eventId"]) {
201
+ serialized[scopeAttribute] = this.recordValue(record, scopeAttribute)
202
+ }
203
+
204
+ return Object.fromEntries(Object.entries(serialized).sort(([leftKey], [rightKey]) => leftKey.localeCompare(rightKey)))
191
205
  }
192
206
 
193
207
  /**