@solgate/server 0.2.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.
@@ -0,0 +1,43 @@
1
+ import {
2
+ MemoryStorage,
3
+ createAllowlistApp,
4
+ createSqliteStorage
5
+ } from "./chunk-MSHXG5G3.js";
6
+
7
+ // src/node.ts
8
+ import { serve } from "@hono/node-server";
9
+ import { getConnInfo } from "@hono/node-server/conninfo";
10
+ async function configFromEnv(env = process.env) {
11
+ const storage = env.ALLOWLIST_DB === "memory" ? new MemoryStorage() : await createSqliteStorage(env.ALLOWLIST_DB ?? "allowlist.db");
12
+ if (!env.SESSION_SECRET || env.SESSION_SECRET.length < 32) throw new Error("SESSION_SECRET must be at least 32 characters");
13
+ return {
14
+ storage,
15
+ baseUrl: env.BASE_URL ?? "http://localhost:8787",
16
+ sessionSecret: env.SESSION_SECRET,
17
+ adminApiKey: env.ADMIN_API_KEY,
18
+ corsOrigins: env.CORS_ORIGINS ? env.CORS_ORIGINS.split(",").map((s) => s.trim()) : "*",
19
+ eligibilityLookup: env.ELIGIBILITY_LOOKUP ?? "minimal",
20
+ trustProxy: env.TRUST_PROXY ?? "none",
21
+ allowedReturnOrigins: env.ALLOWED_RETURN_ORIGINS?.split(",").map((s) => s.trim()).filter(Boolean),
22
+ allowInsecureWebhooks: env.ALLOW_INSECURE_WEBHOOKS === "true",
23
+ solana: { rpcUrl: env.SOLANA_RPC_URL ?? "https://api.mainnet-beta.solana.com", dasUrl: env.SOLANA_DAS_URL },
24
+ oauth: {
25
+ x: env.X_CLIENT_ID ? { clientId: env.X_CLIENT_ID, clientSecret: env.X_CLIENT_SECRET ?? "" } : void 0,
26
+ discord: env.DISCORD_CLIENT_ID ? { clientId: env.DISCORD_CLIENT_ID, clientSecret: env.DISCORD_CLIENT_SECRET ?? "", botToken: env.DISCORD_BOT_TOKEN } : void 0,
27
+ google: env.GOOGLE_CLIENT_ID ? { clientId: env.GOOGLE_CLIENT_ID, clientSecret: env.GOOGLE_CLIENT_SECRET ?? "" } : void 0
28
+ },
29
+ telegram: env.TELEGRAM_BOT_TOKEN ? { botToken: env.TELEGRAM_BOT_TOKEN, botUsername: env.TELEGRAM_BOT_USERNAME ?? "" } : void 0,
30
+ captcha: { turnstileSecret: env.TURNSTILE_SECRET, hcaptchaSecret: env.HCAPTCHA_SECRET, recaptchaSecret: env.RECAPTCHA_SECRET }
31
+ };
32
+ }
33
+ async function startNodeServer(port = Number(process.env.PORT ?? 8787)) {
34
+ const config = await configFromEnv();
35
+ const { app } = createAllowlistApp(config, { getClientIp: (c) => getConnInfo(c).remote.address });
36
+ serve({ fetch: app.fetch, port }, () => console.log(`solgate API listening on http://localhost:${port}`));
37
+ return app;
38
+ }
39
+
40
+ export {
41
+ configFromEnv,
42
+ startNodeServer
43
+ };
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.js ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ startNodeServer
4
+ } from "./chunk-MYF3SW4P.js";
5
+ import "./chunk-MSHXG5G3.js";
6
+ import "./chunk-MCKGQKYU.js";
7
+
8
+ // src/cli.ts
9
+ startNodeServer().catch((e) => {
10
+ console.error(e);
11
+ process.exit(1);
12
+ });
@@ -0,0 +1,156 @@
1
+ import { V as Verifier, a as Storage, b as SocialLink, W as Webhook, c as WebhookDelivery, d as ApiKey, e as Snapshot } from './app-CB9x11xM.js';
2
+ export { f as AllowlistError, g as AllowlistService, A as AppEnv, E as EventBus, N as NormalizedConfig, S as ServerConfig, h as VerificationUnavailable, i as VerifyContext, j as createAllowlistApp, k as fail, p as pass, v as verifyWebhookSignature } from './app-CB9x11xM.js';
3
+ import { NftOwnershipModule, TokenBalanceModule, DiscordVerificationModule, SocialTaskModule, TelegramVerificationModule, XVerificationModule, YouTubeVerificationModule, CaptchaModule, QuizModule, ReferralModule, Campaign, Entry } from '@solgate/core';
4
+ import { z } from 'zod';
5
+ import 'hono/types';
6
+ import 'hono';
7
+
8
+ type TokenCfg = z.infer<typeof TokenBalanceModule.configSchema>;
9
+ type NftCfg = z.infer<typeof NftOwnershipModule.configSchema>;
10
+ /** Scale a UI amount (e.g. 12.5) to raw units as a BigInt, exactly. */
11
+ declare function toRawAmount(ui: number | string, decimals: number): bigint;
12
+ /** Wallet signature is verified at session creation; this verifier just records it. */
13
+ declare const walletSignatureVerifier: Verifier;
14
+ /**
15
+ * SPL / Token-2022 balance. Filtering by `mint` alone returns accounts from
16
+ * whichever token program owns that mint, so one query covers both programs.
17
+ * Amounts are compared as exact integers (raw units), never floats.
18
+ * RPC failures are surfaced as VerificationUnavailable — an outage must not
19
+ * be recorded as "user has zero tokens".
20
+ */
21
+ declare const tokenBalanceVerifier: Verifier<TokenCfg>;
22
+ /** NFT ownership via DAS `getAssetsByOwner` (covers Token Metadata, Core, and compressed NFTs). */
23
+ declare const nftOwnershipVerifier: Verifier<NftCfg>;
24
+
25
+ /**
26
+ * Social verifiers. The OAuth dance itself lives in routes/oauth.ts; once a
27
+ * provider profile has been obtained, it is passed here as `input` where we
28
+ * (1) enforce one-social-account-per-wallet uniqueness and (2) check any
29
+ * extra requirement (follow, guild, role, subscription).
30
+ */
31
+
32
+ interface SocialProfile {
33
+ provider: "x" | "discord" | "google" | "telegram";
34
+ id: string;
35
+ handle?: string;
36
+ accessToken?: string;
37
+ meta?: Record<string, unknown>;
38
+ }
39
+ type XCfg = z.infer<typeof XVerificationModule.configSchema>;
40
+ declare const xVerifier: Verifier<XCfg, SocialProfile>;
41
+ type DiscordCfg = z.infer<typeof DiscordVerificationModule.configSchema>;
42
+ declare const discordVerifier: Verifier<DiscordCfg, SocialProfile>;
43
+ type TgCfg = z.infer<typeof TelegramVerificationModule.configSchema>;
44
+ interface TelegramLoginData {
45
+ id: number;
46
+ first_name?: string;
47
+ last_name?: string;
48
+ username?: string;
49
+ photo_url?: string;
50
+ auth_date: number;
51
+ hash: string;
52
+ }
53
+ /** Validate Telegram Login Widget payload per https://core.telegram.org/widgets/login#checking-authorization */
54
+ declare function verifyTelegramLogin(botToken: string, data: TelegramLoginData, maxAgeSeconds?: number, clockSkewSeconds?: number): boolean;
55
+ declare const telegramVerifier: Verifier<TgCfg, TelegramLoginData>;
56
+ type YtCfg = z.infer<typeof YouTubeVerificationModule.configSchema>;
57
+ declare const youtubeVerifier: Verifier<YtCfg, SocialProfile>;
58
+ type TaskCfg = z.infer<typeof SocialTaskModule.configSchema>;
59
+ interface SocialTaskInput {
60
+ /** "open" records the click; "complete" submits. */
61
+ action: "open" | "complete";
62
+ proofUrl?: string;
63
+ }
64
+ declare const socialTaskVerifier: Verifier<TaskCfg, SocialTaskInput>;
65
+
66
+ type QuizCfg = z.infer<typeof QuizModule.configSchema>;
67
+ interface QuizInput {
68
+ answers: Record<string, number | number[] | string>;
69
+ }
70
+ declare const quizVerifier: Verifier<QuizCfg, QuizInput>;
71
+ type RefCfg = z.infer<typeof ReferralModule.configSchema>;
72
+ interface ReferralInput {
73
+ code?: string;
74
+ }
75
+ declare const referralVerifier: Verifier<RefCfg, ReferralInput>;
76
+ type CaptchaCfg = z.infer<typeof CaptchaModule.configSchema>;
77
+ interface CaptchaInput {
78
+ token: string;
79
+ }
80
+ declare const captchaVerifier: Verifier<CaptchaCfg, CaptchaInput>;
81
+
82
+ declare const builtinVerifiers: Verifier[];
83
+
84
+ /** In-memory adapter: tests, demos, and stateless edge deployments with a warm cache. */
85
+ declare class MemoryStorage implements Storage {
86
+ campaigns: Map<string, Campaign>;
87
+ entries: Map<string, Entry>;
88
+ temp: Map<string, {
89
+ v: string;
90
+ exp: number;
91
+ }>;
92
+ social: Map<string, SocialLink>;
93
+ webhooks: Map<string, Webhook>;
94
+ deliveries: WebhookDelivery[];
95
+ apiKeys: Map<string, ApiKey>;
96
+ snapshots: Map<string, Snapshot>;
97
+ getCampaign(id: string): Promise<Campaign | null>;
98
+ listCampaigns(): Promise<Campaign[]>;
99
+ putCampaign(c: Campaign): Promise<void>;
100
+ deleteCampaign(id: string): Promise<void>;
101
+ getEntry(campaignId: string, wallet: string): Promise<Entry | null>;
102
+ putEntry(e: Entry): Promise<void>;
103
+ listEntries(campaignId: string, opts?: {
104
+ eligibleOnly?: boolean;
105
+ offset?: number;
106
+ limit?: number;
107
+ }): Promise<Entry[]>;
108
+ countEntries(campaignId: string, opts?: {
109
+ eligibleOnly?: boolean;
110
+ }): Promise<number>;
111
+ findEntryByReferralCode(campaignId: string, code: string): Promise<Entry | null>;
112
+ private sweep;
113
+ setTemp(key: string, value: string, ttlSeconds: number): Promise<void>;
114
+ getTemp(key: string): Promise<string | null>;
115
+ deleteTemp(key: string): Promise<void>;
116
+ incrTemp(key: string, ttlSeconds: number): Promise<number>;
117
+ getSocialLink(campaignId: string, provider: string, providerUserId: string): Promise<SocialLink | null>;
118
+ claimSocialLink(link: SocialLink): Promise<{
119
+ ok: true;
120
+ } | {
121
+ ok: false;
122
+ owner: string;
123
+ }>;
124
+ putSnapshot(s: Snapshot): Promise<void>;
125
+ getSnapshot(campaignId: string, id?: string): Promise<Snapshot | null>;
126
+ listSnapshots(campaignId: string): Promise<{
127
+ id: string;
128
+ campaignId: string;
129
+ createdAt: number;
130
+ count: number;
131
+ totalAllocation: number;
132
+ merkle?: {
133
+ scheme: string;
134
+ root: string;
135
+ };
136
+ }[]>;
137
+ listSocialLinksForWallet(campaignId: string, wallet: string): Promise<SocialLink[]>;
138
+ listWebhooks(): Promise<Webhook[]>;
139
+ putWebhook(w: Webhook): Promise<void>;
140
+ deleteWebhook(id: string): Promise<void>;
141
+ putDelivery(d: WebhookDelivery): Promise<void>;
142
+ listApiKeys(): Promise<ApiKey[]>;
143
+ putApiKey(k: ApiKey): Promise<void>;
144
+ deleteApiKey(id: string): Promise<void>;
145
+ }
146
+
147
+ /**
148
+ * SQLite adapter using better-sqlite3 (Node). Single-file, zero-ops.
149
+ * The same SQL works for Postgres with trivial changes — see docs/storage.md.
150
+ */
151
+ declare function createSqliteStorage(file?: string): Promise<Storage>;
152
+
153
+ /** Verify an ed25519 signature over a UTF-8 message from a base58 Solana pubkey. Signature may be base58 or base64. */
154
+ declare function verifyWalletSignature(wallet: string, message: string, signature: string): boolean;
155
+
156
+ export { ApiKey, type CaptchaInput, MemoryStorage, type QuizInput, type ReferralInput, SocialLink, type SocialProfile, type SocialTaskInput, Storage, type TelegramLoginData, Verifier, Webhook, builtinVerifiers, captchaVerifier, createSqliteStorage, discordVerifier, nftOwnershipVerifier, quizVerifier, referralVerifier, socialTaskVerifier, telegramVerifier, toRawAmount, tokenBalanceVerifier, verifyTelegramLogin, verifyTelegramLogin as verifyTelegramLoginData, verifyWalletSignature, walletSignatureVerifier, xVerifier, youtubeVerifier };
package/dist/index.js ADDED
@@ -0,0 +1,56 @@
1
+ import {
2
+ AllowlistError,
3
+ AllowlistService,
4
+ EventBus,
5
+ MemoryStorage,
6
+ VerificationUnavailable,
7
+ builtinVerifiers,
8
+ captchaVerifier,
9
+ createAllowlistApp,
10
+ createSqliteStorage,
11
+ discordVerifier,
12
+ fail,
13
+ nftOwnershipVerifier,
14
+ pass,
15
+ quizVerifier,
16
+ referralVerifier,
17
+ socialTaskVerifier,
18
+ telegramVerifier,
19
+ toRawAmount,
20
+ tokenBalanceVerifier,
21
+ verifyTelegramLogin,
22
+ verifyWalletSignature,
23
+ verifyWebhookSignature,
24
+ walletSignatureVerifier,
25
+ xVerifier,
26
+ youtubeVerifier
27
+ } from "./chunk-MSHXG5G3.js";
28
+ import "./chunk-MCKGQKYU.js";
29
+ export {
30
+ AllowlistError,
31
+ AllowlistService,
32
+ EventBus,
33
+ MemoryStorage,
34
+ VerificationUnavailable,
35
+ builtinVerifiers,
36
+ captchaVerifier,
37
+ createAllowlistApp,
38
+ createSqliteStorage,
39
+ discordVerifier,
40
+ fail,
41
+ nftOwnershipVerifier,
42
+ pass,
43
+ quizVerifier,
44
+ referralVerifier,
45
+ socialTaskVerifier,
46
+ telegramVerifier,
47
+ toRawAmount,
48
+ tokenBalanceVerifier,
49
+ verifyTelegramLogin,
50
+ verifyTelegramLogin as verifyTelegramLoginData,
51
+ verifyWalletSignature,
52
+ verifyWebhookSignature,
53
+ walletSignatureVerifier,
54
+ xVerifier,
55
+ youtubeVerifier
56
+ };