instant-cli 0.22.94 → 0.22.95-experimental.surgical.20385805945.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.94 build /home/runner/work/instant/instant/client/packages/cli
2
+ > instant-cli@0.22.95-experimental.surgical.20385805945.1 build /home/runner/work/instant/instant/client/packages/cli
3
3
  > rm -rf dist; tsc -p tsconfig.json
4
4
 
@@ -0,0 +1,149 @@
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(
41
+ oldFile,
42
+ localSchema,
43
+ serverSchema,
44
+ );
45
+
46
+ expect(result).toContain("status: i.string<'todo' | 'done'>()");
47
+ expect(result).toContain('labels: i.json<Label[]>()');
48
+ expect(result).toContain("import { Label } from './types';");
49
+ expect(result).toContain('projects: i.entity({');
50
+ });
51
+
52
+ test('removes deleted entities and attributes', async () => {
53
+ const oldFile = `
54
+ import { i } from '@instantdb/core';
55
+
56
+ const _schema = i.schema({
57
+ entities: {
58
+ todos: i.entity({
59
+ title: i.string(),
60
+ priority: i.number(),
61
+ }),
62
+ oldEntity: i.entity({
63
+ data: i.json(),
64
+ }),
65
+ },
66
+ links: {},
67
+ rooms: {},
68
+ });
69
+
70
+ export default _schema;
71
+ `;
72
+
73
+ const serverSchema = i.schema({
74
+ entities: {
75
+ todos: i.entity({
76
+ title: i.string(),
77
+ }),
78
+ },
79
+ links: {},
80
+ });
81
+
82
+ const localSchema = schemaTypescriptFileToInstantSchema(oldFile);
83
+ const result = await updateSchemaFile(
84
+ oldFile,
85
+ localSchema,
86
+ serverSchema,
87
+ );
88
+
89
+ expect(result).not.toContain('oldEntity');
90
+ expect(result).not.toContain('priority: i.number()');
91
+ expect(result).toContain('title: i.string()');
92
+ });
93
+
94
+ test('updates constraints and adds links', async () => {
95
+ const oldFile = `
96
+ import { i } from '@instantdb/core';
97
+
98
+ const _schema = i.schema({
99
+ entities: {
100
+ todos: i.entity({
101
+ title: i.string(),
102
+ status: i.string<'todo' | 'done'>(),
103
+ }),
104
+ users: i.entity({
105
+ email: i.string(),
106
+ }),
107
+ },
108
+ links: {},
109
+ rooms: {},
110
+ });
111
+
112
+ export default _schema;
113
+ `;
114
+
115
+ const serverSchema = i.schema({
116
+ entities: {
117
+ todos: i.entity({
118
+ title: i.string().unique().indexed().optional(),
119
+ status: i.string(),
120
+ }),
121
+ users: i.entity({
122
+ email: i.string().unique(),
123
+ }),
124
+ },
125
+ links: {
126
+ todoOwner: {
127
+ forward: { on: 'todos', has: 'one', label: 'owner' },
128
+ reverse: { on: 'users', has: 'many', label: 'todos' },
129
+ },
130
+ },
131
+ });
132
+
133
+ const localSchema = schemaTypescriptFileToInstantSchema(oldFile);
134
+ const result = await updateSchemaFile(
135
+ oldFile,
136
+ localSchema,
137
+ serverSchema,
138
+ );
139
+
140
+ expect(result).toContain(
141
+ 'title: i.string().unique().indexed().optional()',
142
+ );
143
+ expect(result).toContain("status: i.string<'todo' | 'done'>()");
144
+ expect(result).toContain('todoOwner: {');
145
+ expect(result).toContain("on: 'todos'");
146
+ expect(result).toContain("label: 'owner'");
147
+ expect(result).toContain("on: 'users'");
148
+ expect(result).toContain("label: 'todos'");
149
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"AAk7DA,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,6 +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';
40
+ import { updateSchemaFile } from './util/updateSchemaFile.js';
41
41
  const execAsync = promisify(exec);
42
42
  loadEnv();
43
43
  const dev = Boolean(process.env.INSTANT_CLI_DEV);
@@ -353,6 +353,7 @@ program
353
353
  .argument('[schema|perms|all]', 'Which configuration to push. Defaults to `all`')
354
354
  .option('-a --app <app-id>', 'App ID to push to. Defaults to *_INSTANT_APP_ID in .env')
355
355
  .option('-p --package <react|react-native|core|admin>', 'Which package to automatically install if there is not one installed already.')
356
+ .option('--experimental-type-preservation', '[Experimental] Preserve manual type changes and schema edits when pulling schema')
356
357
  .description('Pull schema and perm files from production.')
357
358
  .addHelpText('after', `
358
359
  Environment Variables:
@@ -504,7 +505,7 @@ function handlePull(bag, opts) {
504
505
  error('No app ID detected. Please specify one with --app or set up with `instant-cli init`');
505
506
  return;
506
507
  }
507
- yield pull(bag, appId, pkgAndAuthInfo);
508
+ yield pull(bag, appId, Object.assign(Object.assign({}, pkgAndAuthInfo), opts));
508
509
  });
509
510
  }
510
511
  function push(bag, appId, opts) {
@@ -988,7 +989,7 @@ function getOrPromptPackageAndAuthInfoWithErrorLogging(opts) {
988
989
  });
989
990
  }
990
991
  function pullSchema(appId_1, _a) {
991
- return __awaiter(this, arguments, void 0, function* (appId, { pkgDir, instantModuleName }) {
992
+ return __awaiter(this, arguments, void 0, function* (appId, { pkgDir, instantModuleName, experimentalTypePreservation }) {
992
993
  console.log('Pulling schema...');
993
994
  const pullRes = yield fetchJson({
994
995
  path: `/dash/apps/${appId}/schema/pull`,
@@ -1015,7 +1016,21 @@ function pullSchema(appId_1, _a) {
1015
1016
  }
1016
1017
  const shortSchemaPath = getSchemaPathToWrite(prev === null || prev === void 0 ? void 0 : prev.path);
1017
1018
  const schemaPath = join(pkgDir, shortSchemaPath);
1018
- yield writeTypescript(schemaPath, generateSchemaTypescriptFile(prev === null || prev === void 0 ? void 0 : prev.schema, apiSchemaToInstantSchemaDef(pullRes.data.schema), instantModuleName), 'utf-8');
1019
+ const serverSchema = apiSchemaToInstantSchemaDef(pullRes.data.schema);
1020
+ let newSchemaContent;
1021
+ if (prev && experimentalTypePreservation) {
1022
+ try {
1023
+ const oldSchemaContent = yield readFile(prev.path, 'utf-8');
1024
+ newSchemaContent = yield updateSchemaFile(oldSchemaContent, prev.schema, serverSchema);
1025
+ }
1026
+ catch (e) {
1027
+ warn('Failed to update schema with existing file. Overwriting instead.', e);
1028
+ }
1029
+ }
1030
+ if (!newSchemaContent) {
1031
+ newSchemaContent = generateSchemaTypescriptFile(prev === null || prev === void 0 ? void 0 : prev.schema, serverSchema, instantModuleName);
1032
+ }
1033
+ yield writeTypescript(schemaPath, newSchemaContent, 'utf-8');
1019
1034
  console.log('✅ Wrote schema to ' + shortSchemaPath);
1020
1035
  return { ok: true };
1021
1036
  });