@nymphjs/server 1.0.0-beta.8 → 1.0.0-beta.81
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 +315 -0
- package/README.md +74 -2
- package/dist/HttpError.d.ts +5 -0
- package/dist/HttpError.js +15 -0
- package/dist/HttpError.js.map +1 -0
- package/dist/cache.test.js +2 -1
- 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 +18 -712
- package/dist/index.js.map +1 -1
- package/dist/index.test.js +123 -5
- package/dist/index.test.js.map +1 -1
- package/dist/statusDescriptions.d.ts +6 -0
- package/dist/statusDescriptions.js +72 -0
- package/dist/statusDescriptions.js.map +1 -0
- package/dist/testArtifacts.d.ts +59 -7
- package/dist/testArtifacts.js +170 -58
- package/dist/testArtifacts.js.map +1 -1
- package/package.json +16 -16
- package/src/HttpError.ts +12 -0
- package/src/cache.test.ts +2 -2
- package/src/createServer.ts +974 -0
- package/src/index.test.ts +161 -25
- package/src/index.ts +5 -793
- package/src/statusDescriptions.ts +68 -0
- package/src/testArtifacts.ts +186 -39
- package/tsconfig.json +3 -3
- package/typedoc.json +4 -0
package/src/index.test.ts
CHANGED
|
@@ -2,12 +2,15 @@ import express from 'express';
|
|
|
2
2
|
import SQLite3Driver from '@nymphjs/driver-sqlite3';
|
|
3
3
|
import { Nymph as NymphServer } from '@nymphjs/nymph';
|
|
4
4
|
import { Nymph } from '@nymphjs/client-node';
|
|
5
|
-
import { Entity } from '@nymphjs/client';
|
|
5
|
+
import { Entity, HttpError } from '@nymphjs/client';
|
|
6
6
|
|
|
7
7
|
import createServer from './index';
|
|
8
8
|
import {
|
|
9
9
|
EmployeeModel as EmployeeModelClass,
|
|
10
10
|
Employee as EmployeeClass,
|
|
11
|
+
RestrictedModel as RestrictedModelClass,
|
|
12
|
+
Restricted as RestrictedClass,
|
|
13
|
+
EmployeeData,
|
|
11
14
|
} from './testArtifacts';
|
|
12
15
|
|
|
13
16
|
const sqliteConfig = {
|
|
@@ -16,6 +19,7 @@ const sqliteConfig = {
|
|
|
16
19
|
|
|
17
20
|
const nymphServer = new NymphServer({}, new SQLite3Driver(sqliteConfig));
|
|
18
21
|
const EmployeeModel = nymphServer.addEntityClass(EmployeeModelClass);
|
|
22
|
+
const RestrictedModel = nymphServer.addEntityClass(RestrictedModelClass);
|
|
19
23
|
|
|
20
24
|
const app = express();
|
|
21
25
|
app.use('/test', createServer(nymphServer));
|
|
@@ -25,6 +29,7 @@ const nymph = new Nymph({
|
|
|
25
29
|
restUrl: 'http://localhost:5080/test/',
|
|
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,7 +237,7 @@ 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();
|
|
@@ -252,7 +257,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
252
257
|
{
|
|
253
258
|
type: '&',
|
|
254
259
|
tag: ['employee'],
|
|
255
|
-
}
|
|
260
|
+
},
|
|
256
261
|
);
|
|
257
262
|
|
|
258
263
|
expect(entities.length).toEqual(4);
|
|
@@ -278,13 +283,13 @@ describe('Nymph REST Server and Client', () => {
|
|
|
278
283
|
|
|
279
284
|
const resultSelectors = await nymph.getEntities(
|
|
280
285
|
{ class: Employee },
|
|
281
|
-
{ type: '&', equal: ['name', 'Jane Doe'] }
|
|
286
|
+
{ type: '&', equal: ['name', 'Jane Doe'] },
|
|
282
287
|
);
|
|
283
288
|
|
|
284
289
|
// Testing count return with selectors...
|
|
285
290
|
const resultSelectorsCount = await nymph.getEntities(
|
|
286
291
|
{ class: Employee, return: 'count' },
|
|
287
|
-
{ type: '&', equal: ['name', 'Jane Doe'] }
|
|
292
|
+
{ type: '&', equal: ['name', 'Jane Doe'] },
|
|
288
293
|
);
|
|
289
294
|
expect(resultSelectorsCount).toBeGreaterThanOrEqual(1);
|
|
290
295
|
expect(resultSelectorsCount).toEqual(resultSelectors.length);
|
|
@@ -307,7 +312,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
307
312
|
// Testing empty count...
|
|
308
313
|
const resultSelectorsEmpty = await nymph.getEntities(
|
|
309
314
|
{ class: Employee, return: 'count' },
|
|
310
|
-
{ type: '&', tag: 'pickle' }
|
|
315
|
+
{ type: '&', tag: 'pickle' },
|
|
311
316
|
);
|
|
312
317
|
expect(resultSelectorsEmpty).toEqual(0);
|
|
313
318
|
});
|
|
@@ -326,7 +331,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
326
331
|
{
|
|
327
332
|
type: '&',
|
|
328
333
|
tag: 'employee',
|
|
329
|
-
}
|
|
334
|
+
},
|
|
330
335
|
);
|
|
331
336
|
|
|
332
337
|
expect(entities.length).toEqual(4);
|
|
@@ -352,7 +357,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
352
357
|
{
|
|
353
358
|
type: '&',
|
|
354
359
|
like: ['name', '%Jane%'],
|
|
355
|
-
}
|
|
360
|
+
},
|
|
356
361
|
);
|
|
357
362
|
|
|
358
363
|
expect(entities.length).toEqual(4);
|
|
@@ -378,7 +383,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
378
383
|
type: '|',
|
|
379
384
|
like: ['name', '%Jane%'],
|
|
380
385
|
},
|
|
381
|
-
}
|
|
386
|
+
},
|
|
382
387
|
);
|
|
383
388
|
|
|
384
389
|
expect(entities.length).toEqual(4);
|
|
@@ -413,7 +418,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
413
418
|
},
|
|
414
419
|
],
|
|
415
420
|
},
|
|
416
|
-
}
|
|
421
|
+
},
|
|
417
422
|
);
|
|
418
423
|
|
|
419
424
|
expect(entities.length).toEqual(4);
|
|
@@ -438,7 +443,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
438
443
|
{
|
|
439
444
|
type: '&',
|
|
440
445
|
guid,
|
|
441
|
-
}
|
|
446
|
+
},
|
|
442
447
|
);
|
|
443
448
|
|
|
444
449
|
expect(check.length).toEqual(0);
|
|
@@ -461,7 +466,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
461
466
|
{
|
|
462
467
|
type: '|',
|
|
463
468
|
guid: guids,
|
|
464
|
-
}
|
|
469
|
+
},
|
|
465
470
|
);
|
|
466
471
|
|
|
467
472
|
expect(check.length).toEqual(0);
|
|
@@ -478,7 +483,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
478
483
|
error = e;
|
|
479
484
|
}
|
|
480
485
|
expect(error.message).toEqual(
|
|
481
|
-
"Can't use Entity class directly from the front end."
|
|
486
|
+
"Can't use Entity class directly from the front end.",
|
|
482
487
|
);
|
|
483
488
|
});
|
|
484
489
|
|
|
@@ -493,32 +498,103 @@ describe('Nymph REST Server and Client', () => {
|
|
|
493
498
|
});
|
|
494
499
|
|
|
495
500
|
it('handle server side static error', async () => {
|
|
496
|
-
let error = { error: { name: '' } };
|
|
501
|
+
let error = { status: 0, error: { name: '' } };
|
|
497
502
|
try {
|
|
498
503
|
await Employee.throwErrorStatic();
|
|
499
504
|
} catch (e: any) {
|
|
500
505
|
error = e;
|
|
501
506
|
}
|
|
507
|
+
expect(error.status).toEqual(500);
|
|
508
|
+
expect(error.error.name).toEqual('BadFunctionCallError');
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
it('handle server side static iterator error', async () => {
|
|
512
|
+
let error: any = { status: 0, error: { name: '' } };
|
|
513
|
+
const data = await Employee.throwErrorStaticIterable();
|
|
514
|
+
|
|
515
|
+
let count = 0;
|
|
516
|
+
for await (let value of data) {
|
|
517
|
+
count++;
|
|
518
|
+
if (value instanceof Error) {
|
|
519
|
+
error = value;
|
|
520
|
+
} else {
|
|
521
|
+
expect(value).toEqual(count);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
expect(count).toEqual(2);
|
|
526
|
+
expect(error.status).toEqual(500);
|
|
502
527
|
expect(error.error.name).toEqual('BadFunctionCallError');
|
|
503
528
|
});
|
|
504
529
|
|
|
505
530
|
it('handle server side error', async () => {
|
|
506
531
|
const jane = await createJane();
|
|
507
532
|
|
|
508
|
-
let error = { error: { name: '' } };
|
|
533
|
+
let error = { status: 0, error: { name: '' } };
|
|
509
534
|
try {
|
|
510
535
|
await jane.$throwError();
|
|
511
536
|
} catch (e: any) {
|
|
512
537
|
error = e;
|
|
513
538
|
}
|
|
539
|
+
expect(error.status).toEqual(500);
|
|
514
540
|
expect(error.error.name).toEqual('BadFunctionCallError');
|
|
515
541
|
});
|
|
516
542
|
|
|
543
|
+
it('handle server side HTTP error', async () => {
|
|
544
|
+
const jane = await createJane();
|
|
545
|
+
|
|
546
|
+
let error = { status: 0, statusText: '', message: '' };
|
|
547
|
+
try {
|
|
548
|
+
await jane.$throwHttpError();
|
|
549
|
+
} catch (e: any) {
|
|
550
|
+
error = e;
|
|
551
|
+
}
|
|
552
|
+
expect(error.status).toEqual(501);
|
|
553
|
+
expect(error.statusText).toEqual('Not Implemented');
|
|
554
|
+
expect(error.message).toEqual('A 501 HTTP error.');
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
it('handle server side custom HTTP error', async () => {
|
|
558
|
+
const jane = await createJane();
|
|
559
|
+
|
|
560
|
+
let error = { status: 0, statusText: '', message: '' };
|
|
561
|
+
try {
|
|
562
|
+
await jane.$throwHttpErrorWithDescription();
|
|
563
|
+
} catch (e: any) {
|
|
564
|
+
error = e;
|
|
565
|
+
}
|
|
566
|
+
expect(error.status).toEqual(512);
|
|
567
|
+
expect(error.statusText).toEqual('Some Error');
|
|
568
|
+
expect(error.message).toEqual('A 512 HTTP error.');
|
|
569
|
+
});
|
|
570
|
+
|
|
517
571
|
it('call a server side static method', async () => {
|
|
518
572
|
const data = await Employee.testStatic(5);
|
|
519
573
|
expect(data).toEqual(10);
|
|
520
574
|
});
|
|
521
575
|
|
|
576
|
+
it('call a server side static iterator method', async () => {
|
|
577
|
+
const data = await Employee.testStaticIterable(5);
|
|
578
|
+
|
|
579
|
+
let count = 0;
|
|
580
|
+
for await (let value of data) {
|
|
581
|
+
count++;
|
|
582
|
+
expect(value).toEqual(5 + count);
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
expect(count).toEqual(3);
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
it('aborts a server side static iterator method', async () => {
|
|
589
|
+
const data = await Employee.testStaticIterableAbort();
|
|
590
|
+
data.abortController.abort();
|
|
591
|
+
|
|
592
|
+
// Wait 1 second to ensure server receives abort signal.
|
|
593
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
594
|
+
|
|
595
|
+
expect(true).toBeTruthy();
|
|
596
|
+
});
|
|
597
|
+
|
|
522
598
|
it('call a stateless server side method', async () => {
|
|
523
599
|
const jane = await createJane();
|
|
524
600
|
|
|
@@ -547,7 +623,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
547
623
|
{
|
|
548
624
|
class: Employee,
|
|
549
625
|
},
|
|
550
|
-
jane1.guid
|
|
626
|
+
jane1.guid,
|
|
551
627
|
);
|
|
552
628
|
if (jane1 == null || jane2 == null) {
|
|
553
629
|
throw new Error('Entity is null.');
|
|
@@ -573,7 +649,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
573
649
|
{
|
|
574
650
|
class: Employee,
|
|
575
651
|
},
|
|
576
|
-
first.guid
|
|
652
|
+
first.guid,
|
|
577
653
|
);
|
|
578
654
|
|
|
579
655
|
if (second == null || second.guid == null) {
|
|
@@ -605,7 +681,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
605
681
|
{
|
|
606
682
|
class: Employee,
|
|
607
683
|
},
|
|
608
|
-
first.guid
|
|
684
|
+
first.guid,
|
|
609
685
|
);
|
|
610
686
|
|
|
611
687
|
if (second == null || second.guid == null) {
|
|
@@ -628,7 +704,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
628
704
|
{
|
|
629
705
|
type: '&',
|
|
630
706
|
'!guid': first.guid,
|
|
631
|
-
}
|
|
707
|
+
},
|
|
632
708
|
);
|
|
633
709
|
|
|
634
710
|
if (third == null || third.guid == null) {
|
|
@@ -638,6 +714,66 @@ describe('Nymph REST Server and Client', () => {
|
|
|
638
714
|
expect(first.$is(third)).toEqual(false);
|
|
639
715
|
});
|
|
640
716
|
|
|
717
|
+
it("doesn't allow creation of a restricted entity class", async () => {
|
|
718
|
+
const attempt = await Restricted.factory();
|
|
719
|
+
attempt.name = 'Jane Doe';
|
|
720
|
+
|
|
721
|
+
let error = null;
|
|
722
|
+
|
|
723
|
+
try {
|
|
724
|
+
await attempt.$save();
|
|
725
|
+
} catch (e: any) {
|
|
726
|
+
error = e;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
expect(error).toBeInstanceOf(HttpError);
|
|
730
|
+
expect(error.status).toEqual(403);
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
it("doesn't allow search of a restricted entity class", async () => {
|
|
734
|
+
let error = null;
|
|
735
|
+
|
|
736
|
+
try {
|
|
737
|
+
await nymph.getEntity({
|
|
738
|
+
class: Restricted,
|
|
739
|
+
});
|
|
740
|
+
} catch (e: any) {
|
|
741
|
+
error = e;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
expect(error).toBeInstanceOf(HttpError);
|
|
745
|
+
expect(error.status).toEqual(403);
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
it("doesn't allow methods of a restricted entity class", async () => {
|
|
749
|
+
const attempt = await Restricted.factory();
|
|
750
|
+
attempt.name = 'Jane Doe';
|
|
751
|
+
|
|
752
|
+
let error = null;
|
|
753
|
+
|
|
754
|
+
try {
|
|
755
|
+
await attempt.$testMethod(1);
|
|
756
|
+
} catch (e: any) {
|
|
757
|
+
error = e;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
expect(error).toBeInstanceOf(HttpError);
|
|
761
|
+
expect(error.status).toEqual(403);
|
|
762
|
+
});
|
|
763
|
+
|
|
764
|
+
it("doesn't allow static methods of a restricted entity class", async () => {
|
|
765
|
+
let error = null;
|
|
766
|
+
|
|
767
|
+
try {
|
|
768
|
+
await Restricted.testStatic(1);
|
|
769
|
+
} catch (e: any) {
|
|
770
|
+
error = e;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
expect(error).toBeInstanceOf(HttpError);
|
|
774
|
+
expect(error.status).toEqual(403);
|
|
775
|
+
});
|
|
776
|
+
|
|
641
777
|
it('get a new UID', async () => {
|
|
642
778
|
const uidValue = await nymph.newUID('employee');
|
|
643
779
|
expect(typeof uidValue).toEqual('number');
|