@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.
- package/build/commands/build/internal/mockSite/assets/sw.js +15 -4
- package/build/commands/build/internal/mockSite/mockSite.js +8 -0
- package/build/commands/build/internal/mockSite/spec/mockSite.spec.js +17 -0
- package/build/commands/build/internal/mockSite/spec/sw.spec.js +58 -3
- package/package.json +3 -3
|
@@ -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: '
|
|
328
|
-
|
|
329
|
-
|
|
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 {
|
|
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
|
-
|
|
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.
|
|
74
|
+
"@sasjs/api": "0.23.0",
|
|
75
75
|
"@sasjs/core": "6.1.1",
|
|
76
|
-
"@sasjs/lint": "5.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.
|
|
127
|
+
"version": "6.14.0"
|
|
128
128
|
}
|