@itwin/presentation-backend 5.12.0-dev.8 → 5.13.0-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/CHANGELOG.md +11 -1
  2. package/lib/cjs/presentation-backend/Presentation.d.ts +9 -0
  3. package/lib/cjs/presentation-backend/Presentation.d.ts.map +1 -1
  4. package/lib/cjs/presentation-backend/Presentation.js +2 -0
  5. package/lib/cjs/presentation-backend/Presentation.js.map +1 -1
  6. package/lib/cjs/presentation-backend/PresentationIpcHandler.js +4 -4
  7. package/lib/cjs/presentation-backend/PresentationIpcHandler.js.map +1 -1
  8. package/lib/cjs/presentation-backend/PresentationRpcImpl.d.ts +7 -2
  9. package/lib/cjs/presentation-backend/PresentationRpcImpl.d.ts.map +1 -1
  10. package/lib/cjs/presentation-backend/PresentationRpcImpl.js +52 -23
  11. package/lib/cjs/presentation-backend/PresentationRpcImpl.js.map +1 -1
  12. package/lib/cjs/presentation-backend/TemporaryStorage.d.ts +13 -1
  13. package/lib/cjs/presentation-backend/TemporaryStorage.d.ts.map +1 -1
  14. package/lib/cjs/presentation-backend/TemporaryStorage.js +28 -4
  15. package/lib/cjs/presentation-backend/TemporaryStorage.js.map +1 -1
  16. package/lib/esm/presentation-backend/Presentation.d.ts +9 -0
  17. package/lib/esm/presentation-backend/Presentation.d.ts.map +1 -1
  18. package/lib/esm/presentation-backend/Presentation.js +2 -0
  19. package/lib/esm/presentation-backend/Presentation.js.map +1 -1
  20. package/lib/esm/presentation-backend/PresentationIpcHandler.js +4 -4
  21. package/lib/esm/presentation-backend/PresentationIpcHandler.js.map +1 -1
  22. package/lib/esm/presentation-backend/PresentationRpcImpl.d.ts +7 -2
  23. package/lib/esm/presentation-backend/PresentationRpcImpl.d.ts.map +1 -1
  24. package/lib/esm/presentation-backend/PresentationRpcImpl.js +53 -24
  25. package/lib/esm/presentation-backend/PresentationRpcImpl.js.map +1 -1
  26. package/lib/esm/presentation-backend/TemporaryStorage.d.ts +13 -1
  27. package/lib/esm/presentation-backend/TemporaryStorage.d.ts.map +1 -1
  28. package/lib/esm/presentation-backend/TemporaryStorage.js +28 -4
  29. package/lib/esm/presentation-backend/TemporaryStorage.js.map +1 -1
  30. package/package.json +15 -15
@@ -68,15 +68,38 @@ class TemporaryStorage {
68
68
  }
69
69
  }
70
70
  for (const id of valuesToDispose) {
71
- this.deleteExistingEntry(id, true);
71
+ this.deleteExistingEntry(id, "timeout");
72
72
  }
73
73
  };
74
- deleteExistingEntry(id, isTimeout) {
74
+ deleteExistingEntry(id, reason) {
75
75
  (0, core_bentley_1.assert)(this._values.has(id));
76
- this.props.cleanupHandler && this.props.cleanupHandler(id, this._values.get(id).value, isTimeout ? "timeout" : "request");
76
+ this.props.cleanupHandler && this.props.cleanupHandler(id, this._values.get(id).value, reason);
77
77
  this._values.delete(id);
78
78
  this.props.onDisposedSingle && this.props.onDisposedSingle(id);
79
79
  }
80
+ /**
81
+ * Evicts least-recently-used values until there's room to add one more value
82
+ * without exceeding the configured [[TemporaryStorageProps.maxValues]] limit.
83
+ */
84
+ evictForNewValue() {
85
+ const maxValues = this.props.maxValues;
86
+ if (maxValues === undefined || maxValues < 1) {
87
+ return;
88
+ }
89
+ while (this._values.size >= maxValues) {
90
+ let lruId;
91
+ let lruTime = Number.POSITIVE_INFINITY;
92
+ for (const [key, entry] of this._values.entries()) {
93
+ const time = entry.lastUsed.getTime();
94
+ if (time < lruTime) {
95
+ lruTime = time;
96
+ lruId = key;
97
+ }
98
+ }
99
+ (0, core_bentley_1.assert)(!!lruId);
100
+ this.deleteExistingEntry(lruId, "eviction");
101
+ }
102
+ }
80
103
  /**
81
104
  * Get a value from the storage.
82
105
  *
@@ -104,12 +127,13 @@ class TemporaryStorage {
104
127
  if (this._values.has(id)) {
105
128
  throw new presentation_common_1.PresentationError(presentation_common_1.PresentationStatus.InvalidArgument, `A value with given ID "${id}" already exists in this storage.`);
106
129
  }
130
+ this.evictForNewValue();
107
131
  this._values.set(id, { value, created: new Date(), lastUsed: new Date() });
108
132
  }
109
133
  /** Deletes a value with given id. */
110
134
  deleteValue(id) {
111
135
  if (this._values.has(id)) {
112
- this.deleteExistingEntry(id, false);
136
+ this.deleteExistingEntry(id, "request");
113
137
  }
114
138
  }
115
139
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"TemporaryStorage.js","sourceRoot":"","sources":["../../../src/presentation-backend/TemporaryStorage.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n/** @packageDocumentation\n * @module Core\n */\n\nimport { assert } from \"@itwin/core-bentley\";\nimport { PresentationError, PresentationStatus } from \"@itwin/presentation-common\";\n\n/**\n * Configuration properties for [[TemporaryStorage]].\n * @internal\n */\nexport interface TemporaryStorageProps<T> {\n /** A method that's called for every value before it's removed from storage */\n cleanupHandler?: (id: string, value: T, reason: \"timeout\" | \"dispose\" | \"request\") => void;\n\n onDisposedSingle?: (id: string) => void;\n onDisposedAll?: () => void;\n\n /**\n * An interval at which the storage attempts to clean up its values.\n * When `0` or `undefined` is specified, values are not cleaned up\n * automatically and cleanup has to be initiated manually by calling\n * [[TemporaryStorage.disposeOutdatedValues]].\n */\n cleanupInterval?: number;\n\n /**\n * Shortest period of time which the value should be kept in storage\n * unused before it's cleaned up.\n *\n * `undefined` means the values may be kept unused in the storage indefinitely.\n * `0` means the values are removed from the storage on every cleanup (either manual\n * call to [[TemporaryStorage.disposeOutdatedValues]] or scheduled (controlled\n * by [[cleanupInterval]])).\n */\n unusedValueLifetime?: number;\n\n /**\n * The maximum period of time which the value should be kept in storage\n * before it's cleaned up. The time is measured from the moment the value is added\n * to the storage.\n *\n * `undefined` means the values may be kept indefinitely. `0` means they're removed\n * up on every cleanup (either manual call to [[TemporaryStorage.disposeOutdatedValues]]\n * or scheduled (controlled by [[cleanupInterval]])).\n */\n maxValueLifetime?: number;\n}\n\n/** Value with know last used time */\ninterface TemporaryValue<T> {\n created: Date;\n lastUsed: Date;\n value: T;\n}\n\n/**\n * Storage for values that get removed from it after being unused (not-requested\n * for a specified amount of time).\n *\n * @internal\n */\nexport class TemporaryStorage<T> implements Disposable {\n private _timer?: NodeJS.Timeout;\n protected _values: Map<string, TemporaryValue<T>>;\n public readonly props: TemporaryStorageProps<T>;\n\n /**\n * Constructor. Creates the storage using supplied params.\n */\n constructor(props: TemporaryStorageProps<T>) {\n this.props = props;\n this._values = new Map<string, TemporaryValue<T>>();\n if (this.props.cleanupInterval) {\n this._timer = setInterval(this.disposeOutdatedValues, this.props.cleanupInterval);\n }\n }\n\n /**\n * Destructor. Must be called to clean up the stored values\n * and other resources\n */\n public [Symbol.dispose]() {\n if (this._timer) {\n clearInterval(this._timer);\n }\n\n if (this.props.cleanupHandler) {\n this._values.forEach((v, id) => {\n this.props.cleanupHandler!(id, v.value, \"dispose\");\n });\n }\n this._values.clear();\n this.props.onDisposedAll && this.props.onDisposedAll();\n }\n\n /**\n * Cleans up values that are currently outdated (based\n * on their max and unused value lifetimes specified through [[Props]]).\n */\n public disposeOutdatedValues = () => {\n const now = new Date().getTime();\n const valuesToDispose: string[] = [];\n for (const [key, entry] of this._values.entries()) {\n if (this.props.maxValueLifetime !== undefined) {\n if (this.props.maxValueLifetime === 0 || now - entry.created.getTime() > this.props.maxValueLifetime) {\n valuesToDispose.push(key);\n continue;\n }\n }\n if (this.props.unusedValueLifetime !== undefined) {\n if (this.props.unusedValueLifetime === 0 || now - entry.lastUsed.getTime() > this.props.unusedValueLifetime) {\n valuesToDispose.push(key);\n continue;\n }\n }\n }\n for (const id of valuesToDispose) {\n this.deleteExistingEntry(id, true);\n }\n };\n\n private deleteExistingEntry(id: string, isTimeout: boolean) {\n assert(this._values.has(id));\n this.props.cleanupHandler && this.props.cleanupHandler(id, this._values.get(id)!.value, isTimeout ? \"timeout\" : \"request\");\n this._values.delete(id);\n this.props.onDisposedSingle && this.props.onDisposedSingle(id);\n }\n\n /**\n * Get a value from the storage.\n *\n * **Note:** requesting a value with this method updates it's last used time.\n */\n public getValue(id: string): T | undefined {\n if (this._values.has(id)) {\n const v = this._values.get(id)!;\n v.lastUsed = new Date();\n return v.value;\n }\n return undefined;\n }\n\n public notifyValueUsed(id: string) {\n const entry = this._values.get(id);\n if (entry) {\n entry.lastUsed = new Date();\n }\n }\n\n /**\n * Adds a value into the storage.\n * @throws An error when trying to add a value with ID that's already stored in the storage.\n */\n public addValue(id: string, value: T) {\n if (this._values.has(id)) {\n throw new PresentationError(PresentationStatus.InvalidArgument, `A value with given ID \"${id}\" already exists in this storage.`);\n }\n this._values.set(id, { value, created: new Date(), lastUsed: new Date() });\n }\n\n /** Deletes a value with given id. */\n public deleteValue(id: string) {\n if (this._values.has(id)) {\n this.deleteExistingEntry(id, false);\n }\n }\n\n /**\n * Get all values currently in this storage.\n *\n * **Note:** requesting values with this method **doesn't**\n * update their last used times.\n */\n public get values(): T[] {\n const values = new Array<T>();\n for (const v of this._values.values()) {\n values.push(v.value);\n }\n return values;\n }\n}\n\n/**\n * Configuration properties for [[FactoryBasedTemporaryStorage]].\n * @internal\n */\nexport interface FactoryBasedTemporaryStorageProps<T> extends TemporaryStorageProps<T> {\n /** A factory method that creates a stored value given it's identifier */\n factory: (id: string, onValueUsed: () => void) => T;\n}\n\n/**\n * Storage for values that get removed from it after being unused (not-requested\n * for a specified amount of time).\n *\n * @internal\n */\nexport class FactoryBasedTemporaryStorage<T> extends TemporaryStorage<T> {\n public override readonly props: FactoryBasedTemporaryStorageProps<T>;\n\n /**\n * Constructor. Creates the storage using supplied params.\n */\n constructor(props: FactoryBasedTemporaryStorageProps<T>) {\n super(props);\n this.props = props;\n }\n\n /**\n * Get a value from the storage. If the value with the specified id\n * doesn't exist, it gets created.\n *\n * **Note:** requesting a value with this method updates it's last used time.\n */\n public override getValue(id: string): T {\n const existingValue = super.getValue(id);\n if (existingValue) {\n return existingValue;\n }\n\n const value = this.props.factory(id, () => this.notifyValueUsed(id));\n this.addValue(id, value);\n return value;\n }\n}\n"]}
1
+ {"version":3,"file":"TemporaryStorage.js","sourceRoot":"","sources":["../../../src/presentation-backend/TemporaryStorage.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n/** @packageDocumentation\n * @module Core\n */\n\nimport { assert } from \"@itwin/core-bentley\";\nimport { PresentationError, PresentationStatus } from \"@itwin/presentation-common\";\n\n/**\n * Configuration properties for [[TemporaryStorage]].\n * @internal\n */\nexport interface TemporaryStorageProps<T> {\n /** A method that's called for every value before it's removed from storage */\n cleanupHandler?: (id: string, value: T, reason: \"timeout\" | \"dispose\" | \"request\" | \"eviction\") => void;\n\n onDisposedSingle?: (id: string) => void;\n onDisposedAll?: () => void;\n\n /**\n * An interval at which the storage attempts to clean up its values.\n * When `0` or `undefined` is specified, values are not cleaned up\n * automatically and cleanup has to be initiated manually by calling\n * [[TemporaryStorage.disposeOutdatedValues]].\n */\n cleanupInterval?: number;\n\n /**\n * Shortest period of time which the value should be kept in storage\n * unused before it's cleaned up.\n *\n * `undefined` means the values may be kept unused in the storage indefinitely.\n * `0` means the values are removed from the storage on every cleanup (either manual\n * call to [[TemporaryStorage.disposeOutdatedValues]] or scheduled (controlled\n * by [[cleanupInterval]])).\n */\n unusedValueLifetime?: number;\n\n /**\n * The maximum period of time which the value should be kept in storage\n * before it's cleaned up. The time is measured from the moment the value is added\n * to the storage.\n *\n * `undefined` means the values may be kept indefinitely. `0` means they're removed\n * up on every cleanup (either manual call to [[TemporaryStorage.disposeOutdatedValues]]\n * or scheduled (controlled by [[cleanupInterval]])).\n */\n maxValueLifetime?: number;\n\n /**\n * The maximum number of values the storage is allowed to hold at once. When adding\n * a value would exceed this limit, the least-recently-used value is evicted first.\n *\n * `undefined` (or any value less than `1`) means the number of values is not capped.\n */\n maxValues?: number;\n}\n\n/** Value with know last used time */\ninterface TemporaryValue<T> {\n created: Date;\n lastUsed: Date;\n value: T;\n}\n\n/**\n * Storage for values that get removed from it after being unused (not-requested\n * for a specified amount of time).\n *\n * @internal\n */\nexport class TemporaryStorage<T> implements Disposable {\n private _timer?: NodeJS.Timeout;\n protected _values: Map<string, TemporaryValue<T>>;\n public readonly props: TemporaryStorageProps<T>;\n\n /**\n * Constructor. Creates the storage using supplied params.\n */\n constructor(props: TemporaryStorageProps<T>) {\n this.props = props;\n this._values = new Map<string, TemporaryValue<T>>();\n if (this.props.cleanupInterval) {\n this._timer = setInterval(this.disposeOutdatedValues, this.props.cleanupInterval);\n }\n }\n\n /**\n * Destructor. Must be called to clean up the stored values\n * and other resources\n */\n public [Symbol.dispose]() {\n if (this._timer) {\n clearInterval(this._timer);\n }\n\n if (this.props.cleanupHandler) {\n this._values.forEach((v, id) => {\n this.props.cleanupHandler!(id, v.value, \"dispose\");\n });\n }\n this._values.clear();\n this.props.onDisposedAll && this.props.onDisposedAll();\n }\n\n /**\n * Cleans up values that are currently outdated (based\n * on their max and unused value lifetimes specified through [[Props]]).\n */\n public disposeOutdatedValues = () => {\n const now = new Date().getTime();\n const valuesToDispose: string[] = [];\n for (const [key, entry] of this._values.entries()) {\n if (this.props.maxValueLifetime !== undefined) {\n if (this.props.maxValueLifetime === 0 || now - entry.created.getTime() > this.props.maxValueLifetime) {\n valuesToDispose.push(key);\n continue;\n }\n }\n if (this.props.unusedValueLifetime !== undefined) {\n if (this.props.unusedValueLifetime === 0 || now - entry.lastUsed.getTime() > this.props.unusedValueLifetime) {\n valuesToDispose.push(key);\n continue;\n }\n }\n }\n for (const id of valuesToDispose) {\n this.deleteExistingEntry(id, \"timeout\");\n }\n };\n\n private deleteExistingEntry(id: string, reason: \"timeout\" | \"request\" | \"eviction\") {\n assert(this._values.has(id));\n this.props.cleanupHandler && this.props.cleanupHandler(id, this._values.get(id)!.value, reason);\n this._values.delete(id);\n this.props.onDisposedSingle && this.props.onDisposedSingle(id);\n }\n\n /**\n * Evicts least-recently-used values until there's room to add one more value\n * without exceeding the configured [[TemporaryStorageProps.maxValues]] limit.\n */\n private evictForNewValue() {\n const maxValues = this.props.maxValues;\n if (maxValues === undefined || maxValues < 1) {\n return;\n }\n while (this._values.size >= maxValues) {\n let lruId: string | undefined;\n let lruTime = Number.POSITIVE_INFINITY;\n for (const [key, entry] of this._values.entries()) {\n const time = entry.lastUsed.getTime();\n if (time < lruTime) {\n lruTime = time;\n lruId = key;\n }\n }\n assert(!!lruId);\n this.deleteExistingEntry(lruId, \"eviction\");\n }\n }\n\n /**\n * Get a value from the storage.\n *\n * **Note:** requesting a value with this method updates it's last used time.\n */\n public getValue(id: string): T | undefined {\n if (this._values.has(id)) {\n const v = this._values.get(id)!;\n v.lastUsed = new Date();\n return v.value;\n }\n return undefined;\n }\n\n public notifyValueUsed(id: string) {\n const entry = this._values.get(id);\n if (entry) {\n entry.lastUsed = new Date();\n }\n }\n\n /**\n * Adds a value into the storage.\n * @throws An error when trying to add a value with ID that's already stored in the storage.\n */\n public addValue(id: string, value: T) {\n if (this._values.has(id)) {\n throw new PresentationError(PresentationStatus.InvalidArgument, `A value with given ID \"${id}\" already exists in this storage.`);\n }\n this.evictForNewValue();\n this._values.set(id, { value, created: new Date(), lastUsed: new Date() });\n }\n\n /** Deletes a value with given id. */\n public deleteValue(id: string) {\n if (this._values.has(id)) {\n this.deleteExistingEntry(id, \"request\");\n }\n }\n\n /**\n * Get all values currently in this storage.\n *\n * **Note:** requesting values with this method **doesn't**\n * update their last used times.\n */\n public get values(): T[] {\n const values = new Array<T>();\n for (const v of this._values.values()) {\n values.push(v.value);\n }\n return values;\n }\n}\n\n/**\n * Configuration properties for [[FactoryBasedTemporaryStorage]].\n * @internal\n */\nexport interface FactoryBasedTemporaryStorageProps<T> extends TemporaryStorageProps<T> {\n /** A factory method that creates a stored value given it's identifier */\n factory: (id: string, onValueUsed: () => void) => T;\n}\n\n/**\n * Storage for values that get removed from it after being unused (not-requested\n * for a specified amount of time).\n *\n * @internal\n */\nexport class FactoryBasedTemporaryStorage<T> extends TemporaryStorage<T> {\n public override readonly props: FactoryBasedTemporaryStorageProps<T>;\n\n /**\n * Constructor. Creates the storage using supplied params.\n */\n constructor(props: FactoryBasedTemporaryStorageProps<T>) {\n super(props);\n this.props = props;\n }\n\n /**\n * Get a value from the storage. If the value with the specified id\n * doesn't exist, it gets created.\n *\n * **Note:** requesting a value with this method updates it's last used time.\n */\n public override getValue(id: string): T {\n const existingValue = super.getValue(id);\n if (existingValue) {\n return existingValue;\n }\n\n const value = this.props.factory(id, () => this.notifyValueUsed(id));\n this.addValue(id, value);\n return value;\n }\n}\n"]}
@@ -21,6 +21,15 @@ export interface PresentationProps extends Omit<PresentationManagerProps, "enabl
21
21
  * before it's disposed.
22
22
  */
23
23
  unusedClientLifetime?: number;
24
+ /**
25
+ * The maximum number of client [[PresentationManager]] instances to keep in memory
26
+ * at once. When creating a manager for a new client would exceed this limit, the
27
+ * least-recently-used manager is disposed first. This bounds memory and native
28
+ * resource usage regardless of how many distinct clients make requests.
29
+ *
30
+ * Defaults to `100`. A value less than `1` disables the limit.
31
+ */
32
+ maxClientManagers?: number;
24
33
  }
25
34
  /**
26
35
  * Props for initializing the [[Presentation]] library for using multiple [[PresentationManager]]
@@ -1 +1 @@
1
- {"version":3,"file":"Presentation.d.ts","sourceRoot":"","sources":["../../../src/presentation-backend/Presentation.ts"],"names":[],"mappings":"AAIA;;GAEG;AAQH,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAKzF;;;GAGG;AACH,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,wBAAwB,EAAE,sBAAsB,CAAC;IAC/F;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAE/B;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AASD;;;;;;GAMG;AACH,MAAM,MAAM,6BAA6B,GAAG,iBAAiB,CAAC;AAE9D;;;;;GAKG;AACH,MAAM,MAAM,qBAAqB,GAAG,iBAAiB,CAAC;AAEtD;;;;;;GAMG;AACH,MAAM,MAAM,8BAA8B,GAAG,IAAI,CAAC,iBAAiB,EAAE,sBAAsB,CAAC,CAAC;AAM7F;;;;;;;;;GASG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAC,UAAU,CAA8D;IACvF,OAAO,CAAC,MAAM,CAAC,eAAe,CAA4D;IAC1F,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAA0B;IAC3D,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAA0B;IAC1D,OAAO,CAAC,MAAM,CAAC,4BAA4B,CAA0B;IACrE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAkC;IAGzD,OAAO;IAEP,+DAA+D;IAC/D,WAAkB,SAAS,IAAI,iBAAiB,GAAG,SAAS,CAE3D;IAED;;;;;;;;OAQG;WACW,UAAU,CAAC,KAAK,CAAC,EAAE,iBAAiB,GAAG,IAAI;IAqCzD;;;OAGG;WACW,SAAS,IAAI,IAAI;IAwB/B,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAiBlC,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAInC;;;;OAIG;WACW,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,mBAAmB;IAOhE;;OAEG;WACW,iBAAiB,IAAI,MAAM;IAOzC,OAAO,CAAC,MAAM,CAAC,cAAc,CAK3B;CACH"}
1
+ {"version":3,"file":"Presentation.d.ts","sourceRoot":"","sources":["../../../src/presentation-backend/Presentation.ts"],"names":[],"mappings":"AAIA;;GAEG;AAQH,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAKzF;;;GAGG;AACH,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,wBAAwB,EAAE,sBAAsB,CAAC;IAC/F;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAE/B;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AASD;;;;;;GAMG;AACH,MAAM,MAAM,6BAA6B,GAAG,iBAAiB,CAAC;AAE9D;;;;;GAKG;AACH,MAAM,MAAM,qBAAqB,GAAG,iBAAiB,CAAC;AAEtD;;;;;;GAMG;AACH,MAAM,MAAM,8BAA8B,GAAG,IAAI,CAAC,iBAAiB,EAAE,sBAAsB,CAAC,CAAC;AAM7F;;;;;;;;;GASG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAC,UAAU,CAA8D;IACvF,OAAO,CAAC,MAAM,CAAC,eAAe,CAA4D;IAC1F,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAA0B;IAC3D,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAA0B;IAC1D,OAAO,CAAC,MAAM,CAAC,4BAA4B,CAA0B;IACrE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAkC;IAGzD,OAAO;IAEP,+DAA+D;IAC/D,WAAkB,SAAS,IAAI,iBAAiB,GAAG,SAAS,CAE3D;IAED;;;;;;;;OAQG;WACW,UAAU,CAAC,KAAK,CAAC,EAAE,iBAAiB,GAAG,IAAI;IAuCzD;;;OAGG;WACW,SAAS,IAAI,IAAI;IAwB/B,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAiBlC,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAInC;;;;OAIG;WACW,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,mBAAmB;IAOhE;;OAEG;WACW,iBAAiB,IAAI,MAAM;IAOzC,OAAO,CAAC,MAAM,CAAC,cAAc,CAK3B;CACH"}
@@ -65,6 +65,8 @@ export class Presentation {
65
65
  cleanupInterval: 60 * 1000,
66
66
  // by default, manager is disposed after 1 hour of being unused
67
67
  unusedValueLifetime: this._initProps.unusedClientLifetime ?? 60 * 60 * 1000,
68
+ // by default, keep at most 100 client managers in memory at once
69
+ maxValues: this._initProps.maxClientManagers ?? 100,
68
70
  // add some logging
69
71
  /* c8 ignore next 5 */
70
72
  onDisposedSingle: (id) => Logger.logInfo(PresentationBackendLoggerCategory.PresentationManager, `Disposed PresentationManager instance with ID: ${id}. Total instances: ${this._clientsStorage.values.length}.`),
@@ -1 +1 @@
1
- {"version":3,"file":"Presentation.js","sourceRoot":"","sources":["../../../src/presentation-backend/Presentation.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAChG;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,EAAe,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAC7G,OAAO,EAAE,iCAAiC,EAAE,MAAM,4BAA4B,CAAC;AAC/E,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAA4B,MAAM,0BAA0B,CAAC;AACzF,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC;AA8DpE;;;;;;;;;GASG;AACH,MAAM,OAAO,YAAY;IACf,MAAM,CAAC,UAAU,CAA8D;IAC/E,MAAM,CAAC,eAAe,CAA4D;IAClF,MAAM,CAAC,kBAAkB,CAA0B;IACnD,MAAM,CAAC,iBAAiB,CAA0B;IAClD,MAAM,CAAC,4BAA4B,CAA0B;IAC7D,MAAM,CAAC,QAAQ,CAAkC;IAEzD,oBAAoB;IACpB,gBAAuB,CAAC;IAExB,+DAA+D;IACxD,MAAM,KAAK,SAAS;QACzB,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED;;;;;;;;OAQG;IACI,MAAM,CAAC,UAAU,CAAC,KAAyB;QAChD,IAAI,CAAC,UAAU,GAAG,KAAK,IAAI,EAAE,CAAC;QAC9B,IAAI,CAAC,iBAAiB,GAAG,UAAU,CAAC,gBAAgB,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC,CAAC;QAEjG,IAAI,CAAC,QAAQ,GAAG,IAAI,mBAAmB,CAAC;YACtC,cAAc,EAAE,IAAI,CAAC,UAAU,CAAC,cAAc;SAC/C,CAAC,CAAC;QACH,UAAU,CAAC,YAAY,CAAC,wBAAwB,EAAE,mBAAmB,CAAC,CAAC;QACvE,UAAU,CAAC,kBAAkB,CAAC,wBAAwB,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAEvE,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,IAAI,CAAC,kBAAkB,GAAG,sBAAsB,CAAC,QAAQ,EAAE,CAAC;QAC9D,CAAC;QAED,IAAI,CAAC,eAAe,GAAG,IAAI,4BAA4B,CAAkB;YACvE,OAAO,EAAE,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC;YAC5C,cAAc,EAAE,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,IAAI,CAAC,oBAAoB,CAAC,GAAG,EAAE,SAAS,CAAC;YAC7E,uCAAuC;YACvC,eAAe,EAAE,EAAE,GAAG,IAAI;YAC1B,+DAA+D;YAC/D,mBAAmB,EAAE,IAAI,CAAC,UAAU,CAAC,oBAAoB,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;YAC3E,mBAAmB;YACnB,sBAAsB;YACtB,gBAAgB,EAAE,CAAC,EAAU,EAAE,EAAE,CAC/B,MAAM,CAAC,OAAO,CACZ,iCAAiC,CAAC,mBAAmB,EACrD,kDAAkD,EAAE,sBAAsB,IAAI,CAAC,eAAgB,CAAC,MAAM,CAAC,MAAM,GAAG,CACjH;YACH,oBAAoB;YACpB,aAAa,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,iCAAiC,CAAC,mBAAmB,EAAE,6CAA6C,CAAC;SAC1I,CAAC,CAAC;QAEH,IAAI,IAAI,CAAC,UAAU,CAAC,oBAAoB,EAAE,CAAC;YACzC,IAAI,CAAC,4BAA4B,GAAG,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC5F,CAAC;IACH,CAAC;IAED;;;OAGG;IACI,MAAM,CAAC,SAAS;QACrB,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACzB,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YACvC,IAAI,CAAC,eAAe,GAAG,SAAS,CAAC;QACnC,CAAC;QACD,IAAI,IAAI,CAAC,4BAA4B,EAAE,CAAC;YACtC,IAAI,CAAC,4BAA4B,EAAE,CAAC;YACpC,IAAI,CAAC,4BAA4B,GAAG,SAAS,CAAC;QAChD,CAAC;QACD,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3B,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACzB,IAAI,CAAC,iBAAiB,GAAG,SAAS,CAAC;QACrC,CAAC;QACD,UAAU,CAAC,cAAc,CAAC,wBAAwB,CAAC,CAAC;QACpD,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YAChC,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;QAC5B,CAAC;QACD,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC5B,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAC5B,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;IAC9B,CAAC;IAEO,MAAM,CAAC,mBAAmB,CAAC,QAAgB,EAAE,aAAyB;QAC5E,MAAM,OAAO,GACX,YAAY,CAAC,UAAU,IAAI,YAAY,CAAC,UAAU,CAAC,oBAAoB;YACrE,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,oBAAoB,CAAC,QAAQ,EAAE,YAAY,CAAC,UAAU,CAAC;YACjF,CAAC,CAAC,IAAI,mBAAmB,CAAC;gBACtB,GAAG,YAAY,CAAC,UAAU;gBAC1B,iCAAiC;gBACjC,EAAE,EAAE,QAAQ;aACb,CAAC,CAAC;QACT,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;QAC1C,MAAM,CAAC,OAAO,CACZ,iCAAiC,CAAC,mBAAmB,EACrD,mDAAmD,QAAQ,sBAAsB,IAAI,CAAC,eAAgB,CAAC,MAAM,CAAC,MAAM,GAAG,CACxH,CAAC;QACF,OAAO,EAAE,OAAO,EAAE,CAAC;IACrB,CAAC;IAEO,MAAM,CAAC,oBAAoB,CAAC,GAAW,EAAE,SAA0B;QACzE,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;IACtC,CAAC;IAED;;;;OAIG;IACI,MAAM,CAAC,UAAU,CAAC,QAAiB;QACxC,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC;QAC/D,CAAC;QACD,MAAM,IAAI,iBAAiB,CAAC,kBAAkB,CAAC,cAAc,EAAE,2EAA2E,CAAC,CAAC;IAC9I,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,iBAAiB;QAC7B,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YAChC,MAAM,IAAI,iBAAiB,CAAC,kBAAkB,CAAC,cAAc,EAAE,2EAA2E,CAAC,CAAC;QAC9I,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC;IACtC,CAAC;IAEO,MAAM,CAAC,cAAc,GAAG,CAAC,MAAmB,EAAE,EAAE;QACtD,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAClC,MAAM,WAAW,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC,iBAAiB,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QACrG,mEAAmE;QACnE,OAAO,CAAC,4BAA4B,CAAC,CAAC,iBAAiB,EAAE,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC;IAC1F,CAAC,CAAC","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n/** @packageDocumentation\n * @module Core\n */\n\nimport { BriefcaseDb, IModelHost, IpcHost } from \"@itwin/core-backend\";\nimport { DisposeFunc, Logger } from \"@itwin/core-bentley\";\nimport { RpcManager } from \"@itwin/core-common\";\nimport { PresentationError, PresentationRpcInterface, PresentationStatus } from \"@itwin/presentation-common\";\nimport { PresentationBackendLoggerCategory } from \"./BackendLoggerCategory.js\";\nimport { PresentationIpcHandler } from \"./PresentationIpcHandler.js\";\nimport { PresentationManager, PresentationManagerProps } from \"./PresentationManager.js\";\nimport { PresentationRpcImpl } from \"./PresentationRpcImpl.js\";\nimport { FactoryBasedTemporaryStorage } from \"./TemporaryStorage.js\";\nimport { _presentation_manager_detail } from \"./InternalSymbols.js\";\n\n/**\n * Properties that can be used to configure [[Presentation]] API.\n * @public\n */\nexport interface PresentationProps extends Omit<PresentationManagerProps, \"enableSchemasPreload\"> {\n /**\n * Time in milliseconds after which the request will timeout.\n */\n requestTimeout?: number;\n\n /**\n * Should schemas preloading be enabled. If true, [[Presentation]] library listens\n * for `BriefcaseDb.onOpened` event and force pre-loads all ECSchemas.\n */\n enableSchemasPreload?: boolean;\n\n /**\n * How much time should an unused client manager be stored in memory\n * before it's disposed.\n */\n unusedClientLifetime?: number;\n}\n\ninterface PresentationInternalProps {\n /**\n * Factory method for creating separate managers for each client\n */\n clientManagerFactory?: (clientId: string, props: PresentationManagerProps) => PresentationManager;\n}\n\n/**\n * Props for initializing the [[Presentation]] library for using multiple [[PresentationManager]]\n * instances, one for each frontend.\n *\n * @public\n * @deprecated in 4.8 - might be removed in next major version. Use [[PresentationProps]] instead.\n */\nexport type MultiManagerPresentationProps = PresentationProps;\n\n/**\n * Base props for initializing the [[Presentation]] library.\n *\n * @public\n * @deprecated in 4.8 - might be removed in next major version. Use [[PresentationProps]] instead.\n */\nexport type PresentationPropsBase = PresentationProps;\n\n/**\n * Props for initializing the [[Presentation]] library with ability to use a single\n * [[PresentationManager]] instance for handling all requests.\n *\n * @public\n * @deprecated in 4.8 - might be removed in next major version. Use [[PresentationProps]] instead.\n */\nexport type SingleManagerPresentationProps = Omit<PresentationProps, \"unusedClientLifetime\">;\n\ninterface ClientStoreItem {\n manager: PresentationManager;\n}\n\n/**\n * Static class used to statically set up Presentation library for the backend.\n * Basically what it does is:\n * - Register a RPC implementation\n * - Create a singleton [[PresentationManager]] instance\n * - Subscribe for [IModelHost.onBeforeShutdown]($core-backend) event and terminate\n * the presentation manager when that happens.\n *\n * @public\n */\nexport class Presentation {\n private static _initProps: (PresentationProps & PresentationInternalProps) | undefined;\n private static _clientsStorage: FactoryBasedTemporaryStorage<ClientStoreItem> | undefined;\n private static _disposeIpcHandler: DisposeFunc | undefined;\n private static _shutdownListener: DisposeFunc | undefined;\n private static _disposeIModelOpenedListener: DisposeFunc | undefined;\n private static _rpcImpl: PresentationRpcImpl | undefined;\n\n /* c8 ignore next */\n private constructor() {}\n\n /** Properties used to initialize the presentation framework */\n public static get initProps(): PresentationProps | undefined {\n return this._initProps;\n }\n\n /**\n * Initializes Presentation library for the backend.\n *\n * See [Setting up iTwin.js Presentation library documentation page]($docs/presentation/setup/index.md#backend) for an example.\n *\n * **Important:** The method should be called after a call to [IModelHost.startup]($core-backend)\n *\n * @param props Optional properties for [[PresentationManager]]\n */\n public static initialize(props?: PresentationProps): void {\n this._initProps = props || {};\n this._shutdownListener = IModelHost.onBeforeShutdown.addListener(() => Presentation.terminate());\n\n this._rpcImpl = new PresentationRpcImpl({\n requestTimeout: this._initProps.requestTimeout,\n });\n RpcManager.registerImpl(PresentationRpcInterface, PresentationRpcImpl);\n RpcManager.supplyImplInstance(PresentationRpcInterface, this._rpcImpl);\n\n if (IpcHost.isValid) {\n this._disposeIpcHandler = PresentationIpcHandler.register();\n }\n\n this._clientsStorage = new FactoryBasedTemporaryStorage<ClientStoreItem>({\n factory: this.createClientManager.bind(this),\n cleanupHandler: (_id, storeItem) => this.disposeClientManager(_id, storeItem),\n // cleanup unused managers every minute\n cleanupInterval: 60 * 1000,\n // by default, manager is disposed after 1 hour of being unused\n unusedValueLifetime: this._initProps.unusedClientLifetime ?? 60 * 60 * 1000,\n // add some logging\n /* c8 ignore next 5 */\n onDisposedSingle: (id: string) =>\n Logger.logInfo(\n PresentationBackendLoggerCategory.PresentationManager,\n `Disposed PresentationManager instance with ID: ${id}. Total instances: ${this._clientsStorage!.values.length}.`,\n ),\n /* c8 ignore next */\n onDisposedAll: () => Logger.logInfo(PresentationBackendLoggerCategory.PresentationManager, `Disposed all PresentationManager instances.`),\n });\n\n if (this._initProps.enableSchemasPreload) {\n this._disposeIModelOpenedListener = BriefcaseDb.onOpened.addListener(this.onIModelOpened);\n }\n }\n\n /**\n * Terminates Presentation. Consumers don't need to call this as it's automatically\n * called on [IModelHost.onBeforeShutdown]($core-backend) event.\n */\n public static terminate(): void {\n if (this._clientsStorage) {\n this._clientsStorage[Symbol.dispose]();\n this._clientsStorage = undefined;\n }\n if (this._disposeIModelOpenedListener) {\n this._disposeIModelOpenedListener();\n this._disposeIModelOpenedListener = undefined;\n }\n if (this._shutdownListener) {\n this._shutdownListener();\n this._shutdownListener = undefined;\n }\n RpcManager.unregisterImpl(PresentationRpcInterface);\n if (this._rpcImpl) {\n this._rpcImpl[Symbol.dispose]();\n this._rpcImpl = undefined;\n }\n if (this._disposeIpcHandler) {\n this._disposeIpcHandler();\n }\n this._initProps = undefined;\n }\n\n private static createClientManager(clientId: string, onManagerUsed: () => void): ClientStoreItem {\n const manager =\n Presentation._initProps && Presentation._initProps.clientManagerFactory\n ? Presentation._initProps.clientManagerFactory(clientId, Presentation._initProps)\n : new PresentationManager({\n ...Presentation._initProps,\n // @ts-expect-error internal prop\n id: clientId,\n });\n manager.onUsed.addListener(onManagerUsed);\n Logger.logInfo(\n PresentationBackendLoggerCategory.PresentationManager,\n `Created a PresentationManager instance with ID: ${clientId}. Total instances: ${this._clientsStorage!.values.length}.`,\n );\n return { manager };\n }\n\n private static disposeClientManager(_id: string, storeItem: ClientStoreItem) {\n storeItem.manager[Symbol.dispose]();\n }\n\n /**\n * Get an instance of [[PresentationManager]] for specific client\n * @param clientId ID of the client requesting presentation data. If no\n * ID is provided, the default [[PresentationManager]] is returned.\n */\n public static getManager(clientId?: string): PresentationManager {\n if (this._clientsStorage) {\n return this._clientsStorage.getValue(clientId || \"\").manager;\n }\n throw new PresentationError(PresentationStatus.NotInitialized, \"Presentation must be first initialized by calling Presentation.initialize\");\n }\n\n /**\n * Get the time in milliseconds that backend should respond in .\n */\n public static getRequestTimeout(): number {\n if (this._rpcImpl === undefined) {\n throw new PresentationError(PresentationStatus.NotInitialized, \"Presentation must be first initialized by calling Presentation.initialize\");\n }\n return this._rpcImpl.requestTimeout;\n }\n\n private static onIModelOpened = (imodel: BriefcaseDb) => {\n const manager = this.getManager();\n const imodelAddon = manager[_presentation_manager_detail].getNativePlatform().getImodelAddon(imodel);\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n manager[_presentation_manager_detail].getNativePlatform().forceLoadSchemas(imodelAddon);\n };\n}\n"]}
1
+ {"version":3,"file":"Presentation.js","sourceRoot":"","sources":["../../../src/presentation-backend/Presentation.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n/** @packageDocumentation\n * @module Core\n */\n\nimport { BriefcaseDb, IModelHost, IpcHost } from \"@itwin/core-backend\";\nimport { DisposeFunc, Logger } from \"@itwin/core-bentley\";\nimport { RpcManager } from \"@itwin/core-common\";\nimport { PresentationError, PresentationRpcInterface, PresentationStatus } from \"@itwin/presentation-common\";\nimport { PresentationBackendLoggerCategory } from \"./BackendLoggerCategory.js\";\nimport { PresentationIpcHandler } from \"./PresentationIpcHandler.js\";\nimport { PresentationManager, PresentationManagerProps } from \"./PresentationManager.js\";\nimport { PresentationRpcImpl } from \"./PresentationRpcImpl.js\";\nimport { FactoryBasedTemporaryStorage } from \"./TemporaryStorage.js\";\nimport { _presentation_manager_detail } from \"./InternalSymbols.js\";\n\n/**\n * Properties that can be used to configure [[Presentation]] API.\n * @public\n */\nexport interface PresentationProps extends Omit<PresentationManagerProps, \"enableSchemasPreload\"> {\n /**\n * Time in milliseconds after which the request will timeout.\n */\n requestTimeout?: number;\n\n /**\n * Should schemas preloading be enabled. If true, [[Presentation]] library listens\n * for `BriefcaseDb.onOpened` event and force pre-loads all ECSchemas.\n */\n enableSchemasPreload?: boolean;\n\n /**\n * How much time should an unused client manager be stored in memory\n * before it's disposed.\n */\n unusedClientLifetime?: number;\n\n /**\n * The maximum number of client [[PresentationManager]] instances to keep in memory\n * at once. When creating a manager for a new client would exceed this limit, the\n * least-recently-used manager is disposed first. This bounds memory and native\n * resource usage regardless of how many distinct clients make requests.\n *\n * Defaults to `100`. A value less than `1` disables the limit.\n */\n maxClientManagers?: number;\n}\n\ninterface PresentationInternalProps {\n /**\n * Factory method for creating separate managers for each client\n */\n clientManagerFactory?: (clientId: string, props: PresentationManagerProps) => PresentationManager;\n}\n\n/**\n * Props for initializing the [[Presentation]] library for using multiple [[PresentationManager]]\n * instances, one for each frontend.\n *\n * @public\n * @deprecated in 4.8 - might be removed in next major version. Use [[PresentationProps]] instead.\n */\nexport type MultiManagerPresentationProps = PresentationProps;\n\n/**\n * Base props for initializing the [[Presentation]] library.\n *\n * @public\n * @deprecated in 4.8 - might be removed in next major version. Use [[PresentationProps]] instead.\n */\nexport type PresentationPropsBase = PresentationProps;\n\n/**\n * Props for initializing the [[Presentation]] library with ability to use a single\n * [[PresentationManager]] instance for handling all requests.\n *\n * @public\n * @deprecated in 4.8 - might be removed in next major version. Use [[PresentationProps]] instead.\n */\nexport type SingleManagerPresentationProps = Omit<PresentationProps, \"unusedClientLifetime\">;\n\ninterface ClientStoreItem {\n manager: PresentationManager;\n}\n\n/**\n * Static class used to statically set up Presentation library for the backend.\n * Basically what it does is:\n * - Register a RPC implementation\n * - Create a singleton [[PresentationManager]] instance\n * - Subscribe for [IModelHost.onBeforeShutdown]($core-backend) event and terminate\n * the presentation manager when that happens.\n *\n * @public\n */\nexport class Presentation {\n private static _initProps: (PresentationProps & PresentationInternalProps) | undefined;\n private static _clientsStorage: FactoryBasedTemporaryStorage<ClientStoreItem> | undefined;\n private static _disposeIpcHandler: DisposeFunc | undefined;\n private static _shutdownListener: DisposeFunc | undefined;\n private static _disposeIModelOpenedListener: DisposeFunc | undefined;\n private static _rpcImpl: PresentationRpcImpl | undefined;\n\n /* c8 ignore next */\n private constructor() {}\n\n /** Properties used to initialize the presentation framework */\n public static get initProps(): PresentationProps | undefined {\n return this._initProps;\n }\n\n /**\n * Initializes Presentation library for the backend.\n *\n * See [Setting up iTwin.js Presentation library documentation page]($docs/presentation/setup/index.md#backend) for an example.\n *\n * **Important:** The method should be called after a call to [IModelHost.startup]($core-backend)\n *\n * @param props Optional properties for [[PresentationManager]]\n */\n public static initialize(props?: PresentationProps): void {\n this._initProps = props || {};\n this._shutdownListener = IModelHost.onBeforeShutdown.addListener(() => Presentation.terminate());\n\n this._rpcImpl = new PresentationRpcImpl({\n requestTimeout: this._initProps.requestTimeout,\n });\n RpcManager.registerImpl(PresentationRpcInterface, PresentationRpcImpl);\n RpcManager.supplyImplInstance(PresentationRpcInterface, this._rpcImpl);\n\n if (IpcHost.isValid) {\n this._disposeIpcHandler = PresentationIpcHandler.register();\n }\n\n this._clientsStorage = new FactoryBasedTemporaryStorage<ClientStoreItem>({\n factory: this.createClientManager.bind(this),\n cleanupHandler: (_id, storeItem) => this.disposeClientManager(_id, storeItem),\n // cleanup unused managers every minute\n cleanupInterval: 60 * 1000,\n // by default, manager is disposed after 1 hour of being unused\n unusedValueLifetime: this._initProps.unusedClientLifetime ?? 60 * 60 * 1000,\n // by default, keep at most 100 client managers in memory at once\n maxValues: this._initProps.maxClientManagers ?? 100,\n // add some logging\n /* c8 ignore next 5 */\n onDisposedSingle: (id: string) =>\n Logger.logInfo(\n PresentationBackendLoggerCategory.PresentationManager,\n `Disposed PresentationManager instance with ID: ${id}. Total instances: ${this._clientsStorage!.values.length}.`,\n ),\n /* c8 ignore next */\n onDisposedAll: () => Logger.logInfo(PresentationBackendLoggerCategory.PresentationManager, `Disposed all PresentationManager instances.`),\n });\n\n if (this._initProps.enableSchemasPreload) {\n this._disposeIModelOpenedListener = BriefcaseDb.onOpened.addListener(this.onIModelOpened);\n }\n }\n\n /**\n * Terminates Presentation. Consumers don't need to call this as it's automatically\n * called on [IModelHost.onBeforeShutdown]($core-backend) event.\n */\n public static terminate(): void {\n if (this._clientsStorage) {\n this._clientsStorage[Symbol.dispose]();\n this._clientsStorage = undefined;\n }\n if (this._disposeIModelOpenedListener) {\n this._disposeIModelOpenedListener();\n this._disposeIModelOpenedListener = undefined;\n }\n if (this._shutdownListener) {\n this._shutdownListener();\n this._shutdownListener = undefined;\n }\n RpcManager.unregisterImpl(PresentationRpcInterface);\n if (this._rpcImpl) {\n this._rpcImpl[Symbol.dispose]();\n this._rpcImpl = undefined;\n }\n if (this._disposeIpcHandler) {\n this._disposeIpcHandler();\n }\n this._initProps = undefined;\n }\n\n private static createClientManager(clientId: string, onManagerUsed: () => void): ClientStoreItem {\n const manager =\n Presentation._initProps && Presentation._initProps.clientManagerFactory\n ? Presentation._initProps.clientManagerFactory(clientId, Presentation._initProps)\n : new PresentationManager({\n ...Presentation._initProps,\n // @ts-expect-error internal prop\n id: clientId,\n });\n manager.onUsed.addListener(onManagerUsed);\n Logger.logInfo(\n PresentationBackendLoggerCategory.PresentationManager,\n `Created a PresentationManager instance with ID: ${clientId}. Total instances: ${this._clientsStorage!.values.length}.`,\n );\n return { manager };\n }\n\n private static disposeClientManager(_id: string, storeItem: ClientStoreItem) {\n storeItem.manager[Symbol.dispose]();\n }\n\n /**\n * Get an instance of [[PresentationManager]] for specific client\n * @param clientId ID of the client requesting presentation data. If no\n * ID is provided, the default [[PresentationManager]] is returned.\n */\n public static getManager(clientId?: string): PresentationManager {\n if (this._clientsStorage) {\n return this._clientsStorage.getValue(clientId || \"\").manager;\n }\n throw new PresentationError(PresentationStatus.NotInitialized, \"Presentation must be first initialized by calling Presentation.initialize\");\n }\n\n /**\n * Get the time in milliseconds that backend should respond in .\n */\n public static getRequestTimeout(): number {\n if (this._rpcImpl === undefined) {\n throw new PresentationError(PresentationStatus.NotInitialized, \"Presentation must be first initialized by calling Presentation.initialize\");\n }\n return this._rpcImpl.requestTimeout;\n }\n\n private static onIModelOpened = (imodel: BriefcaseDb) => {\n const manager = this.getManager();\n const imodelAddon = manager[_presentation_manager_detail].getNativePlatform().getImodelAddon(imodel);\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n manager[_presentation_manager_detail].getNativePlatform().forceLoadSchemas(imodelAddon);\n };\n}\n"]}
@@ -13,13 +13,13 @@ import { Presentation } from "./Presentation.js";
13
13
  export class PresentationIpcHandler extends IpcHandler {
14
14
  channelName = PRESENTATION_IPC_CHANNEL_NAME;
15
15
  async setRulesetVariable(params) {
16
- const { clientId, rulesetId, variable } = params;
16
+ const { rulesetId, variable } = params;
17
17
  const parsedVariable = RulesetVariable.fromJSON(variable);
18
- Presentation.getManager(clientId).vars(rulesetId).setValue(parsedVariable.id, parsedVariable.type, parsedVariable.value);
18
+ Presentation.getManager().vars(rulesetId).setValue(parsedVariable.id, parsedVariable.type, parsedVariable.value);
19
19
  }
20
20
  async unsetRulesetVariable(params) {
21
- const { clientId, rulesetId, variableId } = params;
22
- Presentation.getManager(clientId).vars(rulesetId).unset(variableId);
21
+ const { rulesetId, variableId } = params;
22
+ Presentation.getManager().vars(rulesetId).unset(variableId);
23
23
  }
24
24
  }
25
25
  //# sourceMappingURL=PresentationIpcHandler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PresentationIpcHandler.js","sourceRoot":"","sources":["../../../src/presentation-backend/PresentationIpcHandler.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAChG;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,6BAA6B,EAA4B,MAAM,qCAAqC,CAAC;AAC9G,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,gBAAgB;AAChB,MAAM,OAAO,sBAAuB,SAAQ,UAAU;IAC7C,WAAW,GAAG,6BAA6B,CAAC;IAE5C,KAAK,CAAC,kBAAkB,CAAC,MAAqE;QACnG,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;QACjD,MAAM,cAAc,GAAG,eAAe,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC1D,YAAY,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,EAAE,cAAc,CAAC,IAAI,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC;IAC3H,CAAC;IAEM,KAAK,CAAC,oBAAoB,CAAC,MAAuE;QACvG,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC;QACnD,YAAY,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACtE,CAAC;CACF","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n/** @packageDocumentation\n * @module RPC\n */\n\nimport { IpcHandler } from \"@itwin/core-backend\";\nimport { RulesetVariable } from \"@itwin/presentation-common\";\nimport { PRESENTATION_IPC_CHANNEL_NAME, PresentationIpcInterface } from \"@itwin/presentation-common/internal\";\nimport { Presentation } from \"./Presentation.js\";\n\n/** @internal */\nexport class PresentationIpcHandler extends IpcHandler implements PresentationIpcInterface {\n public channelName = PRESENTATION_IPC_CHANNEL_NAME;\n\n public async setRulesetVariable(params: Parameters<PresentationIpcInterface[\"setRulesetVariable\"]>[0]): Promise<void> {\n const { clientId, rulesetId, variable } = params;\n const parsedVariable = RulesetVariable.fromJSON(variable);\n Presentation.getManager(clientId).vars(rulesetId).setValue(parsedVariable.id, parsedVariable.type, parsedVariable.value);\n }\n\n public async unsetRulesetVariable(params: Parameters<PresentationIpcInterface[\"unsetRulesetVariable\"]>[0]): Promise<void> {\n const { clientId, rulesetId, variableId } = params;\n Presentation.getManager(clientId).vars(rulesetId).unset(variableId);\n }\n}\n"]}
1
+ {"version":3,"file":"PresentationIpcHandler.js","sourceRoot":"","sources":["../../../src/presentation-backend/PresentationIpcHandler.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAChG;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,6BAA6B,EAA4B,MAAM,qCAAqC,CAAC;AAC9G,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,gBAAgB;AAChB,MAAM,OAAO,sBAAuB,SAAQ,UAAU;IAC7C,WAAW,GAAG,6BAA6B,CAAC;IAE5C,KAAK,CAAC,kBAAkB,CAAC,MAAqE;QACnG,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;QACvC,MAAM,cAAc,GAAG,eAAe,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC1D,YAAY,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,EAAE,cAAc,CAAC,IAAI,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC;IACnH,CAAC;IAEM,KAAK,CAAC,oBAAoB,CAAC,MAAuE;QACvG,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC;QACzC,YAAY,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC9D,CAAC;CACF","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n/** @packageDocumentation\n * @module RPC\n */\n\nimport { IpcHandler } from \"@itwin/core-backend\";\nimport { RulesetVariable } from \"@itwin/presentation-common\";\nimport { PRESENTATION_IPC_CHANNEL_NAME, PresentationIpcInterface } from \"@itwin/presentation-common/internal\";\nimport { Presentation } from \"./Presentation.js\";\n\n/** @internal */\nexport class PresentationIpcHandler extends IpcHandler implements PresentationIpcInterface {\n public channelName = PRESENTATION_IPC_CHANNEL_NAME;\n\n public async setRulesetVariable(params: Parameters<PresentationIpcInterface[\"setRulesetVariable\"]>[0]): Promise<void> {\n const { rulesetId, variable } = params;\n const parsedVariable = RulesetVariable.fromJSON(variable);\n Presentation.getManager().vars(rulesetId).setValue(parsedVariable.id, parsedVariable.type, parsedVariable.value);\n }\n\n public async unsetRulesetVariable(params: Parameters<PresentationIpcInterface[\"unsetRulesetVariable\"]>[0]): Promise<void> {\n const { rulesetId, variableId } = params;\n Presentation.getManager().vars(rulesetId).unset(variableId);\n }\n}\n"]}
@@ -31,9 +31,14 @@ export declare class PresentationRpcImpl extends PresentationRpcInterface implem
31
31
  /** Returns a bad request response with empty result and an error code */
32
32
  private errorResponse;
33
33
  /**
34
- * Get the [[PresentationManager]] used by this RPC impl.
34
+ * Get the [[PresentationManager]] used by this RPC impl for the currently authenticated client.
35
+ *
36
+ * In IPC apps there's a single trusted local user, so a single shared manager is used for all
37
+ * requests (consistent with [[PresentationIpcHandler]]). In web apps, the manager is keyed by the
38
+ * JWT `sub` (subject) claim derived from the request's access token, so all sessions of the same
39
+ * user share a manager. When there's no usable token, the default shared manager is used.
35
40
  */
36
- getManager(clientId?: string): PresentationManager;
41
+ getManager(): PresentationManager;
37
42
  private getIModel;
38
43
  private makeRequest;
39
44
  getNodesCount(token: IModelRpcProps, requestOptions: HierarchyRpcRequestOptions): PresentationRpcResponse<number>;
@@ -1 +1 @@
1
- {"version":3,"file":"PresentationRpcImpl.d.ts","sourceRoot":"","sources":["../../../src/presentation-backend/PresentationRpcImpl.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PresentationRpcImpl.d.ts","sourceRoot":"","sources":["../../../src/presentation-backend/PresentationRpcImpl.ts"],"names":[],"mappings":"AAIA;;GAEG;AAIH,OAAO,EAAE,cAAc,EAAsB,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAEL,iCAAiC,EACjC,kCAAkC,EAElC,oCAAoC,EACpC,wBAAwB,EACxB,+BAA+B,EAC/B,uBAAuB,EACvB,cAAc,EAEd,6BAA6B,EAC7B,8BAA8B,EAC9B,iBAAiB,EACjB,+BAA+B,EAC/B,iBAAiB,EACjB,+CAA+C,EAC/C,sCAAsC,EAEtC,yCAAyC,EACzC,0BAA0B,EAC1B,QAAQ,EAER,UAAU,EACV,eAAe,EACf,IAAI,EACJ,eAAe,EACf,KAAK,EACL,aAAa,EAGb,wBAAwB,EACxB,uBAAuB,EAQvB,cAAc,EACd,+BAA+B,EAC/B,wCAAwC,EACzC,MAAM,4BAA4B,CAAC;AAQpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAMzD,gBAAgB;AAChB,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAC1C,gBAAgB;AAChB,eAAO,MAAM,0BAA0B,QAAQ,CAAC;AA4BhD;;;;;GAKG;AACH,qBAAa,mBAAoB,SAAQ,wBAAyB,YAAW,UAAU;IACrF,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,gBAAgB,CAAiD;IACzE,OAAO,CAAC,aAAa,CAAmC;IACxD,OAAO,CAAC,cAAc,CAA2C;gBAE9C,KAAK,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE;IA0B/C,CAAC,MAAM,CAAC,OAAO,CAAC;IAKvB,IAAW,cAAc,WAExB;IAED,IAAW,eAAe,mDAEzB;IAED,gDAAgD;IAChD,OAAO,CAAC,eAAe;IAQvB,yEAAyE;IACzE,OAAO,CAAC,aAAa;IASrB;;;;;;;OAOG;IACI,UAAU,IAAI,mBAAmB;YAK1B,SAAS;YAOT,WAAW;IA4FH,aAAa,CAAC,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,0BAA0B,GAAG,uBAAuB,CAAC,MAAM,CAAC;IAMjH,aAAa,CAAC,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,KAAK,CAAC,0BAA0B,CAAC,GAAG,uBAAuB,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IAerI,kBAAkB,CACtC,KAAK,EAAE,cAAc,EACrB,cAAc,EAAE,yCAAyC,GACxD,uBAAuB,CAAC,MAAM,GAAG,cAAc,GAAG,SAAS,CAAC;IAMzC,YAAY,CAChC,KAAK,EAAE,cAAc,EACrB,cAAc,EAAE,+CAA+C,GAC9D,uBAAuB,CAAC,eAAe,EAAE,CAAC;IAMvB,oBAAoB,CACxC,KAAK,EAAE,cAAc,EACrB,cAAc,EAAE,sCAAsC,GACrD,uBAAuB,CAAC,eAAe,EAAE,CAAC;IAQvB,iBAAiB,CACrC,KAAK,EAAE,cAAc,EACrB,cAAc,EAAE,+BAA+B,GAC9C,uBAAuB,CAAC,uBAAuB,CAAC;IAS7B,oBAAoB,CACxC,KAAK,EAAE,cAAc,EACrB,cAAc,EAAE,kCAAkC,GACjD,uBAAuB,CAAC,cAAc,GAAG,SAAS,CAAC;IAahC,iBAAiB,CAAC,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,wBAAwB,GAAG,uBAAuB,CAAC,MAAM,CAAC;IAUnH,eAAe,CACnC,KAAK,EAAE,cAAc,EACrB,cAAc,EAAE,KAAK,CAAC,wBAAwB,CAAC,GAC9C,uBAAuB,CAAC;QAAE,UAAU,EAAE,cAAc,CAAC;QAAC,UAAU,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAA;KAAE,GAAG,SAAS,CAAC;IA0BrF,kBAAkB,CACtC,KAAK,EAAE,cAAc,EACrB,cAAc,EAAE,KAAK,CAAC,wBAAwB,CAAC,GAC9C,uBAAuB,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IAe7B,oBAAoB,CACxC,KAAK,EAAE,cAAc,EACrB,cAAc,EAAE,wCAAwC,GACvD,uBAAuB,CAAC,iBAAiB,GAAG,SAAS,CAAC;IAMnC,sBAAsB,CAC1C,KAAK,EAAE,cAAc,EACrB,cAAc,EAAE,+BAA+B,GAC9C,uBAAuB,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC;IAUtC,sBAAsB,CAC1C,KAAK,EAAE,cAAc,EACrB,cAAc,EAAE,oCAAoC,GACnD,uBAAuB,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAC;IA+B1C,yBAAyB,CAC7C,KAAK,EAAE,cAAc,EACrB,cAAc,EAAE,6BAA6B,GAC5C,uBAAuB,CAAC,eAAe,CAAC;IAOrB,+BAA+B,CACnD,KAAK,EAAE,cAAc,EACrB,cAAc,EAAE,8BAA8B,GAC7C,uBAAuB,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC;IAkBpC,kBAAkB,CAAC,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,+BAA+B,GAAG,uBAAuB,CAAC,cAAc,EAAE,CAAC;IAIrI,gBAAgB,CAAC,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,iCAAiC,GAAG,uBAAuB,CAAC,UAAU,CAAC;CAOtJ"}
@@ -5,7 +5,7 @@
5
5
  /** @packageDocumentation
6
6
  * @module RPC
7
7
  */
8
- import { IModelDb, RpcTrace } from "@itwin/core-backend";
8
+ import { IModelDb, IpcHost, RpcTrace } from "@itwin/core-backend";
9
9
  import { BeEvent, ErrorCategory, Logger, omit, StatusCategory, SuccessCategory } from "@itwin/core-bentley";
10
10
  import { RpcPendingResponse } from "@itwin/core-common";
11
11
  import { ContentFlags, KeySet, PresentationError, PresentationRpcInterface, PresentationStatus, RulesetVariable, SelectClassInfo, } from "@itwin/presentation-common";
@@ -24,6 +24,30 @@ export const MAX_ALLOWED_PAGE_SIZE = 1000;
24
24
  /** @internal */
25
25
  export const MAX_ALLOWED_KEYS_PAGE_SIZE = 10000;
26
26
  const DEFAULT_REQUEST_TIMEOUT = 5000;
27
+ /**
28
+ * Derives a stable cache key for a client `PresentationManager` from the given access token.
29
+ * Returns the JWT `sub` (subject) claim - a stable, server-issued identifier for the authenticated
30
+ * user - when the token is a well-formed JWT. Returns `undefined` otherwise (e.g. no token, opaque
31
+ * token or malformed token), in which case the default shared manager is used.
32
+ */
33
+ function getManagerKeyFromAccessToken(accessToken) {
34
+ if (!accessToken) {
35
+ return undefined;
36
+ }
37
+ try {
38
+ // the token may be prefixed with the authorization scheme (e.g. "Bearer <jwt>")
39
+ const jwt = accessToken.substring(accessToken.lastIndexOf(" ") + 1);
40
+ const parts = jwt.split(".");
41
+ if (parts.length !== 3) {
42
+ return undefined;
43
+ }
44
+ const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
45
+ return typeof payload.sub === "string" && payload.sub.length > 0 ? payload.sub : undefined;
46
+ }
47
+ catch {
48
+ return undefined;
49
+ }
50
+ }
27
51
  /**
28
52
  * The backend implementation of PresentationRpcInterface. All it's basically
29
53
  * responsible for is forwarding calls to [[Presentation.manager]].
@@ -85,10 +109,16 @@ export class PresentationRpcImpl extends PresentationRpcInterface {
85
109
  };
86
110
  }
87
111
  /**
88
- * Get the [[PresentationManager]] used by this RPC impl.
112
+ * Get the [[PresentationManager]] used by this RPC impl for the currently authenticated client.
113
+ *
114
+ * In IPC apps there's a single trusted local user, so a single shared manager is used for all
115
+ * requests (consistent with [[PresentationIpcHandler]]). In web apps, the manager is keyed by the
116
+ * JWT `sub` (subject) claim derived from the request's access token, so all sessions of the same
117
+ * user share a manager. When there's no usable token, the default shared manager is used.
89
118
  */
90
- getManager(clientId) {
91
- return Presentation.getManager(clientId);
119
+ getManager() {
120
+ const managerKey = IpcHost.isValid ? undefined : getManagerKeyFromAccessToken(RpcTrace.expectCurrentActivity.accessToken);
121
+ return Presentation.getManager(managerKey);
92
122
  }
93
123
  async getIModel(token) {
94
124
  const imodel = IModelDb.findByKey(token.key);
@@ -180,15 +210,15 @@ export class PresentationRpcImpl extends PresentationRpcInterface {
180
210
  /* eslint-disable @typescript-eslint/no-deprecated */
181
211
  async getNodesCount(token, requestOptions) {
182
212
  return this.makeRequest(token, "getNodesCount", requestOptions, async (options) => {
183
- return this.getManager(requestOptions.clientId).getNodesCount(options);
213
+ return this.getManager().getNodesCount(options);
184
214
  });
185
215
  }
186
216
  async getPagedNodes(token, requestOptions) {
187
217
  return this.makeRequest(token, "getPagedNodes", requestOptions, async (options) => {
188
218
  options = enforceValidPageSize(options);
189
219
  const [serializedHierarchyLevel, count] = await Promise.all([
190
- this.getManager(requestOptions.clientId)[_presentation_manager_detail].getNodes(options),
191
- this.getManager(requestOptions.clientId).getNodesCount(options),
220
+ this.getManager()[_presentation_manager_detail].getNodes(options),
221
+ this.getManager().getNodesCount(options),
192
222
  ]);
193
223
  const hierarchyLevel = deepReplaceNullsToUndefined(JSON.parse(serializedHierarchyLevel));
194
224
  return {
@@ -199,23 +229,23 @@ export class PresentationRpcImpl extends PresentationRpcInterface {
199
229
  }
200
230
  async getNodesDescriptor(token, requestOptions) {
201
231
  return this.makeRequest(token, "getNodesDescriptor", requestOptions, async (options) => {
202
- return this.getManager(requestOptions.clientId)[_presentation_manager_detail].getNodesDescriptor(options);
232
+ return this.getManager()[_presentation_manager_detail].getNodesDescriptor(options);
203
233
  });
204
234
  }
205
235
  async getNodePaths(token, requestOptions) {
206
236
  return this.makeRequest(token, "getNodePaths", requestOptions, async (options) => {
207
- return this.getManager(requestOptions.clientId)[_presentation_manager_detail].getNodePaths(options);
237
+ return this.getManager()[_presentation_manager_detail].getNodePaths(options);
208
238
  });
209
239
  }
210
240
  async getFilteredNodePaths(token, requestOptions) {
211
241
  return this.makeRequest(token, "getFilteredNodePaths", requestOptions, async (options) => {
212
- return this.getManager(requestOptions.clientId)[_presentation_manager_detail].getFilteredNodePaths(options);
242
+ return this.getManager()[_presentation_manager_detail].getFilteredNodePaths(options);
213
243
  });
214
244
  }
215
245
  /* eslint-enable @typescript-eslint/no-deprecated */
216
246
  async getContentSources(token, requestOptions) {
217
247
  return this.makeRequest(token, "getContentSources", requestOptions, async (options) => {
218
- const result = await this.getManager(requestOptions.clientId).getContentSources(options);
248
+ const result = await this.getManager().getContentSources(options);
219
249
  const classesMap = {};
220
250
  const selectClasses = result.map((sci) => SelectClassInfo.toCompressedJSON(sci, classesMap));
221
251
  return { sources: selectClasses, classesMap };
@@ -230,7 +260,7 @@ export class PresentationRpcImpl extends PresentationRpcInterface {
230
260
  };
231
261
  // Here we send a plain JSON string but we will parse it to DescriptorJSON on the frontend. This way we are
232
262
  // bypassing unnecessary deserialization and serialization.
233
- return Presentation.getManager(requestOptions.clientId)[_presentation_manager_detail].getContentDescriptor(options);
263
+ return this.getManager()[_presentation_manager_detail].getContentDescriptor(options);
234
264
  });
235
265
  }
236
266
  async getContentSetSize(token, requestOptions) {
@@ -239,7 +269,7 @@ export class PresentationRpcImpl extends PresentationRpcInterface {
239
269
  ...options,
240
270
  keys: KeySet.fromJSON(options.keys),
241
271
  };
242
- return this.getManager(requestOptions.clientId).getContentSetSize(options);
272
+ return this.getManager().getContentSetSize(options);
243
273
  });
244
274
  }
245
275
  async getPagedContent(token, requestOptions) {
@@ -249,8 +279,8 @@ export class PresentationRpcImpl extends PresentationRpcInterface {
249
279
  keys: KeySet.fromJSON(options.keys),
250
280
  });
251
281
  const [size, content] = await Promise.all([
252
- this.getManager(requestOptions.clientId).getContentSetSize(options),
253
- this.getManager(requestOptions.clientId)[_presentation_manager_detail].getContent(options),
282
+ this.getManager().getContentSetSize(options),
283
+ this.getManager()[_presentation_manager_detail].getContent(options),
254
284
  ]);
255
285
  if (!content) {
256
286
  return undefined;
@@ -280,8 +310,7 @@ export class PresentationRpcImpl extends PresentationRpcInterface {
280
310
  }
281
311
  async getElementProperties(token, requestOptions) {
282
312
  return this.makeRequest(token, "getElementProperties", { ...requestOptions }, async (options) => {
283
- const { clientId, ...restOptions } = options;
284
- return this.getManager(clientId).getElementProperties(restOptions);
313
+ return this.getManager().getElementProperties(options);
285
314
  });
286
315
  }
287
316
  async getPagedDistinctValues(token, requestOptions) {
@@ -290,7 +319,7 @@ export class PresentationRpcImpl extends PresentationRpcInterface {
290
319
  ...options,
291
320
  keys: KeySet.fromJSON(options.keys),
292
321
  });
293
- return this.getManager(requestOptions.clientId)[_presentation_manager_detail].getPagedDistinctValues(options);
322
+ return this.getManager()[_presentation_manager_detail].getPagedDistinctValues(options);
294
323
  });
295
324
  }
296
325
  async getContentInstanceKeys(token, requestOptions) {
@@ -305,8 +334,8 @@ export class PresentationRpcImpl extends PresentationRpcInterface {
305
334
  },
306
335
  }, MAX_ALLOWED_KEYS_PAGE_SIZE);
307
336
  const [size, content] = await Promise.all([
308
- this.getManager(requestOptions.clientId).getContentSetSize(options),
309
- this.getManager(requestOptions.clientId)[_presentation_manager_detail].getContent(options),
337
+ this.getManager().getContentSetSize(options),
338
+ this.getManager()[_presentation_manager_detail].getContent(options),
310
339
  ]);
311
340
  if (size === 0 || !content) {
312
341
  return { total: 0, items: new KeySet().toJSON() };
@@ -319,7 +348,7 @@ export class PresentationRpcImpl extends PresentationRpcInterface {
319
348
  }
320
349
  async getDisplayLabelDefinition(token, requestOptions) {
321
350
  return this.makeRequest(token, "getDisplayLabelDefinition", requestOptions, async (options) => {
322
- const label = await this.getManager(requestOptions.clientId)[_presentation_manager_detail].getDisplayLabelDefinition(options);
351
+ const label = await this.getManager()[_presentation_manager_detail].getDisplayLabelDefinition(options);
323
352
  return label;
324
353
  });
325
354
  }
@@ -329,7 +358,7 @@ export class PresentationRpcImpl extends PresentationRpcInterface {
329
358
  requestOptions.keys.splice(pageOpts.paging.size);
330
359
  }
331
360
  return this.makeRequest(token, "getPagedDisplayLabelDefinitions", requestOptions, async (options) => {
332
- const labels = await this.getManager(requestOptions.clientId)[_presentation_manager_detail].getDisplayLabelDefinitions({
361
+ const labels = await this.getManager()[_presentation_manager_detail].getDisplayLabelDefinitions({
333
362
  ...options,
334
363
  keys: options.keys,
335
364
  });
@@ -341,11 +370,11 @@ export class PresentationRpcImpl extends PresentationRpcInterface {
341
370
  }
342
371
  /* eslint-disable @typescript-eslint/no-deprecated */
343
372
  async getSelectionScopes(token, requestOptions) {
344
- return this.makeRequest(token, "getSelectionScopes", requestOptions, async (options) => this.getManager(requestOptions.clientId).getSelectionScopes(options));
373
+ return this.makeRequest(token, "getSelectionScopes", requestOptions, async (options) => this.getManager().getSelectionScopes(options));
345
374
  }
346
375
  async computeSelection(token, requestOptions) {
347
376
  return this.makeRequest(token, "computeSelection", requestOptions, async (options) => {
348
- const keys = await this.getManager(requestOptions.clientId).computeSelection(options);
377
+ const keys = await this.getManager().computeSelection(options);
349
378
  return keys.toJSON();
350
379
  });
351
380
  }