@dsh-enhanced/assistant-delivery 0.1.6 → 0.1.7
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 +21 -1
- package/lib/agent-runtime.d.ts +8 -1
- package/lib/agent-runtime.d.ts.map +1 -1
- package/lib/agent-runtime.js +89 -0
- package/lib/agent-runtime.js.map +1 -1
- package/lib/feedback-command.d.ts +14 -0
- package/lib/feedback-command.d.ts.map +1 -0
- package/lib/feedback-command.js +122 -0
- package/lib/feedback-command.js.map +1 -0
- package/lib/service.d.ts +12 -1
- package/lib/service.d.ts.map +1 -1
- package/lib/service.js +132 -0
- package/lib/service.js.map +1 -1
- package/lib/types.d.ts +45 -0
- package/lib/types.d.ts.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ConversationBinding, DeliveryPreferenceFeedback, DeliveryPreferenceSelection, InboundEnvelope } from './types.js';
|
|
2
|
+
export type FeedbackSignalSelection = DeliveryPreferenceSelection;
|
|
3
|
+
export type ParsedFeedbackCommand = {
|
|
4
|
+
kind: 'invalid';
|
|
5
|
+
} | {
|
|
6
|
+
kind: 'signals';
|
|
7
|
+
selections: readonly FeedbackSignalSelection[];
|
|
8
|
+
};
|
|
9
|
+
export declare const feedbackUsage: string;
|
|
10
|
+
/** Parse a closed, typed grammar. No caller-provided text crosses this boundary. */
|
|
11
|
+
export declare function parseFeedbackCommand(rawInput: string): ParsedFeedbackCommand;
|
|
12
|
+
/** Build the exact Host-attested payload accepted by Preference Learning. */
|
|
13
|
+
export declare function feedbackSignalInput(binding: Readonly<ConversationBinding>, envelope: Readonly<InboundEnvelope>, selection: Readonly<FeedbackSignalSelection>, receivedAt: number): DeliveryPreferenceFeedback;
|
|
14
|
+
//# sourceMappingURL=feedback-command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feedback-command.d.ts","sourceRoot":"","sources":["../src/feedback-command.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,mBAAmB,EACnB,0BAA0B,EAC1B,2BAA2B,EAC3B,eAAe,EAChB,MAAM,YAAY,CAAA;AAEnB,MAAM,MAAM,uBAAuB,GAAG,2BAA2B,CAAA;AAEjE,MAAM,MAAM,qBAAqB,GAC7B;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,UAAU,EAAE,SAAS,uBAAuB,EAAE,CAAA;CAAE,CAAA;AA0CvE,eAAO,MAAM,aAAa,QAWd,CAAA;AAEZ,oFAAoF;AACpF,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,qBAAqB,CAmC5E;AA0BD,6EAA6E;AAC7E,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,QAAQ,CAAC,mBAAmB,CAAC,EACtC,QAAQ,EAAE,QAAQ,CAAC,eAAe,CAAC,EACnC,SAAS,EAAE,QAAQ,CAAC,uBAAuB,CAAC,EAC5C,UAAU,EAAE,MAAM,GACjB,0BAA0B,CAW5B"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
const responseFeedback = Object.freeze([
|
|
3
|
+
'helpful',
|
|
4
|
+
'not-helpful',
|
|
5
|
+
'too-long',
|
|
6
|
+
'too-short',
|
|
7
|
+
'wrong-format',
|
|
8
|
+
'wrong-action',
|
|
9
|
+
'unwanted-reminder',
|
|
10
|
+
]);
|
|
11
|
+
const typedPreferences = Object.freeze({
|
|
12
|
+
verbosity: Object.freeze({
|
|
13
|
+
preferenceKey: 'response.verbosity',
|
|
14
|
+
values: Object.freeze(['concise', 'balanced', 'detailed']),
|
|
15
|
+
}),
|
|
16
|
+
structure: Object.freeze({
|
|
17
|
+
preferenceKey: 'response.structure',
|
|
18
|
+
values: Object.freeze(['prose', 'bullets', 'mixed']),
|
|
19
|
+
}),
|
|
20
|
+
language: Object.freeze({
|
|
21
|
+
preferenceKey: 'response.language',
|
|
22
|
+
values: Object.freeze(['zh-CN', 'en']),
|
|
23
|
+
}),
|
|
24
|
+
explanation: Object.freeze({
|
|
25
|
+
preferenceKey: 'response.explanation_depth',
|
|
26
|
+
values: Object.freeze(['result-first', 'balanced', 'tutorial']),
|
|
27
|
+
}),
|
|
28
|
+
suggestions: Object.freeze({
|
|
29
|
+
preferenceKey: 'suggestion.frequency',
|
|
30
|
+
values: Object.freeze(['low', 'normal']),
|
|
31
|
+
}),
|
|
32
|
+
ranking: Object.freeze({
|
|
33
|
+
preferenceKey: 'recommendation.ranking',
|
|
34
|
+
values: Object.freeze(['recency', 'familiarity', 'evidence']),
|
|
35
|
+
}),
|
|
36
|
+
});
|
|
37
|
+
export const feedbackUsage = [
|
|
38
|
+
'反馈命令:',
|
|
39
|
+
'- /feedback helpful|not-helpful|too-long|too-short|wrong-format|wrong-action|unwanted-reminder',
|
|
40
|
+
'- /feedback verbosity concise|balanced|detailed',
|
|
41
|
+
'- /feedback structure prose|bullets|mixed',
|
|
42
|
+
'- /feedback language zh-CN|en',
|
|
43
|
+
'- /feedback explanation result-first|balanced|tutorial',
|
|
44
|
+
'- /feedback suggestions low|normal',
|
|
45
|
+
'- /feedback ranking recency|familiarity|evidence',
|
|
46
|
+
'',
|
|
47
|
+
'反馈只作用于当前工作区与 preset;命令不接受附件,也不会进入模型。',
|
|
48
|
+
].join('\n');
|
|
49
|
+
/** Parse a closed, typed grammar. No caller-provided text crosses this boundary. */
|
|
50
|
+
export function parseFeedbackCommand(rawInput) {
|
|
51
|
+
const normalized = rawInput.trim();
|
|
52
|
+
if (normalized === '')
|
|
53
|
+
return { kind: 'invalid' };
|
|
54
|
+
const tokens = normalized.split(/[\t\n\r ]+/u);
|
|
55
|
+
if (tokens.length === 1) {
|
|
56
|
+
const value = tokens[0];
|
|
57
|
+
if (!responseFeedback.includes(value))
|
|
58
|
+
return { kind: 'invalid' };
|
|
59
|
+
const selections = [
|
|
60
|
+
{
|
|
61
|
+
preferenceKey: 'feedback.response',
|
|
62
|
+
candidateValue: value,
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
if (value === 'too-long') {
|
|
66
|
+
selections.push({ preferenceKey: 'response.verbosity', candidateValue: 'concise' });
|
|
67
|
+
}
|
|
68
|
+
else if (value === 'too-short') {
|
|
69
|
+
selections.push({ preferenceKey: 'response.verbosity', candidateValue: 'detailed' });
|
|
70
|
+
}
|
|
71
|
+
return { kind: 'signals', selections: Object.freeze(selections) };
|
|
72
|
+
}
|
|
73
|
+
if (tokens.length !== 2)
|
|
74
|
+
return { kind: 'invalid' };
|
|
75
|
+
const category = tokens[0];
|
|
76
|
+
const value = tokens[1];
|
|
77
|
+
if (!Object.hasOwn(typedPreferences, category))
|
|
78
|
+
return { kind: 'invalid' };
|
|
79
|
+
const entry = typedPreferences[category];
|
|
80
|
+
if (!entry.values.includes(value))
|
|
81
|
+
return { kind: 'invalid' };
|
|
82
|
+
return {
|
|
83
|
+
kind: 'signals',
|
|
84
|
+
selections: Object.freeze([{
|
|
85
|
+
preferenceKey: entry.preferenceKey,
|
|
86
|
+
candidateValue: value,
|
|
87
|
+
}]),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function feedbackSignalIdempotencyKey(binding, envelope, selection) {
|
|
91
|
+
const identity = JSON.stringify([
|
|
92
|
+
binding.id,
|
|
93
|
+
binding.version,
|
|
94
|
+
binding.sessionId,
|
|
95
|
+
binding.generation,
|
|
96
|
+
envelope.channel,
|
|
97
|
+
envelope.account,
|
|
98
|
+
envelope.eventId,
|
|
99
|
+
selection.preferenceKey,
|
|
100
|
+
selection.candidateValue,
|
|
101
|
+
'support',
|
|
102
|
+
]);
|
|
103
|
+
const digest = createHash('sha256')
|
|
104
|
+
.update('assistant-delivery-feedback-v1\0')
|
|
105
|
+
.update(identity)
|
|
106
|
+
.digest('hex');
|
|
107
|
+
return `delivery-feedback-v1:${digest}`;
|
|
108
|
+
}
|
|
109
|
+
/** Build the exact Host-attested payload accepted by Preference Learning. */
|
|
110
|
+
export function feedbackSignalInput(binding, envelope, selection, receivedAt) {
|
|
111
|
+
return Object.freeze({
|
|
112
|
+
scope: Object.freeze({ workspace: binding.workspace, preset: binding.agentPreset }),
|
|
113
|
+
...selection,
|
|
114
|
+
stance: 'support',
|
|
115
|
+
actorTrust: 'owner-authenticated',
|
|
116
|
+
interpretationTrust: 'typed-feedback',
|
|
117
|
+
source: 'direct-owner-feedback',
|
|
118
|
+
occurredAt: receivedAt,
|
|
119
|
+
idempotencyKey: feedbackSignalIdempotencyKey(binding, envelope, selection),
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=feedback-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feedback-command.js","sourceRoot":"","sources":["../src/feedback-command.ts"],"names":[],"mappings":"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"}
|
package/lib/service.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import Schema from '@deepseek-ai/schemastery';
|
|
|
4
4
|
import { type ApprovalDispatchRoute, type AssistantPolicyService } from '@dsh-enhanced/assistant-policy';
|
|
5
5
|
import { type InboundMessageProcessor } from './coordinator.js';
|
|
6
6
|
import { DeliveryStore } from './store.js';
|
|
7
|
-
import type { ConversationBinding, DeliveryAdapter, ExternalPrincipalKey, InboundEnvelope, InboxRecord, ModelPickerIntent, ModelPickerState, ModelRouteRef, ModelSelectionResult, ModelSelectionSettlementInput, ModelSelectionTerminalResult, OutboxRecord, PairingChallenge, PermissionPickerIntent } from './types.js';
|
|
7
|
+
import type { ConversationBinding, DeliveryAdapter, DeliveryPreferenceFeedbackListener, ExternalPrincipalKey, InboundEnvelope, InboxRecord, ModelPickerIntent, ModelPickerState, ModelRouteRef, ModelSelectionResult, ModelSelectionSettlementInput, ModelSelectionTerminalResult, OutboxRecord, PairingChallenge, PermissionPickerIntent } from './types.js';
|
|
8
8
|
export interface Config {
|
|
9
9
|
databasePath: string;
|
|
10
10
|
spoolPath: string;
|
|
@@ -79,6 +79,7 @@ export declare class AssistantDeliveryService extends Service {
|
|
|
79
79
|
private readonly agentApprovalBindings;
|
|
80
80
|
private readonly toolApprovalControllers;
|
|
81
81
|
private readonly modelSelectionWaiters;
|
|
82
|
+
private preferenceFeedbackSink;
|
|
82
83
|
private modelSelectionFlight;
|
|
83
84
|
private modelSelectionRetryTimer;
|
|
84
85
|
private runtime;
|
|
@@ -152,11 +153,21 @@ export declare class AssistantDeliveryService extends Service {
|
|
|
152
153
|
}): InboxRecord | OutboxRecord;
|
|
153
154
|
registerInboundRuntime(runtime: DeliveryInboundRuntime): () => void;
|
|
154
155
|
registerAdapter(adapter: DeliveryAdapter): Promise<() => Promise<void>>;
|
|
156
|
+
/**
|
|
157
|
+
* Trusted Host registration seam for the one authoritative, durable sink.
|
|
158
|
+
* It is intentionally not an Agent tool. The receipt contract prevents a
|
|
159
|
+
* no-op observer from being mistaken for persistence.
|
|
160
|
+
*/
|
|
161
|
+
subscribePreferenceFeedback(listener: DeliveryPreferenceFeedbackListener): () => void;
|
|
155
162
|
health(): ReturnType<DeliveryStore['health']> & {
|
|
156
163
|
adapters: number;
|
|
157
164
|
};
|
|
158
165
|
private isInboundAuthorized;
|
|
159
166
|
private isPermissionController;
|
|
167
|
+
private isOwnerFeedbackController;
|
|
168
|
+
private authorizeOwnerPreferenceFeedback;
|
|
169
|
+
private preferenceSignalAuthorizationKey;
|
|
170
|
+
private dispatchPreferenceFeedback;
|
|
160
171
|
private authorizePermissionReply;
|
|
161
172
|
/**
|
|
162
173
|
* Provider event ids are scoped to an adapter account, while Outbox and the
|
package/lib/service.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AAGnD,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAC7C,OAAO,EAIL,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAE5B,MAAM,gCAAgC,CAAA;AACvC,OAAO,EAIL,KAAK,uBAAuB,EAC7B,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,aAAa,EAAsB,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
|
package/lib/service.js
CHANGED
|
@@ -175,6 +175,7 @@ export class AssistantDeliveryService extends Service {
|
|
|
175
175
|
agentApprovalBindings = new WeakMap();
|
|
176
176
|
toolApprovalControllers = new Set();
|
|
177
177
|
modelSelectionWaiters = new Map();
|
|
178
|
+
preferenceFeedbackSink;
|
|
178
179
|
modelSelectionFlight;
|
|
179
180
|
modelSelectionRetryTimer;
|
|
180
181
|
runtime;
|
|
@@ -236,6 +237,9 @@ export class AssistantDeliveryService extends Service {
|
|
|
236
237
|
imageMaterializer,
|
|
237
238
|
isInboundAuthorized: (binding, envelope) => this.isInboundAuthorized(binding, envelope),
|
|
238
239
|
isPermissionController: (binding, envelope) => this.isPermissionController(binding, envelope),
|
|
240
|
+
isOwnerFeedbackController: (binding, envelope) => this.isOwnerFeedbackController(binding, envelope),
|
|
241
|
+
authorizeOwnerPreferenceFeedback: (binding, envelope, selections) => this.authorizeOwnerPreferenceFeedback(binding, envelope, selections),
|
|
242
|
+
dispatchPreferenceFeedback: events => this.dispatchPreferenceFeedback(events),
|
|
239
243
|
authorizePermissionReply: (binding, envelope) => this.authorizePermissionReply(binding, envelope),
|
|
240
244
|
beginModelCommand: conversation => this.deliveryStore.beginModelCommand(conversation),
|
|
241
245
|
commitModelCommand: input => this.deliveryStore.commitModelCommand(input),
|
|
@@ -278,6 +282,7 @@ export class AssistantDeliveryService extends Service {
|
|
|
278
282
|
this.start();
|
|
279
283
|
ctx.effect(() => async () => {
|
|
280
284
|
this.active = false;
|
|
285
|
+
this.preferenceFeedbackSink = undefined;
|
|
281
286
|
this.cancelModelSelectionWaiters();
|
|
282
287
|
for (const controller of this.toolApprovalControllers) {
|
|
283
288
|
controller.abort(new Error('assistant-delivery is stopping'));
|
|
@@ -772,6 +777,30 @@ export class AssistantDeliveryService extends Service {
|
|
|
772
777
|
this.assertActive();
|
|
773
778
|
return this.registry.register(adapter);
|
|
774
779
|
}
|
|
780
|
+
/**
|
|
781
|
+
* Trusted Host registration seam for the one authoritative, durable sink.
|
|
782
|
+
* It is intentionally not an Agent tool. The receipt contract prevents a
|
|
783
|
+
* no-op observer from being mistaken for persistence.
|
|
784
|
+
*/
|
|
785
|
+
subscribePreferenceFeedback(listener) {
|
|
786
|
+
this.assertActive();
|
|
787
|
+
if (typeof listener !== 'function') {
|
|
788
|
+
throw new TypeError('assistant-delivery: preference feedback listener must be a function');
|
|
789
|
+
}
|
|
790
|
+
if (this.preferenceFeedbackSink !== undefined) {
|
|
791
|
+
throw new Error('assistant-delivery: a preference feedback sink is already registered');
|
|
792
|
+
}
|
|
793
|
+
const token = Symbol('preference-feedback-sink');
|
|
794
|
+
this.preferenceFeedbackSink = Object.freeze({ token, listener });
|
|
795
|
+
let active = true;
|
|
796
|
+
return () => {
|
|
797
|
+
if (!active)
|
|
798
|
+
return;
|
|
799
|
+
active = false;
|
|
800
|
+
if (this.preferenceFeedbackSink?.token === token)
|
|
801
|
+
this.preferenceFeedbackSink = undefined;
|
|
802
|
+
};
|
|
803
|
+
}
|
|
775
804
|
health() {
|
|
776
805
|
this.assertActive();
|
|
777
806
|
return { ...this.deliveryStore.health(), adapters: this.registry.size() };
|
|
@@ -824,6 +853,109 @@ export class AssistantDeliveryService extends Service {
|
|
|
824
853
|
context: { initiator: 'external' },
|
|
825
854
|
}).effect === 'allow';
|
|
826
855
|
}
|
|
856
|
+
isOwnerFeedbackController(binding, envelope) {
|
|
857
|
+
if (!this.isInboundAuthorized(binding, envelope))
|
|
858
|
+
return false;
|
|
859
|
+
const principal = this.deliveryStore.getPrincipal(binding.principal);
|
|
860
|
+
const inbox = this.deliveryStore.getInboxByProviderEvent(envelope.channel, envelope.account, envelope.eventId);
|
|
861
|
+
if (principal?.status !== 'active' || principal.role !== 'owner'
|
|
862
|
+
|| inbox?.status !== 'claimed'
|
|
863
|
+
|| inbox.bindingId !== binding.id
|
|
864
|
+
|| JSON.stringify(inbox.envelope) !== JSON.stringify(envelope)) {
|
|
865
|
+
return false;
|
|
866
|
+
}
|
|
867
|
+
return this.policy.evaluate({
|
|
868
|
+
subject: {
|
|
869
|
+
kind: 'agent',
|
|
870
|
+
id: binding.agentPreset,
|
|
871
|
+
workspace: binding.workspace,
|
|
872
|
+
principal: externalPrincipalId(binding.principal),
|
|
873
|
+
},
|
|
874
|
+
action: 'reply',
|
|
875
|
+
resource: { kind: 'message', id: binding.id },
|
|
876
|
+
context: { initiator: 'external' },
|
|
877
|
+
}).effect === 'allow';
|
|
878
|
+
}
|
|
879
|
+
authorizeOwnerPreferenceFeedback(binding, envelope, selections) {
|
|
880
|
+
if (!this.isOwnerFeedbackController(binding, envelope)
|
|
881
|
+
|| !Array.isArray(selections) || selections.length < 1 || selections.length > 16)
|
|
882
|
+
return undefined;
|
|
883
|
+
const inbox = this.deliveryStore.getInboxByProviderEvent(envelope.channel, envelope.account, envelope.eventId);
|
|
884
|
+
if (inbox?.status !== 'claimed' || inbox.bindingId !== binding.id
|
|
885
|
+
|| JSON.stringify(inbox.envelope) !== JSON.stringify(envelope))
|
|
886
|
+
return undefined;
|
|
887
|
+
const subject = {
|
|
888
|
+
kind: 'external',
|
|
889
|
+
id: externalPrincipalId(binding.principal),
|
|
890
|
+
workspace: binding.workspace,
|
|
891
|
+
};
|
|
892
|
+
const requests = selections.map(selection => ({
|
|
893
|
+
selection,
|
|
894
|
+
authorization: {
|
|
895
|
+
subject,
|
|
896
|
+
action: 'signal',
|
|
897
|
+
resource: { kind: 'preference', id: `${binding.agentPreset}/${selection.preferenceKey}` },
|
|
898
|
+
context: { initiator: 'external' },
|
|
899
|
+
},
|
|
900
|
+
}));
|
|
901
|
+
const denied = requests.find(entry => this.policy.evaluate(entry.authorization).effect !== 'allow');
|
|
902
|
+
if (denied !== undefined) {
|
|
903
|
+
this.policy.authorize(denied.authorization, {
|
|
904
|
+
idempotencyKey: this.preferenceSignalAuthorizationKey(binding, envelope, denied.authorization.resource.id, denied.selection.candidateValue),
|
|
905
|
+
auditDetails: { bindingVersion: binding.version },
|
|
906
|
+
});
|
|
907
|
+
return undefined;
|
|
908
|
+
}
|
|
909
|
+
for (const { authorization, selection } of requests) {
|
|
910
|
+
const decision = this.policy.authorize(authorization, {
|
|
911
|
+
idempotencyKey: this.preferenceSignalAuthorizationKey(binding, envelope, authorization.resource.id, selection.candidateValue),
|
|
912
|
+
auditDetails: { bindingVersion: binding.version },
|
|
913
|
+
});
|
|
914
|
+
if (decision.effect !== 'allow')
|
|
915
|
+
return undefined;
|
|
916
|
+
}
|
|
917
|
+
// Provider clocks are not authoritative. The locally persisted Inbox time
|
|
918
|
+
// is bounded by the same Host clock as Preference Learning's retention gate.
|
|
919
|
+
return Object.freeze({ occurredAt: inbox.receivedAt });
|
|
920
|
+
}
|
|
921
|
+
preferenceSignalAuthorizationKey(binding, envelope, resourceId, candidateValue) {
|
|
922
|
+
const digest = createHash('sha256').update('assistant-delivery-preference-authorization-v2\0')
|
|
923
|
+
.update(JSON.stringify([
|
|
924
|
+
binding.id,
|
|
925
|
+
binding.version,
|
|
926
|
+
envelope.channel,
|
|
927
|
+
envelope.account,
|
|
928
|
+
envelope.eventId,
|
|
929
|
+
resourceId,
|
|
930
|
+
candidateValue,
|
|
931
|
+
]))
|
|
932
|
+
.digest('hex');
|
|
933
|
+
return `delivery-pref-auth:${digest}`;
|
|
934
|
+
}
|
|
935
|
+
async dispatchPreferenceFeedback(events) {
|
|
936
|
+
const registration = this.preferenceFeedbackSink;
|
|
937
|
+
if (registration === undefined)
|
|
938
|
+
return 'unavailable';
|
|
939
|
+
try {
|
|
940
|
+
const receipts = await registration.listener(events);
|
|
941
|
+
if (!Array.isArray(receipts) || receipts.length !== events.length)
|
|
942
|
+
return 'unknown';
|
|
943
|
+
const expected = new Set(events.map(event => event.idempotencyKey));
|
|
944
|
+
const received = new Set();
|
|
945
|
+
for (const receipt of receipts) {
|
|
946
|
+
if (receipt?.status !== 'recorded'
|
|
947
|
+
|| typeof receipt.idempotencyKey !== 'string'
|
|
948
|
+
|| !expected.has(receipt.idempotencyKey)
|
|
949
|
+
|| received.has(receipt.idempotencyKey))
|
|
950
|
+
return 'unknown';
|
|
951
|
+
received.add(receipt.idempotencyKey);
|
|
952
|
+
}
|
|
953
|
+
return received.size === expected.size ? 'recorded' : 'unknown';
|
|
954
|
+
}
|
|
955
|
+
catch {
|
|
956
|
+
return 'unknown';
|
|
957
|
+
}
|
|
958
|
+
}
|
|
827
959
|
authorizePermissionReply(binding, envelope) {
|
|
828
960
|
if (!this.isPermissionController(binding, envelope))
|
|
829
961
|
return false;
|