@domino-sdk/relay 0.1.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 ADDED
@@ -0,0 +1,11 @@
1
+ # Domino Relay SDK
2
+
3
+ Author quests and connect an application to Domino Relay.
4
+
5
+ ```sh
6
+ pnpm add @domino-sdk/relay
7
+ ```
8
+
9
+ Use `@domino-sdk/relay/authoring` for quest definitions, `/browser` for browser integrations, `/portal-proxy` for server proxies, and `/build` for bundling authored modules.
10
+
11
+ Requires Node.js 24 for tooling. Proprietary software; `UNLICENSED`.
package/build.d.mts ADDED
@@ -0,0 +1,2 @@
1
+ /** Bundle a default-exported quest module without executing it on the build host. */
2
+ export declare function buildQuest(entry: string, options?: {exportName?: string}): Promise<{ code: string }>;
package/build.mjs ADDED
@@ -0,0 +1,30 @@
1
+ import { resolve, dirname } from "node:path";
2
+ import { build } from "esbuild";
3
+ /** Bundle an authored quest without evaluating developer code in the build process. */
4
+ export async function buildQuest(entry, options = {}) {
5
+ if (
6
+ options.exportName &&
7
+ !/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(options.exportName)
8
+ )
9
+ throw new Error("Invalid quest export name");
10
+ const result = await build({
11
+ ...(options.exportName
12
+ ? {
13
+ stdin: {
14
+ contents: `export { ${options.exportName} as default } from ${JSON.stringify(resolve(entry))};`,
15
+ resolveDir: dirname(resolve(entry)),
16
+ loader: "ts",
17
+ },
18
+ }
19
+ : { entryPoints: [entry] }),
20
+ bundle: true,
21
+ write: false,
22
+ format: "esm",
23
+ platform: "neutral",
24
+ target: "es2022",
25
+ minify: true,
26
+ });
27
+ const file = result.outputFiles[0];
28
+ if (!file) throw new Error("Quest build produced no module");
29
+ return { code: file.text };
30
+ }
@@ -0,0 +1,279 @@
1
+ import { z } from 'zod';
2
+ import { PhotoResult, rewardSchema, triggerSchema, QuestPresentation, QuizEvidence, Decision, TieredRewardDefinition } from './schema.js';
3
+ import { W as WalletConnection, S as SolanaBalance } from './settings-BEbCiuhH.js';
4
+ export { s as settings } from './settings-BEbCiuhH.js';
5
+
6
+ type Reward = z.infer<typeof rewardSchema>;
7
+ declare const points: (balance: string, amount: number) => {
8
+ kind: "points";
9
+ balance: string;
10
+ amount: number;
11
+ };
12
+ declare const evidence: {
13
+ photo: () => "photo";
14
+ quiz: () => "quiz";
15
+ };
16
+ declare function manual<const I extends "photo" | "quiz">(options: {
17
+ input: I;
18
+ }): {
19
+ kind: "manual";
20
+ input: I;
21
+ };
22
+ declare function manual(): {
23
+ kind: "manual";
24
+ input: "none";
25
+ };
26
+ declare function manual(options: {
27
+ actor: "staff";
28
+ }): {
29
+ kind: "manual";
30
+ input: "none";
31
+ actor: "staff";
32
+ };
33
+ declare const automatic: () => {
34
+ kind: "automatic";
35
+ };
36
+ declare const completed: (quest: {
37
+ id: string;
38
+ } | string) => {
39
+ quest: string;
40
+ scope: "ever";
41
+ };
42
+ declare const untracked: () => {
43
+ kind: "untracked";
44
+ };
45
+ declare const staffHandover: () => {
46
+ kind: "staff-handover";
47
+ };
48
+ declare function defineTieredReward(input: TieredRewardDefinition): {
49
+ id: string;
50
+ tier: (tier: string) => {
51
+ kind: "tier";
52
+ reward: {
53
+ id: string;
54
+ title: string;
55
+ tiers: {
56
+ id: string;
57
+ title: string;
58
+ }[];
59
+ inventory: {
60
+ kind: "untracked";
61
+ };
62
+ fulfillment: {
63
+ kind: "staff-handover";
64
+ };
65
+ };
66
+ tier: string;
67
+ };
68
+ };
69
+ declare const once: () => {
70
+ kind: "once";
71
+ };
72
+ type Outcome = {
73
+ kind: "accept";
74
+ rewards?: Reward[];
75
+ } | {
76
+ kind: "review";
77
+ reason: string;
78
+ rewards?: Reward[];
79
+ } | {
80
+ kind: "reject";
81
+ reason: string;
82
+ };
83
+ declare const decision: {
84
+ accept: (options?: {
85
+ rewards?: Reward[];
86
+ }) => Outcome;
87
+ reject: (options: {
88
+ reason: string;
89
+ }) => Outcome;
90
+ review: (options: {
91
+ reason: string;
92
+ rewards?: Reward[];
93
+ }) => Outcome;
94
+ };
95
+ type EvaluationContext<T, I = {
96
+ photo: string;
97
+ }> = {
98
+ settings: T;
99
+ member: {
100
+ id: string;
101
+ };
102
+ input: I;
103
+ review: {
104
+ photo(options: {
105
+ image: string;
106
+ criteria: string;
107
+ }): Promise<PhotoResult>;
108
+ };
109
+ wallet: {
110
+ connection(): Promise<WalletConnection | null>;
111
+ solanaBalance(): Promise<SolanaBalance | null>;
112
+ };
113
+ };
114
+ type Evaluator<T, I = {
115
+ photo: string;
116
+ }> = (ctx: EvaluationContext<T, I>) => Promise<Outcome>;
117
+ declare const evaluators: {
118
+ quiz(answerKey: QuizEvidence["answers"], options?: {
119
+ minimumCorrect?: number;
120
+ }): Evaluator<unknown, QuizEvidence>;
121
+ photo<T>(options: (ctx: {
122
+ settings: T;
123
+ }) => {
124
+ criteria: string;
125
+ unclear: "human-review" | "reject";
126
+ }): Evaluator<T>;
127
+ };
128
+ type Trigger = z.infer<typeof triggerSchema>;
129
+ type QuestInput<T extends Trigger> = T extends {
130
+ input: "photo";
131
+ } ? {
132
+ photo: string;
133
+ } : T extends {
134
+ input: "quiz";
135
+ } ? QuizEvidence : Record<string, never>;
136
+ declare function defineQuest<T extends Record<string, z.ZodType>, const G extends Trigger>(definition: {
137
+ id: string;
138
+ title: string | ((ctx: {
139
+ settings: z.output<z.ZodObject<T>>;
140
+ }) => string);
141
+ settings: z.ZodObject<T>;
142
+ presentation?: (ctx: {
143
+ settings: z.output<z.ZodObject<T>>;
144
+ }) => QuestPresentation;
145
+ trigger: G;
146
+ requires?: ReturnType<typeof completed>[];
147
+ completion: ReturnType<typeof once>;
148
+ review?: (ctx: {
149
+ settings: z.output<z.ZodObject<T>>;
150
+ }) => {
151
+ enabled: boolean;
152
+ };
153
+ rewards: Reward[] | ((ctx: {
154
+ settings: z.output<z.ZodObject<T>>;
155
+ }) => Reward[]);
156
+ evaluate?: Evaluator<z.output<z.ZodObject<T>>, QuestInput<G>>;
157
+ }): {
158
+ id: string;
159
+ describe: (input: unknown) => {
160
+ quest: string;
161
+ runtimeVersion: 1 | 2;
162
+ title: string;
163
+ presentation: {
164
+ quiz?: {
165
+ id: string;
166
+ prompt: string;
167
+ choices: {
168
+ id: string;
169
+ label: string;
170
+ }[];
171
+ }[] | undefined;
172
+ instructions?: string | undefined;
173
+ video?: {
174
+ url: string;
175
+ poster?: string | undefined;
176
+ captions?: {
177
+ url: string;
178
+ language: string;
179
+ label: string;
180
+ } | undefined;
181
+ } | undefined;
182
+ };
183
+ fields: Record<string, {
184
+ kind: "quiz";
185
+ default: {
186
+ id: string;
187
+ prompt: string;
188
+ choices: {
189
+ id: string;
190
+ label: string;
191
+ }[];
192
+ correct: string;
193
+ }[];
194
+ label: string;
195
+ description?: string | undefined;
196
+ } | {
197
+ kind: "text";
198
+ default: string;
199
+ minLength: number;
200
+ maxLength: number;
201
+ multiline: boolean;
202
+ label: string;
203
+ description?: string | undefined;
204
+ } | {
205
+ kind: "integer";
206
+ default: number;
207
+ min: number;
208
+ max: number;
209
+ label: string;
210
+ description?: string | undefined;
211
+ } | {
212
+ kind: "boolean";
213
+ default: boolean;
214
+ label: string;
215
+ description?: string | undefined;
216
+ } | {
217
+ kind: "choice";
218
+ default: string;
219
+ options: string[];
220
+ label: string;
221
+ description?: string | undefined;
222
+ }>;
223
+ values: Record<string, string | number | boolean | {
224
+ id: string;
225
+ prompt: string;
226
+ choices: {
227
+ id: string;
228
+ label: string;
229
+ }[];
230
+ correct: string;
231
+ }[]>;
232
+ rewards: ({
233
+ kind: "tier";
234
+ reward: {
235
+ id: string;
236
+ title: string;
237
+ tiers: {
238
+ id: string;
239
+ title: string;
240
+ }[];
241
+ inventory: {
242
+ kind: "untracked";
243
+ };
244
+ fulfillment: {
245
+ kind: "staff-handover";
246
+ };
247
+ };
248
+ tier: string;
249
+ } | {
250
+ kind: "points";
251
+ balance: string;
252
+ amount: number;
253
+ })[];
254
+ humanReview: boolean;
255
+ trigger: {
256
+ kind: "manual";
257
+ input: "photo" | "quiz" | "none";
258
+ actor?: "member" | "staff" | undefined;
259
+ } | {
260
+ kind: "automatic";
261
+ };
262
+ requires: {
263
+ quest: string;
264
+ scope: "ever";
265
+ }[];
266
+ completion: {
267
+ kind: "once";
268
+ };
269
+ };
270
+ evaluate(ctx: EvaluationContext<unknown, QuestInput<G>> & {
271
+ rewards: Reward[];
272
+ humanReview: boolean;
273
+ }): Promise<Decision>;
274
+ };
275
+ /** Publish this artifact as a reusable type. Its id identifies the type;
276
+ * Console instances receive independent quest identities and pinned versions. */
277
+ declare const defineQuestType: typeof defineQuest;
278
+
279
+ export { type EvaluationContext, automatic, completed, decision, defineQuest, defineQuestType, defineTieredReward, evaluators, evidence, manual, once, points, staffHandover, untracked };
@@ -0,0 +1,149 @@
1
+ import {
2
+ decisionSchema,
3
+ parseSettings,
4
+ pointsRewardSchema,
5
+ questDescriptionSchema,
6
+ quizAnswersSchema,
7
+ rewardBundleSchema,
8
+ settingFieldSchema,
9
+ settings,
10
+ tierRewardSchema,
11
+ tieredRewardDefinitionSchema
12
+ } from "./chunk-C2KOMNLG.js";
13
+
14
+ // src/authoring.ts
15
+ import { z } from "zod";
16
+ var points = (balance, amount) => pointsRewardSchema.parse({ kind: "points", balance, amount });
17
+ var evidence = {
18
+ photo: () => "photo",
19
+ quiz: () => "quiz"
20
+ };
21
+ function manual(options) {
22
+ return {
23
+ kind: "manual",
24
+ input: options?.input ?? "none",
25
+ ...options?.actor ? { actor: options.actor } : {}
26
+ };
27
+ }
28
+ var automatic = () => ({ kind: "automatic" });
29
+ var completed = (quest) => ({
30
+ quest: typeof quest === "string" ? quest : quest.id,
31
+ scope: "ever"
32
+ });
33
+ var untracked = () => ({ kind: "untracked" });
34
+ var staffHandover = () => ({ kind: "staff-handover" });
35
+ function defineTieredReward(input) {
36
+ const reward = tieredRewardDefinitionSchema.parse(input);
37
+ return {
38
+ id: reward.id,
39
+ tier: (tier) => tierRewardSchema.parse({ kind: "tier", reward, tier })
40
+ };
41
+ }
42
+ var once = () => ({ kind: "once" });
43
+ var decision = {
44
+ accept: (options = {}) => ({
45
+ kind: "accept",
46
+ ...options
47
+ }),
48
+ reject: (options) => ({
49
+ kind: "reject",
50
+ ...options
51
+ }),
52
+ review: (options) => ({
53
+ kind: "review",
54
+ ...options
55
+ })
56
+ };
57
+ var evaluators = {
58
+ quiz(answerKey, options = {}) {
59
+ const expected = quizAnswersSchema.parse(answerKey);
60
+ const questions = Object.keys(expected);
61
+ const minimum = z.number().int().min(1).max(questions.length).parse(options.minimumCorrect ?? questions.length);
62
+ return async ({ input }) => {
63
+ const complete = Object.keys(input.answers).length === questions.length && questions.every((question) => Object.hasOwn(input.answers, question));
64
+ const correct = questions.filter(
65
+ (question) => input.answers[question] === expected[question]
66
+ ).length;
67
+ return complete && correct >= minimum ? decision.accept() : decision.reject({ reason: "Review your answers and try again." });
68
+ };
69
+ },
70
+ photo(options) {
71
+ return async (ctx) => {
72
+ const config = options(ctx);
73
+ const result = await ctx.review.photo({
74
+ image: ctx.input.photo,
75
+ criteria: config.criteria
76
+ });
77
+ if (result.kind === "unclear")
78
+ return config.unclear === "human-review" ? decision.review({ reason: result.reason }) : decision.reject({ reason: result.reason });
79
+ return result.kind === "pass" ? decision.accept() : decision.reject({ reason: result.reason });
80
+ };
81
+ }
82
+ };
83
+ function defineQuest(definition) {
84
+ if (definition.trigger.kind === "manual" && definition.trigger.input !== "none" && !definition.evaluate)
85
+ throw new Error("Evidence quests require an evaluator");
86
+ const fields = Object.fromEntries(
87
+ Object.entries(definition.settings.shape).map(([key, schema]) => [
88
+ key,
89
+ settingFieldSchema.parse(schema.meta())
90
+ ])
91
+ );
92
+ function describe(input) {
93
+ const settings2 = definition.settings.parse(input);
94
+ const values = parseSettings(fields, settings2);
95
+ const rewards = rewardBundleSchema.parse(
96
+ typeof definition.rewards === "function" ? definition.rewards({ settings: settings2 }) : definition.rewards
97
+ );
98
+ return questDescriptionSchema.parse({
99
+ quest: definition.id,
100
+ runtimeVersion: 2,
101
+ title: typeof definition.title === "function" ? definition.title({ settings: settings2 }) : definition.title,
102
+ presentation: definition.presentation?.({ settings: settings2 }) ?? {},
103
+ fields,
104
+ values,
105
+ rewards,
106
+ humanReview: definition.review?.({ settings: settings2 })?.enabled ?? true,
107
+ trigger: definition.trigger,
108
+ completion: definition.completion,
109
+ requires: definition.requires ?? []
110
+ });
111
+ }
112
+ return {
113
+ id: definition.id,
114
+ describe,
115
+ async evaluate(ctx) {
116
+ const settings2 = definition.settings.parse(ctx.settings);
117
+ const result = definition.evaluate ? await definition.evaluate({
118
+ settings: settings2,
119
+ member: ctx.member,
120
+ input: ctx.input,
121
+ review: ctx.review,
122
+ wallet: ctx.wallet
123
+ }) : decision.accept();
124
+ if (!result) throw new Error("Evaluator returned no decision");
125
+ if (result.kind === "review" && !ctx.humanReview)
126
+ return decisionSchema.parse({ kind: "reject", reason: result.reason });
127
+ return decisionSchema.parse(
128
+ result.kind === "accept" || result.kind === "review" ? { ...result, rewards: result.rewards ?? ctx.rewards } : result
129
+ );
130
+ }
131
+ };
132
+ }
133
+ var defineQuestType = defineQuest;
134
+ export {
135
+ automatic,
136
+ completed,
137
+ decision,
138
+ defineQuest,
139
+ defineQuestType,
140
+ defineTieredReward,
141
+ evaluators,
142
+ evidence,
143
+ manual,
144
+ once,
145
+ points,
146
+ settings,
147
+ staffHandover,
148
+ untracked
149
+ };