@nymphjs/server 1.0.0-beta.5 → 1.0.0-beta.50
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 +195 -0
- package/README.md +78 -6
- package/dist/HttpError.d.ts +5 -0
- package/dist/HttpError.js +13 -0
- package/dist/HttpError.js.map +1 -0
- package/dist/cache.test.js +5 -5
- package/dist/cache.test.js.map +1 -1
- package/dist/createServer.d.ts +8 -0
- package/dist/createServer.js +869 -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 +153 -41
- package/dist/index.test.js.map +1 -1
- package/dist/statusDescriptions.d.ts +3 -0
- package/dist/statusDescriptions.js +69 -0
- package/dist/statusDescriptions.js.map +1 -0
- package/dist/testArtifacts.d.ts +60 -5
- package/dist/testArtifacts.js +161 -29
- package/dist/testArtifacts.js.map +1 -1
- package/package.json +16 -16
- package/src/HttpError.ts +12 -0
- package/src/cache.test.ts +8 -5
- package/src/createServer.ts +971 -0
- package/src/index.test.ts +167 -28
- package/src/index.ts +5 -793
- package/src/statusDescriptions.ts +68 -0
- package/src/testArtifacts.ts +233 -29
- package/typedoc.json +4 -0
package/src/index.test.ts
CHANGED
|
@@ -2,17 +2,24 @@ 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
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
EmployeeModel as EmployeeModelClass,
|
|
10
|
+
Employee as EmployeeClass,
|
|
11
|
+
RestrictedModel as RestrictedModelClass,
|
|
12
|
+
Restricted as RestrictedClass,
|
|
13
|
+
EmployeeData,
|
|
14
|
+
} from './testArtifacts';
|
|
9
15
|
|
|
10
16
|
const sqliteConfig = {
|
|
11
17
|
filename: ':memory:',
|
|
12
18
|
};
|
|
13
19
|
|
|
14
20
|
const nymphServer = new NymphServer({}, new SQLite3Driver(sqliteConfig));
|
|
15
|
-
nymphServer.addEntityClass(
|
|
21
|
+
const EmployeeModel = nymphServer.addEntityClass(EmployeeModelClass);
|
|
22
|
+
const RestrictedModel = nymphServer.addEntityClass(RestrictedModelClass);
|
|
16
23
|
|
|
17
24
|
const app = express();
|
|
18
25
|
app.use('/test', createServer(nymphServer));
|
|
@@ -21,7 +28,8 @@ const server = app.listen(5080);
|
|
|
21
28
|
const nymph = new Nymph({
|
|
22
29
|
restUrl: 'http://localhost:5080/test/',
|
|
23
30
|
});
|
|
24
|
-
nymph.addEntityClass(
|
|
31
|
+
const Employee = nymph.addEntityClass(EmployeeClass);
|
|
32
|
+
const Restricted = nymph.addEntityClass(RestrictedClass);
|
|
25
33
|
|
|
26
34
|
describe('Nymph REST Server and Client', () => {
|
|
27
35
|
async function createJane() {
|
|
@@ -126,7 +134,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
126
134
|
{
|
|
127
135
|
type: '&',
|
|
128
136
|
ref: ['subordinates', jane],
|
|
129
|
-
}
|
|
137
|
+
},
|
|
130
138
|
);
|
|
131
139
|
|
|
132
140
|
expect(checkSteve?.guid).toEqual(steve.guid);
|
|
@@ -139,7 +147,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
139
147
|
'subordinates',
|
|
140
148
|
[{ class: Employee }, { type: '&', guid: jane.guid }],
|
|
141
149
|
],
|
|
142
|
-
}
|
|
150
|
+
},
|
|
143
151
|
);
|
|
144
152
|
|
|
145
153
|
expect(checkSteveQref?.guid).toEqual(steve.guid);
|
|
@@ -153,7 +161,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
153
161
|
expect(entity.$hasTag('test', 'test2')).toEqual(true);
|
|
154
162
|
entity.$addTag('test', 'test3', 'test4', 'test5', 'test6');
|
|
155
163
|
expect(entity.$hasTag('test', 'test3', 'test4', 'test5', 'test6')).toEqual(
|
|
156
|
-
true
|
|
164
|
+
true,
|
|
157
165
|
);
|
|
158
166
|
entity.$removeTag('test2');
|
|
159
167
|
expect(!entity.$hasTag('test2')).toEqual(true);
|
|
@@ -175,10 +183,10 @@ describe('Nymph REST Server and Client', () => {
|
|
|
175
183
|
'nymph_entity_reference',
|
|
176
184
|
jane.guid,
|
|
177
185
|
'Employee',
|
|
178
|
-
]);
|
|
179
|
-
await entity.$
|
|
186
|
+
]) as EmployeeClass & EmployeeData;
|
|
187
|
+
await entity.$wake();
|
|
180
188
|
|
|
181
|
-
expect(
|
|
189
|
+
expect(entity?.name).toEqual('Jane Doe');
|
|
182
190
|
});
|
|
183
191
|
|
|
184
192
|
it('change an entity', async () => {
|
|
@@ -229,7 +237,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
229
237
|
{
|
|
230
238
|
type: '&',
|
|
231
239
|
equal: ['name', 'Jane Doe'],
|
|
232
|
-
}
|
|
240
|
+
},
|
|
233
241
|
);
|
|
234
242
|
|
|
235
243
|
expect(jane).not.toBeNull();
|
|
@@ -249,7 +257,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
249
257
|
{
|
|
250
258
|
type: '&',
|
|
251
259
|
tag: ['employee'],
|
|
252
|
-
}
|
|
260
|
+
},
|
|
253
261
|
);
|
|
254
262
|
|
|
255
263
|
expect(entities.length).toEqual(4);
|
|
@@ -275,13 +283,13 @@ describe('Nymph REST Server and Client', () => {
|
|
|
275
283
|
|
|
276
284
|
const resultSelectors = await nymph.getEntities(
|
|
277
285
|
{ class: Employee },
|
|
278
|
-
{ type: '&', equal: ['name', 'Jane Doe'] }
|
|
286
|
+
{ type: '&', equal: ['name', 'Jane Doe'] },
|
|
279
287
|
);
|
|
280
288
|
|
|
281
289
|
// Testing count return with selectors...
|
|
282
290
|
const resultSelectorsCount = await nymph.getEntities(
|
|
283
291
|
{ class: Employee, return: 'count' },
|
|
284
|
-
{ type: '&', equal: ['name', 'Jane Doe'] }
|
|
292
|
+
{ type: '&', equal: ['name', 'Jane Doe'] },
|
|
285
293
|
);
|
|
286
294
|
expect(resultSelectorsCount).toBeGreaterThanOrEqual(1);
|
|
287
295
|
expect(resultSelectorsCount).toEqual(resultSelectors.length);
|
|
@@ -304,7 +312,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
304
312
|
// Testing empty count...
|
|
305
313
|
const resultSelectorsEmpty = await nymph.getEntities(
|
|
306
314
|
{ class: Employee, return: 'count' },
|
|
307
|
-
{ type: '&', tag: 'pickle' }
|
|
315
|
+
{ type: '&', tag: 'pickle' },
|
|
308
316
|
);
|
|
309
317
|
expect(resultSelectorsEmpty).toEqual(0);
|
|
310
318
|
});
|
|
@@ -323,7 +331,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
323
331
|
{
|
|
324
332
|
type: '&',
|
|
325
333
|
tag: 'employee',
|
|
326
|
-
}
|
|
334
|
+
},
|
|
327
335
|
);
|
|
328
336
|
|
|
329
337
|
expect(entities.length).toEqual(4);
|
|
@@ -349,7 +357,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
349
357
|
{
|
|
350
358
|
type: '&',
|
|
351
359
|
like: ['name', '%Jane%'],
|
|
352
|
-
}
|
|
360
|
+
},
|
|
353
361
|
);
|
|
354
362
|
|
|
355
363
|
expect(entities.length).toEqual(4);
|
|
@@ -375,7 +383,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
375
383
|
type: '|',
|
|
376
384
|
like: ['name', '%Jane%'],
|
|
377
385
|
},
|
|
378
|
-
}
|
|
386
|
+
},
|
|
379
387
|
);
|
|
380
388
|
|
|
381
389
|
expect(entities.length).toEqual(4);
|
|
@@ -410,7 +418,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
410
418
|
},
|
|
411
419
|
],
|
|
412
420
|
},
|
|
413
|
-
}
|
|
421
|
+
},
|
|
414
422
|
);
|
|
415
423
|
|
|
416
424
|
expect(entities.length).toEqual(4);
|
|
@@ -435,7 +443,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
435
443
|
{
|
|
436
444
|
type: '&',
|
|
437
445
|
guid,
|
|
438
|
-
}
|
|
446
|
+
},
|
|
439
447
|
);
|
|
440
448
|
|
|
441
449
|
expect(check.length).toEqual(0);
|
|
@@ -458,7 +466,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
458
466
|
{
|
|
459
467
|
type: '|',
|
|
460
468
|
guid: guids,
|
|
461
|
-
}
|
|
469
|
+
},
|
|
462
470
|
);
|
|
463
471
|
|
|
464
472
|
expect(check.length).toEqual(0);
|
|
@@ -475,7 +483,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
475
483
|
error = e;
|
|
476
484
|
}
|
|
477
485
|
expect(error.message).toEqual(
|
|
478
|
-
"Can't use Entity class directly from the front end."
|
|
486
|
+
"Can't use Entity class directly from the front end.",
|
|
479
487
|
);
|
|
480
488
|
});
|
|
481
489
|
|
|
@@ -490,32 +498,103 @@ describe('Nymph REST Server and Client', () => {
|
|
|
490
498
|
});
|
|
491
499
|
|
|
492
500
|
it('handle server side static error', async () => {
|
|
493
|
-
let error = { error: { name: '' } };
|
|
501
|
+
let error = { status: 0, error: { name: '' } };
|
|
494
502
|
try {
|
|
495
503
|
await Employee.throwErrorStatic();
|
|
496
504
|
} catch (e: any) {
|
|
497
505
|
error = e;
|
|
498
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);
|
|
499
527
|
expect(error.error.name).toEqual('BadFunctionCallError');
|
|
500
528
|
});
|
|
501
529
|
|
|
502
530
|
it('handle server side error', async () => {
|
|
503
531
|
const jane = await createJane();
|
|
504
532
|
|
|
505
|
-
let error = { error: { name: '' } };
|
|
533
|
+
let error = { status: 0, error: { name: '' } };
|
|
506
534
|
try {
|
|
507
535
|
await jane.$throwError();
|
|
508
536
|
} catch (e: any) {
|
|
509
537
|
error = e;
|
|
510
538
|
}
|
|
539
|
+
expect(error.status).toEqual(500);
|
|
511
540
|
expect(error.error.name).toEqual('BadFunctionCallError');
|
|
512
541
|
});
|
|
513
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
|
+
|
|
514
571
|
it('call a server side static method', async () => {
|
|
515
572
|
const data = await Employee.testStatic(5);
|
|
516
573
|
expect(data).toEqual(10);
|
|
517
574
|
});
|
|
518
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
|
+
|
|
519
598
|
it('call a stateless server side method', async () => {
|
|
520
599
|
const jane = await createJane();
|
|
521
600
|
|
|
@@ -544,7 +623,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
544
623
|
{
|
|
545
624
|
class: Employee,
|
|
546
625
|
},
|
|
547
|
-
jane1.guid
|
|
626
|
+
jane1.guid,
|
|
548
627
|
);
|
|
549
628
|
if (jane1 == null || jane2 == null) {
|
|
550
629
|
throw new Error('Entity is null.');
|
|
@@ -570,7 +649,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
570
649
|
{
|
|
571
650
|
class: Employee,
|
|
572
651
|
},
|
|
573
|
-
first.guid
|
|
652
|
+
first.guid,
|
|
574
653
|
);
|
|
575
654
|
|
|
576
655
|
if (second == null || second.guid == null) {
|
|
@@ -602,7 +681,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
602
681
|
{
|
|
603
682
|
class: Employee,
|
|
604
683
|
},
|
|
605
|
-
first.guid
|
|
684
|
+
first.guid,
|
|
606
685
|
);
|
|
607
686
|
|
|
608
687
|
if (second == null || second.guid == null) {
|
|
@@ -625,7 +704,7 @@ describe('Nymph REST Server and Client', () => {
|
|
|
625
704
|
{
|
|
626
705
|
type: '&',
|
|
627
706
|
'!guid': first.guid,
|
|
628
|
-
}
|
|
707
|
+
},
|
|
629
708
|
);
|
|
630
709
|
|
|
631
710
|
if (third == null || third.guid == null) {
|
|
@@ -635,6 +714,66 @@ describe('Nymph REST Server and Client', () => {
|
|
|
635
714
|
expect(first.$is(third)).toEqual(false);
|
|
636
715
|
});
|
|
637
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
|
+
|
|
638
777
|
it('get a new UID', async () => {
|
|
639
778
|
const uidValue = await nymph.newUID('employee');
|
|
640
779
|
expect(typeof uidValue).toEqual('number');
|