@@ -12,10 +12,14 @@ The `@objectql/sdk` package provides a type-safe HTTP client for ObjectQL server
1212## ✨ Features
1313
1414* ** 🌍 Universal Runtime** - Works in browsers, Node.js, Deno, and edge environments
15- * ** 📦 Zero Dependencies** - Only depends on ` @objectql/types ` for type definitions
15+ * ** 📦 Zero Dependencies** - Only depends on ` @objectql/types ` and ` @objectstack/spec ` for type definitions
1616* ** 🔒 Type-Safe** - Full TypeScript support with generics
1717* ** 🚀 Modern APIs** - Uses native ` fetch ` API available in all modern JavaScript runtimes
1818* ** 🎯 RESTful Interface** - Clean, predictable API design
19+ * ** ✅ DriverInterface v4.0** - Fully compliant with ObjectStack protocol specification
20+ * ** 🔐 Authentication** - Built-in support for Bearer tokens and API keys
21+ * ** 🔄 Retry Logic** - Automatic retry with exponential backoff for network resilience
22+ * ** 📊 Request Logging** - Optional request/response logging for debugging
1923
2024---
2125
@@ -290,6 +294,274 @@ const actions = await metadataClient.listActions('users');
290294
291295---
292296
297+ ### RemoteDriver (DriverInterface v4.0)
298+
299+ Client for connecting to a remote ObjectQL server via HTTP. Implements the standard ` DriverInterface ` from ` @objectstack/spec ` .
300+
301+ #### Constructor
302+
303+ ``` typescript
304+ // Legacy constructor
305+ new RemoteDriver (baseUrl : string , rpcPath ?: string )
306+
307+ // New config-based constructor (recommended)
308+ new RemoteDriver (config : SdkConfig )
309+ ```
310+
311+ ** Config Options:**
312+ * ` baseUrl ` (string, required) - Base URL of the ObjectQL server
313+ * ` rpcPath ` (string, optional) - JSON-RPC endpoint path (default: /api/objectql)
314+ * ` queryPath ` (string, optional) - Query endpoint path (default: /api/query)
315+ * ` commandPath ` (string, optional) - Command endpoint path (default: /api/command)
316+ * ` executePath ` (string, optional) - Custom execute endpoint path (default: /api/execute)
317+ * ` token ` (string, optional) - Authentication token (Bearer)
318+ * ` apiKey ` (string, optional) - API key for authentication
319+ * ` headers ` (Record<string, string>, optional) - Custom HTTP headers
320+ * ` timeout ` (number, optional) - Request timeout in milliseconds (default: 30000)
321+ * ` enableRetry ` (boolean, optional) - Enable automatic retry on failure (default: false)
322+ * ` maxRetries ` (number, optional) - Maximum retry attempts (default: 3)
323+ * ` enableLogging ` (boolean, optional) - Enable request/response logging (default: false)
324+
325+ #### Methods
326+
327+ ##### ` executeQuery(ast: QueryAST, options?: any): Promise<{ value: any[]; count?: number }> `
328+
329+ Execute a query using QueryAST format (DriverInterface v4.0).
330+
331+ ``` typescript
332+ import { RemoteDriver } from ' @objectql/sdk' ;
333+
334+ const driver = new RemoteDriver ({
335+ baseUrl: ' http://localhost:3000' ,
336+ token: ' your-auth-token' ,
337+ enableRetry: true ,
338+ maxRetries: 3
339+ });
340+
341+ // Execute a QueryAST
342+ const result = await driver .executeQuery ({
343+ object: ' users' ,
344+ fields: [' name' , ' email' , ' status' ],
345+ filters: {
346+ type: ' comparison' ,
347+ field: ' status' ,
348+ operator: ' =' ,
349+ value: ' active'
350+ },
351+ sort: [{ field: ' created_at' , order: ' desc' }],
352+ top: 10 ,
353+ skip: 0
354+ });
355+
356+ console .log (result .value ); // Array of users
357+ console .log (result .count ); // Total count
358+ ```
359+
360+ ##### ` executeCommand(command: Command, options?: any): Promise<CommandResult> `
361+
362+ Execute a command for mutation operations (create, update, delete, bulk operations).
363+
364+ ``` typescript
365+ // Create a record
366+ const createResult = await driver .executeCommand ({
367+ type: ' create' ,
368+ object: ' users' ,
369+ data: {
370+ name: ' Alice' ,
371+ email: ' alice@example.com' ,
372+ status: ' active'
373+ }
374+ });
375+
376+ console .log (createResult .success ); // true
377+ console .log (createResult .data ); // Created record
378+ console .log (createResult .affected ); // 1
379+
380+ // Update a record
381+ const updateResult = await driver .executeCommand ({
382+ type: ' update' ,
383+ object: ' users' ,
384+ id: ' user_123' ,
385+ data: { status: ' inactive' }
386+ });
387+
388+ // Delete a record
389+ const deleteResult = await driver .executeCommand ({
390+ type: ' delete' ,
391+ object: ' users' ,
392+ id: ' user_123'
393+ });
394+
395+ // Bulk create
396+ const bulkCreateResult = await driver .executeCommand ({
397+ type: ' bulkCreate' ,
398+ object: ' users' ,
399+ records: [
400+ { name: ' Bob' , email: ' bob@example.com' },
401+ { name: ' Charlie' , email: ' charlie@example.com' }
402+ ]
403+ });
404+
405+ // Bulk update
406+ const bulkUpdateResult = await driver .executeCommand ({
407+ type: ' bulkUpdate' ,
408+ object: ' users' ,
409+ updates: [
410+ { id: ' user_1' , data: { status: ' active' } },
411+ { id: ' user_2' , data: { status: ' inactive' } }
412+ ]
413+ });
414+
415+ // Bulk delete
416+ const bulkDeleteResult = await driver .executeCommand ({
417+ type: ' bulkDelete' ,
418+ object: ' users' ,
419+ ids: [' user_1' , ' user_2' , ' user_3' ]
420+ });
421+ ```
422+
423+ ##### ` execute(endpoint?: string, payload?: any, options?: any): Promise<any> `
424+
425+ Execute a custom operation on the remote server.
426+
427+ ``` typescript
428+ // Execute a custom workflow
429+ const workflowResult = await driver .execute (' /api/workflows/approve' , {
430+ workflowId: ' wf_123' ,
431+ comment: ' Approved by manager'
432+ });
433+
434+ // Use default execute endpoint
435+ const customResult = await driver .execute (undefined , {
436+ action: ' calculateMetrics' ,
437+ params: { year: 2024 , quarter: ' Q1' }
438+ });
439+
440+ // Call a custom action
441+ const actionResult = await driver .execute (' /api/actions/send-email' , {
442+ to: ' user@example.com' ,
443+ subject: ' Welcome' ,
444+ body: ' Welcome to our platform!'
445+ });
446+ ```
447+
448+ #### Legacy CRUD Methods
449+
450+ The RemoteDriver also supports legacy CRUD methods for backward compatibility:
451+
452+ ``` typescript
453+ // Find records
454+ const users = await driver .find (' users' , {
455+ filters: [[' status' , ' =' , ' active' ]],
456+ sort: [[' name' , ' asc' ]],
457+ limit: 10
458+ });
459+
460+ // Find one record
461+ const user = await driver .findOne (' users' , ' user_123' );
462+
463+ // Create a record
464+ const newUser = await driver .create (' users' , {
465+ name: ' Alice' ,
466+ email: ' alice@example.com'
467+ });
468+
469+ // Update a record
470+ const updated = await driver .update (' users' , ' user_123' , {
471+ status: ' inactive'
472+ });
473+
474+ // Delete a record
475+ await driver .delete (' users' , ' user_123' );
476+
477+ // Count records
478+ const count = await driver .count (' users' , {
479+ filters: [[' status' , ' =' , ' active' ]]
480+ });
481+ ```
482+
483+ ### Authentication Examples
484+
485+ ``` typescript
486+ // Bearer token authentication
487+ const driverWithToken = new RemoteDriver ({
488+ baseUrl: ' http://localhost:3000' ,
489+ token: ' eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
490+ });
491+
492+ // API key authentication
493+ const driverWithApiKey = new RemoteDriver ({
494+ baseUrl: ' http://localhost:3000' ,
495+ apiKey: ' sk-1234567890abcdef'
496+ });
497+
498+ // Both token and API key
499+ const driverWithBoth = new RemoteDriver ({
500+ baseUrl: ' http://localhost:3000' ,
501+ token: ' jwt-token' ,
502+ apiKey: ' api-key'
503+ });
504+
505+ // Custom headers
506+ const driverWithHeaders = new RemoteDriver ({
507+ baseUrl: ' http://localhost:3000' ,
508+ headers: {
509+ ' X-Tenant-ID' : ' tenant_123' ,
510+ ' X-Request-ID' : crypto .randomUUID ()
511+ }
512+ });
513+ ```
514+
515+ ### Error Handling and Retry
516+
517+ ``` typescript
518+ import { ObjectQLError , ApiErrorCode } from ' @objectql/types' ;
519+
520+ // Enable retry with exponential backoff
521+ const driver = new RemoteDriver ({
522+ baseUrl: ' http://localhost:3000' ,
523+ enableRetry: true ,
524+ maxRetries: 3 ,
525+ timeout: 10000
526+ });
527+
528+ try {
529+ const result = await driver .executeQuery ({ object: ' users' });
530+ } catch (error ) {
531+ if (error instanceof ObjectQLError ) {
532+ switch (error .code ) {
533+ case ApiErrorCode .UNAUTHORIZED :
534+ console .error (' Authentication required' );
535+ break ;
536+ case ApiErrorCode .VALIDATION_ERROR :
537+ console .error (' Validation failed:' , error .details );
538+ break ;
539+ case ApiErrorCode .NOT_FOUND :
540+ console .error (' Resource not found' );
541+ break ;
542+ default :
543+ console .error (' API error:' , error .message );
544+ }
545+ }
546+ }
547+ ```
548+
549+ ### Request Logging
550+
551+ ``` typescript
552+ // Enable logging for debugging
553+ const driver = new RemoteDriver ({
554+ baseUrl: ' http://localhost:3000' ,
555+ enableLogging: true
556+ });
557+
558+ // Logs will be printed to console:
559+ // [RemoteDriver] executeQuery { endpoint: '...', ast: {...} }
560+ // [RemoteDriver] executeQuery response { value: [...], count: 10 }
561+ ```
562+
563+ ---
564+
293565## 🌐 Browser Compatibility
294566
295567The SDK uses modern JavaScript APIs available in all current browsers:
0 commit comments