tablinum 0.1.3 → 0.4.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.
Files changed (60) hide show
  1. package/README.md +134 -85
  2. package/dist/brands.d.ts +5 -0
  3. package/dist/crud/collection-handle.d.ts +8 -6
  4. package/dist/crud/query-builder.d.ts +4 -13
  5. package/dist/crud/watch.d.ts +0 -10
  6. package/dist/db/create-tablinum.d.ts +7 -0
  7. package/dist/db/database-handle.d.ts +23 -1
  8. package/dist/db/epoch.d.ts +48 -0
  9. package/dist/db/invite.d.ts +8 -0
  10. package/dist/db/key-rotation.d.ts +24 -0
  11. package/dist/db/members.d.ts +24 -0
  12. package/dist/db/runtime-config.d.ts +16 -0
  13. package/dist/index.d.ts +8 -1
  14. package/dist/index.js +1744 -842
  15. package/dist/layers/EpochStoreLive.d.ts +6 -0
  16. package/dist/layers/GiftWrapLive.d.ts +5 -0
  17. package/dist/layers/IdentityLive.d.ts +5 -0
  18. package/dist/layers/PublishQueueLive.d.ts +5 -0
  19. package/dist/layers/RelayLive.d.ts +3 -0
  20. package/dist/layers/StorageLive.d.ts +4 -0
  21. package/dist/layers/SyncStatusLive.d.ts +3 -0
  22. package/dist/layers/TablinumLive.d.ts +5 -0
  23. package/dist/layers/index.d.ts +8 -0
  24. package/dist/schema/collection.d.ts +2 -0
  25. package/dist/schema/field.d.ts +7 -2
  26. package/dist/schema/types.d.ts +0 -4
  27. package/dist/services/Config.d.ts +16 -0
  28. package/dist/services/EpochStore.d.ts +6 -0
  29. package/dist/services/GiftWrap.d.ts +6 -0
  30. package/dist/services/Identity.d.ts +6 -0
  31. package/dist/services/PublishQueue.d.ts +6 -0
  32. package/dist/services/Relay.d.ts +6 -0
  33. package/dist/services/Storage.d.ts +6 -0
  34. package/dist/services/Sync.d.ts +6 -0
  35. package/dist/services/SyncStatus.d.ts +6 -0
  36. package/dist/services/Tablinum.d.ts +7 -0
  37. package/dist/services/index.d.ts +10 -0
  38. package/dist/storage/idb.d.ts +13 -3
  39. package/dist/storage/lww.d.ts +0 -5
  40. package/dist/storage/records-store.d.ts +1 -7
  41. package/dist/svelte/collection.svelte.d.ts +10 -6
  42. package/dist/svelte/deferred.d.ts +7 -0
  43. package/dist/svelte/index.svelte.d.ts +6 -6
  44. package/dist/svelte/index.svelte.js +2116 -1084
  45. package/dist/svelte/query.svelte.d.ts +6 -6
  46. package/dist/svelte/tablinum.svelte.d.ts +36 -0
  47. package/dist/sync/gift-wrap.d.ts +6 -2
  48. package/dist/sync/negentropy.d.ts +1 -1
  49. package/dist/sync/publish-queue.d.ts +3 -2
  50. package/dist/sync/relay.d.ts +9 -2
  51. package/dist/sync/sync-service.d.ts +5 -2
  52. package/dist/sync/sync-status.d.ts +1 -0
  53. package/dist/utils/diff.d.ts +2 -0
  54. package/dist/utils/uuid.d.ts +0 -1
  55. package/package.json +10 -7
  56. package/dist/main.d.ts +0 -1
  57. package/dist/storage/events-store.d.ts +0 -6
  58. package/dist/storage/giftwraps-store.d.ts +0 -6
  59. package/dist/svelte/database.svelte.d.ts +0 -15
  60. package/dist/svelte/live-query.svelte.d.ts +0 -8
@@ -1,6 +1,4 @@
1
1
  import type { WhereClause, OrderByBuilder } from "../crud/query-builder.ts";
2
- import { LiveQuery } from "./live-query.svelte.ts";
3
- export type OnLiveCallback = (lq: LiveQuery<unknown>) => void;
4
2
  export interface SvelteQueryBuilder<T> {
5
3
  readonly and: (fn: (item: T) => boolean) => SvelteQueryBuilder<T>;
6
4
  readonly sortBy: (field: string) => SvelteQueryBuilder<T>;
@@ -10,7 +8,6 @@ export interface SvelteQueryBuilder<T> {
10
8
  readonly get: () => Promise<ReadonlyArray<T>>;
11
9
  readonly first: () => Promise<T | null>;
12
10
  readonly count: () => Promise<number>;
13
- readonly live: () => LiveQuery<T>;
14
11
  }
15
12
  export interface SvelteWhereClause<T> {
16
13
  readonly equals: (value: string | number | boolean) => SvelteQueryBuilder<T>;
@@ -33,7 +30,10 @@ export interface SvelteOrderByBuilder<T> {
33
30
  readonly get: () => Promise<ReadonlyArray<T>>;
34
31
  readonly first: () => Promise<T | null>;
35
32
  readonly count: () => Promise<number>;
36
- readonly live: () => LiveQuery<T>;
37
33
  }
38
- export declare function wrapWhereClause<T>(clause: WhereClause<T>, onLive?: OnLiveCallback): SvelteWhereClause<T>;
39
- export declare function wrapOrderByBuilder<T>(builder: OrderByBuilder<T>, onLive?: OnLiveCallback): SvelteOrderByBuilder<T>;
34
+ type TouchVersion = () => void;
35
+ type WhereFactory<T> = () => WhereClause<T>;
36
+ type OrderByFactory<T> = () => OrderByBuilder<T>;
37
+ export declare function wrapWhereClause<T>(getClause: WhereFactory<T>, touchVersion: TouchVersion, ready: Promise<void>): SvelteWhereClause<T>;
38
+ export declare function wrapOrderByBuilder<T>(getBuilder: OrderByFactory<T>, touchVersion: TouchVersion, ready: Promise<void>): SvelteOrderByBuilder<T>;
39
+ export {};
@@ -0,0 +1,36 @@
1
+ import type { SchemaConfig } from "../schema/types.ts";
2
+ import type { CollectionDef, CollectionFields } from "../schema/collection.ts";
3
+ import type { SyncStatus } from "../db/database-handle.ts";
4
+ import type { RelayStatus } from "../sync/relay.ts";
5
+ import type { Invite } from "../db/invite.ts";
6
+ import type { MemberRecord, AuthorProfile } from "../db/members.ts";
7
+ import { type TablinumConfig } from "../db/create-tablinum.ts";
8
+ import { Collection } from "./collection.svelte.ts";
9
+ export declare class Tablinum<S extends SchemaConfig> {
10
+ #private;
11
+ status: "initializing" | "ready" | "error" | "closed";
12
+ syncStatus: SyncStatus;
13
+ pendingCount: number;
14
+ relayStatus: RelayStatus;
15
+ error: Error | null;
16
+ readonly ready: Promise<void>;
17
+ constructor(config: TablinumConfig<S>);
18
+ get publicKey(): string;
19
+ get members(): Collection<CollectionDef<CollectionFields>>;
20
+ collection<K extends string & keyof S>(name: K): Collection<S[K]>;
21
+ exportKey(): string;
22
+ exportInvite(): Invite;
23
+ close: () => Promise<void>;
24
+ sync: () => Promise<void>;
25
+ rebuild: () => Promise<void>;
26
+ addMember: (pubkey: string) => Promise<void>;
27
+ removeMember: (pubkey: string) => Promise<void>;
28
+ getMembers: () => Promise<ReadonlyArray<MemberRecord>>;
29
+ getProfile: () => Promise<AuthorProfile>;
30
+ setProfile: (profile: {
31
+ name?: string;
32
+ picture?: string;
33
+ about?: string;
34
+ nip05?: string;
35
+ }) => Promise<void>;
36
+ }
@@ -1,9 +1,13 @@
1
1
  import { Effect } from "effect";
2
- import { type Rumor } from "nostr-tools/nip59";
2
+ import { unwrapEvent } from "nostr-tools/nip59";
3
3
  import type { NostrEvent, UnsignedEvent } from "nostr-tools/pure";
4
4
  import { CryptoError } from "../errors.ts";
5
+ import type { EpochStore } from "../db/epoch.ts";
6
+ type Rumor = ReturnType<typeof unwrapEvent>;
5
7
  export interface GiftWrapHandle {
6
8
  readonly wrap: (rumor: Partial<UnsignedEvent>) => Effect.Effect<NostrEvent, CryptoError>;
7
9
  readonly unwrap: (giftWrap: NostrEvent) => Effect.Effect<Rumor, CryptoError>;
8
10
  }
9
- export declare function createGiftWrapHandle(privateKey: Uint8Array, publicKey: string): GiftWrapHandle;
11
+ export declare function createGiftWrapHandle(senderPrivateKey: Uint8Array, recipientPublicKey: string, decryptionPrivateKey: Uint8Array): GiftWrapHandle;
12
+ export declare function createEpochGiftWrapHandle(senderPrivateKey: Uint8Array, epochStore: EpochStore): GiftWrapHandle;
13
+ export {};
@@ -6,4 +6,4 @@ export interface ReconcileResult {
6
6
  readonly haveIds: string[];
7
7
  readonly needIds: string[];
8
8
  }
9
- export declare function reconcileWithRelay(storage: IDBStorageHandle, relay: RelayHandle, relayUrl: string, publicKey: string): Effect.Effect<ReconcileResult, SyncError | RelayError | StorageError>;
9
+ export declare function reconcileWithRelay(storage: IDBStorageHandle, relay: RelayHandle, relayUrl: string, publicKeys: string | string[]): Effect.Effect<ReconcileResult, SyncError | RelayError | StorageError>;
@@ -3,8 +3,9 @@ import type { IDBStorageHandle } from "../storage/idb.ts";
3
3
  import type { RelayHandle } from "./relay.ts";
4
4
  import type { RelayError, StorageError } from "../errors.ts";
5
5
  export interface PublishQueueHandle {
6
- readonly enqueue: (eventId: string) => Effect.Effect<void>;
6
+ readonly enqueue: (eventId: string) => Effect.Effect<void, StorageError>;
7
7
  readonly flush: (relayUrls: readonly string[]) => Effect.Effect<void, RelayError | StorageError>;
8
8
  readonly size: () => Effect.Effect<number>;
9
+ readonly subscribe: (callback: (count: number) => void) => () => void;
9
10
  }
10
- export declare function createPublishQueue(storage: IDBStorageHandle, relay: RelayHandle): Effect.Effect<PublishQueueHandle>;
11
+ export declare function createPublishQueue(storage: IDBStorageHandle, relay: RelayHandle): Effect.Effect<PublishQueueHandle, StorageError>;
@@ -1,7 +1,10 @@
1
- import { Effect } from "effect";
1
+ import { Effect, Option, Scope } from "effect";
2
2
  import type { NostrEvent } from "nostr-tools/pure";
3
3
  import type { Filter } from "nostr-tools/filter";
4
4
  import { RelayError } from "../errors.ts";
5
+ export interface RelayStatus {
6
+ readonly connectedUrls: ReadonlyArray<string>;
7
+ }
5
8
  export interface RelayHandle {
6
9
  readonly publish: (event: NostrEvent, urls: readonly string[]) => Effect.Effect<void, RelayError>;
7
10
  readonly fetchEvents: (ids: readonly string[], url: string) => Effect.Effect<NostrEvent[], RelayError>;
@@ -13,5 +16,9 @@ export interface RelayHandle {
13
16
  needIds: string[];
14
17
  }, RelayError>;
15
18
  readonly closeAll: () => Effect.Effect<void>;
19
+ readonly getStatus: () => RelayStatus;
20
+ readonly subscribeStatus: (callback: (status: RelayStatus) => void) => () => void;
16
21
  }
17
- export declare function createRelayHandle(): RelayHandle;
22
+ export type NegFrame = readonly ["NEG-MSG", string, string] | readonly ["NEG-ERR", string, string];
23
+ export declare function parseNegMessageFrame(data: string): Option.Option<NegFrame>;
24
+ export declare function createRelayHandle(): Effect.Effect<RelayHandle, never, Scope.Scope>;
@@ -1,4 +1,4 @@
1
- import { Effect } from "effect";
1
+ import { Effect, Scope } from "effect";
2
2
  import type { IDBStorageHandle, StoredGiftWrap } from "../storage/idb.ts";
3
3
  import type { GiftWrapHandle } from "./gift-wrap.ts";
4
4
  import type { RelayHandle } from "./relay.ts";
@@ -6,9 +6,12 @@ import type { PublishQueueHandle } from "./publish-queue.ts";
6
6
  import type { SyncStatusHandle } from "./sync-status.ts";
7
7
  import type { WatchContext } from "../crud/watch.ts";
8
8
  import { CryptoError, RelayError, StorageError, SyncError } from "../errors.ts";
9
+ import type { EpochStore } from "../db/epoch.ts";
10
+ import type { RemovalNotice } from "../db/key-rotation.ts";
9
11
  export interface SyncHandle {
10
12
  readonly sync: () => Effect.Effect<void, SyncError | RelayError | CryptoError | StorageError>;
11
13
  readonly publishLocal: (giftWrap: StoredGiftWrap) => Effect.Effect<void>;
12
14
  readonly startSubscription: () => Effect.Effect<void>;
15
+ readonly addEpochSubscription: (publicKey: string) => Effect.Effect<void>;
13
16
  }
14
- export declare function createSyncHandle(storage: IDBStorageHandle, giftWrapHandle: GiftWrapHandle, relay: RelayHandle, publishQueue: PublishQueueHandle, syncStatus: SyncStatusHandle, watchCtx: WatchContext, relayUrls: readonly string[], publicKey: string, onSyncError?: ((error: unknown) => void) | undefined): SyncHandle;
17
+ export declare function createSyncHandle(storage: IDBStorageHandle, giftWrapHandle: GiftWrapHandle, relay: RelayHandle, publishQueue: PublishQueueHandle, syncStatus: SyncStatusHandle, watchCtx: WatchContext, relayUrls: readonly string[], knownCollections: ReadonlyMap<string, number>, epochStore: EpochStore, personalPrivateKey: Uint8Array, personalPublicKey: string, scope: Scope.Scope, onSyncError?: ((error: unknown) => void) | undefined, onNewAuthor?: ((pubkey: string) => void) | undefined, onRemoved?: ((notice: RemovalNotice) => void) | undefined, onMembersChanged?: (() => void) | undefined): SyncHandle;
@@ -3,5 +3,6 @@ import type { SyncStatus } from "../db/database-handle.ts";
3
3
  export interface SyncStatusHandle {
4
4
  readonly get: () => Effect.Effect<SyncStatus>;
5
5
  readonly set: (status: SyncStatus) => Effect.Effect<void>;
6
+ readonly subscribe: (callback: (status: SyncStatus) => void) => () => void;
6
7
  }
7
8
  export declare function createSyncStatusHandle(): Effect.Effect<SyncStatusHandle>;
@@ -0,0 +1,2 @@
1
+ export declare function deepDiff(before: Record<string, unknown>, after: Record<string, unknown>): Record<string, unknown> | null;
2
+ export declare function deepMerge(target: Record<string, unknown>, source: Record<string, unknown>): Record<string, unknown>;
@@ -1,2 +1 @@
1
- /** Generate a UUIDv7 (time-sortable) using crypto.getRandomValues. */
2
1
  export declare function uuidv7(): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tablinum",
3
- "version": "0.1.3",
3
+ "version": "0.4.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/kevmodrome/tablinum.git"
@@ -35,7 +35,10 @@
35
35
  "build": "bun build src/index.ts --outdir dist --format esm --packages external && bun build src/svelte/index.svelte.ts --outdir dist/svelte --format esm --packages external && tsc -p tsconfig.build.json --noCheck && tsc -p tsconfig.build.svelte.json --noCheck",
36
36
  "changeset": "changeset",
37
37
  "version": "changeset version",
38
- "release": "changeset publish"
38
+ "release": "changeset publish",
39
+ "relays": "docker compose up -d",
40
+ "relays:down": "docker compose down",
41
+ "relays:clean": "docker compose down -v"
39
42
  },
40
43
  "dependencies": {
41
44
  "@noble/curves": "^2.0.1",
@@ -46,13 +49,13 @@
46
49
  },
47
50
  "devDependencies": {
48
51
  "@changesets/cli": "^2.30.0",
49
- "@effect/vitest": "4.0.0-beta.28",
50
- "@j178/prek": "latest",
52
+ "@effect/vitest": "4.0.0-beta.31",
53
+ "@j178/prek": "0.3.5",
51
54
  "@types/bun": "^1.3.10",
52
55
  "fake-indexeddb": "^6.2.5",
53
- "oxfmt": "latest",
54
- "oxlint": "^1.51.0",
55
- "svelte": "^5.0.0",
56
+ "oxfmt": "0.38.0",
57
+ "oxlint": "^1.53.0",
58
+ "svelte": "^5.53.10",
56
59
  "typescript": "^5.7.0",
57
60
  "vitest": "^3.0.0"
58
61
  },
package/dist/main.d.ts DELETED
@@ -1 +0,0 @@
1
- export {};
@@ -1,6 +0,0 @@
1
- import { Effect } from "effect";
2
- import type { IDBStorageHandle, StoredEvent } from "./idb.ts";
3
- import type { StorageError } from "../errors.ts";
4
- export declare function putEvent(storage: IDBStorageHandle, event: StoredEvent): Effect.Effect<void, StorageError>;
5
- export declare function getEventsByRecord(storage: IDBStorageHandle, collection: string, recordId: string): Effect.Effect<ReadonlyArray<StoredEvent>, StorageError>;
6
- export declare function getAllEvents(storage: IDBStorageHandle): Effect.Effect<ReadonlyArray<StoredEvent>, StorageError>;
@@ -1,6 +0,0 @@
1
- import { Effect } from "effect";
2
- import type { IDBStorageHandle, StoredGiftWrap } from "./idb.ts";
3
- import type { StorageError } from "../errors.ts";
4
- export declare function putGiftWrap(storage: IDBStorageHandle, gw: StoredGiftWrap): Effect.Effect<void, StorageError>;
5
- export declare function getGiftWrap(storage: IDBStorageHandle, id: string): Effect.Effect<StoredGiftWrap | undefined, StorageError>;
6
- export declare function getAllGiftWraps(storage: IDBStorageHandle): Effect.Effect<ReadonlyArray<StoredGiftWrap>, StorageError>;
@@ -1,15 +0,0 @@
1
- import { Scope } from "effect";
2
- import type { SchemaConfig } from "../schema/types.ts";
3
- import type { DatabaseHandle } from "../db/database-handle.ts";
4
- import { Collection } from "./collection.svelte.ts";
5
- export declare class Database<S extends SchemaConfig> {
6
- #private;
7
- status: any;
8
- error: any;
9
- constructor(handle: DatabaseHandle<S>, scope: Scope.Closeable);
10
- collection<K extends string & keyof S>(name: K): Collection<S[K]>;
11
- exportKey(): string;
12
- close: () => Promise<void>;
13
- sync: () => Promise<void>;
14
- rebuild: () => Promise<void>;
15
- }
@@ -1,8 +0,0 @@
1
- import { Stream } from "effect";
2
- export declare class LiveQuery<T> {
3
- #private;
4
- items: any;
5
- error: any;
6
- constructor(stream: Stream.Stream<ReadonlyArray<T>, unknown>);
7
- destroy(): void;
8
- }