@freqhole/haruspex 0.2.1 → 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 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":"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"}
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.2.1",
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
  },