@sasjs/api 0.2.1 → 0.3.1
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/README.md +36 -8
- package/build/browser.js +804 -4
- package/build/cjs/corpus/identity.js +268 -0
- package/build/cjs/corpus/runner.js +11 -2
- package/build/cjs/host/dispatch.js +57 -2
- package/build/cjs/identity/fixture.js +118 -0
- package/build/cjs/identity/memory-store.js +195 -0
- package/build/cjs/identity/service.js +153 -0
- package/build/cjs/identity/types.js +11 -0
- package/build/cjs/index.js +11 -1
- package/build/cjs/routes/generated.js +72 -0
- package/build/cjs/routes/index.js +6 -0
- package/build/cjs/routes/overlay.js +38 -0
- package/build/esm/corpus/drive.d.ts +14 -0
- package/build/esm/corpus/drive.d.ts.map +1 -1
- package/build/esm/corpus/identity.d.ts +17 -0
- package/build/esm/corpus/identity.d.ts.map +1 -0
- package/build/esm/corpus/identity.js +265 -0
- package/build/esm/corpus/runner.d.ts +6 -1
- package/build/esm/corpus/runner.d.ts.map +1 -1
- package/build/esm/corpus/runner.js +11 -2
- package/build/esm/host/dispatch.d.ts +16 -0
- package/build/esm/host/dispatch.d.ts.map +1 -1
- package/build/esm/host/dispatch.js +57 -2
- package/build/esm/identity/fixture.d.ts +84 -0
- package/build/esm/identity/fixture.d.ts.map +1 -0
- package/build/esm/identity/fixture.js +114 -0
- package/build/esm/identity/memory-store.d.ts +61 -0
- package/build/esm/identity/memory-store.d.ts.map +1 -0
- package/build/esm/identity/memory-store.js +191 -0
- package/build/esm/identity/service.d.ts +48 -0
- package/build/esm/identity/service.d.ts.map +1 -0
- package/build/esm/identity/service.js +148 -0
- package/build/esm/identity/types.d.ts +79 -0
- package/build/esm/identity/types.d.ts.map +1 -0
- package/build/esm/identity/types.js +10 -0
- package/build/esm/index.d.ts +7 -0
- package/build/esm/index.d.ts.map +1 -1
- package/build/esm/index.js +4 -0
- package/build/esm/routes/generated.d.ts.map +1 -1
- package/build/esm/routes/generated.js +72 -0
- package/build/esm/routes/index.d.ts.map +1 -1
- package/build/esm/routes/index.js +6 -0
- package/build/esm/routes/overlay.d.ts +9 -0
- package/build/esm/routes/overlay.d.ts.map +1 -1
- package/build/esm/routes/overlay.js +38 -0
- package/build/esm/types.d.ts +11 -0
- package/build/esm/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ The plan that this package implements is tracked in `sasjs/cli#1550`.
|
|
|
9
9
|
|
|
10
10
|
## What is in it
|
|
11
11
|
|
|
12
|
-
**The route table** (`ROUTES`, `findRoute`) is every operation in the API -
|
|
12
|
+
**The route table** (`ROUTES`, `findRoute`) is every operation in the API - 31 paths, 60 operations - derived from `spec/swagger.yaml` by `npm run sync:routes`.
|
|
13
13
|
The statuses come from that document and nowhere else: the overlay cannot add one, and an overlay entry naming a status the document does not state fails the build rather than describing a wish.
|
|
14
14
|
The document cannot say everything a host needs, so the reviewed overlay adds the body each response carries, the capability a route needs, and whether this package implements it.
|
|
15
15
|
Where the document is wrong, it is corrected in `sasjs/server` and re-vendored here - never worked around in the overlay.
|
|
@@ -18,10 +18,10 @@ Where the document is wrong, it is corrected in `sasjs/server` and re-vendored h
|
|
|
18
18
|
|
|
19
19
|
`spec/swagger.yaml` is generated from the controllers in `sasjs/server`. In a checkout of that repository run `npm run swagger` (tsoa), copy `api/public/swagger.yaml` over `spec/swagger.yaml` keeping the header at the top of the file, then run `npm run sync:routes` here. `npm run check:routes` fails if `src/routes/generated.ts` no longer matches the document.
|
|
20
20
|
|
|
21
|
-
**The services** (`createDriveService`) are the API's decisions over storage the host supplies: the statuses, the messages, the order of the checks, and the path rules (including `resolveWithinDrive`'s containment).
|
|
21
|
+
**The services** (`createDriveService`, `createIdentityService`) are the API's decisions over storage the host supplies: the statuses, the messages, the order of the checks, and the path rules (including `resolveWithinDrive`'s containment).
|
|
22
22
|
They are `async`, take a `DriveStore`, and import nothing - so the same code runs under Express and inside a service worker.
|
|
23
23
|
|
|
24
|
-
**The corpus** (`DRIVE_CORPUS`, `runCase`) is what "the same API" means when a test has to check it: each case is a request, the answer a client expects, and the files it starts from.
|
|
24
|
+
**The corpus** (`DRIVE_CORPUS`, `IDENTITY_CORPUS`, `runCase`) is what "the same API" means when a test has to check it: each case is a request, the answer a client expects, and the files it starts from.
|
|
25
25
|
The same cases are meant to run against a live server and against the browser build, so a difference fails a test rather than waiting for a reviewer to notice.
|
|
26
26
|
|
|
27
27
|
## Using it
|
|
@@ -32,16 +32,28 @@ npm install @sasjs/api
|
|
|
32
32
|
|
|
33
33
|
Requires Node `^22.14.0 || >=24.10.0` - the floor the release toolchain needs, and what CI runs.
|
|
34
34
|
|
|
35
|
-
A host supplies a store and,
|
|
36
|
-
In node:
|
|
35
|
+
A host supplies a store and, for the sign-in routes, an identity. `memory-store.ts` ships both memory implementations, so a host with no filesystem and no database has something to start from:
|
|
37
36
|
|
|
38
37
|
```ts
|
|
39
|
-
import {
|
|
38
|
+
import {
|
|
39
|
+
createDriveService,
|
|
40
|
+
createIdentityService,
|
|
41
|
+
MemoryIdentityStore,
|
|
42
|
+
ROUTES,
|
|
43
|
+
findRoute
|
|
44
|
+
} from '@sasjs/api'
|
|
40
45
|
|
|
41
46
|
const drive = createDriveService(nodeDriveStore) // your fs, behind the port
|
|
47
|
+
const identity = createIdentityService(nodeIdentityStore) // your users, tokens
|
|
42
48
|
const match = findRoute('POST', '/SASjsApi/drive/file')
|
|
43
49
|
```
|
|
44
50
|
|
|
51
|
+
An `IdentityStore` is users, clients, token pairs and auth codes, plus the cryptography that names a subject in a token: a server signs JWTs it later verifies against the same secret, a browser build mints opaque strings it can look up. Splitting those two halves would let a host pair one host's minting with another's verification, so they are one port.
|
|
52
|
+
|
|
53
|
+
`MemoryIdentityStore` is a host's identity with no database behind it: it is what a mock build uses, and it is not an identity service. It holds the demo passwords in clear and issues opaque tokens that nothing signs, so every page that shows it says so - a site holding anything real belongs behind a server, not a fixture.
|
|
54
|
+
|
|
55
|
+
`IDENTITY_FORMAT`, `parseIdentity` and `DEFAULT_IDENTITY` describe the fixture a browser build ships - one administrator, one restricted user, two groups, a handful of permission rules and a client - so a mock works with no configuration. `parseIdentity` refuses a fixture it cannot read, by name: another format, a missing collection, no administrator, or a seeded token with only half a pair.
|
|
56
|
+
|
|
45
57
|
In a service worker - the browser build's case - load the bundle the package ships and read it off `self`:
|
|
46
58
|
|
|
47
59
|
```js
|
|
@@ -67,10 +79,24 @@ Both hosts answer with the same shapes:
|
|
|
67
79
|
|
|
68
80
|
## Status
|
|
69
81
|
|
|
70
|
-
Implemented
|
|
71
|
-
|
|
82
|
+
Implemented, exercised by 55 corpus cases:
|
|
83
|
+
|
|
84
|
+
- the nine drive handlers - file read/write/replace/delete, folder read/create/delete, rename, file tree;
|
|
85
|
+
- the seven sign-in handlers - `auth/token`, `auth/refresh`, `auth/logout`, `SASLogon/login`, `SASLogon/authorize`, `SASLogon/logout`, and the session read.
|
|
86
|
+
|
|
87
|
+
Not implemented yet, in the order the plan sets: the rest of identity (`user`, `group`, `permission`, `auth/updatePassword`, `info/authorizedRoutes`), the session record behind `log`/`output`, program execution (`stp`, `code`), `drive/deploy` and its size cap, and the admin routes.
|
|
72
88
|
`src/routes/overlay.ts` is the list: an operation with `implemented: true` has a handler, and everything else answers `501` with its own name.
|
|
73
89
|
|
|
90
|
+
A status the document states but only a host can send - an account lockout (`429`), a provider failure (`500`), a session-store failure - is marked `hostResponses` in the overlay. It stays in the document, because a client still receives it, and is excluded from the parity check, whose other side is what this package answers; the host's own suite pins it.
|
|
91
|
+
|
|
92
|
+
## What a host must do
|
|
93
|
+
|
|
94
|
+
Three of the sign-in flow's defences are the host's, because the package has no request to read and no clock to trust:
|
|
95
|
+
|
|
96
|
+
- **Re-resolve the caller on every request.** A host with its own session passes the subject in (`session`, `authorize`), so the service re-reads the account behind it and refuses a deactivated one; a host that caches the subject it resolved at sign-in defeats that check. `logout` is the exception and does not refuse: dropping a credential is not access, and refusing would leave the pair in the store.
|
|
97
|
+
- **Lock the account out after repeated failures.** `POST /SASLogon/login` answers `401 Username is not found.` for an unknown username and `401 Invalid Password.` for a wrong one, because that is what the server's own form tells a user - which also means the route cannot tell a caller to stop guessing on its own. The defence is the host's limiter, answering `429` with `Retry-After` in seconds; without it the route is a way to enumerate usernames and account state.
|
|
98
|
+
- **Answer a session-store or identity-provider failure with `500`.** Those are the host's own dependencies, and the overlay marks the statuses as `hostResponses`.
|
|
99
|
+
|
|
74
100
|
## Development
|
|
75
101
|
|
|
76
102
|
```bash
|
|
@@ -83,6 +109,8 @@ npm run lint
|
|
|
83
109
|
|
|
84
110
|
Refreshing the API surface: regenerate `api/public/swagger.yaml` in `sasjs/server` (`npm run swagger`), copy it to `spec/swagger.yaml`, and run `npm run sync:routes`. Review the diff - a new operation needs an overlay entry before a host can say whether it implements it.
|
|
85
111
|
|
|
112
|
+
Re-vendoring is a two-repository change and the server half merges first: the document is only true once the controllers it is generated from answer what it states, so a copy taken from an unmerged server branch describes a server that does not exist yet. The current body is the output of `npm run swagger` on sasjs/server#541, which is where the sign-in statuses were added; regenerating before that lands would drop them.
|
|
113
|
+
|
|
86
114
|
## Licence
|
|
87
115
|
|
|
88
116
|
MIT. See `LICENCE.md`.
|