@boltclaw/referrals 0.0.0-stage → 0.4.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 (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +500 -3
  3. package/dist/api-types.d.ts +245 -0
  4. package/dist/api-types.js +2 -0
  5. package/dist/api-types.js.map +1 -0
  6. package/dist/assistant-tools.d.ts +40 -0
  7. package/dist/assistant-tools.js +120 -0
  8. package/dist/assistant-tools.js.map +1 -0
  9. package/dist/assistant.d.ts +62 -0
  10. package/dist/assistant.js +305 -0
  11. package/dist/assistant.js.map +1 -0
  12. package/dist/case.d.ts +2 -0
  13. package/dist/case.js +30 -0
  14. package/dist/case.js.map +1 -0
  15. package/dist/client.d.ts +22 -0
  16. package/dist/client.js +80 -0
  17. package/dist/client.js.map +1 -0
  18. package/dist/element.d.ts +4 -0
  19. package/dist/element.js +204 -0
  20. package/dist/element.js.map +1 -0
  21. package/dist/errors.d.ts +19 -0
  22. package/dist/errors.js +62 -0
  23. package/dist/errors.js.map +1 -0
  24. package/dist/generated/api.d.ts +6477 -0
  25. package/dist/generated/api.js +891 -0
  26. package/dist/generated/api.js.map +1 -0
  27. package/dist/index.d.ts +18 -0
  28. package/dist/index.js +10 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/loader.d.ts +118 -0
  31. package/dist/loader.js +524 -0
  32. package/dist/loader.js.map +1 -0
  33. package/dist/middleware.d.ts +100 -0
  34. package/dist/middleware.js +378 -0
  35. package/dist/middleware.js.map +1 -0
  36. package/dist/origin.d.ts +3 -0
  37. package/dist/origin.js +22 -0
  38. package/dist/origin.js.map +1 -0
  39. package/dist/react.d.ts +69 -0
  40. package/dist/react.js +328 -0
  41. package/dist/react.js.map +1 -0
  42. package/dist/server-index.d.ts +17 -0
  43. package/dist/server-index.js +9 -0
  44. package/dist/server-index.js.map +1 -0
  45. package/dist/server.d.ts +106 -0
  46. package/dist/server.js +511 -0
  47. package/dist/server.js.map +1 -0
  48. package/dist/typed-code.d.ts +78 -0
  49. package/dist/typed-code.js +234 -0
  50. package/dist/typed-code.js.map +1 -0
  51. package/dist/types.d.ts +254 -0
  52. package/dist/types.js +61 -0
  53. package/dist/types.js.map +1 -0
  54. package/dist/webhooks.d.ts +20 -0
  55. package/dist/webhooks.js +90 -0
  56. package/dist/webhooks.js.map +1 -0
  57. package/package.json +97 -6
@@ -0,0 +1,305 @@
1
+ import { ReferralsServer } from "./server.js";
2
+ import { BoltClawApiError } from "./generated/api.js";
3
+ import { ReferralsApiError } from "./errors.js";
4
+ import { parseTypedCode } from "./typed-code.js";
5
+ import { ASSISTANT_TOOLS, CONFIRMATION_PATTERN, GET_MY_INVITE, INVITE_INPUT_MAX, LANGUAGE_TAG_PATTERN, USE_INVITE_CODE, } from "./assistant-tools.js";
6
+ const LANGUAGE = new RegExp(LANGUAGE_TAG_PATTERN);
7
+ const CONFIRMATION = new RegExp(CONFIRMATION_PATTERN);
8
+ export const CONFIRMATION_SECONDS = 15 * 60;
9
+ const nowSeconds = () => Math.floor(Date.now() / 1000);
10
+ const utf8 = (text) => new TextEncoder().encode(text);
11
+ function base64url(bytes) {
12
+ let binary = "";
13
+ for (const b of bytes)
14
+ binary += String.fromCharCode(b);
15
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
16
+ }
17
+ async function confirmationFor(apiKey, personId, code, at) {
18
+ const key = await crypto.subtle.importKey("raw", utf8(`boltclaw-assistant-confirmation\n${apiKey}`), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
19
+ const mac = new Uint8Array(await crypto.subtle.sign("HMAC", key, utf8(`use_invite_code\n${personId}\n${code}\n${at}`)));
20
+ return `${at.toString(36)}.${base64url(mac).slice(0, 32)}`;
21
+ }
22
+ async function confirmationValid(apiKey, personId, code, value) {
23
+ if (typeof value !== "string" || !CONFIRMATION.test(value))
24
+ return false;
25
+ const at = Number.parseInt(value.slice(0, value.indexOf(".")), 36);
26
+ const age = nowSeconds() - at;
27
+ if (!Number.isSafeInteger(at) || age < 0 || age > CONFIRMATION_SECONDS)
28
+ return false;
29
+ const expected = await confirmationFor(apiKey, personId, code, at);
30
+ let diff = expected.length ^ value.length;
31
+ for (let i = 0; i < expected.length; i++)
32
+ diff |= expected.charCodeAt(i) ^ (value.charCodeAt(i) || 0);
33
+ return diff === 0;
34
+ }
35
+ async function leadEventId(personId, code) {
36
+ const plain = `invite-code:${personId}:${code}`;
37
+ if (plain.length <= 255)
38
+ return plain;
39
+ const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", utf8(personId)));
40
+ return `invite-code:${code}:sha256-${[...digest].map((b) => b.toString(16).padStart(2, "0")).join("")}`;
41
+ }
42
+ export function assistantTools(options) {
43
+ if (typeof options?.customerOf !== "function")
44
+ throw new TypeError("customerOf must be a function that reads the person from your own session.");
45
+ if (options.signInAddressOf !== undefined && typeof options.signInAddressOf !== "function")
46
+ throw new TypeError("signInAddressOf must be a function.");
47
+ if (options.elicit !== undefined && typeof options.elicit !== "function")
48
+ throw new TypeError("elicit must be a function.");
49
+ const apiKey = options.apiKey;
50
+ const server = new ReferralsServer({
51
+ apiKey,
52
+ programId: options.programId,
53
+ baseUrl: options.baseUrl,
54
+ fetch: options.fetch,
55
+ dangerouslyAllowBrowser: options.dangerouslyAllowBrowser,
56
+ });
57
+ const hosts = options.linkHosts ?? {};
58
+ const getMyInvite = async (args, context) => {
59
+ const input = readArgs(args, ["language"]);
60
+ if (input === null)
61
+ return problem("The tool takes only an optional language tag.");
62
+ const language = input.language;
63
+ if (language !== undefined && (typeof language !== "string" || !LANGUAGE.test(language)))
64
+ return problem("language must be a language tag like de or pt-BR.");
65
+ const person = await personOf(options, context);
66
+ if (person === null)
67
+ return signInNeeded(GET_MY_INVITE.name);
68
+ const locale = typeof language === "string" ? language : person.locale;
69
+ try {
70
+ let text = await inviteText(server, person, locale);
71
+ if (text === null) {
72
+ await server.upsertReferrer({ externalId: person.id, ...(person.locale ? { locale: person.locale } : {}), ...(person.test ? { test: true } : {}) });
73
+ text = await inviteText(server, person, locale);
74
+ }
75
+ if (text === null)
76
+ return unavailable();
77
+ return { content: [{ type: "text", text }], structuredContent: { invite: text } };
78
+ }
79
+ catch (error) {
80
+ return failure(error);
81
+ }
82
+ };
83
+ const useInviteCode = async (args, context) => {
84
+ const input = readArgs(args, ["code", "confirm", "confirmation"]);
85
+ if (input === null || typeof input.code !== "string" || input.code.length === 0 || input.code.length > INVITE_INPUT_MAX) {
86
+ return problem("code must be the invite code or link the person gave, as text.");
87
+ }
88
+ if (input.confirm !== undefined && typeof input.confirm !== "boolean")
89
+ return problem("confirm must be true or false.");
90
+ if (input.confirmation !== undefined && (typeof input.confirmation !== "string" || !CONFIRMATION.test(input.confirmation))) {
91
+ return problem("confirmation must be the value the tool's previous answer gave.");
92
+ }
93
+ const person = await personOf(options, context);
94
+ if (person === null)
95
+ return signInNeeded(USE_INVITE_CODE.name);
96
+ const code = parseTypedCode(input.code, hosts);
97
+ if (code === null) {
98
+ return answer({
99
+ status: "not_a_code",
100
+ saved: false,
101
+ code: null,
102
+ message: "That is not an invite code. Ask the person to check the code or link their friend gave them. Nothing was saved.",
103
+ });
104
+ }
105
+ let offer;
106
+ try {
107
+ offer = (await server.api.getReferralOffer({ code, customer_id: person.id, ...(person.locale ? { locale: person.locale } : {}) }));
108
+ }
109
+ catch (error) {
110
+ return failure(error);
111
+ }
112
+ const display = offer.code_display ?? offer.code ?? null;
113
+ const details = offerDetails(offer);
114
+ if (offer.eligible !== true || typeof offer.code !== "string") {
115
+ return answer({
116
+ status: "refused",
117
+ saved: false,
118
+ code: display,
119
+ ...details,
120
+ reason: offer.reason_code ?? "unknown_code",
121
+ message: `${clip(offer.reason ?? "This invite code cannot be used.", 400)} Nothing was saved.`,
122
+ });
123
+ }
124
+ const question = `Do you want to use invite code ${display}${details.gives ? ` (${details.gives})` : ""}?`;
125
+ let agreed = null;
126
+ if (options.elicit) {
127
+ const asked = await options.elicit(context, {
128
+ message: [question, details.conditions, details.disclosure].filter(Boolean).join(" "),
129
+ requestedSchema: {
130
+ type: "object",
131
+ properties: { use: { type: "boolean", title: "Use this invite code", description: `Use ${display} for your account` } },
132
+ required: ["use"],
133
+ },
134
+ });
135
+ if (asked)
136
+ agreed = asked.action === "accept" && asked.content?.use === true;
137
+ }
138
+ if (agreed === false) {
139
+ return answer({ status: "declined", saved: false, code: display, ...details, message: "The person chose not to use the code. Nothing was saved." });
140
+ }
141
+ if (agreed === null) {
142
+ if (options.requireElicitation === true) {
143
+ return answer({
144
+ status: "needs_confirmation",
145
+ saved: false,
146
+ code: display,
147
+ ...details,
148
+ message: "This product saves an invite code only when the person confirms it in a window their assistant shows them, and this assistant cannot show one. Nothing was saved; the person can use the code in the product itself.",
149
+ });
150
+ }
151
+ const confirmed = input.confirm === true && (await confirmationValid(apiKey, person.id, offer.code, input.confirmation));
152
+ if (!confirmed) {
153
+ return answer({
154
+ status: "needs_confirmation",
155
+ saved: false,
156
+ code: display,
157
+ ...details,
158
+ question,
159
+ confirmation: await confirmationFor(apiKey, person.id, offer.code, nowSeconds()),
160
+ message: "Nothing is saved yet. Tell the person what the code gives and who else is rewarded, ask them the question, and only if they say yes in their own words call this tool again with the same code, confirm: true and this answer's confirmation.",
161
+ });
162
+ }
163
+ }
164
+ const signIn = (await options.signInAddressOf?.(context)) ?? null;
165
+ try {
166
+ const recorded = await server.recordLead({
167
+ eventId: await leadEventId(person.id, offer.code),
168
+ customerId: person.id,
169
+ ...(person.createdAt ? { customerCreatedAt: person.createdAt } : {}),
170
+ referralCode: offer.code,
171
+ entry: "typed",
172
+ surface: "ai_assistant",
173
+ ...(signIn?.ip ? { signupIp: signIn.ip } : {}),
174
+ ...(signIn?.userAgent ? { signupUserAgent: signIn.userAgent } : {}),
175
+ ...(signIn?.country ? { country: signIn.country } : {}),
176
+ ...(person.locale ? { locale: person.locale } : {}),
177
+ ...(person.test ? { test: true } : {}),
178
+ });
179
+ const conversion = recorded.conversion;
180
+ const refused = typeof conversion.referralRefused === "string" ? conversion.referralRefused : (conversion.attributionSkipped ?? null);
181
+ if (conversion.attributed !== true || refused !== null) {
182
+ return answer({
183
+ status: "refused",
184
+ saved: false,
185
+ code: display,
186
+ ...details,
187
+ reason: refused ?? "not_applied",
188
+ message: `${clip(conversion.referralRefusedMessage ?? "This invite code could not be used for this account.", 400)} Nothing was saved.`,
189
+ });
190
+ }
191
+ return answer({
192
+ status: "saved",
193
+ saved: true,
194
+ code: display,
195
+ ...details,
196
+ message: `Done: invite code ${display} is now used for this account.${details.gives ? ` It gives: ${details.gives}.` : ""}`,
197
+ });
198
+ }
199
+ catch (error) {
200
+ return failure(error);
201
+ }
202
+ };
203
+ const handlers = {
204
+ get_my_invite: getMyInvite,
205
+ use_invite_code: useInviteCode,
206
+ };
207
+ const tools = ASSISTANT_TOOLS.map((definition) => ({ ...definition, handler: handlers[definition.name] }));
208
+ return {
209
+ tools,
210
+ definitions: () => ASSISTANT_TOOLS.map((d) => ({ ...d })),
211
+ call: (name, args, context) => {
212
+ const tool = tools.find((t) => t.name === name);
213
+ return tool ? tool.handler(args, context) : Promise.resolve(problem(`There is no tool called ${clip(String(name), 60)}.`));
214
+ },
215
+ };
216
+ }
217
+ async function inviteText(server, person, locale) {
218
+ try {
219
+ const text = await server.api.getReferralReferrer({
220
+ id: server.programId,
221
+ external_id: person.id,
222
+ format: "text",
223
+ ...(locale && LANGUAGE.test(locale) ? { locale } : {}),
224
+ ...(person.test ? { test: "true" } : {}),
225
+ });
226
+ return typeof text === "string" && text.trim() !== "" ? text : null;
227
+ }
228
+ catch (error) {
229
+ if (error instanceof BoltClawApiError && error.status === 404)
230
+ return null;
231
+ throw error;
232
+ }
233
+ }
234
+ async function personOf(options, context) {
235
+ const person = await options.customerOf(context);
236
+ if (!person || typeof person.id !== "string" || person.id.length === 0 || person.id.length > 200)
237
+ return null;
238
+ return person;
239
+ }
240
+ function readArgs(args, allowed) {
241
+ if (args === undefined || args === null)
242
+ return {};
243
+ if (typeof args !== "object" || Array.isArray(args))
244
+ return null;
245
+ const out = {};
246
+ for (const [name, value] of Object.entries(args)) {
247
+ if (!allowed.includes(name))
248
+ return null;
249
+ out[name] = value;
250
+ }
251
+ return out;
252
+ }
253
+ function offerDetails(offer) {
254
+ const o = offer.offer;
255
+ return {
256
+ gives: o && typeof o.gift === "string" && o.gift.trim() !== "" ? clip(o.gift, 500) : null,
257
+ conditions: o && typeof o.conditions === "string" && o.conditions.trim() !== "" ? clip(o.conditions, 500) : null,
258
+ disclosure: o && typeof o.disclosure === "string" && o.disclosure.trim() !== "" ? clip(o.disclosure, 500) : null,
259
+ };
260
+ }
261
+ function answer(a) {
262
+ const structured = {
263
+ status: a.status,
264
+ saved: a.saved,
265
+ code: a.code === null ? null : clip(a.code, 64),
266
+ gives: a.gives ?? null,
267
+ conditions: a.conditions ?? null,
268
+ disclosure: a.disclosure ?? null,
269
+ question: a.question ?? null,
270
+ confirmation: a.confirmation ?? null,
271
+ reason: a.reason && /^[a-z_]{1,40}$/.test(a.reason) ? a.reason : null,
272
+ message: clip(a.message, 1000),
273
+ };
274
+ const lines = [structured.message];
275
+ if (structured.question)
276
+ lines.push(`Question for the person: ${structured.question}`);
277
+ if (structured.disclosure && a.status === "needs_confirmation")
278
+ lines.push(`Tell them too: ${structured.disclosure}`);
279
+ return { content: [{ type: "text", text: lines.join("\n") }], structuredContent: structured };
280
+ }
281
+ function signInNeeded(tool) {
282
+ const message = "The person is not signed in to this product. Ask them to sign in first, then try again.";
283
+ if (tool === "use_invite_code")
284
+ return answer({ status: "sign_in_needed", saved: false, code: null, message });
285
+ return { content: [{ type: "text", text: message }], structuredContent: { invite: message }, isError: true };
286
+ }
287
+ function problem(message) {
288
+ return { content: [{ type: "text", text: message }], structuredContent: { error: "invalid_arguments", message }, isError: true };
289
+ }
290
+ function unavailable() {
291
+ const message = "The invite service could not answer just now. Nothing was saved; try again in a moment.";
292
+ return { content: [{ type: "text", text: message }], structuredContent: { error: "unavailable", message }, isError: true };
293
+ }
294
+ function failure(error) {
295
+ if ((error instanceof BoltClawApiError || error instanceof ReferralsApiError) && error.status === 429) {
296
+ const message = "Too many tries just now. Nothing was saved; ask the person to wait a few minutes.";
297
+ return { content: [{ type: "text", text: message }], structuredContent: { error: "rate_limited", message }, isError: true };
298
+ }
299
+ return unavailable();
300
+ }
301
+ function clip(text, max) {
302
+ const one = text.replace(/\s+/g, " ").trim();
303
+ return one.length <= max ? one : `${one.slice(0, max - 1)}...`;
304
+ }
305
+ //# sourceMappingURL=assistant.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assistant.js","sourceRoot":"","sources":["../src/assistant.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAoC,MAAM,oBAAoB,CAAC;AACxF,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,cAAc,EAAuB,MAAM,iBAAiB,CAAC;AACtE,OAAO,EACL,eAAe,EACf,oBAAoB,EACpB,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,GAIhB,MAAM,sBAAsB,CAAC;AAuF9B,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,oBAAoB,CAAC,CAAC;AAClD,MAAM,YAAY,GAAG,IAAI,MAAM,CAAC,oBAAoB,CAAC,CAAC;AAEtD,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,GAAG,EAAE,CAAC;AAE5C,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;AACvD,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAE9D,SAAS,SAAS,CAAC,KAAiB;IAClC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,MAAM,CAAC,IAAI,KAAK;QAAE,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACxD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACjF,CAAC;AAOD,KAAK,UAAU,eAAe,CAAC,MAAc,EAAE,QAAgB,EAAE,IAAY,EAAE,EAAU;IACvF,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,oCAAoC,MAAM,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IACzJ,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,oBAAoB,QAAQ,KAAK,IAAI,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IACxH,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;AAC7D,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,MAAc,EAAE,QAAgB,EAAE,IAAY,EAAE,KAAc;IAC7F,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACzE,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACnE,MAAM,GAAG,GAAG,UAAU,EAAE,GAAG,EAAE,CAAC;IAC9B,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,oBAAoB;QAAE,OAAO,KAAK,CAAC;IACrF,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IACnE,IAAI,IAAI,GAAG,QAAQ,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAC1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,IAAI,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACtG,OAAO,IAAI,KAAK,CAAC,CAAC;AACpB,CAAC;AAGD,KAAK,UAAU,WAAW,CAAC,QAAgB,EAAE,IAAY;IACvD,MAAM,KAAK,GAAG,eAAe,QAAQ,IAAI,IAAI,EAAE,CAAC;IAChD,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG;QAAE,OAAO,KAAK,CAAC;IAEtC,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACrF,OAAO,eAAe,IAAI,WAAW,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;AAC1G,CAAC;AAGD,MAAM,UAAU,cAAc,CAAoB,OAAuC;IACvF,IAAI,OAAO,OAAO,EAAE,UAAU,KAAK,UAAU;QAAE,MAAM,IAAI,SAAS,CAAC,4EAA4E,CAAC,CAAC;IACjJ,IAAI,OAAO,CAAC,eAAe,KAAK,SAAS,IAAI,OAAO,OAAO,CAAC,eAAe,KAAK,UAAU;QAAE,MAAM,IAAI,SAAS,CAAC,qCAAqC,CAAC,CAAC;IACvJ,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,IAAI,OAAO,OAAO,CAAC,MAAM,KAAK,UAAU;QAAE,MAAM,IAAI,SAAS,CAAC,4BAA4B,CAAC,CAAC;IAC5H,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAC9B,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;QACjC,MAAM;QACN,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,uBAAuB,EAAE,OAAO,CAAC,uBAAuB;KACzD,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC;IAEtC,MAAM,WAAW,GAAG,KAAK,EAAE,IAAa,EAAE,OAAgB,EAAgC,EAAE;QAC1F,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;QAC3C,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,OAAO,CAAC,+CAA+C,CAAC,CAAC;QACpF,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;QAChC,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAAE,OAAO,OAAO,CAAC,mDAAmD,CAAC,CAAC;QAC9J,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAChD,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,YAAY,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAC7D,MAAM,MAAM,GAAG,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC;QACvE,IAAI,CAAC;YACH,IAAI,IAAI,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;YACpD,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBAElB,MAAM,MAAM,CAAC,cAAc,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;gBACpJ,IAAI,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;YAClD,CAAC;YACD,IAAI,IAAI,KAAK,IAAI;gBAAE,OAAO,WAAW,EAAE,CAAC;YACxC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,iBAAiB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC;QACpF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,aAAa,GAAG,KAAK,EAAE,IAAa,EAAE,OAAgB,EAAgC,EAAE;QAC5F,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC;QAClE,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,gBAAgB,EAAE,CAAC;YACxH,OAAO,OAAO,CAAC,gEAAgE,CAAC,CAAC;QACnF,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC,gCAAgC,CAAC,CAAC;QACxH,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS,IAAI,CAAC,OAAO,KAAK,CAAC,YAAY,KAAK,QAAQ,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;YAC3H,OAAO,OAAO,CAAC,iEAAiE,CAAC,CAAC;QACpF,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAChD,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,YAAY,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QAE/D,MAAM,IAAI,GAAG,cAAc,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC/C,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,OAAO,MAAM,CAAC;gBACZ,MAAM,EAAE,YAAY;gBACpB,KAAK,EAAE,KAAK;gBACZ,IAAI,EAAE,IAAI;gBACV,OAAO,EAAE,iHAAiH;aAC3H,CAAC,CAAC;QACL,CAAC;QACD,IAAI,KAAkB,CAAC;QACvB,IAAI,CAAC;YACH,KAAK,GAAG,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAgB,CAAC;QACpJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;QACD,MAAM,OAAO,GAAG,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC;QACzD,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QAGpC,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC9D,OAAO,MAAM,CAAC;gBACZ,MAAM,EAAE,SAAS;gBACjB,KAAK,EAAE,KAAK;gBACZ,IAAI,EAAE,OAAO;gBACb,GAAG,OAAO;gBACV,MAAM,EAAE,KAAK,CAAC,WAAW,IAAI,cAAc;gBAC3C,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,kCAAkC,EAAE,GAAG,CAAC,qBAAqB;aAC/F,CAAC,CAAC;QACL,CAAC;QAID,MAAM,QAAQ,GAAG,kCAAkC,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;QAC3G,IAAI,MAAM,GAAmB,IAAI,CAAC;QAClC,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE;gBAC1C,OAAO,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;gBACrF,eAAe,EAAE;oBACf,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,sBAAsB,EAAE,WAAW,EAAE,OAAO,OAAO,mBAAmB,EAAE,EAAE;oBACvH,QAAQ,EAAE,CAAC,KAAK,CAAC;iBAClB;aACF,CAAC,CAAC;YACH,IAAI,KAAK;gBAAE,MAAM,GAAG,KAAK,CAAC,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,CAAC;QAC/E,CAAC;QACD,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;YACrB,OAAO,MAAM,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,0DAA0D,EAAE,CAAC,CAAC;QACtJ,CAAC;QACD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,IAAI,OAAO,CAAC,kBAAkB,KAAK,IAAI,EAAE,CAAC;gBACxC,OAAO,MAAM,CAAC;oBACZ,MAAM,EAAE,oBAAoB;oBAC5B,KAAK,EAAE,KAAK;oBACZ,IAAI,EAAE,OAAO;oBACb,GAAG,OAAO;oBACV,OAAO,EACL,sNAAsN;iBACzN,CAAC,CAAC;YACL,CAAC;YAID,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,KAAK,IAAI,IAAI,CAAC,MAAM,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC;YACzH,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,OAAO,MAAM,CAAC;oBACZ,MAAM,EAAE,oBAAoB;oBAC5B,KAAK,EAAE,KAAK;oBACZ,IAAI,EAAE,OAAO;oBACb,GAAG,OAAO;oBACV,QAAQ;oBACR,YAAY,EAAE,MAAM,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC;oBAChF,OAAO,EACL,+OAA+O;iBAClP,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAG,CAAC,MAAM,OAAO,CAAC,eAAe,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,IAAI,CAAC;QAClE,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC;gBACvC,OAAO,EAAE,MAAM,WAAW,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC;gBACjD,UAAU,EAAE,MAAM,CAAC,EAAE;gBACrB,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpE,YAAY,EAAE,KAAK,CAAC,IAAI;gBACxB,KAAK,EAAE,OAAO;gBACd,OAAO,EAAE,cAAc;gBACvB,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC9C,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvD,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnD,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACvC,CAAC,CAAC;YACH,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC;YACvC,MAAM,OAAO,GAAG,OAAO,UAAU,CAAC,eAAe,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,kBAAkB,IAAI,IAAI,CAAC,CAAC;YACtI,IAAI,UAAU,CAAC,UAAU,KAAK,IAAI,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;gBACvD,OAAO,MAAM,CAAC;oBACZ,MAAM,EAAE,SAAS;oBACjB,KAAK,EAAE,KAAK;oBACZ,IAAI,EAAE,OAAO;oBACb,GAAG,OAAO;oBACV,MAAM,EAAE,OAAO,IAAI,aAAa;oBAChC,OAAO,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,sBAAsB,IAAI,sDAAsD,EAAE,GAAG,CAAC,qBAAqB;iBACxI,CAAC,CAAC;YACL,CAAC;YACD,OAAO,MAAM,CAAC;gBACZ,MAAM,EAAE,OAAO;gBACf,KAAK,EAAE,IAAI;gBACX,IAAI,EAAE,OAAO;gBACb,GAAG,OAAO;gBACV,OAAO,EAAE,qBAAqB,OAAO,iCAAiC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;aAC5H,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAiG;QAC7G,aAAa,EAAE,WAAW;QAC1B,eAAe,EAAE,aAAa;KAC/B,CAAC;IACF,MAAM,KAAK,GAAkC,eAAe,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1I,OAAO;QACL,KAAK;QACL,WAAW,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QACzD,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;YAC5B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;YAChD,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,2BAA2B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7H,CAAC;KACF,CAAC;AACJ,CAAC;AAGD,KAAK,UAAU,UAAU,CAAC,MAAuB,EAAE,MAAuB,EAAE,MAAiC;IAC3G,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC;YAChD,EAAE,EAAE,MAAM,CAAC,SAAS;YACpB,WAAW,EAAE,MAAM,CAAC,EAAE;YACtB,MAAM,EAAE,MAAM;YACd,GAAG,CAAC,MAAM,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtD,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACzC,CAAC,CAAC;QACH,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACtE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,gBAAgB,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC;QAC3E,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,KAAK,UAAU,QAAQ,CAAU,OAAuC,EAAE,OAAgB;IACxF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IACjD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,CAAC,EAAE,KAAK,QAAQ,IAAI,MAAM,CAAC,EAAE,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,EAAE,CAAC,MAAM,GAAG,GAAG;QAAE,OAAO,IAAI,CAAC;IAC9G,OAAO,MAAM,CAAC;AAChB,CAAC;AAGD,SAAS,QAAQ,CAAC,IAAa,EAAE,OAA0B;IACzD,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC;IACnD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACjE,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAA+B,CAAC,EAAE,CAAC;QAC5E,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACzC,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IACpB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,YAAY,CAAC,KAAkB;IACtC,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC;IACtB,OAAO;QACL,KAAK,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI;QACzF,UAAU,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI;QAChH,UAAU,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI;KACjH,CAAC;AACJ,CAAC;AAeD,SAAS,MAAM,CAAC,CAAkB;IAChC,MAAM,UAAU,GAA4B;QAC1C,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,IAAI,EAAE,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAC/C,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI;QACtB,UAAU,EAAE,CAAC,CAAC,UAAU,IAAI,IAAI;QAChC,UAAU,EAAE,CAAC,CAAC,UAAU,IAAI,IAAI;QAChC,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,IAAI;QAC5B,YAAY,EAAE,CAAC,CAAC,YAAY,IAAI,IAAI;QACpC,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;QACrE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC;KAC/B,CAAC;IACF,MAAM,KAAK,GAAG,CAAC,UAAU,CAAC,OAAiB,CAAC,CAAC;IAC7C,IAAI,UAAU,CAAC,QAAQ;QAAE,KAAK,CAAC,IAAI,CAAC,4BAA4B,UAAU,CAAC,QAAkB,EAAE,CAAC,CAAC;IACjG,IAAI,UAAU,CAAC,UAAU,IAAI,CAAC,CAAC,MAAM,KAAK,oBAAoB;QAAE,KAAK,CAAC,IAAI,CAAC,kBAAkB,UAAU,CAAC,UAAoB,EAAE,CAAC,CAAC;IAChI,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,iBAAiB,EAAE,UAAU,EAAE,CAAC;AAChG,CAAC;AAED,SAAS,YAAY,CAAC,IAAuB;IAC3C,MAAM,OAAO,GAAG,yFAAyF,CAAC;IAC1G,IAAI,IAAI,KAAK,iBAAiB;QAAE,OAAO,MAAM,CAAC,EAAE,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAC/G,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,iBAAiB,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC/G,CAAC;AAGD,SAAS,OAAO,CAAC,OAAe;IAC9B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,iBAAiB,EAAE,EAAE,KAAK,EAAE,mBAAmB,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACnI,CAAC;AAED,SAAS,WAAW;IAClB,MAAM,OAAO,GAAG,yFAAyF,CAAC;IAC1G,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,iBAAiB,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC7H,CAAC;AAMD,SAAS,OAAO,CAAC,KAAc;IAC7B,IAAI,CAAC,KAAK,YAAY,gBAAgB,IAAI,KAAK,YAAY,iBAAiB,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QACtG,MAAM,OAAO,GAAG,mFAAmF,CAAC;QACpG,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,iBAAiB,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC9H,CAAC;IACD,OAAO,WAAW,EAAE,CAAC;AACvB,CAAC;AAED,SAAS,IAAI,CAAC,IAAY,EAAE,GAAW;IACrC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAC7C,OAAO,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC;AACjE,CAAC"}
package/dist/case.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare function fromSnake<T>(value: unknown): T;
2
+ export declare function toSnake(value: unknown): unknown;
package/dist/case.js ADDED
@@ -0,0 +1,30 @@
1
+ const DATA_KEYED = new Set(["copy", "messages"]);
2
+ function camelKey(key) {
3
+ return key.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
4
+ }
5
+ function snakeKey(key) {
6
+ return key.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);
7
+ }
8
+ function isObject(value) {
9
+ return typeof value === "object" && value !== null && !Array.isArray(value);
10
+ }
11
+ function walk(value, rename) {
12
+ if (Array.isArray(value))
13
+ return value.map((v) => walk(v, rename));
14
+ if (!isObject(value))
15
+ return value;
16
+ const out = {};
17
+ for (const [key, inner] of Object.entries(value)) {
18
+ if (key === "__proto__")
19
+ continue;
20
+ out[rename(key)] = DATA_KEYED.has(key) && isObject(inner) ? { ...inner } : walk(inner, rename);
21
+ }
22
+ return out;
23
+ }
24
+ export function fromSnake(value) {
25
+ return walk(value, camelKey);
26
+ }
27
+ export function toSnake(value) {
28
+ return walk(value, snakeKey);
29
+ }
30
+ //# sourceMappingURL=case.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"case.js","sourceRoot":"","sources":["../src/case.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;AAEjD,SAAS,QAAQ,CAAC,GAAW;IAC3B,OAAO,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AACrE,CAAC;AAED,SAAS,QAAQ,CAAC,GAAW;IAC3B,OAAO,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,IAAI,CAAC,KAAc,EAAE,MAA+B;IAC3D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IACnE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACnC,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,IAAI,GAAG,KAAK,WAAW;YAAE,SAAS;QAClC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACjG,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,SAAS,CAAI,KAAc;IACzC,OAAO,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAM,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,KAAc;IACpC,OAAO,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { type ReferrerPanelView, type ReferrerPayoutMethod, type ShareEventChannel } from "./types.js";
2
+ export type FetchLike = typeof fetch;
3
+ export interface PanelClientOptions {
4
+ token: string;
5
+ origin?: string;
6
+ fetch?: FetchLike;
7
+ }
8
+ export interface PanelClient {
9
+ get(): Promise<ReferrerPanelView>;
10
+ share(channel: ShareEventChannel): Promise<void>;
11
+ savePayoutDetails(details: {
12
+ method: ReferrerPayoutMethod;
13
+ email: string;
14
+ }): Promise<{
15
+ set: boolean;
16
+ method: ReferrerPayoutMethod | null;
17
+ }>;
18
+ dismiss(): Promise<{
19
+ snoozedUntil: string | null;
20
+ }>;
21
+ }
22
+ export declare function createPanelClient(options: PanelClientOptions): PanelClient;
package/dist/client.js ADDED
@@ -0,0 +1,80 @@
1
+ import { errorFromBody, ReferralsApiError } from "./errors.js";
2
+ import { normaliseOrigin } from "./origin.js";
3
+ import { fromSnake } from "./case.js";
4
+ import { EMBED_TOKEN_FORMAT, PAYOUT_METHODS_FOR_REFERRERS, SHARE_EVENT_CHANNELS, } from "./types.js";
5
+ export function createPanelClient(options) {
6
+ if (typeof options?.token !== "string" || !EMBED_TOKEN_FORMAT.test(options.token)) {
7
+ throw new TypeError("token must be an embed token minted by your server (bcet_...).");
8
+ }
9
+ const token = options.token;
10
+ const url = `${normaliseOrigin(options.origin)}/api/referrals/embed`;
11
+ const doFetch = options.fetch ?? (typeof fetch === "function" ? fetch.bind(globalThis) : undefined);
12
+ if (!doFetch)
13
+ throw new TypeError("No fetch is available; pass one in the options.");
14
+ async function call(method, body) {
15
+ const headers = { Authorization: `Bearer ${token}`, Accept: "application/json" };
16
+ if (body !== undefined)
17
+ headers["Content-Type"] = "application/json";
18
+ let response;
19
+ try {
20
+ response = await doFetch(url, {
21
+ method,
22
+ headers,
23
+ body: body === undefined ? undefined : JSON.stringify(body),
24
+ credentials: "omit",
25
+ cache: "no-store",
26
+ referrerPolicy: "no-referrer",
27
+ });
28
+ }
29
+ catch {
30
+ throw new ReferralsApiError({ status: 0, code: "network_error", message: "The request could not be sent." });
31
+ }
32
+ let parsed = null;
33
+ try {
34
+ parsed = await response.json();
35
+ }
36
+ catch {
37
+ parsed = null;
38
+ }
39
+ if (!response.ok) {
40
+ const error = errorFromBody(response.status, parsed, (t) => t.split(token).join("[redacted]"));
41
+ if (response.status === 401) {
42
+ throw new ReferralsApiError({ status: 401, code: "token_expired", message: error.message, requestId: error.requestId });
43
+ }
44
+ if (response.status === 429) {
45
+ throw new ReferralsApiError({ status: 429, code: "rate_limited", message: error.message, requestId: error.requestId });
46
+ }
47
+ throw error;
48
+ }
49
+ if (parsed === null || typeof parsed !== "object") {
50
+ throw new ReferralsApiError({ status: response.status, code: "invalid_response", message: "The answer was not JSON." });
51
+ }
52
+ return parsed;
53
+ }
54
+ return {
55
+ async get() {
56
+ return fromSnake(await call("GET"));
57
+ },
58
+ async share(channel) {
59
+ if (!SHARE_EVENT_CHANNELS.includes(channel))
60
+ throw new TypeError("Unknown share channel.");
61
+ await call("POST", { action: "share", channel });
62
+ },
63
+ async savePayoutDetails(details) {
64
+ if (!PAYOUT_METHODS_FOR_REFERRERS.includes(details?.method)) {
65
+ throw new TypeError("method must be paypal or wise.");
66
+ }
67
+ if (typeof details.email !== "string" || details.email.length === 0 || details.email.length > 320) {
68
+ throw new TypeError("email is required.");
69
+ }
70
+ const answer = (await call("POST", { action: "payout_details", method: details.method, email: details.email }));
71
+ return { set: answer.payout?.set === true, method: answer.payout?.method ?? null };
72
+ },
73
+ async dismiss() {
74
+ const answer = (await call("POST", { action: "dismiss" }));
75
+ const until = answer.ask?.snoozed_until;
76
+ return { snoozedUntil: typeof until === "string" ? until : null };
77
+ },
78
+ };
79
+ }
80
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare const ELEMENT_NAME = "boltclaw-referrals";
2
+ export declare function defineReferralsElement(): boolean;
3
+ export declare const NOTICE_ELEMENT_NAME = "boltclaw-referral-notice";
4
+ export declare function defineNoticeElement(): boolean;