@@ -8,7 +8,10 @@ import {
88 MetadataCacheRequest ,
99 MetadataCacheResponse ,
1010 StandardErrorCode ,
11- ErrorCategory
11+ ErrorCategory ,
12+ GetDiscoveryResponse ,
13+ GetMetaTypesResponse ,
14+ GetMetaItemsResponse
1215} from '@objectstack/spec/api' ;
1316import { Logger , createLogger } from '@objectstack/core' ;
1417
@@ -29,16 +32,11 @@ export interface ClientConfig {
2932 debug ?: boolean ;
3033}
3134
32- export interface DiscoveryResult {
33- routes : {
34- discovery : string ;
35- metadata : string ;
36- data : string ;
37- auth : string ;
38- ui : string ;
39- } ;
40- capabilities ?: Record < string , boolean > ;
41- }
35+ /**
36+ * Discovery Result
37+ * Re-export from @objectstack/spec/api for convenience
38+ */
39+ export type DiscoveryResult = GetDiscoveryResponse ;
4240
4341export interface QueryOptions {
4442 select ?: string [ ] ; // Simplified Selection
@@ -69,7 +67,7 @@ export class ObjectStackClient {
6967 private baseUrl : string ;
7068 private token ?: string ;
7169 private fetchImpl : ( input : RequestInfo | URL , init ?: RequestInit ) => Promise < Response > ;
72- private routes ?: DiscoveryResult [ 'routes' ] ;
70+ private discoveryInfo ?: DiscoveryResult ;
7371 private logger : Logger ;
7472
7573 constructor ( config : ClientConfig ) {
@@ -87,21 +85,21 @@ export class ObjectStackClient {
8785 }
8886
8987 /**
90- * Initialize the client by discovering server capabilities and routes .
88+ * Initialize the client by discovering server capabilities.
9189 */
9290 async connect ( ) {
9391 this . logger . debug ( 'Connecting to ObjectStack server' , { baseUrl : this . baseUrl } ) ;
9492
9593 try {
96- // Connect to the discovery endpoint
97- // During boot, we might not know routes, so we check convention /api/v1 first
94+ // Connect to the discovery endpoint at /api/v1
9895 const res = await this . fetch ( `${ this . baseUrl } /api/v1` ) ;
9996
10097 const data = await res . json ( ) ;
101- this . routes = data . routes ;
98+ this . discoveryInfo = data ;
10299
103100 this . logger . info ( 'Connected to ObjectStack server' , {
104- routes : Object . keys ( data . routes || { } ) ,
101+ version : data . version ,
102+ apiName : data . apiName ,
105103 capabilities : data . capabilities
106104 } ) ;
107105
@@ -116,11 +114,47 @@ export class ObjectStackClient {
116114 * Metadata Operations
117115 */
118116 meta = {
117+ /**
118+ * Get all available metadata types
119+ * Returns types like 'object', 'plugin', 'view', etc.
120+ */
121+ getTypes : async ( ) : Promise < GetMetaTypesResponse > => {
122+ const route = this . getRoute ( 'metadata' ) ;
123+ const res = await this . fetch ( `${ this . baseUrl } ${ route } ` ) ;
124+ return res . json ( ) ;
125+ } ,
126+
127+ /**
128+ * Get all items of a specific metadata type
129+ * @param type - Metadata type name (e.g., 'object', 'plugin')
130+ */
131+ getItems : async ( type : string ) : Promise < GetMetaItemsResponse > => {
132+ const route = this . getRoute ( 'metadata' ) ;
133+ const res = await this . fetch ( `${ this . baseUrl } ${ route } /${ type } ` ) ;
134+ return res . json ( ) ;
135+ } ,
136+
137+ /**
138+ * Get a specific object definition by name
139+ * @deprecated Use `getItem('object', name)` instead for consistency with spec protocol
140+ * @param name - Object name (snake_case identifier)
141+ */
119142 getObject : async ( name : string ) => {
120143 const route = this . getRoute ( 'metadata' ) ;
121144 const res = await this . fetch ( `${ this . baseUrl } ${ route } /object/${ name } ` ) ;
122145 return res . json ( ) ;
123146 } ,
147+
148+ /**
149+ * Get a specific metadata item by type and name
150+ * @param type - Metadata type (e.g., 'object', 'plugin')
151+ * @param name - Item name (snake_case identifier)
152+ */
153+ getItem : async ( type : string , name : string ) => {
154+ const route = this . getRoute ( 'metadata' ) ;
155+ const res = await this . fetch ( `${ this . baseUrl } ${ route } /${ type } /${ name } ` ) ;
156+ return res . json ( ) ;
157+ } ,
124158
125159 /**
126160 * Get object metadata with cache support
@@ -407,16 +441,20 @@ export class ObjectStackClient {
407441 return res ;
408442 }
409443
410- private getRoute ( key : keyof DiscoveryResult [ 'routes' ] ) : string {
411- if ( ! this . routes ) {
412- // Fallback for strictness, but we allow bootstrapping
413- this . logger . warn ( 'Accessing route before connect()' , {
414- route : key ,
415- fallback : `/api/v1/${ key } `
416- } ) ;
417- return `/api/v1/${ key } ` ;
418- }
419- return this . routes [ key ] || `/api/v1/${ key } ` ;
444+ /**
445+ * Get the conventional route path for a given API endpoint type
446+ * ObjectStack uses standard conventions: /api/v1/data, /api/v1/meta, /api/v1/ui
447+ */
448+ private getRoute ( type : 'data' | 'metadata' | 'ui' | 'auth' ) : string {
449+ // Use conventional ObjectStack API paths
450+ const routeMap : Record < string , string > = {
451+ data : '/api/v1/data' ,
452+ metadata : '/api/v1/meta' ,
453+ ui : '/api/v1/ui' ,
454+ auth : '/api/v1/auth'
455+ } ;
456+
457+ return routeMap [ type ] || `/api/v1/${ type } ` ;
420458 }
421459}
422460
@@ -435,5 +473,8 @@ export type {
435473 MetadataCacheRequest ,
436474 MetadataCacheResponse ,
437475 StandardErrorCode ,
438- ErrorCategory
476+ ErrorCategory ,
477+ GetDiscoveryResponse ,
478+ GetMetaTypesResponse ,
479+ GetMetaItemsResponse
439480} from '@objectstack/spec/api' ;
0 commit comments