instant-cli 0.22.177 → 0.22.178
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 +2 -2
- package/__tests__/e2e/cli.e2e.test.ts +3 -3
- package/__tests__/e2e/helpers.ts +1 -1
- package/__tests__/effectHelpers.ts +45 -0
- package/__tests__/mergeSchema.test.ts +2 -2
- package/dist/commands/claim.d.ts +6 -0
- package/dist/commands/claim.d.ts.map +1 -0
- package/dist/commands/claim.js +22 -0
- package/dist/commands/claim.js.map +1 -0
- package/dist/commands/explorer.d.ts +6 -0
- package/dist/commands/explorer.d.ts.map +1 -0
- package/dist/commands/explorer.js +13 -0
- package/dist/commands/explorer.js.map +1 -0
- package/dist/commands/info.d.ts +3 -0
- package/dist/commands/info.d.ts.map +1 -0
- package/dist/commands/info.js +24 -0
- package/dist/commands/info.js.map +1 -0
- package/dist/commands/init.d.ts +5 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +39 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/initWithoutFiles.d.ts +6 -0
- package/dist/commands/initWithoutFiles.d.ts.map +1 -0
- package/dist/commands/initWithoutFiles.js +64 -0
- package/dist/commands/initWithoutFiles.js.map +1 -0
- package/dist/commands/login.d.ts +9 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +52 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +4 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +21 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/pull.d.ts +6 -0
- package/dist/commands/pull.d.ts.map +1 -0
- package/dist/commands/pull.js +16 -0
- package/dist/commands/pull.js.map +1 -0
- package/dist/commands/push.d.ts +6 -0
- package/dist/commands/push.d.ts.map +1 -0
- package/dist/commands/push.js +20 -0
- package/dist/commands/push.js.map +1 -0
- package/dist/commands/query.d.ts +7 -0
- package/dist/commands/query.d.ts.map +1 -0
- package/dist/commands/query.js +52 -0
- package/dist/commands/query.js.map +1 -0
- package/dist/context/authToken.d.ts +30 -0
- package/dist/context/authToken.d.ts.map +1 -0
- package/dist/context/authToken.js +86 -0
- package/dist/context/authToken.js.map +1 -0
- package/dist/context/currentApp.d.ts +37 -0
- package/dist/context/currentApp.d.ts.map +1 -0
- package/dist/context/currentApp.js +204 -0
- package/dist/context/currentApp.js.map +1 -0
- package/dist/context/globalOpts.d.ts +11 -0
- package/dist/context/globalOpts.d.ts.map +1 -0
- package/dist/context/globalOpts.js +13 -0
- package/dist/context/globalOpts.js.map +1 -0
- package/dist/context/platformApi.d.ts +19 -0
- package/dist/context/platformApi.d.ts.map +1 -0
- package/dist/context/platformApi.js +24 -0
- package/dist/context/platformApi.js.map +1 -0
- package/dist/context/projectInfo.d.ts +29 -0
- package/dist/context/projectInfo.d.ts.map +1 -0
- package/dist/context/projectInfo.js +149 -0
- package/dist/context/projectInfo.js.map +1 -0
- package/dist/errors.d.ts +10 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +6 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +41 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +169 -1781
- package/dist/index.js.map +1 -1
- package/dist/layer.d.ts +23 -0
- package/dist/layer.d.ts.map +1 -0
- package/dist/layer.js +68 -0
- package/dist/layer.js.map +1 -0
- package/dist/lib/createApp.d.ts +12 -0
- package/dist/lib/createApp.d.ts.map +1 -0
- package/dist/lib/createApp.js +15 -0
- package/dist/lib/createApp.js.map +1 -0
- package/dist/lib/handleEnv.d.ts +7 -0
- package/dist/lib/handleEnv.d.ts.map +1 -0
- package/dist/lib/handleEnv.js +91 -0
- package/dist/lib/handleEnv.js.map +1 -0
- package/dist/lib/http.d.ts +32 -0
- package/dist/lib/http.d.ts.map +1 -0
- package/dist/lib/http.js +67 -0
- package/dist/lib/http.js.map +1 -0
- package/dist/lib/login.d.ts +13 -0
- package/dist/lib/login.d.ts.map +1 -0
- package/dist/lib/login.js +39 -0
- package/dist/lib/login.js.map +1 -0
- package/dist/lib/pullPerms.d.ts +7 -0
- package/dist/lib/pullPerms.d.ts.map +1 -0
- package/dist/lib/pullPerms.js +41 -0
- package/dist/lib/pullPerms.js.map +1 -0
- package/dist/lib/pullSchema.d.ts +12 -0
- package/dist/lib/pullSchema.d.ts.map +1 -0
- package/dist/lib/pullSchema.js +62 -0
- package/dist/lib/pullSchema.js.map +1 -0
- package/dist/lib/pushPerms.d.ts +13 -0
- package/dist/lib/pushPerms.d.ts.map +1 -0
- package/dist/lib/pushPerms.js +54 -0
- package/dist/lib/pushPerms.js.map +1 -0
- package/dist/lib/pushSchema.d.ts +53 -0
- package/dist/lib/pushSchema.d.ts.map +1 -0
- package/dist/lib/pushSchema.js +160 -0
- package/dist/lib/pushSchema.js.map +1 -0
- package/dist/lib/ui.d.ts +16 -0
- package/dist/lib/ui.d.ts.map +1 -0
- package/dist/lib/ui.js +22 -0
- package/dist/lib/ui.js.map +1 -0
- package/dist/logging.d.ts +4 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +17 -0
- package/dist/logging.js.map +1 -0
- package/dist/old.d.ts +14 -0
- package/dist/old.d.ts.map +1 -0
- package/dist/old.js +417 -0
- package/dist/old.js.map +1 -0
- package/dist/program.d.ts +3 -0
- package/dist/program.d.ts.map +1 -0
- package/dist/program.js +3 -0
- package/dist/program.js.map +1 -0
- package/dist/renderSchemaPlan.d.ts +3 -3
- package/dist/renderSchemaPlan.d.ts.map +1 -1
- package/dist/renderSchemaPlan.js +2 -14
- package/dist/renderSchemaPlan.js.map +1 -1
- package/dist/ui/index.d.ts +4 -3
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +2 -2
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/lib.js +1 -0
- package/dist/ui/lib.js.map +1 -1
- package/dist/util/findConfigCandidates.d.ts +1 -1
- package/dist/util/findConfigCandidates.d.ts.map +1 -1
- package/dist/util/findConfigCandidates.js +1 -3
- package/dist/util/findConfigCandidates.js.map +1 -1
- package/dist/util/fs.d.ts +1 -1
- package/dist/util/fs.d.ts.map +1 -1
- package/dist/util/fs.js.map +1 -1
- package/dist/util/getAuthPaths.d.ts.map +1 -1
- package/dist/util/getAuthPaths.js.map +1 -1
- package/dist/util/isHeadlessEnvironment.d.ts +3 -1
- package/dist/util/isHeadlessEnvironment.d.ts.map +1 -1
- package/dist/util/isHeadlessEnvironment.js.map +1 -1
- package/dist/util/loadConfig.d.ts +1 -1
- package/dist/util/loadConfig.d.ts.map +1 -1
- package/dist/util/loadConfig.js +2 -2
- package/dist/util/loadConfig.js.map +1 -1
- package/dist/util/mergeSchema.d.ts +9 -1
- package/dist/util/mergeSchema.d.ts.map +1 -1
- package/dist/util/mergeSchema.js +4 -0
- package/dist/util/mergeSchema.js.map +1 -1
- package/dist/util/renamePrompt.d.ts +2 -1
- package/dist/util/renamePrompt.d.ts.map +1 -1
- package/dist/util/renamePrompt.js +1 -1
- package/dist/util/renamePrompt.js.map +1 -1
- package/package.json +17 -7
- package/src/commands/claim.ts +31 -0
- package/src/commands/explorer.ts +21 -0
- package/src/commands/info.ts +34 -0
- package/src/commands/init.ts +58 -0
- package/src/commands/initWithoutFiles.ts +107 -0
- package/src/commands/login.ts +76 -0
- package/src/commands/logout.ts +23 -0
- package/src/commands/pull.ts +23 -0
- package/src/commands/push.ts +25 -0
- package/src/commands/query.ts +61 -0
- package/src/context/authToken.ts +149 -0
- package/src/context/currentApp.ts +277 -0
- package/src/context/globalOpts.ts +22 -0
- package/src/context/platformApi.ts +35 -0
- package/src/context/projectInfo.ts +215 -0
- package/src/errors.ts +7 -0
- package/src/index.ts +428 -0
- package/src/layer.ts +155 -0
- package/src/lib/createApp.ts +28 -0
- package/src/lib/handleEnv.ts +115 -0
- package/src/lib/http.ts +148 -0
- package/src/lib/login.ts +54 -0
- package/src/lib/pullPerms.ts +50 -0
- package/src/lib/pullSchema.ts +95 -0
- package/src/lib/pushPerms.ts +80 -0
- package/src/lib/pushSchema.ts +240 -0
- package/src/lib/ui.ts +36 -0
- package/src/logging.ts +32 -0
- package/src/old.js +495 -0
- package/src/program.ts +3 -0
- package/src/renderSchemaPlan.ts +6 -18
- package/src/ui/index.ts +4 -3
- package/src/util/findConfigCandidates.ts +1 -2
- package/src/util/fs.ts +1 -1
- package/src/util/getAuthPaths.ts +1 -0
- package/src/util/isHeadlessEnvironment.ts +1 -1
- package/src/util/loadConfig.ts +3 -6
- package/src/util/{mergeSchema.js → mergeSchema.ts} +26 -16
- package/src/util/renamePrompt.ts +2 -1
- package/tsconfig.build.json +20 -0
- package/tsconfig.json +15 -5
- package/vitest.config.ts +2 -1
- package/dist/util/packageManager.d.ts +0 -3
- package/dist/util/packageManager.d.ts.map +0 -1
- package/dist/util/packageManager.js +0 -70
- package/dist/util/packageManager.js.map +0 -1
- package/dist/util/promptOk.d.ts +0 -4
- package/dist/util/promptOk.d.ts.map +0 -1
- package/dist/util/promptOk.js +0 -18
- package/dist/util/promptOk.js.map +0 -1
- package/src/index.js +0 -2333
- package/src/util/packageManager.js +0 -78
- package/src/util/promptOk.ts +0 -26
package/src/index.ts
ADDED
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
import { loadEnv } from './util/loadEnv.ts';
|
|
2
|
+
loadEnv();
|
|
3
|
+
|
|
4
|
+
import { Command, Option } from '@commander-js/extra-typings';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { Effect, Layer } from 'effect';
|
|
7
|
+
import version from './version.js';
|
|
8
|
+
import { initCommand } from './commands/init.ts';
|
|
9
|
+
import { initWithoutFilesCommand } from './commands/initWithoutFiles.ts';
|
|
10
|
+
import { loginCommand } from './commands/login.ts';
|
|
11
|
+
import { logoutCommand } from './commands/logout.ts';
|
|
12
|
+
import {
|
|
13
|
+
AuthLayerLive,
|
|
14
|
+
BaseLayerLive,
|
|
15
|
+
runCommandEffect,
|
|
16
|
+
WithAppLayer,
|
|
17
|
+
} from './layer.ts';
|
|
18
|
+
import { infoCommand } from './commands/info.ts';
|
|
19
|
+
import { pullCommand } from './commands/pull.ts';
|
|
20
|
+
import type { SchemaPermsOrBoth } from './commands/pull.ts';
|
|
21
|
+
import { claimCommand } from './commands/claim.ts';
|
|
22
|
+
import { pushCommand } from './commands/push.ts';
|
|
23
|
+
import { explorerCmd } from './commands/explorer.ts';
|
|
24
|
+
import { queryCmd } from './commands/query.ts';
|
|
25
|
+
import { program } from './program.ts';
|
|
26
|
+
import { PACKAGE_ALIAS_AND_FULL_NAMES } from './context/projectInfo.ts';
|
|
27
|
+
|
|
28
|
+
export type OptsFromCommand<C> =
|
|
29
|
+
C extends Command<any, infer R, any> ? R : never;
|
|
30
|
+
|
|
31
|
+
program
|
|
32
|
+
.name('instant-cli')
|
|
33
|
+
.addOption(globalOption('-t --token <token>', 'Auth token override'))
|
|
34
|
+
.addOption(globalOption('-y --yes', "Answer 'yes' to all prompts"))
|
|
35
|
+
.addOption(globalOption('--env <file>', 'Use a specific .env file'))
|
|
36
|
+
.addOption(
|
|
37
|
+
globalOption('-v --version', 'Print the version number', () => {
|
|
38
|
+
console.log(version);
|
|
39
|
+
process.exit(0);
|
|
40
|
+
}),
|
|
41
|
+
)
|
|
42
|
+
.addHelpOption(globalOption('-h --help', 'Print the help text for a command'))
|
|
43
|
+
.usage(`<command> ${chalk.dim('[options] [args]')}`);
|
|
44
|
+
|
|
45
|
+
// Command List
|
|
46
|
+
export const initDef = program
|
|
47
|
+
.command('init')
|
|
48
|
+
.description('Set up a new project.')
|
|
49
|
+
.option(
|
|
50
|
+
'-a --app <app-id>',
|
|
51
|
+
'If you have an existing app ID, we can pull schema and perms from there.',
|
|
52
|
+
)
|
|
53
|
+
.option(
|
|
54
|
+
'-p --package <react|react-native|core|admin|solid|svelte>',
|
|
55
|
+
'Which package to automatically install if there is not one installed already.',
|
|
56
|
+
)
|
|
57
|
+
.option('--title <title>', 'Title for the created app')
|
|
58
|
+
.action((options) => {
|
|
59
|
+
return runCommandEffect(
|
|
60
|
+
initCommand(options).pipe(
|
|
61
|
+
Effect.provide(
|
|
62
|
+
WithAppLayer({
|
|
63
|
+
coerce: true,
|
|
64
|
+
coerceAuth: true,
|
|
65
|
+
title: options.title,
|
|
66
|
+
appId: options.app,
|
|
67
|
+
packageName: options.package as any,
|
|
68
|
+
applyEnv: true,
|
|
69
|
+
}),
|
|
70
|
+
),
|
|
71
|
+
),
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
export const initWithoutFilesDef = program
|
|
76
|
+
.command('init-without-files')
|
|
77
|
+
.description('Generate a new app id and admin token pair without any files.')
|
|
78
|
+
.option('--title <title>', 'Title for the created app.')
|
|
79
|
+
.option(
|
|
80
|
+
'--org-id <org-id>',
|
|
81
|
+
'Organization id for app. Cannot be used with --temp flag.',
|
|
82
|
+
)
|
|
83
|
+
.option(
|
|
84
|
+
'--temp',
|
|
85
|
+
'Create a temporary app which will automatically delete itself after >24 hours.',
|
|
86
|
+
)
|
|
87
|
+
.action((opts) => {
|
|
88
|
+
return runCommandEffect(
|
|
89
|
+
initWithoutFilesCommand(opts).pipe(Effect.provide(BaseLayerLive)),
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
export const loginDef = program
|
|
94
|
+
.command('login')
|
|
95
|
+
.description('Log into your account')
|
|
96
|
+
.option('-p --print', 'Prints the auth token into the console.')
|
|
97
|
+
.option(
|
|
98
|
+
'--headless',
|
|
99
|
+
'Print the login URL instead of trying to open the browser',
|
|
100
|
+
)
|
|
101
|
+
.action(async (opts) => {
|
|
102
|
+
await runCommandEffect(
|
|
103
|
+
loginCommand(opts).pipe(Effect.provide(BaseLayerLive)),
|
|
104
|
+
);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
program
|
|
108
|
+
.command('logout')
|
|
109
|
+
.description('Log out of your Instant account')
|
|
110
|
+
.action(async () => {
|
|
111
|
+
return runCommandEffect(
|
|
112
|
+
logoutCommand().pipe(Effect.provide(BaseLayerLive)),
|
|
113
|
+
);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
export const infoDef = program
|
|
117
|
+
.command('info')
|
|
118
|
+
.description('Display CLI version and login status')
|
|
119
|
+
.action(async () => {
|
|
120
|
+
return runCommandEffect(
|
|
121
|
+
infoCommand().pipe(
|
|
122
|
+
Effect.provide(
|
|
123
|
+
AuthLayerLive({
|
|
124
|
+
coerce: false,
|
|
125
|
+
allowAdminToken: false,
|
|
126
|
+
}).pipe(Layer.catchAll(() => Layer.empty)), // make the auth layer optional
|
|
127
|
+
),
|
|
128
|
+
),
|
|
129
|
+
);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
export const explorerDef = program
|
|
133
|
+
.command('explorer')
|
|
134
|
+
.description('Opens the Explorer in your browser')
|
|
135
|
+
.option(
|
|
136
|
+
'-a --app <app-id>',
|
|
137
|
+
'App ID to open the explorer to. Defaults to *_INSTANT_APP_ID in .env',
|
|
138
|
+
)
|
|
139
|
+
.action(async (opts) => {
|
|
140
|
+
return runCommandEffect(
|
|
141
|
+
explorerCmd(opts).pipe(
|
|
142
|
+
Effect.provide(
|
|
143
|
+
WithAppLayer({
|
|
144
|
+
coerce: true,
|
|
145
|
+
coerceAuth: true,
|
|
146
|
+
appId: opts.app,
|
|
147
|
+
}),
|
|
148
|
+
),
|
|
149
|
+
),
|
|
150
|
+
);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
export const queryDef = program
|
|
154
|
+
.command('query')
|
|
155
|
+
.argument('<query>', 'InstaQL query as JSON/JSON5')
|
|
156
|
+
.option(
|
|
157
|
+
'-a --app <app-id>',
|
|
158
|
+
'App ID to query. Defaults to *_INSTANT_APP_ID in .env',
|
|
159
|
+
)
|
|
160
|
+
.option('--admin', 'Run the query as admin (bypasses permissions)')
|
|
161
|
+
.option('--as-email <email>', 'Run the query as a specific user by email')
|
|
162
|
+
.option('--as-guest', 'Run the query as an unauthenticated guest')
|
|
163
|
+
.option(
|
|
164
|
+
'--as-token <refresh-token>',
|
|
165
|
+
'Run the query as a user identified by refresh token',
|
|
166
|
+
)
|
|
167
|
+
.description('Run an InstaQL query against your app.')
|
|
168
|
+
.action(async function (queryArg, opts) {
|
|
169
|
+
return runCommandEffect(queryCmd(queryArg, opts));
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
export const pullDef = program
|
|
173
|
+
.command('pull')
|
|
174
|
+
.argument(
|
|
175
|
+
'[schema|perms|all]',
|
|
176
|
+
'Which configuration to pull. Defaults to `all`',
|
|
177
|
+
)
|
|
178
|
+
.option(
|
|
179
|
+
'-a --app <app-id>',
|
|
180
|
+
'App ID to pull to. Defaults to *_INSTANT_APP_ID in .env',
|
|
181
|
+
)
|
|
182
|
+
.option(
|
|
183
|
+
'-p --package <react|react-native|core|admin|solid|svelte>',
|
|
184
|
+
'Which package to automatically install if there is not one installed already.',
|
|
185
|
+
)
|
|
186
|
+
.option(
|
|
187
|
+
'--experimental-type-preservation',
|
|
188
|
+
"[Experimental] Preserve manual type changes like `status: i.json<'online' | 'offline'>()` when doing `instant-cli pull schema`",
|
|
189
|
+
)
|
|
190
|
+
.description('Pull schema and perm files from production.')
|
|
191
|
+
.addHelpText(
|
|
192
|
+
'after',
|
|
193
|
+
`
|
|
194
|
+
Environment Variables:
|
|
195
|
+
INSTANT_SCHEMA_FILE_PATH Override schema file location (default: instant.schema.ts)
|
|
196
|
+
INSTANT_PERMS_FILE_PATH Override perms file location (default: instant.perms.ts)
|
|
197
|
+
`,
|
|
198
|
+
)
|
|
199
|
+
.action(async function (arg, inputOpts) {
|
|
200
|
+
return runCommandEffect(
|
|
201
|
+
pullCommand(arg as SchemaPermsOrBoth, inputOpts).pipe(
|
|
202
|
+
Effect.provide(
|
|
203
|
+
WithAppLayer({
|
|
204
|
+
coerce: true,
|
|
205
|
+
packageName: inputOpts.package as
|
|
206
|
+
| 'react'
|
|
207
|
+
| 'react-native'
|
|
208
|
+
| 'core'
|
|
209
|
+
| 'admin'
|
|
210
|
+
| undefined,
|
|
211
|
+
appId: inputOpts.app,
|
|
212
|
+
}),
|
|
213
|
+
),
|
|
214
|
+
),
|
|
215
|
+
);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
export const pushDef = program
|
|
219
|
+
.command('push')
|
|
220
|
+
.argument(
|
|
221
|
+
'[schema|perms|all]',
|
|
222
|
+
'Which configuration to push. Defaults to `all`',
|
|
223
|
+
)
|
|
224
|
+
.option(
|
|
225
|
+
'-a --app <app-id>',
|
|
226
|
+
'App ID to push to. Defaults to *_INSTANT_APP_ID in .env',
|
|
227
|
+
)
|
|
228
|
+
.option(
|
|
229
|
+
'--skip-check-types',
|
|
230
|
+
"Don't check types on the server when pushing schema",
|
|
231
|
+
)
|
|
232
|
+
.option(
|
|
233
|
+
'--rename [renames...]',
|
|
234
|
+
'List of full attribute names separated by a ":"\n Example:`push --rename posts.author:posts.creator stores.owner:stores.manager`',
|
|
235
|
+
)
|
|
236
|
+
.option(
|
|
237
|
+
'-p --package <react|react-native|core|admin|solid|svelte>',
|
|
238
|
+
'Which package to automatically install if there is not one installed already.',
|
|
239
|
+
)
|
|
240
|
+
.description('Push schema and perm files to production.')
|
|
241
|
+
.addHelpText(
|
|
242
|
+
'after',
|
|
243
|
+
`
|
|
244
|
+
Environment Variables:
|
|
245
|
+
INSTANT_SCHEMA_FILE_PATH Override schema file location (default: instant.schema.ts)
|
|
246
|
+
INSTANT_PERMS_FILE_PATH Override perms file location (default: instant.perms.ts)
|
|
247
|
+
`,
|
|
248
|
+
)
|
|
249
|
+
.action(async function (arg, inputOpts) {
|
|
250
|
+
return runCommandEffect(
|
|
251
|
+
pushCommand(arg, inputOpts).pipe(
|
|
252
|
+
Effect.provide(
|
|
253
|
+
WithAppLayer({
|
|
254
|
+
coerce: false,
|
|
255
|
+
appId: inputOpts.app,
|
|
256
|
+
coerceLibraryInstall: true,
|
|
257
|
+
coerceAuth: false,
|
|
258
|
+
allowAdminToken: true,
|
|
259
|
+
applyEnv: true,
|
|
260
|
+
packageName:
|
|
261
|
+
inputOpts.package as keyof typeof PACKAGE_ALIAS_AND_FULL_NAMES,
|
|
262
|
+
}),
|
|
263
|
+
),
|
|
264
|
+
),
|
|
265
|
+
);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
export const claimDef = program
|
|
269
|
+
.command('claim')
|
|
270
|
+
.description('Transfer a temporary app into your Instant account')
|
|
271
|
+
.option(
|
|
272
|
+
'-a --app <app-id>',
|
|
273
|
+
'App to claim. Defaults to *_INSTANT_APP_ID in .env',
|
|
274
|
+
)
|
|
275
|
+
.action(async function (opts) {
|
|
276
|
+
return runCommandEffect(
|
|
277
|
+
claimCommand.pipe(
|
|
278
|
+
Effect.provide(
|
|
279
|
+
WithAppLayer({
|
|
280
|
+
coerce: false,
|
|
281
|
+
allowAdminToken: false,
|
|
282
|
+
appId: opts.app,
|
|
283
|
+
applyEnv: false,
|
|
284
|
+
}),
|
|
285
|
+
),
|
|
286
|
+
),
|
|
287
|
+
);
|
|
288
|
+
});
|
|
289
|
+
//// Program setup /////
|
|
290
|
+
|
|
291
|
+
function globalOption(
|
|
292
|
+
flags: string,
|
|
293
|
+
description?: string,
|
|
294
|
+
argParser?: (value: string, prev?: unknown) => unknown,
|
|
295
|
+
) {
|
|
296
|
+
const opt = new Option(flags, description);
|
|
297
|
+
if (argParser) {
|
|
298
|
+
opt.argParser(argParser);
|
|
299
|
+
}
|
|
300
|
+
// @ts-ignore
|
|
301
|
+
// __global does not exist on `Option`,
|
|
302
|
+
// but we use it in `getLocalAndGlobalOptions`, to produce
|
|
303
|
+
// our own custom list of local and global options.
|
|
304
|
+
// For more info, see the original PR:
|
|
305
|
+
// https://github.com/instantdb/instant/pull/505
|
|
306
|
+
opt.__global = true;
|
|
307
|
+
return opt;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function getLocalAndGlobalOptions(cmd: any, helper: any) {
|
|
311
|
+
const mixOfLocalAndGlobal = helper.visibleOptions(cmd);
|
|
312
|
+
const localOptionsFromMix = mixOfLocalAndGlobal.filter(
|
|
313
|
+
(option: any) => !option.__global,
|
|
314
|
+
);
|
|
315
|
+
const globalOptionsFromMix = mixOfLocalAndGlobal.filter(
|
|
316
|
+
(option: any) => option.__global,
|
|
317
|
+
);
|
|
318
|
+
const globalOptions = helper.visibleGlobalOptions(cmd);
|
|
319
|
+
|
|
320
|
+
return [localOptionsFromMix, globalOptionsFromMix.concat(globalOptions)];
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function formatHelp(
|
|
324
|
+
this: { showGlobalOptions: boolean },
|
|
325
|
+
cmd: any,
|
|
326
|
+
helper: any,
|
|
327
|
+
) {
|
|
328
|
+
const termWidth = helper.padWidth(cmd, helper);
|
|
329
|
+
const helpWidth = helper.helpWidth || 80;
|
|
330
|
+
const itemIndentWidth = 2;
|
|
331
|
+
const itemSeparatorWidth = 2; // between term and description
|
|
332
|
+
function formatItem(term: string, description: string | undefined) {
|
|
333
|
+
if (description) {
|
|
334
|
+
const fullText = `${term.padEnd(termWidth + itemSeparatorWidth)}${description}`;
|
|
335
|
+
return helper.wrap(
|
|
336
|
+
fullText,
|
|
337
|
+
helpWidth - itemIndentWidth,
|
|
338
|
+
termWidth + itemSeparatorWidth,
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
return term;
|
|
342
|
+
}
|
|
343
|
+
function formatList(textArray: string[]) {
|
|
344
|
+
return textArray.join('\n').replace(/^/gm, ' '.repeat(itemIndentWidth));
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Usage
|
|
348
|
+
let output = [`${helper.commandUsage(cmd)}`, ''];
|
|
349
|
+
|
|
350
|
+
// Description
|
|
351
|
+
const commandDescription = helper.commandDescription(cmd);
|
|
352
|
+
if (commandDescription.length > 0) {
|
|
353
|
+
output = output.concat([helper.wrap(commandDescription, helpWidth, 0), '']);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Arguments
|
|
357
|
+
const argumentList = helper.visibleArguments(cmd).map((argument: any) => {
|
|
358
|
+
return formatItem(
|
|
359
|
+
helper.argumentTerm(argument),
|
|
360
|
+
helper.argumentDescription(argument),
|
|
361
|
+
);
|
|
362
|
+
});
|
|
363
|
+
if (argumentList.length > 0) {
|
|
364
|
+
output = output.concat([
|
|
365
|
+
chalk.dim.bold('Arguments'),
|
|
366
|
+
formatList(argumentList),
|
|
367
|
+
'',
|
|
368
|
+
]);
|
|
369
|
+
}
|
|
370
|
+
const [visibleOptions, visibleGlobalOptions] = getLocalAndGlobalOptions(
|
|
371
|
+
cmd,
|
|
372
|
+
helper,
|
|
373
|
+
);
|
|
374
|
+
|
|
375
|
+
// Options
|
|
376
|
+
const optionList = visibleOptions.map((option: any) => {
|
|
377
|
+
return formatItem(
|
|
378
|
+
helper.optionTerm(option),
|
|
379
|
+
helper.optionDescription(option),
|
|
380
|
+
);
|
|
381
|
+
});
|
|
382
|
+
if (optionList.length > 0) {
|
|
383
|
+
output = output.concat([
|
|
384
|
+
chalk.dim.bold('Options'),
|
|
385
|
+
formatList(optionList),
|
|
386
|
+
'',
|
|
387
|
+
]);
|
|
388
|
+
}
|
|
389
|
+
// Commands
|
|
390
|
+
const commandList = helper.visibleCommands(cmd).map((cmd: any) => {
|
|
391
|
+
return formatItem(
|
|
392
|
+
helper.subcommandTerm(cmd),
|
|
393
|
+
helper.subcommandDescription(cmd),
|
|
394
|
+
);
|
|
395
|
+
});
|
|
396
|
+
if (commandList.length > 0) {
|
|
397
|
+
output = output.concat([
|
|
398
|
+
chalk.dim.bold('Commands'),
|
|
399
|
+
formatList(commandList),
|
|
400
|
+
'',
|
|
401
|
+
]);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (this.showGlobalOptions) {
|
|
405
|
+
const globalOptionList = visibleGlobalOptions.map((option: any) => {
|
|
406
|
+
return formatItem(
|
|
407
|
+
helper.optionTerm(option),
|
|
408
|
+
helper.optionDescription(option),
|
|
409
|
+
);
|
|
410
|
+
});
|
|
411
|
+
if (globalOptionList.length > 0) {
|
|
412
|
+
output = output.concat([
|
|
413
|
+
chalk.dim.bold('Global Options'),
|
|
414
|
+
formatList(globalOptionList),
|
|
415
|
+
'',
|
|
416
|
+
]);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
return output.join('\n');
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
program.configureHelp({
|
|
424
|
+
showGlobalOptions: true,
|
|
425
|
+
formatHelp,
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
program.parse(process.argv);
|
package/src/layer.ts
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { NodeContext, NodeHttpClient } from '@effect/platform-node';
|
|
2
|
+
import { Cause, Effect, Layer, ManagedRuntime } from 'effect';
|
|
3
|
+
import { AuthTokenLive } from './context/authToken.ts';
|
|
4
|
+
import { CurrentAppLive } from './context/currentApp.ts';
|
|
5
|
+
import { GlobalOptsLive } from './context/globalOpts.ts';
|
|
6
|
+
import { PlatformApi } from './context/platformApi.ts';
|
|
7
|
+
import {
|
|
8
|
+
PACKAGE_ALIAS_AND_FULL_NAMES,
|
|
9
|
+
ProjectInfoLive,
|
|
10
|
+
} from './context/projectInfo.ts';
|
|
11
|
+
import {
|
|
12
|
+
InstantHttpAuthedLive,
|
|
13
|
+
InstantHttpError,
|
|
14
|
+
InstantHttpLive,
|
|
15
|
+
} from './lib/http.ts';
|
|
16
|
+
import { SimpleLogLayer } from './logging.ts';
|
|
17
|
+
|
|
18
|
+
const runtime = ManagedRuntime.make(SimpleLogLayer);
|
|
19
|
+
|
|
20
|
+
export const runCommandEffect = <A, E, R extends never>(
|
|
21
|
+
effect: Effect.Effect<A, E, R>,
|
|
22
|
+
): Promise<A> => runtime.runPromise(effect.pipe(printRedErrors) as any);
|
|
23
|
+
|
|
24
|
+
export const printRedErrors = Effect.catchAllCause((cause) =>
|
|
25
|
+
Effect.gen(function* () {
|
|
26
|
+
const failure = Cause.failureOption(cause);
|
|
27
|
+
|
|
28
|
+
// This should never happen because the catchAllCause should only fire when there IS a failure
|
|
29
|
+
if (failure._tag !== 'Some') {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const theError = failure.value;
|
|
34
|
+
|
|
35
|
+
// Special error handling for specific error types
|
|
36
|
+
if (theError instanceof InstantHttpError) {
|
|
37
|
+
if (theError?.message) {
|
|
38
|
+
yield* Effect.logError(
|
|
39
|
+
'Error making request to Instant API: ' + theError.message,
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
if (Array.isArray(theError?.hint?.errors)) {
|
|
43
|
+
for (const err of theError.hint.errors) {
|
|
44
|
+
yield* Effect.logError(
|
|
45
|
+
`${err.in ? err.in.join('->') + ': ' : ''}${err.message}`,
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Print just the message if the error has a message attribute and no cause
|
|
53
|
+
if (
|
|
54
|
+
typeof failure.value === 'object' &&
|
|
55
|
+
failure.value !== null &&
|
|
56
|
+
'message' in failure.value &&
|
|
57
|
+
typeof failure.value.message === 'string' &&
|
|
58
|
+
!('cause' in failure.value)
|
|
59
|
+
) {
|
|
60
|
+
return yield* Effect.logError(failure.value.message).pipe(
|
|
61
|
+
Effect.tap(() => {
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}),
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return yield* Effect.logError(
|
|
68
|
+
Cause.pretty(cause, { renderErrorCause: true }),
|
|
69
|
+
).pipe(
|
|
70
|
+
Effect.tap(() => {
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}),
|
|
73
|
+
);
|
|
74
|
+
}),
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Note:
|
|
79
|
+
Avoid Duplicate Layer Creation
|
|
80
|
+
|
|
81
|
+
Layers are memoized using reference equality. Therefore, if you have a layer that is created by calling a function like f(), you should only call that f once and re-use the resulting layer so that you are always using the same instance.
|
|
82
|
+
*/
|
|
83
|
+
|
|
84
|
+
// TODO: make coerce param work for auth too
|
|
85
|
+
|
|
86
|
+
// Base layers
|
|
87
|
+
const AuthTokenLayer = ({
|
|
88
|
+
allowAdminToken = true,
|
|
89
|
+
coerce = false,
|
|
90
|
+
}: {
|
|
91
|
+
allowAdminToken: boolean;
|
|
92
|
+
coerce: boolean;
|
|
93
|
+
}) =>
|
|
94
|
+
Layer.provide(AuthTokenLive({ allowAdminToken, coerce }), NodeContext.layer);
|
|
95
|
+
|
|
96
|
+
const InstantHttpLayer = Layer.provide(InstantHttpLive, NodeHttpClient.layer);
|
|
97
|
+
|
|
98
|
+
// Unauthenticated layer with InstantHttp + PlatformApi + GlobalOpts + NodeContext
|
|
99
|
+
export const BaseLayerLive = Layer.provideMerge(
|
|
100
|
+
Layer.mergeAll(InstantHttpLayer, PlatformApi.Default, GlobalOptsLive),
|
|
101
|
+
NodeContext.layer,
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
// Authenticated layer extends BaseLayerLive with InstantHttpAuthed
|
|
105
|
+
export const AuthLayerLive = ({
|
|
106
|
+
allowAdminToken = true,
|
|
107
|
+
coerce = false,
|
|
108
|
+
}: {
|
|
109
|
+
allowAdminToken: boolean;
|
|
110
|
+
coerce: boolean;
|
|
111
|
+
}) =>
|
|
112
|
+
Layer.provideMerge(
|
|
113
|
+
Layer.provideMerge(
|
|
114
|
+
InstantHttpAuthedLive,
|
|
115
|
+
Layer.merge(
|
|
116
|
+
AuthTokenLayer({ allowAdminToken, coerce }),
|
|
117
|
+
InstantHttpLayer,
|
|
118
|
+
),
|
|
119
|
+
),
|
|
120
|
+
BaseLayerLive,
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
export const WithAppLayer = (args: {
|
|
124
|
+
appId?: string;
|
|
125
|
+
title?: string;
|
|
126
|
+
coerce: boolean;
|
|
127
|
+
coerceAuth?: boolean;
|
|
128
|
+
coerceLibraryInstall?: boolean;
|
|
129
|
+
packageName?: keyof typeof PACKAGE_ALIAS_AND_FULL_NAMES;
|
|
130
|
+
allowAdminToken?: boolean;
|
|
131
|
+
applyEnv?: boolean;
|
|
132
|
+
}) =>
|
|
133
|
+
Layer.mergeAll(
|
|
134
|
+
CurrentAppLive({
|
|
135
|
+
coerce: args.coerce,
|
|
136
|
+
appId: args.appId,
|
|
137
|
+
title: args.title,
|
|
138
|
+
applyEnv: args.applyEnv,
|
|
139
|
+
}),
|
|
140
|
+
).pipe(
|
|
141
|
+
Layer.provideMerge(
|
|
142
|
+
AuthLayerLive({
|
|
143
|
+
allowAdminToken:
|
|
144
|
+
args.allowAdminToken !== undefined ? args.allowAdminToken : true,
|
|
145
|
+
coerce: args.coerceAuth ?? false,
|
|
146
|
+
}),
|
|
147
|
+
),
|
|
148
|
+
Layer.provideMerge(
|
|
149
|
+
ProjectInfoLive(
|
|
150
|
+
args.coerceLibraryInstall ?? args.coerce,
|
|
151
|
+
args.packageName,
|
|
152
|
+
),
|
|
153
|
+
),
|
|
154
|
+
Layer.provideMerge(BaseLayerLive),
|
|
155
|
+
);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { randomUUID } from 'crypto';
|
|
2
|
+
import { Data, Effect, Schema } from 'effect';
|
|
3
|
+
import { InstantHttpAuthed } from './http.ts';
|
|
4
|
+
import { HttpClientRequest, HttpClientResponse } from '@effect/platform';
|
|
5
|
+
|
|
6
|
+
export class CreateAppError extends Data.TaggedError('CreateAppError')<{
|
|
7
|
+
message: string;
|
|
8
|
+
}> {}
|
|
9
|
+
|
|
10
|
+
export const createApp = Effect.fn(
|
|
11
|
+
function* (title: string, orgId?: string) {
|
|
12
|
+
const http = yield* InstantHttpAuthed;
|
|
13
|
+
const id = randomUUID();
|
|
14
|
+
const token = randomUUID();
|
|
15
|
+
const app = { id, title, admin_token: token, org_id: orgId };
|
|
16
|
+
|
|
17
|
+
const res = yield* HttpClientRequest.post('/dash/apps').pipe(
|
|
18
|
+
HttpClientRequest.bodyJson(app),
|
|
19
|
+
Effect.flatMap(http.execute),
|
|
20
|
+
Effect.flatMap(HttpClientResponse.schemaBodyJson(Schema.Any)),
|
|
21
|
+
);
|
|
22
|
+
return res;
|
|
23
|
+
},
|
|
24
|
+
Effect.catchTag(
|
|
25
|
+
'HttpBodyError',
|
|
26
|
+
(e) => new CreateAppError({ message: 'Error constructing http body' }),
|
|
27
|
+
),
|
|
28
|
+
);
|