@sasjs/api 0.0.0-stage → 0.2.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.
Files changed (49) hide show
  1. package/LICENCE.md +21 -0
  2. package/README.md +87 -2
  3. package/build/browser.js +2469 -0
  4. package/build/cjs/corpus/drive.js +288 -0
  5. package/build/cjs/corpus/runner.js +35 -0
  6. package/build/cjs/drive/memory-store.js +126 -0
  7. package/build/cjs/drive/paths.js +82 -0
  8. package/build/cjs/drive/service.js +143 -0
  9. package/build/cjs/host/dispatch.js +102 -0
  10. package/build/cjs/index.js +58 -0
  11. package/build/cjs/routes/generated.js +1603 -0
  12. package/build/cjs/routes/index.js +111 -0
  13. package/build/cjs/routes/overlay.js +75 -0
  14. package/build/cjs/types.js +35 -0
  15. package/build/esm/corpus/drive.d.ts +33 -0
  16. package/build/esm/corpus/drive.d.ts.map +1 -0
  17. package/build/esm/corpus/drive.js +285 -0
  18. package/build/esm/corpus/runner.d.ts +27 -0
  19. package/build/esm/corpus/runner.d.ts.map +1 -0
  20. package/build/esm/corpus/runner.js +30 -0
  21. package/build/esm/drive/memory-store.d.ts +37 -0
  22. package/build/esm/drive/memory-store.d.ts.map +1 -0
  23. package/build/esm/drive/memory-store.js +122 -0
  24. package/build/esm/drive/paths.d.ts +49 -0
  25. package/build/esm/drive/paths.d.ts.map +1 -0
  26. package/build/esm/drive/paths.js +73 -0
  27. package/build/esm/drive/service.d.ts +42 -0
  28. package/build/esm/drive/service.d.ts.map +1 -0
  29. package/build/esm/drive/service.js +139 -0
  30. package/build/esm/host/dispatch.d.ts +24 -0
  31. package/build/esm/host/dispatch.d.ts.map +1 -0
  32. package/build/esm/host/dispatch.js +98 -0
  33. package/build/esm/index.d.ts +31 -0
  34. package/build/esm/index.d.ts.map +1 -0
  35. package/build/esm/index.js +24 -0
  36. package/build/esm/package.json +3 -0
  37. package/build/esm/routes/generated.d.ts +14 -0
  38. package/build/esm/routes/generated.d.ts.map +1 -0
  39. package/build/esm/routes/generated.js +1600 -0
  40. package/build/esm/routes/index.d.ts +18 -0
  41. package/build/esm/routes/index.d.ts.map +1 -0
  42. package/build/esm/routes/index.js +106 -0
  43. package/build/esm/routes/overlay.d.ts +40 -0
  44. package/build/esm/routes/overlay.d.ts.map +1 -0
  45. package/build/esm/routes/overlay.js +72 -0
  46. package/build/esm/types.d.ts +110 -0
  47. package/build/esm/types.d.ts.map +1 -0
  48. package/build/esm/types.js +30 -0
  49. package/package.json +55 -4
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HANDLED_ROUTES = exports.dispatch = void 0;
4
+ const index_js_1 = require("../routes/index.js");
5
+ const types_js_1 = require("../types.js");
6
+ /**
7
+ * The parameters the table marks required, checked before the handler runs.
8
+ *
9
+ * Multipart fields are deliberately left to the handler: the payload carries the
10
+ * file itself, and the server words a missing one as `"file" is not present.`
11
+ * rather than `"file" is required` - a distinction a client may already key on.
12
+ */
13
+ const validate = (route, request) => {
14
+ for (const param of route.params) {
15
+ if (!param.required || param.in === 'formData' || param.in === 'header')
16
+ continue;
17
+ // a path parameter comes from the matcher, not from the caller's payload, so
18
+ // it is the host's job to have supplied it
19
+ if (param.in === 'path')
20
+ continue;
21
+ const given = param.in === 'query'
22
+ ? request.query?.[param.name]
23
+ : request.body?.[param.name];
24
+ if (given === undefined || given === '')
25
+ throw new types_js_1.ApiError(400, `"${param.name}" is required`);
26
+ }
27
+ };
28
+ /** The drive path a write names: the query parameter wins over the form field. */
29
+ const targetPath = (request) => {
30
+ const fromQuery = request.query?._filePath;
31
+ const fromBody = request.body?.filePath;
32
+ const path = fromQuery !== undefined
33
+ ? String(fromQuery)
34
+ : fromBody;
35
+ // neither given: the server's validation answers for the query parameter
36
+ if (path === undefined)
37
+ throw new types_js_1.ApiError(400, '"_filePath" is required');
38
+ return path;
39
+ };
40
+ const dispatch = async (services, routeId, request = {}) => {
41
+ const route = (0, index_js_1.routeById)(routeId);
42
+ if (!route)
43
+ throw new types_js_1.ApiError(404, `No such operation: ${routeId}`);
44
+ validate(route, request);
45
+ const { drive } = services;
46
+ const query = request.query || {};
47
+ switch (routeId) {
48
+ case 'GET /SASjsApi/drive/file': {
49
+ const file = await drive.read(String(query._filePath || ''));
50
+ return { status: 200, contents: file.contents };
51
+ }
52
+ case 'POST /SASjsApi/drive/file':
53
+ case 'PATCH /SASjsApi/drive/file': {
54
+ if (!request.file)
55
+ throw new types_js_1.ApiError(400, '"file" is not present.');
56
+ const path = targetPath(request);
57
+ const result = routeId === 'PATCH /SASjsApi/drive/file'
58
+ ? await drive.update(path, request.file.contents)
59
+ : await drive.save(path, request.file.contents);
60
+ return { status: 200, body: result };
61
+ }
62
+ case 'DELETE /SASjsApi/drive/file':
63
+ return {
64
+ status: 200,
65
+ body: await drive.remove(String(query._filePath || ''))
66
+ };
67
+ case 'GET /SASjsApi/drive/folder':
68
+ return { status: 200, body: await drive.list(query._folderPath) };
69
+ case 'POST /SASjsApi/drive/folder':
70
+ return {
71
+ status: 200,
72
+ body: await drive.mkdir(String(request.body?.folderPath || ''))
73
+ };
74
+ case 'DELETE /SASjsApi/drive/folder':
75
+ return {
76
+ status: 200,
77
+ body: await drive.rmdir(String(query._folderPath || ''))
78
+ };
79
+ case 'POST /SASjsApi/drive/rename':
80
+ return {
81
+ status: 200,
82
+ body: await drive.rename(String(request.body?.oldPath || ''), String(request.body?.newPath || ''))
83
+ };
84
+ case 'GET /SASjsApi/drive/filetree':
85
+ return { status: 200, body: await drive.tree(query._folderPath) };
86
+ default:
87
+ throw new types_js_1.ApiError(501, `This package has no handler for ${routeId}.`);
88
+ }
89
+ };
90
+ exports.dispatch = dispatch;
91
+ /** Whether a route is one `dispatch` can answer today. */
92
+ exports.HANDLED_ROUTES = [
93
+ 'GET /SASjsApi/drive/file',
94
+ 'POST /SASjsApi/drive/file',
95
+ 'PATCH /SASjsApi/drive/file',
96
+ 'DELETE /SASjsApi/drive/file',
97
+ 'GET /SASjsApi/drive/folder',
98
+ 'POST /SASjsApi/drive/folder',
99
+ 'DELETE /SASjsApi/drive/folder',
100
+ 'POST /SASjsApi/drive/rename',
101
+ 'GET /SASjsApi/drive/filetree'
102
+ ];
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.servicesFor = exports.runCase = exports.DRIVE_CORPUS = exports.HANDLED_ROUTES = exports.dispatch = exports.TAG_CAPABILITIES = exports.OVERLAY = exports.findRoute = exports.routeById = exports.ROUTES = exports.MemoryDriveStore = exports.createDriveService = exports.isRoot = exports.basename = exports.dirname = exports.hasBlockedExtension = exports.normaliseDrivePath = void 0;
18
+ /**
19
+ * `@sasjs/api` - the SASjs Server API described once.
20
+ *
21
+ * The package has three parts, and each is usable on its own:
22
+ *
23
+ * - the route table (`ROUTES`, `findRoute`), generated from sasjs/server's
24
+ * published OpenAPI document and amended by a reviewed overlay;
25
+ * - the services (`createDriveService`), which are the API's decisions over
26
+ * storage a host supplies;
27
+ * - the conformance corpus (`DRIVE_CORPUS`, `runCase`), which is what "the
28
+ * same API" means when a test has to check it.
29
+ *
30
+ * It imports no runtime on purpose: the same build runs in an Express server and
31
+ * in a service worker, so anything node-shaped is a store a host passes in.
32
+ */
33
+ __exportStar(require("./types.js"), exports);
34
+ var paths_js_1 = require("./drive/paths.js");
35
+ Object.defineProperty(exports, "normaliseDrivePath", { enumerable: true, get: function () { return paths_js_1.normaliseDrivePath; } });
36
+ Object.defineProperty(exports, "hasBlockedExtension", { enumerable: true, get: function () { return paths_js_1.hasBlockedExtension; } });
37
+ Object.defineProperty(exports, "dirname", { enumerable: true, get: function () { return paths_js_1.dirname; } });
38
+ Object.defineProperty(exports, "basename", { enumerable: true, get: function () { return paths_js_1.basename; } });
39
+ Object.defineProperty(exports, "isRoot", { enumerable: true, get: function () { return paths_js_1.isRoot; } });
40
+ var service_js_1 = require("./drive/service.js");
41
+ Object.defineProperty(exports, "createDriveService", { enumerable: true, get: function () { return service_js_1.createDriveService; } });
42
+ var memory_store_js_1 = require("./drive/memory-store.js");
43
+ Object.defineProperty(exports, "MemoryDriveStore", { enumerable: true, get: function () { return memory_store_js_1.MemoryDriveStore; } });
44
+ var index_js_1 = require("./routes/index.js");
45
+ Object.defineProperty(exports, "ROUTES", { enumerable: true, get: function () { return index_js_1.ROUTES; } });
46
+ Object.defineProperty(exports, "routeById", { enumerable: true, get: function () { return index_js_1.routeById; } });
47
+ Object.defineProperty(exports, "findRoute", { enumerable: true, get: function () { return index_js_1.findRoute; } });
48
+ var overlay_js_1 = require("./routes/overlay.js");
49
+ Object.defineProperty(exports, "OVERLAY", { enumerable: true, get: function () { return overlay_js_1.OVERLAY; } });
50
+ Object.defineProperty(exports, "TAG_CAPABILITIES", { enumerable: true, get: function () { return overlay_js_1.TAG_CAPABILITIES; } });
51
+ var dispatch_js_1 = require("./host/dispatch.js");
52
+ Object.defineProperty(exports, "dispatch", { enumerable: true, get: function () { return dispatch_js_1.dispatch; } });
53
+ Object.defineProperty(exports, "HANDLED_ROUTES", { enumerable: true, get: function () { return dispatch_js_1.HANDLED_ROUTES; } });
54
+ var drive_js_1 = require("./corpus/drive.js");
55
+ Object.defineProperty(exports, "DRIVE_CORPUS", { enumerable: true, get: function () { return drive_js_1.DRIVE_CORPUS; } });
56
+ var runner_js_1 = require("./corpus/runner.js");
57
+ Object.defineProperty(exports, "runCase", { enumerable: true, get: function () { return runner_js_1.runCase; } });
58
+ Object.defineProperty(exports, "servicesFor", { enumerable: true, get: function () { return runner_js_1.servicesFor; } });