@sasjs/api 0.6.0 → 0.7.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 (40) hide show
  1. package/README.md +3 -2
  2. package/build/browser.js +2231 -118
  3. package/build/cjs/corpus/records.js +1222 -0
  4. package/build/cjs/corpus/runner.js +15 -6
  5. package/build/cjs/drive/deploy.js +49 -10
  6. package/build/cjs/host/dispatch.js +190 -2
  7. package/build/cjs/identity/memory-store.js +196 -11
  8. package/build/cjs/identity/records.js +398 -0
  9. package/build/cjs/index.js +8 -1
  10. package/build/cjs/routes/generated.js +184 -4
  11. package/build/cjs/routes/overlay.js +53 -58
  12. package/build/esm/corpus/records.d.ts +25 -0
  13. package/build/esm/corpus/records.d.ts.map +1 -0
  14. package/build/esm/corpus/records.js +1219 -0
  15. package/build/esm/corpus/runner.d.ts.map +1 -1
  16. package/build/esm/corpus/runner.js +15 -6
  17. package/build/esm/drive/deploy.d.ts +10 -0
  18. package/build/esm/drive/deploy.d.ts.map +1 -1
  19. package/build/esm/drive/deploy.js +48 -9
  20. package/build/esm/host/dispatch.d.ts +9 -0
  21. package/build/esm/host/dispatch.d.ts.map +1 -1
  22. package/build/esm/host/dispatch.js +190 -2
  23. package/build/esm/identity/fixture.d.ts +6 -0
  24. package/build/esm/identity/fixture.d.ts.map +1 -1
  25. package/build/esm/identity/memory-store.d.ts +29 -5
  26. package/build/esm/identity/memory-store.d.ts.map +1 -1
  27. package/build/esm/identity/memory-store.js +196 -11
  28. package/build/esm/identity/records.d.ts +102 -0
  29. package/build/esm/identity/records.d.ts.map +1 -0
  30. package/build/esm/identity/records.js +393 -0
  31. package/build/esm/identity/types.d.ts +102 -2
  32. package/build/esm/identity/types.d.ts.map +1 -1
  33. package/build/esm/index.d.ts +4 -1
  34. package/build/esm/index.d.ts.map +1 -1
  35. package/build/esm/index.js +2 -0
  36. package/build/esm/routes/generated.d.ts.map +1 -1
  37. package/build/esm/routes/generated.js +184 -4
  38. package/build/esm/routes/overlay.d.ts.map +1 -1
  39. package/build/esm/routes/overlay.js +53 -58
  40. package/package.json +1 -1
@@ -142,7 +142,7 @@ export const GENERATED_ROUTES = [
142
142
  },
143
143
  {
144
144
  status: 401,
145
- description: 'The authorization code is invalid, expired, already used, or was issued for another client, or the client id is unknown'
145
+ description: 'The authorization code is invalid, expired, already used, or was issued for another client, or the client id is unknown. This route is unauthenticated, so an unknown client id is a `401` here where `POST /SASLogon/authorize` (which requires a session) answers `403`'
146
146
  }
147
147
  ]
148
148
  },
@@ -236,6 +236,10 @@ export const GENERATED_ROUTES = [
236
236
  {
237
237
  status: 200,
238
238
  description: 'Ok'
239
+ },
240
+ {
241
+ status: 401,
242
+ description: 'Admin account required'
239
243
  }
240
244
  ]
241
245
  },
@@ -276,6 +280,14 @@ export const GENERATED_ROUTES = [
276
280
  {
277
281
  status: 200,
278
282
  description: 'Ok'
283
+ },
284
+ {
285
+ status: 401,
286
+ description: 'Admin account required'
287
+ },
288
+ {
289
+ status: 403,
290
+ description: 'Client ID already exists.'
279
291
  }
280
292
  ]
281
293
  },
@@ -765,7 +777,7 @@ export const GENERATED_ROUTES = [
765
777
  },
766
778
  {
767
779
  status: 409,
768
- description: 'Folder already exists'
780
+ description: 'Folder already exists. The body is that message as plain text.'
769
781
  }
770
782
  ]
771
783
  },
@@ -805,7 +817,7 @@ export const GENERATED_ROUTES = [
805
817
  },
806
818
  {
807
819
  status: 409,
808
- description: 'Something already exists at the new path'
820
+ description: 'Something already exists at the new path. The body is that message as plain text.'
809
821
  }
810
822
  ]
811
823
  },
@@ -855,6 +867,14 @@ export const GENERATED_ROUTES = [
855
867
  {
856
868
  status: 200,
857
869
  description: 'Ok'
870
+ },
871
+ {
872
+ status: 401,
873
+ description: 'Admin account required'
874
+ },
875
+ {
876
+ status: 409,
877
+ description: 'Group name already exists.'
858
878
  }
859
879
  ]
860
880
  },
@@ -883,6 +903,22 @@ export const GENERATED_ROUTES = [
883
903
  {
884
904
  status: 200,
885
905
  description: 'Ok'
906
+ },
907
+ {
908
+ status: 400,
909
+ description: "Can't add/remove user to 'public' group."
910
+ },
911
+ {
912
+ status: 401,
913
+ description: 'Admin account required'
914
+ },
915
+ {
916
+ status: 404,
917
+ description: 'Group not found. / User not found.'
918
+ },
919
+ {
920
+ status: 405,
921
+ description: "Can't add/remove user to group created by external auth provider."
886
922
  }
887
923
  ]
888
924
  },
@@ -911,6 +947,22 @@ export const GENERATED_ROUTES = [
911
947
  {
912
948
  status: 200,
913
949
  description: 'Ok'
950
+ },
951
+ {
952
+ status: 400,
953
+ description: "Can't add/remove user to 'public' group."
954
+ },
955
+ {
956
+ status: 401,
957
+ description: 'Admin account required'
958
+ },
959
+ {
960
+ status: 404,
961
+ description: 'Group not found. / User not found.'
962
+ },
963
+ {
964
+ status: 405,
965
+ description: "Can't add/remove user to group created by external auth provider."
914
966
  }
915
967
  ]
916
968
  },
@@ -933,6 +985,14 @@ export const GENERATED_ROUTES = [
933
985
  {
934
986
  status: 200,
935
987
  description: 'Ok'
988
+ },
989
+ {
990
+ status: 401,
991
+ description: 'Admin account required'
992
+ },
993
+ {
994
+ status: 404,
995
+ description: 'Group not found.'
936
996
  }
937
997
  ]
938
998
  },
@@ -955,6 +1015,10 @@ export const GENERATED_ROUTES = [
955
1015
  {
956
1016
  status: 200,
957
1017
  description: 'Ok'
1018
+ },
1019
+ {
1020
+ status: 404,
1021
+ description: 'Group not found.'
958
1022
  }
959
1023
  ]
960
1024
  },
@@ -977,6 +1041,10 @@ export const GENERATED_ROUTES = [
977
1041
  {
978
1042
  status: 200,
979
1043
  description: 'Ok'
1044
+ },
1045
+ {
1046
+ status: 404,
1047
+ description: 'Group not found.'
980
1048
  }
981
1049
  ]
982
1050
  },
@@ -1037,6 +1105,14 @@ export const GENERATED_ROUTES = [
1037
1105
  {
1038
1106
  status: 200,
1039
1107
  description: 'Ok'
1108
+ },
1109
+ {
1110
+ status: 401,
1111
+ description: 'Admin account required, or no grant on the route'
1112
+ },
1113
+ {
1114
+ status: 404,
1115
+ description: 'User not found.'
1040
1116
  }
1041
1117
  ]
1042
1118
  },
@@ -1083,6 +1159,22 @@ export const GENERATED_ROUTES = [
1083
1159
  {
1084
1160
  status: 200,
1085
1161
  description: 'Ok'
1162
+ },
1163
+ {
1164
+ status: 400,
1165
+ description: 'Can not add permission for admin user. / Invalid principal type. Valid types are user or group.'
1166
+ },
1167
+ {
1168
+ status: 401,
1169
+ description: 'Admin account required'
1170
+ },
1171
+ {
1172
+ status: 404,
1173
+ description: 'User not found. / Group not found.'
1174
+ },
1175
+ {
1176
+ status: 409,
1177
+ description: 'Permission already exists with provided Path, Type and User. / Permission already exists with provided Path, Type and Group.'
1086
1178
  }
1087
1179
  ]
1088
1180
  },
@@ -1105,6 +1197,14 @@ export const GENERATED_ROUTES = [
1105
1197
  {
1106
1198
  status: 204,
1107
1199
  description: 'No content'
1200
+ },
1201
+ {
1202
+ status: 401,
1203
+ description: 'Admin account required'
1204
+ },
1205
+ {
1206
+ status: 404,
1207
+ description: 'Permission not found.'
1108
1208
  }
1109
1209
  ]
1110
1210
  },
@@ -1133,6 +1233,14 @@ export const GENERATED_ROUTES = [
1133
1233
  {
1134
1234
  status: 200,
1135
1235
  description: 'Ok'
1236
+ },
1237
+ {
1238
+ status: 401,
1239
+ description: 'Admin account required'
1240
+ },
1241
+ {
1242
+ status: 404,
1243
+ description: 'Permission not found.'
1136
1244
  }
1137
1245
  ]
1138
1246
  },
@@ -1397,6 +1505,14 @@ export const GENERATED_ROUTES = [
1397
1505
  {
1398
1506
  status: 200,
1399
1507
  description: 'Ok'
1508
+ },
1509
+ {
1510
+ status: 401,
1511
+ description: 'Admin account required'
1512
+ },
1513
+ {
1514
+ status: 409,
1515
+ description: 'Username already exists.'
1400
1516
  }
1401
1517
  ]
1402
1518
  },
@@ -1425,6 +1541,14 @@ export const GENERATED_ROUTES = [
1425
1541
  {
1426
1542
  status: 204,
1427
1543
  description: 'No content'
1544
+ },
1545
+ {
1546
+ status: 401,
1547
+ description: 'Admin account required, or invalid password'
1548
+ },
1549
+ {
1550
+ status: 404,
1551
+ description: 'User is not found.'
1428
1552
  }
1429
1553
  ]
1430
1554
  },
@@ -1447,6 +1571,14 @@ export const GENERATED_ROUTES = [
1447
1571
  {
1448
1572
  status: 200,
1449
1573
  description: 'Ok'
1574
+ },
1575
+ {
1576
+ status: 401,
1577
+ description: 'Unauthorized'
1578
+ },
1579
+ {
1580
+ status: 404,
1581
+ description: 'User is not found.'
1450
1582
  }
1451
1583
  ]
1452
1584
  },
@@ -1505,6 +1637,22 @@ export const GENERATED_ROUTES = [
1505
1637
  {
1506
1638
  status: 200,
1507
1639
  description: 'Ok'
1640
+ },
1641
+ {
1642
+ status: 401,
1643
+ description: 'Admin account required'
1644
+ },
1645
+ {
1646
+ status: 404,
1647
+ description: 'Unable to find user with <id>'
1648
+ },
1649
+ {
1650
+ status: 405,
1651
+ description: 'Can not update username of user that is created by an external auth provider. / Can not update display name of user that is created by an external auth provider.'
1652
+ },
1653
+ {
1654
+ status: 409,
1655
+ description: 'Username already exists.'
1508
1656
  }
1509
1657
  ]
1510
1658
  },
@@ -1533,6 +1681,14 @@ export const GENERATED_ROUTES = [
1533
1681
  {
1534
1682
  status: 204,
1535
1683
  description: 'No content'
1684
+ },
1685
+ {
1686
+ status: 401,
1687
+ description: 'Admin account required, or invalid password'
1688
+ },
1689
+ {
1690
+ status: 404,
1691
+ description: 'User is not found.'
1536
1692
  }
1537
1693
  ]
1538
1694
  },
@@ -1555,6 +1711,14 @@ export const GENERATED_ROUTES = [
1555
1711
  {
1556
1712
  status: 200,
1557
1713
  description: 'Ok'
1714
+ },
1715
+ {
1716
+ status: 401,
1717
+ description: 'Unauthorized'
1718
+ },
1719
+ {
1720
+ status: 404,
1721
+ description: 'User is not found.'
1558
1722
  }
1559
1723
  ]
1560
1724
  },
@@ -1613,6 +1777,22 @@ export const GENERATED_ROUTES = [
1613
1777
  {
1614
1778
  status: 200,
1615
1779
  description: 'Ok'
1780
+ },
1781
+ {
1782
+ status: 401,
1783
+ description: 'Admin account required'
1784
+ },
1785
+ {
1786
+ status: 404,
1787
+ description: 'Unable to find user with <username>'
1788
+ },
1789
+ {
1790
+ status: 405,
1791
+ description: 'Can not update username of user that is created by an external auth provider. / Can not update display name of user that is created by an external auth provider.'
1792
+ },
1793
+ {
1794
+ status: 409,
1795
+ description: 'Username already exists.'
1616
1796
  }
1617
1797
  ]
1618
1798
  },
@@ -1646,7 +1826,7 @@ export const GENERATED_ROUTES = [
1646
1826
  },
1647
1827
  {
1648
1828
  status: 403,
1649
- description: 'The client id is unknown'
1829
+ description: 'The client id is unknown. This route runs under a signed-in session, so the caller is authenticated and an unknown client is refused as forbidden; the unauthenticated `POST /SASjsApi/auth/token` answers `401` for the same condition'
1650
1830
  }
1651
1831
  ]
1652
1832
  },
@@ -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;AAiDD,eAAO,MAAM,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAmOhD,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;AAiDD,eAAO,MAAM,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CA8NhD,CAAA;AAED,wEAAwE;AACxE,eAAO,MAAM,OAAO,EAAE,UAAU,EAA8C,CAAA"}
@@ -22,7 +22,7 @@ export const TAG_CAPABILITIES = {
22
22
  * operation waits on, and thirty copies of the same sentence would say the same
23
23
  * thing thirty times.
24
24
  */
25
- const IDENTITY_RECORDS = 'The identity service answers the sign-in flow. User, group, permission rule, client and provider records need read and write methods on the same store, which this package does not have yet.';
25
+ const DIRECTORY = 'Synchronising with an external auth provider needs a directory port, which this package does not have: a host decides which directory it holds accounts in, and answers this itself.';
26
26
  const EDITOR = 'Linting and formatting come from @sasjs/lint, which this package does not depend on. They land with the code routes so an editor has one wiring.';
27
27
  const RUNTIME = 'Starting a program needs a runtime port, which this package does not have: a host decides which languages it holds, and answers this itself until then.';
28
28
  const SESSION_RECORD = "A triggered session's record, log, output and state belong to the runtime that ran the program, and this package has no runtime port.";
@@ -77,18 +77,20 @@ export const OVERLAY = {
77
77
  },
78
78
  'POST /SASjsApi/auth/logout': { implemented: true },
79
79
  'PATCH /SASjsApi/auth/updatePassword': {
80
- implemented: false,
81
- reason: IDENTITY_RECORDS
80
+ implemented: true,
81
+ // As with the permission list: the document's 404 is a caller whose record
82
+ // has gone, which a host's store can see and this package cannot.
83
+ hostResponses: [404]
82
84
  },
83
85
  // Auth Config - the providers a host was started with, and an LDAP import
84
86
  'GET /SASjsApi/authConfig': { implemented: false, reason: HOST_CONFIG },
85
87
  'POST /SASjsApi/authConfig/synchroniseWithLDAP': {
86
88
  implemented: false,
87
- reason: IDENTITY_RECORDS
89
+ reason: DIRECTORY
88
90
  },
89
91
  // Client - the OAuth clients the identity store already holds for sign-in
90
- 'GET /SASjsApi/client': { implemented: false, reason: IDENTITY_RECORDS },
91
- 'POST /SASjsApi/client': { implemented: false, reason: IDENTITY_RECORDS },
92
+ 'GET /SASjsApi/client': { implemented: true },
93
+ 'POST /SASjsApi/client': { implemented: true },
92
94
  // Code - the editor's three calls, and the runtime one
93
95
  'POST /SASjsApi/code/execute': { implemented: false, reason: RUNTIME },
94
96
  'POST /SASjsApi/code/trigger': { implemented: false, reason: RUNTIME },
@@ -162,25 +164,13 @@ export const OVERLAY = {
162
164
  reason: UNPUBLISH
163
165
  },
164
166
  // Group - members and the groups themselves
165
- 'GET /SASjsApi/group': { implemented: false, reason: IDENTITY_RECORDS },
166
- 'GET /SASjsApi/group/{uid}': { implemented: false, reason: IDENTITY_RECORDS },
167
- 'GET /SASjsApi/group/by/groupname/{name}': {
168
- implemented: false,
169
- reason: IDENTITY_RECORDS
170
- },
171
- 'POST /SASjsApi/group': { implemented: false, reason: IDENTITY_RECORDS },
172
- 'POST /SASjsApi/group/{groupUid}/{userUid}': {
173
- implemented: false,
174
- reason: IDENTITY_RECORDS
175
- },
176
- 'DELETE /SASjsApi/group/{groupUid}/{userUid}': {
177
- implemented: false,
178
- reason: IDENTITY_RECORDS
179
- },
180
- 'DELETE /SASjsApi/group/{uid}': {
181
- implemented: false,
182
- reason: IDENTITY_RECORDS
183
- },
167
+ 'GET /SASjsApi/group': { implemented: true },
168
+ 'GET /SASjsApi/group/{uid}': { implemented: true },
169
+ 'GET /SASjsApi/group/by/groupname/{name}': { implemented: true },
170
+ 'POST /SASjsApi/group': { implemented: true },
171
+ 'POST /SASjsApi/group/{groupUid}/{userUid}': { implemented: true },
172
+ 'DELETE /SASjsApi/group/{groupUid}/{userUid}': { implemented: true },
173
+ 'DELETE /SASjsApi/group/{uid}': { implemented: true },
184
174
  // Info - what the host is, and what this caller may use
185
175
  'GET /SASjsApi/info': { implemented: false, reason: HOST_CONFIG },
186
176
  'GET /SASjsApi/info/authorizedRoutes': {
@@ -196,16 +186,24 @@ export const OVERLAY = {
196
186
  reason: PERMISSIONS
197
187
  },
198
188
  // Permission - the rules the inventory above is derived from
199
- 'GET /SASjsApi/permission': { implemented: false, reason: IDENTITY_RECORDS },
200
- 'POST /SASjsApi/permission': { implemented: false, reason: IDENTITY_RECORDS },
201
- 'PATCH /SASjsApi/permission/{uid}': {
202
- implemented: false,
203
- reason: IDENTITY_RECORDS
204
- },
205
- 'DELETE /SASjsApi/permission/{uid}': {
206
- implemented: false,
207
- reason: IDENTITY_RECORDS
208
- },
189
+ 'GET /SASjsApi/permission': {
190
+ implemented: true,
191
+ // The document states 404 for a caller whose record has gone - a token that
192
+ // outlived its account. Here a token stops resolving when the account does,
193
+ // so this package answers 401 before it gets that far; the host's own store
194
+ // is what can still see the difference.
195
+ hostResponses: [404]
196
+ },
197
+ 'POST /SASjsApi/permission': { implemented: true },
198
+ 'PATCH /SASjsApi/permission/{uid}': { implemented: true },
199
+ // The three deletes answer 204 here and 200 on the wire: the server's route
200
+ // handlers send `res.status(200).send('Account Deleted!')` and
201
+ // `'Permission Deleted!'`, while tsoa emitted 204 for a void handler, so the
202
+ // document understates the status. Correcting it is a decorator in
203
+ // sasjs/server (`@SuccessResponse('200', ...)`), and this package follows the
204
+ // document until that release lands - a local 200 would fail the schema check
205
+ // that keeps this table honest.
206
+ 'DELETE /SASjsApi/permission/{uid}': { implemented: true },
209
207
  // Session - the caller's own session, then the record behind a triggered one
210
208
  'GET /SASjsApi/session': {
211
209
  implemented: true,
@@ -232,29 +230,26 @@ export const OVERLAY = {
232
230
  'POST /SASjsApi/stp/execute': { implemented: false, reason: RUNTIME },
233
231
  'POST /SASjsApi/stp/trigger': { implemented: false, reason: RUNTIME },
234
232
  // User - the accounts the identity store already holds for sign-in
235
- 'GET /SASjsApi/user': { implemented: false, reason: IDENTITY_RECORDS },
236
- 'GET /SASjsApi/user/{uid}': { implemented: false, reason: IDENTITY_RECORDS },
237
- 'GET /SASjsApi/user/by/username/{username}': {
238
- implemented: false,
239
- reason: IDENTITY_RECORDS
240
- },
241
- 'POST /SASjsApi/user': { implemented: false, reason: IDENTITY_RECORDS },
242
- 'PATCH /SASjsApi/user/{uid}': {
243
- implemented: false,
244
- reason: IDENTITY_RECORDS
245
- },
246
- 'PATCH /SASjsApi/user/by/username/{username}': {
247
- implemented: false,
248
- reason: IDENTITY_RECORDS
249
- },
250
- 'DELETE /SASjsApi/user/{uid}': {
251
- implemented: false,
252
- reason: IDENTITY_RECORDS
253
- },
254
- 'DELETE /SASjsApi/user/by/username/{username}': {
255
- implemented: false,
256
- reason: IDENTITY_RECORDS
257
- }
233
+ // Reading accounts is open to any authenticated caller, which is what
234
+ // sasjs/server's routes do (`authenticateAccessToken` only): the document once
235
+ // said `Admin account required` here, and sasjs/server#551 corrected it to
236
+ // `Unauthorized` because that is the refusal a caller actually receives. The
237
+ // breadth is the server's behaviour, copied deliberately - the auto-exec code
238
+ // is the one field withheld from anyone but an administrator or the account
239
+ // itself.
240
+ 'GET /SASjsApi/user': { implemented: true },
241
+ 'GET /SASjsApi/user/{uid}': { implemented: true },
242
+ 'GET /SASjsApi/user/by/username/{username}': { implemented: true },
243
+ 'POST /SASjsApi/user': { implemented: true },
244
+ 'PATCH /SASjsApi/user/{uid}': { implemented: true },
245
+ 'PATCH /SASjsApi/user/by/username/{username}': { implemented: true },
246
+ // The document also marks `password` optional on these deletes, while the
247
+ // server's schema requires it for anyone who is not an administrator, and for
248
+ // an account deleting itself. A host should treat a passwordless delete from a
249
+ // non-admin as the refusal it is; this package answers 401 `Invalid password.`
250
+ // where the server's schema answers 400 `"password" is required`.
251
+ 'DELETE /SASjsApi/user/{uid}': { implemented: true },
252
+ 'DELETE /SASjsApi/user/by/username/{username}': { implemented: true }
258
253
  };
259
254
  /** Every method the table may state, in the order a diff reads best. */
260
255
  export const METHODS = ['GET', 'POST', 'PATCH', 'DELETE', 'PUT'];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sasjs/api",
3
- "version": "0.6.0",
3
+ "version": "0.7.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",