@@ -19,11 +19,13 @@ import { getTelemetryConfig } from './telemetry-config.js'
1919export * from './constants.js'
2020
2121const WEBSOCKET_REGEX = / ^ w s ( s ) ? : \/ \/ / i
22+ const AUTH_MODE_SYMBOL = Symbol . for ( 'filecoin-pin.authMode' )
2223
2324let synapseInstance : Synapse | null = null
2425let storageInstance : StorageContext | null = null
2526let currentProviderInfo : ProviderInfo | null = null
2627let activeProvider : any = null // Track the provider for cleanup
28+ type AuthMode = 'standard' | 'session-key' | 'read-only' | 'signer'
2729
2830/**
2931 * Complete application configuration interface
@@ -49,6 +51,8 @@ interface BaseSynapseConfig extends Omit<SynapseOptions, 'withCDN' | 'warmStorag
4951 rpcUrl ?: string | undefined
5052 /** Optional override for WarmStorage contract address */
5153 warmStorageAddress ?: string | undefined
54+ /** Optional flag for read-only auth (address-only signer) */
55+ readOnly ?: boolean | undefined
5256 withCDN ?: boolean | undefined
5357 /** Default metadata to apply when creating or reusing datasets */
5458 dataSetMetadata ?: Record < string , string >
@@ -83,6 +87,16 @@ export interface SessionKeyConfig extends BaseSynapseConfig {
8387 sessionKey : string
8488}
8589
90+ /**
91+ * Read-only authentication using an address-only signer
92+ *
93+ * This supports querying balances and status without signing transactions.
94+ */
95+ export interface ReadOnlyConfig extends BaseSynapseConfig {
96+ walletAddress : string
97+ readOnly : true
98+ }
99+
86100/**
87101 * Signer-based authentication with ethers Signer
88102 */
@@ -100,7 +114,7 @@ export interface SignerConfig extends BaseSynapseConfig {
100114 * 2. Session Key: walletAddress + sessionKey
101115 * 3. Signer: ethers Signer instance
102116 */
103- export type SynapseSetupConfig = PrivateKeyConfig | SessionKeyConfig | SignerConfig
117+ export type SynapseSetupConfig = PrivateKeyConfig | SessionKeyConfig | ReadOnlyConfig | SignerConfig
104118
105119/**
106120 * Structured service object containing the fully initialized Synapse SDK and
@@ -190,6 +204,18 @@ export function resetSynapseService(): void {
190204 activeProvider = null
191205}
192206
207+ function setAuthMode ( synapse : Synapse , mode : AuthMode ) : void {
208+ ; ( synapse as any ) [ AUTH_MODE_SYMBOL ] = mode
209+ }
210+
211+ export function isViewOnlyMode ( synapse : Synapse ) : boolean {
212+ try {
213+ return ( synapse as any ) [ AUTH_MODE_SYMBOL ] === 'read-only'
214+ } catch {
215+ return false
216+ }
217+ }
218+
193219/**
194220 * Check if Synapse is using session key authentication
195221 *
@@ -203,6 +229,10 @@ export function resetSynapseService(): void {
203229 */
204230export function isSessionKeyMode ( synapse : Synapse ) : boolean {
205231 try {
232+ const markedMode = ( synapse as any ) [ AUTH_MODE_SYMBOL ]
233+ if ( markedMode === 'session-key' ) return true
234+ if ( markedMode === 'read-only' ) return false
235+
206236 const client = synapse . getClient ( )
207237
208238 // The client might be wrapped in a NonceManager, check the underlying signer
@@ -231,30 +261,40 @@ function isSessionKeyConfig(config: Partial<SynapseSetupConfig>): config is Sess
231261 )
232262}
233263
264+ function isReadOnlyConfig ( config : Partial < SynapseSetupConfig > ) : config is ReadOnlyConfig {
265+ return config . readOnly === true && 'walletAddress' in config && config . walletAddress != null
266+ }
267+
234268function isSignerConfig ( config : Partial < SynapseSetupConfig > ) : config is SignerConfig {
235269 return 'signer' in config && config . signer != null
236270}
237271
238272/**
239273 * Validate authentication configuration
240274 */
241- function validateAuthConfig ( config : Partial < SynapseSetupConfig > ) : 'standard' | 'session-key' | 'signer' {
275+ function validateAuthConfig ( config : Partial < SynapseSetupConfig > ) : 'standard' | 'session-key' | 'read-only' | ' signer' {
242276 const hasPrivateKey = isPrivateKeyConfig ( config )
243277 const hasSessionKey = isSessionKeyConfig ( config )
278+ const hasReadOnly = isReadOnlyConfig ( config )
244279 const hasSigner = isSignerConfig ( config )
245280
246- const authCount = [ hasPrivateKey , hasSessionKey , hasSigner ] . filter ( Boolean ) . length
281+ const authCount = [ hasPrivateKey , hasSessionKey , hasReadOnly , hasSigner ] . filter ( Boolean ) . length
247282
248283 if ( authCount === 0 ) {
249- throw new Error ( 'Authentication required: provide either privateKey, walletAddress + sessionKey, or signer' )
284+ throw new Error (
285+ 'Authentication required: provide either privateKey, walletAddress + sessionKey, view-address, or signer'
286+ )
250287 }
251288
252289 if ( authCount > 1 ) {
253- throw new Error ( 'Conflicting authentication: provide only one of privateKey, walletAddress + sessionKey, or signer' )
290+ throw new Error (
291+ 'Conflicting authentication: provide only one of privateKey, walletAddress + sessionKey, view-address, or signer'
292+ )
254293 }
255294
256295 if ( hasPrivateKey ) return 'standard'
257296 if ( hasSessionKey ) return 'session-key'
297+ if ( hasReadOnly ) return 'read-only'
258298 return 'signer'
259299}
260300
@@ -382,6 +422,23 @@ export async function initializeSynapse(config: Partial<SynapseSetupConfig>, log
382422 signer : ownerSigner ,
383423 } )
384424 await setupSessionKey ( synapse , sessionWallet , logger )
425+ setAuthMode ( synapse , 'session-key' )
426+ } else if ( authMode === 'read-only' ) {
427+ // Read-only mode - type guard ensures walletAddress is defined
428+ if ( ! isReadOnlyConfig ( config ) ) {
429+ throw new Error ( 'Internal error: read-only mode but config type mismatch' )
430+ }
431+
432+ const provider = createProvider ( rpcURL )
433+ activeProvider = provider
434+
435+ const readOnlySigner = new AddressOnlySigner ( config . walletAddress , provider )
436+
437+ synapse = await Synapse . create ( {
438+ ...synapseOptions ,
439+ signer : readOnlySigner ,
440+ } )
441+ setAuthMode ( synapse , 'read-only' )
385442 } else if ( authMode === 'signer' ) {
386443 // Signer mode - type guard ensures signer is defined
387444 if ( ! isSignerConfig ( config ) ) {
@@ -390,6 +447,7 @@ export async function initializeSynapse(config: Partial<SynapseSetupConfig>, log
390447
391448 synapse = await Synapse . create ( { ...synapseOptions , signer : config . signer } )
392449 activeProvider = synapse . getProvider ( )
450+ setAuthMode ( synapse , 'signer' )
393451 } else {
394452 // Private key mode - type guard ensures privateKey is defined
395453 if ( ! isPrivateKeyConfig ( config ) ) {
@@ -398,6 +456,7 @@ export async function initializeSynapse(config: Partial<SynapseSetupConfig>, log
398456
399457 synapse = await Synapse . create ( { ...synapseOptions , privateKey : config . privateKey } )
400458 activeProvider = synapse . getProvider ( )
459+ setAuthMode ( synapse , 'standard' )
401460 }
402461
403462 const network = synapse . getNetwork ( )
0 commit comments