@ascnd-gg/client 1.0.0 → 1.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 CHANGED
@@ -1,5 +1,8 @@
1
1
  # @ascnd-gg/client
2
2
 
3
+ > [!WARNING]
4
+ > This project is under active development. Expect bugs. Please report issues via the [issue tracker](../../issues).
5
+
3
6
  TypeScript/JavaScript client library for the [Ascnd](https://ascnd.gg) leaderboard API. Uses gRPC-Web for efficient, type-safe communication.
4
7
 
5
8
  ## Installation
@@ -305,7 +308,7 @@ const request = create(SubmitScoreRequestSchema, {
305
308
 
306
309
  ## Links
307
310
 
308
- - [Documentation](https://ascnd.gg/docs/sdks/typescript)
311
+ - [Documentation](https://docs.ascnd.gg/sdks/typescript)
309
312
  - [GitHub](https://github.com/ascnd-gg/ascnd-client-js)
310
313
  - [npm](https://www.npmjs.com/package/@ascnd-gg/client)
311
314
 
package/dist/index.cjs CHANGED
@@ -44,7 +44,7 @@ var import_connect_web = require("@connectrpc/connect-web");
44
44
 
45
45
  // src/gen/ascnd_pb.ts
46
46
  var import_codegenv2 = require("@bufbuild/protobuf/codegenv2");
47
- var file_ascnd = /* @__PURE__ */ (0, import_codegenv2.fileDesc)("Cgthc2NuZC5wcm90bxIIYXNjbmQudjEipAEKElN1Ym1pdFNjb3JlUmVxdWVzdBIWCg5sZWFkZXJib2FyZF9pZBgBIAEoCRIRCglwbGF5ZXJfaWQYAiABKAkSDQoFc2NvcmUYAyABKAMSFQoIbWV0YWRhdGEYBCABKAxIAIgBARIcCg9pZGVtcG90ZW5jeV9rZXkYBSABKAlIAYgBAUILCglfbWV0YWRhdGFCEgoQX2lkZW1wb3RlbmN5X2tleSKlAQoTU3VibWl0U2NvcmVSZXNwb25zZRIQCghzY29yZV9pZBgBIAEoCRIMCgRyYW5rGAIgASgFEhMKC2lzX25ld19iZXN0GAMgASgIEhgKEHdhc19kZWR1cGxpY2F0ZWQYBCABKAgSMQoJYW50aWNoZWF0GAUgASgLMhkuYXNjbmQudjEuQW50aWNoZWF0UmVzdWx0SACIAQFCDAoKX2FudGljaGVhdCJjCg9BbnRpY2hlYXRSZXN1bHQSDgoGcGFzc2VkGAEgASgIEjAKCnZpb2xhdGlvbnMYAiADKAsyHC5hc2NuZC52MS5BbnRpY2hlYXRWaW9sYXRpb24SDgoGYWN0aW9uGAMgASgJIjcKEkFudGljaGVhdFZpb2xhdGlvbhIRCglmbGFnX3R5cGUYASABKAkSDgoGcmVhc29uGAIgASgJIrMBChVHZXRMZWFkZXJib2FyZFJlcXVlc3QSFgoObGVhZGVyYm9hcmRfaWQYASABKAkSEgoFbGltaXQYAiABKAVIAIgBARITCgZvZmZzZXQYAyABKAVIAYgBARITCgZwZXJpb2QYBCABKAlIAogBARIWCgl2aWV3X3NsdWcYBSABKAlIA4gBAUIICgZfbGltaXRCCQoHX29mZnNldEIJCgdfcGVyaW9kQgwKCl92aWV3X3NsdWci3AEKFkdldExlYWRlcmJvYXJkUmVzcG9uc2USKwoHZW50cmllcxgBIAMoCzIaLmFzY25kLnYxLkxlYWRlcmJvYXJkRW50cnkSFQoNdG90YWxfZW50cmllcxgCIAEoBRIQCghoYXNfbW9yZRgDIAEoCBIUCgxwZXJpb2Rfc3RhcnQYBCABKAkSFwoKcGVyaW9kX2VuZBgFIAEoCUgAiAEBEiUKBHZpZXcYBiABKAsyEi5hc2NuZC52MS5WaWV3SW5mb0gBiAEBQg0KC19wZXJpb2RfZW5kQgcKBV92aWV3IrUBChBMZWFkZXJib2FyZEVudHJ5EgwKBHJhbmsYASABKAUSEQoJcGxheWVyX2lkGAIgASgJEg0KBXNjb3JlGAMgASgDEhQKDHN1Ym1pdHRlZF9hdBgEIAEoCRIVCghtZXRhZGF0YRgFIAEoDEgAiAEBEisKB2JyYWNrZXQYBiABKAsyFS5hc2NuZC52MS5CcmFja2V0SW5mb0gBiAEBQgsKCV9tZXRhZGF0YUIKCghfYnJhY2tldCJFCgtCcmFja2V0SW5mbxIKCgJpZBgBIAEoCRIMCgRuYW1lGAIgASgJEhIKBWNvbG9yGAMgASgJSACIAQFCCAoGX2NvbG9yIiYKCFZpZXdJbmZvEgwKBHNsdWcYASABKAkSDAoEbmFtZRgCIAEoCSKHAQoUR2V0UGxheWVyUmFua1JlcXVlc3QSFgoObGVhZGVyYm9hcmRfaWQYASABKAkSEQoJcGxheWVyX2lkGAIgASgJEhMKBnBlcmlvZBgDIAEoCUgAiAEBEhYKCXZpZXdfc2x1ZxgEIAEoCUgBiAEBQgkKB19wZXJpb2RCDAoKX3ZpZXdfc2x1ZyLLAgoVR2V0UGxheWVyUmFua1Jlc3BvbnNlEhEKBHJhbmsYASABKAVIAIgBARISCgVzY29yZRgCIAEoA0gBiAEBEhcKCmJlc3Rfc2NvcmUYAyABKANIAogBARIVCg10b3RhbF9lbnRyaWVzGAQgASgFEhcKCnBlcmNlbnRpbGUYBSABKAlIA4gBARIrCgdicmFja2V0GAYgASgLMhUuYXNjbmQudjEuQnJhY2tldEluZm9IBIgBARIlCgR2aWV3GAcgASgLMhIuYXNjbmQudjEuVmlld0luZm9IBYgBARIYCgtnbG9iYWxfcmFuaxgIIAEoBUgGiAEBQgcKBV9yYW5rQggKBl9zY29yZUINCgtfYmVzdF9zY29yZUINCgtfcGVyY2VudGlsZUIKCghfYnJhY2tldEIHCgVfdmlld0IOCgxfZ2xvYmFsX3JhbmsygQIKDEFzY25kU2VydmljZRJKCgtTdWJtaXRTY29yZRIcLmFzY25kLnYxLlN1Ym1pdFNjb3JlUmVxdWVzdBodLmFzY25kLnYxLlN1Ym1pdFNjb3JlUmVzcG9uc2USUwoOR2V0TGVhZGVyYm9hcmQSHy5hc2NuZC52MS5HZXRMZWFkZXJib2FyZFJlcXVlc3QaIC5hc2NuZC52MS5HZXRMZWFkZXJib2FyZFJlc3BvbnNlElAKDUdldFBsYXllclJhbmsSHi5hc2NuZC52MS5HZXRQbGF5ZXJSYW5rUmVxdWVzdBofLmFzY25kLnYxLkdldFBsYXllclJhbmtSZXNwb25zZWIGcHJvdG8z");
47
+ var file_ascnd = /* @__PURE__ */ (0, import_codegenv2.fileDesc)("Cgthc2NuZC5wcm90bxIIYXNjbmQudjEipAEKElN1Ym1pdFNjb3JlUmVxdWVzdBIWCg5sZWFkZXJib2FyZF9pZBgBIAEoCRIRCglwbGF5ZXJfaWQYAiABKAkSDQoFc2NvcmUYAyABKAMSFQoIbWV0YWRhdGEYBCABKAxIAIgBARIcCg9pZGVtcG90ZW5jeV9rZXkYBSABKAlIAYgBAUILCglfbWV0YWRhdGFCEgoQX2lkZW1wb3RlbmN5X2tleSKlAQoTU3VibWl0U2NvcmVSZXNwb25zZRIQCghzY29yZV9pZBgBIAEoCRIMCgRyYW5rGAIgASgFEhMKC2lzX25ld19iZXN0GAMgASgIEhgKEHdhc19kZWR1cGxpY2F0ZWQYBCABKAgSMQoJYW50aWNoZWF0GAUgASgLMhkuYXNjbmQudjEuQW50aWNoZWF0UmVzdWx0SACIAQFCDAoKX2FudGljaGVhdCJjCg9BbnRpY2hlYXRSZXN1bHQSDgoGcGFzc2VkGAEgASgIEjAKCnZpb2xhdGlvbnMYAiADKAsyHC5hc2NuZC52MS5BbnRpY2hlYXRWaW9sYXRpb24SDgoGYWN0aW9uGAMgASgJIjcKEkFudGljaGVhdFZpb2xhdGlvbhIRCglmbGFnX3R5cGUYASABKAkSDgoGcmVhc29uGAIgASgJIusBChVHZXRMZWFkZXJib2FyZFJlcXVlc3QSFgoObGVhZGVyYm9hcmRfaWQYASABKAkSEgoFbGltaXQYAiABKAVIAIgBARITCgZwZXJpb2QYBCABKAlIAYgBARIWCgl2aWV3X3NsdWcYBSABKAlIAogBARITCgZjdXJzb3IYBiABKAlIA4gBARIYCgthcm91bmRfcmFuaxgHIAEoBUgEiAEBQggKBl9saW1pdEIJCgdfcGVyaW9kQgwKCl92aWV3X3NsdWdCCQoHX2N1cnNvckIOCgxfYXJvdW5kX3JhbmtKBAgDEARSBm9mZnNldCKGAgoWR2V0TGVhZGVyYm9hcmRSZXNwb25zZRIrCgdlbnRyaWVzGAEgAygLMhouYXNjbmQudjEuTGVhZGVyYm9hcmRFbnRyeRIVCg10b3RhbF9lbnRyaWVzGAIgASgFEhAKCGhhc19tb3JlGAMgASgIEhQKDHBlcmlvZF9zdGFydBgEIAEoCRIXCgpwZXJpb2RfZW5kGAUgASgJSACIAQESJQoEdmlldxgGIAEoCzISLmFzY25kLnYxLlZpZXdJbmZvSAGIAQESGAoLbmV4dF9jdXJzb3IYByABKAlIAogBAUINCgtfcGVyaW9kX2VuZEIHCgVfdmlld0IOCgxfbmV4dF9jdXJzb3IitQEKEExlYWRlcmJvYXJkRW50cnkSDAoEcmFuaxgBIAEoBRIRCglwbGF5ZXJfaWQYAiABKAkSDQoFc2NvcmUYAyABKAMSFAoMc3VibWl0dGVkX2F0GAQgASgJEhUKCG1ldGFkYXRhGAUgASgMSACIAQESKwoHYnJhY2tldBgGIAEoCzIVLmFzY25kLnYxLkJyYWNrZXRJbmZvSAGIAQFCCwoJX21ldGFkYXRhQgoKCF9icmFja2V0IkUKC0JyYWNrZXRJbmZvEgoKAmlkGAEgASgJEgwKBG5hbWUYAiABKAkSEgoFY29sb3IYAyABKAlIAIgBAUIICgZfY29sb3IiJgoIVmlld0luZm8SDAoEc2x1ZxgBIAEoCRIMCgRuYW1lGAIgASgJIocBChRHZXRQbGF5ZXJSYW5rUmVxdWVzdBIWCg5sZWFkZXJib2FyZF9pZBgBIAEoCRIRCglwbGF5ZXJfaWQYAiABKAkSEwoGcGVyaW9kGAMgASgJSACIAQESFgoJdmlld19zbHVnGAQgASgJSAGIAQFCCQoHX3BlcmlvZEIMCgpfdmlld19zbHVnIssCChVHZXRQbGF5ZXJSYW5rUmVzcG9uc2USEQoEcmFuaxgBIAEoBUgAiAEBEhIKBXNjb3JlGAIgASgDSAGIAQESFwoKYmVzdF9zY29yZRgDIAEoA0gCiAEBEhUKDXRvdGFsX2VudHJpZXMYBCABKAUSFwoKcGVyY2VudGlsZRgFIAEoCUgDiAEBEisKB2JyYWNrZXQYBiABKAsyFS5hc2NuZC52MS5CcmFja2V0SW5mb0gEiAEBEiUKBHZpZXcYByABKAsyEi5hc2NuZC52MS5WaWV3SW5mb0gFiAEBEhgKC2dsb2JhbF9yYW5rGAggASgFSAaIAQFCBwoFX3JhbmtCCAoGX3Njb3JlQg0KC19iZXN0X3Njb3JlQg0KC19wZXJjZW50aWxlQgoKCF9icmFja2V0QgcKBV92aWV3Qg4KDF9nbG9iYWxfcmFuazKBAgoMQXNjbmRTZXJ2aWNlEkoKC1N1Ym1pdFNjb3JlEhwuYXNjbmQudjEuU3VibWl0U2NvcmVSZXF1ZXN0Gh0uYXNjbmQudjEuU3VibWl0U2NvcmVSZXNwb25zZRJTCg5HZXRMZWFkZXJib2FyZBIfLmFzY25kLnYxLkdldExlYWRlcmJvYXJkUmVxdWVzdBogLmFzY25kLnYxLkdldExlYWRlcmJvYXJkUmVzcG9uc2USUAoNR2V0UGxheWVyUmFuaxIeLmFzY25kLnYxLkdldFBsYXllclJhbmtSZXF1ZXN0Gh8uYXNjbmQudjEuR2V0UGxheWVyUmFua1Jlc3BvbnNlYgZwcm90bzM");
48
48
  var SubmitScoreRequestSchema = /* @__PURE__ */ (0, import_codegenv2.messageDesc)(file_ascnd, 0);
49
49
  var SubmitScoreResponseSchema = /* @__PURE__ */ (0, import_codegenv2.messageDesc)(file_ascnd, 1);
50
50
  var AnticheatResultSchema = /* @__PURE__ */ (0, import_codegenv2.messageDesc)(file_ascnd, 2);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/gen/ascnd_pb.ts","../src/types.ts"],"sourcesContent":["/**\n * @ascnd-gg/client - TypeScript/JavaScript client for the Ascnd leaderboard API.\n *\n * @example\n * ```typescript\n * import { AscndClient, create, SubmitScoreRequestSchema } from \"@ascnd-gg/client\";\n *\n * const client = new AscndClient({\n * baseUrl: \"https://api.ascnd.gg\",\n * apiKey: \"your-api-key\",\n * });\n *\n * // Submit a score\n * const result = await client.submitScore(\n * create(SubmitScoreRequestSchema, {\n * leaderboardId: \"high-scores\",\n * playerId: \"player-123\",\n * score: 1000n,\n * })\n * );\n *\n * console.log(`New rank: ${result.rank}`);\n * ```\n *\n * @packageDocumentation\n */\n\n// Export the main client class\nexport { AscndClient } from \"./client.js\";\n\n// Re-export create helper from protobuf for convenience\nexport { create } from \"@bufbuild/protobuf\";\n\n// Export all types\nexport type {\n // Client configuration\n AscndClientConfig,\n\n // Submit Score\n SubmitScoreRequest,\n SubmitScoreResponse,\n\n // Get Leaderboard\n GetLeaderboardRequest,\n GetLeaderboardResponse,\n LeaderboardEntry,\n\n // Get Player Rank\n GetPlayerRankRequest,\n GetPlayerRankResponse,\n\n // Anticheat\n AnticheatResult,\n AnticheatViolation,\n\n // Bracket\n BracketInfo,\n\n // View\n ViewInfo,\n} from \"./types.js\";\n\n// Export error class\nexport { AscndError } from \"./types.js\";\n\n// Export the service definition\nexport { AscndService } from \"./types.js\";\n\n// Export schemas for creating messages\nexport {\n SubmitScoreRequestSchema,\n SubmitScoreResponseSchema,\n GetLeaderboardRequestSchema,\n GetLeaderboardResponseSchema,\n GetPlayerRankRequestSchema,\n GetPlayerRankResponseSchema,\n LeaderboardEntrySchema,\n AnticheatResultSchema,\n AnticheatViolationSchema,\n BracketInfoSchema,\n ViewInfoSchema,\n} from \"./types.js\";\n","import { createClient, type Client, type Interceptor, ConnectError } from \"@connectrpc/connect\";\nimport { createGrpcWebTransport } from \"@connectrpc/connect-web\";\nimport {\n AscndService,\n type SubmitScoreRequest,\n type SubmitScoreResponse,\n type GetLeaderboardRequest,\n type GetLeaderboardResponse,\n type GetPlayerRankRequest,\n type GetPlayerRankResponse,\n AscndClientConfig,\n AscndError,\n} from \"./types.js\";\n\n/**\n * Client for the Ascnd leaderboard API using gRPC-Web.\n *\n * @example\n * ```typescript\n * import { AscndClient, create } from \"@ascnd-gg/client\";\n * import { SubmitScoreRequestSchema } from \"@ascnd-gg/client\";\n *\n * const client = new AscndClient({\n * baseUrl: \"https://api.ascnd.gg\",\n * apiKey: \"your-api-key\",\n * });\n *\n * // Submit a score\n * const result = await client.submitScore(\n * create(SubmitScoreRequestSchema, {\n * leaderboardId: \"high-scores\",\n * playerId: \"player-123\",\n * score: 1000n,\n * })\n * );\n *\n * console.log(`Rank: #${result.rank}`);\n * ```\n */\nexport class AscndClient {\n private readonly client: Client<typeof AscndService>;\n\n /**\n * Creates a new Ascnd client.\n *\n * @param config - Client configuration options.\n */\n constructor(config: AscndClientConfig) {\n if (!config.baseUrl) {\n throw new Error(\"baseUrl is required\");\n }\n if (!config.apiKey) {\n throw new Error(\"apiKey is required\");\n }\n\n // Create an interceptor to add the API key header\n const authInterceptor: Interceptor = (next) => async (req) => {\n req.header.set(\"x-api-key\", config.apiKey);\n return await next(req);\n };\n\n // Create the gRPC-Web transport\n const transport = createGrpcWebTransport({\n baseUrl: config.baseUrl.replace(/\\/$/, \"\"),\n interceptors: [authInterceptor],\n defaultTimeoutMs: config.timeout ?? 30000,\n });\n\n this.client = createClient(AscndService, transport);\n }\n\n /**\n * Submits a player's score to a leaderboard.\n *\n * @param request - The score submission request.\n * @returns The submission result including the player's new rank.\n * @throws {AscndError} If the API returns an error.\n *\n * @example\n * ```typescript\n * import { create } from \"@bufbuild/protobuf\";\n * import { SubmitScoreRequestSchema } from \"@ascnd-gg/client\";\n *\n * const result = await client.submitScore(\n * create(SubmitScoreRequestSchema, {\n * leaderboardId: \"high-scores\",\n * playerId: \"player-123\",\n * score: 1000n,\n * metadata: new TextEncoder().encode(JSON.stringify({ level: 5 })),\n * })\n * );\n *\n * console.log(`New rank: ${result.rank}`);\n * if (result.isNewBest) {\n * console.log(\"New personal best!\");\n * }\n * if (result.anticheat && !result.anticheat.passed) {\n * console.log(\"Anticheat flagged:\", result.anticheat.violations);\n * }\n * ```\n */\n async submitScore(request: SubmitScoreRequest): Promise<SubmitScoreResponse> {\n try {\n return await this.client.submitScore(request);\n } catch (error) {\n throw this.convertError(error);\n }\n }\n\n /**\n * Retrieves the top scores for a leaderboard.\n *\n * @param request - The leaderboard request parameters.\n * @returns The leaderboard entries and pagination info.\n * @throws {AscndError} If the API returns an error.\n *\n * @example\n * ```typescript\n * import { create } from \"@bufbuild/protobuf\";\n * import { GetLeaderboardRequestSchema } from \"@ascnd-gg/client\";\n *\n * const leaderboard = await client.getLeaderboard(\n * create(GetLeaderboardRequestSchema, {\n * leaderboardId: \"high-scores\",\n * limit: 10,\n * viewSlug: \"platform-pc\", // Filter by metadata view\n * })\n * );\n *\n * for (const entry of leaderboard.entries) {\n * console.log(`#${entry.rank}: ${entry.playerId} - ${entry.score}`);\n * if (entry.bracket) {\n * console.log(` Bracket: ${entry.bracket.name}`);\n * }\n * }\n * ```\n */\n async getLeaderboard(\n request: GetLeaderboardRequest\n ): Promise<GetLeaderboardResponse> {\n try {\n return await this.client.getLeaderboard(request);\n } catch (error) {\n throw this.convertError(error);\n }\n }\n\n /**\n * Retrieves a specific player's rank and score information.\n *\n * @param request - The player rank request parameters.\n * @returns The player's rank, score, and percentile information.\n * @throws {AscndError} If the API returns an error.\n *\n * @example\n * ```typescript\n * import { create } from \"@bufbuild/protobuf\";\n * import { GetPlayerRankRequestSchema } from \"@ascnd-gg/client\";\n *\n * const playerRank = await client.getPlayerRank(\n * create(GetPlayerRankRequestSchema, {\n * leaderboardId: \"high-scores\",\n * playerId: \"player-123\",\n * viewSlug: \"platform-pc\",\n * })\n * );\n *\n * if (playerRank.rank !== undefined) {\n * console.log(`Rank: #${playerRank.rank}`);\n * console.log(`Score: ${playerRank.score}`);\n * console.log(`Percentile: ${playerRank.percentile}`);\n * if (playerRank.bracket) {\n * console.log(`Bracket: ${playerRank.bracket.name}`);\n * }\n * if (playerRank.globalRank !== undefined) {\n * console.log(`Global Rank: #${playerRank.globalRank}`);\n * }\n * } else {\n * console.log(\"Player not on leaderboard\");\n * }\n * ```\n */\n async getPlayerRank(\n request: GetPlayerRankRequest\n ): Promise<GetPlayerRankResponse> {\n try {\n return await this.client.getPlayerRank(request);\n } catch (error) {\n throw this.convertError(error);\n }\n }\n\n /**\n * Converts a Connect error to an AscndError.\n */\n private convertError(error: unknown): AscndError {\n if (error instanceof ConnectError) {\n return new AscndError(\n error.message,\n error.code.toString(),\n error.details?.length ? { details: error.details } : undefined\n );\n }\n if (error instanceof Error) {\n return new AscndError(error.message, \"UNKNOWN\");\n }\n return new AscndError(\"Unknown error occurred\", \"UNKNOWN\");\n }\n}\n","// @generated by protoc-gen-es v2.10.2 with parameter \"target=ts\"\n// @generated from file ascnd.proto (package ascnd.v1, syntax proto3)\n/* eslint-disable */\n\nimport type { GenFile, GenMessage, GenService } from \"@bufbuild/protobuf/codegenv2\";\nimport { fileDesc, messageDesc, serviceDesc } from \"@bufbuild/protobuf/codegenv2\";\nimport type { Message } from \"@bufbuild/protobuf\";\n\n/**\n * Describes the file ascnd.proto.\n */\nexport const file_ascnd: GenFile = /*@__PURE__*/\n fileDesc(\"Cgthc2NuZC5wcm90bxIIYXNjbmQudjEipAEKElN1Ym1pdFNjb3JlUmVxdWVzdBIWCg5sZWFkZXJib2FyZF9pZBgBIAEoCRIRCglwbGF5ZXJfaWQYAiABKAkSDQoFc2NvcmUYAyABKAMSFQoIbWV0YWRhdGEYBCABKAxIAIgBARIcCg9pZGVtcG90ZW5jeV9rZXkYBSABKAlIAYgBAUILCglfbWV0YWRhdGFCEgoQX2lkZW1wb3RlbmN5X2tleSKlAQoTU3VibWl0U2NvcmVSZXNwb25zZRIQCghzY29yZV9pZBgBIAEoCRIMCgRyYW5rGAIgASgFEhMKC2lzX25ld19iZXN0GAMgASgIEhgKEHdhc19kZWR1cGxpY2F0ZWQYBCABKAgSMQoJYW50aWNoZWF0GAUgASgLMhkuYXNjbmQudjEuQW50aWNoZWF0UmVzdWx0SACIAQFCDAoKX2FudGljaGVhdCJjCg9BbnRpY2hlYXRSZXN1bHQSDgoGcGFzc2VkGAEgASgIEjAKCnZpb2xhdGlvbnMYAiADKAsyHC5hc2NuZC52MS5BbnRpY2hlYXRWaW9sYXRpb24SDgoGYWN0aW9uGAMgASgJIjcKEkFudGljaGVhdFZpb2xhdGlvbhIRCglmbGFnX3R5cGUYASABKAkSDgoGcmVhc29uGAIgASgJIrMBChVHZXRMZWFkZXJib2FyZFJlcXVlc3QSFgoObGVhZGVyYm9hcmRfaWQYASABKAkSEgoFbGltaXQYAiABKAVIAIgBARITCgZvZmZzZXQYAyABKAVIAYgBARITCgZwZXJpb2QYBCABKAlIAogBARIWCgl2aWV3X3NsdWcYBSABKAlIA4gBAUIICgZfbGltaXRCCQoHX29mZnNldEIJCgdfcGVyaW9kQgwKCl92aWV3X3NsdWci3AEKFkdldExlYWRlcmJvYXJkUmVzcG9uc2USKwoHZW50cmllcxgBIAMoCzIaLmFzY25kLnYxLkxlYWRlcmJvYXJkRW50cnkSFQoNdG90YWxfZW50cmllcxgCIAEoBRIQCghoYXNfbW9yZRgDIAEoCBIUCgxwZXJpb2Rfc3RhcnQYBCABKAkSFwoKcGVyaW9kX2VuZBgFIAEoCUgAiAEBEiUKBHZpZXcYBiABKAsyEi5hc2NuZC52MS5WaWV3SW5mb0gBiAEBQg0KC19wZXJpb2RfZW5kQgcKBV92aWV3IrUBChBMZWFkZXJib2FyZEVudHJ5EgwKBHJhbmsYASABKAUSEQoJcGxheWVyX2lkGAIgASgJEg0KBXNjb3JlGAMgASgDEhQKDHN1Ym1pdHRlZF9hdBgEIAEoCRIVCghtZXRhZGF0YRgFIAEoDEgAiAEBEisKB2JyYWNrZXQYBiABKAsyFS5hc2NuZC52MS5CcmFja2V0SW5mb0gBiAEBQgsKCV9tZXRhZGF0YUIKCghfYnJhY2tldCJFCgtCcmFja2V0SW5mbxIKCgJpZBgBIAEoCRIMCgRuYW1lGAIgASgJEhIKBWNvbG9yGAMgASgJSACIAQFCCAoGX2NvbG9yIiYKCFZpZXdJbmZvEgwKBHNsdWcYASABKAkSDAoEbmFtZRgCIAEoCSKHAQoUR2V0UGxheWVyUmFua1JlcXVlc3QSFgoObGVhZGVyYm9hcmRfaWQYASABKAkSEQoJcGxheWVyX2lkGAIgASgJEhMKBnBlcmlvZBgDIAEoCUgAiAEBEhYKCXZpZXdfc2x1ZxgEIAEoCUgBiAEBQgkKB19wZXJpb2RCDAoKX3ZpZXdfc2x1ZyLLAgoVR2V0UGxheWVyUmFua1Jlc3BvbnNlEhEKBHJhbmsYASABKAVIAIgBARISCgVzY29yZRgCIAEoA0gBiAEBEhcKCmJlc3Rfc2NvcmUYAyABKANIAogBARIVCg10b3RhbF9lbnRyaWVzGAQgASgFEhcKCnBlcmNlbnRpbGUYBSABKAlIA4gBARIrCgdicmFja2V0GAYgASgLMhUuYXNjbmQudjEuQnJhY2tldEluZm9IBIgBARIlCgR2aWV3GAcgASgLMhIuYXNjbmQudjEuVmlld0luZm9IBYgBARIYCgtnbG9iYWxfcmFuaxgIIAEoBUgGiAEBQgcKBV9yYW5rQggKBl9zY29yZUINCgtfYmVzdF9zY29yZUINCgtfcGVyY2VudGlsZUIKCghfYnJhY2tldEIHCgVfdmlld0IOCgxfZ2xvYmFsX3JhbmsygQIKDEFzY25kU2VydmljZRJKCgtTdWJtaXRTY29yZRIcLmFzY25kLnYxLlN1Ym1pdFNjb3JlUmVxdWVzdBodLmFzY25kLnYxLlN1Ym1pdFNjb3JlUmVzcG9uc2USUwoOR2V0TGVhZGVyYm9hcmQSHy5hc2NuZC52MS5HZXRMZWFkZXJib2FyZFJlcXVlc3QaIC5hc2NuZC52MS5HZXRMZWFkZXJib2FyZFJlc3BvbnNlElAKDUdldFBsYXllclJhbmsSHi5hc2NuZC52MS5HZXRQbGF5ZXJSYW5rUmVxdWVzdBofLmFzY25kLnYxLkdldFBsYXllclJhbmtSZXNwb25zZWIGcHJvdG8z\");\n\n/**\n * SubmitScoreRequest contains the score submission details.\n *\n * @generated from message ascnd.v1.SubmitScoreRequest\n */\nexport type SubmitScoreRequest = Message<\"ascnd.v1.SubmitScoreRequest\"> & {\n /**\n * The leaderboard to submit the score to.\n *\n * @generated from field: string leaderboard_id = 1;\n */\n leaderboardId: string;\n\n /**\n * The player's unique identifier (provided by the game).\n *\n * @generated from field: string player_id = 2;\n */\n playerId: string;\n\n /**\n * The score value.\n *\n * @generated from field: int64 score = 3;\n */\n score: bigint;\n\n /**\n * Optional metadata (JSON-encoded game-specific data).\n *\n * @generated from field: optional bytes metadata = 4;\n */\n metadata?: Uint8Array;\n\n /**\n * Optional idempotency key to prevent duplicate submissions.\n *\n * @generated from field: optional string idempotency_key = 5;\n */\n idempotencyKey?: string;\n};\n\n/**\n * Describes the message ascnd.v1.SubmitScoreRequest.\n * Use `create(SubmitScoreRequestSchema)` to create a new message.\n */\nexport const SubmitScoreRequestSchema: GenMessage<SubmitScoreRequest> = /*@__PURE__*/\n messageDesc(file_ascnd, 0);\n\n/**\n * SubmitScoreResponse contains the result of the score submission.\n *\n * @generated from message ascnd.v1.SubmitScoreResponse\n */\nexport type SubmitScoreResponse = Message<\"ascnd.v1.SubmitScoreResponse\"> & {\n /**\n * The unique identifier of the submitted score.\n *\n * @generated from field: string score_id = 1;\n */\n scoreId: string;\n\n /**\n * The player's rank after this submission.\n *\n * @generated from field: int32 rank = 2;\n */\n rank: number;\n\n /**\n * Whether this is the player's new best score for this period.\n *\n * @generated from field: bool is_new_best = 3;\n */\n isNewBest: boolean;\n\n /**\n * Whether the score was deduplicated (already submitted recently).\n *\n * @generated from field: bool was_deduplicated = 4;\n */\n wasDeduplicated: boolean;\n\n /**\n * Anticheat validation result (if anticheat is enabled for this leaderboard).\n *\n * @generated from field: optional ascnd.v1.AnticheatResult anticheat = 5;\n */\n anticheat?: AnticheatResult;\n};\n\n/**\n * Describes the message ascnd.v1.SubmitScoreResponse.\n * Use `create(SubmitScoreResponseSchema)` to create a new message.\n */\nexport const SubmitScoreResponseSchema: GenMessage<SubmitScoreResponse> = /*@__PURE__*/\n messageDesc(file_ascnd, 1);\n\n/**\n * AnticheatResult contains the result of anticheat validation.\n *\n * @generated from message ascnd.v1.AnticheatResult\n */\nexport type AnticheatResult = Message<\"ascnd.v1.AnticheatResult\"> & {\n /**\n * Whether the score passed all anticheat checks.\n *\n * @generated from field: bool passed = 1;\n */\n passed: boolean;\n\n /**\n * List of violation flags that were triggered.\n *\n * @generated from field: repeated ascnd.v1.AnticheatViolation violations = 2;\n */\n violations: AnticheatViolation[];\n\n /**\n * The enforcement action taken: \"none\", \"flag\", \"shadow_ban\", or \"reject\".\n *\n * @generated from field: string action = 3;\n */\n action: string;\n};\n\n/**\n * Describes the message ascnd.v1.AnticheatResult.\n * Use `create(AnticheatResultSchema)` to create a new message.\n */\nexport const AnticheatResultSchema: GenMessage<AnticheatResult> = /*@__PURE__*/\n messageDesc(file_ascnd, 2);\n\n/**\n * AnticheatViolation describes a single anticheat rule violation.\n *\n * @generated from message ascnd.v1.AnticheatViolation\n */\nexport type AnticheatViolation = Message<\"ascnd.v1.AnticheatViolation\"> & {\n /**\n * The type of violation: \"bounds_exceeded\", \"velocity_exceeded\",\n * \"duplicate_idempotency\", \"missing_idempotency_key\".\n *\n * @generated from field: string flag_type = 1;\n */\n flagType: string;\n\n /**\n * Human-readable description of the violation.\n *\n * @generated from field: string reason = 2;\n */\n reason: string;\n};\n\n/**\n * Describes the message ascnd.v1.AnticheatViolation.\n * Use `create(AnticheatViolationSchema)` to create a new message.\n */\nexport const AnticheatViolationSchema: GenMessage<AnticheatViolation> = /*@__PURE__*/\n messageDesc(file_ascnd, 3);\n\n/**\n * GetLeaderboardRequest specifies which leaderboard and page to retrieve.\n *\n * @generated from message ascnd.v1.GetLeaderboardRequest\n */\nexport type GetLeaderboardRequest = Message<\"ascnd.v1.GetLeaderboardRequest\"> & {\n /**\n * The leaderboard to retrieve.\n *\n * @generated from field: string leaderboard_id = 1;\n */\n leaderboardId: string;\n\n /**\n * Maximum number of entries to return (default: 10, max: 100).\n *\n * @generated from field: optional int32 limit = 2;\n */\n limit?: number;\n\n /**\n * Number of entries to skip for pagination.\n *\n * @generated from field: optional int32 offset = 3;\n */\n offset?: number;\n\n /**\n * Which period to retrieve: \"current\", \"previous\", or a timestamp.\n *\n * @generated from field: optional string period = 4;\n */\n period?: string;\n\n /**\n * Optional view slug to filter by metadata criteria.\n * If provided, returns rankings within the view (not global rank).\n *\n * @generated from field: optional string view_slug = 5;\n */\n viewSlug?: string;\n};\n\n/**\n * Describes the message ascnd.v1.GetLeaderboardRequest.\n * Use `create(GetLeaderboardRequestSchema)` to create a new message.\n */\nexport const GetLeaderboardRequestSchema: GenMessage<GetLeaderboardRequest> = /*@__PURE__*/\n messageDesc(file_ascnd, 4);\n\n/**\n * GetLeaderboardResponse contains the leaderboard entries.\n *\n * @generated from message ascnd.v1.GetLeaderboardResponse\n */\nexport type GetLeaderboardResponse = Message<\"ascnd.v1.GetLeaderboardResponse\"> & {\n /**\n * The leaderboard entries.\n *\n * @generated from field: repeated ascnd.v1.LeaderboardEntry entries = 1;\n */\n entries: LeaderboardEntry[];\n\n /**\n * Approximate total number of entries.\n *\n * @generated from field: int32 total_entries = 2;\n */\n totalEntries: number;\n\n /**\n * Whether there are more entries after this page.\n *\n * @generated from field: bool has_more = 3;\n */\n hasMore: boolean;\n\n /**\n * The start of the current period (ISO 8601 timestamp).\n *\n * @generated from field: string period_start = 4;\n */\n periodStart: string;\n\n /**\n * The end of the current period, if applicable (ISO 8601 timestamp).\n *\n * @generated from field: optional string period_end = 5;\n */\n periodEnd?: string;\n\n /**\n * Active view info if filtering by view_slug.\n *\n * @generated from field: optional ascnd.v1.ViewInfo view = 6;\n */\n view?: ViewInfo;\n};\n\n/**\n * Describes the message ascnd.v1.GetLeaderboardResponse.\n * Use `create(GetLeaderboardResponseSchema)` to create a new message.\n */\nexport const GetLeaderboardResponseSchema: GenMessage<GetLeaderboardResponse> = /*@__PURE__*/\n messageDesc(file_ascnd, 5);\n\n/**\n * LeaderboardEntry represents a single entry on the leaderboard.\n *\n * @generated from message ascnd.v1.LeaderboardEntry\n */\nexport type LeaderboardEntry = Message<\"ascnd.v1.LeaderboardEntry\"> & {\n /**\n * The player's rank (1-indexed).\n *\n * @generated from field: int32 rank = 1;\n */\n rank: number;\n\n /**\n * The player's unique identifier.\n *\n * @generated from field: string player_id = 2;\n */\n playerId: string;\n\n /**\n * The player's score.\n *\n * @generated from field: int64 score = 3;\n */\n score: bigint;\n\n /**\n * When the score was submitted (ISO 8601 timestamp).\n *\n * @generated from field: string submitted_at = 4;\n */\n submittedAt: string;\n\n /**\n * Optional metadata associated with the score.\n *\n * @generated from field: optional bytes metadata = 5;\n */\n metadata?: Uint8Array;\n\n /**\n * Optional bracket assignment for this player.\n *\n * @generated from field: optional ascnd.v1.BracketInfo bracket = 6;\n */\n bracket?: BracketInfo;\n};\n\n/**\n * Describes the message ascnd.v1.LeaderboardEntry.\n * Use `create(LeaderboardEntrySchema)` to create a new message.\n */\nexport const LeaderboardEntrySchema: GenMessage<LeaderboardEntry> = /*@__PURE__*/\n messageDesc(file_ascnd, 6);\n\n/**\n * BracketInfo contains minimal bracket information.\n *\n * @generated from message ascnd.v1.BracketInfo\n */\nexport type BracketInfo = Message<\"ascnd.v1.BracketInfo\"> & {\n /**\n * The bracket's unique identifier.\n *\n * @generated from field: string id = 1;\n */\n id: string;\n\n /**\n * The bracket's name (e.g., \"Gold\", \"Silver\", \"Bronze\").\n *\n * @generated from field: string name = 2;\n */\n name: string;\n\n /**\n * Optional hex color code (e.g., \"#FF5500\") for the bracket badge.\n *\n * @generated from field: optional string color = 3;\n */\n color?: string;\n};\n\n/**\n * Describes the message ascnd.v1.BracketInfo.\n * Use `create(BracketInfoSchema)` to create a new message.\n */\nexport const BracketInfoSchema: GenMessage<BracketInfo> = /*@__PURE__*/\n messageDesc(file_ascnd, 7);\n\n/**\n * ViewInfo contains minimal metadata view information.\n *\n * @generated from message ascnd.v1.ViewInfo\n */\nexport type ViewInfo = Message<\"ascnd.v1.ViewInfo\"> & {\n /**\n * The view's slug identifier.\n *\n * @generated from field: string slug = 1;\n */\n slug: string;\n\n /**\n * The view's display name.\n *\n * @generated from field: string name = 2;\n */\n name: string;\n};\n\n/**\n * Describes the message ascnd.v1.ViewInfo.\n * Use `create(ViewInfoSchema)` to create a new message.\n */\nexport const ViewInfoSchema: GenMessage<ViewInfo> = /*@__PURE__*/\n messageDesc(file_ascnd, 8);\n\n/**\n * GetPlayerRankRequest specifies which player and leaderboard to query.\n *\n * @generated from message ascnd.v1.GetPlayerRankRequest\n */\nexport type GetPlayerRankRequest = Message<\"ascnd.v1.GetPlayerRankRequest\"> & {\n /**\n * The leaderboard to query.\n *\n * @generated from field: string leaderboard_id = 1;\n */\n leaderboardId: string;\n\n /**\n * The player's unique identifier.\n *\n * @generated from field: string player_id = 2;\n */\n playerId: string;\n\n /**\n * Which period to query: \"current\", \"previous\", or a timestamp.\n *\n * @generated from field: optional string period = 3;\n */\n period?: string;\n\n /**\n * Optional view slug to get rank within a filtered view.\n *\n * @generated from field: optional string view_slug = 4;\n */\n viewSlug?: string;\n};\n\n/**\n * Describes the message ascnd.v1.GetPlayerRankRequest.\n * Use `create(GetPlayerRankRequestSchema)` to create a new message.\n */\nexport const GetPlayerRankRequestSchema: GenMessage<GetPlayerRankRequest> = /*@__PURE__*/\n messageDesc(file_ascnd, 9);\n\n/**\n * GetPlayerRankResponse contains the player's rank information.\n *\n * @generated from message ascnd.v1.GetPlayerRankResponse\n */\nexport type GetPlayerRankResponse = Message<\"ascnd.v1.GetPlayerRankResponse\"> & {\n /**\n * The player's rank (null if not on leaderboard).\n * When querying a view, this is the rank within the view.\n *\n * @generated from field: optional int32 rank = 1;\n */\n rank?: number;\n\n /**\n * The player's current score (null if not on leaderboard).\n *\n * @generated from field: optional int64 score = 2;\n */\n score?: bigint;\n\n /**\n * The player's best score this period.\n *\n * @generated from field: optional int64 best_score = 3;\n */\n bestScore?: bigint;\n\n /**\n * Total number of entries on this leaderboard (or view if filtered).\n *\n * @generated from field: int32 total_entries = 4;\n */\n totalEntries: number;\n\n /**\n * The player's percentile (e.g., \"top 5%\").\n *\n * @generated from field: optional string percentile = 5;\n */\n percentile?: string;\n\n /**\n * Optional bracket assignment for this player.\n *\n * @generated from field: optional ascnd.v1.BracketInfo bracket = 6;\n */\n bracket?: BracketInfo;\n\n /**\n * Active view info if querying with view_slug.\n *\n * @generated from field: optional ascnd.v1.ViewInfo view = 7;\n */\n view?: ViewInfo;\n\n /**\n * Global rank when querying a view (shows overall position).\n *\n * @generated from field: optional int32 global_rank = 8;\n */\n globalRank?: number;\n};\n\n/**\n * Describes the message ascnd.v1.GetPlayerRankResponse.\n * Use `create(GetPlayerRankResponseSchema)` to create a new message.\n */\nexport const GetPlayerRankResponseSchema: GenMessage<GetPlayerRankResponse> = /*@__PURE__*/\n messageDesc(file_ascnd, 10);\n\n/**\n * AscndService provides leaderboard management for games.\n *\n * @generated from service ascnd.v1.AscndService\n */\nexport const AscndService: GenService<{\n /**\n * SubmitScore records a player's score on a leaderboard.\n *\n * @generated from rpc ascnd.v1.AscndService.SubmitScore\n */\n submitScore: {\n methodKind: \"unary\";\n input: typeof SubmitScoreRequestSchema;\n output: typeof SubmitScoreResponseSchema;\n },\n /**\n * GetLeaderboard retrieves the top scores for a leaderboard.\n *\n * @generated from rpc ascnd.v1.AscndService.GetLeaderboard\n */\n getLeaderboard: {\n methodKind: \"unary\";\n input: typeof GetLeaderboardRequestSchema;\n output: typeof GetLeaderboardResponseSchema;\n },\n /**\n * GetPlayerRank retrieves a specific player's rank and score.\n *\n * @generated from rpc ascnd.v1.AscndService.GetPlayerRank\n */\n getPlayerRank: {\n methodKind: \"unary\";\n input: typeof GetPlayerRankRequestSchema;\n output: typeof GetPlayerRankResponseSchema;\n },\n}> = /*@__PURE__*/\n serviceDesc(file_ascnd, 0);\n\n","/**\n * TypeScript types for the Ascnd gRPC API.\n *\n * Types are generated from the proto file and re-exported here.\n */\n\n// Re-export all generated types\nexport type {\n SubmitScoreRequest,\n SubmitScoreResponse,\n GetLeaderboardRequest,\n GetLeaderboardResponse,\n GetPlayerRankRequest,\n GetPlayerRankResponse,\n LeaderboardEntry,\n AnticheatResult,\n AnticheatViolation,\n BracketInfo,\n ViewInfo,\n} from \"./gen/ascnd_pb.js\";\n\n// Re-export the service definition\nexport { AscndService } from \"./gen/ascnd_pb.js\";\n\n// Re-export schemas for creating messages\nexport {\n SubmitScoreRequestSchema,\n SubmitScoreResponseSchema,\n GetLeaderboardRequestSchema,\n GetLeaderboardResponseSchema,\n GetPlayerRankRequestSchema,\n GetPlayerRankResponseSchema,\n LeaderboardEntrySchema,\n AnticheatResultSchema,\n AnticheatViolationSchema,\n BracketInfoSchema,\n ViewInfoSchema,\n} from \"./gen/ascnd_pb.js\";\n\n// ============================================================================\n// Client Configuration\n// ============================================================================\n\n/**\n * Configuration options for the Ascnd client.\n */\nexport interface AscndClientConfig {\n /** The base URL of the Ascnd API (e.g., \"https://api.ascnd.gg\"). */\n baseUrl: string;\n\n /** Your API key for authentication. */\n apiKey: string;\n\n /** Optional request timeout in milliseconds (default: 30000). */\n timeout?: number;\n}\n\n// ============================================================================\n// Error Types\n// ============================================================================\n\n/**\n * Custom error class for Ascnd API errors.\n */\nexport class AscndError extends Error {\n /** gRPC/Connect error code. */\n readonly code: string;\n\n /** Additional error details. */\n readonly details?: Record<string, unknown>;\n\n constructor(\n message: string,\n code: string,\n details?: Record<string, unknown>\n ) {\n super(message);\n this.name = \"AscndError\";\n this.code = code;\n this.details = details;\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/gen/ascnd_pb.ts","../src/types.ts"],"sourcesContent":["/**\n * @ascnd-gg/client - TypeScript/JavaScript client for the Ascnd leaderboard API.\n *\n * @example\n * ```typescript\n * import { AscndClient, create, SubmitScoreRequestSchema } from \"@ascnd-gg/client\";\n *\n * const client = new AscndClient({\n * baseUrl: \"https://api.ascnd.gg\",\n * apiKey: \"your-api-key\",\n * });\n *\n * // Submit a score\n * const result = await client.submitScore(\n * create(SubmitScoreRequestSchema, {\n * leaderboardId: \"high-scores\",\n * playerId: \"player-123\",\n * score: 1000n,\n * })\n * );\n *\n * console.log(`New rank: ${result.rank}`);\n * ```\n *\n * @packageDocumentation\n */\n\n// Export the main client class\nexport { AscndClient } from \"./client.js\";\n\n// Re-export create helper from protobuf for convenience\nexport { create } from \"@bufbuild/protobuf\";\n\n// Export all types\nexport type {\n // Client configuration\n AscndClientConfig,\n\n // Submit Score\n SubmitScoreRequest,\n SubmitScoreResponse,\n\n // Get Leaderboard\n GetLeaderboardRequest,\n GetLeaderboardResponse,\n LeaderboardEntry,\n\n // Get Player Rank\n GetPlayerRankRequest,\n GetPlayerRankResponse,\n\n // Anticheat\n AnticheatResult,\n AnticheatViolation,\n\n // Bracket\n BracketInfo,\n\n // View\n ViewInfo,\n} from \"./types.js\";\n\n// Export error class\nexport { AscndError } from \"./types.js\";\n\n// Export the service definition\nexport { AscndService } from \"./types.js\";\n\n// Export schemas for creating messages\nexport {\n SubmitScoreRequestSchema,\n SubmitScoreResponseSchema,\n GetLeaderboardRequestSchema,\n GetLeaderboardResponseSchema,\n GetPlayerRankRequestSchema,\n GetPlayerRankResponseSchema,\n LeaderboardEntrySchema,\n AnticheatResultSchema,\n AnticheatViolationSchema,\n BracketInfoSchema,\n ViewInfoSchema,\n} from \"./types.js\";\n","import { createClient, type Client, type Interceptor, ConnectError } from \"@connectrpc/connect\";\nimport { createGrpcWebTransport } from \"@connectrpc/connect-web\";\nimport {\n AscndService,\n type SubmitScoreRequest,\n type SubmitScoreResponse,\n type GetLeaderboardRequest,\n type GetLeaderboardResponse,\n type GetPlayerRankRequest,\n type GetPlayerRankResponse,\n AscndClientConfig,\n AscndError,\n} from \"./types.js\";\n\n/**\n * Client for the Ascnd leaderboard API using gRPC-Web.\n *\n * @example\n * ```typescript\n * import { AscndClient, create } from \"@ascnd-gg/client\";\n * import { SubmitScoreRequestSchema } from \"@ascnd-gg/client\";\n *\n * const client = new AscndClient({\n * baseUrl: \"https://api.ascnd.gg\",\n * apiKey: \"your-api-key\",\n * });\n *\n * // Submit a score\n * const result = await client.submitScore(\n * create(SubmitScoreRequestSchema, {\n * leaderboardId: \"high-scores\",\n * playerId: \"player-123\",\n * score: 1000n,\n * })\n * );\n *\n * console.log(`Rank: #${result.rank}`);\n * ```\n */\nexport class AscndClient {\n private readonly client: Client<typeof AscndService>;\n\n /**\n * Creates a new Ascnd client.\n *\n * @param config - Client configuration options.\n */\n constructor(config: AscndClientConfig) {\n if (!config.baseUrl) {\n throw new Error(\"baseUrl is required\");\n }\n if (!config.apiKey) {\n throw new Error(\"apiKey is required\");\n }\n\n // Create an interceptor to add the API key header\n const authInterceptor: Interceptor = (next) => async (req) => {\n req.header.set(\"x-api-key\", config.apiKey);\n return await next(req);\n };\n\n // Create the gRPC-Web transport\n const transport = createGrpcWebTransport({\n baseUrl: config.baseUrl.replace(/\\/$/, \"\"),\n interceptors: [authInterceptor],\n defaultTimeoutMs: config.timeout ?? 30000,\n });\n\n this.client = createClient(AscndService, transport);\n }\n\n /**\n * Submits a player's score to a leaderboard.\n *\n * @param request - The score submission request.\n * @returns The submission result including the player's new rank.\n * @throws {AscndError} If the API returns an error.\n *\n * @example\n * ```typescript\n * import { create } from \"@bufbuild/protobuf\";\n * import { SubmitScoreRequestSchema } from \"@ascnd-gg/client\";\n *\n * const result = await client.submitScore(\n * create(SubmitScoreRequestSchema, {\n * leaderboardId: \"high-scores\",\n * playerId: \"player-123\",\n * score: 1000n,\n * metadata: new TextEncoder().encode(JSON.stringify({ level: 5 })),\n * })\n * );\n *\n * console.log(`New rank: ${result.rank}`);\n * if (result.isNewBest) {\n * console.log(\"New personal best!\");\n * }\n * if (result.anticheat && !result.anticheat.passed) {\n * console.log(\"Anticheat flagged:\", result.anticheat.violations);\n * }\n * ```\n */\n async submitScore(request: SubmitScoreRequest): Promise<SubmitScoreResponse> {\n try {\n return await this.client.submitScore(request);\n } catch (error) {\n throw this.convertError(error);\n }\n }\n\n /**\n * Retrieves the top scores for a leaderboard.\n *\n * @param request - The leaderboard request parameters.\n * @returns The leaderboard entries and pagination info.\n * @throws {AscndError} If the API returns an error.\n *\n * @example\n * ```typescript\n * import { create } from \"@bufbuild/protobuf\";\n * import { GetLeaderboardRequestSchema } from \"@ascnd-gg/client\";\n *\n * const leaderboard = await client.getLeaderboard(\n * create(GetLeaderboardRequestSchema, {\n * leaderboardId: \"high-scores\",\n * limit: 10,\n * viewSlug: \"platform-pc\", // Filter by metadata view\n * })\n * );\n *\n * for (const entry of leaderboard.entries) {\n * console.log(`#${entry.rank}: ${entry.playerId} - ${entry.score}`);\n * if (entry.bracket) {\n * console.log(` Bracket: ${entry.bracket.name}`);\n * }\n * }\n * ```\n */\n async getLeaderboard(\n request: GetLeaderboardRequest\n ): Promise<GetLeaderboardResponse> {\n try {\n return await this.client.getLeaderboard(request);\n } catch (error) {\n throw this.convertError(error);\n }\n }\n\n /**\n * Retrieves a specific player's rank and score information.\n *\n * @param request - The player rank request parameters.\n * @returns The player's rank, score, and percentile information.\n * @throws {AscndError} If the API returns an error.\n *\n * @example\n * ```typescript\n * import { create } from \"@bufbuild/protobuf\";\n * import { GetPlayerRankRequestSchema } from \"@ascnd-gg/client\";\n *\n * const playerRank = await client.getPlayerRank(\n * create(GetPlayerRankRequestSchema, {\n * leaderboardId: \"high-scores\",\n * playerId: \"player-123\",\n * viewSlug: \"platform-pc\",\n * })\n * );\n *\n * if (playerRank.rank !== undefined) {\n * console.log(`Rank: #${playerRank.rank}`);\n * console.log(`Score: ${playerRank.score}`);\n * console.log(`Percentile: ${playerRank.percentile}`);\n * if (playerRank.bracket) {\n * console.log(`Bracket: ${playerRank.bracket.name}`);\n * }\n * if (playerRank.globalRank !== undefined) {\n * console.log(`Global Rank: #${playerRank.globalRank}`);\n * }\n * } else {\n * console.log(\"Player not on leaderboard\");\n * }\n * ```\n */\n async getPlayerRank(\n request: GetPlayerRankRequest\n ): Promise<GetPlayerRankResponse> {\n try {\n return await this.client.getPlayerRank(request);\n } catch (error) {\n throw this.convertError(error);\n }\n }\n\n /**\n * Converts a Connect error to an AscndError.\n */\n private convertError(error: unknown): AscndError {\n if (error instanceof ConnectError) {\n return new AscndError(\n error.message,\n error.code.toString(),\n error.details?.length ? { details: error.details } : undefined\n );\n }\n if (error instanceof Error) {\n return new AscndError(error.message, \"UNKNOWN\");\n }\n return new AscndError(\"Unknown error occurred\", \"UNKNOWN\");\n }\n}\n","// @generated by protoc-gen-es v2.10.2 with parameter \"target=ts\"\n// @generated from file ascnd.proto (package ascnd.v1, syntax proto3)\n/* eslint-disable */\n\nimport type { GenFile, GenMessage, GenService } from \"@bufbuild/protobuf/codegenv2\";\nimport { fileDesc, messageDesc, serviceDesc } from \"@bufbuild/protobuf/codegenv2\";\nimport type { Message } from \"@bufbuild/protobuf\";\n\n/**\n * Describes the file ascnd.proto.\n */\nexport const file_ascnd: GenFile = /*@__PURE__*/\n fileDesc(\"Cgthc2NuZC5wcm90bxIIYXNjbmQudjEipAEKElN1Ym1pdFNjb3JlUmVxdWVzdBIWCg5sZWFkZXJib2FyZF9pZBgBIAEoCRIRCglwbGF5ZXJfaWQYAiABKAkSDQoFc2NvcmUYAyABKAMSFQoIbWV0YWRhdGEYBCABKAxIAIgBARIcCg9pZGVtcG90ZW5jeV9rZXkYBSABKAlIAYgBAUILCglfbWV0YWRhdGFCEgoQX2lkZW1wb3RlbmN5X2tleSKlAQoTU3VibWl0U2NvcmVSZXNwb25zZRIQCghzY29yZV9pZBgBIAEoCRIMCgRyYW5rGAIgASgFEhMKC2lzX25ld19iZXN0GAMgASgIEhgKEHdhc19kZWR1cGxpY2F0ZWQYBCABKAgSMQoJYW50aWNoZWF0GAUgASgLMhkuYXNjbmQudjEuQW50aWNoZWF0UmVzdWx0SACIAQFCDAoKX2FudGljaGVhdCJjCg9BbnRpY2hlYXRSZXN1bHQSDgoGcGFzc2VkGAEgASgIEjAKCnZpb2xhdGlvbnMYAiADKAsyHC5hc2NuZC52MS5BbnRpY2hlYXRWaW9sYXRpb24SDgoGYWN0aW9uGAMgASgJIjcKEkFudGljaGVhdFZpb2xhdGlvbhIRCglmbGFnX3R5cGUYASABKAkSDgoGcmVhc29uGAIgASgJIusBChVHZXRMZWFkZXJib2FyZFJlcXVlc3QSFgoObGVhZGVyYm9hcmRfaWQYASABKAkSEgoFbGltaXQYAiABKAVIAIgBARITCgZwZXJpb2QYBCABKAlIAYgBARIWCgl2aWV3X3NsdWcYBSABKAlIAogBARITCgZjdXJzb3IYBiABKAlIA4gBARIYCgthcm91bmRfcmFuaxgHIAEoBUgEiAEBQggKBl9saW1pdEIJCgdfcGVyaW9kQgwKCl92aWV3X3NsdWdCCQoHX2N1cnNvckIOCgxfYXJvdW5kX3JhbmtKBAgDEARSBm9mZnNldCKGAgoWR2V0TGVhZGVyYm9hcmRSZXNwb25zZRIrCgdlbnRyaWVzGAEgAygLMhouYXNjbmQudjEuTGVhZGVyYm9hcmRFbnRyeRIVCg10b3RhbF9lbnRyaWVzGAIgASgFEhAKCGhhc19tb3JlGAMgASgIEhQKDHBlcmlvZF9zdGFydBgEIAEoCRIXCgpwZXJpb2RfZW5kGAUgASgJSACIAQESJQoEdmlldxgGIAEoCzISLmFzY25kLnYxLlZpZXdJbmZvSAGIAQESGAoLbmV4dF9jdXJzb3IYByABKAlIAogBAUINCgtfcGVyaW9kX2VuZEIHCgVfdmlld0IOCgxfbmV4dF9jdXJzb3IitQEKEExlYWRlcmJvYXJkRW50cnkSDAoEcmFuaxgBIAEoBRIRCglwbGF5ZXJfaWQYAiABKAkSDQoFc2NvcmUYAyABKAMSFAoMc3VibWl0dGVkX2F0GAQgASgJEhUKCG1ldGFkYXRhGAUgASgMSACIAQESKwoHYnJhY2tldBgGIAEoCzIVLmFzY25kLnYxLkJyYWNrZXRJbmZvSAGIAQFCCwoJX21ldGFkYXRhQgoKCF9icmFja2V0IkUKC0JyYWNrZXRJbmZvEgoKAmlkGAEgASgJEgwKBG5hbWUYAiABKAkSEgoFY29sb3IYAyABKAlIAIgBAUIICgZfY29sb3IiJgoIVmlld0luZm8SDAoEc2x1ZxgBIAEoCRIMCgRuYW1lGAIgASgJIocBChRHZXRQbGF5ZXJSYW5rUmVxdWVzdBIWCg5sZWFkZXJib2FyZF9pZBgBIAEoCRIRCglwbGF5ZXJfaWQYAiABKAkSEwoGcGVyaW9kGAMgASgJSACIAQESFgoJdmlld19zbHVnGAQgASgJSAGIAQFCCQoHX3BlcmlvZEIMCgpfdmlld19zbHVnIssCChVHZXRQbGF5ZXJSYW5rUmVzcG9uc2USEQoEcmFuaxgBIAEoBUgAiAEBEhIKBXNjb3JlGAIgASgDSAGIAQESFwoKYmVzdF9zY29yZRgDIAEoA0gCiAEBEhUKDXRvdGFsX2VudHJpZXMYBCABKAUSFwoKcGVyY2VudGlsZRgFIAEoCUgDiAEBEisKB2JyYWNrZXQYBiABKAsyFS5hc2NuZC52MS5CcmFja2V0SW5mb0gEiAEBEiUKBHZpZXcYByABKAsyEi5hc2NuZC52MS5WaWV3SW5mb0gFiAEBEhgKC2dsb2JhbF9yYW5rGAggASgFSAaIAQFCBwoFX3JhbmtCCAoGX3Njb3JlQg0KC19iZXN0X3Njb3JlQg0KC19wZXJjZW50aWxlQgoKCF9icmFja2V0QgcKBV92aWV3Qg4KDF9nbG9iYWxfcmFuazKBAgoMQXNjbmRTZXJ2aWNlEkoKC1N1Ym1pdFNjb3JlEhwuYXNjbmQudjEuU3VibWl0U2NvcmVSZXF1ZXN0Gh0uYXNjbmQudjEuU3VibWl0U2NvcmVSZXNwb25zZRJTCg5HZXRMZWFkZXJib2FyZBIfLmFzY25kLnYxLkdldExlYWRlcmJvYXJkUmVxdWVzdBogLmFzY25kLnYxLkdldExlYWRlcmJvYXJkUmVzcG9uc2USUAoNR2V0UGxheWVyUmFuaxIeLmFzY25kLnYxLkdldFBsYXllclJhbmtSZXF1ZXN0Gh8uYXNjbmQudjEuR2V0UGxheWVyUmFua1Jlc3BvbnNlYgZwcm90bzM\");\n\n/**\n * SubmitScoreRequest contains the score submission details.\n *\n * @generated from message ascnd.v1.SubmitScoreRequest\n */\nexport type SubmitScoreRequest = Message<\"ascnd.v1.SubmitScoreRequest\"> & {\n /**\n * The leaderboard to submit the score to.\n *\n * @generated from field: string leaderboard_id = 1;\n */\n leaderboardId: string;\n\n /**\n * The player's unique identifier (provided by the game).\n *\n * @generated from field: string player_id = 2;\n */\n playerId: string;\n\n /**\n * The score value.\n *\n * @generated from field: int64 score = 3;\n */\n score: bigint;\n\n /**\n * Optional metadata (JSON-encoded game-specific data).\n *\n * @generated from field: optional bytes metadata = 4;\n */\n metadata?: Uint8Array;\n\n /**\n * Optional idempotency key to prevent duplicate submissions.\n *\n * @generated from field: optional string idempotency_key = 5;\n */\n idempotencyKey?: string;\n};\n\n/**\n * Describes the message ascnd.v1.SubmitScoreRequest.\n * Use `create(SubmitScoreRequestSchema)` to create a new message.\n */\nexport const SubmitScoreRequestSchema: GenMessage<SubmitScoreRequest> = /*@__PURE__*/\n messageDesc(file_ascnd, 0);\n\n/**\n * SubmitScoreResponse contains the result of the score submission.\n *\n * @generated from message ascnd.v1.SubmitScoreResponse\n */\nexport type SubmitScoreResponse = Message<\"ascnd.v1.SubmitScoreResponse\"> & {\n /**\n * The unique identifier of the submitted score.\n *\n * @generated from field: string score_id = 1;\n */\n scoreId: string;\n\n /**\n * The player's rank after this submission.\n *\n * @generated from field: int32 rank = 2;\n */\n rank: number;\n\n /**\n * Whether this is the player's new best score for this period.\n *\n * @generated from field: bool is_new_best = 3;\n */\n isNewBest: boolean;\n\n /**\n * Whether the score was deduplicated (already submitted recently).\n *\n * @generated from field: bool was_deduplicated = 4;\n */\n wasDeduplicated: boolean;\n\n /**\n * Anticheat validation result (if anticheat is enabled for this leaderboard).\n *\n * @generated from field: optional ascnd.v1.AnticheatResult anticheat = 5;\n */\n anticheat?: AnticheatResult;\n};\n\n/**\n * Describes the message ascnd.v1.SubmitScoreResponse.\n * Use `create(SubmitScoreResponseSchema)` to create a new message.\n */\nexport const SubmitScoreResponseSchema: GenMessage<SubmitScoreResponse> = /*@__PURE__*/\n messageDesc(file_ascnd, 1);\n\n/**\n * AnticheatResult contains the result of anticheat validation.\n *\n * @generated from message ascnd.v1.AnticheatResult\n */\nexport type AnticheatResult = Message<\"ascnd.v1.AnticheatResult\"> & {\n /**\n * Whether the score passed all anticheat checks.\n *\n * @generated from field: bool passed = 1;\n */\n passed: boolean;\n\n /**\n * List of violation flags that were triggered.\n *\n * @generated from field: repeated ascnd.v1.AnticheatViolation violations = 2;\n */\n violations: AnticheatViolation[];\n\n /**\n * The enforcement action taken: \"none\", \"flag\", \"shadow_ban\", or \"reject\".\n *\n * @generated from field: string action = 3;\n */\n action: string;\n};\n\n/**\n * Describes the message ascnd.v1.AnticheatResult.\n * Use `create(AnticheatResultSchema)` to create a new message.\n */\nexport const AnticheatResultSchema: GenMessage<AnticheatResult> = /*@__PURE__*/\n messageDesc(file_ascnd, 2);\n\n/**\n * AnticheatViolation describes a single anticheat rule violation.\n *\n * @generated from message ascnd.v1.AnticheatViolation\n */\nexport type AnticheatViolation = Message<\"ascnd.v1.AnticheatViolation\"> & {\n /**\n * The type of violation: \"bounds_exceeded\", \"velocity_exceeded\",\n * \"duplicate_idempotency\", \"missing_idempotency_key\".\n *\n * @generated from field: string flag_type = 1;\n */\n flagType: string;\n\n /**\n * Human-readable description of the violation.\n *\n * @generated from field: string reason = 2;\n */\n reason: string;\n};\n\n/**\n * Describes the message ascnd.v1.AnticheatViolation.\n * Use `create(AnticheatViolationSchema)` to create a new message.\n */\nexport const AnticheatViolationSchema: GenMessage<AnticheatViolation> = /*@__PURE__*/\n messageDesc(file_ascnd, 3);\n\n/**\n * GetLeaderboardRequest specifies which leaderboard and page to retrieve.\n *\n * @generated from message ascnd.v1.GetLeaderboardRequest\n */\nexport type GetLeaderboardRequest = Message<\"ascnd.v1.GetLeaderboardRequest\"> & {\n /**\n * The leaderboard to retrieve.\n *\n * @generated from field: string leaderboard_id = 1;\n */\n leaderboardId: string;\n\n /**\n * Maximum number of entries to return (default: 10, max: 100).\n *\n * @generated from field: optional int32 limit = 2;\n */\n limit?: number;\n\n /**\n * Which period to retrieve: \"current\", \"previous\", or a timestamp.\n *\n * @generated from field: optional string period = 4;\n */\n period?: string;\n\n /**\n * Optional view slug to filter by metadata criteria.\n * If provided, returns rankings within the view (not global rank).\n *\n * @generated from field: optional string view_slug = 5;\n */\n viewSlug?: string;\n\n /**\n * Cursor for keyset pagination (encodes score + player_id).\n * When provided, returns entries after this cursor position.\n *\n * @generated from field: optional string cursor = 6;\n */\n cursor?: string;\n\n /**\n * Jump to a specific rank position.\n * Returns entries starting from this rank, with cursor for continuation.\n * Use this instead of offset for random access to leaderboard positions.\n *\n * @generated from field: optional int32 around_rank = 7;\n */\n aroundRank?: number;\n};\n\n/**\n * Describes the message ascnd.v1.GetLeaderboardRequest.\n * Use `create(GetLeaderboardRequestSchema)` to create a new message.\n */\nexport const GetLeaderboardRequestSchema: GenMessage<GetLeaderboardRequest> = /*@__PURE__*/\n messageDesc(file_ascnd, 4);\n\n/**\n * GetLeaderboardResponse contains the leaderboard entries.\n *\n * @generated from message ascnd.v1.GetLeaderboardResponse\n */\nexport type GetLeaderboardResponse = Message<\"ascnd.v1.GetLeaderboardResponse\"> & {\n /**\n * The leaderboard entries.\n *\n * @generated from field: repeated ascnd.v1.LeaderboardEntry entries = 1;\n */\n entries: LeaderboardEntry[];\n\n /**\n * Approximate total number of entries.\n *\n * @generated from field: int32 total_entries = 2;\n */\n totalEntries: number;\n\n /**\n * Whether there are more entries after this page.\n *\n * @generated from field: bool has_more = 3;\n */\n hasMore: boolean;\n\n /**\n * The start of the current period (ISO 8601 timestamp).\n *\n * @generated from field: string period_start = 4;\n */\n periodStart: string;\n\n /**\n * The end of the current period, if applicable (ISO 8601 timestamp).\n *\n * @generated from field: optional string period_end = 5;\n */\n periodEnd?: string;\n\n /**\n * Active view info if filtering by view_slug.\n *\n * @generated from field: optional ascnd.v1.ViewInfo view = 6;\n */\n view?: ViewInfo;\n\n /**\n * Cursor for fetching the next page (keyset pagination).\n * Only present when has_more is true.\n *\n * @generated from field: optional string next_cursor = 7;\n */\n nextCursor?: string;\n};\n\n/**\n * Describes the message ascnd.v1.GetLeaderboardResponse.\n * Use `create(GetLeaderboardResponseSchema)` to create a new message.\n */\nexport const GetLeaderboardResponseSchema: GenMessage<GetLeaderboardResponse> = /*@__PURE__*/\n messageDesc(file_ascnd, 5);\n\n/**\n * LeaderboardEntry represents a single entry on the leaderboard.\n *\n * @generated from message ascnd.v1.LeaderboardEntry\n */\nexport type LeaderboardEntry = Message<\"ascnd.v1.LeaderboardEntry\"> & {\n /**\n * The player's rank (1-indexed).\n *\n * @generated from field: int32 rank = 1;\n */\n rank: number;\n\n /**\n * The player's unique identifier.\n *\n * @generated from field: string player_id = 2;\n */\n playerId: string;\n\n /**\n * The player's score.\n *\n * @generated from field: int64 score = 3;\n */\n score: bigint;\n\n /**\n * When the score was submitted (ISO 8601 timestamp).\n *\n * @generated from field: string submitted_at = 4;\n */\n submittedAt: string;\n\n /**\n * Optional metadata associated with the score.\n *\n * @generated from field: optional bytes metadata = 5;\n */\n metadata?: Uint8Array;\n\n /**\n * Optional bracket assignment for this player.\n *\n * @generated from field: optional ascnd.v1.BracketInfo bracket = 6;\n */\n bracket?: BracketInfo;\n};\n\n/**\n * Describes the message ascnd.v1.LeaderboardEntry.\n * Use `create(LeaderboardEntrySchema)` to create a new message.\n */\nexport const LeaderboardEntrySchema: GenMessage<LeaderboardEntry> = /*@__PURE__*/\n messageDesc(file_ascnd, 6);\n\n/**\n * BracketInfo contains minimal bracket information.\n *\n * @generated from message ascnd.v1.BracketInfo\n */\nexport type BracketInfo = Message<\"ascnd.v1.BracketInfo\"> & {\n /**\n * The bracket's unique identifier.\n *\n * @generated from field: string id = 1;\n */\n id: string;\n\n /**\n * The bracket's name (e.g., \"Gold\", \"Silver\", \"Bronze\").\n *\n * @generated from field: string name = 2;\n */\n name: string;\n\n /**\n * Optional hex color code (e.g., \"#FF5500\") for the bracket badge.\n *\n * @generated from field: optional string color = 3;\n */\n color?: string;\n};\n\n/**\n * Describes the message ascnd.v1.BracketInfo.\n * Use `create(BracketInfoSchema)` to create a new message.\n */\nexport const BracketInfoSchema: GenMessage<BracketInfo> = /*@__PURE__*/\n messageDesc(file_ascnd, 7);\n\n/**\n * ViewInfo contains minimal metadata view information.\n *\n * @generated from message ascnd.v1.ViewInfo\n */\nexport type ViewInfo = Message<\"ascnd.v1.ViewInfo\"> & {\n /**\n * The view's slug identifier.\n *\n * @generated from field: string slug = 1;\n */\n slug: string;\n\n /**\n * The view's display name.\n *\n * @generated from field: string name = 2;\n */\n name: string;\n};\n\n/**\n * Describes the message ascnd.v1.ViewInfo.\n * Use `create(ViewInfoSchema)` to create a new message.\n */\nexport const ViewInfoSchema: GenMessage<ViewInfo> = /*@__PURE__*/\n messageDesc(file_ascnd, 8);\n\n/**\n * GetPlayerRankRequest specifies which player and leaderboard to query.\n *\n * @generated from message ascnd.v1.GetPlayerRankRequest\n */\nexport type GetPlayerRankRequest = Message<\"ascnd.v1.GetPlayerRankRequest\"> & {\n /**\n * The leaderboard to query.\n *\n * @generated from field: string leaderboard_id = 1;\n */\n leaderboardId: string;\n\n /**\n * The player's unique identifier.\n *\n * @generated from field: string player_id = 2;\n */\n playerId: string;\n\n /**\n * Which period to query: \"current\", \"previous\", or a timestamp.\n *\n * @generated from field: optional string period = 3;\n */\n period?: string;\n\n /**\n * Optional view slug to get rank within a filtered view.\n *\n * @generated from field: optional string view_slug = 4;\n */\n viewSlug?: string;\n};\n\n/**\n * Describes the message ascnd.v1.GetPlayerRankRequest.\n * Use `create(GetPlayerRankRequestSchema)` to create a new message.\n */\nexport const GetPlayerRankRequestSchema: GenMessage<GetPlayerRankRequest> = /*@__PURE__*/\n messageDesc(file_ascnd, 9);\n\n/**\n * GetPlayerRankResponse contains the player's rank information.\n *\n * @generated from message ascnd.v1.GetPlayerRankResponse\n */\nexport type GetPlayerRankResponse = Message<\"ascnd.v1.GetPlayerRankResponse\"> & {\n /**\n * The player's rank (null if not on leaderboard).\n * When querying a view, this is the rank within the view.\n *\n * @generated from field: optional int32 rank = 1;\n */\n rank?: number;\n\n /**\n * The player's current score (null if not on leaderboard).\n *\n * @generated from field: optional int64 score = 2;\n */\n score?: bigint;\n\n /**\n * The player's best score this period.\n *\n * @generated from field: optional int64 best_score = 3;\n */\n bestScore?: bigint;\n\n /**\n * Total number of entries on this leaderboard (or view if filtered).\n *\n * @generated from field: int32 total_entries = 4;\n */\n totalEntries: number;\n\n /**\n * The player's percentile (e.g., \"top 5%\").\n *\n * @generated from field: optional string percentile = 5;\n */\n percentile?: string;\n\n /**\n * Optional bracket assignment for this player.\n *\n * @generated from field: optional ascnd.v1.BracketInfo bracket = 6;\n */\n bracket?: BracketInfo;\n\n /**\n * Active view info if querying with view_slug.\n *\n * @generated from field: optional ascnd.v1.ViewInfo view = 7;\n */\n view?: ViewInfo;\n\n /**\n * Global rank when querying a view (shows overall position).\n *\n * @generated from field: optional int32 global_rank = 8;\n */\n globalRank?: number;\n};\n\n/**\n * Describes the message ascnd.v1.GetPlayerRankResponse.\n * Use `create(GetPlayerRankResponseSchema)` to create a new message.\n */\nexport const GetPlayerRankResponseSchema: GenMessage<GetPlayerRankResponse> = /*@__PURE__*/\n messageDesc(file_ascnd, 10);\n\n/**\n * AscndService provides leaderboard management for games.\n *\n * @generated from service ascnd.v1.AscndService\n */\nexport const AscndService: GenService<{\n /**\n * SubmitScore records a player's score on a leaderboard.\n *\n * @generated from rpc ascnd.v1.AscndService.SubmitScore\n */\n submitScore: {\n methodKind: \"unary\";\n input: typeof SubmitScoreRequestSchema;\n output: typeof SubmitScoreResponseSchema;\n },\n /**\n * GetLeaderboard retrieves the top scores for a leaderboard.\n *\n * @generated from rpc ascnd.v1.AscndService.GetLeaderboard\n */\n getLeaderboard: {\n methodKind: \"unary\";\n input: typeof GetLeaderboardRequestSchema;\n output: typeof GetLeaderboardResponseSchema;\n },\n /**\n * GetPlayerRank retrieves a specific player's rank and score.\n *\n * @generated from rpc ascnd.v1.AscndService.GetPlayerRank\n */\n getPlayerRank: {\n methodKind: \"unary\";\n input: typeof GetPlayerRankRequestSchema;\n output: typeof GetPlayerRankResponseSchema;\n },\n}> = /*@__PURE__*/\n serviceDesc(file_ascnd, 0);\n\n","/**\n * TypeScript types for the Ascnd gRPC API.\n *\n * Types are generated from the proto file and re-exported here.\n */\n\n// Re-export all generated types\nexport type {\n SubmitScoreRequest,\n SubmitScoreResponse,\n GetLeaderboardRequest,\n GetLeaderboardResponse,\n GetPlayerRankRequest,\n GetPlayerRankResponse,\n LeaderboardEntry,\n AnticheatResult,\n AnticheatViolation,\n BracketInfo,\n ViewInfo,\n} from \"./gen/ascnd_pb.js\";\n\n// Re-export the service definition\nexport { AscndService } from \"./gen/ascnd_pb.js\";\n\n// Re-export schemas for creating messages\nexport {\n SubmitScoreRequestSchema,\n SubmitScoreResponseSchema,\n GetLeaderboardRequestSchema,\n GetLeaderboardResponseSchema,\n GetPlayerRankRequestSchema,\n GetPlayerRankResponseSchema,\n LeaderboardEntrySchema,\n AnticheatResultSchema,\n AnticheatViolationSchema,\n BracketInfoSchema,\n ViewInfoSchema,\n} from \"./gen/ascnd_pb.js\";\n\n// ============================================================================\n// Client Configuration\n// ============================================================================\n\n/**\n * Configuration options for the Ascnd client.\n */\nexport interface AscndClientConfig {\n /** The base URL of the Ascnd API (e.g., \"https://api.ascnd.gg\"). */\n baseUrl: string;\n\n /** Your API key for authentication. */\n apiKey: string;\n\n /** Optional request timeout in milliseconds (default: 30000). */\n timeout?: number;\n}\n\n// ============================================================================\n// Error Types\n// ============================================================================\n\n/**\n * Custom error class for Ascnd API errors.\n */\nexport class AscndError extends Error {\n /** gRPC/Connect error code. */\n readonly code: string;\n\n /** Additional error details. */\n readonly details?: Record<string, unknown>;\n\n constructor(\n message: string,\n code: string,\n details?: Record<string, unknown>\n ) {\n super(message);\n this.name = \"AscndError\";\n this.code = code;\n this.details = details;\n }\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -159,12 +159,6 @@ type GetLeaderboardRequest = Message<"ascnd.v1.GetLeaderboardRequest"> & {
159
159
  * @generated from field: optional int32 limit = 2;
160
160
  */
161
161
  limit?: number;
162
- /**
163
- * Number of entries to skip for pagination.
164
- *
165
- * @generated from field: optional int32 offset = 3;
166
- */
167
- offset?: number;
168
162
  /**
169
163
  * Which period to retrieve: "current", "previous", or a timestamp.
170
164
  *
@@ -178,6 +172,21 @@ type GetLeaderboardRequest = Message<"ascnd.v1.GetLeaderboardRequest"> & {
178
172
  * @generated from field: optional string view_slug = 5;
179
173
  */
180
174
  viewSlug?: string;
175
+ /**
176
+ * Cursor for keyset pagination (encodes score + player_id).
177
+ * When provided, returns entries after this cursor position.
178
+ *
179
+ * @generated from field: optional string cursor = 6;
180
+ */
181
+ cursor?: string;
182
+ /**
183
+ * Jump to a specific rank position.
184
+ * Returns entries starting from this rank, with cursor for continuation.
185
+ * Use this instead of offset for random access to leaderboard positions.
186
+ *
187
+ * @generated from field: optional int32 around_rank = 7;
188
+ */
189
+ aroundRank?: number;
181
190
  };
182
191
  /**
183
192
  * Describes the message ascnd.v1.GetLeaderboardRequest.
@@ -226,6 +235,13 @@ type GetLeaderboardResponse = Message<"ascnd.v1.GetLeaderboardResponse"> & {
226
235
  * @generated from field: optional ascnd.v1.ViewInfo view = 6;
227
236
  */
228
237
  view?: ViewInfo;
238
+ /**
239
+ * Cursor for fetching the next page (keyset pagination).
240
+ * Only present when has_more is true.
241
+ *
242
+ * @generated from field: optional string next_cursor = 7;
243
+ */
244
+ nextCursor?: string;
229
245
  };
230
246
  /**
231
247
  * Describes the message ascnd.v1.GetLeaderboardResponse.
package/dist/index.d.ts CHANGED
@@ -159,12 +159,6 @@ type GetLeaderboardRequest = Message<"ascnd.v1.GetLeaderboardRequest"> & {
159
159
  * @generated from field: optional int32 limit = 2;
160
160
  */
161
161
  limit?: number;
162
- /**
163
- * Number of entries to skip for pagination.
164
- *
165
- * @generated from field: optional int32 offset = 3;
166
- */
167
- offset?: number;
168
162
  /**
169
163
  * Which period to retrieve: "current", "previous", or a timestamp.
170
164
  *
@@ -178,6 +172,21 @@ type GetLeaderboardRequest = Message<"ascnd.v1.GetLeaderboardRequest"> & {
178
172
  * @generated from field: optional string view_slug = 5;
179
173
  */
180
174
  viewSlug?: string;
175
+ /**
176
+ * Cursor for keyset pagination (encodes score + player_id).
177
+ * When provided, returns entries after this cursor position.
178
+ *
179
+ * @generated from field: optional string cursor = 6;
180
+ */
181
+ cursor?: string;
182
+ /**
183
+ * Jump to a specific rank position.
184
+ * Returns entries starting from this rank, with cursor for continuation.
185
+ * Use this instead of offset for random access to leaderboard positions.
186
+ *
187
+ * @generated from field: optional int32 around_rank = 7;
188
+ */
189
+ aroundRank?: number;
181
190
  };
182
191
  /**
183
192
  * Describes the message ascnd.v1.GetLeaderboardRequest.
@@ -226,6 +235,13 @@ type GetLeaderboardResponse = Message<"ascnd.v1.GetLeaderboardResponse"> & {
226
235
  * @generated from field: optional ascnd.v1.ViewInfo view = 6;
227
236
  */
228
237
  view?: ViewInfo;
238
+ /**
239
+ * Cursor for fetching the next page (keyset pagination).
240
+ * Only present when has_more is true.
241
+ *
242
+ * @generated from field: optional string next_cursor = 7;
243
+ */
244
+ nextCursor?: string;
229
245
  };
230
246
  /**
231
247
  * Describes the message ascnd.v1.GetLeaderboardResponse.
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { createGrpcWebTransport } from "@connectrpc/connect-web";
4
4
 
5
5
  // src/gen/ascnd_pb.ts
6
6
  import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv2";
7
- var file_ascnd = /* @__PURE__ */ fileDesc("Cgthc2NuZC5wcm90bxIIYXNjbmQudjEipAEKElN1Ym1pdFNjb3JlUmVxdWVzdBIWCg5sZWFkZXJib2FyZF9pZBgBIAEoCRIRCglwbGF5ZXJfaWQYAiABKAkSDQoFc2NvcmUYAyABKAMSFQoIbWV0YWRhdGEYBCABKAxIAIgBARIcCg9pZGVtcG90ZW5jeV9rZXkYBSABKAlIAYgBAUILCglfbWV0YWRhdGFCEgoQX2lkZW1wb3RlbmN5X2tleSKlAQoTU3VibWl0U2NvcmVSZXNwb25zZRIQCghzY29yZV9pZBgBIAEoCRIMCgRyYW5rGAIgASgFEhMKC2lzX25ld19iZXN0GAMgASgIEhgKEHdhc19kZWR1cGxpY2F0ZWQYBCABKAgSMQoJYW50aWNoZWF0GAUgASgLMhkuYXNjbmQudjEuQW50aWNoZWF0UmVzdWx0SACIAQFCDAoKX2FudGljaGVhdCJjCg9BbnRpY2hlYXRSZXN1bHQSDgoGcGFzc2VkGAEgASgIEjAKCnZpb2xhdGlvbnMYAiADKAsyHC5hc2NuZC52MS5BbnRpY2hlYXRWaW9sYXRpb24SDgoGYWN0aW9uGAMgASgJIjcKEkFudGljaGVhdFZpb2xhdGlvbhIRCglmbGFnX3R5cGUYASABKAkSDgoGcmVhc29uGAIgASgJIrMBChVHZXRMZWFkZXJib2FyZFJlcXVlc3QSFgoObGVhZGVyYm9hcmRfaWQYASABKAkSEgoFbGltaXQYAiABKAVIAIgBARITCgZvZmZzZXQYAyABKAVIAYgBARITCgZwZXJpb2QYBCABKAlIAogBARIWCgl2aWV3X3NsdWcYBSABKAlIA4gBAUIICgZfbGltaXRCCQoHX29mZnNldEIJCgdfcGVyaW9kQgwKCl92aWV3X3NsdWci3AEKFkdldExlYWRlcmJvYXJkUmVzcG9uc2USKwoHZW50cmllcxgBIAMoCzIaLmFzY25kLnYxLkxlYWRlcmJvYXJkRW50cnkSFQoNdG90YWxfZW50cmllcxgCIAEoBRIQCghoYXNfbW9yZRgDIAEoCBIUCgxwZXJpb2Rfc3RhcnQYBCABKAkSFwoKcGVyaW9kX2VuZBgFIAEoCUgAiAEBEiUKBHZpZXcYBiABKAsyEi5hc2NuZC52MS5WaWV3SW5mb0gBiAEBQg0KC19wZXJpb2RfZW5kQgcKBV92aWV3IrUBChBMZWFkZXJib2FyZEVudHJ5EgwKBHJhbmsYASABKAUSEQoJcGxheWVyX2lkGAIgASgJEg0KBXNjb3JlGAMgASgDEhQKDHN1Ym1pdHRlZF9hdBgEIAEoCRIVCghtZXRhZGF0YRgFIAEoDEgAiAEBEisKB2JyYWNrZXQYBiABKAsyFS5hc2NuZC52MS5CcmFja2V0SW5mb0gBiAEBQgsKCV9tZXRhZGF0YUIKCghfYnJhY2tldCJFCgtCcmFja2V0SW5mbxIKCgJpZBgBIAEoCRIMCgRuYW1lGAIgASgJEhIKBWNvbG9yGAMgASgJSACIAQFCCAoGX2NvbG9yIiYKCFZpZXdJbmZvEgwKBHNsdWcYASABKAkSDAoEbmFtZRgCIAEoCSKHAQoUR2V0UGxheWVyUmFua1JlcXVlc3QSFgoObGVhZGVyYm9hcmRfaWQYASABKAkSEQoJcGxheWVyX2lkGAIgASgJEhMKBnBlcmlvZBgDIAEoCUgAiAEBEhYKCXZpZXdfc2x1ZxgEIAEoCUgBiAEBQgkKB19wZXJpb2RCDAoKX3ZpZXdfc2x1ZyLLAgoVR2V0UGxheWVyUmFua1Jlc3BvbnNlEhEKBHJhbmsYASABKAVIAIgBARISCgVzY29yZRgCIAEoA0gBiAEBEhcKCmJlc3Rfc2NvcmUYAyABKANIAogBARIVCg10b3RhbF9lbnRyaWVzGAQgASgFEhcKCnBlcmNlbnRpbGUYBSABKAlIA4gBARIrCgdicmFja2V0GAYgASgLMhUuYXNjbmQudjEuQnJhY2tldEluZm9IBIgBARIlCgR2aWV3GAcgASgLMhIuYXNjbmQudjEuVmlld0luZm9IBYgBARIYCgtnbG9iYWxfcmFuaxgIIAEoBUgGiAEBQgcKBV9yYW5rQggKBl9zY29yZUINCgtfYmVzdF9zY29yZUINCgtfcGVyY2VudGlsZUIKCghfYnJhY2tldEIHCgVfdmlld0IOCgxfZ2xvYmFsX3JhbmsygQIKDEFzY25kU2VydmljZRJKCgtTdWJtaXRTY29yZRIcLmFzY25kLnYxLlN1Ym1pdFNjb3JlUmVxdWVzdBodLmFzY25kLnYxLlN1Ym1pdFNjb3JlUmVzcG9uc2USUwoOR2V0TGVhZGVyYm9hcmQSHy5hc2NuZC52MS5HZXRMZWFkZXJib2FyZFJlcXVlc3QaIC5hc2NuZC52MS5HZXRMZWFkZXJib2FyZFJlc3BvbnNlElAKDUdldFBsYXllclJhbmsSHi5hc2NuZC52MS5HZXRQbGF5ZXJSYW5rUmVxdWVzdBofLmFzY25kLnYxLkdldFBsYXllclJhbmtSZXNwb25zZWIGcHJvdG8z");
7
+ var file_ascnd = /* @__PURE__ */ fileDesc("Cgthc2NuZC5wcm90bxIIYXNjbmQudjEipAEKElN1Ym1pdFNjb3JlUmVxdWVzdBIWCg5sZWFkZXJib2FyZF9pZBgBIAEoCRIRCglwbGF5ZXJfaWQYAiABKAkSDQoFc2NvcmUYAyABKAMSFQoIbWV0YWRhdGEYBCABKAxIAIgBARIcCg9pZGVtcG90ZW5jeV9rZXkYBSABKAlIAYgBAUILCglfbWV0YWRhdGFCEgoQX2lkZW1wb3RlbmN5X2tleSKlAQoTU3VibWl0U2NvcmVSZXNwb25zZRIQCghzY29yZV9pZBgBIAEoCRIMCgRyYW5rGAIgASgFEhMKC2lzX25ld19iZXN0GAMgASgIEhgKEHdhc19kZWR1cGxpY2F0ZWQYBCABKAgSMQoJYW50aWNoZWF0GAUgASgLMhkuYXNjbmQudjEuQW50aWNoZWF0UmVzdWx0SACIAQFCDAoKX2FudGljaGVhdCJjCg9BbnRpY2hlYXRSZXN1bHQSDgoGcGFzc2VkGAEgASgIEjAKCnZpb2xhdGlvbnMYAiADKAsyHC5hc2NuZC52MS5BbnRpY2hlYXRWaW9sYXRpb24SDgoGYWN0aW9uGAMgASgJIjcKEkFudGljaGVhdFZpb2xhdGlvbhIRCglmbGFnX3R5cGUYASABKAkSDgoGcmVhc29uGAIgASgJIusBChVHZXRMZWFkZXJib2FyZFJlcXVlc3QSFgoObGVhZGVyYm9hcmRfaWQYASABKAkSEgoFbGltaXQYAiABKAVIAIgBARITCgZwZXJpb2QYBCABKAlIAYgBARIWCgl2aWV3X3NsdWcYBSABKAlIAogBARITCgZjdXJzb3IYBiABKAlIA4gBARIYCgthcm91bmRfcmFuaxgHIAEoBUgEiAEBQggKBl9saW1pdEIJCgdfcGVyaW9kQgwKCl92aWV3X3NsdWdCCQoHX2N1cnNvckIOCgxfYXJvdW5kX3JhbmtKBAgDEARSBm9mZnNldCKGAgoWR2V0TGVhZGVyYm9hcmRSZXNwb25zZRIrCgdlbnRyaWVzGAEgAygLMhouYXNjbmQudjEuTGVhZGVyYm9hcmRFbnRyeRIVCg10b3RhbF9lbnRyaWVzGAIgASgFEhAKCGhhc19tb3JlGAMgASgIEhQKDHBlcmlvZF9zdGFydBgEIAEoCRIXCgpwZXJpb2RfZW5kGAUgASgJSACIAQESJQoEdmlldxgGIAEoCzISLmFzY25kLnYxLlZpZXdJbmZvSAGIAQESGAoLbmV4dF9jdXJzb3IYByABKAlIAogBAUINCgtfcGVyaW9kX2VuZEIHCgVfdmlld0IOCgxfbmV4dF9jdXJzb3IitQEKEExlYWRlcmJvYXJkRW50cnkSDAoEcmFuaxgBIAEoBRIRCglwbGF5ZXJfaWQYAiABKAkSDQoFc2NvcmUYAyABKAMSFAoMc3VibWl0dGVkX2F0GAQgASgJEhUKCG1ldGFkYXRhGAUgASgMSACIAQESKwoHYnJhY2tldBgGIAEoCzIVLmFzY25kLnYxLkJyYWNrZXRJbmZvSAGIAQFCCwoJX21ldGFkYXRhQgoKCF9icmFja2V0IkUKC0JyYWNrZXRJbmZvEgoKAmlkGAEgASgJEgwKBG5hbWUYAiABKAkSEgoFY29sb3IYAyABKAlIAIgBAUIICgZfY29sb3IiJgoIVmlld0luZm8SDAoEc2x1ZxgBIAEoCRIMCgRuYW1lGAIgASgJIocBChRHZXRQbGF5ZXJSYW5rUmVxdWVzdBIWCg5sZWFkZXJib2FyZF9pZBgBIAEoCRIRCglwbGF5ZXJfaWQYAiABKAkSEwoGcGVyaW9kGAMgASgJSACIAQESFgoJdmlld19zbHVnGAQgASgJSAGIAQFCCQoHX3BlcmlvZEIMCgpfdmlld19zbHVnIssCChVHZXRQbGF5ZXJSYW5rUmVzcG9uc2USEQoEcmFuaxgBIAEoBUgAiAEBEhIKBXNjb3JlGAIgASgDSAGIAQESFwoKYmVzdF9zY29yZRgDIAEoA0gCiAEBEhUKDXRvdGFsX2VudHJpZXMYBCABKAUSFwoKcGVyY2VudGlsZRgFIAEoCUgDiAEBEisKB2JyYWNrZXQYBiABKAsyFS5hc2NuZC52MS5CcmFja2V0SW5mb0gEiAEBEiUKBHZpZXcYByABKAsyEi5hc2NuZC52MS5WaWV3SW5mb0gFiAEBEhgKC2dsb2JhbF9yYW5rGAggASgFSAaIAQFCBwoFX3JhbmtCCAoGX3Njb3JlQg0KC19iZXN0X3Njb3JlQg0KC19wZXJjZW50aWxlQgoKCF9icmFja2V0QgcKBV92aWV3Qg4KDF9nbG9iYWxfcmFuazKBAgoMQXNjbmRTZXJ2aWNlEkoKC1N1Ym1pdFNjb3JlEhwuYXNjbmQudjEuU3VibWl0U2NvcmVSZXF1ZXN0Gh0uYXNjbmQudjEuU3VibWl0U2NvcmVSZXNwb25zZRJTCg5HZXRMZWFkZXJib2FyZBIfLmFzY25kLnYxLkdldExlYWRlcmJvYXJkUmVxdWVzdBogLmFzY25kLnYxLkdldExlYWRlcmJvYXJkUmVzcG9uc2USUAoNR2V0UGxheWVyUmFuaxIeLmFzY25kLnYxLkdldFBsYXllclJhbmtSZXF1ZXN0Gh8uYXNjbmQudjEuR2V0UGxheWVyUmFua1Jlc3BvbnNlYgZwcm90bzM");
8
8
  var SubmitScoreRequestSchema = /* @__PURE__ */ messageDesc(file_ascnd, 0);
9
9
  var SubmitScoreResponseSchema = /* @__PURE__ */ messageDesc(file_ascnd, 1);
10
10
  var AnticheatResultSchema = /* @__PURE__ */ messageDesc(file_ascnd, 2);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts","../src/gen/ascnd_pb.ts","../src/types.ts","../src/index.ts"],"sourcesContent":["import { createClient, type Client, type Interceptor, ConnectError } from \"@connectrpc/connect\";\nimport { createGrpcWebTransport } from \"@connectrpc/connect-web\";\nimport {\n AscndService,\n type SubmitScoreRequest,\n type SubmitScoreResponse,\n type GetLeaderboardRequest,\n type GetLeaderboardResponse,\n type GetPlayerRankRequest,\n type GetPlayerRankResponse,\n AscndClientConfig,\n AscndError,\n} from \"./types.js\";\n\n/**\n * Client for the Ascnd leaderboard API using gRPC-Web.\n *\n * @example\n * ```typescript\n * import { AscndClient, create } from \"@ascnd-gg/client\";\n * import { SubmitScoreRequestSchema } from \"@ascnd-gg/client\";\n *\n * const client = new AscndClient({\n * baseUrl: \"https://api.ascnd.gg\",\n * apiKey: \"your-api-key\",\n * });\n *\n * // Submit a score\n * const result = await client.submitScore(\n * create(SubmitScoreRequestSchema, {\n * leaderboardId: \"high-scores\",\n * playerId: \"player-123\",\n * score: 1000n,\n * })\n * );\n *\n * console.log(`Rank: #${result.rank}`);\n * ```\n */\nexport class AscndClient {\n private readonly client: Client<typeof AscndService>;\n\n /**\n * Creates a new Ascnd client.\n *\n * @param config - Client configuration options.\n */\n constructor(config: AscndClientConfig) {\n if (!config.baseUrl) {\n throw new Error(\"baseUrl is required\");\n }\n if (!config.apiKey) {\n throw new Error(\"apiKey is required\");\n }\n\n // Create an interceptor to add the API key header\n const authInterceptor: Interceptor = (next) => async (req) => {\n req.header.set(\"x-api-key\", config.apiKey);\n return await next(req);\n };\n\n // Create the gRPC-Web transport\n const transport = createGrpcWebTransport({\n baseUrl: config.baseUrl.replace(/\\/$/, \"\"),\n interceptors: [authInterceptor],\n defaultTimeoutMs: config.timeout ?? 30000,\n });\n\n this.client = createClient(AscndService, transport);\n }\n\n /**\n * Submits a player's score to a leaderboard.\n *\n * @param request - The score submission request.\n * @returns The submission result including the player's new rank.\n * @throws {AscndError} If the API returns an error.\n *\n * @example\n * ```typescript\n * import { create } from \"@bufbuild/protobuf\";\n * import { SubmitScoreRequestSchema } from \"@ascnd-gg/client\";\n *\n * const result = await client.submitScore(\n * create(SubmitScoreRequestSchema, {\n * leaderboardId: \"high-scores\",\n * playerId: \"player-123\",\n * score: 1000n,\n * metadata: new TextEncoder().encode(JSON.stringify({ level: 5 })),\n * })\n * );\n *\n * console.log(`New rank: ${result.rank}`);\n * if (result.isNewBest) {\n * console.log(\"New personal best!\");\n * }\n * if (result.anticheat && !result.anticheat.passed) {\n * console.log(\"Anticheat flagged:\", result.anticheat.violations);\n * }\n * ```\n */\n async submitScore(request: SubmitScoreRequest): Promise<SubmitScoreResponse> {\n try {\n return await this.client.submitScore(request);\n } catch (error) {\n throw this.convertError(error);\n }\n }\n\n /**\n * Retrieves the top scores for a leaderboard.\n *\n * @param request - The leaderboard request parameters.\n * @returns The leaderboard entries and pagination info.\n * @throws {AscndError} If the API returns an error.\n *\n * @example\n * ```typescript\n * import { create } from \"@bufbuild/protobuf\";\n * import { GetLeaderboardRequestSchema } from \"@ascnd-gg/client\";\n *\n * const leaderboard = await client.getLeaderboard(\n * create(GetLeaderboardRequestSchema, {\n * leaderboardId: \"high-scores\",\n * limit: 10,\n * viewSlug: \"platform-pc\", // Filter by metadata view\n * })\n * );\n *\n * for (const entry of leaderboard.entries) {\n * console.log(`#${entry.rank}: ${entry.playerId} - ${entry.score}`);\n * if (entry.bracket) {\n * console.log(` Bracket: ${entry.bracket.name}`);\n * }\n * }\n * ```\n */\n async getLeaderboard(\n request: GetLeaderboardRequest\n ): Promise<GetLeaderboardResponse> {\n try {\n return await this.client.getLeaderboard(request);\n } catch (error) {\n throw this.convertError(error);\n }\n }\n\n /**\n * Retrieves a specific player's rank and score information.\n *\n * @param request - The player rank request parameters.\n * @returns The player's rank, score, and percentile information.\n * @throws {AscndError} If the API returns an error.\n *\n * @example\n * ```typescript\n * import { create } from \"@bufbuild/protobuf\";\n * import { GetPlayerRankRequestSchema } from \"@ascnd-gg/client\";\n *\n * const playerRank = await client.getPlayerRank(\n * create(GetPlayerRankRequestSchema, {\n * leaderboardId: \"high-scores\",\n * playerId: \"player-123\",\n * viewSlug: \"platform-pc\",\n * })\n * );\n *\n * if (playerRank.rank !== undefined) {\n * console.log(`Rank: #${playerRank.rank}`);\n * console.log(`Score: ${playerRank.score}`);\n * console.log(`Percentile: ${playerRank.percentile}`);\n * if (playerRank.bracket) {\n * console.log(`Bracket: ${playerRank.bracket.name}`);\n * }\n * if (playerRank.globalRank !== undefined) {\n * console.log(`Global Rank: #${playerRank.globalRank}`);\n * }\n * } else {\n * console.log(\"Player not on leaderboard\");\n * }\n * ```\n */\n async getPlayerRank(\n request: GetPlayerRankRequest\n ): Promise<GetPlayerRankResponse> {\n try {\n return await this.client.getPlayerRank(request);\n } catch (error) {\n throw this.convertError(error);\n }\n }\n\n /**\n * Converts a Connect error to an AscndError.\n */\n private convertError(error: unknown): AscndError {\n if (error instanceof ConnectError) {\n return new AscndError(\n error.message,\n error.code.toString(),\n error.details?.length ? { details: error.details } : undefined\n );\n }\n if (error instanceof Error) {\n return new AscndError(error.message, \"UNKNOWN\");\n }\n return new AscndError(\"Unknown error occurred\", \"UNKNOWN\");\n }\n}\n","// @generated by protoc-gen-es v2.10.2 with parameter \"target=ts\"\n// @generated from file ascnd.proto (package ascnd.v1, syntax proto3)\n/* eslint-disable */\n\nimport type { GenFile, GenMessage, GenService } from \"@bufbuild/protobuf/codegenv2\";\nimport { fileDesc, messageDesc, serviceDesc } from \"@bufbuild/protobuf/codegenv2\";\nimport type { Message } from \"@bufbuild/protobuf\";\n\n/**\n * Describes the file ascnd.proto.\n */\nexport const file_ascnd: GenFile = /*@__PURE__*/\n fileDesc(\"Cgthc2NuZC5wcm90bxIIYXNjbmQudjEipAEKElN1Ym1pdFNjb3JlUmVxdWVzdBIWCg5sZWFkZXJib2FyZF9pZBgBIAEoCRIRCglwbGF5ZXJfaWQYAiABKAkSDQoFc2NvcmUYAyABKAMSFQoIbWV0YWRhdGEYBCABKAxIAIgBARIcCg9pZGVtcG90ZW5jeV9rZXkYBSABKAlIAYgBAUILCglfbWV0YWRhdGFCEgoQX2lkZW1wb3RlbmN5X2tleSKlAQoTU3VibWl0U2NvcmVSZXNwb25zZRIQCghzY29yZV9pZBgBIAEoCRIMCgRyYW5rGAIgASgFEhMKC2lzX25ld19iZXN0GAMgASgIEhgKEHdhc19kZWR1cGxpY2F0ZWQYBCABKAgSMQoJYW50aWNoZWF0GAUgASgLMhkuYXNjbmQudjEuQW50aWNoZWF0UmVzdWx0SACIAQFCDAoKX2FudGljaGVhdCJjCg9BbnRpY2hlYXRSZXN1bHQSDgoGcGFzc2VkGAEgASgIEjAKCnZpb2xhdGlvbnMYAiADKAsyHC5hc2NuZC52MS5BbnRpY2hlYXRWaW9sYXRpb24SDgoGYWN0aW9uGAMgASgJIjcKEkFudGljaGVhdFZpb2xhdGlvbhIRCglmbGFnX3R5cGUYASABKAkSDgoGcmVhc29uGAIgASgJIrMBChVHZXRMZWFkZXJib2FyZFJlcXVlc3QSFgoObGVhZGVyYm9hcmRfaWQYASABKAkSEgoFbGltaXQYAiABKAVIAIgBARITCgZvZmZzZXQYAyABKAVIAYgBARITCgZwZXJpb2QYBCABKAlIAogBARIWCgl2aWV3X3NsdWcYBSABKAlIA4gBAUIICgZfbGltaXRCCQoHX29mZnNldEIJCgdfcGVyaW9kQgwKCl92aWV3X3NsdWci3AEKFkdldExlYWRlcmJvYXJkUmVzcG9uc2USKwoHZW50cmllcxgBIAMoCzIaLmFzY25kLnYxLkxlYWRlcmJvYXJkRW50cnkSFQoNdG90YWxfZW50cmllcxgCIAEoBRIQCghoYXNfbW9yZRgDIAEoCBIUCgxwZXJpb2Rfc3RhcnQYBCABKAkSFwoKcGVyaW9kX2VuZBgFIAEoCUgAiAEBEiUKBHZpZXcYBiABKAsyEi5hc2NuZC52MS5WaWV3SW5mb0gBiAEBQg0KC19wZXJpb2RfZW5kQgcKBV92aWV3IrUBChBMZWFkZXJib2FyZEVudHJ5EgwKBHJhbmsYASABKAUSEQoJcGxheWVyX2lkGAIgASgJEg0KBXNjb3JlGAMgASgDEhQKDHN1Ym1pdHRlZF9hdBgEIAEoCRIVCghtZXRhZGF0YRgFIAEoDEgAiAEBEisKB2JyYWNrZXQYBiABKAsyFS5hc2NuZC52MS5CcmFja2V0SW5mb0gBiAEBQgsKCV9tZXRhZGF0YUIKCghfYnJhY2tldCJFCgtCcmFja2V0SW5mbxIKCgJpZBgBIAEoCRIMCgRuYW1lGAIgASgJEhIKBWNvbG9yGAMgASgJSACIAQFCCAoGX2NvbG9yIiYKCFZpZXdJbmZvEgwKBHNsdWcYASABKAkSDAoEbmFtZRgCIAEoCSKHAQoUR2V0UGxheWVyUmFua1JlcXVlc3QSFgoObGVhZGVyYm9hcmRfaWQYASABKAkSEQoJcGxheWVyX2lkGAIgASgJEhMKBnBlcmlvZBgDIAEoCUgAiAEBEhYKCXZpZXdfc2x1ZxgEIAEoCUgBiAEBQgkKB19wZXJpb2RCDAoKX3ZpZXdfc2x1ZyLLAgoVR2V0UGxheWVyUmFua1Jlc3BvbnNlEhEKBHJhbmsYASABKAVIAIgBARISCgVzY29yZRgCIAEoA0gBiAEBEhcKCmJlc3Rfc2NvcmUYAyABKANIAogBARIVCg10b3RhbF9lbnRyaWVzGAQgASgFEhcKCnBlcmNlbnRpbGUYBSABKAlIA4gBARIrCgdicmFja2V0GAYgASgLMhUuYXNjbmQudjEuQnJhY2tldEluZm9IBIgBARIlCgR2aWV3GAcgASgLMhIuYXNjbmQudjEuVmlld0luZm9IBYgBARIYCgtnbG9iYWxfcmFuaxgIIAEoBUgGiAEBQgcKBV9yYW5rQggKBl9zY29yZUINCgtfYmVzdF9zY29yZUINCgtfcGVyY2VudGlsZUIKCghfYnJhY2tldEIHCgVfdmlld0IOCgxfZ2xvYmFsX3JhbmsygQIKDEFzY25kU2VydmljZRJKCgtTdWJtaXRTY29yZRIcLmFzY25kLnYxLlN1Ym1pdFNjb3JlUmVxdWVzdBodLmFzY25kLnYxLlN1Ym1pdFNjb3JlUmVzcG9uc2USUwoOR2V0TGVhZGVyYm9hcmQSHy5hc2NuZC52MS5HZXRMZWFkZXJib2FyZFJlcXVlc3QaIC5hc2NuZC52MS5HZXRMZWFkZXJib2FyZFJlc3BvbnNlElAKDUdldFBsYXllclJhbmsSHi5hc2NuZC52MS5HZXRQbGF5ZXJSYW5rUmVxdWVzdBofLmFzY25kLnYxLkdldFBsYXllclJhbmtSZXNwb25zZWIGcHJvdG8z\");\n\n/**\n * SubmitScoreRequest contains the score submission details.\n *\n * @generated from message ascnd.v1.SubmitScoreRequest\n */\nexport type SubmitScoreRequest = Message<\"ascnd.v1.SubmitScoreRequest\"> & {\n /**\n * The leaderboard to submit the score to.\n *\n * @generated from field: string leaderboard_id = 1;\n */\n leaderboardId: string;\n\n /**\n * The player's unique identifier (provided by the game).\n *\n * @generated from field: string player_id = 2;\n */\n playerId: string;\n\n /**\n * The score value.\n *\n * @generated from field: int64 score = 3;\n */\n score: bigint;\n\n /**\n * Optional metadata (JSON-encoded game-specific data).\n *\n * @generated from field: optional bytes metadata = 4;\n */\n metadata?: Uint8Array;\n\n /**\n * Optional idempotency key to prevent duplicate submissions.\n *\n * @generated from field: optional string idempotency_key = 5;\n */\n idempotencyKey?: string;\n};\n\n/**\n * Describes the message ascnd.v1.SubmitScoreRequest.\n * Use `create(SubmitScoreRequestSchema)` to create a new message.\n */\nexport const SubmitScoreRequestSchema: GenMessage<SubmitScoreRequest> = /*@__PURE__*/\n messageDesc(file_ascnd, 0);\n\n/**\n * SubmitScoreResponse contains the result of the score submission.\n *\n * @generated from message ascnd.v1.SubmitScoreResponse\n */\nexport type SubmitScoreResponse = Message<\"ascnd.v1.SubmitScoreResponse\"> & {\n /**\n * The unique identifier of the submitted score.\n *\n * @generated from field: string score_id = 1;\n */\n scoreId: string;\n\n /**\n * The player's rank after this submission.\n *\n * @generated from field: int32 rank = 2;\n */\n rank: number;\n\n /**\n * Whether this is the player's new best score for this period.\n *\n * @generated from field: bool is_new_best = 3;\n */\n isNewBest: boolean;\n\n /**\n * Whether the score was deduplicated (already submitted recently).\n *\n * @generated from field: bool was_deduplicated = 4;\n */\n wasDeduplicated: boolean;\n\n /**\n * Anticheat validation result (if anticheat is enabled for this leaderboard).\n *\n * @generated from field: optional ascnd.v1.AnticheatResult anticheat = 5;\n */\n anticheat?: AnticheatResult;\n};\n\n/**\n * Describes the message ascnd.v1.SubmitScoreResponse.\n * Use `create(SubmitScoreResponseSchema)` to create a new message.\n */\nexport const SubmitScoreResponseSchema: GenMessage<SubmitScoreResponse> = /*@__PURE__*/\n messageDesc(file_ascnd, 1);\n\n/**\n * AnticheatResult contains the result of anticheat validation.\n *\n * @generated from message ascnd.v1.AnticheatResult\n */\nexport type AnticheatResult = Message<\"ascnd.v1.AnticheatResult\"> & {\n /**\n * Whether the score passed all anticheat checks.\n *\n * @generated from field: bool passed = 1;\n */\n passed: boolean;\n\n /**\n * List of violation flags that were triggered.\n *\n * @generated from field: repeated ascnd.v1.AnticheatViolation violations = 2;\n */\n violations: AnticheatViolation[];\n\n /**\n * The enforcement action taken: \"none\", \"flag\", \"shadow_ban\", or \"reject\".\n *\n * @generated from field: string action = 3;\n */\n action: string;\n};\n\n/**\n * Describes the message ascnd.v1.AnticheatResult.\n * Use `create(AnticheatResultSchema)` to create a new message.\n */\nexport const AnticheatResultSchema: GenMessage<AnticheatResult> = /*@__PURE__*/\n messageDesc(file_ascnd, 2);\n\n/**\n * AnticheatViolation describes a single anticheat rule violation.\n *\n * @generated from message ascnd.v1.AnticheatViolation\n */\nexport type AnticheatViolation = Message<\"ascnd.v1.AnticheatViolation\"> & {\n /**\n * The type of violation: \"bounds_exceeded\", \"velocity_exceeded\",\n * \"duplicate_idempotency\", \"missing_idempotency_key\".\n *\n * @generated from field: string flag_type = 1;\n */\n flagType: string;\n\n /**\n * Human-readable description of the violation.\n *\n * @generated from field: string reason = 2;\n */\n reason: string;\n};\n\n/**\n * Describes the message ascnd.v1.AnticheatViolation.\n * Use `create(AnticheatViolationSchema)` to create a new message.\n */\nexport const AnticheatViolationSchema: GenMessage<AnticheatViolation> = /*@__PURE__*/\n messageDesc(file_ascnd, 3);\n\n/**\n * GetLeaderboardRequest specifies which leaderboard and page to retrieve.\n *\n * @generated from message ascnd.v1.GetLeaderboardRequest\n */\nexport type GetLeaderboardRequest = Message<\"ascnd.v1.GetLeaderboardRequest\"> & {\n /**\n * The leaderboard to retrieve.\n *\n * @generated from field: string leaderboard_id = 1;\n */\n leaderboardId: string;\n\n /**\n * Maximum number of entries to return (default: 10, max: 100).\n *\n * @generated from field: optional int32 limit = 2;\n */\n limit?: number;\n\n /**\n * Number of entries to skip for pagination.\n *\n * @generated from field: optional int32 offset = 3;\n */\n offset?: number;\n\n /**\n * Which period to retrieve: \"current\", \"previous\", or a timestamp.\n *\n * @generated from field: optional string period = 4;\n */\n period?: string;\n\n /**\n * Optional view slug to filter by metadata criteria.\n * If provided, returns rankings within the view (not global rank).\n *\n * @generated from field: optional string view_slug = 5;\n */\n viewSlug?: string;\n};\n\n/**\n * Describes the message ascnd.v1.GetLeaderboardRequest.\n * Use `create(GetLeaderboardRequestSchema)` to create a new message.\n */\nexport const GetLeaderboardRequestSchema: GenMessage<GetLeaderboardRequest> = /*@__PURE__*/\n messageDesc(file_ascnd, 4);\n\n/**\n * GetLeaderboardResponse contains the leaderboard entries.\n *\n * @generated from message ascnd.v1.GetLeaderboardResponse\n */\nexport type GetLeaderboardResponse = Message<\"ascnd.v1.GetLeaderboardResponse\"> & {\n /**\n * The leaderboard entries.\n *\n * @generated from field: repeated ascnd.v1.LeaderboardEntry entries = 1;\n */\n entries: LeaderboardEntry[];\n\n /**\n * Approximate total number of entries.\n *\n * @generated from field: int32 total_entries = 2;\n */\n totalEntries: number;\n\n /**\n * Whether there are more entries after this page.\n *\n * @generated from field: bool has_more = 3;\n */\n hasMore: boolean;\n\n /**\n * The start of the current period (ISO 8601 timestamp).\n *\n * @generated from field: string period_start = 4;\n */\n periodStart: string;\n\n /**\n * The end of the current period, if applicable (ISO 8601 timestamp).\n *\n * @generated from field: optional string period_end = 5;\n */\n periodEnd?: string;\n\n /**\n * Active view info if filtering by view_slug.\n *\n * @generated from field: optional ascnd.v1.ViewInfo view = 6;\n */\n view?: ViewInfo;\n};\n\n/**\n * Describes the message ascnd.v1.GetLeaderboardResponse.\n * Use `create(GetLeaderboardResponseSchema)` to create a new message.\n */\nexport const GetLeaderboardResponseSchema: GenMessage<GetLeaderboardResponse> = /*@__PURE__*/\n messageDesc(file_ascnd, 5);\n\n/**\n * LeaderboardEntry represents a single entry on the leaderboard.\n *\n * @generated from message ascnd.v1.LeaderboardEntry\n */\nexport type LeaderboardEntry = Message<\"ascnd.v1.LeaderboardEntry\"> & {\n /**\n * The player's rank (1-indexed).\n *\n * @generated from field: int32 rank = 1;\n */\n rank: number;\n\n /**\n * The player's unique identifier.\n *\n * @generated from field: string player_id = 2;\n */\n playerId: string;\n\n /**\n * The player's score.\n *\n * @generated from field: int64 score = 3;\n */\n score: bigint;\n\n /**\n * When the score was submitted (ISO 8601 timestamp).\n *\n * @generated from field: string submitted_at = 4;\n */\n submittedAt: string;\n\n /**\n * Optional metadata associated with the score.\n *\n * @generated from field: optional bytes metadata = 5;\n */\n metadata?: Uint8Array;\n\n /**\n * Optional bracket assignment for this player.\n *\n * @generated from field: optional ascnd.v1.BracketInfo bracket = 6;\n */\n bracket?: BracketInfo;\n};\n\n/**\n * Describes the message ascnd.v1.LeaderboardEntry.\n * Use `create(LeaderboardEntrySchema)` to create a new message.\n */\nexport const LeaderboardEntrySchema: GenMessage<LeaderboardEntry> = /*@__PURE__*/\n messageDesc(file_ascnd, 6);\n\n/**\n * BracketInfo contains minimal bracket information.\n *\n * @generated from message ascnd.v1.BracketInfo\n */\nexport type BracketInfo = Message<\"ascnd.v1.BracketInfo\"> & {\n /**\n * The bracket's unique identifier.\n *\n * @generated from field: string id = 1;\n */\n id: string;\n\n /**\n * The bracket's name (e.g., \"Gold\", \"Silver\", \"Bronze\").\n *\n * @generated from field: string name = 2;\n */\n name: string;\n\n /**\n * Optional hex color code (e.g., \"#FF5500\") for the bracket badge.\n *\n * @generated from field: optional string color = 3;\n */\n color?: string;\n};\n\n/**\n * Describes the message ascnd.v1.BracketInfo.\n * Use `create(BracketInfoSchema)` to create a new message.\n */\nexport const BracketInfoSchema: GenMessage<BracketInfo> = /*@__PURE__*/\n messageDesc(file_ascnd, 7);\n\n/**\n * ViewInfo contains minimal metadata view information.\n *\n * @generated from message ascnd.v1.ViewInfo\n */\nexport type ViewInfo = Message<\"ascnd.v1.ViewInfo\"> & {\n /**\n * The view's slug identifier.\n *\n * @generated from field: string slug = 1;\n */\n slug: string;\n\n /**\n * The view's display name.\n *\n * @generated from field: string name = 2;\n */\n name: string;\n};\n\n/**\n * Describes the message ascnd.v1.ViewInfo.\n * Use `create(ViewInfoSchema)` to create a new message.\n */\nexport const ViewInfoSchema: GenMessage<ViewInfo> = /*@__PURE__*/\n messageDesc(file_ascnd, 8);\n\n/**\n * GetPlayerRankRequest specifies which player and leaderboard to query.\n *\n * @generated from message ascnd.v1.GetPlayerRankRequest\n */\nexport type GetPlayerRankRequest = Message<\"ascnd.v1.GetPlayerRankRequest\"> & {\n /**\n * The leaderboard to query.\n *\n * @generated from field: string leaderboard_id = 1;\n */\n leaderboardId: string;\n\n /**\n * The player's unique identifier.\n *\n * @generated from field: string player_id = 2;\n */\n playerId: string;\n\n /**\n * Which period to query: \"current\", \"previous\", or a timestamp.\n *\n * @generated from field: optional string period = 3;\n */\n period?: string;\n\n /**\n * Optional view slug to get rank within a filtered view.\n *\n * @generated from field: optional string view_slug = 4;\n */\n viewSlug?: string;\n};\n\n/**\n * Describes the message ascnd.v1.GetPlayerRankRequest.\n * Use `create(GetPlayerRankRequestSchema)` to create a new message.\n */\nexport const GetPlayerRankRequestSchema: GenMessage<GetPlayerRankRequest> = /*@__PURE__*/\n messageDesc(file_ascnd, 9);\n\n/**\n * GetPlayerRankResponse contains the player's rank information.\n *\n * @generated from message ascnd.v1.GetPlayerRankResponse\n */\nexport type GetPlayerRankResponse = Message<\"ascnd.v1.GetPlayerRankResponse\"> & {\n /**\n * The player's rank (null if not on leaderboard).\n * When querying a view, this is the rank within the view.\n *\n * @generated from field: optional int32 rank = 1;\n */\n rank?: number;\n\n /**\n * The player's current score (null if not on leaderboard).\n *\n * @generated from field: optional int64 score = 2;\n */\n score?: bigint;\n\n /**\n * The player's best score this period.\n *\n * @generated from field: optional int64 best_score = 3;\n */\n bestScore?: bigint;\n\n /**\n * Total number of entries on this leaderboard (or view if filtered).\n *\n * @generated from field: int32 total_entries = 4;\n */\n totalEntries: number;\n\n /**\n * The player's percentile (e.g., \"top 5%\").\n *\n * @generated from field: optional string percentile = 5;\n */\n percentile?: string;\n\n /**\n * Optional bracket assignment for this player.\n *\n * @generated from field: optional ascnd.v1.BracketInfo bracket = 6;\n */\n bracket?: BracketInfo;\n\n /**\n * Active view info if querying with view_slug.\n *\n * @generated from field: optional ascnd.v1.ViewInfo view = 7;\n */\n view?: ViewInfo;\n\n /**\n * Global rank when querying a view (shows overall position).\n *\n * @generated from field: optional int32 global_rank = 8;\n */\n globalRank?: number;\n};\n\n/**\n * Describes the message ascnd.v1.GetPlayerRankResponse.\n * Use `create(GetPlayerRankResponseSchema)` to create a new message.\n */\nexport const GetPlayerRankResponseSchema: GenMessage<GetPlayerRankResponse> = /*@__PURE__*/\n messageDesc(file_ascnd, 10);\n\n/**\n * AscndService provides leaderboard management for games.\n *\n * @generated from service ascnd.v1.AscndService\n */\nexport const AscndService: GenService<{\n /**\n * SubmitScore records a player's score on a leaderboard.\n *\n * @generated from rpc ascnd.v1.AscndService.SubmitScore\n */\n submitScore: {\n methodKind: \"unary\";\n input: typeof SubmitScoreRequestSchema;\n output: typeof SubmitScoreResponseSchema;\n },\n /**\n * GetLeaderboard retrieves the top scores for a leaderboard.\n *\n * @generated from rpc ascnd.v1.AscndService.GetLeaderboard\n */\n getLeaderboard: {\n methodKind: \"unary\";\n input: typeof GetLeaderboardRequestSchema;\n output: typeof GetLeaderboardResponseSchema;\n },\n /**\n * GetPlayerRank retrieves a specific player's rank and score.\n *\n * @generated from rpc ascnd.v1.AscndService.GetPlayerRank\n */\n getPlayerRank: {\n methodKind: \"unary\";\n input: typeof GetPlayerRankRequestSchema;\n output: typeof GetPlayerRankResponseSchema;\n },\n}> = /*@__PURE__*/\n serviceDesc(file_ascnd, 0);\n\n","/**\n * TypeScript types for the Ascnd gRPC API.\n *\n * Types are generated from the proto file and re-exported here.\n */\n\n// Re-export all generated types\nexport type {\n SubmitScoreRequest,\n SubmitScoreResponse,\n GetLeaderboardRequest,\n GetLeaderboardResponse,\n GetPlayerRankRequest,\n GetPlayerRankResponse,\n LeaderboardEntry,\n AnticheatResult,\n AnticheatViolation,\n BracketInfo,\n ViewInfo,\n} from \"./gen/ascnd_pb.js\";\n\n// Re-export the service definition\nexport { AscndService } from \"./gen/ascnd_pb.js\";\n\n// Re-export schemas for creating messages\nexport {\n SubmitScoreRequestSchema,\n SubmitScoreResponseSchema,\n GetLeaderboardRequestSchema,\n GetLeaderboardResponseSchema,\n GetPlayerRankRequestSchema,\n GetPlayerRankResponseSchema,\n LeaderboardEntrySchema,\n AnticheatResultSchema,\n AnticheatViolationSchema,\n BracketInfoSchema,\n ViewInfoSchema,\n} from \"./gen/ascnd_pb.js\";\n\n// ============================================================================\n// Client Configuration\n// ============================================================================\n\n/**\n * Configuration options for the Ascnd client.\n */\nexport interface AscndClientConfig {\n /** The base URL of the Ascnd API (e.g., \"https://api.ascnd.gg\"). */\n baseUrl: string;\n\n /** Your API key for authentication. */\n apiKey: string;\n\n /** Optional request timeout in milliseconds (default: 30000). */\n timeout?: number;\n}\n\n// ============================================================================\n// Error Types\n// ============================================================================\n\n/**\n * Custom error class for Ascnd API errors.\n */\nexport class AscndError extends Error {\n /** gRPC/Connect error code. */\n readonly code: string;\n\n /** Additional error details. */\n readonly details?: Record<string, unknown>;\n\n constructor(\n message: string,\n code: string,\n details?: Record<string, unknown>\n ) {\n super(message);\n this.name = \"AscndError\";\n this.code = code;\n this.details = details;\n }\n}\n","/**\n * @ascnd-gg/client - TypeScript/JavaScript client for the Ascnd leaderboard API.\n *\n * @example\n * ```typescript\n * import { AscndClient, create, SubmitScoreRequestSchema } from \"@ascnd-gg/client\";\n *\n * const client = new AscndClient({\n * baseUrl: \"https://api.ascnd.gg\",\n * apiKey: \"your-api-key\",\n * });\n *\n * // Submit a score\n * const result = await client.submitScore(\n * create(SubmitScoreRequestSchema, {\n * leaderboardId: \"high-scores\",\n * playerId: \"player-123\",\n * score: 1000n,\n * })\n * );\n *\n * console.log(`New rank: ${result.rank}`);\n * ```\n *\n * @packageDocumentation\n */\n\n// Export the main client class\nexport { AscndClient } from \"./client.js\";\n\n// Re-export create helper from protobuf for convenience\nexport { create } from \"@bufbuild/protobuf\";\n\n// Export all types\nexport type {\n // Client configuration\n AscndClientConfig,\n\n // Submit Score\n SubmitScoreRequest,\n SubmitScoreResponse,\n\n // Get Leaderboard\n GetLeaderboardRequest,\n GetLeaderboardResponse,\n LeaderboardEntry,\n\n // Get Player Rank\n GetPlayerRankRequest,\n GetPlayerRankResponse,\n\n // Anticheat\n AnticheatResult,\n AnticheatViolation,\n\n // Bracket\n BracketInfo,\n\n // View\n ViewInfo,\n} from \"./types.js\";\n\n// Export error class\nexport { AscndError } from \"./types.js\";\n\n// Export the service definition\nexport { AscndService } from \"./types.js\";\n\n// Export schemas for creating messages\nexport {\n SubmitScoreRequestSchema,\n SubmitScoreResponseSchema,\n GetLeaderboardRequestSchema,\n GetLeaderboardResponseSchema,\n GetPlayerRankRequestSchema,\n GetPlayerRankResponseSchema,\n LeaderboardEntrySchema,\n AnticheatResultSchema,\n AnticheatViolationSchema,\n BracketInfoSchema,\n ViewInfoSchema,\n} from \"./types.js\";\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/client.ts","../src/gen/ascnd_pb.ts","../src/types.ts","../src/index.ts"],"sourcesContent":["import { createClient, type Client, type Interceptor, ConnectError } from \"@connectrpc/connect\";\nimport { createGrpcWebTransport } from \"@connectrpc/connect-web\";\nimport {\n AscndService,\n type SubmitScoreRequest,\n type SubmitScoreResponse,\n type GetLeaderboardRequest,\n type GetLeaderboardResponse,\n type GetPlayerRankRequest,\n type GetPlayerRankResponse,\n AscndClientConfig,\n AscndError,\n} from \"./types.js\";\n\n/**\n * Client for the Ascnd leaderboard API using gRPC-Web.\n *\n * @example\n * ```typescript\n * import { AscndClient, create } from \"@ascnd-gg/client\";\n * import { SubmitScoreRequestSchema } from \"@ascnd-gg/client\";\n *\n * const client = new AscndClient({\n * baseUrl: \"https://api.ascnd.gg\",\n * apiKey: \"your-api-key\",\n * });\n *\n * // Submit a score\n * const result = await client.submitScore(\n * create(SubmitScoreRequestSchema, {\n * leaderboardId: \"high-scores\",\n * playerId: \"player-123\",\n * score: 1000n,\n * })\n * );\n *\n * console.log(`Rank: #${result.rank}`);\n * ```\n */\nexport class AscndClient {\n private readonly client: Client<typeof AscndService>;\n\n /**\n * Creates a new Ascnd client.\n *\n * @param config - Client configuration options.\n */\n constructor(config: AscndClientConfig) {\n if (!config.baseUrl) {\n throw new Error(\"baseUrl is required\");\n }\n if (!config.apiKey) {\n throw new Error(\"apiKey is required\");\n }\n\n // Create an interceptor to add the API key header\n const authInterceptor: Interceptor = (next) => async (req) => {\n req.header.set(\"x-api-key\", config.apiKey);\n return await next(req);\n };\n\n // Create the gRPC-Web transport\n const transport = createGrpcWebTransport({\n baseUrl: config.baseUrl.replace(/\\/$/, \"\"),\n interceptors: [authInterceptor],\n defaultTimeoutMs: config.timeout ?? 30000,\n });\n\n this.client = createClient(AscndService, transport);\n }\n\n /**\n * Submits a player's score to a leaderboard.\n *\n * @param request - The score submission request.\n * @returns The submission result including the player's new rank.\n * @throws {AscndError} If the API returns an error.\n *\n * @example\n * ```typescript\n * import { create } from \"@bufbuild/protobuf\";\n * import { SubmitScoreRequestSchema } from \"@ascnd-gg/client\";\n *\n * const result = await client.submitScore(\n * create(SubmitScoreRequestSchema, {\n * leaderboardId: \"high-scores\",\n * playerId: \"player-123\",\n * score: 1000n,\n * metadata: new TextEncoder().encode(JSON.stringify({ level: 5 })),\n * })\n * );\n *\n * console.log(`New rank: ${result.rank}`);\n * if (result.isNewBest) {\n * console.log(\"New personal best!\");\n * }\n * if (result.anticheat && !result.anticheat.passed) {\n * console.log(\"Anticheat flagged:\", result.anticheat.violations);\n * }\n * ```\n */\n async submitScore(request: SubmitScoreRequest): Promise<SubmitScoreResponse> {\n try {\n return await this.client.submitScore(request);\n } catch (error) {\n throw this.convertError(error);\n }\n }\n\n /**\n * Retrieves the top scores for a leaderboard.\n *\n * @param request - The leaderboard request parameters.\n * @returns The leaderboard entries and pagination info.\n * @throws {AscndError} If the API returns an error.\n *\n * @example\n * ```typescript\n * import { create } from \"@bufbuild/protobuf\";\n * import { GetLeaderboardRequestSchema } from \"@ascnd-gg/client\";\n *\n * const leaderboard = await client.getLeaderboard(\n * create(GetLeaderboardRequestSchema, {\n * leaderboardId: \"high-scores\",\n * limit: 10,\n * viewSlug: \"platform-pc\", // Filter by metadata view\n * })\n * );\n *\n * for (const entry of leaderboard.entries) {\n * console.log(`#${entry.rank}: ${entry.playerId} - ${entry.score}`);\n * if (entry.bracket) {\n * console.log(` Bracket: ${entry.bracket.name}`);\n * }\n * }\n * ```\n */\n async getLeaderboard(\n request: GetLeaderboardRequest\n ): Promise<GetLeaderboardResponse> {\n try {\n return await this.client.getLeaderboard(request);\n } catch (error) {\n throw this.convertError(error);\n }\n }\n\n /**\n * Retrieves a specific player's rank and score information.\n *\n * @param request - The player rank request parameters.\n * @returns The player's rank, score, and percentile information.\n * @throws {AscndError} If the API returns an error.\n *\n * @example\n * ```typescript\n * import { create } from \"@bufbuild/protobuf\";\n * import { GetPlayerRankRequestSchema } from \"@ascnd-gg/client\";\n *\n * const playerRank = await client.getPlayerRank(\n * create(GetPlayerRankRequestSchema, {\n * leaderboardId: \"high-scores\",\n * playerId: \"player-123\",\n * viewSlug: \"platform-pc\",\n * })\n * );\n *\n * if (playerRank.rank !== undefined) {\n * console.log(`Rank: #${playerRank.rank}`);\n * console.log(`Score: ${playerRank.score}`);\n * console.log(`Percentile: ${playerRank.percentile}`);\n * if (playerRank.bracket) {\n * console.log(`Bracket: ${playerRank.bracket.name}`);\n * }\n * if (playerRank.globalRank !== undefined) {\n * console.log(`Global Rank: #${playerRank.globalRank}`);\n * }\n * } else {\n * console.log(\"Player not on leaderboard\");\n * }\n * ```\n */\n async getPlayerRank(\n request: GetPlayerRankRequest\n ): Promise<GetPlayerRankResponse> {\n try {\n return await this.client.getPlayerRank(request);\n } catch (error) {\n throw this.convertError(error);\n }\n }\n\n /**\n * Converts a Connect error to an AscndError.\n */\n private convertError(error: unknown): AscndError {\n if (error instanceof ConnectError) {\n return new AscndError(\n error.message,\n error.code.toString(),\n error.details?.length ? { details: error.details } : undefined\n );\n }\n if (error instanceof Error) {\n return new AscndError(error.message, \"UNKNOWN\");\n }\n return new AscndError(\"Unknown error occurred\", \"UNKNOWN\");\n }\n}\n","// @generated by protoc-gen-es v2.10.2 with parameter \"target=ts\"\n// @generated from file ascnd.proto (package ascnd.v1, syntax proto3)\n/* eslint-disable */\n\nimport type { GenFile, GenMessage, GenService } from \"@bufbuild/protobuf/codegenv2\";\nimport { fileDesc, messageDesc, serviceDesc } from \"@bufbuild/protobuf/codegenv2\";\nimport type { Message } from \"@bufbuild/protobuf\";\n\n/**\n * Describes the file ascnd.proto.\n */\nexport const file_ascnd: GenFile = /*@__PURE__*/\n fileDesc(\"Cgthc2NuZC5wcm90bxIIYXNjbmQudjEipAEKElN1Ym1pdFNjb3JlUmVxdWVzdBIWCg5sZWFkZXJib2FyZF9pZBgBIAEoCRIRCglwbGF5ZXJfaWQYAiABKAkSDQoFc2NvcmUYAyABKAMSFQoIbWV0YWRhdGEYBCABKAxIAIgBARIcCg9pZGVtcG90ZW5jeV9rZXkYBSABKAlIAYgBAUILCglfbWV0YWRhdGFCEgoQX2lkZW1wb3RlbmN5X2tleSKlAQoTU3VibWl0U2NvcmVSZXNwb25zZRIQCghzY29yZV9pZBgBIAEoCRIMCgRyYW5rGAIgASgFEhMKC2lzX25ld19iZXN0GAMgASgIEhgKEHdhc19kZWR1cGxpY2F0ZWQYBCABKAgSMQoJYW50aWNoZWF0GAUgASgLMhkuYXNjbmQudjEuQW50aWNoZWF0UmVzdWx0SACIAQFCDAoKX2FudGljaGVhdCJjCg9BbnRpY2hlYXRSZXN1bHQSDgoGcGFzc2VkGAEgASgIEjAKCnZpb2xhdGlvbnMYAiADKAsyHC5hc2NuZC52MS5BbnRpY2hlYXRWaW9sYXRpb24SDgoGYWN0aW9uGAMgASgJIjcKEkFudGljaGVhdFZpb2xhdGlvbhIRCglmbGFnX3R5cGUYASABKAkSDgoGcmVhc29uGAIgASgJIusBChVHZXRMZWFkZXJib2FyZFJlcXVlc3QSFgoObGVhZGVyYm9hcmRfaWQYASABKAkSEgoFbGltaXQYAiABKAVIAIgBARITCgZwZXJpb2QYBCABKAlIAYgBARIWCgl2aWV3X3NsdWcYBSABKAlIAogBARITCgZjdXJzb3IYBiABKAlIA4gBARIYCgthcm91bmRfcmFuaxgHIAEoBUgEiAEBQggKBl9saW1pdEIJCgdfcGVyaW9kQgwKCl92aWV3X3NsdWdCCQoHX2N1cnNvckIOCgxfYXJvdW5kX3JhbmtKBAgDEARSBm9mZnNldCKGAgoWR2V0TGVhZGVyYm9hcmRSZXNwb25zZRIrCgdlbnRyaWVzGAEgAygLMhouYXNjbmQudjEuTGVhZGVyYm9hcmRFbnRyeRIVCg10b3RhbF9lbnRyaWVzGAIgASgFEhAKCGhhc19tb3JlGAMgASgIEhQKDHBlcmlvZF9zdGFydBgEIAEoCRIXCgpwZXJpb2RfZW5kGAUgASgJSACIAQESJQoEdmlldxgGIAEoCzISLmFzY25kLnYxLlZpZXdJbmZvSAGIAQESGAoLbmV4dF9jdXJzb3IYByABKAlIAogBAUINCgtfcGVyaW9kX2VuZEIHCgVfdmlld0IOCgxfbmV4dF9jdXJzb3IitQEKEExlYWRlcmJvYXJkRW50cnkSDAoEcmFuaxgBIAEoBRIRCglwbGF5ZXJfaWQYAiABKAkSDQoFc2NvcmUYAyABKAMSFAoMc3VibWl0dGVkX2F0GAQgASgJEhUKCG1ldGFkYXRhGAUgASgMSACIAQESKwoHYnJhY2tldBgGIAEoCzIVLmFzY25kLnYxLkJyYWNrZXRJbmZvSAGIAQFCCwoJX21ldGFkYXRhQgoKCF9icmFja2V0IkUKC0JyYWNrZXRJbmZvEgoKAmlkGAEgASgJEgwKBG5hbWUYAiABKAkSEgoFY29sb3IYAyABKAlIAIgBAUIICgZfY29sb3IiJgoIVmlld0luZm8SDAoEc2x1ZxgBIAEoCRIMCgRuYW1lGAIgASgJIocBChRHZXRQbGF5ZXJSYW5rUmVxdWVzdBIWCg5sZWFkZXJib2FyZF9pZBgBIAEoCRIRCglwbGF5ZXJfaWQYAiABKAkSEwoGcGVyaW9kGAMgASgJSACIAQESFgoJdmlld19zbHVnGAQgASgJSAGIAQFCCQoHX3BlcmlvZEIMCgpfdmlld19zbHVnIssCChVHZXRQbGF5ZXJSYW5rUmVzcG9uc2USEQoEcmFuaxgBIAEoBUgAiAEBEhIKBXNjb3JlGAIgASgDSAGIAQESFwoKYmVzdF9zY29yZRgDIAEoA0gCiAEBEhUKDXRvdGFsX2VudHJpZXMYBCABKAUSFwoKcGVyY2VudGlsZRgFIAEoCUgDiAEBEisKB2JyYWNrZXQYBiABKAsyFS5hc2NuZC52MS5CcmFja2V0SW5mb0gEiAEBEiUKBHZpZXcYByABKAsyEi5hc2NuZC52MS5WaWV3SW5mb0gFiAEBEhgKC2dsb2JhbF9yYW5rGAggASgFSAaIAQFCBwoFX3JhbmtCCAoGX3Njb3JlQg0KC19iZXN0X3Njb3JlQg0KC19wZXJjZW50aWxlQgoKCF9icmFja2V0QgcKBV92aWV3Qg4KDF9nbG9iYWxfcmFuazKBAgoMQXNjbmRTZXJ2aWNlEkoKC1N1Ym1pdFNjb3JlEhwuYXNjbmQudjEuU3VibWl0U2NvcmVSZXF1ZXN0Gh0uYXNjbmQudjEuU3VibWl0U2NvcmVSZXNwb25zZRJTCg5HZXRMZWFkZXJib2FyZBIfLmFzY25kLnYxLkdldExlYWRlcmJvYXJkUmVxdWVzdBogLmFzY25kLnYxLkdldExlYWRlcmJvYXJkUmVzcG9uc2USUAoNR2V0UGxheWVyUmFuaxIeLmFzY25kLnYxLkdldFBsYXllclJhbmtSZXF1ZXN0Gh8uYXNjbmQudjEuR2V0UGxheWVyUmFua1Jlc3BvbnNlYgZwcm90bzM\");\n\n/**\n * SubmitScoreRequest contains the score submission details.\n *\n * @generated from message ascnd.v1.SubmitScoreRequest\n */\nexport type SubmitScoreRequest = Message<\"ascnd.v1.SubmitScoreRequest\"> & {\n /**\n * The leaderboard to submit the score to.\n *\n * @generated from field: string leaderboard_id = 1;\n */\n leaderboardId: string;\n\n /**\n * The player's unique identifier (provided by the game).\n *\n * @generated from field: string player_id = 2;\n */\n playerId: string;\n\n /**\n * The score value.\n *\n * @generated from field: int64 score = 3;\n */\n score: bigint;\n\n /**\n * Optional metadata (JSON-encoded game-specific data).\n *\n * @generated from field: optional bytes metadata = 4;\n */\n metadata?: Uint8Array;\n\n /**\n * Optional idempotency key to prevent duplicate submissions.\n *\n * @generated from field: optional string idempotency_key = 5;\n */\n idempotencyKey?: string;\n};\n\n/**\n * Describes the message ascnd.v1.SubmitScoreRequest.\n * Use `create(SubmitScoreRequestSchema)` to create a new message.\n */\nexport const SubmitScoreRequestSchema: GenMessage<SubmitScoreRequest> = /*@__PURE__*/\n messageDesc(file_ascnd, 0);\n\n/**\n * SubmitScoreResponse contains the result of the score submission.\n *\n * @generated from message ascnd.v1.SubmitScoreResponse\n */\nexport type SubmitScoreResponse = Message<\"ascnd.v1.SubmitScoreResponse\"> & {\n /**\n * The unique identifier of the submitted score.\n *\n * @generated from field: string score_id = 1;\n */\n scoreId: string;\n\n /**\n * The player's rank after this submission.\n *\n * @generated from field: int32 rank = 2;\n */\n rank: number;\n\n /**\n * Whether this is the player's new best score for this period.\n *\n * @generated from field: bool is_new_best = 3;\n */\n isNewBest: boolean;\n\n /**\n * Whether the score was deduplicated (already submitted recently).\n *\n * @generated from field: bool was_deduplicated = 4;\n */\n wasDeduplicated: boolean;\n\n /**\n * Anticheat validation result (if anticheat is enabled for this leaderboard).\n *\n * @generated from field: optional ascnd.v1.AnticheatResult anticheat = 5;\n */\n anticheat?: AnticheatResult;\n};\n\n/**\n * Describes the message ascnd.v1.SubmitScoreResponse.\n * Use `create(SubmitScoreResponseSchema)` to create a new message.\n */\nexport const SubmitScoreResponseSchema: GenMessage<SubmitScoreResponse> = /*@__PURE__*/\n messageDesc(file_ascnd, 1);\n\n/**\n * AnticheatResult contains the result of anticheat validation.\n *\n * @generated from message ascnd.v1.AnticheatResult\n */\nexport type AnticheatResult = Message<\"ascnd.v1.AnticheatResult\"> & {\n /**\n * Whether the score passed all anticheat checks.\n *\n * @generated from field: bool passed = 1;\n */\n passed: boolean;\n\n /**\n * List of violation flags that were triggered.\n *\n * @generated from field: repeated ascnd.v1.AnticheatViolation violations = 2;\n */\n violations: AnticheatViolation[];\n\n /**\n * The enforcement action taken: \"none\", \"flag\", \"shadow_ban\", or \"reject\".\n *\n * @generated from field: string action = 3;\n */\n action: string;\n};\n\n/**\n * Describes the message ascnd.v1.AnticheatResult.\n * Use `create(AnticheatResultSchema)` to create a new message.\n */\nexport const AnticheatResultSchema: GenMessage<AnticheatResult> = /*@__PURE__*/\n messageDesc(file_ascnd, 2);\n\n/**\n * AnticheatViolation describes a single anticheat rule violation.\n *\n * @generated from message ascnd.v1.AnticheatViolation\n */\nexport type AnticheatViolation = Message<\"ascnd.v1.AnticheatViolation\"> & {\n /**\n * The type of violation: \"bounds_exceeded\", \"velocity_exceeded\",\n * \"duplicate_idempotency\", \"missing_idempotency_key\".\n *\n * @generated from field: string flag_type = 1;\n */\n flagType: string;\n\n /**\n * Human-readable description of the violation.\n *\n * @generated from field: string reason = 2;\n */\n reason: string;\n};\n\n/**\n * Describes the message ascnd.v1.AnticheatViolation.\n * Use `create(AnticheatViolationSchema)` to create a new message.\n */\nexport const AnticheatViolationSchema: GenMessage<AnticheatViolation> = /*@__PURE__*/\n messageDesc(file_ascnd, 3);\n\n/**\n * GetLeaderboardRequest specifies which leaderboard and page to retrieve.\n *\n * @generated from message ascnd.v1.GetLeaderboardRequest\n */\nexport type GetLeaderboardRequest = Message<\"ascnd.v1.GetLeaderboardRequest\"> & {\n /**\n * The leaderboard to retrieve.\n *\n * @generated from field: string leaderboard_id = 1;\n */\n leaderboardId: string;\n\n /**\n * Maximum number of entries to return (default: 10, max: 100).\n *\n * @generated from field: optional int32 limit = 2;\n */\n limit?: number;\n\n /**\n * Which period to retrieve: \"current\", \"previous\", or a timestamp.\n *\n * @generated from field: optional string period = 4;\n */\n period?: string;\n\n /**\n * Optional view slug to filter by metadata criteria.\n * If provided, returns rankings within the view (not global rank).\n *\n * @generated from field: optional string view_slug = 5;\n */\n viewSlug?: string;\n\n /**\n * Cursor for keyset pagination (encodes score + player_id).\n * When provided, returns entries after this cursor position.\n *\n * @generated from field: optional string cursor = 6;\n */\n cursor?: string;\n\n /**\n * Jump to a specific rank position.\n * Returns entries starting from this rank, with cursor for continuation.\n * Use this instead of offset for random access to leaderboard positions.\n *\n * @generated from field: optional int32 around_rank = 7;\n */\n aroundRank?: number;\n};\n\n/**\n * Describes the message ascnd.v1.GetLeaderboardRequest.\n * Use `create(GetLeaderboardRequestSchema)` to create a new message.\n */\nexport const GetLeaderboardRequestSchema: GenMessage<GetLeaderboardRequest> = /*@__PURE__*/\n messageDesc(file_ascnd, 4);\n\n/**\n * GetLeaderboardResponse contains the leaderboard entries.\n *\n * @generated from message ascnd.v1.GetLeaderboardResponse\n */\nexport type GetLeaderboardResponse = Message<\"ascnd.v1.GetLeaderboardResponse\"> & {\n /**\n * The leaderboard entries.\n *\n * @generated from field: repeated ascnd.v1.LeaderboardEntry entries = 1;\n */\n entries: LeaderboardEntry[];\n\n /**\n * Approximate total number of entries.\n *\n * @generated from field: int32 total_entries = 2;\n */\n totalEntries: number;\n\n /**\n * Whether there are more entries after this page.\n *\n * @generated from field: bool has_more = 3;\n */\n hasMore: boolean;\n\n /**\n * The start of the current period (ISO 8601 timestamp).\n *\n * @generated from field: string period_start = 4;\n */\n periodStart: string;\n\n /**\n * The end of the current period, if applicable (ISO 8601 timestamp).\n *\n * @generated from field: optional string period_end = 5;\n */\n periodEnd?: string;\n\n /**\n * Active view info if filtering by view_slug.\n *\n * @generated from field: optional ascnd.v1.ViewInfo view = 6;\n */\n view?: ViewInfo;\n\n /**\n * Cursor for fetching the next page (keyset pagination).\n * Only present when has_more is true.\n *\n * @generated from field: optional string next_cursor = 7;\n */\n nextCursor?: string;\n};\n\n/**\n * Describes the message ascnd.v1.GetLeaderboardResponse.\n * Use `create(GetLeaderboardResponseSchema)` to create a new message.\n */\nexport const GetLeaderboardResponseSchema: GenMessage<GetLeaderboardResponse> = /*@__PURE__*/\n messageDesc(file_ascnd, 5);\n\n/**\n * LeaderboardEntry represents a single entry on the leaderboard.\n *\n * @generated from message ascnd.v1.LeaderboardEntry\n */\nexport type LeaderboardEntry = Message<\"ascnd.v1.LeaderboardEntry\"> & {\n /**\n * The player's rank (1-indexed).\n *\n * @generated from field: int32 rank = 1;\n */\n rank: number;\n\n /**\n * The player's unique identifier.\n *\n * @generated from field: string player_id = 2;\n */\n playerId: string;\n\n /**\n * The player's score.\n *\n * @generated from field: int64 score = 3;\n */\n score: bigint;\n\n /**\n * When the score was submitted (ISO 8601 timestamp).\n *\n * @generated from field: string submitted_at = 4;\n */\n submittedAt: string;\n\n /**\n * Optional metadata associated with the score.\n *\n * @generated from field: optional bytes metadata = 5;\n */\n metadata?: Uint8Array;\n\n /**\n * Optional bracket assignment for this player.\n *\n * @generated from field: optional ascnd.v1.BracketInfo bracket = 6;\n */\n bracket?: BracketInfo;\n};\n\n/**\n * Describes the message ascnd.v1.LeaderboardEntry.\n * Use `create(LeaderboardEntrySchema)` to create a new message.\n */\nexport const LeaderboardEntrySchema: GenMessage<LeaderboardEntry> = /*@__PURE__*/\n messageDesc(file_ascnd, 6);\n\n/**\n * BracketInfo contains minimal bracket information.\n *\n * @generated from message ascnd.v1.BracketInfo\n */\nexport type BracketInfo = Message<\"ascnd.v1.BracketInfo\"> & {\n /**\n * The bracket's unique identifier.\n *\n * @generated from field: string id = 1;\n */\n id: string;\n\n /**\n * The bracket's name (e.g., \"Gold\", \"Silver\", \"Bronze\").\n *\n * @generated from field: string name = 2;\n */\n name: string;\n\n /**\n * Optional hex color code (e.g., \"#FF5500\") for the bracket badge.\n *\n * @generated from field: optional string color = 3;\n */\n color?: string;\n};\n\n/**\n * Describes the message ascnd.v1.BracketInfo.\n * Use `create(BracketInfoSchema)` to create a new message.\n */\nexport const BracketInfoSchema: GenMessage<BracketInfo> = /*@__PURE__*/\n messageDesc(file_ascnd, 7);\n\n/**\n * ViewInfo contains minimal metadata view information.\n *\n * @generated from message ascnd.v1.ViewInfo\n */\nexport type ViewInfo = Message<\"ascnd.v1.ViewInfo\"> & {\n /**\n * The view's slug identifier.\n *\n * @generated from field: string slug = 1;\n */\n slug: string;\n\n /**\n * The view's display name.\n *\n * @generated from field: string name = 2;\n */\n name: string;\n};\n\n/**\n * Describes the message ascnd.v1.ViewInfo.\n * Use `create(ViewInfoSchema)` to create a new message.\n */\nexport const ViewInfoSchema: GenMessage<ViewInfo> = /*@__PURE__*/\n messageDesc(file_ascnd, 8);\n\n/**\n * GetPlayerRankRequest specifies which player and leaderboard to query.\n *\n * @generated from message ascnd.v1.GetPlayerRankRequest\n */\nexport type GetPlayerRankRequest = Message<\"ascnd.v1.GetPlayerRankRequest\"> & {\n /**\n * The leaderboard to query.\n *\n * @generated from field: string leaderboard_id = 1;\n */\n leaderboardId: string;\n\n /**\n * The player's unique identifier.\n *\n * @generated from field: string player_id = 2;\n */\n playerId: string;\n\n /**\n * Which period to query: \"current\", \"previous\", or a timestamp.\n *\n * @generated from field: optional string period = 3;\n */\n period?: string;\n\n /**\n * Optional view slug to get rank within a filtered view.\n *\n * @generated from field: optional string view_slug = 4;\n */\n viewSlug?: string;\n};\n\n/**\n * Describes the message ascnd.v1.GetPlayerRankRequest.\n * Use `create(GetPlayerRankRequestSchema)` to create a new message.\n */\nexport const GetPlayerRankRequestSchema: GenMessage<GetPlayerRankRequest> = /*@__PURE__*/\n messageDesc(file_ascnd, 9);\n\n/**\n * GetPlayerRankResponse contains the player's rank information.\n *\n * @generated from message ascnd.v1.GetPlayerRankResponse\n */\nexport type GetPlayerRankResponse = Message<\"ascnd.v1.GetPlayerRankResponse\"> & {\n /**\n * The player's rank (null if not on leaderboard).\n * When querying a view, this is the rank within the view.\n *\n * @generated from field: optional int32 rank = 1;\n */\n rank?: number;\n\n /**\n * The player's current score (null if not on leaderboard).\n *\n * @generated from field: optional int64 score = 2;\n */\n score?: bigint;\n\n /**\n * The player's best score this period.\n *\n * @generated from field: optional int64 best_score = 3;\n */\n bestScore?: bigint;\n\n /**\n * Total number of entries on this leaderboard (or view if filtered).\n *\n * @generated from field: int32 total_entries = 4;\n */\n totalEntries: number;\n\n /**\n * The player's percentile (e.g., \"top 5%\").\n *\n * @generated from field: optional string percentile = 5;\n */\n percentile?: string;\n\n /**\n * Optional bracket assignment for this player.\n *\n * @generated from field: optional ascnd.v1.BracketInfo bracket = 6;\n */\n bracket?: BracketInfo;\n\n /**\n * Active view info if querying with view_slug.\n *\n * @generated from field: optional ascnd.v1.ViewInfo view = 7;\n */\n view?: ViewInfo;\n\n /**\n * Global rank when querying a view (shows overall position).\n *\n * @generated from field: optional int32 global_rank = 8;\n */\n globalRank?: number;\n};\n\n/**\n * Describes the message ascnd.v1.GetPlayerRankResponse.\n * Use `create(GetPlayerRankResponseSchema)` to create a new message.\n */\nexport const GetPlayerRankResponseSchema: GenMessage<GetPlayerRankResponse> = /*@__PURE__*/\n messageDesc(file_ascnd, 10);\n\n/**\n * AscndService provides leaderboard management for games.\n *\n * @generated from service ascnd.v1.AscndService\n */\nexport const AscndService: GenService<{\n /**\n * SubmitScore records a player's score on a leaderboard.\n *\n * @generated from rpc ascnd.v1.AscndService.SubmitScore\n */\n submitScore: {\n methodKind: \"unary\";\n input: typeof SubmitScoreRequestSchema;\n output: typeof SubmitScoreResponseSchema;\n },\n /**\n * GetLeaderboard retrieves the top scores for a leaderboard.\n *\n * @generated from rpc ascnd.v1.AscndService.GetLeaderboard\n */\n getLeaderboard: {\n methodKind: \"unary\";\n input: typeof GetLeaderboardRequestSchema;\n output: typeof GetLeaderboardResponseSchema;\n },\n /**\n * GetPlayerRank retrieves a specific player's rank and score.\n *\n * @generated from rpc ascnd.v1.AscndService.GetPlayerRank\n */\n getPlayerRank: {\n methodKind: \"unary\";\n input: typeof GetPlayerRankRequestSchema;\n output: typeof GetPlayerRankResponseSchema;\n },\n}> = /*@__PURE__*/\n serviceDesc(file_ascnd, 0);\n\n","/**\n * TypeScript types for the Ascnd gRPC API.\n *\n * Types are generated from the proto file and re-exported here.\n */\n\n// Re-export all generated types\nexport type {\n SubmitScoreRequest,\n SubmitScoreResponse,\n GetLeaderboardRequest,\n GetLeaderboardResponse,\n GetPlayerRankRequest,\n GetPlayerRankResponse,\n LeaderboardEntry,\n AnticheatResult,\n AnticheatViolation,\n BracketInfo,\n ViewInfo,\n} from \"./gen/ascnd_pb.js\";\n\n// Re-export the service definition\nexport { AscndService } from \"./gen/ascnd_pb.js\";\n\n// Re-export schemas for creating messages\nexport {\n SubmitScoreRequestSchema,\n SubmitScoreResponseSchema,\n GetLeaderboardRequestSchema,\n GetLeaderboardResponseSchema,\n GetPlayerRankRequestSchema,\n GetPlayerRankResponseSchema,\n LeaderboardEntrySchema,\n AnticheatResultSchema,\n AnticheatViolationSchema,\n BracketInfoSchema,\n ViewInfoSchema,\n} from \"./gen/ascnd_pb.js\";\n\n// ============================================================================\n// Client Configuration\n// ============================================================================\n\n/**\n * Configuration options for the Ascnd client.\n */\nexport interface AscndClientConfig {\n /** The base URL of the Ascnd API (e.g., \"https://api.ascnd.gg\"). */\n baseUrl: string;\n\n /** Your API key for authentication. */\n apiKey: string;\n\n /** Optional request timeout in milliseconds (default: 30000). */\n timeout?: number;\n}\n\n// ============================================================================\n// Error Types\n// ============================================================================\n\n/**\n * Custom error class for Ascnd API errors.\n */\nexport class AscndError extends Error {\n /** gRPC/Connect error code. */\n readonly code: string;\n\n /** Additional error details. */\n readonly details?: Record<string, unknown>;\n\n constructor(\n message: string,\n code: string,\n details?: Record<string, unknown>\n ) {\n super(message);\n this.name = \"AscndError\";\n this.code = code;\n this.details = details;\n }\n}\n","/**\n * @ascnd-gg/client - TypeScript/JavaScript client for the Ascnd leaderboard API.\n *\n * @example\n * ```typescript\n * import { AscndClient, create, SubmitScoreRequestSchema } from \"@ascnd-gg/client\";\n *\n * const client = new AscndClient({\n * baseUrl: \"https://api.ascnd.gg\",\n * apiKey: \"your-api-key\",\n * });\n *\n * // Submit a score\n * const result = await client.submitScore(\n * create(SubmitScoreRequestSchema, {\n * leaderboardId: \"high-scores\",\n * playerId: \"player-123\",\n * score: 1000n,\n * })\n * );\n *\n * console.log(`New rank: ${result.rank}`);\n * ```\n *\n * @packageDocumentation\n */\n\n// Export the main client class\nexport { AscndClient } from \"./client.js\";\n\n// Re-export create helper from protobuf for convenience\nexport { create } from \"@bufbuild/protobuf\";\n\n// Export all types\nexport type {\n // Client configuration\n AscndClientConfig,\n\n // Submit Score\n SubmitScoreRequest,\n SubmitScoreResponse,\n\n // Get Leaderboard\n GetLeaderboardRequest,\n GetLeaderboardResponse,\n LeaderboardEntry,\n\n // Get Player Rank\n GetPlayerRankRequest,\n GetPlayerRankResponse,\n\n // Anticheat\n AnticheatResult,\n AnticheatViolation,\n\n // Bracket\n BracketInfo,\n\n // View\n ViewInfo,\n} from \"./types.js\";\n\n// Export error class\nexport { AscndError } from \"./types.js\";\n\n// Export the service definition\nexport { AscndService } from \"./types.js\";\n\n// Export schemas for creating messages\nexport {\n SubmitScoreRequestSchema,\n SubmitScoreResponseSchema,\n GetLeaderboardRequestSchema,\n GetLeaderboardResponseSchema,\n GetPlayerRankRequestSchema,\n GetPlayerRankResponseSchema,\n LeaderboardEntrySchema,\n AnticheatResultSchema,\n AnticheatViolationSchema,\n BracketInfoSchema,\n ViewInfoSchema,\n} from \"./types.js\";\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ascnd-gg/client",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "TypeScript/JavaScript client for the Ascnd leaderboard API",
5
5
  "author": "Ascnd",
6
6
  "license": "MIT",