@chill-sharp/ts-client 1.1.12 → 1.1.15

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 CHANGED
@@ -1,707 +1,707 @@
1
- # @chill-sharp/ts-client
2
-
3
- TypeScript client for a generic ChillSharp service.
4
-
5
- This package targets the standard ChillSharp HTTP surface:
6
-
7
- - core Chill API at `/api/chill`
8
- - schema API at `/api/chill-schema`
9
- - auth API at `/api/chill-auth`
10
- - i18n API at `/api/chill-i18n`
11
- - entity-change notifications at `/api/chill/notify`
12
-
13
- It is intentionally lightweight. Payloads are plain JavaScript objects so the client can work against arbitrary ChillSharp models without code generation.
14
-
15
- ## Install
16
-
17
- From the repository root:
18
-
19
- ```bash
20
- cd extra/chill-sharp-ts-client
21
- npm install
22
- npm run build
23
- ```
24
-
25
- Or from another project:
26
-
27
- ```bash
28
- npm install ../extra/chill-sharp-ts-client
29
- ```
30
-
31
- The client uses the runtime `fetch` API available in modern browsers and Node.js 18+.
32
-
33
- ## Local Linking
34
-
35
- This package now builds automatically on `npm install`, `npm pack`, and `npm link` through the `prepare` and `prepack` scripts.
36
-
37
- Example local workflow:
38
-
39
- ```bash
40
- cd extra/chill-sharp-ts-client
41
- npm install
42
- npm link
43
-
44
- cd path/to/your-app
45
- npm link @chill-sharp/ts-client
46
- ```
47
-
48
- ## Quick Start
49
-
50
- ```ts
51
- import { ChillSharpClient } from "@chill-sharp/ts-client";
52
-
53
- const client = new ChillSharpClient("http://localhost:5000/api/chill", {
54
- cultureName: "it-IT"
55
- });
56
-
57
- const created = await client.create({
58
- ChillType: "Model.Post",
59
- Guid: "00000000-0000-0000-0000-000000000001",
60
- Properties: {
61
- Title: "Hello",
62
- Author: "Ada Lovelace"
63
- }
64
- });
65
-
66
- const found = await client.find({
67
- ChillType: "Model.Post",
68
- Guid: created.Guid as string
69
- });
70
- ```
71
-
72
- ## Construction Modes
73
-
74
- ### Anonymous or externally authenticated
75
-
76
- ```ts
77
- const client = new ChillSharpClient("http://localhost:5000/api/chill", {
78
- cultureName: "it-IT"
79
- });
80
- ```
81
-
82
- SignalR entity-change subscriptions use the same bearer token flow as the other authenticated endpoints. Browser SignalR connections send credentials by default; if your app needs a non-credentialed cross-origin negotiate request, set `signalRWithCredentials: false` when creating the client.
83
-
84
- ### With an existing access token
85
-
86
- ```ts
87
- const client = new ChillSharpClient("http://localhost:5000/api/chill", {
88
- accessToken: "your-jwt-token",
89
- cultureName: "it-IT"
90
- });
91
- ```
92
-
93
- ### With username and password
94
-
95
- ```ts
96
- const client = new ChillSharpClient("http://localhost:5000/api/chill", {
97
- username: "root",
98
- password: "Pass123$",
99
- cultureName: "it-IT"
100
- });
101
- ```
102
-
103
- If the service supports ChillSharp auth endpoints, the client can log in and refresh tokens automatically.
104
-
105
- ## Core ChillSharp Operations
106
-
107
- Query payloads can now include:
108
-
109
- - `ordering.propertyName`
110
- - `ordering.direction`
111
-
112
- If you omit `ordering`, the backend defaults to `Position`. Entity payloads also include `position`, which defaults to `0`.
113
-
114
- ### Query
115
-
116
- Use `query()` when `ChillType` points to a concrete query type such as `Query.PostQuery`.
117
-
118
- ```ts
119
- const result = await client.query({
120
- chillType: "Query.PostQuery",
121
- properties: {
122
- title: "Hello"
123
- },
124
- ordering: {
125
- propertyName: "Position",
126
- direction: "ASC"
127
- },
128
- resultProperties: [
129
- { name: "Guid" },
130
- { name: "Title" },
131
- { name: "Author" }
132
- ]
133
- });
134
- ```
135
-
136
- When `ordering.propertyName` points to a Chill entity reference such as `Blog`, the backend orders by `Blog.Label`.
137
-
138
- ### Lookup
139
-
140
- Use `lookup()` when `ChillType` points to an entity type and you only need generic full-text search.
141
-
142
- ```ts
143
- const result = await client.lookup({
144
- chillType: "Model.Post",
145
- properties: {
146
- fullTextSearch: "Ada Lovelace"
147
- },
148
- ordering: {
149
- propertyName: "Blog",
150
- direction: "ASC"
151
- },
152
- resultProperties: [
153
- { name: "Guid" },
154
- { name: "Title" },
155
- { name: "Author" }
156
- ]
157
- });
158
- ```
159
-
160
- ### Find
161
-
162
- ```ts
163
- const entity = await client.find({
164
- ChillType: "Model.Post",
165
- Guid: "f2d5d5e3-0a1f-4d15-9396-2ab5f6c4ff11"
166
- });
167
- ```
168
-
169
- ### Create
170
-
171
- ```ts
172
- const entity = await client.create({
173
- chillType: "Model.Post",
174
- guid: "f2d5d5e3-0a1f-4d15-9396-2ab5f6c4ff11",
175
- position: 10,
176
- properties: {
177
- title: "New title",
178
- author: "Grace Hopper"
179
- }
180
- });
181
- ```
182
-
183
- ### Update
184
-
185
- ```ts
186
- const updated = await client.update({
187
- chillType: "Model.Post",
188
- guid: "f2d5d5e3-0a1f-4d15-9396-2ab5f6c4ff11",
189
- position: 20,
190
- properties: {
191
- title: "Updated title"
192
- }
193
- });
194
- ```
195
-
196
- ### Delete
197
-
198
- ```ts
199
- await client.delete({
200
- ChillType: "Model.Post",
201
- Guid: "f2d5d5e3-0a1f-4d15-9396-2ab5f6c4ff11"
202
- });
203
- ```
204
-
205
- ### Attachments
206
-
207
- Use the attachment helpers when the host enables `ChillSharp.Attachment`.
208
-
209
- ```ts
210
- const post = {
211
- ChillType: "Model.Post",
212
- Guid: "f2d5d5e3-0a1f-4d15-9396-2ab5f6c4ff11"
213
- };
214
-
215
- const uploaded = await client.uploadAttachment(post, {
216
- fileName: "contract.txt",
217
- content: new Blob(["hello attachment"], { type: "text/plain" }),
218
- contentType: "text/plain"
219
- }, {
220
- title: "Contract",
221
- description: "Signed draft",
222
- isPublic: false
223
- });
224
-
225
- const attachments = await client.getAttachments(post);
226
- const fileBlob = await client.downloadAttachment(uploaded[0]);
227
- ```
228
-
229
- ### Chunk
230
-
231
- Use `chunk()` when several operations should be sent in one HTTP request.
232
- The operations are executed in `Index` order when you provide it. For write-heavy batches, set `Index` explicitly.
233
-
234
- ```ts
235
- const operations = await client.chunk([
236
- {
237
- Index: 0,
238
- Verb: "create",
239
- Entity: {
240
- ChillType: "Model.Post",
241
- Guid: "11111111-1111-1111-1111-111111111111",
242
- Properties: { Title: "First", Author: "A" }
243
- }
244
- },
245
- {
246
- Index: 1,
247
- Verb: "create",
248
- Entity: {
249
- ChillType: "Model.Post",
250
- Guid: "22222222-2222-2222-2222-222222222222",
251
- Properties: { Title: "Second", Author: "B" }
252
- }
253
- },
254
- {
255
- Index: 2,
256
- Verb: "update",
257
- Entity: {
258
- ChillType: "Model.Post",
259
- Guid: "11111111-1111-1111-1111-111111111111",
260
- Properties: { Title: "First updated" }
261
- }
262
- }
263
- ]);
264
- ```
265
-
266
- ### Chunk inside one transaction
267
-
268
- Wrap the batch with `transaction` and `commit` when all write operations must succeed or fail together.
269
-
270
- ```ts
271
- const operations = await client.chunk([
272
- {
273
- Index: 0,
274
- Verb: "transaction"
275
- },
276
- {
277
- Index: 1,
278
- Verb: "create",
279
- Entity: {
280
- ChillType: "Model.Blog",
281
- Guid: crypto.randomUUID(),
282
- Properties: {
283
- Name: "Batch blog",
284
- Url: "https://example.local/batch-blog"
285
- }
286
- }
287
- },
288
- {
289
- Index: 2,
290
- Verb: "create",
291
- Entity: {
292
- ChillType: "Model.Post",
293
- Guid: crypto.randomUUID(),
294
- Properties: {
295
- Title: "Batch post",
296
- Author: "Grace Hopper"
297
- }
298
- }
299
- },
300
- {
301
- Index: 3,
302
- Verb: "commit"
303
- }
304
- ]);
305
- ```
306
-
307
- Use this pattern only for the operations that must share the same database transaction. If one write fails before `commit`, the transaction is not committed.
308
-
309
- ### Test
310
-
311
- ```ts
312
- const status = await client.test();
313
- // "ChillSharp is up and running!"
314
- ```
315
-
316
- Use this to verify the Chill endpoint is reachable before sending API payloads.
317
-
318
- ## Notification Operations
319
-
320
- ### Subscribe to all changes for a chill type
321
-
322
- ```ts
323
- const subscription = await client.subscribeToEntityChanges("Model.Post", (changes) => {
324
- for (const change of changes) {
325
- console.log(change.chillType, change.guid, change.action);
326
- }
327
- });
328
- ```
329
-
330
- ### Subscribe to one entity only
331
-
332
- ```ts
333
- const subscription = await client.subscribeToEntityChanges(
334
- "Model.Post",
335
- (changes) => {
336
- console.log("single entity changed", changes);
337
- },
338
- "f2d5d5e3-0a1f-4d15-9396-2ab5f6c4ff11"
339
- );
340
- ```
341
-
342
- ### Unsubscribe
343
-
344
- ```ts
345
- await subscription.unsubscribe();
346
- ```
347
-
348
- ### Close the shared notification connection
349
-
350
- ```ts
351
- await client.disconnectEntityChanges();
352
- ```
353
-
354
- The notification callback receives arrays shaped like:
355
-
356
- ```ts
357
- [
358
- {
359
- chillType: "Model.Post",
360
- guid: "f2d5d5e3-0a1f-4d15-9396-2ab5f6c4ff11",
361
- action: "UPDATED"
362
- }
363
- ]
364
- ```
365
-
366
- ## Schema Operations
367
-
368
- ### Get schema
369
-
370
- ```ts
371
- const schema = await client.getSchema("Model.Post", "default");
372
- console.log(schema.handleAttachments);
373
- console.log(schema.relations);
374
-
375
- // Override the constructor default for one call
376
- const englishSchema = await client.getSchema("Model.Post", "default", "en-GB");
377
-
378
- // Refresh a persisted schema from the current runtime model for one call.
379
- // Existing properties keep their saved metadata, new model properties are added,
380
- // and properties no longer present on the model are removed.
381
- const refreshedSchema = await client.getSchema("Model.Post", "default", undefined, true);
382
- ```
383
-
384
- Entity schemas now also expose `relations`, derived from annotated collection properties. Each relation entry includes:
385
-
386
- - `chillType` for the child or relation entity
387
- - `chillQuery` for the resolved query type when available
388
- - `fixedValues` and `fixedQueryValues` containing the `@{mock}` parent placeholder keyed by the child FK/reference property name
389
- - `relationLabel` with `labelGuid`, `primaryDefaultText`, and `secondaryDefaultText`
390
-
391
- ### Get schema list
392
-
393
- ```ts
394
- const schemaList = await client.getSchemaList();
395
- const englishSchemaList = await client.getSchemaList("en-GB");
396
- ```
397
-
398
- ### Set schema
399
-
400
- ```ts
401
- await client.setSchema({
402
- ChillType: "Model.Post",
403
- ChillViewCode: "default",
404
- DisplayName: "Post",
405
- Properties: [
406
- {
407
- Name: "Title",
408
- DisplayName: "Post title"
409
- }
410
- ]
411
- });
412
- ```
413
-
414
- ### Get entity options
415
-
416
- ```ts
417
- const options = await client.getEntityOptions("Model.Post");
418
- console.log(options.handleAttachments);
419
- ```
420
-
421
- ### Set entity options
422
-
423
- ```ts
424
- const options = await client.setEntityOptions({
425
- chillType: "Model.Post",
426
- checksumEnabled: true,
427
- handleAttachments: true,
428
- labelFormatString: "{Title}",
429
- shortLabelFormatString: "{Title}",
430
- fullTextContentFormatString: "{Title} {Author}",
431
- enableMCP: true,
432
- mcpDescription: "Post resource exposed to MCP clients.",
433
- changeLogEnabled: true
434
- });
435
- ```
436
-
437
- ### Get menu
438
-
439
- Use `getMenu()` to load root menu nodes or the direct children of one menu item.
440
-
441
- ```ts
442
- const rootMenu = await client.getMenu();
443
- const childMenu = await client.getMenu("8d0946dc-fc2b-4d95-b5ca-6f12d9618a5b");
444
- ```
445
-
446
- `getMenu()` returns one tree level at a time.
447
-
1
+ # @chill-sharp/ts-client
2
+
3
+ TypeScript client for a generic ChillSharp service.
4
+
5
+ This package targets the standard ChillSharp HTTP surface:
6
+
7
+ - core Chill API at `/api/chill`
8
+ - schema API at `/api/chill-schema`
9
+ - auth API at `/api/chill-auth`
10
+ - i18n API at `/api/chill-i18n`
11
+ - entity-change notifications at `/api/chill/notify`
12
+
13
+ It is intentionally lightweight. Payloads are plain JavaScript objects so the client can work against arbitrary ChillSharp models without code generation.
14
+
15
+ ## Install
16
+
17
+ From the repository root:
18
+
19
+ ```bash
20
+ cd extra/chill-sharp-ts-client
21
+ npm install
22
+ npm run build
23
+ ```
24
+
25
+ Or from another project:
26
+
27
+ ```bash
28
+ npm install ../extra/chill-sharp-ts-client
29
+ ```
30
+
31
+ The client uses the runtime `fetch` API available in modern browsers and Node.js 18+.
32
+
33
+ ## Local Linking
34
+
35
+ This package now builds automatically on `npm install`, `npm pack`, and `npm link` through the `prepare` and `prepack` scripts.
36
+
37
+ Example local workflow:
38
+
39
+ ```bash
40
+ cd extra/chill-sharp-ts-client
41
+ npm install
42
+ npm link
43
+
44
+ cd path/to/your-app
45
+ npm link @chill-sharp/ts-client
46
+ ```
47
+
48
+ ## Quick Start
49
+
50
+ ```ts
51
+ import { ChillSharpClient } from "@chill-sharp/ts-client";
52
+
53
+ const client = new ChillSharpClient("http://localhost:5000/api/chill", {
54
+ cultureName: "it-IT"
55
+ });
56
+
57
+ const created = await client.create({
58
+ ChillType: "Model.Post",
59
+ Guid: "00000000-0000-0000-0000-000000000001",
60
+ Properties: {
61
+ Title: "Hello",
62
+ Author: "Ada Lovelace"
63
+ }
64
+ });
65
+
66
+ const found = await client.find({
67
+ ChillType: "Model.Post",
68
+ Guid: created.Guid as string
69
+ });
70
+ ```
71
+
72
+ ## Construction Modes
73
+
74
+ ### Anonymous or externally authenticated
75
+
76
+ ```ts
77
+ const client = new ChillSharpClient("http://localhost:5000/api/chill", {
78
+ cultureName: "it-IT"
79
+ });
80
+ ```
81
+
82
+ SignalR entity-change subscriptions use the same bearer token flow as the other authenticated endpoints. Browser SignalR connections send credentials by default; if your app needs a non-credentialed cross-origin negotiate request, set `signalRWithCredentials: false` when creating the client.
83
+
84
+ ### With an existing access token
85
+
86
+ ```ts
87
+ const client = new ChillSharpClient("http://localhost:5000/api/chill", {
88
+ accessToken: "your-jwt-token",
89
+ cultureName: "it-IT"
90
+ });
91
+ ```
92
+
93
+ ### With username and password
94
+
95
+ ```ts
96
+ const client = new ChillSharpClient("http://localhost:5000/api/chill", {
97
+ username: "root",
98
+ password: "Pass123$",
99
+ cultureName: "it-IT"
100
+ });
101
+ ```
102
+
103
+ If the service supports ChillSharp auth endpoints, the client can log in and refresh tokens automatically.
104
+
105
+ ## Core ChillSharp Operations
106
+
107
+ Query payloads can now include:
108
+
109
+ - `ordering.propertyName`
110
+ - `ordering.direction`
111
+
112
+ If you omit `ordering`, the backend defaults to `Position`. Entity payloads also include `position`, which defaults to `0`.
113
+
114
+ ### Query
115
+
116
+ Use `query()` when `ChillType` points to a concrete query type such as `Query.PostQuery`.
117
+
118
+ ```ts
119
+ const result = await client.query({
120
+ chillType: "Query.PostQuery",
121
+ properties: {
122
+ title: "Hello"
123
+ },
124
+ ordering: {
125
+ propertyName: "Position",
126
+ direction: "ASC"
127
+ },
128
+ resultProperties: [
129
+ { name: "Guid" },
130
+ { name: "Title" },
131
+ { name: "Author" }
132
+ ]
133
+ });
134
+ ```
135
+
136
+ When `ordering.propertyName` points to a Chill entity reference such as `Blog`, the backend orders by `Blog.Label`.
137
+
138
+ ### Lookup
139
+
140
+ Use `lookup()` when `ChillType` points to an entity type and you only need generic full-text search.
141
+
142
+ ```ts
143
+ const result = await client.lookup({
144
+ chillType: "Model.Post",
145
+ properties: {
146
+ fullTextSearch: "Ada Lovelace"
147
+ },
148
+ ordering: {
149
+ propertyName: "Blog",
150
+ direction: "ASC"
151
+ },
152
+ resultProperties: [
153
+ { name: "Guid" },
154
+ { name: "Title" },
155
+ { name: "Author" }
156
+ ]
157
+ });
158
+ ```
159
+
160
+ ### Find
161
+
162
+ ```ts
163
+ const entity = await client.find({
164
+ ChillType: "Model.Post",
165
+ Guid: "f2d5d5e3-0a1f-4d15-9396-2ab5f6c4ff11"
166
+ });
167
+ ```
168
+
169
+ ### Create
170
+
171
+ ```ts
172
+ const entity = await client.create({
173
+ chillType: "Model.Post",
174
+ guid: "f2d5d5e3-0a1f-4d15-9396-2ab5f6c4ff11",
175
+ position: 10,
176
+ properties: {
177
+ title: "New title",
178
+ author: "Grace Hopper"
179
+ }
180
+ });
181
+ ```
182
+
183
+ ### Update
184
+
185
+ ```ts
186
+ const updated = await client.update({
187
+ chillType: "Model.Post",
188
+ guid: "f2d5d5e3-0a1f-4d15-9396-2ab5f6c4ff11",
189
+ position: 20,
190
+ properties: {
191
+ title: "Updated title"
192
+ }
193
+ });
194
+ ```
195
+
196
+ ### Delete
197
+
198
+ ```ts
199
+ await client.delete({
200
+ ChillType: "Model.Post",
201
+ Guid: "f2d5d5e3-0a1f-4d15-9396-2ab5f6c4ff11"
202
+ });
203
+ ```
204
+
205
+ ### Attachments
206
+
207
+ Use the attachment helpers when the host enables `ChillSharp.Attachment`.
208
+
209
+ ```ts
210
+ const post = {
211
+ ChillType: "Model.Post",
212
+ Guid: "f2d5d5e3-0a1f-4d15-9396-2ab5f6c4ff11"
213
+ };
214
+
215
+ const uploaded = await client.uploadAttachment(post, {
216
+ fileName: "contract.txt",
217
+ content: new Blob(["hello attachment"], { type: "text/plain" }),
218
+ contentType: "text/plain"
219
+ }, {
220
+ title: "Contract",
221
+ description: "Signed draft",
222
+ isPublic: false
223
+ });
224
+
225
+ const attachments = await client.getAttachments(post);
226
+ const fileBlob = await client.downloadAttachment(uploaded[0]);
227
+ ```
228
+
229
+ ### Chunk
230
+
231
+ Use `chunk()` when several operations should be sent in one HTTP request.
232
+ The operations are executed in `Index` order when you provide it. For write-heavy batches, set `Index` explicitly.
233
+
234
+ ```ts
235
+ const operations = await client.chunk([
236
+ {
237
+ Index: 0,
238
+ Verb: "create",
239
+ Entity: {
240
+ ChillType: "Model.Post",
241
+ Guid: "11111111-1111-1111-1111-111111111111",
242
+ Properties: { Title: "First", Author: "A" }
243
+ }
244
+ },
245
+ {
246
+ Index: 1,
247
+ Verb: "create",
248
+ Entity: {
249
+ ChillType: "Model.Post",
250
+ Guid: "22222222-2222-2222-2222-222222222222",
251
+ Properties: { Title: "Second", Author: "B" }
252
+ }
253
+ },
254
+ {
255
+ Index: 2,
256
+ Verb: "update",
257
+ Entity: {
258
+ ChillType: "Model.Post",
259
+ Guid: "11111111-1111-1111-1111-111111111111",
260
+ Properties: { Title: "First updated" }
261
+ }
262
+ }
263
+ ]);
264
+ ```
265
+
266
+ ### Chunk inside one transaction
267
+
268
+ Wrap the batch with `transaction` and `commit` when all write operations must succeed or fail together.
269
+
270
+ ```ts
271
+ const operations = await client.chunk([
272
+ {
273
+ Index: 0,
274
+ Verb: "transaction"
275
+ },
276
+ {
277
+ Index: 1,
278
+ Verb: "create",
279
+ Entity: {
280
+ ChillType: "Model.Blog",
281
+ Guid: crypto.randomUUID(),
282
+ Properties: {
283
+ Name: "Batch blog",
284
+ Url: "https://example.local/batch-blog"
285
+ }
286
+ }
287
+ },
288
+ {
289
+ Index: 2,
290
+ Verb: "create",
291
+ Entity: {
292
+ ChillType: "Model.Post",
293
+ Guid: crypto.randomUUID(),
294
+ Properties: {
295
+ Title: "Batch post",
296
+ Author: "Grace Hopper"
297
+ }
298
+ }
299
+ },
300
+ {
301
+ Index: 3,
302
+ Verb: "commit"
303
+ }
304
+ ]);
305
+ ```
306
+
307
+ Use this pattern only for the operations that must share the same database transaction. If one write fails before `commit`, the transaction is not committed.
308
+
309
+ ### Test
310
+
311
+ ```ts
312
+ const status = await client.test();
313
+ // "ChillSharp is up and running!"
314
+ ```
315
+
316
+ Use this to verify the Chill endpoint is reachable before sending API payloads.
317
+
318
+ ## Notification Operations
319
+
320
+ ### Subscribe to all changes for a chill type
321
+
322
+ ```ts
323
+ const subscription = await client.subscribeToEntityChanges("Model.Post", (changes) => {
324
+ for (const change of changes) {
325
+ console.log(change.chillType, change.guid, change.action);
326
+ }
327
+ });
328
+ ```
329
+
330
+ ### Subscribe to one entity only
331
+
332
+ ```ts
333
+ const subscription = await client.subscribeToEntityChanges(
334
+ "Model.Post",
335
+ (changes) => {
336
+ console.log("single entity changed", changes);
337
+ },
338
+ "f2d5d5e3-0a1f-4d15-9396-2ab5f6c4ff11"
339
+ );
340
+ ```
341
+
342
+ ### Unsubscribe
343
+
344
+ ```ts
345
+ await subscription.unsubscribe();
346
+ ```
347
+
348
+ ### Close the shared notification connection
349
+
350
+ ```ts
351
+ await client.disconnectEntityChanges();
352
+ ```
353
+
354
+ The notification callback receives arrays shaped like:
355
+
356
+ ```ts
357
+ [
358
+ {
359
+ chillType: "Model.Post",
360
+ guid: "f2d5d5e3-0a1f-4d15-9396-2ab5f6c4ff11",
361
+ action: "UPDATED"
362
+ }
363
+ ]
364
+ ```
365
+
366
+ ## Schema Operations
367
+
368
+ ### Get schema
369
+
370
+ ```ts
371
+ const schema = await client.getSchema("Model.Post", "default");
372
+ console.log(schema.handleAttachments);
373
+ console.log(schema.relations);
374
+
375
+ // Override the constructor default for one call
376
+ const englishSchema = await client.getSchema("Model.Post", "default", "en-GB");
377
+
378
+ // Refresh a persisted schema from the current runtime model for one call.
379
+ // Existing properties keep their saved metadata, new model properties are added,
380
+ // and properties no longer present on the model are removed.
381
+ const refreshedSchema = await client.getSchema("Model.Post", "default", undefined, true);
382
+ ```
383
+
384
+ Entity schemas now also expose `relations`, derived from annotated collection properties. Each relation entry includes:
385
+
386
+ - `chillType` for the child or relation entity
387
+ - `chillQuery` for the resolved query type when available
388
+ - `fixedValues` and `fixedQueryValues` containing the `@{mock}` parent placeholder keyed by the child FK/reference property name
389
+ - `relationLabel` with `labelGuid`, `primaryDefaultText`, and `secondaryDefaultText`
390
+
391
+ ### Get schema list
392
+
393
+ ```ts
394
+ const schemaList = await client.getSchemaList();
395
+ const englishSchemaList = await client.getSchemaList("en-GB");
396
+ ```
397
+
398
+ ### Set schema
399
+
400
+ ```ts
401
+ await client.setSchema({
402
+ ChillType: "Model.Post",
403
+ ChillViewCode: "default",
404
+ DisplayName: "Post",
405
+ Properties: [
406
+ {
407
+ Name: "Title",
408
+ DisplayName: "Post title"
409
+ }
410
+ ]
411
+ });
412
+ ```
413
+
414
+ ### Get entity options
415
+
416
+ ```ts
417
+ const options = await client.getEntityOptions("Model.Post");
418
+ console.log(options.handleAttachments);
419
+ ```
420
+
421
+ ### Set entity options
422
+
423
+ ```ts
424
+ const options = await client.setEntityOptions({
425
+ chillType: "Model.Post",
426
+ checksumEnabled: true,
427
+ handleAttachments: true,
428
+ labelFormatString: "{Title}",
429
+ shortLabelFormatString: "{Title}",
430
+ fullTextContentFormatString: "{Title} {Author}",
431
+ enableMCP: true,
432
+ mcpDescription: "Post resource exposed to MCP clients.",
433
+ changeLogEnabled: true
434
+ });
435
+ ```
436
+
437
+ ### Get menu
438
+
439
+ Use `getMenu()` to load root menu nodes or the direct children of one menu item.
440
+
441
+ ```ts
442
+ const rootMenu = await client.getMenu();
443
+ const childMenu = await client.getMenu("8d0946dc-fc2b-4d95-b5ca-6f12d9618a5b");
444
+ ```
445
+
446
+ `getMenu()` returns one tree level at a time.
447
+
448
448
  For the full menu-tree contract and `MenuHierarchy` filtering behavior, see [../../doc/MenuGuide/README.md](../../doc/MenuGuide/README.md).
449
-
450
- ### Set menu
451
-
452
- Use `setMenu()` to create or update one menu item.
453
-
454
- ```ts
455
- const savedMenu = await client.setMenu({
456
- guid: "00000000-0000-0000-0000-000000000000",
457
- positionNo: 10,
458
- title: "Posts",
459
- description: "Open the post management screen",
460
- parent: null,
461
- componentName: "CRUD",
462
- componentConfigurationJson: "{\"chillType\":\"Model.Post\"}",
463
- menuHierarchy: "SECTION-A.POSTS"
464
- });
465
- ```
466
-
467
- `positionNo` is persisted by the backend and controls sibling ordering. Lower values are returned first.
468
-
469
- ### Delete menu
470
-
471
- Use `deleteMenu()` to remove one menu item and all nested child nodes below it.
472
-
473
- ```ts
474
- await client.deleteMenu("8d0946dc-fc2b-4d95-b5ca-6f12d9618a5b");
475
- ```
476
-
449
+
450
+ ### Set menu
451
+
452
+ Use `setMenu()` to create or update one menu item.
453
+
454
+ ```ts
455
+ const savedMenu = await client.setMenu({
456
+ guid: "00000000-0000-0000-0000-000000000000",
457
+ positionNo: 10,
458
+ title: "Posts",
459
+ description: "Open the post management screen",
460
+ parent: null,
461
+ componentName: "CRUD",
462
+ componentConfigurationJson: "{\"chillType\":\"Model.Post\"}",
463
+ menuHierarchy: "SECTION-A.POSTS"
464
+ });
465
+ ```
466
+
467
+ `positionNo` is persisted by the backend and controls sibling ordering. Lower values are returned first.
468
+
469
+ ### Delete menu
470
+
471
+ Use `deleteMenu()` to remove one menu item and all nested child nodes below it.
472
+
473
+ ```ts
474
+ await client.deleteMenu("8d0946dc-fc2b-4d95-b5ca-6f12d9618a5b");
475
+ ```
476
+
477
477
  For parent handling, delete behavior, validation rules, and filtering behavior, see [../../doc/MenuGuide/README.md](../../doc/MenuGuide/README.md).
478
-
479
- ## I18n Operations
480
-
481
- ### Get text
482
-
483
- ```ts
484
- const text = await client.getText({
485
- LabelGuid: "4e16f6c0-6b95-4d67-98bc-9f4d0d63eaf1",
486
- CultureName: "it-IT",
487
- PrimaryCultureName: "en-GB",
488
- PrimaryDefaultText: "Blog title",
489
- SecondaryCultureName: "it-IT",
490
- SecondaryDefaultText: "Titolo del blog"
491
- });
492
- ```
493
-
494
- ### Get texts
495
-
496
- ```ts
497
- const texts = await client.getTexts([
498
- {
499
- LabelGuid: "4e16f6c0-6b95-4d67-98bc-9f4d0d63eaf1",
500
- CultureName: "it-IT",
501
- PrimaryCultureName: "en-GB",
502
- PrimaryDefaultText: "Blog title",
503
- SecondaryCultureName: "it-IT",
504
- SecondaryDefaultText: "Titolo del blog"
505
- },
506
- {
507
- LabelGuid: "2f6ef6f7-b0a9-44f8-bfd2-a3b3ed5b9a81",
508
- CultureName: "it-IT",
509
- PrimaryCultureName: "en-GB",
510
- PrimaryDefaultText: "Blog url",
511
- SecondaryCultureName: "it-IT",
512
- SecondaryDefaultText: "Url del blog"
513
- }
514
- ]);
515
- ```
516
-
517
- ### Set text
518
-
519
- ```ts
520
- const saved = await client.setText({
521
- LabelGuid: "4e16f6c0-6b95-4d67-98bc-9f4d0d63eaf1",
522
- CultureName: "it-IT",
523
- Value: "Titolo del blog"
524
- });
525
- ```
526
-
527
- ## Auth Operations
528
-
529
- The client assumes the auth base path is derived from `/api/chill` to `/api/chill-auth`, matching the .NET client.
530
-
531
- ### Register account
532
-
533
- ```ts
534
- const token = await client.registerAuthAccount({
535
- UserName: "root",
536
- Email: "root@example.com",
537
- Password: "Pass123$",
538
- DisplayName: "Root",
539
- DisplayCultureName: "it-IT",
540
- CreateChillAuthUser: true
541
- });
542
- ```
543
-
544
- If `DisplayCultureName` is provided and `CreateChillAuthUser` is `true`, the server presets the linked `AuthUser` with culture-based defaults for `displayTimeZone`, `displayDateFormat`, and `displayNumberFormat`.
545
-
546
- ### Login
547
-
548
- ```ts
549
- const token = await client.loginAuthAccount({
550
- UserNameOrEmail: "root",
551
- Password: "Pass123$"
552
- });
553
- ```
554
-
555
- ### Refresh current token
556
-
557
- ```ts
558
- const token = await client.refreshAuthAccount();
559
- ```
560
-
561
- ### Change password
562
-
563
- ```ts
564
- const result = await client.changeAuthPassword({
565
- CurrentPassword: "Pass123$",
566
- NewPassword: "Pass456$"
567
- });
568
- ```
569
-
570
- ### Request password reset
571
-
572
- ```ts
573
- const resetToken = await client.requestAuthPasswordReset({
574
- UserNameOrEmail: "root"
575
- });
576
- ```
577
-
578
- ### Reset password
579
-
580
- ```ts
581
- const result = await client.resetAuthPassword({
582
- UserId: resetToken.UserId as string,
583
- ResetToken: resetToken.ResetToken as string,
584
- NewPassword: "Pass789$"
585
- });
586
- ```
587
-
588
- ## Auth Management Operations
589
-
590
- Use these endpoints when the host exposes ChillSharp auth management APIs.
591
-
592
- ### Get current permissions
593
-
594
- ```ts
595
- const permissions = await client.getAuthPermissions();
596
- ```
597
-
598
- ### Get user list
599
-
600
- ```ts
601
- const users = await client.getAuthUserList();
602
- ```
603
-
604
- Each auth user item includes `displayCultureName`, `displayTimeZone`, `displayDateFormat`, and `displayNumberFormat`.
605
-
606
- ### Get managed user
607
-
608
- ```ts
609
- const user = await client.getAuthUser("f2d5d5e3-0a1f-4d15-9396-2ab5f6c4ff11");
610
- ```
611
-
612
- ### Set managed user
613
-
614
- ```ts
615
- const user = await client.setAuthUser({
616
- guid: null,
617
- externalId: "identity-user-001",
618
- userName: "identity.user",
619
- displayName: "Identity User",
620
- displayCultureName: "it-IT",
621
- displayTimeZone: "W. Europe Standard Time",
622
- displayDateFormat: "DD/MM/YYYY",
623
- displayNumberFormat: "1.000,00",
624
- isActive: true,
625
- canManagePermissions: false,
626
- canManageSchema: true,
627
- roleGuids: [],
628
- permissions: []
629
- });
630
- ```
631
-
632
- ### Get role list
633
-
634
- ```ts
635
- const roles = await client.getAuthRoleList();
636
- ```
637
-
638
- ### Get managed role
639
-
640
- ```ts
641
- const role = await client.getAuthRole("e2f0d8d5-0a1f-4d15-9396-2ab5f6c4ff22");
642
- ```
643
-
644
- ### Set managed role
645
-
646
- ```ts
647
- const role = await client.setAuthRole({
648
- guid: null,
649
- name: "Editors",
650
- description: "Can edit posts",
651
- isActive: true,
652
- userGuids: [],
653
- permissions: []
654
- });
655
- ```
656
-
657
- ## Error Handling
658
-
659
- All request failures raise `ChillSharpClientError`.
660
-
661
- ```ts
662
- import { ChillSharpClient, ChillSharpClientError } from "@chill-sharp/ts-client";
663
-
664
- const client = new ChillSharpClient("http://localhost:5000/api/chill", {
665
- cultureName: "it-IT"
666
- });
667
-
668
- try {
669
- await client.getSchema("Model.Post", "default");
670
- } catch (error) {
671
- if (error instanceof ChillSharpClientError) {
672
- console.log(error.statusCode);
673
- console.log(error.responseText);
674
- }
675
- }
676
- ```
677
-
678
- ## Custom Fetch
679
-
680
- If you need custom transport behavior, pass your own `fetch` implementation:
681
-
682
- ```ts
683
- const client = new ChillSharpClient("http://localhost:5000/api/chill", {
684
- fetchImpl: fetch
685
- });
686
- ```
687
-
688
- ## Generic Payload Strategy
689
-
690
- This package does not generate TypeScript model classes for your Chill entities.
691
-
692
- That is intentional:
693
-
694
- - ChillSharp models are application-specific
695
- - the standard Chill API already works well with generic objects
696
- - a generic client is easier to reuse across many different ChillSharp services
697
-
698
- If you need strongly typed TypeScript clients, generate them from your host OpenAPI document as described in [doc/ClientGeneration/README.md](../../doc/ClientGeneration/README.md).
699
-
700
-
701
-
702
-
703
-
704
-
705
-
706
-
707
-
478
+
479
+ ## I18n Operations
480
+
481
+ ### Get text
482
+
483
+ ```ts
484
+ const text = await client.getText({
485
+ LabelGuid: "4e16f6c0-6b95-4d67-98bc-9f4d0d63eaf1",
486
+ CultureName: "it-IT",
487
+ PrimaryCultureName: "en-GB",
488
+ PrimaryDefaultText: "Blog title",
489
+ SecondaryCultureName: "it-IT",
490
+ SecondaryDefaultText: "Titolo del blog"
491
+ });
492
+ ```
493
+
494
+ ### Get texts
495
+
496
+ ```ts
497
+ const texts = await client.getTexts([
498
+ {
499
+ LabelGuid: "4e16f6c0-6b95-4d67-98bc-9f4d0d63eaf1",
500
+ CultureName: "it-IT",
501
+ PrimaryCultureName: "en-GB",
502
+ PrimaryDefaultText: "Blog title",
503
+ SecondaryCultureName: "it-IT",
504
+ SecondaryDefaultText: "Titolo del blog"
505
+ },
506
+ {
507
+ LabelGuid: "2f6ef6f7-b0a9-44f8-bfd2-a3b3ed5b9a81",
508
+ CultureName: "it-IT",
509
+ PrimaryCultureName: "en-GB",
510
+ PrimaryDefaultText: "Blog url",
511
+ SecondaryCultureName: "it-IT",
512
+ SecondaryDefaultText: "Url del blog"
513
+ }
514
+ ]);
515
+ ```
516
+
517
+ ### Set text
518
+
519
+ ```ts
520
+ const saved = await client.setText({
521
+ LabelGuid: "4e16f6c0-6b95-4d67-98bc-9f4d0d63eaf1",
522
+ CultureName: "it-IT",
523
+ Value: "Titolo del blog"
524
+ });
525
+ ```
526
+
527
+ ## Auth Operations
528
+
529
+ The client assumes the auth base path is derived from `/api/chill` to `/api/chill-auth`, matching the .NET client.
530
+
531
+ ### Register account
532
+
533
+ ```ts
534
+ const token = await client.registerAuthAccount({
535
+ UserName: "root",
536
+ Email: "root@example.com",
537
+ Password: "Pass123$",
538
+ DisplayName: "Root",
539
+ DisplayCultureName: "it-IT",
540
+ CreateChillAuthUser: true
541
+ });
542
+ ```
543
+
544
+ If `DisplayCultureName` is provided and `CreateChillAuthUser` is `true`, the server presets the linked `AuthUser` with culture-based defaults for `displayTimeZone`, `displayDateFormat`, and `displayNumberFormat`.
545
+
546
+ ### Login
547
+
548
+ ```ts
549
+ const token = await client.loginAuthAccount({
550
+ UserNameOrEmail: "root",
551
+ Password: "Pass123$"
552
+ });
553
+ ```
554
+
555
+ ### Refresh current token
556
+
557
+ ```ts
558
+ const token = await client.refreshAuthAccount();
559
+ ```
560
+
561
+ ### Change password
562
+
563
+ ```ts
564
+ const result = await client.changeAuthPassword({
565
+ CurrentPassword: "Pass123$",
566
+ NewPassword: "Pass456$"
567
+ });
568
+ ```
569
+
570
+ ### Request password reset
571
+
572
+ ```ts
573
+ const resetToken = await client.requestAuthPasswordReset({
574
+ UserNameOrEmail: "root"
575
+ });
576
+ ```
577
+
578
+ ### Reset password
579
+
580
+ ```ts
581
+ const result = await client.resetAuthPassword({
582
+ UserId: resetToken.UserId as string,
583
+ ResetToken: resetToken.ResetToken as string,
584
+ NewPassword: "Pass789$"
585
+ });
586
+ ```
587
+
588
+ ## Auth Management Operations
589
+
590
+ Use these endpoints when the host exposes ChillSharp auth management APIs.
591
+
592
+ ### Get current permissions
593
+
594
+ ```ts
595
+ const permissions = await client.getAuthPermissions();
596
+ ```
597
+
598
+ ### Get user list
599
+
600
+ ```ts
601
+ const users = await client.getAuthUserList();
602
+ ```
603
+
604
+ Each auth user item includes `displayCultureName`, `displayTimeZone`, `displayDateFormat`, and `displayNumberFormat`.
605
+
606
+ ### Get managed user
607
+
608
+ ```ts
609
+ const user = await client.getAuthUser("f2d5d5e3-0a1f-4d15-9396-2ab5f6c4ff11");
610
+ ```
611
+
612
+ ### Set managed user
613
+
614
+ ```ts
615
+ const user = await client.setAuthUser({
616
+ guid: null,
617
+ externalId: "identity-user-001",
618
+ userName: "identity.user",
619
+ displayName: "Identity User",
620
+ displayCultureName: "it-IT",
621
+ displayTimeZone: "W. Europe Standard Time",
622
+ displayDateFormat: "DD/MM/YYYY",
623
+ displayNumberFormat: "1.000,00",
624
+ isActive: true,
625
+ canManagePermissions: false,
626
+ canManageSchema: true,
627
+ roleGuids: [],
628
+ permissions: []
629
+ });
630
+ ```
631
+
632
+ ### Get role list
633
+
634
+ ```ts
635
+ const roles = await client.getAuthRoleList();
636
+ ```
637
+
638
+ ### Get managed role
639
+
640
+ ```ts
641
+ const role = await client.getAuthRole("e2f0d8d5-0a1f-4d15-9396-2ab5f6c4ff22");
642
+ ```
643
+
644
+ ### Set managed role
645
+
646
+ ```ts
647
+ const role = await client.setAuthRole({
648
+ guid: null,
649
+ name: "Editors",
650
+ description: "Can edit posts",
651
+ isActive: true,
652
+ userGuids: [],
653
+ permissions: []
654
+ });
655
+ ```
656
+
657
+ ## Error Handling
658
+
659
+ All request failures raise `ChillSharpClientError`.
660
+
661
+ ```ts
662
+ import { ChillSharpClient, ChillSharpClientError } from "@chill-sharp/ts-client";
663
+
664
+ const client = new ChillSharpClient("http://localhost:5000/api/chill", {
665
+ cultureName: "it-IT"
666
+ });
667
+
668
+ try {
669
+ await client.getSchema("Model.Post", "default");
670
+ } catch (error) {
671
+ if (error instanceof ChillSharpClientError) {
672
+ console.log(error.statusCode);
673
+ console.log(error.responseText);
674
+ }
675
+ }
676
+ ```
677
+
678
+ ## Custom Fetch
679
+
680
+ If you need custom transport behavior, pass your own `fetch` implementation:
681
+
682
+ ```ts
683
+ const client = new ChillSharpClient("http://localhost:5000/api/chill", {
684
+ fetchImpl: fetch
685
+ });
686
+ ```
687
+
688
+ ## Generic Payload Strategy
689
+
690
+ This package does not generate TypeScript model classes for your Chill entities.
691
+
692
+ That is intentional:
693
+
694
+ - ChillSharp models are application-specific
695
+ - the standard Chill API already works well with generic objects
696
+ - a generic client is easier to reuse across many different ChillSharp services
697
+
698
+ If you need strongly typed TypeScript clients, generate them from your host OpenAPI document as described in [doc/ClientGeneration/README.md](../../doc/ClientGeneration/README.md).
699
+
700
+
701
+
702
+
703
+
704
+
705
+
706
+
707
+