@aboutcircles/sdk-invitations 0.1.24 → 0.1.25
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/Distributions.d.ts +41 -0
- package/dist/Distributions.d.ts.map +1 -0
- package/dist/Distributions.js +170 -0
- package/dist/Referrals.d.ts +35 -20
- package/dist/Referrals.d.ts.map +1 -1
- package/dist/Referrals.js +84 -91
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/tests/findInvitePath.test.d.ts +2 -0
- package/dist/tests/findInvitePath.test.d.ts.map +1 -0
- package/dist/tests/findInvitePath.test.js +41 -0
- package/dist/tests/fuzz/invite-checker.d.ts +2 -0
- package/dist/tests/fuzz/invite-checker.d.ts.map +1 -0
- package/dist/tests/fuzz/invite-checker.js +117 -0
- package/dist/tests/fuzz/networkFuzz.d.ts +6 -0
- package/dist/tests/fuzz/networkFuzz.d.ts.map +1 -0
- package/dist/tests/fuzz/networkFuzz.js +290 -0
- package/dist/tests/generateInvite.test.d.ts +2 -0
- package/dist/tests/generateInvite.test.d.ts.map +1 -0
- package/dist/tests/generateInvite.test.js +55 -0
- package/dist/tests/getRealInviters.test.d.ts +2 -0
- package/dist/tests/getRealInviters.test.d.ts.map +1 -0
- package/dist/tests/getRealInviters.test.js +77 -0
- package/dist/tests/helpers/mockFetch.d.ts +7 -0
- package/dist/tests/helpers/mockFetch.d.ts.map +1 -0
- package/dist/tests/helpers/mockFetch.js +282 -0
- package/dist/tests/helpers/scenario.d.ts +77 -0
- package/dist/tests/helpers/scenario.d.ts.map +1 -0
- package/dist/tests/helpers/scenario.js +104 -0
- package/dist/tests/helpers/scenarios.d.ts +40 -0
- package/dist/tests/helpers/scenarios.d.ts.map +1 -0
- package/dist/tests/helpers/scenarios.js +111 -0
- package/dist/types.d.ts +156 -23
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +26 -1
- package/package.json +1 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type DistributionSession, type DistributionSessionList, type CreateSessionParams, type UpdateSessionParams, type SessionKeyList, type AddKeysResult, type DispenseResult } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* HTTP client for distribution session management.
|
|
4
|
+
*
|
|
5
|
+
* Distribution sessions gate access to an inviter's key pool via
|
|
6
|
+
* quota, expiry, and pause controls. Each session gets a unique slug
|
|
7
|
+
* for QR codes / links.
|
|
8
|
+
*
|
|
9
|
+
* Session management endpoints require authentication. Pass a `getToken`
|
|
10
|
+
* callback to supply the Bearer JWT. The `dispense` endpoint is public.
|
|
11
|
+
*/
|
|
12
|
+
export declare class Distributions {
|
|
13
|
+
private readonly baseUrl;
|
|
14
|
+
private readonly getToken?;
|
|
15
|
+
constructor(baseUrl: string, getToken?: (() => Promise<string>) | undefined);
|
|
16
|
+
private getBaseUrl;
|
|
17
|
+
private getAuthHeaders;
|
|
18
|
+
createSession(params: CreateSessionParams): Promise<DistributionSession>;
|
|
19
|
+
listSessions(inviter: string, opts?: {
|
|
20
|
+
limit?: number;
|
|
21
|
+
offset?: number;
|
|
22
|
+
}): Promise<DistributionSessionList>;
|
|
23
|
+
getSession(id: string): Promise<DistributionSession>;
|
|
24
|
+
updateSession(id: string, params: UpdateSessionParams): Promise<DistributionSession>;
|
|
25
|
+
deleteSession(id: string): Promise<void>;
|
|
26
|
+
addKeys(id: string, keys: string[]): Promise<AddKeysResult>;
|
|
27
|
+
listKeys(id: string, opts?: {
|
|
28
|
+
limit?: number;
|
|
29
|
+
offset?: number;
|
|
30
|
+
}): Promise<SessionKeyList>;
|
|
31
|
+
removeKey(id: string, keyId: string): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Dispense a key via a distribution session slug (public, no auth required).
|
|
34
|
+
*
|
|
35
|
+
* @throws {DispenseError} with typed code:
|
|
36
|
+
* - `SESSION_NOT_FOUND` (404), `POOL_EMPTY` (404), `SESSION_EXPIRED` (410),
|
|
37
|
+
* `QUOTA_EXHAUSTED` (410), `SESSION_PAUSED` (423), `RATE_LIMITED` (429)
|
|
38
|
+
*/
|
|
39
|
+
dispense(slug: string): Promise<DispenseResult>;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=Distributions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Distributions.d.ts","sourceRoot":"","sources":["../src/Distributions.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,cAAc,EAIpB,MAAM,SAAS,CAAC;AASjB;;;;;;;;;GASG;AACH,qBAAa,aAAa;IAEtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBADT,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,GAAE,MAAM,OAAO,CAAC,MAAM,CAAC,aAAA;IAGnD,OAAO,CAAC,UAAU;YAMJ,cAAc;IAOtB,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAsBxE,YAAY,CAChB,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GACzC,OAAO,CAAC,uBAAuB,CAAC;IAsB7B,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAkBpD,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAsBpF,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBxC,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC;IAsB3D,QAAQ,CACZ,EAAE,EAAE,MAAM,EACV,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GACzC,OAAO,CAAC,cAAc,CAAC;IAuBpB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBzD;;;;;;OAMG;IACG,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;CAuCtD"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { DispenseError, SessionError, } from "./types";
|
|
2
|
+
function sessionErrorCode(status) {
|
|
3
|
+
if (status === 400)
|
|
4
|
+
return "VALIDATION_ERROR";
|
|
5
|
+
if (status === 404)
|
|
6
|
+
return "NOT_FOUND";
|
|
7
|
+
if (status === 409)
|
|
8
|
+
return "CONFLICT";
|
|
9
|
+
return "SERVER_ERROR";
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* HTTP client for distribution session management.
|
|
13
|
+
*
|
|
14
|
+
* Distribution sessions gate access to an inviter's key pool via
|
|
15
|
+
* quota, expiry, and pause controls. Each session gets a unique slug
|
|
16
|
+
* for QR codes / links.
|
|
17
|
+
*
|
|
18
|
+
* Session management endpoints require authentication. Pass a `getToken`
|
|
19
|
+
* callback to supply the Bearer JWT. The `dispense` endpoint is public.
|
|
20
|
+
*/
|
|
21
|
+
export class Distributions {
|
|
22
|
+
baseUrl;
|
|
23
|
+
getToken;
|
|
24
|
+
constructor(baseUrl, getToken) {
|
|
25
|
+
this.baseUrl = baseUrl;
|
|
26
|
+
this.getToken = getToken;
|
|
27
|
+
}
|
|
28
|
+
getBaseUrl() {
|
|
29
|
+
return this.baseUrl.endsWith("/")
|
|
30
|
+
? this.baseUrl.slice(0, -1)
|
|
31
|
+
: this.baseUrl;
|
|
32
|
+
}
|
|
33
|
+
async getAuthHeaders() {
|
|
34
|
+
const base = { "Content-Type": "application/json" };
|
|
35
|
+
if (!this.getToken)
|
|
36
|
+
return base;
|
|
37
|
+
const token = await this.getToken();
|
|
38
|
+
return { ...base, Authorization: `Bearer ${token}` };
|
|
39
|
+
}
|
|
40
|
+
async createSession(params) {
|
|
41
|
+
const response = await fetch(`${this.getBaseUrl()}/distributions/sessions`, {
|
|
42
|
+
method: "POST",
|
|
43
|
+
headers: await this.getAuthHeaders(),
|
|
44
|
+
body: JSON.stringify(params),
|
|
45
|
+
});
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
const error = (await response.json());
|
|
48
|
+
throw new SessionError(error.error || `Failed to create session: ${response.statusText}`, sessionErrorCode(response.status), response.status);
|
|
49
|
+
}
|
|
50
|
+
return response.json();
|
|
51
|
+
}
|
|
52
|
+
async listSessions(inviter, opts) {
|
|
53
|
+
const params = new URLSearchParams({ inviter });
|
|
54
|
+
if (opts?.limit !== undefined)
|
|
55
|
+
params.set("limit", String(opts.limit));
|
|
56
|
+
if (opts?.offset !== undefined)
|
|
57
|
+
params.set("offset", String(opts.offset));
|
|
58
|
+
const response = await fetch(`${this.getBaseUrl()}/distributions/sessions?${params}`, { headers: await this.getAuthHeaders() });
|
|
59
|
+
if (!response.ok) {
|
|
60
|
+
const error = (await response.json());
|
|
61
|
+
throw new SessionError(error.error || `Failed to list sessions: ${response.statusText}`, sessionErrorCode(response.status), response.status);
|
|
62
|
+
}
|
|
63
|
+
return response.json();
|
|
64
|
+
}
|
|
65
|
+
async getSession(id) {
|
|
66
|
+
const response = await fetch(`${this.getBaseUrl()}/distributions/sessions/${encodeURIComponent(id)}`, { headers: await this.getAuthHeaders() });
|
|
67
|
+
if (!response.ok) {
|
|
68
|
+
const error = (await response.json());
|
|
69
|
+
throw new SessionError(error.error || `Failed to get session: ${response.statusText}`, sessionErrorCode(response.status), response.status);
|
|
70
|
+
}
|
|
71
|
+
return response.json();
|
|
72
|
+
}
|
|
73
|
+
async updateSession(id, params) {
|
|
74
|
+
const response = await fetch(`${this.getBaseUrl()}/distributions/sessions/${encodeURIComponent(id)}`, {
|
|
75
|
+
method: "PATCH",
|
|
76
|
+
headers: await this.getAuthHeaders(),
|
|
77
|
+
body: JSON.stringify(params),
|
|
78
|
+
});
|
|
79
|
+
if (!response.ok) {
|
|
80
|
+
const error = (await response.json());
|
|
81
|
+
throw new SessionError(error.error || `Failed to update session: ${response.statusText}`, sessionErrorCode(response.status), response.status);
|
|
82
|
+
}
|
|
83
|
+
return response.json();
|
|
84
|
+
}
|
|
85
|
+
async deleteSession(id) {
|
|
86
|
+
const response = await fetch(`${this.getBaseUrl()}/distributions/sessions/${encodeURIComponent(id)}`, {
|
|
87
|
+
method: "DELETE",
|
|
88
|
+
headers: await this.getAuthHeaders(),
|
|
89
|
+
});
|
|
90
|
+
if (!response.ok) {
|
|
91
|
+
const error = (await response.json());
|
|
92
|
+
throw new SessionError(error.error || `Failed to delete session: ${response.statusText}`, sessionErrorCode(response.status), response.status);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async addKeys(id, keys) {
|
|
96
|
+
const response = await fetch(`${this.getBaseUrl()}/distributions/sessions/${encodeURIComponent(id)}/keys`, {
|
|
97
|
+
method: "POST",
|
|
98
|
+
headers: await this.getAuthHeaders(),
|
|
99
|
+
body: JSON.stringify({ keys }),
|
|
100
|
+
});
|
|
101
|
+
if (!response.ok) {
|
|
102
|
+
const error = (await response.json());
|
|
103
|
+
throw new SessionError(error.error || `Failed to add keys: ${response.statusText}`, sessionErrorCode(response.status), response.status);
|
|
104
|
+
}
|
|
105
|
+
return response.json();
|
|
106
|
+
}
|
|
107
|
+
async listKeys(id, opts) {
|
|
108
|
+
const params = new URLSearchParams();
|
|
109
|
+
if (opts?.limit !== undefined)
|
|
110
|
+
params.set("limit", String(opts.limit));
|
|
111
|
+
if (opts?.offset !== undefined)
|
|
112
|
+
params.set("offset", String(opts.offset));
|
|
113
|
+
const query = params.toString() ? `?${params}` : "";
|
|
114
|
+
const response = await fetch(`${this.getBaseUrl()}/distributions/sessions/${encodeURIComponent(id)}/keys${query}`, { headers: await this.getAuthHeaders() });
|
|
115
|
+
if (!response.ok) {
|
|
116
|
+
const error = (await response.json());
|
|
117
|
+
throw new SessionError(error.error || `Failed to list keys: ${response.statusText}`, sessionErrorCode(response.status), response.status);
|
|
118
|
+
}
|
|
119
|
+
return response.json();
|
|
120
|
+
}
|
|
121
|
+
async removeKey(id, keyId) {
|
|
122
|
+
const response = await fetch(`${this.getBaseUrl()}/distributions/sessions/${encodeURIComponent(id)}/keys/${encodeURIComponent(keyId)}`, {
|
|
123
|
+
method: "DELETE",
|
|
124
|
+
headers: await this.getAuthHeaders(),
|
|
125
|
+
});
|
|
126
|
+
if (!response.ok) {
|
|
127
|
+
const error = (await response.json());
|
|
128
|
+
throw new SessionError(error.error || `Failed to remove key: ${response.statusText}`, sessionErrorCode(response.status), response.status);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Dispense a key via a distribution session slug (public, no auth required).
|
|
133
|
+
*
|
|
134
|
+
* @throws {DispenseError} with typed code:
|
|
135
|
+
* - `SESSION_NOT_FOUND` (404), `POOL_EMPTY` (404), `SESSION_EXPIRED` (410),
|
|
136
|
+
* `QUOTA_EXHAUSTED` (410), `SESSION_PAUSED` (423), `RATE_LIMITED` (429)
|
|
137
|
+
*/
|
|
138
|
+
async dispense(slug) {
|
|
139
|
+
const response = await fetch(`${this.getBaseUrl()}/d/${encodeURIComponent(slug)}`, { headers: { Accept: "application/json" } });
|
|
140
|
+
if (!response.ok) {
|
|
141
|
+
let message;
|
|
142
|
+
let code;
|
|
143
|
+
try {
|
|
144
|
+
const error = (await response.json());
|
|
145
|
+
message = error.error;
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
message = response.statusText;
|
|
149
|
+
}
|
|
150
|
+
switch (response.status) {
|
|
151
|
+
case 404:
|
|
152
|
+
code = message.includes("keys available") ? "POOL_EMPTY" : "SESSION_NOT_FOUND";
|
|
153
|
+
break;
|
|
154
|
+
case 410:
|
|
155
|
+
code = message.includes("quota") ? "QUOTA_EXHAUSTED" : "SESSION_EXPIRED";
|
|
156
|
+
break;
|
|
157
|
+
case 423:
|
|
158
|
+
code = "SESSION_PAUSED";
|
|
159
|
+
break;
|
|
160
|
+
case 429:
|
|
161
|
+
code = "RATE_LIMITED";
|
|
162
|
+
break;
|
|
163
|
+
default:
|
|
164
|
+
code = "UNKNOWN";
|
|
165
|
+
}
|
|
166
|
+
throw new DispenseError(message, code, response.status);
|
|
167
|
+
}
|
|
168
|
+
return response.json();
|
|
169
|
+
}
|
|
170
|
+
}
|
package/dist/Referrals.d.ts
CHANGED
|
@@ -1,44 +1,59 @@
|
|
|
1
|
-
import type { ReferralInfo, ReferralList } from "./types";
|
|
1
|
+
import type { ReferralInfo, ReferralList, ReferralPreviewList, StoreBatchResult } from "./types";
|
|
2
2
|
/**
|
|
3
|
-
* Referrals service client for retrieving referral
|
|
3
|
+
* Referrals service client for storing and retrieving referral links
|
|
4
4
|
*
|
|
5
|
-
* The referrals backend enables Circles SDK users to
|
|
5
|
+
* The referrals backend enables Circles SDK users to invite others via referral links.
|
|
6
|
+
* - Store: Save a referral private key with on-chain validation
|
|
6
7
|
* - Retrieve: Get referral info by private key (public)
|
|
7
8
|
* - List: Get all referrals created by authenticated user
|
|
8
|
-
*
|
|
9
|
-
* Note: Storing referrals is handled by Invitations.generateReferral()
|
|
10
9
|
*/
|
|
11
10
|
export declare class Referrals {
|
|
12
11
|
private readonly baseUrl;
|
|
13
12
|
private readonly getToken?;
|
|
14
|
-
/**
|
|
15
|
-
* Create a new Referrals client
|
|
16
|
-
*
|
|
17
|
-
* @param baseUrl - The referrals service base URL (e.g., "https://referrals.circles.example")
|
|
18
|
-
* @param getToken - Optional function to get auth token for authenticated endpoints
|
|
19
|
-
*/
|
|
20
13
|
constructor(baseUrl: string, getToken?: (() => Promise<string>) | undefined);
|
|
21
14
|
private getBaseUrl;
|
|
22
15
|
private getAuthHeaders;
|
|
23
16
|
/**
|
|
24
|
-
*
|
|
17
|
+
* Store a referral private key
|
|
25
18
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
19
|
+
* The private key is validated on-chain via ReferralsModule.accounts() to ensure
|
|
20
|
+
* the account exists and has not been claimed. The inviter address is self-declared
|
|
21
|
+
* for dashboard visibility only - the on-chain indexer captures the true inviter.
|
|
22
|
+
*/
|
|
23
|
+
store(privateKey: string, inviter: string): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Store multiple referral private keys in a single request (max 200)
|
|
28
26
|
*
|
|
29
|
-
*
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
* Processing is independent — one failure doesn't block others.
|
|
28
|
+
*/
|
|
29
|
+
storeBatch(invitations: Array<{
|
|
30
|
+
privateKey: string;
|
|
31
|
+
inviter: string;
|
|
32
|
+
}>): Promise<StoreBatchResult>;
|
|
33
|
+
/**
|
|
34
|
+
* Retrieve referral info by private key (public endpoint, no auth required)
|
|
32
35
|
*/
|
|
33
36
|
retrieve(privateKey: string): Promise<ReferralInfo>;
|
|
34
37
|
/**
|
|
35
38
|
* List all referrals created by the authenticated user
|
|
36
39
|
*
|
|
37
40
|
* Requires authentication - the user's address is extracted from the JWT token.
|
|
41
|
+
*/
|
|
42
|
+
listMine(opts?: {
|
|
43
|
+
limit?: number;
|
|
44
|
+
offset?: number;
|
|
45
|
+
inSession?: boolean;
|
|
46
|
+
status?: string;
|
|
47
|
+
}): Promise<ReferralList>;
|
|
48
|
+
/**
|
|
49
|
+
* List referrals for a given address (public, no auth required)
|
|
38
50
|
*
|
|
39
|
-
*
|
|
40
|
-
* @throws InvitationError if not authenticated or request fails
|
|
51
|
+
* Returns masked key previews — full keys are never exposed here.
|
|
41
52
|
*/
|
|
42
|
-
|
|
53
|
+
listPublic(address: string, opts?: {
|
|
54
|
+
limit?: number;
|
|
55
|
+
offset?: number;
|
|
56
|
+
inSession?: boolean;
|
|
57
|
+
}): Promise<ReferralPreviewList>;
|
|
43
58
|
}
|
|
44
59
|
//# sourceMappingURL=Referrals.d.ts.map
|
package/dist/Referrals.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Referrals.d.ts","sourceRoot":"","sources":["../src/Referrals.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAY,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"Referrals.d.ts","sourceRoot":"","sources":["../src/Referrals.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,mBAAmB,EAAE,gBAAgB,EAAY,MAAM,SAAS,CAAC;AAE3G;;;;;;;GAOG;AACH,qBAAa,SAAS;IAElB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBADT,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,GAAE,MAAM,OAAO,CAAC,MAAM,CAAC,aAAA;IAGnD,OAAO,CAAC,UAAU;YAMJ,cAAc;IAO5B;;;;;;OAMG;IACG,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAa/D;;;;OAIG;IACG,UAAU,CACd,WAAW,EAAE,KAAK,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,GAC1D,OAAO,CAAC,gBAAgB,CAAC;IAe5B;;OAEG;IACG,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAazD;;;;OAIG;IACG,QAAQ,CAAC,IAAI,CAAC,EAAE;QACpB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,OAAO,CAAC,YAAY,CAAC;IAuBzB;;;;OAIG;IACG,UAAU,CACd,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,GAC9D,OAAO,CAAC,mBAAmB,CAAC;CAkBhC"}
|
package/dist/Referrals.js
CHANGED
|
@@ -1,22 +1,14 @@
|
|
|
1
|
-
import { InvitationError } from "./errors";
|
|
2
1
|
/**
|
|
3
|
-
* Referrals service client for retrieving referral
|
|
2
|
+
* Referrals service client for storing and retrieving referral links
|
|
4
3
|
*
|
|
5
|
-
* The referrals backend enables Circles SDK users to
|
|
4
|
+
* The referrals backend enables Circles SDK users to invite others via referral links.
|
|
5
|
+
* - Store: Save a referral private key with on-chain validation
|
|
6
6
|
* - Retrieve: Get referral info by private key (public)
|
|
7
7
|
* - List: Get all referrals created by authenticated user
|
|
8
|
-
*
|
|
9
|
-
* Note: Storing referrals is handled by Invitations.generateReferral()
|
|
10
8
|
*/
|
|
11
9
|
export class Referrals {
|
|
12
10
|
baseUrl;
|
|
13
11
|
getToken;
|
|
14
|
-
/**
|
|
15
|
-
* Create a new Referrals client
|
|
16
|
-
*
|
|
17
|
-
* @param baseUrl - The referrals service base URL (e.g., "https://referrals.circles.example")
|
|
18
|
-
* @param getToken - Optional function to get auth token for authenticated endpoints
|
|
19
|
-
*/
|
|
20
12
|
constructor(baseUrl, getToken) {
|
|
21
13
|
this.baseUrl = baseUrl;
|
|
22
14
|
this.getToken = getToken;
|
|
@@ -27,103 +19,104 @@ export class Referrals {
|
|
|
27
19
|
: this.baseUrl;
|
|
28
20
|
}
|
|
29
21
|
async getAuthHeaders() {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
22
|
+
const base = { "Content-Type": "application/json" };
|
|
23
|
+
if (!this.getToken)
|
|
24
|
+
return base;
|
|
33
25
|
const token = await this.getToken();
|
|
34
|
-
return {
|
|
35
|
-
"Content-Type": "application/json",
|
|
36
|
-
Authorization: `Bearer ${token}`,
|
|
37
|
-
};
|
|
26
|
+
return { ...base, Authorization: `Bearer ${token}` };
|
|
38
27
|
}
|
|
39
28
|
/**
|
|
40
|
-
*
|
|
29
|
+
* Store a referral private key
|
|
41
30
|
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
31
|
+
* The private key is validated on-chain via ReferralsModule.accounts() to ensure
|
|
32
|
+
* the account exists and has not been claimed. The inviter address is self-declared
|
|
33
|
+
* for dashboard visibility only - the on-chain indexer captures the true inviter.
|
|
34
|
+
*/
|
|
35
|
+
async store(privateKey, inviter) {
|
|
36
|
+
const response = await fetch(`${this.getBaseUrl()}/store`, {
|
|
37
|
+
method: "POST",
|
|
38
|
+
headers: { "Content-Type": "application/json" },
|
|
39
|
+
body: JSON.stringify({ privateKey, inviter }),
|
|
40
|
+
});
|
|
41
|
+
if (!response.ok) {
|
|
42
|
+
const error = (await response.json());
|
|
43
|
+
throw new Error(error.error || `Failed to store referral: ${response.statusText}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Store multiple referral private keys in a single request (max 200)
|
|
44
48
|
*
|
|
45
|
-
*
|
|
46
|
-
* @returns Referral info including inviter and status
|
|
47
|
-
* @throws InvitationError if referral not found or expired
|
|
49
|
+
* Processing is independent — one failure doesn't block others.
|
|
48
50
|
*/
|
|
49
|
-
async
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
catch {
|
|
60
|
-
errorMessage = response.statusText || errorMessage;
|
|
61
|
-
}
|
|
62
|
-
throw new InvitationError(errorMessage, {
|
|
63
|
-
code: 'INVITATION_RETRIEVE_FAILED',
|
|
64
|
-
source: 'INVITATIONS',
|
|
65
|
-
context: { status: response.status, url, privateKey }
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
return response.json();
|
|
51
|
+
async storeBatch(invitations) {
|
|
52
|
+
const response = await fetch(`${this.getBaseUrl()}/store-batch`, {
|
|
53
|
+
method: "POST",
|
|
54
|
+
headers: { "Content-Type": "application/json" },
|
|
55
|
+
body: JSON.stringify({ invitations }),
|
|
56
|
+
});
|
|
57
|
+
if (!response.ok) {
|
|
58
|
+
const error = (await response.json());
|
|
59
|
+
throw new Error(error.error || `Failed to store batch: ${response.statusText}`);
|
|
69
60
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
});
|
|
61
|
+
return response.json();
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Retrieve referral info by private key (public endpoint, no auth required)
|
|
65
|
+
*/
|
|
66
|
+
async retrieve(privateKey) {
|
|
67
|
+
const response = await fetch(`${this.getBaseUrl()}/retrieve?key=${encodeURIComponent(privateKey)}`);
|
|
68
|
+
if (!response.ok) {
|
|
69
|
+
const error = (await response.json());
|
|
70
|
+
throw new Error(error.error || `Failed to retrieve referral: ${response.statusText}`);
|
|
80
71
|
}
|
|
72
|
+
return response.json();
|
|
81
73
|
}
|
|
82
74
|
/**
|
|
83
75
|
* List all referrals created by the authenticated user
|
|
84
76
|
*
|
|
85
77
|
* Requires authentication - the user's address is extracted from the JWT token.
|
|
86
|
-
*
|
|
87
|
-
* @returns List of referrals with their status and metadata
|
|
88
|
-
* @throws InvitationError if not authenticated or request fails
|
|
89
78
|
*/
|
|
90
|
-
async listMine() {
|
|
79
|
+
async listMine(opts) {
|
|
91
80
|
if (!this.getToken) {
|
|
92
|
-
throw new
|
|
93
|
-
code: 'INVITATION_AUTH_REQUIRED',
|
|
94
|
-
source: 'INVITATIONS'
|
|
95
|
-
});
|
|
81
|
+
throw new Error("Authentication required to list referrals");
|
|
96
82
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
source: 'INVITATIONS',
|
|
113
|
-
context: { status: response.status, url }
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
return response.json();
|
|
83
|
+
const params = new URLSearchParams();
|
|
84
|
+
if (opts?.limit !== undefined)
|
|
85
|
+
params.set("limit", String(opts.limit));
|
|
86
|
+
if (opts?.offset !== undefined)
|
|
87
|
+
params.set("offset", String(opts.offset));
|
|
88
|
+
if (opts?.inSession !== undefined)
|
|
89
|
+
params.set("inSession", String(opts.inSession));
|
|
90
|
+
if (opts?.status !== undefined)
|
|
91
|
+
params.set("status", opts.status);
|
|
92
|
+
const query = params.toString() ? `?${params}` : "";
|
|
93
|
+
const headers = await this.getAuthHeaders();
|
|
94
|
+
const response = await fetch(`${this.getBaseUrl()}/my-referrals${query}`, { headers });
|
|
95
|
+
if (!response.ok) {
|
|
96
|
+
const error = (await response.json());
|
|
97
|
+
throw new Error(error.error || `Failed to list referrals: ${response.statusText}`);
|
|
117
98
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
99
|
+
return response.json();
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* List referrals for a given address (public, no auth required)
|
|
103
|
+
*
|
|
104
|
+
* Returns masked key previews — full keys are never exposed here.
|
|
105
|
+
*/
|
|
106
|
+
async listPublic(address, opts) {
|
|
107
|
+
const params = new URLSearchParams();
|
|
108
|
+
if (opts?.limit !== undefined)
|
|
109
|
+
params.set("limit", String(opts.limit));
|
|
110
|
+
if (opts?.offset !== undefined)
|
|
111
|
+
params.set("offset", String(opts.offset));
|
|
112
|
+
if (opts?.inSession !== undefined)
|
|
113
|
+
params.set("inSession", String(opts.inSession));
|
|
114
|
+
const query = params.toString() ? `?${params}` : "";
|
|
115
|
+
const response = await fetch(`${this.getBaseUrl()}/list/${encodeURIComponent(address)}${query}`);
|
|
116
|
+
if (!response.ok) {
|
|
117
|
+
const error = (await response.json());
|
|
118
|
+
throw new Error(error.error || `Failed to list referrals: ${response.statusText}`);
|
|
127
119
|
}
|
|
120
|
+
return response.json();
|
|
128
121
|
}
|
|
129
122
|
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC"}
|