@fjell/client-api 4.4.6 ā 4.4.7
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/dist/Instance.d.ts +19 -0
- package/dist/Instance.js +19 -0
- package/dist/Instance.js.map +1 -0
- package/dist/InstanceFactory.d.ts +8 -0
- package/dist/InstanceFactory.js +19 -0
- package/dist/InstanceFactory.js.map +1 -0
- package/dist/Registry.d.ts +15 -0
- package/dist/Registry.js +31 -0
- package/dist/Registry.js.map +1 -0
- package/dist/index.cjs +106 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/examples/README.md +387 -0
- package/examples/enterprise-example.ts +852 -0
- package/examples/multi-level-keys.ts +467 -0
- package/examples/simple-example.ts +346 -0
- package/package.json +4 -3
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
+
/**
|
|
3
|
+
* Simple Fjell-Client-API Example - Basic Client API Operations
|
|
4
|
+
*
|
|
5
|
+
* This example demonstrates the conceptual usage of fjell-client-api for HTTP-based
|
|
6
|
+
* data operations. It shows the patterns and API design for client-side operations.
|
|
7
|
+
*
|
|
8
|
+
* This is a conceptual guide showing:
|
|
9
|
+
* - How to create and configure client APIs (PItemApi and CItemApi)
|
|
10
|
+
* - Basic CRUD operations through HTTP endpoints
|
|
11
|
+
* - Primary and contained item patterns
|
|
12
|
+
* - Error handling and response management
|
|
13
|
+
*
|
|
14
|
+
* Run this example with: npx tsx examples/simple-example.ts
|
|
15
|
+
*
|
|
16
|
+
* Note: This is a conceptual example showing API patterns.
|
|
17
|
+
* In a real application, import from the built package:
|
|
18
|
+
* import { createPItemApi, createCItemApi } from '@fjell/client-api';
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Conceptual demonstration of fjell-client-api usage patterns
|
|
23
|
+
* This example shows the API structure without full type implementation
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
// ===== Mock API Implementations =====
|
|
27
|
+
|
|
28
|
+
interface MockPItemApi {
|
|
29
|
+
all(query: any): Promise<any[]>;
|
|
30
|
+
create(item: any): Promise<any>;
|
|
31
|
+
get(key: any): Promise<any>;
|
|
32
|
+
update(key: any, updates: any): Promise<any>;
|
|
33
|
+
remove(key: any): Promise<boolean>;
|
|
34
|
+
action(key: any, action: string, body?: any): Promise<any>;
|
|
35
|
+
find(finder: string, params?: any): Promise<any[]>;
|
|
36
|
+
facet(key: any, facet: string, params?: any): Promise<any>;
|
|
37
|
+
allAction(action: string, body?: any): Promise<any[]>;
|
|
38
|
+
allFacet(facet: string, params?: any): Promise<any>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface MockCItemApi extends MockPItemApi {
|
|
42
|
+
all(query: any, locations?: any[]): Promise<any[]>;
|
|
43
|
+
create(item: any, locations?: any[]): Promise<any>;
|
|
44
|
+
find(finder: string, params?: any, locations?: any[]): Promise<any[]>;
|
|
45
|
+
allAction(action: string, body?: any, locations?: any[]): Promise<any[]>;
|
|
46
|
+
allFacet(facet: string, params?: any, locations?: any[]): Promise<any>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Mock implementation that logs operations
|
|
50
|
+
const createMockPItemApi = (itemType: string): MockPItemApi => ({
|
|
51
|
+
async all(query: any) {
|
|
52
|
+
console.log(`š PItemApi.all(${itemType}) - query:`, query);
|
|
53
|
+
return [
|
|
54
|
+
{ id: '1', name: 'Item 1', keyType: itemType },
|
|
55
|
+
{ id: '2', name: 'Item 2', keyType: itemType }
|
|
56
|
+
];
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
async create(item: any) {
|
|
60
|
+
const created = { ...item, id: `${itemType}-${Date.now()}` };
|
|
61
|
+
console.log(`ā PItemApi.create(${itemType}) - created:`, created.id);
|
|
62
|
+
return created;
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
async get(key: any) {
|
|
66
|
+
console.log(`š PItemApi.get(${itemType}) - key:`, key);
|
|
67
|
+
return { id: key.id, name: `${itemType} ${key.id}`, keyType: itemType };
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
async update(key: any, updates: any) {
|
|
71
|
+
console.log(`āļø PItemApi.update(${itemType}) - key:`, key, 'updates:', updates);
|
|
72
|
+
return { id: key.id, ...updates, keyType: itemType };
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
async remove(key: any) {
|
|
76
|
+
console.log(`šļø PItemApi.remove(${itemType}) - key:`, key);
|
|
77
|
+
return true;
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
async action(key: any, action: string, body?: any) {
|
|
81
|
+
console.log(`ā” PItemApi.action(${itemType}) - action:`, action, 'on:', key.id);
|
|
82
|
+
return { success: true, action, result: body };
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
async find(finder: string, params?: any) {
|
|
86
|
+
console.log(`š PItemApi.find(${itemType}) - finder:`, finder, 'params:', params);
|
|
87
|
+
return [{ id: '1', name: 'Found Item', keyType: itemType }];
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
async facet(key: any, facet: string, params?: any) {
|
|
91
|
+
console.log(`š PItemApi.facet(${itemType}) - facet:`, facet, 'on:', key.id);
|
|
92
|
+
return { facet, data: { count: 42, stats: 'mock data' } };
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
async allAction(action: string, body?: any) {
|
|
96
|
+
console.log(`š¦ PItemApi.allAction(${itemType}) - action:`, action);
|
|
97
|
+
return [{ id: '1', result: 'updated' }, { id: '2', result: 'updated' }];
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
async allFacet(facet: string, params?: any) {
|
|
101
|
+
console.log(`š PItemApi.allFacet(${itemType}) - facet:`, facet);
|
|
102
|
+
return { facet, totalCount: 100, data: 'aggregated results' };
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const createMockCItemApi = (itemType: string, parentType: string): MockCItemApi => ({
|
|
107
|
+
...createMockPItemApi(itemType),
|
|
108
|
+
|
|
109
|
+
async all(query: any, locations?: any[]) {
|
|
110
|
+
console.log(`š CItemApi.all(${itemType}) - query:`, query, 'locations:', locations);
|
|
111
|
+
return [
|
|
112
|
+
{ id: '1', name: `${itemType} 1`, keyType: itemType, parentId: locations?.[0] },
|
|
113
|
+
{ id: '2', name: `${itemType} 2`, keyType: itemType, parentId: locations?.[0] }
|
|
114
|
+
];
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
async create(item: any, locations?: any[]) {
|
|
118
|
+
const created = { ...item, id: `${itemType}-${Date.now()}`, parentId: locations?.[0] };
|
|
119
|
+
console.log(`ā CItemApi.create(${itemType}) - created:`, created.id, 'in:', locations);
|
|
120
|
+
return created;
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
async find(finder: string, params?: any, locations?: any[]) {
|
|
124
|
+
console.log(`š CItemApi.find(${itemType}) - finder:`, finder, 'in:', locations);
|
|
125
|
+
return [{ id: '1', name: 'Found Item', keyType: itemType, parentId: locations?.[0] }];
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
async allAction(action: string, body?: any, locations?: any[]) {
|
|
129
|
+
console.log(`š¦ CItemApi.allAction(${itemType}) - action:`, action, 'in:', locations);
|
|
130
|
+
return [{ id: '1', result: 'updated' }, { id: '2', result: 'updated' }];
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
async allFacet(facet: string, params?: any, locations?: any[]) {
|
|
134
|
+
console.log(`š CItemApi.allFacet(${itemType}) - facet:`, facet, 'in:', locations);
|
|
135
|
+
return { facet, totalCount: 25, data: 'location-specific results' };
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Demonstrates Primary Item API operations with User entity
|
|
141
|
+
* Primary items exist independently and have their own endpoints
|
|
142
|
+
*/
|
|
143
|
+
async function demonstratePrimaryItemOperations() {
|
|
144
|
+
console.log('\nš === Primary Item Operations (Users) ===');
|
|
145
|
+
|
|
146
|
+
// Conceptual: const userApi = createPItemApi<User, 'user'>('user', ['users'], apiConfig);
|
|
147
|
+
const userApi = createMockPItemApi('user');
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
// 1. Get all users
|
|
151
|
+
console.log('\nš Getting all users...');
|
|
152
|
+
const users = await userApi.all({ filter: {} });
|
|
153
|
+
console.log(`Found ${users.length} users`);
|
|
154
|
+
|
|
155
|
+
// 2. Create a new user
|
|
156
|
+
console.log('\nā Creating a new user...');
|
|
157
|
+
const newUser = {
|
|
158
|
+
name: 'John Doe',
|
|
159
|
+
email: 'john.doe@example.com',
|
|
160
|
+
keyType: 'user'
|
|
161
|
+
};
|
|
162
|
+
const createdUser = await userApi.create(newUser);
|
|
163
|
+
console.log(`Created user: ${createdUser.name} (${createdUser.id})`);
|
|
164
|
+
|
|
165
|
+
// 3. Get specific user
|
|
166
|
+
console.log('\nš Getting specific user...');
|
|
167
|
+
const userId = { keyType: 'user', id: createdUser.id };
|
|
168
|
+
const retrievedUser = await userApi.get(userId);
|
|
169
|
+
console.log(`Retrieved user: ${retrievedUser?.name}`);
|
|
170
|
+
|
|
171
|
+
// 4. Update user
|
|
172
|
+
console.log('\nāļø Updating user...');
|
|
173
|
+
const updates = { name: 'John Smith' };
|
|
174
|
+
const updatedUser = await userApi.update(userId, updates);
|
|
175
|
+
console.log(`Updated user name to: ${updatedUser?.name}`);
|
|
176
|
+
|
|
177
|
+
// 5. Execute action on user
|
|
178
|
+
console.log('\nā” Executing action on user...');
|
|
179
|
+
await userApi.action(userId, 'activate', { reason: 'manual activation' });
|
|
180
|
+
console.log(`Action result: User activated`);
|
|
181
|
+
|
|
182
|
+
// 6. Query with finder
|
|
183
|
+
console.log('\nš Finding users by email...');
|
|
184
|
+
const foundUsers = await userApi.find('byEmail', { email: 'john.smith@example.com' });
|
|
185
|
+
console.log(`Found ${foundUsers.length} users with matching email`);
|
|
186
|
+
|
|
187
|
+
// 7. Get facet data
|
|
188
|
+
console.log('\nš Getting user statistics...');
|
|
189
|
+
const userStats = await userApi.facet(userId, 'stats', {});
|
|
190
|
+
console.log(`User stats:`, userStats);
|
|
191
|
+
|
|
192
|
+
return createdUser.id;
|
|
193
|
+
|
|
194
|
+
} catch (error) {
|
|
195
|
+
console.error('ā Error in primary item operations:', error);
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Demonstrates Contained Item API operations with Task entity
|
|
202
|
+
* Contained items belong to a location/parent and have hierarchical endpoints
|
|
203
|
+
*/
|
|
204
|
+
async function demonstrateContainedItemOperations(userId: string) {
|
|
205
|
+
console.log('\nš === Contained Item Operations (Tasks) ===');
|
|
206
|
+
|
|
207
|
+
// Conceptual: const taskApi = createCItemApi<Task, 'task', 'user'>('task', ['users', 'tasks'], apiConfig);
|
|
208
|
+
const taskApi = createMockCItemApi('task', 'user');
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
// Define user location for contained items
|
|
212
|
+
const userLocation = [userId];
|
|
213
|
+
|
|
214
|
+
// 1. Get all tasks for user
|
|
215
|
+
console.log('\nš Getting all tasks for user...');
|
|
216
|
+
const tasks = await taskApi.all({ filter: {} }, userLocation);
|
|
217
|
+
console.log(`Found ${tasks.length} tasks for user`);
|
|
218
|
+
|
|
219
|
+
// 2. Create a new task
|
|
220
|
+
console.log('\nā Creating a new task...');
|
|
221
|
+
const newTask = {
|
|
222
|
+
title: 'Complete Project Documentation',
|
|
223
|
+
description: 'Write comprehensive docs for the fjell-client-api',
|
|
224
|
+
completed: false,
|
|
225
|
+
userId: userId,
|
|
226
|
+
keyType: 'task'
|
|
227
|
+
};
|
|
228
|
+
const createdTask = await taskApi.create(newTask, userLocation);
|
|
229
|
+
console.log(`Created task: ${createdTask.title} (${createdTask.id})`);
|
|
230
|
+
|
|
231
|
+
// 3. Get specific task
|
|
232
|
+
console.log('\nš Getting specific task...');
|
|
233
|
+
const taskKey = { keyType: 'task', id: createdTask.id };
|
|
234
|
+
const retrievedTask = await taskApi.get(taskKey);
|
|
235
|
+
console.log(`Retrieved task: ${retrievedTask?.title}`);
|
|
236
|
+
|
|
237
|
+
// 4. Update task
|
|
238
|
+
console.log('\nāļø Updating task...');
|
|
239
|
+
const updates = { completed: true };
|
|
240
|
+
const updatedTask = await taskApi.update(taskKey, updates);
|
|
241
|
+
console.log(`Task completed: ${updatedTask?.completed}`);
|
|
242
|
+
|
|
243
|
+
// 5. Execute action on task
|
|
244
|
+
console.log('\nā” Executing action on task...');
|
|
245
|
+
await taskApi.action(taskKey, 'setPriority', { priority: 'high' });
|
|
246
|
+
console.log(`Action result: Task priority set`);
|
|
247
|
+
|
|
248
|
+
// 6. Find tasks by status
|
|
249
|
+
console.log('\nš Finding completed tasks...');
|
|
250
|
+
const completedTasks = await taskApi.find('byStatus', { completed: true }, userLocation);
|
|
251
|
+
console.log(`Found ${completedTasks.length} completed tasks`);
|
|
252
|
+
|
|
253
|
+
// 7. Get task analytics
|
|
254
|
+
console.log('\nš Getting task analytics...');
|
|
255
|
+
const taskAnalytics = await taskApi.allFacet('analytics', { period: 'week' }, userLocation);
|
|
256
|
+
console.log(`Task analytics:`, taskAnalytics);
|
|
257
|
+
|
|
258
|
+
// 8. Remove task
|
|
259
|
+
console.log('\nšļø Removing task...');
|
|
260
|
+
const removed = await taskApi.remove(taskKey);
|
|
261
|
+
console.log(`Task removed: ${removed}`);
|
|
262
|
+
|
|
263
|
+
} catch (error) {
|
|
264
|
+
console.error('ā Error in contained item operations:', error);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Demonstrates advanced API features
|
|
270
|
+
*/
|
|
271
|
+
async function demonstrateAdvancedFeatures() {
|
|
272
|
+
console.log('\nš === Advanced API Features ===');
|
|
273
|
+
|
|
274
|
+
const userApi = createMockPItemApi('user');
|
|
275
|
+
|
|
276
|
+
try {
|
|
277
|
+
// 1. Batch operations
|
|
278
|
+
console.log('\nš¦ Executing batch action...');
|
|
279
|
+
const batchResult = await userApi.allAction('batchUpdate', {
|
|
280
|
+
updates: { lastLogin: new Date() }
|
|
281
|
+
});
|
|
282
|
+
console.log(`Batch updated ${batchResult.length} users`);
|
|
283
|
+
|
|
284
|
+
// 2. Complex facet queries
|
|
285
|
+
console.log('\nš Getting complex analytics...');
|
|
286
|
+
const analytics = await userApi.allFacet('analytics', {
|
|
287
|
+
startDate: new Date('2024-01-01'),
|
|
288
|
+
endDate: new Date(),
|
|
289
|
+
metrics: ['registrations', 'activity', 'retention']
|
|
290
|
+
});
|
|
291
|
+
console.log(`Analytics data:`, analytics);
|
|
292
|
+
|
|
293
|
+
// 3. Advanced queries
|
|
294
|
+
console.log('\nš Advanced user search...');
|
|
295
|
+
const activeUsers = await userApi.find('activeUsers', {
|
|
296
|
+
lastLoginAfter: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), // Last 7 days
|
|
297
|
+
includeMetrics: true
|
|
298
|
+
});
|
|
299
|
+
console.log(`Found ${activeUsers.length} active users`);
|
|
300
|
+
|
|
301
|
+
} catch (error) {
|
|
302
|
+
console.error('ā Error in advanced features:', error);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Main function to run the simple example
|
|
308
|
+
*/
|
|
309
|
+
export async function runSimpleExample() {
|
|
310
|
+
console.log('šÆ Fjell-Client-API Simple Example');
|
|
311
|
+
console.log('===================================');
|
|
312
|
+
console.log('Demonstrating basic client API operations with HTTP endpoints\n');
|
|
313
|
+
|
|
314
|
+
try {
|
|
315
|
+
// Run primary item operations
|
|
316
|
+
const userId = await demonstratePrimaryItemOperations();
|
|
317
|
+
|
|
318
|
+
if (userId) {
|
|
319
|
+
// Run contained item operations
|
|
320
|
+
await demonstrateContainedItemOperations(userId);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Run advanced features
|
|
324
|
+
await demonstrateAdvancedFeatures();
|
|
325
|
+
|
|
326
|
+
console.log('\nā
Simple example completed successfully!');
|
|
327
|
+
console.log('\nKey Concepts Demonstrated:');
|
|
328
|
+
console.log('⢠Primary Item API (PItemApi) for independent entities');
|
|
329
|
+
console.log('⢠Contained Item API (CItemApi) for hierarchical data');
|
|
330
|
+
console.log('⢠CRUD operations through HTTP endpoints');
|
|
331
|
+
console.log('⢠Actions and facets for business logic');
|
|
332
|
+
console.log('⢠Query patterns and finders');
|
|
333
|
+
console.log('⢠Error handling and response management');
|
|
334
|
+
console.log('\nNote: This is a conceptual example showing API patterns.');
|
|
335
|
+
console.log('In production, use actual fjell-client-api with proper types.');
|
|
336
|
+
|
|
337
|
+
} catch (error) {
|
|
338
|
+
console.error('ā Example failed:', error);
|
|
339
|
+
throw error;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Run the example if this file is executed directly
|
|
344
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
345
|
+
runSimpleExample().catch(console.error);
|
|
346
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fjell/client-api",
|
|
3
3
|
"description": "Client API for Fjell",
|
|
4
|
-
"version": "4.4.
|
|
4
|
+
"version": "4.4.7",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"client",
|
|
7
7
|
"api",
|
|
@@ -20,12 +20,13 @@
|
|
|
20
20
|
"@fjell/core": "^4.4.7",
|
|
21
21
|
"@fjell/http-api": "^4.4.5",
|
|
22
22
|
"@fjell/logging": "^4.4.7",
|
|
23
|
+
"@fjell/registry": "^4.4.7",
|
|
23
24
|
"deepmerge": "^4.3.1"
|
|
24
25
|
},
|
|
25
26
|
"devDependencies": {
|
|
26
27
|
"@eslint/eslintrc": "^3.3.1",
|
|
27
28
|
"@eslint/js": "^9.31.0",
|
|
28
|
-
"@swc/core": "^1.
|
|
29
|
+
"@swc/core": "^1.13.1",
|
|
29
30
|
"@tsconfig/recommended": "^1.0.10",
|
|
30
31
|
"@typescript-eslint/eslint-plugin": "^8.37.0",
|
|
31
32
|
"@typescript-eslint/parser": "^8.37.0",
|
|
@@ -36,7 +37,7 @@
|
|
|
36
37
|
"eslint": "^9.31.0",
|
|
37
38
|
"rimraf": "^6.0.1",
|
|
38
39
|
"typescript": "^5.8.3",
|
|
39
|
-
"vite": "^7.0.
|
|
40
|
+
"vite": "^7.0.5",
|
|
40
41
|
"vite-plugin-dts": "^4.5.4",
|
|
41
42
|
"vite-plugin-node": "^7.0.0",
|
|
42
43
|
"vitest": "^3.2.4"
|