@opendatalabs/vana-sdk 0.1.0-alpha.f2a82f7 → 0.1.0-alpha.f35bb9c
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/dist/controllers/base.cjs +0 -33
- package/dist/controllers/base.cjs.map +1 -1
- package/dist/controllers/base.d.ts +0 -10
- package/dist/controllers/base.js +0 -33
- package/dist/controllers/base.js.map +1 -1
- package/dist/controllers/data.cjs +19 -26
- package/dist/controllers/data.cjs.map +1 -1
- package/dist/controllers/data.d.ts +9 -9
- package/dist/controllers/data.js +19 -26
- package/dist/controllers/data.js.map +1 -1
- package/dist/controllers/permissions.cjs +65 -124
- package/dist/controllers/permissions.cjs.map +1 -1
- package/dist/controllers/permissions.d.ts +11 -20
- package/dist/controllers/permissions.js +65 -124
- package/dist/controllers/permissions.js.map +1 -1
- package/dist/core.cjs +1 -4
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.ts +1 -2
- package/dist/core.js +1 -4
- package/dist/core.js.map +1 -1
- package/dist/index.node.cjs +0 -2
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.d.ts +4 -27
- package/dist/index.node.js +0 -2
- package/dist/index.node.js.map +1 -1
- package/dist/server/relayerHandler.cjs +87 -201
- package/dist/server/relayerHandler.cjs.map +1 -1
- package/dist/server/relayerHandler.d.ts +1 -3
- package/dist/server/relayerHandler.js +87 -201
- package/dist/server/relayerHandler.js.map +1 -1
- package/dist/types/config.cjs.map +1 -1
- package/dist/types/config.d.ts +0 -32
- package/dist/types/config.js.map +1 -1
- package/dist/types/controller-context.cjs.map +1 -1
- package/dist/types/controller-context.d.ts +1 -3
- package/dist/types/generics.cjs.map +1 -1
- package/dist/types/generics.d.ts +1 -1
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.d.ts +2 -3
- package/dist/types/index.js.map +1 -1
- package/dist/types/operations.cjs.map +1 -1
- package/dist/types/operations.d.ts +0 -46
- package/dist/types/operations.js.map +1 -1
- package/dist/types/relayer.cjs.map +1 -1
- package/dist/types/relayer.d.ts +8 -19
- package/dist/utils/ipfs.cjs +4 -2
- package/dist/utils/ipfs.cjs.map +1 -1
- package/dist/utils/ipfs.d.ts +1 -1
- package/dist/utils/ipfs.js +4 -2
- package/dist/utils/ipfs.js.map +1 -1
- package/package.json +1 -3
package/dist/index.node.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { NodePlatformAdapter } from "./platform/node";
|
|
2
2
|
import { VanaCore } from "./core";
|
|
3
3
|
class VanaNodeImpl extends VanaCore {
|
|
4
|
-
operationStore;
|
|
5
4
|
constructor(config) {
|
|
6
5
|
super(new NodePlatformAdapter(), config);
|
|
7
|
-
this.operationStore = config.operationStore;
|
|
8
6
|
}
|
|
9
7
|
}
|
|
10
8
|
function Vana(config) {
|
package/dist/index.node.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.node.ts"],"sourcesContent":["/**\n * @module Node\n * Node.js-specific implementation of the Vana SDK\n */\n\nimport { NodePlatformAdapter } from \"./platform/node\";\nimport { VanaCore } from \"./core\";\nimport type {\n VanaConfig,\n VanaConfigWithStorage,\n StorageRequiredMarker,\n RelayerRequiredMarker,\n IOperationStore,\n} from \"./types\";\n\n/**\n * Node.js-specific configuration interface with operation store support\n *\n * @category Configuration\n */\nexport type VanaNodeConfig = VanaConfig & {\n operationStore?: IOperationStore;\n};\n\n/**\n * Node.js configuration with storage requirements\n *\n * @category Configuration\n */\nexport type VanaNodeConfigWithStorage = VanaConfigWithStorage & {\n operationStore?: IOperationStore;\n};\n\n/**\n * Internal implementation class for Node.js environments.\n * This class is not exported directly - use the Vana factory function instead.\n */\nclass VanaNodeImpl extends VanaCore {\n override readonly operationStore?: IOperationStore;\n\n constructor(config: VanaNodeConfig) {\n super(new NodePlatformAdapter(), config);\n this.operationStore = config.operationStore;\n }\n}\n\n/**\n * Creates a new Vana SDK instance configured for Node.js environments.\n *\n * @remarks\n * This is the primary entry point for Node.js applications using the Vana SDK. The function\n * automatically detects your configuration type and provides compile-time type safety:\n * - **With storage configured**: All methods including file upload/download are available\n * - **Without storage**: Storage-dependent methods throw runtime errors and are excluded from TypeScript\n *\n * The Node.js version provides enhanced capabilities including native file system access,\n * server-side cryptographic operations, and support for personal server deployment.\n * It includes all browser capabilities plus Node.js-specific optimizations and utilities.\n *\n * @param config - Configuration object containing wallet, storage, and relayer settings\n * @returns A fully configured Vana SDK instance for Node.js use\n * @throws {InvalidConfigurationError} When configuration parameters are invalid or missing\n * @example\n * ```typescript\n * import { Vana } from '@opendatalabs/vana-sdk/node';\n * import { createWalletClient, http } from 'viem';\n * import { privateKeyToAccount } from 'viem/accounts';\n * import { IPFSStorage, PinataStorage } from '@opendatalabs/vana-sdk/node';\n * import { mokshaTestnet } from '@opendatalabs/vana-sdk/node';\n *\n * // Server setup with private key\n * const account = privateKeyToAccount('0x...');\n * const walletClient = createWalletClient({\n * account,\n * chain: mokshaTestnet,\n * transport: http('https://rpc.moksha.vana.org')\n * });\n *\n * const vana = Vana({\n * walletClient,\n * storage: {\n * providers: {\n * ipfs: new IPFSStorage({\n * gateway: 'https://gateway.pinata.cloud',\n * timeout: 30000\n * }),\n * pinata: new PinataStorage({\n * apiKey: process.env.PINATA_KEY,\n * secretKey: process.env.PINATA_SECRET\n * })\n * },\n * defaultProvider: 'pinata'\n * },\n * relayerCallbacks: {\n * async submitPermissionGrant(typedData, signature) {\n * // Server-side relayer implementation\n * return await submitToCustomRelayer(typedData, signature);\n * }\n * }\n * });\n *\n * // Server operations\n * const uploadResult = await vana.data.upload({\n * content: await fs.readFile('./user-data.json'),\n * filename: 'user-data.json',\n * schemaId: 1\n * });\n *\n * // Personal server setup\n * await vana.server.setupPersonalServer({\n * serverUrl: 'https://my-server.example.com',\n * capabilities: ['data_processing', 'ml_inference']\n * });\n * ```\n *\n * @example\n * ```typescript\n * // CLI tool or script usage\n * const vana = Vana({\n * chainId: 14800, // Moksha testnet\n * account: privateKeyToAccount(process.env.PRIVATE_KEY),\n * rpcUrl: process.env.RPC_URL,\n * storage: {\n * providers: { ipfs: new IPFSStorage() },\n * defaultProvider: 'ipfs'\n * }\n * });\n *\n * // Batch operations for data processing\n * const userFiles = await vana.data.getUserFiles({\n * owner: process.env.USER_ADDRESS\n * });\n *\n * for (const file of userFiles) {\n * const decrypted = await vana.data.decryptFile(file);\n * // Process file data...\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Express.js server integration\n * import express from 'express';\n * import { handleRelayerOperation } from '@opendatalabs/vana-sdk/node';\n *\n * const app = express();\n *\n * app.post('/api/relay', async (req, res) => {\n * try {\n * const result = await handleRelayerOperation(\n * vana,\n * req.body\n * );\n * res.json(result);\n * } catch (error) {\n * res.status(500).json({ error: error.message });\n * }\n * });\n * ```\n *\n * @see {@link https://docs.vana.org/docs/sdk/server-setup | Server Setup Guide} for Node.js-specific features\n * @see {@link VanaCore} for the underlying implementation details\n * @category Core SDK\n */\n// Overload 1: For configurations that include both storage and operation store\nexport function Vana(\n config: VanaNodeConfigWithStorage & { operationStore: IOperationStore },\n): VanaNodeImpl & StorageRequiredMarker & RelayerRequiredMarker;\n\n// Overload 2: For configurations that include only the operation store\nexport function Vana(\n config: VanaNodeConfig & { operationStore: IOperationStore },\n): VanaNodeImpl & RelayerRequiredMarker;\n\n// Overload 3: For configurations with storage but no operation store\nexport function Vana(\n config: VanaNodeConfigWithStorage,\n): VanaNodeImpl & StorageRequiredMarker;\n\n// Overload 4: Base configuration without special requirements\nexport function Vana(config: VanaNodeConfig): VanaNodeImpl;\n\n// Implementation\nexport function Vana(config: VanaNodeConfig) {\n return new VanaNodeImpl(config);\n}\n\n/**\n * The type of a Vana SDK instance in Node.js environments.\n * Uses InstanceType to properly expose all public methods from the class hierarchy.\n *\n * @see {@link Vana}\n */\nexport type VanaInstance = InstanceType<typeof VanaNodeImpl>;\n\n// Export as default export\nexport default Vana;\n\n// Re-export everything that was in index.ts (avoiding circular dependency)\n// Core class and factory\nexport { VanaCore, VanaCoreFactory } from \"./core\";\n\n// Types - modular exports\nexport type * from \"./types\";\n\n// Type guards and utilities\nexport {\n isReplicateAPIResponse,\n isAPIResponse,\n safeParseJSON,\n parseReplicateOutput,\n} from \"./types/external-apis\";\n\n// VanaContract is exported from abi to avoid circular dependencies\nexport type { VanaContract } from \"./generated/abi\";\n\n// Error classes\nexport * from \"./errors\";\n\n// Controllers\nexport { PermissionsController } from \"./controllers/permissions\";\nexport { DataController } from \"./controllers/data\";\nexport { ServerController } from \"./controllers/server\";\nexport { ProtocolController } from \"./controllers/protocol\";\nexport { SchemaController } from \"./controllers/schemas\";\n\n// Contract controller\nexport * from \"./contracts/contractController\";\n\n// Utilities\nexport * from \"./utils/encryption\";\nexport * from \"./utils/formatters\";\nexport * from \"./utils/grantFiles\";\nexport * from \"./utils/grantValidation\";\nexport * from \"./utils/grants\";\nexport * from \"./utils/ipfs\";\nexport * from \"./utils/schemaValidation\";\nexport * from \"./utils/signatureCache\";\n\n// Storage API\nexport * from \"./storage\";\n\n// Configuration\nexport { getContractAddress } from \"./config/addresses\";\nexport { chains } from \"./config/chains\";\nexport {\n type ServiceEndpoints,\n mainnetServices,\n mokshaServices,\n getServiceEndpoints,\n getDefaultPersonalServerUrl,\n} from \"./config/default-services\";\n\n// Chain configurations with subgraph URLs - explicit exports for better DX\nexport {\n vanaMainnet,\n mokshaTestnet,\n moksha,\n type VanaChainConfig,\n getChainConfig,\n getAllChains,\n} from \"./chains\";\nexport * from \"./chains\";\n\n// ABIs\nexport { getAbi } from \"./generated/abi\";\nexport type { VanaContract as VanaContractAbi } from \"./generated/abi\";\n\n// Generic utilities for extensibility\nexport {\n BaseController,\n RetryUtility,\n RateLimiter,\n MemoryCache,\n EventEmitter,\n MiddlewarePipeline,\n AsyncQueue,\n CircuitBreaker,\n} from \"./core/generics\";\n\n// Server-side utilities\nexport { handleRelayerOperation } from \"./server/relayerHandler\";\nexport type {\n UnifiedRelayerRequest,\n UnifiedRelayerResponse,\n} from \"./types/relayer\";\n// TransactionHandle removed - using POJOs instead\nexport type {\n Operation,\n TransactionResult,\n TransactionReceipt,\n PollingOptions,\n TransactionWaitOptions,\n} from \"./types/operations\";\n\n// Platform adapters\nexport { NodePlatformAdapter } from \"./platform/node\";\nexport { BrowserPlatformAdapter } from \"./platform/browser\";\nexport type { VanaPlatformAdapter } from \"./platform/interface\";\n\n// Platform utilities\nexport {\n detectPlatform,\n createPlatformAdapter,\n createPlatformAdapterFor,\n isPlatformSupported,\n getPlatformCapabilities,\n} from \"./platform/utils\";\n\n// Browser-safe platform utilities\nexport {\n createNodePlatformAdapter,\n createBrowserPlatformAdapter,\n createPlatformAdapterSafe,\n} from \"./platform/browser-safe\";\n\nexport { ApiClient } from \"./core/apiClient\";\n\nexport type {\n ApiClientConfig,\n HttpMethod,\n RequestOptions,\n} from \"./core/apiClient\";\n\n// Note: Default export is already handled above with the Vana factory function\n// For testing purposes, we also export the implementation class\nexport { VanaNodeImpl };\n"],"mappings":"AAKA,SAAS,2BAA2B;AACpC,SAAS,gBAAgB;AA+BzB,MAAM,qBAAqB,SAAS;AAAA,EAChB;AAAA,EAElB,YAAY,QAAwB;AAClC,UAAM,IAAI,oBAAoB,GAAG,MAAM;AACvC,SAAK,iBAAiB,OAAO;AAAA,EAC/B;AACF;AA2IO,SAAS,KAAK,QAAwB;AAC3C,SAAO,IAAI,aAAa,MAAM;AAChC;AAWA,IAAO,qBAAQ;AAIf,SAAS,YAAAA,WAAU,uBAAuB;AAM1C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAMP,cAAc;AAGd,SAAS,6BAA6B;AACtC,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AACjC,SAAS,0BAA0B;AACnC,SAAS,wBAAwB;AAGjC,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AAGd,SAAS,0BAA0B;AACnC,SAAS,cAAc;AACvB;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,OACK;AACP,cAAc;AAGd,SAAS,cAAc;AAIvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,8BAA8B;AAevC,SAAS,uBAAAC,4BAA2B;AACpC,SAAS,8BAA8B;AAIvC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,iBAAiB;","names":["VanaCore","NodePlatformAdapter"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.node.ts"],"sourcesContent":["/**\n * @module Node\n * Node.js-specific implementation of the Vana SDK\n */\n\nimport { NodePlatformAdapter } from \"./platform/node\";\nimport { VanaCore } from \"./core\";\nimport type {\n VanaConfig,\n VanaConfigWithStorage,\n StorageRequiredMarker,\n} from \"./types\";\n\n/**\n * Internal implementation class for Node.js environments.\n * This class is not exported directly - use the Vana factory function instead.\n */\nclass VanaNodeImpl extends VanaCore {\n constructor(config: VanaConfig) {\n super(new NodePlatformAdapter(), config);\n }\n}\n\n/**\n * Creates a new Vana SDK instance configured for Node.js environments.\n *\n * @remarks\n * This is the primary entry point for Node.js applications using the Vana SDK. The function\n * automatically detects your configuration type and provides compile-time type safety:\n * - **With storage configured**: All methods including file upload/download are available\n * - **Without storage**: Storage-dependent methods throw runtime errors and are excluded from TypeScript\n *\n * The Node.js version provides enhanced capabilities including native file system access,\n * server-side cryptographic operations, and support for personal server deployment.\n * It includes all browser capabilities plus Node.js-specific optimizations and utilities.\n *\n * @param config - Configuration object containing wallet, storage, and relayer settings\n * @returns A fully configured Vana SDK instance for Node.js use\n * @throws {InvalidConfigurationError} When configuration parameters are invalid or missing\n * @example\n * ```typescript\n * import { Vana } from '@opendatalabs/vana-sdk/node';\n * import { createWalletClient, http } from 'viem';\n * import { privateKeyToAccount } from 'viem/accounts';\n * import { IPFSStorage, PinataStorage } from '@opendatalabs/vana-sdk/node';\n * import { mokshaTestnet } from '@opendatalabs/vana-sdk/node';\n *\n * // Server setup with private key\n * const account = privateKeyToAccount('0x...');\n * const walletClient = createWalletClient({\n * account,\n * chain: mokshaTestnet,\n * transport: http('https://rpc.moksha.vana.org')\n * });\n *\n * const vana = Vana({\n * walletClient,\n * storage: {\n * providers: {\n * ipfs: new IPFSStorage({\n * gateway: 'https://gateway.pinata.cloud',\n * timeout: 30000\n * }),\n * pinata: new PinataStorage({\n * apiKey: process.env.PINATA_KEY,\n * secretKey: process.env.PINATA_SECRET\n * })\n * },\n * defaultProvider: 'pinata'\n * },\n * relayerCallbacks: {\n * async submitPermissionGrant(typedData, signature) {\n * // Server-side relayer implementation\n * return await submitToCustomRelayer(typedData, signature);\n * }\n * }\n * });\n *\n * // Server operations\n * const uploadResult = await vana.data.upload({\n * content: await fs.readFile('./user-data.json'),\n * filename: 'user-data.json',\n * schemaId: 1\n * });\n *\n * // Personal server setup\n * await vana.server.setupPersonalServer({\n * serverUrl: 'https://my-server.example.com',\n * capabilities: ['data_processing', 'ml_inference']\n * });\n * ```\n *\n * @example\n * ```typescript\n * // CLI tool or script usage\n * const vana = Vana({\n * chainId: 14800, // Moksha testnet\n * account: privateKeyToAccount(process.env.PRIVATE_KEY),\n * rpcUrl: process.env.RPC_URL,\n * storage: {\n * providers: { ipfs: new IPFSStorage() },\n * defaultProvider: 'ipfs'\n * }\n * });\n *\n * // Batch operations for data processing\n * const userFiles = await vana.data.getUserFiles({\n * owner: process.env.USER_ADDRESS\n * });\n *\n * for (const file of userFiles) {\n * const decrypted = await vana.data.decryptFile(file);\n * // Process file data...\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Express.js server integration\n * import express from 'express';\n * import { handleRelayerOperation } from '@opendatalabs/vana-sdk/node';\n *\n * const app = express();\n *\n * app.post('/api/relay', async (req, res) => {\n * try {\n * const result = await handleRelayerOperation(\n * vana,\n * req.body\n * );\n * res.json(result);\n * } catch (error) {\n * res.status(500).json({ error: error.message });\n * }\n * });\n * ```\n *\n * @see {@link https://docs.vana.org/docs/sdk/server-setup | Server Setup Guide} for Node.js-specific features\n * @see {@link VanaCore} for the underlying implementation details\n * @category Core SDK\n */\nexport function Vana(\n config: VanaConfigWithStorage,\n): VanaNodeImpl & StorageRequiredMarker;\nexport function Vana(config: VanaConfig): VanaNodeImpl;\n/**\n * Creates a new Vana SDK instance.\n *\n * @param config - The configuration for the Vana SDK\n * @returns A new Vana SDK instance\n */\nexport function Vana(config: VanaConfig) {\n return new VanaNodeImpl(config);\n}\n\n/**\n * The type of a Vana SDK instance in Node.js environments.\n * Uses InstanceType to properly expose all public methods from the class hierarchy.\n *\n * @see {@link Vana}\n */\nexport type VanaInstance = InstanceType<typeof VanaNodeImpl>;\n\n// Export as default export\nexport default Vana;\n\n// Re-export everything that was in index.ts (avoiding circular dependency)\n// Core class and factory\nexport { VanaCore, VanaCoreFactory } from \"./core\";\n\n// Types - modular exports\nexport type * from \"./types\";\n\n// Type guards and utilities\nexport {\n isReplicateAPIResponse,\n isAPIResponse,\n safeParseJSON,\n parseReplicateOutput,\n} from \"./types/external-apis\";\n\n// VanaContract is exported from abi to avoid circular dependencies\nexport type { VanaContract } from \"./generated/abi\";\n\n// Error classes\nexport * from \"./errors\";\n\n// Controllers\nexport { PermissionsController } from \"./controllers/permissions\";\nexport { DataController } from \"./controllers/data\";\nexport { ServerController } from \"./controllers/server\";\nexport { ProtocolController } from \"./controllers/protocol\";\nexport { SchemaController } from \"./controllers/schemas\";\n\n// Contract controller\nexport * from \"./contracts/contractController\";\n\n// Utilities\nexport * from \"./utils/encryption\";\nexport * from \"./utils/formatters\";\nexport * from \"./utils/grantFiles\";\nexport * from \"./utils/grantValidation\";\nexport * from \"./utils/grants\";\nexport * from \"./utils/ipfs\";\nexport * from \"./utils/schemaValidation\";\nexport * from \"./utils/signatureCache\";\n\n// Storage API\nexport * from \"./storage\";\n\n// Configuration\nexport { getContractAddress } from \"./config/addresses\";\nexport { chains } from \"./config/chains\";\nexport {\n type ServiceEndpoints,\n mainnetServices,\n mokshaServices,\n getServiceEndpoints,\n getDefaultPersonalServerUrl,\n} from \"./config/default-services\";\n\n// Chain configurations with subgraph URLs - explicit exports for better DX\nexport {\n vanaMainnet,\n mokshaTestnet,\n moksha,\n type VanaChainConfig,\n getChainConfig,\n getAllChains,\n} from \"./chains\";\nexport * from \"./chains\";\n\n// ABIs\nexport { getAbi } from \"./generated/abi\";\nexport type { VanaContract as VanaContractAbi } from \"./generated/abi\";\n\n// Generic utilities for extensibility\nexport {\n BaseController,\n RetryUtility,\n RateLimiter,\n MemoryCache,\n EventEmitter,\n MiddlewarePipeline,\n AsyncQueue,\n CircuitBreaker,\n} from \"./core/generics\";\n\n// Server-side utilities\nexport { handleRelayerOperation } from \"./server/relayerHandler\";\nexport type {\n UnifiedRelayerRequest,\n UnifiedRelayerResponse,\n} from \"./types/relayer\";\n// TransactionHandle removed - using POJOs instead\nexport type {\n Operation,\n TransactionResult,\n TransactionReceipt,\n PollingOptions,\n TransactionWaitOptions,\n} from \"./types/operations\";\n\n// Platform adapters\nexport { NodePlatformAdapter } from \"./platform/node\";\nexport { BrowserPlatformAdapter } from \"./platform/browser\";\nexport type { VanaPlatformAdapter } from \"./platform/interface\";\n\n// Platform utilities\nexport {\n detectPlatform,\n createPlatformAdapter,\n createPlatformAdapterFor,\n isPlatformSupported,\n getPlatformCapabilities,\n} from \"./platform/utils\";\n\n// Browser-safe platform utilities\nexport {\n createNodePlatformAdapter,\n createBrowserPlatformAdapter,\n createPlatformAdapterSafe,\n} from \"./platform/browser-safe\";\n\nexport { ApiClient } from \"./core/apiClient\";\n\nexport type {\n ApiClientConfig,\n HttpMethod,\n RequestOptions,\n} from \"./core/apiClient\";\n\n// Note: Default export is already handled above with the Vana factory function\n// For testing purposes, we also export the implementation class\nexport { VanaNodeImpl };\n"],"mappings":"AAKA,SAAS,2BAA2B;AACpC,SAAS,gBAAgB;AAWzB,MAAM,qBAAqB,SAAS;AAAA,EAClC,YAAY,QAAoB;AAC9B,UAAM,IAAI,oBAAoB,GAAG,MAAM;AAAA,EACzC;AACF;AAkIO,SAAS,KAAK,QAAoB;AACvC,SAAO,IAAI,aAAa,MAAM;AAChC;AAWA,IAAO,qBAAQ;AAIf,SAAS,YAAAA,WAAU,uBAAuB;AAM1C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAMP,cAAc;AAGd,SAAS,6BAA6B;AACtC,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AACjC,SAAS,0BAA0B;AACnC,SAAS,wBAAwB;AAGjC,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AAGd,SAAS,0BAA0B;AACnC,SAAS,cAAc;AACvB;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,OACK;AACP,cAAc;AAGd,SAAS,cAAc;AAIvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,8BAA8B;AAevC,SAAS,uBAAAC,4BAA2B;AACpC,SAAS,8BAA8B;AAIvC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,iBAAiB;","names":["VanaCore","NodePlatformAdapter"]}
|
|
@@ -21,171 +21,49 @@ __export(relayerHandler_exports, {
|
|
|
21
21
|
handleRelayerOperation: () => handleRelayerOperation
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(relayerHandler_exports);
|
|
24
|
-
var import_uuid = require("uuid");
|
|
25
24
|
var import_errors = require("../errors");
|
|
26
25
|
var import_viem = require("viem");
|
|
27
|
-
async function handleRelayerOperation(sdk, request
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (request.type === "status_check") {
|
|
31
|
-
const state = await store.get(request.operationId);
|
|
32
|
-
if (!state) return { type: "error", error: "Operation not found" };
|
|
33
|
-
if (state.status === "confirmed")
|
|
34
|
-
return {
|
|
35
|
-
type: "confirmed",
|
|
36
|
-
hash: state.transactionHash,
|
|
37
|
-
receipt: state.finalReceipt
|
|
38
|
-
};
|
|
39
|
-
if (state.status === "failed")
|
|
40
|
-
return { type: "error", error: state.error ?? "Operation failed" };
|
|
41
|
-
if (state.status === "pending") {
|
|
42
|
-
try {
|
|
43
|
-
const publicClient = sdk.publicClient;
|
|
44
|
-
if (publicClient) {
|
|
45
|
-
let receipt;
|
|
46
|
-
try {
|
|
47
|
-
receipt = await publicClient.getTransactionReceipt({
|
|
48
|
-
hash: state.transactionHash
|
|
49
|
-
});
|
|
50
|
-
} catch (receiptError) {
|
|
51
|
-
if (receiptError?.name !== "TransactionReceiptNotFoundError") {
|
|
52
|
-
console.warn(
|
|
53
|
-
`\u26A0\uFE0F [Relayer] Unexpected error checking receipt:`,
|
|
54
|
-
receiptError?.message ?? receiptError
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
receipt = null;
|
|
58
|
-
}
|
|
59
|
-
if (receipt) {
|
|
60
|
-
const updatedState = {
|
|
61
|
-
...state,
|
|
62
|
-
status: receipt.status === "success" ? "confirmed" : "failed",
|
|
63
|
-
finalReceipt: receipt,
|
|
64
|
-
...receipt.status !== "success" && {
|
|
65
|
-
error: "Transaction reverted on chain"
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
await store.set(request.operationId, updatedState);
|
|
69
|
-
if (receipt.status === "success") {
|
|
70
|
-
return {
|
|
71
|
-
type: "confirmed",
|
|
72
|
-
hash: state.transactionHash,
|
|
73
|
-
receipt
|
|
74
|
-
};
|
|
75
|
-
} else {
|
|
76
|
-
return {
|
|
77
|
-
type: "error",
|
|
78
|
-
error: "Transaction reverted on chain"
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
} else {
|
|
83
|
-
console.warn(
|
|
84
|
-
"\u26A0\uFE0F [Relayer] No public client available for status checking"
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
} catch (error) {
|
|
88
|
-
console.error(
|
|
89
|
-
`\u274C [Relayer] Unexpected error in status check:`,
|
|
90
|
-
error
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return { type: "pending", operationId: request.operationId };
|
|
95
|
-
}
|
|
96
|
-
const operationId = (0, import_uuid.v4)();
|
|
97
|
-
try {
|
|
98
|
-
const txResult = await routeAndExecuteRequest(sdk, request, options);
|
|
99
|
-
if ("hash" in txResult) {
|
|
100
|
-
await store.set(operationId, {
|
|
101
|
-
status: "pending",
|
|
102
|
-
transactionHash: txResult.hash,
|
|
103
|
-
originalRequest: request,
|
|
104
|
-
nonce: options?.nonce,
|
|
105
|
-
retryCount: 0,
|
|
106
|
-
lastAttemptedGas: {
|
|
107
|
-
maxFeePerGas: options?.maxFeePerGas?.toString(),
|
|
108
|
-
maxPriorityFeePerGas: options?.maxPriorityFeePerGas?.toString()
|
|
109
|
-
},
|
|
110
|
-
submittedAt: Date.now()
|
|
111
|
-
});
|
|
112
|
-
return { type: "pending", operationId };
|
|
113
|
-
} else {
|
|
114
|
-
return { type: "direct", result: txResult };
|
|
115
|
-
}
|
|
116
|
-
} catch (e) {
|
|
117
|
-
const error = e instanceof Error ? e : new Error("Unknown error during operation submission");
|
|
118
|
-
return { type: "error", error: error.message };
|
|
119
|
-
}
|
|
120
|
-
} else {
|
|
121
|
-
if (request.type === "status_check") {
|
|
122
|
-
return {
|
|
123
|
-
type: "error",
|
|
124
|
-
error: "Stateless relayer does not support operation status checks."
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
try {
|
|
128
|
-
const txResult = await routeAndExecuteRequest(sdk, request, options);
|
|
129
|
-
if ("hash" in txResult) {
|
|
130
|
-
return { type: "submitted", hash: txResult.hash };
|
|
131
|
-
} else {
|
|
132
|
-
return { type: "direct", result: txResult };
|
|
133
|
-
}
|
|
134
|
-
} catch (e) {
|
|
135
|
-
const error = e instanceof Error ? e : new Error("Unknown error during operation submission");
|
|
136
|
-
return { type: "error", error: error.message };
|
|
137
|
-
}
|
|
26
|
+
async function handleRelayerOperation(sdk, request) {
|
|
27
|
+
if (request.type === "signed") {
|
|
28
|
+
return handleSignedOperation(sdk, request);
|
|
138
29
|
}
|
|
30
|
+
return handleDirectOperation(sdk, request);
|
|
139
31
|
}
|
|
140
|
-
async function
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
domain
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
32
|
+
async function handleSignedOperation(sdk, request) {
|
|
33
|
+
const { typedData, signature, expectedUserAddress } = request;
|
|
34
|
+
let recoveredAddress;
|
|
35
|
+
try {
|
|
36
|
+
recoveredAddress = await (0, import_viem.recoverTypedDataAddress)({
|
|
37
|
+
domain: {
|
|
38
|
+
...typedData.domain,
|
|
39
|
+
chainId: typedData.domain.chainId ? BigInt(typedData.domain.chainId) : void 0
|
|
40
|
+
},
|
|
41
|
+
types: typedData.types,
|
|
42
|
+
primaryType: typedData.primaryType,
|
|
43
|
+
message: typedData.message,
|
|
44
|
+
signature
|
|
45
|
+
});
|
|
46
|
+
} catch (error) {
|
|
47
|
+
throw new import_errors.SignatureError(
|
|
48
|
+
`Signature verification failed: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
if (expectedUserAddress) {
|
|
52
|
+
const normalizedExpected = (0, import_viem.getAddress)(expectedUserAddress);
|
|
53
|
+
const normalizedSigner = (0, import_viem.getAddress)(recoveredAddress);
|
|
54
|
+
if (normalizedSigner !== normalizedExpected) {
|
|
156
55
|
throw new import_errors.SignatureError(
|
|
157
|
-
`
|
|
56
|
+
`Security verification failed: Recovered signer address (${normalizedSigner}) does not match expected user address (${normalizedExpected})`
|
|
158
57
|
);
|
|
159
58
|
}
|
|
160
|
-
if (expectedUserAddress) {
|
|
161
|
-
const normalizedExpected = (0, import_viem.getAddress)(expectedUserAddress);
|
|
162
|
-
const normalizedSigner = (0, import_viem.getAddress)(recoveredAddress);
|
|
163
|
-
if (normalizedSigner !== normalizedExpected) {
|
|
164
|
-
throw new import_errors.SignatureError(
|
|
165
|
-
`Security verification failed: Recovered signer address (${normalizedSigner}) does not match expected user address (${normalizedExpected})`
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
return await routeSignedOperation(sdk, typedData, signature, options);
|
|
170
|
-
} else if (request.type === "direct") {
|
|
171
|
-
return await handleDirectOperation(sdk, request, options);
|
|
172
59
|
}
|
|
173
|
-
|
|
60
|
+
const result = await routeSignedOperation(sdk, typedData, signature);
|
|
61
|
+
return {
|
|
62
|
+
type: "signed",
|
|
63
|
+
hash: result.hash
|
|
64
|
+
};
|
|
174
65
|
}
|
|
175
|
-
async function routeSignedOperation(sdk, typedData, signature
|
|
176
|
-
const validPrimaryTypes = [
|
|
177
|
-
"Permission",
|
|
178
|
-
"RevokePermission",
|
|
179
|
-
"TrustServer",
|
|
180
|
-
"AddServer",
|
|
181
|
-
"UntrustServer",
|
|
182
|
-
"ServerFilesAndPermission"
|
|
183
|
-
];
|
|
184
|
-
if (!validPrimaryTypes.includes(typedData.primaryType)) {
|
|
185
|
-
throw new Error(
|
|
186
|
-
`Unsupported operation type: ${typedData.primaryType}. Supported types: ${validPrimaryTypes.join(", ")}`
|
|
187
|
-
);
|
|
188
|
-
}
|
|
66
|
+
async function routeSignedOperation(sdk, typedData, signature) {
|
|
189
67
|
const primaryType = typedData.primaryType;
|
|
190
68
|
switch (primaryType) {
|
|
191
69
|
case "Permission":
|
|
@@ -194,8 +72,7 @@ async function routeSignedOperation(sdk, typedData, signature, options) {
|
|
|
194
72
|
...typedData,
|
|
195
73
|
primaryType: "Permission"
|
|
196
74
|
},
|
|
197
|
-
signature
|
|
198
|
-
options
|
|
75
|
+
signature
|
|
199
76
|
);
|
|
200
77
|
case "RevokePermission":
|
|
201
78
|
return sdk.permissions.submitSignedRevoke(
|
|
@@ -203,8 +80,7 @@ async function routeSignedOperation(sdk, typedData, signature, options) {
|
|
|
203
80
|
...typedData,
|
|
204
81
|
primaryType: "RevokePermission"
|
|
205
82
|
},
|
|
206
|
-
signature
|
|
207
|
-
options
|
|
83
|
+
signature
|
|
208
84
|
);
|
|
209
85
|
case "TrustServer":
|
|
210
86
|
return sdk.permissions.submitSignedTrustServer(
|
|
@@ -212,8 +88,7 @@ async function routeSignedOperation(sdk, typedData, signature, options) {
|
|
|
212
88
|
...typedData,
|
|
213
89
|
primaryType: "TrustServer"
|
|
214
90
|
},
|
|
215
|
-
signature
|
|
216
|
-
options
|
|
91
|
+
signature
|
|
217
92
|
);
|
|
218
93
|
case "AddServer":
|
|
219
94
|
return sdk.permissions.submitSignedAddAndTrustServer(
|
|
@@ -221,8 +96,7 @@ async function routeSignedOperation(sdk, typedData, signature, options) {
|
|
|
221
96
|
...typedData,
|
|
222
97
|
primaryType: "AddServer"
|
|
223
98
|
},
|
|
224
|
-
signature
|
|
225
|
-
options
|
|
99
|
+
signature
|
|
226
100
|
);
|
|
227
101
|
case "UntrustServer":
|
|
228
102
|
return sdk.permissions.submitSignedUntrustServer(
|
|
@@ -230,8 +104,7 @@ async function routeSignedOperation(sdk, typedData, signature, options) {
|
|
|
230
104
|
...typedData,
|
|
231
105
|
primaryType: "UntrustServer"
|
|
232
106
|
},
|
|
233
|
-
signature
|
|
234
|
-
options
|
|
107
|
+
signature
|
|
235
108
|
);
|
|
236
109
|
case "ServerFilesAndPermission":
|
|
237
110
|
return sdk.permissions.submitSignedAddServerFilesAndPermissions(
|
|
@@ -239,81 +112,94 @@ async function routeSignedOperation(sdk, typedData, signature, options) {
|
|
|
239
112
|
...typedData,
|
|
240
113
|
primaryType: "ServerFilesAndPermission"
|
|
241
114
|
},
|
|
242
|
-
signature
|
|
243
|
-
options
|
|
115
|
+
signature
|
|
244
116
|
);
|
|
245
117
|
// TODO: RegisterGrantee with signature is not supported until
|
|
246
118
|
// DataPortabilityGrantees contract adds registerGranteeWithSignature function
|
|
247
119
|
// case "RegisterGrantee":
|
|
248
120
|
// return sdk.permissions.submitSignedRegisterGrantee(...);
|
|
249
121
|
default:
|
|
250
|
-
throw new Error(
|
|
251
|
-
`Unsupported operation type: ${typedData.primaryType}. Supported types: Permission, RevokePermission, TrustServer, AddServer, UntrustServer, ServerFilesAndPermission`
|
|
252
|
-
);
|
|
122
|
+
throw new Error(`Unsupported operation type: ${typedData.primaryType}`);
|
|
253
123
|
}
|
|
254
124
|
}
|
|
255
|
-
async function handleDirectOperation(sdk, request
|
|
125
|
+
async function handleDirectOperation(sdk, request) {
|
|
256
126
|
switch (request.operation) {
|
|
257
127
|
case "submitFileAddition": {
|
|
258
128
|
const { url, userAddress } = request.params;
|
|
259
129
|
const result = await sdk.data.addFileWithPermissions(
|
|
260
130
|
url,
|
|
261
131
|
userAddress,
|
|
262
|
-
[]
|
|
132
|
+
[]
|
|
263
133
|
// No permissions
|
|
264
|
-
options
|
|
265
134
|
);
|
|
266
|
-
|
|
135
|
+
const eventData = await sdk.waitForTransactionEvents(result);
|
|
136
|
+
const fileId = eventData.expectedEvents?.FileAdded?.fileId;
|
|
137
|
+
if (!fileId) {
|
|
138
|
+
throw new Error("Failed to get fileId from transaction events");
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
type: "direct",
|
|
142
|
+
result: {
|
|
143
|
+
fileId: Number(fileId),
|
|
144
|
+
transactionHash: result.hash
|
|
145
|
+
}
|
|
146
|
+
};
|
|
267
147
|
}
|
|
268
148
|
case "submitFileAdditionWithPermissions": {
|
|
269
149
|
const { url, userAddress, permissions } = request.params;
|
|
270
150
|
const result = await sdk.data.addFileWithPermissions(
|
|
271
151
|
url,
|
|
272
152
|
userAddress,
|
|
273
|
-
permissions
|
|
274
|
-
options
|
|
153
|
+
permissions
|
|
275
154
|
);
|
|
276
|
-
|
|
155
|
+
const eventData = await sdk.waitForTransactionEvents(result);
|
|
156
|
+
const fileId = eventData.expectedEvents?.FileAdded?.fileId;
|
|
157
|
+
if (!fileId) {
|
|
158
|
+
throw new Error("Failed to get fileId from transaction events");
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
type: "direct",
|
|
162
|
+
result: {
|
|
163
|
+
fileId: Number(fileId),
|
|
164
|
+
transactionHash: result.hash
|
|
165
|
+
}
|
|
166
|
+
};
|
|
277
167
|
}
|
|
278
168
|
case "submitFileAdditionComplete": {
|
|
279
169
|
const { url, userAddress, permissions, schemaId, ownerAddress } = request.params;
|
|
280
|
-
const
|
|
170
|
+
const result = await sdk.data.addFileWithEncryptedPermissionsAndSchema(
|
|
281
171
|
url,
|
|
282
172
|
ownerAddress ?? userAddress,
|
|
283
173
|
permissions,
|
|
284
174
|
// Already in correct format with encrypted 'key' field
|
|
285
|
-
schemaId
|
|
286
|
-
options
|
|
175
|
+
schemaId
|
|
287
176
|
);
|
|
288
|
-
const
|
|
289
|
-
const
|
|
290
|
-
if (!
|
|
291
|
-
|
|
292
|
-
throw new Error("FileAdded event not found in transaction");
|
|
177
|
+
const eventData = await sdk.waitForTransactionEvents(result);
|
|
178
|
+
const fileId = eventData.expectedEvents?.FileAdded?.fileId;
|
|
179
|
+
if (!fileId) {
|
|
180
|
+
throw new Error("Failed to get fileId from transaction events");
|
|
293
181
|
}
|
|
294
|
-
const fileId = Number(fileAddedEvent.fileId);
|
|
295
182
|
return {
|
|
296
|
-
|
|
297
|
-
|
|
183
|
+
type: "direct",
|
|
184
|
+
result: {
|
|
185
|
+
fileId: Number(fileId),
|
|
186
|
+
transactionHash: result.hash
|
|
187
|
+
}
|
|
298
188
|
};
|
|
299
189
|
}
|
|
300
190
|
case "storeGrantFile": {
|
|
301
191
|
const grantFile = request.params;
|
|
302
|
-
const dataController = sdk.data;
|
|
303
|
-
const context = dataController.context;
|
|
304
|
-
if (!context?.storageManager) {
|
|
305
|
-
throw new Error(
|
|
306
|
-
"Storage configuration is required for storing grant files"
|
|
307
|
-
);
|
|
308
|
-
}
|
|
309
192
|
const blob = new Blob([JSON.stringify(grantFile)], {
|
|
310
193
|
type: "application/json"
|
|
311
194
|
});
|
|
312
|
-
const
|
|
313
|
-
blob,
|
|
314
|
-
`grant-${Date.now()}.json`
|
|
315
|
-
);
|
|
316
|
-
return {
|
|
195
|
+
const result = await sdk.data.upload({
|
|
196
|
+
content: blob,
|
|
197
|
+
filename: `grant-${Date.now()}.json`
|
|
198
|
+
});
|
|
199
|
+
return {
|
|
200
|
+
type: "direct",
|
|
201
|
+
result: { url: result.url }
|
|
202
|
+
};
|
|
317
203
|
}
|
|
318
204
|
default: {
|
|
319
205
|
const exhaustiveCheck = request;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/server/relayerHandler.ts"],"sourcesContent":["import { v4 as uuidv4 } from \"uuid\";\nimport type { VanaInstance } from \"../index.node\";\nimport type {\n UnifiedRelayerRequest,\n UnifiedRelayerResponse,\n DirectRelayerRequest,\n} from \"../types/relayer\";\nimport type {\n TransactionResult,\n TransactionOptions,\n IOperationStore,\n OperationState,\n TransactionReceipt,\n} from \"../types\";\nimport type { Contract, Fn } from \"../generated/event-types\";\nimport type {\n GenericTypedData,\n PermissionGrantTypedData,\n RevokePermissionTypedData,\n TrustServerTypedData,\n AddAndTrustServerTypedData,\n ServerFilesAndPermissionTypedData,\n TypedDataPrimaryType,\n} from \"../types/permissions\";\nimport { SignatureError } from \"../errors\";\nimport { recoverTypedDataAddress, getAddress, type Hash } from \"viem\";\n\n/**\n * Universal handler for all relayer operations.\n *\n * This function processes both EIP-712 signed operations and direct operations,\n * automatically routing to the appropriate SDK methods.\n *\n * @param sdk - Initialized Vana SDK instance\n * @param request - The unified relayer request\n * @returns Promise resolving to operation-specific response\n *\n * @category Server\n * @example\n * ```typescript\n * // In your server endpoint (Next.js example):\n * import { handleRelayerOperation } from '@opendatalabs/vana-sdk/node';\n *\n * export async function POST(request: NextRequest) {\n * try {\n * const body = await request.json();\n * const vana = getServerVanaInstance(); // Your server SDK instance\n *\n * const result = await handleRelayerOperation(vana, body);\n *\n * return NextResponse.json(result);\n * } catch (error) {\n * return NextResponse.json(\n * { error: error.message },\n * { status: 500 }\n * );\n * }\n * }\n * ```\n */\nexport async function handleRelayerOperation(\n sdk: VanaInstance, // The public signature is generic\n request: UnifiedRelayerRequest,\n options?: TransactionOptions,\n): Promise<UnifiedRelayerResponse> {\n // Type assertion required: VanaInstance public interface doesn't expose operationStore\n // to maintain API simplicity, but server-side handler needs access for stateful mode.\n // The factory overloads guarantee this is safe for relayer-configured instances.\n // TODO(TYPES): Consider exposing operationStore through a server-specific interface\n\n const store = (sdk as any).operationStore as IOperationStore | undefined;\n\n // --- STATEFUL (ROBUST) MODE ---\n // This block executes ONLY if the developer provided an IOperationStore.\n if (store) {\n if (request.type === \"status_check\") {\n const state = await store.get(request.operationId);\n if (!state) return { type: \"error\", error: \"Operation not found\" };\n\n // If already confirmed or failed, return immediately\n if (state.status === \"confirmed\")\n return {\n type: \"confirmed\",\n hash: state.transactionHash,\n receipt: state.finalReceipt,\n };\n if (state.status === \"failed\")\n return { type: \"error\", error: state.error ?? \"Operation failed\" };\n\n // For pending operations, check the blockchain for transaction status\n if (state.status === \"pending\") {\n try {\n // Get a public client to check transaction status\n // The SDK stores it as a direct property\n const publicClient = (sdk as any).publicClient;\n\n if (publicClient) {\n // Check if transaction has been mined\n let receipt;\n try {\n receipt = await publicClient.getTransactionReceipt({\n hash: state.transactionHash,\n });\n } catch (receiptError: any) {\n // Transaction not found is expected - it may not be mined yet\n if (receiptError?.name !== \"TransactionReceiptNotFoundError\") {\n // Unexpected error - log but don't fail\n console.warn(\n `⚠️ [Relayer] Unexpected error checking receipt:`,\n receiptError?.message ?? receiptError,\n );\n }\n // Continue returning pending status\n receipt = null;\n }\n\n if (receipt) {\n // Update the operation state based on transaction status\n const updatedState: OperationState = {\n ...state,\n status: receipt.status === \"success\" ? \"confirmed\" : \"failed\",\n finalReceipt: receipt as TransactionReceipt,\n ...(receipt.status !== \"success\" && {\n error: \"Transaction reverted on chain\",\n }),\n };\n\n // Persist the updated state\n await store.set(request.operationId, updatedState);\n\n // Return the appropriate response\n if (receipt.status === \"success\") {\n return {\n type: \"confirmed\",\n hash: state.transactionHash,\n receipt: receipt as TransactionReceipt,\n };\n } else {\n return {\n type: \"error\",\n error: \"Transaction reverted on chain\",\n };\n }\n }\n } else {\n console.warn(\n \"⚠️ [Relayer] No public client available for status checking\",\n );\n }\n } catch (error) {\n console.error(\n `❌ [Relayer] Unexpected error in status check:`,\n error,\n );\n // Don't fail the operation, just continue returning pending\n }\n }\n\n return { type: \"pending\", operationId: request.operationId };\n }\n\n const operationId = uuidv4();\n try {\n const txResult = await routeAndExecuteRequest(sdk, request, options);\n // We only store state for operations that result in a transaction.\n if (\"hash\" in txResult) {\n await store.set(operationId, {\n status: \"pending\",\n transactionHash: txResult.hash,\n originalRequest: request,\n nonce: options?.nonce,\n retryCount: 0,\n lastAttemptedGas: {\n maxFeePerGas: options?.maxFeePerGas?.toString(),\n maxPriorityFeePerGas: options?.maxPriorityFeePerGas?.toString(),\n },\n submittedAt: Date.now(),\n });\n return { type: \"pending\", operationId };\n } else {\n // This handles non-transactional direct operations like `storeGrantFile`\n return { type: \"direct\", result: txResult };\n }\n } catch (e) {\n const error =\n e instanceof Error\n ? e\n : new Error(\"Unknown error during operation submission\");\n // We don't create a persistent error state for an initial submission failure.\n return { type: \"error\", error: error.message };\n }\n }\n\n // --- STATELESS (SIMPLE) MODE ---\n // This block executes if no IOperationStore was provided. Fire-and-forget.\n else {\n if (request.type === \"status_check\") {\n return {\n type: \"error\",\n error: \"Stateless relayer does not support operation status checks.\",\n };\n }\n\n try {\n const txResult = await routeAndExecuteRequest(sdk, request, options);\n\n // For stateless relayers, we can only handle transactional results.\n if (\"hash\" in txResult) {\n return { type: \"submitted\", hash: txResult.hash };\n } else {\n // Non-transactional direct operations can return their result directly.\n return { type: \"direct\", result: txResult };\n }\n } catch (e) {\n const error =\n e instanceof Error\n ? e\n : new Error(\"Unknown error during operation submission\");\n return { type: \"error\", error: error.message };\n }\n }\n}\n\n/**\n * Helper function to route and execute requests.\n * This simply delegates to the appropriate handler based on request type.\n */\nasync function routeAndExecuteRequest(\n sdk: VanaInstance,\n request: UnifiedRelayerRequest,\n options?: TransactionOptions,\n): Promise<\n | TransactionResult<Contract, Fn<Contract>>\n | { url: string }\n | { fileId: number; transactionHash: Hash }\n> {\n if (request.type === \"signed\") {\n const { typedData, signature, expectedUserAddress } = request;\n\n // Step 1: Verify the signature (security check)\n let recoveredAddress: `0x${string}`;\n try {\n recoveredAddress = await recoverTypedDataAddress({\n domain: {\n ...typedData.domain,\n chainId: typedData.domain.chainId\n ? BigInt(typedData.domain.chainId)\n : undefined,\n },\n types: typedData.types,\n primaryType: typedData.primaryType,\n message: typedData.message as unknown as Record<string, unknown>,\n signature,\n });\n } catch (error) {\n // Handle signature verification errors\n throw new SignatureError(\n `Signature verification failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n\n // Optional security check: Verify the signer matches expected address\n if (expectedUserAddress) {\n const normalizedExpected = getAddress(expectedUserAddress);\n const normalizedSigner = getAddress(recoveredAddress);\n\n if (normalizedSigner !== normalizedExpected) {\n throw new SignatureError(\n `Security verification failed: Recovered signer address (${normalizedSigner}) does not match expected user address (${normalizedExpected})`,\n );\n }\n }\n\n // Step 2: Route to appropriate SDK method based on primaryType\n return await routeSignedOperation(sdk, typedData, signature, options);\n } else if (request.type === \"direct\") {\n return await handleDirectOperation(sdk, request, options);\n }\n throw new Error(\"Invalid request type for execution\");\n}\n\n/**\n * Route signed operations to the appropriate SDK method with type safety.\n *\n * Returns a TransactionResult for one of the valid contracts and their functions.\n * Using Contract and Fn<Contract> ensures we're working with known contract types.\n */\nasync function routeSignedOperation(\n sdk: VanaInstance,\n typedData: GenericTypedData,\n signature: Hash,\n options?: TransactionOptions,\n): Promise<TransactionResult<Contract, Fn<Contract>>> {\n // Validate primaryType before casting\n const validPrimaryTypes: readonly TypedDataPrimaryType[] = [\n \"Permission\",\n \"RevokePermission\",\n \"TrustServer\",\n \"AddServer\",\n \"UntrustServer\",\n \"ServerFilesAndPermission\",\n ] as const;\n\n if (\n !validPrimaryTypes.includes(typedData.primaryType as TypedDataPrimaryType)\n ) {\n throw new Error(\n `Unsupported operation type: ${typedData.primaryType}. ` +\n `Supported types: ${validPrimaryTypes.join(\", \")}`,\n );\n }\n\n const primaryType = typedData.primaryType as TypedDataPrimaryType;\n\n // Type-safe routing based on primaryType\n switch (primaryType) {\n case \"Permission\":\n // TypeScript knows this is a Permission operation\n return sdk.permissions.submitSignedGrant(\n {\n ...typedData,\n primaryType: \"Permission\",\n } as PermissionGrantTypedData,\n signature,\n options,\n );\n\n case \"RevokePermission\":\n return sdk.permissions.submitSignedRevoke(\n {\n ...typedData,\n primaryType: \"RevokePermission\",\n } as RevokePermissionTypedData,\n signature,\n options,\n );\n\n case \"TrustServer\":\n // Note: TrustServer operation is deprecated but still supported for backwards compatibility\n // New implementations should use AddServer (AddAndTrustServer) instead\n return sdk.permissions.submitSignedTrustServer(\n {\n ...typedData,\n primaryType: \"TrustServer\",\n } as TrustServerTypedData,\n signature,\n options,\n );\n\n case \"AddServer\":\n return sdk.permissions.submitSignedAddAndTrustServer(\n {\n ...typedData,\n primaryType: \"AddServer\",\n } as AddAndTrustServerTypedData,\n signature,\n options,\n );\n\n case \"UntrustServer\":\n return sdk.permissions.submitSignedUntrustServer(\n {\n ...typedData,\n primaryType: \"UntrustServer\",\n } as GenericTypedData,\n signature,\n options,\n );\n\n case \"ServerFilesAndPermission\":\n return sdk.permissions.submitSignedAddServerFilesAndPermissions(\n {\n ...typedData,\n primaryType: \"ServerFilesAndPermission\",\n } as ServerFilesAndPermissionTypedData,\n signature,\n options,\n );\n\n // TODO: RegisterGrantee with signature is not supported until\n // DataPortabilityGrantees contract adds registerGranteeWithSignature function\n // case \"RegisterGrantee\":\n // return sdk.permissions.submitSignedRegisterGrantee(...);\n\n default:\n // This should never be reached due to validation above, but TypeScript requires it\n throw new Error(\n `Unsupported operation type: ${typedData.primaryType}. ` +\n `Supported types: Permission, RevokePermission, TrustServer, AddServer, UntrustServer, ServerFilesAndPermission`,\n );\n }\n}\n\n/**\n * Handle direct (non-signed) operations\n */\nasync function handleDirectOperation(\n sdk: VanaInstance,\n request: DirectRelayerRequest,\n options?: TransactionOptions,\n): Promise<\n | TransactionResult<Contract, Fn<Contract>>\n | { url: string }\n | { fileId: number; transactionHash: Hash }\n> {\n switch (request.operation) {\n case \"submitFileAddition\": {\n const { url, userAddress } = request.params;\n\n // Use SDK to add file with no permissions\n const result = await sdk.data.addFileWithPermissions(\n url,\n userAddress,\n [], // No permissions\n options,\n );\n\n // Return the TransactionResult directly\n return result;\n }\n\n case \"submitFileAdditionWithPermissions\": {\n const { url, userAddress, permissions } = request.params;\n\n // Use SDK to add file with permissions\n const result = await sdk.data.addFileWithPermissions(\n url,\n userAddress,\n permissions,\n options,\n );\n\n // Return the TransactionResult directly\n return result;\n }\n\n case \"submitFileAdditionComplete\": {\n const { url, userAddress, permissions, schemaId, ownerAddress } =\n request.params;\n\n // Permissions are already encrypted, use the appropriate method\n // No mapping needed - permissions already have { account, key } format\n const txResult = await sdk.data.addFileWithEncryptedPermissionsAndSchema(\n url,\n ownerAddress ?? userAddress,\n permissions, // Already in correct format with encrypted 'key' field\n schemaId,\n options,\n );\n\n // File uploads need synchronous response with fileId\n // Use the SDK's built-in event parsing - it knows how to extract events from TransactionResult\n // The SDK has waitForTransactionEvents as a public method\n const eventResult = await (sdk as any).waitForTransactionEvents(txResult);\n const fileAddedEvent = eventResult.expectedEvents?.FileAdded;\n\n if (!fileAddedEvent || !fileAddedEvent.fileId) {\n console.error(\"Event result:\", eventResult);\n throw new Error(\"FileAdded event not found in transaction\");\n }\n\n const fileId = Number(fileAddedEvent.fileId);\n\n // Return as a direct result that the SDK expects\n return {\n fileId,\n transactionHash: txResult.hash,\n };\n }\n\n case \"storeGrantFile\": {\n const grantFile = request.params;\n\n // Access the data controller's context which has storage\n const dataController = sdk.data as any;\n const context = dataController.context;\n\n if (!context?.storageManager) {\n throw new Error(\n \"Storage configuration is required for storing grant files\",\n );\n }\n\n // Convert grant file to blob for storage\n const blob = new Blob([JSON.stringify(grantFile)], {\n type: \"application/json\",\n });\n\n // Upload directly to storage (IPFS) without blockchain transaction\n const uploadResult = await context.storageManager.upload(\n blob,\n `grant-${Date.now()}.json`,\n );\n\n return { url: uploadResult.url };\n }\n\n default: {\n // TypeScript exhaustiveness check - ensures all cases are handled at compile time\n const exhaustiveCheck: never = request;\n // Return exhaustiveCheck to satisfy TypeScript while throwing an error\n // This should never be reached if all cases are handled\n return exhaustiveCheck;\n }\n }\n}\n"],"mappings":"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","names":["uuidv4"]}
|
|
1
|
+
{"version":3,"sources":["../../src/server/relayerHandler.ts"],"sourcesContent":["import type { VanaInstance } from \"../index.node\";\nimport type {\n UnifiedRelayerRequest,\n UnifiedRelayerResponse,\n SignedRelayerRequest,\n DirectRelayerRequest,\n} from \"../types/relayer\";\nimport type {\n GenericTypedData,\n PermissionGrantTypedData,\n RevokePermissionTypedData,\n TrustServerTypedData,\n AddAndTrustServerTypedData,\n ServerFilesAndPermissionTypedData,\n TypedDataPrimaryType,\n} from \"../types/permissions\";\nimport { SignatureError } from \"../errors\";\nimport { recoverTypedDataAddress, getAddress, type Hash } from \"viem\";\n\n/**\n * Universal handler for all relayer operations.\n *\n * This function processes both EIP-712 signed operations and direct operations,\n * automatically routing to the appropriate SDK methods.\n *\n * @param sdk - Initialized Vana SDK instance\n * @param request - The unified relayer request\n * @returns Promise resolving to operation-specific response\n *\n * @category Server\n * @example\n * ```typescript\n * // In your server endpoint (Next.js example):\n * import { handleRelayerOperation } from '@opendatalabs/vana-sdk/node';\n *\n * export async function POST(request: NextRequest) {\n * try {\n * const body = await request.json();\n * const vana = getServerVanaInstance(); // Your server SDK instance\n *\n * const result = await handleRelayerOperation(vana, body);\n *\n * return NextResponse.json(result);\n * } catch (error) {\n * return NextResponse.json(\n * { error: error.message },\n * { status: 500 }\n * );\n * }\n * }\n * ```\n */\nexport async function handleRelayerOperation(\n sdk: VanaInstance,\n request: UnifiedRelayerRequest,\n): Promise<UnifiedRelayerResponse> {\n // Handle signed operations (EIP-712)\n if (request.type === \"signed\") {\n return handleSignedOperation(sdk, request);\n }\n\n // Handle direct operations (non-signed)\n return handleDirectOperation(sdk, request);\n}\n\n/**\n * Handle EIP-712 signed operations with full type safety\n */\nasync function handleSignedOperation(\n sdk: VanaInstance,\n request: SignedRelayerRequest,\n): Promise<UnifiedRelayerResponse> {\n const { typedData, signature, expectedUserAddress } = request;\n\n // Step 1: Verify the signature (security check)\n let recoveredAddress: `0x${string}`;\n try {\n recoveredAddress = await recoverTypedDataAddress({\n domain: {\n ...typedData.domain,\n chainId: typedData.domain.chainId\n ? BigInt(typedData.domain.chainId)\n : undefined,\n },\n types: typedData.types,\n primaryType: typedData.primaryType,\n message: typedData.message as unknown as Record<string, unknown>,\n signature,\n });\n } catch (error) {\n // Handle signature verification errors\n throw new SignatureError(\n `Signature verification failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n\n // Optional security check: Verify the signer matches expected address\n if (expectedUserAddress) {\n const normalizedExpected = getAddress(expectedUserAddress);\n const normalizedSigner = getAddress(recoveredAddress);\n\n if (normalizedSigner !== normalizedExpected) {\n throw new SignatureError(\n `Security verification failed: Recovered signer address (${normalizedSigner}) does not match expected user address (${normalizedExpected})`,\n );\n }\n }\n\n // Step 2: Route to appropriate SDK method based on primaryType\n // Using proper type narrowing instead of unsafe casts\n const result = await routeSignedOperation(sdk, typedData, signature);\n\n // Return the transaction hash with type\n return {\n type: \"signed\",\n hash: result.hash,\n };\n}\n\n/**\n * Route signed operations to the appropriate SDK method with type safety\n */\nasync function routeSignedOperation(\n sdk: VanaInstance,\n typedData: GenericTypedData,\n signature: Hash,\n) {\n const primaryType = typedData.primaryType as TypedDataPrimaryType;\n\n // Type-safe routing based on primaryType\n switch (primaryType) {\n case \"Permission\":\n // TypeScript knows this is a Permission operation\n return sdk.permissions.submitSignedGrant(\n {\n ...typedData,\n primaryType: \"Permission\",\n } as PermissionGrantTypedData,\n signature,\n );\n\n case \"RevokePermission\":\n return sdk.permissions.submitSignedRevoke(\n {\n ...typedData,\n primaryType: \"RevokePermission\",\n } as RevokePermissionTypedData,\n signature,\n );\n\n case \"TrustServer\":\n return sdk.permissions.submitSignedTrustServer(\n {\n ...typedData,\n primaryType: \"TrustServer\",\n } as TrustServerTypedData,\n signature,\n );\n\n case \"AddServer\":\n return sdk.permissions.submitSignedAddAndTrustServer(\n {\n ...typedData,\n primaryType: \"AddServer\",\n } as AddAndTrustServerTypedData,\n signature,\n );\n\n case \"UntrustServer\":\n return sdk.permissions.submitSignedUntrustServer(\n {\n ...typedData,\n primaryType: \"UntrustServer\",\n } as GenericTypedData,\n signature,\n );\n\n case \"ServerFilesAndPermission\":\n return sdk.permissions.submitSignedAddServerFilesAndPermissions(\n {\n ...typedData,\n primaryType: \"ServerFilesAndPermission\",\n } as ServerFilesAndPermissionTypedData,\n signature,\n );\n\n // TODO: RegisterGrantee with signature is not supported until\n // DataPortabilityGrantees contract adds registerGranteeWithSignature function\n // case \"RegisterGrantee\":\n // return sdk.permissions.submitSignedRegisterGrantee(...);\n\n default:\n throw new Error(`Unsupported operation type: ${typedData.primaryType}`);\n }\n}\n\n/**\n * Handle direct (non-signed) operations\n */\nasync function handleDirectOperation(\n sdk: VanaInstance,\n request: DirectRelayerRequest,\n): Promise<UnifiedRelayerResponse> {\n switch (request.operation) {\n case \"submitFileAddition\": {\n const { url, userAddress } = request.params;\n\n // Use SDK to add file with no permissions\n const result = await sdk.data.addFileWithPermissions(\n url,\n userAddress,\n [], // No permissions\n );\n\n // Wait for transaction events to get fileId\n const eventData = await sdk.waitForTransactionEvents(result);\n const fileId = eventData.expectedEvents?.FileAdded?.fileId;\n\n if (!fileId) {\n throw new Error(\"Failed to get fileId from transaction events\");\n }\n\n return {\n type: \"direct\",\n result: {\n fileId: Number(fileId),\n transactionHash: result.hash,\n },\n };\n }\n\n case \"submitFileAdditionWithPermissions\": {\n const { url, userAddress, permissions } = request.params;\n\n // Use SDK to add file with permissions\n const result = await sdk.data.addFileWithPermissions(\n url,\n userAddress,\n permissions,\n );\n\n // Wait for transaction events to get fileId\n const eventData = await sdk.waitForTransactionEvents(result);\n const fileId = eventData.expectedEvents?.FileAdded?.fileId;\n\n if (!fileId) {\n throw new Error(\"Failed to get fileId from transaction events\");\n }\n\n return {\n type: \"direct\",\n result: {\n fileId: Number(fileId),\n transactionHash: result.hash,\n },\n };\n }\n\n case \"submitFileAdditionComplete\": {\n const { url, userAddress, permissions, schemaId, ownerAddress } =\n request.params;\n\n // Permissions are already encrypted, use the appropriate method\n // No mapping needed - permissions already have { account, key } format\n const result = await sdk.data.addFileWithEncryptedPermissionsAndSchema(\n url,\n ownerAddress ?? userAddress,\n permissions, // Already in correct format with encrypted 'key' field\n schemaId,\n );\n\n // Wait for transaction events to get fileId\n const eventData = await sdk.waitForTransactionEvents(result);\n const fileId = eventData.expectedEvents?.FileAdded?.fileId;\n\n if (!fileId) {\n throw new Error(\"Failed to get fileId from transaction events\");\n }\n\n return {\n type: \"direct\",\n result: {\n fileId: Number(fileId),\n transactionHash: result.hash,\n },\n };\n }\n\n case \"storeGrantFile\": {\n const grantFile = request.params;\n\n // Store grant file using SDK's data controller\n // Convert grant file to blob for storage\n const blob = new Blob([JSON.stringify(grantFile)], {\n type: \"application/json\",\n });\n\n // Upload using the data controller\n const result = await sdk.data.upload({\n content: blob,\n filename: `grant-${Date.now()}.json`,\n });\n\n return {\n type: \"direct\",\n result: { url: result.url },\n };\n }\n\n default: {\n // TypeScript exhaustiveness check - ensures all cases are handled at compile time\n const exhaustiveCheck: never = request;\n // Return exhaustiveCheck to satisfy TypeScript while throwing an error\n // This should never be reached if all cases are handled\n return exhaustiveCheck;\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { VanaInstance } from "../index.node";
|
|
2
2
|
import type { UnifiedRelayerRequest, UnifiedRelayerResponse } from "../types/relayer";
|
|
3
|
-
import type { TransactionOptions } from "../types";
|
|
4
3
|
/**
|
|
5
4
|
* Universal handler for all relayer operations.
|
|
6
5
|
*
|
|
@@ -34,5 +33,4 @@ import type { TransactionOptions } from "../types";
|
|
|
34
33
|
* }
|
|
35
34
|
* ```
|
|
36
35
|
*/
|
|
37
|
-
export declare function handleRelayerOperation(sdk: VanaInstance,
|
|
38
|
-
request: UnifiedRelayerRequest, options?: TransactionOptions): Promise<UnifiedRelayerResponse>;
|
|
36
|
+
export declare function handleRelayerOperation(sdk: VanaInstance, request: UnifiedRelayerRequest): Promise<UnifiedRelayerResponse>;
|