instant-cli 0.22.155 → 0.22.156

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,4 +1,4 @@
1
1
 
2
- > instant-cli@0.22.155 build /home/runner/work/instant/instant/client/packages/cli
2
+ > instant-cli@0.22.156 build /home/runner/work/instant/instant/client/packages/cli
3
3
  > rm -rf dist; tsc -p tsconfig.json
4
4
 
@@ -0,0 +1,551 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { readFile } from 'fs/promises';
3
+ import { join } from 'path';
4
+ import { runCli, createTestProject, createTempApp } from './helpers';
5
+
6
+ const SCHEMA_FILE = `
7
+ import { i } from "@instantdb/core";
8
+
9
+ const _schema = i.schema({
10
+ entities: {
11
+ posts: i.entity({
12
+ title: i.string(),
13
+ body: i.string(),
14
+ }),
15
+ comments: i.entity({
16
+ text: i.string(),
17
+ }),
18
+ },
19
+ links: {
20
+ postComments: {
21
+ forward: { on: "posts", has: "many", label: "comments" },
22
+ reverse: { on: "comments", has: "one", label: "post" },
23
+ },
24
+ },
25
+ });
26
+
27
+ export default _schema;
28
+ `;
29
+
30
+ const PERMS_FILE = `export default {
31
+ posts: { allow: { view: "true", create: "true" } },
32
+ };
33
+ `;
34
+
35
+ describe.concurrent('CLI e2e', { timeout: 30_000 }, () => {
36
+ describe('init-without-files', () => {
37
+ it('creates a temp app and outputs JSON', async () => {
38
+ const result = await runCli([
39
+ 'init-without-files',
40
+ '--title',
41
+ 'e2e-temp-test',
42
+ '--temp',
43
+ ]);
44
+
45
+ expect(result.exitCode).toBe(0);
46
+
47
+ const jsonMatch = result.stdout.match(/\{[\s\S]*\}/);
48
+ expect(jsonMatch).toBeTruthy();
49
+
50
+ const parsed = JSON.parse(jsonMatch![0]);
51
+ expect(parsed.app).toBeTruthy();
52
+ expect(parsed.app.appId).toBeTruthy();
53
+ expect(parsed.app.adminToken).toBeTruthy();
54
+ expect(parsed.error).toBeNull();
55
+ });
56
+
57
+ it('fails without --title', async () => {
58
+ const result = await runCli(['init-without-files', '--temp']);
59
+ expect(result.exitCode).not.toBe(0);
60
+ });
61
+
62
+ it('fails when title value looks like a flag', async () => {
63
+ const result = await runCli([
64
+ 'init-without-files',
65
+ '--title',
66
+ '--bad-title',
67
+ ]);
68
+
69
+ expect(result.exitCode).not.toBe(0);
70
+ });
71
+
72
+ it('outputs JSON error format on failure', async () => {
73
+ const result = await runCli(['init-without-files', '--title', 'test']);
74
+
75
+ const jsonMatch = result.stdout.match(/\{[\s\S]*\}/);
76
+ expect(jsonMatch).toBeTruthy();
77
+
78
+ const parsed = JSON.parse(jsonMatch![0]);
79
+ expect(parsed.app).toBeNull();
80
+ expect(parsed.error).toHaveProperty('message');
81
+ });
82
+
83
+ it('rejects --temp with --org-id', async () => {
84
+ const result = await runCli([
85
+ 'init-without-files',
86
+ '--title',
87
+ 'test',
88
+ '--temp',
89
+ '--org-id',
90
+ 'org-1',
91
+ ]);
92
+
93
+ expect(result.exitCode).not.toBe(0);
94
+ const output = result.stdout + result.stderr;
95
+ expect(output).toMatch(/cannot.*--temp.*--org-id|cannot.*together/i);
96
+ });
97
+ });
98
+
99
+ describe('push schema', () => {
100
+ it('pushes schema to a real app', async () => {
101
+ const { appId, adminToken } = await createTempApp();
102
+ const project = await createTestProject({
103
+ appId,
104
+ schemaFile: SCHEMA_FILE,
105
+ });
106
+
107
+ try {
108
+ const result = await runCli(['push', 'schema', '--yes'], {
109
+ cwd: project.dir,
110
+ env: {
111
+ INSTANT_CLI_AUTH_TOKEN: adminToken,
112
+ INSTANT_APP_ID: appId,
113
+ },
114
+ });
115
+
116
+ expect(result.exitCode).toBe(0);
117
+ const output = result.stdout + result.stderr;
118
+ expect(output).toContain('posts');
119
+ } finally {
120
+ await project.cleanup();
121
+ }
122
+ });
123
+
124
+ it('reports no changes on second push', async () => {
125
+ const { appId, adminToken } = await createTempApp();
126
+ const project = await createTestProject({
127
+ appId,
128
+ schemaFile: SCHEMA_FILE,
129
+ });
130
+
131
+ try {
132
+ await runCli(['push', 'schema', '--yes'], {
133
+ cwd: project.dir,
134
+ env: {
135
+ INSTANT_CLI_AUTH_TOKEN: adminToken,
136
+ INSTANT_APP_ID: appId,
137
+ },
138
+ });
139
+
140
+ const result = await runCli(['push', 'schema', '--yes'], {
141
+ cwd: project.dir,
142
+ env: {
143
+ INSTANT_CLI_AUTH_TOKEN: adminToken,
144
+ INSTANT_APP_ID: appId,
145
+ },
146
+ });
147
+
148
+ expect(result.exitCode).toBe(0);
149
+ const output = result.stdout + result.stderr;
150
+ expect(output.toLowerCase()).toMatch(/no.*change/);
151
+ } finally {
152
+ await project.cleanup();
153
+ }
154
+ });
155
+
156
+ it('works with --app flag instead of env var', async () => {
157
+ const { appId, adminToken } = await createTempApp();
158
+ const project = await createTestProject({
159
+ schemaFile: SCHEMA_FILE,
160
+ });
161
+
162
+ try {
163
+ const result = await runCli(
164
+ ['push', 'schema', '--app', appId, '--yes'],
165
+ {
166
+ cwd: project.dir,
167
+ env: { INSTANT_CLI_AUTH_TOKEN: adminToken },
168
+ },
169
+ );
170
+
171
+ expect(result.exitCode).toBe(0);
172
+ } finally {
173
+ await project.cleanup();
174
+ }
175
+ });
176
+ });
177
+
178
+ describe('push schema with --rename', () => {
179
+ it('renames an attribute', async () => {
180
+ const { appId, adminToken } = await createTempApp();
181
+
182
+ const initialSchema = `
183
+ import { i } from "@instantdb/core";
184
+ const _schema = i.schema({
185
+ entities: {
186
+ posts: i.entity({
187
+ title: i.string(),
188
+ body: i.string(),
189
+ }),
190
+ },
191
+ });
192
+ export default _schema;
193
+ `;
194
+
195
+ const renamedSchema = `
196
+ import { i } from "@instantdb/core";
197
+ const _schema = i.schema({
198
+ entities: {
199
+ posts: i.entity({
200
+ name: i.string(),
201
+ body: i.string(),
202
+ }),
203
+ },
204
+ });
205
+ export default _schema;
206
+ `;
207
+
208
+ const project1 = await createTestProject({
209
+ appId,
210
+ schemaFile: initialSchema,
211
+ });
212
+ const seedResult = await runCli(['push', 'schema', '--yes'], {
213
+ cwd: project1.dir,
214
+ env: {
215
+ INSTANT_CLI_AUTH_TOKEN: adminToken,
216
+ INSTANT_APP_ID: appId,
217
+ },
218
+ });
219
+ expect(seedResult.exitCode).toBe(0);
220
+ await project1.cleanup();
221
+
222
+ const project2 = await createTestProject({
223
+ appId,
224
+ schemaFile: renamedSchema,
225
+ });
226
+
227
+ try {
228
+ const result = await runCli(
229
+ ['push', 'schema', '--yes', '--rename', 'posts.title:posts.name'],
230
+ {
231
+ cwd: project2.dir,
232
+ env: {
233
+ INSTANT_CLI_AUTH_TOKEN: adminToken,
234
+ INSTANT_APP_ID: appId,
235
+ },
236
+ },
237
+ );
238
+
239
+ expect(result.exitCode).toBe(0);
240
+
241
+ // Pull and verify the rename took effect
242
+ const pullProject = await createTestProject({ appId });
243
+ await runCli(['pull', 'schema', '--yes'], {
244
+ cwd: pullProject.dir,
245
+ env: {
246
+ INSTANT_CLI_AUTH_TOKEN: adminToken,
247
+ INSTANT_APP_ID: appId,
248
+ },
249
+ });
250
+
251
+ const pulled = await readFile(
252
+ join(pullProject.dir, 'instant.schema.ts'),
253
+ 'utf-8',
254
+ );
255
+ expect(pulled).toContain('name: i.string()');
256
+ expect(pulled).toContain('body: i.string()');
257
+ expect(pulled).not.toContain('title: i.string()');
258
+ await pullProject.cleanup();
259
+ } finally {
260
+ await project2.cleanup();
261
+ }
262
+ });
263
+ });
264
+
265
+ describe('push perms', () => {
266
+ it('succeeds gracefully when no perms file exists', async () => {
267
+ const { appId, adminToken } = await createTempApp();
268
+ const project = await createTestProject({ appId });
269
+
270
+ try {
271
+ const result = await runCli(['push', 'perms', '--yes'], {
272
+ cwd: project.dir,
273
+ env: {
274
+ INSTANT_CLI_AUTH_TOKEN: adminToken,
275
+ INSTANT_APP_ID: appId,
276
+ },
277
+ });
278
+
279
+ expect(result.exitCode).toBe(0);
280
+ } finally {
281
+ await project.cleanup();
282
+ }
283
+ });
284
+
285
+ it('pushes perms to a real app', async () => {
286
+ const { appId, adminToken } = await createTempApp();
287
+ const project = await createTestProject({
288
+ appId,
289
+ permsFile: PERMS_FILE,
290
+ });
291
+
292
+ try {
293
+ const result = await runCli(['push', 'perms', '--yes'], {
294
+ cwd: project.dir,
295
+ env: {
296
+ INSTANT_CLI_AUTH_TOKEN: adminToken,
297
+ INSTANT_APP_ID: appId,
298
+ },
299
+ });
300
+
301
+ expect(result.exitCode).toBe(0);
302
+ } finally {
303
+ await project.cleanup();
304
+ }
305
+ });
306
+ });
307
+
308
+ describe('push all', () => {
309
+ it('pushes both schema and perms', async () => {
310
+ const { appId, adminToken } = await createTempApp();
311
+ const project = await createTestProject({
312
+ appId,
313
+ schemaFile: SCHEMA_FILE,
314
+ permsFile: PERMS_FILE,
315
+ });
316
+
317
+ try {
318
+ const result = await runCli(['push', '--yes'], {
319
+ cwd: project.dir,
320
+ env: {
321
+ INSTANT_CLI_AUTH_TOKEN: adminToken,
322
+ INSTANT_APP_ID: appId,
323
+ },
324
+ });
325
+
326
+ expect(result.exitCode).toBe(0);
327
+ } finally {
328
+ await project.cleanup();
329
+ }
330
+ });
331
+ });
332
+
333
+ describe('pull', () => {
334
+ it('pulls schema from app with no user-defined entities', async () => {
335
+ const { appId, adminToken } = await createTempApp();
336
+ const project = await createTestProject({ appId });
337
+
338
+ try {
339
+ const result = await runCli(['pull', 'schema', '--yes'], {
340
+ cwd: project.dir,
341
+ env: {
342
+ INSTANT_CLI_AUTH_TOKEN: adminToken,
343
+ INSTANT_APP_ID: appId,
344
+ },
345
+ });
346
+
347
+ expect(result.exitCode).toBe(0);
348
+
349
+ const schemaContent = await readFile(
350
+ join(project.dir, 'instant.schema.ts'),
351
+ 'utf-8',
352
+ );
353
+ expect(schemaContent).toContain('i.schema');
354
+ expect(schemaContent).not.toContain('posts');
355
+ } finally {
356
+ await project.cleanup();
357
+ }
358
+ });
359
+ });
360
+
361
+ describe('schema roundtrip', () => {
362
+ it('push then pull produces matching schema', async () => {
363
+ const { appId, adminToken } = await createTempApp();
364
+ const pushProject = await createTestProject({
365
+ appId,
366
+ schemaFile: SCHEMA_FILE,
367
+ });
368
+ const pushResult = await runCli(['push', 'schema', '--yes'], {
369
+ cwd: pushProject.dir,
370
+ env: {
371
+ INSTANT_CLI_AUTH_TOKEN: adminToken,
372
+ INSTANT_APP_ID: appId,
373
+ },
374
+ });
375
+ expect(pushResult.exitCode).toBe(0);
376
+ await pushProject.cleanup();
377
+
378
+ const project = await createTestProject({ appId });
379
+
380
+ try {
381
+ const pullResult = await runCli(['pull', 'schema', '--yes'], {
382
+ cwd: project.dir,
383
+ env: {
384
+ INSTANT_CLI_AUTH_TOKEN: adminToken,
385
+ INSTANT_APP_ID: appId,
386
+ },
387
+ });
388
+ expect(pullResult.exitCode).toBe(0);
389
+
390
+ const pulled = await readFile(
391
+ join(project.dir, 'instant.schema.ts'),
392
+ 'utf-8',
393
+ );
394
+
395
+ expect(pulled).toContain('posts');
396
+ expect(pulled).toContain('comments');
397
+ expect(pulled).toContain('title: i.string()');
398
+ expect(pulled).toContain('body: i.string()');
399
+ expect(pulled).toContain('text: i.string()');
400
+ expect(pulled).toContain('postsComments');
401
+ } finally {
402
+ await project.cleanup();
403
+ }
404
+ });
405
+ });
406
+
407
+ describe('perms roundtrip', () => {
408
+ it('push then pull produces matching perms', async () => {
409
+ const { appId, adminToken } = await createTempApp();
410
+ const pushProject = await createTestProject({
411
+ appId,
412
+ permsFile: PERMS_FILE,
413
+ });
414
+ const pushResult = await runCli(['push', 'perms', '--yes'], {
415
+ cwd: pushProject.dir,
416
+ env: {
417
+ INSTANT_CLI_AUTH_TOKEN: adminToken,
418
+ INSTANT_APP_ID: appId,
419
+ },
420
+ });
421
+ expect(pushResult.exitCode).toBe(0);
422
+ await pushProject.cleanup();
423
+
424
+ const project = await createTestProject({ appId });
425
+
426
+ try {
427
+ await runCli(['pull', 'perms', '--yes'], {
428
+ cwd: project.dir,
429
+ env: {
430
+ INSTANT_CLI_AUTH_TOKEN: adminToken,
431
+ INSTANT_APP_ID: appId,
432
+ },
433
+ });
434
+
435
+ const pulled = await readFile(
436
+ join(project.dir, 'instant.perms.ts'),
437
+ 'utf-8',
438
+ );
439
+ expect(pulled).toContain('posts');
440
+ expect(pulled).toContain('view');
441
+ expect(pulled).toContain('"true"');
442
+ expect(pulled).toContain('create');
443
+ } finally {
444
+ await project.cleanup();
445
+ }
446
+ });
447
+ });
448
+
449
+ describe('pull all', () => {
450
+ it('pulls both schema and perms', async () => {
451
+ const { appId, adminToken } = await createTempApp();
452
+ const pushProject = await createTestProject({
453
+ appId,
454
+ schemaFile: SCHEMA_FILE,
455
+ permsFile: PERMS_FILE,
456
+ });
457
+ const pushResult = await runCli(['push', '--yes'], {
458
+ cwd: pushProject.dir,
459
+ env: {
460
+ INSTANT_CLI_AUTH_TOKEN: adminToken,
461
+ INSTANT_APP_ID: appId,
462
+ },
463
+ });
464
+ expect(pushResult.exitCode).toBe(0);
465
+ await pushProject.cleanup();
466
+
467
+ const project = await createTestProject({ appId });
468
+
469
+ try {
470
+ const result = await runCli(['pull', '--yes'], {
471
+ cwd: project.dir,
472
+ env: {
473
+ INSTANT_CLI_AUTH_TOKEN: adminToken,
474
+ INSTANT_APP_ID: appId,
475
+ },
476
+ });
477
+
478
+ expect(result.exitCode).toBe(0);
479
+
480
+ const schemaContent = await readFile(
481
+ join(project.dir, 'instant.schema.ts'),
482
+ 'utf-8',
483
+ );
484
+ expect(schemaContent).toContain('posts');
485
+
486
+ const permsContent = await readFile(
487
+ join(project.dir, 'instant.perms.ts'),
488
+ 'utf-8',
489
+ );
490
+ expect(permsContent).toContain('posts');
491
+ } finally {
492
+ await project.cleanup();
493
+ }
494
+ });
495
+ });
496
+
497
+ describe('info', () => {
498
+ it('shows version', async () => {
499
+ const result = await runCli(['info']);
500
+
501
+ expect(result.exitCode).toBe(0);
502
+ const output = result.stdout + result.stderr;
503
+ expect(output.toLowerCase()).toMatch(/version/i);
504
+ });
505
+
506
+ it('shows not logged in without token', async () => {
507
+ const result = await runCli(['info'], {
508
+ env: { INSTANT_CLI_AUTH_TOKEN: '' },
509
+ });
510
+
511
+ const output = result.stdout + result.stderr;
512
+ expect(output.toLowerCase()).toMatch(/not logged in/);
513
+ });
514
+ });
515
+
516
+ describe('logout', () => {
517
+ it('prints logged out message', async () => {
518
+ const result = await runCli(['logout']);
519
+
520
+ expect(result.exitCode).toBe(0);
521
+ const output = result.stdout + result.stderr;
522
+ expect(output.toLowerCase()).toMatch(/logged out/);
523
+ });
524
+ });
525
+
526
+ describe('claim', () => {
527
+ it('fails when not logged in', async () => {
528
+ const result = await runCli(['claim'], {
529
+ env: {
530
+ INSTANT_CLI_AUTH_TOKEN: '',
531
+ INSTANT_APP_ID: 'fake-app-id',
532
+ INSTANT_APP_ADMIN_TOKEN: 'fake-token',
533
+ },
534
+ });
535
+
536
+ expect(result.exitCode).not.toBe(0);
537
+ });
538
+
539
+ it('fails when no app ID in env', async () => {
540
+ const result = await runCli(['claim'], {
541
+ env: {
542
+ INSTANT_CLI_AUTH_TOKEN: 'some-token',
543
+ INSTANT_APP_ID: '',
544
+ INSTANT_APP_ADMIN_TOKEN: '',
545
+ },
546
+ });
547
+
548
+ expect(result.exitCode).not.toBe(0);
549
+ });
550
+ });
551
+ });
@@ -0,0 +1,133 @@
1
+ import { execFile } from 'child_process';
2
+ import { mkdtemp, writeFile, mkdir, rm } from 'fs/promises';
3
+ import { join, dirname } from 'path';
4
+ import { tmpdir } from 'os';
5
+ import { fileURLToPath } from 'url';
6
+
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ const CLI_BIN = join(__dirname, '../../bin/index.js');
9
+
10
+ const apiUrl = process.env.INSTANT_CLI_API_URI || 'https://api.instantdb.com';
11
+
12
+ // Temp directory used to sandbox CLI config (auth tokens, etc.)
13
+ // so tests never read or mutate the real user config on disk.
14
+ const sandboxHome = join(tmpdir(), 'instant-cli-e2e-home');
15
+
16
+ export type CliResult = {
17
+ stdout: string;
18
+ stderr: string;
19
+ exitCode: number;
20
+ };
21
+
22
+ export function runCli(
23
+ args: string[],
24
+ opts: {
25
+ env?: Record<string, string>;
26
+ cwd?: string;
27
+ } = {},
28
+ ): Promise<CliResult> {
29
+ return new Promise((resolve) => {
30
+ execFile(
31
+ process.execPath,
32
+ [CLI_BIN, ...args],
33
+ {
34
+ env: {
35
+ ...process.env,
36
+ INSTANT_CLI_API_URI: apiUrl,
37
+ DOTENV_CONFIG_PATH: '/dev/null',
38
+ INSTANT_CLI_AUTH_TOKEN: '',
39
+ HOME: sandboxHome,
40
+ XDG_CONFIG_HOME: join(sandboxHome, '.config'),
41
+ XDG_DATA_HOME: join(sandboxHome, '.local', 'share'),
42
+ ...opts.env,
43
+ },
44
+ cwd: opts.cwd,
45
+ timeout: 30_000,
46
+ },
47
+ (error, stdout, stderr) => {
48
+ resolve({
49
+ stdout: stdout?.toString() ?? '',
50
+ stderr: stderr?.toString() ?? '',
51
+ exitCode: error
52
+ ? typeof error.code === 'number'
53
+ ? error.code
54
+ : 1
55
+ : 0,
56
+ });
57
+ },
58
+ );
59
+ });
60
+ }
61
+
62
+ export type TestProject = {
63
+ dir: string;
64
+ cleanup: () => Promise<void>;
65
+ };
66
+
67
+ export async function createTestProject(
68
+ opts: {
69
+ appId?: string;
70
+ schemaFile?: string;
71
+ permsFile?: string;
72
+ } = {},
73
+ ): Promise<TestProject> {
74
+ const dir = await mkdtemp(join(tmpdir(), 'instant-cli-e2e-'));
75
+
76
+ await writeFile(
77
+ join(dir, 'package.json'),
78
+ JSON.stringify(
79
+ {
80
+ name: 'e2e-test-project',
81
+ version: '1.0.0',
82
+ dependencies: { '@instantdb/react': '^0.0.1' },
83
+ },
84
+ null,
85
+ 2,
86
+ ),
87
+ );
88
+
89
+ await mkdir(join(dir, 'node_modules', '@instantdb', 'react'), {
90
+ recursive: true,
91
+ });
92
+ await writeFile(
93
+ join(dir, 'node_modules', '@instantdb', 'react', 'package.json'),
94
+ JSON.stringify({ name: '@instantdb/react', version: '0.0.1' }),
95
+ );
96
+
97
+ if (opts.appId) {
98
+ await writeFile(join(dir, '.env'), `INSTANT_APP_ID=${opts.appId}\n`);
99
+ }
100
+
101
+ if (opts.schemaFile) {
102
+ await writeFile(join(dir, 'instant.schema.ts'), opts.schemaFile);
103
+ }
104
+
105
+ if (opts.permsFile) {
106
+ await writeFile(join(dir, 'instant.perms.ts'), opts.permsFile);
107
+ }
108
+
109
+ return {
110
+ dir,
111
+ async cleanup() {
112
+ await rm(dir, { recursive: true, force: true });
113
+ },
114
+ };
115
+ }
116
+
117
+ export async function createTempApp(title = 'cli-e2e-test'): Promise<{
118
+ appId: string;
119
+ adminToken: string;
120
+ }> {
121
+ const response = await fetch(`${apiUrl}/dash/apps/ephemeral`, {
122
+ method: 'POST',
123
+ headers: { 'Content-Type': 'application/json' },
124
+ body: JSON.stringify({ title }),
125
+ });
126
+ if (!response.ok) {
127
+ throw new Error(
128
+ `Failed to create ephemeral app: ${response.status} ${await response.text()}`,
129
+ );
130
+ }
131
+ const { app } = await response.json();
132
+ return { appId: app.id, adminToken: app['admin-token'] };
133
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "instant-cli",
3
3
  "type": "module",
4
- "version": "0.22.155",
4
+ "version": "0.22.156",
5
5
  "description": "Instant's CLI",
6
6
  "homepage": "https://github.com/instantdb/instant/tree/main/client/packages/cli",
7
7
  "repository": {
@@ -41,9 +41,9 @@
41
41
  "strip-ansi": "^7.1.2",
42
42
  "terminal-link": "^3.0.0",
43
43
  "unconfig": "^0.5.5",
44
- "@instantdb/core": "0.22.155",
45
- "@instantdb/platform": "0.22.155",
46
- "@instantdb/version": "0.22.155"
44
+ "@instantdb/core": "0.22.156",
45
+ "@instantdb/platform": "0.22.156",
46
+ "@instantdb/version": "0.22.156"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@babel/core": "^7.17.9",
@@ -58,7 +58,7 @@
58
58
  "scripts": {
59
59
  "build": "rm -rf dist; tsc -p tsconfig.json",
60
60
  "dev": "tsc -p tsconfig.json --watch --skipLibCheck --preserveWatchOutput | grep -v '^$'",
61
- "test": "vitest",
61
+ "test": "vitest --project unit",
62
62
  "test:ci": "vitest run",
63
63
  "publish-package": "pnpm pack && npm publish *.tgz --access public",
64
64
  "clean": "rm -rf dist"
@@ -0,0 +1,21 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ projects: [
6
+ {
7
+ test: {
8
+ name: 'unit',
9
+ include: ['**/*.test.ts'],
10
+ exclude: ['**/*.e2e.test.ts'],
11
+ },
12
+ },
13
+ {
14
+ test: {
15
+ name: 'e2e',
16
+ include: ['**/*.e2e.test.ts'],
17
+ },
18
+ },
19
+ ],
20
+ },
21
+ });