velocious 1.0.489 → 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.
Files changed (103) hide show
  1. package/build/application.js +3 -0
  2. package/build/cli/commands/db/tenants/create.js +7 -5
  3. package/build/cli/commands/db/tenants/drop.js +6 -6
  4. package/build/configuration-types.js +8 -0
  5. package/build/configuration.js +29 -0
  6. package/build/database/query/index.js +30 -0
  7. package/build/database/query/model-class-query.js +17 -0
  8. package/build/database/record/index.js +16 -0
  9. package/build/src/application.d.ts.map +1 -1
  10. package/build/src/application.js +3 -1
  11. package/build/src/cli/commands/db/tenants/create.d.ts.map +1 -1
  12. package/build/src/cli/commands/db/tenants/create.js +8 -5
  13. package/build/src/cli/commands/db/tenants/drop.d.ts +1 -1
  14. package/build/src/cli/commands/db/tenants/drop.d.ts.map +1 -1
  15. package/build/src/cli/commands/db/tenants/drop.js +7 -6
  16. package/build/src/configuration-types.d.ts +24 -0
  17. package/build/src/configuration-types.d.ts.map +1 -1
  18. package/build/src/configuration-types.js +8 -1
  19. package/build/src/configuration.d.ts +6 -0
  20. package/build/src/configuration.d.ts.map +1 -1
  21. package/build/src/configuration.js +26 -1
  22. package/build/src/database/query/index.d.ts +25 -0
  23. package/build/src/database/query/index.d.ts.map +1 -1
  24. package/build/src/database/query/index.js +26 -1
  25. package/build/src/database/query/model-class-query.d.ts +10 -0
  26. package/build/src/database/query/model-class-query.d.ts.map +1 -1
  27. package/build/src/database/query/model-class-query.js +16 -1
  28. package/build/src/database/record/index.d.ts +7 -0
  29. package/build/src/database/record/index.d.ts.map +1 -1
  30. package/build/src/database/record/index.js +15 -1
  31. package/build/src/sync/query-scope.d.ts +18 -0
  32. package/build/src/sync/query-scope.d.ts.map +1 -0
  33. package/build/src/sync/query-scope.js +77 -0
  34. package/build/src/sync/server-change-feed.d.ts.map +1 -1
  35. package/build/src/sync/server-change-feed.js +2 -24
  36. package/build/src/sync/stable-json.d.ts +9 -0
  37. package/build/src/sync/stable-json.d.ts.map +1 -0
  38. package/build/src/sync/stable-json.js +27 -0
  39. package/build/src/sync/sync-api-client.d.ts +185 -5
  40. package/build/src/sync/sync-api-client.d.ts.map +1 -1
  41. package/build/src/sync/sync-api-client.js +309 -17
  42. package/build/src/sync/sync-api-controller.d.ts +8 -0
  43. package/build/src/sync/sync-api-controller.d.ts.map +1 -1
  44. package/build/src/sync/sync-api-controller.js +17 -1
  45. package/build/src/sync/sync-client-registry.d.ts +12 -0
  46. package/build/src/sync/sync-client-registry.d.ts.map +1 -0
  47. package/build/src/sync/sync-client-registry.js +27 -0
  48. package/build/src/sync/sync-client-types.d.ts +127 -0
  49. package/build/src/sync/sync-client-types.d.ts.map +1 -0
  50. package/build/src/sync/sync-client-types.js +3 -0
  51. package/build/src/sync/sync-client.d.ts +176 -0
  52. package/build/src/sync/sync-client.d.ts.map +1 -0
  53. package/build/src/sync/sync-client.js +380 -0
  54. package/build/src/sync/sync-envelope-replay-service.d.ts +38 -4
  55. package/build/src/sync/sync-envelope-replay-service.d.ts.map +1 -1
  56. package/build/src/sync/sync-envelope-replay-service.js +73 -6
  57. package/build/src/sync/sync-resource-base.d.ts +98 -0
  58. package/build/src/sync/sync-resource-base.d.ts.map +1 -0
  59. package/build/src/sync/sync-resource-base.js +122 -0
  60. package/build/src/sync/sync-scope-store.d.ts +128 -0
  61. package/build/src/sync/sync-scope-store.d.ts.map +1 -0
  62. package/build/src/sync/sync-scope-store.js +282 -0
  63. package/build/src/tenants/default-tenant-database-provisioning.d.ts +21 -0
  64. package/build/src/tenants/default-tenant-database-provisioning.d.ts.map +1 -0
  65. package/build/src/tenants/default-tenant-database-provisioning.js +106 -0
  66. package/build/src/tenants/tenant.d.ts.map +1 -1
  67. package/build/src/tenants/tenant.js +6 -5
  68. package/build/sync/query-scope.js +84 -0
  69. package/build/sync/server-change-feed.js +1 -25
  70. package/build/sync/stable-json.js +28 -0
  71. package/build/sync/sync-api-client.js +331 -17
  72. package/build/sync/sync-api-controller.js +20 -0
  73. package/build/sync/sync-client-registry.js +30 -0
  74. package/build/sync/sync-client-types.js +41 -0
  75. package/build/sync/sync-client.js +433 -0
  76. package/build/sync/sync-envelope-replay-service.js +77 -5
  77. package/build/sync/sync-resource-base.js +143 -0
  78. package/build/sync/sync-scope-store.js +327 -0
  79. package/build/tenants/default-tenant-database-provisioning.js +124 -0
  80. package/build/tenants/tenant.js +5 -5
  81. package/build/tsconfig.tsbuildinfo +1 -1
  82. package/package.json +1 -1
  83. package/src/application.js +3 -0
  84. package/src/cli/commands/db/tenants/create.js +7 -5
  85. package/src/cli/commands/db/tenants/drop.js +6 -6
  86. package/src/configuration-types.js +8 -0
  87. package/src/configuration.js +29 -0
  88. package/src/database/query/index.js +30 -0
  89. package/src/database/query/model-class-query.js +17 -0
  90. package/src/database/record/index.js +16 -0
  91. package/src/sync/query-scope.js +84 -0
  92. package/src/sync/server-change-feed.js +1 -25
  93. package/src/sync/stable-json.js +28 -0
  94. package/src/sync/sync-api-client.js +331 -17
  95. package/src/sync/sync-api-controller.js +20 -0
  96. package/src/sync/sync-client-registry.js +30 -0
  97. package/src/sync/sync-client-types.js +41 -0
  98. package/src/sync/sync-client.js +433 -0
  99. package/src/sync/sync-envelope-replay-service.js +77 -5
  100. package/src/sync/sync-resource-base.js +143 -0
  101. package/src/sync/sync-scope-store.js +327 -0
  102. package/src/tenants/default-tenant-database-provisioning.js +124 -0
  103. package/src/tenants/tenant.js +5 -5
@@ -0,0 +1,282 @@
1
+ // @ts-check
2
+ import TableData from "../database/table-data/index.js";
3
+ import UUID from "pure-uuid";
4
+ import { scopeKey } from "./query-scope.js";
5
+ import stableJsonStringify from "./stable-json.js";
6
+ const TABLE_NAME = "velocious_sync_scopes";
7
+ const SCOPE_DIGEST_PREFIX = "velocious-sync-scope:";
8
+ /**
9
+ * Digests a serialized scope into a fixed-size deterministic key, so scope
10
+ * identities with long condition values fit an indexed string column.
11
+ * @param {import("./sync-client-types.js").SerializedSyncScope} scope - Serialized sync scope.
12
+ * @returns {string} Deterministic UUIDv5 digest of the canonical scope key.
13
+ */
14
+ function scopeDigestForScope(scope) {
15
+ return new UUID(5, "ns:URL", `${SCOPE_DIGEST_PREFIX}${scopeKey(scope)}`).format();
16
+ }
17
+ /**
18
+ * @typedef {object} SyncScopeRow
19
+ * @property {Record<string, ?>} conditions - Scope attribute conditions.
20
+ * @property {string | null} cursorPayload - Persisted cursor JSON payload.
21
+ * @property {string} id - Scope row id.
22
+ * @property {string} resourceType - Scope resource/model name.
23
+ * @property {string} scopeDigest - Fixed-size deterministic digest of the canonical scope key.
24
+ * @property {string} state - Scope state ("active" or "removed").
25
+ */
26
+ /**
27
+ * Framework-owned local persistence for declared sync scopes and their cursors.
28
+ *
29
+ * Backed by an auto-created `velocious_sync_scopes` table on the configured
30
+ * database, with a process-local memory fallback when no database is
31
+ * configured (mirroring the server change-feed store).
32
+ */
33
+ export default class SyncScopeStore {
34
+ /**
35
+ * Creates a sync scope store.
36
+ * @param {object} args - Options.
37
+ * @param {import("../configuration.js").default} args.configuration - Configuration owning the database.
38
+ * @param {string} [args.databaseIdentifier] - Database identifier.
39
+ */
40
+ constructor({ configuration, databaseIdentifier = "default" }) {
41
+ this.configuration = configuration;
42
+ this.databaseIdentifier = databaseIdentifier;
43
+ /** @type {Map<string, SyncScopeRow>} */
44
+ this._memoryScopes = new Map();
45
+ this._isReady = false;
46
+ /** @type {Promise<void> | null} */
47
+ this._readyPromise = null;
48
+ }
49
+ /**
50
+ * Ensures the backing table exists.
51
+ * @returns {Promise<void>} Resolves when ready.
52
+ */
53
+ async ensureReady() {
54
+ if (this._isReady)
55
+ return;
56
+ if (this._usesMemoryStorage()) {
57
+ this._isReady = true;
58
+ return;
59
+ }
60
+ if (this._readyPromise)
61
+ return await this._readyPromise;
62
+ this._readyPromise = this._withDb(async (db) => {
63
+ await this._ensureScopesTable(db);
64
+ this._isReady = true;
65
+ });
66
+ try {
67
+ await this._readyPromise;
68
+ }
69
+ finally {
70
+ if (!this._isReady)
71
+ this._readyPromise = null;
72
+ }
73
+ }
74
+ /**
75
+ * Finds or creates the scope row for a serialized scope, reactivating removed scopes.
76
+ * @param {import("./sync-client-types.js").SerializedSyncScope} scope - Serialized sync scope.
77
+ * @returns {Promise<SyncScopeRow>} Persisted scope row.
78
+ */
79
+ async findOrCreateScope(scope) {
80
+ await this.ensureReady();
81
+ const digest = scopeDigestForScope(scope);
82
+ if (this._usesMemoryStorage()) {
83
+ const existingScope = this._memoryScopes.get(digest);
84
+ if (existingScope) {
85
+ if (existingScope.state !== "active")
86
+ existingScope.state = "active";
87
+ return existingScope;
88
+ }
89
+ const newScope = {
90
+ conditions: scope.conditions,
91
+ cursorPayload: null,
92
+ id: new UUID(4).format(),
93
+ resourceType: scope.resourceType,
94
+ scopeDigest: digest,
95
+ state: "active"
96
+ };
97
+ this._memoryScopes.set(digest, newScope);
98
+ return newScope;
99
+ }
100
+ return await this._withDb(async (db) => {
101
+ const existingRow = await this._rowByScopeDigest(db, digest);
102
+ if (existingRow) {
103
+ if (existingRow.state !== "active") {
104
+ await db.update({ conditions: { id: existingRow.id }, data: { state: "active", updated_at: new Date() }, tableName: TABLE_NAME });
105
+ existingRow.state = "active";
106
+ }
107
+ return existingRow;
108
+ }
109
+ await db.insert({
110
+ tableName: TABLE_NAME,
111
+ data: {
112
+ conditions_json: stableJsonStringify(scope.conditions),
113
+ created_at: new Date(),
114
+ cursor_json: null,
115
+ id: new UUID(4).format(),
116
+ resource_type: scope.resourceType,
117
+ scope_digest: digest,
118
+ state: "active",
119
+ updated_at: new Date()
120
+ }
121
+ });
122
+ const createdRow = await this._rowByScopeDigest(db, digest);
123
+ if (!createdRow)
124
+ throw new Error("Failed to persist sync scope");
125
+ return createdRow;
126
+ });
127
+ }
128
+ /**
129
+ * Returns all active scope rows.
130
+ * @returns {Promise<SyncScopeRow[]>} Active scope rows.
131
+ */
132
+ async activeScopes() {
133
+ await this.ensureReady();
134
+ if (this._usesMemoryStorage()) {
135
+ return [...this._memoryScopes.values()].filter((scope) => scope.state === "active");
136
+ }
137
+ return await this._withDb(async (db) => {
138
+ const rows = /** @type {Array<Record<string, ?>>} */ (await db
139
+ .newQuery()
140
+ .from(TABLE_NAME)
141
+ .where({ state: "active" })
142
+ .order("created_at ASC")
143
+ .results());
144
+ return rows.map((row) => this._normalizeScopeRow(row));
145
+ });
146
+ }
147
+ /**
148
+ * Loads the persisted cursor payload for a scope row.
149
+ * @param {SyncScopeRow} scopeRow - Scope row.
150
+ * @returns {Promise<string | null>} Cursor JSON payload.
151
+ */
152
+ async loadCursor(scopeRow) {
153
+ await this.ensureReady();
154
+ if (this._usesMemoryStorage()) {
155
+ return this._memoryScopes.get(scopeRow.scopeDigest)?.cursorPayload ?? null;
156
+ }
157
+ return await this._withDb(async (db) => {
158
+ const row = await this._rowByScopeDigest(db, scopeRow.scopeDigest);
159
+ return row ? row.cursorPayload : null;
160
+ });
161
+ }
162
+ /**
163
+ * Persists the acknowledged cursor for a scope row.
164
+ * @param {SyncScopeRow} scopeRow - Scope row.
165
+ * @param {import("./sync-api-client-types.js").SyncCursor} cursor - Acknowledged cursor.
166
+ * @returns {Promise<void>}
167
+ */
168
+ async saveCursor(scopeRow, cursor) {
169
+ if (!cursor)
170
+ return;
171
+ await this.ensureReady();
172
+ const cursorPayload = JSON.stringify(cursor);
173
+ if (this._usesMemoryStorage()) {
174
+ const memoryScope = this._memoryScopes.get(scopeRow.scopeDigest);
175
+ if (!memoryScope)
176
+ throw new Error(`No sync scope found for: ${scopeRow.scopeDigest}`);
177
+ memoryScope.cursorPayload = cursorPayload;
178
+ return;
179
+ }
180
+ await this._withDb(async (db) => {
181
+ await db.update({
182
+ conditions: { scope_digest: scopeRow.scopeDigest },
183
+ data: { cursor_json: cursorPayload, updated_at: new Date() },
184
+ tableName: TABLE_NAME
185
+ });
186
+ });
187
+ }
188
+ /**
189
+ * Deactivates the scope row for a serialized scope.
190
+ * @param {import("./sync-client-types.js").SerializedSyncScope} scope - Serialized sync scope.
191
+ * @returns {Promise<void>}
192
+ */
193
+ async deactivate(scope) {
194
+ await this.ensureReady();
195
+ const digest = scopeDigestForScope(scope);
196
+ if (this._usesMemoryStorage()) {
197
+ const memoryScope = this._memoryScopes.get(digest);
198
+ if (memoryScope)
199
+ memoryScope.state = "removed";
200
+ return;
201
+ }
202
+ await this._withDb(async (db) => {
203
+ await db.update({ conditions: { scope_digest: digest }, data: { state: "removed", updated_at: new Date() }, tableName: TABLE_NAME });
204
+ });
205
+ }
206
+ /**
207
+ * Whether the store runs without a configured database.
208
+ * @returns {boolean} Whether memory storage is used.
209
+ */
210
+ _usesMemoryStorage() {
211
+ try {
212
+ return !this.configuration.getDatabaseConfiguration()[this.databaseIdentifier];
213
+ }
214
+ catch {
215
+ return true;
216
+ }
217
+ }
218
+ /**
219
+ * Runs a callback with a database connection.
220
+ * @template Result
221
+ * @param {(db: import("../database/drivers/base.js").default) => Promise<Result>} callback - Database callback.
222
+ * @returns {Promise<Result>} Callback result.
223
+ */
224
+ async _withDb(callback) {
225
+ return await this.configuration.ensureConnections({ name: "Sync scope store" }, async (dbs) => {
226
+ const db = dbs[this.databaseIdentifier];
227
+ if (!db)
228
+ throw new Error(`No database connection available for identifier: ${this.databaseIdentifier}`);
229
+ return await callback(db);
230
+ });
231
+ }
232
+ /**
233
+ * Ensures the scopes table exists.
234
+ * @param {import("../database/drivers/base.js").default} db - Database connection.
235
+ * @returns {Promise<void>}
236
+ */
237
+ async _ensureScopesTable(db) {
238
+ if (await db.tableExists(TABLE_NAME))
239
+ return;
240
+ const table = new TableData(TABLE_NAME, { ifNotExists: true });
241
+ table.string("id", { null: false, primaryKey: true });
242
+ table.string("scope_digest", { index: true, null: false });
243
+ table.string("resource_type", { index: true, null: false });
244
+ table.text("conditions_json", { null: false });
245
+ table.text("cursor_json", { null: true });
246
+ table.string("state", { index: true, null: false });
247
+ table.datetime("created_at", { null: false });
248
+ table.datetime("updated_at", { null: false });
249
+ await db.createTable(table);
250
+ }
251
+ /**
252
+ * Resolves a scope row by its digest.
253
+ * @param {import("../database/drivers/base.js").default} db - Database connection.
254
+ * @param {string} digest - Fixed-size scope digest.
255
+ * @returns {Promise<SyncScopeRow | null>} Scope row or null.
256
+ */
257
+ async _rowByScopeDigest(db, digest) {
258
+ const rows = /** @type {Array<Record<string, ?>>} */ (await db
259
+ .newQuery()
260
+ .from(TABLE_NAME)
261
+ .where({ scope_digest: digest })
262
+ .limit(1)
263
+ .results());
264
+ return rows[0] ? this._normalizeScopeRow(rows[0]) : null;
265
+ }
266
+ /**
267
+ * Normalizes a raw scope table row.
268
+ * @param {Record<string, ?>} row - Raw table row.
269
+ * @returns {SyncScopeRow} Normalized scope row.
270
+ */
271
+ _normalizeScopeRow(row) {
272
+ return {
273
+ conditions: /** @type {Record<string, ?>} */ (JSON.parse(String(row.conditions_json))),
274
+ cursorPayload: row.cursor_json === null || row.cursor_json === undefined ? null : String(row.cursor_json),
275
+ id: String(row.id),
276
+ resourceType: String(row.resource_type),
277
+ scopeDigest: String(row.scope_digest),
278
+ state: String(row.state)
279
+ };
280
+ }
281
+ }
282
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luYy1zY29wZS1zdG9yZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zeW5jL3N5bmMtc2NvcGUtc3RvcmUuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE9BQU8sU0FBUyxNQUFNLGlDQUFpQyxDQUFBO0FBQ3ZELE9BQU8sSUFBSSxNQUFNLFdBQVcsQ0FBQTtBQUU1QixPQUFPLEVBQUMsUUFBUSxFQUFDLE1BQU0sa0JBQWtCLENBQUE7QUFDekMsT0FBTyxtQkFBbUIsTUFBTSxrQkFBa0IsQ0FBQTtBQUVsRCxNQUFNLFVBQVUsR0FBRyx1QkFBdUIsQ0FBQTtBQUMxQyxNQUFNLG1CQUFtQixHQUFHLHVCQUF1QixDQUFBO0FBRW5EOzs7OztHQUtHO0FBQ0gsU0FBUyxtQkFBbUIsQ0FBQyxLQUFLO0lBQ2hDLE9BQU8sSUFBSSxJQUFJLENBQUMsQ0FBQyxFQUFFLFFBQVEsRUFBRSxHQUFHLG1CQUFtQixHQUFHLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUE7QUFDbkYsQ0FBQztBQUVEOzs7Ozs7OztHQVFHO0FBRUg7Ozs7OztHQU1HO0FBQ0gsTUFBTSxDQUFDLE9BQU8sT0FBTyxjQUFjO0lBQ2pDOzs7OztPQUtHO0lBQ0gsWUFBWSxFQUFDLGFBQWEsRUFBRSxrQkFBa0IsR0FBRyxTQUFTLEVBQUM7UUFDekQsSUFBSSxDQUFDLGFBQWEsR0FBRyxhQUFhLENBQUE7UUFDbEMsSUFBSSxDQUFDLGtCQUFrQixHQUFHLGtCQUFrQixDQUFBO1FBQzVDLHdDQUF3QztRQUN4QyxJQUFJLENBQUMsYUFBYSxHQUFHLElBQUksR0FBRyxFQUFFLENBQUE7UUFDOUIsSUFBSSxDQUFDLFFBQVEsR0FBRyxLQUFLLENBQUE7UUFDckIsbUNBQW1DO1FBQ25DLElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSxDQUFBO0lBQzNCLENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMs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TyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFBO0lBQzFELENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsa0JBQWtCLENBQUMsR0FBRztRQUNwQixPQUFPO1lBQ0wsVUFBVSxFQUFFLGdDQUFnQyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUM7WUFDdEYsYUFBYSxFQUFFLEdBQUcsQ0FBQyxXQUFXLEtBQUssSUFBSSxJQUFJLEdBQUcsQ0FBQyxXQUFXLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDO1lBQ3pHLEVBQUUsRUFBRSxNQUFNLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUNsQixZQUFZLEVBQUUsTUFBTSxDQUFDLEdBQUcsQ0FBQyxhQUFhLENBQUM7WUFDdkMsV0FBVyxFQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDO1lBQ3JDLEtBQUssRUFBRSxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQztTQUN6QixDQUFBO0lBQ0gsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmltcG9ydCBUYWJsZURhdGEgZnJvbSBcIi4uL2RhdGFiYXNlL3RhYmxlLWRhdGEvaW5kZXguanNcIlxuaW1wb3J0IFVVSUQgZnJvbSBcInB1cmUtdXVpZFwiXG5cbmltcG9ydCB7c2NvcGVLZXl9IGZyb20gXCIuL3F1ZXJ5LXNjb3BlLmpzXCJcbmltcG9ydCBzdGFibGVKc29uU3RyaW5naWZ5IGZyb20gXCIuL3N0YWJsZS1qc29uLmpzXCJcblxuY29uc3QgVEFCTEVfTkFNRSA9IFwidmVsb2Npb3VzX3N5bmNfc2NvcGVzXCJcbmNvbnN0IFNDT1BFX0RJR0VTVF9QUkVGSVggPSBcInZlbG9jaW91cy1zeW5jLXNjb3BlOlwiXG5cbi8qKlxuICogRGlnZXN0cyBhIHNlcmlhbGl6ZWQgc2NvcGUgaW50byBhIGZpeGVkLXNpemUgZGV0ZXJtaW5pc3RpYyBrZXksIHNvIHNjb3BlXG4gKiBpZGVudGl0aWVzIHdpdGggbG9uZyBjb25kaXRpb24gdmFsdWVzIGZpdCBhbiBpbmRleGVkIHN0cmluZyBjb2x1bW4uXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4vc3luYy1jbGllbnQtdHlwZXMuanNcIikuU2VyaWFsaXplZFN5bmNTY29wZX0gc2NvcGUgLSBTZXJpYWxpemVkIHN5bmMgc2NvcGUuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBEZXRlcm1pbmlzdGljIFVVSUR2NSBkaWdlc3Qgb2YgdGhlIGNhbm9uaWNhbCBzY29wZSBrZXkuXG4gKi9cbmZ1bmN0aW9uIHNjb3BlRGlnZXN0Rm9yU2NvcGUoc2NvcGUpIHtcbiAgcmV0dXJuIG5ldyBVVUlEKDUsIFwibnM6VVJMXCIsIGAke1NDT1BFX0RJR0VTVF9QUkVGSVh9JHtzY29wZUtleShzY29wZSl9YCkuZm9ybWF0KClcbn1cblxuLyoqXG4gKiBAdHlwZWRlZiB7b2JqZWN0fSBTeW5jU2NvcGVSb3dcbiAqIEBwcm9wZXJ0eSB7UmVjb3JkPHN0cmluZywgPz59IGNvbmRpdGlvbnMgLSBTY29wZSBhdHRyaWJ1dGUgY29uZGl0aW9ucy5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nIHwgbnVsbH0gY3Vyc29yUGF5bG9hZCAtIFBlcnNpc3RlZCBjdXJzb3IgSlNPTiBwYXlsb2FkLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IGlkIC0gU2NvcGUgcm93IGlkLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IHJlc291cmNlVHlwZSAtIFNjb3BlIHJlc291cmNlL21vZGVsIG5hbWUuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gc2NvcGVEaWdlc3QgLSBGaXhlZC1zaXplIGRldGVybWluaXN0aWMgZGlnZXN0IG9mIHRoZSBjYW5vbmljYWwgc2NvcGUga2V5LlxuICogQHByb3BlcnR5IHtzdHJpbmd9IHN0YXRlIC0gU2NvcGUgc3RhdGUgKFwiYWN0aXZlXCIgb3IgXCJyZW1vdmVkXCIpLlxuICovXG5cbi8qKlxuICogRnJhbWV3b3JrLW93bmVkIGxvY2FsIHBlcnNpc3RlbmNlIGZvciBkZWNsYXJlZCBzeW5jIHNjb3BlcyBhbmQgdGhlaXIgY3Vyc29ycy5cbiAqXG4gKiBCYWNrZWQgYnkgYW4gYXV0by1jcmVhdGVkIGB2ZWxvY2lvdXNfc3luY19zY29wZXNgIHRhYmxlIG9uIHRoZSBjb25maWd1cmVkXG4gKiBkYXRhYmFzZSwgd2l0aCBhIHByb2Nlc3MtbG9jYWwgbWVtb3J5IGZhbGxiYWNrIHdoZW4gbm8gZGF0YWJhc2UgaXNcbiAqIGNvbmZpZ3VyZWQgKG1pcnJvcmluZyB0aGUgc2VydmVyIGNoYW5nZS1mZWVkIHN0b3JlKS5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgU3luY1Njb3BlU3RvcmUge1xuICAvKipcbiAgICogQ3JlYXRlcyBhIHN5bmMgc2NvcGUgc3RvcmUuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gT3B0aW9ucy5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLmpzXCIpLmRlZmF1bHR9IGFyZ3MuY29uZmlndXJhdGlvbiAtIENvbmZpZ3VyYXRpb24gb3duaW5nIHRoZSBkYXRhYmFzZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IFthcmdzLmRhdGFiYXNlSWRlbnRpZmllcl0gLSBEYXRhYmFzZSBpZGVudGlmaWVyLlxuICAgKi9cbiAgY29uc3RydWN0b3Ioe2NvbmZpZ3VyYXRpb24sIGRhdGFiYXNlSWRlbnRpZmllciA9IFwiZGVmYXVsdFwifSkge1xuICAgIHRoaXMuY29uZmlndXJhdGlvbiA9IGNvbmZpZ3VyYXRpb25cbiAgICB0aGlzLmRhdGFiYXNlSWRlbnRpZmllciA9IGRhdGFiYXNlSWRlbnRpZmllclxuICAgIC8qKiBAdHlwZSB7TWFwPHN0cmluZywgU3luY1Njb3BlUm93Pn0gKi9cbiAgICB0aGlzLl9tZW1vcnlTY29wZXMgPSBuZXcgTWFwKClcbiAgICB0aGlzLl9pc1JlYWR5ID0gZmFsc2VcbiAgICAvKiogQHR5cGUge1Byb21pc2U8dm9pZD4gfCBudWxsfSAqL1xuICAgIHRoaXMuX3JlYWR5UHJvbWlzZSA9IG51bGxcbiAgfVxuXG4gIC8qKlxuICAgKiBFbnN1cmVzIHRoZSBiYWNraW5nIHRhYmxlIGV4aXN0cy5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IFJlc29sdmVzIHdoZW4gcmVhZHkuXG4gICAqL1xuICBhc3luYyBlbnN1cmVSZWFkeSgpIHtcbiAgICBpZiAodGhpcy5faXNSZWFkeSkgcmV0dXJuXG5cbiAgICBpZiAodGhpcy5fdXNlc01lbW9yeVN0b3JhZ2UoKSkge1xuICAgICAgdGhpcy5faXNSZWFkeSA9IHRydWVcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIGlmICh0aGlzLl9yZWFkeVByb21pc2UpIHJldHVybiBhd2FpdCB0aGlzLl9yZWFkeVByb21pc2VcblxuICAgIHRoaXMuX3JlYWR5UHJvbWlzZSA9IHRoaXMuX3dpdGhEYihhc3luYyAoZGIpID0+IHtcbiAgICAgIGF3YWl0IHRoaXMuX2Vuc3VyZVNjb3Blc1RhYmxlKGRiKVxuICAgICAgdGhpcy5faXNSZWFkeSA9IHRydWVcbiAgICB9KVxuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMuX3JlYWR5UHJvbWlzZVxuICAgIH0gZmluYWxseSB7XG4gICAgICBpZiAoIXRoaXMuX2lzUmVhZHkpIHRoaXMuX3JlYWR5UHJvbWlzZSA9IG51bGxcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRmluZHMgb3IgY3JlYXRlcyB0aGUgc2NvcGUgcm93IGZvciBhIHNlcmlhbGl6ZWQgc2NvcGUsIHJlYWN0aXZhdGluZyByZW1vdmVkIHNjb3Blcy5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuL3N5bmMtY2xpZW50LXR5cGVzLmpzXCIpLlNlcmlhbGl6ZWRTeW5jU2NvcGV9IHNjb3BlIC0gU2VyaWFsaXplZCBzeW5jIHNjb3BlLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxTeW5jU2NvcGVSb3c+fSBQZXJzaXN0ZWQgc2NvcGUgcm93LlxuICAgKi9cbiAgYXN5bmMgZmluZE9yQ3JlYXRlU2NvcGUoc2NvcGUpIHtcbiAgICBhd2FpdCB0aGlzLmVuc3VyZVJlYWR5KClcblxuICAgIGNvbnN0IGRpZ2VzdCA9IHNjb3BlRGlnZXN0Rm9yU2NvcGUoc2NvcGUpXG5cbiAgICBpZiAodGhpcy5fdXNlc01lbW9yeVN0b3JhZ2UoKSkge1xuICAgICAgY29uc3QgZXhpc3RpbmdTY29wZSA9IHRoaXMuX21lbW9yeVNjb3Blcy5nZXQoZGlnZXN0KVxuXG4gICAgICBpZiAoZXhpc3RpbmdTY29wZSkge1xuICAgICAgICBpZiAoZXhpc3RpbmdTY29wZS5zdGF0ZSAhPT0gXCJhY3RpdmVcIikgZXhpc3RpbmdTY29wZS5zdGF0ZSA9IFwiYWN0aXZlXCJcblxuICAgICAgICByZXR1cm4gZXhpc3RpbmdTY29wZVxuICAgICAgfVxuXG4gICAgICBjb25zdCBuZXdTY29wZSA9IHtcbiAgICAgICAgY29uZGl0aW9uczogc2NvcGUuY29uZGl0aW9ucyxcbiAgICAgICAgY3Vyc29yUGF5bG9hZDogbnVsbCxcbiAgICAgICAgaWQ6IG5ldyBVVUlEKDQpLmZvcm1hdCgpLFxuICAgICAgICByZXNvdXJjZVR5cGU6IHNjb3BlLnJlc291cmNlVHlwZSxcbiAgICAgICAgc2NvcGVEaWdlc3Q6IGRpZ2VzdCxcbiAgICAgICAgc3RhdGU6IFwiYWN0aXZlXCJcbiAgICAgIH1cblxuICAgICAgdGhpcy5fbWVtb3J5U2NvcGVzLnNldChkaWdlc3QsIG5ld1Njb3BlKVxuXG4gICAgICByZXR1cm4gbmV3U2NvcGVcbiAgICB9XG5cbiAgICByZXR1cm4gYXdhaXQgdGhpcy5fd2l0aERiKGFzeW5jIChkYikgPT4ge1xuICAgICAgY29uc3QgZXhpc3RpbmdSb3cgPSBhd2FpdCB0aGlzLl9yb3dCeVNjb3BlRGlnZXN0KGRiLCBkaWdlc3QpXG5cbiAgICAgIGlmIChleGlzdGluZ1Jvdykge1xuICAgICAgICBpZiAoZXhpc3RpbmdSb3cuc3RhdGUgIT09IFwiYWN0aXZlXCIpIHtcbiAgICAgICAgICBhd2FpdCBkYi51cGRhdGUoe2NvbmRpdGlvbnM6IHtpZDogZXhpc3RpbmdSb3cuaWR9LCBkYXRhOiB7c3RhdGU6IFwiYWN0aXZlXCIsIHVwZGF0ZWRfYXQ6IG5ldyBEYXRlKCl9LCB0YWJsZU5hbWU6IFRBQkxFX05BTUV9KVxuICAgICAgICAgIGV4aXN0aW5nUm93LnN0YXRlID0gXCJhY3RpdmVcIlxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGV4aXN0aW5nUm93XG4gICAgICB9XG5cbiAgICAgIGF3YWl0IGRiLmluc2VydCh7XG4gICAgICAgIHRhYmxlTmFtZTogVEFCTEVfTkFNRSxcbiAgICAgICAgZGF0YToge1xuICAgICAgICAgIGNvbmRpdGlvbnNfanNvbjogc3RhYmxlSnNvblN0cmluZ2lmeShzY29wZS5jb25kaXRpb25zKSxcbiAgICAgICAgICBjcmVhdGVkX2F0OiBuZXcgRGF0ZSgpLFxuICAgICAgICAgIGN1cnNvcl9qc29uOiBudWxsLFxuICAgICAgICAgIGlkOiBuZXcgVVVJRCg0KS5mb3JtYXQoKSxcbiAgICAgICAgICByZXNvdXJjZV90eXBlOiBzY29wZS5yZXNvdXJjZVR5cGUsXG4gICAgICAgICAgc2NvcGVfZGlnZXN0OiBkaWdlc3QsXG4gICAgICAgICAgc3RhdGU6IFwiYWN0aXZlXCIsXG4gICAgICAgICAgdXBkYXRlZF9hdDogbmV3IERhdGUoKVxuICAgICAgICB9XG4gICAgICB9KVxuXG4gICAgICBjb25zdCBjcmVhdGVkUm93ID0gYXdhaXQgdGhpcy5fcm93QnlTY29wZURpZ2VzdChkYiwgZGlnZXN0KVxuXG4gICAgICBpZiAoIWNyZWF0ZWRSb3cpIHRocm93IG5ldyBFcnJvcihcIkZhaWxlZCB0byBwZXJzaXN0IHN5bmMgc2NvcGVcIilcblxuICAgICAgcmV0dXJuIGNyZWF0ZWRSb3dcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYWxsIGFjdGl2ZSBzY29wZSByb3dzLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxTeW5jU2NvcGVSb3dbXT59IEFjdGl2ZSBzY29wZSByb3dzLlxuICAgKi9cbiAgYXN5bmMgYWN0aXZlU2NvcGVzKCkge1xuICAgIGF3YWl0IHRoaXMuZW5zdXJlUmVhZHkoKVxuXG4gICAgaWYgKHRoaXMuX3VzZXNNZW1vcnlTdG9yYWdlKCkpIHtcbiAgICAgIHJldHVybiBbLi4udGhpcy5fbWVtb3J5U2NvcGVzLnZhbHVlcygpXS5maWx0ZXIoKHNjb3BlKSA9PiBzY29wZS5zdGF0ZSA9PT0gXCJhY3RpdmVcIilcbiAgICB9XG5cbiAgICByZXR1cm4gYXdhaXQgdGhpcy5fd2l0aERiKGFzeW5jIChkYikgPT4ge1xuICAgICAgY29uc3Qgcm93cyA9IC8qKiBAdHlwZSB7QXJyYXk8UmVjb3JkPHN0cmluZywgPz4+fSAqLyAoYXdhaXQgZGJcbiAgICAgICAgLm5ld1F1ZXJ5KClcbiAgICAgICAgLmZyb20oVEFCTEVfTkFNRSlcbiAgICAgICAgLndoZXJlKHtzdGF0ZTogXCJhY3RpdmVcIn0pXG4gICAgICAgIC5vcmRlcihcImNyZWF0ZWRfYXQgQVNDXCIpXG4gICAgICAgIC5yZXN1bHRzKCkpXG5cbiAgICAgIHJldHVybiByb3dzLm1hcCgocm93KSA9PiB0aGlzLl9ub3JtYWxpemVTY29wZVJvdyhyb3cpKVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogTG9hZHMgdGhlIHBlcnNpc3RlZCBjdXJzb3IgcGF5bG9hZCBmb3IgYSBzY29wZSByb3cuXG4gICAqIEBwYXJhbSB7U3luY1Njb3BlUm93fSBzY29wZVJvdyAtIFNjb3BlIHJvdy5cbiAgICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nIHwgbnVsbD59IEN1cnNvciBKU09OIHBheWxvYWQuXG4gICAqL1xuICBhc3luYyBsb2FkQ3Vyc29yKHNjb3BlUm93KSB7XG4gICAgYXdhaXQgdGhpcy5lbnN1cmVSZWFkeSgpXG5cbiAgICBpZiAodGhpcy5fdXNlc01lbW9yeVN0b3JhZ2UoKSkge1xuICAgICAgcmV0dXJuIHRoaXMuX21lbW9yeVNjb3Blcy5nZXQoc2NvcGVSb3cuc2NvcGVEaWdlc3QpPy5jdXJzb3JQYXlsb2FkID8/IG51bGxcbiAgICB9XG5cbiAgICByZXR1cm4gYXdhaXQgdGhpcy5fd2l0aERiKGFzeW5jIChkYikgPT4ge1xuICAgICAgY29uc3Qgcm93ID0gYXdhaXQgdGhpcy5fcm93QnlTY29wZURpZ2VzdChkYiwgc2NvcGVSb3cuc2NvcGVEaWdlc3QpXG5cbiAgICAgIHJldHVybiByb3cgPyByb3cuY3Vyc29yUGF5bG9hZCA6IG51bGxcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIFBlcnNpc3RzIHRoZSBhY2tub3dsZWRnZWQgY3Vyc29yIGZvciBhIHNjb3BlIHJvdy5cbiAgICogQHBhcmFtIHtTeW5jU2NvcGVSb3d9IHNjb3BlUm93IC0gU2NvcGUgcm93LlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4vc3luYy1hcGktY2xpZW50LXR5cGVzLmpzXCIpLlN5bmNDdXJzb3J9IGN1cnNvciAtIEFja25vd2xlZGdlZCBjdXJzb3IuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgc2F2ZUN1cnNvcihzY29wZVJvdywgY3Vyc29yKSB7XG4gICAgaWYgKCFjdXJzb3IpIHJldHVyblxuXG4gICAgYXdhaXQgdGhpcy5lbnN1cmVSZWFkeSgpXG5cbiAgICBjb25zdCBjdXJzb3JQYXlsb2FkID0gSlNPTi5zdHJpbmdpZnkoY3Vyc29yKVxuXG4gICAgaWYgKHRoaXMuX3VzZXNNZW1vcnlTdG9yYWdlKCkpIHtcbiAgICAgIGNvbnN0IG1lbW9yeVNjb3BlID0gdGhpcy5fbWVtb3J5U2NvcGVzLmdldChzY29wZVJvdy5zY29wZURpZ2VzdClcblxuICAgICAgaWYgKCFtZW1vcnlTY29wZSkgdGhyb3cgbmV3IEVycm9yKGBObyBzeW5jIHNjb3BlIGZvdW5kIGZvcjogJHtzY29wZVJvdy5zY29wZURpZ2VzdH1gKVxuXG4gICAgICBtZW1vcnlTY29wZS5jdXJzb3JQYXlsb2FkID0gY3Vyc29yUGF5bG9hZFxuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgYXdhaXQgdGhpcy5fd2l0aERiKGFzeW5jIChkYikgPT4ge1xuICAgICAgYXdhaXQgZGIudXBkYXRlKHtcbiAgICAgICAgY29uZGl0aW9uczoge3Njb3BlX2RpZ2VzdDogc2NvcGVSb3cuc2NvcGVEaWdlc3R9LFxuICAgICAgICBkYXRhOiB7Y3Vyc29yX2pzb246IGN1cnNvclBheWxvYWQsIHVwZGF0ZWRfYXQ6IG5ldyBEYXRlKCl9LFxuICAgICAgICB0YWJsZU5hbWU6IFRBQkxFX05BTUVcbiAgICAgIH0pXG4gICAgfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWFjdGl2YXRlcyB0aGUgc2NvcGUgcm93IGZvciBhIHNlcmlhbGl6ZWQgc2NvcGUuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi9zeW5jLWNsaWVudC10eXBlcy5qc1wiKS5TZXJpYWxpemVkU3luY1Njb3BlfSBzY29wZSAtIFNlcmlhbGl6ZWQgc3luYyBzY29wZS5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBkZWFjdGl2YXRlKHNjb3BlKSB7XG4gICAgYXdhaXQgdGhpcy5lbnN1cmVSZWFkeSgpXG5cbiAgICBjb25zdCBkaWdlc3QgPSBzY29wZURpZ2VzdEZvclNjb3BlKHNjb3BlKVxuXG4gICAgaWYgKHRoaXMuX3VzZXNNZW1vcnlTdG9yYWdlKCkpIHtcbiAgICAgIGNvbnN0IG1lbW9yeVNjb3BlID0gdGhpcy5fbWVtb3J5U2NvcGVzLmdldChkaWdlc3QpXG5cbiAgICAgIGlmIChtZW1vcnlTY29wZSkgbWVtb3J5U2NvcGUuc3RhdGUgPSBcInJlbW92ZWRcIlxuXG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICBhd2FpdCB0aGlzLl93aXRoRGIoYXN5bmMgKGRiKSA9PiB7XG4gICAgICBhd2FpdCBkYi51cGRhdGUoe2NvbmRpdGlvbnM6IHtzY29wZV9kaWdlc3Q6IGRpZ2VzdH0sIGRhdGE6IHtzdGF0ZTogXCJyZW1vdmVkXCIsIHVwZGF0ZWRfYXQ6IG5ldyBEYXRlKCl9LCB0YWJsZU5hbWU6IFRBQkxFX05BTUV9KVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogV2hldGhlciB0aGUgc3RvcmUgcnVucyB3aXRob3V0IGEgY29uZmlndXJlZCBkYXRhYmFzZS5cbiAgICogQHJldHVybnMge2Jvb2xlYW59IFdoZXRoZXIgbWVtb3J5IHN0b3JhZ2UgaXMgdXNlZC5cbiAgICovXG4gIF91c2VzTWVtb3J5U3RvcmFnZSgpIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuICF0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0RGF0YWJhc2VDb25maWd1cmF0aW9uKClbdGhpcy5kYXRhYmFzZUlkZW50aWZpZXJdXG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4gdHJ1ZVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGEgY2FsbGJhY2sgd2l0aCBhIGRhdGFiYXNlIGNvbm5lY3Rpb24uXG4gICAqIEB0ZW1wbGF0ZSBSZXN1bHRcbiAgICogQHBhcmFtIHsoZGI6IGltcG9ydChcIi4uL2RhdGFiYXNlL2RyaXZlcnMvYmFzZS5qc1wiKS5kZWZhdWx0KSA9PiBQcm9taXNlPFJlc3VsdD59IGNhbGxiYWNrIC0gRGF0YWJhc2UgY2FsbGJhY2suXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPFJlc3VsdD59IENhbGxiYWNrIHJlc3VsdC5cbiAgICovXG4gIGFzeW5jIF93aXRoRGIoY2FsbGJhY2spIHtcbiAgICByZXR1cm4gYXdhaXQgdGhpcy5jb25maWd1cmF0aW9uLmVuc3VyZUNvbm5lY3Rpb25zKHtuYW1lOiBcIlN5bmMgc2NvcGUgc3RvcmVcIn0sIGFzeW5jIChkYnMpID0+IHtcbiAgICAgIGNvbnN0IGRiID0gZGJzW3RoaXMuZGF0YWJhc2VJZGVudGlmaWVyXVxuXG4gICAgICBpZiAoIWRiKSB0aHJvdyBuZXcgRXJyb3IoYE5vIGRhdGFiYXNlIGNvbm5lY3Rpb24gYXZhaWxhYmxlIGZvciBpZGVudGlmaWVyOiAke3RoaXMuZGF0YWJhc2VJZGVudGlmaWVyfWApXG5cbiAgICAgIHJldHVybiBhd2FpdCBjYWxsYmFjayhkYilcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIEVuc3VyZXMgdGhlIHNjb3BlcyB0YWJsZSBleGlzdHMuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vZGF0YWJhc2UvZHJpdmVycy9iYXNlLmpzXCIpLmRlZmF1bHR9IGRiIC0gRGF0YWJhc2UgY29ubmVjdGlvbi5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBfZW5zdXJlU2NvcGVzVGFibGUoZGIpIHtcbiAgICBpZiAoYXdhaXQgZGIudGFibGVFeGlzdHMoVEFCTEVfTkFNRSkpIHJldHVyblxuXG4gICAgY29uc3QgdGFibGUgPSBuZXcgVGFibGVEYXRhKFRBQkxFX05BTUUsIHtpZk5vdEV4aXN0czogdHJ1ZX0pXG5cbiAgICB0YWJsZS5zdHJpbmcoXCJpZFwiLCB7bnVsbDogZmFsc2UsIHByaW1hcnlLZXk6IHRydWV9KVxuICAgIHRhYmxlLnN0cmluZyhcInNjb3BlX2RpZ2VzdFwiLCB7aW5kZXg6IHRydWUsIG51bGw6IGZhbHNlfSlcbiAgICB0YWJsZS5zdHJpbmcoXCJyZXNvdXJjZV90eXBlXCIsIHtpbmRleDogdHJ1ZSwgbnVsbDogZmFsc2V9KVxuICAgIHRhYmxlLnRleHQoXCJjb25kaXRpb25zX2pzb25cIiwge251bGw6IGZhbHNlfSlcbiAgICB0YWJsZS50ZXh0KFwiY3Vyc29yX2pzb25cIiwge251bGw6IHRydWV9KVxuICAgIHRhYmxlLnN0cmluZyhcInN0YXRlXCIsIHtpbmRleDogdHJ1ZSwgbnVsbDogZmFsc2V9KVxuICAgIHRhYmxlLmRhdGV0aW1lKFwiY3JlYXRlZF9hdFwiLCB7bnVsbDogZmFsc2V9KVxuICAgIHRhYmxlLmRhdGV0aW1lKFwidXBkYXRlZF9hdFwiLCB7bnVsbDogZmFsc2V9KVxuXG4gICAgYXdhaXQgZGIuY3JlYXRlVGFibGUodGFibGUpXG4gIH1cblxuICAvKipcbiAgICogUmVzb2x2ZXMgYSBzY29wZSByb3cgYnkgaXRzIGRpZ2VzdC5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuLi9kYXRhYmFzZS9kcml2ZXJzL2Jhc2UuanNcIikuZGVmYXVsdH0gZGIgLSBEYXRhYmFzZSBjb25uZWN0aW9uLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gZGlnZXN0IC0gRml4ZWQtc2l6ZSBzY29wZSBkaWdlc3QuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPFN5bmNTY29wZVJvdyB8IG51bGw+fSBTY29wZSByb3cgb3IgbnVsbC5cbiAgICovXG4gIGFzeW5jIF9yb3dCeVNjb3BlRGlnZXN0KGRiLCBkaWdlc3QpIHtcbiAgICBjb25zdCByb3dzID0gLyoqIEB0eXBlIHtBcnJheTxSZWNvcmQ8c3RyaW5nLCA/Pj59ICovIChhd2FpdCBkYlxuICAgICAgLm5ld1F1ZXJ5KClcbiAgICAgIC5mcm9tKFRBQkxFX05BTUUpXG4gICAgICAud2hlcmUoe3Njb3BlX2RpZ2VzdDogZGlnZXN0fSlcbiAgICAgIC5saW1pdCgxKVxuICAgICAgLnJlc3VsdHMoKSlcblxuICAgIHJldHVybiByb3dzWzBdID8gdGhpcy5fbm9ybWFsaXplU2NvcGVSb3cocm93c1swXSkgOiBudWxsXG4gIH1cblxuICAvKipcbiAgICogTm9ybWFsaXplcyBhIHJhdyBzY29wZSB0YWJsZSByb3cuXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgPz59IHJvdyAtIFJhdyB0YWJsZSByb3cuXG4gICAqIEByZXR1cm5zIHtTeW5jU2NvcGVSb3d9IE5vcm1hbGl6ZWQgc2NvcGUgcm93LlxuICAgKi9cbiAgX25vcm1hbGl6ZVNjb3BlUm93KHJvdykge1xuICAgIHJldHVybiB7XG4gICAgICBjb25kaXRpb25zOiAvKiogQHR5cGUge1JlY29yZDxzdHJpbmcsID8+fSAqLyAoSlNPTi5wYXJzZShTdHJpbmcocm93LmNvbmRpdGlvbnNfanNvbikpKSxcbiAgICAgIGN1cnNvclBheWxvYWQ6IHJvdy5jdXJzb3JfanNvbiA9PT0gbnVsbCB8fCByb3cuY3Vyc29yX2pzb24gPT09IHVuZGVmaW5lZCA/IG51bGwgOiBTdHJpbmcocm93LmN1cnNvcl9qc29uKSxcbiAgICAgIGlkOiBTdHJpbmcocm93LmlkKSxcbiAgICAgIHJlc291cmNlVHlwZTogU3RyaW5nKHJvdy5yZXNvdXJjZV90eXBlKSxcbiAgICAgIHNjb3BlRGlnZXN0OiBTdHJpbmcocm93LnNjb3BlX2RpZ2VzdCksXG4gICAgICBzdGF0ZTogU3RyaW5nKHJvdy5zdGF0ZSlcbiAgICB9XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Creates the tenant database for one tenant.
3
+ * @param {{configuration: import("../configuration.js").default, databaseConfiguration: import("../configuration-types.js").DatabaseConfigurationType, tenant: ?}} args - Provisioning arguments.
4
+ * @returns {Promise<void>} - Resolves once the tenant database exists.
5
+ */
6
+ export function createTenantDatabase({ configuration, databaseConfiguration, tenant }: {
7
+ configuration: import("../configuration.js").default;
8
+ databaseConfiguration: import("../configuration-types.js").DatabaseConfigurationType;
9
+ tenant: unknown;
10
+ }): Promise<void>;
11
+ /**
12
+ * Drops the tenant database for one tenant. Uses `DROP DATABASE IF EXISTS`, so it
13
+ * is a safe no-op for a tenant that was never fully provisioned.
14
+ * @param {{configuration: import("../configuration.js").default, databaseConfiguration: import("../configuration-types.js").DatabaseConfigurationType}} args - Provisioning arguments.
15
+ * @returns {Promise<void>} - Resolves once the tenant database is gone.
16
+ */
17
+ export function dropTenantDatabase({ configuration, databaseConfiguration }: {
18
+ configuration: import("../configuration.js").default;
19
+ databaseConfiguration: import("../configuration-types.js").DatabaseConfigurationType;
20
+ }): Promise<void>;
21
+ //# sourceMappingURL=default-tenant-database-provisioning.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"default-tenant-database-provisioning.d.ts","sourceRoot":"","sources":["../../../src/tenants/default-tenant-database-provisioning.js"],"names":[],"mappings":"AAgEA;;;;GAIG;AACH,uFAHW;IAAC,aAAa,EAAE,OAAO,qBAAqB,EAAE,OAAO,CAAC;IAAC,qBAAqB,EAAE,OAAO,2BAA2B,EAAE,yBAAyB,CAAC;IAAC,MAAM,EAAE,OAAC,CAAA;CAAC,GACrJ,OAAO,CAAC,IAAI,CAAC,CA6BzB;AAED;;;;;GAKG;AACH,6EAHW;IAAC,aAAa,EAAE,OAAO,qBAAqB,EAAE,OAAO,CAAC;IAAC,qBAAqB,EAAE,OAAO,2BAA2B,EAAE,yBAAyB,CAAA;CAAC,GAC1I,OAAO,CAAC,IAAI,CAAC,CAqBzB"}
@@ -0,0 +1,106 @@
1
+ // @ts-check
2
+ /**
3
+ * Default tenant-database provisioning used by `db:tenants:create`,
4
+ * `db:tenants:drop`, and `Tenant.drop` when a tenant-database provider does not
5
+ * define its own `createDatabase`/`dropDatabase`. This is the generic,
6
+ * driver-agnostic lifecycle every app on the tenant framework needs, so it lives
7
+ * in the framework instead of being reimplemented in each consuming project.
8
+ *
9
+ * File-backed drivers (sqlite) have no server-side CREATE/DROP DATABASE — the file
10
+ * is created on connect and left in place on drop — so creating just ensures the
11
+ * tenant's connection and dropping is a no-op. Server drivers (mysql, pgsql, …)
12
+ * connect to the configured maintenance database (`useDatabase`) and run the
13
+ * driver's own `createDatabaseSql`/`dropDatabaseSql`.
14
+ */
15
+ const SAFE_TENANT_DATABASE_NAME = /^[a-z0-9_]+$/;
16
+ /**
17
+ * Whether the driver stores each database as a local file instead of on a server.
18
+ * @param {import("../configuration-types.js").DatabaseConfigurationType} databaseConfiguration - Resolved tenant database configuration.
19
+ * @returns {boolean} - True for file-backed drivers such as sqlite.
20
+ */
21
+ function fileBackedDriver(databaseConfiguration) {
22
+ return databaseConfiguration.type === "sqlite";
23
+ }
24
+ /**
25
+ * Validates the tenant database name against a strict allowlist before it is
26
+ * interpolated into DDL.
27
+ * @param {import("../configuration-types.js").DatabaseConfigurationType} databaseConfiguration - Resolved tenant database configuration.
28
+ * @returns {string} - The validated tenant database name.
29
+ */
30
+ function guardedDatabaseName(databaseConfiguration) {
31
+ const databaseName = databaseConfiguration.database;
32
+ if (!databaseName || !SAFE_TENANT_DATABASE_NAME.test(databaseName)) {
33
+ throw new Error(`Unsafe tenant database name: ${databaseName}`);
34
+ }
35
+ return databaseName;
36
+ }
37
+ /**
38
+ * Opens a driver connected to the server's maintenance database (`useDatabase`),
39
+ * from which `CREATE DATABASE` / `DROP DATABASE` for the tenant can be issued.
40
+ * @param {import("../configuration-types.js").DatabaseConfigurationType} databaseConfiguration - Resolved tenant database configuration.
41
+ * @param {import("../configuration.js").default} configuration - The Velocious configuration.
42
+ * @returns {import("../database/drivers/base.js").default} - A driver bound to the maintenance database.
43
+ */
44
+ function maintenanceConnection(databaseConfiguration, configuration) {
45
+ const DriverClass = databaseConfiguration.driver;
46
+ if (!DriverClass) {
47
+ throw new Error("Tenant database configuration is missing a driver.");
48
+ }
49
+ if (!databaseConfiguration.useDatabase) {
50
+ throw new Error("Tenant database configuration is missing a maintenance database in useDatabase.");
51
+ }
52
+ return new DriverClass({ ...databaseConfiguration, database: databaseConfiguration.useDatabase }, configuration);
53
+ }
54
+ /**
55
+ * Creates the tenant database for one tenant.
56
+ * @param {{configuration: import("../configuration.js").default, databaseConfiguration: import("../configuration-types.js").DatabaseConfigurationType, tenant: ?}} args - Provisioning arguments.
57
+ * @returns {Promise<void>} - Resolves once the tenant database exists.
58
+ */
59
+ export async function createTenantDatabase({ configuration, databaseConfiguration, tenant }) {
60
+ if (fileBackedDriver(databaseConfiguration)) {
61
+ await configuration.runWithTenant(tenant, async () => {
62
+ await configuration.ensureConnections(async () => { });
63
+ });
64
+ return;
65
+ }
66
+ const databaseName = guardedDatabaseName(databaseConfiguration);
67
+ const connection = maintenanceConnection(databaseConfiguration, configuration);
68
+ await connection.connect();
69
+ try {
70
+ const sqls = connection.createDatabaseSql(databaseName, {
71
+ databaseCharset: databaseConfiguration.databaseCharset,
72
+ databaseCollation: databaseConfiguration.databaseCollation,
73
+ ifNotExists: true
74
+ });
75
+ for (const sql of sqls) {
76
+ await connection.query(sql);
77
+ }
78
+ }
79
+ finally {
80
+ await connection.close();
81
+ }
82
+ }
83
+ /**
84
+ * Drops the tenant database for one tenant. Uses `DROP DATABASE IF EXISTS`, so it
85
+ * is a safe no-op for a tenant that was never fully provisioned.
86
+ * @param {{configuration: import("../configuration.js").default, databaseConfiguration: import("../configuration-types.js").DatabaseConfigurationType}} args - Provisioning arguments.
87
+ * @returns {Promise<void>} - Resolves once the tenant database is gone.
88
+ */
89
+ export async function dropTenantDatabase({ configuration, databaseConfiguration }) {
90
+ if (fileBackedDriver(databaseConfiguration)) {
91
+ return;
92
+ }
93
+ const databaseName = guardedDatabaseName(databaseConfiguration);
94
+ const connection = maintenanceConnection(databaseConfiguration, configuration);
95
+ await connection.connect();
96
+ try {
97
+ const sqls = connection.dropDatabaseSql(databaseName, { ifExists: true });
98
+ for (const sql of sqls) {
99
+ await connection.query(sql);
100
+ }
101
+ }
102
+ finally {
103
+ await connection.close();
104
+ }
105
+ }
106
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVmYXVsdC10ZW5hbnQtZGF0YWJhc2UtcHJvdmlzaW9uaW5nLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RlbmFudHMvZGVmYXVsdC10ZW5hbnQtZGF0YWJhc2UtcHJvdmlzaW9uaW5nLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWjs7Ozs7Ozs7Ozs7O0dBWUc7QUFFSCxNQUFNLHlCQUF5QixHQUFHLGNBQWMsQ0FBQTtBQUVoRDs7OztHQUlHO0FBQ0gsU0FBUyxnQkFBZ0IsQ0FBQyxxQkFBcUI7SUFDN0MsT0FBTyxxQkFBcUIsQ0FBQyxJQUFJLEtBQUssUUFBUSxDQUFBO0FBQ2hELENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILFNBQVMsbUJBQW1CLENBQUMscUJBQXFCO0lBQ2hELE1BQU0sWUFBWSxHQUFHLHFCQUFxQixDQUFDLFFBQVEsQ0FBQTtJQUVuRCxJQUFJLENBQUMsWUFBWSxJQUFJLENBQUMseUJBQXlCLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUM7UUFDbkUsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsWUFBWSxFQUFFLENBQUMsQ0FBQTtJQUNqRSxDQUFDO0lBRUQsT0FBTyxZQUFZLENBQUE7QUFDckIsQ0FBQztBQUVEOzs7Ozs7R0FNRztBQUNILFNBQVMscUJBQXFCLENBQUMscUJBQXFCLEVBQUUsYUFBYTtJQUNqRSxNQUFNLFdBQVcsR0FBRyxxQkFBcUIsQ0FBQyxNQUFNLENBQUE7SUFFaEQsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ2pCLE1BQU0sSUFBSSxLQUFLLENBQUMsb0RBQW9ELENBQUMsQ0FBQTtJQUN2RSxDQUFDO0lBRUQsSUFBSSxDQUFDLHFCQUFxQixDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ3ZDLE1BQU0sSUFBSSxLQUFLLENBQUMsaUZBQWlGLENBQUMsQ0FBQTtJQUNwRyxDQUFDO0lBRUQsT0FBTyxJQUFJLFdBQVcsQ0FBQyxFQUFDLEdBQUcscUJBQXFCLEVBQUUsUUFBUSxFQUFFLHFCQUFxQixDQUFDLFdBQVcsRUFBQyxFQUFFLGFBQWEsQ0FBQyxDQUFBO0FBQ2hILENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxvQkFBb0IsQ0FBQyxFQUFDLGFBQWEsRUFBRSxxQkFBcUIsRUFBRSxNQUFNLEVBQUM7SUFDdkYsSUFBSSxnQkFBZ0IsQ0FBQyxxQkFBcUIsQ0FBQyxFQUFFLENBQUM7UUFDNUMsTUFBTSxhQUFhLENBQUMsYUFBYSxDQUFDLE1BQU0sRUFBRSxLQUFLLElBQUksRUFBRTtZQUNuRCxNQUFNLGFBQWEsQ0FBQyxpQkFBaUIsQ0FBQyxLQUFLLElBQUksRUFBRSxHQUFFLENBQUMsQ0FBQyxDQUFBO1FBQ3ZELENBQUMsQ0FBQyxDQUFBO1FBRUYsT0FBTTtJQUNSLENBQUM7SUFFRCxNQUFNLFlBQVksR0FBRyxtQkFBbUIsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFBO0lBQy9ELE1BQU0sVUFBVSxHQUFHLHFCQUFxQixDQUFDLHFCQUFxQixFQUFFLGFBQWEsQ0FBQyxDQUFBO0lBRTlFLE1BQU0sVUFBVSxDQUFDLE9BQU8sRUFBRSxDQUFBO0lBRTFCLElBQUksQ0FBQztRQUNILE1BQU0sSUFBSSxHQUFHLFVBQVUsQ0FBQyxpQkFBaUIsQ0FBQyxZQUFZLEVBQUU7WUFDdEQsZUFBZSxFQUFFLHFCQUFxQixDQUFDLGVBQWU7WUFDdEQsaUJBQWlCLEVBQUUscUJBQXFCLENBQUMsaUJBQWlCO1lBQzFELFdBQVcsRUFBRSxJQUFJO1NBQ2xCLENBQUMsQ0FBQTtRQUVGLEtBQUssTUFBTSxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7WUFDdkIsTUFBTSxVQUFVLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFBO1FBQzdCLENBQUM7SUFDSCxDQUFDO1lBQVMsQ0FBQztRQUNULE1BQU0sVUFBVSxDQUFDLEtBQUssRUFBRSxDQUFBO0lBQzFCLENBQUM7QUFDSCxDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLGtCQUFrQixDQUFDLEVBQUMsYUFBYSxFQUFFLHFCQUFxQixFQUFDO0lBQzdFLElBQUksZ0JBQWdCLENBQUMscUJBQXFCLENBQUMsRUFBRSxDQUFDO1FBQzVDLE9BQU07SUFDUixDQUFDO0lBRUQsTUFBTSxZQUFZLEdBQUcsbUJBQW1CLENBQUMscUJBQXFCLENBQUMsQ0FBQTtJQUMvRCxNQUFNLFVBQVUsR0FBRyxxQkFBcUIsQ0FBQyxxQkFBcUIsRUFBRSxhQUFhLENBQUMsQ0FBQTtJQUU5RSxNQUFNLFVBQVUsQ0FBQyxPQUFPLEVBQUUsQ0FBQTtJQUUxQixJQUFJLENBQUM7UUFDSCxNQUFNLElBQUksR0FBRyxVQUFVLENBQUMsZUFBZSxDQUFDLFlBQVksRUFBRSxFQUFDLFFBQVEsRUFBRSxJQUFJLEVBQUMsQ0FBQyxDQUFBO1FBRXZFLEtBQUssTUFBTSxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7WUFDdkIsTUFBTSxVQUFVLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFBO1FBQzdCLENBQUM7SUFDSCxDQUFDO1lBQVMsQ0FBQztRQUNULE1BQU0sVUFBVSxDQUFDLEtBQUssRUFBRSxDQUFBO0lBQzFCLENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbi8qKlxuICogRGVmYXVsdCB0ZW5hbnQtZGF0YWJhc2UgcHJvdmlzaW9uaW5nIHVzZWQgYnkgYGRiOnRlbmFudHM6Y3JlYXRlYCxcbiAqIGBkYjp0ZW5hbnRzOmRyb3BgLCBhbmQgYFRlbmFudC5kcm9wYCB3aGVuIGEgdGVuYW50LWRhdGFiYXNlIHByb3ZpZGVyIGRvZXMgbm90XG4gKiBkZWZpbmUgaXRzIG93biBgY3JlYXRlRGF0YWJhc2VgL2Bkcm9wRGF0YWJhc2VgLiBUaGlzIGlzIHRoZSBnZW5lcmljLFxuICogZHJpdmVyLWFnbm9zdGljIGxpZmVjeWNsZSBldmVyeSBhcHAgb24gdGhlIHRlbmFudCBmcmFtZXdvcmsgbmVlZHMsIHNvIGl0IGxpdmVzXG4gKiBpbiB0aGUgZnJhbWV3b3JrIGluc3RlYWQgb2YgYmVpbmcgcmVpbXBsZW1lbnRlZCBpbiBlYWNoIGNvbnN1bWluZyBwcm9qZWN0LlxuICpcbiAqIEZpbGUtYmFja2VkIGRyaXZlcnMgKHNxbGl0ZSkgaGF2ZSBubyBzZXJ2ZXItc2lkZSBDUkVBVEUvRFJPUCBEQVRBQkFTRSDigJQgdGhlIGZpbGVcbiAqIGlzIGNyZWF0ZWQgb24gY29ubmVjdCBhbmQgbGVmdCBpbiBwbGFjZSBvbiBkcm9wIOKAlCBzbyBjcmVhdGluZyBqdXN0IGVuc3VyZXMgdGhlXG4gKiB0ZW5hbnQncyBjb25uZWN0aW9uIGFuZCBkcm9wcGluZyBpcyBhIG5vLW9wLiBTZXJ2ZXIgZHJpdmVycyAobXlzcWwsIHBnc3FsLCDigKYpXG4gKiBjb25uZWN0IHRvIHRoZSBjb25maWd1cmVkIG1haW50ZW5hbmNlIGRhdGFiYXNlIChgdXNlRGF0YWJhc2VgKSBhbmQgcnVuIHRoZVxuICogZHJpdmVyJ3Mgb3duIGBjcmVhdGVEYXRhYmFzZVNxbGAvYGRyb3BEYXRhYmFzZVNxbGAuXG4gKi9cblxuY29uc3QgU0FGRV9URU5BTlRfREFUQUJBU0VfTkFNRSA9IC9eW2EtejAtOV9dKyQvXG5cbi8qKlxuICogV2hldGhlciB0aGUgZHJpdmVyIHN0b3JlcyBlYWNoIGRhdGFiYXNlIGFzIGEgbG9jYWwgZmlsZSBpbnN0ZWFkIG9mIG9uIGEgc2VydmVyLlxuICogQHBhcmFtIHtpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLkRhdGFiYXNlQ29uZmlndXJhdGlvblR5cGV9IGRhdGFiYXNlQ29uZmlndXJhdGlvbiAtIFJlc29sdmVkIHRlbmFudCBkYXRhYmFzZSBjb25maWd1cmF0aW9uLlxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBmb3IgZmlsZS1iYWNrZWQgZHJpdmVycyBzdWNoIGFzIHNxbGl0ZS5cbiAqL1xuZnVuY3Rpb24gZmlsZUJhY2tlZERyaXZlcihkYXRhYmFzZUNvbmZpZ3VyYXRpb24pIHtcbiAgcmV0dXJuIGRhdGFiYXNlQ29uZmlndXJhdGlvbi50eXBlID09PSBcInNxbGl0ZVwiXG59XG5cbi8qKlxuICogVmFsaWRhdGVzIHRoZSB0ZW5hbnQgZGF0YWJhc2UgbmFtZSBhZ2FpbnN0IGEgc3RyaWN0IGFsbG93bGlzdCBiZWZvcmUgaXQgaXNcbiAqIGludGVycG9sYXRlZCBpbnRvIERETC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5EYXRhYmFzZUNvbmZpZ3VyYXRpb25UeXBlfSBkYXRhYmFzZUNvbmZpZ3VyYXRpb24gLSBSZXNvbHZlZCB0ZW5hbnQgZGF0YWJhc2UgY29uZmlndXJhdGlvbi5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIHZhbGlkYXRlZCB0ZW5hbnQgZGF0YWJhc2UgbmFtZS5cbiAqL1xuZnVuY3Rpb24gZ3VhcmRlZERhdGFiYXNlTmFtZShkYXRhYmFzZUNvbmZpZ3VyYXRpb24pIHtcbiAgY29uc3QgZGF0YWJhc2VOYW1lID0gZGF0YWJhc2VDb25maWd1cmF0aW9uLmRhdGFiYXNlXG5cbiAgaWYgKCFkYXRhYmFzZU5hbWUgfHwgIVNBRkVfVEVOQU5UX0RBVEFCQVNFX05BTUUudGVzdChkYXRhYmFzZU5hbWUpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBVbnNhZmUgdGVuYW50IGRhdGFiYXNlIG5hbWU6ICR7ZGF0YWJhc2VOYW1lfWApXG4gIH1cblxuICByZXR1cm4gZGF0YWJhc2VOYW1lXG59XG5cbi8qKlxuICogT3BlbnMgYSBkcml2ZXIgY29ubmVjdGVkIHRvIHRoZSBzZXJ2ZXIncyBtYWludGVuYW5jZSBkYXRhYmFzZSAoYHVzZURhdGFiYXNlYCksXG4gKiBmcm9tIHdoaWNoIGBDUkVBVEUgREFUQUJBU0VgIC8gYERST1AgREFUQUJBU0VgIGZvciB0aGUgdGVuYW50IGNhbiBiZSBpc3N1ZWQuXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24tdHlwZXMuanNcIikuRGF0YWJhc2VDb25maWd1cmF0aW9uVHlwZX0gZGF0YWJhc2VDb25maWd1cmF0aW9uIC0gUmVzb2x2ZWQgdGVuYW50IGRhdGFiYXNlIGNvbmZpZ3VyYXRpb24uXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24uanNcIikuZGVmYXVsdH0gY29uZmlndXJhdGlvbiAtIFRoZSBWZWxvY2lvdXMgY29uZmlndXJhdGlvbi5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9kYXRhYmFzZS9kcml2ZXJzL2Jhc2UuanNcIikuZGVmYXVsdH0gLSBBIGRyaXZlciBib3VuZCB0byB0aGUgbWFpbnRlbmFuY2UgZGF0YWJhc2UuXG4gKi9cbmZ1bmN0aW9uIG1haW50ZW5hbmNlQ29ubmVjdGlvbihkYXRhYmFzZUNvbmZpZ3VyYXRpb24sIGNvbmZpZ3VyYXRpb24pIHtcbiAgY29uc3QgRHJpdmVyQ2xhc3MgPSBkYXRhYmFzZUNvbmZpZ3VyYXRpb24uZHJpdmVyXG5cbiAgaWYgKCFEcml2ZXJDbGFzcykge1xuICAgIHRocm93IG5ldyBFcnJvcihcIlRlbmFudCBkYXRhYmFzZSBjb25maWd1cmF0aW9uIGlzIG1pc3NpbmcgYSBkcml2ZXIuXCIpXG4gIH1cblxuICBpZiAoIWRhdGFiYXNlQ29uZmlndXJhdGlvbi51c2VEYXRhYmFzZSkge1xuICAgIHRocm93IG5ldyBFcnJvcihcIlRlbmFudCBkYXRhYmFzZSBjb25maWd1cmF0aW9uIGlzIG1pc3NpbmcgYSBtYWludGVuYW5jZSBkYXRhYmFzZSBpbiB1c2VEYXRhYmFzZS5cIilcbiAgfVxuXG4gIHJldHVybiBuZXcgRHJpdmVyQ2xhc3Moey4uLmRhdGFiYXNlQ29uZmlndXJhdGlvbiwgZGF0YWJhc2U6IGRhdGFiYXNlQ29uZmlndXJhdGlvbi51c2VEYXRhYmFzZX0sIGNvbmZpZ3VyYXRpb24pXG59XG5cbi8qKlxuICogQ3JlYXRlcyB0aGUgdGVuYW50IGRhdGFiYXNlIGZvciBvbmUgdGVuYW50LlxuICogQHBhcmFtIHt7Y29uZmlndXJhdGlvbjogaW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi5qc1wiKS5kZWZhdWx0LCBkYXRhYmFzZUNvbmZpZ3VyYXRpb246IGltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24tdHlwZXMuanNcIikuRGF0YWJhc2VDb25maWd1cmF0aW9uVHlwZSwgdGVuYW50OiA/fX0gYXJncyAtIFByb3Zpc2lvbmluZyBhcmd1bWVudHMuXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyBvbmNlIHRoZSB0ZW5hbnQgZGF0YWJhc2UgZXhpc3RzLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlVGVuYW50RGF0YWJhc2Uoe2NvbmZpZ3VyYXRpb24sIGRhdGFiYXNlQ29uZmlndXJhdGlvbiwgdGVuYW50fSkge1xuICBpZiAoZmlsZUJhY2tlZERyaXZlcihkYXRhYmFzZUNvbmZpZ3VyYXRpb24pKSB7XG4gICAgYXdhaXQgY29uZmlndXJhdGlvbi5ydW5XaXRoVGVuYW50KHRlbmFudCwgYXN5bmMgKCkgPT4ge1xuICAgICAgYXdhaXQgY29uZmlndXJhdGlvbi5lbnN1cmVDb25uZWN0aW9ucyhhc3luYyAoKSA9PiB7fSlcbiAgICB9KVxuXG4gICAgcmV0dXJuXG4gIH1cblxuICBjb25zdCBkYXRhYmFzZU5hbWUgPSBndWFyZGVkRGF0YWJhc2VOYW1lKGRhdGFiYXNlQ29uZmlndXJhdGlvbilcbiAgY29uc3QgY29ubmVjdGlvbiA9IG1haW50ZW5hbmNlQ29ubmVjdGlvbihkYXRhYmFzZUNvbmZpZ3VyYXRpb24sIGNvbmZpZ3VyYXRpb24pXG5cbiAgYXdhaXQgY29ubmVjdGlvbi5jb25uZWN0KClcblxuICB0cnkge1xuICAgIGNvbnN0IHNxbHMgPSBjb25uZWN0aW9uLmNyZWF0ZURhdGFiYXNlU3FsKGRhdGFiYXNlTmFtZSwge1xuICAgICAgZGF0YWJhc2VDaGFyc2V0OiBkYXRhYmFzZUNvbmZpZ3VyYXRpb24uZGF0YWJhc2VDaGFyc2V0LFxuICAgICAgZGF0YWJhc2VDb2xsYXRpb246IGRhdGFiYXNlQ29uZmlndXJhdGlvbi5kYXRhYmFzZUNvbGxhdGlvbixcbiAgICAgIGlmTm90RXhpc3RzOiB0cnVlXG4gICAgfSlcblxuICAgIGZvciAoY29uc3Qgc3FsIG9mIHNxbHMpIHtcbiAgICAgIGF3YWl0IGNvbm5lY3Rpb24ucXVlcnkoc3FsKVxuICAgIH1cbiAgfSBmaW5hbGx5IHtcbiAgICBhd2FpdCBjb25uZWN0aW9uLmNsb3NlKClcbiAgfVxufVxuXG4vKipcbiAqIERyb3BzIHRoZSB0ZW5hbnQgZGF0YWJhc2UgZm9yIG9uZSB0ZW5hbnQuIFVzZXMgYERST1AgREFUQUJBU0UgSUYgRVhJU1RTYCwgc28gaXRcbiAqIGlzIGEgc2FmZSBuby1vcCBmb3IgYSB0ZW5hbnQgdGhhdCB3YXMgbmV2ZXIgZnVsbHkgcHJvdmlzaW9uZWQuXG4gKiBAcGFyYW0ge3tjb25maWd1cmF0aW9uOiBpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLmpzXCIpLmRlZmF1bHQsIGRhdGFiYXNlQ29uZmlndXJhdGlvbjogaW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5EYXRhYmFzZUNvbmZpZ3VyYXRpb25UeXBlfX0gYXJncyAtIFByb3Zpc2lvbmluZyBhcmd1bWVudHMuXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyBvbmNlIHRoZSB0ZW5hbnQgZGF0YWJhc2UgaXMgZ29uZS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGRyb3BUZW5hbnREYXRhYmFzZSh7Y29uZmlndXJhdGlvbiwgZGF0YWJhc2VDb25maWd1cmF0aW9ufSkge1xuICBpZiAoZmlsZUJhY2tlZERyaXZlcihkYXRhYmFzZUNvbmZpZ3VyYXRpb24pKSB7XG4gICAgcmV0dXJuXG4gIH1cblxuICBjb25zdCBkYXRhYmFzZU5hbWUgPSBndWFyZGVkRGF0YWJhc2VOYW1lKGRhdGFiYXNlQ29uZmlndXJhdGlvbilcbiAgY29uc3QgY29ubmVjdGlvbiA9IG1haW50ZW5hbmNlQ29ubmVjdGlvbihkYXRhYmFzZUNvbmZpZ3VyYXRpb24sIGNvbmZpZ3VyYXRpb24pXG5cbiAgYXdhaXQgY29ubmVjdGlvbi5jb25uZWN0KClcblxuICB0cnkge1xuICAgIGNvbnN0IHNxbHMgPSBjb25uZWN0aW9uLmRyb3BEYXRhYmFzZVNxbChkYXRhYmFzZU5hbWUsIHtpZkV4aXN0czogdHJ1ZX0pXG5cbiAgICBmb3IgKGNvbnN0IHNxbCBvZiBzcWxzKSB7XG4gICAgICBhd2FpdCBjb25uZWN0aW9uLnF1ZXJ5KHNxbClcbiAgICB9XG4gIH0gZmluYWxseSB7XG4gICAgYXdhaXQgY29ubmVjdGlvbi5jbG9zZSgpXG4gIH1cbn1cbiJdfQ==
@@ -1 +1 @@
1
- {"version":3,"file":"tenant.d.ts","sourceRoot":"","sources":["../../../src/tenants/tenant.js"],"names":[],"mappings":"AAKA;;;;;;;;;;GAUG;AACH;IACE;;;;;;;;;;;;OAYG;IACH,YALa,CAAC,UACH,MAAM,YACN,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,6BAA6B,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GACxF,OAAO,CAAC,CAAC,CAAC,CAMtB;IAED;;;OAGG;IACH,kBAFa,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAI/C;IAED;;;;;;;;OAQG;IACH,uEAHW;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,CAAS,IAAiG,EAAjG;YAAC,qBAAqB,EAAE,OAAO,2BAA2B,EAAE,yBAAyB,CAAC;YAAC,MAAM,EAAE,OAAC,CAAA;SAAC,KAAI,OAAO,CAAC,IAAI,CAAC,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,OAAC,KAAK,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,OAAO,qBAAqB,EAAE,OAAO,CAAA;KAAC,GACpQ,OAAO,CAAC,MAAM,CAAC,CAsB3B;IAED;;;;OAIG;IACH,mDAHW;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,OAAO,qBAAqB,EAAE,OAAO,CAAA;KAAC,GACzF,OAAO,CAAC,IAAI,CAAC,CAyBzB;CACF"}
1
+ {"version":3,"file":"tenant.d.ts","sourceRoot":"","sources":["../../../src/tenants/tenant.js"],"names":[],"mappings":"AAMA;;;;;;;;;;GAUG;AACH;IACE;;;;;;;;;;;;OAYG;IACH,YALa,CAAC,UACH,MAAM,YACN,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,6BAA6B,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GACxF,OAAO,CAAC,CAAC,CAAC,CAMtB;IAED;;;OAGG;IACH,kBAFa,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAI/C;IAED;;;;;;;;OAQG;IACH,uEAHW;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,CAAS,IAAiG,EAAjG;YAAC,qBAAqB,EAAE,OAAO,2BAA2B,EAAE,yBAAyB,CAAC;YAAC,MAAM,EAAE,OAAC,CAAA;SAAC,KAAI,OAAO,CAAC,IAAI,CAAC,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,OAAC,KAAK,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,OAAO,qBAAqB,EAAE,OAAO,CAAA;KAAC,GACpQ,OAAO,CAAC,MAAM,CAAC,CAsB3B;IAED;;;;OAIG;IACH,mDAHW;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,OAAO,qBAAqB,EAAE,OAAO,CAAA;KAAC,GACzF,OAAO,CAAC,IAAI,CAAC,CAwBzB;CACF"}
@@ -1,5 +1,6 @@
1
1
  // @ts-check
2
2
  import Current from "../current.js";
3
+ import { dropTenantDatabase } from "./default-tenant-database-provisioning.js";
3
4
  import TenantIterator from "./tenant-iterator.js";
4
5
  /**
5
6
  * Apartment-style runtime façade for multi-tenant apps. A "tenant" is whatever descriptor
@@ -71,9 +72,9 @@ export default class Tenant {
71
72
  */
72
73
  static async drop({ identifier, tenant, configuration = Current.configuration() }) {
73
74
  const provider = configuration.getTenantDatabaseProvider(identifier);
74
- if (typeof provider.dropDatabase !== "function") {
75
- throw new Error(`Tenant database provider for ${identifier} must define dropDatabase to drop a tenant`);
76
- }
75
+ const dropDatabase = typeof provider.dropDatabase === "function"
76
+ ? provider.dropDatabase.bind(provider)
77
+ : dropTenantDatabase;
77
78
  await configuration.runWithTenant(tenant, async () => {
78
79
  // Guard against an unresolved tenant. resolveDatabaseConfiguration falls back to the
79
80
  // base (template/default) tenant database when the resolver returns nothing for this
@@ -82,7 +83,7 @@ export default class Tenant {
82
83
  if (!configuration.isDatabaseIdentifierActive(identifier)) {
83
84
  throw new Error(`Tenant database identifier ${identifier} is inactive for tenant: ${TenantIterator.tenantLabel(tenant)}`);
84
85
  }
85
- await provider.dropDatabase?.({
86
+ await dropDatabase({
86
87
  configuration,
87
88
  databaseConfiguration: configuration.resolveDatabaseConfiguration(identifier),
88
89
  identifier,
@@ -91,4 +92,4 @@ export default class Tenant {
91
92
  });
92
93
  }
93
94
  }
94
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVuYW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RlbmFudHMvdGVuYW50LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWixPQUFPLE9BQU8sTUFBTSxlQUFlLENBQUE7QUFDbkMsT0FBTyxjQUFjLE1BQU0sc0JBQXNCLENBQUE7QUFFakQ7Ozs7Ozs7Ozs7R0FVRztBQUNILE1BQU0sQ0FBQyxPQUFPLE9BQU8sTUFBTTtJQUN6Qjs7Ozs7Ozs7Ozs7O09BWUc7SUFDSCxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsUUFBUTtRQUNoQyxNQUFNLGFBQWEsR0FBRyxPQUFPLENBQUMsYUFBYSxFQUFFLENBQUE7UUFFN0MsT0FBTyxNQUFNLE9BQU8sQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLEtBQUssSUFBSSxFQUFFLENBQUMsTUFBTSxhQUFhLENBQUMsaUJBQWlCLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQTtJQUN0RyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsTUFBTSxDQUFDLE9BQU87UUFDWixPQUFPLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQTtJQUN6QixDQUFDO0lBRUQ7Ozs7Ozs7O09BUUc7SUFDSCxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFDLFVBQVUsRUFBRSxRQUFRLEVBQUUsUUFBUSxHQUFHLENBQUMsRUFBRSxNQUFNLEVBQUUsYUFBYSxHQUFHLE9BQU8sQ0FBQyxhQUFhLEVBQUUsRUFBQztRQUNyRyxNQUFNLFFBQVEsR0FBRyxhQUFhLENBQUMseUJBQXlCLENBQUMsVUFBVSxDQUFDLENBQUE7UUFDcEUsTUFBTSxhQUFhLEdBQUcsTUFBTSxhQUFhLENBQUMsaUJBQWlCLENBQUMsRUFBQyxJQUFJLEVBQUUsZ0JBQWdCLFVBQVUsRUFBRSxFQUFDLEVBQUUsS0FBSyxJQUFJLEVBQUU7WUFDM0csT0FBTyxNQUFNLFFBQVEsQ0FBQyxXQUFXLENBQUMsRUFBQyxhQUFhLEVBQUUsVUFBVSxFQUFDLENBQUMsQ0FBQTtRQUNoRSxDQUFDLENBQUMsQ0FBQTtRQUVGLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxFQUFFLENBQUM7WUFDbEMsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsVUFBVSx3Q0FBd0MsQ0FBQyxDQUFBO1FBQ3JHLENBQUM7UUFFRCxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQTtRQUNyRSxNQUFNLFFBQVEsR0FBRyxJQUFJLGNBQWMsQ0FBQyxFQUFDLGFBQWEsRUFBRSxVQUFVLEVBQUUsYUFBYSxFQUFFLFFBQVEsRUFBQyxDQUFDLENBQUE7UUFFekYsNEVBQTRFO1FBQzVFLHVGQUF1RjtRQUN2RixvRkFBb0Y7UUFDcEYsMEZBQTBGO1FBQzFGLE9BQU8sTUFBTSxRQUFRLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxLQUFLLEVBQUUsWUFBWSxFQUFFLEVBQUU7WUFDeEQsTUFBTSxhQUFhLENBQUMsaUJBQWlCLENBQUMsRUFBQyxJQUFJLEVBQUUsZ0JBQWdCLFVBQVUsRUFBRSxFQUFDLEVBQUUsS0FBSyxJQUFJLEVBQUUsQ0FBQyxNQUFNLFFBQVEsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFBO1FBQ3ZILENBQUMsQ0FBQyxDQUFBO0lBQ0osQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFDLFVBQVUsRUFBRSxNQUFNLEVBQUUsYUFBYSxHQUFHLE9BQU8sQ0FBQyxhQUFhLEVBQUUsRUFBQztRQUM3RSxNQUFNLFFBQVEsR0FBRyxhQUFhLENBQUMseUJBQXlCLENBQUMsVUFBVSxDQUFDLENBQUE7UUFFcEUsSUFBSSxPQUFPLFFBQVEsQ0FBQyxZQUFZLEtBQUssVUFBVSxFQUFFLENBQUM7WUFDaEQsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsVUFBVSw0Q0FBNEMsQ0FBQyxDQUFBO1FBQ3pHLENBQUM7UUFFRCxNQUFNLGFBQWEsQ0FBQyxhQUFhLENBQUMsTUFBTSxFQUFFLEtBQUssSUFBSSxFQUFFO1lBQ25ELHFGQUFxRjtZQUNyRixxRkFBcUY7WUFDckYsd0ZBQXdGO1lBQ3hGLHdFQUF3RTtZQUN4RSxJQUFJLENBQUMsYUFBYSxDQUFDLDBCQUEwQixDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7Z0JBQzFELE1BQU0sSUFBSSxLQUFLLENBQUMsOEJBQThCLFVBQVUsNEJBQTRCLGNBQWMsQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFBO1lBQzNILENBQUM7WUFFRCxNQUFNLFFBQVEsQ0FBQyxZQUFZLEVBQUUsQ0FBQztnQkFDNUIsYUFBYTtnQkFDYixxQkFBcUIsRUFBRSxhQUFhLENBQUMsNEJBQTRCLENBQUMsVUFBVSxDQUFDO2dCQUM3RSxVQUFVO2dCQUNWLE1BQU07YUFDUCxDQUFDLENBQUE7UUFDSixDQUFDLENBQUMsQ0FBQTtJQUNKLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG5pbXBvcnQgQ3VycmVudCBmcm9tIFwiLi4vY3VycmVudC5qc1wiXG5pbXBvcnQgVGVuYW50SXRlcmF0b3IgZnJvbSBcIi4vdGVuYW50LWl0ZXJhdG9yLmpzXCJcblxuLyoqXG4gKiBBcGFydG1lbnQtc3R5bGUgcnVudGltZSBmYcOnYWRlIGZvciBtdWx0aS10ZW5hbnQgYXBwcy4gQSBcInRlbmFudFwiIGlzIHdoYXRldmVyIGRlc2NyaXB0b3JcbiAqIG9iamVjdCB0aGUgYXBwJ3MgYHRlbmFudERhdGFiYXNlUmVzb2x2ZXJgIHVuZGVyc3RhbmRzIChhbiBhY2NvdW50LCBhIHByb2plY3QsIOKApik7IHRoaXNcbiAqIGNsYXNzIGlzIHRoZSBzaW5nbGUgZGlzY292ZXJhYmxlIGhvbWUgZm9yIHN3aXRjaGluZyBpbnRvIGEgdGVuYW50J3MgY29udGV4dCwgcmVhZGluZyB0aGVcbiAqIGN1cnJlbnQgb25lLCBpdGVyYXRpbmcgZXZlcnkgdGVuYW50IG9mIGEgZGF0YWJhc2UgaWRlbnRpZmllciwgYW5kIGRyb3BwaW5nIGEgdGVuYW50J3NcbiAqIGRhdGFiYXNlLiBTd2l0Y2hpbmcgZGVsZWdhdGVzIHRvIHtAbGluayBDdXJyZW50fSAod2hpY2ggb3ducyB0aGUgYXN5bmMtY29udGV4dCB0ZW5hbnRcbiAqIHN0YXRlKSBhbmQgYWRkaXRpb25hbGx5IHJ1bnMgdGhlIGNhbGxiYWNrIGluc2lkZSBgZW5zdXJlQ29ubmVjdGlvbnNgLCBzbyBlbnRlcmluZyBhIHRlbmFudFxuICogbWFrZXMgaXRzIGRhdGFiYXNlIGltbWVkaWF0ZWx5IHF1ZXJ5YWJsZSDigJQgdGhlIGFwYXJ0bWVudC1zdHlsZSBcInN3aXRjaFwiIHNlbWFudGljcyDigJQgd2l0aG91dFxuICogdGhlIGNhbGxlciBlc3RhYmxpc2hpbmcgY29ubmVjdGlvbnMgaXRzZWxmOyBpdGVyYXRpb24gYW5kIGRyb3AgZHJpdmUgdGhlIGFwcCdzIHRlbmFudFxuICogZGF0YWJhc2UgcHJvdmlkZXIgaG9va3MuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFRlbmFudCB7XG4gIC8qKlxuICAgKiBSdW5zIGBjYWxsYmFja2Agd2l0aCBgdGVuYW50YCBhcyB0aGUgY3VycmVudCB0ZW5hbnQsIHJlc3RvcmluZyB0aGUgcHJldmlvdXMgdGVuYW50IGFmdGVyLlxuICAgKiBUaGUgY2FsbGJhY2sgcnVucyBpbnNpZGUgYGVuc3VyZUNvbm5lY3Rpb25zYCwgc28gZXZlcnkgZGF0YWJhc2UgaWRlbnRpZmllciB0aGUgdGVuYW50XG4gICAqIGFjdGl2YXRlcyAodGhlIGdsb2JhbCBkYXRhYmFzZSBwbHVzIHRoZSB0ZW5hbnQncyBkYXRhYmFzZSkgaGFzIGEgY2hlY2tlZC1vdXQgY29ubmVjdGlvblxuICAgKiBhdmFpbGFibGUgZm9yIHRoZSBjYWxsYmFjaydzIGR1cmF0aW9uOiBzd2l0Y2hpbmcgaW50byBhIHRlbmFudCBtYWtlcyBpdCBxdWVyeWFibGUgd2l0aG91dFxuICAgKiB0aGUgY2FsbGVyIHdpcmluZyB1cCBjb25uZWN0aW9ucy4gQWxyZWFkeS1jaGVja2VkLW91dCBjb25uZWN0aW9ucyBhcmUgcmV1c2VkLCBzbyBuZXN0aW5nXG4gICAqIGBUZW5hbnQud2l0aGAgY2FsbHMgZG9lcyBub3Qgb3BlbiByZWR1bmRhbnQgY29ubmVjdGlvbnMuIFRoZSBjYWxsYmFjayByZWNlaXZlcyB0aGUgYWN0aXZlXG4gICAqIGNvbm5lY3Rpb25zIGtleWVkIGJ5IGlkZW50aWZpZXIsIHRoZSBzYW1lIGFzIGBlbnN1cmVDb25uZWN0aW9uc2AuXG4gICAqIEB0ZW1wbGF0ZSBUXG4gICAqIEBwYXJhbSB7b2JqZWN0fSB0ZW5hbnQgRGVzY3JpcHRvciB1bmRlcnN0b29kIGJ5IHRoZSBhcHAncyB0ZW5hbnREYXRhYmFzZVJlc29sdmVyLlxuICAgKiBAcGFyYW0geyhjb25uZWN0aW9uczogUmVjb3JkPHN0cmluZywgaW1wb3J0KFwiLi4vZGF0YWJhc2UvZHJpdmVycy9iYXNlLmpzXCIpLmRlZmF1bHQ+KSA9PiBQcm9taXNlPFQ+fSBjYWxsYmFja1xuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxUPn1cbiAgICovXG4gIHN0YXRpYyBhc3luYyB3aXRoKHRlbmFudCwgY2FsbGJhY2spIHtcbiAgICBjb25zdCBjb25maWd1cmF0aW9uID0gQ3VycmVudC5jb25maWd1cmF0aW9uKClcblxuICAgIHJldHVybiBhd2FpdCBDdXJyZW50LndpdGhUZW5hbnQodGVuYW50LCBhc3luYyAoKSA9PiBhd2FpdCBjb25maWd1cmF0aW9uLmVuc3VyZUNvbm5lY3Rpb25zKGNhbGxiYWNrKSlcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgY3VycmVudCB0ZW5hbnQgZGVzY3JpcHRvciwgb3IgdW5kZWZpbmVkIHdoZW4gcnVubmluZyBvdXRzaWRlIGFueSB0ZW5hbnQgY29udGV4dC5cbiAgICogQHJldHVybnMge1JlY29yZDxzdHJpbmcsIHVua25vd24+IHwgdW5kZWZpbmVkfVxuICAgKi9cbiAgc3RhdGljIGN1cnJlbnQoKSB7XG4gICAgcmV0dXJuIEN1cnJlbnQudGVuYW50KClcbiAgfVxuXG4gIC8qKlxuICAgKiBMaXN0cyB0aGUgdGVuYW50cyBmb3IgYSBkYXRhYmFzZSBpZGVudGlmaWVyIHRocm91Z2ggdGhlIHByb3ZpZGVyIGFuZCBydW5zIGBjYWxsYmFja2BcbiAgICogd2l0aGluIGVhY2ggdGVuYW50J3MgY29udGV4dCwgb3B0aW9uYWxseSBmaWx0ZXJlZCBhbmQgc2V2ZXJhbCBhdCBhIHRpbWUuIExpa2VcbiAgICoge0BsaW5rIFRlbmFudC53aXRofSwgdGhlIGNhbGxiYWNrIHJ1bnMgaW5zaWRlIGBlbnN1cmVDb25uZWN0aW9uc2Agc28gZWFjaCB0ZW5hbnQnc1xuICAgKiBkYXRhYmFzZSBpcyBxdWVyeWFibGUgd2l0aG91dCB0aGUgY2FsbGVyIHdpcmluZyB1cCBjb25uZWN0aW9ucy4gUmV0dXJucyBob3cgbWFueSB0ZW5hbnRzXG4gICAqIHRoZSBjYWxsYmFjayByYW4gZm9yIChhZnRlciBmaWx0ZXJpbmcpLlxuICAgKiBAcGFyYW0ge3tpZGVudGlmaWVyOiBzdHJpbmcsIGNhbGxiYWNrOiBmdW5jdGlvbih7ZGF0YWJhc2VDb25maWd1cmF0aW9uOiBpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLkRhdGFiYXNlQ29uZmlndXJhdGlvblR5cGUsIHRlbmFudDogP30pIDogUHJvbWlzZTx2b2lkPiwgcGFyYWxsZWw/OiBudW1iZXIsIGZpbHRlcj86ICh0ZW5hbnQ6ID8pID0+IGJvb2xlYW4sIGNvbmZpZ3VyYXRpb24/OiBpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLmpzXCIpLmRlZmF1bHR9fSBhcmdzXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPG51bWJlcj59XG4gICAqL1xuICBzdGF0aWMgYXN5bmMgZWFjaCh7aWRlbnRpZmllciwgY2FsbGJhY2ssIHBhcmFsbGVsID0gMSwgZmlsdGVyLCBjb25maWd1cmF0aW9uID0gQ3VycmVudC5jb25maWd1cmF0aW9uKCl9KSB7XG4gICAgY29uc3QgcHJvdmlkZXIgPSBjb25maWd1cmF0aW9uLmdldFRlbmFudERhdGFiYXNlUHJvdmlkZXIoaWRlbnRpZmllcilcbiAgICBjb25zdCBsaXN0ZWRUZW5hbnRzID0gYXdhaXQgY29uZmlndXJhdGlvbi5lbnN1cmVDb25uZWN0aW9ucyh7bmFtZTogYFRlbmFudC5lYWNoOiAke2lkZW50aWZpZXJ9YH0sIGFzeW5jICgpID0+IHtcbiAgICAgIHJldHVybiBhd2FpdCBwcm92aWRlci5saXN0VGVuYW50cyh7Y29uZmlndXJhdGlvbiwgaWRlbnRpZmllcn0pXG4gICAgfSlcblxuICAgIGlmICghQXJyYXkuaXNBcnJheShsaXN0ZWRUZW5hbnRzKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBUZW5hbnQgZGF0YWJhc2UgcHJvdmlkZXIgZm9yICR7aWRlbnRpZmllcn0gbXVzdCByZXR1cm4gYW4gYXJyYXkgZnJvbSBsaXN0VGVuYW50c2ApXG4gICAgfVxuXG4gICAgY29uc3QgdGVuYW50cyA9IGZpbHRlciA/IGxpc3RlZFRlbmFudHMuZmlsdGVyKGZpbHRlcikgOiBsaXN0ZWRUZW5hbnRzXG4gICAgY29uc3QgaXRlcmF0b3IgPSBuZXcgVGVuYW50SXRlcmF0b3Ioe2NvbmZpZ3VyYXRpb24sIGlkZW50aWZpZXIsIHBhcmFsbGVsQ291bnQ6IHBhcmFsbGVsfSlcblxuICAgIC8vIFJ1biBlYWNoIHRlbmFudCdzIGNhbGxiYWNrIGluc2lkZSBlbnN1cmVDb25uZWN0aW9ucyBzbyB0aGUgaXRlcmF0b3Igc3RheXNcbiAgICAvLyBjb25uZWN0aW9uLWFnbm9zdGljICh0aGUgZGI6dGVuYW50czoqIENMSSBjb21tYW5kcyBzaGFyZSBUZW5hbnRJdGVyYXRvciBhbmQgbXVzdCBydW5cbiAgICAvLyB0aGVpciBjYWxsYmFja3MsIHN1Y2ggYXMgY3JlYXRlLCBiZWZvcmUgdGhlIHRlbmFudCBkYXRhYmFzZSBleGlzdHMpIHdoaWxlIHJ1bnRpbWVcbiAgICAvLyBpdGVyYXRpb24gaGVyZSBnZXRzIHRoZSB0ZW5hbnQncyBjb25uZWN0aW9ucyBlc3RhYmxpc2hlZCB0aGUgc2FtZSB3YXkgVGVuYW50LndpdGggZG9lcy5cbiAgICByZXR1cm4gYXdhaXQgaXRlcmF0b3IucnVuKHRlbmFudHMsIGFzeW5jIChjYWxsYmFja0FyZ3MpID0+IHtcbiAgICAgIGF3YWl0IGNvbmZpZ3VyYXRpb24uZW5zdXJlQ29ubmVjdGlvbnMoe25hbWU6IGBUZW5hbnQuZWFjaDogJHtpZGVudGlmaWVyfWB9LCBhc3luYyAoKSA9PiBhd2FpdCBjYWxsYmFjayhjYWxsYmFja0FyZ3MpKVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogRHJvcHMgb25lIHRlbmFudCdzIGRhdGFiYXNlL3NjaGVtYSB0aHJvdWdoIHRoZSBwcm92aWRlcidzIGBkcm9wRGF0YWJhc2VgIGhvb2suXG4gICAqIEBwYXJhbSB7e2lkZW50aWZpZXI6IHN0cmluZywgdGVuYW50OiBvYmplY3QsIGNvbmZpZ3VyYXRpb24/OiBpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLmpzXCIpLmRlZmF1bHR9fSBhcmdzXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgc3RhdGljIGFzeW5jIGRyb3Aoe2lkZW50aWZpZXIsIHRlbmFudCwgY29uZmlndXJhdGlvbiA9IEN1cnJlbnQuY29uZmlndXJhdGlvbigpfSkge1xuICAgIGNvbnN0IHByb3ZpZGVyID0gY29uZmlndXJhdGlvbi5nZXRUZW5hbnREYXRhYmFzZVByb3ZpZGVyKGlkZW50aWZpZXIpXG5cbiAgICBpZiAodHlwZW9mIHByb3ZpZGVyLmRyb3BEYXRhYmFzZSAhPT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFRlbmFudCBkYXRhYmFzZSBwcm92aWRlciBmb3IgJHtpZGVudGlmaWVyfSBtdXN0IGRlZmluZSBkcm9wRGF0YWJhc2UgdG8gZHJvcCBhIHRlbmFudGApXG4gICAgfVxuXG4gICAgYXdhaXQgY29uZmlndXJhdGlvbi5ydW5XaXRoVGVuYW50KHRlbmFudCwgYXN5bmMgKCkgPT4ge1xuICAgICAgLy8gR3VhcmQgYWdhaW5zdCBhbiB1bnJlc29sdmVkIHRlbmFudC4gcmVzb2x2ZURhdGFiYXNlQ29uZmlndXJhdGlvbiBmYWxscyBiYWNrIHRvIHRoZVxuICAgICAgLy8gYmFzZSAodGVtcGxhdGUvZGVmYXVsdCkgdGVuYW50IGRhdGFiYXNlIHdoZW4gdGhlIHJlc29sdmVyIHJldHVybnMgbm90aGluZyBmb3IgdGhpc1xuICAgICAgLy8gZGVzY3JpcHRvciwgc28gd2l0aG91dCB0aGlzIGNoZWNrIGEgcHJvdmlkZXIgdGhhdCBkcm9wcyBieSBkYXRhYmFzZUNvbmZpZ3VyYXRpb24ubmFtZVxuICAgICAgLy8gd291bGQgZHJvcCB0aGUgdGVtcGxhdGUgZGF0YWJhc2UgaW5zdGVhZCBvZiByZWplY3RpbmcgdGhlIGJhZCB0ZW5hbnQuXG4gICAgICBpZiAoIWNvbmZpZ3VyYXRpb24uaXNEYXRhYmFzZUlkZW50aWZpZXJBY3RpdmUoaWRlbnRpZmllcikpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBUZW5hbnQgZGF0YWJhc2UgaWRlbnRpZmllciAke2lkZW50aWZpZXJ9IGlzIGluYWN0aXZlIGZvciB0ZW5hbnQ6ICR7VGVuYW50SXRlcmF0b3IudGVuYW50TGFiZWwodGVuYW50KX1gKVxuICAgICAgfVxuXG4gICAgICBhd2FpdCBwcm92aWRlci5kcm9wRGF0YWJhc2U/Lih7XG4gICAgICAgIGNvbmZpZ3VyYXRpb24sXG4gICAgICAgIGRhdGFiYXNlQ29uZmlndXJhdGlvbjogY29uZmlndXJhdGlvbi5yZXNvbHZlRGF0YWJhc2VDb25maWd1cmF0aW9uKGlkZW50aWZpZXIpLFxuICAgICAgICBpZGVudGlmaWVyLFxuICAgICAgICB0ZW5hbnRcbiAgICAgIH0pXG4gICAgfSlcbiAgfVxufVxuIl19
95
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVuYW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RlbmFudHMvdGVuYW50LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWixPQUFPLE9BQU8sTUFBTSxlQUFlLENBQUE7QUFDbkMsT0FBTyxFQUFDLGtCQUFrQixFQUFDLE1BQU0sMkNBQTJDLENBQUE7QUFDNUUsT0FBTyxjQUFjLE1BQU0sc0JBQXNCLENBQUE7QUFFakQ7Ozs7Ozs7Ozs7R0FVRztBQUNILE1BQU0sQ0FBQyxPQUFPLE9BQU8sTUFBTTtJQUN6Qjs7Ozs7Ozs7Ozs7O09BWUc7SUFDSCxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsUUFBUTtRQUNoQyxNQUFNLGFBQWEsR0FBRyxPQUFPLENBQUMsYUFBYSxFQUFFLENBQUE7UUFFN0MsT0FBTyxNQUFNLE9BQU8sQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLEtBQUssSUFBSSxFQUFFLENBQUMsTUFBTSxhQUFhLENBQUMsaUJBQWlCLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQTtJQUN0RyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsTUFBTSxDQUFDLE9BQU87UUFDWixPQUFPLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQTtJQUN6QixDQUFDO0lBRUQ7Ozs7Ozs7O09BUUc7SUFDSCxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFDLFVBQVUsRUFBRSxRQUFRLEVBQUUsUUFBUSxHQUFHLENBQUMsRUFBRSxNQUFNLEVBQUUsYUFBYSxHQUFHLE9BQU8sQ0FBQyxhQUFhLEVBQUUsRUFBQztRQUNyRyxNQUFNLFFBQVEsR0FBRyxhQUFhLENBQUMseUJBQXlCLENBQUMsVUFBVSxDQUFDLENBQUE7UUFDcEUsTUFBTSxhQUFhLEdBQUcsTUFBTSxhQUFhLENBQUMsaUJBQWlCLENBQUMsRUFBQyxJQUFJLEVBQUUsZ0JBQWdCLFVBQVUsRUFBRSxFQUFDLEVBQUUsS0FBSyxJQUFJLEVBQUU7WUFDM0csT0FBTyxNQUFNLFFBQVEsQ0FBQyxXQUFXLENBQUMsRUFBQyxhQUFhLEVBQUUsVUFBVSxFQUFDLENBQUMsQ0FBQTtRQUNoRSxDQUFDLENBQUMsQ0FBQTtRQUVGLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxFQUFFLENBQUM7WUFDbEMsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsVUFBVSx3Q0FBd0MsQ0FBQyxDQUFBO1FBQ3JHLENBQUM7UUFFRCxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQTtRQUNyRSxNQUFNLFFBQVEsR0FBRyxJQUFJLGNBQWMsQ0FBQyxFQUFDLGFBQWEsRUFBRSxVQUFVLEVBQUUsYUFBYSxFQUFFLFFBQVEsRUFBQyxDQUFDLENBQUE7UUFFekYsNEVBQTRFO1FBQzVFLHVGQUF1RjtRQUN2RixvRkFBb0Y7UUFDcEYsMEZBQTBGO1FBQzFGLE9BQU8sTUFBTSxRQUFRLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxLQUFLLEVBQUUsWUFBWSxFQUFFLEVBQUU7WUFDeEQsTUFBTSxhQUFhLENBQUMsaUJBQWlCLENBQUMsRUFBQyxJQUFJLEVBQUUsZ0JBQWdCLFVBQVUsRUFBRSxFQUFDLEVBQUUsS0FBSyxJQUFJLEVBQUUsQ0FBQyxNQUFNLFFBQVEsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFBO1FBQ3ZILENBQUMsQ0FBQyxDQUFBO0lBQ0osQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFDLFVBQVUsRUFBRSxNQUFNLEVBQUUsYUFBYSxHQUFHLE9BQU8sQ0FBQyxhQUFhLEVBQUUsRUFBQztRQUM3RSxNQUFNLFFBQVEsR0FBRyxhQUFhLENBQUMseUJBQXlCLENBQUMsVUFBVSxDQUFDLENBQUE7UUFDcEUsTUFBTSxZQUFZLEdBQUcsT0FBTyxRQUFRLENBQUMsWUFBWSxLQUFLLFVBQVU7WUFDOUQsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQztZQUN0QyxDQUFDLENBQUMsa0JBQWtCLENBQUE7UUFFdEIsTUFBTSxhQUFhLENBQUMsYUFBYSxDQUFDLE1BQU0sRUFBRSxLQUFLLElBQUksRUFBRTtZQUNuRCxxRkFBcUY7WUFDckYscUZBQXFGO1lBQ3JGLHdGQUF3RjtZQUN4Rix3RUFBd0U7WUFDeEUsSUFBSSxDQUFDLGFBQWEsQ0FBQywwQkFBMEIsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO2dCQUMxRCxNQUFNLElBQUksS0FBSyxDQUFDLDhCQUE4QixVQUFVLDRCQUE0QixjQUFjLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQTtZQUMzSCxDQUFDO1lBRUQsTUFBTSxZQUFZLENBQUM7Z0JBQ2pCLGFBQWE7Z0JBQ2IscUJBQXFCLEVBQUUsYUFBYSxDQUFDLDRCQUE0QixDQUFDLFVBQVUsQ0FBQztnQkFDN0UsVUFBVTtnQkFDVixNQUFNO2FBQ1AsQ0FBQyxDQUFBO1FBQ0osQ0FBQyxDQUFDLENBQUE7SUFDSixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBAdHMtY2hlY2tcblxuaW1wb3J0IEN1cnJlbnQgZnJvbSBcIi4uL2N1cnJlbnQuanNcIlxuaW1wb3J0IHtkcm9wVGVuYW50RGF0YWJhc2V9IGZyb20gXCIuL2RlZmF1bHQtdGVuYW50LWRhdGFiYXNlLXByb3Zpc2lvbmluZy5qc1wiXG5pbXBvcnQgVGVuYW50SXRlcmF0b3IgZnJvbSBcIi4vdGVuYW50LWl0ZXJhdG9yLmpzXCJcblxuLyoqXG4gKiBBcGFydG1lbnQtc3R5bGUgcnVudGltZSBmYcOnYWRlIGZvciBtdWx0aS10ZW5hbnQgYXBwcy4gQSBcInRlbmFudFwiIGlzIHdoYXRldmVyIGRlc2NyaXB0b3JcbiAqIG9iamVjdCB0aGUgYXBwJ3MgYHRlbmFudERhdGFiYXNlUmVzb2x2ZXJgIHVuZGVyc3RhbmRzIChhbiBhY2NvdW50LCBhIHByb2plY3QsIOKApik7IHRoaXNcbiAqIGNsYXNzIGlzIHRoZSBzaW5nbGUgZGlzY292ZXJhYmxlIGhvbWUgZm9yIHN3aXRjaGluZyBpbnRvIGEgdGVuYW50J3MgY29udGV4dCwgcmVhZGluZyB0aGVcbiAqIGN1cnJlbnQgb25lLCBpdGVyYXRpbmcgZXZlcnkgdGVuYW50IG9mIGEgZGF0YWJhc2UgaWRlbnRpZmllciwgYW5kIGRyb3BwaW5nIGEgdGVuYW50J3NcbiAqIGRhdGFiYXNlLiBTd2l0Y2hpbmcgZGVsZWdhdGVzIHRvIHtAbGluayBDdXJyZW50fSAod2hpY2ggb3ducyB0aGUgYXN5bmMtY29udGV4dCB0ZW5hbnRcbiAqIHN0YXRlKSBhbmQgYWRkaXRpb25hbGx5IHJ1bnMgdGhlIGNhbGxiYWNrIGluc2lkZSBgZW5zdXJlQ29ubmVjdGlvbnNgLCBzbyBlbnRlcmluZyBhIHRlbmFudFxuICogbWFrZXMgaXRzIGRhdGFiYXNlIGltbWVkaWF0ZWx5IHF1ZXJ5YWJsZSDigJQgdGhlIGFwYXJ0bWVudC1zdHlsZSBcInN3aXRjaFwiIHNlbWFudGljcyDigJQgd2l0aG91dFxuICogdGhlIGNhbGxlciBlc3RhYmxpc2hpbmcgY29ubmVjdGlvbnMgaXRzZWxmOyBpdGVyYXRpb24gYW5kIGRyb3AgZHJpdmUgdGhlIGFwcCdzIHRlbmFudFxuICogZGF0YWJhc2UgcHJvdmlkZXIgaG9va3MuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFRlbmFudCB7XG4gIC8qKlxuICAgKiBSdW5zIGBjYWxsYmFja2Agd2l0aCBgdGVuYW50YCBhcyB0aGUgY3VycmVudCB0ZW5hbnQsIHJlc3RvcmluZyB0aGUgcHJldmlvdXMgdGVuYW50IGFmdGVyLlxuICAgKiBUaGUgY2FsbGJhY2sgcnVucyBpbnNpZGUgYGVuc3VyZUNvbm5lY3Rpb25zYCwgc28gZXZlcnkgZGF0YWJhc2UgaWRlbnRpZmllciB0aGUgdGVuYW50XG4gICAqIGFjdGl2YXRlcyAodGhlIGdsb2JhbCBkYXRhYmFzZSBwbHVzIHRoZSB0ZW5hbnQncyBkYXRhYmFzZSkgaGFzIGEgY2hlY2tlZC1vdXQgY29ubmVjdGlvblxuICAgKiBhdmFpbGFibGUgZm9yIHRoZSBjYWxsYmFjaydzIGR1cmF0aW9uOiBzd2l0Y2hpbmcgaW50byBhIHRlbmFudCBtYWtlcyBpdCBxdWVyeWFibGUgd2l0aG91dFxuICAgKiB0aGUgY2FsbGVyIHdpcmluZyB1cCBjb25uZWN0aW9ucy4gQWxyZWFkeS1jaGVja2VkLW91dCBjb25uZWN0aW9ucyBhcmUgcmV1c2VkLCBzbyBuZXN0aW5nXG4gICAqIGBUZW5hbnQud2l0aGAgY2FsbHMgZG9lcyBub3Qgb3BlbiByZWR1bmRhbnQgY29ubmVjdGlvbnMuIFRoZSBjYWxsYmFjayByZWNlaXZlcyB0aGUgYWN0aXZlXG4gICAqIGNvbm5lY3Rpb25zIGtleWVkIGJ5IGlkZW50aWZpZXIsIHRoZSBzYW1lIGFzIGBlbnN1cmVDb25uZWN0aW9uc2AuXG4gICAqIEB0ZW1wbGF0ZSBUXG4gICAqIEBwYXJhbSB7b2JqZWN0fSB0ZW5hbnQgRGVzY3JpcHRvciB1bmRlcnN0b29kIGJ5IHRoZSBhcHAncyB0ZW5hbnREYXRhYmFzZVJlc29sdmVyLlxuICAgKiBAcGFyYW0geyhjb25uZWN0aW9uczogUmVjb3JkPHN0cmluZywgaW1wb3J0KFwiLi4vZGF0YWJhc2UvZHJpdmVycy9iYXNlLmpzXCIpLmRlZmF1bHQ+KSA9PiBQcm9taXNlPFQ+fSBjYWxsYmFja1xuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxUPn1cbiAgICovXG4gIHN0YXRpYyBhc3luYyB3aXRoKHRlbmFudCwgY2FsbGJhY2spIHtcbiAgICBjb25zdCBjb25maWd1cmF0aW9uID0gQ3VycmVudC5jb25maWd1cmF0aW9uKClcblxuICAgIHJldHVybiBhd2FpdCBDdXJyZW50LndpdGhUZW5hbnQodGVuYW50LCBhc3luYyAoKSA9PiBhd2FpdCBjb25maWd1cmF0aW9uLmVuc3VyZUNvbm5lY3Rpb25zKGNhbGxiYWNrKSlcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgY3VycmVudCB0ZW5hbnQgZGVzY3JpcHRvciwgb3IgdW5kZWZpbmVkIHdoZW4gcnVubmluZyBvdXRzaWRlIGFueSB0ZW5hbnQgY29udGV4dC5cbiAgICogQHJldHVybnMge1JlY29yZDxzdHJpbmcsIHVua25vd24+IHwgdW5kZWZpbmVkfVxuICAgKi9cbiAgc3RhdGljIGN1cnJlbnQoKSB7XG4gICAgcmV0dXJuIEN1cnJlbnQudGVuYW50KClcbiAgfVxuXG4gIC8qKlxuICAgKiBMaXN0cyB0aGUgdGVuYW50cyBmb3IgYSBkYXRhYmFzZSBpZGVudGlmaWVyIHRocm91Z2ggdGhlIHByb3ZpZGVyIGFuZCBydW5zIGBjYWxsYmFja2BcbiAgICogd2l0aGluIGVhY2ggdGVuYW50J3MgY29udGV4dCwgb3B0aW9uYWxseSBmaWx0ZXJlZCBhbmQgc2V2ZXJhbCBhdCBhIHRpbWUuIExpa2VcbiAgICoge0BsaW5rIFRlbmFudC53aXRofSwgdGhlIGNhbGxiYWNrIHJ1bnMgaW5zaWRlIGBlbnN1cmVDb25uZWN0aW9uc2Agc28gZWFjaCB0ZW5hbnQnc1xuICAgKiBkYXRhYmFzZSBpcyBxdWVyeWFibGUgd2l0aG91dCB0aGUgY2FsbGVyIHdpcmluZyB1cCBjb25uZWN0aW9ucy4gUmV0dXJucyBob3cgbWFueSB0ZW5hbnRzXG4gICAqIHRoZSBjYWxsYmFjayByYW4gZm9yIChhZnRlciBmaWx0ZXJpbmcpLlxuICAgKiBAcGFyYW0ge3tpZGVudGlmaWVyOiBzdHJpbmcsIGNhbGxiYWNrOiBmdW5jdGlvbih7ZGF0YWJhc2VDb25maWd1cmF0aW9uOiBpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLkRhdGFiYXNlQ29uZmlndXJhdGlvblR5cGUsIHRlbmFudDogP30pIDogUHJvbWlzZTx2b2lkPiwgcGFyYWxsZWw/OiBudW1iZXIsIGZpbHRlcj86ICh0ZW5hbnQ6ID8pID0+IGJvb2xlYW4sIGNvbmZpZ3VyYXRpb24/OiBpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLmpzXCIpLmRlZmF1bHR9fSBhcmdzXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPG51bWJlcj59XG4gICAqL1xuICBzdGF0aWMgYXN5bmMgZWFjaCh7aWRlbnRpZmllciwgY2FsbGJhY2ssIHBhcmFsbGVsID0gMSwgZmlsdGVyLCBjb25maWd1cmF0aW9uID0gQ3VycmVudC5jb25maWd1cmF0aW9uKCl9KSB7XG4gICAgY29uc3QgcHJvdmlkZXIgPSBjb25maWd1cmF0aW9uLmdldFRlbmFudERhdGFiYXNlUHJvdmlkZXIoaWRlbnRpZmllcilcbiAgICBjb25zdCBsaXN0ZWRUZW5hbnRzID0gYXdhaXQgY29uZmlndXJhdGlvbi5lbnN1cmVDb25uZWN0aW9ucyh7bmFtZTogYFRlbmFudC5lYWNoOiAke2lkZW50aWZpZXJ9YH0sIGFzeW5jICgpID0+IHtcbiAgICAgIHJldHVybiBhd2FpdCBwcm92aWRlci5saXN0VGVuYW50cyh7Y29uZmlndXJhdGlvbiwgaWRlbnRpZmllcn0pXG4gICAgfSlcblxuICAgIGlmICghQXJyYXkuaXNBcnJheShsaXN0ZWRUZW5hbnRzKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBUZW5hbnQgZGF0YWJhc2UgcHJvdmlkZXIgZm9yICR7aWRlbnRpZmllcn0gbXVzdCByZXR1cm4gYW4gYXJyYXkgZnJvbSBsaXN0VGVuYW50c2ApXG4gICAgfVxuXG4gICAgY29uc3QgdGVuYW50cyA9IGZpbHRlciA/IGxpc3RlZFRlbmFudHMuZmlsdGVyKGZpbHRlcikgOiBsaXN0ZWRUZW5hbnRzXG4gICAgY29uc3QgaXRlcmF0b3IgPSBuZXcgVGVuYW50SXRlcmF0b3Ioe2NvbmZpZ3VyYXRpb24sIGlkZW50aWZpZXIsIHBhcmFsbGVsQ291bnQ6IHBhcmFsbGVsfSlcblxuICAgIC8vIFJ1biBlYWNoIHRlbmFudCdzIGNhbGxiYWNrIGluc2lkZSBlbnN1cmVDb25uZWN0aW9ucyBzbyB0aGUgaXRlcmF0b3Igc3RheXNcbiAgICAvLyBjb25uZWN0aW9uLWFnbm9zdGljICh0aGUgZGI6dGVuYW50czoqIENMSSBjb21tYW5kcyBzaGFyZSBUZW5hbnRJdGVyYXRvciBhbmQgbXVzdCBydW5cbiAgICAvLyB0aGVpciBjYWxsYmFja3MsIHN1Y2ggYXMgY3JlYXRlLCBiZWZvcmUgdGhlIHRlbmFudCBkYXRhYmFzZSBleGlzdHMpIHdoaWxlIHJ1bnRpbWVcbiAgICAvLyBpdGVyYXRpb24gaGVyZSBnZXRzIHRoZSB0ZW5hbnQncyBjb25uZWN0aW9ucyBlc3RhYmxpc2hlZCB0aGUgc2FtZSB3YXkgVGVuYW50LndpdGggZG9lcy5cbiAgICByZXR1cm4gYXdhaXQgaXRlcmF0b3IucnVuKHRlbmFudHMsIGFzeW5jIChjYWxsYmFja0FyZ3MpID0+IHtcbiAgICAgIGF3YWl0IGNvbmZpZ3VyYXRpb24uZW5zdXJlQ29ubmVjdGlvbnMoe25hbWU6IGBUZW5hbnQuZWFjaDogJHtpZGVudGlmaWVyfWB9LCBhc3luYyAoKSA9PiBhd2FpdCBjYWxsYmFjayhjYWxsYmFja0FyZ3MpKVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogRHJvcHMgb25lIHRlbmFudCdzIGRhdGFiYXNlL3NjaGVtYSB0aHJvdWdoIHRoZSBwcm92aWRlcidzIGBkcm9wRGF0YWJhc2VgIGhvb2suXG4gICAqIEBwYXJhbSB7e2lkZW50aWZpZXI6IHN0cmluZywgdGVuYW50OiBvYmplY3QsIGNvbmZpZ3VyYXRpb24/OiBpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLmpzXCIpLmRlZmF1bHR9fSBhcmdzXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgc3RhdGljIGFzeW5jIGRyb3Aoe2lkZW50aWZpZXIsIHRlbmFudCwgY29uZmlndXJhdGlvbiA9IEN1cnJlbnQuY29uZmlndXJhdGlvbigpfSkge1xuICAgIGNvbnN0IHByb3ZpZGVyID0gY29uZmlndXJhdGlvbi5nZXRUZW5hbnREYXRhYmFzZVByb3ZpZGVyKGlkZW50aWZpZXIpXG4gICAgY29uc3QgZHJvcERhdGFiYXNlID0gdHlwZW9mIHByb3ZpZGVyLmRyb3BEYXRhYmFzZSA9PT0gXCJmdW5jdGlvblwiXG4gICAgICA/IHByb3ZpZGVyLmRyb3BEYXRhYmFzZS5iaW5kKHByb3ZpZGVyKVxuICAgICAgOiBkcm9wVGVuYW50RGF0YWJhc2VcblxuICAgIGF3YWl0IGNvbmZpZ3VyYXRpb24ucnVuV2l0aFRlbmFudCh0ZW5hbnQsIGFzeW5jICgpID0+IHtcbiAgICAgIC8vIEd1YXJkIGFnYWluc3QgYW4gdW5yZXNvbHZlZCB0ZW5hbnQuIHJlc29sdmVEYXRhYmFzZUNvbmZpZ3VyYXRpb24gZmFsbHMgYmFjayB0byB0aGVcbiAgICAgIC8vIGJhc2UgKHRlbXBsYXRlL2RlZmF1bHQpIHRlbmFudCBkYXRhYmFzZSB3aGVuIHRoZSByZXNvbHZlciByZXR1cm5zIG5vdGhpbmcgZm9yIHRoaXNcbiAgICAgIC8vIGRlc2NyaXB0b3IsIHNvIHdpdGhvdXQgdGhpcyBjaGVjayBhIHByb3ZpZGVyIHRoYXQgZHJvcHMgYnkgZGF0YWJhc2VDb25maWd1cmF0aW9uLm5hbWVcbiAgICAgIC8vIHdvdWxkIGRyb3AgdGhlIHRlbXBsYXRlIGRhdGFiYXNlIGluc3RlYWQgb2YgcmVqZWN0aW5nIHRoZSBiYWQgdGVuYW50LlxuICAgICAgaWYgKCFjb25maWd1cmF0aW9uLmlzRGF0YWJhc2VJZGVudGlmaWVyQWN0aXZlKGlkZW50aWZpZXIpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgVGVuYW50IGRhdGFiYXNlIGlkZW50aWZpZXIgJHtpZGVudGlmaWVyfSBpcyBpbmFjdGl2ZSBmb3IgdGVuYW50OiAke1RlbmFudEl0ZXJhdG9yLnRlbmFudExhYmVsKHRlbmFudCl9YClcbiAgICAgIH1cblxuICAgICAgYXdhaXQgZHJvcERhdGFiYXNlKHtcbiAgICAgICAgY29uZmlndXJhdGlvbixcbiAgICAgICAgZGF0YWJhc2VDb25maWd1cmF0aW9uOiBjb25maWd1cmF0aW9uLnJlc29sdmVEYXRhYmFzZUNvbmZpZ3VyYXRpb24oaWRlbnRpZmllciksXG4gICAgICAgIGlkZW50aWZpZXIsXG4gICAgICAgIHRlbmFudFxuICAgICAgfSlcbiAgICB9KVxuICB9XG59XG4iXX0=