@domino-sdk/relay 1.61.0 → 1.62.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/CHANGELOG.md +156 -8
- package/README.md +3 -2
- package/dist/{schema-CZ6Rj0ZF.d.ts → accounts-CCqCKCVx.d.ts} +3127 -1764
- package/dist/action-9Xl0StBg.d.ts +33 -0
- package/dist/{integrations-B3y36OaB.d.ts → analytics-BwAKLi7O.d.ts} +347 -57
- package/dist/{attempt-captures-DYnJVkfg.d.ts → attempt-captures-Cm-5G0PC.d.ts} +1 -1
- package/dist/authoring.d.ts +130 -42
- package/dist/authoring.js +112 -37
- package/dist/{automatic-outcomes-If88LR9f.d.ts → automatic-outcomes-pAsOyIVp.d.ts} +5 -1
- package/dist/avatar.d.ts +1 -1
- package/dist/browser.d.ts +15 -11
- package/dist/browser.js +15 -11
- package/dist/{announcements-CHx3-HBw.d.ts → capability-error-DFMwSuSf.d.ts} +161 -4
- package/dist/{pages-K7-KjSXw.d.ts → catalog--ZIlskAo.d.ts} +39 -561
- package/dist/{chunk-DYXDZFKA.js → chunk-3KLC4AMA.js} +37 -11
- package/dist/{chunk-XBV2CK2H.js → chunk-3PYYGFSB.js} +14 -2
- package/dist/{chunk-RHBS5FJL.js → chunk-5TEYFX6X.js} +2 -2
- package/dist/chunk-6WCIWXUV.js +31 -0
- package/dist/chunk-CICDIBOF.js +373 -0
- package/dist/{chunk-MHPKEVEW.js → chunk-CZFXGGEK.js} +5 -0
- package/dist/chunk-D26YNACF.js +320 -0
- package/dist/{chunk-5I54XBK2.js → chunk-E6IKQHTX.js} +2 -2
- package/dist/chunk-FWLQ5XCS.js +21 -0
- package/dist/{chunk-SKGTNTLF.js → chunk-GKIFABGN.js} +150 -61
- package/dist/chunk-GTDW453U.js +522 -0
- package/dist/{chunk-VURRFVNP.js → chunk-HTZHBTIL.js} +69 -27
- package/dist/chunk-K2KS3JLY.js +188 -0
- package/dist/{chunk-ZDJLPN4L.js → chunk-MK425RXJ.js} +3143 -3209
- package/dist/{chunk-L77O64I4.js → chunk-QYPMPWVX.js} +1 -1
- package/dist/chunk-UAKYDVT3.js +565 -0
- package/dist/{chunk-DHXDBAJF.js → chunk-UPQPUJOU.js} +36 -123
- package/dist/{chunk-24I4R732.js → chunk-UW5232GG.js} +34 -19
- package/dist/chunk-WSBYWVTZ.js +717 -0
- package/dist/{chunk-PPB7HALD.js → chunk-XJFYAXET.js} +9 -8
- package/dist/{chunk-7A4J67ZL.js → chunk-XNKSSE32.js} +1 -1
- package/dist/{chunk-QEAS4ZGS.js → chunk-Y322OTCH.js} +1 -1
- package/dist/{client-C51w7fMb.d.ts → client-B-hbHX30.d.ts} +109 -40
- package/dist/{deployments-kWoHFaqj.d.ts → deployments-M4OHn7G3.d.ts} +407 -18
- package/dist/identity-integration-3mX6b5iH.d.ts +1241 -0
- package/dist/index.d.ts +13 -11
- package/dist/index.js +14 -11
- package/dist/internal.d.ts +14 -12
- package/dist/internal.js +26 -14
- package/dist/{offers-BoV4ryUc.d.ts → offers-DhAtss4_.d.ts} +21 -4
- package/dist/pages-B8q8Y_dQ.d.ts +715 -0
- package/dist/{participant-activity-DHL8QYks.d.ts → participant-activity-D-Drp24G.d.ts} +16 -3
- package/dist/portal-proxy.d.ts +59 -2
- package/dist/portal-proxy.js +109 -23
- package/dist/react/index.d.ts +206 -26
- package/dist/react/index.js +153 -25
- package/dist/{action-DBzILFx9.d.ts → request-error-D_dUPLwo.d.ts} +1 -31
- package/dist/runtime/authoring.js +1 -1
- package/dist/runtime/chunks/Y4OAVXFR.js +1 -0
- package/dist/runtime/manifest.json +3 -3
- package/dist/runtime/schema.js +1 -1
- package/dist/schema.d.ts +154 -30
- package/dist/schema.js +126 -75
- package/dist/server/index.d.ts +14 -12
- package/dist/server/index.js +2137 -1633
- package/dist/sign-in-providers-BkjcDsFF.d.ts +39 -0
- package/dist/submission-input-DHGKhXfp.d.ts +342 -0
- package/dist/{telegram-browser-BUceZIGZ.d.ts → telegram-browser-BCE7zdOb.d.ts} +46 -6
- package/dist/telegram.d.ts +64 -0
- package/dist/telegram.js +23 -0
- package/dist/testing.d.ts +112 -15
- package/dist/testing.js +321 -16
- package/dist/tracker-data-Hb1uQnk5.d.ts +1855 -0
- package/dist/{transport-BrX9pIGN.d.ts → transport-DkhX2Cbs.d.ts} +5764 -2217
- package/dist/{wallet-CIqFoxdm.d.ts → wallet-DTO7SXj7.d.ts} +20 -7
- package/package.json +5 -1
- package/dist/accounts-DoabriBX.d.ts +0 -306
- package/dist/capability-error-DufwG3G0.d.ts +0 -159
- package/dist/chunk-3Y3L2F54.js +0 -982
- package/dist/chunk-EN3M5Z4J.js +0 -13
- package/dist/chunk-QNUHWK7R.js +0 -602
- package/dist/chunk-SE4PFJPT.js +0 -247
- package/dist/groups-CqcA2Ycs.d.ts +0 -2827
- package/dist/runtime/chunks/5QVFB4TU.js +0 -1
- package/dist/submission-input-C54Q8yAD.d.ts +0 -146
- package/dist/x-D1PGi8Sq.d.ts +0 -331
package/dist/testing.d.ts
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d3 as pointBalanceSchema, bD as discordMemberSchema, bG as discordMessageSchema, cZ as photoResultSchema, a8 as TextReviewInput, H as Reward, ac as Decision, P as PointBalance, y as PointLedgerReference, u as PointEntry, o as LeaderboardPage } from './accounts-CCqCKCVx.js';
|
|
2
2
|
import * as z from 'zod';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
3
|
+
import { k as CapabilityFailure, _ as memberCompletionSchema } from './capability-error-DFMwSuSf.js';
|
|
4
|
+
export { C as CapabilityError } from './capability-error-DFMwSuSf.js';
|
|
5
|
+
import { z as xConnectionSchema, C as xProfileSchema, B as xPostSchema, f as ImageReference, s as imageInspectionSchema, o as imageComparisonSchema, v as imageSightingsSchema } from './analytics-BwAKLi7O.js';
|
|
6
|
+
import { aI as memberIdentitySchema, bc as trackerQuerySchema, b7 as trackerPageSchema, bl as trackerSummarySchema, a8 as TrackerContentQuery, aU as trackerContentSchema, a4 as TrackerAttribution, l as Tracker, m as TrackerData, C as ContentBody, v as TrackerTriggerContext, H as TrackerPage } from './tracker-data-Hb1uQnk5.js';
|
|
7
|
+
import { aO as profileReferralSchema, aE as linkedWalletSchema, aY as walletBalanceSchema, b2 as walletNftsSchema, M as WalletCallArgument, aZ as walletCallSchema, a$ as walletDelegationsSchema, U as WalletEventCondition, b0 as walletEventsSchema, b7 as walletTransactionsSchema } from './wallet-DTO7SXj7.js';
|
|
8
|
+
import { C as telegramConnectionSchema, y as telegramChatMemberSchema } from './submission-input-DHGKhXfp.js';
|
|
9
|
+
import { EvaluationMember } from './authoring.js';
|
|
10
|
+
export { A as AttemptCapture, C as CapturedFact } from './attempt-captures-Cm-5G0PC.js';
|
|
11
|
+
import { b as ParticipantSession, R as RelayEvent } from './participant-activity-D-Drp24G.js';
|
|
12
|
+
import { B as Badge } from './offers-DhAtss4_.js';
|
|
13
|
+
import { b as QuestView, q as questExperienceSchema } from './catalog--ZIlskAo.js';
|
|
14
|
+
import './streaks-0YuipsUQ.js';
|
|
15
|
+
import './units-CwgsPB_r.js';
|
|
9
16
|
|
|
10
17
|
/** One project time-zone change: from `effectiveAt` on, days are counted in `timeZone`. */
|
|
11
18
|
type CalendarSegment = {
|
|
@@ -257,7 +264,7 @@ type WalletDelegationsQueryRequest = {
|
|
|
257
264
|
};
|
|
258
265
|
/**
|
|
259
266
|
* An event query as Relay receives it: `afterActivation` false, and `where` and `address` null,
|
|
260
|
-
* when the quest leaves them out.
|
|
267
|
+
* when the quest leaves them out; `newest` only when the quest sets it.
|
|
261
268
|
*/
|
|
262
269
|
type WalletEventsQueryRequest = {
|
|
263
270
|
event: string;
|
|
@@ -266,6 +273,7 @@ type WalletEventsQueryRequest = {
|
|
|
266
273
|
afterActivation: boolean;
|
|
267
274
|
where: Record<string, WalletEventCondition> | null;
|
|
268
275
|
address: string | null;
|
|
276
|
+
newest?: number;
|
|
269
277
|
};
|
|
270
278
|
/**
|
|
271
279
|
* A transaction query as Relay receives it: `afterActivation` false, and `mint` and `address`
|
|
@@ -301,7 +309,7 @@ type TrackerFacts = {
|
|
|
301
309
|
* Reads of the member's own accounts default to a member who has linked nothing:
|
|
302
310
|
* `member.identities()`, `wallet.list()`, `wallet.balance()`, `wallet.nfts()`, `wallet.call()`,
|
|
303
311
|
* `wallet.delegations()`, `x.connection()`, `x.profile()`,
|
|
304
|
-
* `x.follows()`, `x.reposted()`, `discord.member()` and `telegram.member()` resolve to null. Once the test links an
|
|
312
|
+
* `x.follows()`, `x.reposted()`, `discord.member()`, `telegram.connection()` and `telegram.member()` resolve to null. Once the test links an
|
|
305
313
|
* account (`wallet.list` or `x.connection` set to a value), supply every read of it the quest
|
|
306
314
|
* makes. Every other read (the member's balances, completions, groups, campaigns and referrals, an
|
|
307
315
|
* X post, a Discord message, trackers, images and AI review) needs an answer: a call without one
|
|
@@ -373,8 +381,9 @@ type TestFacts = {
|
|
|
373
381
|
], Result<typeof walletDelegationsSchema> | null>;
|
|
374
382
|
/**
|
|
375
383
|
* `ctx.wallet.events({ event, account, since })`. Like `balance`, it reads null while the
|
|
376
|
-
* member has no linked EVM wallet. The kit does not apply `where` or `
|
|
377
|
-
* logs Relay would return
|
|
384
|
+
* member has no linked EVM wallet. The kit does not apply `where`, `since` or `newest`: answer
|
|
385
|
+
* with the logs Relay would return, and `complete: false` for a `newest` read that left older
|
|
386
|
+
* events out. A run's `calls` does not list event reads.
|
|
378
387
|
*/
|
|
379
388
|
events?: FakeAnswer<[
|
|
380
389
|
query: WalletEventsQueryRequest
|
|
@@ -414,11 +423,14 @@ type TestFacts = {
|
|
|
414
423
|
], Result<typeof discordMessageSchema> | null>;
|
|
415
424
|
};
|
|
416
425
|
/**
|
|
417
|
-
* `ctx.telegram.member({ chat })`, which the testing kit supplies
|
|
418
|
-
*
|
|
419
|
-
*
|
|
426
|
+
* `ctx.telegram.connection()` and `ctx.telegram.member({ chat })`, which the testing kit supplies
|
|
427
|
+
* to every quest as Relay does. `connection` is answered once per run, as Relay pins the account.
|
|
428
|
+
* Throw `new CapabilityError("integration-required", …)` from `member` to act out a chat the
|
|
429
|
+
* project has not connected. A run's `calls` does not list Telegram calls: its request type is
|
|
430
|
+
* closed in SDK 1.x.
|
|
420
431
|
*/
|
|
421
432
|
telegram?: {
|
|
433
|
+
connection?: FakeAnswer<[], Result<typeof telegramConnectionSchema> | null>;
|
|
422
434
|
member?: FakeAnswer<[
|
|
423
435
|
input: {
|
|
424
436
|
chat: string;
|
|
@@ -658,6 +670,16 @@ declare function createTestContext<Q extends TestableQuest>(quest: Q, options?:
|
|
|
658
670
|
*/
|
|
659
671
|
declare function runQuest<Q extends TestableQuest>(quest: Q, options?: RunQuestOptions<Q>): Promise<DiagnosedRun>;
|
|
660
672
|
|
|
673
|
+
/**
|
|
674
|
+
* An `EvaluationMember` for a test that builds its own evaluation context, such as one that calls
|
|
675
|
+
* `quest.evaluate` with readers of its own. Pass the methods the code under test reads; the rest
|
|
676
|
+
* answer for a member with no linked accounts, completions, groups or enrollments, and `balance`
|
|
677
|
+
* and `referrals` fail as Relay does for an unknown ledger or program. A minor release can give
|
|
678
|
+
* `EvaluationMember` a method; this helper gives it a default, so a test that uses it keeps
|
|
679
|
+
* compiling. `createTestContext` and `runQuest` create the member themselves.
|
|
680
|
+
*/
|
|
681
|
+
declare function fakeEvaluationMember(member?: Partial<EvaluationMember>): EvaluationMember;
|
|
682
|
+
|
|
661
683
|
type Kind = Decision["kind"];
|
|
662
684
|
type DecisionOf<K extends Kind> = Extract<Decision, {
|
|
663
685
|
kind: K;
|
|
@@ -803,4 +825,79 @@ type AttemptReplay = {
|
|
|
803
825
|
*/
|
|
804
826
|
declare function replayAttempt<Q extends TestableQuest>(quest: Q, capture: unknown, options?: ReplayOptions): Promise<AttemptReplay>;
|
|
805
827
|
|
|
806
|
-
|
|
828
|
+
type Experience = z.output<typeof questExperienceSchema>;
|
|
829
|
+
/**
|
|
830
|
+
* What `createFakeRelay` answers with. Every seed is optional; an omitted one answers empty.
|
|
831
|
+
*
|
|
832
|
+
* @experimental A minor release can change it, like `createFakeRelay`.
|
|
833
|
+
*/
|
|
834
|
+
type FakeRelayOptions = {
|
|
835
|
+
/** The signed-in member's ID, or null (the default) for a signed-out visitor. */
|
|
836
|
+
member?: string | null;
|
|
837
|
+
/** The session's project scope. Defaults to `org_test`, `project_test` and `test`. */
|
|
838
|
+
scope?: Pick<ParticipantSession, "organization" | "project" | "environment">;
|
|
839
|
+
/** The member's quests, as `GET /v1/me/experience` lists them. */
|
|
840
|
+
quests?: QuestView[];
|
|
841
|
+
/** The experience's collections. */
|
|
842
|
+
collections?: Experience["collections"];
|
|
843
|
+
/** The experience's entitlements. */
|
|
844
|
+
entitlements?: Experience["entitlements"];
|
|
845
|
+
/**
|
|
846
|
+
* The member's balance in each ledger (`GET /v1/me/points`). `GET /v1/point-ledgers` lists these
|
|
847
|
+
* ledgers unless `ledgers` is given.
|
|
848
|
+
*/
|
|
849
|
+
balances?: PointBalance[];
|
|
850
|
+
/** The project's ledgers (`GET /v1/point-ledgers`). */
|
|
851
|
+
ledgers?: PointLedgerReference[];
|
|
852
|
+
/** Each ledger's history (`GET /v1/me/points/:ledger/history`), keyed by ledger key or ID. */
|
|
853
|
+
pointHistory?: Record<string, PointEntry[]>;
|
|
854
|
+
/** The member's activity feed (`GET /v1/me/activity`), oldest event first. */
|
|
855
|
+
activity?: RelayEvent[];
|
|
856
|
+
/** The project's active badge catalog (`GET /v1/badges/catalog` and `GET /v1/badges`). */
|
|
857
|
+
badges?: Badge[];
|
|
858
|
+
/** Each board's standings (`GET /v1/leaderboards/:board`), keyed by the board's key or ID. */
|
|
859
|
+
leaderboards?: Record<string, LeaderboardPage>;
|
|
860
|
+
/**
|
|
861
|
+
* Answers for routes the fake does not cover, or replacements for ones it does, keyed
|
|
862
|
+
* `"METHOD /v1/path"`. A `:name` path segment matches any one segment, as in
|
|
863
|
+
* `"POST /v1/me/submissions/:submission/submit"`.
|
|
864
|
+
*/
|
|
865
|
+
routes?: Record<string, (request: Request) => Response | Promise<Response>>;
|
|
866
|
+
};
|
|
867
|
+
/**
|
|
868
|
+
* One request the fake answered: its method and `/v1/...` path, without the query.
|
|
869
|
+
*
|
|
870
|
+
* @experimental A minor release can change it, like `createFakeRelay`.
|
|
871
|
+
*/
|
|
872
|
+
type FakeRelayRequest = {
|
|
873
|
+
method: string;
|
|
874
|
+
path: string;
|
|
875
|
+
};
|
|
876
|
+
/**
|
|
877
|
+
* The fake `createFakeRelay` returns.
|
|
878
|
+
*
|
|
879
|
+
* @experimental A minor release can change it, like `createFakeRelay`.
|
|
880
|
+
*/
|
|
881
|
+
type FakeRelay = {
|
|
882
|
+
/** Answers one request. Use it from a Playwright `page.route` handler or an MSW handler. */
|
|
883
|
+
handle(request: Request): Promise<Response>;
|
|
884
|
+
/** A `fetch` that answers from the fake, for `createRelayClient({ fetch })`. */
|
|
885
|
+
fetch: typeof fetch;
|
|
886
|
+
/** Every request answered so far, in order. */
|
|
887
|
+
readonly requests: FakeRelayRequest[];
|
|
888
|
+
};
|
|
889
|
+
/**
|
|
890
|
+
* An in-memory participant API for UI tests: it answers what `RelayProvider` and the hooks read
|
|
891
|
+
* from the seeds, as Relay would, under `/v1/...` and the hosted proxy's `/relay/v1/...`.
|
|
892
|
+
*
|
|
893
|
+
* Every answer is checked against the schema the SDK reads it with, so a seed Relay could never
|
|
894
|
+
* send throws a `TestSetupError` naming the route. A participant route the fake does not cover
|
|
895
|
+
* answers 501 with code `not-faked`, so a test cannot pass on an empty answer; `routes` answers
|
|
896
|
+
* it instead. Any other path answers 404 with code `route-not-found`, as the proxy does.
|
|
897
|
+
*
|
|
898
|
+
* @experimental Outside the 1.x compatibility promise: a minor release can change its options,
|
|
899
|
+
* the routes it fakes and its answers, as the participant API it imitates grows.
|
|
900
|
+
*/
|
|
901
|
+
declare function createFakeRelay(options?: FakeRelayOptions): FakeRelay;
|
|
902
|
+
|
|
903
|
+
export { type AttemptReplay, type CalendarSegment, type CapabilityCall, type CapabilityOutcome, type CapabilityRequest, Decision, DecisionAssertionError, EvaluatorError, type FakeAnswer, type FakeRelay, type FakeRelayOptions, type FakeRelayRequest, type QuestDiagnostic, type QuestHostContext, type QuestInputOf, type QuestRun, type ReplayDivergence, type ReplayOptions, type RunQuestOptions, type TestContext, type TestFacts, type TestRelease, TestSetupError, type TestableQuest, type TrackerFacts, type TrackerObservationInput, type TrackerReadRequest, type TrackerRecordInput, type WalletBalanceRequest, createFakeRelay, createTestContext, defaultMember, defaultNow, defaultSeed, expectAccept, expectDefer, expectProgress, expectReject, expectReview, fakeEvaluationMember, maxCapabilityCalls, replayAttempt, runQuest, trackerObservation, trackerPage };
|
package/dist/testing.js
CHANGED
|
@@ -1,23 +1,40 @@
|
|
|
1
1
|
import {
|
|
2
2
|
attemptCaptureSchema
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-XNKSSE32.js";
|
|
4
4
|
import {
|
|
5
5
|
CapabilityError
|
|
6
6
|
} from "./chunk-4OC7REYX.js";
|
|
7
7
|
import {
|
|
8
8
|
parseImageResult
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-E6IKQHTX.js";
|
|
10
10
|
import {
|
|
11
11
|
imageRequestSchema,
|
|
12
12
|
xConnectionSchema,
|
|
13
13
|
xPostSchema,
|
|
14
14
|
xProfileSchema,
|
|
15
15
|
xRequestSchema
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-QYPMPWVX.js";
|
|
17
17
|
import {
|
|
18
|
+
isParticipantRoute
|
|
19
|
+
} from "./chunk-CZFXGGEK.js";
|
|
20
|
+
import {
|
|
21
|
+
participantActivitySchema,
|
|
22
|
+
questExperienceSchema
|
|
23
|
+
} from "./chunk-D26YNACF.js";
|
|
24
|
+
import {
|
|
25
|
+
badgeCatalogSchema,
|
|
26
|
+
badgeSchema,
|
|
27
|
+
leaderboardPageSchema,
|
|
18
28
|
pointBalanceSchema,
|
|
29
|
+
pointBalancesSchema,
|
|
30
|
+
pointHistoryPageSchema,
|
|
31
|
+
pointLedgerReferenceSchema,
|
|
19
32
|
profileReferralSchema
|
|
20
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-WSBYWVTZ.js";
|
|
34
|
+
import {
|
|
35
|
+
exchangeResultSchema,
|
|
36
|
+
participantSessionSchema
|
|
37
|
+
} from "./chunk-XJFYAXET.js";
|
|
21
38
|
import {
|
|
22
39
|
contentPerformanceSnapshotSchema,
|
|
23
40
|
cosmosAddressSchema,
|
|
@@ -32,8 +49,10 @@ import {
|
|
|
32
49
|
isContractEvent,
|
|
33
50
|
isNftCollection,
|
|
34
51
|
isSolanaProgram,
|
|
52
|
+
knownResponse,
|
|
35
53
|
linkedWalletSchema,
|
|
36
54
|
maxMemberCompletions,
|
|
55
|
+
maxWalletEventLogs,
|
|
37
56
|
memberCompletionSchema,
|
|
38
57
|
memberIdentitySchema,
|
|
39
58
|
photoResultSchema,
|
|
@@ -42,6 +61,8 @@ import {
|
|
|
42
61
|
solanaAddressSchema,
|
|
43
62
|
solanaMainnet,
|
|
44
63
|
telegramChatMemberSchema,
|
|
64
|
+
telegramConnectionInputSchema,
|
|
65
|
+
telegramConnectionSchema,
|
|
45
66
|
telegramMemberInputSchema,
|
|
46
67
|
textEvidenceSchema,
|
|
47
68
|
textResultSchema,
|
|
@@ -61,7 +82,10 @@ import {
|
|
|
61
82
|
walletEventsSchema,
|
|
62
83
|
walletNftsSchema,
|
|
63
84
|
walletTransactionsSchema
|
|
64
|
-
} from "./chunk-
|
|
85
|
+
} from "./chunk-MK425RXJ.js";
|
|
86
|
+
import {
|
|
87
|
+
RelayErrorCode
|
|
88
|
+
} from "./chunk-K2KS3JLY.js";
|
|
65
89
|
|
|
66
90
|
// src/testing/run.ts
|
|
67
91
|
import * as z3 from "zod";
|
|
@@ -202,7 +226,7 @@ var capabilityRequestSchemas = {
|
|
|
202
226
|
};
|
|
203
227
|
var telegramRequestSchema = z.strictObject({
|
|
204
228
|
kind: z.literal("telegram"),
|
|
205
|
-
input: telegramMemberInputSchema
|
|
229
|
+
input: z.union([telegramMemberInputSchema, telegramConnectionInputSchema])
|
|
206
230
|
});
|
|
207
231
|
var walletNftsRequestSchema = z.strictObject({
|
|
208
232
|
kind: z.literal("wallet-nfts"),
|
|
@@ -221,7 +245,8 @@ var walletEventsRequestSchema = z.strictObject({
|
|
|
221
245
|
since: z.number().int().nonnegative().safe(),
|
|
222
246
|
afterActivation: z.boolean(),
|
|
223
247
|
where: z.record(z.string().min(1).max(100), walletEventConditionSchema).refine((where) => Object.keys(where).length <= 10).nullable(),
|
|
224
|
-
address: z.string().min(1).max(100).nullable()
|
|
248
|
+
address: z.string().min(1).max(100).nullable(),
|
|
249
|
+
newest: z.number().int().min(1).max(maxWalletEventLogs).optional()
|
|
225
250
|
});
|
|
226
251
|
var walletTransactionsRequestSchema = z.strictObject({
|
|
227
252
|
kind: z.literal("wallet-transactions"),
|
|
@@ -342,7 +367,7 @@ function parseCapabilityResult(request, value) {
|
|
|
342
367
|
case "member-identities":
|
|
343
368
|
return z.array(memberIdentitySchema).min(1).nullable().parse(value);
|
|
344
369
|
case "telegram":
|
|
345
|
-
return telegramChatMemberSchema.nullable().parse(value);
|
|
370
|
+
return ("chat" in request.input ? telegramChatMemberSchema : telegramConnectionSchema).nullable().parse(value);
|
|
346
371
|
case "wallet-nfts":
|
|
347
372
|
return walletNftsSchema.nullable().parse(value);
|
|
348
373
|
case "wallet-call":
|
|
@@ -414,6 +439,7 @@ var readerFactories = {
|
|
|
414
439
|
message: (input) => call({ kind: "discord", input })
|
|
415
440
|
}),
|
|
416
441
|
telegram: (call) => ({
|
|
442
|
+
connection: () => call({ kind: "telegram", input: { operation: "connection" } }),
|
|
417
443
|
member: (input) => call({ kind: "telegram", input })
|
|
418
444
|
}),
|
|
419
445
|
x: (call) => ({
|
|
@@ -493,7 +519,9 @@ var readerFactories = {
|
|
|
493
519
|
since: query.since,
|
|
494
520
|
afterActivation: query.afterActivation ?? false,
|
|
495
521
|
where: query.where ?? null,
|
|
496
|
-
address: query.address ?? null
|
|
522
|
+
address: query.address ?? null,
|
|
523
|
+
// Only when set, so a call without it sends the request it always did.
|
|
524
|
+
...query.newest === void 0 ? {} : { newest: query.newest }
|
|
497
525
|
}),
|
|
498
526
|
transactions: (query) => call({
|
|
499
527
|
kind: "wallet-transactions",
|
|
@@ -641,21 +669,21 @@ function install(now, seed, restores) {
|
|
|
641
669
|
const crypto = globalThis.crypto;
|
|
642
670
|
if (crypto) {
|
|
643
671
|
restores.push(
|
|
644
|
-
replace(crypto, "getRandomValues", (
|
|
645
|
-
if (!integerArrays.some((type) =>
|
|
672
|
+
replace(crypto, "getRandomValues", (array4) => {
|
|
673
|
+
if (!integerArrays.some((type) => array4 instanceof type)) {
|
|
646
674
|
throw new DOMException(
|
|
647
675
|
"getRandomValues takes an integer typed array",
|
|
648
676
|
"TypeMismatchError"
|
|
649
677
|
);
|
|
650
678
|
}
|
|
651
|
-
if (
|
|
679
|
+
if (array4.byteLength > 65536) {
|
|
652
680
|
throw new DOMException(
|
|
653
681
|
"getRandomValues takes at most 65536 bytes",
|
|
654
682
|
"QuotaExceededError"
|
|
655
683
|
);
|
|
656
684
|
}
|
|
657
|
-
fill(new Uint8Array(
|
|
658
|
-
return
|
|
685
|
+
fill(new Uint8Array(array4.buffer, array4.byteOffset, array4.byteLength));
|
|
686
|
+
return array4;
|
|
659
687
|
})
|
|
660
688
|
);
|
|
661
689
|
restores.push(
|
|
@@ -796,10 +824,14 @@ function fakeFor(facts, request) {
|
|
|
796
824
|
};
|
|
797
825
|
}
|
|
798
826
|
case "telegram":
|
|
799
|
-
return {
|
|
827
|
+
return "chat" in request.input ? {
|
|
800
828
|
name: "telegram.member",
|
|
801
829
|
answer: facts.telegram?.member,
|
|
802
830
|
args: [request.input]
|
|
831
|
+
} : {
|
|
832
|
+
name: "telegram.connection",
|
|
833
|
+
answer: facts.telegram?.connection,
|
|
834
|
+
args: []
|
|
803
835
|
};
|
|
804
836
|
case "tracker-records":
|
|
805
837
|
case "tracker-summary": {
|
|
@@ -1082,6 +1114,9 @@ function factsAnswerer(facts) {
|
|
|
1082
1114
|
return "channelId" in request.input || fake.answer !== void 0 ? ask(fake) : { value: null };
|
|
1083
1115
|
// Without an answer, the member has not linked Telegram.
|
|
1084
1116
|
case "telegram":
|
|
1117
|
+
if (!("chat" in request.input)) {
|
|
1118
|
+
return pin(request);
|
|
1119
|
+
}
|
|
1085
1120
|
return fake.answer !== void 0 ? ask(fake) : { value: null };
|
|
1086
1121
|
case "image": {
|
|
1087
1122
|
if (imageReferences(request.input).some(
|
|
@@ -1518,6 +1553,33 @@ async function runQuest(quest, options = {}) {
|
|
|
1518
1553
|
);
|
|
1519
1554
|
}
|
|
1520
1555
|
|
|
1556
|
+
// src/testing/member.ts
|
|
1557
|
+
var keyOf = (resource) => typeof resource === "string" ? resource : resource.key;
|
|
1558
|
+
function fakeEvaluationMember(member = {}) {
|
|
1559
|
+
return {
|
|
1560
|
+
id: defaultMember,
|
|
1561
|
+
identities: async () => null,
|
|
1562
|
+
balance: async (ledger) => {
|
|
1563
|
+
throw new CapabilityError(
|
|
1564
|
+
"author-error",
|
|
1565
|
+
`The fake member has no balance in point ledger ${keyOf(ledger)}; pass balance to fakeEvaluationMember`,
|
|
1566
|
+
{ retryable: false }
|
|
1567
|
+
);
|
|
1568
|
+
},
|
|
1569
|
+
completions: async () => [],
|
|
1570
|
+
groups: async () => [],
|
|
1571
|
+
enrolled: async () => false,
|
|
1572
|
+
referrals: async (program) => {
|
|
1573
|
+
throw new CapabilityError(
|
|
1574
|
+
"author-error",
|
|
1575
|
+
`The fake member has no progress in referral program ${keyOf(program)}; pass referrals to fakeEvaluationMember`,
|
|
1576
|
+
{ retryable: false }
|
|
1577
|
+
);
|
|
1578
|
+
},
|
|
1579
|
+
...member
|
|
1580
|
+
};
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1521
1583
|
// src/testing/assertions.ts
|
|
1522
1584
|
var DecisionAssertionError = class extends Error {
|
|
1523
1585
|
decision;
|
|
@@ -1685,7 +1747,7 @@ function captureAnswerer(facts, fallback, diverged) {
|
|
|
1685
1747
|
if (unlistedRequest(request)) {
|
|
1686
1748
|
if (!answerFallback) {
|
|
1687
1749
|
const [reader, fact2] = {
|
|
1688
|
-
telegram: ["ctx.telegram.member()", "facts.telegram"],
|
|
1750
|
+
telegram: request.kind === "telegram" && !("chat" in request.input) ? ["ctx.telegram.connection()", "facts.telegram.connection"] : ["ctx.telegram.member()", "facts.telegram"],
|
|
1689
1751
|
"wallet-nfts": ["ctx.wallet.nfts()", "facts.wallet.nfts"],
|
|
1690
1752
|
"wallet-call": ["ctx.wallet.call()", "facts.wallet.call"],
|
|
1691
1753
|
"wallet-delegations": [
|
|
@@ -1782,11 +1844,253 @@ async function replayAttempt(quest, capture, options = {}) {
|
|
|
1782
1844
|
calls: host.calls
|
|
1783
1845
|
};
|
|
1784
1846
|
}
|
|
1847
|
+
|
|
1848
|
+
// src/testing/participant-api.ts
|
|
1849
|
+
import * as z5 from "zod";
|
|
1850
|
+
var defaultScope = {
|
|
1851
|
+
organization: "org_test",
|
|
1852
|
+
project: "project_test",
|
|
1853
|
+
environment: "test"
|
|
1854
|
+
};
|
|
1855
|
+
var sessionLifetimeMs = 24 * 60 * 60 * 1e3;
|
|
1856
|
+
var refuse = (status, code, error) => Response.json({ error, code }, { status });
|
|
1857
|
+
function createFakeRelay(options = {}) {
|
|
1858
|
+
let member = options.member ?? null;
|
|
1859
|
+
const scope = options.scope ?? defaultScope;
|
|
1860
|
+
const requests = [];
|
|
1861
|
+
const activity = options.activity ?? [];
|
|
1862
|
+
const balances = options.balances ?? [];
|
|
1863
|
+
const badges = options.badges ?? [];
|
|
1864
|
+
const ledgers = options.ledgers ?? balances.map((balance) => balance.ledger).filter(
|
|
1865
|
+
(ledger, index, all) => all.findIndex((other) => other.id === ledger.id) === index
|
|
1866
|
+
);
|
|
1867
|
+
const overrides = Object.entries(options.routes ?? {}).map(
|
|
1868
|
+
([key, answer2]) => {
|
|
1869
|
+
const [method, path, ...rest] = key.trim().split(/\s+/);
|
|
1870
|
+
if (!method || !path?.startsWith("/v1/") || rest.length > 0) {
|
|
1871
|
+
throw new TestSetupError(
|
|
1872
|
+
`routes["${key}"]: name a route as "METHOD /v1/path"`
|
|
1873
|
+
);
|
|
1874
|
+
}
|
|
1875
|
+
const source = path.split("/").map(
|
|
1876
|
+
(segment) => segment.startsWith(":") ? "[^/]+" : segment.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
|
|
1877
|
+
).join("/");
|
|
1878
|
+
return {
|
|
1879
|
+
method: method.toUpperCase(),
|
|
1880
|
+
pattern: new RegExp(`^${source}$`),
|
|
1881
|
+
answer: answer2
|
|
1882
|
+
};
|
|
1883
|
+
}
|
|
1884
|
+
);
|
|
1885
|
+
const session = (current) => ({
|
|
1886
|
+
...scope,
|
|
1887
|
+
id: `session_${current}`,
|
|
1888
|
+
principal: { kind: "member", member: current },
|
|
1889
|
+
expiresAt: Date.now() + sessionLifetimeMs
|
|
1890
|
+
});
|
|
1891
|
+
const answer = (route, schema, value) => {
|
|
1892
|
+
const wire = JSON.parse(JSON.stringify(value));
|
|
1893
|
+
const parsed = knownResponse(schema).safeParse(wire);
|
|
1894
|
+
if (!parsed.success) {
|
|
1895
|
+
const issue = parsed.error.issues[0];
|
|
1896
|
+
const at = issue?.path.length ? ` at ${issue.path.join(".")}` : "";
|
|
1897
|
+
throw new TestSetupError(
|
|
1898
|
+
`createFakeRelay: the answer to ${route} is not one Relay sends${at}: ${issue?.message ?? parsed.error.message}`
|
|
1899
|
+
);
|
|
1900
|
+
}
|
|
1901
|
+
return Response.json(wire);
|
|
1902
|
+
};
|
|
1903
|
+
const experience = (current) => answer("GET /v1/me/experience", questExperienceSchema, {
|
|
1904
|
+
member: current,
|
|
1905
|
+
quests: options.quests ?? [],
|
|
1906
|
+
collections: options.collections ?? [],
|
|
1907
|
+
entitlements: options.entitlements ?? []
|
|
1908
|
+
});
|
|
1909
|
+
const activityPage = (current, query) => {
|
|
1910
|
+
const cursor = query.get("cursor");
|
|
1911
|
+
const limit = Number(query.get("limit") ?? 50);
|
|
1912
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
|
|
1913
|
+
return refuse(400, "invalid-request", "limit must be 1 to 100");
|
|
1914
|
+
}
|
|
1915
|
+
const start = query.get("start") === "latest" ? activity.length : cursor === null ? 0 : Number(cursor.replace(/^fake-/, ""));
|
|
1916
|
+
if (!Number.isInteger(start) || start < 0 || start > activity.length) {
|
|
1917
|
+
return refuse(400, "invalid-request", "Invalid activity cursor");
|
|
1918
|
+
}
|
|
1919
|
+
const items = activity.slice(start, start + limit);
|
|
1920
|
+
return answer("GET /v1/me/activity", participantActivitySchema, {
|
|
1921
|
+
member: current,
|
|
1922
|
+
items,
|
|
1923
|
+
nextCursor: `fake-${start + items.length}`
|
|
1924
|
+
});
|
|
1925
|
+
};
|
|
1926
|
+
const leaderboard = (board) => {
|
|
1927
|
+
const page = options.leaderboards?.[board] ?? Object.values(options.leaderboards ?? {}).find(
|
|
1928
|
+
(seed) => seed.leaderboard === board
|
|
1929
|
+
);
|
|
1930
|
+
return page ? answer("GET /v1/leaderboards/:board", leaderboardPageSchema, page) : refuse(404, RelayErrorCode.NotFound, "Leaderboard not found");
|
|
1931
|
+
};
|
|
1932
|
+
const pointHistory = (ledger) => {
|
|
1933
|
+
const known = ledgers.find(
|
|
1934
|
+
(reference) => reference.id === ledger || reference.key === ledger
|
|
1935
|
+
);
|
|
1936
|
+
const entries = options.pointHistory?.[ledger] ?? (known && (options.pointHistory?.[known.id] ?? (known.key ? options.pointHistory?.[known.key] : void 0)));
|
|
1937
|
+
if (!known && !entries) {
|
|
1938
|
+
return refuse(404, RelayErrorCode.NotFound, "Point ledger not found");
|
|
1939
|
+
}
|
|
1940
|
+
return answer("GET /v1/me/points/:ledger/history", pointHistoryPageSchema, {
|
|
1941
|
+
items: entries ?? [],
|
|
1942
|
+
nextCursor: null
|
|
1943
|
+
});
|
|
1944
|
+
};
|
|
1945
|
+
const exchange = async (request) => {
|
|
1946
|
+
const credential = request.headers.get("Authorization") ?? "";
|
|
1947
|
+
if (!/^Bearer di_\S+$/.test(credential)) {
|
|
1948
|
+
return Response.json(
|
|
1949
|
+
{
|
|
1950
|
+
error: "Use a valid identity integration server key from Console Settings. CLI and management credentials cannot issue participant sessions."
|
|
1951
|
+
},
|
|
1952
|
+
{ status: 401 }
|
|
1953
|
+
);
|
|
1954
|
+
}
|
|
1955
|
+
const body = await request.json().catch(() => null);
|
|
1956
|
+
const subject = typeof body === "object" && body && "subject" in body ? body.subject : void 0;
|
|
1957
|
+
if (typeof subject !== "string" || subject.length === 0) {
|
|
1958
|
+
return refuse(400, "invalid-request", "subject is required");
|
|
1959
|
+
}
|
|
1960
|
+
if (member === null && !identifier.safeParse(subject).success) {
|
|
1961
|
+
throw new TestSetupError(
|
|
1962
|
+
`createFakeRelay: POST /v1/auth/exchange signs in subject "${subject}", which is not a member ID; seed options.member`
|
|
1963
|
+
);
|
|
1964
|
+
}
|
|
1965
|
+
member ??= subject;
|
|
1966
|
+
return answer("POST /v1/auth/exchange", exchangeResultSchema, {
|
|
1967
|
+
token: `fake_${member}`,
|
|
1968
|
+
session: session(member)
|
|
1969
|
+
});
|
|
1970
|
+
};
|
|
1971
|
+
const builtIn = (request, method, path, query) => {
|
|
1972
|
+
if (method === "GET" && path === "/v1/auth/session") {
|
|
1973
|
+
return member === null ? Response.json(null) : answer(
|
|
1974
|
+
"GET /v1/auth/session",
|
|
1975
|
+
participantSessionSchema,
|
|
1976
|
+
session(member)
|
|
1977
|
+
);
|
|
1978
|
+
}
|
|
1979
|
+
if (method === "POST" && path === "/v1/auth/logout") {
|
|
1980
|
+
member = null;
|
|
1981
|
+
return answer("POST /v1/auth/logout", z5.object({ ok: z5.boolean() }), {
|
|
1982
|
+
ok: true
|
|
1983
|
+
});
|
|
1984
|
+
}
|
|
1985
|
+
if (method === "POST" && path === "/v1/auth/exchange") {
|
|
1986
|
+
return exchange(request);
|
|
1987
|
+
}
|
|
1988
|
+
if (method === "GET" && path === "/v1/point-ledgers") {
|
|
1989
|
+
return answer(
|
|
1990
|
+
"GET /v1/point-ledgers",
|
|
1991
|
+
z5.array(pointLedgerReferenceSchema),
|
|
1992
|
+
ledgers
|
|
1993
|
+
);
|
|
1994
|
+
}
|
|
1995
|
+
if (method === "GET" && path === "/v1/badges/catalog") {
|
|
1996
|
+
return answer("GET /v1/badges/catalog", badgeCatalogSchema, {
|
|
1997
|
+
items: badges
|
|
1998
|
+
});
|
|
1999
|
+
}
|
|
2000
|
+
if (method === "GET" && path === "/v1/badges") {
|
|
2001
|
+
return answer("GET /v1/badges", z5.array(badgeSchema), badges);
|
|
2002
|
+
}
|
|
2003
|
+
const board = method === "GET" && /^\/v1\/leaderboards\/([\w-]+)$/.exec(path);
|
|
2004
|
+
if (board) {
|
|
2005
|
+
return leaderboard(board[1]);
|
|
2006
|
+
}
|
|
2007
|
+
if (method !== "GET" || !path.startsWith("/v1/me/")) {
|
|
2008
|
+
return void 0;
|
|
2009
|
+
}
|
|
2010
|
+
const history = /^\/v1\/me\/points\/([\w-]+)\/history$/.exec(path);
|
|
2011
|
+
const covered = path === "/v1/me/experience" || path === "/v1/me/points" || path === "/v1/me/activity" || history;
|
|
2012
|
+
if (!covered) {
|
|
2013
|
+
return void 0;
|
|
2014
|
+
}
|
|
2015
|
+
if (member === null) {
|
|
2016
|
+
return refuse(401, RelayErrorCode.NotSignedIn, "Sign in to continue");
|
|
2017
|
+
}
|
|
2018
|
+
if (history) {
|
|
2019
|
+
return pointHistory(history[1]);
|
|
2020
|
+
}
|
|
2021
|
+
switch (path) {
|
|
2022
|
+
case "/v1/me/experience":
|
|
2023
|
+
return experience(member);
|
|
2024
|
+
case "/v1/me/points":
|
|
2025
|
+
return answer("GET /v1/me/points", pointBalancesSchema, {
|
|
2026
|
+
items: balances
|
|
2027
|
+
});
|
|
2028
|
+
default:
|
|
2029
|
+
return activityPage(member, query);
|
|
2030
|
+
}
|
|
2031
|
+
};
|
|
2032
|
+
const handle = async (request) => {
|
|
2033
|
+
const url = new URL(request.url);
|
|
2034
|
+
const path = url.pathname.startsWith("/relay/v1/") ? url.pathname.slice("/relay".length) : url.pathname;
|
|
2035
|
+
const method = request.method.toUpperCase();
|
|
2036
|
+
requests.push({ method, path });
|
|
2037
|
+
const override = overrides.find(
|
|
2038
|
+
(route) => route.method === method && route.pattern.test(path)
|
|
2039
|
+
);
|
|
2040
|
+
if (override) {
|
|
2041
|
+
return override.answer(request);
|
|
2042
|
+
}
|
|
2043
|
+
const response = builtIn(request, method, path, url.searchParams);
|
|
2044
|
+
if (response) {
|
|
2045
|
+
return response;
|
|
2046
|
+
}
|
|
2047
|
+
if (isParticipantRoute(path, method)) {
|
|
2048
|
+
return refuse(
|
|
2049
|
+
501,
|
|
2050
|
+
"not-faked",
|
|
2051
|
+
`createFakeRelay does not answer ${method} ${path}: answer it with options.routes["${method} ${path}"]`
|
|
2052
|
+
);
|
|
2053
|
+
}
|
|
2054
|
+
return refuse(404, "route-not-found", "Route not found");
|
|
2055
|
+
};
|
|
2056
|
+
experience(member ?? "member_test");
|
|
2057
|
+
answer("GET /v1/me/points", pointBalancesSchema, { items: balances });
|
|
2058
|
+
answer("GET /v1/point-ledgers", z5.array(pointLedgerReferenceSchema), ledgers);
|
|
2059
|
+
answer("GET /v1/badges/catalog", badgeCatalogSchema, { items: badges });
|
|
2060
|
+
answer("GET /v1/me/activity", participantActivitySchema, {
|
|
2061
|
+
member: member ?? "member_test",
|
|
2062
|
+
items: activity,
|
|
2063
|
+
nextCursor: "fake-0"
|
|
2064
|
+
});
|
|
2065
|
+
for (const ledger of Object.keys(options.pointHistory ?? {})) {
|
|
2066
|
+
pointHistory(ledger);
|
|
2067
|
+
}
|
|
2068
|
+
for (const board of Object.keys(options.leaderboards ?? {})) {
|
|
2069
|
+
leaderboard(board);
|
|
2070
|
+
}
|
|
2071
|
+
if (member !== null) {
|
|
2072
|
+
answer("GET /v1/auth/session", participantSessionSchema, session(member));
|
|
2073
|
+
}
|
|
2074
|
+
return {
|
|
2075
|
+
handle,
|
|
2076
|
+
fetch: (input, init) => handle(
|
|
2077
|
+
new Request(
|
|
2078
|
+
input instanceof Request ? input : new URL(
|
|
2079
|
+
String(input),
|
|
2080
|
+
globalThis.location?.href ?? "http://localhost"
|
|
2081
|
+
),
|
|
2082
|
+
init
|
|
2083
|
+
)
|
|
2084
|
+
),
|
|
2085
|
+
requests
|
|
2086
|
+
};
|
|
2087
|
+
}
|
|
1785
2088
|
export {
|
|
1786
2089
|
CapabilityError,
|
|
1787
2090
|
DecisionAssertionError,
|
|
1788
2091
|
EvaluatorError,
|
|
1789
2092
|
TestSetupError,
|
|
2093
|
+
createFakeRelay,
|
|
1790
2094
|
createTestContext,
|
|
1791
2095
|
defaultMember,
|
|
1792
2096
|
defaultNow,
|
|
@@ -1796,6 +2100,7 @@ export {
|
|
|
1796
2100
|
expectProgress,
|
|
1797
2101
|
expectReject,
|
|
1798
2102
|
expectReview,
|
|
2103
|
+
fakeEvaluationMember,
|
|
1799
2104
|
maxCapabilityCalls,
|
|
1800
2105
|
replayAttempt,
|
|
1801
2106
|
runQuest,
|