velocious 1.0.483 → 1.0.484

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2242,6 +2242,6 @@ npx velocious db:tenants:migrate projectTenant --parallel 20
2242
2242
 
2243
2243
  `afterMigrateTenant` hooks run inside the active default and tenant database connection scope for the tenant being migrated.
2244
2244
 
2245
- At runtime, the apartment-style `Tenant` façade (`velocious/build/src/tenants/tenant.js`) is the single entry point: `Tenant.with(tenant, callback)` / `Tenant.current()` to switch into and read a tenant context, `Tenant.each({identifier, callback, parallel?, filter?})` to run a callback within every provider-listed tenant, and `Tenant.drop({identifier, tenant})` (plus the `db:tenants:drop` CLI command) to drop a tenant's database through the provider's `dropDatabase` hook.
2245
+ At runtime, the apartment-style `Tenant` façade (`velocious/build/src/tenants/tenant.js`) is the single entry point: `Tenant.with(tenant, callback)` / `Tenant.current()` to switch into and read a tenant context, `Tenant.each({identifier, callback, parallel?, filter?})` to run a callback within every provider-listed tenant, and `Tenant.drop({identifier, tenant})` (plus the `db:tenants:drop` CLI command) to drop a tenant's database through the provider's `dropDatabase` hook. `Tenant.with` and `Tenant.each` run their callbacks inside `ensureConnections`, so switching into a tenant establishes its database connections (global + tenant) and passes them to the callback — the tenant is immediately queryable without the caller wiring up connections (already-open connections are reused, so nesting does not double-connect).
2246
2246
 
2247
2247
  See [docs/tenant-databases.md](docs/tenant-databases.md) for the full configuration and migration pattern.
@@ -3,18 +3,26 @@
3
3
  * object the app's `tenantDatabaseResolver` understands (an account, a project, …); this
4
4
  * class is the single discoverable home for switching into a tenant's context, reading the
5
5
  * current one, iterating every tenant of a database identifier, and dropping a tenant's
6
- * database. Switching/reading delegate to {@link Current} (which owns the async-context
7
- * tenant state), so they compose with the existing connection pools and request lifecycle;
8
- * iteration and drop drive the app's tenant database provider hooks.
6
+ * database. Switching delegates to {@link Current} (which owns the async-context tenant
7
+ * state) and additionally runs the callback inside `ensureConnections`, so entering a tenant
8
+ * makes its database immediately queryable — the apartment-style "switch" semantics without
9
+ * the caller establishing connections itself; iteration and drop drive the app's tenant
10
+ * database provider hooks.
9
11
  */
10
12
  export default class Tenant {
11
13
  /**
12
14
  * Runs `callback` with `tenant` as the current tenant, restoring the previous tenant after.
15
+ * The callback runs inside `ensureConnections`, so every database identifier the tenant
16
+ * activates (the global database plus the tenant's database) has a checked-out connection
17
+ * available for the callback's duration: switching into a tenant makes it queryable without
18
+ * the caller wiring up connections. Already-checked-out connections are reused, so nesting
19
+ * `Tenant.with` calls does not open redundant connections. The callback receives the active
20
+ * connections keyed by identifier, the same as `ensureConnections`.
13
21
  * @param {object} tenant Descriptor understood by the app's tenantDatabaseResolver.
14
- * @param {() => Promise<?>} callback
22
+ * @param {(connections: Record<string, import("../database/drivers/base.js").default>) => Promise<?>} callback
15
23
  * @returns {Promise<?>}
16
24
  */
17
- static with(tenant: object, callback: () => Promise<unknown>): Promise<unknown>;
25
+ static with(tenant: object, callback: (connections: Record<string, import("../database/drivers/base.js").default>) => Promise<unknown>): Promise<unknown>;
18
26
  /**
19
27
  * The current tenant descriptor, or undefined when running outside any tenant context.
20
28
  * @returns {Record<string, unknown> | undefined}
@@ -22,8 +30,10 @@ export default class Tenant {
22
30
  static current(): Record<string, unknown> | undefined;
23
31
  /**
24
32
  * Lists the tenants for a database identifier through the provider and runs `callback`
25
- * within each tenant's context, optionally filtered and several at a time. Returns how
26
- * many tenants the callback ran for (after filtering).
33
+ * within each tenant's context, optionally filtered and several at a time. Like
34
+ * {@link Tenant.with}, the callback runs inside `ensureConnections` so each tenant's
35
+ * database is queryable without the caller wiring up connections. Returns how many tenants
36
+ * the callback ran for (after filtering).
27
37
  * @param {{identifier: string, callback: function({databaseConfiguration: import("../configuration-types.js").DatabaseConfigurationType, tenant: ?}) : Promise<void>, parallel?: number, filter?: (tenant: ?) => boolean, configuration?: import("../configuration.js").default}} args
28
38
  * @returns {Promise<number>}
29
39
  */
@@ -1 +1 @@
1
- {"version":3,"file":"tenant.d.ts","sourceRoot":"","sources":["../../../src/tenants/tenant.js"],"names":[],"mappings":"AAKA;;;;;;;;GAQG;AACH;IACE;;;;;OAKG;IACH,oBAJW,MAAM,YACN,MAAM,OAAO,CAAC,OAAC,CAAC,GACd,OAAO,CAAC,OAAC,CAAC,CAItB;IAED;;;OAGG;IACH,kBAFa,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAI/C;IAED;;;;;;OAMG;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,CAgB3B;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":"AAKA;;;;;;;;;;GAUG;AACH;IACE;;;;;;;;;;;OAWG;IACH,oBAJW,MAAM,YACN,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,6BAA6B,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAC,CAAC,GACxF,OAAO,CAAC,OAAC,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"}
@@ -6,19 +6,28 @@ import TenantIterator from "./tenant-iterator.js";
6
6
  * object the app's `tenantDatabaseResolver` understands (an account, a project, …); this
7
7
  * class is the single discoverable home for switching into a tenant's context, reading the
8
8
  * current one, iterating every tenant of a database identifier, and dropping a tenant's
9
- * database. Switching/reading delegate to {@link Current} (which owns the async-context
10
- * tenant state), so they compose with the existing connection pools and request lifecycle;
11
- * iteration and drop drive the app's tenant database provider hooks.
9
+ * database. Switching delegates to {@link Current} (which owns the async-context tenant
10
+ * state) and additionally runs the callback inside `ensureConnections`, so entering a tenant
11
+ * makes its database immediately queryable — the apartment-style "switch" semantics without
12
+ * the caller establishing connections itself; iteration and drop drive the app's tenant
13
+ * database provider hooks.
12
14
  */
13
15
  export default class Tenant {
14
16
  /**
15
17
  * Runs `callback` with `tenant` as the current tenant, restoring the previous tenant after.
18
+ * The callback runs inside `ensureConnections`, so every database identifier the tenant
19
+ * activates (the global database plus the tenant's database) has a checked-out connection
20
+ * available for the callback's duration: switching into a tenant makes it queryable without
21
+ * the caller wiring up connections. Already-checked-out connections are reused, so nesting
22
+ * `Tenant.with` calls does not open redundant connections. The callback receives the active
23
+ * connections keyed by identifier, the same as `ensureConnections`.
16
24
  * @param {object} tenant Descriptor understood by the app's tenantDatabaseResolver.
17
- * @param {() => Promise<?>} callback
25
+ * @param {(connections: Record<string, import("../database/drivers/base.js").default>) => Promise<?>} callback
18
26
  * @returns {Promise<?>}
19
27
  */
20
28
  static async with(tenant, callback) {
21
- return await Current.withTenant(tenant, callback);
29
+ const configuration = Current.configuration();
30
+ return await Current.withTenant(tenant, async () => await configuration.ensureConnections(callback));
22
31
  }
23
32
  /**
24
33
  * The current tenant descriptor, or undefined when running outside any tenant context.
@@ -29,8 +38,10 @@ export default class Tenant {
29
38
  }
30
39
  /**
31
40
  * Lists the tenants for a database identifier through the provider and runs `callback`
32
- * within each tenant's context, optionally filtered and several at a time. Returns how
33
- * many tenants the callback ran for (after filtering).
41
+ * within each tenant's context, optionally filtered and several at a time. Like
42
+ * {@link Tenant.with}, the callback runs inside `ensureConnections` so each tenant's
43
+ * database is queryable without the caller wiring up connections. Returns how many tenants
44
+ * the callback ran for (after filtering).
34
45
  * @param {{identifier: string, callback: function({databaseConfiguration: import("../configuration-types.js").DatabaseConfigurationType, tenant: ?}) : Promise<void>, parallel?: number, filter?: (tenant: ?) => boolean, configuration?: import("../configuration.js").default}} args
35
46
  * @returns {Promise<number>}
36
47
  */
@@ -44,7 +55,13 @@ export default class Tenant {
44
55
  }
45
56
  const tenants = filter ? listedTenants.filter(filter) : listedTenants;
46
57
  const iterator = new TenantIterator({ configuration, identifier, parallelCount: parallel });
47
- return await iterator.run(tenants, callback);
58
+ // Run each tenant's callback inside ensureConnections so the iterator stays
59
+ // connection-agnostic (the db:tenants:* CLI commands share TenantIterator and must run
60
+ // their callbacks, such as create, before the tenant database exists) while runtime
61
+ // iteration here gets the tenant's connections established the same way Tenant.with does.
62
+ return await iterator.run(tenants, async (callbackArgs) => {
63
+ await configuration.ensureConnections({ name: `Tenant.each: ${identifier}` }, async () => await callback(callbackArgs));
64
+ });
48
65
  }
49
66
  /**
50
67
  * Drops one tenant's database/schema through the provider's `dropDatabase` hook.
@@ -73,4 +90,4 @@ export default class Tenant {
73
90
  });
74
91
  }
75
92
  }
76
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVuYW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RlbmFudHMvdGVuYW50LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWixPQUFPLE9BQU8sTUFBTSxlQUFlLENBQUE7QUFDbkMsT0FBTyxjQUFjLE1BQU0sc0JBQXNCLENBQUE7QUFFakQ7Ozs7Ozs7O0dBUUc7QUFDSCxNQUFNLENBQUMsT0FBTyxPQUFPLE1BQU07SUFDekI7Ozs7O09BS0c7SUFDSCxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsUUFBUTtRQUNoQyxPQUFPLE1BQU0sT0FBTyxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsUUFBUSxDQUFDLENBQUE7SUFDbkQsQ0FBQztJQUVEOzs7T0FHRztJQUNILE1BQU0sQ0FBQyxPQUFPO1FBQ1osT0FBTyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUE7SUFDekIsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNILE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUMsVUFBVSxFQUFFLFFBQVEsRUFBRSxRQUFRLEdBQUcsQ0FBQyxFQUFFLE1BQU0sRUFBRSxhQUFhLEdBQUcsT0FBTyxDQUFDLGFBQWEsRUFBRSxFQUFDO1FBQ3JHLE1BQU0sUUFBUSxHQUFHLGFBQWEsQ0FBQyx5QkFBeUIsQ0FBQyxVQUFVLENBQUMsQ0FBQTtRQUNwRSxNQUFNLGFBQWEsR0FBRyxNQUFNLGFBQWEsQ0FBQyxpQkFBaUIsQ0FBQyxFQUFDLElBQUksRUFBRSxnQkFBZ0IsVUFBVSxFQUFFLEVBQUMsRUFBRSxLQUFLLElBQUksRUFBRTtZQUMzRyxPQUFPLE1BQU0sUUFBUSxDQUFDLFdBQVcsQ0FBQyxFQUFDLGFBQWEsRUFBRSxVQUFVLEVBQUMsQ0FBQyxDQUFBO1FBQ2hFLENBQUMsQ0FBQyxDQUFBO1FBRUYsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLEVBQUUsQ0FBQztZQUNsQyxNQUFNLElBQUksS0FBSyxDQUFDLGdDQUFnQyxVQUFVLHdDQUF3QyxDQUFDLENBQUE7UUFDckcsQ0FBQztRQUVELE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFBO1FBQ3JFLE1BQU0sUUFBUSxHQUFHLElBQUksY0FBYyxDQUFDLEVBQUMsYUFBYSxFQUFFLFVBQVUsRUFBRSxhQUFhLEVBQUUsUUFBUSxFQUFDLENBQUMsQ0FBQTtRQUV6RixPQUFPLE1BQU0sUUFBUSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsUUFBUSxDQUFDLENBQUE7SUFDOUMsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFDLFVBQVUsRUFBRSxNQUFNLEVBQUUsYUFBYSxHQUFHLE9BQU8sQ0FBQyxhQUFhLEVBQUUsRUFBQztRQUM3RSxNQUFNLFFBQVEsR0FBRyxhQUFhLENBQUMseUJBQXlCLENBQUMsVUFBVSxDQUFDLENBQUE7UUFFcEUsSUFBSSxPQUFPLFFBQVEsQ0FBQyxZQUFZLEtBQUssVUFBVSxFQUFFLENBQUM7WUFDaEQsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsVUFBVSw0Q0FBNEMsQ0FBQyxDQUFBO1FBQ3pHLENBQUM7UUFFRCxNQUFNLGFBQWEsQ0FBQyxhQUFhLENBQUMsTUFBTSxFQUFFLEtBQUssSUFBSSxFQUFFO1lBQ25ELHFGQUFxRjtZQUNyRixxRkFBcUY7WUFDckYsd0ZBQXdGO1lBQ3hGLHdFQUF3RTtZQUN4RSxJQUFJLENBQUMsYUFBYSxDQUFDLDBCQUEwQixDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7Z0JBQzFELE1BQU0sSUFBSSxLQUFLLENBQUMsOEJBQThCLFVBQVUsNEJBQTRCLGNBQWMsQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFBO1lBQzNILENBQUM7WUFFRCxNQUFNLFFBQVEsQ0FBQyxZQUFZLEVBQUUsQ0FBQztnQkFDNUIsYUFBYTtnQkFDYixxQkFBcUIsRUFBRSxhQUFhLENBQUMsNEJBQTRCLENBQUMsVUFBVSxDQUFDO2dCQUM3RSxVQUFVO2dCQUNWLE1BQU07YUFDUCxDQUFDLENBQUE7UUFDSixDQUFDLENBQUMsQ0FBQTtJQUNKLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG5pbXBvcnQgQ3VycmVudCBmcm9tIFwiLi4vY3VycmVudC5qc1wiXG5pbXBvcnQgVGVuYW50SXRlcmF0b3IgZnJvbSBcIi4vdGVuYW50LWl0ZXJhdG9yLmpzXCJcblxuLyoqXG4gKiBBcGFydG1lbnQtc3R5bGUgcnVudGltZSBmYcOnYWRlIGZvciBtdWx0aS10ZW5hbnQgYXBwcy4gQSBcInRlbmFudFwiIGlzIHdoYXRldmVyIGRlc2NyaXB0b3JcbiAqIG9iamVjdCB0aGUgYXBwJ3MgYHRlbmFudERhdGFiYXNlUmVzb2x2ZXJgIHVuZGVyc3RhbmRzIChhbiBhY2NvdW50LCBhIHByb2plY3QsIOKApik7IHRoaXNcbiAqIGNsYXNzIGlzIHRoZSBzaW5nbGUgZGlzY292ZXJhYmxlIGhvbWUgZm9yIHN3aXRjaGluZyBpbnRvIGEgdGVuYW50J3MgY29udGV4dCwgcmVhZGluZyB0aGVcbiAqIGN1cnJlbnQgb25lLCBpdGVyYXRpbmcgZXZlcnkgdGVuYW50IG9mIGEgZGF0YWJhc2UgaWRlbnRpZmllciwgYW5kIGRyb3BwaW5nIGEgdGVuYW50J3NcbiAqIGRhdGFiYXNlLiBTd2l0Y2hpbmcvcmVhZGluZyBkZWxlZ2F0ZSB0byB7QGxpbmsgQ3VycmVudH0gKHdoaWNoIG93bnMgdGhlIGFzeW5jLWNvbnRleHRcbiAqIHRlbmFudCBzdGF0ZSksIHNvIHRoZXkgY29tcG9zZSB3aXRoIHRoZSBleGlzdGluZyBjb25uZWN0aW9uIHBvb2xzIGFuZCByZXF1ZXN0IGxpZmVjeWNsZTtcbiAqIGl0ZXJhdGlvbiBhbmQgZHJvcCBkcml2ZSB0aGUgYXBwJ3MgdGVuYW50IGRhdGFiYXNlIHByb3ZpZGVyIGhvb2tzLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBUZW5hbnQge1xuICAvKipcbiAgICogUnVucyBgY2FsbGJhY2tgIHdpdGggYHRlbmFudGAgYXMgdGhlIGN1cnJlbnQgdGVuYW50LCByZXN0b3JpbmcgdGhlIHByZXZpb3VzIHRlbmFudCBhZnRlci5cbiAgICogQHBhcmFtIHtvYmplY3R9IHRlbmFudCBEZXNjcmlwdG9yIHVuZGVyc3Rvb2QgYnkgdGhlIGFwcCdzIHRlbmFudERhdGFiYXNlUmVzb2x2ZXIuXG4gICAqIEBwYXJhbSB7KCkgPT4gUHJvbWlzZTw/Pn0gY2FsbGJhY2tcbiAgICogQHJldHVybnMge1Byb21pc2U8Pz59XG4gICAqL1xuICBzdGF0aWMgYXN5bmMgd2l0aCh0ZW5hbnQsIGNhbGxiYWNrKSB7XG4gICAgcmV0dXJuIGF3YWl0IEN1cnJlbnQud2l0aFRlbmFudCh0ZW5hbnQsIGNhbGxiYWNrKVxuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBjdXJyZW50IHRlbmFudCBkZXNjcmlwdG9yLCBvciB1bmRlZmluZWQgd2hlbiBydW5uaW5nIG91dHNpZGUgYW55IHRlbmFudCBjb250ZXh0LlxuICAgKiBAcmV0dXJucyB7UmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCB1bmRlZmluZWR9XG4gICAqL1xuICBzdGF0aWMgY3VycmVudCgpIHtcbiAgICByZXR1cm4gQ3VycmVudC50ZW5hbnQoKVxuICB9XG5cbiAgLyoqXG4gICAqIExpc3RzIHRoZSB0ZW5hbnRzIGZvciBhIGRhdGFiYXNlIGlkZW50aWZpZXIgdGhyb3VnaCB0aGUgcHJvdmlkZXIgYW5kIHJ1bnMgYGNhbGxiYWNrYFxuICAgKiB3aXRoaW4gZWFjaCB0ZW5hbnQncyBjb250ZXh0LCBvcHRpb25hbGx5IGZpbHRlcmVkIGFuZCBzZXZlcmFsIGF0IGEgdGltZS4gUmV0dXJucyBob3dcbiAgICogbWFueSB0ZW5hbnRzIHRoZSBjYWxsYmFjayByYW4gZm9yIChhZnRlciBmaWx0ZXJpbmcpLlxuICAgKiBAcGFyYW0ge3tpZGVudGlmaWVyOiBzdHJpbmcsIGNhbGxiYWNrOiBmdW5jdGlvbih7ZGF0YWJhc2VDb25maWd1cmF0aW9uOiBpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLkRhdGFiYXNlQ29uZmlndXJhdGlvblR5cGUsIHRlbmFudDogP30pIDogUHJvbWlzZTx2b2lkPiwgcGFyYWxsZWw/OiBudW1iZXIsIGZpbHRlcj86ICh0ZW5hbnQ6ID8pID0+IGJvb2xlYW4sIGNvbmZpZ3VyYXRpb24/OiBpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLmpzXCIpLmRlZmF1bHR9fSBhcmdzXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPG51bWJlcj59XG4gICAqL1xuICBzdGF0aWMgYXN5bmMgZWFjaCh7aWRlbnRpZmllciwgY2FsbGJhY2ssIHBhcmFsbGVsID0gMSwgZmlsdGVyLCBjb25maWd1cmF0aW9uID0gQ3VycmVudC5jb25maWd1cmF0aW9uKCl9KSB7XG4gICAgY29uc3QgcHJvdmlkZXIgPSBjb25maWd1cmF0aW9uLmdldFRlbmFudERhdGFiYXNlUHJvdmlkZXIoaWRlbnRpZmllcilcbiAgICBjb25zdCBsaXN0ZWRUZW5hbnRzID0gYXdhaXQgY29uZmlndXJhdGlvbi5lbnN1cmVDb25uZWN0aW9ucyh7bmFtZTogYFRlbmFudC5lYWNoOiAke2lkZW50aWZpZXJ9YH0sIGFzeW5jICgpID0+IHtcbiAgICAgIHJldHVybiBhd2FpdCBwcm92aWRlci5saXN0VGVuYW50cyh7Y29uZmlndXJhdGlvbiwgaWRlbnRpZmllcn0pXG4gICAgfSlcblxuICAgIGlmICghQXJyYXkuaXNBcnJheShsaXN0ZWRUZW5hbnRzKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBUZW5hbnQgZGF0YWJhc2UgcHJvdmlkZXIgZm9yICR7aWRlbnRpZmllcn0gbXVzdCByZXR1cm4gYW4gYXJyYXkgZnJvbSBsaXN0VGVuYW50c2ApXG4gICAgfVxuXG4gICAgY29uc3QgdGVuYW50cyA9IGZpbHRlciA/IGxpc3RlZFRlbmFudHMuZmlsdGVyKGZpbHRlcikgOiBsaXN0ZWRUZW5hbnRzXG4gICAgY29uc3QgaXRlcmF0b3IgPSBuZXcgVGVuYW50SXRlcmF0b3Ioe2NvbmZpZ3VyYXRpb24sIGlkZW50aWZpZXIsIHBhcmFsbGVsQ291bnQ6IHBhcmFsbGVsfSlcblxuICAgIHJldHVybiBhd2FpdCBpdGVyYXRvci5ydW4odGVuYW50cywgY2FsbGJhY2spXG4gIH1cblxuICAvKipcbiAgICogRHJvcHMgb25lIHRlbmFudCdzIGRhdGFiYXNlL3NjaGVtYSB0aHJvdWdoIHRoZSBwcm92aWRlcidzIGBkcm9wRGF0YWJhc2VgIGhvb2suXG4gICAqIEBwYXJhbSB7e2lkZW50aWZpZXI6IHN0cmluZywgdGVuYW50OiBvYmplY3QsIGNvbmZpZ3VyYXRpb24/OiBpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLmpzXCIpLmRlZmF1bHR9fSBhcmdzXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgc3RhdGljIGFzeW5jIGRyb3Aoe2lkZW50aWZpZXIsIHRlbmFudCwgY29uZmlndXJhdGlvbiA9IEN1cnJlbnQuY29uZmlndXJhdGlvbigpfSkge1xuICAgIGNvbnN0IHByb3ZpZGVyID0gY29uZmlndXJhdGlvbi5nZXRUZW5hbnREYXRhYmFzZVByb3ZpZGVyKGlkZW50aWZpZXIpXG5cbiAgICBpZiAodHlwZW9mIHByb3ZpZGVyLmRyb3BEYXRhYmFzZSAhPT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFRlbmFudCBkYXRhYmFzZSBwcm92aWRlciBmb3IgJHtpZGVudGlmaWVyfSBtdXN0IGRlZmluZSBkcm9wRGF0YWJhc2UgdG8gZHJvcCBhIHRlbmFudGApXG4gICAgfVxuXG4gICAgYXdhaXQgY29uZmlndXJhdGlvbi5ydW5XaXRoVGVuYW50KHRlbmFudCwgYXN5bmMgKCkgPT4ge1xuICAgICAgLy8gR3VhcmQgYWdhaW5zdCBhbiB1bnJlc29sdmVkIHRlbmFudC4gcmVzb2x2ZURhdGFiYXNlQ29uZmlndXJhdGlvbiBmYWxscyBiYWNrIHRvIHRoZVxuICAgICAgLy8gYmFzZSAodGVtcGxhdGUvZGVmYXVsdCkgdGVuYW50IGRhdGFiYXNlIHdoZW4gdGhlIHJlc29sdmVyIHJldHVybnMgbm90aGluZyBmb3IgdGhpc1xuICAgICAgLy8gZGVzY3JpcHRvciwgc28gd2l0aG91dCB0aGlzIGNoZWNrIGEgcHJvdmlkZXIgdGhhdCBkcm9wcyBieSBkYXRhYmFzZUNvbmZpZ3VyYXRpb24ubmFtZVxuICAgICAgLy8gd291bGQgZHJvcCB0aGUgdGVtcGxhdGUgZGF0YWJhc2UgaW5zdGVhZCBvZiByZWplY3RpbmcgdGhlIGJhZCB0ZW5hbnQuXG4gICAgICBpZiAoIWNvbmZpZ3VyYXRpb24uaXNEYXRhYmFzZUlkZW50aWZpZXJBY3RpdmUoaWRlbnRpZmllcikpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBUZW5hbnQgZGF0YWJhc2UgaWRlbnRpZmllciAke2lkZW50aWZpZXJ9IGlzIGluYWN0aXZlIGZvciB0ZW5hbnQ6ICR7VGVuYW50SXRlcmF0b3IudGVuYW50TGFiZWwodGVuYW50KX1gKVxuICAgICAgfVxuXG4gICAgICBhd2FpdCBwcm92aWRlci5kcm9wRGF0YWJhc2U/Lih7XG4gICAgICAgIGNvbmZpZ3VyYXRpb24sXG4gICAgICAgIGRhdGFiYXNlQ29uZmlndXJhdGlvbjogY29uZmlndXJhdGlvbi5yZXNvbHZlRGF0YWJhc2VDb25maWd1cmF0aW9uKGlkZW50aWZpZXIpLFxuICAgICAgICBpZGVudGlmaWVyLFxuICAgICAgICB0ZW5hbnRcbiAgICAgIH0pXG4gICAgfSlcbiAgfVxufVxuIl19
93
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVuYW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RlbmFudHMvdGVuYW50LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWixPQUFPLE9BQU8sTUFBTSxlQUFlLENBQUE7QUFDbkMsT0FBTyxjQUFjLE1BQU0sc0JBQXNCLENBQUE7QUFFakQ7Ozs7Ozs7Ozs7R0FVRztBQUNILE1BQU0sQ0FBQyxPQUFPLE9BQU8sTUFBTTtJQUN6Qjs7Ozs7Ozs7Ozs7T0FXRztJQUNILE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxRQUFRO1FBQ2hDLE1BQU0sYUFBYSxHQUFHLE9BQU8sQ0FBQyxhQUFhLEVBQUUsQ0FBQTtRQUU3QyxPQUFPLE1BQU0sT0FBTyxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsS0FBSyxJQUFJLEVBQUUsQ0FBQyxNQUFNLGFBQWEsQ0FBQyxpQkFBaUIsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFBO0lBQ3RHLENBQUM7SUFFRDs7O09BR0c7SUFDSCxNQUFNLENBQUMsT0FBTztRQUNaLE9BQU8sT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFBO0lBQ3pCLENBQUM7SUFFRDs7Ozs7Ozs7T0FRRztJQUNILE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUMsVUFBVSxFQUFFLFFBQVEsRUFBRSxRQUFRLEdBQUcsQ0FBQyxFQUFFLE1BQU0sRUFBRSxhQUFhLEdBQUcsT0FBTyxDQUFDLGFBQWEsRUFBRSxFQUFDO1FBQ3JHLE1BQU0sUUFBUSxHQUFHLGFBQWEsQ0FBQyx5QkFBeUIsQ0FBQyxVQUFVLENBQUMsQ0FBQTtRQUNwRSxNQUFNLGFBQWEsR0FBRyxNQUFNLGFBQWEsQ0FBQyxpQkFBaUIsQ0FBQyxFQUFDLElBQUksRUFBRSxnQkFBZ0IsVUFBVSxFQUFFLEVBQUMsRUFBRSxLQUFLLElBQUksRUFBRTtZQUMzRyxPQUFPLE1BQU0sUUFBUSxDQUFDLFdBQVcsQ0FBQyxFQUFDLGFBQWEsRUFBRSxVQUFVLEVBQUMsQ0FBQyxDQUFBO1FBQ2hFLENBQUMsQ0FBQyxDQUFBO1FBRUYsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLEVBQUUsQ0FBQztZQUNsQyxNQUFNLElBQUksS0FBSyxDQUFDLGdDQUFnQyxVQUFVLHdDQUF3QyxDQUFDLENBQUE7UUFDckcsQ0FBQztRQUVELE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFBO1FBQ3JFLE1BQU0sUUFBUSxHQUFHLElBQUksY0FBYyxDQUFDLEVBQUMsYUFBYSxFQUFFLFVBQVUsRUFBRSxhQUFhLEVBQUUsUUFBUSxFQUFDLENBQUMsQ0FBQTtRQUV6Riw0RUFBNEU7UUFDNUUsdUZBQXVGO1FBQ3ZGLG9GQUFvRjtRQUNwRiwwRkFBMEY7UUFDMUYsT0FBTyxNQUFNLFFBQVEsQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsRUFBRTtZQUN4RCxNQUFNLGFBQWEsQ0FBQyxpQkFBaUIsQ0FBQyxFQUFDLElBQUksRUFBRSxnQkFBZ0IsVUFBVSxFQUFFLEVBQUMsRUFBRSxLQUFLLElBQUksRUFBRSxDQUFDLE1BQU0sUUFBUSxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUE7UUFDdkgsQ0FBQyxDQUFDLENBQUE7SUFDSixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUMsVUFBVSxFQUFFLE1BQU0sRUFBRSxhQUFhLEdBQUcsT0FBTyxDQUFDLGFBQWEsRUFBRSxFQUFDO1FBQzdFLE1BQU0sUUFBUSxHQUFHLGFBQWEsQ0FBQyx5QkFBeUIsQ0FBQyxVQUFVLENBQUMsQ0FBQTtRQUVwRSxJQUFJLE9BQU8sUUFBUSxDQUFDLFlBQVksS0FBSyxVQUFVLEVBQUUsQ0FBQztZQUNoRCxNQUFNLElBQUksS0FBSyxDQUFDLGdDQUFnQyxVQUFVLDRDQUE0QyxDQUFDLENBQUE7UUFDekcsQ0FBQztRQUVELE1BQU0sYUFBYSxDQUFDLGFBQWEsQ0FBQyxNQUFNLEVBQUUsS0FBSyxJQUFJLEVBQUU7WUFDbkQscUZBQXFGO1lBQ3JGLHFGQUFxRjtZQUNyRix3RkFBd0Y7WUFDeEYsd0VBQXdFO1lBQ3hFLElBQUksQ0FBQyxhQUFhLENBQUMsMEJBQTBCLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztnQkFDMUQsTUFBTSxJQUFJLEtBQUssQ0FBQyw4QkFBOEIsVUFBVSw0QkFBNEIsY0FBYyxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUE7WUFDM0gsQ0FBQztZQUVELE1BQU0sUUFBUSxDQUFDLFlBQVksRUFBRSxDQUFDO2dCQUM1QixhQUFhO2dCQUNiLHFCQUFxQixFQUFFLGFBQWEsQ0FBQyw0QkFBNEIsQ0FBQyxVQUFVLENBQUM7Z0JBQzdFLFVBQVU7Z0JBQ1YsTUFBTTthQUNQLENBQUMsQ0FBQTtRQUNKLENBQUMsQ0FBQyxDQUFBO0lBQ0osQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmltcG9ydCBDdXJyZW50IGZyb20gXCIuLi9jdXJyZW50LmpzXCJcbmltcG9ydCBUZW5hbnRJdGVyYXRvciBmcm9tIFwiLi90ZW5hbnQtaXRlcmF0b3IuanNcIlxuXG4vKipcbiAqIEFwYXJ0bWVudC1zdHlsZSBydW50aW1lIGZhw6dhZGUgZm9yIG11bHRpLXRlbmFudCBhcHBzLiBBIFwidGVuYW50XCIgaXMgd2hhdGV2ZXIgZGVzY3JpcHRvclxuICogb2JqZWN0IHRoZSBhcHAncyBgdGVuYW50RGF0YWJhc2VSZXNvbHZlcmAgdW5kZXJzdGFuZHMgKGFuIGFjY291bnQsIGEgcHJvamVjdCwg4oCmKTsgdGhpc1xuICogY2xhc3MgaXMgdGhlIHNpbmdsZSBkaXNjb3ZlcmFibGUgaG9tZSBmb3Igc3dpdGNoaW5nIGludG8gYSB0ZW5hbnQncyBjb250ZXh0LCByZWFkaW5nIHRoZVxuICogY3VycmVudCBvbmUsIGl0ZXJhdGluZyBldmVyeSB0ZW5hbnQgb2YgYSBkYXRhYmFzZSBpZGVudGlmaWVyLCBhbmQgZHJvcHBpbmcgYSB0ZW5hbnQnc1xuICogZGF0YWJhc2UuIFN3aXRjaGluZyBkZWxlZ2F0ZXMgdG8ge0BsaW5rIEN1cnJlbnR9ICh3aGljaCBvd25zIHRoZSBhc3luYy1jb250ZXh0IHRlbmFudFxuICogc3RhdGUpIGFuZCBhZGRpdGlvbmFsbHkgcnVucyB0aGUgY2FsbGJhY2sgaW5zaWRlIGBlbnN1cmVDb25uZWN0aW9uc2AsIHNvIGVudGVyaW5nIGEgdGVuYW50XG4gKiBtYWtlcyBpdHMgZGF0YWJhc2UgaW1tZWRpYXRlbHkgcXVlcnlhYmxlIOKAlCB0aGUgYXBhcnRtZW50LXN0eWxlIFwic3dpdGNoXCIgc2VtYW50aWNzIOKAlCB3aXRob3V0XG4gKiB0aGUgY2FsbGVyIGVzdGFibGlzaGluZyBjb25uZWN0aW9ucyBpdHNlbGY7IGl0ZXJhdGlvbiBhbmQgZHJvcCBkcml2ZSB0aGUgYXBwJ3MgdGVuYW50XG4gKiBkYXRhYmFzZSBwcm92aWRlciBob29rcy5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgVGVuYW50IHtcbiAgLyoqXG4gICAqIFJ1bnMgYGNhbGxiYWNrYCB3aXRoIGB0ZW5hbnRgIGFzIHRoZSBjdXJyZW50IHRlbmFudCwgcmVzdG9yaW5nIHRoZSBwcmV2aW91cyB0ZW5hbnQgYWZ0ZXIuXG4gICAqIFRoZSBjYWxsYmFjayBydW5zIGluc2lkZSBgZW5zdXJlQ29ubmVjdGlvbnNgLCBzbyBldmVyeSBkYXRhYmFzZSBpZGVudGlmaWVyIHRoZSB0ZW5hbnRcbiAgICogYWN0aXZhdGVzICh0aGUgZ2xvYmFsIGRhdGFiYXNlIHBsdXMgdGhlIHRlbmFudCdzIGRhdGFiYXNlKSBoYXMgYSBjaGVja2VkLW91dCBjb25uZWN0aW9uXG4gICAqIGF2YWlsYWJsZSBmb3IgdGhlIGNhbGxiYWNrJ3MgZHVyYXRpb246IHN3aXRjaGluZyBpbnRvIGEgdGVuYW50IG1ha2VzIGl0IHF1ZXJ5YWJsZSB3aXRob3V0XG4gICAqIHRoZSBjYWxsZXIgd2lyaW5nIHVwIGNvbm5lY3Rpb25zLiBBbHJlYWR5LWNoZWNrZWQtb3V0IGNvbm5lY3Rpb25zIGFyZSByZXVzZWQsIHNvIG5lc3RpbmdcbiAgICogYFRlbmFudC53aXRoYCBjYWxscyBkb2VzIG5vdCBvcGVuIHJlZHVuZGFudCBjb25uZWN0aW9ucy4gVGhlIGNhbGxiYWNrIHJlY2VpdmVzIHRoZSBhY3RpdmVcbiAgICogY29ubmVjdGlvbnMga2V5ZWQgYnkgaWRlbnRpZmllciwgdGhlIHNhbWUgYXMgYGVuc3VyZUNvbm5lY3Rpb25zYC5cbiAgICogQHBhcmFtIHtvYmplY3R9IHRlbmFudCBEZXNjcmlwdG9yIHVuZGVyc3Rvb2QgYnkgdGhlIGFwcCdzIHRlbmFudERhdGFiYXNlUmVzb2x2ZXIuXG4gICAqIEBwYXJhbSB7KGNvbm5lY3Rpb25zOiBSZWNvcmQ8c3RyaW5nLCBpbXBvcnQoXCIuLi9kYXRhYmFzZS9kcml2ZXJzL2Jhc2UuanNcIikuZGVmYXVsdD4pID0+IFByb21pc2U8Pz59IGNhbGxiYWNrXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPD8+fVxuICAgKi9cbiAgc3RhdGljIGFzeW5jIHdpdGgodGVuYW50LCBjYWxsYmFjaykge1xuICAgIGNvbnN0IGNvbmZpZ3VyYXRpb24gPSBDdXJyZW50LmNvbmZpZ3VyYXRpb24oKVxuXG4gICAgcmV0dXJuIGF3YWl0IEN1cnJlbnQud2l0aFRlbmFudCh0ZW5hbnQsIGFzeW5jICgpID0+IGF3YWl0IGNvbmZpZ3VyYXRpb24uZW5zdXJlQ29ubmVjdGlvbnMoY2FsbGJhY2spKVxuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBjdXJyZW50IHRlbmFudCBkZXNjcmlwdG9yLCBvciB1bmRlZmluZWQgd2hlbiBydW5uaW5nIG91dHNpZGUgYW55IHRlbmFudCBjb250ZXh0LlxuICAgKiBAcmV0dXJucyB7UmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCB1bmRlZmluZWR9XG4gICAqL1xuICBzdGF0aWMgY3VycmVudCgpIHtcbiAgICByZXR1cm4gQ3VycmVudC50ZW5hbnQoKVxuICB9XG5cbiAgLyoqXG4gICAqIExpc3RzIHRoZSB0ZW5hbnRzIGZvciBhIGRhdGFiYXNlIGlkZW50aWZpZXIgdGhyb3VnaCB0aGUgcHJvdmlkZXIgYW5kIHJ1bnMgYGNhbGxiYWNrYFxuICAgKiB3aXRoaW4gZWFjaCB0ZW5hbnQncyBjb250ZXh0LCBvcHRpb25hbGx5IGZpbHRlcmVkIGFuZCBzZXZlcmFsIGF0IGEgdGltZS4gTGlrZVxuICAgKiB7QGxpbmsgVGVuYW50LndpdGh9LCB0aGUgY2FsbGJhY2sgcnVucyBpbnNpZGUgYGVuc3VyZUNvbm5lY3Rpb25zYCBzbyBlYWNoIHRlbmFudCdzXG4gICAqIGRhdGFiYXNlIGlzIHF1ZXJ5YWJsZSB3aXRob3V0IHRoZSBjYWxsZXIgd2lyaW5nIHVwIGNvbm5lY3Rpb25zLiBSZXR1cm5zIGhvdyBtYW55IHRlbmFudHNcbiAgICogdGhlIGNhbGxiYWNrIHJhbiBmb3IgKGFmdGVyIGZpbHRlcmluZykuXG4gICAqIEBwYXJhbSB7e2lkZW50aWZpZXI6IHN0cmluZywgY2FsbGJhY2s6IGZ1bmN0aW9uKHtkYXRhYmFzZUNvbmZpZ3VyYXRpb246IGltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24tdHlwZXMuanNcIikuRGF0YWJhc2VDb25maWd1cmF0aW9uVHlwZSwgdGVuYW50OiA/fSkgOiBQcm9taXNlPHZvaWQ+LCBwYXJhbGxlbD86IG51bWJlciwgZmlsdGVyPzogKHRlbmFudDogPykgPT4gYm9vbGVhbiwgY29uZmlndXJhdGlvbj86IGltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24uanNcIikuZGVmYXVsdH19IGFyZ3NcbiAgICogQHJldHVybnMge1Byb21pc2U8bnVtYmVyPn1cbiAgICovXG4gIHN0YXRpYyBhc3luYyBlYWNoKHtpZGVudGlmaWVyLCBjYWxsYmFjaywgcGFyYWxsZWwgPSAxLCBmaWx0ZXIsIGNvbmZpZ3VyYXRpb24gPSBDdXJyZW50LmNvbmZpZ3VyYXRpb24oKX0pIHtcbiAgICBjb25zdCBwcm92aWRlciA9IGNvbmZpZ3VyYXRpb24uZ2V0VGVuYW50RGF0YWJhc2VQcm92aWRlcihpZGVudGlmaWVyKVxuICAgIGNvbnN0IGxpc3RlZFRlbmFudHMgPSBhd2FpdCBjb25maWd1cmF0aW9uLmVuc3VyZUNvbm5lY3Rpb25zKHtuYW1lOiBgVGVuYW50LmVhY2g6ICR7aWRlbnRpZmllcn1gfSwgYXN5bmMgKCkgPT4ge1xuICAgICAgcmV0dXJuIGF3YWl0IHByb3ZpZGVyLmxpc3RUZW5hbnRzKHtjb25maWd1cmF0aW9uLCBpZGVudGlmaWVyfSlcbiAgICB9KVxuXG4gICAgaWYgKCFBcnJheS5pc0FycmF5KGxpc3RlZFRlbmFudHMpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFRlbmFudCBkYXRhYmFzZSBwcm92aWRlciBmb3IgJHtpZGVudGlmaWVyfSBtdXN0IHJldHVybiBhbiBhcnJheSBmcm9tIGxpc3RUZW5hbnRzYClcbiAgICB9XG5cbiAgICBjb25zdCB0ZW5hbnRzID0gZmlsdGVyID8gbGlzdGVkVGVuYW50cy5maWx0ZXIoZmlsdGVyKSA6IGxpc3RlZFRlbmFudHNcbiAgICBjb25zdCBpdGVyYXRvciA9IG5ldyBUZW5hbnRJdGVyYXRvcih7Y29uZmlndXJhdGlvbiwgaWRlbnRpZmllciwgcGFyYWxsZWxDb3VudDogcGFyYWxsZWx9KVxuXG4gICAgLy8gUnVuIGVhY2ggdGVuYW50J3MgY2FsbGJhY2sgaW5zaWRlIGVuc3VyZUNvbm5lY3Rpb25zIHNvIHRoZSBpdGVyYXRvciBzdGF5c1xuICAgIC8vIGNvbm5lY3Rpb24tYWdub3N0aWMgKHRoZSBkYjp0ZW5hbnRzOiogQ0xJIGNvbW1hbmRzIHNoYXJlIFRlbmFudEl0ZXJhdG9yIGFuZCBtdXN0IHJ1blxuICAgIC8vIHRoZWlyIGNhbGxiYWNrcywgc3VjaCBhcyBjcmVhdGUsIGJlZm9yZSB0aGUgdGVuYW50IGRhdGFiYXNlIGV4aXN0cykgd2hpbGUgcnVudGltZVxuICAgIC8vIGl0ZXJhdGlvbiBoZXJlIGdldHMgdGhlIHRlbmFudCdzIGNvbm5lY3Rpb25zIGVzdGFibGlzaGVkIHRoZSBzYW1lIHdheSBUZW5hbnQud2l0aCBkb2VzLlxuICAgIHJldHVybiBhd2FpdCBpdGVyYXRvci5ydW4odGVuYW50cywgYXN5bmMgKGNhbGxiYWNrQXJncykgPT4ge1xuICAgICAgYXdhaXQgY29uZmlndXJhdGlvbi5lbnN1cmVDb25uZWN0aW9ucyh7bmFtZTogYFRlbmFudC5lYWNoOiAke2lkZW50aWZpZXJ9YH0sIGFzeW5jICgpID0+IGF3YWl0IGNhbGxiYWNrKGNhbGxiYWNrQXJncykpXG4gICAgfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBEcm9wcyBvbmUgdGVuYW50J3MgZGF0YWJhc2Uvc2NoZW1hIHRocm91Z2ggdGhlIHByb3ZpZGVyJ3MgYGRyb3BEYXRhYmFzZWAgaG9vay5cbiAgICogQHBhcmFtIHt7aWRlbnRpZmllcjogc3RyaW5nLCB0ZW5hbnQ6IG9iamVjdCwgY29uZmlndXJhdGlvbj86IGltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24uanNcIikuZGVmYXVsdH19IGFyZ3NcbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBzdGF0aWMgYXN5bmMgZHJvcCh7aWRlbnRpZmllciwgdGVuYW50LCBjb25maWd1cmF0aW9uID0gQ3VycmVudC5jb25maWd1cmF0aW9uKCl9KSB7XG4gICAgY29uc3QgcHJvdmlkZXIgPSBjb25maWd1cmF0aW9uLmdldFRlbmFudERhdGFiYXNlUHJvdmlkZXIoaWRlbnRpZmllcilcblxuICAgIGlmICh0eXBlb2YgcHJvdmlkZXIuZHJvcERhdGFiYXNlICE9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgVGVuYW50IGRhdGFiYXNlIHByb3ZpZGVyIGZvciAke2lkZW50aWZpZXJ9IG11c3QgZGVmaW5lIGRyb3BEYXRhYmFzZSB0byBkcm9wIGEgdGVuYW50YClcbiAgICB9XG5cbiAgICBhd2FpdCBjb25maWd1cmF0aW9uLnJ1bldpdGhUZW5hbnQodGVuYW50LCBhc3luYyAoKSA9PiB7XG4gICAgICAvLyBHdWFyZCBhZ2FpbnN0IGFuIHVucmVzb2x2ZWQgdGVuYW50LiByZXNvbHZlRGF0YWJhc2VDb25maWd1cmF0aW9uIGZhbGxzIGJhY2sgdG8gdGhlXG4gICAgICAvLyBiYXNlICh0ZW1wbGF0ZS9kZWZhdWx0KSB0ZW5hbnQgZGF0YWJhc2Ugd2hlbiB0aGUgcmVzb2x2ZXIgcmV0dXJucyBub3RoaW5nIGZvciB0aGlzXG4gICAgICAvLyBkZXNjcmlwdG9yLCBzbyB3aXRob3V0IHRoaXMgY2hlY2sgYSBwcm92aWRlciB0aGF0IGRyb3BzIGJ5IGRhdGFiYXNlQ29uZmlndXJhdGlvbi5uYW1lXG4gICAgICAvLyB3b3VsZCBkcm9wIHRoZSB0ZW1wbGF0ZSBkYXRhYmFzZSBpbnN0ZWFkIG9mIHJlamVjdGluZyB0aGUgYmFkIHRlbmFudC5cbiAgICAgIGlmICghY29uZmlndXJhdGlvbi5pc0RhdGFiYXNlSWRlbnRpZmllckFjdGl2ZShpZGVudGlmaWVyKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFRlbmFudCBkYXRhYmFzZSBpZGVudGlmaWVyICR7aWRlbnRpZmllcn0gaXMgaW5hY3RpdmUgZm9yIHRlbmFudDogJHtUZW5hbnRJdGVyYXRvci50ZW5hbnRMYWJlbCh0ZW5hbnQpfWApXG4gICAgICB9XG5cbiAgICAgIGF3YWl0IHByb3ZpZGVyLmRyb3BEYXRhYmFzZT8uKHtcbiAgICAgICAgY29uZmlndXJhdGlvbixcbiAgICAgICAgZGF0YWJhc2VDb25maWd1cmF0aW9uOiBjb25maWd1cmF0aW9uLnJlc29sdmVEYXRhYmFzZUNvbmZpZ3VyYXRpb24oaWRlbnRpZmllciksXG4gICAgICAgIGlkZW50aWZpZXIsXG4gICAgICAgIHRlbmFudFxuICAgICAgfSlcbiAgICB9KVxuICB9XG59XG4iXX0=
@@ -8,19 +8,29 @@ import TenantIterator from "./tenant-iterator.js"
8
8
  * object the app's `tenantDatabaseResolver` understands (an account, a project, …); this
9
9
  * class is the single discoverable home for switching into a tenant's context, reading the
10
10
  * current one, iterating every tenant of a database identifier, and dropping a tenant's
11
- * database. Switching/reading delegate to {@link Current} (which owns the async-context
12
- * tenant state), so they compose with the existing connection pools and request lifecycle;
13
- * iteration and drop drive the app's tenant database provider hooks.
11
+ * database. Switching delegates to {@link Current} (which owns the async-context tenant
12
+ * state) and additionally runs the callback inside `ensureConnections`, so entering a tenant
13
+ * makes its database immediately queryable — the apartment-style "switch" semantics without
14
+ * the caller establishing connections itself; iteration and drop drive the app's tenant
15
+ * database provider hooks.
14
16
  */
15
17
  export default class Tenant {
16
18
  /**
17
19
  * Runs `callback` with `tenant` as the current tenant, restoring the previous tenant after.
20
+ * The callback runs inside `ensureConnections`, so every database identifier the tenant
21
+ * activates (the global database plus the tenant's database) has a checked-out connection
22
+ * available for the callback's duration: switching into a tenant makes it queryable without
23
+ * the caller wiring up connections. Already-checked-out connections are reused, so nesting
24
+ * `Tenant.with` calls does not open redundant connections. The callback receives the active
25
+ * connections keyed by identifier, the same as `ensureConnections`.
18
26
  * @param {object} tenant Descriptor understood by the app's tenantDatabaseResolver.
19
- * @param {() => Promise<?>} callback
27
+ * @param {(connections: Record<string, import("../database/drivers/base.js").default>) => Promise<?>} callback
20
28
  * @returns {Promise<?>}
21
29
  */
22
30
  static async with(tenant, callback) {
23
- return await Current.withTenant(tenant, callback)
31
+ const configuration = Current.configuration()
32
+
33
+ return await Current.withTenant(tenant, async () => await configuration.ensureConnections(callback))
24
34
  }
25
35
 
26
36
  /**
@@ -33,8 +43,10 @@ export default class Tenant {
33
43
 
34
44
  /**
35
45
  * Lists the tenants for a database identifier through the provider and runs `callback`
36
- * within each tenant's context, optionally filtered and several at a time. Returns how
37
- * many tenants the callback ran for (after filtering).
46
+ * within each tenant's context, optionally filtered and several at a time. Like
47
+ * {@link Tenant.with}, the callback runs inside `ensureConnections` so each tenant's
48
+ * database is queryable without the caller wiring up connections. Returns how many tenants
49
+ * the callback ran for (after filtering).
38
50
  * @param {{identifier: string, callback: function({databaseConfiguration: import("../configuration-types.js").DatabaseConfigurationType, tenant: ?}) : Promise<void>, parallel?: number, filter?: (tenant: ?) => boolean, configuration?: import("../configuration.js").default}} args
39
51
  * @returns {Promise<number>}
40
52
  */
@@ -51,7 +63,13 @@ export default class Tenant {
51
63
  const tenants = filter ? listedTenants.filter(filter) : listedTenants
52
64
  const iterator = new TenantIterator({configuration, identifier, parallelCount: parallel})
53
65
 
54
- return await iterator.run(tenants, callback)
66
+ // Run each tenant's callback inside ensureConnections so the iterator stays
67
+ // connection-agnostic (the db:tenants:* CLI commands share TenantIterator and must run
68
+ // their callbacks, such as create, before the tenant database exists) while runtime
69
+ // iteration here gets the tenant's connections established the same way Tenant.with does.
70
+ return await iterator.run(tenants, async (callbackArgs) => {
71
+ await configuration.ensureConnections({name: `Tenant.each: ${identifier}`}, async () => await callback(callbackArgs))
72
+ })
55
73
  }
56
74
 
57
75
  /**
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "velocious": "build/bin/velocious.js"
4
4
  },
5
5
  "name": "velocious",
6
- "version": "1.0.483",
6
+ "version": "1.0.484",
7
7
  "main": "build/index.js",
8
8
  "types": "build/index.d.ts",
9
9
  "files": [
@@ -8,19 +8,29 @@ import TenantIterator from "./tenant-iterator.js"
8
8
  * object the app's `tenantDatabaseResolver` understands (an account, a project, …); this
9
9
  * class is the single discoverable home for switching into a tenant's context, reading the
10
10
  * current one, iterating every tenant of a database identifier, and dropping a tenant's
11
- * database. Switching/reading delegate to {@link Current} (which owns the async-context
12
- * tenant state), so they compose with the existing connection pools and request lifecycle;
13
- * iteration and drop drive the app's tenant database provider hooks.
11
+ * database. Switching delegates to {@link Current} (which owns the async-context tenant
12
+ * state) and additionally runs the callback inside `ensureConnections`, so entering a tenant
13
+ * makes its database immediately queryable — the apartment-style "switch" semantics without
14
+ * the caller establishing connections itself; iteration and drop drive the app's tenant
15
+ * database provider hooks.
14
16
  */
15
17
  export default class Tenant {
16
18
  /**
17
19
  * Runs `callback` with `tenant` as the current tenant, restoring the previous tenant after.
20
+ * The callback runs inside `ensureConnections`, so every database identifier the tenant
21
+ * activates (the global database plus the tenant's database) has a checked-out connection
22
+ * available for the callback's duration: switching into a tenant makes it queryable without
23
+ * the caller wiring up connections. Already-checked-out connections are reused, so nesting
24
+ * `Tenant.with` calls does not open redundant connections. The callback receives the active
25
+ * connections keyed by identifier, the same as `ensureConnections`.
18
26
  * @param {object} tenant Descriptor understood by the app's tenantDatabaseResolver.
19
- * @param {() => Promise<?>} callback
27
+ * @param {(connections: Record<string, import("../database/drivers/base.js").default>) => Promise<?>} callback
20
28
  * @returns {Promise<?>}
21
29
  */
22
30
  static async with(tenant, callback) {
23
- return await Current.withTenant(tenant, callback)
31
+ const configuration = Current.configuration()
32
+
33
+ return await Current.withTenant(tenant, async () => await configuration.ensureConnections(callback))
24
34
  }
25
35
 
26
36
  /**
@@ -33,8 +43,10 @@ export default class Tenant {
33
43
 
34
44
  /**
35
45
  * Lists the tenants for a database identifier through the provider and runs `callback`
36
- * within each tenant's context, optionally filtered and several at a time. Returns how
37
- * many tenants the callback ran for (after filtering).
46
+ * within each tenant's context, optionally filtered and several at a time. Like
47
+ * {@link Tenant.with}, the callback runs inside `ensureConnections` so each tenant's
48
+ * database is queryable without the caller wiring up connections. Returns how many tenants
49
+ * the callback ran for (after filtering).
38
50
  * @param {{identifier: string, callback: function({databaseConfiguration: import("../configuration-types.js").DatabaseConfigurationType, tenant: ?}) : Promise<void>, parallel?: number, filter?: (tenant: ?) => boolean, configuration?: import("../configuration.js").default}} args
39
51
  * @returns {Promise<number>}
40
52
  */
@@ -51,7 +63,13 @@ export default class Tenant {
51
63
  const tenants = filter ? listedTenants.filter(filter) : listedTenants
52
64
  const iterator = new TenantIterator({configuration, identifier, parallelCount: parallel})
53
65
 
54
- return await iterator.run(tenants, callback)
66
+ // Run each tenant's callback inside ensureConnections so the iterator stays
67
+ // connection-agnostic (the db:tenants:* CLI commands share TenantIterator and must run
68
+ // their callbacks, such as create, before the tenant database exists) while runtime
69
+ // iteration here gets the tenant's connections established the same way Tenant.with does.
70
+ return await iterator.run(tenants, async (callbackArgs) => {
71
+ await configuration.ensureConnections({name: `Tenant.each: ${identifier}`}, async () => await callback(callbackArgs))
72
+ })
55
73
  }
56
74
 
57
75
  /**