Skip to content
Open
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
15 changes: 15 additions & 0 deletions src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,21 @@ export function loadConfig(override = true): void {

loadConfig(false);

export const RPC_429_USER_MESSAGE =
"Your RPC endpoint is returning too many requests (HTTP 429). Please configure your own private RPC URL via RPC_URL and try again.";

/**
* Returns true when Satellite is using the default (public) RPC URL,
* i.e. when the user has NOT provided a custom RPC_URL override.
*/
export function isUsingPublicRpc(): boolean {
return !process.env.RPC_URL || process.env.RPC_URL.trim().length === 0;
}

export function isRpc429Error(err: unknown): boolean {
return (err as any)?.response?.status === 429;
}
Comment on lines +35 to +37
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: @swagnikdutta to make this more robust.


export function getRuntimeConfig() {
return {
get API_KEY() {
Expand Down
8 changes: 7 additions & 1 deletion src/domain/portal/publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { generateKeyPairFromSeed } from "@stablelib/ed25519";
import * as ucans from "@ucans/ucans";
import { AgentClient } from "../../sdk/smart-agent";
import { FileManager } from "../../sdk/file-manager";
import { getRuntimeConfig } from "../../config";
import { getRuntimeConfig, isUsingPublicRpc, isRpc429Error, RPC_429_USER_MESSAGE } from "../../config";

import type { PublishResult } from "../../types";

Expand Down Expand Up @@ -104,6 +104,12 @@ export const handleExistingFileOp = async (fileId: string, operation: "update" |

return executeOperation(fileManager, file, operation);
} catch (error: any) {
if (isUsingPublicRpc() && isRpc429Error(error)) {
// For public RPCs, map HTTP 429 into a clear user-facing message.
logger.error(`Failed to publish file ${fileId}: ${RPC_429_USER_MESSAGE}`);
throw new Error(RPC_429_USER_MESSAGE);
}

logger.error(`Failed to publish file ${fileId}:`, error);
throw error;
}
Expand Down
9 changes: 6 additions & 3 deletions src/infra/worker/eventProcessor.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getRuntimeConfig } from "../../config";
import { getRuntimeConfig, isUsingPublicRpc, isRpc429Error, RPC_429_USER_MESSAGE } from "../../config";
import { handleNewFileOp, getProxyAuthParams, handleExistingFileOp } from "../../domain/portal";
import { FilesModel, EventsModel } from "../database/models";
import type { Event, ProcessResult, UpdateFilePayload } from "../../types";
Expand Down Expand Up @@ -31,8 +31,11 @@ export const processEvent = async (event: Event): Promise<ProcessResult> => {
} catch (error) {
const normalized = normalizeRateLimitError(error);
if (normalized instanceof RateLimitError) throw normalized;
const errorMsg = error instanceof Error ? error.message : String(error);
logger.error(`Error processing ${type} event for file ${fileId}:`, errorMsg);
let errorMsg = error instanceof Error ? error.message : String(error);
if (isUsingPublicRpc() && isRpc429Error(error)) {
errorMsg = RPC_429_USER_MESSAGE;
}
logger.error(`Error processing ${type} event for file ${fileId}: ${errorMsg}`);
return { success: false, error: errorMsg };
}
};
Expand Down
22 changes: 9 additions & 13 deletions src/sdk/smart-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,19 +81,15 @@ export class AgentClient {
request: IExecuteUserOperationRequest | IExecuteUserOperationRequest[],
customGasLimit?: number,
) {
try {
const smartAccountAgent = this.getSmartAccountAgent();

const callData = await this.getCallData(request);

return await smartAccountAgent.sendUserOperation({
callData,
callGasLimit: BigInt(customGasLimit || this.MAX_CALL_GAS_LIMIT),
nonce: getNonce(),
});
} catch (error) {
throw error;
}
const smartAccountAgent = this.getSmartAccountAgent();

const callData = await this.getCallData(request);

return await smartAccountAgent.sendUserOperation({
callData,
callGasLimit: BigInt(customGasLimit || this.MAX_CALL_GAS_LIMIT),
nonce: getNonce(),
});
}

async executeUserOperationRequest(
Expand Down