@juspay/neurolink 11.29.2 → 12.0.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 (56) hide show
  1. package/CHANGELOG.md +54 -2
  2. package/dist/auth/anthropicOAuth.d.ts +50 -0
  3. package/dist/auth/anthropicOAuth.js +78 -0
  4. package/dist/browser/neurolink.min.js +393 -393
  5. package/dist/cli/commands/proxy.d.ts +2 -0
  6. package/dist/cli/commands/proxy.js +284 -4
  7. package/dist/cli/commands/proxyExpose.d.ts +35 -0
  8. package/dist/cli/commands/proxyExpose.js +252 -0
  9. package/dist/cli/commands/proxyPeer.d.ts +29 -0
  10. package/dist/cli/commands/proxyPeer.js +738 -0
  11. package/dist/cli/commands/proxyShare.d.ts +37 -0
  12. package/dist/cli/commands/proxyShare.js +1080 -0
  13. package/dist/cli/parser.js +7 -1
  14. package/dist/core/baseProvider.js +20 -1
  15. package/dist/neurolink.js +30 -2
  16. package/dist/proxy/peerStore.d.ts +52 -0
  17. package/dist/proxy/peerStore.js +324 -0
  18. package/dist/proxy/peerTransport.d.ts +38 -0
  19. package/dist/proxy/peerTransport.js +242 -0
  20. package/dist/proxy/proxyPaths.d.ts +8 -0
  21. package/dist/proxy/proxyPaths.js +55 -17
  22. package/dist/proxy/requestLogger.js +8 -0
  23. package/dist/proxy/residentGrants.d.ts +57 -0
  24. package/dist/proxy/residentGrants.js +393 -0
  25. package/dist/proxy/shareAudit.d.ts +81 -0
  26. package/dist/proxy/shareAudit.js +280 -0
  27. package/dist/proxy/shareContext.d.ts +38 -0
  28. package/dist/proxy/shareContext.js +92 -0
  29. package/dist/proxy/shareGate.d.ts +64 -0
  30. package/dist/proxy/shareGate.js +216 -0
  31. package/dist/proxy/shareGrants.d.ts +115 -0
  32. package/dist/proxy/shareGrants.js +590 -0
  33. package/dist/proxy/shareLease.d.ts +101 -0
  34. package/dist/proxy/shareLease.js +192 -0
  35. package/dist/proxy/shareLedger.d.ts +105 -0
  36. package/dist/proxy/shareLedger.js +406 -0
  37. package/dist/proxy/shareListener.d.ts +60 -0
  38. package/dist/proxy/shareListener.js +143 -0
  39. package/dist/proxy/shareNotes.d.ts +97 -0
  40. package/dist/proxy/shareNotes.js +234 -0
  41. package/dist/proxy/sharePolicy.d.ts +110 -0
  42. package/dist/proxy/sharePolicy.js +366 -0
  43. package/dist/proxy/shareProvisioning.d.ts +110 -0
  44. package/dist/proxy/shareProvisioning.js +237 -0
  45. package/dist/proxy/shareReceipts.d.ts +99 -0
  46. package/dist/proxy/shareReceipts.js +303 -0
  47. package/dist/proxy/shareSigning.d.ts +40 -0
  48. package/dist/proxy/shareSigning.js +78 -0
  49. package/dist/server/routes/claudeProxyRoutes.js +1066 -3
  50. package/dist/types/cli.d.ts +61 -0
  51. package/dist/types/proxy.d.ts +781 -0
  52. package/dist/utils/streamCancellation.d.ts +46 -0
  53. package/dist/utils/streamCancellation.js +90 -0
  54. package/dist/utils/ttsStream.js +34 -1
  55. package/dist/voice/livekit/realtimeEventBridge.js +27 -6
  56. package/package.json +2 -1
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Transferable coin notes — A issues, B holds, C redeems against A.
3
+ *
4
+ * A grant's coins are bound to the pair that agreed them. A note is not: it is a
5
+ * bearer credit against the issuing node, redeemable by whoever presents it and
6
+ * holds a grant with that node. That is what lets capacity move through a mesh
7
+ * rather than only along the edge it was granted on.
8
+ *
9
+ * **Replay protection is the whole design.** A note is worth exactly one
10
+ * redemption, so the issuer keeps a record of every note it minted and marks it
11
+ * spent under the same lock that credits the balance. Two nodes racing the same
12
+ * note produce one credit and one `spent`.
13
+ *
14
+ * **What a holder can and cannot check.** Notes are signed with an HMAC keyed by
15
+ * a secret only the issuer has, so an intermediate holder cannot verify one
16
+ * offline — it can only ask the issuer, which is what `POST /peer/note` is for.
17
+ * That check is safe to expose because holding the note is itself the
18
+ * credential: the request must carry a note whose signature the issuer accepts,
19
+ * so it tells a stranger nothing they did not already have.
20
+ *
21
+ * An asymmetric signature would let a holder verify without asking. It is not
22
+ * available here — the package's browser bundle stubs `node:crypto` down to a
23
+ * subset with no Ed25519 — and the check-with-the-issuer step has to exist
24
+ * regardless, because a valid signature says nothing about whether the note has
25
+ * already been spent.
26
+ *
27
+ * @module proxy/shareNotes
28
+ */
29
+ import type { ProxyShareNote, ProxyShareNoteRecord, ProxyShareNoteStatus } from "../types/index.js";
30
+ /** Default life of a note. Long enough to hand over, short enough to expire. */
31
+ export declare const DEFAULT_NOTE_TTL_MS = 2592000000;
32
+ /** Wire prefix, so a note is never mistaken for a share token. */
33
+ export declare const NOTE_PREFIX = "nln";
34
+ /**
35
+ * How long a record outlives the note it tracks.
36
+ *
37
+ * Every mint appends a record and nothing ever removed one, so the file grew
38
+ * for the life of the node. A record past its `notAfter` cannot authorize
39
+ * anything — the note is refused as `expired` — so the only thing the extra
40
+ * retention buys is that a holder presenting a just-lapsed note is told
41
+ * `expired` rather than the more alarming `unknown`. A month of that is plenty.
42
+ */
43
+ export declare const NOTE_RECORD_RETENTION_MS = 2592000000;
44
+ export declare function initShareNotes(filePath: string): void;
45
+ /** Render a note as one line that survives a chat window. */
46
+ export declare function encodeShareNote(note: ProxyShareNote): string;
47
+ /** Read a note back. Returns undefined for anything that is not one of ours. */
48
+ export declare function decodeShareNote(encoded: string): ProxyShareNote | undefined;
49
+ /**
50
+ * Mint a note against this node.
51
+ *
52
+ * The record is written before the note is returned, so a note can never exist
53
+ * that the issuer has no memory of — the case where a crash between the two
54
+ * would leave an unredeemable credit in someone's hands.
55
+ */
56
+ export declare function issueShareNote(args: {
57
+ issuer: string;
58
+ coins: number;
59
+ ttlMs?: number;
60
+ memo?: string;
61
+ now?: number;
62
+ }): Promise<ProxyShareNote>;
63
+ /**
64
+ * What the issuer makes of a note it is shown.
65
+ *
66
+ * `forged` and `unknown` are kept apart deliberately: the first means the
67
+ * signature does not check out, the second means it does but this node has no
68
+ * record of minting it — which is what a note from a *different* issuer looks
69
+ * like, and is a different thing to tell the holder.
70
+ */
71
+ export declare function inspectShareNote(note: ProxyShareNote, secret: string | undefined, now?: number): Promise<{
72
+ status: ProxyShareNoteStatus;
73
+ coins: number;
74
+ }>;
75
+ /**
76
+ * Redeem a note into a grant's balance.
77
+ *
78
+ * Marking spent and crediting happen under one lock, so two holders racing the
79
+ * same note produce exactly one credit. The record is marked **before** the
80
+ * credit: a crash between them costs the redeemer the note, which is the safe
81
+ * direction — the alternative is a note that can be redeemed twice.
82
+ */
83
+ export declare function redeemShareNote(args: {
84
+ note: ProxyShareNote;
85
+ grantId: string;
86
+ secret: string | undefined;
87
+ now?: number;
88
+ }): Promise<{
89
+ ok: true;
90
+ coins: number;
91
+ balance: number | undefined;
92
+ } | {
93
+ ok: false;
94
+ status: ProxyShareNoteStatus;
95
+ }>;
96
+ /** Every note this node has minted, newest first. */
97
+ export declare function listShareNotes(): Promise<ProxyShareNoteRecord[]>;
@@ -0,0 +1,234 @@
1
+ /**
2
+ * Transferable coin notes — A issues, B holds, C redeems against A.
3
+ *
4
+ * A grant's coins are bound to the pair that agreed them. A note is not: it is a
5
+ * bearer credit against the issuing node, redeemable by whoever presents it and
6
+ * holds a grant with that node. That is what lets capacity move through a mesh
7
+ * rather than only along the edge it was granted on.
8
+ *
9
+ * **Replay protection is the whole design.** A note is worth exactly one
10
+ * redemption, so the issuer keeps a record of every note it minted and marks it
11
+ * spent under the same lock that credits the balance. Two nodes racing the same
12
+ * note produce one credit and one `spent`.
13
+ *
14
+ * **What a holder can and cannot check.** Notes are signed with an HMAC keyed by
15
+ * a secret only the issuer has, so an intermediate holder cannot verify one
16
+ * offline — it can only ask the issuer, which is what `POST /peer/note` is for.
17
+ * That check is safe to expose because holding the note is itself the
18
+ * credential: the request must carry a note whose signature the issuer accepts,
19
+ * so it tells a stranger nothing they did not already have.
20
+ *
21
+ * An asymmetric signature would let a holder verify without asking. It is not
22
+ * available here — the package's browser bundle stubs `node:crypto` down to a
23
+ * subset with no Ed25519 — and the check-with-the-issuer step has to exist
24
+ * regardless, because a valid signature says nothing about whether the note has
25
+ * already been spent.
26
+ *
27
+ * @module proxy/shareNotes
28
+ */
29
+ import { randomBytes } from "node:crypto";
30
+ import { readFile } from "node:fs/promises";
31
+ import { homedir } from "node:os";
32
+ import { join } from "node:path";
33
+ import { AsyncMutex } from "../utils/asyncMutex.js";
34
+ import { creditShareGrantCoins, getOrCreateNoteSecret } from "./shareGrants.js";
35
+ import { signSharePayload, verifySharePayload } from "./shareSigning.js";
36
+ const NOTES_FILE = "proxy-share-notes.json";
37
+ /** Default life of a note. Long enough to hand over, short enough to expire. */
38
+ export const DEFAULT_NOTE_TTL_MS = 2_592_000_000;
39
+ /** Wire prefix, so a note is never mistaken for a share token. */
40
+ export const NOTE_PREFIX = "nln";
41
+ /**
42
+ * How long a record outlives the note it tracks.
43
+ *
44
+ * Every mint appends a record and nothing ever removed one, so the file grew
45
+ * for the life of the node. A record past its `notAfter` cannot authorize
46
+ * anything — the note is refused as `expired` — so the only thing the extra
47
+ * retention buys is that a holder presenting a just-lapsed note is told
48
+ * `expired` rather than the more alarming `unknown`. A month of that is plenty.
49
+ */
50
+ export const NOTE_RECORD_RETENTION_MS = 2_592_000_000;
51
+ let customFilePath = null;
52
+ let notes = {};
53
+ let loaded = false;
54
+ const mutationMutex = new AsyncMutex();
55
+ export function initShareNotes(filePath) {
56
+ customFilePath = filePath;
57
+ notes = {};
58
+ loaded = false;
59
+ }
60
+ function getFilePath() {
61
+ return customFilePath ?? join(homedir(), ".neurolink", NOTES_FILE);
62
+ }
63
+ async function ensureLoaded(options = {}) {
64
+ if (loaded && !options.force) {
65
+ return;
66
+ }
67
+ try {
68
+ const parsed = JSON.parse(await readFile(getFilePath(), "utf8"));
69
+ notes = parsed?.notes ?? {};
70
+ }
71
+ catch {
72
+ notes = {};
73
+ }
74
+ loaded = true;
75
+ }
76
+ async function persist() {
77
+ const { writeJsonSnapshotAtomically } = await import("./snapshotPersistence.js");
78
+ const file = { schemaVersion: 1, notes };
79
+ await writeJsonSnapshotAtomically(getFilePath(), file);
80
+ }
81
+ /** Everything the signature covers. */
82
+ function notePayload(note) {
83
+ return note;
84
+ }
85
+ /** Render a note as one line that survives a chat window. */
86
+ export function encodeShareNote(note) {
87
+ return `${NOTE_PREFIX}_${Buffer.from(JSON.stringify(note), "utf8").toString("base64url")}`;
88
+ }
89
+ /** Read a note back. Returns undefined for anything that is not one of ours. */
90
+ export function decodeShareNote(encoded) {
91
+ const trimmed = encoded.trim();
92
+ if (!trimmed.startsWith(`${NOTE_PREFIX}_`)) {
93
+ return undefined;
94
+ }
95
+ try {
96
+ const parsed = JSON.parse(Buffer.from(trimmed.slice(NOTE_PREFIX.length + 1), "base64url").toString("utf8"));
97
+ if (typeof parsed?.noteId !== "string" ||
98
+ typeof parsed.coins !== "number" ||
99
+ typeof parsed.signature !== "string" ||
100
+ typeof parsed.notAfter !== "number") {
101
+ return undefined;
102
+ }
103
+ return parsed;
104
+ }
105
+ catch {
106
+ return undefined;
107
+ }
108
+ }
109
+ /**
110
+ * Mint a note against this node.
111
+ *
112
+ * The record is written before the note is returned, so a note can never exist
113
+ * that the issuer has no memory of — the case where a crash between the two
114
+ * would leave an unredeemable credit in someone's hands.
115
+ */
116
+ export async function issueShareNote(args) {
117
+ if (!(args.coins > 0)) {
118
+ throw new Error("A note must carry a positive number of coins.");
119
+ }
120
+ const secret = await getOrCreateNoteSecret();
121
+ const now = args.now ?? Date.now();
122
+ const unsigned = {
123
+ schemaVersion: 1,
124
+ noteId: randomBytes(12).toString("base64url"),
125
+ issuer: args.issuer,
126
+ coins: args.coins,
127
+ issuedAt: now,
128
+ notAfter: now + (args.ttlMs ?? DEFAULT_NOTE_TTL_MS),
129
+ ...(args.memo ? { memo: args.memo } : {}),
130
+ };
131
+ const note = {
132
+ ...unsigned,
133
+ signature: signSharePayload(notePayload(unsigned), secret),
134
+ };
135
+ await mutationMutex.runExclusive(async () => {
136
+ await ensureLoaded({ force: true });
137
+ // Minting is the only thing that grows this file, so it is also where the
138
+ // pruning belongs — no timer, and the cost is paid by the operation that
139
+ // caused it.
140
+ pruneExpiredNotes(now);
141
+ notes[note.noteId] = {
142
+ noteId: note.noteId,
143
+ coins: note.coins,
144
+ issuedAt: note.issuedAt,
145
+ notAfter: note.notAfter,
146
+ ...(note.memo ? { memo: note.memo } : {}),
147
+ };
148
+ await persist();
149
+ });
150
+ return note;
151
+ }
152
+ /**
153
+ * Drop records for notes that can no longer be redeemed or usefully explained.
154
+ *
155
+ * Must be called under the mutation mutex, by something that persists after.
156
+ */
157
+ function pruneExpiredNotes(now) {
158
+ for (const [noteId, record] of Object.entries(notes)) {
159
+ if (record.notAfter + NOTE_RECORD_RETENTION_MS <= now) {
160
+ delete notes[noteId];
161
+ }
162
+ }
163
+ }
164
+ /**
165
+ * What the issuer makes of a note it is shown.
166
+ *
167
+ * `forged` and `unknown` are kept apart deliberately: the first means the
168
+ * signature does not check out, the second means it does but this node has no
169
+ * record of minting it — which is what a note from a *different* issuer looks
170
+ * like, and is a different thing to tell the holder.
171
+ */
172
+ export async function inspectShareNote(note, secret, now = Date.now()) {
173
+ const { signature, ...unsigned } = note;
174
+ if (!secret || !verifySharePayload(unsigned, signature, secret)) {
175
+ return { status: "forged", coins: 0 };
176
+ }
177
+ await ensureLoaded({ force: true });
178
+ const record = notes[note.noteId];
179
+ if (!record) {
180
+ return { status: "unknown", coins: 0 };
181
+ }
182
+ if (record.redeemedAt !== undefined) {
183
+ return { status: "spent", coins: record.coins };
184
+ }
185
+ if (record.notAfter <= now) {
186
+ return { status: "expired", coins: record.coins };
187
+ }
188
+ return { status: "valid", coins: record.coins };
189
+ }
190
+ /**
191
+ * Redeem a note into a grant's balance.
192
+ *
193
+ * Marking spent and crediting happen under one lock, so two holders racing the
194
+ * same note produce exactly one credit. The record is marked **before** the
195
+ * credit: a crash between them costs the redeemer the note, which is the safe
196
+ * direction — the alternative is a note that can be redeemed twice.
197
+ */
198
+ export async function redeemShareNote(args) {
199
+ const now = args.now ?? Date.now();
200
+ const { signature, ...unsigned } = args.note;
201
+ if (!args.secret || !verifySharePayload(unsigned, signature, args.secret)) {
202
+ return { ok: false, status: "forged" };
203
+ }
204
+ const claimed = await mutationMutex.runExclusive(async () => {
205
+ await ensureLoaded({ force: true });
206
+ const record = notes[args.note.noteId];
207
+ if (!record) {
208
+ return { status: "unknown", coins: 0 };
209
+ }
210
+ if (record.redeemedAt !== undefined) {
211
+ return { status: "spent", coins: record.coins };
212
+ }
213
+ if (record.notAfter <= now) {
214
+ return { status: "expired", coins: record.coins };
215
+ }
216
+ notes[record.noteId] = {
217
+ ...record,
218
+ redeemedAt: now,
219
+ redeemedByGrant: args.grantId,
220
+ };
221
+ await persist();
222
+ return { status: "valid", coins: record.coins };
223
+ });
224
+ if (claimed.status !== "valid") {
225
+ return { ok: false, status: claimed.status };
226
+ }
227
+ const balance = await creditShareGrantCoins(args.grantId, claimed.coins);
228
+ return { ok: true, coins: claimed.coins, balance };
229
+ }
230
+ /** Every note this node has minted, newest first. */
231
+ export async function listShareNotes() {
232
+ await ensureLoaded({ force: true });
233
+ return Object.values(notes).sort((a, b) => b.issuedAt - a.issuedAt);
234
+ }
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Peer-sharing admission policy.
3
+ *
4
+ * Pure evaluation, no I/O — every input is passed in, so this module is cheap on
5
+ * the hot path and directly exercisable from a test.
6
+ *
7
+ * The gate set is deliberately **orthogonal and AND-ed**: a grant may carry a
8
+ * headroom floor *and* a window-slice ceiling *and* a model allowlist, and each
9
+ * is checked independently. The effective allowance is therefore the minimum
10
+ * across whatever is configured, which is what lets "share only what I am not
11
+ * using, and never more than a fifth of it" be one grant rather than two
12
+ * competing modes.
13
+ *
14
+ * Evaluation splits in two, because the two halves answer different questions:
15
+ *
16
+ * - `evaluateShareAdmission` — request-level. Is this borrower allowed to ask at
17
+ * all, right now, for this model?
18
+ * - `filterAccountsForGrant` — account-level. Of the lender's accounts, which
19
+ * may serve this borrower? Headroom and slice ceilings live here because they
20
+ * are properties of an individual account's windows, not of the request.
21
+ *
22
+ * @module proxy/sharePolicy
23
+ */
24
+ import type { ProxyShareAccountExclusion, ProxyShareAccountFilterResult, ProxyShareAccountView, ProxyShareAdmission, ProxyShareAdmissionInput, ProxyShareGates, ProxyShareGrant, ProxyShareRefusalReason, ProxyShareRefusedAdmission, ProxySharePoolUsage } from "../types/index.js";
25
+ /**
26
+ * Narrow an admission to its refusing half.
27
+ *
28
+ * A plain `!admission.admitted` check would do this under `strict`, but one of
29
+ * the package's build steps compiles without `strictNullChecks`, where TypeScript
30
+ * declines to narrow a boolean discriminant at all. An explicit predicate holds
31
+ * in both modes.
32
+ */
33
+ export declare function isShareRefusal(admission: ProxyShareAdmission): admission is ProxyShareRefusedAdmission;
34
+ export declare function shareRefusalMessage(reason: ProxyShareRefusalReason): string;
35
+ /** HTTP status for a refusal. 401 is "who are you", 403 is "not you, not ever
36
+ * under this grant", 429 is "not now" — the borrower retries only the last. */
37
+ export declare function shareRefusalStatus(reason: ProxyShareRefusalReason): number;
38
+ /**
39
+ * Is `now` inside the grant's allowed hours?
40
+ *
41
+ * A window whose start hour is greater than its end hour wraps midnight
42
+ * (`21 → 9` means the night shift), which is the common case for lending
43
+ * capacity you are asleep through.
44
+ */
45
+ export declare function isWithinSchedule(schedule: {
46
+ fromHour: number;
47
+ toHour: number;
48
+ }, now: number): boolean;
49
+ /**
50
+ * Does the requested model fall inside the allowlist?
51
+ *
52
+ * Entries are matched as case-insensitive substrings so a grant can name a tier
53
+ * (`sonnet`) rather than having to track every dated model id.
54
+ */
55
+ export declare function isModelAllowed(models: string[] | undefined, model: string | undefined): boolean;
56
+ /**
57
+ * Request-level admission.
58
+ *
59
+ * Order matters: identity and lifecycle first (they are permanent refusals),
60
+ * then scope, then the transient limits that carry a `Retry-After`. A borrower
61
+ * that is told "paused" must not also be told "slow down".
62
+ */
63
+ export declare function evaluateShareAdmission(input: ProxyShareAdmissionInput): ProxyShareAdmission;
64
+ /**
65
+ * Is the account inside its spillover window — close enough to a reset, with
66
+ * little enough consumed, that the remaining capacity would otherwise expire?
67
+ *
68
+ * Unknown reset times fail closed. A spillover grant is a promise about capacity
69
+ * that is *about to be lost*; without a reset time there is no such promise to
70
+ * keep, and guessing would hand out capacity the lender still intends to use.
71
+ */
72
+ export declare function isSpilloverActive(gates: ProxyShareGates, account: ProxyShareAccountView, now: number): boolean;
73
+ /**
74
+ * Split the pool into the accounts this grant may draw on and the rest.
75
+ *
76
+ * An entry in `gates.accounts` matches either the full store key
77
+ * (`anthropic:alice`) or the bare label (`alice`), because operators think in
78
+ * labels and the routing path thinks in keys.
79
+ *
80
+ * Exported because the scope decides more than admission: it is also the
81
+ * denominator of the pool-wide slice, and computing that over accounts the grant
82
+ * can never touch would loosen the ceiling in proportion to how many there are.
83
+ */
84
+ export declare function accountsInGrantScope(gates: ProxyShareGates, accounts: readonly ProxyShareAccountView[]): {
85
+ inScope: ProxyShareAccountView[];
86
+ outOfScope: ProxyShareAccountView[];
87
+ };
88
+ /**
89
+ * Decide which of the lender's accounts this grant may draw on.
90
+ *
91
+ * Returning exclusions alongside the survivors is deliberate: when nothing
92
+ * survives, the caller needs to say *why* — "your slice is spent" and "I am
93
+ * holding back my reserve" are different answers, and only one of them will
94
+ * change on its own.
95
+ */
96
+ export declare function filterAccountsForGrant(grant: ProxyShareGrant, accounts: readonly ProxyShareAccountView[], now: number,
97
+ /**
98
+ * Required, not optional. `gates.maxSlice` is a ceiling on what this grant
99
+ * has already drawn from the pool, and with nothing to compare against the
100
+ * only available answer is "not yet" — so an omitted argument would not relax
101
+ * the ceiling, it would remove it. `readSharePoolWindowUsage` returns zeroed
102
+ * fractions for a grant with no history, which is the honest empty value.
103
+ */
104
+ poolUsage: ProxySharePoolUsage): ProxyShareAccountFilterResult;
105
+ /**
106
+ * Collapse per-account exclusions into the single reason the borrower is told
107
+ * when nothing survived. A transient cause outranks a structural one so the
108
+ * borrower learns whether waiting is worth anything.
109
+ */
110
+ export declare function summarizeAccountExclusions(excluded: readonly ProxyShareAccountExclusion[]): ProxyShareRefusalReason;