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.
- package/.turbo/turbo-build.log +1 -1
- package/__tests__/updateSchemaFile.test.ts +149 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -4
- package/dist/index.js.map +1 -1
- package/dist/util/updateSchemaFile.d.ts +3 -0
- package/dist/util/updateSchemaFile.d.ts.map +1 -0
- package/dist/util/updateSchemaFile.js +531 -0
- package/dist/util/updateSchemaFile.js.map +1 -0
- package/package.json +6 -4
- package/src/index.js +37 -10
- package/src/util/updateSchemaFile.ts +666 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -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
|
+
});
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"
|
|
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
|
-
|
|
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
|
});
|