@nymphjs/server 1.0.0-beta.9 → 1.0.0-beta.91
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 +357 -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 +902 -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 +137 -25
- 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 +976 -0
- package/src/index.test.ts +163 -28
- 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,6 +18,7 @@ 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));
|
|
@@ -25,6 +28,7 @@ const nymph = new Nymph({
|
|
|
25
28
|
restUrl: 'http://localhost:5080/test/',
|
|
26
29
|
});
|
|
27
30
|
const Employee = nymph.addEntityClass(EmployeeClass);
|
|
31
|
+
const Restricted = nymph.addEntityClass(RestrictedClass);
|
|
28
32
|
|
|
29
33
|
describe('Nymph REST Server and Client', () => {
|
|
30
34
|
async function createJane() {
|
|
@@ -129,7 +133,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
129
133
|
{
|
|
130
134
|
type: '&',
|
|
131
135
|
ref: ['subordinates', jane],
|
|
132
|
-
}
|
|
136
|
+
},
|
|
133
137
|
);
|
|
134
138
|
|
|
135
139
|
expect(checkSteve?.guid).toEqual(steve.guid);
|
|
@@ -142,7 +146,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
142
146
|
'subordinates',
|
|
143
147
|
[{ class: Employee }, { type: '&', guid: jane.guid }],
|
|
144
148
|
],
|
|
145
|
-
}
|
|
149
|
+
},
|
|
146
150
|
);
|
|
147
151
|
|
|
148
152
|
expect(checkSteveQref?.guid).toEqual(steve.guid);
|
|
@@ -156,7 +160,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
156
160
|
expect(entity.$hasTag('test', 'test2')).toEqual(true);
|
|
157
161
|
entity.$addTag('test', 'test3', 'test4', 'test5', 'test6');
|
|
158
162
|
expect(entity.$hasTag('test', 'test3', 'test4', 'test5', 'test6')).toEqual(
|
|
159
|
-
true
|
|
163
|
+
true,
|
|
160
164
|
);
|
|
161
165
|
entity.$removeTag('test2');
|
|
162
166
|
expect(!entity.$hasTag('test2')).toEqual(true);
|
|
@@ -178,10 +182,10 @@ describe('Nymph REST Server and Client', () => {
|
|
|
178
182
|
'nymph_entity_reference',
|
|
179
183
|
jane.guid,
|
|
180
184
|
'Employee',
|
|
181
|
-
]);
|
|
182
|
-
await entity.$
|
|
185
|
+
]) as EmployeeClass & EmployeeData;
|
|
186
|
+
await entity.$wake();
|
|
183
187
|
|
|
184
|
-
expect(
|
|
188
|
+
expect(entity?.name).toEqual('Jane Doe');
|
|
185
189
|
});
|
|
186
190
|
|
|
187
191
|
it('change an entity', async () => {
|
|
@@ -232,7 +236,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
232
236
|
{
|
|
233
237
|
type: '&',
|
|
234
238
|
equal: ['name', 'Jane Doe'],
|
|
235
|
-
}
|
|
239
|
+
},
|
|
236
240
|
);
|
|
237
241
|
|
|
238
242
|
expect(jane).not.toBeNull();
|
|
@@ -252,7 +256,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
252
256
|
{
|
|
253
257
|
type: '&',
|
|
254
258
|
tag: ['employee'],
|
|
255
|
-
}
|
|
259
|
+
},
|
|
256
260
|
);
|
|
257
261
|
|
|
258
262
|
expect(entities.length).toEqual(4);
|
|
@@ -278,13 +282,13 @@ describe('Nymph REST Server and Client', () => {
|
|
|
278
282
|
|
|
279
283
|
const resultSelectors = await nymph.getEntities(
|
|
280
284
|
{ class: Employee },
|
|
281
|
-
{ type: '&', equal: ['name', 'Jane Doe'] }
|
|
285
|
+
{ type: '&', equal: ['name', 'Jane Doe'] },
|
|
282
286
|
);
|
|
283
287
|
|
|
284
288
|
// Testing count return with selectors...
|
|
285
289
|
const resultSelectorsCount = await nymph.getEntities(
|
|
286
290
|
{ class: Employee, return: 'count' },
|
|
287
|
-
{ type: '&', equal: ['name', 'Jane Doe'] }
|
|
291
|
+
{ type: '&', equal: ['name', 'Jane Doe'] },
|
|
288
292
|
);
|
|
289
293
|
expect(resultSelectorsCount).toBeGreaterThanOrEqual(1);
|
|
290
294
|
expect(resultSelectorsCount).toEqual(resultSelectors.length);
|
|
@@ -307,7 +311,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
307
311
|
// Testing empty count...
|
|
308
312
|
const resultSelectorsEmpty = await nymph.getEntities(
|
|
309
313
|
{ class: Employee, return: 'count' },
|
|
310
|
-
{ type: '&', tag: 'pickle' }
|
|
314
|
+
{ type: '&', tag: 'pickle' },
|
|
311
315
|
);
|
|
312
316
|
expect(resultSelectorsEmpty).toEqual(0);
|
|
313
317
|
});
|
|
@@ -326,7 +330,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
326
330
|
{
|
|
327
331
|
type: '&',
|
|
328
332
|
tag: 'employee',
|
|
329
|
-
}
|
|
333
|
+
},
|
|
330
334
|
);
|
|
331
335
|
|
|
332
336
|
expect(entities.length).toEqual(4);
|
|
@@ -352,7 +356,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
352
356
|
{
|
|
353
357
|
type: '&',
|
|
354
358
|
like: ['name', '%Jane%'],
|
|
355
|
-
}
|
|
359
|
+
},
|
|
356
360
|
);
|
|
357
361
|
|
|
358
362
|
expect(entities.length).toEqual(4);
|
|
@@ -378,7 +382,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
378
382
|
type: '|',
|
|
379
383
|
like: ['name', '%Jane%'],
|
|
380
384
|
},
|
|
381
|
-
}
|
|
385
|
+
},
|
|
382
386
|
);
|
|
383
387
|
|
|
384
388
|
expect(entities.length).toEqual(4);
|
|
@@ -413,7 +417,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
413
417
|
},
|
|
414
418
|
],
|
|
415
419
|
},
|
|
416
|
-
}
|
|
420
|
+
},
|
|
417
421
|
);
|
|
418
422
|
|
|
419
423
|
expect(entities.length).toEqual(4);
|
|
@@ -438,7 +442,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
438
442
|
{
|
|
439
443
|
type: '&',
|
|
440
444
|
guid,
|
|
441
|
-
}
|
|
445
|
+
},
|
|
442
446
|
);
|
|
443
447
|
|
|
444
448
|
expect(check.length).toEqual(0);
|
|
@@ -461,7 +465,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
461
465
|
{
|
|
462
466
|
type: '|',
|
|
463
467
|
guid: guids,
|
|
464
|
-
}
|
|
468
|
+
},
|
|
465
469
|
);
|
|
466
470
|
|
|
467
471
|
expect(check.length).toEqual(0);
|
|
@@ -478,7 +482,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
478
482
|
error = e;
|
|
479
483
|
}
|
|
480
484
|
expect(error.message).toEqual(
|
|
481
|
-
"Can't use Entity class directly from the front end."
|
|
485
|
+
"Can't use Entity class directly from the front end.",
|
|
482
486
|
);
|
|
483
487
|
});
|
|
484
488
|
|
|
@@ -493,32 +497,103 @@ describe('Nymph REST Server and Client', () => {
|
|
|
493
497
|
});
|
|
494
498
|
|
|
495
499
|
it('handle server side static error', async () => {
|
|
496
|
-
let error = { error: { name: '' } };
|
|
500
|
+
let error = { status: 0, error: { name: '' } };
|
|
497
501
|
try {
|
|
498
502
|
await Employee.throwErrorStatic();
|
|
499
503
|
} catch (e: any) {
|
|
500
504
|
error = e;
|
|
501
505
|
}
|
|
506
|
+
expect(error.status).toEqual(500);
|
|
507
|
+
expect(error.error.name).toEqual('BadFunctionCallError');
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
it('handle server side static iterator error', async () => {
|
|
511
|
+
let error: any = { status: 0, error: { name: '' } };
|
|
512
|
+
const data = await Employee.throwErrorStaticIterable();
|
|
513
|
+
|
|
514
|
+
let count = 0;
|
|
515
|
+
for await (let value of data) {
|
|
516
|
+
count++;
|
|
517
|
+
if (value instanceof Error) {
|
|
518
|
+
error = value;
|
|
519
|
+
} else {
|
|
520
|
+
expect(value).toEqual(count);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
expect(count).toEqual(2);
|
|
525
|
+
expect(error.status).toEqual(500);
|
|
502
526
|
expect(error.error.name).toEqual('BadFunctionCallError');
|
|
503
527
|
});
|
|
504
528
|
|
|
505
529
|
it('handle server side error', async () => {
|
|
506
530
|
const jane = await createJane();
|
|
507
531
|
|
|
508
|
-
let error = { error: { name: '' } };
|
|
532
|
+
let error = { status: 0, error: { name: '' } };
|
|
509
533
|
try {
|
|
510
534
|
await jane.$throwError();
|
|
511
535
|
} catch (e: any) {
|
|
512
536
|
error = e;
|
|
513
537
|
}
|
|
538
|
+
expect(error.status).toEqual(500);
|
|
514
539
|
expect(error.error.name).toEqual('BadFunctionCallError');
|
|
515
540
|
});
|
|
516
541
|
|
|
542
|
+
it('handle server side HTTP error', async () => {
|
|
543
|
+
const jane = await createJane();
|
|
544
|
+
|
|
545
|
+
let error = { status: 0, statusText: '', message: '' };
|
|
546
|
+
try {
|
|
547
|
+
await jane.$throwHttpError();
|
|
548
|
+
} catch (e: any) {
|
|
549
|
+
error = e;
|
|
550
|
+
}
|
|
551
|
+
expect(error.status).toEqual(501);
|
|
552
|
+
expect(error.statusText).toEqual('Not Implemented');
|
|
553
|
+
expect(error.message).toEqual('A 501 HTTP error.');
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
it('handle server side custom HTTP error', async () => {
|
|
557
|
+
const jane = await createJane();
|
|
558
|
+
|
|
559
|
+
let error = { status: 0, statusText: '', message: '' };
|
|
560
|
+
try {
|
|
561
|
+
await jane.$throwHttpErrorWithDescription();
|
|
562
|
+
} catch (e: any) {
|
|
563
|
+
error = e;
|
|
564
|
+
}
|
|
565
|
+
expect(error.status).toEqual(512);
|
|
566
|
+
expect(error.statusText).toEqual('Some Error');
|
|
567
|
+
expect(error.message).toEqual('A 512 HTTP error.');
|
|
568
|
+
});
|
|
569
|
+
|
|
517
570
|
it('call a server side static method', async () => {
|
|
518
571
|
const data = await Employee.testStatic(5);
|
|
519
572
|
expect(data).toEqual(10);
|
|
520
573
|
});
|
|
521
574
|
|
|
575
|
+
it('call a server side static iterator method', async () => {
|
|
576
|
+
const data = await Employee.testStaticIterable(5);
|
|
577
|
+
|
|
578
|
+
let count = 0;
|
|
579
|
+
for await (let value of data) {
|
|
580
|
+
count++;
|
|
581
|
+
expect(value).toEqual(5 + count);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
expect(count).toEqual(3);
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
it('aborts a server side static iterator method', async () => {
|
|
588
|
+
const data = await Employee.testStaticIterableAbort();
|
|
589
|
+
data.abortController.abort();
|
|
590
|
+
|
|
591
|
+
// Wait 1 second to ensure server receives abort signal.
|
|
592
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
593
|
+
|
|
594
|
+
expect(true).toBeTruthy();
|
|
595
|
+
});
|
|
596
|
+
|
|
522
597
|
it('call a stateless server side method', async () => {
|
|
523
598
|
const jane = await createJane();
|
|
524
599
|
|
|
@@ -547,7 +622,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
547
622
|
{
|
|
548
623
|
class: Employee,
|
|
549
624
|
},
|
|
550
|
-
jane1.guid
|
|
625
|
+
jane1.guid,
|
|
551
626
|
);
|
|
552
627
|
if (jane1 == null || jane2 == null) {
|
|
553
628
|
throw new Error('Entity is null.');
|
|
@@ -573,7 +648,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
573
648
|
{
|
|
574
649
|
class: Employee,
|
|
575
650
|
},
|
|
576
|
-
first.guid
|
|
651
|
+
first.guid,
|
|
577
652
|
);
|
|
578
653
|
|
|
579
654
|
if (second == null || second.guid == null) {
|
|
@@ -605,7 +680,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
605
680
|
{
|
|
606
681
|
class: Employee,
|
|
607
682
|
},
|
|
608
|
-
first.guid
|
|
683
|
+
first.guid,
|
|
609
684
|
);
|
|
610
685
|
|
|
611
686
|
if (second == null || second.guid == null) {
|
|
@@ -628,7 +703,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
628
703
|
{
|
|
629
704
|
type: '&',
|
|
630
705
|
'!guid': first.guid,
|
|
631
|
-
}
|
|
706
|
+
},
|
|
632
707
|
);
|
|
633
708
|
|
|
634
709
|
if (third == null || third.guid == null) {
|
|
@@ -638,6 +713,66 @@ describe('Nymph REST Server and Client', () => {
|
|
|
638
713
|
expect(first.$is(third)).toEqual(false);
|
|
639
714
|
});
|
|
640
715
|
|
|
716
|
+
it("doesn't allow creation of a restricted entity class", async () => {
|
|
717
|
+
const attempt = await Restricted.factory();
|
|
718
|
+
attempt.name = 'Jane Doe';
|
|
719
|
+
|
|
720
|
+
let error = null;
|
|
721
|
+
|
|
722
|
+
try {
|
|
723
|
+
await attempt.$save();
|
|
724
|
+
} catch (e: any) {
|
|
725
|
+
error = e;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
expect(error).toBeInstanceOf(HttpError);
|
|
729
|
+
expect(error.status).toEqual(403);
|
|
730
|
+
});
|
|
731
|
+
|
|
732
|
+
it("doesn't allow search of a restricted entity class", async () => {
|
|
733
|
+
let error = null;
|
|
734
|
+
|
|
735
|
+
try {
|
|
736
|
+
await nymph.getEntity({
|
|
737
|
+
class: Restricted,
|
|
738
|
+
});
|
|
739
|
+
} catch (e: any) {
|
|
740
|
+
error = e;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
expect(error).toBeInstanceOf(HttpError);
|
|
744
|
+
expect(error.status).toEqual(403);
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
it("doesn't allow methods of a restricted entity class", async () => {
|
|
748
|
+
const attempt = await Restricted.factory();
|
|
749
|
+
attempt.name = 'Jane Doe';
|
|
750
|
+
|
|
751
|
+
let error = null;
|
|
752
|
+
|
|
753
|
+
try {
|
|
754
|
+
await attempt.$testMethod(1);
|
|
755
|
+
} catch (e: any) {
|
|
756
|
+
error = e;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
expect(error).toBeInstanceOf(HttpError);
|
|
760
|
+
expect(error.status).toEqual(403);
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
it("doesn't allow static methods of a restricted entity class", async () => {
|
|
764
|
+
let error = null;
|
|
765
|
+
|
|
766
|
+
try {
|
|
767
|
+
await Restricted.testStatic(1);
|
|
768
|
+
} catch (e: any) {
|
|
769
|
+
error = e;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
expect(error).toBeInstanceOf(HttpError);
|
|
773
|
+
expect(error.status).toEqual(403);
|
|
774
|
+
});
|
|
775
|
+
|
|
641
776
|
it('get a new UID', async () => {
|
|
642
777
|
const uidValue = await nymph.newUID('employee');
|
|
643
778
|
expect(typeof uidValue).toEqual('number');
|