@decentrl/sdk 0.0.1
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/dist/client.d.ts +36 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +192 -0
- package/dist/contract-manager.d.ts +23 -0
- package/dist/contract-manager.d.ts.map +1 -0
- package/dist/contract-manager.js +91 -0
- package/dist/define-app.d.ts +8 -0
- package/dist/define-app.d.ts.map +1 -0
- package/dist/define-app.js +7 -0
- package/dist/direct-transport.d.ts +69 -0
- package/dist/direct-transport.d.ts.map +1 -0
- package/dist/direct-transport.js +450 -0
- package/dist/errors.d.ts +7 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +10 -0
- package/dist/event-processor.d.ts +19 -0
- package/dist/event-processor.d.ts.map +1 -0
- package/dist/event-processor.js +93 -0
- package/dist/identity-manager.d.ts +22 -0
- package/dist/identity-manager.d.ts.map +1 -0
- package/dist/identity-manager.js +62 -0
- package/dist/identity-serialization.d.ts +5 -0
- package/dist/identity-serialization.d.ts.map +1 -0
- package/dist/identity-serialization.js +30 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/persistence.d.ts +11 -0
- package/dist/persistence.d.ts.map +1 -0
- package/dist/persistence.js +82 -0
- package/dist/state-store.d.ts +12 -0
- package/dist/state-store.d.ts.map +1 -0
- package/dist/state-store.js +32 -0
- package/dist/sync-manager.d.ts +33 -0
- package/dist/sync-manager.d.ts.map +1 -0
- package/dist/sync-manager.js +244 -0
- package/dist/tag-templates.d.ts +2 -0
- package/dist/tag-templates.d.ts.map +1 -0
- package/dist/tag-templates.js +23 -0
- package/dist/test-helpers.d.ts +15 -0
- package/dist/test-helpers.d.ts.map +1 -0
- package/dist/test-helpers.js +65 -0
- package/dist/transport.d.ts +41 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +1 -0
- package/dist/types.d.ts +131 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/websocket-transport.d.ts +36 -0
- package/dist/websocket-transport.d.ts.map +1 -0
- package/dist/websocket-transport.js +160 -0
- package/package.json +35 -0
- package/src/client.ts +277 -0
- package/src/contract-manager.test.ts +207 -0
- package/src/contract-manager.ts +130 -0
- package/src/define-app.ts +25 -0
- package/src/direct-transport.test.ts +460 -0
- package/src/direct-transport.ts +729 -0
- package/src/errors.ts +23 -0
- package/src/event-processor.ts +133 -0
- package/src/identity-manager.ts +91 -0
- package/src/identity-serialization.ts +33 -0
- package/src/index.ts +43 -0
- package/src/persistence.ts +103 -0
- package/src/sdk.e2e.test.ts +367 -0
- package/src/state-store.ts +42 -0
- package/src/sync-manager.test.ts +414 -0
- package/src/sync-manager.ts +308 -0
- package/src/tag-templates.test.ts +111 -0
- package/src/tag-templates.ts +30 -0
- package/src/test-helpers.ts +88 -0
- package/src/transport.ts +65 -0
- package/src/types.ts +191 -0
- package/src/websocket-transport.ts +233 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { evaluateTagTemplates } from './tag-templates.js';
|
|
3
|
+
|
|
4
|
+
describe('evaluateTagTemplates', () => {
|
|
5
|
+
it('resolves simple property', () => {
|
|
6
|
+
expect(evaluateTagTemplates(['chat.${id}'], { id: 'abc' })).toEqual(['chat.abc']);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('resolves array index via dot notation', () => {
|
|
10
|
+
const data = { participants: ['alice', 'bob'] };
|
|
11
|
+
expect(evaluateTagTemplates(['participant.${participants.1}'], data)).toEqual([
|
|
12
|
+
'participant.bob',
|
|
13
|
+
]);
|
|
14
|
+
expect(evaluateTagTemplates(['participant.${participants.0}'], data)).toEqual([
|
|
15
|
+
'participant.alice',
|
|
16
|
+
]);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('resolves nested object property', () => {
|
|
20
|
+
expect(evaluateTagTemplates(['${x.y.z}'], { x: { y: { z: 'deep' } } })).toEqual(['deep']);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('returns empty string for missing property', () => {
|
|
24
|
+
expect(evaluateTagTemplates(['tag.${nonexistent}'], { id: 'abc' })).toEqual(['tag.']);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('returns static templates unchanged', () => {
|
|
28
|
+
expect(evaluateTagTemplates(['chat', 'readmarker'], {})).toEqual(['chat', 'readmarker']);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('returns empty array for empty templates', () => {
|
|
32
|
+
expect(evaluateTagTemplates([], {})).toEqual([]);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('handles multiple placeholders in one template', () => {
|
|
36
|
+
expect(evaluateTagTemplates(['${a}.${b}'], { a: 'foo', b: 'bar' })).toEqual(['foo.bar']);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('blocks prototype pollution paths', () => {
|
|
40
|
+
expect(evaluateTagTemplates(['${__proto__}'], {})).toEqual(['']);
|
|
41
|
+
expect(evaluateTagTemplates(['${constructor}'], {})).toEqual(['']);
|
|
42
|
+
expect(evaluateTagTemplates(['${prototype}'], {})).toEqual(['']);
|
|
43
|
+
expect(evaluateTagTemplates(['${x.__proto__}'], { x: {} })).toEqual(['']);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('handles null/undefined data gracefully', () => {
|
|
47
|
+
expect(evaluateTagTemplates(['${id}'], null)).toEqual(['']);
|
|
48
|
+
expect(evaluateTagTemplates(['${id}'], undefined)).toEqual(['']);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('handles numeric values', () => {
|
|
52
|
+
expect(evaluateTagTemplates(['ts.${timestamp}'], { timestamp: 123 })).toEqual(['ts.123']);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('handles boolean values', () => {
|
|
56
|
+
expect(evaluateTagTemplates(['active.${flag}'], { flag: true })).toEqual(['active.true']);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe('chat app tag templates', () => {
|
|
60
|
+
it('chat.create tags', () => {
|
|
61
|
+
const data = {
|
|
62
|
+
id: 'chat-1',
|
|
63
|
+
participants: ['did:decentrl:alice', 'did:decentrl:bob'],
|
|
64
|
+
communicationContractId: 'contract-1',
|
|
65
|
+
createdBy: 'did:decentrl:alice',
|
|
66
|
+
createdAt: 1000,
|
|
67
|
+
};
|
|
68
|
+
const templates = ['chat', 'chat.${id}', 'participant.${participants.1}'];
|
|
69
|
+
expect(evaluateTagTemplates(templates, data)).toEqual([
|
|
70
|
+
'chat',
|
|
71
|
+
'chat.chat-1',
|
|
72
|
+
'participant.did:decentrl:bob',
|
|
73
|
+
]);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('chat.message tags', () => {
|
|
77
|
+
const data = {
|
|
78
|
+
id: 'msg-1',
|
|
79
|
+
chatId: 'chat-1',
|
|
80
|
+
content: 'Hello',
|
|
81
|
+
sender: 'did:decentrl:alice',
|
|
82
|
+
timestamp: 1000,
|
|
83
|
+
};
|
|
84
|
+
expect(evaluateTagTemplates(['chat.${chatId}'], data)).toEqual(['chat.chat-1']);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('chat.react tags', () => {
|
|
88
|
+
const data = {
|
|
89
|
+
id: 'react-1',
|
|
90
|
+
messageId: 'msg-1',
|
|
91
|
+
chatId: 'chat-1',
|
|
92
|
+
emoji: '👍',
|
|
93
|
+
sender: 'did:decentrl:alice',
|
|
94
|
+
timestamp: 1000,
|
|
95
|
+
};
|
|
96
|
+
expect(evaluateTagTemplates(['chat.${chatId}'], data)).toEqual(['chat.chat-1']);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('chat.read tags', () => {
|
|
100
|
+
const data = { chatId: 'chat-1', timestamp: 1000 };
|
|
101
|
+
expect(evaluateTagTemplates(['readmarker', 'readmarker.${chatId}'], data)).toEqual([
|
|
102
|
+
'readmarker',
|
|
103
|
+
'readmarker.chat-1',
|
|
104
|
+
]);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('chat.presence tags (empty)', () => {
|
|
108
|
+
expect(evaluateTagTemplates([], { timestamp: 1000 })).toEqual([]);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export function evaluateTagTemplates(templates: string[], data: unknown): string[] {
|
|
2
|
+
return templates.map((t) => evaluateTemplate(t, data));
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function evaluateTemplate(template: string, data: unknown): string {
|
|
6
|
+
return template.replace(/\$\{([^}]+)\}/g, (_, path) => {
|
|
7
|
+
return String(resolveProperty(data, path) ?? '');
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const BLOCKED_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
12
|
+
|
|
13
|
+
function resolveProperty(obj: unknown, path: string): unknown {
|
|
14
|
+
const parts = path.split(/[.[\]]+/).filter(Boolean);
|
|
15
|
+
let value: unknown = obj;
|
|
16
|
+
|
|
17
|
+
for (const part of parts) {
|
|
18
|
+
if (BLOCKED_KEYS.has(part)) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (value == null || typeof value !== 'object') {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
value = (value as Record<string, unknown>)[part];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { vi } from 'vitest';
|
|
2
|
+
import type { ContractManager } from './contract-manager.js';
|
|
3
|
+
import type { EventProcessor } from './event-processor.js';
|
|
4
|
+
import type { IdentityManager } from './identity-manager.js';
|
|
5
|
+
import type { DecentrlTransport } from './transport.js';
|
|
6
|
+
import type { EventDefinitions, StateDefinitions, StoredSignedContract } from './types.js';
|
|
7
|
+
|
|
8
|
+
export const makeContract = (
|
|
9
|
+
overrides: Partial<StoredSignedContract> & {
|
|
10
|
+
participantDid: string;
|
|
11
|
+
expiresAt: number;
|
|
12
|
+
timestamp: number;
|
|
13
|
+
},
|
|
14
|
+
): StoredSignedContract => ({
|
|
15
|
+
id: overrides.id ?? `contract-${Math.random().toString(36).slice(2)}`,
|
|
16
|
+
participantDid: overrides.participantDid,
|
|
17
|
+
signedCommunicationContract: {
|
|
18
|
+
communication_contract: {
|
|
19
|
+
requestor_did:
|
|
20
|
+
overrides.signedCommunicationContract?.communication_contract?.requestor_did ??
|
|
21
|
+
'did:decentrl:alice',
|
|
22
|
+
recipient_did: overrides.participantDid,
|
|
23
|
+
requestor_signing_key_id: 'did:decentrl:alice#signing',
|
|
24
|
+
recipient_signing_key_id: `${overrides.participantDid}#signing`,
|
|
25
|
+
requestor_encryption_public_key: 'key-a',
|
|
26
|
+
recipient_encryption_public_key: 'key-b',
|
|
27
|
+
expires_at: overrides.expiresAt,
|
|
28
|
+
timestamp: overrides.timestamp,
|
|
29
|
+
},
|
|
30
|
+
requestor_signature: 'sig-a',
|
|
31
|
+
recipient_signature: 'sig-b',
|
|
32
|
+
},
|
|
33
|
+
rootSecret: overrides.rootSecret ?? 'c2VjcmV0',
|
|
34
|
+
createdAt: overrides.createdAt ?? Date.now(),
|
|
35
|
+
status: overrides.status ?? 'active',
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export const createMockIdentityManager = (
|
|
39
|
+
overrides: Partial<Record<keyof IdentityManager, unknown>> = {},
|
|
40
|
+
) =>
|
|
41
|
+
({
|
|
42
|
+
requireIdentity: vi.fn(() => ({
|
|
43
|
+
did: 'did:decentrl:alice',
|
|
44
|
+
mediatorDid: 'did:web:mediator',
|
|
45
|
+
mediatorEndpoint: 'http://mediator',
|
|
46
|
+
keys: {
|
|
47
|
+
signing: {
|
|
48
|
+
privateKey: new Uint8Array(32),
|
|
49
|
+
publicKey: new Uint8Array(32),
|
|
50
|
+
},
|
|
51
|
+
encryption: {
|
|
52
|
+
privateKey: new Uint8Array(32),
|
|
53
|
+
publicKey: new Uint8Array(32),
|
|
54
|
+
},
|
|
55
|
+
storageKey: new Uint8Array(32),
|
|
56
|
+
},
|
|
57
|
+
})),
|
|
58
|
+
getIdentity: vi.fn(() => null),
|
|
59
|
+
...overrides,
|
|
60
|
+
}) as unknown as IdentityManager;
|
|
61
|
+
|
|
62
|
+
export const createMockTransport = (overrides: Partial<DecentrlTransport> = {}) =>
|
|
63
|
+
({
|
|
64
|
+
refreshContracts: vi.fn(async () => []),
|
|
65
|
+
processAutoRenewals: vi.fn(async () => {}),
|
|
66
|
+
processContractCleanup: vi.fn(async () => {}),
|
|
67
|
+
requestContract: vi.fn(async () => {}),
|
|
68
|
+
getPendingContracts: vi.fn(async () => []),
|
|
69
|
+
acceptContract: vi.fn(async () => {}),
|
|
70
|
+
getActiveContracts: vi.fn(() => []),
|
|
71
|
+
processPendingEvents: vi.fn(async () => []),
|
|
72
|
+
...overrides,
|
|
73
|
+
}) as unknown as DecentrlTransport;
|
|
74
|
+
|
|
75
|
+
export const createMockEventProcessor = (overrides: Partial<Record<string, unknown>> = {}) =>
|
|
76
|
+
({
|
|
77
|
+
processBatch: vi.fn(() => 0),
|
|
78
|
+
computeTagsSafe: vi.fn((type: string) => [`tag:${type}`]),
|
|
79
|
+
...overrides,
|
|
80
|
+
}) as unknown as EventProcessor<EventDefinitions, StateDefinitions<EventDefinitions>>;
|
|
81
|
+
|
|
82
|
+
export const createMockContractManager = (overrides: Partial<Record<string, unknown>> = {}) =>
|
|
83
|
+
({
|
|
84
|
+
refresh: vi.fn(async () => {}),
|
|
85
|
+
processAutoRenewals: vi.fn(async () => {}),
|
|
86
|
+
processContractCleanup: vi.fn(async () => {}),
|
|
87
|
+
...overrides,
|
|
88
|
+
}) as unknown as ContractManager;
|
package/src/transport.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
EventEnvelope,
|
|
3
|
+
PendingContractRequest,
|
|
4
|
+
SerializedIdentity,
|
|
5
|
+
StoredSignedContract,
|
|
6
|
+
} from './types.js';
|
|
7
|
+
|
|
8
|
+
export interface DecentrlTransport {
|
|
9
|
+
// Identity
|
|
10
|
+
createIdentity(options: { alias: string; mediatorDid: string }): Promise<SerializedIdentity>;
|
|
11
|
+
getIdentity(): SerializedIdentity | null;
|
|
12
|
+
loadIdentity?(serialized: SerializedIdentity): void;
|
|
13
|
+
|
|
14
|
+
// Events
|
|
15
|
+
publishEvent(
|
|
16
|
+
envelope: EventEnvelope,
|
|
17
|
+
options: { tags: string[]; recipient?: string; ephemeral?: boolean },
|
|
18
|
+
): Promise<void>;
|
|
19
|
+
processPendingEvents(): Promise<EventEnvelope[]>;
|
|
20
|
+
processPreFetchedPendingEvents?(
|
|
21
|
+
rawEvents: Array<{ id: string; sender_did: string; payload: string }>,
|
|
22
|
+
): Promise<EventEnvelope[]>;
|
|
23
|
+
|
|
24
|
+
// Contracts
|
|
25
|
+
requestContract(recipientDid: string, expiresIn?: number): Promise<void>;
|
|
26
|
+
getPendingContracts(): Promise<PendingContractRequest[]>;
|
|
27
|
+
acceptContract(
|
|
28
|
+
pendingId: string,
|
|
29
|
+
encryptedPayload: string,
|
|
30
|
+
requestorEphemeralPublicKey: string,
|
|
31
|
+
): Promise<void>;
|
|
32
|
+
refreshContracts(): Promise<StoredSignedContract[]>;
|
|
33
|
+
getActiveContracts(): StoredSignedContract[];
|
|
34
|
+
|
|
35
|
+
// Optional: auto-renew expiring contracts
|
|
36
|
+
processAutoRenewals?(threshold: number): Promise<void>;
|
|
37
|
+
|
|
38
|
+
// Optional: clean up old superseded contracts
|
|
39
|
+
processContractCleanup?(): Promise<void>;
|
|
40
|
+
|
|
41
|
+
// Optional: query archived contract history
|
|
42
|
+
getContractHistory?(): Promise<import('./types.js').ArchivedContract[]>;
|
|
43
|
+
|
|
44
|
+
// Optional: query stored events (extension proxy mode)
|
|
45
|
+
queryEvents?(
|
|
46
|
+
options?: import('./types.js').QueryOptions,
|
|
47
|
+
): Promise<import('./types.js').PaginatedResult<EventEnvelope>>;
|
|
48
|
+
|
|
49
|
+
// Optional: push-based event delivery (extension mode)
|
|
50
|
+
onEvents?(listener: (events: EventEnvelope[]) => void): () => void;
|
|
51
|
+
|
|
52
|
+
// Optional: push-based contract change notification (extension mode)
|
|
53
|
+
onContractsChanged?(listener: () => void): () => void;
|
|
54
|
+
|
|
55
|
+
// Optional: update event tags on mediator (app-side tag enrichment)
|
|
56
|
+
updateEventTags?(events: Array<{ eventId: string; tags: string[] }>): Promise<void>;
|
|
57
|
+
|
|
58
|
+
// Optional: query events not yet processed by the app
|
|
59
|
+
queryUnprocessedEvents?(pagination?: {
|
|
60
|
+
page: number;
|
|
61
|
+
pageSize: number;
|
|
62
|
+
}): Promise<import('./types.js').PaginatedResult<EventEnvelope>>;
|
|
63
|
+
|
|
64
|
+
dispose(): void;
|
|
65
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import type { DecentrlIdentityKeys } from '@decentrl/crypto';
|
|
2
|
+
import type { SignedCommunicationContract } from '@decentrl/identity/communication-contract/communication-contract.schema';
|
|
3
|
+
import type { z } from 'zod';
|
|
4
|
+
|
|
5
|
+
// --- Event Definition Types ---
|
|
6
|
+
|
|
7
|
+
export interface EventDefinition<TSchema extends z.ZodType = z.ZodType> {
|
|
8
|
+
schema: TSchema;
|
|
9
|
+
tags: string[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type EventDefinitions = Record<
|
|
13
|
+
string,
|
|
14
|
+
{
|
|
15
|
+
schema: z.ZodType;
|
|
16
|
+
tags: string[];
|
|
17
|
+
}
|
|
18
|
+
>;
|
|
19
|
+
|
|
20
|
+
// --- State Slice Types ---
|
|
21
|
+
|
|
22
|
+
export interface StateSliceDefinition<
|
|
23
|
+
TSlice = unknown,
|
|
24
|
+
TEvents extends EventDefinitions = EventDefinitions,
|
|
25
|
+
> {
|
|
26
|
+
initial: TSlice;
|
|
27
|
+
reduce: {
|
|
28
|
+
[K in keyof TEvents]?: (
|
|
29
|
+
state: TSlice,
|
|
30
|
+
data: z.infer<TEvents[K]['schema']>,
|
|
31
|
+
meta: EventMeta,
|
|
32
|
+
) => TSlice;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type StateDefinitions<TEvents extends EventDefinitions = EventDefinitions> = Record<
|
|
37
|
+
string,
|
|
38
|
+
StateSliceDefinition<any, TEvents>
|
|
39
|
+
>;
|
|
40
|
+
|
|
41
|
+
// --- Inferred State ---
|
|
42
|
+
|
|
43
|
+
export type InferState<TState extends StateDefinitions> = {
|
|
44
|
+
[K in keyof TState]: TState[K]['initial'];
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// --- Event Meta & Envelope ---
|
|
48
|
+
|
|
49
|
+
export interface EventMeta {
|
|
50
|
+
senderDid: string;
|
|
51
|
+
timestamp: number;
|
|
52
|
+
eventId: string;
|
|
53
|
+
ephemeral?: boolean;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface EventEnvelope {
|
|
57
|
+
type: string;
|
|
58
|
+
data: unknown;
|
|
59
|
+
meta: EventMeta;
|
|
60
|
+
tags?: string[];
|
|
61
|
+
_mediatorEventId?: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// --- Client Config ---
|
|
65
|
+
|
|
66
|
+
export interface DecentrlClientConfig {
|
|
67
|
+
mediatorDid: string;
|
|
68
|
+
/** Enable localStorage persistence. Pass a key prefix (e.g. "decentrl-myapp"). */
|
|
69
|
+
persist?: { key: string };
|
|
70
|
+
/** Optional transport layer. Defaults to DirectTransport (direct HTTP to mediator). */
|
|
71
|
+
transport?: import('./transport.js').DecentrlTransport;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// --- App Config ---
|
|
75
|
+
|
|
76
|
+
export interface DecentrlAppConfig<
|
|
77
|
+
TEvents extends EventDefinitions = EventDefinitions,
|
|
78
|
+
TState extends StateDefinitions<TEvents> = StateDefinitions<TEvents>,
|
|
79
|
+
> {
|
|
80
|
+
events: TEvents;
|
|
81
|
+
state: TState;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// --- Serialized Identity ---
|
|
85
|
+
|
|
86
|
+
export interface SerializedKeyPair {
|
|
87
|
+
privateKey: string;
|
|
88
|
+
publicKey: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface SerializedIdentity {
|
|
92
|
+
did: string;
|
|
93
|
+
alias: string;
|
|
94
|
+
mediatorDid: string;
|
|
95
|
+
mediatorEndpoint: string;
|
|
96
|
+
keys: {
|
|
97
|
+
signing: SerializedKeyPair;
|
|
98
|
+
encryption: SerializedKeyPair;
|
|
99
|
+
storageKey: string;
|
|
100
|
+
};
|
|
101
|
+
mediatorContract: SignedCommunicationContract | null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// --- Identity State ---
|
|
105
|
+
|
|
106
|
+
export interface IdentityState {
|
|
107
|
+
did: string;
|
|
108
|
+
alias: string;
|
|
109
|
+
mediatorDid: string;
|
|
110
|
+
mediatorEndpoint: string;
|
|
111
|
+
keys: DecentrlIdentityKeys;
|
|
112
|
+
mediatorContract: SignedCommunicationContract | null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// --- Contract Types ---
|
|
116
|
+
|
|
117
|
+
export interface StoredSignedContract {
|
|
118
|
+
id: string;
|
|
119
|
+
participantDid: string;
|
|
120
|
+
participantAlias?: string;
|
|
121
|
+
signedCommunicationContract: SignedCommunicationContract;
|
|
122
|
+
rootSecret: string;
|
|
123
|
+
createdAt: number;
|
|
124
|
+
status: 'active' | 'expired' | 'superseded';
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface ArchivedContract {
|
|
128
|
+
contractId: string;
|
|
129
|
+
participantDid: string;
|
|
130
|
+
participantAlias?: string;
|
|
131
|
+
timestamp: number; // contract creation (seconds)
|
|
132
|
+
expiresAt: number; // contract expiry (seconds)
|
|
133
|
+
supersededAt: number; // when it was archived (ms)
|
|
134
|
+
supersededBy: string; // the replacing contract ID
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export interface PendingContractRequest {
|
|
138
|
+
id: string;
|
|
139
|
+
senderDid: string;
|
|
140
|
+
encryptedPayload: string;
|
|
141
|
+
requestorEphemeralPublicKey: string;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// --- Query Options ---
|
|
145
|
+
|
|
146
|
+
export interface QueryOptions {
|
|
147
|
+
tags?: string[];
|
|
148
|
+
participantDid?: string;
|
|
149
|
+
afterTimestamp?: number;
|
|
150
|
+
beforeTimestamp?: number;
|
|
151
|
+
pagination?: { page: number; pageSize: number };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface PaginationMeta {
|
|
155
|
+
page: number;
|
|
156
|
+
pageSize: number;
|
|
157
|
+
total: number;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export interface PaginatedResult<T> {
|
|
161
|
+
data: T[];
|
|
162
|
+
pagination: PaginationMeta;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// --- Publish Options ---
|
|
166
|
+
|
|
167
|
+
export interface PublishOptions {
|
|
168
|
+
recipient?: string;
|
|
169
|
+
ephemeral?: boolean;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// --- Sync Options ---
|
|
173
|
+
|
|
174
|
+
export interface SyncOptions {
|
|
175
|
+
intervalMs?: number;
|
|
176
|
+
fallbackIntervalMs?: number;
|
|
177
|
+
onError?: (error: unknown) => void;
|
|
178
|
+
websocket?: boolean;
|
|
179
|
+
autoRenew?: {
|
|
180
|
+
enabled: boolean;
|
|
181
|
+
threshold?: number; // fraction of lifetime remaining before renewal, default 0.2
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// --- Connection Status ---
|
|
186
|
+
|
|
187
|
+
export type { ConnectionStatus } from './websocket-transport.js';
|
|
188
|
+
|
|
189
|
+
// --- Listener ---
|
|
190
|
+
|
|
191
|
+
export type StateListener<TState> = (state: TState) => void;
|