@flxbl-dev/client 0.1.0

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/README.md ADDED
@@ -0,0 +1,177 @@
1
+ # @flxbl-dev/client
2
+
3
+ Lightweight, type-safe runtime SDK for [FLXBL](https://flxbl.dev). Zero dependencies — uses native `fetch`.
4
+
5
+ This package is the **production dependency** your app ships with. The generated typed client (from `@flxbl-dev/cli`) extends `FlxblClient` with schema-specific collections and full autocomplete.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @flxbl-dev/client
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ Use the generated client from `@flxbl-dev/cli` for full type safety:
16
+
17
+ ```typescript
18
+ import { createFlxblClient } from './flxbl/_generated';
19
+
20
+ const db = createFlxblClient({
21
+ instanceUrl: 'https://api.flxbl.dev',
22
+ apiKey: process.env.FLXBL_API_KEY,
23
+ });
24
+
25
+ // Fully typed — autocomplete on fields, type-checked inputs
26
+ const users = await db.users.findMany({ where: { role: 'admin' }, limit: 10 });
27
+ const post = await db.posts.create({ title: 'Hello', content: '...', published: true });
28
+ const user = await db.users.findById('abc123');
29
+ await db.users.update('abc123', { role: 'user' });
30
+ await db.users.delete('abc123');
31
+ ```
32
+
33
+ Or use the base client directly for untyped access:
34
+
35
+ ```typescript
36
+ import { FlxblClient } from '@flxbl-dev/client';
37
+
38
+ const client = new FlxblClient({
39
+ instanceUrl: 'https://api.flxbl.dev',
40
+ apiKey: process.env.FLXBL_API_KEY,
41
+ });
42
+
43
+ // Raw request
44
+ const users = await client.request('POST', '/api/v1/dynamic/User/query', {
45
+ where: { role: 'admin' },
46
+ limit: 10,
47
+ });
48
+ ```
49
+
50
+ ## Configuration
51
+
52
+ ```typescript
53
+ import { FlxblClient } from '@flxbl-dev/client';
54
+
55
+ const client = new FlxblClient({
56
+ // Required
57
+ instanceUrl: 'https://api.flxbl.dev',
58
+
59
+ // Auth — provide one of:
60
+ apiKey: 'flxbl_abc123...', // API key (recommended for server-side)
61
+ accessToken: 'eyJhbG...', // JWT token (for browser/short-lived)
62
+
63
+ // Optional
64
+ fetch: customFetch, // Custom fetch implementation
65
+ });
66
+
67
+ // You can also set the token dynamically
68
+ client.setAccessToken('eyJhbG...');
69
+ ```
70
+
71
+ ## Collection Methods
72
+
73
+ Each generated collection (e.g., `db.users`) provides:
74
+
75
+ | Method | Description |
76
+ |--------|-------------|
77
+ | `findMany(options?)` | Query with filters, sorting, pagination, traversals |
78
+ | `findById(id)` | Get a single record by ID |
79
+ | `create(data)` | Create a new record |
80
+ | `update(id, data)` | Partial update by ID |
81
+ | `delete(id)` | Delete by ID |
82
+
83
+ ### Query Options
84
+
85
+ ```typescript
86
+ const result = await db.users.findMany({
87
+ where: { isActive: true, role: { $in: ['admin', 'editor'] } },
88
+ select: ['id', 'email', 'role'],
89
+ orderBy: 'createdAt',
90
+ orderDirection: 'DESC',
91
+ offset: 0,
92
+ limit: 25,
93
+ includeCount: true,
94
+ traverse: [{ relationship: 'AUTHORED', direction: 'out', select: ['title'] }],
95
+ });
96
+
97
+ console.log(result.items); // User[]
98
+ console.log(result.count); // total count (if includeCount: true)
99
+ ```
100
+
101
+ ### Filter Operators
102
+
103
+ | Operator | Description |
104
+ |----------|-------------|
105
+ | `$eq` | Equals |
106
+ | `$neq` | Not equals |
107
+ | `$gt`, `$gte` | Greater than (or equal) |
108
+ | `$lt`, `$lte` | Less than (or equal) |
109
+ | `$in`, `$notIn` | Value in / not in array |
110
+ | `$isNull` | Is null check |
111
+ | `$contains` | String contains |
112
+ | `$startsWith`, `$endsWith` | String prefix/suffix |
113
+ | `$and`, `$or` | Logical operators |
114
+
115
+ ## GraphQL
116
+
117
+ ```typescript
118
+ const { data, errors } = await client.graphql(
119
+ 'tenant-id',
120
+ `query { users { id email } }`,
121
+ { /* variables */ },
122
+ );
123
+ ```
124
+
125
+ ## Relationships
126
+
127
+ ```typescript
128
+ const rels = client.relationships('User', 'user-123');
129
+
130
+ // Create a relationship
131
+ await rels.create('AUTHORED', 'post-456', { role: 'primary' });
132
+
133
+ // List related entities
134
+ const { items, count } = await rels.list('AUTHORED', 'out');
135
+
136
+ // Delete a relationship
137
+ await rels.delete('AUTHORED', 'post-456');
138
+ ```
139
+
140
+ ## Error Handling
141
+
142
+ ```typescript
143
+ import { FlxblApiError, FlxblAuthError, FlxblValidationError } from '@flxbl-dev/client';
144
+
145
+ try {
146
+ await db.users.create({ email: 'bad' });
147
+ } catch (error) {
148
+ if (error instanceof FlxblAuthError) {
149
+ // 401 — re-authenticate
150
+ } else if (error instanceof FlxblValidationError) {
151
+ // 400 — check error.validationErrors
152
+ } else if (error instanceof FlxblApiError) {
153
+ // Generic API error — check error.statusCode
154
+ }
155
+ }
156
+ ```
157
+
158
+ ## How It Works
159
+
160
+ Under the hood, the client maps collection methods to FLXBL's Dynamic REST API:
161
+
162
+ | Method | HTTP Request |
163
+ |--------|-------------|
164
+ | `db.users.findMany(opts)` | `POST /api/v1/dynamic/User/query` |
165
+ | `db.users.findById(id)` | `GET /api/v1/dynamic/User/:id` |
166
+ | `db.users.create(data)` | `POST /api/v1/dynamic/User` |
167
+ | `db.users.update(id, data)` | `PATCH /api/v1/dynamic/User/:id` |
168
+ | `db.users.delete(id)` | `DELETE /api/v1/dynamic/User/:id` |
169
+
170
+ ## Requirements
171
+
172
+ - Node.js >= 18 (for native `fetch`)
173
+ - A FLXBL instance with an active schema
174
+
175
+ ## License
176
+
177
+ MIT
@@ -0,0 +1,47 @@
1
+ /**
2
+ * FlxblClient — Base runtime client for FLXBL
3
+ *
4
+ * Zero dependencies. Uses native fetch.
5
+ * Generated TypedFlxblClient extends this with typed collections.
6
+ */
7
+ import type { FlxblClientConfig, CollectionMethods } from './types.js';
8
+ export declare class FlxblClient {
9
+ protected readonly instanceUrl: string;
10
+ private readonly apiKey?;
11
+ private accessToken?;
12
+ private readonly fetchFn;
13
+ constructor(config: FlxblClientConfig);
14
+ /** Set the access token dynamically (e.g., after login) */
15
+ setAccessToken(token: string): void;
16
+ private getAuthToken;
17
+ /** Low-level HTTP request method. Available for advanced usage. */
18
+ request<T>(method: string, path: string, body?: unknown): Promise<T>;
19
+ private toError;
20
+ /**
21
+ * Creates a typed collection for an entity.
22
+ * Used by generated code to wire entity-specific CRUD.
23
+ */
24
+ protected createCollection<T extends {
25
+ id: string;
26
+ }, TCreate, TUpdate>(entityName: string): CollectionMethods<T, TCreate, TUpdate>;
27
+ /** Execute a raw GraphQL query against the tenant's GraphQL endpoint */
28
+ graphql<T = Record<string, unknown>>(tenantId: string, query: string, variables?: Record<string, unknown>): Promise<{
29
+ data?: T;
30
+ errors?: Array<{
31
+ message: string;
32
+ }>;
33
+ }>;
34
+ /** Manage relationships between entities */
35
+ relationships(entityName: string, entityId: string): {
36
+ create: (relationshipName: string, targetId: string, properties?: Record<string, unknown>) => Promise<Record<string, unknown>>;
37
+ list: (relationshipName: string, direction?: "out" | "in" | "both") => Promise<{
38
+ items: Array<Record<string, unknown>>;
39
+ count: number;
40
+ }>;
41
+ delete: (relationshipName: string, targetId: string) => Promise<{
42
+ success: boolean;
43
+ message: string;
44
+ }>;
45
+ };
46
+ }
47
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAA6B,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAElG,qBAAa,WAAW;IACtB,SAAS,CAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;IACjC,OAAO,CAAC,WAAW,CAAC,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;gBAE3B,MAAM,EAAE,iBAAiB;IAOrC,2DAA2D;IAC3D,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAInC,OAAO,CAAC,YAAY;IAMpB,mEAAmE;IAC7D,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAiD1E,OAAO,CAAC,OAAO;IAaf;;;OAGG;IACH,SAAS,CAAC,gBAAgB,CAAC,CAAC,SAAS;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,OAAO,EAAE,OAAO,EACnE,UAAU,EAAE,MAAM,GACjB,iBAAiB,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC;IA+CzC,wEAAwE;IAClE,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,OAAO,CAAC;QAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QAAC,MAAM,CAAC,EAAE,KAAK,CAAC;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC;IAO7D,4CAA4C;IAC5C,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;mCAK1B,MAAM,YACd,MAAM,eACH,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KACnC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;iCAQf,MAAM,cACb,KAAK,GAAG,IAAI,GAAG,MAAM,KAC/B,OAAO,CAAC;YAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;mCAUhD,MAAM,YACd,MAAM,KACf,OAAO,CAAC;YAAE,OAAO,EAAE,OAAO,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC;;CAKtD"}
package/dist/client.js ADDED
@@ -0,0 +1,164 @@
1
+ /**
2
+ * FlxblClient — Base runtime client for FLXBL
3
+ *
4
+ * Zero dependencies. Uses native fetch.
5
+ * Generated TypedFlxblClient extends this with typed collections.
6
+ */
7
+ import { FlxblApiError, FlxblAuthError, FlxblValidationError } from './errors.js';
8
+ export class FlxblClient {
9
+ instanceUrl;
10
+ apiKey;
11
+ accessToken;
12
+ fetchFn;
13
+ constructor(config) {
14
+ this.instanceUrl = config.instanceUrl.replace(/\/$/, '');
15
+ this.apiKey = config.apiKey;
16
+ this.accessToken = config.accessToken;
17
+ this.fetchFn = config.fetch ?? globalThis.fetch;
18
+ }
19
+ /** Set the access token dynamically (e.g., after login) */
20
+ setAccessToken(token) {
21
+ this.accessToken = token;
22
+ }
23
+ getAuthToken() {
24
+ if (this.accessToken)
25
+ return this.accessToken;
26
+ if (this.apiKey)
27
+ return this.apiKey;
28
+ throw new FlxblAuthError();
29
+ }
30
+ /** Low-level HTTP request method. Available for advanced usage. */
31
+ async request(method, path, body) {
32
+ const token = this.getAuthToken();
33
+ const url = `${this.instanceUrl}${path}`;
34
+ const headers = {
35
+ Authorization: `Bearer ${token}`,
36
+ Accept: 'application/json',
37
+ };
38
+ const options = { method, headers };
39
+ if (body !== undefined) {
40
+ headers['Content-Type'] = 'application/json';
41
+ options.body = JSON.stringify(body);
42
+ }
43
+ let response;
44
+ try {
45
+ response = await this.fetchFn(url, options);
46
+ }
47
+ catch (error) {
48
+ throw new FlxblApiError(`Network error: ${error instanceof Error ? error.message : 'Unknown error'}`, 0);
49
+ }
50
+ // Handle text responses (e.g., GraphQL SDL)
51
+ const contentType = response.headers.get('content-type');
52
+ if (contentType?.includes('text/plain') || contentType?.includes('application/graphql')) {
53
+ if (!response.ok)
54
+ throw this.toError(response);
55
+ return (await response.text());
56
+ }
57
+ let data;
58
+ try {
59
+ data = await response.json();
60
+ }
61
+ catch {
62
+ if (!response.ok) {
63
+ throw new FlxblApiError(`API error: ${response.statusText}`, response.status);
64
+ }
65
+ return null;
66
+ }
67
+ if (!response.ok) {
68
+ throw this.toError(response, data);
69
+ }
70
+ return data;
71
+ }
72
+ toError(response, data) {
73
+ const status = response.status;
74
+ const message = data?.message || response.statusText;
75
+ if (status === 401)
76
+ return new FlxblAuthError(message);
77
+ if (status === 404)
78
+ return new FlxblApiError(message, 404);
79
+ if (status === 400) {
80
+ const errors = data?.errors;
81
+ return new FlxblValidationError(message, errors);
82
+ }
83
+ return new FlxblApiError(message, status, data);
84
+ }
85
+ /**
86
+ * Creates a typed collection for an entity.
87
+ * Used by generated code to wire entity-specific CRUD.
88
+ */
89
+ createCollection(entityName) {
90
+ const basePath = `/api/v1/dynamic/${entityName}`;
91
+ return {
92
+ findMany: async (options) => {
93
+ const body = {};
94
+ if (options?.where)
95
+ body.where = options.where;
96
+ if (options?.select)
97
+ body.select = options.select;
98
+ if (options?.orderBy)
99
+ body.orderBy = options.orderBy;
100
+ if (options?.orderDirection)
101
+ body.orderDirection = options.orderDirection;
102
+ if (options?.offset !== undefined)
103
+ body.offset = options.offset;
104
+ if (options?.limit !== undefined)
105
+ body.limit = options.limit;
106
+ if (options?.includeCount)
107
+ body.includeCount = options.includeCount;
108
+ if (options?.traverse)
109
+ body.traverse = options.traverse;
110
+ const response = await this.request('POST', `${basePath}/query`, body);
111
+ // Normalize backend response
112
+ if (Array.isArray(response)) {
113
+ return { items: response };
114
+ }
115
+ const wrapped = response;
116
+ return {
117
+ items: wrapped.data ?? [],
118
+ count: wrapped.totalCount,
119
+ hasMore: false,
120
+ };
121
+ },
122
+ findById: async (id) => {
123
+ return this.request('GET', `${basePath}/${id}`);
124
+ },
125
+ create: async (data) => {
126
+ return this.request('POST', basePath, data);
127
+ },
128
+ update: async (id, data) => {
129
+ return this.request('PATCH', `${basePath}/${id}`, data);
130
+ },
131
+ delete: async (id) => {
132
+ await this.request('DELETE', `${basePath}/${id}`);
133
+ },
134
+ };
135
+ }
136
+ /** Execute a raw GraphQL query against the tenant's GraphQL endpoint */
137
+ async graphql(tenantId, query, variables) {
138
+ return this.request(`POST`, `/api/v1/dynamic-gql/${tenantId}`, {
139
+ query,
140
+ variables,
141
+ });
142
+ }
143
+ /** Manage relationships between entities */
144
+ relationships(entityName, entityId) {
145
+ const basePath = `/api/v1/dynamic/${entityName}/${entityId}/relationships`;
146
+ return {
147
+ create: async (relationshipName, targetId, properties) => {
148
+ return this.request('POST', `${basePath}/${relationshipName}`, {
149
+ targetId,
150
+ properties,
151
+ });
152
+ },
153
+ list: async (relationshipName, direction = 'out') => {
154
+ const response = await this.request('GET', `${basePath}/${relationshipName}?direction=${direction}`);
155
+ const items = response.map((r) => r.target);
156
+ return { items, count: items.length };
157
+ },
158
+ delete: async (relationshipName, targetId) => {
159
+ return this.request('DELETE', `${basePath}/${relationshipName}/${targetId}`);
160
+ },
161
+ };
162
+ }
163
+ }
164
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * FLXBL Client Errors
3
+ *
4
+ * Lightweight error classes for the runtime SDK.
5
+ */
6
+ export declare class FlxblApiError extends Error {
7
+ readonly statusCode: number;
8
+ readonly details?: Record<string, unknown> | undefined;
9
+ constructor(message: string, statusCode: number, details?: Record<string, unknown> | undefined);
10
+ }
11
+ export declare class FlxblAuthError extends FlxblApiError {
12
+ constructor(message?: string);
13
+ }
14
+ export declare class FlxblNotFoundError extends FlxblApiError {
15
+ constructor(entity: string, id: string);
16
+ }
17
+ export declare class FlxblValidationError extends FlxblApiError {
18
+ readonly validationErrors?: Array<{
19
+ field: string;
20
+ message: string;
21
+ }> | undefined;
22
+ constructor(message: string, validationErrors?: Array<{
23
+ field: string;
24
+ message: string;
25
+ }> | undefined);
26
+ }
27
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,qBAAa,aAAc,SAAQ,KAAK;aAGpB,UAAU,EAAE,MAAM;aAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBAFjD,OAAO,EAAE,MAAM,EACC,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,YAAA;CAKpD;AAED,qBAAa,cAAe,SAAQ,aAAa;gBACnC,OAAO,GAAE,MAAiE;CAIvF;AAED,qBAAa,kBAAmB,SAAQ,aAAa;gBACvC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;CAIvC;AAED,qBAAa,oBAAqB,SAAQ,aAAa;aAGnC,gBAAgB,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;gBAD5E,OAAO,EAAE,MAAM,EACC,gBAAgB,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,YAAA;CAK/E"}
package/dist/errors.js ADDED
@@ -0,0 +1,36 @@
1
+ /**
2
+ * FLXBL Client Errors
3
+ *
4
+ * Lightweight error classes for the runtime SDK.
5
+ */
6
+ export class FlxblApiError extends Error {
7
+ statusCode;
8
+ details;
9
+ constructor(message, statusCode, details) {
10
+ super(message);
11
+ this.statusCode = statusCode;
12
+ this.details = details;
13
+ this.name = 'FlxblApiError';
14
+ }
15
+ }
16
+ export class FlxblAuthError extends FlxblApiError {
17
+ constructor(message = 'Not authenticated. Provide an API key or access token.') {
18
+ super(message, 401);
19
+ this.name = 'FlxblAuthError';
20
+ }
21
+ }
22
+ export class FlxblNotFoundError extends FlxblApiError {
23
+ constructor(entity, id) {
24
+ super(`${entity} with id "${id}" not found`, 404);
25
+ this.name = 'FlxblNotFoundError';
26
+ }
27
+ }
28
+ export class FlxblValidationError extends FlxblApiError {
29
+ validationErrors;
30
+ constructor(message, validationErrors) {
31
+ super(message, 400, validationErrors ? { validationErrors } : undefined);
32
+ this.validationErrors = validationErrors;
33
+ this.name = 'FlxblValidationError';
34
+ }
35
+ }
36
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,OAAO,aAAc,SAAQ,KAAK;IAGpB;IACA;IAHlB,YACE,OAAe,EACC,UAAkB,EAClB,OAAiC;QAEjD,KAAK,CAAC,OAAO,CAAC,CAAC;QAHC,eAAU,GAAV,UAAU,CAAQ;QAClB,YAAO,GAAP,OAAO,CAA0B;QAGjD,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AAED,MAAM,OAAO,cAAe,SAAQ,aAAa;IAC/C,YAAY,UAAkB,wDAAwD;QACpF,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACpB,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED,MAAM,OAAO,kBAAmB,SAAQ,aAAa;IACnD,YAAY,MAAc,EAAE,EAAU;QACpC,KAAK,CAAC,GAAG,MAAM,aAAa,EAAE,aAAa,EAAE,GAAG,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AAED,MAAM,OAAO,oBAAqB,SAAQ,aAAa;IAGnC;IAFlB,YACE,OAAe,EACC,gBAA4D;QAE5E,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAFzD,qBAAgB,GAAhB,gBAAgB,CAA4C;QAG5E,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF"}
@@ -0,0 +1,4 @@
1
+ export { FlxblClient } from './client.js';
2
+ export { FlxblApiError, FlxblAuthError, FlxblNotFoundError, FlxblValidationError } from './errors.js';
3
+ export type { FlxblClientConfig, QueryFilter, QueryOptions, QueryResult, CollectionMethods, } from './types.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACtG,YAAY,EACV,iBAAiB,EACjB,WAAW,EACX,YAAY,EACZ,WAAW,EACX,iBAAiB,GAClB,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { FlxblClient } from './client.js';
2
+ export { FlxblApiError, FlxblAuthError, FlxblNotFoundError, FlxblValidationError } from './errors.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Runtime query types for @flxbl-dev/client
3
+ *
4
+ * These types power the generated TypedFlxblClient's CRUD operations.
5
+ */
6
+ export interface FlxblClientConfig {
7
+ /** URL of the FLXBL instance (e.g., https://api.flxbl.dev) */
8
+ instanceUrl: string;
9
+ /** API key for authentication */
10
+ apiKey?: string;
11
+ /** Access token (JWT) for authentication */
12
+ accessToken?: string;
13
+ /** Custom fetch implementation (defaults to global fetch) */
14
+ fetch?: typeof fetch;
15
+ }
16
+ export interface QueryFilter {
17
+ $eq?: unknown;
18
+ $neq?: unknown;
19
+ $gt?: number | string;
20
+ $gte?: number | string;
21
+ $lt?: number | string;
22
+ $lte?: number | string;
23
+ $in?: unknown[];
24
+ $notIn?: unknown[];
25
+ $isNull?: boolean;
26
+ $contains?: string;
27
+ $startsWith?: string;
28
+ $endsWith?: string;
29
+ $and?: QueryFilter[];
30
+ $or?: QueryFilter[];
31
+ }
32
+ export interface QueryOptions<T> {
33
+ /** Filter conditions. Keys are field names of T. */
34
+ where?: {
35
+ [K in keyof T]?: T[K] | QueryFilter;
36
+ };
37
+ /** Fields to select (empty = all) */
38
+ select?: Array<keyof T & string>;
39
+ /** Order by field name */
40
+ orderBy?: keyof T & string;
41
+ /** Order direction */
42
+ orderDirection?: 'ASC' | 'DESC';
43
+ /** Number of items to skip */
44
+ offset?: number;
45
+ /** Maximum number of items to return */
46
+ limit?: number;
47
+ /** Include total count in response */
48
+ includeCount?: boolean;
49
+ /** Relationship traversals */
50
+ traverse?: Array<{
51
+ relationship: string;
52
+ direction?: 'out' | 'in' | 'both';
53
+ select?: string[];
54
+ where?: Record<string, unknown>;
55
+ }>;
56
+ }
57
+ export interface QueryResult<T> {
58
+ items: T[];
59
+ count?: number;
60
+ hasMore?: boolean;
61
+ }
62
+ export interface CollectionMethods<T, TCreate, TUpdate> {
63
+ /** Find multiple records matching query options */
64
+ findMany(options?: QueryOptions<T>): Promise<QueryResult<T>>;
65
+ /** Find a single record by ID */
66
+ findById(id: string): Promise<T>;
67
+ /** Create a new record */
68
+ create(data: TCreate): Promise<T>;
69
+ /** Update a record by ID (partial update) */
70
+ update(id: string, data: TUpdate): Promise<T>;
71
+ /** Delete a record by ID */
72
+ delete(id: string): Promise<void>;
73
+ }
74
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Runtime query types for @flxbl-dev/client
3
+ *
4
+ * These types power the generated TypedFlxblClient's CRUD operations.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@flxbl-dev/client",
3
+ "version": "0.1.0",
4
+ "description": "Lightweight runtime SDK for FLXBL — zero dependencies, uses native fetch",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc",
19
+ "dev": "tsc --watch",
20
+ "typecheck": "tsc --noEmit",
21
+ "clean": "rm -rf dist",
22
+ "test": "vitest run",
23
+ "test:watch": "vitest"
24
+ },
25
+ "keywords": [
26
+ "flxbl",
27
+ "sdk",
28
+ "client",
29
+ "typescript",
30
+ "schema",
31
+ "api"
32
+ ],
33
+ "author": "FLXBL",
34
+ "license": "MIT",
35
+ "devDependencies": {
36
+ "@types/node": "^22.0.0",
37
+ "typescript": "^5.7.0",
38
+ "vitest": "^2.0.0"
39
+ },
40
+ "engines": {
41
+ "node": ">=18.0.0"
42
+ },
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "https://github.com/flxbl/flxbl-monolith.git",
46
+ "directory": "packages/client"
47
+ }
48
+ }