@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,157 @@
1
+ /**
2
+ * Automations Module
3
+ * CRUD operations for workflow automations
4
+ */
5
+
6
+ import { IInstanceAdapter } from '../adapters/types';
7
+
8
+ export interface TriggerCondition {
9
+ field: string;
10
+ operator: string;
11
+ value: unknown;
12
+ }
13
+
14
+ export interface FieldMapping {
15
+ type: 'static' | 'trigger_field';
16
+ value: string;
17
+ }
18
+
19
+ export interface AutomationAction {
20
+ id: string;
21
+ type: 'create_record' | 'update_record' | 'delete_record' | 'webhook';
22
+ config: {
23
+ targetObjectId?: string;
24
+ fieldMappings?: Record<string, FieldMapping>;
25
+ url?: string;
26
+ method?: 'POST' | 'PUT' | 'PATCH';
27
+ headers?: Record<string, string>;
28
+ body?: string;
29
+ };
30
+ }
31
+
32
+ export interface Automation {
33
+ id: string;
34
+ name: string;
35
+ description?: string;
36
+ workspaceId: string;
37
+ triggerObjectId: string;
38
+ triggerType: 'record.created' | 'record.updated' | 'record.deleted';
39
+ triggerConditions: TriggerCondition[];
40
+ actions: AutomationAction[];
41
+ isEnabled: boolean;
42
+ lastRunAt?: number;
43
+ runCount: number;
44
+ createdAt: number;
45
+ updatedAt: number;
46
+ deletedAt?: number;
47
+ triggerObject?: {
48
+ id: string;
49
+ singleName: string;
50
+ pluralName: string;
51
+ slug: string;
52
+ icon?: string;
53
+ };
54
+ }
55
+
56
+ export interface CreateAutomationPayload {
57
+ name: string;
58
+ description?: string;
59
+ triggerObjectId: string;
60
+ triggerType: 'record.created' | 'record.updated' | 'record.deleted';
61
+ triggerConditions?: TriggerCondition[];
62
+ actions: Omit<AutomationAction, 'id'>[];
63
+ }
64
+
65
+ export interface UpdateAutomationPayload {
66
+ name?: string;
67
+ description?: string;
68
+ triggerConditions?: TriggerCondition[];
69
+ actions?: AutomationAction[];
70
+ isEnabled?: boolean;
71
+ }
72
+
73
+ export interface ExecuteAutomationResult {
74
+ success: boolean;
75
+ results: Array<{
76
+ actionId: string;
77
+ success: boolean;
78
+ error?: string;
79
+ }>;
80
+ message: string;
81
+ }
82
+
83
+ export class AutomationModule {
84
+ constructor(private adapter: IInstanceAdapter) { }
85
+
86
+ /**
87
+ * List all automations for the current workspace
88
+ */
89
+ async list(): Promise<{ automations: Automation[] }> {
90
+ return this.adapter.request<{ automations: Automation[] }>(
91
+ 'GET',
92
+ 'automations'
93
+ );
94
+ }
95
+
96
+ /**
97
+ * Get a single automation by ID
98
+ */
99
+ async get(id: string): Promise<Automation> {
100
+ return this.adapter.request<Automation>('GET', `automations/${id}`);
101
+ }
102
+
103
+ /**
104
+ * Create a new automation
105
+ */
106
+ async create(data: CreateAutomationPayload): Promise<Automation> {
107
+ return this.adapter.request<Automation>('POST', 'automations', {
108
+ body: data,
109
+ });
110
+ }
111
+
112
+ /**
113
+ * Update an existing automation
114
+ */
115
+ async update(id: string, data: UpdateAutomationPayload): Promise<Automation> {
116
+ return this.adapter.request<Automation>('PUT', `automations/${id}`, {
117
+ body: data,
118
+ });
119
+ }
120
+
121
+ /**
122
+ * Delete an automation
123
+ */
124
+ async delete(id: string, soft = true): Promise<{ deleted: boolean }> {
125
+ return this.adapter.request<{ deleted: boolean }>(
126
+ 'DELETE',
127
+ `automations/${id}`,
128
+ { params: { soft: String(soft) } }
129
+ );
130
+ }
131
+
132
+ /**
133
+ * Toggle automation enabled/disabled
134
+ */
135
+ async toggle(id: string): Promise<Automation> {
136
+ return this.adapter.request<Automation>('POST', `automations/${id}/toggle`);
137
+ }
138
+
139
+ /**
140
+ * Execute an automation manually (for testing)
141
+ */
142
+ async execute(
143
+ id: string,
144
+ testData?: Record<string, unknown>
145
+ ): Promise<ExecuteAutomationResult> {
146
+ return this.adapter.request<ExecuteAutomationResult>(
147
+ 'POST',
148
+ `automations/${id}/execute`,
149
+ { body: testData }
150
+ );
151
+ }
152
+ }
153
+
154
+
155
+
156
+
157
+
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Conversations Module
3
+ * AI chat conversation management
4
+ */
5
+
6
+ import { IInstanceAdapter } from '../adapters/types';
7
+
8
+ export interface ToolCall {
9
+ name: string;
10
+ arguments?: Record<string, unknown>;
11
+ result?: unknown;
12
+ error?: string;
13
+ }
14
+
15
+ export interface Message {
16
+ id: string;
17
+ role: 'user' | 'assistant' | 'system';
18
+ content: string;
19
+ toolCalls?: ToolCall[];
20
+ createdAt: number;
21
+ }
22
+
23
+ export interface Conversation {
24
+ id: string;
25
+ workspaceId: string;
26
+ userId?: string;
27
+ title: string;
28
+ lastMessage?: string;
29
+ messageCount: number;
30
+ createdAt: number;
31
+ updatedAt: number;
32
+ }
33
+
34
+ export interface ConversationWithMessages extends Conversation {
35
+ messages: Message[];
36
+ }
37
+
38
+ export interface CreateConversationPayload {
39
+ title?: string;
40
+ }
41
+
42
+ export interface AddMessagePayload {
43
+ role: 'user' | 'assistant' | 'system';
44
+ content: string;
45
+ toolCalls?: ToolCall[];
46
+ }
47
+
48
+ export interface ConversationListResponse {
49
+ conversations: Conversation[];
50
+ total: number;
51
+ }
52
+
53
+ export class ConversationModule {
54
+ constructor(private adapter: IInstanceAdapter) { }
55
+
56
+ /**
57
+ * List conversations for the current user/workspace
58
+ */
59
+ async list(options?: {
60
+ limit?: number;
61
+ offset?: number;
62
+ }): Promise<ConversationListResponse> {
63
+ const params: Record<string, string> = {};
64
+ if (options?.limit) params.limit = String(options.limit);
65
+ if (options?.offset) params.offset = String(options.offset);
66
+
67
+ return this.adapter.request<ConversationListResponse>(
68
+ 'GET',
69
+ 'conversations',
70
+ { params }
71
+ );
72
+ }
73
+
74
+ /**
75
+ * Get a single conversation with messages
76
+ */
77
+ async get(id: string): Promise<ConversationWithMessages> {
78
+ return this.adapter.request<ConversationWithMessages>(
79
+ 'GET',
80
+ `conversations/${id}`
81
+ );
82
+ }
83
+
84
+ /**
85
+ * Create a new conversation
86
+ */
87
+ async create(data?: CreateConversationPayload): Promise<{ conversation: ConversationWithMessages }> {
88
+ return this.adapter.request<{ conversation: ConversationWithMessages }>(
89
+ 'POST',
90
+ 'conversations',
91
+ { body: data || {} }
92
+ );
93
+ }
94
+
95
+ /**
96
+ * Update a conversation (title)
97
+ */
98
+ async update(id: string, title: string): Promise<{ conversation: Conversation }> {
99
+ return this.adapter.request<{ conversation: Conversation }>(
100
+ 'PATCH',
101
+ `conversations/${id}`,
102
+ { body: { title } }
103
+ );
104
+ }
105
+
106
+ /**
107
+ * Delete a conversation
108
+ */
109
+ async delete(id: string): Promise<{ deleted: boolean }> {
110
+ return this.adapter.request<{ deleted: boolean }>(
111
+ 'DELETE',
112
+ `conversations/${id}`
113
+ );
114
+ }
115
+
116
+ /**
117
+ * Add a message to a conversation
118
+ */
119
+ async addMessage(
120
+ conversationId: string,
121
+ message: AddMessagePayload
122
+ ): Promise<{ message: Message }> {
123
+ return this.adapter.request<{ message: Message }>(
124
+ 'POST',
125
+ `conversations/${conversationId}/messages`,
126
+ { body: message }
127
+ );
128
+ }
129
+ }
130
+
131
+
132
+
133
+
134
+
@@ -1,27 +1,77 @@
1
- import { AxiosInstance } from 'axios';
2
- import { handleRequest } from '../request';
3
- import { TapstackField, TapstackResponse } from '../types';
1
+ /**
2
+ * Fields Module
3
+ * CRUD operations for Tapstack fields (object schema)
4
+ */
5
+
6
+ import { IInstanceAdapter } from '../adapters/types';
7
+ import {
8
+ TapstackField,
9
+ CreateFieldPayload,
10
+ UpdateFieldPayload,
11
+ FieldListResponse,
12
+ } from '../types';
4
13
 
5
14
  export class FieldModule {
6
- constructor(private client: AxiosInstance) {}
15
+ constructor(private adapter: IInstanceAdapter) { }
7
16
 
8
- list(slug: string): Promise<TapstackResponse<TapstackField[]>> {
9
- return handleRequest(this.client, { method: 'GET', url: `/system/${slug}/fields` });
17
+ /**
18
+ * List all fields for an object
19
+ */
20
+ async list(objectSlug: string): Promise<FieldListResponse> {
21
+ return this.adapter.request<FieldListResponse>(
22
+ 'GET',
23
+ `schema/objects/${objectSlug}/fields`
24
+ );
10
25
  }
11
26
 
12
- get(slug: string, fieldID: string): Promise<TapstackResponse<TapstackField>> {
13
- return handleRequest(this.client, { method: 'GET', url: `/system/${slug}/fields/${fieldID}` });
27
+ /**
28
+ * Get a single field by ID
29
+ */
30
+ async get(objectSlug: string, fieldId: string): Promise<TapstackField> {
31
+ return this.adapter.request<TapstackField>(
32
+ 'GET',
33
+ `schema/objects/${objectSlug}/fields/${fieldId}`
34
+ );
14
35
  }
15
36
 
16
- create(slug: string, data: Partial<TapstackField>): Promise<TapstackResponse<TapstackField>> {
17
- return handleRequest(this.client, { method: 'POST', url: `/system/${slug}/fields`, data });
37
+ /**
38
+ * Create a new field
39
+ */
40
+ async create(objectSlug: string, data: CreateFieldPayload): Promise<TapstackField> {
41
+ return this.adapter.request<TapstackField>(
42
+ 'POST',
43
+ `schema/objects/${objectSlug}/fields`,
44
+ { body: data }
45
+ );
18
46
  }
19
47
 
20
- update(slug: string, fieldID: string, data: Partial<TapstackField>): Promise<TapstackResponse<TapstackField>> {
21
- return handleRequest(this.client, { method: 'PUT', url: `/system/${slug}/fields/${fieldID}`, data });
48
+ /**
49
+ * Update an existing field
50
+ */
51
+ async update(
52
+ objectSlug: string,
53
+ fieldId: string,
54
+ data: UpdateFieldPayload
55
+ ): Promise<TapstackField> {
56
+ return this.adapter.request<TapstackField>(
57
+ 'PATCH',
58
+ `schema/objects/${objectSlug}/fields/${fieldId}`,
59
+ { body: data }
60
+ );
22
61
  }
23
62
 
24
- delete(slug: string, fieldID: string): Promise<TapstackResponse<void>> {
25
- return handleRequest(this.client, { method: 'DELETE', url: `/system/${slug}/fields/${fieldID}` });
63
+ /**
64
+ * Delete a field (soft delete by default)
65
+ */
66
+ async delete(
67
+ objectSlug: string,
68
+ fieldId: string,
69
+ soft = true
70
+ ): Promise<{ deleted: boolean }> {
71
+ return this.adapter.request<{ deleted: boolean }>(
72
+ 'DELETE',
73
+ `schema/objects/${objectSlug}/fields/${fieldId}`,
74
+ { params: { soft: String(soft) } }
75
+ );
26
76
  }
27
77
  }
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Files Module
3
+ * File and folder operations using Supabase Storage
4
+ */
5
+
6
+ import { IInstanceAdapter } from '../adapters/types';
7
+ import {
8
+ TapstackFile,
9
+ TapstackFolder,
10
+ FileUploadOptions,
11
+ FileListResponse,
12
+ FolderListResponse,
13
+ } from '../types';
14
+
15
+ export class FileModule {
16
+ constructor(private adapter: IInstanceAdapter) { }
17
+
18
+ // ==================== Files ====================
19
+
20
+ /**
21
+ * List files in the workspace (optionally filtered by folder)
22
+ */
23
+ async list(folderId?: string): Promise<FileListResponse> {
24
+ const params: Record<string, string> = {};
25
+ if (folderId) params.folderId = folderId;
26
+
27
+ return this.adapter.request<FileListResponse>('GET', 'files/list', { params });
28
+ }
29
+
30
+ /**
31
+ * Get a single file by ID
32
+ */
33
+ async get(fileId: string): Promise<TapstackFile> {
34
+ return this.adapter.request<TapstackFile>('GET', `files/${fileId}`);
35
+ }
36
+
37
+ /**
38
+ * Upload a file
39
+ */
40
+ async upload(file: File | Blob, options?: FileUploadOptions): Promise<TapstackFile> {
41
+ const metadata: Record<string, string> = {};
42
+ if (options?.folderId) metadata.folderId = options.folderId;
43
+ if (options?.folder) metadata.folder = options.folder;
44
+
45
+ return this.adapter.upload<TapstackFile>('files/upload', file, metadata);
46
+ }
47
+
48
+ /**
49
+ * Delete a file
50
+ */
51
+ async delete(fileId: string): Promise<{ deleted: boolean }> {
52
+ return this.adapter.request<{ deleted: boolean }>('DELETE', `files/${fileId}`);
53
+ }
54
+
55
+ /**
56
+ * Get a signed download URL for a file
57
+ */
58
+ async getDownloadUrl(fileId: string, expiresIn = 3600): Promise<{ url: string }> {
59
+ return this.adapter.request<{ url: string }>(
60
+ 'GET',
61
+ `files/${fileId}/download`,
62
+ { params: { expiresIn: String(expiresIn) } }
63
+ );
64
+ }
65
+
66
+ /**
67
+ * Move a file to a different folder
68
+ */
69
+ async move(fileId: string, targetFolderId: string | null): Promise<TapstackFile> {
70
+ return this.adapter.request<TapstackFile>('PATCH', `files/${fileId}/move`, {
71
+ body: { folderId: targetFolderId },
72
+ });
73
+ }
74
+
75
+ /**
76
+ * Rename a file
77
+ */
78
+ async rename(fileId: string, newName: string): Promise<TapstackFile> {
79
+ return this.adapter.request<TapstackFile>('PATCH', `files/${fileId}`, {
80
+ body: { name: newName },
81
+ });
82
+ }
83
+
84
+ // ==================== Folders ====================
85
+
86
+ /**
87
+ * List folders (optionally filtered by parent)
88
+ */
89
+ async listFolders(parentId?: string | null): Promise<FolderListResponse> {
90
+ const params: Record<string, string> = {};
91
+ if (parentId !== undefined) {
92
+ params.parentId = parentId ?? 'null';
93
+ }
94
+
95
+ return this.adapter.request<FolderListResponse>('GET', 'files/folders', { params });
96
+ }
97
+
98
+ /**
99
+ * Get a single folder by ID
100
+ */
101
+ async getFolder(folderId: string): Promise<TapstackFolder> {
102
+ return this.adapter.request<TapstackFolder>('GET', `files/folders/${folderId}`);
103
+ }
104
+
105
+ /**
106
+ * Create a new folder
107
+ */
108
+ async createFolder(name: string, parentId?: string): Promise<TapstackFolder> {
109
+ return this.adapter.request<TapstackFolder>('POST', 'files/folders', {
110
+ body: { name, parentId },
111
+ });
112
+ }
113
+
114
+ /**
115
+ * Rename a folder
116
+ */
117
+ async renameFolder(folderId: string, newName: string): Promise<TapstackFolder> {
118
+ return this.adapter.request<TapstackFolder>('PATCH', `files/folders/${folderId}`, {
119
+ body: { name: newName },
120
+ });
121
+ }
122
+
123
+ /**
124
+ * Move a folder to a different parent
125
+ */
126
+ async moveFolder(folderId: string, targetParentId: string | null): Promise<TapstackFolder> {
127
+ return this.adapter.request<TapstackFolder>('PATCH', `files/folders/${folderId}/move`, {
128
+ body: { parentId: targetParentId },
129
+ });
130
+ }
131
+
132
+ /**
133
+ * Delete a folder (and all contents)
134
+ */
135
+ async deleteFolder(folderId: string): Promise<{ deleted: boolean }> {
136
+ return this.adapter.request<{ deleted: boolean }>('DELETE', `files/folders/${folderId}`);
137
+ }
138
+ }
139
+
140
+
141
+
142
+
143
+
144
+
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Modules Index
3
+ * Export all module classes
4
+ */
5
+
6
+ export * from './objects';
7
+ export * from './fields';
8
+ export * from './records';
9
+ export * from './organizations';
10
+ export * from './workspaces';
11
+ export * from './files';
12
+ export * from './automations';
13
+ export * from './conversations';
14
+
15
+
16
+
17
+
18
+
19
+
@@ -1,27 +1,59 @@
1
- import { AxiosInstance } from 'axios';
2
- import { handleRequest } from '../request';
3
- import { TapstackObject, TapstackResponse } from '../types';
1
+ /**
2
+ * Objects Module
3
+ * CRUD operations for Tapstack objects (data models)
4
+ */
5
+
6
+ import { IInstanceAdapter } from '../adapters/types';
7
+ import {
8
+ TapstackObject,
9
+ CreateObjectPayload,
10
+ UpdateObjectPayload,
11
+ ObjectListResponse,
12
+ } from '../types';
4
13
 
5
14
  export class ObjectModule {
6
- constructor(private client: AxiosInstance) {}
15
+ constructor(private adapter: IInstanceAdapter) { }
7
16
 
8
- get(slug: string): Promise<TapstackResponse<TapstackObject>> {
9
- return handleRequest(this.client, { method: 'GET', url: `/system/${slug}` });
17
+ /**
18
+ * List all objects in the workspace
19
+ */
20
+ async list(): Promise<ObjectListResponse> {
21
+ return this.adapter.request<ObjectListResponse>('GET', 'schema/objects');
10
22
  }
11
23
 
12
- list(): Promise<TapstackResponse<TapstackObject[]>> {
13
- return handleRequest(this.client, { method: 'GET', url: `/system` });
24
+ /**
25
+ * Get a single object by slug
26
+ */
27
+ async get(slug: string): Promise<TapstackObject> {
28
+ return this.adapter.request<TapstackObject>('GET', `schema/objects/${slug}`);
14
29
  }
15
30
 
16
- create(data: Partial<TapstackObject>): Promise<TapstackResponse<TapstackObject>> {
17
- return handleRequest(this.client, { method: 'POST', url: `/system`, data });
31
+ /**
32
+ * Create a new object
33
+ */
34
+ async create(data: CreateObjectPayload): Promise<TapstackObject> {
35
+ return this.adapter.request<TapstackObject>('POST', 'schema/objects', {
36
+ body: data,
37
+ });
18
38
  }
19
39
 
20
- update(slug: string, data: Partial<TapstackObject>): Promise<TapstackResponse<TapstackObject>> {
21
- return handleRequest(this.client, { method: 'PUT', url: `/system/${slug}`, data });
40
+ /**
41
+ * Update an existing object
42
+ */
43
+ async update(slug: string, data: UpdateObjectPayload): Promise<TapstackObject> {
44
+ return this.adapter.request<TapstackObject>('PATCH', `schema/objects/${slug}`, {
45
+ body: data,
46
+ });
22
47
  }
23
48
 
24
- delete(slug: string): Promise<TapstackResponse<void>> {
25
- return handleRequest(this.client, { method: 'DELETE', url: `/system/${slug}` });
49
+ /**
50
+ * Delete an object (soft delete by default)
51
+ */
52
+ async delete(slug: string, soft = true): Promise<{ deleted: boolean }> {
53
+ return this.adapter.request<{ deleted: boolean }>(
54
+ 'DELETE',
55
+ `schema/objects/${slug}`,
56
+ { params: { soft: String(soft) } }
57
+ );
26
58
  }
27
59
  }