@itwin/core-backend 5.15.0-dev.16 → 5.15.0-dev.18

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 (64) hide show
  1. package/CHANGELOG.md +11 -1
  2. package/lib/cjs/EditTxn.d.ts +5 -0
  3. package/lib/cjs/EditTxn.d.ts.map +1 -1
  4. package/lib/cjs/EditTxn.js +30 -10
  5. package/lib/cjs/EditTxn.js.map +1 -1
  6. package/lib/cjs/GeoCoordConfig.d.ts +1 -0
  7. package/lib/cjs/GeoCoordConfig.d.ts.map +1 -1
  8. package/lib/cjs/GeoCoordConfig.js +12 -8
  9. package/lib/cjs/GeoCoordConfig.js.map +1 -1
  10. package/lib/cjs/IModelDb.d.ts +9 -1
  11. package/lib/cjs/IModelDb.d.ts.map +1 -1
  12. package/lib/cjs/IModelDb.js +32 -0
  13. package/lib/cjs/IModelDb.js.map +1 -1
  14. package/lib/cjs/TxnManager.d.ts.map +1 -1
  15. package/lib/cjs/TxnManager.js +5 -1
  16. package/lib/cjs/TxnManager.js.map +1 -1
  17. package/lib/cjs/internal/Symbols.d.ts +3 -0
  18. package/lib/cjs/internal/Symbols.d.ts.map +1 -1
  19. package/lib/cjs/internal/Symbols.js +4 -1
  20. package/lib/cjs/internal/Symbols.js.map +1 -1
  21. package/lib/cjs/internal/workspace/WorkspaceImpl.d.ts.map +1 -1
  22. package/lib/cjs/internal/workspace/WorkspaceImpl.js +20 -6
  23. package/lib/cjs/internal/workspace/WorkspaceImpl.js.map +1 -1
  24. package/lib/esm/EditTxn.d.ts +5 -0
  25. package/lib/esm/EditTxn.d.ts.map +1 -1
  26. package/lib/esm/EditTxn.js +32 -12
  27. package/lib/esm/EditTxn.js.map +1 -1
  28. package/lib/esm/GeoCoordConfig.d.ts +1 -0
  29. package/lib/esm/GeoCoordConfig.d.ts.map +1 -1
  30. package/lib/esm/GeoCoordConfig.js +12 -8
  31. package/lib/esm/GeoCoordConfig.js.map +1 -1
  32. package/lib/esm/IModelDb.d.ts +9 -1
  33. package/lib/esm/IModelDb.d.ts.map +1 -1
  34. package/lib/esm/IModelDb.js +34 -2
  35. package/lib/esm/IModelDb.js.map +1 -1
  36. package/lib/esm/TxnManager.d.ts.map +1 -1
  37. package/lib/esm/TxnManager.js +6 -2
  38. package/lib/esm/TxnManager.js.map +1 -1
  39. package/lib/esm/internal/Symbols.d.ts +3 -0
  40. package/lib/esm/internal/Symbols.d.ts.map +1 -1
  41. package/lib/esm/internal/Symbols.js +3 -0
  42. package/lib/esm/internal/Symbols.js.map +1 -1
  43. package/lib/esm/internal/workspace/WorkspaceImpl.d.ts.map +1 -1
  44. package/lib/esm/internal/workspace/WorkspaceImpl.js +20 -6
  45. package/lib/esm/internal/workspace/WorkspaceImpl.js.map +1 -1
  46. package/lib/esm/test/imodel/IModelGeolocation.test.js +8 -6
  47. package/lib/esm/test/imodel/IModelGeolocation.test.js.map +1 -1
  48. package/lib/esm/test/imodel/IModelProps.test.d.ts +2 -0
  49. package/lib/esm/test/imodel/IModelProps.test.d.ts.map +1 -0
  50. package/lib/esm/test/imodel/IModelProps.test.js +411 -0
  51. package/lib/esm/test/imodel/IModelProps.test.js.map +1 -0
  52. package/lib/esm/test/schema/SchemaViewPropertyOverrides.test.d.ts +2 -0
  53. package/lib/esm/test/schema/SchemaViewPropertyOverrides.test.d.ts.map +1 -0
  54. package/lib/esm/test/schema/SchemaViewPropertyOverrides.test.js +240 -0
  55. package/lib/esm/test/schema/SchemaViewPropertyOverrides.test.js.map +1 -0
  56. package/lib/esm/test/schema/SchemaViewValidation.test.js +2 -8
  57. package/lib/esm/test/schema/SchemaViewValidation.test.js.map +1 -1
  58. package/lib/esm/test/standalone/EditTxn.test.js +72 -1
  59. package/lib/esm/test/standalone/EditTxn.test.js.map +1 -1
  60. package/lib/esm/test/standalone/GeoCoordConfig.test.d.ts +2 -0
  61. package/lib/esm/test/standalone/GeoCoordConfig.test.d.ts.map +1 -0
  62. package/lib/esm/test/standalone/GeoCoordConfig.test.js +158 -0
  63. package/lib/esm/test/standalone/GeoCoordConfig.test.js.map +1 -0
  64. package/package.json +14 -14
@@ -6,7 +6,8 @@ import { Logger, OpenMode } from "@itwin/core-bentley";
6
6
  import { expect } from "chai";
7
7
  import * as sinon from "sinon";
8
8
  import { EditTxnError } from "@itwin/core-common";
9
- import { EditTxn, IModelJsFs, StandaloneDb } from "../../core-backend";
9
+ import { BackendLoggerCategory, EditTxn, IModelJsFs, StandaloneDb, withEditTxn } from "../../core-backend";
10
+ import { _nativeDb } from "../../internal/Symbols";
10
11
  import { IModelTestUtils } from "../IModelTestUtils";
11
12
  class TestEditTxn extends EditTxn {
12
13
  constructor(iModel) {
@@ -177,6 +178,76 @@ describe("EditTxn", () => {
177
178
  second.end("abandon");
178
179
  expect(second.isActive).to.be.false;
179
180
  });
181
+ for (const mode of ["save", "abandon"]) {
182
+ it(`retains transaction ownership when native ${mode} fails`, () => {
183
+ const txn = new TestEditTxn(iModel);
184
+ txn.start();
185
+ txn.writeFileProperty("pending", "value");
186
+ const failure = new Error(`native ${mode} failed`);
187
+ const nativeOperation = sinon.stub(iModel[_nativeDb], mode === "save" ? "saveChanges" : "abandonChanges").throws(failure);
188
+ expect(() => txn.end(mode)).to.throw(failure);
189
+ expect(txn.isActive).to.be.true;
190
+ expect(iModel.txns.hasUnsavedChanges).to.be.true;
191
+ nativeOperation.restore();
192
+ txn.end("abandon");
193
+ expect(txn.isActive).to.be.false;
194
+ expect(iModel.queryFilePropertyString({ name: "pending", namespace: "EditTxnTest" })).to.be.undefined;
195
+ });
196
+ }
197
+ it("preserves the callback error and transaction ownership when scoped native abandonment fails", () => {
198
+ const failure = new Error("callback failure");
199
+ const abandonFailure = new Error("native abandonment failed");
200
+ const nativeOperation = sinon.stub(iModel[_nativeDb], "abandonChanges").throws(abandonFailure);
201
+ const logError = sinon.spy(Logger, "logError");
202
+ let activeTxn;
203
+ expect(() => withEditTxn(iModel, (txn) => {
204
+ activeTxn = txn;
205
+ txn.saveFileProperty({ name: "pending", namespace: "EditTxnTest" }, "value");
206
+ throw failure;
207
+ })).to.throw(failure);
208
+ expect(activeTxn?.isActive).to.be.true;
209
+ expect(iModel.txns.hasUnsavedChanges).to.be.true;
210
+ expect(logError.calledOnceWithExactly(BackendLoggerCategory.IModelDb, abandonFailure)).to.be.true;
211
+ nativeOperation.restore();
212
+ activeTxn?.end("abandon");
213
+ expect(iModel.queryFilePropertyString({ name: "pending", namespace: "EditTxnTest" })).to.be.undefined;
214
+ });
215
+ for (const asynchronous of [false, true]) {
216
+ it(`preserves the ${asynchronous ? "asynchronous" : "synchronous"} callback error when rollback and error logging both fail`, async () => {
217
+ const failure = new Error("callback failure");
218
+ const abandonFailure = new Error("native abandonment failed");
219
+ const loggingFailure = new Error("error logging failed");
220
+ const nativeOperation = sinon.stub(iModel[_nativeDb], "abandonChanges").throws(abandonFailure);
221
+ const logError = sinon.stub(Logger, "logError").throws(loggingFailure);
222
+ let activeTxn;
223
+ const edit = (txn) => {
224
+ activeTxn = txn;
225
+ txn.saveFileProperty({ name: "pending", namespace: "EditTxnTest" }, "value");
226
+ throw failure;
227
+ };
228
+ try {
229
+ if (asynchronous) {
230
+ const error = await withEditTxn(iModel, async (txn) => {
231
+ await Promise.resolve();
232
+ edit(txn);
233
+ }).catch((err) => err);
234
+ expect(error).to.equal(failure);
235
+ }
236
+ else {
237
+ expect(() => withEditTxn(iModel, edit)).to.throw(failure);
238
+ }
239
+ expect(logError.calledOnceWithExactly(BackendLoggerCategory.IModelDb, abandonFailure)).to.be.true;
240
+ expect(logError.firstCall.exception).to.equal(loggingFailure);
241
+ expect(activeTxn?.isActive).to.be.true;
242
+ expect(iModel.txns.hasUnsavedChanges).to.be.true;
243
+ }
244
+ finally {
245
+ nativeOperation.restore();
246
+ activeTxn?.end("abandon");
247
+ }
248
+ expect(iModel.queryFilePropertyString({ name: "pending", namespace: "EditTxnTest" })).to.be.undefined;
249
+ });
250
+ }
180
251
  it("uses the default description unless save is given an override", () => {
181
252
  const txn = new EditTxn(iModel, "default description");
182
253
  txn.start();
@@ -1 +1 @@
1
- {"version":3,"file":"EditTxn.test.js","sourceRoot":"","sources":["../../../../src/test/standalone/EditTxn.test.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n * See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Logger, OpenMode } from \"@itwin/core-bentley\";\r\nimport { expect } from \"chai\";\r\nimport * as sinon from \"sinon\";\r\nimport { EditTxnError } from \"@itwin/core-common\";\r\nimport { EditTxn, type IModelDb, IModelJsFs, StandaloneDb } from \"../../core-backend\";\r\nimport { IModelTestUtils } from \"../IModelTestUtils\";\r\n\r\nclass TestEditTxn extends EditTxn {\r\n public constructor(iModel: IModelDb) {\r\n super(iModel, \"test\");\r\n }\r\n\r\n public writeFileProperty(name: string, value: string | undefined): void {\r\n super.saveFileProperty({ name, namespace: \"EditTxnTest\" }, value);\r\n }\r\n}\r\n\r\nclass AbandonOnCloseEditTxn extends TestEditTxn {\r\n public override onClose(): void {\r\n if (this.isActive)\r\n this.abandonChanges();\r\n }\r\n}\r\n\r\nfunction expectEditTxnError(fn: () => void, key: EditTxnError.Key): void {\r\n expect(fn).to.throw().that.satisfies((error: unknown) => EditTxnError.isError(error, key));\r\n}\r\n\r\nfunction legacyWriteFileProperty(iModel: StandaloneDb, name: string, value: string): void {\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n iModel.saveFileProperty({ name, namespace: \"EditTxnTest\" }, value);\r\n}\r\n\r\ndescribe(\"EditTxn\", () => {\r\n let iModel: StandaloneDb;\r\n let fileName: string;\r\n\r\n beforeEach(() => {\r\n EditTxn.implicitWriteEnforcement = \"allow\";\r\n fileName = IModelTestUtils.prepareOutputFile(\"EditTxn\", \"EditTxn.bim\");\r\n iModel = StandaloneDb.createEmpty(fileName, {\r\n rootSubject: { name: \"EditTxn\" },\r\n enableTransactions: true,\r\n });\r\n });\r\n\r\n afterEach(() => {\r\n EditTxn.implicitWriteEnforcement = \"allow\";\r\n sinon.restore();\r\n\r\n if (iModel.isOpen)\r\n iModel.close();\r\n\r\n IModelJsFs.removeSync(fileName);\r\n });\r\n\r\n it(\"allows implicit writes before and after explicit txn scopes\", () => {\r\n // Implicit IModelDb mutators should work before any explicit EditTxn starts.\r\n legacyWriteFileProperty(iModel, \"legacy-before-start\", \"value\");\r\n expect(iModel.queryFilePropertyString({ name: \"legacy-before-start\", namespace: \"EditTxnTest\" })).to.equal(\"value\");\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n iModel.abandonChanges();\r\n\r\n const txn = new TestEditTxn(iModel);\r\n txn.start();\r\n expect(txn.isActive).to.be.true;\r\n\r\n txn.writeFileProperty(\"cancelled\", \"value\");\r\n txn.end(\"abandon\");\r\n // After canceling, implicit writes should still work.\r\n expect(txn.isActive).to.be.false;\r\n legacyWriteFileProperty(iModel, \"legacy-after-cancel\", \"value\");\r\n expect(iModel.queryFilePropertyString({ name: \"legacy-after-cancel\", namespace: \"EditTxnTest\" })).to.equal(\"value\");\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n iModel.abandonChanges();\r\n expect(iModel.queryFilePropertyString({ name: \"cancelled\", namespace: \"EditTxnTest\" })).to.be.undefined;\r\n\r\n txn.start();\r\n txn.writeFileProperty(\"saved\", \"value\");\r\n txn.end();\r\n // Committing also leaves the iModel ready for later implicit writes.\r\n expect(txn.isActive).to.be.false;\r\n expect(iModel.queryFilePropertyString({ name: \"saved\", namespace: \"EditTxnTest\" })).to.equal(\"value\");\r\n legacyWriteFileProperty(iModel, \"legacy-after-end\", \"value\");\r\n expect(iModel.queryFilePropertyString({ name: \"legacy-after-end\", namespace: \"EditTxnTest\" })).to.equal(\"value\");\r\n });\r\n\r\n it(\"enforces identical explicit transaction behavior across allow, log, and throw settings\", () => {\r\n const settings: Array<\"allow\" | \"log\" | \"throw\"> = [\"allow\", \"log\", \"throw\"];\r\n\r\n for (const setting of settings) {\r\n EditTxn.implicitWriteEnforcement = setting;\r\n const txn = new TestEditTxn(iModel);\r\n const inactiveName = `inactive-${setting}`;\r\n const savedName = `saved-${setting}`;\r\n const inactiveAgainName = `inactive-again-${setting}`;\r\n\r\n // Inactive explicit txn writes must always fail, regardless of enforcement.\r\n expectEditTxnError(() => txn.writeFileProperty(inactiveName, \"value\"), \"not-active\");\r\n expectEditTxnError(() => txn.saveChanges(`save ${inactiveName}`), \"not-active\");\r\n expect(iModel.queryFilePropertyString({ name: inactiveName, namespace: \"EditTxnTest\" })).to.be.undefined;\r\n expectEditTxnError(() => txn.end(\"abandon\"), \"not-active\");\r\n\r\n txn.start();\r\n txn.writeFileProperty(savedName, \"value\");\r\n txn.saveChanges(`save ${savedName}`);\r\n expect(txn.isActive).to.be.true;\r\n\r\n txn.end();\r\n expect(iModel.queryFilePropertyString({ name: savedName, namespace: \"EditTxnTest\" })).to.equal(\"value\");\r\n\r\n expectEditTxnError(() => txn.writeFileProperty(inactiveAgainName, \"value\"), \"not-active\");\r\n expectEditTxnError(() => txn.saveChanges(`save ${inactiveAgainName}`), \"not-active\");\r\n expect(iModel.queryFilePropertyString({ name: inactiveAgainName, namespace: \"EditTxnTest\" })).to.be.undefined;\r\n expectEditTxnError(() => txn.end(\"abandon\"), \"not-active\");\r\n }\r\n });\r\n\r\n it(\"logs implicit writes in log mode but still rejects inactive explicit writes\", () => {\r\n EditTxn.implicitWriteEnforcement = \"log\";\r\n const logError = sinon.spy(Logger, \"logError\");\r\n const txn = new TestEditTxn(iModel);\r\n\r\n legacyWriteFileProperty(iModel, \"implicit-log\", \"value\");\r\n expect(iModel.queryFilePropertyString({ name: \"implicit-log\", namespace: \"EditTxnTest\" })).to.equal(\"value\");\r\n expect(logError.called).to.be.true;\r\n expect(logError.firstCall.args[0]).to.equal(\"core-backend.IModelDb\");\r\n expect(EditTxnError.isError(logError.firstCall.args[1], \"implicit-txn-write-disallowed\")).to.be.true;\r\n\r\n const callCount = logError.callCount;\r\n expectEditTxnError(() => txn.writeFileProperty(\"inactive-log\", \"value\"), \"not-active\");\r\n expectEditTxnError(() => txn.saveChanges(\"save inactive log\"), \"not-active\");\r\n expect(logError.callCount).to.equal(callCount);\r\n expectEditTxnError(() => txn.end(\"abandon\"), \"not-active\");\r\n });\r\n\r\n it(\"rejects implicit writes in throw mode and still allows active explicit writes\", () => {\r\n EditTxn.implicitWriteEnforcement = \"throw\";\r\n\r\n expectEditTxnError(() => legacyWriteFileProperty(iModel, \"implicit-throw\", \"value\"), \"implicit-txn-write-disallowed\");\r\n expect(iModel.queryFilePropertyString({ name: \"implicit-throw\", namespace: \"EditTxnTest\" })).to.be.undefined;\r\n\r\n const txn = new TestEditTxn(iModel);\r\n txn.start();\r\n txn.writeFileProperty(\"explicit-enforce\", \"value\");\r\n txn.end();\r\n\r\n expect(iModel.queryFilePropertyString({ name: \"explicit-enforce\", namespace: \"EditTxnTest\" })).to.equal(\"value\");\r\n });\r\n\r\n it(\"throws when started with unsaved changes\", () => {\r\n // Unsaved changes made through the implicit surface block a new explicit EditTxn.\r\n legacyWriteFileProperty(iModel, \"unsaved\", \"value\");\r\n\r\n const txn = new TestEditTxn(iModel);\r\n expectEditTxnError(() => txn.start(), \"unsaved-changes\");\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n iModel.abandonChanges();\r\n legacyWriteFileProperty(iModel, \"legacy-after-abandon\", \"value\");\r\n expect(iModel.queryFilePropertyString({ name: \"legacy-after-abandon\", namespace: \"EditTxnTest\" })).to.equal(\"value\");\r\n });\r\n\r\n it(\"rejects starting an explicit txn while another explicit txn is active\", () => {\r\n const first = new TestEditTxn(iModel);\r\n const second = new TestEditTxn(iModel);\r\n\r\n first.start();\r\n expect(first.isActive).to.be.true;\r\n\r\n // EditTxn.start() now requires the implicit txn to be active, so a second explicit txn cannot start yet.\r\n expectEditTxnError(() => second.start(), \"already-active\");\r\n expect(first.isActive).to.be.true;\r\n expect(second.isActive).to.be.false;\r\n\r\n first.end(\"abandon\");\r\n expect(first.isActive).to.be.false;\r\n });\r\n\r\n it(\"allows deprecated mutating APIs while an explicit txn is active when enforcement is none\", () => {\r\n const txn = new TestEditTxn(iModel);\r\n txn.start();\r\n\r\n // Deprecated IModelDb mutators route through the implicit txn and are allowed in compatibility mode.\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n iModel.saveFileProperty({ name: \"legacy\", namespace: \"EditTxnTest\" }, \"value\");\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n iModel.saveChanges(\"legacy save\");\r\n expect(iModel.queryFilePropertyString({ name: \"legacy\", namespace: \"EditTxnTest\" })).to.equal(\"value\");\r\n\r\n txn.writeFileProperty(\"explicit\", \"value\");\r\n txn.saveChanges(\"explicit save\");\r\n expect(iModel.queryFilePropertyString({ name: \"explicit\", namespace: \"EditTxnTest\" })).to.equal(\"value\");\r\n\r\n txn.end(\"abandon\");\r\n expect(txn.isActive).to.be.false;\r\n });\r\n\r\n it(\"allows starting a new explicit txn when only pending changes exist\", () => {\r\n const first = new TestEditTxn(iModel);\r\n const second = new TestEditTxn(iModel);\r\n\r\n first.start();\r\n first.writeFileProperty(\"pending\", \"value\");\r\n first.saveChanges(\"save pending\");\r\n\r\n // Saved-but-unpushed changes are allowed; only unsaved local changes block start().\r\n expect(iModel.txns.hasPendingTxns).to.be.true;\r\n expect(iModel.txns.hasUnsavedChanges).to.be.false;\r\n\r\n first.end(\"abandon\");\r\n expect(() => second.start()).to.not.throw();\r\n expect(first.isActive).to.be.false;\r\n expect(second.isActive).to.be.true;\r\n\r\n second.end(\"abandon\");\r\n expect(second.isActive).to.be.false;\r\n });\r\n\r\n it(\"uses the default description unless save is given an override\", () => {\r\n const txn = new EditTxn(iModel, \"default description\");\r\n\r\n txn.start();\r\n txn.saveFileProperty({ name: \"default-description\", namespace: \"EditTxnTest\" }, \"value\");\r\n txn.saveChanges();\r\n expect(iModel.txns.getLastSavedTxnProps()?.props.description).to.equal(\"default description\");\r\n\r\n txn.saveFileProperty({ name: \"override-description\", namespace: \"EditTxnTest\" }, \"value\");\r\n txn.end(\"save\", \"override description\");\r\n expect(iModel.txns.getLastSavedTxnProps()?.props.description).to.equal(\"override description\");\r\n });\r\n\r\n it(\"reverseTxns abandons unsaved changes from the active explicit txn\", () => {\r\n const txn = new TestEditTxn(iModel);\r\n txn.start();\r\n txn.writeFileProperty(\"reverse\", \"value\");\r\n\r\n // Reversing txns abandons the active explicit txn's local changes, but the explicit txn remains active.\r\n iModel.txns.reverseTxns(1);\r\n\r\n expect(txn.isActive).to.be.true;\r\n expect(iModel.txns.hasUnsavedChanges).to.be.false;\r\n expect(iModel.queryFilePropertyString({ name: \"reverse\", namespace: \"EditTxnTest\" })).to.be.undefined;\r\n\r\n txn.end(\"abandon\");\r\n expect(txn.isActive).to.be.false;\r\n });\r\n\r\n it(\"saves unsaved changes from the active explicit txn when the iModel closes\", () => {\r\n const txn = new TestEditTxn(iModel);\r\n txn.start();\r\n txn.writeFileProperty(\"unsaved-on-close\", \"value\");\r\n\r\n iModel.close();\r\n iModel = StandaloneDb.openFile(fileName, OpenMode.Readonly);\r\n\r\n expect(iModel.queryFilePropertyString({ name: \"unsaved-on-close\", namespace: \"EditTxnTest\" })).to.equal(\"value\");\r\n });\r\n\r\n it(\"allows subclasses to abandon unsaved changes when the iModel closes\", () => {\r\n const txn = new AbandonOnCloseEditTxn(iModel);\r\n txn.start();\r\n txn.writeFileProperty(\"saved-on-close\", \"value\");\r\n\r\n iModel.close();\r\n iModel = StandaloneDb.openFile(fileName, OpenMode.Readonly);\r\n\r\n expect(iModel.queryFilePropertyString({ name: \"saved-on-close\", namespace: \"EditTxnTest\" })).to.be.undefined;\r\n });\r\n});\r\n\r\n"]}
1
+ {"version":3,"file":"EditTxn.test.js","sourceRoot":"","sources":["../../../../src/test/standalone/EditTxn.test.ts"],"names":[],"mappings":"AAAA;;;+FAG+F;AAE/F,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAC9B,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,OAAO,EAAiB,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC1H,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,WAAY,SAAQ,OAAO;IAC/B,YAAmB,MAAgB;QACjC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxB,CAAC;IAEM,iBAAiB,CAAC,IAAY,EAAE,KAAyB;QAC9D,KAAK,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,aAAa,EAAE,EAAE,KAAK,CAAC,CAAC;IACpE,CAAC;CACF;AAED,MAAM,qBAAsB,SAAQ,WAAW;IAC7B,OAAO;QACrB,IAAI,IAAI,CAAC,QAAQ;YACf,IAAI,CAAC,cAAc,EAAE,CAAC;IAC1B,CAAC;CACF;AAED,SAAS,kBAAkB,CAAC,EAAc,EAAE,GAAqB;IAC/D,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,KAAc,EAAE,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;AAC7F,CAAC;AAED,SAAS,uBAAuB,CAAC,MAAoB,EAAE,IAAY,EAAE,KAAa;IAChF,4DAA4D;IAC5D,MAAM,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,aAAa,EAAE,EAAE,KAAK,CAAC,CAAC;AACrE,CAAC;AAED,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE;IACvB,IAAI,MAAoB,CAAC;IACzB,IAAI,QAAgB,CAAC;IAErB,UAAU,CAAC,GAAG,EAAE;QACd,OAAO,CAAC,wBAAwB,GAAG,OAAO,CAAC;QAC3C,QAAQ,GAAG,eAAe,CAAC,iBAAiB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QACvE,MAAM,GAAG,YAAY,CAAC,WAAW,CAAC,QAAQ,EAAE;YAC1C,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;YAChC,kBAAkB,EAAE,IAAI;SACzB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,CAAC,wBAAwB,GAAG,OAAO,CAAC;QAC3C,KAAK,CAAC,OAAO,EAAE,CAAC;QAEhB,IAAI,MAAM,CAAC,MAAM;YACf,MAAM,CAAC,KAAK,EAAE,CAAC;QAEjB,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,6EAA6E;QAC7E,uBAAuB,CAAC,MAAM,EAAE,qBAAqB,EAAE,OAAO,CAAC,CAAC;QAChE,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,qBAAqB,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACpH,4DAA4D;QAC5D,MAAM,CAAC,cAAc,EAAE,CAAC;QAExB,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;QACpC,GAAG,CAAC,KAAK,EAAE,CAAC;QACZ,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QAEhC,GAAG,CAAC,iBAAiB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAC5C,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACnB,sDAAsD;QACtD,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;QACjC,uBAAuB,CAAC,MAAM,EAAE,qBAAqB,EAAE,OAAO,CAAC,CAAC;QAChE,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,qBAAqB,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACpH,4DAA4D;QAC5D,MAAM,CAAC,cAAc,EAAE,CAAC;QACxB,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC;QAExG,GAAG,CAAC,KAAK,EAAE,CAAC;QACZ,GAAG,CAAC,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxC,GAAG,CAAC,GAAG,EAAE,CAAC;QACV,qEAAqE;QACrE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;QACjC,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACtG,uBAAuB,CAAC,MAAM,EAAE,kBAAkB,EAAE,OAAO,CAAC,CAAC;QAC7D,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACnH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wFAAwF,EAAE,GAAG,EAAE;QAChG,MAAM,QAAQ,GAAqC,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QAE7E,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,OAAO,CAAC,wBAAwB,GAAG,OAAO,CAAC;YAC3C,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM,YAAY,GAAG,YAAY,OAAO,EAAE,CAAC;YAC3C,MAAM,SAAS,GAAG,SAAS,OAAO,EAAE,CAAC;YACrC,MAAM,iBAAiB,GAAG,kBAAkB,OAAO,EAAE,CAAC;YAEtD,4EAA4E;YAC5E,kBAAkB,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,iBAAiB,CAAC,YAAY,EAAE,OAAO,CAAC,EAAE,YAAY,CAAC,CAAC;YACrF,kBAAkB,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,QAAQ,YAAY,EAAE,CAAC,EAAE,YAAY,CAAC,CAAC;YAChF,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC;YACzG,kBAAkB,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,YAAY,CAAC,CAAC;YAE3D,GAAG,CAAC,KAAK,EAAE,CAAC;YACZ,GAAG,CAAC,iBAAiB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAC1C,GAAG,CAAC,WAAW,CAAC,QAAQ,SAAS,EAAE,CAAC,CAAC;YACrC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;YAEhC,GAAG,CAAC,GAAG,EAAE,CAAC;YACV,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAExG,kBAAkB,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,iBAAiB,CAAC,iBAAiB,EAAE,OAAO,CAAC,EAAE,YAAY,CAAC,CAAC;YAC1F,kBAAkB,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,QAAQ,iBAAiB,EAAE,CAAC,EAAE,YAAY,CAAC,CAAC;YACrF,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC;YAC9G,kBAAkB,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,YAAY,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6EAA6E,EAAE,GAAG,EAAE;QACrF,OAAO,CAAC,wBAAwB,GAAG,KAAK,CAAC;QACzC,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAC/C,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;QAEpC,uBAAuB,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC7G,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QACnC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACrE,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,+BAA+B,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QAErG,MAAM,SAAS,GAAG,QAAQ,CAAC,SAAS,CAAC;QACrC,kBAAkB,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,iBAAiB,CAAC,cAAc,EAAE,OAAO,CAAC,EAAE,YAAY,CAAC,CAAC;QACvF,kBAAkB,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,mBAAmB,CAAC,EAAE,YAAY,CAAC,CAAC;QAC7E,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC/C,kBAAkB,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,YAAY,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+EAA+E,EAAE,GAAG,EAAE;QACvF,OAAO,CAAC,wBAAwB,GAAG,OAAO,CAAC;QAE3C,kBAAkB,CAAC,GAAG,EAAE,CAAC,uBAAuB,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,+BAA+B,CAAC,CAAC;QACtH,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC;QAE7G,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;QACpC,GAAG,CAAC,KAAK,EAAE,CAAC;QACZ,GAAG,CAAC,iBAAiB,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC;QACnD,GAAG,CAAC,GAAG,EAAE,CAAC;QAEV,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACnH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,kFAAkF;QAClF,uBAAuB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QAEpD,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;QACpC,kBAAkB,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,iBAAiB,CAAC,CAAC;QAEzD,4DAA4D;QAC5D,MAAM,CAAC,cAAc,EAAE,CAAC;QACxB,uBAAuB,CAAC,MAAM,EAAE,sBAAsB,EAAE,OAAO,CAAC,CAAC;QACjE,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,sBAAsB,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACvH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uEAAuE,EAAE,GAAG,EAAE;QAC/E,MAAM,KAAK,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;QAEvC,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QAElC,yGAAyG;QACzG,kBAAkB,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,gBAAgB,CAAC,CAAC;QAC3D,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;QAEpC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACrB,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0FAA0F,EAAE,GAAG,EAAE;QAClG,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;QACpC,GAAG,CAAC,KAAK,EAAE,CAAC;QAEZ,qGAAqG;QACrG,4DAA4D;QAC5D,MAAM,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,EAAE,OAAO,CAAC,CAAC;QAC/E,4DAA4D;QAC5D,MAAM,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAEvG,GAAG,CAAC,iBAAiB,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC3C,GAAG,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC;QACjC,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAEzG,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACnB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,KAAK,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;QAEvC,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,KAAK,CAAC,iBAAiB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAC5C,KAAK,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;QAElC,oFAAoF;QACpF,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QAC9C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;QAElD,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACrB,MAAM,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;QAC5C,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;QACnC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QAEnC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACtB,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,SAAS,CAAU,EAAE,CAAC;QAChD,EAAE,CAAC,6CAA6C,IAAI,QAAQ,EAAE,GAAG,EAAE;YACjE,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;YACpC,GAAG,CAAC,KAAK,EAAE,CAAC;YACZ,GAAG,CAAC,iBAAiB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAC1C,MAAM,OAAO,GAAG,IAAI,KAAK,CAAC,UAAU,IAAI,SAAS,CAAC,CAAC;YACnD,MAAM,eAAe,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC1H,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC9C,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;YAChC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;YACjD,eAAe,CAAC,OAAO,EAAE,CAAC;YAC1B,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACnB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;YACjC,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC;QACxG,CAAC,CAAC,CAAC;IACL,CAAC;IAED,EAAE,CAAC,6FAA6F,EAAE,GAAG,EAAE;QACrG,MAAM,OAAO,GAAG,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAC9C,MAAM,cAAc,GAAG,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC9D,MAAM,eAAe,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,gBAAgB,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QAC/F,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAC/C,IAAI,SAA8B,CAAC;QACnC,MAAM,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE;YACvC,SAAS,GAAG,GAAG,CAAC;YAChB,GAAG,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,EAAE,OAAO,CAAC,CAAC;YAC7E,MAAM,OAAO,CAAC;QAChB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACtB,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QACvC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QACjD,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAC,qBAAqB,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QAClG,eAAe,CAAC,OAAO,EAAE,CAAC;QAC1B,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;QAC1B,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC;IACxG,CAAC,CAAC,CAAC;IAEH,KAAK,MAAM,YAAY,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;QACzC,EAAE,CAAC,iBAAiB,YAAY,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,aAAa,2DAA2D,EAAE,KAAK,IAAI,EAAE;YACvI,MAAM,OAAO,GAAG,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;YAC9C,MAAM,cAAc,GAAG,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;YAC9D,MAAM,cAAc,GAAG,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;YACzD,MAAM,eAAe,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,gBAAgB,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;YAC/F,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;YACvE,IAAI,SAA8B,CAAC;YACnC,MAAM,IAAI,GAAG,CAAC,GAAY,EAAE,EAAE;gBAC5B,SAAS,GAAG,GAAG,CAAC;gBAChB,GAAG,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,EAAE,OAAO,CAAC,CAAC;gBAC7E,MAAM,OAAO,CAAC;YAChB,CAAC,CAAC;YACF,IAAI,CAAC;gBACH,IAAI,YAAY,EAAE,CAAC;oBACjB,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;wBACpD,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;wBACxB,IAAI,CAAC,GAAG,CAAC,CAAC;oBACZ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;oBAChC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBAClC,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBAC5D,CAAC;gBACD,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAC,qBAAqB,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;gBAClG,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;gBAC9D,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;gBACvC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;YACnD,CAAC;oBAAS,CAAC;gBACT,eAAe,CAAC,OAAO,EAAE,CAAC;gBAC1B,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;YAC5B,CAAC;YACD,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC;QACxG,CAAC,CAAC,CAAC;IACL,CAAC;IAED,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;QAEvD,GAAG,CAAC,KAAK,EAAE,CAAC;QACZ,GAAG,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,qBAAqB,EAAE,SAAS,EAAE,aAAa,EAAE,EAAE,OAAO,CAAC,CAAC;QACzF,GAAG,CAAC,WAAW,EAAE,CAAC;QAClB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;QAE9F,GAAG,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,sBAAsB,EAAE,SAAS,EAAE,aAAa,EAAE,EAAE,OAAO,CAAC,CAAC;QAC1F,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;IACjG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;QACpC,GAAG,CAAC,KAAK,EAAE,CAAC;QACZ,GAAG,CAAC,iBAAiB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAE1C,wGAAwG;QACxG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QAE3B,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;QAClD,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC;QAEtG,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACnB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2EAA2E,EAAE,GAAG,EAAE;QACnF,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;QACpC,GAAG,CAAC,KAAK,EAAE,CAAC;QACZ,GAAG,CAAC,iBAAiB,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC;QAEnD,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAE5D,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACnH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;QAC7E,MAAM,GAAG,GAAG,IAAI,qBAAqB,CAAC,MAAM,CAAC,CAAC;QAC9C,GAAG,CAAC,KAAK,EAAE,CAAC;QACZ,GAAG,CAAC,iBAAiB,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;QAEjD,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAE5D,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC;IAC/G,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n * See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Logger, OpenMode } from \"@itwin/core-bentley\";\r\nimport { expect } from \"chai\";\r\nimport * as sinon from \"sinon\";\r\nimport { EditTxnError } from \"@itwin/core-common\";\r\nimport { BackendLoggerCategory, EditTxn, type IModelDb, IModelJsFs, StandaloneDb, withEditTxn } from \"../../core-backend\";\r\nimport { _nativeDb } from \"../../internal/Symbols\";\r\nimport { IModelTestUtils } from \"../IModelTestUtils\";\r\n\r\nclass TestEditTxn extends EditTxn {\r\n public constructor(iModel: IModelDb) {\r\n super(iModel, \"test\");\r\n }\r\n\r\n public writeFileProperty(name: string, value: string | undefined): void {\r\n super.saveFileProperty({ name, namespace: \"EditTxnTest\" }, value);\r\n }\r\n}\r\n\r\nclass AbandonOnCloseEditTxn extends TestEditTxn {\r\n public override onClose(): void {\r\n if (this.isActive)\r\n this.abandonChanges();\r\n }\r\n}\r\n\r\nfunction expectEditTxnError(fn: () => void, key: EditTxnError.Key): void {\r\n expect(fn).to.throw().that.satisfies((error: unknown) => EditTxnError.isError(error, key));\r\n}\r\n\r\nfunction legacyWriteFileProperty(iModel: StandaloneDb, name: string, value: string): void {\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n iModel.saveFileProperty({ name, namespace: \"EditTxnTest\" }, value);\r\n}\r\n\r\ndescribe(\"EditTxn\", () => {\r\n let iModel: StandaloneDb;\r\n let fileName: string;\r\n\r\n beforeEach(() => {\r\n EditTxn.implicitWriteEnforcement = \"allow\";\r\n fileName = IModelTestUtils.prepareOutputFile(\"EditTxn\", \"EditTxn.bim\");\r\n iModel = StandaloneDb.createEmpty(fileName, {\r\n rootSubject: { name: \"EditTxn\" },\r\n enableTransactions: true,\r\n });\r\n });\r\n\r\n afterEach(() => {\r\n EditTxn.implicitWriteEnforcement = \"allow\";\r\n sinon.restore();\r\n\r\n if (iModel.isOpen)\r\n iModel.close();\r\n\r\n IModelJsFs.removeSync(fileName);\r\n });\r\n\r\n it(\"allows implicit writes before and after explicit txn scopes\", () => {\r\n // Implicit IModelDb mutators should work before any explicit EditTxn starts.\r\n legacyWriteFileProperty(iModel, \"legacy-before-start\", \"value\");\r\n expect(iModel.queryFilePropertyString({ name: \"legacy-before-start\", namespace: \"EditTxnTest\" })).to.equal(\"value\");\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n iModel.abandonChanges();\r\n\r\n const txn = new TestEditTxn(iModel);\r\n txn.start();\r\n expect(txn.isActive).to.be.true;\r\n\r\n txn.writeFileProperty(\"cancelled\", \"value\");\r\n txn.end(\"abandon\");\r\n // After canceling, implicit writes should still work.\r\n expect(txn.isActive).to.be.false;\r\n legacyWriteFileProperty(iModel, \"legacy-after-cancel\", \"value\");\r\n expect(iModel.queryFilePropertyString({ name: \"legacy-after-cancel\", namespace: \"EditTxnTest\" })).to.equal(\"value\");\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n iModel.abandonChanges();\r\n expect(iModel.queryFilePropertyString({ name: \"cancelled\", namespace: \"EditTxnTest\" })).to.be.undefined;\r\n\r\n txn.start();\r\n txn.writeFileProperty(\"saved\", \"value\");\r\n txn.end();\r\n // Committing also leaves the iModel ready for later implicit writes.\r\n expect(txn.isActive).to.be.false;\r\n expect(iModel.queryFilePropertyString({ name: \"saved\", namespace: \"EditTxnTest\" })).to.equal(\"value\");\r\n legacyWriteFileProperty(iModel, \"legacy-after-end\", \"value\");\r\n expect(iModel.queryFilePropertyString({ name: \"legacy-after-end\", namespace: \"EditTxnTest\" })).to.equal(\"value\");\r\n });\r\n\r\n it(\"enforces identical explicit transaction behavior across allow, log, and throw settings\", () => {\r\n const settings: Array<\"allow\" | \"log\" | \"throw\"> = [\"allow\", \"log\", \"throw\"];\r\n\r\n for (const setting of settings) {\r\n EditTxn.implicitWriteEnforcement = setting;\r\n const txn = new TestEditTxn(iModel);\r\n const inactiveName = `inactive-${setting}`;\r\n const savedName = `saved-${setting}`;\r\n const inactiveAgainName = `inactive-again-${setting}`;\r\n\r\n // Inactive explicit txn writes must always fail, regardless of enforcement.\r\n expectEditTxnError(() => txn.writeFileProperty(inactiveName, \"value\"), \"not-active\");\r\n expectEditTxnError(() => txn.saveChanges(`save ${inactiveName}`), \"not-active\");\r\n expect(iModel.queryFilePropertyString({ name: inactiveName, namespace: \"EditTxnTest\" })).to.be.undefined;\r\n expectEditTxnError(() => txn.end(\"abandon\"), \"not-active\");\r\n\r\n txn.start();\r\n txn.writeFileProperty(savedName, \"value\");\r\n txn.saveChanges(`save ${savedName}`);\r\n expect(txn.isActive).to.be.true;\r\n\r\n txn.end();\r\n expect(iModel.queryFilePropertyString({ name: savedName, namespace: \"EditTxnTest\" })).to.equal(\"value\");\r\n\r\n expectEditTxnError(() => txn.writeFileProperty(inactiveAgainName, \"value\"), \"not-active\");\r\n expectEditTxnError(() => txn.saveChanges(`save ${inactiveAgainName}`), \"not-active\");\r\n expect(iModel.queryFilePropertyString({ name: inactiveAgainName, namespace: \"EditTxnTest\" })).to.be.undefined;\r\n expectEditTxnError(() => txn.end(\"abandon\"), \"not-active\");\r\n }\r\n });\r\n\r\n it(\"logs implicit writes in log mode but still rejects inactive explicit writes\", () => {\r\n EditTxn.implicitWriteEnforcement = \"log\";\r\n const logError = sinon.spy(Logger, \"logError\");\r\n const txn = new TestEditTxn(iModel);\r\n\r\n legacyWriteFileProperty(iModel, \"implicit-log\", \"value\");\r\n expect(iModel.queryFilePropertyString({ name: \"implicit-log\", namespace: \"EditTxnTest\" })).to.equal(\"value\");\r\n expect(logError.called).to.be.true;\r\n expect(logError.firstCall.args[0]).to.equal(\"core-backend.IModelDb\");\r\n expect(EditTxnError.isError(logError.firstCall.args[1], \"implicit-txn-write-disallowed\")).to.be.true;\r\n\r\n const callCount = logError.callCount;\r\n expectEditTxnError(() => txn.writeFileProperty(\"inactive-log\", \"value\"), \"not-active\");\r\n expectEditTxnError(() => txn.saveChanges(\"save inactive log\"), \"not-active\");\r\n expect(logError.callCount).to.equal(callCount);\r\n expectEditTxnError(() => txn.end(\"abandon\"), \"not-active\");\r\n });\r\n\r\n it(\"rejects implicit writes in throw mode and still allows active explicit writes\", () => {\r\n EditTxn.implicitWriteEnforcement = \"throw\";\r\n\r\n expectEditTxnError(() => legacyWriteFileProperty(iModel, \"implicit-throw\", \"value\"), \"implicit-txn-write-disallowed\");\r\n expect(iModel.queryFilePropertyString({ name: \"implicit-throw\", namespace: \"EditTxnTest\" })).to.be.undefined;\r\n\r\n const txn = new TestEditTxn(iModel);\r\n txn.start();\r\n txn.writeFileProperty(\"explicit-enforce\", \"value\");\r\n txn.end();\r\n\r\n expect(iModel.queryFilePropertyString({ name: \"explicit-enforce\", namespace: \"EditTxnTest\" })).to.equal(\"value\");\r\n });\r\n\r\n it(\"throws when started with unsaved changes\", () => {\r\n // Unsaved changes made through the implicit surface block a new explicit EditTxn.\r\n legacyWriteFileProperty(iModel, \"unsaved\", \"value\");\r\n\r\n const txn = new TestEditTxn(iModel);\r\n expectEditTxnError(() => txn.start(), \"unsaved-changes\");\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n iModel.abandonChanges();\r\n legacyWriteFileProperty(iModel, \"legacy-after-abandon\", \"value\");\r\n expect(iModel.queryFilePropertyString({ name: \"legacy-after-abandon\", namespace: \"EditTxnTest\" })).to.equal(\"value\");\r\n });\r\n\r\n it(\"rejects starting an explicit txn while another explicit txn is active\", () => {\r\n const first = new TestEditTxn(iModel);\r\n const second = new TestEditTxn(iModel);\r\n\r\n first.start();\r\n expect(first.isActive).to.be.true;\r\n\r\n // EditTxn.start() now requires the implicit txn to be active, so a second explicit txn cannot start yet.\r\n expectEditTxnError(() => second.start(), \"already-active\");\r\n expect(first.isActive).to.be.true;\r\n expect(second.isActive).to.be.false;\r\n\r\n first.end(\"abandon\");\r\n expect(first.isActive).to.be.false;\r\n });\r\n\r\n it(\"allows deprecated mutating APIs while an explicit txn is active when enforcement is none\", () => {\r\n const txn = new TestEditTxn(iModel);\r\n txn.start();\r\n\r\n // Deprecated IModelDb mutators route through the implicit txn and are allowed in compatibility mode.\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n iModel.saveFileProperty({ name: \"legacy\", namespace: \"EditTxnTest\" }, \"value\");\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n iModel.saveChanges(\"legacy save\");\r\n expect(iModel.queryFilePropertyString({ name: \"legacy\", namespace: \"EditTxnTest\" })).to.equal(\"value\");\r\n\r\n txn.writeFileProperty(\"explicit\", \"value\");\r\n txn.saveChanges(\"explicit save\");\r\n expect(iModel.queryFilePropertyString({ name: \"explicit\", namespace: \"EditTxnTest\" })).to.equal(\"value\");\r\n\r\n txn.end(\"abandon\");\r\n expect(txn.isActive).to.be.false;\r\n });\r\n\r\n it(\"allows starting a new explicit txn when only pending changes exist\", () => {\r\n const first = new TestEditTxn(iModel);\r\n const second = new TestEditTxn(iModel);\r\n\r\n first.start();\r\n first.writeFileProperty(\"pending\", \"value\");\r\n first.saveChanges(\"save pending\");\r\n\r\n // Saved-but-unpushed changes are allowed; only unsaved local changes block start().\r\n expect(iModel.txns.hasPendingTxns).to.be.true;\r\n expect(iModel.txns.hasUnsavedChanges).to.be.false;\r\n\r\n first.end(\"abandon\");\r\n expect(() => second.start()).to.not.throw();\r\n expect(first.isActive).to.be.false;\r\n expect(second.isActive).to.be.true;\r\n\r\n second.end(\"abandon\");\r\n expect(second.isActive).to.be.false;\r\n });\r\n\r\n for (const mode of [\"save\", \"abandon\"] as const) {\r\n it(`retains transaction ownership when native ${mode} fails`, () => {\r\n const txn = new TestEditTxn(iModel);\r\n txn.start();\r\n txn.writeFileProperty(\"pending\", \"value\");\r\n const failure = new Error(`native ${mode} failed`);\r\n const nativeOperation = sinon.stub(iModel[_nativeDb], mode === \"save\" ? \"saveChanges\" : \"abandonChanges\").throws(failure);\r\n expect(() => txn.end(mode)).to.throw(failure);\r\n expect(txn.isActive).to.be.true;\r\n expect(iModel.txns.hasUnsavedChanges).to.be.true;\r\n nativeOperation.restore();\r\n txn.end(\"abandon\");\r\n expect(txn.isActive).to.be.false;\r\n expect(iModel.queryFilePropertyString({ name: \"pending\", namespace: \"EditTxnTest\" })).to.be.undefined;\r\n });\r\n }\r\n\r\n it(\"preserves the callback error and transaction ownership when scoped native abandonment fails\", () => {\r\n const failure = new Error(\"callback failure\");\r\n const abandonFailure = new Error(\"native abandonment failed\");\r\n const nativeOperation = sinon.stub(iModel[_nativeDb], \"abandonChanges\").throws(abandonFailure);\r\n const logError = sinon.spy(Logger, \"logError\");\r\n let activeTxn: EditTxn | undefined;\r\n expect(() => withEditTxn(iModel, (txn) => {\r\n activeTxn = txn;\r\n txn.saveFileProperty({ name: \"pending\", namespace: \"EditTxnTest\" }, \"value\");\r\n throw failure;\r\n })).to.throw(failure);\r\n expect(activeTxn?.isActive).to.be.true;\r\n expect(iModel.txns.hasUnsavedChanges).to.be.true;\r\n expect(logError.calledOnceWithExactly(BackendLoggerCategory.IModelDb, abandonFailure)).to.be.true;\r\n nativeOperation.restore();\r\n activeTxn?.end(\"abandon\");\r\n expect(iModel.queryFilePropertyString({ name: \"pending\", namespace: \"EditTxnTest\" })).to.be.undefined;\r\n });\r\n\r\n for (const asynchronous of [false, true]) {\r\n it(`preserves the ${asynchronous ? \"asynchronous\" : \"synchronous\"} callback error when rollback and error logging both fail`, async () => {\r\n const failure = new Error(\"callback failure\");\r\n const abandonFailure = new Error(\"native abandonment failed\");\r\n const loggingFailure = new Error(\"error logging failed\");\r\n const nativeOperation = sinon.stub(iModel[_nativeDb], \"abandonChanges\").throws(abandonFailure);\r\n const logError = sinon.stub(Logger, \"logError\").throws(loggingFailure);\r\n let activeTxn: EditTxn | undefined;\r\n const edit = (txn: EditTxn) => {\r\n activeTxn = txn;\r\n txn.saveFileProperty({ name: \"pending\", namespace: \"EditTxnTest\" }, \"value\");\r\n throw failure;\r\n };\r\n try {\r\n if (asynchronous) {\r\n const error = await withEditTxn(iModel, async (txn) => {\r\n await Promise.resolve();\r\n edit(txn);\r\n }).catch((err: unknown) => err);\r\n expect(error).to.equal(failure);\r\n } else {\r\n expect(() => withEditTxn(iModel, edit)).to.throw(failure);\r\n }\r\n expect(logError.calledOnceWithExactly(BackendLoggerCategory.IModelDb, abandonFailure)).to.be.true;\r\n expect(logError.firstCall.exception).to.equal(loggingFailure);\r\n expect(activeTxn?.isActive).to.be.true;\r\n expect(iModel.txns.hasUnsavedChanges).to.be.true;\r\n } finally {\r\n nativeOperation.restore();\r\n activeTxn?.end(\"abandon\");\r\n }\r\n expect(iModel.queryFilePropertyString({ name: \"pending\", namespace: \"EditTxnTest\" })).to.be.undefined;\r\n });\r\n }\r\n\r\n it(\"uses the default description unless save is given an override\", () => {\r\n const txn = new EditTxn(iModel, \"default description\");\r\n\r\n txn.start();\r\n txn.saveFileProperty({ name: \"default-description\", namespace: \"EditTxnTest\" }, \"value\");\r\n txn.saveChanges();\r\n expect(iModel.txns.getLastSavedTxnProps()?.props.description).to.equal(\"default description\");\r\n\r\n txn.saveFileProperty({ name: \"override-description\", namespace: \"EditTxnTest\" }, \"value\");\r\n txn.end(\"save\", \"override description\");\r\n expect(iModel.txns.getLastSavedTxnProps()?.props.description).to.equal(\"override description\");\r\n });\r\n\r\n it(\"reverseTxns abandons unsaved changes from the active explicit txn\", () => {\r\n const txn = new TestEditTxn(iModel);\r\n txn.start();\r\n txn.writeFileProperty(\"reverse\", \"value\");\r\n\r\n // Reversing txns abandons the active explicit txn's local changes, but the explicit txn remains active.\r\n iModel.txns.reverseTxns(1);\r\n\r\n expect(txn.isActive).to.be.true;\r\n expect(iModel.txns.hasUnsavedChanges).to.be.false;\r\n expect(iModel.queryFilePropertyString({ name: \"reverse\", namespace: \"EditTxnTest\" })).to.be.undefined;\r\n\r\n txn.end(\"abandon\");\r\n expect(txn.isActive).to.be.false;\r\n });\r\n\r\n it(\"saves unsaved changes from the active explicit txn when the iModel closes\", () => {\r\n const txn = new TestEditTxn(iModel);\r\n txn.start();\r\n txn.writeFileProperty(\"unsaved-on-close\", \"value\");\r\n\r\n iModel.close();\r\n iModel = StandaloneDb.openFile(fileName, OpenMode.Readonly);\r\n\r\n expect(iModel.queryFilePropertyString({ name: \"unsaved-on-close\", namespace: \"EditTxnTest\" })).to.equal(\"value\");\r\n });\r\n\r\n it(\"allows subclasses to abandon unsaved changes when the iModel closes\", () => {\r\n const txn = new AbandonOnCloseEditTxn(iModel);\r\n txn.start();\r\n txn.writeFileProperty(\"saved-on-close\", \"value\");\r\n\r\n iModel.close();\r\n iModel = StandaloneDb.openFile(fileName, OpenMode.Readonly);\r\n\r\n expect(iModel.queryFilePropertyString({ name: \"saved-on-close\", namespace: \"EditTxnTest\" })).to.be.undefined;\r\n });\r\n});\r\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=GeoCoordConfig.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GeoCoordConfig.test.d.ts","sourceRoot":"","sources":["../../../../src/test/standalone/GeoCoordConfig.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,158 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
+ * See LICENSE.md in the project root for license terms and full copyright notice.
4
+ *--------------------------------------------------------------------------------------------*/
5
+ import { expect } from "chai";
6
+ import * as sinon from "sinon";
7
+ import { Logger } from "@itwin/core-bentley";
8
+ import { CloudSqlite, GeoCoordConfig, IModelHost } from "../../core-backend";
9
+ import { IModelNative } from "../../internal/NativePlatform";
10
+ import { constructWorkspace } from "../../internal/workspace/WorkspaceImpl";
11
+ import { SettingsImpl } from "../../internal/workspace/SettingsImpl";
12
+ import { SettingsPriority } from "../../workspace/Settings";
13
+ import { TestUtils } from "../TestUtils";
14
+ describe("GeoCoordConfig", () => {
15
+ const dbProps = { baseUri: "", storageType: "azure", containerId: "gcs-retry-test", dbName: "vertical", prefetch: true };
16
+ const sandbox = sinon.createSandbox();
17
+ let getContainer;
18
+ let getArray;
19
+ let getBoolean;
20
+ let queryDatabase;
21
+ let addWorkspace;
22
+ let prefetch;
23
+ let logError;
24
+ let connected;
25
+ beforeEach(() => {
26
+ GeoCoordConfig.onStartup();
27
+ const workspace = IModelHost.appWorkspace;
28
+ const container = workspace.getContainer({ ...dbProps, accessToken: "" });
29
+ connected = true;
30
+ queryDatabase = sandbox.stub().returns({ totalBlocks: 10, localBlocks: 0 });
31
+ sandbox.stub(container, "cloudContainer").get(() => ({ isConnected: connected, queryDatabase }));
32
+ sandbox.stub(container, "resolveDbFileName").callsFake((props) => `${props.dbName}:1.0.0`);
33
+ getContainer = sandbox.stub(workspace, "getContainer").returns(container);
34
+ getArray = sandbox.stub(workspace.settings, "getArray").returns([dbProps]);
35
+ getBoolean = sandbox.stub(workspace.settings, "getBoolean").returns(false);
36
+ addWorkspace = sandbox.stub().returns(true);
37
+ const nativePlatform = { ...IModelNative.platform, addGcsWorkspaceDb: addWorkspace };
38
+ sandbox.stub(IModelNative, "platform").get(() => nativePlatform);
39
+ prefetch = sandbox.stub(CloudSqlite, "startCloudPrefetch").callsFake((cloudContainer, dbName) => ({
40
+ cloudContainer, dbName, promise: Promise.resolve(true), cancel: () => undefined,
41
+ }));
42
+ logError = sandbox.stub(Logger, "logError");
43
+ });
44
+ afterEach(() => {
45
+ sandbox.restore();
46
+ GeoCoordConfig.onStartup();
47
+ TestUtils.disableGcsWorkspaces();
48
+ });
49
+ function expectRetryToSucceed() {
50
+ GeoCoordConfig.loadDefaultDatabases();
51
+ expect(getContainer.callCount).to.equal(2);
52
+ expect(prefetch.callCount).to.equal(1);
53
+ expect(GeoCoordConfig.prefetches).to.have.lengthOf(1);
54
+ GeoCoordConfig.loadDefaultDatabases();
55
+ expect(getContainer.callCount).to.equal(2);
56
+ }
57
+ it("retries after a container load throws", () => {
58
+ getContainer.onFirstCall().throws(new Error("temporary container failure"));
59
+ GeoCoordConfig.loadDefaultDatabases();
60
+ expect(logError.calledOnce).to.be.true;
61
+ expect(addWorkspace.called).to.be.false;
62
+ expectRetryToSucceed();
63
+ });
64
+ it("retries after a disconnected container", () => {
65
+ connected = false;
66
+ GeoCoordConfig.loadDefaultDatabases();
67
+ expect(logError.calledOnce).to.be.true;
68
+ expect(addWorkspace.called).to.be.false;
69
+ connected = true;
70
+ expectRetryToSucceed();
71
+ });
72
+ it("retries after a missing database", () => {
73
+ queryDatabase.onFirstCall().returns(undefined);
74
+ GeoCoordConfig.loadDefaultDatabases();
75
+ expect(logError.calledOnce).to.be.true;
76
+ expect(addWorkspace.called).to.be.false;
77
+ expectRetryToSucceed();
78
+ });
79
+ it("recovers a failed initial cloud connection through the real workspace cache", () => {
80
+ const workspace = constructWorkspace(new SettingsImpl());
81
+ const sharedWorkspace = constructWorkspace(new SettingsImpl());
82
+ const props = { ...dbProps, baseUri: "https://example.invalid", containerId: "gcs-initial-connect-retry", isPublic: true, priority: 42 };
83
+ workspace.settings.addDictionary({ name: "gcs connection retry", priority: SettingsPriority.application }, {
84
+ [GeoCoordConfig.settingName.disableWorkspaces]: false,
85
+ [GeoCoordConfig.settingName.defaultDatabases]: [props],
86
+ });
87
+ sandbox.stub(IModelHost, "appWorkspace").get(() => workspace);
88
+ const cloud = CloudSqlite.createCloudContainer({ ...props, accessToken: "" });
89
+ let isConnected = false;
90
+ const connect = sandbox.stub().callsFake(() => { isConnected = true; });
91
+ connect.onFirstCall().throws(new Error("temporary cloud connection failure"));
92
+ const disconnect = sandbox.stub().callsFake(() => { isConnected = false; });
93
+ Object.defineProperties(cloud, {
94
+ isConnected: { get: () => isConnected },
95
+ connect: { value: connect },
96
+ disconnect: { value: disconnect },
97
+ checkForChanges: { value: sandbox.stub() },
98
+ queryDatabases: { value: sandbox.stub().returns(["vertical:1.0.0"]) },
99
+ queryDatabase: { value: sandbox.stub().returns({ totalBlocks: 10, localBlocks: 0, dirtyBlocks: 0, transactions: false, state: "", nClient: 0, nPrefetch: 0 }) },
100
+ });
101
+ sandbox.stub(CloudSqlite, "createCloudContainer").returns(cloud);
102
+ try {
103
+ GeoCoordConfig.loadDefaultDatabases();
104
+ expect(logError.calledOnce).to.be.true;
105
+ expect(addWorkspace.called).to.be.false;
106
+ expect(workspace.findContainer(props.containerId)).to.be.undefined;
107
+ GeoCoordConfig.loadDefaultDatabases();
108
+ expect(connect.callCount).to.equal(2);
109
+ expect(addWorkspace.callCount, JSON.stringify(logError.args)).to.equal(1);
110
+ expect(addWorkspace.firstCall.args).to.deep.equal(["vertical:1.0.0", cloud, props.priority]);
111
+ expect(prefetch.calledOnce).to.be.true;
112
+ const container = workspace.findContainer(props.containerId);
113
+ expect(container?.cloudContainer).to.equal(cloud);
114
+ expect(sharedWorkspace.getContainer({ ...props, accessToken: "" }).cloudContainer).to.equal(cloud);
115
+ expect(connect.callCount).to.equal(2);
116
+ GeoCoordConfig.loadDefaultDatabases();
117
+ expect(addWorkspace.calledOnce).to.be.true;
118
+ }
119
+ finally {
120
+ try {
121
+ sharedWorkspace.close();
122
+ expect(disconnect.called).to.be.false;
123
+ }
124
+ finally {
125
+ workspace.close();
126
+ }
127
+ }
128
+ expect(disconnect.calledOnce).to.be.true;
129
+ });
130
+ it("attempts every database and accepts already registered databases on retry", () => {
131
+ getArray.returns([dbProps, { ...dbProps, dbName: "horizontal" }]);
132
+ queryDatabase.onFirstCall().returns(undefined);
133
+ addWorkspace.onSecondCall().returns(true);
134
+ addWorkspace.onThirdCall().returns(false);
135
+ GeoCoordConfig.loadDefaultDatabases();
136
+ expect(getContainer.callCount).to.equal(2);
137
+ expect(addWorkspace.calledOnceWithExactly("horizontal:1.0.0", sinon.match.object, undefined)).to.be.true;
138
+ expect(logError.calledOnce).to.be.true;
139
+ GeoCoordConfig.loadDefaultDatabases();
140
+ expect(getContainer.callCount).to.equal(4);
141
+ expect(addWorkspace.callCount).to.equal(3);
142
+ expect(prefetch.callCount).to.equal(2);
143
+ expect(GeoCoordConfig.prefetches).to.have.lengthOf(2);
144
+ GeoCoordConfig.loadDefaultDatabases();
145
+ expect(getContainer.callCount).to.equal(4);
146
+ });
147
+ it("loads defaults after workspaces are re-enabled", () => {
148
+ getBoolean.returns(true);
149
+ GeoCoordConfig.loadDefaultDatabases();
150
+ expect(getContainer.called).to.be.false;
151
+ getBoolean.returns(false);
152
+ GeoCoordConfig.loadDefaultDatabases();
153
+ expect(addWorkspace.calledOnce).to.be.true;
154
+ GeoCoordConfig.loadDefaultDatabases();
155
+ expect(addWorkspace.calledOnce).to.be.true;
156
+ });
157
+ });
158
+ //# sourceMappingURL=GeoCoordConfig.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GeoCoordConfig.test.js","sourceRoot":"","sources":["../../../../src/test/standalone/GeoCoordConfig.test.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n\r\nimport { expect } from \"chai\";\r\nimport * as sinon from \"sinon\";\r\nimport { Logger } from \"@itwin/core-bentley\";\r\nimport { CloudSqlite, GcsDbProps, GeoCoordConfig, IModelHost } from \"../../core-backend\";\r\nimport { IModelNative } from \"../../internal/NativePlatform\";\r\nimport { constructWorkspace } from \"../../internal/workspace/WorkspaceImpl\";\r\nimport { SettingsImpl } from \"../../internal/workspace/SettingsImpl\";\r\nimport { SettingsPriority } from \"../../workspace/Settings\";\r\nimport { TestUtils } from \"../TestUtils\";\r\n\r\ndescribe(\"GeoCoordConfig\", () => {\r\n const dbProps: GcsDbProps = { baseUri: \"\", storageType: \"azure\", containerId: \"gcs-retry-test\", dbName: \"vertical\", prefetch: true };\r\n const sandbox = sinon.createSandbox();\r\n let getContainer: sinon.SinonStub;\r\n let getArray: sinon.SinonStub;\r\n let getBoolean: sinon.SinonStub;\r\n let queryDatabase: sinon.SinonStub;\r\n let addWorkspace: sinon.SinonStub;\r\n let prefetch: sinon.SinonStub;\r\n let logError: sinon.SinonStub;\r\n let connected: boolean;\r\n\r\n beforeEach(() => {\r\n GeoCoordConfig.onStartup();\r\n const workspace = IModelHost.appWorkspace;\r\n const container = workspace.getContainer({ ...dbProps, accessToken: \"\" });\r\n connected = true;\r\n queryDatabase = sandbox.stub().returns({ totalBlocks: 10, localBlocks: 0 });\r\n sandbox.stub(container, \"cloudContainer\").get(() => ({ isConnected: connected, queryDatabase }));\r\n sandbox.stub(container, \"resolveDbFileName\").callsFake((props) => `${props.dbName}:1.0.0`);\r\n getContainer = sandbox.stub(workspace, \"getContainer\").returns(container);\r\n getArray = sandbox.stub(workspace.settings, \"getArray\").returns([dbProps]);\r\n getBoolean = sandbox.stub(workspace.settings, \"getBoolean\").returns(false);\r\n addWorkspace = sandbox.stub().returns(true);\r\n const nativePlatform = { ...IModelNative.platform, addGcsWorkspaceDb: addWorkspace };\r\n sandbox.stub(IModelNative, \"platform\").get(() => nativePlatform);\r\n prefetch = sandbox.stub(CloudSqlite, \"startCloudPrefetch\").callsFake((cloudContainer, dbName) => ({\r\n cloudContainer, dbName, promise: Promise.resolve(true), cancel: () => undefined,\r\n }));\r\n logError = sandbox.stub(Logger, \"logError\");\r\n });\r\n\r\n afterEach(() => {\r\n sandbox.restore();\r\n GeoCoordConfig.onStartup();\r\n TestUtils.disableGcsWorkspaces();\r\n });\r\n\r\n function expectRetryToSucceed() {\r\n GeoCoordConfig.loadDefaultDatabases();\r\n expect(getContainer.callCount).to.equal(2);\r\n expect(prefetch.callCount).to.equal(1);\r\n expect(GeoCoordConfig.prefetches).to.have.lengthOf(1);\r\n GeoCoordConfig.loadDefaultDatabases();\r\n expect(getContainer.callCount).to.equal(2);\r\n }\r\n\r\n it(\"retries after a container load throws\", () => {\r\n getContainer.onFirstCall().throws(new Error(\"temporary container failure\"));\r\n GeoCoordConfig.loadDefaultDatabases();\r\n expect(logError.calledOnce).to.be.true;\r\n expect(addWorkspace.called).to.be.false;\r\n expectRetryToSucceed();\r\n });\r\n\r\n it(\"retries after a disconnected container\", () => {\r\n connected = false;\r\n GeoCoordConfig.loadDefaultDatabases();\r\n expect(logError.calledOnce).to.be.true;\r\n expect(addWorkspace.called).to.be.false;\r\n connected = true;\r\n expectRetryToSucceed();\r\n });\r\n\r\n it(\"retries after a missing database\", () => {\r\n queryDatabase.onFirstCall().returns(undefined);\r\n GeoCoordConfig.loadDefaultDatabases();\r\n expect(logError.calledOnce).to.be.true;\r\n expect(addWorkspace.called).to.be.false;\r\n expectRetryToSucceed();\r\n });\r\n\r\n it(\"recovers a failed initial cloud connection through the real workspace cache\", () => {\r\n const workspace = constructWorkspace(new SettingsImpl());\r\n const sharedWorkspace = constructWorkspace(new SettingsImpl());\r\n const props = { ...dbProps, baseUri: \"https://example.invalid\", containerId: \"gcs-initial-connect-retry\", isPublic: true, priority: 42 };\r\n workspace.settings.addDictionary({ name: \"gcs connection retry\", priority: SettingsPriority.application }, {\r\n [GeoCoordConfig.settingName.disableWorkspaces]: false,\r\n [GeoCoordConfig.settingName.defaultDatabases]: [props],\r\n });\r\n sandbox.stub(IModelHost, \"appWorkspace\").get(() => workspace);\r\n const cloud = CloudSqlite.createCloudContainer({ ...props, accessToken: \"\" });\r\n let isConnected = false;\r\n const connect = sandbox.stub().callsFake(() => { isConnected = true; });\r\n connect.onFirstCall().throws(new Error(\"temporary cloud connection failure\"));\r\n const disconnect = sandbox.stub().callsFake(() => { isConnected = false; });\r\n Object.defineProperties(cloud, {\r\n isConnected: { get: () => isConnected },\r\n connect: { value: connect },\r\n disconnect: { value: disconnect },\r\n checkForChanges: { value: sandbox.stub() },\r\n queryDatabases: { value: sandbox.stub().returns([\"vertical:1.0.0\"]) },\r\n queryDatabase: { value: sandbox.stub().returns({ totalBlocks: 10, localBlocks: 0, dirtyBlocks: 0, transactions: false, state: \"\", nClient: 0, nPrefetch: 0 }) },\r\n });\r\n sandbox.stub(CloudSqlite, \"createCloudContainer\").returns(cloud);\r\n try {\r\n GeoCoordConfig.loadDefaultDatabases();\r\n expect(logError.calledOnce).to.be.true;\r\n expect(addWorkspace.called).to.be.false;\r\n expect(workspace.findContainer(props.containerId)).to.be.undefined;\r\n GeoCoordConfig.loadDefaultDatabases();\r\n expect(connect.callCount).to.equal(2);\r\n expect(addWorkspace.callCount, JSON.stringify(logError.args)).to.equal(1);\r\n expect(addWorkspace.firstCall.args).to.deep.equal([\"vertical:1.0.0\", cloud, props.priority]);\r\n expect(prefetch.calledOnce).to.be.true;\r\n const container = workspace.findContainer(props.containerId);\r\n expect(container?.cloudContainer).to.equal(cloud);\r\n expect(sharedWorkspace.getContainer({ ...props, accessToken: \"\" }).cloudContainer).to.equal(cloud);\r\n expect(connect.callCount).to.equal(2);\r\n GeoCoordConfig.loadDefaultDatabases();\r\n expect(addWorkspace.calledOnce).to.be.true;\r\n } finally {\r\n try {\r\n sharedWorkspace.close();\r\n expect(disconnect.called).to.be.false;\r\n } finally {\r\n workspace.close();\r\n }\r\n }\r\n expect(disconnect.calledOnce).to.be.true;\r\n });\r\n\r\n it(\"attempts every database and accepts already registered databases on retry\", () => {\r\n getArray.returns([dbProps, { ...dbProps, dbName: \"horizontal\" }]);\r\n queryDatabase.onFirstCall().returns(undefined);\r\n addWorkspace.onSecondCall().returns(true);\r\n addWorkspace.onThirdCall().returns(false);\r\n GeoCoordConfig.loadDefaultDatabases();\r\n expect(getContainer.callCount).to.equal(2);\r\n expect(addWorkspace.calledOnceWithExactly(\"horizontal:1.0.0\", sinon.match.object, undefined)).to.be.true;\r\n expect(logError.calledOnce).to.be.true;\r\n GeoCoordConfig.loadDefaultDatabases();\r\n expect(getContainer.callCount).to.equal(4);\r\n expect(addWorkspace.callCount).to.equal(3);\r\n expect(prefetch.callCount).to.equal(2);\r\n expect(GeoCoordConfig.prefetches).to.have.lengthOf(2);\r\n GeoCoordConfig.loadDefaultDatabases();\r\n expect(getContainer.callCount).to.equal(4);\r\n });\r\n\r\n it(\"loads defaults after workspaces are re-enabled\", () => {\r\n getBoolean.returns(true);\r\n GeoCoordConfig.loadDefaultDatabases();\r\n expect(getContainer.called).to.be.false;\r\n getBoolean.returns(false);\r\n GeoCoordConfig.loadDefaultDatabases();\r\n expect(addWorkspace.calledOnce).to.be.true;\r\n GeoCoordConfig.loadDefaultDatabases();\r\n expect(addWorkspace.calledOnce).to.be.true;\r\n });\r\n});\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itwin/core-backend",
3
- "version": "5.15.0-dev.16",
3
+ "version": "5.15.0-dev.18",
4
4
  "description": "iTwin.js backend components",
5
5
  "main": "lib/cjs/core-backend.js",
6
6
  "module": "lib/esm/core-backend.js",
@@ -27,11 +27,11 @@
27
27
  },
28
28
  "peerDependencies": {
29
29
  "@opentelemetry/api": "^1.0.4",
30
- "@itwin/core-bentley": "5.15.0-dev.16",
31
- "@itwin/core-quantity": "5.15.0-dev.16",
32
- "@itwin/core-geometry": "5.15.0-dev.16",
33
- "@itwin/core-common": "5.15.0-dev.16",
34
- "@itwin/ecschema-metadata": "5.15.0-dev.16"
30
+ "@itwin/core-bentley": "5.15.0-dev.18",
31
+ "@itwin/core-quantity": "5.15.0-dev.18",
32
+ "@itwin/core-common": "5.15.0-dev.18",
33
+ "@itwin/core-geometry": "5.15.0-dev.18",
34
+ "@itwin/ecschema-metadata": "5.15.0-dev.18"
35
35
  },
36
36
  "peerDependenciesMeta": {
37
37
  "@opentelemetry/api": {
@@ -72,15 +72,15 @@
72
72
  "marked": "^14.1.3",
73
73
  "sql-formatter": "^15.4.6",
74
74
  "vite": "^6.4.4",
75
- "@itwin/core-geometry": "5.15.0-dev.16",
76
- "@itwin/core-quantity": "5.15.0-dev.16",
77
- "@itwin/build-tools": "5.15.0-dev.16",
78
- "@itwin/core-common": "5.15.0-dev.16",
79
- "@itwin/core-bentley": "5.15.0-dev.16",
80
- "@itwin/ecschema-metadata": "5.15.0-dev.16",
75
+ "@itwin/core-geometry": "5.15.0-dev.18",
76
+ "@itwin/core-common": "5.15.0-dev.18",
77
+ "@itwin/build-tools": "5.15.0-dev.18",
78
+ "@itwin/ecschema-locaters": "5.15.0-dev.18",
79
+ "@itwin/core-bentley": "5.15.0-dev.18",
80
+ "@itwin/core-quantity": "5.15.0-dev.18",
81
+ "@itwin/ecsql-common": "5.15.0-dev.18",
81
82
  "internal-tools": "3.0.0-dev.69",
82
- "@itwin/ecsql-common": "5.15.0-dev.16",
83
- "@itwin/ecschema-locaters": "5.15.0-dev.16"
83
+ "@itwin/ecschema-metadata": "5.15.0-dev.18"
84
84
  },
85
85
  "dependencies": {
86
86
  "@bentley/imodeljs-native": "5.15.32",