@sasjs/cli 6.26.1 → 6.27.0
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.
|
@@ -698,63 +698,50 @@ const directorySource = {
|
|
|
698
698
|
}
|
|
699
699
|
|
|
700
700
|
/**
|
|
701
|
-
* The app
|
|
701
|
+
* The app stream, over the drive this site carries.
|
|
702
702
|
*
|
|
703
|
-
* The
|
|
704
|
-
*
|
|
705
|
-
*
|
|
706
|
-
*
|
|
707
|
-
*
|
|
703
|
+
* The package owns the index and every rule about it: what a publish must say,
|
|
704
|
+
* when an id is minted and when a redeploy keeps it, what the listing answers,
|
|
705
|
+
* how an app's files are found, what a removal removes. This host owns only the
|
|
706
|
+
* bytes - the drive store, which is persisted with the rest of the drive, so an
|
|
707
|
+
* app published in a mock survives a reload exactly as it would on a server.
|
|
708
708
|
*
|
|
709
|
-
*
|
|
710
|
-
*
|
|
711
|
-
*
|
|
712
|
-
*
|
|
709
|
+
* Nothing is published until a deploy publishes something, which is what makes
|
|
710
|
+
* the mock honest: a `sasjs deploy` against it, or a bundle posted to
|
|
711
|
+
* `/SASjsApi/drive/deploy`, is listed and served here the way it is on a server.
|
|
712
|
+
* The folder the site itself was built for is deliberately not seeded as an app:
|
|
713
|
+
* its files are this site's static build, not a deployment in the drive, so a
|
|
714
|
+
* tile for it would open a 404.
|
|
713
715
|
*/
|
|
714
|
-
const
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
const appStreamService = () => {
|
|
718
|
-
if (!appStreamPromise)
|
|
719
|
-
appStreamPromise = (async () => {
|
|
720
|
-
let appLoc
|
|
721
|
-
try {
|
|
722
|
-
const config = await (await fetch('host/mock-config.json')).json()
|
|
723
|
-
appLoc = config && config.appLoc
|
|
724
|
-
} catch (e) {
|
|
725
|
-
appLoc = undefined
|
|
726
|
-
}
|
|
716
|
+
const APP_STREAM = API.createAppStreamService(
|
|
717
|
+
API.createDriveAppStreamStore(API.createDriveService(DRIVE_STORE))
|
|
718
|
+
)
|
|
727
719
|
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
720
|
+
/**
|
|
721
|
+
* The app stream's own web surface: the landing page, the listing, an app's
|
|
722
|
+
* files and the removal of one.
|
|
723
|
+
*
|
|
724
|
+
* Mounted at the short spelling, which is what the interface links to; the
|
|
725
|
+
* canonical one is translated to it below, so both answer.
|
|
726
|
+
*
|
|
727
|
+
* `basePath` is the site's own folder plus that spelling, and the paths handed
|
|
728
|
+
* to the package include the folder too - the package builds an app's URL, its
|
|
729
|
+
* tiles and its logo links from `basePath`, so a surface mounted at `/app` on a
|
|
730
|
+
* site served from `/demo` would answer a listing whose every link pointed at
|
|
731
|
+
* the site root. Both sides take the same base and the answers land inside the
|
|
732
|
+
* folder.
|
|
733
|
+
*/
|
|
734
|
+
let appStreamWeb
|
|
735
|
+
const appStreamSurface = () => {
|
|
736
|
+
if (!appStreamWeb)
|
|
737
|
+
appStreamWeb = API.createAppStreamWebService(
|
|
738
|
+
APP_STREAM,
|
|
739
|
+
API.createDriveService(DRIVE_STORE),
|
|
740
|
+
{ basePath: `${BASE}${SHORT_APP_STREAM_PATH}` }
|
|
741
|
+
)
|
|
742
|
+
return appStreamWeb
|
|
745
743
|
}
|
|
746
744
|
|
|
747
|
-
/** The package's service, built once the config names the folder. */
|
|
748
|
-
const APP_STREAM = new Proxy(
|
|
749
|
-
{},
|
|
750
|
-
{
|
|
751
|
-
get:
|
|
752
|
-
(_target, method) =>
|
|
753
|
-
(...args) =>
|
|
754
|
-
appStreamService().then((service) => service[method](...args))
|
|
755
|
-
}
|
|
756
|
-
)
|
|
757
|
-
|
|
758
745
|
/**
|
|
759
746
|
* The page at `/`.
|
|
760
747
|
*
|
|
@@ -1247,18 +1234,10 @@ const routeRequest = async (request, url) => {
|
|
|
1247
1234
|
//
|
|
1248
1235
|
// `/app` is the spelling the interface links to and the server serves; the
|
|
1249
1236
|
// canonical `/AppStream` still answers, because a client built before the
|
|
1250
|
-
// short paths existed asks for it.
|
|
1251
|
-
//
|
|
1252
|
-
//
|
|
1253
|
-
//
|
|
1254
|
-
//
|
|
1255
|
-
// The listing is empty rather than read from `registry()`, which records this
|
|
1256
|
-
// deployment's own folder so the delete route has something to remove: the
|
|
1257
|
-
// stream really does serve nothing at `/app/<name>/` here, and a listing that
|
|
1258
|
-
// named it would offer a tile that 404s.
|
|
1259
|
-
// `path` has its trailing slashes stripped, and the landing answers differ by
|
|
1260
|
-
// exactly that, so they are decided on the request's own pathname - minus the
|
|
1261
|
-
// folder the site is served from, which the patterns do not name.
|
|
1237
|
+
// short paths existed asks for it. `/AppStream` itself redirects to `/app`,
|
|
1238
|
+
// exactly as the server redirects it, and every request under either prefix
|
|
1239
|
+
// is handed to the package as the short one - so a mock lists and serves what
|
|
1240
|
+
// it published at the same URLs, with the same headers, as a server.
|
|
1262
1241
|
const stream = withoutBase(url.pathname)
|
|
1263
1242
|
|
|
1264
1243
|
if (/^\/AppStream$/i.test(stream))
|
|
@@ -1267,31 +1246,31 @@ const routeRequest = async (request, url) => {
|
|
|
1267
1246
|
headers: { location: `${BASE}${SHORT_APP_STREAM_PATH}` }
|
|
1268
1247
|
})
|
|
1269
1248
|
|
|
1270
|
-
if (
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
].join(''),
|
|
1282
|
-
{ status: 200, headers: { 'content-type': 'text/html; charset=utf-8' } }
|
|
1283
|
-
)
|
|
1249
|
+
if (/^\/(app|AppStream)(\/|$)/i.test(stream)) {
|
|
1250
|
+
// the path the surface matches on includes the site's folder, which is what
|
|
1251
|
+
// it builds the answers' URLs from; `/AppStream` is translated to the short
|
|
1252
|
+
// spelling so a client built before it existed reaches the same surface
|
|
1253
|
+
const page = await appStreamSurface().request({
|
|
1254
|
+
method: request.method,
|
|
1255
|
+
path: url.pathname.replace(
|
|
1256
|
+
/\/AppStream(?=\/|$)/i,
|
|
1257
|
+
SHORT_APP_STREAM_PATH
|
|
1258
|
+
)
|
|
1259
|
+
})
|
|
1284
1260
|
|
|
1285
|
-
|
|
1286
|
-
|
|
1261
|
+
// a removal changes the index, which lives in the drive: persisted in the
|
|
1262
|
+
// same breath as any other change, or a reload would bring the app back
|
|
1263
|
+
if (request.method !== 'GET') await persistChanges()
|
|
1287
1264
|
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1265
|
+
const headers = Object.assign({}, page.headers)
|
|
1266
|
+
// a location the package states is already inside the folder, because the
|
|
1267
|
+
// base it built it from carries it
|
|
1268
|
+
if (page.location) headers.location = page.location
|
|
1269
|
+
if (page.contentType) headers['content-type'] = page.contentType
|
|
1270
|
+
|
|
1271
|
+
return new Response(
|
|
1272
|
+
page.body === undefined || page.body === null ? null : page.body,
|
|
1273
|
+
{ status: page.status, headers }
|
|
1295
1274
|
)
|
|
1296
1275
|
}
|
|
1297
1276
|
|
|
@@ -1339,6 +1318,13 @@ const routeRequest = async (request, url) => {
|
|
|
1339
1318
|
const answer = await API.dispatch(SERVICES, routeId, apiRequest)
|
|
1340
1319
|
if (request.method !== 'GET') await persistChanges()
|
|
1341
1320
|
|
|
1321
|
+
// A deploy that published an app states its URL against the package's own
|
|
1322
|
+
// default mount. This site may be served from a folder, so the answer has to
|
|
1323
|
+
// name the URL a reader can actually open - the folder the surface above is
|
|
1324
|
+
// mounted under, which is the same base its links are built from.
|
|
1325
|
+
if (BASE && answer.body && answer.body.app && answer.body.app.url)
|
|
1326
|
+
answer.body.app.url = `${BASE}${answer.body.app.url}`
|
|
1327
|
+
|
|
1342
1328
|
// the shell is a page, not a file the caller named: the document states
|
|
1343
1329
|
// text/html for it, and the extension of `/` says nothing
|
|
1344
1330
|
if (routeId === 'GET /')
|
|
@@ -955,8 +955,8 @@ describe('service worker host', function () {
|
|
|
955
955
|
}
|
|
956
956
|
});
|
|
957
957
|
}); });
|
|
958
|
-
it('imports the fixture directory
|
|
959
|
-
var dispatch, synced, _a
|
|
958
|
+
it('imports the fixture directory', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
959
|
+
var dispatch, synced, _a;
|
|
960
960
|
return __generator(this, function (_b) {
|
|
961
961
|
switch (_b.label) {
|
|
962
962
|
case 0:
|
|
@@ -969,28 +969,6 @@ describe('service worker host', function () {
|
|
|
969
969
|
return [4 /*yield*/, synced.json()];
|
|
970
970
|
case 2:
|
|
971
971
|
_a.apply(void 0, [_b.sent()]).toEqual({ userCount: 0, groupCount: 0 });
|
|
972
|
-
siteAppId = '6f1c1c1e-6a1e-4c4a-9d1a-1b2c3d4e5f60';
|
|
973
|
-
return [4 /*yield*/, dispatch('/SASjsApi/drive/deploy', {
|
|
974
|
-
method: 'DELETE',
|
|
975
|
-
headers: { 'content-type': 'application/json' },
|
|
976
|
-
body: JSON.stringify({ id: siteAppId })
|
|
977
|
-
})];
|
|
978
|
-
case 3:
|
|
979
|
-
unpublished = _b.sent();
|
|
980
|
-
expect(unpublished.status).toBe(200);
|
|
981
|
-
return [4 /*yield*/, unpublished.json()];
|
|
982
|
-
case 4:
|
|
983
|
-
removed = _b.sent();
|
|
984
|
-
expect(removed.status).toBe('success');
|
|
985
|
-
expect(removed.app.id).toBe(siteAppId);
|
|
986
|
-
return [4 /*yield*/, dispatch('/SASjsApi/drive/deploy', {
|
|
987
|
-
method: 'DELETE',
|
|
988
|
-
headers: { 'content-type': 'application/json' },
|
|
989
|
-
body: JSON.stringify({ id: '00000000-0000-4000-8000-000000000000' })
|
|
990
|
-
})];
|
|
991
|
-
case 5:
|
|
992
|
-
other = _b.sent();
|
|
993
|
-
expect(other.status).toBe(404);
|
|
994
972
|
return [2 /*return*/];
|
|
995
973
|
}
|
|
996
974
|
});
|
|
@@ -1023,6 +1001,61 @@ describe('service worker host', function () {
|
|
|
1023
1001
|
}
|
|
1024
1002
|
});
|
|
1025
1003
|
}); });
|
|
1004
|
+
it('keeps an app’s URL and tiles inside the folder the site is served from', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1005
|
+
var worker, archive, form, published, app, listing, apps, landing, _a, page, _b;
|
|
1006
|
+
return __generator(this, function (_c) {
|
|
1007
|
+
switch (_c.label) {
|
|
1008
|
+
case 0:
|
|
1009
|
+
worker = loadWorker('/demo');
|
|
1010
|
+
return [4 /*yield*/, zipOf({
|
|
1011
|
+
'services/web/index.html': '<h1>Deployed</h1>'
|
|
1012
|
+
})];
|
|
1013
|
+
case 1:
|
|
1014
|
+
archive = _c.sent();
|
|
1015
|
+
form = new FormData();
|
|
1016
|
+
form.set('appLoc', '/Public/apps/demo');
|
|
1017
|
+
form.set('streamWebFolder', 'web');
|
|
1018
|
+
form.set('file', new Blob([new Uint8Array(archive)]), 'deploy.zip');
|
|
1019
|
+
return [4 /*yield*/, worker.dispatch('/demo/SASjsApi/drive/deploy/upload', { method: 'POST', body: form })];
|
|
1020
|
+
case 2:
|
|
1021
|
+
published = _c.sent();
|
|
1022
|
+
expect(published.status).toBe(200);
|
|
1023
|
+
return [4 /*yield*/, published.json()];
|
|
1024
|
+
case 3:
|
|
1025
|
+
app = (_c.sent()).app;
|
|
1026
|
+
// The package builds an app's URL - and the landing page's links - from the
|
|
1027
|
+
// base it was mounted on. Mounted at `/app` on a site served from `/demo`,
|
|
1028
|
+
// every one of them would point at the site root and 404, so this asserts
|
|
1029
|
+
// the mount and the requests carry the same folder.
|
|
1030
|
+
expect(app.url).toBe("/demo/app/".concat(app.id, "/"));
|
|
1031
|
+
return [4 /*yield*/, worker.dispatch('/demo/app/apps.json')];
|
|
1032
|
+
case 4:
|
|
1033
|
+
listing = _c.sent();
|
|
1034
|
+
return [4 /*yield*/, listing.json()];
|
|
1035
|
+
case 5:
|
|
1036
|
+
apps = (_c.sent()).apps;
|
|
1037
|
+
expect(apps.map(function (entry) { return entry.url; })).toEqual([
|
|
1038
|
+
"/demo/app/".concat(app.id, "/")
|
|
1039
|
+
]);
|
|
1040
|
+
return [4 /*yield*/, worker.dispatch('/demo/app/')];
|
|
1041
|
+
case 6:
|
|
1042
|
+
landing = _c.sent();
|
|
1043
|
+
_a = expect;
|
|
1044
|
+
return [4 /*yield*/, landing.text()];
|
|
1045
|
+
case 7:
|
|
1046
|
+
_a.apply(void 0, [_c.sent()]).toContain("href=\"/demo/app/".concat(app.id, "/\""));
|
|
1047
|
+
return [4 /*yield*/, worker.dispatch("/demo/app/".concat(app.id, "/"))];
|
|
1048
|
+
case 8:
|
|
1049
|
+
page = _c.sent();
|
|
1050
|
+
expect(page.status).toBe(200);
|
|
1051
|
+
_b = expect;
|
|
1052
|
+
return [4 /*yield*/, page.text()];
|
|
1053
|
+
case 9:
|
|
1054
|
+
_b.apply(void 0, [_c.sent()]).toContain('<h1>Deployed</h1>');
|
|
1055
|
+
return [2 /*return*/];
|
|
1056
|
+
}
|
|
1057
|
+
});
|
|
1058
|
+
}); });
|
|
1026
1059
|
it('answers every route under the folder the site is published in', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1027
1060
|
var worker, info, _a, page, folder, stream, landing, apps, _b, aliased, _c;
|
|
1028
1061
|
var _d;
|
|
@@ -1502,120 +1535,211 @@ describe('service worker host', function () {
|
|
|
1502
1535
|
}
|
|
1503
1536
|
});
|
|
1504
1537
|
}); });
|
|
1505
|
-
it('
|
|
1506
|
-
var dispatch, _a, _b, path_2, listing, _c, e_1_1, _d, _e, path_3, landing,
|
|
1507
|
-
var e_1,
|
|
1508
|
-
return __generator(this, function (
|
|
1509
|
-
switch (
|
|
1538
|
+
it('publishes, lists, serves and removes an app through the package surface', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1539
|
+
var dispatch, _a, _b, path_2, listing, _c, e_1_1, _d, _e, path_3, landing, e_2_1, root, archive, form, published, app, _f, _g, path_4, listing, _h, e_3_1, _j, _k, path_5, page, _l, e_4_1, folder, _m, refused, missing, removed, _o, after, _p, gone;
|
|
1540
|
+
var e_1, _q, e_2, _r, e_3, _s, e_4, _t;
|
|
1541
|
+
return __generator(this, function (_u) {
|
|
1542
|
+
switch (_u.label) {
|
|
1510
1543
|
case 0:
|
|
1511
1544
|
dispatch = seeded().dispatch;
|
|
1512
|
-
|
|
1545
|
+
_u.label = 1;
|
|
1513
1546
|
case 1:
|
|
1514
|
-
|
|
1547
|
+
_u.trys.push([1, 7, 8, 9]);
|
|
1515
1548
|
_a = __values(['/app/apps.json', '/AppStream/apps.json']), _b = _a.next();
|
|
1516
|
-
|
|
1549
|
+
_u.label = 2;
|
|
1517
1550
|
case 2:
|
|
1518
1551
|
if (!!_b.done) return [3 /*break*/, 6];
|
|
1519
1552
|
path_2 = _b.value;
|
|
1520
1553
|
return [4 /*yield*/, dispatch(path_2)];
|
|
1521
1554
|
case 3:
|
|
1522
|
-
listing =
|
|
1555
|
+
listing = _u.sent();
|
|
1523
1556
|
expect(listing.status).toBe(200);
|
|
1524
1557
|
_c = expect;
|
|
1525
1558
|
return [4 /*yield*/, listing.json()];
|
|
1526
1559
|
case 4:
|
|
1527
|
-
_c.apply(void 0, [
|
|
1528
|
-
|
|
1560
|
+
_c.apply(void 0, [_u.sent()]).toEqual({ apps: [] });
|
|
1561
|
+
_u.label = 5;
|
|
1529
1562
|
case 5:
|
|
1530
1563
|
_b = _a.next();
|
|
1531
1564
|
return [3 /*break*/, 2];
|
|
1532
1565
|
case 6: return [3 /*break*/, 9];
|
|
1533
1566
|
case 7:
|
|
1534
|
-
e_1_1 =
|
|
1567
|
+
e_1_1 = _u.sent();
|
|
1535
1568
|
e_1 = { error: e_1_1 };
|
|
1536
1569
|
return [3 /*break*/, 9];
|
|
1537
1570
|
case 8:
|
|
1538
1571
|
try {
|
|
1539
|
-
if (_b && !_b.done && (
|
|
1572
|
+
if (_b && !_b.done && (_q = _a.return)) _q.call(_a);
|
|
1540
1573
|
}
|
|
1541
1574
|
finally { if (e_1) throw e_1.error; }
|
|
1542
1575
|
return [7 /*endfinally*/];
|
|
1543
1576
|
case 9:
|
|
1544
|
-
|
|
1577
|
+
_u.trys.push([9, 14, 15, 16]);
|
|
1545
1578
|
_d = __values(['/app', '/app/', '/app/index.html']), _e = _d.next();
|
|
1546
|
-
|
|
1579
|
+
_u.label = 10;
|
|
1547
1580
|
case 10:
|
|
1548
|
-
if (!!_e.done) return [3 /*break*/,
|
|
1581
|
+
if (!!_e.done) return [3 /*break*/, 13];
|
|
1549
1582
|
path_3 = _e.value;
|
|
1550
1583
|
return [4 /*yield*/, dispatch(path_3)];
|
|
1551
1584
|
case 11:
|
|
1552
|
-
landing =
|
|
1585
|
+
landing = _u.sent();
|
|
1553
1586
|
expect(landing.status).toBe(200);
|
|
1554
1587
|
expect(landing.headers.get('content-type')).toContain('text/html');
|
|
1555
|
-
|
|
1556
|
-
return [4 /*yield*/, landing.text()];
|
|
1588
|
+
_u.label = 12;
|
|
1557
1589
|
case 12:
|
|
1558
|
-
_f.apply(void 0, [_p.sent()]).toContain('serves no apps');
|
|
1559
|
-
_p.label = 13;
|
|
1560
|
-
case 13:
|
|
1561
1590
|
_e = _d.next();
|
|
1562
1591
|
return [3 /*break*/, 10];
|
|
1563
|
-
case
|
|
1564
|
-
case
|
|
1565
|
-
e_2_1 =
|
|
1592
|
+
case 13: return [3 /*break*/, 16];
|
|
1593
|
+
case 14:
|
|
1594
|
+
e_2_1 = _u.sent();
|
|
1566
1595
|
e_2 = { error: e_2_1 };
|
|
1567
|
-
return [3 /*break*/,
|
|
1568
|
-
case
|
|
1596
|
+
return [3 /*break*/, 16];
|
|
1597
|
+
case 15:
|
|
1569
1598
|
try {
|
|
1570
|
-
if (_e && !_e.done && (
|
|
1599
|
+
if (_e && !_e.done && (_r = _d.return)) _r.call(_d);
|
|
1571
1600
|
}
|
|
1572
1601
|
finally { if (e_2) throw e_2.error; }
|
|
1573
1602
|
return [7 /*endfinally*/];
|
|
1574
|
-
case
|
|
1575
|
-
case
|
|
1576
|
-
root =
|
|
1603
|
+
case 16: return [4 /*yield*/, dispatch('/AppStream')];
|
|
1604
|
+
case 17:
|
|
1605
|
+
root = _u.sent();
|
|
1577
1606
|
expect(root.status).toBe(301);
|
|
1578
1607
|
expect(root.headers.get('location')).toBe('/app');
|
|
1579
|
-
return [4 /*yield*/,
|
|
1608
|
+
return [4 /*yield*/, zipOf({
|
|
1609
|
+
'services/web/index.html': '<h1>Demo</h1>'
|
|
1610
|
+
})];
|
|
1611
|
+
case 18:
|
|
1612
|
+
archive = _u.sent();
|
|
1613
|
+
form = new FormData();
|
|
1614
|
+
form.set('appLoc', '/Public/apps/demo');
|
|
1615
|
+
form.set('streamWebFolder', 'web');
|
|
1616
|
+
form.set('file', new Blob([new Uint8Array(archive)]), 'deploy.zip');
|
|
1617
|
+
return [4 /*yield*/, dispatch('/SASjsApi/drive/deploy/upload', {
|
|
1618
|
+
method: 'POST',
|
|
1619
|
+
body: form
|
|
1620
|
+
})];
|
|
1580
1621
|
case 19:
|
|
1581
|
-
|
|
1582
|
-
expect(
|
|
1583
|
-
|
|
1584
|
-
return [4 /*yield*/, canonicalLanding.text()];
|
|
1622
|
+
published = _u.sent();
|
|
1623
|
+
expect(published.status).toBe(200);
|
|
1624
|
+
return [4 /*yield*/, published.json()];
|
|
1585
1625
|
case 20:
|
|
1586
|
-
|
|
1587
|
-
|
|
1626
|
+
app = (_u.sent()).app;
|
|
1627
|
+
expect(app.name).toBe('demo');
|
|
1628
|
+
expect(app.url).toBe("/app/".concat(app.id, "/"));
|
|
1629
|
+
_u.label = 21;
|
|
1588
1630
|
case 21:
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1631
|
+
_u.trys.push([21, 27, 28, 29]);
|
|
1632
|
+
_f = __values(['/app/apps.json', '/AppStream/apps.json']), _g = _f.next();
|
|
1633
|
+
_u.label = 22;
|
|
1592
1634
|
case 22:
|
|
1593
|
-
if (!!
|
|
1594
|
-
path_4 =
|
|
1635
|
+
if (!!_g.done) return [3 /*break*/, 26];
|
|
1636
|
+
path_4 = _g.value;
|
|
1595
1637
|
return [4 /*yield*/, dispatch(path_4)];
|
|
1596
1638
|
case 23:
|
|
1597
|
-
|
|
1598
|
-
expect
|
|
1599
|
-
|
|
1600
|
-
return [4 /*yield*/, app.json()];
|
|
1639
|
+
listing = _u.sent();
|
|
1640
|
+
_h = expect;
|
|
1641
|
+
return [4 /*yield*/, listing.json()];
|
|
1601
1642
|
case 24:
|
|
1602
|
-
|
|
1603
|
-
|
|
1643
|
+
_h.apply(void 0, [(_u.sent()).apps[0]]).toMatchObject({
|
|
1644
|
+
id: app.id,
|
|
1645
|
+
name: 'demo',
|
|
1646
|
+
url: "/app/".concat(app.id, "/")
|
|
1647
|
+
});
|
|
1648
|
+
_u.label = 25;
|
|
1604
1649
|
case 25:
|
|
1605
|
-
|
|
1650
|
+
_g = _f.next();
|
|
1606
1651
|
return [3 /*break*/, 22];
|
|
1607
1652
|
case 26: return [3 /*break*/, 29];
|
|
1608
1653
|
case 27:
|
|
1609
|
-
e_3_1 =
|
|
1654
|
+
e_3_1 = _u.sent();
|
|
1610
1655
|
e_3 = { error: e_3_1 };
|
|
1611
1656
|
return [3 /*break*/, 29];
|
|
1612
1657
|
case 28:
|
|
1613
1658
|
try {
|
|
1614
|
-
if (
|
|
1659
|
+
if (_g && !_g.done && (_s = _f.return)) _s.call(_f);
|
|
1615
1660
|
}
|
|
1616
1661
|
finally { if (e_3) throw e_3.error; }
|
|
1617
1662
|
return [7 /*endfinally*/];
|
|
1618
|
-
case 29:
|
|
1663
|
+
case 29:
|
|
1664
|
+
_u.trys.push([29, 35, 36, 37]);
|
|
1665
|
+
_j = __values([
|
|
1666
|
+
"/app/".concat(app.id, "/"),
|
|
1667
|
+
"/app/".concat(app.id, "/index.html"),
|
|
1668
|
+
"/AppStream/".concat(app.id, "/")
|
|
1669
|
+
]), _k = _j.next();
|
|
1670
|
+
_u.label = 30;
|
|
1671
|
+
case 30:
|
|
1672
|
+
if (!!_k.done) return [3 /*break*/, 34];
|
|
1673
|
+
path_5 = _k.value;
|
|
1674
|
+
return [4 /*yield*/, dispatch(path_5)];
|
|
1675
|
+
case 31:
|
|
1676
|
+
page = _u.sent();
|
|
1677
|
+
expect(page.status).toBe(200);
|
|
1678
|
+
_l = expect;
|
|
1679
|
+
return [4 /*yield*/, page.text()];
|
|
1680
|
+
case 32:
|
|
1681
|
+
_l.apply(void 0, [_u.sent()]).toContain('<h1>Demo</h1>');
|
|
1682
|
+
_u.label = 33;
|
|
1683
|
+
case 33:
|
|
1684
|
+
_k = _j.next();
|
|
1685
|
+
return [3 /*break*/, 30];
|
|
1686
|
+
case 34: return [3 /*break*/, 37];
|
|
1687
|
+
case 35:
|
|
1688
|
+
e_4_1 = _u.sent();
|
|
1689
|
+
e_4 = { error: e_4_1 };
|
|
1690
|
+
return [3 /*break*/, 37];
|
|
1691
|
+
case 36:
|
|
1692
|
+
try {
|
|
1693
|
+
if (_k && !_k.done && (_t = _j.return)) _t.call(_j);
|
|
1694
|
+
}
|
|
1695
|
+
finally { if (e_4) throw e_4.error; }
|
|
1696
|
+
return [7 /*endfinally*/];
|
|
1697
|
+
case 37: return [4 /*yield*/, dispatch("/app/".concat(app.id))];
|
|
1698
|
+
case 38:
|
|
1699
|
+
folder = _u.sent();
|
|
1700
|
+
expect(folder.status).toBe(301);
|
|
1701
|
+
expect(folder.headers.get('location')).toBe("/app/".concat(app.id, "/"));
|
|
1702
|
+
_m = expect;
|
|
1703
|
+
return [4 /*yield*/, folder.text()];
|
|
1704
|
+
case 39:
|
|
1705
|
+
_m.apply(void 0, [_u.sent()]).toBe('');
|
|
1706
|
+
return [4 /*yield*/, dispatch('/app/apps.json', {
|
|
1707
|
+
method: 'POST',
|
|
1708
|
+
headers: { 'content-type': 'application/json' },
|
|
1709
|
+
body: '{}'
|
|
1710
|
+
})];
|
|
1711
|
+
case 40:
|
|
1712
|
+
refused = _u.sent();
|
|
1713
|
+
expect(refused.status).toBe(405);
|
|
1714
|
+
expect(refused.headers.get('allow')).toBe('GET');
|
|
1715
|
+
return [4 /*yield*/, dispatch('/app/00000000-0000-4000-8000-000000000000/')];
|
|
1716
|
+
case 41:
|
|
1717
|
+
missing = _u.sent();
|
|
1718
|
+
expect(missing.status).toBe(404);
|
|
1719
|
+
return [4 /*yield*/, dispatch('/SASjsApi/drive/deploy', {
|
|
1720
|
+
method: 'DELETE',
|
|
1721
|
+
headers: { 'content-type': 'application/json' },
|
|
1722
|
+
body: JSON.stringify({ id: app.id })
|
|
1723
|
+
})];
|
|
1724
|
+
case 42:
|
|
1725
|
+
removed = _u.sent();
|
|
1726
|
+
expect(removed.status).toBe(200);
|
|
1727
|
+
_o = expect;
|
|
1728
|
+
return [4 /*yield*/, removed.json()];
|
|
1729
|
+
case 43:
|
|
1730
|
+
_o.apply(void 0, [(_u.sent()).app.id]).toBe(app.id);
|
|
1731
|
+
return [4 /*yield*/, dispatch('/app/apps.json')];
|
|
1732
|
+
case 44:
|
|
1733
|
+
after = _u.sent();
|
|
1734
|
+
_p = expect;
|
|
1735
|
+
return [4 /*yield*/, after.json()];
|
|
1736
|
+
case 45:
|
|
1737
|
+
_p.apply(void 0, [_u.sent()]).toEqual({ apps: [] });
|
|
1738
|
+
return [4 /*yield*/, dispatch("/app/".concat(app.id, "/"))];
|
|
1739
|
+
case 46:
|
|
1740
|
+
gone = _u.sent();
|
|
1741
|
+
expect(gone.status).toBe(404);
|
|
1742
|
+
return [2 /*return*/];
|
|
1619
1743
|
}
|
|
1620
1744
|
});
|
|
1621
1745
|
}); });
|
|
@@ -2507,7 +2631,7 @@ describe('service worker host', function () {
|
|
|
2507
2631
|
}); });
|
|
2508
2632
|
});
|
|
2509
2633
|
describe('conformance corpus', function () {
|
|
2510
|
-
var
|
|
2634
|
+
var e_5, _a;
|
|
2511
2635
|
/**
|
|
2512
2636
|
* The corpus is what "the same API" means: the cases @sasjs/api runs against
|
|
2513
2637
|
* its own services, and against a live sasjs/server, run here against this
|
|
@@ -2516,7 +2640,7 @@ describe('service worker host', function () {
|
|
|
2516
2640
|
* used to have - and it is a test rather than a review.
|
|
2517
2641
|
*/
|
|
2518
2642
|
var httpFor = function (testCase) {
|
|
2519
|
-
var
|
|
2643
|
+
var e_6, _a;
|
|
2520
2644
|
var _b;
|
|
2521
2645
|
var _c = __read(testCase.route.split(' '), 2), method = _c[0], routePath = _c[1];
|
|
2522
2646
|
var query = new URLSearchParams();
|
|
@@ -2527,12 +2651,12 @@ describe('service worker host', function () {
|
|
|
2527
2651
|
query.set(key, String(value));
|
|
2528
2652
|
}
|
|
2529
2653
|
}
|
|
2530
|
-
catch (
|
|
2654
|
+
catch (e_6_1) { e_6 = { error: e_6_1 }; }
|
|
2531
2655
|
finally {
|
|
2532
2656
|
try {
|
|
2533
2657
|
if (_e && !_e.done && (_a = _d.return)) _a.call(_d);
|
|
2534
2658
|
}
|
|
2535
|
-
finally { if (
|
|
2659
|
+
finally { if (e_6) throw e_6.error; }
|
|
2536
2660
|
}
|
|
2537
2661
|
var suffix = query.toString() ? "?".concat(query) : '';
|
|
2538
2662
|
var init = { method: method };
|
|
@@ -2563,8 +2687,8 @@ describe('service worker host', function () {
|
|
|
2563
2687
|
* does.
|
|
2564
2688
|
*/
|
|
2565
2689
|
var seedDrive = function (runtime, testCase) { return __awaiter(void 0, void 0, void 0, function () {
|
|
2566
|
-
var text, _a, _b, _c, file, contents, _d, _e, _f, file, contents,
|
|
2567
|
-
var
|
|
2690
|
+
var text, _a, _b, _c, file, contents, _d, _e, _f, file, contents, e_7_1;
|
|
2691
|
+
var e_8, _g, e_7, _h;
|
|
2568
2692
|
return __generator(this, function (_j) {
|
|
2569
2693
|
switch (_j.label) {
|
|
2570
2694
|
case 0:
|
|
@@ -2576,12 +2700,12 @@ describe('service worker host', function () {
|
|
|
2576
2700
|
text["/sasjs/drive/files".concat(file)] = contents;
|
|
2577
2701
|
}
|
|
2578
2702
|
}
|
|
2579
|
-
catch (
|
|
2703
|
+
catch (e_8_1) { e_8 = { error: e_8_1 }; }
|
|
2580
2704
|
finally {
|
|
2581
2705
|
try {
|
|
2582
2706
|
if (_b && !_b.done && (_g = _a.return)) _g.call(_a);
|
|
2583
2707
|
}
|
|
2584
|
-
finally { if (
|
|
2708
|
+
finally { if (e_8) throw e_8.error; }
|
|
2585
2709
|
}
|
|
2586
2710
|
return [4 /*yield*/, runtime.load(text)];
|
|
2587
2711
|
case 1:
|
|
@@ -2604,14 +2728,14 @@ describe('service worker host', function () {
|
|
|
2604
2728
|
return [3 /*break*/, 3];
|
|
2605
2729
|
case 6: return [3 /*break*/, 9];
|
|
2606
2730
|
case 7:
|
|
2607
|
-
|
|
2608
|
-
|
|
2731
|
+
e_7_1 = _j.sent();
|
|
2732
|
+
e_7 = { error: e_7_1 };
|
|
2609
2733
|
return [3 /*break*/, 9];
|
|
2610
2734
|
case 8:
|
|
2611
2735
|
try {
|
|
2612
2736
|
if (_e && !_e.done && (_h = _d.return)) _h.call(_d);
|
|
2613
2737
|
}
|
|
2614
|
-
finally { if (
|
|
2738
|
+
finally { if (e_7) throw e_7.error; }
|
|
2615
2739
|
return [7 /*endfinally*/];
|
|
2616
2740
|
case 9: return [2 /*return*/];
|
|
2617
2741
|
}
|
|
@@ -2679,12 +2803,12 @@ describe('service worker host', function () {
|
|
|
2679
2803
|
_loop_1(testCase);
|
|
2680
2804
|
}
|
|
2681
2805
|
}
|
|
2682
|
-
catch (
|
|
2806
|
+
catch (e_5_1) { e_5 = { error: e_5_1 }; }
|
|
2683
2807
|
finally {
|
|
2684
2808
|
try {
|
|
2685
2809
|
if (DRIVE_CORPUS_1_1 && !DRIVE_CORPUS_1_1.done && (_a = DRIVE_CORPUS_1.return)) _a.call(DRIVE_CORPUS_1);
|
|
2686
2810
|
}
|
|
2687
|
-
finally { if (
|
|
2811
|
+
finally { if (e_5) throw e_5.error; }
|
|
2688
2812
|
}
|
|
2689
2813
|
});
|
|
2690
2814
|
/**
|
|
@@ -2696,7 +2820,7 @@ describe('service worker host', function () {
|
|
|
2696
2820
|
* are the package's.
|
|
2697
2821
|
*/
|
|
2698
2822
|
describe('identity and record conformance', function () {
|
|
2699
|
-
var
|
|
2823
|
+
var e_9, _a;
|
|
2700
2824
|
/**
|
|
2701
2825
|
* Boots the worker from a fixture, the way the page does: the case's own
|
|
2702
2826
|
* identity, and `subject: null` for no implicit caller, so a case that
|
|
@@ -2729,7 +2853,7 @@ describe('service worker host', function () {
|
|
|
2729
2853
|
};
|
|
2730
2854
|
/** The request a case describes, as HTTP: path parameters filled, token sent. */
|
|
2731
2855
|
var httpForCase = function (testCase) {
|
|
2732
|
-
var
|
|
2856
|
+
var e_10, _a;
|
|
2733
2857
|
var _b = __read(testCase.route.split(' '), 2), method = _b[0], routePath = _b[1];
|
|
2734
2858
|
var filled = routePath.replace(/\{(\w+)\}/g, function (_match, name) {
|
|
2735
2859
|
return encodeURIComponent(String((testCase.request.params || {})[name]));
|
|
@@ -2742,12 +2866,12 @@ describe('service worker host', function () {
|
|
|
2742
2866
|
query.set(key, String(value));
|
|
2743
2867
|
}
|
|
2744
2868
|
}
|
|
2745
|
-
catch (
|
|
2869
|
+
catch (e_10_1) { e_10 = { error: e_10_1 }; }
|
|
2746
2870
|
finally {
|
|
2747
2871
|
try {
|
|
2748
2872
|
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
|
|
2749
2873
|
}
|
|
2750
|
-
finally { if (
|
|
2874
|
+
finally { if (e_10) throw e_10.error; }
|
|
2751
2875
|
}
|
|
2752
2876
|
var suffix = query.toString() ? "?".concat(query) : '';
|
|
2753
2877
|
var headers = {};
|
|
@@ -2869,12 +2993,12 @@ describe('service worker host', function () {
|
|
|
2869
2993
|
_loop_2(testCase);
|
|
2870
2994
|
}
|
|
2871
2995
|
}
|
|
2872
|
-
catch (
|
|
2996
|
+
catch (e_9_1) { e_9 = { error: e_9_1 }; }
|
|
2873
2997
|
finally {
|
|
2874
2998
|
try {
|
|
2875
2999
|
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
2876
3000
|
}
|
|
2877
|
-
finally { if (
|
|
3001
|
+
finally { if (e_9) throw e_9.error; }
|
|
2878
3002
|
}
|
|
2879
3003
|
it('answers as the fixture administrator when no subject was chosen', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2880
3004
|
var worker, response, rules;
|
package/package.json
CHANGED