@commonpub/server 2.54.0 → 2.54.2
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/package.json +9 -7
- package/dist/identity/__tests__/health.test.d.ts +0 -2
- package/dist/identity/__tests__/health.test.d.ts.map +0 -1
- package/dist/identity/__tests__/health.test.js +0 -113
- package/dist/identity/__tests__/health.test.js.map +0 -1
- package/dist/identity/__tests__/router.test.d.ts +0 -2
- package/dist/identity/__tests__/router.test.d.ts.map +0 -1
- package/dist/identity/__tests__/router.test.js +0 -163
- package/dist/identity/__tests__/router.test.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@commonpub/server",
|
|
3
|
-
"version": "2.54.
|
|
3
|
+
"version": "2.54.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Framework-agnostic business logic for CommonPub instances",
|
|
6
6
|
"license": "AGPL-3.0-or-later",
|
|
@@ -98,7 +98,9 @@
|
|
|
98
98
|
},
|
|
99
99
|
"files": [
|
|
100
100
|
"dist/",
|
|
101
|
-
"
|
|
101
|
+
"!**/__tests__/",
|
|
102
|
+
"!**/*.test.*",
|
|
103
|
+
"!**/*.spec.*",
|
|
102
104
|
"README.md",
|
|
103
105
|
"LICENSE"
|
|
104
106
|
],
|
|
@@ -108,14 +110,14 @@
|
|
|
108
110
|
"linkedom": "^0.18.12",
|
|
109
111
|
"megalodon": "^10.3.0",
|
|
110
112
|
"turndown": "^7.2.4",
|
|
113
|
+
"@commonpub/config": "0.13.0",
|
|
114
|
+
"@commonpub/docs": "0.6.3",
|
|
111
115
|
"@commonpub/auth": "0.6.0",
|
|
112
|
-
"@commonpub/editor": "0.7.
|
|
113
|
-
"@commonpub/infra": "0.7.0",
|
|
116
|
+
"@commonpub/editor": "0.7.10",
|
|
114
117
|
"@commonpub/learning": "0.5.2",
|
|
115
|
-
"@commonpub/
|
|
116
|
-
"@commonpub/protocol": "0.10.0",
|
|
118
|
+
"@commonpub/infra": "0.7.1",
|
|
117
119
|
"@commonpub/schema": "0.16.0",
|
|
118
|
-
"@commonpub/
|
|
120
|
+
"@commonpub/protocol": "0.10.1"
|
|
119
121
|
},
|
|
120
122
|
"peerDependencies": {
|
|
121
123
|
"drizzle-orm": "^0.45.1"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"health.test.d.ts","sourceRoot":"","sources":["../../../src/identity/__tests__/health.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { checkIdentityConfig, assertIdentityConfig } from '../health.js';
|
|
3
|
-
const VALID_KEY = '0'.repeat(64);
|
|
4
|
-
// Minimal CommonPubConfig builder — kept inline (rather than importing
|
|
5
|
-
// @commonpub/test-utils) so this test file doesn't add a workspace dep
|
|
6
|
-
// that @commonpub/server otherwise doesn't need.
|
|
7
|
-
function makeConfig(idOverrides = {}) {
|
|
8
|
-
return {
|
|
9
|
-
instance: {
|
|
10
|
-
domain: 'test.example.com',
|
|
11
|
-
name: 'Test',
|
|
12
|
-
description: 'Test instance',
|
|
13
|
-
},
|
|
14
|
-
features: {
|
|
15
|
-
content: true, social: true, hubs: true, docs: true, video: true,
|
|
16
|
-
contests: false, events: false, learning: true, explainers: true,
|
|
17
|
-
editorial: true, federation: false, seamlessFederation: false,
|
|
18
|
-
federateHubs: false, admin: false, emailNotifications: false,
|
|
19
|
-
publicApi: false, contentImport: true,
|
|
20
|
-
identity: {
|
|
21
|
-
linkRemoteAccounts: false,
|
|
22
|
-
signInWithRemote: false,
|
|
23
|
-
actingAs: false,
|
|
24
|
-
remoteInteract: false,
|
|
25
|
-
remotePublish: false,
|
|
26
|
-
...idOverrides,
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
auth: {
|
|
30
|
-
emailPassword: true,
|
|
31
|
-
magicLink: false,
|
|
32
|
-
passkeys: false,
|
|
33
|
-
},
|
|
34
|
-
docs: {
|
|
35
|
-
searchLanguage: 'english',
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
describe('checkIdentityConfig', () => {
|
|
40
|
-
let originalKey;
|
|
41
|
-
beforeEach(() => {
|
|
42
|
-
originalKey = process.env.CPUB_FED_TOKEN_KEY;
|
|
43
|
-
});
|
|
44
|
-
afterEach(() => {
|
|
45
|
-
if (originalKey === undefined)
|
|
46
|
-
delete process.env.CPUB_FED_TOKEN_KEY;
|
|
47
|
-
else
|
|
48
|
-
process.env.CPUB_FED_TOKEN_KEY = originalKey;
|
|
49
|
-
});
|
|
50
|
-
it('ok when no identity flags are enabled', () => {
|
|
51
|
-
delete process.env.CPUB_FED_TOKEN_KEY;
|
|
52
|
-
const result = checkIdentityConfig(makeConfig());
|
|
53
|
-
expect(result).toEqual({ ok: true, errors: [] });
|
|
54
|
-
});
|
|
55
|
-
it('ok when only `actingAs` is enabled (no token I/O)', () => {
|
|
56
|
-
delete process.env.CPUB_FED_TOKEN_KEY;
|
|
57
|
-
const result = checkIdentityConfig(makeConfig({ actingAs: true }));
|
|
58
|
-
expect(result.ok).toBe(true);
|
|
59
|
-
});
|
|
60
|
-
it('errors when linkRemoteAccounts is on without key', () => {
|
|
61
|
-
delete process.env.CPUB_FED_TOKEN_KEY;
|
|
62
|
-
const result = checkIdentityConfig(makeConfig({ linkRemoteAccounts: true }));
|
|
63
|
-
expect(result.ok).toBe(false);
|
|
64
|
-
expect(result.errors[0]).toMatch(/CPUB_FED_TOKEN_KEY/);
|
|
65
|
-
});
|
|
66
|
-
it('errors when signInWithRemote is on without key', () => {
|
|
67
|
-
delete process.env.CPUB_FED_TOKEN_KEY;
|
|
68
|
-
const result = checkIdentityConfig(makeConfig({ signInWithRemote: true }));
|
|
69
|
-
expect(result.ok).toBe(false);
|
|
70
|
-
});
|
|
71
|
-
it('errors when remoteInteract is on without key', () => {
|
|
72
|
-
delete process.env.CPUB_FED_TOKEN_KEY;
|
|
73
|
-
const result = checkIdentityConfig(makeConfig({ remoteInteract: true }));
|
|
74
|
-
expect(result.ok).toBe(false);
|
|
75
|
-
});
|
|
76
|
-
it('errors when remotePublish is on without key', () => {
|
|
77
|
-
delete process.env.CPUB_FED_TOKEN_KEY;
|
|
78
|
-
const result = checkIdentityConfig(makeConfig({ remotePublish: true }));
|
|
79
|
-
expect(result.ok).toBe(false);
|
|
80
|
-
});
|
|
81
|
-
it('ok when token-using flag is on AND key is configured', () => {
|
|
82
|
-
process.env.CPUB_FED_TOKEN_KEY = VALID_KEY;
|
|
83
|
-
const result = checkIdentityConfig(makeConfig({ linkRemoteAccounts: true, remotePublish: true }));
|
|
84
|
-
expect(result.ok).toBe(true);
|
|
85
|
-
});
|
|
86
|
-
it('errors when key is malformed (wrong length)', () => {
|
|
87
|
-
process.env.CPUB_FED_TOKEN_KEY = '0'.repeat(63);
|
|
88
|
-
const result = checkIdentityConfig(makeConfig({ linkRemoteAccounts: true }));
|
|
89
|
-
expect(result.ok).toBe(false);
|
|
90
|
-
expect(result.errors[0]).toMatch(/CPUB_FED_TOKEN_KEY/);
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
describe('assertIdentityConfig', () => {
|
|
94
|
-
let originalKey;
|
|
95
|
-
beforeEach(() => {
|
|
96
|
-
originalKey = process.env.CPUB_FED_TOKEN_KEY;
|
|
97
|
-
});
|
|
98
|
-
afterEach(() => {
|
|
99
|
-
if (originalKey === undefined)
|
|
100
|
-
delete process.env.CPUB_FED_TOKEN_KEY;
|
|
101
|
-
else
|
|
102
|
-
process.env.CPUB_FED_TOKEN_KEY = originalKey;
|
|
103
|
-
});
|
|
104
|
-
it('does not throw when ok', () => {
|
|
105
|
-
process.env.CPUB_FED_TOKEN_KEY = VALID_KEY;
|
|
106
|
-
expect(() => assertIdentityConfig(makeConfig({ linkRemoteAccounts: true }))).not.toThrow();
|
|
107
|
-
});
|
|
108
|
-
it('throws with all errors joined when not ok', () => {
|
|
109
|
-
delete process.env.CPUB_FED_TOKEN_KEY;
|
|
110
|
-
expect(() => assertIdentityConfig(makeConfig({ linkRemoteAccounts: true }))).toThrow(/misconfigured.*CPUB_FED_TOKEN_KEY/s);
|
|
111
|
-
});
|
|
112
|
-
});
|
|
113
|
-
//# sourceMappingURL=health.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"health.test.js","sourceRoot":"","sources":["../../../src/identity/__tests__/health.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"router.test.d.ts","sourceRoot":"","sources":["../../../src/identity/__tests__/router.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, afterEach } from 'vitest';
|
|
2
|
-
import { run, ActionUnavailable, InsufficientScopes, LinkedIdentityRevoked, } from '../router.js';
|
|
3
|
-
import { setFediClientFactory, } from '../fediClient.js';
|
|
4
|
-
// Reset the factory between tests so leakage between cases is impossible.
|
|
5
|
-
afterEach(() => setFediClientFactory(null));
|
|
6
|
-
const fakeEvent = {};
|
|
7
|
-
const NATIVE = {
|
|
8
|
-
kind: 'native',
|
|
9
|
-
id: 'u1',
|
|
10
|
-
userId: 'u1',
|
|
11
|
-
username: 'moheeb',
|
|
12
|
-
instance: 'deveco.io',
|
|
13
|
-
actorUri: 'https://deveco.io/users/moheeb',
|
|
14
|
-
handle: '@moheeb@deveco.io',
|
|
15
|
-
};
|
|
16
|
-
function makeLinked(overrides = {}) {
|
|
17
|
-
return {
|
|
18
|
-
kind: 'linked',
|
|
19
|
-
id: 'fa1',
|
|
20
|
-
userId: 'u1',
|
|
21
|
-
username: 'moheeb',
|
|
22
|
-
instance: 'commonpub.io',
|
|
23
|
-
actorUri: 'https://commonpub.io/users/moheeb',
|
|
24
|
-
handle: '@moheeb@commonpub.io',
|
|
25
|
-
scopes: ['read', 'write'],
|
|
26
|
-
softwareKind: 'cpub',
|
|
27
|
-
revokedAt: null,
|
|
28
|
-
...overrides,
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
function makeAction(opts = {}) {
|
|
32
|
-
return {
|
|
33
|
-
name: opts.name ?? 'test-action',
|
|
34
|
-
scopes: opts.scopes ?? [],
|
|
35
|
-
local: opts.local ?? vi.fn(async () => 'local-result'),
|
|
36
|
-
remote: opts.remote,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
describe('run() — native identity', () => {
|
|
40
|
-
it('dispatches to action.local', async () => {
|
|
41
|
-
const local = vi.fn(async () => 'OK');
|
|
42
|
-
const action = makeAction({ local });
|
|
43
|
-
const result = await run(fakeEvent, NATIVE, action, undefined);
|
|
44
|
-
expect(result).toBe('OK');
|
|
45
|
-
expect(local).toHaveBeenCalledOnce();
|
|
46
|
-
expect(local).toHaveBeenCalledWith(fakeEvent, NATIVE, undefined);
|
|
47
|
-
});
|
|
48
|
-
it('passes input through unchanged', async () => {
|
|
49
|
-
const local = vi.fn(async (_e, _id, x) => x.hello);
|
|
50
|
-
const action = {
|
|
51
|
-
name: 'test',
|
|
52
|
-
scopes: [],
|
|
53
|
-
local,
|
|
54
|
-
};
|
|
55
|
-
const result = await run(fakeEvent, NATIVE, action, { hello: 'world' });
|
|
56
|
-
expect(result).toBe('world');
|
|
57
|
-
});
|
|
58
|
-
it('does NOT check scopes for native (scopes are linked-only)', async () => {
|
|
59
|
-
const action = makeAction({ scopes: ['publish'] });
|
|
60
|
-
// Native passes through even though "scopes: ['publish']" is declared.
|
|
61
|
-
const result = await run(fakeEvent, NATIVE, action, undefined);
|
|
62
|
-
expect(result).toBe('local-result');
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
describe('run() — linked identity', () => {
|
|
66
|
-
it('throws ActionUnavailable when the action has no remote half', async () => {
|
|
67
|
-
const action = makeAction(); // no remote
|
|
68
|
-
await expect(run(fakeEvent, makeLinked(), action, undefined))
|
|
69
|
-
.rejects.toBeInstanceOf(ActionUnavailable);
|
|
70
|
-
await expect(run(fakeEvent, makeLinked(), action, undefined))
|
|
71
|
-
.rejects.toMatchObject({ action: 'test-action', reason: 'not-proxiable' });
|
|
72
|
-
});
|
|
73
|
-
it('throws LinkedIdentityRevoked when the grant is revoked', async () => {
|
|
74
|
-
const remote = vi.fn(async () => 'remote-result');
|
|
75
|
-
const action = makeAction({ remote });
|
|
76
|
-
const revoked = makeLinked({ revokedAt: new Date() });
|
|
77
|
-
await expect(run(fakeEvent, revoked, action, undefined))
|
|
78
|
-
.rejects.toBeInstanceOf(LinkedIdentityRevoked);
|
|
79
|
-
expect(remote).not.toHaveBeenCalled();
|
|
80
|
-
});
|
|
81
|
-
it('throws InsufficientScopes when granted scopes do not cover required', async () => {
|
|
82
|
-
const remote = vi.fn(async () => 'remote-result');
|
|
83
|
-
const action = makeAction({ scopes: ['publish'], remote });
|
|
84
|
-
const linked = makeLinked({ scopes: ['read', 'write'] });
|
|
85
|
-
try {
|
|
86
|
-
await run(fakeEvent, linked, action, undefined);
|
|
87
|
-
throw new Error('expected throw');
|
|
88
|
-
}
|
|
89
|
-
catch (err) {
|
|
90
|
-
expect(err).toBeInstanceOf(InsufficientScopes);
|
|
91
|
-
expect(err.required).toEqual(['publish']);
|
|
92
|
-
expect(err.granted).toEqual(['read', 'write']);
|
|
93
|
-
}
|
|
94
|
-
expect(remote).not.toHaveBeenCalled();
|
|
95
|
-
});
|
|
96
|
-
it('throws when no FediClient factory is registered', async () => {
|
|
97
|
-
// Phase 1a default state: no factory. Reaching getFediClient must
|
|
98
|
-
// surface a clear, actionable error rather than silently no-op'ing.
|
|
99
|
-
const remote = vi.fn(async () => 'remote-result');
|
|
100
|
-
const action = makeAction({ scopes: ['read'], remote });
|
|
101
|
-
const linked = makeLinked({ scopes: ['read', 'write'] });
|
|
102
|
-
await expect(run(fakeEvent, linked, action, undefined))
|
|
103
|
-
.rejects.toThrow(/factory not registered/);
|
|
104
|
-
expect(remote).not.toHaveBeenCalled();
|
|
105
|
-
});
|
|
106
|
-
it('dispatches to action.remote with the factory-built client', async () => {
|
|
107
|
-
// The crucial chain-completeness test: Phase 1b plugs in a factory,
|
|
108
|
-
// and run() must thread the constructed client through to the
|
|
109
|
-
// action's remote handler with the linked identity unchanged.
|
|
110
|
-
const fakeClient = {
|
|
111
|
-
account: { verifyCredentials: vi.fn(async () => ({ id: '1', username: 'm', acct: 'm@host' })) },
|
|
112
|
-
};
|
|
113
|
-
const factory = vi.fn(async () => fakeClient);
|
|
114
|
-
setFediClientFactory(factory);
|
|
115
|
-
const remote = vi.fn(async (client, _id, _input) => {
|
|
116
|
-
// Verify it's actually the registered factory's client
|
|
117
|
-
expect(client).toBe(fakeClient);
|
|
118
|
-
return 'remote-result';
|
|
119
|
-
});
|
|
120
|
-
const action = makeAction({ scopes: ['read'], remote });
|
|
121
|
-
const linked = makeLinked({ scopes: ['read', 'write'] });
|
|
122
|
-
const result = await run(fakeEvent, linked, action, undefined);
|
|
123
|
-
expect(result).toBe('remote-result');
|
|
124
|
-
expect(factory).toHaveBeenCalledOnce();
|
|
125
|
-
expect(factory).toHaveBeenCalledWith(linked);
|
|
126
|
-
expect(remote).toHaveBeenCalledOnce();
|
|
127
|
-
});
|
|
128
|
-
it('propagates factory errors as-is (no silent swallow)', async () => {
|
|
129
|
-
setFediClientFactory(async () => { throw new Error('database unreachable'); });
|
|
130
|
-
const action = makeAction({ scopes: ['read'], remote: vi.fn() });
|
|
131
|
-
const linked = makeLinked({ scopes: ['read'] });
|
|
132
|
-
await expect(run(fakeEvent, linked, action, undefined))
|
|
133
|
-
.rejects.toThrow(/database unreachable/);
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
describe('error classes', () => {
|
|
137
|
-
it('ActionUnavailable carries action + reason', () => {
|
|
138
|
-
const e = new ActionUnavailable('publish', 'no-token');
|
|
139
|
-
expect(e.name).toBe('ActionUnavailable');
|
|
140
|
-
expect(e.action).toBe('publish');
|
|
141
|
-
expect(e.reason).toBe('no-token');
|
|
142
|
-
expect(e.message).toContain('publish');
|
|
143
|
-
expect(e.message).toContain('no-token');
|
|
144
|
-
});
|
|
145
|
-
it('InsufficientScopes carries required + granted', () => {
|
|
146
|
-
const e = new InsufficientScopes('publish', ['publish'], ['read']);
|
|
147
|
-
expect(e.required).toEqual(['publish']);
|
|
148
|
-
expect(e.granted).toEqual(['read']);
|
|
149
|
-
expect(e.message).toContain('publish');
|
|
150
|
-
});
|
|
151
|
-
it('LinkedIdentityRevoked carries identity reference', () => {
|
|
152
|
-
const id = makeLinked({ revokedAt: new Date() });
|
|
153
|
-
const e = new LinkedIdentityRevoked(id);
|
|
154
|
-
expect(e.identity).toBe(id);
|
|
155
|
-
expect(e.message).toContain(id.handle);
|
|
156
|
-
});
|
|
157
|
-
// Sanity: typeof Identity narrowing works at runtime
|
|
158
|
-
it('Identity union still includes both kinds', () => {
|
|
159
|
-
const ids = [NATIVE, makeLinked()];
|
|
160
|
-
expect(ids.map(i => i.kind).sort()).toEqual(['linked', 'native']);
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
//# sourceMappingURL=router.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"router.test.js","sourceRoot":"","sources":["../../../src/identity/__tests__/router.test.ts"],"names":[],"mappings":"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"}
|