@urbackend/sdk 0.2.1 → 0.2.3

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.
@@ -1,154 +0,0 @@
1
- export interface UrBackendConfig {
2
- apiKey: string;
3
- baseUrl?: string;
4
- headers?: Record<string, string>;
5
- }
6
-
7
- export interface RequestOptions {
8
- body?: unknown;
9
- token?: string;
10
- isMultipart?: boolean;
11
- credentials?: RequestCredentials;
12
- headers?: Record<string, string>;
13
- }
14
-
15
- export interface QueryParams {
16
- page?: number;
17
- limit?: number;
18
- sort?: string;
19
- populate?: string | string[];
20
- expand?: string | string[];
21
- filter?: Record<string, unknown>;
22
- [key: string]: unknown;
23
- }
24
-
25
- export interface SignUpPayload {
26
- email: string;
27
- password: string;
28
- username?: string;
29
- name?: string;
30
- [key: string]: unknown;
31
- }
32
-
33
- export interface LoginPayload {
34
- email: string;
35
- password: string;
36
- }
37
-
38
- export interface UpdateProfilePayload {
39
- username?: string;
40
- name?: string;
41
- [key: string]: unknown;
42
- }
43
-
44
- export interface ChangePasswordPayload {
45
- currentPassword: string;
46
- newPassword: string;
47
- }
48
-
49
- export interface VerifyEmailPayload {
50
- email: string;
51
- otp: string;
52
- }
53
-
54
- export interface ResendOtpPayload {
55
- email: string;
56
- }
57
-
58
- export interface RequestPasswordResetPayload {
59
- email: string;
60
- }
61
-
62
- export interface ResetPasswordPayload {
63
- email: string;
64
- otp: string;
65
- newPassword: string;
66
- }
67
-
68
- export interface SocialExchangePayload {
69
- token: string;
70
- rtCode: string;
71
- }
72
-
73
- export interface SocialExchangeResponse {
74
- refreshToken: string;
75
- }
76
-
77
- export interface AuthUser {
78
- _id: string;
79
- email: string;
80
- username?: string;
81
- name?: string;
82
- [key: string]: unknown;
83
- }
84
-
85
- export interface AuthResponse {
86
- accessToken?: string;
87
- /** @deprecated use accessToken instead */
88
- token?: string;
89
- expiresIn?: string;
90
- userId?: string;
91
- user?: AuthUser;
92
- }
93
-
94
- export interface DocumentData {
95
- _id: string;
96
- [key: string]: unknown;
97
- }
98
-
99
- export interface InsertPayload {
100
- [key: string]: unknown;
101
- }
102
-
103
- export interface UpdatePayload {
104
- [key: string]: unknown;
105
- }
106
-
107
- export interface PatchPayload {
108
- [key: string]: unknown;
109
- }
110
-
111
- export interface SchemaField {
112
- key: string;
113
- type: string;
114
- required: boolean;
115
- unique?: boolean;
116
- ref?: string;
117
- items?: {
118
- type: string;
119
- fields?: SchemaField[];
120
- };
121
- fields?: SchemaField[];
122
- }
123
-
124
- export interface CollectionSchema {
125
- name: string;
126
- model: SchemaField[];
127
- }
128
-
129
- export interface SendMailPayload {
130
- to: string | string[];
131
- subject: string;
132
- text?: string;
133
- html?: string;
134
- }
135
-
136
- export interface SendMailResponse {
137
- id: string | null;
138
- provider: 'byok' | 'default';
139
- monthlyUsage: number;
140
- monthlyLimit: number;
141
- }
142
-
143
- export interface UploadResponse {
144
- url: string;
145
- path: string;
146
- provider: 'internal' | 'external';
147
- message?: string;
148
- }
149
-
150
- export interface ApiResponse<T> {
151
- data: T;
152
- success: boolean;
153
- message?: string;
154
- }
@@ -1,169 +0,0 @@
1
- import { expect, test, vi, beforeEach } from 'vitest';
2
- import urBackend from '../src/index';
3
-
4
- const mockApiKey = 'pk_live_test';
5
- let client: ReturnType<typeof urBackend>;
6
-
7
- beforeEach(() => {
8
- vi.resetAllMocks();
9
- client = urBackend({ apiKey: mockApiKey });
10
- });
11
-
12
- test('signUp returns user object on success', async () => {
13
- const mockUser = { _id: '123', email: 'test@example.com' };
14
- vi.stubGlobal(
15
- 'fetch',
16
- vi.fn().mockResolvedValue({
17
- ok: true,
18
- headers: new Headers({ 'content-type': 'application/json' }),
19
- json: () => Promise.resolve({ success: true, data: mockUser }),
20
- }),
21
- );
22
-
23
- const user = await client.auth.signUp({ email: 'test@example.com', password: 'password' });
24
- expect(user).toEqual(mockUser);
25
- });
26
-
27
- test('login stores accessToken', async () => {
28
- const mockAccessToken = 'mock-access-token';
29
- vi.stubGlobal(
30
- 'fetch',
31
- vi.fn().mockResolvedValue({
32
- ok: true,
33
- headers: new Headers({ 'content-type': 'application/json' }),
34
- json: () =>
35
- Promise.resolve({
36
- success: true,
37
- data: { accessToken: mockAccessToken, user: { _id: '123', email: 'test@example.com' } },
38
- }),
39
- }),
40
- );
41
-
42
- const response = await client.auth.login({ email: 'test@example.com', password: 'password' });
43
- expect(response.accessToken).toBe(mockAccessToken);
44
- expect(client.auth.getToken()).toBe(mockAccessToken);
45
- });
46
-
47
- test('me() uses stored token from login', async () => {
48
- const mockToken = 'mock-token';
49
- const mockUser = { _id: '123', email: 'test@example.com' };
50
-
51
- // First mock login
52
- vi.stubGlobal(
53
- 'fetch',
54
- vi.fn().mockResolvedValue({
55
- ok: true,
56
- headers: new Headers({ 'content-type': 'application/json' }),
57
- json: () =>
58
- Promise.resolve({
59
- success: true,
60
- data: { accessToken: mockToken, user: mockUser },
61
- }),
62
- }),
63
- );
64
- await client.auth.login({ email: 'test@example.com', password: 'password' });
65
-
66
- // Then mock me call
67
- const meFetchMock = vi.fn().mockResolvedValue({
68
- ok: true,
69
- headers: new Headers({ 'content-type': 'application/json' }),
70
- json: () => Promise.resolve({ success: true, data: mockUser }),
71
- });
72
- vi.stubGlobal('fetch', meFetchMock);
73
-
74
- await client.auth.me();
75
-
76
- expect(meFetchMock).toHaveBeenCalledWith(
77
- expect.stringContaining('/api/userAuth/me'),
78
- expect.objectContaining({
79
- headers: expect.objectContaining({
80
- Authorization: `Bearer ${mockToken}`,
81
- }),
82
- }),
83
- );
84
- });
85
-
86
- test('logout() calls server and clears local token', async () => {
87
- client.auth.setToken('test-token');
88
- const logoutFetchMock = vi.fn().mockResolvedValue({
89
- ok: true,
90
- headers: new Headers({ 'content-type': 'application/json' }),
91
- json: () => Promise.resolve({ success: true, message: 'Logged out' }),
92
- });
93
- vi.stubGlobal('fetch', logoutFetchMock);
94
-
95
- await client.auth.logout();
96
-
97
- expect(logoutFetchMock).toHaveBeenCalledWith(
98
- expect.stringContaining('/api/userAuth/logout'),
99
- expect.objectContaining({
100
- method: 'POST',
101
- headers: expect.objectContaining({
102
- Authorization: 'Bearer test-token',
103
- }),
104
- }),
105
- );
106
- expect(client.auth.getToken()).toBeUndefined();
107
- });
108
-
109
- test('refreshToken() uses credentials: include by default', async () => {
110
- const refreshFetchMock = vi.fn().mockResolvedValue({
111
- ok: true,
112
- headers: new Headers({ 'content-type': 'application/json' }),
113
- json: () => Promise.resolve({ success: true, data: { accessToken: 'new-token' } }),
114
- });
115
- vi.stubGlobal('fetch', refreshFetchMock);
116
-
117
- await client.auth.refreshToken();
118
-
119
- expect(refreshFetchMock).toHaveBeenCalledWith(
120
- expect.stringContaining('/api/userAuth/refresh-token'),
121
- expect.objectContaining({
122
- method: 'POST',
123
- credentials: 'include',
124
- }),
125
- );
126
- });
127
-
128
- test('refreshToken(token) uses header mode', async () => {
129
- const refreshFetchMock = vi.fn().mockResolvedValue({
130
- ok: true,
131
- headers: new Headers({ 'content-type': 'application/json' }),
132
- json: () => Promise.resolve({ success: true, data: { accessToken: 'new-token' } }),
133
- });
134
- vi.stubGlobal('fetch', refreshFetchMock);
135
-
136
- await client.auth.refreshToken('manual-refresh-token');
137
-
138
- expect(refreshFetchMock).toHaveBeenCalledWith(
139
- expect.stringContaining('/api/userAuth/refresh-token'),
140
- expect.objectContaining({
141
- method: 'POST',
142
- headers: expect.objectContaining({
143
- 'x-refresh-token': 'manual-refresh-token',
144
- 'x-refresh-token-mode': 'header',
145
- }),
146
- }),
147
- );
148
- });
149
-
150
- test('socialStart returns correct URL', () => {
151
- const url = client.auth.socialStart('github');
152
- expect(url).toBe('https://api.ub.bitbros.in/api/userAuth/social/github/start?key=pk_live_test');
153
- });
154
-
155
- test('publicProfile calls correct endpoint', async () => {
156
- const fetchMock = vi.fn().mockResolvedValue({
157
- ok: true,
158
- headers: new Headers({ 'content-type': 'application/json' }),
159
- json: () => Promise.resolve({ success: true, data: { username: 'yash' } }),
160
- });
161
- vi.stubGlobal('fetch', fetchMock);
162
-
163
- await client.auth.publicProfile('yash');
164
-
165
- expect(fetchMock).toHaveBeenCalledWith(
166
- expect.stringContaining('/api/userAuth/public/yash'),
167
- expect.any(Object),
168
- );
169
- });
@@ -1,134 +0,0 @@
1
- import { expect, test, vi, beforeEach } from 'vitest';
2
- import urBackend from '../src/index';
3
-
4
- const mockApiKey = 'pk_live_test';
5
- const client = urBackend({ apiKey: mockApiKey });
6
-
7
- beforeEach(() => {
8
- vi.resetAllMocks();
9
- });
10
-
11
- test('getAll returns array of typed documents', async () => {
12
- const mockData = [
13
- { _id: '1', name: 'Product 1' },
14
- { _id: '2', name: 'Product 2' },
15
- ];
16
- vi.stubGlobal(
17
- 'fetch',
18
- vi.fn().mockResolvedValue({
19
- ok: true,
20
- headers: new Headers({ 'content-type': 'application/json' }),
21
- json: () => Promise.resolve({ success: true, data: mockData }),
22
- }),
23
- );
24
-
25
- const items = await client.db.getAll<{ _id: string; name: string }>('products');
26
- expect(items).toEqual(mockData);
27
- });
28
-
29
- test('getAll with query params builds correct query string', async () => {
30
- const fetchMock = vi.fn().mockResolvedValue({
31
- ok: true,
32
- headers: new Headers({ 'content-type': 'application/json' }),
33
- json: () => Promise.resolve({ success: true, data: [] }),
34
- });
35
- vi.stubGlobal('fetch', fetchMock);
36
-
37
- await client.db.getAll('products', {
38
- page: 2,
39
- limit: 10,
40
- sort: 'price:asc',
41
- populate: 'category',
42
- filter: { price_gt: 100 }
43
- });
44
-
45
- const url = fetchMock.mock.calls[0][0] as string;
46
- const searchParams = new URL(url).searchParams;
47
-
48
- expect(searchParams.get('page')).toBe('2');
49
- expect(searchParams.get('limit')).toBe('10');
50
- expect(searchParams.get('sort')).toBe('price:asc');
51
- expect(searchParams.get('populate')).toBe('category');
52
- expect(searchParams.get('price_gt')).toBe('100');
53
- });
54
-
55
- test('insert returns created document and handles optional token', async () => {
56
- const payload = { name: 'New Item' };
57
- const mockCreated = { _id: 'new-id', ...payload };
58
- const fetchMock = vi.fn().mockResolvedValue({
59
- ok: true,
60
- headers: new Headers({ 'content-type': 'application/json' }),
61
- json: () => Promise.resolve({ success: true, data: mockCreated }),
62
- });
63
- vi.stubGlobal('fetch', fetchMock);
64
-
65
- const result = await client.db.insert<{ _id: string; name: string }>('products', payload, 'user-token');
66
-
67
- expect(result._id).toBe('new-id');
68
- expect(fetchMock).toHaveBeenCalledWith(
69
- expect.stringContaining('/api/data/products'),
70
- expect.objectContaining({
71
- method: 'POST',
72
- headers: expect.objectContaining({
73
- Authorization: 'Bearer user-token',
74
- }),
75
- }),
76
- );
77
- });
78
-
79
- test('patch sends PATCH request', async () => {
80
- const payload = { price: 50 };
81
- const mockUpdated = { _id: '1', name: 'Original', price: 50 };
82
- const fetchMock = vi.fn().mockResolvedValue({
83
- ok: true,
84
- headers: new Headers({ 'content-type': 'application/json' }),
85
- json: () => Promise.resolve({ success: true, data: mockUpdated }),
86
- });
87
- vi.stubGlobal('fetch', fetchMock);
88
-
89
- await client.db.patch('products', '1', payload);
90
-
91
- expect(fetchMock).toHaveBeenCalledWith(
92
- expect.stringContaining('/api/data/products/1'),
93
- expect.objectContaining({
94
- method: 'PATCH',
95
- body: JSON.stringify(payload),
96
- }),
97
- );
98
- });
99
-
100
- test('getOne with populate builds correct query string', async () => {
101
- const fetchMock = vi.fn().mockResolvedValue({
102
- ok: true,
103
- headers: new Headers({ 'content-type': 'application/json' }),
104
- json: () => Promise.resolve({ success: true, data: { _id: '1' } }),
105
- });
106
- vi.stubGlobal('fetch', fetchMock);
107
-
108
- await client.db.getOne('products', '1', { populate: 'category' });
109
-
110
- const url = fetchMock.mock.calls[0][0] as string;
111
- expect(url).toContain('?populate=category');
112
- });
113
-
114
- test('delete returns { deleted: true } and handles token', async () => {
115
- const fetchMock = vi.fn().mockResolvedValue({
116
- ok: true,
117
- headers: new Headers({ 'content-type': 'application/json' }),
118
- json: () => Promise.resolve({ success: true, data: { message: 'Document deleted', id: 'id-1' } }),
119
- });
120
- vi.stubGlobal('fetch', fetchMock);
121
-
122
- const result = await client.db.delete('products', 'id-1', 'admin-token');
123
-
124
- expect(result.deleted).toBe(true);
125
- expect(fetchMock).toHaveBeenCalledWith(
126
- expect.stringContaining('/api/data/products/id-1'),
127
- expect.objectContaining({
128
- method: 'DELETE',
129
- headers: expect.objectContaining({
130
- Authorization: 'Bearer admin-token',
131
- }),
132
- }),
133
- );
134
- });
@@ -1,41 +0,0 @@
1
- import { expect, test, vi, beforeEach } from 'vitest';
2
- import urBackend from '../src/index';
3
-
4
- const mockApiKey = 'sk_live_test';
5
- const client = urBackend({ apiKey: mockApiKey });
6
-
7
- beforeEach(() => {
8
- vi.resetAllMocks();
9
- });
10
-
11
- test('send() sends POST request to mail endpoint', async () => {
12
- const payload = {
13
- to: 'user@example.com',
14
- subject: 'Hello',
15
- text: 'Test mail'
16
- };
17
-
18
- const mockResponse = {
19
- success: true,
20
- data: { id: 'msg_1', provider: 'default', monthlyUsage: 1, monthlyLimit: 100 },
21
- message: 'Sent'
22
- };
23
-
24
- const fetchMock = vi.fn().mockResolvedValue({
25
- ok: true,
26
- headers: new Headers({ 'content-type': 'application/json' }),
27
- json: () => Promise.resolve(mockResponse),
28
- });
29
- vi.stubGlobal('fetch', fetchMock);
30
-
31
- const result = await client.mail.send(payload);
32
-
33
- expect(result).toEqual(mockResponse.data);
34
- expect(fetchMock).toHaveBeenCalledWith(
35
- expect.stringContaining('/api/mail/send'),
36
- expect.objectContaining({
37
- method: 'POST',
38
- body: JSON.stringify(payload),
39
- }),
40
- );
41
- });
@@ -1,32 +0,0 @@
1
- import { expect, test, vi, beforeEach } from 'vitest';
2
- import urBackend from '../src/index';
3
-
4
- const mockApiKey = 'pk_live_test';
5
- const client = urBackend({ apiKey: mockApiKey });
6
-
7
- beforeEach(() => {
8
- vi.resetAllMocks();
9
- });
10
-
11
- test('getSchema returns collection schema', async () => {
12
- const mockSchema = {
13
- name: 'products',
14
- model: [
15
- { key: 'name', type: 'String', required: true },
16
- { key: 'price', type: 'Number', required: true }
17
- ]
18
- };
19
-
20
- vi.stubGlobal(
21
- 'fetch',
22
- vi.fn().mockResolvedValue({
23
- ok: true,
24
- headers: new Headers({ 'content-type': 'application/json' }),
25
- json: () => Promise.resolve({ message: 'Schema exists', collection: mockSchema }),
26
- }),
27
- );
28
-
29
- const schema = await client.schema.getSchema('products');
30
- expect(schema).toEqual(mockSchema);
31
- expect(schema.name).toBe('products');
32
- });
@@ -1,62 +0,0 @@
1
- /// <reference types="node" />
2
- import { expect, test, vi } from 'vitest';
3
- import urBackend from '../src/index';
4
-
5
- const mockApiKey = 'test-api-key';
6
- const client = urBackend({ apiKey: mockApiKey });
7
-
8
- test('upload sends FormData and returns { url, path }', async () => {
9
- const mockResponse = { url: 'http://cdn.com/file.jpg', path: '/uploads/file.jpg' };
10
- const fetchMock = vi.fn().mockResolvedValue({
11
- ok: true,
12
- headers: new Headers({ 'content-type': 'application/json' }),
13
- json: () => Promise.resolve({ success: true, data: mockResponse }),
14
- });
15
- vi.stubGlobal('fetch', fetchMock);
16
-
17
- // In Node.js testing environment, use a Buffer as mock file
18
- const result = await client.storage.upload(Buffer.from('mock binary data'), 'test.jpg');
19
-
20
- expect(result).toEqual(mockResponse);
21
- expect(fetchMock).toHaveBeenCalledWith(
22
- expect.stringContaining('/api/storage/upload'),
23
- expect.objectContaining({
24
- method: 'POST',
25
- body: expect.any(Object), // FormData
26
- }),
27
- );
28
- });
29
-
30
- test('deleteFile sends path in body', async () => {
31
- const fetchMock = vi.fn().mockResolvedValue({
32
- ok: true,
33
- headers: new Headers({ 'content-type': 'application/json' }),
34
- json: () => Promise.resolve({ success: true, data: { deleted: true } }),
35
- });
36
- vi.stubGlobal('fetch', fetchMock);
37
-
38
- const result = await client.storage.deleteFile('/uploads/file.jpg');
39
-
40
- expect(result.deleted).toBe(true);
41
- expect(fetchMock).toHaveBeenCalledWith(
42
- expect.stringContaining('/api/storage/file'),
43
- expect.objectContaining({
44
- method: 'DELETE',
45
- body: JSON.stringify({ path: '/uploads/file.jpg' }),
46
- }),
47
- );
48
- });
49
-
50
- test('StorageError thrown on failure', async () => {
51
- vi.stubGlobal(
52
- 'fetch',
53
- vi.fn().mockResolvedValue({
54
- ok: false,
55
- status: 500,
56
- url: 'https://api.urbackend.bitbros.in/api/storage/upload',
57
- json: () => Promise.resolve({ success: false, message: 'Upload failed' }),
58
- }),
59
- );
60
-
61
- await expect(client.storage.upload(Buffer.from('data'))).rejects.toThrow('Upload failed');
62
- });
@@ -1,9 +0,0 @@
1
- {
2
- "extends": "../tsconfig.json",
3
- "compilerOptions": {
4
- "rootDir": "..",
5
- "outDir": "../dist-test",
6
- "types": ["node", "vitest/globals"]
7
- },
8
- "include": ["./**/*", "../src/**/*"]
9
- }
package/tsconfig.json DELETED
@@ -1,18 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "ESNext",
5
- "moduleResolution": "bundler",
6
- "lib": ["DOM", "DOM.Iterable", "ESNext"],
7
- "types": ["node"],
8
- "strict": true,
9
- "declaration": true,
10
- "outDir": "dist",
11
- "rootDir": "src",
12
- "esModuleInterop": true,
13
- "skipLibCheck": true,
14
- "forceConsistentCasingInFileNames": true
15
- },
16
- "include": ["src/**/*"],
17
- "exclude": ["node_modules", "dist", "tests"]
18
- }
package/tsup.config.ts DELETED
@@ -1,16 +0,0 @@
1
- import { defineConfig } from 'tsup';
2
-
3
- export default defineConfig({
4
- entry: ['src/index.ts'],
5
- format: ['cjs', 'esm'],
6
- outExtension({ format }) {
7
- return {
8
- js: format === 'cjs' ? '.cjs' : '.mjs',
9
- };
10
- },
11
- dts: true,
12
- clean: true,
13
- minify: false,
14
- sourcemap: true,
15
- target: 'es2020',
16
- });
package/vitest.config.ts DELETED
@@ -1,12 +0,0 @@
1
- import { defineConfig } from 'vitest/config';
2
-
3
- export default defineConfig({
4
- test: {
5
- globals: true,
6
- environment: 'node',
7
- coverage: {
8
- provider: 'v8',
9
- reporter: ['text', 'json', 'html'],
10
- },
11
- },
12
- });