@freqhole/haruspex 0.0.0 → 0.2.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/README.md +125 -0
- package/dist/protocol/messages.d.ts +2 -0
- package/dist/protocol/messages.d.ts.map +1 -1
- package/dist/protocol/messages.js +1 -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,6 +94,7 @@ 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">;
|
|
@@ -288,6 +289,7 @@ export declare const CoreMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
288
289
|
accentColor: z.ZodOptional<z.ZodNumber>;
|
|
289
290
|
profileDocId: z.ZodOptional<z.ZodString>;
|
|
290
291
|
profileUpdatedAt: z.ZodOptional<z.ZodString>;
|
|
292
|
+
isHub: z.ZodOptional<z.ZodBoolean>;
|
|
291
293
|
}, z.core.$strip>, z.ZodObject<{
|
|
292
294
|
type: z.ZodLiteral<"friend-request">;
|
|
293
295
|
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,6 +87,7 @@ 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"),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@freqhole/haruspex",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.2",
|
|
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
|
},
|