@domino-sdk/relay 1.11.1 → 1.14.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.
- package/README.md +1 -0
- package/build.mjs +15 -0
- package/dist/accounts-5ciAkCMP.d.ts +147 -0
- package/dist/{activity-CNiPDPK6.d.ts → activity-D_R3J-gU.d.ts} +115 -115
- package/dist/attempt-captures-DZldPZJc.d.ts +285 -0
- package/dist/authoring.d.ts +49 -47
- package/dist/authoring.js +6 -4
- package/dist/{automatic-outcomes-kPIDv6X_.d.ts → automatic-outcomes-6lJGnSDe.d.ts} +1 -1
- package/dist/browser.d.ts +8 -7
- package/dist/browser.js +7 -6
- package/dist/capability-error-oTd3eYFH.d.ts +151 -0
- package/dist/chunk-2UAVZCMH.js +314 -0
- package/dist/chunk-5TS3OAWS.js +470 -0
- package/dist/{chunk-PUDL4JBY.js → chunk-6DD7DVNQ.js} +2 -2
- package/dist/{chunk-AGFUDCNM.js → chunk-C3CB4WIQ.js} +1 -1
- package/dist/{chunk-T657WO56.js → chunk-LLMJ2SUT.js} +6 -2
- package/dist/chunk-NIYCAW2I.js +79 -0
- package/dist/chunk-UJACD6K2.js +987 -0
- package/dist/{chunk-XK5E4HAS.js → chunk-VBHFJH3P.js} +80 -28
- package/dist/chunk-W335CWYJ.js +53 -0
- package/dist/{chunk-X7ECZ3AK.js → chunk-XMBM2XD5.js} +1 -1
- package/dist/{chunk-2K2QBPAD.js → chunk-ZLYBUM7K.js} +6 -4
- package/dist/{client-fUSERMAC.d.ts → client-BTd_CyX3.d.ts} +26 -6
- package/dist/{groups-BK8ts2yK.d.ts → groups-4Jb3uYFO.d.ts} +1 -1
- package/dist/{images-aw6W7vFZ.d.ts → images-D5kpqHxv.d.ts} +1 -1
- package/dist/index.d.ts +9 -8
- package/dist/index.js +8 -6
- package/dist/{capability-error-ty3SqD_b.d.ts → integrations-Cr9EhGI_.d.ts} +1 -149
- package/dist/internal.d.ts +32 -5
- package/dist/internal.js +8 -3
- package/dist/{offers-C2FANzrG.d.ts → offers-BFI5t-e-.d.ts} +2 -2
- package/dist/{pages-Chb6OZSB.d.ts → pages-nIoMT9J3.d.ts} +1 -1
- package/dist/{participant-activity-DkL3nY5a.d.ts → participant-activity-DYdUUhw2.d.ts} +1 -0
- package/dist/portal-proxy.js +1 -1
- package/dist/react/index.d.ts +246 -177
- package/dist/react/index.js +954 -383
- package/dist/{referral-reward-kinds-M3f0PdiR.d.ts → referral-reward-kinds-DnvQXL8L.d.ts} +100 -3
- package/dist/{schema-DEM8y8Fm.d.ts → schema-K-Pg5lPz.d.ts} +1 -1
- package/dist/schema.d.ts +316 -314
- package/dist/schema.js +16 -14
- package/dist/server/index.d.ts +2546 -377
- package/dist/server/index.js +594 -841
- package/dist/{sign-in-options-iWOp9puZ.d.ts → sign-in-options-DBjMzgnu.d.ts} +2 -2
- package/dist/submission-input-CPIsJt-_.d.ts +146 -0
- package/dist/testing.d.ts +641 -0
- package/dist/testing.js +1282 -0
- package/package.json +6 -2
- package/dist/chunk-OCXGG75K.js +0 -171
- package/dist/chunk-ZFABFKIY.js +0 -1295
- package/dist/submission-input-BbBJTVlT.d.ts +0 -290
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
declare const xIdSchema: z.ZodString;
|
|
4
|
+
declare const xConnectionSchema: z.ZodObject<{
|
|
5
|
+
userId: z.ZodString;
|
|
6
|
+
}, z.core.$strip>;
|
|
7
|
+
declare const xProfileSchema: z.ZodObject<{
|
|
8
|
+
id: z.ZodString;
|
|
9
|
+
username: z.ZodString;
|
|
10
|
+
name: z.ZodString;
|
|
11
|
+
bio: z.ZodNullable<z.ZodString>;
|
|
12
|
+
profileImageUrl: z.ZodNullable<z.ZodString>;
|
|
13
|
+
followersCount: z.ZodNullable<z.ZodNumber>;
|
|
14
|
+
verified: z.ZodNullable<z.ZodBoolean>;
|
|
15
|
+
}, z.core.$strip>;
|
|
16
|
+
declare const xPostSchema: z.ZodObject<{
|
|
17
|
+
id: z.ZodString;
|
|
18
|
+
userId: z.ZodString;
|
|
19
|
+
content: z.ZodString;
|
|
20
|
+
createdAt: z.ZodISODateTime;
|
|
21
|
+
author: z.ZodObject<{
|
|
22
|
+
id: z.ZodString;
|
|
23
|
+
username: z.ZodString;
|
|
24
|
+
name: z.ZodString;
|
|
25
|
+
verified: z.ZodDefault<z.ZodNullable<z.ZodBoolean>>;
|
|
26
|
+
}, z.core.$loose>;
|
|
27
|
+
likeCount: z.ZodDefault<z.ZodNullable<z.ZodNumber>>;
|
|
28
|
+
replyCount: z.ZodDefault<z.ZodNullable<z.ZodNumber>>;
|
|
29
|
+
retweetCount: z.ZodDefault<z.ZodNullable<z.ZodNumber>>;
|
|
30
|
+
quoteCount: z.ZodDefault<z.ZodNullable<z.ZodNumber>>;
|
|
31
|
+
viewCount: z.ZodDefault<z.ZodNullable<z.ZodNumber>>;
|
|
32
|
+
bookmarkCount: z.ZodDefault<z.ZodNullable<z.ZodNumber>>;
|
|
33
|
+
isReply: z.ZodBoolean;
|
|
34
|
+
isRetweet: z.ZodBoolean;
|
|
35
|
+
isQuoteTweet: z.ZodBoolean;
|
|
36
|
+
quotedTweetId: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | null, string | null | undefined>>;
|
|
37
|
+
inReplyToUserId: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | null, string | null | undefined>>;
|
|
38
|
+
inReplyToStatusId: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | null, string | null | undefined>>;
|
|
39
|
+
retweetedTweetId: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | null, string | null | undefined>>;
|
|
40
|
+
media: z.ZodPipe<z.ZodUnknown, z.ZodTransform<{
|
|
41
|
+
type: string;
|
|
42
|
+
url: string;
|
|
43
|
+
}[], unknown>>;
|
|
44
|
+
}, z.core.$loose>;
|
|
45
|
+
declare const xRequestSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
46
|
+
operation: z.ZodLiteral<"connection">;
|
|
47
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
48
|
+
operation: z.ZodLiteral<"profile">;
|
|
49
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
50
|
+
operation: z.ZodLiteral<"post">;
|
|
51
|
+
postId: z.ZodString;
|
|
52
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
53
|
+
operation: z.ZodLiteral<"follows">;
|
|
54
|
+
userId: z.ZodString;
|
|
55
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
56
|
+
operation: z.ZodLiteral<"reposted">;
|
|
57
|
+
postId: z.ZodString;
|
|
58
|
+
}, z.core.$strict>], "operation">;
|
|
59
|
+
type XConnection = z.infer<typeof xConnectionSchema>;
|
|
60
|
+
type XProfile = z.infer<typeof xProfileSchema>;
|
|
61
|
+
type XPost = z.infer<typeof xPostSchema>;
|
|
62
|
+
/**
|
|
63
|
+
* Reads the member's linked X account and public X data. The account is pinned at the attempt's
|
|
64
|
+
* first X read: later links and unlinks do not change the attempt. `connection()`, `profile()`,
|
|
65
|
+
* `follows()` and `reposted()` resolve to `null` when the member has no linked X account;
|
|
66
|
+
* `post()` reads any public post and resolves to `null` when it does not exist. Provider failures
|
|
67
|
+
* throw `CapabilityError` with code `"provider-unavailable"`.
|
|
68
|
+
*/
|
|
69
|
+
interface XReader {
|
|
70
|
+
connection(): Promise<XConnection | null>;
|
|
71
|
+
profile(): Promise<XProfile | null>;
|
|
72
|
+
post(input: {
|
|
73
|
+
postId: string;
|
|
74
|
+
}): Promise<XPost | null>;
|
|
75
|
+
follows(input: {
|
|
76
|
+
userId: string;
|
|
77
|
+
}): Promise<boolean | null>;
|
|
78
|
+
reposted(input: {
|
|
79
|
+
postId: string;
|
|
80
|
+
}): Promise<boolean | null>;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Why an evaluator capability could not answer:
|
|
85
|
+
*
|
|
86
|
+
* - `not-linked`: the call needs a member account that is not linked, and its result cannot be
|
|
87
|
+
* null, such as an image check of the member's X profile picture. Readers of the member's own
|
|
88
|
+
* accounts return `null` instead.
|
|
89
|
+
* - `provider-unavailable`: the provider (X, Discord, a chain RPC, AI review) did not answer, or
|
|
90
|
+
* the project's integration cannot reach it.
|
|
91
|
+
* - `author-error`: the call cannot be answered as written: invalid input, an undeclared
|
|
92
|
+
* integration, an unknown tracker, a chain Relay does not read, a wallet the member never
|
|
93
|
+
* linked, or an image that does not exist.
|
|
94
|
+
*
|
|
95
|
+
* Later versions can add codes. Treat an unknown code as a failure its `message` explains.
|
|
96
|
+
*/
|
|
97
|
+
declare const capabilityErrorCodes: readonly ["not-linked", "provider-unavailable", "author-error"];
|
|
98
|
+
/** @compat open */
|
|
99
|
+
type KnownCapabilityErrorCode = (typeof capabilityErrorCodes)[number];
|
|
100
|
+
/** A known code, or one a newer Relay added. */
|
|
101
|
+
type CapabilityErrorCode = KnownCapabilityErrorCode | (string & {});
|
|
102
|
+
/**
|
|
103
|
+
* A capability failure as it crosses the sandbox boundary and as Relay captures it. Open, so a
|
|
104
|
+
* newer Relay can add codes and fields without breaking an older evaluator or Worker.
|
|
105
|
+
*/
|
|
106
|
+
declare const capabilityFailureSchema: z.ZodObject<{
|
|
107
|
+
code: z.ZodString;
|
|
108
|
+
message: z.ZodString;
|
|
109
|
+
/**
|
|
110
|
+
* True when Relay retries the attempt if the error reaches it uncaught, and calls the provider
|
|
111
|
+
* again. A failure that is not retryable is captured (or follows from the attempt's pinned
|
|
112
|
+
* inputs), so every run of the attempt sees it again. A retryable failure that quest code
|
|
113
|
+
* handles and moves past is final for the attempt; one that escapes the evaluation is retried.
|
|
114
|
+
*/
|
|
115
|
+
retryable: z.ZodBoolean;
|
|
116
|
+
}, z.core.$loose>;
|
|
117
|
+
type CapabilityFailure = z.infer<typeof capabilityFailureSchema>;
|
|
118
|
+
/**
|
|
119
|
+
* Thrown by an evaluator capability (`ctx.x`, `ctx.discord`, `ctx.wallet`, `ctx.trackers`,
|
|
120
|
+
* `ctx.images`, `ctx.review`) that could not answer. A capability whose subject is missing (an
|
|
121
|
+
* account the member has not linked, a deleted post or message) returns `null` instead of
|
|
122
|
+
* throwing.
|
|
123
|
+
*
|
|
124
|
+
* Catch it to decide yourself; rethrow anything else. An uncaught retryable error makes Relay
|
|
125
|
+
* retry the attempt later; an uncaught one that is not retryable fails it.
|
|
126
|
+
*
|
|
127
|
+
* ```ts
|
|
128
|
+
* try {
|
|
129
|
+
* return (await ctx.x.follows({ userId })) ? decision.accept() : decision.reject({ reason })
|
|
130
|
+
* } catch (error) {
|
|
131
|
+
* if (error instanceof CapabilityError && error.code === "provider-unavailable")
|
|
132
|
+
* return decision.review({ reason: "X is unavailable" })
|
|
133
|
+
* throw error
|
|
134
|
+
* }
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
declare class CapabilityError extends Error {
|
|
138
|
+
readonly code: CapabilityErrorCode;
|
|
139
|
+
readonly retryable: boolean;
|
|
140
|
+
constructor(code: CapabilityErrorCode, message: string, options?: {
|
|
141
|
+
retryable?: boolean;
|
|
142
|
+
});
|
|
143
|
+
static [Symbol.hasInstance](value: unknown): boolean;
|
|
144
|
+
/**
|
|
145
|
+
* The error for a captured or transported failure. A code this SDK does not know is never
|
|
146
|
+
* retryable: nothing tells it a retry would help.
|
|
147
|
+
*/
|
|
148
|
+
static from(failure: CapabilityFailure): CapabilityError;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export { CapabilityError as C, type KnownCapabilityErrorCode as K, type XReader as X, type CapabilityErrorCode as a, type CapabilityFailure as b, capabilityErrorCodes as c, type XConnection as d, type XPost as e, type XProfile as f, capabilityFailureSchema as g, xIdSchema as h, xPostSchema as i, xProfileSchema as j, xRequestSchema as k, xConnectionSchema as x };
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import {
|
|
2
|
+
RequestError,
|
|
3
|
+
isRequestError
|
|
4
|
+
} from "./chunk-NPGENI7K.js";
|
|
5
|
+
import {
|
|
6
|
+
responseShape
|
|
7
|
+
} from "./chunk-46C33ASD.js";
|
|
8
|
+
|
|
9
|
+
// src/errors.ts
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
var RelayErrorCode = {
|
|
12
|
+
/** The call needs a signed-in member. */
|
|
13
|
+
NotSignedIn: "not-signed-in",
|
|
14
|
+
/** The session changed since the app read it (the `session` option). Reload before retrying. */
|
|
15
|
+
StaleSession: "stale-session",
|
|
16
|
+
/** The input failed validation before it was sent. */
|
|
17
|
+
InvalidInput: "invalid-input",
|
|
18
|
+
/** Relay's answer was not JSON or not the expected shape (kind `invalid-response`). */
|
|
19
|
+
InvalidResponse: "invalid-response",
|
|
20
|
+
/** The transport failed, before a response or while reading its body (kind `network`). */
|
|
21
|
+
Network: "network",
|
|
22
|
+
/** The client's deadline elapsed (kind `timeout`). */
|
|
23
|
+
Timeout: "timeout",
|
|
24
|
+
/** The caller cancelled the request (kind `aborted`). */
|
|
25
|
+
Aborted: "aborted",
|
|
26
|
+
/** A quest or collection the call named is not in the member's experience. */
|
|
27
|
+
NotFound: "not-found",
|
|
28
|
+
/** The quest has no failed attempt the member can retry. */
|
|
29
|
+
RetryUnavailable: "retry-unavailable",
|
|
30
|
+
/**
|
|
31
|
+
* Durable submission storage is missing, blocked or unreadable. Nothing was lost: call the
|
|
32
|
+
* handle's `status()` or `resume()` again once storage is available.
|
|
33
|
+
*/
|
|
34
|
+
SubmissionStorage: "submission-storage",
|
|
35
|
+
/** Browser storage is full, so submission progress was not saved. Free space, then resume. */
|
|
36
|
+
SubmissionStorageQuota: "submission-storage-quota",
|
|
37
|
+
/** The saved submission is in a state that does not allow this action. */
|
|
38
|
+
SubmissionConflict: "submission-conflict",
|
|
39
|
+
/** The quest changed since the member saw it; review it before submitting again. */
|
|
40
|
+
QuestUpdated: "quest-updated",
|
|
41
|
+
/** Wait for the deferred attempt before submitting another action. */
|
|
42
|
+
AttemptPending: "attempt-pending",
|
|
43
|
+
/** The quiz changed since the member answered it. */
|
|
44
|
+
StaleQuiz: "stale-quiz",
|
|
45
|
+
/** Relay refused the submitted evidence. */
|
|
46
|
+
InvalidSubmission: "invalid-submission",
|
|
47
|
+
/** A page cursor Relay cannot read; start again from the first page. */
|
|
48
|
+
InvalidCursor: "invalid-cursor",
|
|
49
|
+
/** No point ledger in the project has the key or ID the call named. */
|
|
50
|
+
PointLedgerNotFound: "point-ledger-not-found",
|
|
51
|
+
/** The member has not joined this project, so it holds no points here. */
|
|
52
|
+
NotJoined: "not-joined",
|
|
53
|
+
/** The quest or campaign is not open at this time. */
|
|
54
|
+
OutsideWindow: "outside-window",
|
|
55
|
+
/** The signed-in member must enroll in the campaign first. */
|
|
56
|
+
EnrollmentRequired: "enrollment-required",
|
|
57
|
+
/** The quest's current reward budget has no remaining capacity. */
|
|
58
|
+
BudgetExhausted: "budget-exhausted",
|
|
59
|
+
/** No published offer has the key or ID the call named. */
|
|
60
|
+
OfferNotFound: "offer-not-found",
|
|
61
|
+
/** The operator paused this offer. */
|
|
62
|
+
OfferPaused: "offer-paused",
|
|
63
|
+
/** This member has already used the offer's allowed number of redemptions. */
|
|
64
|
+
OfferLimitReached: "offer-limit-reached",
|
|
65
|
+
/** No declared units remain. */
|
|
66
|
+
OfferOutOfStock: "offer-out-of-stock",
|
|
67
|
+
/** The participant's available point balance is below the offer price. */
|
|
68
|
+
InsufficientPoints: "insufficient-points",
|
|
69
|
+
/** A wallet signer failed or the member refused to sign; `cause` is the wallet's own error. */
|
|
70
|
+
WalletSigner: "wallet-signer",
|
|
71
|
+
/** The member has not met the quest's prerequisites; `missing` lists them. */
|
|
72
|
+
PrerequisitesIncomplete: "prerequisites-incomplete",
|
|
73
|
+
/** The quest is archived or retired: it takes no new participation. */
|
|
74
|
+
QuestClosed: "quest-closed",
|
|
75
|
+
/** An operator paused the quest. */
|
|
76
|
+
QuestPaused: "quest-paused",
|
|
77
|
+
/** An operator locked the member's profile; hiding it is still allowed. */
|
|
78
|
+
ProfileLocked: "profile-locked",
|
|
79
|
+
/** No member in the project has the invitation code the member accepted. */
|
|
80
|
+
InvitationNotFound: "invitation-not-found",
|
|
81
|
+
/** The email sign-in code is wrong; the member can type it again. */
|
|
82
|
+
InvalidCode: "invalid-code",
|
|
83
|
+
/** The email sign-in code expired, was used or had too many attempts; request another. */
|
|
84
|
+
CodeExpired: "code-expired",
|
|
85
|
+
/** The wallet sign-in challenge expired, was used or changed; start sign-in again. */
|
|
86
|
+
ChallengeExpired: "challenge-expired",
|
|
87
|
+
/** Too many requests; `retryAfter` says how long to wait when Relay knows. */
|
|
88
|
+
RateLimited: "rate-limited"
|
|
89
|
+
};
|
|
90
|
+
var relayErrorBrand = /* @__PURE__ */ Symbol.for("@domino-sdk/relay.RelayError");
|
|
91
|
+
function isRelayError(value) {
|
|
92
|
+
return isRequestError(value) && value[relayErrorBrand] === true;
|
|
93
|
+
}
|
|
94
|
+
var RelayError = class extends RequestError {
|
|
95
|
+
name = "RelayError";
|
|
96
|
+
[relayErrorBrand] = true;
|
|
97
|
+
/** Which window refused admission when `code` is `outside-window`. */
|
|
98
|
+
window;
|
|
99
|
+
/** Prerequisites the member does not currently meet, when Relay refused for that reason. */
|
|
100
|
+
missing;
|
|
101
|
+
constructor(message, details) {
|
|
102
|
+
super(message, details);
|
|
103
|
+
this.window = details.window;
|
|
104
|
+
this.missing = details.missing ?? [];
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
function asRelayError(cause, fallback = "Request failed") {
|
|
108
|
+
if (isRelayError(cause)) {
|
|
109
|
+
return cause;
|
|
110
|
+
}
|
|
111
|
+
return new RelayError(
|
|
112
|
+
cause instanceof Error && cause.message ? cause.message : fallback,
|
|
113
|
+
{ kind: "client", cause }
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
function clientError(message, code, details = {}) {
|
|
117
|
+
return new RelayError(message, { ...details, kind: "client", code });
|
|
118
|
+
}
|
|
119
|
+
function parseInput(schema, value) {
|
|
120
|
+
const parsed = schema.safeParse(value);
|
|
121
|
+
if (!parsed.success) {
|
|
122
|
+
throw clientError(
|
|
123
|
+
z.prettifyError(parsed.error),
|
|
124
|
+
RelayErrorCode.InvalidInput,
|
|
125
|
+
{ cause: parsed.error }
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
return parsed.data;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// src/wallet.ts
|
|
132
|
+
import { z as z2 } from "zod";
|
|
133
|
+
var solanaAddressSchema = z2.string().min(32).max(44).regex(/^[1-9A-HJ-NP-Za-km-z]+$/);
|
|
134
|
+
var walletChainSchema = z2.enum(["solana", "eip155", "cosmos"]);
|
|
135
|
+
var cosmosNetworkPattern = /^cosmos:[-_a-zA-Z0-9]{1,32}$/;
|
|
136
|
+
var cosmosNetworkSchema = z2.custom(
|
|
137
|
+
(value) => typeof value === "string" && cosmosNetworkPattern.test(value),
|
|
138
|
+
"Use a Cosmos network: cosmos:<chain ID>"
|
|
139
|
+
);
|
|
140
|
+
var cosmosDenomSchema = z2.string().regex(
|
|
141
|
+
/^[a-zA-Z][a-zA-Z0-9/:._-]{2,127}$/,
|
|
142
|
+
"Use a Cosmos bank denomination such as uatom or uosmo"
|
|
143
|
+
);
|
|
144
|
+
function cosmosChain(chain) {
|
|
145
|
+
if (typeof chain === "string" && !chain.startsWith("cosmos:")) {
|
|
146
|
+
throw new Error('Use a Cosmos network such as "cosmos:cosmoshub-4"');
|
|
147
|
+
}
|
|
148
|
+
const value = typeof chain === "string" ? { chainId: chain.slice("cosmos:".length) } : chain;
|
|
149
|
+
if (typeof value?.chainId !== "string") {
|
|
150
|
+
throw new Error(
|
|
151
|
+
'Pass a Cosmos chain as { chainId } or a network such as "cosmos:cosmoshub-4"'
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
const network = `cosmos:${value.chainId}`;
|
|
155
|
+
if (!cosmosNetworkPattern.test(network)) {
|
|
156
|
+
throw new Error(
|
|
157
|
+
"A Cosmos chain ID has 1 to 32 letters, digits, hyphens or underscores"
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
if (value.chainInfo && value.chainInfo.chainId !== value.chainId) {
|
|
161
|
+
throw new Error("The chain info describes another chain ID");
|
|
162
|
+
}
|
|
163
|
+
return { ...value, network };
|
|
164
|
+
}
|
|
165
|
+
var solanaMainnet = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
|
|
166
|
+
var evmAddressSchema = z2.string().regex(/^0x[0-9a-fA-F]{40}$/);
|
|
167
|
+
var cosmosAddressSchema = z2.string().min(8).max(90).regex(
|
|
168
|
+
/^(?:[a-z][a-z0-9]{0,82}1[02-9ac-hj-np-z]{38,}|[A-Z][A-Z0-9]{0,82}1[02-9AC-HJ-NP-Z]{38,})$/
|
|
169
|
+
);
|
|
170
|
+
var walletAddressInputSchema = z2.discriminatedUnion("chain", [
|
|
171
|
+
z2.object({ chain: z2.literal("solana"), address: solanaAddressSchema }).strict(),
|
|
172
|
+
z2.object({
|
|
173
|
+
chain: z2.literal("eip155"),
|
|
174
|
+
address: evmAddressSchema,
|
|
175
|
+
/** Shown in the sign-in message's Chain ID line only: links are chain-agnostic. Defaults to 1. */
|
|
176
|
+
chainId: z2.number().int().positive().safe().optional()
|
|
177
|
+
}).strict(),
|
|
178
|
+
z2.object({
|
|
179
|
+
chain: z2.literal("cosmos"),
|
|
180
|
+
network: cosmosNetworkSchema,
|
|
181
|
+
address: cosmosAddressSchema
|
|
182
|
+
}).strict()
|
|
183
|
+
]);
|
|
184
|
+
var walletMessageChallengeSchema = z2.object({
|
|
185
|
+
id: z2.string().min(1).max(200),
|
|
186
|
+
purpose: z2.enum(["link", "sign-in"]),
|
|
187
|
+
chain: walletChainSchema,
|
|
188
|
+
network: cosmosNetworkSchema.nullable(),
|
|
189
|
+
/** Canonical (base58, EIP-55 or lowercase bech32). The signer must sign with this address. */
|
|
190
|
+
address: z2.string(),
|
|
191
|
+
message: z2.string().max(4096),
|
|
192
|
+
expiresAt: z2.number().int()
|
|
193
|
+
});
|
|
194
|
+
var walletSignatureSchema = z2.object({
|
|
195
|
+
challenge: z2.string().min(1).max(200),
|
|
196
|
+
/** solana: base58, 64 bytes · eip155: 0x and 130 hex digits (65 bytes) · cosmos: base64, 64 bytes (r‖s) */
|
|
197
|
+
signature: z2.string().min(1).max(256),
|
|
198
|
+
/** cosmos only: the base64 33-byte compressed secp256k1 key from signArbitrary's pub_key.value */
|
|
199
|
+
publicKey: z2.string().max(128).optional()
|
|
200
|
+
}).strict();
|
|
201
|
+
var linkedWalletSchema = z2.object({
|
|
202
|
+
chain: walletChainSchema,
|
|
203
|
+
network: cosmosNetworkSchema.nullable(),
|
|
204
|
+
address: z2.string(),
|
|
205
|
+
verifiedAt: z2.number().int().nonnegative(),
|
|
206
|
+
revision: z2.number().int().positive(),
|
|
207
|
+
/** True when this wallet can sign in: it was first used through wallet sign-in. Linking never enables sign-in. */
|
|
208
|
+
signIn: z2.boolean()
|
|
209
|
+
});
|
|
210
|
+
var walletUnlinkInputSchema = z2.object({ chain: walletChainSchema, address: z2.string().min(1).max(100) }).strict();
|
|
211
|
+
async function walletAddressInput(signer) {
|
|
212
|
+
const address = await signer.address();
|
|
213
|
+
switch (signer.chain) {
|
|
214
|
+
case "solana":
|
|
215
|
+
return { chain: "solana", address };
|
|
216
|
+
case "eip155":
|
|
217
|
+
return {
|
|
218
|
+
chain: "eip155",
|
|
219
|
+
address,
|
|
220
|
+
...signer.chainId ? { chainId: await signer.chainId() } : {}
|
|
221
|
+
};
|
|
222
|
+
case "cosmos":
|
|
223
|
+
if (!signer.network) {
|
|
224
|
+
throw clientError(
|
|
225
|
+
"Choose the Cosmos chain for this wallet",
|
|
226
|
+
RelayErrorCode.InvalidInput
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
return { chain: "cosmos", network: signer.network, address };
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
var WALLETS_PER_CHAIN = 5;
|
|
233
|
+
var walletSignInFamilies = ["solana", "eip155", "cosmos"];
|
|
234
|
+
var walletSignInNetworkSchema = z2.enum(walletSignInFamilies);
|
|
235
|
+
var walletSignInNetworksSchema = z2.array(walletSignInNetworkSchema).max(walletSignInFamilies.length).refine((values) => new Set(values).size === values.length, {
|
|
236
|
+
message: "Duplicate wallet family"
|
|
237
|
+
}).transform(
|
|
238
|
+
(values) => walletSignInFamilies.filter((family) => values.includes(family))
|
|
239
|
+
);
|
|
240
|
+
function walletSignInNetwork(wallet) {
|
|
241
|
+
return wallet.chain;
|
|
242
|
+
}
|
|
243
|
+
function caip10(wallet, network) {
|
|
244
|
+
if (wallet.chain === "cosmos") {
|
|
245
|
+
if (!wallet.network || network && network !== wallet.network) {
|
|
246
|
+
throw new Error("A Cosmos wallet belongs to its own network");
|
|
247
|
+
}
|
|
248
|
+
return `${wallet.network}:${wallet.address}`;
|
|
249
|
+
}
|
|
250
|
+
const selected = network ?? (wallet.chain === "solana" ? solanaMainnet : "eip155:1");
|
|
251
|
+
const valid = wallet.chain === "solana" ? /^solana:[1-9A-HJ-NP-Za-km-z]{32}$/.test(selected) : isEvmChainId(selected);
|
|
252
|
+
if (!valid) {
|
|
253
|
+
throw new Error(`Use a ${wallet.chain} network for this wallet`);
|
|
254
|
+
}
|
|
255
|
+
return `${selected}:${wallet.address}`;
|
|
256
|
+
}
|
|
257
|
+
function isEvmChainId(value) {
|
|
258
|
+
return /^eip155:[1-9][0-9]{0,15}$/.test(value);
|
|
259
|
+
}
|
|
260
|
+
var evmChainIdSchema = z2.custom(
|
|
261
|
+
(value) => typeof value === "string" && isEvmChainId(value),
|
|
262
|
+
'Use an EVM chain ID such as "eip155:8453"'
|
|
263
|
+
);
|
|
264
|
+
var units = z2.string().regex(/^(0|[1-9][0-9]*)$/);
|
|
265
|
+
var walletBalanceSchema = responseShape(
|
|
266
|
+
z2.object({
|
|
267
|
+
/** Canonical CAIP-2 ID for Solana, EVM or a supported Cosmos SDK chain. */
|
|
268
|
+
chain: z2.string(),
|
|
269
|
+
/** The canonical mint, EIP-55 contract or Cosmos bank denom; null for a native coin. */
|
|
270
|
+
token: z2.string().nullable(),
|
|
271
|
+
/** Null when token metadata does not report decimals. */
|
|
272
|
+
decimals: z2.number().int().min(0).max(255).nullable(),
|
|
273
|
+
/** The sum over `wallets`. */
|
|
274
|
+
total: units,
|
|
275
|
+
wallets: z2.array(
|
|
276
|
+
z2.object({ address: z2.string(), amount: units }).strict()
|
|
277
|
+
),
|
|
278
|
+
/** Solana: lowest slot. EVM: approximate latest block. Cosmos: the fixed queried block. */
|
|
279
|
+
at: z2.object({ kind: z2.enum(["slot", "block"]), number: units }).strict(),
|
|
280
|
+
observedAt: z2.number().int().nonnegative()
|
|
281
|
+
}).strict()
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
export {
|
|
285
|
+
RelayErrorCode,
|
|
286
|
+
isRelayError,
|
|
287
|
+
RelayError,
|
|
288
|
+
asRelayError,
|
|
289
|
+
clientError,
|
|
290
|
+
parseInput,
|
|
291
|
+
solanaAddressSchema,
|
|
292
|
+
walletChainSchema,
|
|
293
|
+
cosmosNetworkSchema,
|
|
294
|
+
cosmosDenomSchema,
|
|
295
|
+
cosmosChain,
|
|
296
|
+
solanaMainnet,
|
|
297
|
+
evmAddressSchema,
|
|
298
|
+
cosmosAddressSchema,
|
|
299
|
+
walletAddressInputSchema,
|
|
300
|
+
walletMessageChallengeSchema,
|
|
301
|
+
walletSignatureSchema,
|
|
302
|
+
linkedWalletSchema,
|
|
303
|
+
walletUnlinkInputSchema,
|
|
304
|
+
walletAddressInput,
|
|
305
|
+
WALLETS_PER_CHAIN,
|
|
306
|
+
walletSignInFamilies,
|
|
307
|
+
walletSignInNetworkSchema,
|
|
308
|
+
walletSignInNetworksSchema,
|
|
309
|
+
walletSignInNetwork,
|
|
310
|
+
caip10,
|
|
311
|
+
isEvmChainId,
|
|
312
|
+
evmChainIdSchema,
|
|
313
|
+
walletBalanceSchema
|
|
314
|
+
};
|