@tapstack/db 1.0.7 → 3.0.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.
Files changed (48) hide show
  1. package/README.md +655 -0
  2. package/dist/adapters/index.d.ts +6 -0
  3. package/dist/adapters/index.js +22 -0
  4. package/dist/adapters/nodejs.adapter.d.ts +63 -0
  5. package/dist/adapters/nodejs.adapter.js +204 -0
  6. package/dist/adapters/types.d.ts +77 -0
  7. package/dist/adapters/types.js +19 -0
  8. package/dist/index.d.ts +101 -21
  9. package/dist/index.js +114 -41
  10. package/dist/modules/automations.d.ts +109 -0
  11. package/dist/modules/automations.js +59 -0
  12. package/dist/modules/conversations.d.ts +82 -0
  13. package/dist/modules/conversations.js +54 -0
  14. package/dist/modules/fields.d.ts +30 -9
  15. package/dist/modules/fields.js +31 -13
  16. package/dist/modules/files.d.ts +68 -0
  17. package/dist/modules/files.js +115 -0
  18. package/dist/modules/index.d.ts +12 -0
  19. package/dist/modules/index.js +28 -0
  20. package/dist/modules/objects.d.ts +30 -9
  21. package/dist/modules/objects.js +35 -13
  22. package/dist/modules/organizations.d.ts +69 -0
  23. package/dist/modules/organizations.js +83 -0
  24. package/dist/modules/records.d.ts +47 -5
  25. package/dist/modules/records.js +70 -5
  26. package/dist/modules/workspaces.d.ts +44 -0
  27. package/dist/modules/workspaces.js +57 -0
  28. package/dist/types.d.ts +159 -10
  29. package/dist/types.js +19 -0
  30. package/package.json +16 -7
  31. package/src/__tests__/client.test.ts +305 -49
  32. package/src/adapters/index.ts +13 -0
  33. package/src/adapters/nodejs.adapter.ts +298 -0
  34. package/src/adapters/types.ts +108 -0
  35. package/src/index.ts +132 -44
  36. package/src/modules/automations.ts +157 -0
  37. package/src/modules/conversations.ts +134 -0
  38. package/src/modules/fields.ts +64 -14
  39. package/src/modules/files.ts +144 -0
  40. package/src/modules/index.ts +19 -0
  41. package/src/modules/objects.ts +46 -14
  42. package/src/modules/organizations.ts +137 -0
  43. package/src/modules/records.ts +119 -6
  44. package/src/modules/workspaces.ts +95 -0
  45. package/src/types.ts +229 -9
  46. package/dist/request.d.ts +0 -2
  47. package/dist/request.js +0 -20
  48. package/src/request.ts +0 -14
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Organizations Module
3
+ * CRUD operations for Tapstack organizations
4
+ */
5
+
6
+ import { IInstanceAdapter } from '../adapters/types';
7
+ import {
8
+ TapstackOrganization,
9
+ CreateOrganizationPayload,
10
+ UpdateOrganizationPayload,
11
+ OrganizationListResponse,
12
+ OrganizationMember,
13
+ TapstackWorkspace,
14
+ WorkspaceListResponse,
15
+ } from '../types';
16
+
17
+ export class OrganizationModule {
18
+ constructor(private adapter: IInstanceAdapter) { }
19
+
20
+ /**
21
+ * List all organizations the user belongs to
22
+ */
23
+ async list(): Promise<OrganizationListResponse> {
24
+ return this.adapter.request<OrganizationListResponse>('GET', 'organizations');
25
+ }
26
+
27
+ /**
28
+ * Get a single organization by ID
29
+ */
30
+ async get(orgId: string): Promise<TapstackOrganization> {
31
+ return this.adapter.request<TapstackOrganization>('GET', `organizations/${orgId}`);
32
+ }
33
+
34
+ /**
35
+ * Create a new organization
36
+ */
37
+ async create(data: CreateOrganizationPayload): Promise<TapstackOrganization> {
38
+ return this.adapter.request<TapstackOrganization>('POST', 'organizations', {
39
+ body: data,
40
+ });
41
+ }
42
+
43
+ /**
44
+ * Update an existing organization
45
+ */
46
+ async update(orgId: string, data: UpdateOrganizationPayload): Promise<TapstackOrganization> {
47
+ return this.adapter.request<TapstackOrganization>('PATCH', `organizations/${orgId}`, {
48
+ body: data,
49
+ });
50
+ }
51
+
52
+ /**
53
+ * Delete an organization
54
+ */
55
+ async delete(orgId: string): Promise<{ deleted: boolean }> {
56
+ return this.adapter.request<{ deleted: boolean }>('DELETE', `organizations/${orgId}`);
57
+ }
58
+
59
+ /**
60
+ * List workspaces in an organization
61
+ */
62
+ async listWorkspaces(orgId: string): Promise<WorkspaceListResponse> {
63
+ return this.adapter.request<WorkspaceListResponse>(
64
+ 'GET',
65
+ `organizations/${orgId}/workspaces`
66
+ );
67
+ }
68
+
69
+ /**
70
+ * Create a workspace in an organization
71
+ */
72
+ async createWorkspace(
73
+ orgId: string,
74
+ data: { name: string; slug?: string; description?: string }
75
+ ): Promise<TapstackWorkspace> {
76
+ return this.adapter.request<TapstackWorkspace>(
77
+ 'POST',
78
+ `organizations/${orgId}/workspaces`,
79
+ { body: data }
80
+ );
81
+ }
82
+
83
+ /**
84
+ * List members of an organization
85
+ */
86
+ async listMembers(orgId: string): Promise<{ members: OrganizationMember[] }> {
87
+ return this.adapter.request<{ members: OrganizationMember[] }>(
88
+ 'GET',
89
+ `organizations/${orgId}/members`
90
+ );
91
+ }
92
+
93
+ /**
94
+ * Add a member to an organization
95
+ */
96
+ async addMember(
97
+ orgId: string,
98
+ data: { email: string; role?: string }
99
+ ): Promise<OrganizationMember> {
100
+ return this.adapter.request<OrganizationMember>(
101
+ 'POST',
102
+ `organizations/${orgId}/members`,
103
+ { body: data }
104
+ );
105
+ }
106
+
107
+ /**
108
+ * Update a member's role
109
+ */
110
+ async updateMember(
111
+ orgId: string,
112
+ memberId: string,
113
+ data: { role: string }
114
+ ): Promise<OrganizationMember> {
115
+ return this.adapter.request<OrganizationMember>(
116
+ 'PATCH',
117
+ `organizations/${orgId}/members/${memberId}`,
118
+ { body: data }
119
+ );
120
+ }
121
+
122
+ /**
123
+ * Remove a member from an organization
124
+ */
125
+ async removeMember(orgId: string, memberId: string): Promise<{ removed: boolean }> {
126
+ return this.adapter.request<{ removed: boolean }>(
127
+ 'DELETE',
128
+ `organizations/${orgId}/members/${memberId}`
129
+ );
130
+ }
131
+ }
132
+
133
+
134
+
135
+
136
+
137
+
@@ -1,11 +1,124 @@
1
- import { AxiosInstance } from 'axios';
2
- import { handleRequest } from '../request';
3
- import { TapstackRecord, TapstackResponse } from '../types';
1
+ /**
2
+ * Records Module
3
+ * CRUD operations for Tapstack records (data entries)
4
+ */
5
+
6
+ import { IInstanceAdapter } from '../adapters/types';
7
+ import {
8
+ TapstackRecord,
9
+ CreateRecordPayload,
10
+ UpdateRecordPayload,
11
+ RecordQueryOptions,
12
+ RecordListResponse,
13
+ } from '../types';
4
14
 
5
15
  export class RecordModule {
6
- constructor(private client: AxiosInstance) {}
16
+ constructor(private adapter: IInstanceAdapter) { }
17
+
18
+ /**
19
+ * List records for an object with pagination and filtering
20
+ */
21
+ async list(objectSlug: string, options?: RecordQueryOptions): Promise<RecordListResponse> {
22
+ const params: Record<string, string> = {};
23
+
24
+ if (options?.page) params.page = String(options.page);
25
+ if (options?.pageSize) params.pageSize = String(options.pageSize);
26
+ if (options?.sortBy) params.sortBy = options.sortBy;
27
+ if (options?.sortOrder) params.sortOrder = options.sortOrder;
28
+ if (options?.filters) params.filters = JSON.stringify(options.filters);
29
+
30
+ return this.adapter.request<RecordListResponse>('GET', `records/${objectSlug}`, {
31
+ params,
32
+ });
33
+ }
34
+
35
+ /**
36
+ * Get a single record by ID
37
+ */
38
+ async get(objectSlug: string, recordId: string): Promise<TapstackRecord> {
39
+ return this.adapter.request<TapstackRecord>(
40
+ 'GET',
41
+ `records/${objectSlug}/${recordId}`
42
+ );
43
+ }
44
+
45
+ /**
46
+ * Create a new record
47
+ */
48
+ async create(objectSlug: string, data: CreateRecordPayload): Promise<TapstackRecord> {
49
+ return this.adapter.request<TapstackRecord>('POST', `records/${objectSlug}`, {
50
+ body: data,
51
+ });
52
+ }
53
+
54
+ /**
55
+ * Update an existing record
56
+ */
57
+ async update(
58
+ objectSlug: string,
59
+ recordId: string,
60
+ data: UpdateRecordPayload
61
+ ): Promise<TapstackRecord> {
62
+ return this.adapter.request<TapstackRecord>(
63
+ 'PATCH',
64
+ `records/${objectSlug}/${recordId}`,
65
+ { body: data }
66
+ );
67
+ }
68
+
69
+ /**
70
+ * Delete a record (soft delete by default)
71
+ */
72
+ async delete(
73
+ objectSlug: string,
74
+ recordId: string,
75
+ soft = true
76
+ ): Promise<{ deleted: boolean }> {
77
+ return this.adapter.request<{ deleted: boolean }>(
78
+ 'DELETE',
79
+ `records/${objectSlug}/${recordId}`,
80
+ { params: { soft: String(soft) } }
81
+ );
82
+ }
83
+
84
+ /**
85
+ * Bulk create records
86
+ */
87
+ async bulkCreate(
88
+ objectSlug: string,
89
+ records: CreateRecordPayload[]
90
+ ): Promise<{ records: TapstackRecord[]; count: number }> {
91
+ return this.adapter.request<{ records: TapstackRecord[]; count: number }>(
92
+ 'POST',
93
+ `records/${objectSlug}/bulk`,
94
+ { body: { records } }
95
+ );
96
+ }
97
+
98
+ /**
99
+ * Bulk delete records (soft delete by default)
100
+ */
101
+ async bulkDelete(
102
+ objectSlug: string,
103
+ recordIds: string[],
104
+ soft = true
105
+ ): Promise<{ deleted: number }> {
106
+ return this.adapter.request<{ deleted: number }>(
107
+ 'POST',
108
+ `records/${objectSlug}/bulk/delete`,
109
+ { body: { recordIds, soft } }
110
+ );
111
+ }
7
112
 
8
- query<T = TapstackRecord[]>(slug: string, variables: any): Promise<TapstackResponse<T>> {
9
- return handleRequest(this.client, { method: 'POST', url: `/${slug}`, data: variables });
113
+ /**
114
+ * Query records with advanced filtering (legacy method for backwards compatibility)
115
+ */
116
+ async query<T = TapstackRecord[]>(
117
+ objectSlug: string,
118
+ variables: Record<string, unknown>
119
+ ): Promise<T> {
120
+ return this.adapter.request<T>('POST', `records/${objectSlug}/query`, {
121
+ body: variables,
122
+ });
10
123
  }
11
124
  }
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Workspaces Module
3
+ * CRUD operations for Tapstack workspaces
4
+ */
5
+
6
+ import { IInstanceAdapter } from '../adapters/types';
7
+ import {
8
+ TapstackWorkspace,
9
+ CreateWorkspacePayload,
10
+ UpdateWorkspacePayload,
11
+ WorkspaceListResponse,
12
+ } from '../types';
13
+
14
+ export class WorkspaceModule {
15
+ constructor(private adapter: IInstanceAdapter) { }
16
+
17
+ /**
18
+ * List all workspaces the user has access to
19
+ */
20
+ async list(): Promise<WorkspaceListResponse> {
21
+ return this.adapter.request<WorkspaceListResponse>('GET', 'workspaces');
22
+ }
23
+
24
+ /**
25
+ * Get a single workspace by ID
26
+ */
27
+ async get(workspaceId: string): Promise<TapstackWorkspace> {
28
+ return this.adapter.request<TapstackWorkspace>('GET', `workspaces/${workspaceId}`);
29
+ }
30
+
31
+ /**
32
+ * Create a new workspace (within an organization)
33
+ */
34
+ async create(orgId: string, data: CreateWorkspacePayload): Promise<TapstackWorkspace> {
35
+ return this.adapter.request<TapstackWorkspace>('POST', `workspaces/org/${orgId}`, {
36
+ body: data,
37
+ });
38
+ }
39
+
40
+ /**
41
+ * Update an existing workspace
42
+ */
43
+ async update(
44
+ orgId: string,
45
+ workspaceId: string,
46
+ data: UpdateWorkspacePayload
47
+ ): Promise<TapstackWorkspace> {
48
+ return this.adapter.request<TapstackWorkspace>(
49
+ 'PATCH',
50
+ `workspaces/org/${orgId}/${workspaceId}`,
51
+ { body: data }
52
+ );
53
+ }
54
+
55
+ /**
56
+ * Delete a workspace
57
+ */
58
+ async delete(orgId: string, workspaceId: string): Promise<{ deleted: boolean }> {
59
+ return this.adapter.request<{ deleted: boolean }>(
60
+ 'DELETE',
61
+ `workspaces/org/${orgId}/${workspaceId}`
62
+ );
63
+ }
64
+
65
+ /**
66
+ * Get workspace statistics
67
+ */
68
+ async getStats(workspaceId: string): Promise<{
69
+ objectCount: number;
70
+ recordCount: number;
71
+ storageUsed: number;
72
+ }> {
73
+ return this.adapter.request<{
74
+ objectCount: number;
75
+ recordCount: number;
76
+ storageUsed: number;
77
+ }>('GET', `workspaces/${workspaceId}/stats`);
78
+ }
79
+
80
+ /**
81
+ * Resolve a workspace by slug (for routing)
82
+ */
83
+ async resolveBySlug(orgSlug: string, workspaceSlug: string): Promise<TapstackWorkspace> {
84
+ return this.adapter.request<TapstackWorkspace>(
85
+ 'GET',
86
+ `resolve-workspace/${orgSlug}/${workspaceSlug}`
87
+ );
88
+ }
89
+ }
90
+
91
+
92
+
93
+
94
+
95
+
package/src/types.ts CHANGED
@@ -1,21 +1,241 @@
1
+ /**
2
+ * Core Types for @tapstack/db
3
+ */
4
+
5
+ // Re-export adapter types
6
+ export * from './adapters/types';
7
+
8
+ // ==================== Objects ====================
9
+
1
10
  export interface TapstackObject {
11
+ id: string;
12
+ singleName: string;
13
+ pluralName: string;
2
14
  slug: string;
3
- name: string;
4
- [key: string]: any;
15
+ icon: string;
16
+ isSystemObject: boolean;
17
+ use?: string | null;
18
+ parentId?: string | null;
19
+ workspaceId?: string | null;
20
+ createdAt: number;
21
+ updatedAt: number;
22
+ deletedAt?: number | null;
23
+ fields?: TapstackField[];
5
24
  }
6
25
 
26
+ export type CreateObjectPayload = {
27
+ singleName: string;
28
+ pluralName: string;
29
+ slug?: string;
30
+ icon?: string;
31
+ use?: string;
32
+ parentId?: string;
33
+ };
34
+
35
+ export type UpdateObjectPayload = Partial<CreateObjectPayload>;
36
+
37
+ // ==================== Fields ====================
38
+
39
+ export type FieldType =
40
+ | 'text'
41
+ | 'number'
42
+ | 'boolean'
43
+ | 'date'
44
+ | 'datetime'
45
+ | 'json'
46
+ | 'select'
47
+ | 'single_select'
48
+ | 'multi_select'
49
+ | 'checkbox'
50
+ | 'radio'
51
+ | 'relation'
52
+ | 'input'
53
+ | 'textarea'
54
+ | 'autoincrement'
55
+ | 'htmlBox'
56
+ | 'email'
57
+ | 'phone'
58
+ | 'url'
59
+ | 'currency'
60
+ | 'rating'
61
+ | 'fullName'
62
+ | 'address'
63
+ | 'array'
64
+ | 'ai'
65
+ | 'person'
66
+ | 'files';
67
+
7
68
  export interface TapstackField {
69
+ id: string;
70
+ label: string;
71
+ value: string;
72
+ type: FieldType;
73
+ data?: Record<string, unknown>;
74
+ systemData?: Record<string, unknown>;
75
+ objectId: string;
76
+ createdAt: number;
77
+ updatedAt: number;
78
+ deletedAt?: number | null;
79
+ }
80
+
81
+ export type CreateFieldPayload = {
82
+ label: string;
83
+ value: string;
84
+ type: FieldType;
85
+ data?: Record<string, unknown>;
86
+ };
87
+
88
+ export type UpdateFieldPayload = Partial<Omit<CreateFieldPayload, 'value'>>;
89
+
90
+ // ==================== Records ====================
91
+
92
+ export type RecordStatus = 'draft' | 'published' | 'deleted';
93
+
94
+ export interface TapstackRecord {
95
+ id: string;
96
+ objectId: string;
97
+ workspaceId?: string;
98
+ data: Record<string, unknown>;
99
+ status: RecordStatus;
100
+ version: number;
101
+ createdAt: number;
102
+ updatedAt: number;
103
+ deletedAt?: number | null;
104
+ }
105
+
106
+ export type CreateRecordPayload = {
107
+ data: Record<string, unknown>;
108
+ status?: RecordStatus;
109
+ };
110
+
111
+ export type UpdateRecordPayload = {
112
+ data?: Record<string, unknown>;
113
+ status?: RecordStatus;
114
+ };
115
+
116
+ export interface RecordQueryOptions {
117
+ page?: number;
118
+ pageSize?: number;
119
+ sortBy?: string;
120
+ sortOrder?: 'asc' | 'desc';
121
+ filters?: Record<string, unknown>;
122
+ }
123
+
124
+ export interface RecordListResponse {
125
+ items: TapstackRecord[];
126
+ total: number;
127
+ page: number;
128
+ pageSize: number;
129
+ totalPages: number;
130
+ }
131
+
132
+ // ==================== Organizations ====================
133
+
134
+ export interface TapstackOrganization {
135
+ id: string;
136
+ name: string;
137
+ slug: string;
138
+ ownerId: string;
139
+ stripeCustomerId?: string | null;
140
+ createdAt: number;
141
+ updatedAt: number;
142
+ deletedAt?: number | null;
143
+ }
144
+
145
+ export type CreateOrganizationPayload = {
146
+ name: string;
147
+ slug?: string;
148
+ };
149
+
150
+ export type UpdateOrganizationPayload = Partial<CreateOrganizationPayload>;
151
+
152
+ export interface OrganizationMember {
153
+ id: string;
154
+ organizationId: string;
155
+ userId: string;
156
+ role: string;
157
+ createdAt: number;
158
+ updatedAt: number;
159
+ }
160
+
161
+ // ==================== Workspaces ====================
162
+
163
+ export interface TapstackWorkspace {
164
+ id: string;
165
+ name: string;
166
+ slug: string;
167
+ description?: string | null;
168
+ organizationId: string;
169
+ createdAt: number;
170
+ updatedAt: number;
171
+ deletedAt?: number | null;
172
+ }
173
+
174
+ export type CreateWorkspacePayload = {
175
+ name: string;
176
+ slug?: string;
177
+ description?: string;
178
+ };
179
+
180
+ export type UpdateWorkspacePayload = Partial<CreateWorkspacePayload>;
181
+
182
+ // ==================== Files ====================
183
+
184
+ export interface TapstackFile {
185
+ id: string;
186
+ name: string;
187
+ path: string;
188
+ mimeType: string;
189
+ size: number;
190
+ url?: string;
191
+ folderId?: string | null;
192
+ workspaceId: string;
193
+ createdAt: number;
194
+ updatedAt: number;
195
+ }
196
+
197
+ export interface TapstackFolder {
8
198
  id: string;
9
199
  name: string;
10
- type: string;
11
- [key: string]: any;
200
+ parentId?: string | null;
201
+ workspaceId: string;
202
+ createdAt: number;
203
+ updatedAt: number;
204
+ }
205
+
206
+ export interface FileUploadOptions {
207
+ folderId?: string;
208
+ folder?: string;
209
+ }
210
+
211
+ export interface FileListResponse {
212
+ files: TapstackFile[];
213
+ total: number;
214
+ }
215
+
216
+ export interface FolderListResponse {
217
+ folders: TapstackFolder[];
218
+ }
219
+
220
+ // ==================== API Response Types ====================
221
+
222
+ export interface ObjectListResponse {
223
+ objects: TapstackObject[];
12
224
  }
13
225
 
14
- export type TapstackRecord = Record<string, any> & { id?: string };
226
+ export interface FieldListResponse {
227
+ fields: TapstackField[];
228
+ }
229
+
230
+ export interface OrganizationListResponse {
231
+ organizations: TapstackOrganization[];
232
+ }
15
233
 
16
- export interface TapstackResponse<T> {
17
- data: T;
234
+ export interface WorkspaceListResponse {
235
+ workspaces: TapstackWorkspace[];
18
236
  }
19
237
 
20
- export type CreateObjectPayload = Partial<TapstackObject>;
21
- export type CreateFieldPayload = Partial<TapstackField>;
238
+ // ==================== Legacy Types (for backwards compatibility) ====================
239
+
240
+ /** @deprecated Use TapstackObject instead */
241
+ export type TapstackResponse<T> = { data: T };
package/dist/request.d.ts DELETED
@@ -1,2 +0,0 @@
1
- import { AxiosInstance, AxiosRequestConfig } from 'axios';
2
- export declare function handleRequest<T>(client: AxiosInstance, config: AxiosRequestConfig): Promise<T>;
package/dist/request.js DELETED
@@ -1,20 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.handleRequest = handleRequest;
7
- const axios_1 = __importDefault(require("axios"));
8
- async function handleRequest(client, config) {
9
- try {
10
- const response = await client.request(config);
11
- return response.data;
12
- }
13
- catch (err) {
14
- if (axios_1.default.isAxiosError(err)) {
15
- const message = err.response?.data?.message || err.message;
16
- throw new Error(message);
17
- }
18
- throw err;
19
- }
20
- }
package/src/request.ts DELETED
@@ -1,14 +0,0 @@
1
- import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
2
-
3
- export async function handleRequest<T>(client: AxiosInstance, config: AxiosRequestConfig): Promise<T> {
4
- try {
5
- const response = await client.request<T>(config);
6
- return response.data;
7
- } catch (err) {
8
- if (axios.isAxiosError(err)) {
9
- const message = (err.response?.data as any)?.message || err.message;
10
- throw new Error(message);
11
- }
12
- throw err;
13
- }
14
- }