feat(fetcher): add configureNativeFetcher cross-platform API

Add configureNativeFetcher() plugin method to enable TypeScript configuration
of native fetchers with API credentials. This provides a cross-platform
mechanism for passing configuration from JavaScript to native code without
relying on platform-specific storage.

- Add configure() method to NativeNotificationContentFetcher interface
  (optional, defaults to no-op for fetchers that don't need config)
- Add configureNativeFetcher plugin method in DailyNotificationPlugin
- Add TypeScript definitions and comprehensive JSDoc
- Create NATIVE_FETCHER_CONFIGURATION.md documentation
- Update TestNativeFetcher to use real API endpoint (10.0.2.2:3000)
- Update DemoNativeFetcher Javadoc explaining configure() is optional
- Add configureNativeFetcher() call to demo app's configurePlugin()

Enables host apps to configure native fetchers from TypeScript, keeping
the interface consistent across Android, iOS, and web platforms.
This commit is contained in:
Matthew Raymer
2025-10-30 10:03:47 +00:00
parent 59cd975c24
commit c1cc8802f6
5 changed files with 954 additions and 30 deletions

View File

@@ -82,5 +82,62 @@ public interface NativeNotificationContentFetcher {
*/
@NonNull
CompletableFuture<List<NotificationContent>> fetchContent(@NonNull FetchContext context);
/**
* Optional: Configure the native fetcher with API credentials and settings
*
* <p>This method is called by the plugin when {@code configureNativeFetcher} is invoked
* from TypeScript. It provides a cross-platform mechanism for passing configuration
* from the JavaScript layer to native code without using platform-specific storage
* mechanisms.</p>
*
* <p><b>When to implement:</b></p>
* <ul>
* <li>Your fetcher needs API credentials (URL, authentication tokens, etc.)</li>
* <li>Configuration should come from TypeScript/JavaScript code (e.g., from app config)</li>
* <li>You want to avoid hardcoding credentials in native code</li>
* </ul>
*
* <p><b>When to skip (use default no-op):</b></p>
* <ul>
* <li>Your fetcher gets credentials from platform-specific storage (SharedPreferences, Keychain, etc.)</li>
* <li>Your fetcher has hardcoded test credentials</li>
* <li>Configuration is handled internally and doesn't need external input</li>
* </ul>
*
* <p><b>Thread Safety:</b> This method may be called from any thread. Implementations
* must be thread-safe if storing configuration in instance variables.</p>
*
* <p><b>Implementation Pattern:</b></p>
* <pre>{@code
* private volatile String apiBaseUrl;
* private volatile String activeDid;
* private volatile String jwtSecret;
*
* @Override
* public void configure(String apiBaseUrl, String activeDid, String jwtSecret) {
* this.apiBaseUrl = apiBaseUrl;
* this.activeDid = activeDid;
* this.jwtSecret = jwtSecret;
* Log.i(TAG, "Fetcher configured with API: " + apiBaseUrl);
* }
* }</pre>
*
* @param apiBaseUrl Base URL for API server. Examples:
* - Android emulator: "http://10.0.2.2:3000" (maps to host localhost:3000)
* - iOS simulator: "http://localhost:3000"
* - Production: "https://api.timesafari.com"
* @param activeDid Active DID (Decentralized Identifier) for authentication.
* Used as the JWT issuer/subject. Format: "did:ethr:0x..."
* @param jwtSecret JWT secret key for signing authentication tokens.
* Keep this secure - consider using secure storage for production.
*
* @see DailyNotificationPlugin#configureNativeFetcher(PluginCall)
*/
default void configure(String apiBaseUrl, String activeDid, String jwtSecret) {
// Default no-op implementation - fetchers that need config can override
// This allows fetchers that don't need TypeScript-provided configuration
// to ignore this method without implementing an empty body.
}
}