@leodamours/jsonapi-client 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -0
- package/dist/index.d.mts +66 -20
- package/dist/index.d.ts +66 -20
- package/dist/index.js +63 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +55 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -147,6 +147,105 @@ await api.findAll(User, {
|
|
|
147
147
|
});
|
|
148
148
|
```
|
|
149
149
|
|
|
150
|
+
## Response Deserialization
|
|
151
|
+
|
|
152
|
+
Client methods return raw JSON:API documents with nested structure (`data.attributes`, `data.relationships`). Use `deserialize` / `deserializeMany` from the DSL to flatten them into plain objects (also re-exported from this package for convenience):
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import { deserialize, deserializeMany } from "@leodamours/jsonapi-dsl";
|
|
156
|
+
|
|
157
|
+
const doc = await api.findOne(Post, "1", { include: "author,comments" });
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Without registry** — relationships stay as `{ type, id }` linkage:
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
const { data: post } = deserialize(Post, doc);
|
|
164
|
+
post.id; // string
|
|
165
|
+
post.type; // "posts"
|
|
166
|
+
post.title; // string (was doc.data.attributes.title)
|
|
167
|
+
post.author; // { type: "users"; id: string } | null
|
|
168
|
+
post.comments; // { type: "comments"; id: string }[]
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**With registry** — relationships resolved one level from `included`:
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
const { data: post } = deserialize(Post, doc, {
|
|
175
|
+
users: User,
|
|
176
|
+
comments: Comment,
|
|
177
|
+
});
|
|
178
|
+
post.author.name; // string — resolved from included
|
|
179
|
+
post.author.email; // string
|
|
180
|
+
post.comments[0].body; // string — resolved from included
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Resolution is **one level deep**: a resolved author's own relationships (e.g. `company`) remain as `{ type, id }` linkage. If a relationship's type isn't in the registry or the resource isn't in `included`, it falls back to linkage.
|
|
184
|
+
|
|
185
|
+
**Collections:**
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
const allPosts = await api.findAll(Post, {
|
|
189
|
+
page: { size: 10 },
|
|
190
|
+
include: "author",
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
const { data: posts, meta, links } = deserializeMany(Post, allPosts, {
|
|
194
|
+
users: User,
|
|
195
|
+
});
|
|
196
|
+
// posts[0].title — string
|
|
197
|
+
// posts[0].author — resolved User or linkage
|
|
198
|
+
// meta, links — preserved from document
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Deserialization types** for standalone use:
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
import type {
|
|
205
|
+
Deserialized,
|
|
206
|
+
DeserializedWith,
|
|
207
|
+
DeserializeResult,
|
|
208
|
+
DeserializeManyResult,
|
|
209
|
+
} from "@leodamours/jsonapi-dsl";
|
|
210
|
+
|
|
211
|
+
type FlatPost = Deserialized<typeof Post>;
|
|
212
|
+
// { id: string; type: "posts"; title: string; content: string; author: { type: "users"; id: string } | null; ... }
|
|
213
|
+
|
|
214
|
+
type ResolvedPost = DeserializedWith<typeof Post, { users: typeof User }>;
|
|
215
|
+
// { id: string; type: "posts"; title: string; author: Deserialized<typeof User> | null; ... }
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Relationship Endpoints
|
|
219
|
+
|
|
220
|
+
Manipulate relationships directly via [JSON:API relationship endpoints](https://jsonapi.org/format/#crud-updating-relationships) without touching the resource itself:
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
// GET — read relationship linkage
|
|
224
|
+
const rel = await api.getRelationship(Post, "1", "comments");
|
|
225
|
+
rel.data; // { type: "comments"; id: string }[]
|
|
226
|
+
|
|
227
|
+
// POST — add members to a to-many relationship
|
|
228
|
+
await api.addRelationship(Post, "1", "comments", [
|
|
229
|
+
{ type: "comments", id: "10" },
|
|
230
|
+
]);
|
|
231
|
+
|
|
232
|
+
// PATCH — replace a relationship entirely
|
|
233
|
+
await api.replaceRelationship(Post, "1", "author", {
|
|
234
|
+
type: "users",
|
|
235
|
+
id: "2",
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// PATCH — clear a to-one relationship
|
|
239
|
+
await api.replaceRelationship(Post, "1", "author", null);
|
|
240
|
+
|
|
241
|
+
// DELETE — remove members from a to-many relationship
|
|
242
|
+
await api.removeRelationship(Post, "1", "comments", [
|
|
243
|
+
{ type: "comments", id: "10" },
|
|
244
|
+
]);
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
All relationship methods operate on `/{resourceType}/{id}/relationships/{name}` and return a `RelationshipResponse` with the updated linkage.
|
|
248
|
+
|
|
150
249
|
## Type-Safe Included Resources
|
|
151
250
|
|
|
152
251
|
When using `include`, the response's `included` array contains mixed resource types. Use `isResourceOf` from the DSL to narrow them:
|
package/dist/index.d.mts
CHANGED
|
@@ -1,24 +1,7 @@
|
|
|
1
1
|
import { AxiosRequestConfig, AxiosInstance } from 'axios';
|
|
2
|
-
import { ResourceDefinition, InferAttributesSimple, RelationshipsSchema, JsonApiDocument, InferResource, JsonApiCollectionDocument, JsonApiRelationships } from '@leodamours/jsonapi-dsl';
|
|
2
|
+
import { ResourceDefinition, InferAttributesSimple, SimplifiedRelationships, JsonApiLinks, JsonApiMeta, RelationshipsSchema, JsonApiDocument, InferResource, JsonApiCollectionDocument, JsonApiRelationships } from '@leodamours/jsonapi-dsl';
|
|
3
|
+
export { DeserializeManyResult, DeserializeResult, Deserialized, DeserializedWith, ResourceRegistry, SimplifiedHasMany, SimplifiedHasOne, SimplifiedRelationships, deserialize, deserializeMany } from '@leodamours/jsonapi-dsl';
|
|
3
4
|
|
|
4
|
-
type SimplifiedHasOne<T extends string> = {
|
|
5
|
-
type: T;
|
|
6
|
-
id: string;
|
|
7
|
-
} | null;
|
|
8
|
-
type SimplifiedHasMany<T extends string> = Array<{
|
|
9
|
-
type: T;
|
|
10
|
-
id: string;
|
|
11
|
-
}>;
|
|
12
|
-
/**
|
|
13
|
-
* Indexed lookup for simplified relationship shapes — avoids conditional types.
|
|
14
|
-
*/
|
|
15
|
-
interface SimplifiedRelTypeMap<T extends string> {
|
|
16
|
-
one: SimplifiedHasOne<T>;
|
|
17
|
-
many: SimplifiedHasMany<T>;
|
|
18
|
-
}
|
|
19
|
-
type SimplifiedRelationships<Schema extends RelationshipsSchema> = {
|
|
20
|
-
[K in keyof Schema]: SimplifiedRelTypeMap<Schema[K]["type"]>[Schema[K]["_rel"]];
|
|
21
|
-
};
|
|
22
5
|
type RelationshipClause<Rels extends RelationshipsSchema> = {
|
|
23
6
|
relationships?: Partial<SimplifiedRelationships<Rels>>;
|
|
24
7
|
};
|
|
@@ -62,6 +45,26 @@ interface QueryParams {
|
|
|
62
45
|
fields?: Record<string, string | string[]>;
|
|
63
46
|
[key: string]: unknown;
|
|
64
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Resource linkage — the `data` member of a relationship object.
|
|
50
|
+
* Used by relationship endpoint methods.
|
|
51
|
+
*/
|
|
52
|
+
type ResourceLinkage = {
|
|
53
|
+
type: string;
|
|
54
|
+
id: string;
|
|
55
|
+
} | {
|
|
56
|
+
type: string;
|
|
57
|
+
id: string;
|
|
58
|
+
}[] | null;
|
|
59
|
+
/**
|
|
60
|
+
* Response from a relationship endpoint
|
|
61
|
+
* (GET/POST/PATCH/DELETE on /{type}/{id}/relationships/{rel}).
|
|
62
|
+
*/
|
|
63
|
+
interface RelationshipResponse {
|
|
64
|
+
data: ResourceLinkage;
|
|
65
|
+
links?: JsonApiLinks;
|
|
66
|
+
meta?: JsonApiMeta;
|
|
67
|
+
}
|
|
65
68
|
|
|
66
69
|
declare class JsonApiClient {
|
|
67
70
|
private axios;
|
|
@@ -86,6 +89,31 @@ declare class JsonApiClient {
|
|
|
86
89
|
* DELETE /{resourceType}/{id}
|
|
87
90
|
*/
|
|
88
91
|
remove(definition: ResourceDefinition, id: string, options?: AxiosRequestConfig): Promise<void>;
|
|
92
|
+
/**
|
|
93
|
+
* GET /{resourceType}/{id}/relationships/{relationshipName}
|
|
94
|
+
*/
|
|
95
|
+
getRelationship(definition: ResourceDefinition, id: string, relationshipName: string, options?: AxiosRequestConfig): Promise<RelationshipResponse>;
|
|
96
|
+
/**
|
|
97
|
+
* POST /{resourceType}/{id}/relationships/{relationshipName}
|
|
98
|
+
* Add members to a to-many relationship.
|
|
99
|
+
*/
|
|
100
|
+
addRelationship(definition: ResourceDefinition, id: string, relationshipName: string, data: {
|
|
101
|
+
type: string;
|
|
102
|
+
id: string;
|
|
103
|
+
}[], options?: AxiosRequestConfig): Promise<RelationshipResponse>;
|
|
104
|
+
/**
|
|
105
|
+
* PATCH /{resourceType}/{id}/relationships/{relationshipName}
|
|
106
|
+
* Replace a relationship entirely.
|
|
107
|
+
*/
|
|
108
|
+
replaceRelationship(definition: ResourceDefinition, id: string, relationshipName: string, data: ResourceLinkage, options?: AxiosRequestConfig): Promise<RelationshipResponse>;
|
|
109
|
+
/**
|
|
110
|
+
* DELETE /{resourceType}/{id}/relationships/{relationshipName}
|
|
111
|
+
* Remove members from a to-many relationship.
|
|
112
|
+
*/
|
|
113
|
+
removeRelationship(definition: ResourceDefinition, id: string, relationshipName: string, data: {
|
|
114
|
+
type: string;
|
|
115
|
+
id: string;
|
|
116
|
+
}[], options?: AxiosRequestConfig): Promise<RelationshipResponse>;
|
|
89
117
|
/**
|
|
90
118
|
* Update client configuration at runtime.
|
|
91
119
|
*/
|
|
@@ -126,5 +154,23 @@ declare function serializeUpdatePayload(definition: ResourceDefinition, id: stri
|
|
|
126
154
|
* `{ sort: ["-createdAt", "title"] }` → `"sort=-createdAt,title"`
|
|
127
155
|
*/
|
|
128
156
|
declare function serializeQueryParams(params: Record<string, unknown>): Record<string, string>;
|
|
157
|
+
/**
|
|
158
|
+
* Wrap resource linkage in a JSON:API request body for relationship endpoints.
|
|
159
|
+
*/
|
|
160
|
+
declare function serializeRelationshipPayload(data: {
|
|
161
|
+
type: string;
|
|
162
|
+
id: string;
|
|
163
|
+
} | {
|
|
164
|
+
type: string;
|
|
165
|
+
id: string;
|
|
166
|
+
}[] | null): {
|
|
167
|
+
data: {
|
|
168
|
+
type: string;
|
|
169
|
+
id: string;
|
|
170
|
+
} | {
|
|
171
|
+
type: string;
|
|
172
|
+
id: string;
|
|
173
|
+
}[] | null;
|
|
174
|
+
};
|
|
129
175
|
|
|
130
|
-
export { type ClientConfig, type CreatePayload, JsonApiClient, type QueryParams, type RelationshipClause, type
|
|
176
|
+
export { type ClientConfig, type CreatePayload, JsonApiClient, type QueryParams, type RelationshipClause, type RelationshipResponse, type ResourceLinkage, type UpdatePayload, createClient, serializeCreatePayload, serializeQueryParams, serializeRelationshipPayload, serializeRelationships, serializeUpdatePayload };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,24 +1,7 @@
|
|
|
1
1
|
import { AxiosRequestConfig, AxiosInstance } from 'axios';
|
|
2
|
-
import { ResourceDefinition, InferAttributesSimple, RelationshipsSchema, JsonApiDocument, InferResource, JsonApiCollectionDocument, JsonApiRelationships } from '@leodamours/jsonapi-dsl';
|
|
2
|
+
import { ResourceDefinition, InferAttributesSimple, SimplifiedRelationships, JsonApiLinks, JsonApiMeta, RelationshipsSchema, JsonApiDocument, InferResource, JsonApiCollectionDocument, JsonApiRelationships } from '@leodamours/jsonapi-dsl';
|
|
3
|
+
export { DeserializeManyResult, DeserializeResult, Deserialized, DeserializedWith, ResourceRegistry, SimplifiedHasMany, SimplifiedHasOne, SimplifiedRelationships, deserialize, deserializeMany } from '@leodamours/jsonapi-dsl';
|
|
3
4
|
|
|
4
|
-
type SimplifiedHasOne<T extends string> = {
|
|
5
|
-
type: T;
|
|
6
|
-
id: string;
|
|
7
|
-
} | null;
|
|
8
|
-
type SimplifiedHasMany<T extends string> = Array<{
|
|
9
|
-
type: T;
|
|
10
|
-
id: string;
|
|
11
|
-
}>;
|
|
12
|
-
/**
|
|
13
|
-
* Indexed lookup for simplified relationship shapes — avoids conditional types.
|
|
14
|
-
*/
|
|
15
|
-
interface SimplifiedRelTypeMap<T extends string> {
|
|
16
|
-
one: SimplifiedHasOne<T>;
|
|
17
|
-
many: SimplifiedHasMany<T>;
|
|
18
|
-
}
|
|
19
|
-
type SimplifiedRelationships<Schema extends RelationshipsSchema> = {
|
|
20
|
-
[K in keyof Schema]: SimplifiedRelTypeMap<Schema[K]["type"]>[Schema[K]["_rel"]];
|
|
21
|
-
};
|
|
22
5
|
type RelationshipClause<Rels extends RelationshipsSchema> = {
|
|
23
6
|
relationships?: Partial<SimplifiedRelationships<Rels>>;
|
|
24
7
|
};
|
|
@@ -62,6 +45,26 @@ interface QueryParams {
|
|
|
62
45
|
fields?: Record<string, string | string[]>;
|
|
63
46
|
[key: string]: unknown;
|
|
64
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Resource linkage — the `data` member of a relationship object.
|
|
50
|
+
* Used by relationship endpoint methods.
|
|
51
|
+
*/
|
|
52
|
+
type ResourceLinkage = {
|
|
53
|
+
type: string;
|
|
54
|
+
id: string;
|
|
55
|
+
} | {
|
|
56
|
+
type: string;
|
|
57
|
+
id: string;
|
|
58
|
+
}[] | null;
|
|
59
|
+
/**
|
|
60
|
+
* Response from a relationship endpoint
|
|
61
|
+
* (GET/POST/PATCH/DELETE on /{type}/{id}/relationships/{rel}).
|
|
62
|
+
*/
|
|
63
|
+
interface RelationshipResponse {
|
|
64
|
+
data: ResourceLinkage;
|
|
65
|
+
links?: JsonApiLinks;
|
|
66
|
+
meta?: JsonApiMeta;
|
|
67
|
+
}
|
|
65
68
|
|
|
66
69
|
declare class JsonApiClient {
|
|
67
70
|
private axios;
|
|
@@ -86,6 +89,31 @@ declare class JsonApiClient {
|
|
|
86
89
|
* DELETE /{resourceType}/{id}
|
|
87
90
|
*/
|
|
88
91
|
remove(definition: ResourceDefinition, id: string, options?: AxiosRequestConfig): Promise<void>;
|
|
92
|
+
/**
|
|
93
|
+
* GET /{resourceType}/{id}/relationships/{relationshipName}
|
|
94
|
+
*/
|
|
95
|
+
getRelationship(definition: ResourceDefinition, id: string, relationshipName: string, options?: AxiosRequestConfig): Promise<RelationshipResponse>;
|
|
96
|
+
/**
|
|
97
|
+
* POST /{resourceType}/{id}/relationships/{relationshipName}
|
|
98
|
+
* Add members to a to-many relationship.
|
|
99
|
+
*/
|
|
100
|
+
addRelationship(definition: ResourceDefinition, id: string, relationshipName: string, data: {
|
|
101
|
+
type: string;
|
|
102
|
+
id: string;
|
|
103
|
+
}[], options?: AxiosRequestConfig): Promise<RelationshipResponse>;
|
|
104
|
+
/**
|
|
105
|
+
* PATCH /{resourceType}/{id}/relationships/{relationshipName}
|
|
106
|
+
* Replace a relationship entirely.
|
|
107
|
+
*/
|
|
108
|
+
replaceRelationship(definition: ResourceDefinition, id: string, relationshipName: string, data: ResourceLinkage, options?: AxiosRequestConfig): Promise<RelationshipResponse>;
|
|
109
|
+
/**
|
|
110
|
+
* DELETE /{resourceType}/{id}/relationships/{relationshipName}
|
|
111
|
+
* Remove members from a to-many relationship.
|
|
112
|
+
*/
|
|
113
|
+
removeRelationship(definition: ResourceDefinition, id: string, relationshipName: string, data: {
|
|
114
|
+
type: string;
|
|
115
|
+
id: string;
|
|
116
|
+
}[], options?: AxiosRequestConfig): Promise<RelationshipResponse>;
|
|
89
117
|
/**
|
|
90
118
|
* Update client configuration at runtime.
|
|
91
119
|
*/
|
|
@@ -126,5 +154,23 @@ declare function serializeUpdatePayload(definition: ResourceDefinition, id: stri
|
|
|
126
154
|
* `{ sort: ["-createdAt", "title"] }` → `"sort=-createdAt,title"`
|
|
127
155
|
*/
|
|
128
156
|
declare function serializeQueryParams(params: Record<string, unknown>): Record<string, string>;
|
|
157
|
+
/**
|
|
158
|
+
* Wrap resource linkage in a JSON:API request body for relationship endpoints.
|
|
159
|
+
*/
|
|
160
|
+
declare function serializeRelationshipPayload(data: {
|
|
161
|
+
type: string;
|
|
162
|
+
id: string;
|
|
163
|
+
} | {
|
|
164
|
+
type: string;
|
|
165
|
+
id: string;
|
|
166
|
+
}[] | null): {
|
|
167
|
+
data: {
|
|
168
|
+
type: string;
|
|
169
|
+
id: string;
|
|
170
|
+
} | {
|
|
171
|
+
type: string;
|
|
172
|
+
id: string;
|
|
173
|
+
}[] | null;
|
|
174
|
+
};
|
|
129
175
|
|
|
130
|
-
export { type ClientConfig, type CreatePayload, JsonApiClient, type QueryParams, type RelationshipClause, type
|
|
176
|
+
export { type ClientConfig, type CreatePayload, JsonApiClient, type QueryParams, type RelationshipClause, type RelationshipResponse, type ResourceLinkage, type UpdatePayload, createClient, serializeCreatePayload, serializeQueryParams, serializeRelationshipPayload, serializeRelationships, serializeUpdatePayload };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var axios = require('axios');
|
|
4
|
+
var jsonapiDsl = require('@leodamours/jsonapi-dsl');
|
|
4
5
|
|
|
5
6
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
6
7
|
|
|
@@ -64,6 +65,9 @@ function serializeQueryParams(params) {
|
|
|
64
65
|
}
|
|
65
66
|
return out;
|
|
66
67
|
}
|
|
68
|
+
function serializeRelationshipPayload(data) {
|
|
69
|
+
return { data };
|
|
70
|
+
}
|
|
67
71
|
|
|
68
72
|
// src/client.ts
|
|
69
73
|
var JsonApiClient = class {
|
|
@@ -124,6 +128,56 @@ var JsonApiClient = class {
|
|
|
124
128
|
async remove(definition, id, options) {
|
|
125
129
|
await this.axios.delete(`/${definition.resourceType}/${id}`, options);
|
|
126
130
|
}
|
|
131
|
+
// -------------------------------------------------------------------------
|
|
132
|
+
// Relationship endpoints
|
|
133
|
+
// -------------------------------------------------------------------------
|
|
134
|
+
/**
|
|
135
|
+
* GET /{resourceType}/{id}/relationships/{relationshipName}
|
|
136
|
+
*/
|
|
137
|
+
async getRelationship(definition, id, relationshipName, options) {
|
|
138
|
+
const res = await this.axios.get(
|
|
139
|
+
`/${definition.resourceType}/${id}/relationships/${relationshipName}`,
|
|
140
|
+
options
|
|
141
|
+
);
|
|
142
|
+
return res.data;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* POST /{resourceType}/{id}/relationships/{relationshipName}
|
|
146
|
+
* Add members to a to-many relationship.
|
|
147
|
+
*/
|
|
148
|
+
async addRelationship(definition, id, relationshipName, data, options) {
|
|
149
|
+
const body = serializeRelationshipPayload(data);
|
|
150
|
+
const res = await this.axios.post(
|
|
151
|
+
`/${definition.resourceType}/${id}/relationships/${relationshipName}`,
|
|
152
|
+
body,
|
|
153
|
+
options
|
|
154
|
+
);
|
|
155
|
+
return res.data;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* PATCH /{resourceType}/{id}/relationships/{relationshipName}
|
|
159
|
+
* Replace a relationship entirely.
|
|
160
|
+
*/
|
|
161
|
+
async replaceRelationship(definition, id, relationshipName, data, options) {
|
|
162
|
+
const body = serializeRelationshipPayload(data);
|
|
163
|
+
const res = await this.axios.patch(
|
|
164
|
+
`/${definition.resourceType}/${id}/relationships/${relationshipName}`,
|
|
165
|
+
body,
|
|
166
|
+
options
|
|
167
|
+
);
|
|
168
|
+
return res.data;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* DELETE /{resourceType}/{id}/relationships/{relationshipName}
|
|
172
|
+
* Remove members from a to-many relationship.
|
|
173
|
+
*/
|
|
174
|
+
async removeRelationship(definition, id, relationshipName, data, options) {
|
|
175
|
+
const res = await this.axios.delete(
|
|
176
|
+
`/${definition.resourceType}/${id}/relationships/${relationshipName}`,
|
|
177
|
+
{ data: serializeRelationshipPayload(data), ...options }
|
|
178
|
+
);
|
|
179
|
+
return res.data;
|
|
180
|
+
}
|
|
127
181
|
/**
|
|
128
182
|
* Update client configuration at runtime.
|
|
129
183
|
*/
|
|
@@ -151,10 +205,19 @@ function createClient(config) {
|
|
|
151
205
|
return new JsonApiClient(config);
|
|
152
206
|
}
|
|
153
207
|
|
|
208
|
+
Object.defineProperty(exports, "deserialize", {
|
|
209
|
+
enumerable: true,
|
|
210
|
+
get: function () { return jsonapiDsl.deserialize; }
|
|
211
|
+
});
|
|
212
|
+
Object.defineProperty(exports, "deserializeMany", {
|
|
213
|
+
enumerable: true,
|
|
214
|
+
get: function () { return jsonapiDsl.deserializeMany; }
|
|
215
|
+
});
|
|
154
216
|
exports.JsonApiClient = JsonApiClient;
|
|
155
217
|
exports.createClient = createClient;
|
|
156
218
|
exports.serializeCreatePayload = serializeCreatePayload;
|
|
157
219
|
exports.serializeQueryParams = serializeQueryParams;
|
|
220
|
+
exports.serializeRelationshipPayload = serializeRelationshipPayload;
|
|
158
221
|
exports.serializeRelationships = serializeRelationships;
|
|
159
222
|
exports.serializeUpdatePayload = serializeUpdatePayload;
|
|
160
223
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/serialize.ts","../src/client.ts"],"names":["axios"],"mappings":"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","file":"index.js","sourcesContent":["import type { ResourceDefinition, JsonApiRelationships } from \"@leodamours/jsonapi-dsl\";\n\n/**\n * Wrap simplified relationship values in `{ data: ... }` per JSON:API spec.\n */\nexport function serializeRelationships(\n simplified: Record<string, unknown> | undefined,\n definition: ResourceDefinition,\n): JsonApiRelationships | undefined {\n if (!simplified) return undefined;\n\n const result: JsonApiRelationships = {};\n let hasKeys = false;\n\n for (const key of Object.keys(simplified)) {\n const value = simplified[key];\n if (value === undefined) continue;\n\n const relDef = definition.relationships[key];\n if (!relDef) continue;\n\n hasKeys = true;\n\n if (relDef._rel === \"one\") {\n result[key] = { data: value as { type: string; id: string } | null };\n } else {\n result[key] = { data: value as { type: string; id: string }[] };\n }\n }\n\n return hasKeys ? result : undefined;\n}\n\n/**\n * Build a JSON:API request body for creating a resource.\n */\nexport function serializeCreatePayload(\n definition: ResourceDefinition,\n payload: { attributes: Record<string, unknown>; relationships?: Record<string, unknown> },\n): { data: Record<string, unknown> } {\n const data: Record<string, unknown> = {\n type: definition.resourceType,\n attributes: payload.attributes,\n };\n\n const rels = serializeRelationships(payload.relationships, definition);\n if (rels) data.relationships = rels;\n\n return { data };\n}\n\n/**\n * Build a JSON:API request body for updating a resource.\n */\nexport function serializeUpdatePayload(\n definition: ResourceDefinition,\n id: string,\n payload: { attributes?: Record<string, unknown>; relationships?: Record<string, unknown> },\n): { data: Record<string, unknown> } {\n const data: Record<string, unknown> = {\n type: definition.resourceType,\n id,\n };\n\n if (payload.attributes && Object.keys(payload.attributes).length > 0) {\n data.attributes = payload.attributes;\n }\n\n const rels = serializeRelationships(payload.relationships, definition);\n if (rels) data.relationships = rels;\n\n return { data };\n}\n\n/**\n * Encode query params using JSON:API bracket conventions.\n *\n * `{ page: { size: 10 } }` → `\"page[size]=10\"`\n * `{ sort: [\"-createdAt\", \"title\"] }` → `\"sort=-createdAt,title\"`\n */\nexport function serializeQueryParams(params: Record<string, unknown>): Record<string, string> {\n const out: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(params)) {\n if (value == null) continue;\n\n if (typeof value === \"object\" && !Array.isArray(value)) {\n for (const [nested, nv] of Object.entries(value as Record<string, unknown>)) {\n if (nv != null) out[`${key}[${nested}]`] = String(nv);\n }\n } else if (Array.isArray(value)) {\n out[key] = value.join(\",\");\n } else {\n out[key] = String(value);\n }\n }\n\n return out;\n}\n","import axios, { type AxiosInstance, type AxiosRequestConfig } from \"axios\";\nimport type {\n ResourceDefinition,\n InferResource,\n JsonApiDocument,\n JsonApiCollectionDocument,\n} from \"@leodamours/jsonapi-dsl\";\nimport type { ClientConfig, QueryParams, CreatePayload, UpdatePayload } from \"./types\";\nimport { serializeCreatePayload, serializeUpdatePayload, serializeQueryParams } from \"./serialize\";\n\nexport class JsonApiClient {\n private axios: AxiosInstance;\n\n constructor(config: ClientConfig) {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/vnd.api+json\",\n Accept: \"application/vnd.api+json\",\n ...config.headers,\n };\n\n if (config.jwtToken) {\n headers.Authorization = `Bearer ${config.jwtToken}`;\n }\n\n this.axios = axios.create({\n baseURL: config.baseURL,\n headers,\n timeout: config.timeout,\n });\n }\n\n /**\n * POST /{resourceType}\n */\n async create<Def extends ResourceDefinition>(\n definition: Def,\n payload: CreatePayload<Def>,\n options?: AxiosRequestConfig,\n ): Promise<JsonApiDocument<InferResource<Def>>> {\n const body = serializeCreatePayload(definition, payload as any);\n const res = await this.axios.post(`/${definition.resourceType}`, body, options);\n return res.data;\n }\n\n /**\n * GET /{resourceType}/{id}\n */\n async findOne<Def extends ResourceDefinition>(\n definition: Def,\n id: string,\n params?: QueryParams,\n options?: AxiosRequestConfig,\n ): Promise<JsonApiDocument<InferResource<Def>>> {\n const res = await this.axios.get(`/${definition.resourceType}/${id}`, {\n params: params ? serializeQueryParams(params) : undefined,\n ...options,\n });\n return res.data;\n }\n\n /**\n * GET /{resourceType}\n */\n async findAll<Def extends ResourceDefinition>(\n definition: Def,\n params?: QueryParams,\n options?: AxiosRequestConfig,\n ): Promise<JsonApiCollectionDocument<InferResource<Def>>> {\n const res = await this.axios.get(`/${definition.resourceType}`, {\n params: params ? serializeQueryParams(params) : undefined,\n ...options,\n });\n return res.data;\n }\n\n /**\n * PATCH /{resourceType}/{id}\n */\n async update<Def extends ResourceDefinition>(\n definition: Def,\n id: string,\n payload: UpdatePayload<Def>,\n options?: AxiosRequestConfig,\n ): Promise<JsonApiDocument<InferResource<Def>>> {\n const body = serializeUpdatePayload(definition, id, payload as any);\n const res = await this.axios.patch(`/${definition.resourceType}/${id}`, body, options);\n return res.data;\n }\n\n /**\n * DELETE /{resourceType}/{id}\n */\n async remove(\n definition: ResourceDefinition,\n id: string,\n options?: AxiosRequestConfig,\n ): Promise<void> {\n await this.axios.delete(`/${definition.resourceType}/${id}`, options);\n }\n\n /**\n * Update client configuration at runtime.\n */\n updateConfig(config: Partial<ClientConfig>): void {\n if (config.baseURL) {\n this.axios.defaults.baseURL = config.baseURL;\n }\n if (config.headers) {\n Object.assign(this.axios.defaults.headers.common, config.headers);\n }\n if (config.jwtToken) {\n this.axios.defaults.headers.common.Authorization = `Bearer ${config.jwtToken}`;\n } else if (config.jwtToken === null) {\n delete this.axios.defaults.headers.common.Authorization;\n }\n }\n\n /**\n * Access the underlying Axios instance for advanced use.\n */\n getAxiosInstance(): AxiosInstance {\n return this.axios;\n }\n}\n\nexport function createClient(config: ClientConfig): JsonApiClient {\n return new JsonApiClient(config);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/serialize.ts","../src/client.ts"],"names":["axios"],"mappings":"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","file":"index.js","sourcesContent":["import type { ResourceDefinition, JsonApiRelationships } from \"@leodamours/jsonapi-dsl\";\n\n/**\n * Wrap simplified relationship values in `{ data: ... }` per JSON:API spec.\n */\nexport function serializeRelationships(\n simplified: Record<string, unknown> | undefined,\n definition: ResourceDefinition,\n): JsonApiRelationships | undefined {\n if (!simplified) return undefined;\n\n const result: JsonApiRelationships = {};\n let hasKeys = false;\n\n for (const key of Object.keys(simplified)) {\n const value = simplified[key];\n if (value === undefined) continue;\n\n const relDef = definition.relationships[key];\n if (!relDef) continue;\n\n hasKeys = true;\n\n if (relDef._rel === \"one\") {\n result[key] = { data: value as { type: string; id: string } | null };\n } else {\n result[key] = { data: value as { type: string; id: string }[] };\n }\n }\n\n return hasKeys ? result : undefined;\n}\n\n/**\n * Build a JSON:API request body for creating a resource.\n */\nexport function serializeCreatePayload(\n definition: ResourceDefinition,\n payload: { attributes: Record<string, unknown>; relationships?: Record<string, unknown> },\n): { data: Record<string, unknown> } {\n const data: Record<string, unknown> = {\n type: definition.resourceType,\n attributes: payload.attributes,\n };\n\n const rels = serializeRelationships(payload.relationships, definition);\n if (rels) data.relationships = rels;\n\n return { data };\n}\n\n/**\n * Build a JSON:API request body for updating a resource.\n */\nexport function serializeUpdatePayload(\n definition: ResourceDefinition,\n id: string,\n payload: { attributes?: Record<string, unknown>; relationships?: Record<string, unknown> },\n): { data: Record<string, unknown> } {\n const data: Record<string, unknown> = {\n type: definition.resourceType,\n id,\n };\n\n if (payload.attributes && Object.keys(payload.attributes).length > 0) {\n data.attributes = payload.attributes;\n }\n\n const rels = serializeRelationships(payload.relationships, definition);\n if (rels) data.relationships = rels;\n\n return { data };\n}\n\n/**\n * Encode query params using JSON:API bracket conventions.\n *\n * `{ page: { size: 10 } }` → `\"page[size]=10\"`\n * `{ sort: [\"-createdAt\", \"title\"] }` → `\"sort=-createdAt,title\"`\n */\nexport function serializeQueryParams(params: Record<string, unknown>): Record<string, string> {\n const out: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(params)) {\n if (value == null) continue;\n\n if (typeof value === \"object\" && !Array.isArray(value)) {\n for (const [nested, nv] of Object.entries(value as Record<string, unknown>)) {\n if (nv != null) out[`${key}[${nested}]`] = String(nv);\n }\n } else if (Array.isArray(value)) {\n out[key] = value.join(\",\");\n } else {\n out[key] = String(value);\n }\n }\n\n return out;\n}\n\n/**\n * Wrap resource linkage in a JSON:API request body for relationship endpoints.\n */\nexport function serializeRelationshipPayload(\n data: { type: string; id: string } | { type: string; id: string }[] | null,\n): { data: { type: string; id: string } | { type: string; id: string }[] | null } {\n return { data };\n}\n","import axios, { type AxiosInstance, type AxiosRequestConfig } from \"axios\";\nimport type {\n ResourceDefinition,\n InferResource,\n JsonApiDocument,\n JsonApiCollectionDocument,\n} from \"@leodamours/jsonapi-dsl\";\nimport type { ClientConfig, QueryParams, CreatePayload, UpdatePayload, ResourceLinkage, RelationshipResponse } from \"./types\";\nimport { serializeCreatePayload, serializeUpdatePayload, serializeQueryParams, serializeRelationshipPayload } from \"./serialize\";\n\nexport class JsonApiClient {\n private axios: AxiosInstance;\n\n constructor(config: ClientConfig) {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/vnd.api+json\",\n Accept: \"application/vnd.api+json\",\n ...config.headers,\n };\n\n if (config.jwtToken) {\n headers.Authorization = `Bearer ${config.jwtToken}`;\n }\n\n this.axios = axios.create({\n baseURL: config.baseURL,\n headers,\n timeout: config.timeout,\n });\n }\n\n /**\n * POST /{resourceType}\n */\n async create<Def extends ResourceDefinition>(\n definition: Def,\n payload: CreatePayload<Def>,\n options?: AxiosRequestConfig,\n ): Promise<JsonApiDocument<InferResource<Def>>> {\n const body = serializeCreatePayload(definition, payload as any);\n const res = await this.axios.post(`/${definition.resourceType}`, body, options);\n return res.data;\n }\n\n /**\n * GET /{resourceType}/{id}\n */\n async findOne<Def extends ResourceDefinition>(\n definition: Def,\n id: string,\n params?: QueryParams,\n options?: AxiosRequestConfig,\n ): Promise<JsonApiDocument<InferResource<Def>>> {\n const res = await this.axios.get(`/${definition.resourceType}/${id}`, {\n params: params ? serializeQueryParams(params) : undefined,\n ...options,\n });\n return res.data;\n }\n\n /**\n * GET /{resourceType}\n */\n async findAll<Def extends ResourceDefinition>(\n definition: Def,\n params?: QueryParams,\n options?: AxiosRequestConfig,\n ): Promise<JsonApiCollectionDocument<InferResource<Def>>> {\n const res = await this.axios.get(`/${definition.resourceType}`, {\n params: params ? serializeQueryParams(params) : undefined,\n ...options,\n });\n return res.data;\n }\n\n /**\n * PATCH /{resourceType}/{id}\n */\n async update<Def extends ResourceDefinition>(\n definition: Def,\n id: string,\n payload: UpdatePayload<Def>,\n options?: AxiosRequestConfig,\n ): Promise<JsonApiDocument<InferResource<Def>>> {\n const body = serializeUpdatePayload(definition, id, payload as any);\n const res = await this.axios.patch(`/${definition.resourceType}/${id}`, body, options);\n return res.data;\n }\n\n /**\n * DELETE /{resourceType}/{id}\n */\n async remove(\n definition: ResourceDefinition,\n id: string,\n options?: AxiosRequestConfig,\n ): Promise<void> {\n await this.axios.delete(`/${definition.resourceType}/${id}`, options);\n }\n\n // -------------------------------------------------------------------------\n // Relationship endpoints\n // -------------------------------------------------------------------------\n\n /**\n * GET /{resourceType}/{id}/relationships/{relationshipName}\n */\n async getRelationship(\n definition: ResourceDefinition,\n id: string,\n relationshipName: string,\n options?: AxiosRequestConfig,\n ): Promise<RelationshipResponse> {\n const res = await this.axios.get(\n `/${definition.resourceType}/${id}/relationships/${relationshipName}`,\n options,\n );\n return res.data;\n }\n\n /**\n * POST /{resourceType}/{id}/relationships/{relationshipName}\n * Add members to a to-many relationship.\n */\n async addRelationship(\n definition: ResourceDefinition,\n id: string,\n relationshipName: string,\n data: { type: string; id: string }[],\n options?: AxiosRequestConfig,\n ): Promise<RelationshipResponse> {\n const body = serializeRelationshipPayload(data);\n const res = await this.axios.post(\n `/${definition.resourceType}/${id}/relationships/${relationshipName}`,\n body,\n options,\n );\n return res.data;\n }\n\n /**\n * PATCH /{resourceType}/{id}/relationships/{relationshipName}\n * Replace a relationship entirely.\n */\n async replaceRelationship(\n definition: ResourceDefinition,\n id: string,\n relationshipName: string,\n data: ResourceLinkage,\n options?: AxiosRequestConfig,\n ): Promise<RelationshipResponse> {\n const body = serializeRelationshipPayload(data);\n const res = await this.axios.patch(\n `/${definition.resourceType}/${id}/relationships/${relationshipName}`,\n body,\n options,\n );\n return res.data;\n }\n\n /**\n * DELETE /{resourceType}/{id}/relationships/{relationshipName}\n * Remove members from a to-many relationship.\n */\n async removeRelationship(\n definition: ResourceDefinition,\n id: string,\n relationshipName: string,\n data: { type: string; id: string }[],\n options?: AxiosRequestConfig,\n ): Promise<RelationshipResponse> {\n const res = await this.axios.delete(\n `/${definition.resourceType}/${id}/relationships/${relationshipName}`,\n { data: serializeRelationshipPayload(data), ...options },\n );\n return res.data;\n }\n\n /**\n * Update client configuration at runtime.\n */\n updateConfig(config: Partial<ClientConfig>): void {\n if (config.baseURL) {\n this.axios.defaults.baseURL = config.baseURL;\n }\n if (config.headers) {\n Object.assign(this.axios.defaults.headers.common, config.headers);\n }\n if (config.jwtToken) {\n this.axios.defaults.headers.common.Authorization = `Bearer ${config.jwtToken}`;\n } else if (config.jwtToken === null) {\n delete this.axios.defaults.headers.common.Authorization;\n }\n }\n\n /**\n * Access the underlying Axios instance for advanced use.\n */\n getAxiosInstance(): AxiosInstance {\n return this.axios;\n }\n}\n\nexport function createClient(config: ClientConfig): JsonApiClient {\n return new JsonApiClient(config);\n}\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
|
+
export { deserialize, deserializeMany } from '@leodamours/jsonapi-dsl';
|
|
2
3
|
|
|
3
4
|
// src/client.ts
|
|
4
5
|
|
|
@@ -58,6 +59,9 @@ function serializeQueryParams(params) {
|
|
|
58
59
|
}
|
|
59
60
|
return out;
|
|
60
61
|
}
|
|
62
|
+
function serializeRelationshipPayload(data) {
|
|
63
|
+
return { data };
|
|
64
|
+
}
|
|
61
65
|
|
|
62
66
|
// src/client.ts
|
|
63
67
|
var JsonApiClient = class {
|
|
@@ -118,6 +122,56 @@ var JsonApiClient = class {
|
|
|
118
122
|
async remove(definition, id, options) {
|
|
119
123
|
await this.axios.delete(`/${definition.resourceType}/${id}`, options);
|
|
120
124
|
}
|
|
125
|
+
// -------------------------------------------------------------------------
|
|
126
|
+
// Relationship endpoints
|
|
127
|
+
// -------------------------------------------------------------------------
|
|
128
|
+
/**
|
|
129
|
+
* GET /{resourceType}/{id}/relationships/{relationshipName}
|
|
130
|
+
*/
|
|
131
|
+
async getRelationship(definition, id, relationshipName, options) {
|
|
132
|
+
const res = await this.axios.get(
|
|
133
|
+
`/${definition.resourceType}/${id}/relationships/${relationshipName}`,
|
|
134
|
+
options
|
|
135
|
+
);
|
|
136
|
+
return res.data;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* POST /{resourceType}/{id}/relationships/{relationshipName}
|
|
140
|
+
* Add members to a to-many relationship.
|
|
141
|
+
*/
|
|
142
|
+
async addRelationship(definition, id, relationshipName, data, options) {
|
|
143
|
+
const body = serializeRelationshipPayload(data);
|
|
144
|
+
const res = await this.axios.post(
|
|
145
|
+
`/${definition.resourceType}/${id}/relationships/${relationshipName}`,
|
|
146
|
+
body,
|
|
147
|
+
options
|
|
148
|
+
);
|
|
149
|
+
return res.data;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* PATCH /{resourceType}/{id}/relationships/{relationshipName}
|
|
153
|
+
* Replace a relationship entirely.
|
|
154
|
+
*/
|
|
155
|
+
async replaceRelationship(definition, id, relationshipName, data, options) {
|
|
156
|
+
const body = serializeRelationshipPayload(data);
|
|
157
|
+
const res = await this.axios.patch(
|
|
158
|
+
`/${definition.resourceType}/${id}/relationships/${relationshipName}`,
|
|
159
|
+
body,
|
|
160
|
+
options
|
|
161
|
+
);
|
|
162
|
+
return res.data;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* DELETE /{resourceType}/{id}/relationships/{relationshipName}
|
|
166
|
+
* Remove members from a to-many relationship.
|
|
167
|
+
*/
|
|
168
|
+
async removeRelationship(definition, id, relationshipName, data, options) {
|
|
169
|
+
const res = await this.axios.delete(
|
|
170
|
+
`/${definition.resourceType}/${id}/relationships/${relationshipName}`,
|
|
171
|
+
{ data: serializeRelationshipPayload(data), ...options }
|
|
172
|
+
);
|
|
173
|
+
return res.data;
|
|
174
|
+
}
|
|
121
175
|
/**
|
|
122
176
|
* Update client configuration at runtime.
|
|
123
177
|
*/
|
|
@@ -145,6 +199,6 @@ function createClient(config) {
|
|
|
145
199
|
return new JsonApiClient(config);
|
|
146
200
|
}
|
|
147
201
|
|
|
148
|
-
export { JsonApiClient, createClient, serializeCreatePayload, serializeQueryParams, serializeRelationships, serializeUpdatePayload };
|
|
202
|
+
export { JsonApiClient, createClient, serializeCreatePayload, serializeQueryParams, serializeRelationshipPayload, serializeRelationships, serializeUpdatePayload };
|
|
149
203
|
//# sourceMappingURL=index.mjs.map
|
|
150
204
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/serialize.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import type { ResourceDefinition, JsonApiRelationships } from \"@leodamours/jsonapi-dsl\";\n\n/**\n * Wrap simplified relationship values in `{ data: ... }` per JSON:API spec.\n */\nexport function serializeRelationships(\n simplified: Record<string, unknown> | undefined,\n definition: ResourceDefinition,\n): JsonApiRelationships | undefined {\n if (!simplified) return undefined;\n\n const result: JsonApiRelationships = {};\n let hasKeys = false;\n\n for (const key of Object.keys(simplified)) {\n const value = simplified[key];\n if (value === undefined) continue;\n\n const relDef = definition.relationships[key];\n if (!relDef) continue;\n\n hasKeys = true;\n\n if (relDef._rel === \"one\") {\n result[key] = { data: value as { type: string; id: string } | null };\n } else {\n result[key] = { data: value as { type: string; id: string }[] };\n }\n }\n\n return hasKeys ? result : undefined;\n}\n\n/**\n * Build a JSON:API request body for creating a resource.\n */\nexport function serializeCreatePayload(\n definition: ResourceDefinition,\n payload: { attributes: Record<string, unknown>; relationships?: Record<string, unknown> },\n): { data: Record<string, unknown> } {\n const data: Record<string, unknown> = {\n type: definition.resourceType,\n attributes: payload.attributes,\n };\n\n const rels = serializeRelationships(payload.relationships, definition);\n if (rels) data.relationships = rels;\n\n return { data };\n}\n\n/**\n * Build a JSON:API request body for updating a resource.\n */\nexport function serializeUpdatePayload(\n definition: ResourceDefinition,\n id: string,\n payload: { attributes?: Record<string, unknown>; relationships?: Record<string, unknown> },\n): { data: Record<string, unknown> } {\n const data: Record<string, unknown> = {\n type: definition.resourceType,\n id,\n };\n\n if (payload.attributes && Object.keys(payload.attributes).length > 0) {\n data.attributes = payload.attributes;\n }\n\n const rels = serializeRelationships(payload.relationships, definition);\n if (rels) data.relationships = rels;\n\n return { data };\n}\n\n/**\n * Encode query params using JSON:API bracket conventions.\n *\n * `{ page: { size: 10 } }` → `\"page[size]=10\"`\n * `{ sort: [\"-createdAt\", \"title\"] }` → `\"sort=-createdAt,title\"`\n */\nexport function serializeQueryParams(params: Record<string, unknown>): Record<string, string> {\n const out: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(params)) {\n if (value == null) continue;\n\n if (typeof value === \"object\" && !Array.isArray(value)) {\n for (const [nested, nv] of Object.entries(value as Record<string, unknown>)) {\n if (nv != null) out[`${key}[${nested}]`] = String(nv);\n }\n } else if (Array.isArray(value)) {\n out[key] = value.join(\",\");\n } else {\n out[key] = String(value);\n }\n }\n\n return out;\n}\n","import axios, { type AxiosInstance, type AxiosRequestConfig } from \"axios\";\nimport type {\n ResourceDefinition,\n InferResource,\n JsonApiDocument,\n JsonApiCollectionDocument,\n} from \"@leodamours/jsonapi-dsl\";\nimport type { ClientConfig, QueryParams, CreatePayload, UpdatePayload } from \"./types\";\nimport { serializeCreatePayload, serializeUpdatePayload, serializeQueryParams } from \"./serialize\";\n\nexport class JsonApiClient {\n private axios: AxiosInstance;\n\n constructor(config: ClientConfig) {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/vnd.api+json\",\n Accept: \"application/vnd.api+json\",\n ...config.headers,\n };\n\n if (config.jwtToken) {\n headers.Authorization = `Bearer ${config.jwtToken}`;\n }\n\n this.axios = axios.create({\n baseURL: config.baseURL,\n headers,\n timeout: config.timeout,\n });\n }\n\n /**\n * POST /{resourceType}\n */\n async create<Def extends ResourceDefinition>(\n definition: Def,\n payload: CreatePayload<Def>,\n options?: AxiosRequestConfig,\n ): Promise<JsonApiDocument<InferResource<Def>>> {\n const body = serializeCreatePayload(definition, payload as any);\n const res = await this.axios.post(`/${definition.resourceType}`, body, options);\n return res.data;\n }\n\n /**\n * GET /{resourceType}/{id}\n */\n async findOne<Def extends ResourceDefinition>(\n definition: Def,\n id: string,\n params?: QueryParams,\n options?: AxiosRequestConfig,\n ): Promise<JsonApiDocument<InferResource<Def>>> {\n const res = await this.axios.get(`/${definition.resourceType}/${id}`, {\n params: params ? serializeQueryParams(params) : undefined,\n ...options,\n });\n return res.data;\n }\n\n /**\n * GET /{resourceType}\n */\n async findAll<Def extends ResourceDefinition>(\n definition: Def,\n params?: QueryParams,\n options?: AxiosRequestConfig,\n ): Promise<JsonApiCollectionDocument<InferResource<Def>>> {\n const res = await this.axios.get(`/${definition.resourceType}`, {\n params: params ? serializeQueryParams(params) : undefined,\n ...options,\n });\n return res.data;\n }\n\n /**\n * PATCH /{resourceType}/{id}\n */\n async update<Def extends ResourceDefinition>(\n definition: Def,\n id: string,\n payload: UpdatePayload<Def>,\n options?: AxiosRequestConfig,\n ): Promise<JsonApiDocument<InferResource<Def>>> {\n const body = serializeUpdatePayload(definition, id, payload as any);\n const res = await this.axios.patch(`/${definition.resourceType}/${id}`, body, options);\n return res.data;\n }\n\n /**\n * DELETE /{resourceType}/{id}\n */\n async remove(\n definition: ResourceDefinition,\n id: string,\n options?: AxiosRequestConfig,\n ): Promise<void> {\n await this.axios.delete(`/${definition.resourceType}/${id}`, options);\n }\n\n /**\n * Update client configuration at runtime.\n */\n updateConfig(config: Partial<ClientConfig>): void {\n if (config.baseURL) {\n this.axios.defaults.baseURL = config.baseURL;\n }\n if (config.headers) {\n Object.assign(this.axios.defaults.headers.common, config.headers);\n }\n if (config.jwtToken) {\n this.axios.defaults.headers.common.Authorization = `Bearer ${config.jwtToken}`;\n } else if (config.jwtToken === null) {\n delete this.axios.defaults.headers.common.Authorization;\n }\n }\n\n /**\n * Access the underlying Axios instance for advanced use.\n */\n getAxiosInstance(): AxiosInstance {\n return this.axios;\n }\n}\n\nexport function createClient(config: ClientConfig): JsonApiClient {\n return new JsonApiClient(config);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/serialize.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import type { ResourceDefinition, JsonApiRelationships } from \"@leodamours/jsonapi-dsl\";\n\n/**\n * Wrap simplified relationship values in `{ data: ... }` per JSON:API spec.\n */\nexport function serializeRelationships(\n simplified: Record<string, unknown> | undefined,\n definition: ResourceDefinition,\n): JsonApiRelationships | undefined {\n if (!simplified) return undefined;\n\n const result: JsonApiRelationships = {};\n let hasKeys = false;\n\n for (const key of Object.keys(simplified)) {\n const value = simplified[key];\n if (value === undefined) continue;\n\n const relDef = definition.relationships[key];\n if (!relDef) continue;\n\n hasKeys = true;\n\n if (relDef._rel === \"one\") {\n result[key] = { data: value as { type: string; id: string } | null };\n } else {\n result[key] = { data: value as { type: string; id: string }[] };\n }\n }\n\n return hasKeys ? result : undefined;\n}\n\n/**\n * Build a JSON:API request body for creating a resource.\n */\nexport function serializeCreatePayload(\n definition: ResourceDefinition,\n payload: { attributes: Record<string, unknown>; relationships?: Record<string, unknown> },\n): { data: Record<string, unknown> } {\n const data: Record<string, unknown> = {\n type: definition.resourceType,\n attributes: payload.attributes,\n };\n\n const rels = serializeRelationships(payload.relationships, definition);\n if (rels) data.relationships = rels;\n\n return { data };\n}\n\n/**\n * Build a JSON:API request body for updating a resource.\n */\nexport function serializeUpdatePayload(\n definition: ResourceDefinition,\n id: string,\n payload: { attributes?: Record<string, unknown>; relationships?: Record<string, unknown> },\n): { data: Record<string, unknown> } {\n const data: Record<string, unknown> = {\n type: definition.resourceType,\n id,\n };\n\n if (payload.attributes && Object.keys(payload.attributes).length > 0) {\n data.attributes = payload.attributes;\n }\n\n const rels = serializeRelationships(payload.relationships, definition);\n if (rels) data.relationships = rels;\n\n return { data };\n}\n\n/**\n * Encode query params using JSON:API bracket conventions.\n *\n * `{ page: { size: 10 } }` → `\"page[size]=10\"`\n * `{ sort: [\"-createdAt\", \"title\"] }` → `\"sort=-createdAt,title\"`\n */\nexport function serializeQueryParams(params: Record<string, unknown>): Record<string, string> {\n const out: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(params)) {\n if (value == null) continue;\n\n if (typeof value === \"object\" && !Array.isArray(value)) {\n for (const [nested, nv] of Object.entries(value as Record<string, unknown>)) {\n if (nv != null) out[`${key}[${nested}]`] = String(nv);\n }\n } else if (Array.isArray(value)) {\n out[key] = value.join(\",\");\n } else {\n out[key] = String(value);\n }\n }\n\n return out;\n}\n\n/**\n * Wrap resource linkage in a JSON:API request body for relationship endpoints.\n */\nexport function serializeRelationshipPayload(\n data: { type: string; id: string } | { type: string; id: string }[] | null,\n): { data: { type: string; id: string } | { type: string; id: string }[] | null } {\n return { data };\n}\n","import axios, { type AxiosInstance, type AxiosRequestConfig } from \"axios\";\nimport type {\n ResourceDefinition,\n InferResource,\n JsonApiDocument,\n JsonApiCollectionDocument,\n} from \"@leodamours/jsonapi-dsl\";\nimport type { ClientConfig, QueryParams, CreatePayload, UpdatePayload, ResourceLinkage, RelationshipResponse } from \"./types\";\nimport { serializeCreatePayload, serializeUpdatePayload, serializeQueryParams, serializeRelationshipPayload } from \"./serialize\";\n\nexport class JsonApiClient {\n private axios: AxiosInstance;\n\n constructor(config: ClientConfig) {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/vnd.api+json\",\n Accept: \"application/vnd.api+json\",\n ...config.headers,\n };\n\n if (config.jwtToken) {\n headers.Authorization = `Bearer ${config.jwtToken}`;\n }\n\n this.axios = axios.create({\n baseURL: config.baseURL,\n headers,\n timeout: config.timeout,\n });\n }\n\n /**\n * POST /{resourceType}\n */\n async create<Def extends ResourceDefinition>(\n definition: Def,\n payload: CreatePayload<Def>,\n options?: AxiosRequestConfig,\n ): Promise<JsonApiDocument<InferResource<Def>>> {\n const body = serializeCreatePayload(definition, payload as any);\n const res = await this.axios.post(`/${definition.resourceType}`, body, options);\n return res.data;\n }\n\n /**\n * GET /{resourceType}/{id}\n */\n async findOne<Def extends ResourceDefinition>(\n definition: Def,\n id: string,\n params?: QueryParams,\n options?: AxiosRequestConfig,\n ): Promise<JsonApiDocument<InferResource<Def>>> {\n const res = await this.axios.get(`/${definition.resourceType}/${id}`, {\n params: params ? serializeQueryParams(params) : undefined,\n ...options,\n });\n return res.data;\n }\n\n /**\n * GET /{resourceType}\n */\n async findAll<Def extends ResourceDefinition>(\n definition: Def,\n params?: QueryParams,\n options?: AxiosRequestConfig,\n ): Promise<JsonApiCollectionDocument<InferResource<Def>>> {\n const res = await this.axios.get(`/${definition.resourceType}`, {\n params: params ? serializeQueryParams(params) : undefined,\n ...options,\n });\n return res.data;\n }\n\n /**\n * PATCH /{resourceType}/{id}\n */\n async update<Def extends ResourceDefinition>(\n definition: Def,\n id: string,\n payload: UpdatePayload<Def>,\n options?: AxiosRequestConfig,\n ): Promise<JsonApiDocument<InferResource<Def>>> {\n const body = serializeUpdatePayload(definition, id, payload as any);\n const res = await this.axios.patch(`/${definition.resourceType}/${id}`, body, options);\n return res.data;\n }\n\n /**\n * DELETE /{resourceType}/{id}\n */\n async remove(\n definition: ResourceDefinition,\n id: string,\n options?: AxiosRequestConfig,\n ): Promise<void> {\n await this.axios.delete(`/${definition.resourceType}/${id}`, options);\n }\n\n // -------------------------------------------------------------------------\n // Relationship endpoints\n // -------------------------------------------------------------------------\n\n /**\n * GET /{resourceType}/{id}/relationships/{relationshipName}\n */\n async getRelationship(\n definition: ResourceDefinition,\n id: string,\n relationshipName: string,\n options?: AxiosRequestConfig,\n ): Promise<RelationshipResponse> {\n const res = await this.axios.get(\n `/${definition.resourceType}/${id}/relationships/${relationshipName}`,\n options,\n );\n return res.data;\n }\n\n /**\n * POST /{resourceType}/{id}/relationships/{relationshipName}\n * Add members to a to-many relationship.\n */\n async addRelationship(\n definition: ResourceDefinition,\n id: string,\n relationshipName: string,\n data: { type: string; id: string }[],\n options?: AxiosRequestConfig,\n ): Promise<RelationshipResponse> {\n const body = serializeRelationshipPayload(data);\n const res = await this.axios.post(\n `/${definition.resourceType}/${id}/relationships/${relationshipName}`,\n body,\n options,\n );\n return res.data;\n }\n\n /**\n * PATCH /{resourceType}/{id}/relationships/{relationshipName}\n * Replace a relationship entirely.\n */\n async replaceRelationship(\n definition: ResourceDefinition,\n id: string,\n relationshipName: string,\n data: ResourceLinkage,\n options?: AxiosRequestConfig,\n ): Promise<RelationshipResponse> {\n const body = serializeRelationshipPayload(data);\n const res = await this.axios.patch(\n `/${definition.resourceType}/${id}/relationships/${relationshipName}`,\n body,\n options,\n );\n return res.data;\n }\n\n /**\n * DELETE /{resourceType}/{id}/relationships/{relationshipName}\n * Remove members from a to-many relationship.\n */\n async removeRelationship(\n definition: ResourceDefinition,\n id: string,\n relationshipName: string,\n data: { type: string; id: string }[],\n options?: AxiosRequestConfig,\n ): Promise<RelationshipResponse> {\n const res = await this.axios.delete(\n `/${definition.resourceType}/${id}/relationships/${relationshipName}`,\n { data: serializeRelationshipPayload(data), ...options },\n );\n return res.data;\n }\n\n /**\n * Update client configuration at runtime.\n */\n updateConfig(config: Partial<ClientConfig>): void {\n if (config.baseURL) {\n this.axios.defaults.baseURL = config.baseURL;\n }\n if (config.headers) {\n Object.assign(this.axios.defaults.headers.common, config.headers);\n }\n if (config.jwtToken) {\n this.axios.defaults.headers.common.Authorization = `Bearer ${config.jwtToken}`;\n } else if (config.jwtToken === null) {\n delete this.axios.defaults.headers.common.Authorization;\n }\n }\n\n /**\n * Access the underlying Axios instance for advanced use.\n */\n getAxiosInstance(): AxiosInstance {\n return this.axios;\n }\n}\n\nexport function createClient(config: ClientConfig): JsonApiClient {\n return new JsonApiClient(config);\n}\n"]}
|
package/package.json
CHANGED