instant-cli 0.22.95-experimental.drewh-fix-expand-wrap.20385945911.1 → 0.22.95-experimental.surgical.20386112228.1

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.95-experimental.drewh-fix-expand-wrap.20385945911.1 build /home/runner/work/instant/instant/client/packages/cli
2
+ > instant-cli@0.22.95-experimental.surgical.20386112228.1 build /home/runner/work/instant/instant/client/packages/cli
3
3
  > rm -rf dist; tsc -p tsconfig.json
4
4
 
@@ -0,0 +1,135 @@
1
+ import { test, expect } from 'vitest';
2
+ import { i, schemaTypescriptFileToInstantSchema } from '@instantdb/platform';
3
+ import { updateSchemaFile } from '../src/util/updateSchemaFile';
4
+
5
+ test('preserves type annotations while adding entities', async () => {
6
+ const oldFile = `
7
+ import { i } from '@instantdb/core';
8
+ import { Label } from './types';
9
+
10
+ const _schema = i.schema({
11
+ entities: {
12
+ todos: i.entity({
13
+ title: i.string(),
14
+ status: i.string<'todo' | 'done'>(),
15
+ labels: i.json<Label[]>(),
16
+ }),
17
+ },
18
+ links: {},
19
+ rooms: {},
20
+ });
21
+
22
+ export default _schema;
23
+ `;
24
+
25
+ const serverSchema = i.schema({
26
+ entities: {
27
+ todos: i.entity({
28
+ title: i.string(),
29
+ status: i.string(),
30
+ labels: i.json(),
31
+ }),
32
+ projects: i.entity({
33
+ name: i.string(),
34
+ }),
35
+ },
36
+ links: {},
37
+ });
38
+
39
+ const localSchema = schemaTypescriptFileToInstantSchema(oldFile);
40
+ const result = await updateSchemaFile(oldFile, localSchema, serverSchema);
41
+
42
+ expect(result).toContain("status: i.string<'todo' | 'done'>()");
43
+ expect(result).toContain('labels: i.json<Label[]>()');
44
+ expect(result).toContain("import { Label } from './types';");
45
+ expect(result).toContain('projects: i.entity({');
46
+ });
47
+
48
+ test('removes deleted entities and attributes', async () => {
49
+ const oldFile = `
50
+ import { i } from '@instantdb/core';
51
+
52
+ const _schema = i.schema({
53
+ entities: {
54
+ todos: i.entity({
55
+ title: i.string(),
56
+ priority: i.number(),
57
+ }),
58
+ oldEntity: i.entity({
59
+ data: i.json(),
60
+ }),
61
+ },
62
+ links: {},
63
+ rooms: {},
64
+ });
65
+
66
+ export default _schema;
67
+ `;
68
+
69
+ const serverSchema = i.schema({
70
+ entities: {
71
+ todos: i.entity({
72
+ title: i.string(),
73
+ }),
74
+ },
75
+ links: {},
76
+ });
77
+
78
+ const localSchema = schemaTypescriptFileToInstantSchema(oldFile);
79
+ const result = await updateSchemaFile(oldFile, localSchema, serverSchema);
80
+
81
+ expect(result).not.toContain('oldEntity');
82
+ expect(result).not.toContain('priority: i.number()');
83
+ expect(result).toContain('title: i.string()');
84
+ });
85
+
86
+ test('updates constraints and adds links', async () => {
87
+ const oldFile = `
88
+ import { i } from '@instantdb/core';
89
+
90
+ const _schema = i.schema({
91
+ entities: {
92
+ todos: i.entity({
93
+ title: i.string(),
94
+ status: i.string<'todo' | 'done'>(),
95
+ }),
96
+ users: i.entity({
97
+ email: i.string(),
98
+ }),
99
+ },
100
+ links: {},
101
+ rooms: {},
102
+ });
103
+
104
+ export default _schema;
105
+ `;
106
+
107
+ const serverSchema = i.schema({
108
+ entities: {
109
+ todos: i.entity({
110
+ title: i.string().unique().indexed().optional(),
111
+ status: i.string(),
112
+ }),
113
+ users: i.entity({
114
+ email: i.string().unique(),
115
+ }),
116
+ },
117
+ links: {
118
+ todoOwner: {
119
+ forward: { on: 'todos', has: 'one', label: 'owner' },
120
+ reverse: { on: 'users', has: 'many', label: 'todos' },
121
+ },
122
+ },
123
+ });
124
+
125
+ const localSchema = schemaTypescriptFileToInstantSchema(oldFile);
126
+ const result = await updateSchemaFile(oldFile, localSchema, serverSchema);
127
+
128
+ expect(result).toContain('title: i.string().unique().indexed().optional()');
129
+ expect(result).toContain("status: i.string<'todo' | 'done'>()");
130
+ expect(result).toContain('todoOwner: {');
131
+ expect(result).toContain("on: 'todos'");
132
+ expect(result).toContain("label: 'owner'");
133
+ expect(result).toContain("on: 'users'");
134
+ expect(result).toContain("label: 'todos'");
135
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"AAo8DA,8EAQC;AA+ED;;;;;EAKE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"AA68DA,8EAQC;AA+ED;;;;;EAKE"}
package/dist/index.js CHANGED
@@ -10,7 +10,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  // @ts-check
11
11
  import { generatePermsTypescriptFile, apiSchemaToInstantSchemaDef, generateSchemaTypescriptFile, diffSchemas, convertTxSteps, validateSchema, SchemaValidationError, PlatformApi, } from '@instantdb/platform';
12
12
  import version from './version.js';
13
- import { existsSync } from 'fs';
14
13
  import { mkdir, writeFile, readFile, unlink } from 'fs/promises';
15
14
  import path, { join } from 'path';
16
15
  import { randomUUID } from 'crypto';
@@ -38,7 +37,7 @@ import { buildAutoRenameSelector } from './rename.js';
38
37
  import { loadEnv } from './util/loadEnv.js';
39
38
  import { isHeadlessEnvironment } from './util/isHeadlessEnvironment.js';
40
39
  import { getSchemaReadCandidates, getPermsReadCandidates, getSchemaPathToWrite, getPermsPathToWrite, } from './util/findConfigCandidates.js';
41
- import { mergeSchema } from './util/mergeSchema.js';
40
+ import { updateSchemaFile } from './util/updateSchemaFile.js';
42
41
  const execAsync = promisify(exec);
43
42
  loadEnv();
44
43
  const dev = Boolean(process.env.INSTANT_CLI_DEV);
@@ -354,7 +353,7 @@ program
354
353
  .argument('[schema|perms|all]', 'Which configuration to push. Defaults to `all`')
355
354
  .option('-a --app <app-id>', 'App ID to push to. Defaults to *_INSTANT_APP_ID in .env')
356
355
  .option('-p --package <react|react-native|core|admin>', 'Which package to automatically install if there is not one installed already.')
357
- .option('--experimental-type-preservation', "[Experimental] Preserve manual type changes like `status: i.json<'online' | 'offline'>()` when doing `instant-cli pull schema`")
356
+ .option('--experimental-type-preservation', '[Experimental] Preserve manual type changes and schema edits when pulling schema')
358
357
  .description('Pull schema and perm files from production.')
359
358
  .addHelpText('after', `
360
359
  Environment Variables:
@@ -1017,16 +1016,20 @@ function pullSchema(appId_1, _a) {
1017
1016
  }
1018
1017
  const shortSchemaPath = getSchemaPathToWrite(prev === null || prev === void 0 ? void 0 : prev.path);
1019
1018
  const schemaPath = join(pkgDir, shortSchemaPath);
1020
- let newSchemaContent = generateSchemaTypescriptFile(prev === null || prev === void 0 ? void 0 : prev.schema, apiSchemaToInstantSchemaDef(pullRes.data.schema), instantModuleName);
1019
+ const serverSchema = apiSchemaToInstantSchemaDef(pullRes.data.schema);
1020
+ let newSchemaContent;
1021
1021
  if (prev && experimentalTypePreservation) {
1022
1022
  try {
1023
1023
  const oldSchemaContent = yield readFile(prev.path, 'utf-8');
1024
- newSchemaContent = mergeSchema(oldSchemaContent, newSchemaContent);
1024
+ newSchemaContent = yield updateSchemaFile(oldSchemaContent, prev.schema, serverSchema);
1025
1025
  }
1026
1026
  catch (e) {
1027
- warn('Failed to merge schema with existing file. Overwriting instead.', e);
1027
+ warn('Failed to update schema with existing file. Overwriting instead.', e);
1028
1028
  }
1029
1029
  }
1030
+ if (!newSchemaContent) {
1031
+ newSchemaContent = generateSchemaTypescriptFile(prev === null || prev === void 0 ? void 0 : prev.schema, serverSchema, instantModuleName);
1032
+ }
1030
1033
  yield writeTypescript(schemaPath, newSchemaContent, 'utf-8');
1031
1034
  console.log('✅ Wrote schema to ' + shortSchemaPath);
1032
1035
  return { ok: true };