@sovereignfs/sdk 1.25.0 → 2.0.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/LICENSE +373 -661
- package/README.md +97 -0
- package/dist/browser.d.ts +2 -0
- package/dist/browser.js +4 -0
- package/dist/chunk-NYL4LLXF.js +65 -0
- package/dist/index.d.ts +57 -529
- package/dist/index.js +1283 -572
- package/dist/next.d.ts +37 -0
- package/dist/next.js +68 -0
- package/dist/session-DJl2XYMc.d.ts +44 -0
- package/dist/sovereign-CazGKEVc.d.ts +517 -0
- package/dist/testing.d.ts +181 -0
- package/dist/testing.js +560 -0
- package/package.json +53 -27
- package/dist/chunk-MLKGABMK.js +0 -9
- package/dist/chunk-NQLGPAL6.js +0 -62
- package/dist/e2ee-crypto.d.ts +0 -84
- package/dist/e2ee-crypto.js +0 -162
- package/dist/e2ee-device.d.ts +0 -21
- package/dist/e2ee-device.js +0 -13
- package/dist/e2ee-object.d.ts +0 -50
- package/dist/e2ee-object.js +0 -75
- package/dist/e2ee-state-U-GEJ7oL.d.ts +0 -411
- package/dist/e2ee-state.d.ts +0 -1
- package/dist/e2ee-state.js +0 -36
- package/src/__tests__/e2ee-crypto.test.ts +0 -156
- package/src/__tests__/e2ee-object.test.ts +0 -90
- package/src/__tests__/e2ee-state.test.ts +0 -83
- package/src/__tests__/sdk.test.ts +0 -427
- package/src/__tests__/sessions.test.ts +0 -63
- package/src/activity.ts +0 -19
- package/src/auth.ts +0 -134
- package/src/connections.ts +0 -106
- package/src/data.ts +0 -88
- package/src/db.ts +0 -34
- package/src/directory.ts +0 -31
- package/src/e2ee-crypto.ts +0 -260
- package/src/e2ee-device.ts +0 -75
- package/src/e2ee-object.ts +0 -118
- package/src/e2ee-state.ts +0 -72
- package/src/e2ee.ts +0 -65
- package/src/env.ts +0 -37
- package/src/errors.ts +0 -46
- package/src/host.ts +0 -251
- package/src/index.ts +0 -160
- package/src/mailer.ts +0 -7
- package/src/notifications.ts +0 -36
- package/src/platform.ts +0 -10
- package/src/plugins.ts +0 -146
- package/src/portability.ts +0 -176
- package/src/secrets.ts +0 -68
- package/src/sessions.ts +0 -36
- package/src/storage.ts +0 -49
- package/src/types.ts +0 -418
- package/src/unimplemented.ts +0 -48
package/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# @sovereignfs/sdk
|
|
2
|
+
|
|
3
|
+
How a JavaScript app's **server** talks to the Sovereign server it signs people in with. It wraps the generated
|
|
4
|
+
[`@sovereignfs/api-client`](../api-client) with what is tedious to do by hand: tokens, failure, and version support. What it
|
|
5
|
+
promises is in [`docs/specs/sdk.md`](../../docs/specs/sdk.md); the contract it never goes beyond is
|
|
6
|
+
[`spec/core-api/openapi.yaml`](../../spec/core-api/openapi.yaml).
|
|
7
|
+
|
|
8
|
+
> Not published yet.
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { createSovereign } from '@sovereignfs/sdk';
|
|
12
|
+
|
|
13
|
+
// Reads NOTES_URL, NOTES_CORE_URL, NOTES_CORE_CLIENT_ID and NOTES_CORE_CLIENT_SECRET (or its _FILE form).
|
|
14
|
+
// Makes no network call, so the app starts while core is down.
|
|
15
|
+
export const sv = createSovereign({ prefix: 'NOTES', tokenStore });
|
|
16
|
+
|
|
17
|
+
const { users } = await sv.as(person).directory.searchUsers({ q: 'ada' }); // as a person
|
|
18
|
+
const branding = await sv.instance.getBranding(); // public, so no actor
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
- **Actors.** Every call names who it is made as: `sv.as(person)`, `sv.app`, or `sv.instance` for public calls. A method exists
|
|
22
|
+
only on an actor that can use it, and the SDK never falls back from one to another.
|
|
23
|
+
- **Tokens.** An app never handles an access token. Access tokens are cached in memory until 30 seconds before they expire. A
|
|
24
|
+
person's refresh token is kept in a **token store** the app gives (`read`, and a conditional `write`); core rotates it on every
|
|
25
|
+
use and takes one used twice for theft, so refreshes run one at a time for each person, and an app that runs more than one
|
|
26
|
+
process gives its store a `lock`.
|
|
27
|
+
- **Failure.** Every call can fail, as one of `CoreApiError`, `CoreUnavailableError`, `SessionEndedError`, `NotSupportedError` or
|
|
28
|
+
`ConfigurationError`. Requests time out (5 seconds), safe ones are retried, and nothing logs a token or a person's details.
|
|
29
|
+
- **Version support.** The SDK reads the instance document and raises `NotSupportedError` for a capability this core lacks,
|
|
30
|
+
without sending the call.
|
|
31
|
+
- **Signing in.** `sv.auth` signs people in through core with [`openid-client`](https://github.com/panva/openid-client) (PKCE `S256`,
|
|
32
|
+
`state`, `nonce`), keeps the sessions in a **session store** the app gives, and ends them on sign-out and on core's back-channel
|
|
33
|
+
logout notice, which it verifies (signature, issuer, audience, age, event, `jti`, and no `nonce`). The session cookie is host-only
|
|
34
|
+
(`__Host-`, `Secure`, `HttpOnly`) over https. `getSession` makes no call to core.
|
|
35
|
+
- **Server only.** Importing it in a browser throws.
|
|
36
|
+
|
|
37
|
+
## In Next.js
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
// app/auth/[action]/route.ts: /auth/login, /auth/callback, /auth/logout (POST) and /auth/backchannel-logout (POST)
|
|
41
|
+
import { nextAuth } from '@sovereignfs/sdk/next';
|
|
42
|
+
export const { GET, POST } = nextAuth(sv).handlers;
|
|
43
|
+
|
|
44
|
+
// A Server Component:
|
|
45
|
+
const session = await nextAuth(sv).requireSession('/notes'); // sends a person to sign in, and back
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Register `https://notes.example.test/auth/callback` as the app's sign-in address, `https://notes.example.test/` as its address after
|
|
49
|
+
sign-out, and `https://notes.example.test/auth/backchannel-logout` as its back-channel logout address. `next` is an optional peer
|
|
50
|
+
dependency, and nothing outside `/next` needs it.
|
|
51
|
+
|
|
52
|
+
## Testing an app
|
|
53
|
+
|
|
54
|
+
`@sovereignfs/sdk/testing` is a core that needs no server:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { createFakeCore } from '@sovereignfs/sdk/testing';
|
|
58
|
+
|
|
59
|
+
const core = createFakeCore();
|
|
60
|
+
core.addPerson({ sub: 'u1', name: 'Ada Lovelace' });
|
|
61
|
+
const sv = createSovereign({
|
|
62
|
+
appUrl: 'https://notes.example.test',
|
|
63
|
+
coreUrl: core.url,
|
|
64
|
+
...core.credentials,
|
|
65
|
+
tokenStore,
|
|
66
|
+
fetch: core.fetch,
|
|
67
|
+
});
|
|
68
|
+
await tokenStore.write('u1', core.signIn('u1'), undefined);
|
|
69
|
+
|
|
70
|
+
core.fail({ kind: 'down' }); // or 'timeout', 'lost-answer', or { kind: 'status', status: 503 }
|
|
71
|
+
|
|
72
|
+
// Signing in: the person agrees at core, and core can send a logout notice, wrong in any way you want to test.
|
|
73
|
+
const back = core.authorize((await sv.auth.beginSignIn()).url, 'u1');
|
|
74
|
+
const notice = await core.logoutToken({ sub: 'u1' }, { wrong: 'expired' });
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`memorySessionStore()` is a session store for tests.
|
|
78
|
+
|
|
79
|
+
## Core versions
|
|
80
|
+
|
|
81
|
+
This release supports core `>=0.46.0` (`sovereign.core` in `package.json`). A core too old to say what it serves is treated as
|
|
82
|
+
serving the Directory and the instance document, and nothing else. The guide for an app's developer is
|
|
83
|
+
[Using the SDK](../../docs/using-the-sdk.md).
|
|
84
|
+
|
|
85
|
+
## Which exports are stable
|
|
86
|
+
|
|
87
|
+
`createSovereign` and the error types are **stable** and change only in a major version; everything else is **experimental** and may
|
|
88
|
+
change in a minor version ([`src/stability.ts`](src/stability.ts) lists both).
|
|
89
|
+
|
|
90
|
+
## Versions
|
|
91
|
+
|
|
92
|
+
This SDK starts at `2.0.0`. Versions up to `1.25.0` of `@sovereignfs/sdk` are the legacy SDK, which ran inside the old platform and is
|
|
93
|
+
not an earlier release of this one.
|
|
94
|
+
|
|
95
|
+
## Licence
|
|
96
|
+
|
|
97
|
+
MPL-2.0, so an app under any licence can use it.
|
package/dist/browser.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var SovereignError = class extends Error {
|
|
3
|
+
name = "SovereignError";
|
|
4
|
+
};
|
|
5
|
+
var ConfigurationError = class extends SovereignError {
|
|
6
|
+
name = "ConfigurationError";
|
|
7
|
+
};
|
|
8
|
+
var CoreApiError = class extends SovereignError {
|
|
9
|
+
constructor(status, code, message, retryAfter) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.status = status;
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.retryAfter = retryAfter;
|
|
14
|
+
}
|
|
15
|
+
status;
|
|
16
|
+
code;
|
|
17
|
+
retryAfter;
|
|
18
|
+
name = "CoreApiError";
|
|
19
|
+
};
|
|
20
|
+
var CoreUnavailableError = class extends SovereignError {
|
|
21
|
+
name = "CoreUnavailableError";
|
|
22
|
+
/**
|
|
23
|
+
* Whether the request may have reached core. `false` only when it certainly did not (the connection was refused, the
|
|
24
|
+
* name did not resolve, or the call had no time left), so that nothing can have happened to it.
|
|
25
|
+
*/
|
|
26
|
+
requestSent;
|
|
27
|
+
/** For a 5xx, its status: core answered, with a failure. */
|
|
28
|
+
status;
|
|
29
|
+
constructor(message, details = {}) {
|
|
30
|
+
super(message, details.cause === void 0 ? void 0 : { cause: details.cause });
|
|
31
|
+
this.requestSent = details.requestSent ?? true;
|
|
32
|
+
this.status = details.status;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
var SessionEndedError = class extends SovereignError {
|
|
36
|
+
name = "SessionEndedError";
|
|
37
|
+
};
|
|
38
|
+
var NotSupportedError = class extends SovereignError {
|
|
39
|
+
constructor(capability) {
|
|
40
|
+
super(`This instance's core does not offer ${capability}.`);
|
|
41
|
+
this.capability = capability;
|
|
42
|
+
}
|
|
43
|
+
capability;
|
|
44
|
+
name = "NotSupportedError";
|
|
45
|
+
};
|
|
46
|
+
var NotAuthenticatedError = class extends SovereignError {
|
|
47
|
+
name = "NotAuthenticatedError";
|
|
48
|
+
constructor() {
|
|
49
|
+
super("There is no signed-in person.");
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
var SignInError = class extends SovereignError {
|
|
53
|
+
name = "SignInError";
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export {
|
|
57
|
+
SovereignError,
|
|
58
|
+
ConfigurationError,
|
|
59
|
+
CoreApiError,
|
|
60
|
+
CoreUnavailableError,
|
|
61
|
+
SessionEndedError,
|
|
62
|
+
NotSupportedError,
|
|
63
|
+
NotAuthenticatedError,
|
|
64
|
+
SignInError
|
|
65
|
+
};
|