Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/dashboard/test/activity-hash-chain-durable.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ if (!connectionString) {
const repository = new DurableActivityRepository(connectionString);
const storage = new DurableActivityStorage({ ttlSeconds: 3600 });

await repository.append({
await repository.append("guild-1", {
type: "member.joined",
source: "dashboard",
severity: "info",
Expand All @@ -86,7 +86,7 @@ if (!connectionString) {
),
"recorded",
);
await repository.append({
await repository.append("guild-1", {
type: "pass.created",
source: "dashboard",
severity: "info",
Expand Down
2 changes: 1 addition & 1 deletion apps/dashboard/test/activity-hash-chain.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ describe("activity hash-chain canonical format", () => {

test("mock repository events remain unhashed application events", async () => {
const repository = new DurableActivityRepository("mock://activity-chain");
const event = await repository.append({
const event = await repository.append("guild-1", {
type: "member.joined",
source: "dashboard",
severity: "info",
Expand Down
2 changes: 1 addition & 1 deletion apps/dashboard/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"ignoreDeprecations": "5.0",
"paths": {
"@/*": ["./*"],
"@guildpass/env": ["../../packages/env/src/index.ts"],
"@guildpass/env": ["../../packages/env/dist/index.d.ts"],
"@guildpass/integration-client/*": ["../../packages/integration-client/*"],
"@guildpass/mock-repositories": ["../../packages/integration-client/mock/mockRepositories"]
}
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"typecheck": "pnpm -r typecheck",
"lint": "pnpm -r lint",
"test": "pnpm -r test",
"test:run": "pnpm -r test",
"test:webhook-utils": "pnpm --filter @guildpass/webhook-utils test",
"db:migrate": "pnpm --filter @guildpass/dashboard db:migrate",
"db:seed": "pnpm --filter @guildpass/dashboard db:seed",
Expand Down
44 changes: 44 additions & 0 deletions packages/integration-client/src/errors/GuildPassError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import type { ErrorCode } from "./errorCodes.js";
import { ErrorCodes } from "./errorCodes.js";
import type { GuildPassErrorOptions, IGuildPassError } from "./error.types.js";

/**
* Base error class for all GuildPass SDK and platform errors.
*
* Every specific error subclass inherits from `GuildPassError`, preserving
* `instanceof GuildPassError` checks and maintaining the `code` property for
* backward compatibility with string-based checks.
*/
export class GuildPassError extends Error implements IGuildPassError {
readonly code: ErrorCode;
readonly statusCode?: number;
readonly details?: unknown;
readonly cause?: unknown;

constructor(message?: string, options: GuildPassErrorOptions = {}) {
const msg = message || options.message || "An unexpected GuildPass error occurred.";
super(msg);
this.name = new.target.name || "GuildPassError";
this.code = options.code ?? ErrorCodes.INTERNAL_ERROR;
this.statusCode = options.statusCode;
this.details = options.details;
this.cause = options.cause;

// Restore prototype chain for proper `instanceof` support across transpilation targets
Object.setPrototypeOf(this, new.target.prototype);
}

/**
* Format the error as a JSON object suitable for serialization or logging.
*/
toJSON(): Record<string, unknown> {
return {
name: this.name,
code: this.code,
message: this.message,
...(this.statusCode !== undefined ? { statusCode: this.statusCode } : {}),
...(this.details !== undefined ? { details: this.details } : {}),
...(this.cause !== undefined ? { cause: this.cause } : {}),
};
}
}
28 changes: 28 additions & 0 deletions packages/integration-client/src/errors/error.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { ErrorCode } from "./errorCodes.js";

/**
* Options for constructing a GuildPassError or one of its subclasses.
*/
export interface GuildPassErrorOptions {
/** A human-readable description of the error. */
message?: string;
/** The error code identifying the type of error. */
code?: ErrorCode;
/** Optional HTTP status code associated with the error. */
statusCode?: number;
/** Additional structured metadata or details. */
details?: unknown;
/** The underlying cause of the error. */
cause?: unknown;
}

/**
* Interface representing common error properties across GuildPass errors.
*/
export interface IGuildPassError {
readonly code: ErrorCode;
readonly message: string;
readonly statusCode?: number;
readonly details?: unknown;
readonly cause?: unknown;
}
42 changes: 42 additions & 0 deletions packages/integration-client/src/errors/errorCodes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* Standard error codes used across the GuildPass SDK and platform.
*
* @module
*/

export const ErrorCodes = {
// Generic / System Errors
INTERNAL_ERROR: "INTERNAL_ERROR",
UNKNOWN_ERROR: "UNKNOWN_ERROR",
UNSUPPORTED: "UNSUPPORTED",

// Network / Transport Errors (retaining existing codes for backward compatibility)
NETWORK_ERROR: "network",
TIMEOUT_ERROR: "timeout",
CIRCUIT_OPEN: "circuit_open",
UPSTREAM_ERROR: "upstream",

// Client / Request Errors
BAD_REQUEST: "BAD_REQUEST",
VALIDATION_ERROR: "VALIDATION_ERROR",
INVALID_CONFIG: "INVALID_CONFIG",
INVALID_SIGNATURE: "INVALID_SIGNATURE",
RATE_LIMIT_EXCEEDED: "RATE_LIMIT_EXCEEDED",

// Auth / Permissions Errors
UNAUTHORIZED: "UNAUTHORIZED",
FORBIDDEN: "FORBIDDEN",
ACCESS_DENIED: "ACCESS_DENIED",

// Resource / Entity Errors
NOT_FOUND: "NOT_FOUND",
CONFLICT: "CONFLICT",
MEMBERSHIP_NOT_FOUND: "MEMBERSHIP_NOT_FOUND",
GUILD_NOT_FOUND: "GUILD_NOT_FOUND",
PASS_NOT_FOUND: "PASS_NOT_FOUND",

// Smart Contract / Web3 Errors
CONTRACT_ERROR: "CONTRACT_ERROR",
} as const;

export type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes] | (string & {});
Loading