@api-client/core 0.18.47 → 0.18.49

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 (33) hide show
  1. package/build/src/mocking/ModelingMock.d.ts +2 -0
  2. package/build/src/mocking/ModelingMock.d.ts.map +1 -1
  3. package/build/src/mocking/ModelingMock.js +2 -0
  4. package/build/src/mocking/ModelingMock.js.map +1 -1
  5. package/build/src/mocking/lib/File.d.ts +1 -0
  6. package/build/src/mocking/lib/File.d.ts.map +1 -1
  7. package/build/src/mocking/lib/File.js +1 -0
  8. package/build/src/mocking/lib/File.js.map +1 -1
  9. package/build/src/mocking/lib/Permission.d.ts +35 -0
  10. package/build/src/mocking/lib/Permission.d.ts.map +1 -0
  11. package/build/src/mocking/lib/Permission.js +89 -0
  12. package/build/src/mocking/lib/Permission.js.map +1 -0
  13. package/build/src/modeling/ApiModel.d.ts +12 -4
  14. package/build/src/modeling/ApiModel.d.ts.map +1 -1
  15. package/build/src/modeling/ApiModel.js +76 -31
  16. package/build/src/modeling/ApiModel.js.map +1 -1
  17. package/build/src/modeling/ExposedEntity.d.ts +9 -0
  18. package/build/src/modeling/ExposedEntity.d.ts.map +1 -1
  19. package/build/src/modeling/ExposedEntity.js +23 -0
  20. package/build/src/modeling/ExposedEntity.js.map +1 -1
  21. package/build/tsconfig.tsbuildinfo +1 -1
  22. package/data/models/example-generator-api.json +9 -9
  23. package/package.json +3 -3
  24. package/src/mocking/ModelingMock.ts +2 -0
  25. package/src/mocking/lib/File.ts +1 -0
  26. package/src/mocking/lib/Permission.ts +100 -0
  27. package/src/modeling/ApiModel.ts +82 -37
  28. package/src/modeling/ExposedEntity.ts +28 -0
  29. package/tests/unit/mocking/current/Permission.spec.ts +285 -0
  30. package/tests/unit/modeling/api_model.spec.ts +20 -0
  31. package/tests/unit/modeling/api_model_expose_entity.spec.ts +25 -0
  32. package/tests/unit/modeling/api_model_remove_entity.spec.ts +17 -10
  33. package/tests/unit/modeling/exposed_entity_setter_validation.spec.ts +107 -0
@@ -7,6 +7,7 @@ import { Invitation } from './lib/Invitation.js';
7
7
  import { Trash } from './lib/Trash.js';
8
8
  import { Patch } from './lib/Patch.js';
9
9
  import { DataCatalog } from './lib/DataCatalog.js';
10
+ import { Permission } from './lib/Permission.js';
10
11
  export declare class ModelingMock {
11
12
  faker: Faker;
12
13
  organization: Organization;
@@ -17,5 +18,6 @@ export declare class ModelingMock {
17
18
  trash: Trash;
18
19
  patch: Patch;
19
20
  dataCatalog: DataCatalog;
21
+ permission: Permission;
20
22
  }
21
23
  //# sourceMappingURL=ModelingMock.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ModelingMock.d.ts","sourceRoot":"","sources":["../../../src/mocking/ModelingMock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,KAAK,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAElD,qBAAa,YAAY;IACvB,KAAK,EAAE,KAAK,CAAQ;IACpB,YAAY,eAAqB;IACjC,KAAK,QAAc;IACnB,KAAK,OAAa;IAClB,KAAK,OAAa;IAClB,UAAU,aAAmB;IAC7B,KAAK,QAAc;IACnB,KAAK,QAAc;IACnB,WAAW,cAAoB;CAChC"}
1
+ {"version":3,"file":"ModelingMock.d.ts","sourceRoot":"","sources":["../../../src/mocking/ModelingMock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,KAAK,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAEhD,qBAAa,YAAY;IACvB,KAAK,EAAE,KAAK,CAAQ;IACpB,YAAY,eAAqB;IACjC,KAAK,QAAc;IACnB,KAAK,OAAa;IAClB,KAAK,OAAa;IAClB,UAAU,aAAmB;IAC7B,KAAK,QAAc;IACnB,KAAK,QAAc;IACnB,WAAW,cAAoB;IAC/B,UAAU,aAAmB;CAC9B"}
@@ -7,6 +7,7 @@ import { Invitation } from './lib/Invitation.js';
7
7
  import { Trash } from './lib/Trash.js';
8
8
  import { Patch } from './lib/Patch.js';
9
9
  import { DataCatalog } from './lib/DataCatalog.js';
10
+ import { Permission } from './lib/Permission.js';
10
11
  export class ModelingMock {
11
12
  faker = faker;
12
13
  organization = new Organization();
@@ -17,5 +18,6 @@ export class ModelingMock {
17
18
  trash = new Trash();
18
19
  patch = new Patch();
19
20
  dataCatalog = new DataCatalog();
21
+ permission = new Permission();
20
22
  }
21
23
  //# sourceMappingURL=ModelingMock.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ModelingMock.js","sourceRoot":"","sources":["../../../src/mocking/ModelingMock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAc,MAAM,iBAAiB,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAElD,MAAM,OAAO,YAAY;IACvB,KAAK,GAAU,KAAK,CAAA;IACpB,YAAY,GAAG,IAAI,YAAY,EAAE,CAAA;IACjC,KAAK,GAAG,IAAI,KAAK,EAAE,CAAA;IACnB,KAAK,GAAG,IAAI,IAAI,EAAE,CAAA;IAClB,KAAK,GAAG,IAAI,IAAI,EAAE,CAAA;IAClB,UAAU,GAAG,IAAI,UAAU,EAAE,CAAA;IAC7B,KAAK,GAAG,IAAI,KAAK,EAAE,CAAA;IACnB,KAAK,GAAG,IAAI,KAAK,EAAE,CAAA;IACnB,WAAW,GAAG,IAAI,WAAW,EAAE,CAAA;CAChC","sourcesContent":["import { faker, type Faker } from '@faker-js/faker'\nimport { Organization } from './lib/Organization.js'\nimport { Group } from './lib/Group.js'\nimport { User } from './lib/User.js'\nimport { File } from './lib/File.js'\nimport { Invitation } from './lib/Invitation.js'\nimport { Trash } from './lib/Trash.js'\nimport { Patch } from './lib/Patch.js'\nimport { DataCatalog } from './lib/DataCatalog.js'\n\nexport class ModelingMock {\n faker: Faker = faker\n organization = new Organization()\n group = new Group()\n users = new User()\n files = new File()\n invitation = new Invitation()\n trash = new Trash()\n patch = new Patch()\n dataCatalog = new DataCatalog()\n}\n"]}
1
+ {"version":3,"file":"ModelingMock.js","sourceRoot":"","sources":["../../../src/mocking/ModelingMock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAc,MAAM,iBAAiB,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAEhD,MAAM,OAAO,YAAY;IACvB,KAAK,GAAU,KAAK,CAAA;IACpB,YAAY,GAAG,IAAI,YAAY,EAAE,CAAA;IACjC,KAAK,GAAG,IAAI,KAAK,EAAE,CAAA;IACnB,KAAK,GAAG,IAAI,IAAI,EAAE,CAAA;IAClB,KAAK,GAAG,IAAI,IAAI,EAAE,CAAA;IAClB,UAAU,GAAG,IAAI,UAAU,EAAE,CAAA;IAC7B,KAAK,GAAG,IAAI,KAAK,EAAE,CAAA;IACnB,KAAK,GAAG,IAAI,KAAK,EAAE,CAAA;IACnB,WAAW,GAAG,IAAI,WAAW,EAAE,CAAA;IAC/B,UAAU,GAAG,IAAI,UAAU,EAAE,CAAA;CAC9B","sourcesContent":["import { faker, type Faker } from '@faker-js/faker'\nimport { Organization } from './lib/Organization.js'\nimport { Group } from './lib/Group.js'\nimport { User } from './lib/User.js'\nimport { File } from './lib/File.js'\nimport { Invitation } from './lib/Invitation.js'\nimport { Trash } from './lib/Trash.js'\nimport { Patch } from './lib/Patch.js'\nimport { DataCatalog } from './lib/DataCatalog.js'\nimport { Permission } from './lib/Permission.js'\n\nexport class ModelingMock {\n faker: Faker = faker\n organization = new Organization()\n group = new Group()\n users = new User()\n files = new File()\n invitation = new Invitation()\n trash = new Trash()\n patch = new Patch()\n dataCatalog = new DataCatalog()\n permission = new Permission()\n}\n"]}
@@ -2,6 +2,7 @@ import { type IFile, type FileBreadcrumb } from '../../models/store/File.js';
2
2
  export declare class File {
3
3
  /**
4
4
  * Generates a random file object.
5
+ * Note that this generator doesn't create the permissions object. Use Permission class for that.
5
6
  * @param init Optional values to be present in the object.
6
7
  * @returns Random file
7
8
  */
@@ -1 +1 @@
1
- {"version":3,"file":"File.d.ts","sourceRoot":"","sources":["../../../../src/mocking/lib/File.ts"],"names":[],"mappings":"AAEA,OAAO,EAAoB,KAAK,KAAK,EAAE,KAAK,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAG9F,qBAAa,IAAI;IACf;;;;OAIG;IACH,IAAI,CAAC,IAAI,GAAE,OAAO,CAAC,KAAK,CAAM,GAAG,KAAK;IAQtC;;;;OAIG;IACH,KAAK,CAAC,IAAI,SAAK,GAAG,KAAK,EAAE;IAQzB;;;;OAIG;IACH,MAAM,CAAC,IAAI,GAAE,OAAO,CAAC,KAAK,CAAM,GAAG,KAAK;IAIxC;;;;OAIG;IACH,OAAO,CAAC,IAAI,SAAK,GAAG,KAAK,EAAE;IAQ3B;;;;OAIG;IACH,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,cAAc,EAAE;CAYjD"}
1
+ {"version":3,"file":"File.d.ts","sourceRoot":"","sources":["../../../../src/mocking/lib/File.ts"],"names":[],"mappings":"AAEA,OAAO,EAAoB,KAAK,KAAK,EAAE,KAAK,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAG9F,qBAAa,IAAI;IACf;;;;;OAKG;IACH,IAAI,CAAC,IAAI,GAAE,OAAO,CAAC,KAAK,CAAM,GAAG,KAAK;IAQtC;;;;OAIG;IACH,KAAK,CAAC,IAAI,SAAK,GAAG,KAAK,EAAE;IAQzB;;;;OAIG;IACH,MAAM,CAAC,IAAI,GAAE,OAAO,CAAC,KAAK,CAAM,GAAG,KAAK;IAIxC;;;;OAIG;IACH,OAAO,CAAC,IAAI,SAAK,GAAG,KAAK,EAAE;IAQ3B;;;;OAIG;IACH,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,cAAc,EAAE;CAYjD"}
@@ -5,6 +5,7 @@ import { nanoid } from '../../nanoid.js';
5
5
  export class File {
6
6
  /**
7
7
  * Generates a random file object.
8
+ * Note that this generator doesn't create the permissions object. Use Permission class for that.
8
9
  * @param init Optional values to be present in the object.
9
10
  * @returns Random file
10
11
  */
@@ -1 +1 @@
1
- {"version":3,"file":"File.js","sourceRoot":"","sources":["../../../../src/mocking/lib/File.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AACvC,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,mBAAmB,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACjH,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAmC,MAAM,4BAA4B,CAAA;AAC9F,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAExC,MAAM,OAAO,IAAI;IACf;;;;OAIG;IACH,IAAI,CAAC,OAAuB,EAAE;QAC5B,MAAM,EACJ,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE,cAAc,EAAE,mBAAmB,EAAE,WAAW,CAAU,CAAC,EAC3G,IAAI,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,GACzC,GAAG,IAAI,CAAA;QACR,OAAO,QAAQ,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IAC9C,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,IAAI,GAAG,EAAE;QACb,MAAM,MAAM,GAAG,EAAE,CAAA;QACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;QAC1B,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,OAAuB,EAAE;QAC9B,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,CAAC,CAAA;IACjD,CAAC;IAED;;;;OAIG;IACH,OAAO,CAAC,IAAI,GAAG,EAAE;QACf,MAAM,MAAM,GAAG,EAAE,CAAA;QACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAA;QAC5B,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;IAED;;;;OAIG;IACH,eAAe,CAAC,IAAa;QAC3B,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAA,CAAC,MAAM;QAC9D,MAAM,KAAK,GAAqB,EAAE,CAAA;QAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAClC,MAAM,IAAI,GACR,CAAC,KAAK,KAAK,GAAG,CAAC;gBACb,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE,cAAc,EAAE,mBAAmB,EAAE,WAAW,CAAU,CAAC;gBACtG,CAAC,CAAC,UAAU,CAAA;YAChB,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;QACpE,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;CACF","sourcesContent":["import { faker } from '@faker-js/faker'\nimport { ProjectKind, DomainFileKind, CertificateFileKind, FolderKind, ApiFileKind } from '../../models/kinds.js'\nimport { File as CoreFile, type IFile, type FileBreadcrumb } from '../../models/store/File.js'\nimport { nanoid } from '../../nanoid.js'\n\nexport class File {\n /**\n * Generates a random file object.\n * @param init Optional values to be present in the object.\n * @returns Random file\n */\n file(init: Partial<IFile> = {}): IFile {\n const {\n kind = faker.helpers.arrayElement([ProjectKind, DomainFileKind, CertificateFileKind, ApiFileKind] as const),\n info = { name: faker.system.fileName() },\n } = init\n return CoreFile.createSchema({ kind, info })\n }\n\n /**\n * Generates a list of random file objects.\n * @param size Number of files to generate. Default is 25.\n * @returns List of random files\n */\n files(size = 25): IFile[] {\n const result = []\n for (let i = 0; i < size; i++) {\n result.push(this.file())\n }\n return result\n }\n\n /**\n * Generates a random folder object.\n * @param init Optional values to be present in the object.\n * @returns Random folder\n */\n folder(init: Partial<IFile> = {}): IFile {\n return this.file({ kind: FolderKind, ...init })\n }\n\n /**\n * Generates a list of random folder objects.\n * @param size Number of folders to generate. Default is 25.\n * @returns List of random folders\n */\n folders(size = 25): IFile[] {\n const result = []\n for (let i = 0; i < size; i++) {\n result.push(this.folder())\n }\n return result\n }\n\n /**\n * Generates a random file breadcrumb object.\n * @param size Optional depth of the breadcrumb. Default is random between 2-3.\n * @returns Random file breadcrumb\n */\n fileBreadcrumbs(size?: number): FileBreadcrumb[] {\n const depth = size ?? 2 + Math.floor(Math.random() * 2) // 2-3\n const items: FileBreadcrumb[] = []\n for (let i = 0; i < depth; i += 1) {\n const kind =\n i === depth - 1\n ? faker.helpers.arrayElement([ProjectKind, DomainFileKind, CertificateFileKind, ApiFileKind] as const)\n : FolderKind\n items.push({ key: nanoid(), kind, name: faker.system.fileName() })\n }\n return items\n }\n}\n"]}
1
+ {"version":3,"file":"File.js","sourceRoot":"","sources":["../../../../src/mocking/lib/File.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AACvC,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,mBAAmB,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACjH,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAmC,MAAM,4BAA4B,CAAA;AAC9F,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAExC,MAAM,OAAO,IAAI;IACf;;;;;OAKG;IACH,IAAI,CAAC,OAAuB,EAAE;QAC5B,MAAM,EACJ,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE,cAAc,EAAE,mBAAmB,EAAE,WAAW,CAAU,CAAC,EAC3G,IAAI,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,GACzC,GAAG,IAAI,CAAA;QACR,OAAO,QAAQ,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IAC9C,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,IAAI,GAAG,EAAE;QACb,MAAM,MAAM,GAAG,EAAE,CAAA;QACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;QAC1B,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,OAAuB,EAAE;QAC9B,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,CAAC,CAAA;IACjD,CAAC;IAED;;;;OAIG;IACH,OAAO,CAAC,IAAI,GAAG,EAAE;QACf,MAAM,MAAM,GAAG,EAAE,CAAA;QACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAA;QAC5B,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;IAED;;;;OAIG;IACH,eAAe,CAAC,IAAa;QAC3B,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAA,CAAC,MAAM;QAC9D,MAAM,KAAK,GAAqB,EAAE,CAAA;QAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAClC,MAAM,IAAI,GACR,CAAC,KAAK,KAAK,GAAG,CAAC;gBACb,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE,cAAc,EAAE,mBAAmB,EAAE,WAAW,CAAU,CAAC;gBACtG,CAAC,CAAC,UAAU,CAAA;YAChB,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;QACpE,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;CACF","sourcesContent":["import { faker } from '@faker-js/faker'\nimport { ProjectKind, DomainFileKind, CertificateFileKind, FolderKind, ApiFileKind } from '../../models/kinds.js'\nimport { File as CoreFile, type IFile, type FileBreadcrumb } from '../../models/store/File.js'\nimport { nanoid } from '../../nanoid.js'\n\nexport class File {\n /**\n * Generates a random file object.\n * Note that this generator doesn't create the permissions object. Use Permission class for that.\n * @param init Optional values to be present in the object.\n * @returns Random file\n */\n file(init: Partial<IFile> = {}): IFile {\n const {\n kind = faker.helpers.arrayElement([ProjectKind, DomainFileKind, CertificateFileKind, ApiFileKind] as const),\n info = { name: faker.system.fileName() },\n } = init\n return CoreFile.createSchema({ kind, info })\n }\n\n /**\n * Generates a list of random file objects.\n * @param size Number of files to generate. Default is 25.\n * @returns List of random files\n */\n files(size = 25): IFile[] {\n const result = []\n for (let i = 0; i < size; i++) {\n result.push(this.file())\n }\n return result\n }\n\n /**\n * Generates a random folder object.\n * @param init Optional values to be present in the object.\n * @returns Random folder\n */\n folder(init: Partial<IFile> = {}): IFile {\n return this.file({ kind: FolderKind, ...init })\n }\n\n /**\n * Generates a list of random folder objects.\n * @param size Number of folders to generate. Default is 25.\n * @returns List of random folders\n */\n folders(size = 25): IFile[] {\n const result = []\n for (let i = 0; i < size; i++) {\n result.push(this.folder())\n }\n return result\n }\n\n /**\n * Generates a random file breadcrumb object.\n * @param size Optional depth of the breadcrumb. Default is random between 2-3.\n * @returns Random file breadcrumb\n */\n fileBreadcrumbs(size?: number): FileBreadcrumb[] {\n const depth = size ?? 2 + Math.floor(Math.random() * 2) // 2-3\n const items: FileBreadcrumb[] = []\n for (let i = 0; i < depth; i += 1) {\n const kind =\n i === depth - 1\n ? faker.helpers.arrayElement([ProjectKind, DomainFileKind, CertificateFileKind, ApiFileKind] as const)\n : FolderKind\n items.push({ key: nanoid(), kind, name: faker.system.fileName() })\n }\n return items\n }\n}\n"]}
@@ -0,0 +1,35 @@
1
+ import { IPermission } from '../../models/store/Permission.js';
2
+ export declare class Permission {
3
+ /**
4
+ * Generates a random permission object.
5
+ * @param init Configuration options for the permission object.
6
+ * @returns Random permission
7
+ */
8
+ permission(init?: Partial<IPermission>): IPermission;
9
+ /**
10
+ * Generates a random user permission object.
11
+ * @param init Configuration options for the permission object.
12
+ * @returns Random user permission
13
+ */
14
+ userPermission(init?: Partial<IPermission>): IPermission;
15
+ /**
16
+ * Generates a random group permission object.
17
+ * @param init Configuration options for the permission object.
18
+ * @returns Random group permission
19
+ */
20
+ groupPermission(init?: Partial<IPermission>): IPermission;
21
+ /**
22
+ * Generates a random organization permission object.
23
+ * @param init Configuration options for the permission object.
24
+ * @returns Random organization permission
25
+ */
26
+ organizationPermission(init?: Partial<IPermission>): IPermission;
27
+ /**
28
+ * Generates a list of random permission objects.
29
+ * @param size The size of the returning array. Default is 25.
30
+ * @param init Configuration options for the permission object.
31
+ * @returns List of random permissions
32
+ */
33
+ permissions(size?: number, init?: Partial<IPermission>): IPermission[];
34
+ }
35
+ //# sourceMappingURL=Permission.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Permission.d.ts","sourceRoot":"","sources":["../../../../src/mocking/lib/Permission.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,WAAW,EAKZ,MAAM,kCAAkC,CAAA;AAEzC,qBAAa,UAAU;IACrB;;;;OAIG;IACH,UAAU,CAAC,IAAI,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,WAAW;IA2CxD;;;;OAIG;IACH,cAAc,CAAC,IAAI,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,WAAW;IAI5D;;;;OAIG;IACH,eAAe,CAAC,IAAI,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,WAAW;IAI7D;;;;OAIG;IACH,sBAAsB,CAAC,IAAI,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,WAAW;IAIpE;;;;;OAKG;IACH,WAAW,CAAC,IAAI,SAAK,EAAE,IAAI,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,WAAW,EAAE;CAOvE"}
@@ -0,0 +1,89 @@
1
+ import { faker } from '@faker-js/faker';
2
+ import { nanoid } from '../../nanoid.js';
3
+ import { Kind as PermissionKind, } from '../../models/store/Permission.js';
4
+ export class Permission {
5
+ /**
6
+ * Generates a random permission object.
7
+ * @param init Configuration options for the permission object.
8
+ * @returns Random permission
9
+ */
10
+ permission(init = {}) {
11
+ const type = init.type ?? faker.helpers.arrayElement(['user', 'group', 'organization']);
12
+ const role = init.role ?? faker.helpers.arrayElement(['reader', 'commenter', 'writer', 'owner']);
13
+ const result = {
14
+ kind: PermissionKind,
15
+ key: init.key ?? nanoid(),
16
+ type,
17
+ granteeId: init.granteeId ?? nanoid(),
18
+ itemId: init.itemId ?? nanoid(),
19
+ role,
20
+ addingUser: init.addingUser ?? nanoid(),
21
+ depth: init.depth ?? 0,
22
+ sourceRule: init.sourceRule ??
23
+ faker.helpers.arrayElement([
24
+ 'direct_user_grant',
25
+ 'creator_default_owner',
26
+ 'parent_owner_editor_rule',
27
+ ]),
28
+ };
29
+ if ('displayName' in init) {
30
+ result.displayName = init.displayName;
31
+ }
32
+ else {
33
+ if (type === 'user') {
34
+ result.displayName = faker.person.fullName();
35
+ }
36
+ else if (type === 'group') {
37
+ result.displayName = faker.lorem.word();
38
+ }
39
+ else if (type === 'organization') {
40
+ result.displayName = faker.company.name();
41
+ }
42
+ }
43
+ if ('expirationTime' in init) {
44
+ result.expirationTime = init.expirationTime;
45
+ }
46
+ else if (type === 'user' || type === 'group') {
47
+ result.expirationTime = faker.date.future().getTime();
48
+ }
49
+ return result;
50
+ }
51
+ /**
52
+ * Generates a random user permission object.
53
+ * @param init Configuration options for the permission object.
54
+ * @returns Random user permission
55
+ */
56
+ userPermission(init = {}) {
57
+ return this.permission({ ...init, type: 'user' });
58
+ }
59
+ /**
60
+ * Generates a random group permission object.
61
+ * @param init Configuration options for the permission object.
62
+ * @returns Random group permission
63
+ */
64
+ groupPermission(init = {}) {
65
+ return this.permission({ ...init, type: 'group' });
66
+ }
67
+ /**
68
+ * Generates a random organization permission object.
69
+ * @param init Configuration options for the permission object.
70
+ * @returns Random organization permission
71
+ */
72
+ organizationPermission(init = {}) {
73
+ return this.permission({ ...init, type: 'organization' });
74
+ }
75
+ /**
76
+ * Generates a list of random permission objects.
77
+ * @param size The size of the returning array. Default is 25.
78
+ * @param init Configuration options for the permission object.
79
+ * @returns List of random permissions
80
+ */
81
+ permissions(size = 25, init = {}) {
82
+ const result = [];
83
+ for (let i = 0; i < size; i++) {
84
+ result.push(this.permission(init));
85
+ }
86
+ return result;
87
+ }
88
+ }
89
+ //# sourceMappingURL=Permission.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Permission.js","sourceRoot":"","sources":["../../../../src/mocking/lib/Permission.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,EAEL,IAAI,IAAI,cAAc,GAIvB,MAAM,kCAAkC,CAAA;AAEzC,MAAM,OAAO,UAAU;IACrB;;;;OAIG;IACH,UAAU,CAAC,OAA6B,EAAE;QACxC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,cAAc,CAAqB,CAAC,CAAA;QAC3G,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,CAAqB,CAAC,CAAA;QAEpH,MAAM,MAAM,GAAgB;YAC1B,IAAI,EAAE,cAAc;YACpB,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,MAAM,EAAE;YACzB,IAAI;YACJ,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,MAAM,EAAE;YACrC,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,MAAM,EAAE;YAC/B,IAAI;YACJ,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,MAAM,EAAE;YACvC,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,CAAC;YACtB,UAAU,EACR,IAAI,CAAC,UAAU;gBACf,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC;oBACzB,mBAAmB;oBACnB,uBAAuB;oBACvB,0BAA0B;iBACD,CAAC;SAC/B,CAAA;QAED,IAAI,aAAa,IAAI,IAAI,EAAE,CAAC;YAC1B,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAA;QACvC,CAAC;aAAM,CAAC;YACN,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;gBACpB,MAAM,CAAC,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAA;YAC9C,CAAC;iBAAM,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC5B,MAAM,CAAC,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAA;YACzC,CAAC;iBAAM,IAAI,IAAI,KAAK,cAAc,EAAE,CAAC;gBACnC,MAAM,CAAC,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;YAC3C,CAAC;QACH,CAAC;QAED,IAAI,gBAAgB,IAAI,IAAI,EAAE,CAAC;YAC7B,MAAM,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,CAAA;QAC7C,CAAC;aAAM,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YAC/C,MAAM,CAAC,cAAc,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,CAAA;QACvD,CAAC;QAED,OAAO,MAAM,CAAA;IACf,CAAC;IAED;;;;OAIG;IACH,cAAc,CAAC,OAA6B,EAAE;QAC5C,OAAO,IAAI,CAAC,UAAU,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;IACnD,CAAC;IAED;;;;OAIG;IACH,eAAe,CAAC,OAA6B,EAAE;QAC7C,OAAO,IAAI,CAAC,UAAU,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;IACpD,CAAC;IAED;;;;OAIG;IACH,sBAAsB,CAAC,OAA6B,EAAE;QACpD,OAAO,IAAI,CAAC,UAAU,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAA;IAC3D,CAAC;IAED;;;;;OAKG;IACH,WAAW,CAAC,IAAI,GAAG,EAAE,EAAE,OAA6B,EAAE;QACpD,MAAM,MAAM,GAAkB,EAAE,CAAA;QAChC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAA;QACpC,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;CACF","sourcesContent":["import { faker } from '@faker-js/faker'\nimport { nanoid } from '../../nanoid.js'\nimport {\n IPermission,\n Kind as PermissionKind,\n type PermissionRole,\n type PermissionType,\n type PermissionSourceRule,\n} from '../../models/store/Permission.js'\n\nexport class Permission {\n /**\n * Generates a random permission object.\n * @param init Configuration options for the permission object.\n * @returns Random permission\n */\n permission(init: Partial<IPermission> = {}): IPermission {\n const type = init.type ?? faker.helpers.arrayElement(['user', 'group', 'organization'] as PermissionType[])\n const role = init.role ?? faker.helpers.arrayElement(['reader', 'commenter', 'writer', 'owner'] as PermissionRole[])\n\n const result: IPermission = {\n kind: PermissionKind,\n key: init.key ?? nanoid(),\n type,\n granteeId: init.granteeId ?? nanoid(),\n itemId: init.itemId ?? nanoid(),\n role,\n addingUser: init.addingUser ?? nanoid(),\n depth: init.depth ?? 0,\n sourceRule:\n init.sourceRule ??\n faker.helpers.arrayElement([\n 'direct_user_grant',\n 'creator_default_owner',\n 'parent_owner_editor_rule',\n ] as PermissionSourceRule[]),\n }\n\n if ('displayName' in init) {\n result.displayName = init.displayName\n } else {\n if (type === 'user') {\n result.displayName = faker.person.fullName()\n } else if (type === 'group') {\n result.displayName = faker.lorem.word()\n } else if (type === 'organization') {\n result.displayName = faker.company.name()\n }\n }\n\n if ('expirationTime' in init) {\n result.expirationTime = init.expirationTime\n } else if (type === 'user' || type === 'group') {\n result.expirationTime = faker.date.future().getTime()\n }\n\n return result\n }\n\n /**\n * Generates a random user permission object.\n * @param init Configuration options for the permission object.\n * @returns Random user permission\n */\n userPermission(init: Partial<IPermission> = {}): IPermission {\n return this.permission({ ...init, type: 'user' })\n }\n\n /**\n * Generates a random group permission object.\n * @param init Configuration options for the permission object.\n * @returns Random group permission\n */\n groupPermission(init: Partial<IPermission> = {}): IPermission {\n return this.permission({ ...init, type: 'group' })\n }\n\n /**\n * Generates a random organization permission object.\n * @param init Configuration options for the permission object.\n * @returns Random organization permission\n */\n organizationPermission(init: Partial<IPermission> = {}): IPermission {\n return this.permission({ ...init, type: 'organization' })\n }\n\n /**\n * Generates a list of random permission objects.\n * @param size The size of the returning array. Default is 25.\n * @param init Configuration options for the permission object.\n * @returns List of random permissions\n */\n permissions(size = 25, init: Partial<IPermission> = {}): IPermission[] {\n const result: IPermission[] = []\n for (let i = 0; i < size; i++) {\n result.push(this.permission(init))\n }\n return result\n }\n}\n"]}
@@ -191,6 +191,12 @@ export declare class ApiModel extends DependentModel {
191
191
  /**
192
192
  * Exposes a new entity in the API model.
193
193
  * If the entity already exists, it returns the existing one.
194
+ *
195
+ * The logic regarding exposing an entity:
196
+ * - If the entity is already exposed as a root entity, it returns the existing one.
197
+ * - If the entity has an association, we expose that entity as a nested entity (by setting the parent property).
198
+ * - If the associated entity is already exposed as a root entity, we do not follow the association.
199
+ *
194
200
  * @param entity The entity key and domain to expose.
195
201
  * @returns The exposed entity.
196
202
  */
@@ -205,9 +211,11 @@ export declare class ApiModel extends DependentModel {
205
211
  private followEntityAssociations;
206
212
  /**
207
213
  * Removes an exposed entity from the API model.
208
- * @param entity The entity to remove.
214
+ * This also removes any nested exposed entities that are children of the removed entity.
215
+ *
216
+ * @param key The key of the exposed entity to remove.
209
217
  */
210
- removeEntity(entity: AssociationTarget): void;
218
+ removeExposedEntity(key: string): void;
211
219
  private removeWithChildren;
212
220
  /**
213
221
  * Returns the exposed entity by its key.
@@ -216,11 +224,11 @@ export declare class ApiModel extends DependentModel {
216
224
  */
217
225
  getExposedEntity(entity: AssociationTarget): ExposedEntity | undefined;
218
226
  /**
219
- * Clears the API model for a new entity change.
227
+ * Clears the API model for a new data domain change.
220
228
  * This method resets the dependencies, exposes, user,
221
229
  * authentication, authorization, and session properties.
222
230
  */
223
- cleanForEntityChange(): void;
231
+ cleanForDomainChange(): void;
224
232
  /**
225
233
  * Attaches a DataDomain to this API model.
226
234
  * This method clears any existing dependencies and sets the new domain.
@@ -1 +1 @@
1
- {"version":3,"file":"ApiModel.d.ts","sourceRoot":"","sources":["../../../src/modeling/ApiModel.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ApiModel.d.ts","sourceRoot":"","sources":["../../../src/modeling/ApiModel.ts"],"names":[],"mappings":"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"}
@@ -189,6 +189,16 @@ let ApiModel = (() => {
189
189
  else if (domain) {
190
190
  throw new Error(`Invalid domain provided. Expected a DataDomain instance or schema.`);
191
191
  }
192
+ // Note that since we're using the `DependentModel` class, but the API Model can have only one dependency,
193
+ // we keep the reference to the data domain under the `dependencyList` property.
194
+ // It is all handled by the parent class `DependentModel`. This way we simplify the dependency management (loading)
195
+ // process when the API model is loaded from the API.
196
+ if (domain) {
197
+ if (!domain.info.version) {
198
+ throw new Error(`Domain ${domain.key} must have a version.`);
199
+ }
200
+ init.dependencyList = [{ key: domain.key, version: domain.info.version }];
201
+ }
192
202
  super(init.dependencyList, instances);
193
203
  this.kind = init.kind;
194
204
  this.key = init.key;
@@ -287,6 +297,12 @@ let ApiModel = (() => {
287
297
  /**
288
298
  * Exposes a new entity in the API model.
289
299
  * If the entity already exists, it returns the existing one.
300
+ *
301
+ * The logic regarding exposing an entity:
302
+ * - If the entity is already exposed as a root entity, it returns the existing one.
303
+ * - If the entity has an association, we expose that entity as a nested entity (by setting the parent property).
304
+ * - If the associated entity is already exposed as a root entity, we do not follow the association.
305
+ *
290
306
  * @param entity The entity key and domain to expose.
291
307
  * @returns The exposed entity.
292
308
  */
@@ -308,8 +324,16 @@ let ApiModel = (() => {
308
324
  }
309
325
  const name = domainEntity.info.name || '';
310
326
  const segment = pluralize(name.toLocaleLowerCase());
311
- const relativeCollectionPath = `/${segment}`;
312
- const relativeResourcePath = `/${segment}/{id}`;
327
+ let relativeCollectionPath = `/${segment}`;
328
+ let relativeResourcePath = `/${segment}/{id}`;
329
+ // Check for root path collision and resolve by appending a number
330
+ let counter = 1;
331
+ const originalCollectionPath = relativeCollectionPath;
332
+ while (this.exposes.some((e) => e.isRoot && e.collectionPath === relativeCollectionPath)) {
333
+ relativeCollectionPath = `${originalCollectionPath}-${counter}`;
334
+ relativeResourcePath = `${relativeCollectionPath}/{id}`;
335
+ counter++;
336
+ }
313
337
  const newEntity = {
314
338
  kind: ExposedEntityKind,
315
339
  key: nanoid(),
@@ -347,11 +371,7 @@ let ApiModel = (() => {
347
371
  return;
348
372
  }
349
373
  const maxDepth = options.maxDepth ?? 6;
350
- const visited = new Set();
351
- // Add parent entity's key to the visited set so we won't skip it when traversing
352
- // associations.
353
- visited.add(createDomainKey(parentExposure.entity));
354
- const follow = (currentEntity, parentKey, depth) => {
374
+ const follow = (currentEntity, parentKey, depth, currentPath) => {
355
375
  // Find the domain entity
356
376
  const domainEntity = domain.findEntity(currentEntity.key, currentEntity.domain);
357
377
  if (!domainEntity)
@@ -363,19 +383,41 @@ let ApiModel = (() => {
363
383
  if (target.key === currentEntity.key && target.domain === currentEntity.domain) {
364
384
  continue;
365
385
  }
366
- // Create unique identifier for circular detection
367
- const visitKey = createDomainKey(target);
368
- if (visited.has(visitKey)) {
369
- continue; // Skip circular references
386
+ const targetKeys = createDomainKey(target);
387
+ // Circular dependency check: if this entity is already in our *current* traversal path
388
+ if (currentPath.includes(targetKeys)) {
389
+ continue;
370
390
  }
371
- visited.add(visitKey);
372
- // Check if this nested exposure already exists
373
- const existingNested = this.exposes.find((e) => !e.isRoot &&
374
- e.entity.key === target.key &&
375
- e.entity.domain === target.domain &&
376
- e.parent?.key === parentKey);
377
- if (existingNested) {
378
- continue; // Already exposed under this parent
391
+ // Check if this entity is ALREADY exposed anywhere in the model
392
+ const existingExposure = this.getExposedEntity(target);
393
+ if (existingExposure) {
394
+ // If it's already exposed and NOT root (i.e., it's currently a nested child of someone else),
395
+ // promote it to ROOT to avoid duplicating it or deeply nesting it in multiple places.
396
+ if (!existingExposure.isRoot) {
397
+ // 1. Calculate new root paths (handling collisions)
398
+ const targetDomEntity = domain.findEntity(target.key, target.domain);
399
+ if (targetDomEntity) {
400
+ const name = targetDomEntity.info.name || '';
401
+ const segment = pluralize(name.toLocaleLowerCase());
402
+ let relativeCollectionPath = `/${segment}`;
403
+ let relativeResourcePath = `/${segment}/{id}`;
404
+ let counter = 1;
405
+ const originalCollectionPath = relativeCollectionPath;
406
+ while (this.exposes.some((e) => e.isRoot && e.collectionPath === relativeCollectionPath)) {
407
+ relativeCollectionPath = `${originalCollectionPath}-${counter}`;
408
+ relativeResourcePath = `${relativeCollectionPath}/{id}`;
409
+ counter++;
410
+ }
411
+ // 2. Update properties to make it root
412
+ existingExposure.isRoot = true;
413
+ existingExposure.parent = undefined;
414
+ existingExposure.collectionPath = relativeCollectionPath;
415
+ existingExposure.resourcePath = relativeResourcePath;
416
+ existingExposure.hasCollection = true;
417
+ }
418
+ }
419
+ // Whether it was already root or we just promoted it, we stop following here.
420
+ continue;
379
421
  }
380
422
  // Find the target domain entity for path generation
381
423
  const targetDomainEntity = domain.findEntity(target.key, target.domain);
@@ -411,25 +453,28 @@ let ApiModel = (() => {
411
453
  }
412
454
  else {
413
455
  // Recursively follow associations
414
- follow(target, nestedExposure.key, depth + 1);
456
+ follow(target, nestedExposure.key, depth + 1, [...currentPath, targetKeys]);
415
457
  }
416
458
  }
417
459
  }
418
460
  };
419
461
  // Start following from the root exposure
420
- follow(parentExposure.entity, parentExposure.key, 0);
462
+ // Initial path contains the root entity itself
463
+ const rootKey = createDomainKey(parentExposure.entity);
464
+ follow(parentExposure.entity, parentExposure.key, 0, [rootKey]);
421
465
  }
422
466
  /**
423
467
  * Removes an exposed entity from the API model.
424
- * @param entity The entity to remove.
468
+ * This also removes any nested exposed entities that are children of the removed entity.
469
+ *
470
+ * @param key The key of the exposed entity to remove.
425
471
  */
426
- removeEntity(entity) {
427
- const current = this.exposes.find((e) => e.entity.key === entity.key && e.entity.domain === entity.domain);
428
- if (!current) {
429
- return;
472
+ removeExposedEntity(key) {
473
+ const index = this.exposes.findIndex((e) => e.key === key);
474
+ if (index < 0) {
475
+ throw new Error(`Exposed entity with key "${key}" not found.`);
430
476
  }
431
- this.removeWithChildren(current.key);
432
- this.notifyChange();
477
+ this.removeWithChildren(key);
433
478
  }
434
479
  removeWithChildren(key) {
435
480
  const index = this.exposes.findIndex((e) => e.key === key);
@@ -463,11 +508,11 @@ let ApiModel = (() => {
463
508
  return this.exposes.find((e) => e.entity.key === entity.key && e.entity.domain === entity.domain);
464
509
  }
465
510
  /**
466
- * Clears the API model for a new entity change.
511
+ * Clears the API model for a new data domain change.
467
512
  * This method resets the dependencies, exposes, user,
468
513
  * authentication, authorization, and session properties.
469
514
  */
470
- cleanForEntityChange() {
515
+ cleanForDomainChange() {
471
516
  this.dependencies.clear();
472
517
  this.dependencyList = [];
473
518
  this.exposes = [];
@@ -495,7 +540,7 @@ let ApiModel = (() => {
495
540
  if (!domain.info.version) {
496
541
  throw new Error(`Cannot attach DataDomain without a version. Please set the version in the domain info.`);
497
542
  }
498
- this.cleanForEntityChange();
543
+ this.cleanForDomainChange();
499
544
  this.dependencies.set(domain.key, domain);
500
545
  this.dependencyList = [{ key: domain.key, version: domain.info.version }];
501
546
  this.notifyChange();