@decentrl/sdk 0.0.6 → 0.0.8
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 +15 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +74 -14
- package/dist/define-app.d.ts +5 -5
- package/dist/define-app.d.ts.map +1 -1
- package/dist/direct-transport.d.ts +32 -0
- package/dist/direct-transport.d.ts.map +1 -1
- package/dist/direct-transport.js +26 -0
- package/dist/event-processor.d.ts +12 -2
- package/dist/event-processor.d.ts.map +1 -1
- package/dist/event-processor.js +100 -3
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/public-channel-reader.d.ts +21 -0
- package/dist/public-channel-reader.d.ts.map +1 -0
- package/dist/public-channel-reader.js +169 -0
- package/dist/transport.d.ts +32 -0
- package/dist/transport.d.ts.map +1 -1
- package/dist/types.d.ts +84 -7
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/client.ts +132 -19
- package/src/define-app.ts +19 -5
- package/src/direct-transport-public.test.ts +139 -0
- package/src/direct-transport.ts +55 -0
- package/src/event-processor-public.test.ts +343 -0
- package/src/event-processor.ts +144 -5
- package/src/index.ts +11 -0
- package/src/public-channel-reader.ts +239 -0
- package/src/sdk.e2e.test.ts +165 -0
- package/src/transport.ts +32 -0
- package/src/types.ts +138 -13
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { multibaseDecode, verifyJsonSignature } from '@decentrl/crypto';
|
|
2
|
+
import { resolveMediatorServiceEndpoint } from '@decentrl/identity/mediator/mediator.resolver';
|
|
3
|
+
export class PublicChannelReader {
|
|
4
|
+
transport;
|
|
5
|
+
eventProcessor;
|
|
6
|
+
channelDefinitions;
|
|
7
|
+
subscriptions = new Map();
|
|
8
|
+
mediatorEndpointCache = new Map();
|
|
9
|
+
signingKeyCache = new Map();
|
|
10
|
+
constructor(transport, eventProcessor, channelDefinitions) {
|
|
11
|
+
this.transport = transport;
|
|
12
|
+
this.eventProcessor = eventProcessor;
|
|
13
|
+
this.channelDefinitions = channelDefinitions;
|
|
14
|
+
}
|
|
15
|
+
subscribe(config) {
|
|
16
|
+
const subId = crypto.randomUUID();
|
|
17
|
+
const pollIntervalMs = config.pollIntervalMs ?? 10_000;
|
|
18
|
+
let afterTimestamp = Math.floor(Date.now() / 1000);
|
|
19
|
+
const poll = async () => {
|
|
20
|
+
try {
|
|
21
|
+
const mediatorEndpoint = await this.resolveMediatorEndpoint(config.did);
|
|
22
|
+
if (!this.transport.fetchPublicEvents) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const result = await this.transport.fetchPublicEvents({
|
|
26
|
+
mediatorEndpoint,
|
|
27
|
+
publisherDid: config.did,
|
|
28
|
+
channelId: config.channelId,
|
|
29
|
+
tags: config.tags,
|
|
30
|
+
afterTimestamp,
|
|
31
|
+
});
|
|
32
|
+
for (const event of result.events) {
|
|
33
|
+
const parsed = await this.parseAndVerifyPublicEvent(event, config.did);
|
|
34
|
+
if (parsed) {
|
|
35
|
+
this.eventProcessor.processChannelEvent(parsed);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (result.events.length > 0) {
|
|
39
|
+
const maxTimestamp = Math.max(...result.events.map((e) => e.timestamp));
|
|
40
|
+
afterTimestamp = maxTimestamp;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
console.warn('[Decentrl] Public channel poll failed:', err);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
poll();
|
|
48
|
+
const intervalId = setInterval(poll, pollIntervalMs);
|
|
49
|
+
this.subscriptions.set(subId, { intervalId });
|
|
50
|
+
return {
|
|
51
|
+
unsubscribe: () => {
|
|
52
|
+
const sub = this.subscriptions.get(subId);
|
|
53
|
+
if (sub) {
|
|
54
|
+
clearInterval(sub.intervalId);
|
|
55
|
+
this.subscriptions.delete(subId);
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
async fetch(options) {
|
|
61
|
+
const mediatorEndpoint = options.mediatorEndpoint ?? (await this.resolveMediatorEndpoint(options.did));
|
|
62
|
+
if (!this.transport.fetchPublicEvents) {
|
|
63
|
+
return { data: [], pagination: { page: 0, pageSize: 20, total: 0 } };
|
|
64
|
+
}
|
|
65
|
+
const result = await this.transport.fetchPublicEvents({
|
|
66
|
+
mediatorEndpoint,
|
|
67
|
+
publisherDid: options.did,
|
|
68
|
+
channelId: options.channelId,
|
|
69
|
+
tags: options.tags,
|
|
70
|
+
afterTimestamp: options.afterTimestamp,
|
|
71
|
+
beforeTimestamp: options.beforeTimestamp,
|
|
72
|
+
page: options.pagination?.page,
|
|
73
|
+
pageSize: options.pagination?.pageSize,
|
|
74
|
+
});
|
|
75
|
+
return {
|
|
76
|
+
data: result.events,
|
|
77
|
+
pagination: result.pagination,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
dispose() {
|
|
81
|
+
for (const sub of this.subscriptions.values()) {
|
|
82
|
+
clearInterval(sub.intervalId);
|
|
83
|
+
}
|
|
84
|
+
this.subscriptions.clear();
|
|
85
|
+
}
|
|
86
|
+
async parseAndVerifyPublicEvent(raw, publisherDid) {
|
|
87
|
+
try {
|
|
88
|
+
// Verify signature over { channel_id, event, tags, timestamp }
|
|
89
|
+
const signingKey = this.resolveSigningKeyFromDid(publisherDid);
|
|
90
|
+
if (signingKey) {
|
|
91
|
+
const signedData = {
|
|
92
|
+
channel_id: raw.channelId,
|
|
93
|
+
event: raw.event,
|
|
94
|
+
tags: raw.tags,
|
|
95
|
+
timestamp: raw.timestamp,
|
|
96
|
+
};
|
|
97
|
+
const isValid = verifyJsonSignature(signedData, raw.eventSignature, signingKey);
|
|
98
|
+
if (!isValid) {
|
|
99
|
+
console.warn(`[Decentrl] Invalid signature on public event ${raw.id}, skipping`);
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const parsed = JSON.parse(raw.event);
|
|
104
|
+
const eventType = parsed.type;
|
|
105
|
+
if (!eventType || typeof eventType !== 'string') {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
if (this.channelDefinitions &&
|
|
109
|
+
!this.eventProcessor.validateChannelEvent(eventType, parsed.data)) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
type: eventType,
|
|
114
|
+
data: parsed.data,
|
|
115
|
+
meta: {
|
|
116
|
+
publisherDid,
|
|
117
|
+
timestamp: raw.timestamp,
|
|
118
|
+
eventId: raw.id,
|
|
119
|
+
channelId: raw.channelId,
|
|
120
|
+
},
|
|
121
|
+
tags: raw.tags,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
resolveSigningKeyFromDid(did) {
|
|
129
|
+
const cached = this.signingKeyCache.get(did);
|
|
130
|
+
if (cached) {
|
|
131
|
+
return cached;
|
|
132
|
+
}
|
|
133
|
+
// did:decentrl:alias:signingKey:encKey:mediatorHost
|
|
134
|
+
if (!did.startsWith('did:decentrl:')) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
const parts = did.replace('did:decentrl:', '').split(':');
|
|
138
|
+
if (parts.length < 2) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
const key = multibaseDecode(parts[1]);
|
|
143
|
+
this.signingKeyCache.set(did, key);
|
|
144
|
+
return key;
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async resolveMediatorEndpoint(did) {
|
|
151
|
+
const cached = this.mediatorEndpointCache.get(did);
|
|
152
|
+
if (cached) {
|
|
153
|
+
return cached;
|
|
154
|
+
}
|
|
155
|
+
const parts = did.replace('did:decentrl:', '').split(':');
|
|
156
|
+
if (parts.length >= 4) {
|
|
157
|
+
const mediatorDid = `did:web:${parts[3]}`;
|
|
158
|
+
const endpoint = await resolveMediatorServiceEndpoint(mediatorDid);
|
|
159
|
+
this.mediatorEndpointCache.set(did, endpoint);
|
|
160
|
+
return endpoint;
|
|
161
|
+
}
|
|
162
|
+
if (did.startsWith('did:web:')) {
|
|
163
|
+
const endpoint = await resolveMediatorServiceEndpoint(did);
|
|
164
|
+
this.mediatorEndpointCache.set(did, endpoint);
|
|
165
|
+
return endpoint;
|
|
166
|
+
}
|
|
167
|
+
throw new Error(`Cannot resolve mediator endpoint for DID: ${did}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
package/dist/transport.d.ts
CHANGED
|
@@ -36,6 +36,38 @@ export interface DecentrlTransport {
|
|
|
36
36
|
page: number;
|
|
37
37
|
pageSize: number;
|
|
38
38
|
}): Promise<import('./types.js').PaginatedResult<EventEnvelope>>;
|
|
39
|
+
publishPublicEvent?(options: {
|
|
40
|
+
channelId: string;
|
|
41
|
+
event: string;
|
|
42
|
+
tags: string[];
|
|
43
|
+
}): Promise<{
|
|
44
|
+
publicEventId: string;
|
|
45
|
+
}>;
|
|
46
|
+
deletePublicEvent?(publicEventId: string, eventType?: string): Promise<void>;
|
|
47
|
+
fetchPublicEvents?(options: {
|
|
48
|
+
mediatorEndpoint: string;
|
|
49
|
+
publisherDid: string;
|
|
50
|
+
channelId?: string;
|
|
51
|
+
tags?: string[];
|
|
52
|
+
afterTimestamp?: number;
|
|
53
|
+
beforeTimestamp?: number;
|
|
54
|
+
page?: number;
|
|
55
|
+
pageSize?: number;
|
|
56
|
+
}): Promise<{
|
|
57
|
+
events: Array<{
|
|
58
|
+
id: string;
|
|
59
|
+
channelId: string;
|
|
60
|
+
event: string;
|
|
61
|
+
tags: string[];
|
|
62
|
+
timestamp: number;
|
|
63
|
+
eventSignature: string;
|
|
64
|
+
}>;
|
|
65
|
+
pagination: {
|
|
66
|
+
page: number;
|
|
67
|
+
pageSize: number;
|
|
68
|
+
total: number;
|
|
69
|
+
};
|
|
70
|
+
}>;
|
|
39
71
|
dispose(): void;
|
|
40
72
|
}
|
|
41
73
|
//# sourceMappingURL=transport.d.ts.map
|
package/dist/transport.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,aAAa,EACb,sBAAsB,EACtB,kBAAkB,EAClB,oBAAoB,EACpB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,iBAAiB;IAEjC,cAAc,CAAC,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC7F,WAAW,IAAI,kBAAkB,GAAG,IAAI,CAAC;IACzC,YAAY,CAAC,CAAC,UAAU,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAGpD,YAAY,CACX,QAAQ,EAAE,aAAa,EACvB,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,GAClE,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,oBAAoB,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;IACjD,8BAA8B,CAAC,CAC9B,SAAS,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,GACnE,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;IAG5B,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,mBAAmB,IAAI,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAAC;IACzD,cAAc,CACb,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,MAAM,EACxB,2BAA2B,EAAE,MAAM,GACjC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,gBAAgB,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC;IACpD,kBAAkB,IAAI,oBAAoB,EAAE,CAAC;IAG7C,mBAAmB,CAAC,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAGvD,sBAAsB,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAGzC,kBAAkB,CAAC,IAAI,OAAO,CAAC,OAAO,YAAY,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAGxE,WAAW,CAAC,CACX,OAAO,CAAC,EAAE,OAAO,YAAY,EAAE,YAAY,GACzC,OAAO,CAAC,OAAO,YAAY,EAAE,eAAe,CAAC,aAAa,CAAC,CAAC,CAAC;IAGhE,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAGnE,kBAAkB,CAAC,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;IAGtD,eAAe,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAGpF,sBAAsB,CAAC,CAAC,UAAU,CAAC,EAAE;QACpC,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;KACjB,GAAG,OAAO,CAAC,OAAO,YAAY,EAAE,eAAe,CAAC,aAAa,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,aAAa,EACb,sBAAsB,EACtB,kBAAkB,EAClB,oBAAoB,EACpB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,iBAAiB;IAEjC,cAAc,CAAC,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC7F,WAAW,IAAI,kBAAkB,GAAG,IAAI,CAAC;IACzC,YAAY,CAAC,CAAC,UAAU,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAGpD,YAAY,CACX,QAAQ,EAAE,aAAa,EACvB,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,GAClE,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,oBAAoB,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;IACjD,8BAA8B,CAAC,CAC9B,SAAS,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,GACnE,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;IAG5B,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,mBAAmB,IAAI,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAAC;IACzD,cAAc,CACb,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,MAAM,EACxB,2BAA2B,EAAE,MAAM,GACjC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,gBAAgB,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC;IACpD,kBAAkB,IAAI,oBAAoB,EAAE,CAAC;IAG7C,mBAAmB,CAAC,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAGvD,sBAAsB,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAGzC,kBAAkB,CAAC,IAAI,OAAO,CAAC,OAAO,YAAY,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAGxE,WAAW,CAAC,CACX,OAAO,CAAC,EAAE,OAAO,YAAY,EAAE,YAAY,GACzC,OAAO,CAAC,OAAO,YAAY,EAAE,eAAe,CAAC,aAAa,CAAC,CAAC,CAAC;IAGhE,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAGnE,kBAAkB,CAAC,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;IAGtD,eAAe,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAGpF,sBAAsB,CAAC,CAAC,UAAU,CAAC,EAAE;QACpC,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;KACjB,GAAG,OAAO,CAAC,OAAO,YAAY,EAAE,eAAe,CAAC,aAAa,CAAC,CAAC,CAAC;IAGjE,kBAAkB,CAAC,CAAC,OAAO,EAAE;QAC5B,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,EAAE,CAAC;KACf,GAAG,OAAO,CAAC;QAAE,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAGvC,iBAAiB,CAAC,CAAC,aAAa,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAG7E,iBAAiB,CAAC,CAAC,OAAO,EAAE;QAC3B,gBAAgB,EAAE,MAAM,CAAC;QACzB,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC;QACX,MAAM,EAAE,KAAK,CAAC;YACb,EAAE,EAAE,MAAM,CAAC;YACX,SAAS,EAAE,MAAM,CAAC;YAClB,KAAK,EAAE,MAAM,CAAC;YACd,IAAI,EAAE,MAAM,EAAE,CAAC;YACf,SAAS,EAAE,MAAM,CAAC;YAClB,cAAc,EAAE,MAAM,CAAC;SACvB,CAAC,CAAC;QACH,UAAU,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;KAC9D,CAAC,CAAC;IAEH,OAAO,IAAI,IAAI,CAAC;CAChB"}
|
package/dist/types.d.ts
CHANGED
|
@@ -9,13 +9,66 @@ export type EventDefinitions = Record<string, {
|
|
|
9
9
|
schema: z.ZodType;
|
|
10
10
|
tags: string[];
|
|
11
11
|
}>;
|
|
12
|
-
export interface
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
export interface PublicEventDefinition<TSchema extends z.ZodType = z.ZodType> {
|
|
13
|
+
schema: TSchema;
|
|
14
|
+
tags: string[];
|
|
15
|
+
channelId: string;
|
|
16
|
+
}
|
|
17
|
+
export type PublicEventDefinitions = Record<string, {
|
|
18
|
+
schema: z.ZodType;
|
|
19
|
+
tags: string[];
|
|
20
|
+
channelId: string;
|
|
21
|
+
}>;
|
|
22
|
+
export interface ChannelDefinition<TSchema extends z.ZodType = z.ZodType> {
|
|
23
|
+
schema: TSchema;
|
|
24
|
+
}
|
|
25
|
+
export type ChannelDefinitions = Record<string, {
|
|
26
|
+
schema: z.ZodType;
|
|
27
|
+
}>;
|
|
28
|
+
export interface PublicEventMeta {
|
|
29
|
+
publisherDid: string;
|
|
30
|
+
timestamp: number;
|
|
31
|
+
eventId: string;
|
|
32
|
+
channelId: string;
|
|
33
|
+
}
|
|
34
|
+
export interface PublicEventEnvelope {
|
|
35
|
+
type: string;
|
|
36
|
+
data: unknown;
|
|
37
|
+
meta: PublicEventMeta;
|
|
38
|
+
tags?: string[];
|
|
39
|
+
}
|
|
40
|
+
export interface ChannelSubscriptionConfig {
|
|
41
|
+
did: string;
|
|
42
|
+
channelId: string;
|
|
43
|
+
tags?: string[];
|
|
44
|
+
pollIntervalMs?: number;
|
|
45
|
+
}
|
|
46
|
+
export interface ChannelFetchOptions {
|
|
47
|
+
did: string;
|
|
48
|
+
mediatorEndpoint?: string;
|
|
49
|
+
channelId?: string;
|
|
50
|
+
tags?: string[];
|
|
51
|
+
afterTimestamp?: number;
|
|
52
|
+
beforeTimestamp?: number;
|
|
53
|
+
pagination?: {
|
|
54
|
+
page: number;
|
|
55
|
+
pageSize: number;
|
|
16
56
|
};
|
|
17
57
|
}
|
|
18
|
-
|
|
58
|
+
type PrivateReducers<TSlice, TEvents extends EventDefinitions> = {
|
|
59
|
+
[K in string & keyof TEvents]?: (state: TSlice, data: z.infer<TEvents[K]['schema']>, meta: EventMeta) => TSlice;
|
|
60
|
+
};
|
|
61
|
+
type PublicReducers<TSlice, TPublicEvents extends PublicEventDefinitions> = {
|
|
62
|
+
[K in string & keyof TPublicEvents as `public:${K}`]?: (state: TSlice, data: z.infer<TPublicEvents[K]['schema']>, meta: PublicEventMeta) => TSlice;
|
|
63
|
+
};
|
|
64
|
+
type ChannelReducers<TSlice, TChannels extends ChannelDefinitions> = {
|
|
65
|
+
[K in string & keyof TChannels as `channel:${K}`]?: (state: TSlice, data: z.infer<TChannels[K]['schema']>, meta: PublicEventMeta) => TSlice;
|
|
66
|
+
};
|
|
67
|
+
export interface StateSliceDefinition<TSlice = unknown, TEvents extends EventDefinitions = EventDefinitions, TPublicEvents extends PublicEventDefinitions = PublicEventDefinitions, TChannels extends ChannelDefinitions = ChannelDefinitions> {
|
|
68
|
+
initial: TSlice;
|
|
69
|
+
reduce: PrivateReducers<TSlice, TEvents> & PublicReducers<TSlice, TPublicEvents> & ChannelReducers<TSlice, TChannels>;
|
|
70
|
+
}
|
|
71
|
+
export type StateDefinitions<TEvents extends EventDefinitions = EventDefinitions, TPublicEvents extends PublicEventDefinitions = PublicEventDefinitions, TChannels extends ChannelDefinitions = ChannelDefinitions> = Record<string, StateSliceDefinition<unknown, TEvents, TPublicEvents, TChannels>>;
|
|
19
72
|
export type InferState<TState extends StateDefinitions> = {
|
|
20
73
|
[K in keyof TState]: TState[K]['initial'];
|
|
21
74
|
};
|
|
@@ -33,7 +86,7 @@ export interface EventEnvelope {
|
|
|
33
86
|
_mediatorEventId?: string;
|
|
34
87
|
}
|
|
35
88
|
export interface DecentrlClientConfig {
|
|
36
|
-
mediatorDid
|
|
89
|
+
mediatorDid?: string;
|
|
37
90
|
/** Enable localStorage persistence. Pass a key prefix (e.g. "decentrl-myapp"). */
|
|
38
91
|
persist?: {
|
|
39
92
|
key: string;
|
|
@@ -41,9 +94,11 @@ export interface DecentrlClientConfig {
|
|
|
41
94
|
/** Optional transport layer. Defaults to DirectTransport (direct HTTP to mediator). */
|
|
42
95
|
transport?: import('./transport.js').DecentrlTransport;
|
|
43
96
|
}
|
|
44
|
-
export interface DecentrlAppConfig<TEvents extends EventDefinitions = EventDefinitions, TState extends StateDefinitions<TEvents> = StateDefinitions<TEvents>> {
|
|
97
|
+
export interface DecentrlAppConfig<TEvents extends EventDefinitions = EventDefinitions, TPublicEvents extends PublicEventDefinitions = PublicEventDefinitions, TChannels extends ChannelDefinitions = ChannelDefinitions, TState extends StateDefinitions<TEvents, TPublicEvents, TChannels> = StateDefinitions<TEvents, TPublicEvents, TChannels>> {
|
|
45
98
|
events: TEvents;
|
|
46
99
|
state: TState;
|
|
100
|
+
publicEvents?: TPublicEvents;
|
|
101
|
+
channels?: TChannels;
|
|
47
102
|
}
|
|
48
103
|
export interface SerializedKeyPair {
|
|
49
104
|
privateKey: string;
|
|
@@ -112,6 +167,28 @@ export interface PaginatedResult<T> {
|
|
|
112
167
|
data: T[];
|
|
113
168
|
pagination: PaginationMeta;
|
|
114
169
|
}
|
|
170
|
+
export interface PublicQueryOptions {
|
|
171
|
+
publisherDid: string;
|
|
172
|
+
mediatorEndpoint?: string;
|
|
173
|
+
channelId?: string;
|
|
174
|
+
tags?: string[];
|
|
175
|
+
/** Unix timestamp in seconds */
|
|
176
|
+
afterTimestamp?: number;
|
|
177
|
+
/** Unix timestamp in seconds */
|
|
178
|
+
beforeTimestamp?: number;
|
|
179
|
+
pagination?: {
|
|
180
|
+
page: number;
|
|
181
|
+
pageSize: number;
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
export interface PublicEventResult {
|
|
185
|
+
id: string;
|
|
186
|
+
channelId: string;
|
|
187
|
+
event: string;
|
|
188
|
+
tags: string[];
|
|
189
|
+
timestamp: number;
|
|
190
|
+
eventSignature: string;
|
|
191
|
+
}
|
|
115
192
|
export interface PublishOptions {
|
|
116
193
|
recipient?: string;
|
|
117
194
|
ephemeral?: boolean;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yEAAyE,CAAC;AAC3H,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAI7B,MAAM,WAAW,eAAe,CAAC,OAAO,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO;IACrE,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CACf;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,CACpC,MAAM,EACN;IACC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,EAAE,CAAC;CACf,CACD,CAAC;AAIF,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decentrl/sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"description": "Declarative SDK for building Decentrl protocol applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"zod": "^4.0.10",
|
|
10
10
|
"axios": "1.11.0",
|
|
11
|
-
"@decentrl/crypto": "0.0.
|
|
12
|
-
"@decentrl/identity": "0.0.
|
|
13
|
-
"@decentrl/event-store": "0.0.
|
|
11
|
+
"@decentrl/crypto": "0.0.8",
|
|
12
|
+
"@decentrl/identity": "0.0.8",
|
|
13
|
+
"@decentrl/event-store": "0.0.8"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
16
|
"typescript": "^5.8.3",
|
package/src/client.ts
CHANGED
|
@@ -10,10 +10,14 @@ import {
|
|
|
10
10
|
persistIdentity,
|
|
11
11
|
persistState,
|
|
12
12
|
} from './persistence.js';
|
|
13
|
+
import { PublicChannelReader } from './public-channel-reader.js';
|
|
13
14
|
import { StateStore } from './state-store.js';
|
|
14
15
|
import { SyncManager } from './sync-manager.js';
|
|
15
16
|
import type { DecentrlTransport } from './transport.js';
|
|
16
17
|
import type {
|
|
18
|
+
ChannelDefinitions,
|
|
19
|
+
ChannelFetchOptions,
|
|
20
|
+
ChannelSubscriptionConfig,
|
|
17
21
|
DecentrlAppConfig,
|
|
18
22
|
DecentrlClientConfig,
|
|
19
23
|
EventDefinitions,
|
|
@@ -21,6 +25,10 @@ import type {
|
|
|
21
25
|
EventMeta,
|
|
22
26
|
InferState,
|
|
23
27
|
PaginatedResult,
|
|
28
|
+
PublicEventDefinitions,
|
|
29
|
+
PublicEventEnvelope,
|
|
30
|
+
PublicEventResult,
|
|
31
|
+
PublicQueryOptions,
|
|
24
32
|
PublishOptions,
|
|
25
33
|
QueryOptions,
|
|
26
34
|
StateDefinitions,
|
|
@@ -31,12 +39,19 @@ import type { ConnectionStatus } from './websocket-transport.js';
|
|
|
31
39
|
|
|
32
40
|
export class DecentrlClient<
|
|
33
41
|
TEvents extends EventDefinitions,
|
|
34
|
-
|
|
42
|
+
TPublicEvents extends PublicEventDefinitions = PublicEventDefinitions,
|
|
43
|
+
TChannels extends ChannelDefinitions = ChannelDefinitions,
|
|
44
|
+
TState extends StateDefinitions<TEvents, TPublicEvents, TChannels> = StateDefinitions<
|
|
45
|
+
TEvents,
|
|
46
|
+
TPublicEvents,
|
|
47
|
+
TChannels
|
|
48
|
+
>,
|
|
35
49
|
> {
|
|
36
50
|
private stateStore: StateStore<InferState<TState>>;
|
|
37
51
|
private eventProcessor: EventProcessor<TEvents, TState>;
|
|
38
52
|
private syncManager: SyncManager<TEvents, TState>;
|
|
39
53
|
private transport: DecentrlTransport;
|
|
54
|
+
private publicChannelReader: PublicChannelReader<TEvents, TState>;
|
|
40
55
|
private unsubscribePersistState: (() => void) | null = null;
|
|
41
56
|
private unsubscribePersistIdentity: (() => void) | null = null;
|
|
42
57
|
|
|
@@ -44,15 +59,14 @@ export class DecentrlClient<
|
|
|
44
59
|
readonly contracts: ContractManager;
|
|
45
60
|
|
|
46
61
|
constructor(
|
|
47
|
-
private appConfig: DecentrlAppConfig<TEvents, TState>,
|
|
62
|
+
private appConfig: DecentrlAppConfig<TEvents, TPublicEvents, TChannels, TState>,
|
|
48
63
|
private clientConfig: DecentrlClientConfig,
|
|
49
64
|
) {
|
|
50
65
|
// Build initial state from slice definitions
|
|
51
66
|
const initialState = {} as InferState<TState>;
|
|
52
67
|
|
|
53
68
|
for (const key of Object.keys(appConfig.state)) {
|
|
54
|
-
|
|
55
|
-
(initialState as any)[key] = appConfig.state[key].initial;
|
|
69
|
+
(initialState as Record<string, unknown>)[key] = appConfig.state[key].initial;
|
|
56
70
|
}
|
|
57
71
|
|
|
58
72
|
// Restore persisted state if available
|
|
@@ -63,7 +77,6 @@ export class DecentrlClient<
|
|
|
63
77
|
const saved = loadPersistedState<InferState<TState>>(persistOpts);
|
|
64
78
|
|
|
65
79
|
if (saved) {
|
|
66
|
-
// Merge: use saved values for slices that exist, fall back to initial for new slices
|
|
67
80
|
restoredState = { ...initialState, ...saved };
|
|
68
81
|
}
|
|
69
82
|
}
|
|
@@ -88,7 +101,19 @@ export class DecentrlClient<
|
|
|
88
101
|
}
|
|
89
102
|
}
|
|
90
103
|
|
|
91
|
-
this.eventProcessor = new EventProcessor(
|
|
104
|
+
this.eventProcessor = new EventProcessor(
|
|
105
|
+
appConfig.events,
|
|
106
|
+
appConfig.state,
|
|
107
|
+
this.stateStore,
|
|
108
|
+
appConfig.publicEvents,
|
|
109
|
+
appConfig.channels,
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
this.publicChannelReader = new PublicChannelReader(
|
|
113
|
+
this.transport,
|
|
114
|
+
this.eventProcessor,
|
|
115
|
+
appConfig.channels,
|
|
116
|
+
);
|
|
92
117
|
|
|
93
118
|
this.syncManager = new SyncManager(
|
|
94
119
|
this.eventProcessor,
|
|
@@ -105,7 +130,6 @@ export class DecentrlClient<
|
|
|
105
130
|
try {
|
|
106
131
|
this.identity.load(savedIdentity);
|
|
107
132
|
} catch {
|
|
108
|
-
// Corrupted identity data — clear it
|
|
109
133
|
persistIdentity(persistOpts, null);
|
|
110
134
|
}
|
|
111
135
|
}
|
|
@@ -121,7 +145,6 @@ export class DecentrlClient<
|
|
|
121
145
|
return;
|
|
122
146
|
}
|
|
123
147
|
|
|
124
|
-
// Auto-persist identity on changes
|
|
125
148
|
this.unsubscribePersistIdentity = this.identity.onChange((identity) => {
|
|
126
149
|
if (identity) {
|
|
127
150
|
persistIdentity(persistOpts, this.identity.serialize());
|
|
@@ -130,7 +153,6 @@ export class DecentrlClient<
|
|
|
130
153
|
}
|
|
131
154
|
});
|
|
132
155
|
|
|
133
|
-
// Auto-persist state on changes (debounced)
|
|
134
156
|
let persistTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
135
157
|
this.unsubscribePersistState = this.stateStore.subscribe((state) => {
|
|
136
158
|
if (persistTimeout) {
|
|
@@ -141,6 +163,8 @@ export class DecentrlClient<
|
|
|
141
163
|
});
|
|
142
164
|
}
|
|
143
165
|
|
|
166
|
+
// --- Private Events ---
|
|
167
|
+
|
|
144
168
|
async publish<K extends string & keyof TEvents>(
|
|
145
169
|
eventType: K,
|
|
146
170
|
data: TEvents[K] extends { schema: infer S extends import('zod').ZodType }
|
|
@@ -148,10 +172,8 @@ export class DecentrlClient<
|
|
|
148
172
|
: never,
|
|
149
173
|
options?: PublishOptions,
|
|
150
174
|
): Promise<void> {
|
|
151
|
-
// 1. Validate data against schema
|
|
152
175
|
this.eventProcessor.validate(eventType, data);
|
|
153
176
|
|
|
154
|
-
// 2. Build envelope
|
|
155
177
|
const meta: EventMeta = {
|
|
156
178
|
senderDid: this.identity.requireIdentity().did,
|
|
157
179
|
timestamp: Date.now(),
|
|
@@ -159,19 +181,15 @@ export class DecentrlClient<
|
|
|
159
181
|
...(options?.ephemeral ? { ephemeral: true } : {}),
|
|
160
182
|
};
|
|
161
183
|
const envelope = this.eventProcessor.buildEnvelope(eventType, data, meta);
|
|
162
|
-
|
|
163
|
-
// 3. Compute tags
|
|
164
184
|
const tags = this.eventProcessor.computeTags(eventType, data);
|
|
165
185
|
|
|
166
186
|
try {
|
|
167
|
-
// 4. Publish via transport
|
|
168
187
|
await this.transport.publishEvent(envelope, {
|
|
169
188
|
tags,
|
|
170
189
|
recipient: options?.recipient,
|
|
171
190
|
ephemeral: options?.ephemeral,
|
|
172
191
|
});
|
|
173
192
|
|
|
174
|
-
// 5. Optimistic local state update
|
|
175
193
|
this.eventProcessor.processEvent(envelope);
|
|
176
194
|
} catch (error) {
|
|
177
195
|
throw new DecentrlSDKError(
|
|
@@ -213,6 +231,99 @@ export class DecentrlClient<
|
|
|
213
231
|
return { processed, total: result.pagination.total };
|
|
214
232
|
}
|
|
215
233
|
|
|
234
|
+
// --- Public Events (publishing) ---
|
|
235
|
+
|
|
236
|
+
async publishPublic<K extends string & keyof TPublicEvents>(
|
|
237
|
+
eventType: K,
|
|
238
|
+
data: TPublicEvents[K] extends { schema: infer S extends import('zod').ZodType }
|
|
239
|
+
? import('zod').infer<S>
|
|
240
|
+
: never,
|
|
241
|
+
): Promise<{ publicEventId: string }> {
|
|
242
|
+
this.eventProcessor.validatePublicEvent(eventType, data);
|
|
243
|
+
|
|
244
|
+
const identity = this.identity.requireIdentity();
|
|
245
|
+
const tags = this.eventProcessor.computePublicTags(eventType, data);
|
|
246
|
+
const channelId = this.eventProcessor.getPublicChannelId(eventType);
|
|
247
|
+
const eventPayload = JSON.stringify({ type: eventType, data });
|
|
248
|
+
|
|
249
|
+
if (!this.transport.publishPublicEvent) {
|
|
250
|
+
throw new DecentrlSDKError('Transport does not support publishPublicEvent', 'PUBLISH_FAILED');
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
try {
|
|
254
|
+
const result = await this.transport.publishPublicEvent({
|
|
255
|
+
channelId,
|
|
256
|
+
event: eventPayload,
|
|
257
|
+
tags,
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
this.eventProcessor.processPublicEvent({
|
|
261
|
+
type: eventType,
|
|
262
|
+
data,
|
|
263
|
+
meta: {
|
|
264
|
+
publisherDid: identity.did,
|
|
265
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
266
|
+
eventId: result.publicEventId,
|
|
267
|
+
channelId,
|
|
268
|
+
},
|
|
269
|
+
tags,
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
return result;
|
|
273
|
+
} catch (error) {
|
|
274
|
+
throw new DecentrlSDKError(
|
|
275
|
+
`Failed to publish public event "${eventType}": ${error instanceof Error ? error.message : String(error)}`,
|
|
276
|
+
'PUBLISH_FAILED',
|
|
277
|
+
{ eventType, data, error },
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
async deletePublicEvent(publicEventId: string, eventType?: string): Promise<void> {
|
|
283
|
+
if (!this.transport.deletePublicEvent) {
|
|
284
|
+
throw new DecentrlSDKError('Transport does not support deletePublicEvent', 'PUBLISH_FAILED');
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
await this.transport.deletePublicEvent(publicEventId, eventType);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// --- Public Events (reading) ---
|
|
291
|
+
|
|
292
|
+
async queryPublicEvents(
|
|
293
|
+
options: PublicQueryOptions,
|
|
294
|
+
): Promise<PaginatedResult<PublicEventResult>> {
|
|
295
|
+
// Auto-resolve mediator endpoint when querying own events
|
|
296
|
+
let mediatorEndpoint = options.mediatorEndpoint;
|
|
297
|
+
|
|
298
|
+
if (!mediatorEndpoint) {
|
|
299
|
+
const ownIdentity = this.identity.getIdentity();
|
|
300
|
+
|
|
301
|
+
if (ownIdentity && options.publisherDid === ownIdentity.did) {
|
|
302
|
+
mediatorEndpoint = ownIdentity.mediatorEndpoint;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return this.publicChannelReader.fetch({
|
|
307
|
+
did: options.publisherDid,
|
|
308
|
+
mediatorEndpoint,
|
|
309
|
+
channelId: options.channelId,
|
|
310
|
+
tags: options.tags,
|
|
311
|
+
afterTimestamp: options.afterTimestamp,
|
|
312
|
+
beforeTimestamp: options.beforeTimestamp,
|
|
313
|
+
pagination: options.pagination,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
subscribeToChannel(config: ChannelSubscriptionConfig): { unsubscribe: () => void } {
|
|
318
|
+
return this.publicChannelReader.subscribe(config);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
onPublicEvent(listener: (envelope: PublicEventEnvelope) => void): () => void {
|
|
322
|
+
return this.eventProcessor.onPublicEvent(listener);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// --- State ---
|
|
326
|
+
|
|
216
327
|
getState = (): InferState<TState> => {
|
|
217
328
|
return this.stateStore.getState();
|
|
218
329
|
};
|
|
@@ -221,6 +332,8 @@ export class DecentrlClient<
|
|
|
221
332
|
return this.stateStore.subscribe(listener);
|
|
222
333
|
};
|
|
223
334
|
|
|
335
|
+
// --- Sync ---
|
|
336
|
+
|
|
224
337
|
startSync(options?: SyncOptions): void {
|
|
225
338
|
this.syncManager.start(options);
|
|
226
339
|
}
|
|
@@ -241,8 +354,11 @@ export class DecentrlClient<
|
|
|
241
354
|
return this.syncManager.onConnectionStatusChange(listener);
|
|
242
355
|
};
|
|
243
356
|
|
|
357
|
+
// --- Reset ---
|
|
358
|
+
|
|
244
359
|
reset(): void {
|
|
245
360
|
this.syncManager.stop();
|
|
361
|
+
this.publicChannelReader.dispose();
|
|
246
362
|
this.identity.reset();
|
|
247
363
|
this.contracts.reset();
|
|
248
364
|
this.eventProcessor.reset();
|
|
@@ -257,21 +373,18 @@ export class DecentrlClient<
|
|
|
257
373
|
this.unsubscribePersistIdentity = null;
|
|
258
374
|
}
|
|
259
375
|
|
|
260
|
-
// Rebuild initial state
|
|
261
376
|
const initialState = {} as InferState<TState>;
|
|
262
377
|
|
|
263
378
|
for (const key of Object.keys(this.appConfig.state)) {
|
|
264
|
-
(initialState as
|
|
379
|
+
(initialState as Record<string, unknown>)[key] = this.appConfig.state[key].initial;
|
|
265
380
|
}
|
|
266
381
|
|
|
267
382
|
this.stateStore.reset(initialState);
|
|
268
383
|
|
|
269
|
-
// Clear persisted data
|
|
270
384
|
if (this.clientConfig.persist) {
|
|
271
385
|
clearPersisted(this.clientConfig.persist);
|
|
272
386
|
}
|
|
273
387
|
|
|
274
|
-
// Re-subscribe persistence listeners
|
|
275
388
|
this.setupPersistence();
|
|
276
389
|
}
|
|
277
390
|
}
|