@freqhole/haruspex 0.2.1 → 0.2.3
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 +125 -0
- package/dist/protocol/messages.d.ts +18 -0
- package/dist/protocol/messages.d.ts.map +1 -1
- package/dist/protocol/messages.js +14 -0
- package/package.json +2 -2
package/README.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# haruspex
|
|
2
|
+
|
|
3
|
+
everything auth for the freqhole world of apps: webauthn passkeys, knock access requests,
|
|
4
|
+
user identity with multi-device node ids, roles + groups, api keys + invite codes, an acl
|
|
5
|
+
evaluator, and the friendz peer protocol (presence, gossip, friend requests). rust crate
|
|
6
|
+
`haruspex` + npm package `@freqhole/haruspex`.
|
|
7
|
+
|
|
8
|
+
## architecture
|
|
9
|
+
|
|
10
|
+
protocol logic is transport-agnostic: it takes (caller identity, message) and returns
|
|
11
|
+
responses. iroh p2p, http, or ipc bindings are thin shells around the same core. this is a
|
|
12
|
+
decentralized, peer-to-peer system - peers talk to peers; some are always-on, some ephemeral.
|
|
13
|
+
|
|
14
|
+
```mermaid
|
|
15
|
+
graph LR
|
|
16
|
+
subgraph apps
|
|
17
|
+
A[your app + policy glue]
|
|
18
|
+
end
|
|
19
|
+
subgraph haruspex core
|
|
20
|
+
S[stores: identity / knock / friendz /<br/>groups / invites / credentials]
|
|
21
|
+
E[acl evaluator:<br/>role grants + live groups]
|
|
22
|
+
P[friendz protocol:<br/>dispatch + gossip + presence]
|
|
23
|
+
W[webauthn ceremonies<br/>+ ChallengeStore]
|
|
24
|
+
end
|
|
25
|
+
T1[iroh ProtocolHandler] --- P
|
|
26
|
+
T2[http / ipc / anything] --- P
|
|
27
|
+
A --> S & E & P & W
|
|
28
|
+
S --- DB[(haruspex.db<br/>own sqlite file)]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- each library owns its OWN sqlite db file (`haruspex.db`) - never tables inside a host
|
|
32
|
+
app's db. cross-domain joins are an app concern (batch resolvers provided).
|
|
33
|
+
- apps extend the wire protocol with namespaced `AppExtension` messages (`myapp:thing`)
|
|
34
|
+
without forking this repo.
|
|
35
|
+
|
|
36
|
+
## structure
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
rust/ crate: haruspex
|
|
40
|
+
src/
|
|
41
|
+
identity/ users, device node ids, attestation
|
|
42
|
+
stores/ store traits + sqlite impls (identity, knock, friendz, groups, invites, credentials)
|
|
43
|
+
acl/ evaluator: role grants, live groups, resource ancestry, RoleResolver seam
|
|
44
|
+
knock/ knock lifecycle + KnockPolicy trait
|
|
45
|
+
webauthn/ ceremony handlers (feature: webauthn)
|
|
46
|
+
protocol/ friendz messages, codec, FriendzService, gossip; iroh shell (feature: iroh)
|
|
47
|
+
sqlite/ pool open/migrations
|
|
48
|
+
testing/ fixtures + fake stores (feature: test-utils)
|
|
49
|
+
examples/ runnable walkthroughs (see below)
|
|
50
|
+
fixtures/ committed protocol wire fixtures (shared with ts)
|
|
51
|
+
ts/ npm: @freqhole/haruspex
|
|
52
|
+
src/{identity,webauthn,knock,share,flows,protocol,permissions,state,solid,testing}
|
|
53
|
+
docs/ design notes specific to this repo
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## rust: getting started
|
|
57
|
+
|
|
58
|
+
```rust
|
|
59
|
+
use haruspex::stores::IdentityStore;
|
|
60
|
+
use haruspex::testing::{identity_store, open_in_memory};
|
|
61
|
+
|
|
62
|
+
let pool = open_in_memory().await; // or sqlite::open(path) in an app
|
|
63
|
+
let identities = identity_store(&pool);
|
|
64
|
+
let alice = identities.upsert_identity(/* Identity { .. } */).await?;
|
|
65
|
+
identities.add_device(/* DeviceNode { node_id, .. } */).await?;
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
features: `webauthn` (passkey ceremonies), `iroh` (friendz ProtocolHandler), `test-utils`
|
|
69
|
+
(in-memory fixtures). default = none of them - the core is dependency-light.
|
|
70
|
+
|
|
71
|
+
examples (each runnable, each a tiny tour):
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
cargo run --example identity-lifecycle --features test-utils # identity + devices + attestation
|
|
75
|
+
cargo run --example acl-roles --features test-utils # grants, groups, evaluator
|
|
76
|
+
cargo run --example role-backfill --features test-utils # legacy role column -> grants
|
|
77
|
+
cargo run --example knock-exchange --features test-utils # knock lifecycle + policy
|
|
78
|
+
cargo run --example two-peer-knock-iroh --features "iroh test-utils" # real iroh, two endpoints
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## ts: getting started
|
|
82
|
+
|
|
83
|
+
framework-free core subpaths; `solid-js` is an optional peer dep used only by `./solid`.
|
|
84
|
+
|
|
85
|
+
| subpath | what |
|
|
86
|
+
| --------------- | ---------------------------------------------------------------------------- |
|
|
87
|
+
| `./identity` | P2PIdentity, idb store, cross-app resolution, web-locks leadership |
|
|
88
|
+
| `./webauthn` | credential codecs + transport-injected ceremony runners |
|
|
89
|
+
| `./knock` | knock requester/responder state machines over idb stores |
|
|
90
|
+
| `./share` | share-token codec + peer-address parsing/detection |
|
|
91
|
+
| `./flows` | headless add-peer FSM (send(event) -> effects) |
|
|
92
|
+
| `./protocol` | friendz zod schemas + codec + FriendzClient (fixture-validated against rust) |
|
|
93
|
+
| `./permissions` | role-hierarchy logic over an injected role table |
|
|
94
|
+
| `./state` | peer-names, endpoint-control (framework-free singletons) |
|
|
95
|
+
| `./solid` | solid-js components/signals (optional) |
|
|
96
|
+
| `./testing` | fixtures + fakes for consumer test suites |
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import {
|
|
100
|
+
resolveIdentity,
|
|
101
|
+
createIdbIdentityStore,
|
|
102
|
+
} from "@freqhole/haruspex/identity";
|
|
103
|
+
import { sendKnock, createIdbKnockStore } from "@freqhole/haruspex/knock";
|
|
104
|
+
// stores get their OWN idb database name - never your app's main db
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## developer quick start
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
# rust
|
|
111
|
+
cargo test --workspace --all-features
|
|
112
|
+
cargo fmt --all --check && cargo clippy --workspace --all-targets
|
|
113
|
+
|
|
114
|
+
# ts
|
|
115
|
+
cd ts && npm i
|
|
116
|
+
npm run typecheck && npm test && npm run build
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
the crate owns its own sqlite db (`haruspex.db`); compiling needs no database (see
|
|
120
|
+
`rust/src/sqlite/mod.rs`). consumers today: tomb/grimoire (auth storage + evaluator),
|
|
121
|
+
tomb/spume (identity, webauthn), playlistz (knock, share), skein (friendz/peer stores) -
|
|
122
|
+
via path/git deps (rust) and `file:` deps (ts), no registry publishing yet.
|
|
123
|
+
|
|
124
|
+
see [docs/](docs/) for design notes; the canonical refactor plan lives in
|
|
125
|
+
tomb/docs/xl-refactor/.
|
|
@@ -94,12 +94,16 @@ declare const ProfileResponseSchema: z.ZodObject<{
|
|
|
94
94
|
accentColor: z.ZodOptional<z.ZodNumber>;
|
|
95
95
|
profileDocId: z.ZodOptional<z.ZodString>;
|
|
96
96
|
profileUpdatedAt: z.ZodOptional<z.ZodString>;
|
|
97
|
+
isHub: z.ZodOptional<z.ZodBoolean>;
|
|
97
98
|
}, z.core.$strip>;
|
|
98
99
|
declare const FriendRequestSchema: z.ZodObject<{
|
|
99
100
|
type: z.ZodLiteral<"friend-request">;
|
|
100
101
|
v: z.ZodDefault<z.ZodNumber>;
|
|
101
102
|
fromNodeId: z.ZodString;
|
|
102
103
|
fromUsername: z.ZodString;
|
|
104
|
+
bio: z.ZodOptional<z.ZodString>;
|
|
105
|
+
avatarDataUrl: z.ZodOptional<z.ZodString>;
|
|
106
|
+
accentColor: z.ZodOptional<z.ZodNumber>;
|
|
103
107
|
isHub: z.ZodOptional<z.ZodBoolean>;
|
|
104
108
|
}, z.core.$strip>;
|
|
105
109
|
declare const FriendAcceptSchema: z.ZodObject<{
|
|
@@ -107,6 +111,9 @@ declare const FriendAcceptSchema: z.ZodObject<{
|
|
|
107
111
|
v: z.ZodDefault<z.ZodNumber>;
|
|
108
112
|
fromNodeId: z.ZodString;
|
|
109
113
|
fromUsername: z.ZodString;
|
|
114
|
+
bio: z.ZodOptional<z.ZodString>;
|
|
115
|
+
avatarDataUrl: z.ZodOptional<z.ZodString>;
|
|
116
|
+
accentColor: z.ZodOptional<z.ZodNumber>;
|
|
110
117
|
isHub: z.ZodOptional<z.ZodBoolean>;
|
|
111
118
|
}, z.core.$strip>;
|
|
112
119
|
declare const FriendAcceptAckSchema: z.ZodObject<{
|
|
@@ -211,6 +218,8 @@ declare const IdentityUpdateSchema: z.ZodObject<{
|
|
|
211
218
|
nodeId: z.ZodString;
|
|
212
219
|
username: z.ZodOptional<z.ZodString>;
|
|
213
220
|
avatarDataUrl: z.ZodOptional<z.ZodString>;
|
|
221
|
+
bio: z.ZodOptional<z.ZodString>;
|
|
222
|
+
accentColor: z.ZodOptional<z.ZodNumber>;
|
|
214
223
|
}, z.core.$strip>;
|
|
215
224
|
declare const AclChangeSchema: z.ZodObject<{
|
|
216
225
|
type: z.ZodLiteral<"acl-change">;
|
|
@@ -288,17 +297,24 @@ export declare const CoreMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
288
297
|
accentColor: z.ZodOptional<z.ZodNumber>;
|
|
289
298
|
profileDocId: z.ZodOptional<z.ZodString>;
|
|
290
299
|
profileUpdatedAt: z.ZodOptional<z.ZodString>;
|
|
300
|
+
isHub: z.ZodOptional<z.ZodBoolean>;
|
|
291
301
|
}, z.core.$strip>, z.ZodObject<{
|
|
292
302
|
type: z.ZodLiteral<"friend-request">;
|
|
293
303
|
v: z.ZodDefault<z.ZodNumber>;
|
|
294
304
|
fromNodeId: z.ZodString;
|
|
295
305
|
fromUsername: z.ZodString;
|
|
306
|
+
bio: z.ZodOptional<z.ZodString>;
|
|
307
|
+
avatarDataUrl: z.ZodOptional<z.ZodString>;
|
|
308
|
+
accentColor: z.ZodOptional<z.ZodNumber>;
|
|
296
309
|
isHub: z.ZodOptional<z.ZodBoolean>;
|
|
297
310
|
}, z.core.$strip>, z.ZodObject<{
|
|
298
311
|
type: z.ZodLiteral<"friend-accept">;
|
|
299
312
|
v: z.ZodDefault<z.ZodNumber>;
|
|
300
313
|
fromNodeId: z.ZodString;
|
|
301
314
|
fromUsername: z.ZodString;
|
|
315
|
+
bio: z.ZodOptional<z.ZodString>;
|
|
316
|
+
avatarDataUrl: z.ZodOptional<z.ZodString>;
|
|
317
|
+
accentColor: z.ZodOptional<z.ZodNumber>;
|
|
302
318
|
isHub: z.ZodOptional<z.ZodBoolean>;
|
|
303
319
|
}, z.core.$strip>, z.ZodObject<{
|
|
304
320
|
type: z.ZodLiteral<"friend-accept-ack">;
|
|
@@ -393,6 +409,8 @@ export declare const CoreMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
393
409
|
nodeId: z.ZodString;
|
|
394
410
|
username: z.ZodOptional<z.ZodString>;
|
|
395
411
|
avatarDataUrl: z.ZodOptional<z.ZodString>;
|
|
412
|
+
bio: z.ZodOptional<z.ZodString>;
|
|
413
|
+
accentColor: z.ZodOptional<z.ZodNumber>;
|
|
396
414
|
}, z.core.$strip>, z.ZodObject<{
|
|
397
415
|
type: z.ZodLiteral<"acl-change">;
|
|
398
416
|
v: z.ZodDefault<z.ZodNumber>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/protocol/messages.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB,qFAAqF;AACrF,eAAO,MAAM,cAAc;;;;;EAAgD,CAAC;AAC5E,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,qCAAqC;AACrC,eAAO,MAAM,qBAAqB;;;;EAA4C,CAAC;AAC/E,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,uEAAuE;AACvE,eAAO,MAAM,sBAAsB;;;EAA8B,CAAC;AAClE,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,8DAA8D;AAC9D,eAAO,MAAM,kBAAkB;;;;;iBAE7B,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAM9D;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;2BAa/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAMlE,iEAAiE;AACjE,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;iBAOzC,CAAC;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,CAAC;AAEtF,sDAAsD;AACtD,eAAO,MAAM,8BAA8B;;;;iBAIzC,CAAC;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,CAAC;AAMtF,QAAA,MAAM,oBAAoB;;;iBAGxB,CAAC;AAEH,QAAA,MAAM,qBAAqB
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/protocol/messages.ts"],"names":[],"mappings":"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"}
|
|
@@ -87,12 +87,21 @@ const ProfileResponseSchema = z.object({
|
|
|
87
87
|
accentColor: z.number().optional(),
|
|
88
88
|
profileDocId: z.string().optional(),
|
|
89
89
|
profileUpdatedAt: z.string().optional(),
|
|
90
|
+
isHub: z.boolean().optional(),
|
|
90
91
|
});
|
|
91
92
|
const FriendRequestSchema = z.object({
|
|
92
93
|
type: z.literal("friend-request"),
|
|
93
94
|
v: wireVersion,
|
|
94
95
|
fromNodeId: z.string(),
|
|
95
96
|
fromUsername: z.string(),
|
|
97
|
+
// identity info sent alongside a friend request regardless of the
|
|
98
|
+
// sender's own profile visibility setting - the recipient hasn't
|
|
99
|
+
// agreed to anything yet, but seeing a name/avatar/bio rather than a
|
|
100
|
+
// bare node id is expected for a request the sender is actively
|
|
101
|
+
// initiating themselves.
|
|
102
|
+
bio: z.string().optional(),
|
|
103
|
+
avatarDataUrl: z.string().optional(),
|
|
104
|
+
accentColor: z.number().optional(),
|
|
96
105
|
isHub: z.boolean().optional(),
|
|
97
106
|
});
|
|
98
107
|
const FriendAcceptSchema = z.object({
|
|
@@ -100,6 +109,9 @@ const FriendAcceptSchema = z.object({
|
|
|
100
109
|
v: wireVersion,
|
|
101
110
|
fromNodeId: z.string(),
|
|
102
111
|
fromUsername: z.string(),
|
|
112
|
+
bio: z.string().optional(),
|
|
113
|
+
avatarDataUrl: z.string().optional(),
|
|
114
|
+
accentColor: z.number().optional(),
|
|
103
115
|
isHub: z.boolean().optional(),
|
|
104
116
|
});
|
|
105
117
|
const FriendAcceptAckSchema = z.object({
|
|
@@ -171,6 +183,8 @@ const IdentityUpdateSchema = z.object({
|
|
|
171
183
|
nodeId: z.string(),
|
|
172
184
|
username: z.string().optional(),
|
|
173
185
|
avatarDataUrl: z.string().optional(),
|
|
186
|
+
bio: z.string().optional(),
|
|
187
|
+
accentColor: z.number().optional(),
|
|
174
188
|
});
|
|
175
189
|
const AclChangeSchema = z.object({
|
|
176
190
|
type: z.literal("acl-change"),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@freqhole/haruspex",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "freqhole auth domain: identity, webauthn, knock + friendz protocols, permissions",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
}
|
|
60
60
|
},
|
|
61
61
|
"scripts": {
|
|
62
|
-
"build": "tsc -p tsconfig.json",
|
|
62
|
+
"build": "cp ../README.md ./README.md && tsc -p tsconfig.json",
|
|
63
63
|
"typecheck": "tsc --noEmit",
|
|
64
64
|
"test": "vitest run"
|
|
65
65
|
},
|