@mittwald/api-models 4.54.0 → 4.55.0

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 (35) hide show
  1. package/README.md +55 -11
  2. package/dist/esm/app/AppInstallation/AppInstallation.js +45 -2
  3. package/dist/esm/app/AppInstallation/behaviors/api.js +5 -2
  4. package/dist/esm/base/ListDataModel.js +8 -0
  5. package/dist/esm/base/ListQueryModel.js +9 -0
  6. package/dist/esm/config/config.js +1 -0
  7. package/dist/esm/customer/Customer/Customer.js +53 -4
  8. package/dist/esm/customer/Customer/behaviors/api.js +5 -2
  9. package/dist/esm/domain/Ingress/Ingress.js +53 -4
  10. package/dist/esm/domain/Ingress/behaviors/api.js +7 -5
  11. package/dist/esm/project/Project/Project.js +54 -3
  12. package/dist/esm/project/Project/behaviors/api.js +5 -2
  13. package/dist/esm/project/Project/behaviors/inMem.js +5 -1
  14. package/dist/esm/server/Server/Server.js +51 -3
  15. package/dist/esm/server/Server/behaviors/api.js +5 -2
  16. package/dist/types/app/AppInstallation/AppInstallation.d.ts +32 -4
  17. package/dist/types/app/AppInstallation/behaviors/types.d.ts +3 -2
  18. package/dist/types/app/AppInstallation/types.d.ts +1 -1
  19. package/dist/types/base/ListDataModel.d.ts +5 -0
  20. package/dist/types/base/ListQueryModel.d.ts +5 -0
  21. package/dist/types/base/types.d.ts +4 -0
  22. package/dist/types/config/config.d.ts +1 -0
  23. package/dist/types/customer/Customer/Customer.d.ts +33 -2
  24. package/dist/types/customer/Customer/behaviors/types.d.ts +3 -2
  25. package/dist/types/customer/Customer/types.d.ts +1 -1
  26. package/dist/types/domain/Ingress/Ingress.d.ts +30 -4
  27. package/dist/types/domain/Ingress/behaviors/types.d.ts +3 -2
  28. package/dist/types/domain/Ingress/types.d.ts +5 -3
  29. package/dist/types/project/Project/Project.d.ts +56 -25
  30. package/dist/types/project/Project/behaviors/types.d.ts +3 -2
  31. package/dist/types/project/Project/types.d.ts +7 -1
  32. package/dist/types/server/Server/Server.d.ts +34 -5
  33. package/dist/types/server/Server/behaviors/types.d.ts +3 -2
  34. package/dist/types/server/Server/types.d.ts +5 -1
  35. package/package.json +4 -3
package/README.md CHANGED
@@ -60,10 +60,10 @@ await projectRef.updateDescription("My new description!");
60
60
  const server = project.server;
61
61
 
62
62
  // List all projects of this server
63
- const serversProjects = await server.listProjects();
63
+ const serversProjects = await server.projects.execute();
64
64
 
65
65
  // List all projects
66
- const allProjects = await Project.list();
66
+ const allProjects = await Project.query().execute();
67
67
 
68
68
  // Iterate over project List Models
69
69
  for (const project of serversProjects) {
@@ -105,10 +105,10 @@ const anotherDetailedProject = projectRef.getDetailed.use();
105
105
  const server = project.server;
106
106
 
107
107
  // List all projects of this server
108
- const serversProjects = server.listProjects.use();
108
+ const serversProjects = server.projects.execute.use();
109
109
 
110
110
  // List all projects
111
- const allProjects = Project.list.use();
111
+ const allProjects = Project.query().execute.use();
112
112
  ```
113
113
 
114
114
  ## Immutability and state updates
@@ -190,10 +190,55 @@ model operations often just need the ID and some input data (deleting, renaming,
190
190
  should be used as a return type for newly created models or for linked models.
191
191
 
192
192
  To get the actual Detailed Model, Reference Models _must_ have a
193
- `function getDetailed(): Promise<ModelDetailed>` method.
193
+ `function getDetailed(): Promise<ModelDetailed>` and
194
+ `function findDetailed(): Promise<ModelDetailed|undefined>` method.
194
195
 
195
196
  Consider extending the Reference Model when implementing the Entry-Point Model.
196
197
 
198
+ #### Query Models
199
+
200
+ Querying models usually requires a query object – or short query. The query
201
+ mostly includes pagination settings like `limit`, `skip` or `page`. It may also
202
+ include filters like `fromDate` or `toDate`, and filters to other models like
203
+ `customerId`.
204
+
205
+ A Query Model represents a specific query to a specific model and should include
206
+ the following methods:
207
+
208
+ - `execute()`: executes the query and returns the respective List Model
209
+ - `refine(overrideQuery)`: creates a new Query Model with a refined query object
210
+ - `getTotalCount()`: gets the total count of the query (executes the query with
211
+ `limit: 0`)
212
+
213
+ When a model supports queries, it should provide a static `query()` method to
214
+ create the respective Query Model.
215
+
216
+ When a model is used as a query parameters in a Query Model, the model should
217
+ have a property in its Reference Model for this Query Model. See the following
218
+ example:
219
+
220
+ ```typescript
221
+ class Server {
222
+ public readonly projects: ProjectsListQuery;
223
+
224
+ public constructor(id: string) {
225
+ this.projects = new ProjectListQuery({
226
+ server: this,
227
+ });
228
+ }
229
+ }
230
+ ```
231
+
232
+ #### List Models
233
+
234
+ List Models are the result of a Query Model execution. A List Model includes
235
+
236
+ - a list of the respective List Models, limited by the pagination configuration
237
+ - the available total count (useful to implement pagination or count data)
238
+
239
+ List Models should extend their respective Query Model, because it might be
240
+ helpful to also call `refine()` on an already executed query.
241
+
197
242
  #### Implementation details
198
243
 
199
244
  When implementing shared functionality, like in the Common Models, you can use
@@ -204,7 +249,7 @@ implementation examples.
204
249
  #### Entry-Point Model
205
250
 
206
251
  Provide a single model (name it `[Model]`) as an entry point for all different
207
- model types (detailed, list, ...). As a convention provide a default export for
252
+ model types (detailed, query, ...). As a convention provide a default export for
208
253
  this model.
209
254
 
210
255
  ### Use the correct verbs
@@ -221,9 +266,9 @@ method. The get method should return the desired object or throw an
221
266
  `ObjectNotFoundError`. You can use the `find` method and assert the existence
222
267
  with the `assertObjectFound` function.
223
268
 
224
- #### `list`
269
+ #### `query`
225
270
 
226
- When a list of objects should be loaded use a `list` method. It may support a
271
+ When a list of objects should be queried use a `query` method. It may support a
227
272
  `query` parameter to filter the result by given criteria.
228
273
 
229
274
  #### `create`
@@ -234,9 +279,8 @@ return a reference of the created resource.
234
279
  ### Accessing "linked" models
235
280
 
236
281
  Most of the models are part of a larger model tree. Models should provide
237
- methods to get the parent and child models, like `project.getServer()`,
238
- `server.listProjects()` or `server.getCustomer()`. Use `get`, `list` or `find`
239
- prefixes as described above.
282
+ properties to get the parent and child models, like `project.server`,
283
+ `server.projects` or `server.customer`.
240
284
 
241
285
  #### Use Reference Models resp. Entry-Point Models when possible!
242
286
 
@@ -4,6 +4,9 @@ import { DataModel } from "../../base/DataModel.js";
4
4
  import assertObjectFound from "../../base/assertObjectFound.js";
5
5
  import { ReferenceModel } from "../../base/ReferenceModel.js";
6
6
  import { provideReact } from "../../lib/provideReact.js";
7
+ import { ListQueryModel } from "../../base/ListQueryModel.js";
8
+ import { ListDataModel } from "../../base/ListDataModel.js";
9
+ import { Project } from "../../project/index.js";
7
10
  export class AppInstallation extends ReferenceModel {
8
11
  static find = provideReact(async (id) => {
9
12
  const data = await config.behaviors.appInstallation.find(id);
@@ -19,9 +22,14 @@ export class AppInstallation extends ReferenceModel {
19
22
  static ofId(id) {
20
23
  return new AppInstallation(id);
21
24
  }
25
+ query(project, query = {}) {
26
+ return new AppInstallationListQuery(project, query);
27
+ }
28
+ /** @deprecated: use query() or project.appInstallations */
22
29
  static list = provideReact(async (projectId, query = {}) => {
23
- const data = await config.behaviors.appInstallation.list(projectId, query);
24
- return data.map((d) => new AppInstallationListItem(d));
30
+ return new AppInstallationListQuery(Project.ofId(projectId), query)
31
+ .execute()
32
+ .then((r) => r.items);
25
33
  });
26
34
  getDetailed = provideReact(() => AppInstallation.get(this.id), [this.id]);
27
35
  findDetailed = provideReact(() => AppInstallation.find(this.id), [this.id]);
@@ -42,3 +50,38 @@ export class AppInstallationListItem extends classes(AppInstallationCommon, (Dat
42
50
  super([data], [data]);
43
51
  }
44
52
  }
53
+ export class AppInstallationListQuery extends ListQueryModel {
54
+ project;
55
+ constructor(project, query = {}) {
56
+ super(query);
57
+ this.project = project;
58
+ }
59
+ refine(query) {
60
+ return new AppInstallationListQuery(this.project, {
61
+ ...this.query,
62
+ ...query,
63
+ });
64
+ }
65
+ execute = provideReact(async () => {
66
+ const { items, totalCount } = await config.behaviors.appInstallation.list(this.project.id, {
67
+ limit: config.defaultPaginationLimit,
68
+ ...this.query,
69
+ });
70
+ return new AppInstallationList(this.project, this.query, items.map((d) => new AppInstallationListItem(d)), totalCount);
71
+ }, [this.queryId]);
72
+ getTotalCount = provideReact(async () => {
73
+ const { totalCount } = await this.refine({ limit: 1 }).execute();
74
+ return totalCount;
75
+ }, [this.queryId]);
76
+ findOneAndOnly = provideReact(async () => {
77
+ const { items, totalCount } = await this.refine({ limit: 2 }).execute();
78
+ if (totalCount === 1) {
79
+ return items[0];
80
+ }
81
+ }, [this.queryId]);
82
+ }
83
+ export class AppInstallationList extends classes(AppInstallationListQuery, (ListDataModel)) {
84
+ constructor(project, query, appInstallations, totalCount) {
85
+ super([project, query], [appInstallations, totalCount]);
86
+ }
87
+ }
@@ -1,4 +1,4 @@
1
- import { assertStatus } from "@mittwald/api-client";
1
+ import { assertStatus, extractTotalCountHeader, } from "@mittwald/api-client";
2
2
  import { assertOneOfStatus } from "@mittwald/api-client";
3
3
  export const apiAppInstallationBehaviors = (client) => ({
4
4
  find: async (id) => {
@@ -16,6 +16,9 @@ export const apiAppInstallationBehaviors = (client) => ({
16
16
  projectId,
17
17
  });
18
18
  assertStatus(response, 200);
19
- return response.data;
19
+ return {
20
+ items: response.data,
21
+ totalCount: extractTotalCountHeader(response),
22
+ };
20
23
  },
21
24
  });
@@ -0,0 +1,8 @@
1
+ export class ListDataModel {
2
+ items;
3
+ totalCount;
4
+ constructor(items, totalCount) {
5
+ this.items = Object.freeze(items);
6
+ this.totalCount = totalCount;
7
+ }
8
+ }
@@ -0,0 +1,9 @@
1
+ import { hash } from "object-code";
2
+ export class ListQueryModel {
3
+ query;
4
+ queryId;
5
+ constructor(query) {
6
+ this.query = query;
7
+ this.queryId = hash(query).toString();
8
+ }
9
+ }
@@ -1,4 +1,5 @@
1
1
  export const config = {
2
+ defaultPaginationLimit: 50,
2
3
  behaviors: {
3
4
  project: undefined,
4
5
  server: undefined,
@@ -4,7 +4,22 @@ import { DataModel } from "../../base/DataModel.js";
4
4
  import assertObjectFound from "../../base/assertObjectFound.js";
5
5
  import { ReferenceModel } from "../../base/ReferenceModel.js";
6
6
  import { provideReact } from "../../lib/provideReact.js";
7
+ import { ListQueryModel } from "../../base/ListQueryModel.js";
8
+ import { ListDataModel } from "../../base/ListDataModel.js";
9
+ import { ServerListQuery } from "../../server/index.js";
10
+ import { ProjectListQuery } from "../../project/index.js";
7
11
  export class Customer extends ReferenceModel {
12
+ servers;
13
+ projects;
14
+ constructor(id) {
15
+ super(id);
16
+ this.servers = new ServerListQuery({
17
+ customer: this,
18
+ });
19
+ this.projects = new ProjectListQuery({
20
+ customer: this,
21
+ });
22
+ }
8
23
  static ofId(id) {
9
24
  return new Customer(id);
10
25
  }
@@ -14,10 +29,11 @@ export class Customer extends ReferenceModel {
14
29
  return new CustomerDetailed(data);
15
30
  }
16
31
  });
17
- static list = provideReact(async (query = {}) => {
18
- const data = await config.behaviors.customer.list(query);
19
- return Object.freeze(data.map((d) => new CustomerListItem(d)));
20
- });
32
+ static query(query = {}) {
33
+ return new CustomerListQuery(query);
34
+ }
35
+ /** @deprecated Use query() */
36
+ static list = provideReact(async (query = {}) => new CustomerListQuery(query).execute().then((res) => res.items));
21
37
  static get = provideReact(async (id) => {
22
38
  const customer = await this.find(id);
23
39
  assertObjectFound(customer, this, id);
@@ -42,3 +58,36 @@ export class CustomerListItem extends classes(CustomerCommon, (DataModel)) {
42
58
  super([data], [data]);
43
59
  }
44
60
  }
61
+ export class CustomerListQuery extends ListQueryModel {
62
+ constructor(query = {}) {
63
+ super(query);
64
+ }
65
+ refine(query) {
66
+ return new CustomerListQuery({
67
+ ...this.query,
68
+ ...query,
69
+ });
70
+ }
71
+ execute = provideReact(async () => {
72
+ const { items, totalCount } = await config.behaviors.customer.list({
73
+ limit: config.defaultPaginationLimit,
74
+ ...this.query,
75
+ });
76
+ return new CustomerList(this.query, items.map((d) => new CustomerListItem(d)), totalCount);
77
+ }, [this.queryId]);
78
+ getTotalCount = provideReact(async () => {
79
+ const { totalCount } = await this.refine({ limit: 1 }).execute();
80
+ return totalCount;
81
+ }, [this.queryId]);
82
+ findOneAndOnly = provideReact(async () => {
83
+ const { items, totalCount } = await this.refine({ limit: 2 }).execute();
84
+ if (totalCount === 1) {
85
+ return items[0];
86
+ }
87
+ }, [this.queryId]);
88
+ }
89
+ export class CustomerList extends classes(CustomerListQuery, (ListDataModel)) {
90
+ constructor(query, customers, totalCount) {
91
+ super([query], [customers, totalCount]);
92
+ }
93
+ }
@@ -1,4 +1,4 @@
1
- import { assertStatus } from "@mittwald/api-client";
1
+ import { assertStatus, extractTotalCountHeader, } from "@mittwald/api-client";
2
2
  import { assertOneOfStatus } from "@mittwald/api-client";
3
3
  export const apiCustomerBehaviors = (client) => ({
4
4
  find: async (id) => {
@@ -15,6 +15,9 @@ export const apiCustomerBehaviors = (client) => ({
15
15
  queryParameters: query,
16
16
  });
17
17
  assertStatus(response, 200);
18
- return response.data;
18
+ return {
19
+ items: response.data,
20
+ totalCount: extractTotalCountHeader(response),
21
+ };
19
22
  },
20
23
  });
@@ -5,6 +5,8 @@ import assertObjectFound from "../../base/assertObjectFound.js";
5
5
  import { ReferenceModel } from "../../base/ReferenceModel.js";
6
6
  import { provideReact } from "../../lib/provideReact.js";
7
7
  import { IngressPath } from "../IngressPath/IngressPath.js";
8
+ import { ListQueryModel } from "../../base/ListQueryModel.js";
9
+ import { ListDataModel } from "../../base/ListDataModel.js";
8
10
  export class Ingress extends ReferenceModel {
9
11
  static ofId(id) {
10
12
  return new Ingress(id);
@@ -12,10 +14,8 @@ export class Ingress extends ReferenceModel {
12
14
  static ofHostname(hostname) {
13
15
  return Ingress.ofId(hostname);
14
16
  }
15
- static list = provideReact(async (query = {}) => {
16
- const data = await config.behaviors.ingress.list(query);
17
- return data.map((d) => new IngressListItem(d));
18
- });
17
+ /** @deprecated: use query() or project.ingresses */
18
+ static list = provideReact(async (query = {}) => new IngressListQuery(query).execute().then((r) => r.items));
19
19
  static find = provideReact(async (id) => {
20
20
  const data = await config.behaviors.ingress.find(id);
21
21
  if (data !== undefined) {
@@ -55,3 +55,52 @@ export class IngressListItem extends classes(IngressCommon, (DataModel)) {
55
55
  super([data], [data]);
56
56
  }
57
57
  }
58
+ export class IngressListQuery extends ListQueryModel {
59
+ constructor(query = {}) {
60
+ super(query);
61
+ }
62
+ refine(query = {}) {
63
+ return new IngressListQuery({
64
+ ...this.query,
65
+ ...query,
66
+ });
67
+ }
68
+ execute = provideReact(async () => {
69
+ const { project, ...query } = this.query;
70
+ const { items, totalCount } = await config.behaviors.ingress.list({
71
+ /** @todo: use this code when pagination is supported by API */
72
+ // limit: config.defaultPaginationLimit,
73
+ ...query,
74
+ projectId: project?.id,
75
+ });
76
+ return new IngressList(this.query, items.map((d) => new IngressListItem(d)), totalCount);
77
+ }, [this.queryId]);
78
+ getTotalCount = provideReact(async () => {
79
+ /** @todo: use this code when pagination is supported by API */
80
+ // const { totalCount } = await this.refine({ limit: 1 }).execute();
81
+ // return totalCount;
82
+ const { items } = await this.refine({}).execute();
83
+ return items.length;
84
+ }, [this.queryId]);
85
+ findOneAndOnly = provideReact(async () => {
86
+ /** @todo: use this code when pagination is supported by API */
87
+ // const { items, totalCount } = await this.refine({ limit: 2 }).execute();
88
+ // if (totalCount === 1) {
89
+ // return items[0];
90
+ // }
91
+ const { items, totalCount } = await this.refine({}).execute();
92
+ if (totalCount === 1) {
93
+ return items[0];
94
+ }
95
+ }, [this.queryId]);
96
+ }
97
+ export class IngressList extends classes(IngressListQuery, (ListDataModel)) {
98
+ constructor(query, ingresses, totalCount) {
99
+ super([query], [ingresses, totalCount]);
100
+ }
101
+ getDefault() {
102
+ const defaultIngress = this.items.find((i) => i.data.isDefault);
103
+ assertObjectFound(defaultIngress, IngressListItem, "IngressList");
104
+ return defaultIngress;
105
+ }
106
+ }
@@ -11,13 +11,15 @@ export const apiIngressBehaviors = (client) => ({
11
11
  assertOneOfStatus(response, [404]);
12
12
  },
13
13
  list: async (query = {}) => {
14
- const { projectId } = query;
15
14
  const response = await client.domain.ingressListIngresses({
16
- queryParameters: {
17
- projectId,
18
- },
15
+ queryParameters: query,
19
16
  });
20
17
  assertStatus(response, 200);
21
- return response.data;
18
+ return {
19
+ items: response.data,
20
+ totalCount: response.data.length,
21
+ /** @todo: use this code when pagination is supported by API */
22
+ // totalCount: extractTotalCountHeader(response),
23
+ };
22
24
  },
23
25
  });
@@ -6,8 +6,20 @@ import { Server } from "../../server/index.js";
6
6
  import { provideReact, } from "../../lib/provideReact.js";
7
7
  import { Customer } from "../../customer/Customer/Customer.js";
8
8
  import { ReferenceModel } from "../../base/ReferenceModel.js";
9
- import { Ingress, IngressListItem } from "../../domain/index.js";
9
+ import { Ingress, IngressListItem, IngressListQuery, } from "../../domain/index.js";
10
+ import { ListQueryModel } from "../../base/ListQueryModel.js";
11
+ import { ListDataModel } from "../../base/ListDataModel.js";
12
+ import { AppInstallationListQuery } from "../../app/index.js";
10
13
  export class Project extends ReferenceModel {
14
+ ingresses;
15
+ appInstallations;
16
+ constructor(id) {
17
+ super(id);
18
+ this.ingresses = new IngressListQuery({
19
+ project: this,
20
+ });
21
+ this.appInstallations = new AppInstallationListQuery(this);
22
+ }
11
23
  static ofId(id) {
12
24
  return new Project(id);
13
25
  }
@@ -22,9 +34,12 @@ export class Project extends ReferenceModel {
22
34
  assertObjectFound(project, this, id);
23
35
  return project;
24
36
  });
37
+ query(query = {}) {
38
+ return new ProjectListQuery(query);
39
+ }
40
+ /** @deprecated: use query(), Customer.projects or Server.projects */
25
41
  static list = provideReact(async (query = {}) => {
26
- const data = await config.behaviors.project.list(query);
27
- return Object.freeze(data.map((d) => new ProjectListItem(d)));
42
+ return new ProjectListQuery(query).execute().then((r) => r.items);
28
43
  });
29
44
  static async create(serverId, description) {
30
45
  const { id } = await config.behaviors.project.create(serverId, description);
@@ -32,6 +47,7 @@ export class Project extends ReferenceModel {
32
47
  }
33
48
  getDetailed = provideReact(() => Project.get(this.id), [this.id]);
34
49
  findDetailed = provideReact(() => Project.find(this.id), [this.id]);
50
+ /** @deprecated: use ingresses property */
35
51
  listIngresses = provideReact(() => Ingress.list({ projectId: this.id }));
36
52
  getDefaultIngress = provideReact(async () => {
37
53
  const ingresses = await Project.ofId(this.id).listIngresses();
@@ -68,3 +84,38 @@ export class ProjectListItem extends classes(ProjectCommon, (DataModel)) {
68
84
  super([data], [data]);
69
85
  }
70
86
  }
87
+ export class ProjectListQuery extends ListQueryModel {
88
+ constructor(query = {}) {
89
+ super(query);
90
+ }
91
+ refine(query) {
92
+ return new ProjectListQuery({
93
+ ...this.query,
94
+ ...query,
95
+ });
96
+ }
97
+ execute = provideReact(async () => {
98
+ const { server, customer, ...query } = this.query;
99
+ const { items, totalCount } = await config.behaviors.project.list({
100
+ ...query,
101
+ serverId: server?.id,
102
+ customerId: customer?.id,
103
+ });
104
+ return new ProjectList(this.query, items.map((d) => new ProjectListItem(d)), totalCount);
105
+ }, [this.queryId]);
106
+ getTotalCount = provideReact(async () => {
107
+ const { totalCount } = await this.refine({ limit: 1 }).execute();
108
+ return totalCount;
109
+ }, [this.queryId]);
110
+ findOneAndOnly = provideReact(async () => {
111
+ const { items, totalCount } = await this.refine({ limit: 2 }).execute();
112
+ if (totalCount === 1) {
113
+ return items[0];
114
+ }
115
+ }, [this.queryId]);
116
+ }
117
+ export class ProjectList extends classes(ProjectListQuery, (ListDataModel)) {
118
+ constructor(query, projects, totalCount) {
119
+ super([query], [projects, totalCount]);
120
+ }
121
+ }
@@ -1,4 +1,4 @@
1
- import { assertStatus } from "@mittwald/api-client";
1
+ import { assertStatus, extractTotalCountHeader, } from "@mittwald/api-client";
2
2
  import { assertOneOfStatus } from "@mittwald/api-client";
3
3
  export const apiProjectBehaviors = (client) => ({
4
4
  find: async (id) => {
@@ -15,7 +15,10 @@ export const apiProjectBehaviors = (client) => ({
15
15
  queryParameters: query,
16
16
  });
17
17
  assertStatus(response, 200);
18
- return response.data;
18
+ return {
19
+ items: response.data,
20
+ totalCount: extractTotalCountHeader(response),
21
+ };
19
22
  },
20
23
  create: async (serverId, description) => {
21
24
  const response = await client.project.createProject({
@@ -1,12 +1,16 @@
1
1
  export const inMemProjectBehaviors = (store) => ({
2
2
  find: async (id) => store.get(id),
3
3
  list: async () => {
4
- return Array.from(store.values()).map((detailedProject) => ({
4
+ const items = Array.from(store.values()).map((detailedProject) => ({
5
5
  ...detailedProject,
6
6
  customerMeta: {
7
7
  id: detailedProject.customerId,
8
8
  },
9
9
  }));
10
+ return {
11
+ items,
12
+ totalCount: items.length,
13
+ };
10
14
  },
11
15
  create: async () => {
12
16
  throw new Error("Not implemented");
@@ -3,9 +3,18 @@ import { config } from "../../config/config.js";
3
3
  import { classes } from "polytype";
4
4
  import { DataModel } from "../../base/DataModel.js";
5
5
  import assertObjectFound from "../../base/assertObjectFound.js";
6
- import { Project } from "../../project/index.js";
6
+ import { Project, ProjectListQuery } from "../../project/index.js";
7
7
  import { provideReact } from "../../lib/provideReact.js";
8
+ import { ListQueryModel } from "../../base/ListQueryModel.js";
9
+ import { ListDataModel } from "../../base/ListDataModel.js";
8
10
  export class Server extends ReferenceModel {
11
+ projects;
12
+ constructor(id) {
13
+ super(id);
14
+ this.projects = new ProjectListQuery({
15
+ server: this,
16
+ });
17
+ }
9
18
  static ofId(id) {
10
19
  return new Server(id);
11
20
  }
@@ -20,13 +29,17 @@ export class Server extends ReferenceModel {
20
29
  assertObjectFound(server, this, id);
21
30
  return server;
22
31
  });
32
+ static query(query = {}) {
33
+ return new ServerListQuery(query);
34
+ }
35
+ /** @deprecated: use query() or customer.servers */
23
36
  static list = provideReact(async (query = {}) => {
24
- const projectListData = await config.behaviors.server.list(query);
25
- return projectListData.map((d) => new ServerListItem(d));
37
+ return new ServerListQuery(query).execute().then((r) => r.items);
26
38
  });
27
39
  async createProject(...parameters) {
28
40
  return Project.create(this.id, ...parameters);
29
41
  }
42
+ /** @deprecated Use Server.projects property */
30
43
  listProjects = provideReact(async (query = {}) => {
31
44
  return Project.list({
32
45
  ...query,
@@ -52,3 +65,38 @@ export class ServerListItem extends classes(ServerCommon, (DataModel)) {
52
65
  super([data], [data]);
53
66
  }
54
67
  }
68
+ export class ServerListQuery extends ListQueryModel {
69
+ constructor(query = {}) {
70
+ super(query);
71
+ }
72
+ refine(query) {
73
+ return new ServerListQuery({
74
+ ...this.query,
75
+ ...query,
76
+ });
77
+ }
78
+ execute = provideReact(async () => {
79
+ const { customer, ...query } = this.query;
80
+ const { items, totalCount } = await config.behaviors.server.list({
81
+ limit: config.defaultPaginationLimit,
82
+ customerId: customer?.id,
83
+ ...query,
84
+ });
85
+ return new ServerList(this.query, items.map((d) => new ServerListItem(d)), totalCount);
86
+ }, [this.queryId]);
87
+ getTotalCount = provideReact(async () => {
88
+ const { totalCount } = await this.refine({ limit: 1 }).execute();
89
+ return totalCount;
90
+ }, [this.queryId]);
91
+ findOneAndOnly = provideReact(async () => {
92
+ const { items, totalCount } = await this.refine({ limit: 2 }).execute();
93
+ if (totalCount === 1) {
94
+ return items[0];
95
+ }
96
+ }, [this.queryId]);
97
+ }
98
+ export class ServerList extends classes(ServerListQuery, (ListDataModel)) {
99
+ constructor(query, servers, totalCount) {
100
+ super([query], [servers, totalCount]);
101
+ }
102
+ }
@@ -1,4 +1,4 @@
1
- import { assertStatus, assertOneOfStatus, } from "@mittwald/api-client";
1
+ import { assertStatus, assertOneOfStatus, extractTotalCountHeader, } from "@mittwald/api-client";
2
2
  export const apiServerBehaviors = (client) => ({
3
3
  find: async (id) => {
4
4
  const response = await client.project.getServer({
@@ -14,6 +14,9 @@ export const apiServerBehaviors = (client) => ({
14
14
  queryParameters: query,
15
15
  });
16
16
  assertStatus(response, 200);
17
- return response.data;
17
+ return {
18
+ items: response.data,
19
+ totalCount: extractTotalCountHeader(response),
20
+ };
18
21
  },
19
22
  });
@@ -1,7 +1,10 @@
1
1
  import { DataModel } from "../../base/DataModel.js";
2
2
  import { ReferenceModel } from "../../base/ReferenceModel.js";
3
3
  import type { AsyncResourceVariant } from "../../lib/provideReact.js";
4
- import { AppInstallationListItemData, AppInstallationData } from "./types.js";
4
+ import { AppInstallationData, AppInstallationListItemData, AppInstallationListQueryData } from "./types.js";
5
+ import { ListQueryModel } from "../../base/ListQueryModel.js";
6
+ import { ListDataModel } from "../../base/ListDataModel.js";
7
+ import { Project } from "../../project/index.js";
5
8
  export declare class AppInstallation extends ReferenceModel {
6
9
  static find: ((id: string) => Promise<AppInstallationDetailed | undefined>) & {
7
10
  asResource: (id: string) => import("@mittwald/react-use-promise").AsyncResource<AppInstallationDetailed | undefined>;
@@ -12,9 +15,11 @@ export declare class AppInstallation extends ReferenceModel {
12
15
  use: (id: string) => AppInstallationDetailed;
13
16
  };
14
17
  static ofId(id: string): AppInstallation;
15
- static list: ((projectId: string, query?: import("@mittwald/api-client").MittwaldAPIV2.Paths.V2ProjectsProjectIdAppInstallations.Get.Parameters.Query | undefined) => Promise<AppInstallationListItem[]>) & {
16
- asResource: (projectId: string, query?: import("@mittwald/api-client").MittwaldAPIV2.Paths.V2ProjectsProjectIdAppInstallations.Get.Parameters.Query | undefined) => import("@mittwald/react-use-promise").AsyncResource<AppInstallationListItem[]>;
17
- use: (projectId: string, query?: import("@mittwald/api-client").MittwaldAPIV2.Paths.V2ProjectsProjectIdAppInstallations.Get.Parameters.Query | undefined) => AppInstallationListItem[];
18
+ query(project: Project, query?: AppInstallationListQueryData): AppInstallationListQuery;
19
+ /** @deprecated: use query() or project.appInstallations */
20
+ static list: ((projectId: string, query?: import("@mittwald/api-client").MittwaldAPIV2.Paths.V2ProjectsProjectIdAppInstallations.Get.Parameters.Query | undefined) => Promise<readonly AppInstallationListItem[]>) & {
21
+ asResource: (projectId: string, query?: import("@mittwald/api-client").MittwaldAPIV2.Paths.V2ProjectsProjectIdAppInstallations.Get.Parameters.Query | undefined) => import("@mittwald/react-use-promise").AsyncResource<readonly AppInstallationListItem[]>;
22
+ use: (projectId: string, query?: import("@mittwald/api-client").MittwaldAPIV2.Paths.V2ProjectsProjectIdAppInstallations.Get.Parameters.Query | undefined) => readonly AppInstallationListItem[];
18
23
  };
19
24
  getDetailed: AsyncResourceVariant<AppInstallationDetailed, []>;
20
25
  findDetailed: AsyncResourceVariant<AppInstallationDetailed | undefined, []>;
@@ -105,4 +110,27 @@ declare const AppInstallationListItem_base: import("polytype").Polytype.Clustere
105
110
  export declare class AppInstallationListItem extends AppInstallationListItem_base {
106
111
  constructor(data: AppInstallationListItemData);
107
112
  }
113
+ export declare class AppInstallationListQuery extends ListQueryModel<AppInstallationListQueryData> {
114
+ readonly project: Project;
115
+ constructor(project: Project, query?: AppInstallationListQueryData);
116
+ refine(query: AppInstallationListQueryData): AppInstallationListQuery;
117
+ execute: (() => Promise<AppInstallationList>) & {
118
+ asResource: () => import("@mittwald/react-use-promise").AsyncResource<AppInstallationList>;
119
+ use: () => AppInstallationList;
120
+ };
121
+ getTotalCount: (() => Promise<number>) & {
122
+ asResource: () => import("@mittwald/react-use-promise").AsyncResource<number>;
123
+ use: () => number;
124
+ };
125
+ findOneAndOnly: (() => Promise<AppInstallationListItem | undefined>) & {
126
+ asResource: () => import("@mittwald/react-use-promise").AsyncResource<AppInstallationListItem | undefined>;
127
+ use: () => AppInstallationListItem | undefined;
128
+ };
129
+ }
130
+ declare const AppInstallationList_base: import("polytype").Polytype.ClusteredConstructor<[typeof AppInstallationListQuery, {
131
+ new (items: AppInstallationListItem[], totalCount: number): ListDataModel<AppInstallationListItem>;
132
+ }]>;
133
+ export declare class AppInstallationList extends AppInstallationList_base {
134
+ constructor(project: Project, query: AppInstallationListQueryData, appInstallations: AppInstallationListItem[], totalCount: number);
135
+ }
108
136
  export {};
@@ -1,5 +1,6 @@
1
- import { AppInstallationListItemData, AppInstallationData, AppInstallationListQuery } from "../types.js";
1
+ import { AppInstallationListItemData, AppInstallationData, AppInstallationListQueryData } from "../types.js";
2
+ import { QueryResponseData } from "../../../base/index.js";
2
3
  export interface AppInstallationBehaviors {
3
4
  find: (id: string) => Promise<AppInstallationData | undefined>;
4
- list: (projectId: string, query?: AppInstallationListQuery) => Promise<AppInstallationListItemData[]>;
5
+ list: (projectId: string, query?: AppInstallationListQueryData) => Promise<QueryResponseData<AppInstallationListItemData>>;
5
6
  }
@@ -1,4 +1,4 @@
1
1
  import { MittwaldAPIV2 } from "@mittwald/api-client";
2
- export type AppInstallationListQuery = MittwaldAPIV2.Paths.V2ProjectsProjectIdAppInstallations.Get.Parameters.Query;
2
+ export type AppInstallationListQueryData = MittwaldAPIV2.Paths.V2ProjectsProjectIdAppInstallations.Get.Parameters.Query;
3
3
  export type AppInstallationData = MittwaldAPIV2.Operations.AppGetAppinstallation.ResponseData;
4
4
  export type AppInstallationListItemData = MittwaldAPIV2.Operations.AppListAppinstallations.ResponseData[number];
@@ -0,0 +1,5 @@
1
+ export declare class ListDataModel<TItem> {
2
+ readonly items: readonly TItem[];
3
+ readonly totalCount: number;
4
+ constructor(items: TItem[], totalCount: number);
5
+ }
@@ -0,0 +1,5 @@
1
+ export declare abstract class ListQueryModel<TQuery> {
2
+ protected readonly query: TQuery;
3
+ readonly queryId: string;
4
+ constructor(query: TQuery);
5
+ }
@@ -1,2 +1,6 @@
1
1
  import { DataModel } from "./DataModel.js";
2
2
  export type DataType<T> = T extends DataModel<infer TData> ? TData : never;
3
+ export type QueryResponseData<T> = {
4
+ items: readonly T[];
5
+ totalCount: number;
6
+ };
@@ -4,6 +4,7 @@ import { CustomerBehaviors } from "../customer/Customer/behaviors/index.js";
4
4
  import { IngressBehaviors } from "../domain/Ingress/behaviors/index.js";
5
5
  import { AppInstallationBehaviors } from "../app/AppInstallation/behaviors/index.js";
6
6
  interface Config {
7
+ defaultPaginationLimit: number;
7
8
  behaviors: {
8
9
  project: ProjectBehaviors;
9
10
  server: ServerBehaviors;
@@ -1,13 +1,22 @@
1
1
  import { DataModel } from "../../base/DataModel.js";
2
2
  import { ReferenceModel } from "../../base/ReferenceModel.js";
3
- import type { AsyncResourceVariant } from "../../lib/provideReact.js";
4
- import { CustomerListItemData, CustomerData } from "./types.js";
3
+ import { AsyncResourceVariant } from "../../lib/provideReact.js";
4
+ import { CustomerListItemData, CustomerData, CustomerListQueryData } from "./types.js";
5
+ import { ListQueryModel } from "../../base/ListQueryModel.js";
6
+ import { ListDataModel } from "../../base/ListDataModel.js";
7
+ import { ServerListQuery } from "../../server/index.js";
8
+ import { ProjectListQuery } from "../../project/index.js";
5
9
  export declare class Customer extends ReferenceModel {
10
+ readonly servers: ServerListQuery;
11
+ readonly projects: ProjectListQuery;
12
+ constructor(id: string);
6
13
  static ofId(id: string): Customer;
7
14
  static find: ((id: string) => Promise<CustomerDetailed | undefined>) & {
8
15
  asResource: (id: string) => import("@mittwald/react-use-promise").AsyncResource<CustomerDetailed | undefined>;
9
16
  use: (id: string) => CustomerDetailed | undefined;
10
17
  };
18
+ static query(query?: CustomerListQueryData): CustomerListQuery;
19
+ /** @deprecated Use query() */
11
20
  static list: ((query?: import("@mittwald/api-client").MittwaldAPIV2.Paths.V2Customers.Get.Parameters.Query | undefined) => Promise<readonly CustomerListItem[]>) & {
12
21
  asResource: (query?: import("@mittwald/api-client").MittwaldAPIV2.Paths.V2Customers.Get.Parameters.Query | undefined) => import("@mittwald/react-use-promise").AsyncResource<readonly CustomerListItem[]>;
13
22
  use: (query?: import("@mittwald/api-client").MittwaldAPIV2.Paths.V2Customers.Get.Parameters.Query | undefined) => readonly CustomerListItem[];
@@ -109,4 +118,26 @@ declare const CustomerListItem_base: import("polytype").Polytype.ClusteredConstr
109
118
  export declare class CustomerListItem extends CustomerListItem_base {
110
119
  constructor(data: CustomerListItemData);
111
120
  }
121
+ export declare class CustomerListQuery extends ListQueryModel<CustomerListQueryData> {
122
+ constructor(query?: CustomerListQueryData);
123
+ refine(query: CustomerListQueryData): CustomerListQuery;
124
+ execute: (() => Promise<CustomerList>) & {
125
+ asResource: () => import("@mittwald/react-use-promise").AsyncResource<CustomerList>;
126
+ use: () => CustomerList;
127
+ };
128
+ getTotalCount: (() => Promise<number>) & {
129
+ asResource: () => import("@mittwald/react-use-promise").AsyncResource<number>;
130
+ use: () => number;
131
+ };
132
+ findOneAndOnly: (() => Promise<CustomerListItem | undefined>) & {
133
+ asResource: () => import("@mittwald/react-use-promise").AsyncResource<CustomerListItem | undefined>;
134
+ use: () => CustomerListItem | undefined;
135
+ };
136
+ }
137
+ declare const CustomerList_base: import("polytype").Polytype.ClusteredConstructor<[typeof CustomerListQuery, {
138
+ new (items: CustomerListItem[], totalCount: number): ListDataModel<CustomerListItem>;
139
+ }]>;
140
+ export declare class CustomerList extends CustomerList_base {
141
+ constructor(query: CustomerListQueryData, customers: CustomerListItem[], totalCount: number);
142
+ }
112
143
  export {};
@@ -1,5 +1,6 @@
1
- import { CustomerListItemData, CustomerData, CustomerListQuery } from "../types.js";
1
+ import { CustomerListItemData, CustomerData, CustomerListQueryData } from "../types.js";
2
+ import { QueryResponseData } from "../../../base/index.js";
2
3
  export interface CustomerBehaviors {
3
4
  find: (id: string) => Promise<CustomerData | undefined>;
4
- list: (query?: CustomerListQuery) => Promise<CustomerListItemData[]>;
5
+ list: (query?: CustomerListQueryData) => Promise<QueryResponseData<CustomerListItemData>>;
5
6
  }
@@ -1,4 +1,4 @@
1
1
  import { MittwaldAPIV2 } from "@mittwald/api-client";
2
- export type CustomerListQuery = MittwaldAPIV2.Paths.V2Customers.Get.Parameters.Query;
2
+ export type CustomerListQueryData = MittwaldAPIV2.Paths.V2Customers.Get.Parameters.Query;
3
3
  export type CustomerData = MittwaldAPIV2.Operations.CustomerGetCustomer.ResponseData;
4
4
  export type CustomerListItemData = MittwaldAPIV2.Operations.CustomerListCustomers.ResponseData[number];
@@ -1,14 +1,17 @@
1
1
  import { DataModel } from "../../base/DataModel.js";
2
2
  import { ReferenceModel } from "../../base/ReferenceModel.js";
3
3
  import type { AsyncResourceVariant } from "../../lib/provideReact.js";
4
- import { IngressListItemData, IngressData, IngressListQuery } from "./types.js";
4
+ import { IngressData, IngressListItemData, IngressListQueryModelData } from "./types.js";
5
5
  import { IngressPath } from "../IngressPath/IngressPath.js";
6
+ import { ListQueryModel } from "../../base/ListQueryModel.js";
7
+ import { ListDataModel } from "../../base/ListDataModel.js";
6
8
  export declare class Ingress extends ReferenceModel {
7
9
  static ofId(id: string): Ingress;
8
10
  static ofHostname(hostname: string): Ingress;
9
- static list: ((query?: IngressListQuery | undefined) => Promise<IngressListItem[]>) & {
10
- asResource: (query?: IngressListQuery | undefined) => import("@mittwald/react-use-promise").AsyncResource<IngressListItem[]>;
11
- use: (query?: IngressListQuery | undefined) => IngressListItem[];
11
+ /** @deprecated: use query() or project.ingresses */
12
+ static list: ((query?: import("@mittwald/api-client").MittwaldAPIV2.Paths.V2Ingresses.Get.Parameters.Query | undefined) => Promise<readonly IngressListItem[]>) & {
13
+ asResource: (query?: import("@mittwald/api-client").MittwaldAPIV2.Paths.V2Ingresses.Get.Parameters.Query | undefined) => import("@mittwald/react-use-promise").AsyncResource<readonly IngressListItem[]>;
14
+ use: (query?: import("@mittwald/api-client").MittwaldAPIV2.Paths.V2Ingresses.Get.Parameters.Query | undefined) => readonly IngressListItem[];
12
15
  };
13
16
  static find: ((id: string) => Promise<IngressDetailed | undefined>) & {
14
17
  asResource: (id: string) => import("@mittwald/react-use-promise").AsyncResource<IngressDetailed | undefined>;
@@ -98,4 +101,27 @@ declare const IngressListItem_base: import("polytype").Polytype.ClusteredConstru
98
101
  export declare class IngressListItem extends IngressListItem_base {
99
102
  constructor(data: IngressListItemData);
100
103
  }
104
+ export declare class IngressListQuery extends ListQueryModel<IngressListQueryModelData> {
105
+ constructor(query?: IngressListQueryModelData);
106
+ refine(query?: IngressListQueryModelData): IngressListQuery;
107
+ execute: (() => Promise<IngressList>) & {
108
+ asResource: () => import("@mittwald/react-use-promise").AsyncResource<IngressList>;
109
+ use: () => IngressList;
110
+ };
111
+ getTotalCount: (() => Promise<number>) & {
112
+ asResource: () => import("@mittwald/react-use-promise").AsyncResource<number>;
113
+ use: () => number;
114
+ };
115
+ findOneAndOnly: (() => Promise<IngressListItem | undefined>) & {
116
+ asResource: () => import("@mittwald/react-use-promise").AsyncResource<IngressListItem | undefined>;
117
+ use: () => IngressListItem | undefined;
118
+ };
119
+ }
120
+ declare const IngressList_base: import("polytype").Polytype.ClusteredConstructor<[typeof IngressListQuery, {
121
+ new (items: IngressListItem[], totalCount: number): ListDataModel<IngressListItem>;
122
+ }]>;
123
+ export declare class IngressList extends IngressList_base {
124
+ constructor(query: IngressListQueryModelData, ingresses: IngressListItem[], totalCount: number);
125
+ getDefault(): IngressListItem;
126
+ }
101
127
  export {};
@@ -1,5 +1,6 @@
1
- import { IngressListItemData, IngressData, IngressListQuery } from "../types.js";
1
+ import { IngressListItemData, IngressData, IngressListQueryData } from "../types.js";
2
+ import { QueryResponseData } from "../../../base/index.js";
2
3
  export interface IngressBehaviors {
3
4
  find: (id: string) => Promise<IngressData | undefined>;
4
- list: (query?: IngressListQuery) => Promise<IngressListItemData[]>;
5
+ list: (query?: IngressListQueryData) => Promise<QueryResponseData<IngressListItemData>>;
5
6
  }
@@ -1,6 +1,8 @@
1
1
  import { MittwaldAPIV2 } from "@mittwald/api-client";
2
- export interface IngressListQuery {
3
- projectId?: string;
4
- }
2
+ import { Project } from "../../project/index.js";
3
+ export type IngressListQueryData = MittwaldAPIV2.Paths.V2Ingresses.Get.Parameters.Query;
4
+ export type IngressListQueryModelData = Omit<IngressListQueryData, "projectId"> & {
5
+ project?: Project;
6
+ };
5
7
  export type IngressData = MittwaldAPIV2.Operations.IngressGetIngress.ResponseData;
6
8
  export type IngressListItemData = MittwaldAPIV2.Operations.IngressListIngresses.ResponseData[number];
@@ -1,11 +1,17 @@
1
- import { ProjectListItemData, ProjectData } from "./types.js";
1
+ import { ProjectData, ProjectListItemData, ProjectListQueryModelData } from "./types.js";
2
2
  import { DataModel } from "../../base/DataModel.js";
3
3
  import { Server } from "../../server/index.js";
4
4
  import { type AsyncResourceVariant } from "../../lib/provideReact.js";
5
5
  import { Customer } from "../../customer/Customer/Customer.js";
6
6
  import { ReferenceModel } from "../../base/ReferenceModel.js";
7
- import { IngressListItem } from "../../domain/index.js";
7
+ import { IngressListItem, IngressListQuery } from "../../domain/index.js";
8
+ import { ListQueryModel } from "../../base/ListQueryModel.js";
9
+ import { ListDataModel } from "../../base/ListDataModel.js";
10
+ import { AppInstallationListQuery } from "../../app/index.js";
8
11
  export declare class Project extends ReferenceModel {
12
+ readonly ingresses: IngressListQuery;
13
+ readonly appInstallations: AppInstallationListQuery;
14
+ constructor(id: string);
9
15
  static ofId(id: string): Project;
10
16
  static find: ((id: string) => Promise<ProjectDetailed | undefined>) & {
11
17
  asResource: (id: string) => import("@mittwald/react-use-promise").AsyncResource<ProjectDetailed | undefined>;
@@ -15,6 +21,8 @@ export declare class Project extends ReferenceModel {
15
21
  asResource: (id: string) => import("@mittwald/react-use-promise").AsyncResource<ProjectDetailed>;
16
22
  use: (id: string) => ProjectDetailed;
17
23
  };
24
+ query(query?: ProjectListQueryModelData): ProjectListQuery;
25
+ /** @deprecated: use query(), Customer.projects or Server.projects */
18
26
  static list: ((query?: import("@mittwald/api-client").MittwaldAPIV2.Paths.V2Projects.Get.Parameters.Query | undefined) => Promise<readonly ProjectListItem[]>) & {
19
27
  asResource: (query?: import("@mittwald/api-client").MittwaldAPIV2.Paths.V2Projects.Get.Parameters.Query | undefined) => import("@mittwald/react-use-promise").AsyncResource<readonly ProjectListItem[]>;
20
28
  use: (query?: import("@mittwald/api-client").MittwaldAPIV2.Paths.V2Projects.Get.Parameters.Query | undefined) => readonly ProjectListItem[];
@@ -22,6 +30,7 @@ export declare class Project extends ReferenceModel {
22
30
  static create(serverId: string, description: string): Promise<Project>;
23
31
  getDetailed: AsyncResourceVariant<ProjectDetailed, []>;
24
32
  findDetailed: AsyncResourceVariant<ProjectDetailed | undefined, []>;
33
+ /** @deprecated: use ingresses property */
25
34
  listIngresses: AsyncResourceVariant<IngressListItem[], []>;
26
35
  getDefaultIngress: AsyncResourceVariant<IngressListItem, []>;
27
36
  updateDescription(description: string): Promise<void>;
@@ -30,6 +39,27 @@ export declare class Project extends ReferenceModel {
30
39
  }
31
40
  declare const ProjectCommon_base: import("polytype").Polytype.ClusteredConstructor<[{
32
41
  new (data: {
42
+ createdAt: string;
43
+ customerId: string;
44
+ customerMeta: {
45
+ id: string;
46
+ };
47
+ description: string;
48
+ disableReason?: import("@mittwald/api-client").MittwaldAPIV2.Components.Schemas.ProjectDisableReason;
49
+ disabledAt?: string;
50
+ enabled: boolean;
51
+ id: string;
52
+ imageRefId?: string;
53
+ isReady: boolean;
54
+ projectHostingId?: string;
55
+ readiness: import("@mittwald/api-client").MittwaldAPIV2.Components.Schemas.ProjectDeprecatedProjectReadinessStatus;
56
+ serverId?: string;
57
+ shortId: string;
58
+ status: import("@mittwald/api-client").MittwaldAPIV2.Components.Schemas.ProjectProjectStatus;
59
+ statusSetAt: string;
60
+ webStorageUsageInBytes: number;
61
+ webStorageUsageInBytesSetAt: string;
62
+ } | {
33
63
  clusterDomain?: string | undefined;
34
64
  clusterID?: string | undefined;
35
65
  clusterId?: string | undefined;
@@ -56,7 +86,7 @@ declare const ProjectCommon_base: import("polytype").Polytype.ClusteredConstruct
56
86
  statusSetAt: string;
57
87
  webStorageUsageInBytes: number;
58
88
  webStorageUsageInBytesSetAt: string;
59
- } | {
89
+ }): DataModel<{
60
90
  createdAt: string;
61
91
  customerId: string;
62
92
  customerMeta: {
@@ -77,7 +107,7 @@ declare const ProjectCommon_base: import("polytype").Polytype.ClusteredConstruct
77
107
  statusSetAt: string;
78
108
  webStorageUsageInBytes: number;
79
109
  webStorageUsageInBytesSetAt: string;
80
- }): DataModel<{
110
+ } | {
81
111
  clusterDomain?: string | undefined;
82
112
  clusterID?: string | undefined;
83
113
  clusterId?: string | undefined;
@@ -104,27 +134,6 @@ declare const ProjectCommon_base: import("polytype").Polytype.ClusteredConstruct
104
134
  statusSetAt: string;
105
135
  webStorageUsageInBytes: number;
106
136
  webStorageUsageInBytesSetAt: string;
107
- } | {
108
- createdAt: string;
109
- customerId: string;
110
- customerMeta: {
111
- id: string;
112
- };
113
- description: string;
114
- disableReason?: import("@mittwald/api-client").MittwaldAPIV2.Components.Schemas.ProjectDisableReason;
115
- disabledAt?: string;
116
- enabled: boolean;
117
- id: string;
118
- imageRefId?: string;
119
- isReady: boolean;
120
- projectHostingId?: string;
121
- readiness: import("@mittwald/api-client").MittwaldAPIV2.Components.Schemas.ProjectDeprecatedProjectReadinessStatus;
122
- serverId?: string;
123
- shortId: string;
124
- status: import("@mittwald/api-client").MittwaldAPIV2.Components.Schemas.ProjectProjectStatus;
125
- statusSetAt: string;
126
- webStorageUsageInBytes: number;
127
- webStorageUsageInBytesSetAt: string;
128
137
  }>;
129
138
  }, typeof Project]>;
130
139
  declare class ProjectCommon extends ProjectCommon_base {
@@ -240,4 +249,26 @@ declare const ProjectListItem_base: import("polytype").Polytype.ClusteredConstru
240
249
  export declare class ProjectListItem extends ProjectListItem_base {
241
250
  constructor(data: ProjectListItemData);
242
251
  }
252
+ export declare class ProjectListQuery extends ListQueryModel<ProjectListQueryModelData> {
253
+ constructor(query?: ProjectListQueryModelData);
254
+ refine(query: ProjectListQueryModelData): ProjectListQuery;
255
+ execute: (() => Promise<ProjectList>) & {
256
+ asResource: () => import("@mittwald/react-use-promise").AsyncResource<ProjectList>;
257
+ use: () => ProjectList;
258
+ };
259
+ getTotalCount: (() => Promise<number>) & {
260
+ asResource: () => import("@mittwald/react-use-promise").AsyncResource<number>;
261
+ use: () => number;
262
+ };
263
+ findOneAndOnly: (() => Promise<ProjectListItem | undefined>) & {
264
+ asResource: () => import("@mittwald/react-use-promise").AsyncResource<ProjectListItem | undefined>;
265
+ use: () => ProjectListItem | undefined;
266
+ };
267
+ }
268
+ declare const ProjectList_base: import("polytype").Polytype.ClusteredConstructor<[typeof ProjectListQuery, {
269
+ new (items: ProjectListItem[], totalCount: number): ListDataModel<ProjectListItem>;
270
+ }]>;
271
+ export declare class ProjectList extends ProjectList_base {
272
+ constructor(query: ProjectListQueryModelData, projects: ProjectListItem[], totalCount: number);
273
+ }
243
274
  export {};
@@ -1,7 +1,8 @@
1
- import { ProjectListItemData, ProjectData, ProjectListQuery } from "../types.js";
1
+ import { ProjectListItemData, ProjectData, ProjectListQueryData } from "../types.js";
2
+ import { QueryResponseData } from "../../../base/index.js";
2
3
  export interface ProjectBehaviors {
3
4
  find: (id: string) => Promise<ProjectData | undefined>;
4
- list: (query?: ProjectListQuery) => Promise<ProjectListItemData[]>;
5
+ list: (query?: ProjectListQueryData) => Promise<QueryResponseData<ProjectListItemData>>;
5
6
  create: (serverId: string, description: string) => Promise<{
6
7
  id: string;
7
8
  }>;
@@ -1,4 +1,10 @@
1
1
  import { MittwaldAPIV2 } from "@mittwald/api-client";
2
- export type ProjectListQuery = MittwaldAPIV2.Paths.V2Projects.Get.Parameters.Query;
2
+ import { Server } from "../../server/index.js";
3
+ import { Customer } from "../../customer/index.js";
4
+ export type ProjectListQueryData = MittwaldAPIV2.Paths.V2Projects.Get.Parameters.Query;
5
+ export type ProjectListQueryModelData = Omit<ProjectListQueryData, "serverId" | "customerId"> & {
6
+ server?: Server;
7
+ customer?: Customer;
8
+ };
3
9
  export type ProjectData = MittwaldAPIV2.Operations.ProjectGetProject.ResponseData;
4
10
  export type ProjectListItemData = MittwaldAPIV2.Operations.ProjectListProjects.ResponseData[number];
@@ -1,10 +1,14 @@
1
1
  import { ReferenceModel } from "../../base/ReferenceModel.js";
2
- import { ServerData, ServerListItemData } from "./types.js";
2
+ import { ServerData, ServerListItemData, ServerListQueryData, ServerListQueryModelData } from "./types.js";
3
3
  import { DataModel } from "../../base/DataModel.js";
4
- import { Project } from "../../project/index.js";
4
+ import { Project, ProjectListQuery } from "../../project/index.js";
5
5
  import { ParamsExceptFirst } from "../../lib/types.js";
6
6
  import { AsyncResourceVariant } from "../../lib/provideReact.js";
7
+ import { ListQueryModel } from "../../base/ListQueryModel.js";
8
+ import { ListDataModel } from "../../base/ListDataModel.js";
7
9
  export declare class Server extends ReferenceModel {
10
+ readonly projects: ProjectListQuery;
11
+ constructor(id: string);
8
12
  static ofId(id: string): Server;
9
13
  static find: ((id: string) => Promise<ServerDetailed | undefined>) & {
10
14
  asResource: (id: string) => import("@mittwald/react-use-promise").AsyncResource<ServerDetailed | undefined>;
@@ -14,11 +18,14 @@ export declare class Server extends ReferenceModel {
14
18
  asResource: (id: string) => import("@mittwald/react-use-promise").AsyncResource<ServerDetailed>;
15
19
  use: (id: string) => ServerDetailed;
16
20
  };
17
- static list: ((query?: import("@mittwald/api-client").MittwaldAPIV2.Paths.V2Servers.Get.Parameters.Query | undefined) => Promise<ServerListItem[]>) & {
18
- asResource: (query?: import("@mittwald/api-client").MittwaldAPIV2.Paths.V2Servers.Get.Parameters.Query | undefined) => import("@mittwald/react-use-promise").AsyncResource<ServerListItem[]>;
19
- use: (query?: import("@mittwald/api-client").MittwaldAPIV2.Paths.V2Servers.Get.Parameters.Query | undefined) => ServerListItem[];
21
+ static query(query?: ServerListQueryModelData): ServerListQuery;
22
+ /** @deprecated: use query() or customer.servers */
23
+ static list: ((query?: import("@mittwald/api-client").MittwaldAPIV2.Paths.V2Servers.Get.Parameters.Query | undefined) => Promise<readonly ServerListItem[]>) & {
24
+ asResource: (query?: import("@mittwald/api-client").MittwaldAPIV2.Paths.V2Servers.Get.Parameters.Query | undefined) => import("@mittwald/react-use-promise").AsyncResource<readonly ServerListItem[]>;
25
+ use: (query?: import("@mittwald/api-client").MittwaldAPIV2.Paths.V2Servers.Get.Parameters.Query | undefined) => readonly ServerListItem[];
20
26
  };
21
27
  createProject(...parameters: ParamsExceptFirst<typeof Project.create>): ReturnType<typeof Project.create>;
28
+ /** @deprecated Use Server.projects property */
22
29
  listProjects: ((query?: Omit<import("@mittwald/api-client").MittwaldAPIV2.Paths.V2Projects.Get.Parameters.Query | undefined, "serverId"> | undefined) => Promise<readonly import("../../project/index.js").ProjectListItem[]>) & {
23
30
  asResource: (query?: Omit<import("@mittwald/api-client").MittwaldAPIV2.Paths.V2Projects.Get.Parameters.Query | undefined, "serverId"> | undefined) => import("@mittwald/react-use-promise").AsyncResource<readonly import("../../project/index.js").ProjectListItem[]>;
24
31
  use: (query?: Omit<import("@mittwald/api-client").MittwaldAPIV2.Paths.V2Projects.Get.Parameters.Query | undefined, "serverId"> | undefined) => readonly import("../../project/index.js").ProjectListItem[];
@@ -104,4 +111,26 @@ declare const ServerListItem_base: import("polytype").Polytype.ClusteredConstruc
104
111
  export declare class ServerListItem extends ServerListItem_base {
105
112
  constructor(data: ServerListItemData);
106
113
  }
114
+ export declare class ServerListQuery extends ListQueryModel<ServerListQueryModelData> {
115
+ constructor(query?: ServerListQueryModelData);
116
+ refine(query: ServerListQueryModelData): ServerListQuery;
117
+ execute: (() => Promise<ServerList>) & {
118
+ asResource: () => import("@mittwald/react-use-promise").AsyncResource<ServerList>;
119
+ use: () => ServerList;
120
+ };
121
+ getTotalCount: (() => Promise<number>) & {
122
+ asResource: () => import("@mittwald/react-use-promise").AsyncResource<number>;
123
+ use: () => number;
124
+ };
125
+ findOneAndOnly: (() => Promise<ServerListItem | undefined>) & {
126
+ asResource: () => import("@mittwald/react-use-promise").AsyncResource<ServerListItem | undefined>;
127
+ use: () => ServerListItem | undefined;
128
+ };
129
+ }
130
+ declare const ServerList_base: import("polytype").Polytype.ClusteredConstructor<[typeof ServerListQuery, {
131
+ new (items: ServerListItem[], totalCount: number): ListDataModel<ServerListItem>;
132
+ }]>;
133
+ export declare class ServerList extends ServerList_base {
134
+ constructor(query: ServerListQueryData, servers: ServerListItem[], totalCount: number);
135
+ }
107
136
  export {};
@@ -1,5 +1,6 @@
1
- import { ServerListItemData, ServerData, ServerListQuery } from "../types.js";
1
+ import { ServerListItemData, ServerData, ServerListQueryData } from "../types.js";
2
+ import { QueryResponseData } from "../../../base/index.js";
2
3
  export interface ServerBehaviors {
3
4
  find: (id: string) => Promise<ServerData | undefined>;
4
- list: (query?: ServerListQuery) => Promise<ServerListItemData[]>;
5
+ list: (query?: ServerListQueryData) => Promise<QueryResponseData<ServerListItemData>>;
5
6
  }
@@ -1,4 +1,8 @@
1
1
  import { MittwaldAPIV2 } from "@mittwald/api-client";
2
- export type ServerListQuery = MittwaldAPIV2.Paths.V2Servers.Get.Parameters.Query;
2
+ import { Customer } from "../../customer/index.js";
3
+ export type ServerListQueryData = MittwaldAPIV2.Paths.V2Servers.Get.Parameters.Query;
4
+ export type ServerListQueryModelData = Omit<ServerListQueryData, "customerId"> & {
5
+ customer?: Customer;
6
+ };
3
7
  export type ServerData = MittwaldAPIV2.Operations.ProjectGetServer.ResponseData;
4
8
  export type ServerListItemData = MittwaldAPIV2.Operations.ProjectListServers.ResponseData[number];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mittwald/api-models",
3
- "version": "4.54.0",
3
+ "version": "4.55.0",
4
4
  "author": "Mittwald CM Service GmbH & Co. KG <opensource@mittwald.de>",
5
5
  "type": "module",
6
6
  "description": "Collection of domain models for coherent interaction with the API",
@@ -39,8 +39,9 @@
39
39
  "test:unit": "node --experimental-vm-modules $(yarn bin jest)"
40
40
  },
41
41
  "dependencies": {
42
- "@mittwald/api-client": "^4.53.0",
42
+ "@mittwald/api-client": "^4.55.0",
43
43
  "another-deep-freeze": "^1.0.0",
44
+ "object-code": "^1.3.3",
44
45
  "polytype": "^0.17.0",
45
46
  "type-fest": "^4.23.0"
46
47
  },
@@ -73,5 +74,5 @@
73
74
  "optional": true
74
75
  }
75
76
  },
76
- "gitHead": "7a402b9e0f16e0412eb6791eabb61a4f695e1557"
77
+ "gitHead": "29dc540f1f5b407220608e22b966a103b593ae55"
77
78
  }