@sasjs/cli 6.13.2 → 6.14.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.
@@ -322,12 +322,23 @@ const handle = async (request, url) => {
322
322
  await R.ensureReady()
323
323
 
324
324
  if (path.endsWith('/SASjsApi/info')) {
325
+ // The documented body field for field, with the values @sasjs/api's
326
+ // BROWSER_INFO states for this host: `cors` is the document's CorsType
327
+ // (`enable` | `disable`), both ports are null because a static origin has
328
+ // no listener, and `localLoginEnabled` is false because there is no
329
+ // account to sign in to - true would render a login form with no route
330
+ // behind it. `version` is `dev`, the fallback a server reports when it
331
+ // carries no build stamp. This block goes when the release carrying the
332
+ // package's own info service lands; until then the two answers agree.
325
333
  return json({
326
334
  mode: 'desktop',
327
- cors: 'disabled',
328
- whiteList: [],
329
- protocol: 'browser',
330
- runTimes: ['js']
335
+ cors: 'disable',
336
+ httpPort: null,
337
+ httpsPort: null,
338
+ runTimes: ['js'],
339
+ authProviders: [],
340
+ localLoginEnabled: false,
341
+ version: 'dev'
331
342
  })
332
343
  }
333
344
 
@@ -399,6 +399,14 @@ var EXECUTABLE_TYPES = [
399
399
  var patchIndexHtml = function (html, version) {
400
400
  var warnings = [];
401
401
  var patched = html;
402
+ // States where this page's API comes from, for anything in the page that
403
+ // wants to say so: the server's own interface reads it to describe the host
404
+ // it is running on, and a browser host is a different thing to explain than a
405
+ // server process. Absence means the server answered the page.
406
+ if (!/<meta\s+name=["']sasjs-host["']/i.test(patched))
407
+ patched = patched.replace(/<head(\s[^>]*)?>/i, function (head) {
408
+ return "".concat(head, "\n <meta name=\"sasjs-host\" content=\"browser\" />");
409
+ });
402
410
  if (/<sasjs[^>]*>/i.test(patched)) {
403
411
  patched = patched.replace(/(<sasjs[^>]*?)\sserverurl="[^"]*"/i, '$1 serverurl=""');
404
412
  patched = patched.replace(/(<sasjs[^>]*?)\sloginmechanism="[^"]*"/i, '$1 loginmechanism="Default"');
@@ -367,6 +367,23 @@ describe('browser-hosted build', function () {
367
367
  }
368
368
  });
369
369
  }); });
370
+ it('states in the page that the API is answered here', function () { return __awaiter(void 0, void 0, void 0, function () {
371
+ var html;
372
+ return __generator(this, function (_a) {
373
+ switch (_a.label) {
374
+ case 0: return [4 /*yield*/, (0, mockSite_1.buildMockSite)(target())];
375
+ case 1:
376
+ _a.sent();
377
+ html = fs_1.default.readFileSync(path_1.default.join(out(), 'index.html'), 'utf8');
378
+ // The interface reads this to tell a browser host from a server: the API
379
+ // cannot, because a browser host answers the same routes and the same
380
+ // /SASjsApi/info shape. Only the host knows, so the host says.
381
+ expect(html).toContain('<meta name="sasjs-host" content="browser" />');
382
+ expect(html.indexOf('sasjs-host')).toBeLessThan(html.indexOf('</head>'));
383
+ return [2 /*return*/];
384
+ }
385
+ });
386
+ }); });
370
387
  it('replays every script tag a page loads, not just a bundled entry point', function () { return __awaiter(void 0, void 0, void 0, function () {
371
388
  var html, tag, specs;
372
389
  return __generator(this, function (_a) {
@@ -89,6 +89,7 @@ var apiBrowserBuild = function () {
89
89
  var loadWorker = function () {
90
90
  jest.resetModules();
91
91
  var handlers = {};
92
+ var refusingWrites = false;
92
93
  var self = {
93
94
  location: { origin: origin },
94
95
  addEventListener: function (type, fn) {
@@ -107,6 +108,28 @@ var loadWorker = function () {
107
108
  if (path.includes('api-browser'))
108
109
  return require(apiBrowserBuild());
109
110
  require('../assets/runtime-core.js');
111
+ // The corpus needs the same drive with its writes refused, without building
112
+ // a second site. The flag is flipped after the case has seeded, because a
113
+ // store that refused during seeding could not be seeded - the package seeds
114
+ // its refusing store through the constructor for the same reason.
115
+ var base = self.SASjsMockRuntime.driveStore;
116
+ var refused = function () {
117
+ return Promise.reject(new Error('the store refused the write'));
118
+ };
119
+ self.SASjsMockRuntime.driveStore = {
120
+ read: function (file) { return base.read(file); },
121
+ exists: function (file) { return base.exists(file); },
122
+ stat: function (file) { return base.stat(file); },
123
+ list: function (folder) { return base.list(folder); },
124
+ remove: function (file) { return base.remove(file); },
125
+ move: function (from, to) { return base.move(from, to); },
126
+ write: function (file, contents) {
127
+ return refusingWrites ? refused() : base.write(file, contents);
128
+ },
129
+ mkdirp: function (folder) {
130
+ return refusingWrites ? refused() : base.mkdirp(folder);
131
+ }
132
+ };
110
133
  };
111
134
  require('../assets/sw.js');
112
135
  global.fetch = jest.fn(function (url) { return __awaiter(void 0, void 0, void 0, function () {
@@ -150,7 +173,16 @@ var loadWorker = function () {
150
173
  var event = { waitUntil: function () { } };
151
174
  (handlers[type] || []).forEach(function (fn) { return fn(event); });
152
175
  };
153
- return { runtime: runtime, dispatch: dispatch, message: message, lifecycle: lifecycle, self: self };
176
+ return {
177
+ runtime: runtime,
178
+ dispatch: dispatch,
179
+ message: message,
180
+ lifecycle: lifecycle,
181
+ self: self,
182
+ refuseWrites: function (value) {
183
+ refusingWrites = value;
184
+ }
185
+ };
154
186
  };
155
187
  var jsonResponse = function (body) { return ({
156
188
  ok: true,
@@ -724,13 +756,35 @@ describe('service worker host', function () {
724
756
  switch (_f.label) {
725
757
  case 0:
726
758
  dispatch = seeded().dispatch;
727
- return [4 /*yield*/, dispatch('/SASjsApi/info')];
759
+ return [4 /*yield*/, dispatch('/SASjsApi/info')
760
+ // the documented body, field for field, in the values @sasjs/api's
761
+ // BROWSER_INFO states: a property the document does not state, or a login
762
+ // form told there are accounts when there are none, is this host describing
763
+ // an API the server does not serve
764
+ ];
728
765
  case 1:
729
766
  info = _f.sent();
767
+ // the documented body, field for field, in the values @sasjs/api's
768
+ // BROWSER_INFO states: a property the document does not state, or a login
769
+ // form told there are accounts when there are none, is this host describing
770
+ // an API the server does not serve
730
771
  _a = expect;
731
772
  return [4 /*yield*/, info.json()];
732
773
  case 2:
733
- _a.apply(void 0, [_f.sent()]).toEqual(expect.objectContaining({ protocol: 'browser', runTimes: ['js'] }));
774
+ // the documented body, field for field, in the values @sasjs/api's
775
+ // BROWSER_INFO states: a property the document does not state, or a login
776
+ // form told there are accounts when there are none, is this host describing
777
+ // an API the server does not serve
778
+ _a.apply(void 0, [_f.sent()]).toEqual({
779
+ mode: 'desktop',
780
+ cors: 'disable',
781
+ httpPort: null,
782
+ httpsPort: null,
783
+ runTimes: ['js'],
784
+ authProviders: [],
785
+ localLoginEnabled: false,
786
+ version: 'dev'
787
+ });
734
788
  return [4 /*yield*/, dispatch('/SASjsApi/drive/folder?_folderPath=' +
735
789
  encodeURIComponent("".concat(appLoc, "/services/public")))];
736
790
  case 3:
@@ -1459,6 +1513,7 @@ describe('service worker host', function () {
1459
1513
  return [4 /*yield*/, seedDrive(worker.runtime, testCase)];
1460
1514
  case 1:
1461
1515
  _f.sent();
1516
+ worker.refuseWrites(Boolean(testCase.unwritable));
1462
1517
  _a = httpFor(testCase), requestPath = _a.path, init = _a.init;
1463
1518
  return [4 /*yield*/, worker.dispatch(requestPath, init)];
1464
1519
  case 2:
package/package.json CHANGED
@@ -71,9 +71,9 @@
71
71
  },
72
72
  "dependencies": {
73
73
  "@sasjs/adapter": "5.1.3",
74
- "@sasjs/api": "0.2.1",
74
+ "@sasjs/api": "0.23.0",
75
75
  "@sasjs/core": "6.1.1",
76
- "@sasjs/lint": "5.0.0",
76
+ "@sasjs/lint": "5.0.1",
77
77
  "@sasjs/utils": "4.9.0",
78
78
  "axios": "1.20.0",
79
79
  "chalk": "4.1.2",
@@ -124,5 +124,5 @@
124
124
  "ws": "8.21.0",
125
125
  "nanoid": "3.3.18"
126
126
  },
127
- "version": "6.13.2"
127
+ "version": "6.14.0"
128
128
  }