@sasjs/api 0.12.0 → 0.13.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/browser.js CHANGED
@@ -1,4 +1,4 @@
1
- /* @sasjs/api 0.12.0 - the SASjs Server API, for a service worker. https://github.com/sasjs/api */
1
+ /* @sasjs/api 0.13.0 - the SASjs Server API, for a service worker. https://github.com/sasjs/api */
2
2
  "use strict";
3
3
  var SASjsApi = (() => {
4
4
  var __defProp = Object.defineProperty;
@@ -2514,7 +2514,6 @@ var SASjsApi = (() => {
2514
2514
  var HOST_CONFIG = "The body is the host's own configuration - ports, run times and providers - which a mock states for itself and this package cannot know.";
2515
2515
  var HOST_OWNED = "The host owns this report: it describes the host's own process and files, which a browser build has no equivalent of.";
2516
2516
  var WEB_BUNDLE = "The host serves its own web bundle; there is no API decision here for this package to answer.";
2517
- var ARCHIVE = "Expanding the uploaded archive is the host's transport work - multer and a zip library on the server, `DecompressionStream` in a worker - and the host hands this package the tree it produces, which is the same tree `POST /SASjsApi/drive/deploy` takes.";
2518
2517
  var success = { status: "success" };
2519
2518
  var user = {
2520
2519
  uid: "",
@@ -2642,10 +2641,7 @@ var SASjsApi = (() => {
2642
2641
  500: { status: "failure", message: "Deployment failed!" }
2643
2642
  }
2644
2643
  },
2645
- "POST /SASjsApi/drive/deploy/upload": {
2646
- implemented: false,
2647
- reason: ARCHIVE
2648
- },
2644
+ "POST /SASjsApi/drive/deploy/upload": { implemented: true },
2649
2645
  // `404` is a pair - the registry name and the appLoc it was published from -
2650
2646
  // that matches no entry, and the drive's content is deliberately left alone.
2651
2647
  "DELETE /SASjsApi/drive/deploy": { implemented: true },
@@ -2966,6 +2962,11 @@ var SASjsApi = (() => {
2966
2962
  String(request.body?.newPath || "")
2967
2963
  )
2968
2964
  };
2965
+ // The archive is the host's transport - multer and a zip library on a
2966
+ // server, `DecompressionStream` in a worker - and it hands this the same tree
2967
+ // `POST /deploy` takes. The deploy cap is measured on that tree, after
2968
+ // expansion, which is why the two share this path rather than reading bytes.
2969
+ case "POST /SASjsApi/drive/deploy/upload":
2969
2970
  case "POST /SASjsApi/drive/deploy": {
2970
2971
  await drive.deploy(String(body.appLoc ?? ""), body.fileTree);
2971
2972
  return { status: 200, body: DEPLOY_SUCCESS };
@@ -3234,6 +3235,7 @@ var SASjsApi = (() => {
3234
3235
  }
3235
3236
  };
3236
3237
  var HANDLED_ROUTES = [
3238
+ "POST /SASjsApi/drive/deploy/upload",
3237
3239
  "DELETE /SASjsApi/drive/deploy",
3238
3240
  "GET /SASjsApi/session/{sessionId}",
3239
3241
  "GET /SASjsApi/session/{sessionId}/log",
@@ -4958,6 +4960,11 @@ var SASjsApi = (() => {
4958
4960
 
4959
4961
  // src/corpus/deploy.ts
4960
4962
  var SUBJECT = { userId: "user-admin", clientId: "web_app" };
4963
+ var manyMembers2 = (count) => Array.from({ length: count }, (_, at) => ({
4964
+ name: `file-${at}.txt`,
4965
+ type: "file",
4966
+ code: ""
4967
+ }));
4961
4968
  var DEPLOY_CORPUS = [
4962
4969
  {
4963
4970
  id: "deploy-unpublish",
@@ -5002,6 +5009,89 @@ var SASjsApi = (() => {
5002
5009
  body: { streamServiceName: "myApp", appLoc: "/Public/not-an-app" }
5003
5010
  },
5004
5011
  expect: { status: 404, error: "No such app stream entry." }
5012
+ },
5013
+ // ------------------------------------------- the uploaded-archive route
5014
+ // The archive is expanded by the host, so what arrives here is the same tree
5015
+ // `POST /deploy` takes - which is why every answer below matches its twin.
5016
+ {
5017
+ id: "upload-tree",
5018
+ route: "POST /SASjsApi/drive/deploy/upload",
5019
+ description: "writes the tree an uploaded archive expanded to",
5020
+ request: {
5021
+ subject: SUBJECT,
5022
+ body: {
5023
+ appLoc: "/Public/apps/uploaded",
5024
+ fileTree: {
5025
+ members: [
5026
+ { name: "index.html", type: "file", code: "PGgxPkhlbGxvPC9oMT4=" }
5027
+ ]
5028
+ }
5029
+ }
5030
+ },
5031
+ expect: {
5032
+ status: 200,
5033
+ body: {
5034
+ status: "success",
5035
+ message: "Files deployed successfully to @sasjs/server."
5036
+ }
5037
+ }
5038
+ },
5039
+ {
5040
+ id: "upload-refused-by-shape",
5041
+ route: "POST /SASjsApi/drive/deploy/upload",
5042
+ description: "refuses an expansion that is not a tree",
5043
+ request: {
5044
+ subject: SUBJECT,
5045
+ body: { appLoc: "/Public/apps/bad", fileTree: { members: 1 } }
5046
+ },
5047
+ expect: {
5048
+ status: 400,
5049
+ body: {
5050
+ status: "failure",
5051
+ message: "Provided not supported data format."
5052
+ },
5053
+ error: "Provided not supported data format."
5054
+ }
5055
+ },
5056
+ {
5057
+ id: "upload-refused-by-entry-count",
5058
+ route: "POST /SASjsApi/drive/deploy/upload",
5059
+ description: "applies the deploy cap to the expanded tree, not the bytes",
5060
+ request: {
5061
+ subject: SUBJECT,
5062
+ body: {
5063
+ appLoc: "/Public/apps/many",
5064
+ fileTree: { members: manyMembers2(10001) }
5065
+ }
5066
+ },
5067
+ expect: {
5068
+ status: 413,
5069
+ body: {
5070
+ status: "failure",
5071
+ message: "The file tree exceeds the deploy limit: 10001 entries (maximum 10000)."
5072
+ },
5073
+ error: "The file tree exceeds the deploy limit: 10001 entries (maximum 10000)."
5074
+ }
5075
+ },
5076
+ {
5077
+ id: "upload-refused-by-store",
5078
+ route: "POST /SASjsApi/drive/deploy/upload",
5079
+ description: "answers the routes 500 when the drive refuses the write",
5080
+ unwritable: true,
5081
+ request: {
5082
+ subject: SUBJECT,
5083
+ body: {
5084
+ appLoc: "/Public/apps/demo",
5085
+ fileTree: {
5086
+ members: [{ name: "run", type: "service", code: "%put hi;" }]
5087
+ }
5088
+ }
5089
+ },
5090
+ expect: {
5091
+ status: 500,
5092
+ body: { status: "failure", message: "Deployment failed!" },
5093
+ error: "Deployment failed!"
5094
+ }
5005
5095
  }
5006
5096
  ];
5007
5097
 
@@ -2,6 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DEPLOY_CORPUS = void 0;
4
4
  const SUBJECT = { userId: 'user-admin', clientId: 'web_app' };
5
+ /** A tree of `count` file members, for the deploy cap. */
6
+ const manyMembers = (count) => Array.from({ length: count }, (_, at) => ({
7
+ name: `file-${at}.txt`,
8
+ type: 'file',
9
+ code: ''
10
+ }));
5
11
  exports.DEPLOY_CORPUS = [
6
12
  {
7
13
  id: 'deploy-unpublish',
@@ -46,5 +52,88 @@ exports.DEPLOY_CORPUS = [
46
52
  body: { streamServiceName: 'myApp', appLoc: '/Public/not-an-app' }
47
53
  },
48
54
  expect: { status: 404, error: 'No such app stream entry.' }
55
+ },
56
+ // ------------------------------------------- the uploaded-archive route
57
+ // The archive is expanded by the host, so what arrives here is the same tree
58
+ // `POST /deploy` takes - which is why every answer below matches its twin.
59
+ {
60
+ id: 'upload-tree',
61
+ route: 'POST /SASjsApi/drive/deploy/upload',
62
+ description: 'writes the tree an uploaded archive expanded to',
63
+ request: {
64
+ subject: SUBJECT,
65
+ body: {
66
+ appLoc: '/Public/apps/uploaded',
67
+ fileTree: {
68
+ members: [
69
+ { name: 'index.html', type: 'file', code: 'PGgxPkhlbGxvPC9oMT4=' }
70
+ ]
71
+ }
72
+ }
73
+ },
74
+ expect: {
75
+ status: 200,
76
+ body: {
77
+ status: 'success',
78
+ message: 'Files deployed successfully to @sasjs/server.'
79
+ }
80
+ }
81
+ },
82
+ {
83
+ id: 'upload-refused-by-shape',
84
+ route: 'POST /SASjsApi/drive/deploy/upload',
85
+ description: 'refuses an expansion that is not a tree',
86
+ request: {
87
+ subject: SUBJECT,
88
+ body: { appLoc: '/Public/apps/bad', fileTree: { members: 1 } }
89
+ },
90
+ expect: {
91
+ status: 400,
92
+ body: {
93
+ status: 'failure',
94
+ message: 'Provided not supported data format.'
95
+ },
96
+ error: 'Provided not supported data format.'
97
+ }
98
+ },
99
+ {
100
+ id: 'upload-refused-by-entry-count',
101
+ route: 'POST /SASjsApi/drive/deploy/upload',
102
+ description: 'applies the deploy cap to the expanded tree, not the bytes',
103
+ request: {
104
+ subject: SUBJECT,
105
+ body: {
106
+ appLoc: '/Public/apps/many',
107
+ fileTree: { members: manyMembers(10001) }
108
+ }
109
+ },
110
+ expect: {
111
+ status: 413,
112
+ body: {
113
+ status: 'failure',
114
+ message: 'The file tree exceeds the deploy limit: 10001 entries (maximum 10000).'
115
+ },
116
+ error: 'The file tree exceeds the deploy limit: 10001 entries (maximum 10000).'
117
+ }
118
+ },
119
+ {
120
+ id: 'upload-refused-by-store',
121
+ route: 'POST /SASjsApi/drive/deploy/upload',
122
+ description: 'answers the routes 500 when the drive refuses the write',
123
+ unwritable: true,
124
+ request: {
125
+ subject: SUBJECT,
126
+ body: {
127
+ appLoc: '/Public/apps/demo',
128
+ fileTree: {
129
+ members: [{ name: 'run', type: 'service', code: '%put hi;' }]
130
+ }
131
+ }
132
+ },
133
+ expect: {
134
+ status: 500,
135
+ body: { status: 'failure', message: 'Deployment failed!' },
136
+ error: 'Deployment failed!'
137
+ }
49
138
  }
50
139
  ];
@@ -170,6 +170,11 @@ const dispatch = async (services, routeId, request = {}) => {
170
170
  status: 200,
171
171
  body: await drive.rename(String(request.body?.oldPath || ''), String(request.body?.newPath || ''))
172
172
  };
173
+ // The archive is the host's transport - multer and a zip library on a
174
+ // server, `DecompressionStream` in a worker - and it hands this the same tree
175
+ // `POST /deploy` takes. The deploy cap is measured on that tree, after
176
+ // expansion, which is why the two share this path rather than reading bytes.
177
+ case 'POST /SASjsApi/drive/deploy/upload':
173
178
  case 'POST /SASjsApi/drive/deploy': {
174
179
  // `streamWebFolder` is the host's: publishing an app stream is not a drive
175
180
  // operation, and a host that has no app stream ignores it.
@@ -396,6 +401,7 @@ const dispatch = async (services, routeId, request = {}) => {
396
401
  exports.dispatch = dispatch;
397
402
  /** Whether a route is one `dispatch` can answer today. */
398
403
  exports.HANDLED_ROUTES = [
404
+ 'POST /SASjsApi/drive/deploy/upload',
399
405
  'DELETE /SASjsApi/drive/deploy',
400
406
  'GET /SASjsApi/session/{sessionId}',
401
407
  'GET /SASjsApi/session/{sessionId}/log',
@@ -30,7 +30,6 @@ const RUNTIME = 'Starting a program needs a runtime port, which this package doe
30
30
  const HOST_CONFIG = "The body is the host's own configuration - ports, run times and providers - which a mock states for itself and this package cannot know.";
31
31
  const HOST_OWNED = "The host owns this report: it describes the host's own process and files, which a browser build has no equivalent of.";
32
32
  const WEB_BUNDLE = 'The host serves its own web bundle; there is no API decision here for this package to answer.';
33
- const ARCHIVE = "Expanding the uploaded archive is the host's transport work - multer and a zip library on the server, `DecompressionStream` in a worker - and the host hands this package the tree it produces, which is the same tree `POST /SASjsApi/drive/deploy` takes.";
34
33
  const success = { status: 'success' };
35
34
  const user = {
36
35
  uid: '',
@@ -158,10 +157,7 @@ exports.OVERLAY = {
158
157
  500: { status: 'failure', message: 'Deployment failed!' }
159
158
  }
160
159
  },
161
- 'POST /SASjsApi/drive/deploy/upload': {
162
- implemented: false,
163
- reason: ARCHIVE
164
- },
160
+ 'POST /SASjsApi/drive/deploy/upload': { implemented: true },
165
161
  // `404` is a pair - the registry name and the appLoc it was published from -
166
162
  // that matches no entry, and the drive's content is deliberately left alone.
167
163
  'DELETE /SASjsApi/drive/deploy': { implemented: true },
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../../src/corpus/deploy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAI5C,eAAO,MAAM,aAAa,EAAE,UAAU,EA6CrC,CAAA"}
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../../src/corpus/deploy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAW5C,eAAO,MAAM,aAAa,EAAE,UAAU,EAmIrC,CAAA"}
@@ -1,4 +1,10 @@
1
1
  const SUBJECT = { userId: 'user-admin', clientId: 'web_app' };
2
+ /** A tree of `count` file members, for the deploy cap. */
3
+ const manyMembers = (count) => Array.from({ length: count }, (_, at) => ({
4
+ name: `file-${at}.txt`,
5
+ type: 'file',
6
+ code: ''
7
+ }));
2
8
  export const DEPLOY_CORPUS = [
3
9
  {
4
10
  id: 'deploy-unpublish',
@@ -43,5 +49,88 @@ export const DEPLOY_CORPUS = [
43
49
  body: { streamServiceName: 'myApp', appLoc: '/Public/not-an-app' }
44
50
  },
45
51
  expect: { status: 404, error: 'No such app stream entry.' }
52
+ },
53
+ // ------------------------------------------- the uploaded-archive route
54
+ // The archive is expanded by the host, so what arrives here is the same tree
55
+ // `POST /deploy` takes - which is why every answer below matches its twin.
56
+ {
57
+ id: 'upload-tree',
58
+ route: 'POST /SASjsApi/drive/deploy/upload',
59
+ description: 'writes the tree an uploaded archive expanded to',
60
+ request: {
61
+ subject: SUBJECT,
62
+ body: {
63
+ appLoc: '/Public/apps/uploaded',
64
+ fileTree: {
65
+ members: [
66
+ { name: 'index.html', type: 'file', code: 'PGgxPkhlbGxvPC9oMT4=' }
67
+ ]
68
+ }
69
+ }
70
+ },
71
+ expect: {
72
+ status: 200,
73
+ body: {
74
+ status: 'success',
75
+ message: 'Files deployed successfully to @sasjs/server.'
76
+ }
77
+ }
78
+ },
79
+ {
80
+ id: 'upload-refused-by-shape',
81
+ route: 'POST /SASjsApi/drive/deploy/upload',
82
+ description: 'refuses an expansion that is not a tree',
83
+ request: {
84
+ subject: SUBJECT,
85
+ body: { appLoc: '/Public/apps/bad', fileTree: { members: 1 } }
86
+ },
87
+ expect: {
88
+ status: 400,
89
+ body: {
90
+ status: 'failure',
91
+ message: 'Provided not supported data format.'
92
+ },
93
+ error: 'Provided not supported data format.'
94
+ }
95
+ },
96
+ {
97
+ id: 'upload-refused-by-entry-count',
98
+ route: 'POST /SASjsApi/drive/deploy/upload',
99
+ description: 'applies the deploy cap to the expanded tree, not the bytes',
100
+ request: {
101
+ subject: SUBJECT,
102
+ body: {
103
+ appLoc: '/Public/apps/many',
104
+ fileTree: { members: manyMembers(10001) }
105
+ }
106
+ },
107
+ expect: {
108
+ status: 413,
109
+ body: {
110
+ status: 'failure',
111
+ message: 'The file tree exceeds the deploy limit: 10001 entries (maximum 10000).'
112
+ },
113
+ error: 'The file tree exceeds the deploy limit: 10001 entries (maximum 10000).'
114
+ }
115
+ },
116
+ {
117
+ id: 'upload-refused-by-store',
118
+ route: 'POST /SASjsApi/drive/deploy/upload',
119
+ description: 'answers the routes 500 when the drive refuses the write',
120
+ unwritable: true,
121
+ request: {
122
+ subject: SUBJECT,
123
+ body: {
124
+ appLoc: '/Public/apps/demo',
125
+ fileTree: {
126
+ members: [{ name: 'run', type: 'service', code: '%put hi;' }]
127
+ }
128
+ }
129
+ },
130
+ expect: {
131
+ status: 500,
132
+ body: { status: 'failure', message: 'Deployment failed!' },
133
+ error: 'Deployment failed!'
134
+ }
46
135
  }
47
136
  ];
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../../src/host/dispatch.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAE7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AAOnD,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,oFAAoF;IACpF,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAAA;KAAE,CAAA;IACtD;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iEAAiE;IACjE,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,mBAAmB;IACnB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,GAAG,UAAU,CAAA;CAC/B;AAED,MAAM,WAAW,QAAQ;IACvB,2DAA2D;IAC3D,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,KAAK,EAAE,YAAY,CAAA;IACnB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,eAAe,CAAA;IAC1B,yFAAyF;IACzF,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB;;;OAGG;IACH,OAAO,CAAC,EAAE,cAAc,CAAA;IACxB;;;OAGG;IACH,QAAQ,CAAC,EAAE,iBAAiB,CAAA;CAC7B;AA2CD,eAAO,MAAM,QAAQ,GACnB,UAAU,QAAQ,EAClB,SAAS,MAAM,EACf,UAAS,UAAe,KACvB,OAAO,CAAC,WAAW,CAycrB,CAAA;AAED,0DAA0D;AAC1D,eAAO,MAAM,cAAc,EAAE,MAAM,EAiDlC,CAAA"}
1
+ {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../../src/host/dispatch.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAE7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AAOnD,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,oFAAoF;IACpF,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAAA;KAAE,CAAA;IACtD;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iEAAiE;IACjE,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,mBAAmB;IACnB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,GAAG,UAAU,CAAA;CAC/B;AAED,MAAM,WAAW,QAAQ;IACvB,2DAA2D;IAC3D,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,KAAK,EAAE,YAAY,CAAA;IACnB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,eAAe,CAAA;IAC1B,yFAAyF;IACzF,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB;;;OAGG;IACH,OAAO,CAAC,EAAE,cAAc,CAAA;IACxB;;;OAGG;IACH,QAAQ,CAAC,EAAE,iBAAiB,CAAA;CAC7B;AA2CD,eAAO,MAAM,QAAQ,GACnB,UAAU,QAAQ,EAClB,SAAS,MAAM,EACf,UAAS,UAAe,KACvB,OAAO,CAAC,WAAW,CA8crB,CAAA;AAED,0DAA0D;AAC1D,eAAO,MAAM,cAAc,EAAE,MAAM,EAkDlC,CAAA"}
@@ -167,6 +167,11 @@ export const dispatch = async (services, routeId, request = {}) => {
167
167
  status: 200,
168
168
  body: await drive.rename(String(request.body?.oldPath || ''), String(request.body?.newPath || ''))
169
169
  };
170
+ // The archive is the host's transport - multer and a zip library on a
171
+ // server, `DecompressionStream` in a worker - and it hands this the same tree
172
+ // `POST /deploy` takes. The deploy cap is measured on that tree, after
173
+ // expansion, which is why the two share this path rather than reading bytes.
174
+ case 'POST /SASjsApi/drive/deploy/upload':
170
175
  case 'POST /SASjsApi/drive/deploy': {
171
176
  // `streamWebFolder` is the host's: publishing an app stream is not a drive
172
177
  // operation, and a host that has no app stream ignores it.
@@ -392,6 +397,7 @@ export const dispatch = async (services, routeId, request = {}) => {
392
397
  };
393
398
  /** Whether a route is one `dispatch` can answer today. */
394
399
  export const HANDLED_ROUTES = [
400
+ 'POST /SASjsApi/drive/deploy/upload',
395
401
  'DELETE /SASjsApi/drive/deploy',
396
402
  'GET /SASjsApi/session/{sessionId}',
397
403
  'GET /SASjsApi/session/{sessionId}/log',
@@ -1 +1 @@
1
- {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../../src/routes/overlay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAGzD,yDAAyD;AACzD,UAAU,aAAa;IACrB,YAAY,CAAC,EAAE,UAAU,EAAE,CAAA;IAC3B;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACpC;AAED;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG,aAAa,GACtC,CAAC;IAAE,WAAW,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,WAAW,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AAElE,kFAAkF;AAClF,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,CAczD,CAAA;AAqCD,eAAO,MAAM,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CA6MhD,CAAA;AAED,wEAAwE;AACxE,eAAO,MAAM,OAAO,EAAE,UAAU,EAA8C,CAAA"}
1
+ {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../../src/routes/overlay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAGzD,yDAAyD;AACzD,UAAU,aAAa;IACrB,YAAY,CAAC,EAAE,UAAU,EAAE,CAAA;IAC3B;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACpC;AAED;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG,aAAa,GACtC,CAAC;IAAE,WAAW,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,WAAW,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AAElE,kFAAkF;AAClF,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,CAczD,CAAA;AAkCD,eAAO,MAAM,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CA0MhD,CAAA;AAED,wEAAwE;AACxE,eAAO,MAAM,OAAO,EAAE,UAAU,EAA8C,CAAA"}
@@ -27,7 +27,6 @@ const RUNTIME = 'Starting a program needs a runtime port, which this package doe
27
27
  const HOST_CONFIG = "The body is the host's own configuration - ports, run times and providers - which a mock states for itself and this package cannot know.";
28
28
  const HOST_OWNED = "The host owns this report: it describes the host's own process and files, which a browser build has no equivalent of.";
29
29
  const WEB_BUNDLE = 'The host serves its own web bundle; there is no API decision here for this package to answer.';
30
- const ARCHIVE = "Expanding the uploaded archive is the host's transport work - multer and a zip library on the server, `DecompressionStream` in a worker - and the host hands this package the tree it produces, which is the same tree `POST /SASjsApi/drive/deploy` takes.";
31
30
  const success = { status: 'success' };
32
31
  const user = {
33
32
  uid: '',
@@ -155,10 +154,7 @@ export const OVERLAY = {
155
154
  500: { status: 'failure', message: 'Deployment failed!' }
156
155
  }
157
156
  },
158
- 'POST /SASjsApi/drive/deploy/upload': {
159
- implemented: false,
160
- reason: ARCHIVE
161
- },
157
+ 'POST /SASjsApi/drive/deploy/upload': { implemented: true },
162
158
  // `404` is a pair - the registry name and the appLoc it was published from -
163
159
  // that matches no entry, and the drive's content is deliberately left alone.
164
160
  'DELETE /SASjsApi/drive/deploy': { implemented: true },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sasjs/api",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "The SASjs Server API, described once - a generated route table, the services behind it, and the conformance corpus both hosts run",
5
5
  "license": "MIT",
6
6
  "author": "SASjs",