@sasjs/cli 6.26.0 → 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 streams this host published: the site itself.
701
+ * The app stream, over the drive this site carries.
702
702
  *
703
- * The index is the package's, so the contract is the package's - an app is its
704
- * id, one app per `appLoc`, and unpublish takes the id (sasjs/server#544). The id
705
- * is fixed here rather than minted: this host publishes exactly one app, the
706
- * folder the site was built for, and a stable id is a handle a test and a
707
- * reviewer can both name.
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
- * The folder is the identity, so unpublishing the app the site was built for
710
- * answers with that app; any other id is the documented 404. The static files
711
- * stay where they are - a worker cannot delete the site it is served from - so
712
- * this is a record of the publication, not a filesystem operation.
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 SITE_APP_ID = '6f1c1c1e-6a1e-4c4a-9d1a-1b2c3d4e5f60'
715
-
716
- let appStreamPromise
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
- return API.createAppStreamService(
729
- new API.MemoryAppStreamStore(
730
- appLoc
731
- ? [
732
- {
733
- id: SITE_APP_ID,
734
- name: API.defaultAppName(appLoc),
735
- appLoc,
736
- streamWebFolder: 'web',
737
- publishedAt: new Date(0).toISOString()
738
- }
739
- ]
740
- : []
741
- )
742
- )
743
- })()
744
- return appStreamPromise
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. The answers are the same either way, so
1251
- // `/AppStream` redirects to `/app` - exactly as the server redirects it -
1252
- // and the landing page, the listing and the missing-name refusal are decided
1253
- // on both.
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
- /^\/(app|AppStream)\/?$/i.test(stream) ||
1272
- /^\/(app|AppStream)\/index\.html$/i.test(stream)
1273
- )
1274
- return new Response(
1275
- [
1276
- '<!doctype html><html><head><meta charset="utf-8">',
1277
- '<title>App Stream</title></head><body>',
1278
- '<h1>SASjs App Stream</h1>',
1279
- '<p>This browser host serves no apps: nothing is published on a static site.</p>',
1280
- '</body></html>'
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
- if (/^\/(app|AppStream)\/apps\.json$/i.test(stream))
1286
- return json({ apps: [] })
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
- if (/^\/(app|AppStream)\//i.test(stream)) {
1289
- return json(
1290
- {
1291
- message:
1292
- 'This browser host serves no apps: nothing is published on a static site.'
1293
- },
1294
- 404
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, and unpublishes the site itself', function () { return __awaiter(void 0, void 0, void 0, function () {
959
- var dispatch, synced, _a, siteAppId, unpublished, removed, other;
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('answers the app stream on the short path, and the canonical one as an alias', function () { return __awaiter(void 0, void 0, void 0, function () {
1506
- var dispatch, _a, _b, path_2, listing, _c, e_1_1, _d, _e, path_3, landing, _f, e_2_1, root, canonicalLanding, _g, _h, _j, path_4, app, _k, e_3_1;
1507
- var e_1, _l, e_2, _m, e_3, _o;
1508
- return __generator(this, function (_p) {
1509
- switch (_p.label) {
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
- _p.label = 1;
1545
+ _u.label = 1;
1513
1546
  case 1:
1514
- _p.trys.push([1, 7, 8, 9]);
1547
+ _u.trys.push([1, 7, 8, 9]);
1515
1548
  _a = __values(['/app/apps.json', '/AppStream/apps.json']), _b = _a.next();
1516
- _p.label = 2;
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 = _p.sent();
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, [_p.sent()]).toEqual({ apps: [] });
1528
- _p.label = 5;
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 = _p.sent();
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 && (_l = _a.return)) _l.call(_a);
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
- _p.trys.push([9, 15, 16, 17]);
1577
+ _u.trys.push([9, 14, 15, 16]);
1545
1578
  _d = __values(['/app', '/app/', '/app/index.html']), _e = _d.next();
1546
- _p.label = 10;
1579
+ _u.label = 10;
1547
1580
  case 10:
1548
- if (!!_e.done) return [3 /*break*/, 14];
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 = _p.sent();
1585
+ landing = _u.sent();
1553
1586
  expect(landing.status).toBe(200);
1554
1587
  expect(landing.headers.get('content-type')).toContain('text/html');
1555
- _f = expect;
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 14: return [3 /*break*/, 17];
1564
- case 15:
1565
- e_2_1 = _p.sent();
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*/, 17];
1568
- case 16:
1596
+ return [3 /*break*/, 16];
1597
+ case 15:
1569
1598
  try {
1570
- if (_e && !_e.done && (_m = _d.return)) _m.call(_d);
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 17: return [4 /*yield*/, dispatch('/AppStream')];
1575
- case 18:
1576
- root = _p.sent();
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*/, dispatch('/AppStream/')];
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
- canonicalLanding = _p.sent();
1582
- expect(canonicalLanding.status).toBe(200);
1583
- _g = expect;
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
- _g.apply(void 0, [_p.sent()]).toContain('serves no apps');
1587
- _p.label = 21;
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
- _p.trys.push([21, 27, 28, 29]);
1590
- _h = __values(['/app/Demo/', '/AppStream/Demo/']), _j = _h.next();
1591
- _p.label = 22;
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 (!!_j.done) return [3 /*break*/, 26];
1594
- path_4 = _j.value;
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
- app = _p.sent();
1598
- expect(app.status).toBe(404);
1599
- _k = expect;
1600
- return [4 /*yield*/, app.json()];
1639
+ listing = _u.sent();
1640
+ _h = expect;
1641
+ return [4 /*yield*/, listing.json()];
1601
1642
  case 24:
1602
- _k.apply(void 0, [(_p.sent()).message]).toContain('serves no apps');
1603
- _p.label = 25;
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
- _j = _h.next();
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 = _p.sent();
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 (_j && !_j.done && (_o = _h.return)) _o.call(_h);
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: return [2 /*return*/];
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 e_4, _a;
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 e_5, _a;
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 (e_5_1) { e_5 = { error: e_5_1 }; }
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 (e_5) throw e_5.error; }
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, e_6_1;
2567
- var e_7, _g, e_6, _h;
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 (e_7_1) { e_7 = { error: e_7_1 }; }
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 (e_7) throw e_7.error; }
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
- e_6_1 = _j.sent();
2608
- e_6 = { error: e_6_1 };
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 (e_6) throw e_6.error; }
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 (e_4_1) { e_4 = { error: e_4_1 }; }
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 (e_4) throw e_4.error; }
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 e_8, _a;
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 e_9, _a;
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 (e_9_1) { e_9 = { error: e_9_1 }; }
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 (e_9) throw e_9.error; }
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 (e_8_1) { e_8 = { error: e_8_1 }; }
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 (e_8) throw e_8.error; }
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
@@ -70,7 +70,7 @@
70
70
  "registry": "https://registry.npmjs.org"
71
71
  },
72
72
  "dependencies": {
73
- "@sasjs/adapter": "5.2.6",
73
+ "@sasjs/adapter": "6.0.2",
74
74
  "@sasjs/api": "0.27.0",
75
75
  "@sasjs/core": "7.1.12",
76
76
  "@sasjs/lint": "5.1.1",
@@ -125,5 +125,5 @@
125
125
  "ws": "8.21.0",
126
126
  "nanoid": "3.3.18"
127
127
  },
128
- "version": "6.26.0"
128
+ "version": "6.27.0"
129
129
  }