@nymphjs/server 1.0.0-beta.10 → 1.0.0-beta.100
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/CHANGELOG.md +397 -0
- package/README.md +75 -3
- package/dist/HttpError.d.ts +5 -0
- package/dist/HttpError.js +11 -0
- package/dist/HttpError.js.map +1 -0
- package/dist/cache.test.js +14 -18
- package/dist/cache.test.js.map +1 -1
- package/dist/createServer.d.ts +17 -0
- package/dist/createServer.js +907 -0
- package/dist/createServer.js.map +1 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +5 -715
- package/dist/index.js.map +1 -1
- package/dist/index.test.js +168 -26
- package/dist/index.test.js.map +1 -1
- package/dist/statusDescriptions.d.ts +6 -0
- package/dist/statusDescriptions.js +69 -0
- package/dist/statusDescriptions.js.map +1 -0
- package/dist/testArtifacts.d.ts +59 -7
- package/dist/testArtifacts.js +171 -69
- package/dist/testArtifacts.js.map +1 -1
- package/jest.config.js +11 -2
- package/package.json +20 -20
- package/src/HttpError.ts +12 -0
- package/src/cache.test.ts +5 -5
- package/src/createServer.ts +981 -0
- package/src/index.test.ts +203 -29
- package/src/index.ts +5 -793
- package/src/statusDescriptions.ts +68 -0
- package/src/testArtifacts.ts +186 -39
- package/tsconfig.json +5 -3
- package/typedoc.json +4 -0
package/src/index.test.ts
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
2
|
import SQLite3Driver from '@nymphjs/driver-sqlite3';
|
|
3
3
|
import { Nymph as NymphServer } from '@nymphjs/nymph';
|
|
4
|
-
import { Nymph } from '@nymphjs/client
|
|
5
|
-
import { Entity } from '@nymphjs/client';
|
|
4
|
+
import { Nymph, Entity, HttpError } from '@nymphjs/client';
|
|
6
5
|
|
|
7
|
-
import createServer from './index';
|
|
6
|
+
import createServer from './index.js';
|
|
8
7
|
import {
|
|
9
8
|
EmployeeModel as EmployeeModelClass,
|
|
10
9
|
Employee as EmployeeClass,
|
|
11
|
-
|
|
10
|
+
RestrictedModel as RestrictedModelClass,
|
|
11
|
+
Restricted as RestrictedClass,
|
|
12
|
+
EmployeeData,
|
|
13
|
+
} from './testArtifacts.js';
|
|
12
14
|
|
|
13
15
|
const sqliteConfig = {
|
|
14
16
|
filename: ':memory:',
|
|
@@ -16,15 +18,18 @@ const sqliteConfig = {
|
|
|
16
18
|
|
|
17
19
|
const nymphServer = new NymphServer({}, new SQLite3Driver(sqliteConfig));
|
|
18
20
|
const EmployeeModel = nymphServer.addEntityClass(EmployeeModelClass);
|
|
21
|
+
const RestrictedModel = nymphServer.addEntityClass(RestrictedModelClass);
|
|
19
22
|
|
|
20
23
|
const app = express();
|
|
21
24
|
app.use('/test', createServer(nymphServer));
|
|
22
25
|
const server = app.listen(5080);
|
|
23
26
|
|
|
27
|
+
const REST_URL = 'http://localhost:5080/test/';
|
|
24
28
|
const nymph = new Nymph({
|
|
25
|
-
restUrl:
|
|
29
|
+
restUrl: REST_URL,
|
|
26
30
|
});
|
|
27
31
|
const Employee = nymph.addEntityClass(EmployeeClass);
|
|
32
|
+
const Restricted = nymph.addEntityClass(RestrictedClass);
|
|
28
33
|
|
|
29
34
|
describe('Nymph REST Server and Client', () => {
|
|
30
35
|
async function createJane() {
|
|
@@ -129,7 +134,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
129
134
|
{
|
|
130
135
|
type: '&',
|
|
131
136
|
ref: ['subordinates', jane],
|
|
132
|
-
}
|
|
137
|
+
},
|
|
133
138
|
);
|
|
134
139
|
|
|
135
140
|
expect(checkSteve?.guid).toEqual(steve.guid);
|
|
@@ -142,7 +147,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
142
147
|
'subordinates',
|
|
143
148
|
[{ class: Employee }, { type: '&', guid: jane.guid }],
|
|
144
149
|
],
|
|
145
|
-
}
|
|
150
|
+
},
|
|
146
151
|
);
|
|
147
152
|
|
|
148
153
|
expect(checkSteveQref?.guid).toEqual(steve.guid);
|
|
@@ -156,7 +161,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
156
161
|
expect(entity.$hasTag('test', 'test2')).toEqual(true);
|
|
157
162
|
entity.$addTag('test', 'test3', 'test4', 'test5', 'test6');
|
|
158
163
|
expect(entity.$hasTag('test', 'test3', 'test4', 'test5', 'test6')).toEqual(
|
|
159
|
-
true
|
|
164
|
+
true,
|
|
160
165
|
);
|
|
161
166
|
entity.$removeTag('test2');
|
|
162
167
|
expect(!entity.$hasTag('test2')).toEqual(true);
|
|
@@ -178,10 +183,10 @@ describe('Nymph REST Server and Client', () => {
|
|
|
178
183
|
'nymph_entity_reference',
|
|
179
184
|
jane.guid,
|
|
180
185
|
'Employee',
|
|
181
|
-
]);
|
|
182
|
-
await entity.$
|
|
186
|
+
]) as EmployeeClass & EmployeeData;
|
|
187
|
+
await entity.$wake();
|
|
183
188
|
|
|
184
|
-
expect(
|
|
189
|
+
expect(entity?.name).toEqual('Jane Doe');
|
|
185
190
|
});
|
|
186
191
|
|
|
187
192
|
it('change an entity', async () => {
|
|
@@ -232,13 +237,51 @@ describe('Nymph REST Server and Client', () => {
|
|
|
232
237
|
{
|
|
233
238
|
type: '&',
|
|
234
239
|
equal: ['name', 'Jane Doe'],
|
|
235
|
-
}
|
|
240
|
+
},
|
|
236
241
|
);
|
|
237
242
|
|
|
238
243
|
expect(jane).not.toBeNull();
|
|
239
244
|
expect(jane?.guid).not.toBeNull();
|
|
240
245
|
});
|
|
241
246
|
|
|
247
|
+
it('try to get a non-existent entity', async () => {
|
|
248
|
+
let error = { status: 200 };
|
|
249
|
+
try {
|
|
250
|
+
await nymph.getEntity(
|
|
251
|
+
{
|
|
252
|
+
class: Employee,
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
type: '&',
|
|
256
|
+
equal: ['name', 'Non Existent'],
|
|
257
|
+
},
|
|
258
|
+
);
|
|
259
|
+
} catch (e: any) {
|
|
260
|
+
error = e;
|
|
261
|
+
}
|
|
262
|
+
expect(error.status).toEqual(404);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('try to get a non-existent entity without error', async () => {
|
|
266
|
+
const nymph = new Nymph({
|
|
267
|
+
restUrl: REST_URL,
|
|
268
|
+
returnNullOnNotFound: true,
|
|
269
|
+
});
|
|
270
|
+
const Employee = nymph.addEntityClass(EmployeeClass);
|
|
271
|
+
|
|
272
|
+
const nonexistent = await nymph.getEntity(
|
|
273
|
+
{
|
|
274
|
+
class: Employee,
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
type: '&',
|
|
278
|
+
equal: ['name', 'Non Existent'],
|
|
279
|
+
},
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
expect(nonexistent).toBeNull();
|
|
283
|
+
});
|
|
284
|
+
|
|
242
285
|
it('get entities', async () => {
|
|
243
286
|
for (let i = 0; i < 4; i++) {
|
|
244
287
|
await createJane();
|
|
@@ -252,7 +295,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
252
295
|
{
|
|
253
296
|
type: '&',
|
|
254
297
|
tag: ['employee'],
|
|
255
|
-
}
|
|
298
|
+
},
|
|
256
299
|
);
|
|
257
300
|
|
|
258
301
|
expect(entities.length).toEqual(4);
|
|
@@ -278,13 +321,13 @@ describe('Nymph REST Server and Client', () => {
|
|
|
278
321
|
|
|
279
322
|
const resultSelectors = await nymph.getEntities(
|
|
280
323
|
{ class: Employee },
|
|
281
|
-
{ type: '&', equal: ['name', 'Jane Doe'] }
|
|
324
|
+
{ type: '&', equal: ['name', 'Jane Doe'] },
|
|
282
325
|
);
|
|
283
326
|
|
|
284
327
|
// Testing count return with selectors...
|
|
285
328
|
const resultSelectorsCount = await nymph.getEntities(
|
|
286
329
|
{ class: Employee, return: 'count' },
|
|
287
|
-
{ type: '&', equal: ['name', 'Jane Doe'] }
|
|
330
|
+
{ type: '&', equal: ['name', 'Jane Doe'] },
|
|
288
331
|
);
|
|
289
332
|
expect(resultSelectorsCount).toBeGreaterThanOrEqual(1);
|
|
290
333
|
expect(resultSelectorsCount).toEqual(resultSelectors.length);
|
|
@@ -307,7 +350,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
307
350
|
// Testing empty count...
|
|
308
351
|
const resultSelectorsEmpty = await nymph.getEntities(
|
|
309
352
|
{ class: Employee, return: 'count' },
|
|
310
|
-
{ type: '&', tag: 'pickle' }
|
|
353
|
+
{ type: '&', tag: 'pickle' },
|
|
311
354
|
);
|
|
312
355
|
expect(resultSelectorsEmpty).toEqual(0);
|
|
313
356
|
});
|
|
@@ -326,7 +369,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
326
369
|
{
|
|
327
370
|
type: '&',
|
|
328
371
|
tag: 'employee',
|
|
329
|
-
}
|
|
372
|
+
},
|
|
330
373
|
);
|
|
331
374
|
|
|
332
375
|
expect(entities.length).toEqual(4);
|
|
@@ -352,7 +395,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
352
395
|
{
|
|
353
396
|
type: '&',
|
|
354
397
|
like: ['name', '%Jane%'],
|
|
355
|
-
}
|
|
398
|
+
},
|
|
356
399
|
);
|
|
357
400
|
|
|
358
401
|
expect(entities.length).toEqual(4);
|
|
@@ -378,7 +421,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
378
421
|
type: '|',
|
|
379
422
|
like: ['name', '%Jane%'],
|
|
380
423
|
},
|
|
381
|
-
}
|
|
424
|
+
},
|
|
382
425
|
);
|
|
383
426
|
|
|
384
427
|
expect(entities.length).toEqual(4);
|
|
@@ -413,7 +456,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
413
456
|
},
|
|
414
457
|
],
|
|
415
458
|
},
|
|
416
|
-
}
|
|
459
|
+
},
|
|
417
460
|
);
|
|
418
461
|
|
|
419
462
|
expect(entities.length).toEqual(4);
|
|
@@ -438,7 +481,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
438
481
|
{
|
|
439
482
|
type: '&',
|
|
440
483
|
guid,
|
|
441
|
-
}
|
|
484
|
+
},
|
|
442
485
|
);
|
|
443
486
|
|
|
444
487
|
expect(check.length).toEqual(0);
|
|
@@ -461,7 +504,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
461
504
|
{
|
|
462
505
|
type: '|',
|
|
463
506
|
guid: guids,
|
|
464
|
-
}
|
|
507
|
+
},
|
|
465
508
|
);
|
|
466
509
|
|
|
467
510
|
expect(check.length).toEqual(0);
|
|
@@ -478,7 +521,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
478
521
|
error = e;
|
|
479
522
|
}
|
|
480
523
|
expect(error.message).toEqual(
|
|
481
|
-
"Can't use Entity class directly from the front end."
|
|
524
|
+
"Can't use Entity class directly from the front end.",
|
|
482
525
|
);
|
|
483
526
|
});
|
|
484
527
|
|
|
@@ -493,32 +536,103 @@ describe('Nymph REST Server and Client', () => {
|
|
|
493
536
|
});
|
|
494
537
|
|
|
495
538
|
it('handle server side static error', async () => {
|
|
496
|
-
let error = { error: { name: '' } };
|
|
539
|
+
let error = { status: 0, error: { name: '' } };
|
|
497
540
|
try {
|
|
498
541
|
await Employee.throwErrorStatic();
|
|
499
542
|
} catch (e: any) {
|
|
500
543
|
error = e;
|
|
501
544
|
}
|
|
545
|
+
expect(error.status).toEqual(500);
|
|
546
|
+
expect(error.error.name).toEqual('BadFunctionCallError');
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
it('handle server side static iterator error', async () => {
|
|
550
|
+
let error: any = { status: 0, error: { name: '' } };
|
|
551
|
+
const data = await Employee.throwErrorStaticIterable();
|
|
552
|
+
|
|
553
|
+
let count = 0;
|
|
554
|
+
for await (let value of data) {
|
|
555
|
+
count++;
|
|
556
|
+
if (value instanceof Error) {
|
|
557
|
+
error = value;
|
|
558
|
+
} else {
|
|
559
|
+
expect(value).toEqual(count);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
expect(count).toEqual(2);
|
|
564
|
+
expect(error.status).toEqual(500);
|
|
502
565
|
expect(error.error.name).toEqual('BadFunctionCallError');
|
|
503
566
|
});
|
|
504
567
|
|
|
505
568
|
it('handle server side error', async () => {
|
|
506
569
|
const jane = await createJane();
|
|
507
570
|
|
|
508
|
-
let error = { error: { name: '' } };
|
|
571
|
+
let error = { status: 0, error: { name: '' } };
|
|
509
572
|
try {
|
|
510
573
|
await jane.$throwError();
|
|
511
574
|
} catch (e: any) {
|
|
512
575
|
error = e;
|
|
513
576
|
}
|
|
577
|
+
expect(error.status).toEqual(500);
|
|
514
578
|
expect(error.error.name).toEqual('BadFunctionCallError');
|
|
515
579
|
});
|
|
516
580
|
|
|
581
|
+
it('handle server side HTTP error', async () => {
|
|
582
|
+
const jane = await createJane();
|
|
583
|
+
|
|
584
|
+
let error = { status: 0, statusText: '', message: '' };
|
|
585
|
+
try {
|
|
586
|
+
await jane.$throwHttpError();
|
|
587
|
+
} catch (e: any) {
|
|
588
|
+
error = e;
|
|
589
|
+
}
|
|
590
|
+
expect(error.status).toEqual(501);
|
|
591
|
+
expect(error.statusText).toEqual('Not Implemented');
|
|
592
|
+
expect(error.message).toEqual('A 501 HTTP error.');
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
it('handle server side custom HTTP error', async () => {
|
|
596
|
+
const jane = await createJane();
|
|
597
|
+
|
|
598
|
+
let error = { status: 0, statusText: '', message: '' };
|
|
599
|
+
try {
|
|
600
|
+
await jane.$throwHttpErrorWithDescription();
|
|
601
|
+
} catch (e: any) {
|
|
602
|
+
error = e;
|
|
603
|
+
}
|
|
604
|
+
expect(error.status).toEqual(512);
|
|
605
|
+
expect(error.statusText).toEqual('Some Error');
|
|
606
|
+
expect(error.message).toEqual('A 512 HTTP error.');
|
|
607
|
+
});
|
|
608
|
+
|
|
517
609
|
it('call a server side static method', async () => {
|
|
518
610
|
const data = await Employee.testStatic(5);
|
|
519
611
|
expect(data).toEqual(10);
|
|
520
612
|
});
|
|
521
613
|
|
|
614
|
+
it('call a server side static iterator method', async () => {
|
|
615
|
+
const data = await Employee.testStaticIterable(5);
|
|
616
|
+
|
|
617
|
+
let count = 0;
|
|
618
|
+
for await (let value of data) {
|
|
619
|
+
count++;
|
|
620
|
+
expect(value).toEqual(5 + count);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
expect(count).toEqual(3);
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
it('aborts a server side static iterator method', async () => {
|
|
627
|
+
const data = await Employee.testStaticIterableAbort();
|
|
628
|
+
data.abortController.abort();
|
|
629
|
+
|
|
630
|
+
// Wait 1 second to ensure server receives abort signal.
|
|
631
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
632
|
+
|
|
633
|
+
expect(true).toBeTruthy();
|
|
634
|
+
});
|
|
635
|
+
|
|
522
636
|
it('call a stateless server side method', async () => {
|
|
523
637
|
const jane = await createJane();
|
|
524
638
|
|
|
@@ -547,7 +661,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
547
661
|
{
|
|
548
662
|
class: Employee,
|
|
549
663
|
},
|
|
550
|
-
jane1.guid
|
|
664
|
+
jane1.guid,
|
|
551
665
|
);
|
|
552
666
|
if (jane1 == null || jane2 == null) {
|
|
553
667
|
throw new Error('Entity is null.');
|
|
@@ -573,7 +687,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
573
687
|
{
|
|
574
688
|
class: Employee,
|
|
575
689
|
},
|
|
576
|
-
first.guid
|
|
690
|
+
first.guid,
|
|
577
691
|
);
|
|
578
692
|
|
|
579
693
|
if (second == null || second.guid == null) {
|
|
@@ -605,7 +719,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
605
719
|
{
|
|
606
720
|
class: Employee,
|
|
607
721
|
},
|
|
608
|
-
first.guid
|
|
722
|
+
first.guid,
|
|
609
723
|
);
|
|
610
724
|
|
|
611
725
|
if (second == null || second.guid == null) {
|
|
@@ -628,7 +742,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
628
742
|
{
|
|
629
743
|
type: '&',
|
|
630
744
|
'!guid': first.guid,
|
|
631
|
-
}
|
|
745
|
+
},
|
|
632
746
|
);
|
|
633
747
|
|
|
634
748
|
if (third == null || third.guid == null) {
|
|
@@ -638,6 +752,66 @@ describe('Nymph REST Server and Client', () => {
|
|
|
638
752
|
expect(first.$is(third)).toEqual(false);
|
|
639
753
|
});
|
|
640
754
|
|
|
755
|
+
it("doesn't allow creation of a restricted entity class", async () => {
|
|
756
|
+
const attempt = await Restricted.factory();
|
|
757
|
+
attempt.name = 'Jane Doe';
|
|
758
|
+
|
|
759
|
+
let error = null;
|
|
760
|
+
|
|
761
|
+
try {
|
|
762
|
+
await attempt.$save();
|
|
763
|
+
} catch (e: any) {
|
|
764
|
+
error = e;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
expect(error).toBeInstanceOf(HttpError);
|
|
768
|
+
expect(error.status).toEqual(403);
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
it("doesn't allow search of a restricted entity class", async () => {
|
|
772
|
+
let error = null;
|
|
773
|
+
|
|
774
|
+
try {
|
|
775
|
+
await nymph.getEntity({
|
|
776
|
+
class: Restricted,
|
|
777
|
+
});
|
|
778
|
+
} catch (e: any) {
|
|
779
|
+
error = e;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
expect(error).toBeInstanceOf(HttpError);
|
|
783
|
+
expect(error.status).toEqual(403);
|
|
784
|
+
});
|
|
785
|
+
|
|
786
|
+
it("doesn't allow methods of a restricted entity class", async () => {
|
|
787
|
+
const attempt = await Restricted.factory();
|
|
788
|
+
attempt.name = 'Jane Doe';
|
|
789
|
+
|
|
790
|
+
let error = null;
|
|
791
|
+
|
|
792
|
+
try {
|
|
793
|
+
await attempt.$testMethod(1);
|
|
794
|
+
} catch (e: any) {
|
|
795
|
+
error = e;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
expect(error).toBeInstanceOf(HttpError);
|
|
799
|
+
expect(error.status).toEqual(403);
|
|
800
|
+
});
|
|
801
|
+
|
|
802
|
+
it("doesn't allow static methods of a restricted entity class", async () => {
|
|
803
|
+
let error = null;
|
|
804
|
+
|
|
805
|
+
try {
|
|
806
|
+
await Restricted.testStatic(1);
|
|
807
|
+
} catch (e: any) {
|
|
808
|
+
error = e;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
expect(error).toBeInstanceOf(HttpError);
|
|
812
|
+
expect(error.status).toEqual(403);
|
|
813
|
+
});
|
|
814
|
+
|
|
641
815
|
it('get a new UID', async () => {
|
|
642
816
|
const uidValue = await nymph.newUID('employee');
|
|
643
817
|
expect(typeof uidValue).toEqual('number');
|