@wirechunk/cli 0.0.1 → 0.0.3
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/build/main.js +3821 -281
- package/package.json +6 -1
- package/src/commands/bootstrap.ts +1 -1
- package/src/commands/create-extension-version.ts +56 -109
- package/src/commands/ext-dev/{db-connect-info.ts → get-db-url.ts} +3 -3
- package/src/commands/ext-dev/init-db.ts +3 -2
- package/src/core-api/api.ts +4248 -0
- package/src/core-api/mutations/create-extension-version.generated.ts +96 -0
- package/src/core-api/mutations/create-extension-version.graphql +14 -0
- package/src/core-api/operations.ts +23 -0
- package/src/main.ts +9 -5
- package/src/users/permissions.ts +2 -2
- package/tsconfig.json +4 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wirechunk/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -19,17 +19,22 @@
|
|
|
19
19
|
"bin": {
|
|
20
20
|
"wirechunk": "build/main.js"
|
|
21
21
|
},
|
|
22
|
+
"imports": {
|
|
23
|
+
"#api": "./src/core-api/api.ts"
|
|
24
|
+
},
|
|
22
25
|
"dependencies": {
|
|
23
26
|
"argon2": "^0.41.1"
|
|
24
27
|
},
|
|
25
28
|
"devDependencies": {
|
|
26
29
|
"@commander-js/extra-typings": "^13.0.0",
|
|
30
|
+
"@graphql-typed-document-node/core": "^3.2.0",
|
|
27
31
|
"@types/archiver": "^6.0.3",
|
|
28
32
|
"@wirechunk/backend-lib": "0.0.0",
|
|
29
33
|
"@wirechunk/lib": "0.0.0",
|
|
30
34
|
"archiver": "^7.0.1",
|
|
31
35
|
"chalk": "^5.3.0",
|
|
32
36
|
"commander": "^13.0.0",
|
|
37
|
+
"graphql-request": "^7.1.2",
|
|
33
38
|
"slonik": "^46.3.0",
|
|
34
39
|
"slonik-interceptor-query-logging": "^46.3.0",
|
|
35
40
|
"zod": "^3.24.1"
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { cleanTinyId } from '@wirechunk/lib/clean-small-id.ts';
|
|
3
|
+
import { normalizeDomain } from '@wirechunk/lib/domains.ts';
|
|
3
4
|
import { normalizeEmailAddress } from '@wirechunk/lib/emails.ts';
|
|
4
5
|
import {
|
|
5
6
|
defaultFormattedDataTemplate,
|
|
6
7
|
defaultNotificationEmailBodyTemplate,
|
|
7
8
|
} from '@wirechunk/lib/mixer/form-formatting-templates.ts';
|
|
8
|
-
import { normalizeDomain } from '@wirechunk/server/site-domains/util.ts';
|
|
9
9
|
import type { DatabasePool } from 'slonik';
|
|
10
10
|
import { createPool, sql } from 'slonik';
|
|
11
11
|
import type { Env } from '../env.ts';
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { parseEnv } from 'node:util';
|
|
1
4
|
import { requireValidExtensionDir } from '@wirechunk/backend-lib/extensions/require-extension-dir.ts';
|
|
2
5
|
import { parseErrorMessage } from '@wirechunk/lib/errors.ts';
|
|
3
6
|
import archiver from 'archiver';
|
|
4
|
-
import {
|
|
7
|
+
import { GraphQLClient } from 'graphql-request';
|
|
8
|
+
import { createExtensionVersion as createExtensionVersionRequest } from '../core-api/operations.ts';
|
|
5
9
|
import type { Env } from '../env.ts';
|
|
6
10
|
import { requireApiToken } from '../env.ts';
|
|
7
11
|
import type { WithGlobalOptions } from '../global-options.js';
|
|
@@ -16,44 +20,21 @@ const bytesFormat = Intl.NumberFormat('en', {
|
|
|
16
20
|
maximumFractionDigits: 1,
|
|
17
21
|
});
|
|
18
22
|
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
message: z.string(),
|
|
30
|
-
}),
|
|
31
|
-
z.object({
|
|
32
|
-
__typename: z.literal('GenericInternalError'),
|
|
33
|
-
message: z.string(),
|
|
34
|
-
}),
|
|
35
|
-
z.object({
|
|
36
|
-
__typename: z.literal('GenericUserError'),
|
|
37
|
-
message: z.string(),
|
|
38
|
-
}),
|
|
39
|
-
]);
|
|
40
|
-
|
|
41
|
-
const graphQlErrorSchema = z.object({
|
|
42
|
-
message: z.string(),
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
const createExtensionVersionResultSchema = z.object({
|
|
46
|
-
errors: z.array(graphQlErrorSchema).optional().nullable(),
|
|
47
|
-
data: z
|
|
48
|
-
.object({
|
|
49
|
-
createExtensionVersion: createExtensionVersionResultDataSchema,
|
|
50
|
-
})
|
|
51
|
-
.nullable(),
|
|
52
|
-
});
|
|
23
|
+
const ignoreGlobs = [
|
|
24
|
+
'**/.git/**/*',
|
|
25
|
+
'.git/**/*',
|
|
26
|
+
'eslint.config.js',
|
|
27
|
+
'**/eslint.config.js',
|
|
28
|
+
'node_modules/**/*',
|
|
29
|
+
'**/node_modules/**/*',
|
|
30
|
+
'yalc.lock',
|
|
31
|
+
'**/yalc.lock',
|
|
32
|
+
];
|
|
53
33
|
|
|
54
34
|
type CreateExtensionVersionOptions = {
|
|
55
35
|
extensionId?: string;
|
|
56
36
|
versionName: string;
|
|
37
|
+
configFile?: string;
|
|
57
38
|
};
|
|
58
39
|
|
|
59
40
|
export const createExtensionVersion = async (
|
|
@@ -63,33 +44,47 @@ export const createExtensionVersion = async (
|
|
|
63
44
|
const extensionId = requireExtensionIdOptionOrEnvVar(opts, env);
|
|
64
45
|
const apiToken = requireApiToken(env);
|
|
65
46
|
const cwd = process.cwd();
|
|
66
|
-
const
|
|
47
|
+
const { manifest } = await requireValidExtensionDir(cwd);
|
|
67
48
|
let enableServer: boolean;
|
|
68
49
|
let enableDb: boolean;
|
|
69
|
-
if (
|
|
70
|
-
enableServer = !!
|
|
71
|
-
if (
|
|
50
|
+
if (manifest.server) {
|
|
51
|
+
enableServer = !!manifest.server.enable;
|
|
52
|
+
if (manifest.server.database?.enable && manifest.server.enable === false) {
|
|
72
53
|
// Server was explicitly disabled, so don't allow database.
|
|
73
54
|
console.warn('WARNING: Automatically disabling database because server is disabled');
|
|
74
55
|
enableDb = false;
|
|
75
|
-
} else if (
|
|
56
|
+
} else if (manifest.server.database?.enable && !manifest.server.enable) {
|
|
76
57
|
// Server was unspecified, so enable it because database is enabled.
|
|
77
58
|
console.warn('WARNING: Automatically enabling server because database is enabled');
|
|
78
59
|
enableServer = true;
|
|
79
60
|
enableDb = true;
|
|
80
61
|
} else {
|
|
81
|
-
enableDb = !!
|
|
62
|
+
enableDb = !!manifest.server.database?.enable;
|
|
82
63
|
}
|
|
83
64
|
} else {
|
|
84
65
|
enableServer = false;
|
|
85
66
|
enableDb = false;
|
|
86
67
|
}
|
|
68
|
+
let config: Record<string, string> | null = null;
|
|
69
|
+
if (opts.configFile) {
|
|
70
|
+
const configFilePath = resolve(cwd, opts.configFile);
|
|
71
|
+
if (opts.verbose) {
|
|
72
|
+
console.log(`Loading config file ${configFilePath}`);
|
|
73
|
+
}
|
|
74
|
+
const configFile = await readFile(configFilePath, 'utf8');
|
|
75
|
+
try {
|
|
76
|
+
config = parseEnv(configFile) as Record<string, string>;
|
|
77
|
+
} catch (e) {
|
|
78
|
+
console.error(`Failed to parse config file at ${configFilePath}:`, parseErrorMessage(e));
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
87
82
|
|
|
88
83
|
const { versionName } = opts;
|
|
89
84
|
console.log(`Creating extension version ${versionName} (Extension ID ${extensionId})
|
|
90
85
|
Server: ${enableServer ? 'enabled' : 'disabled'}
|
|
91
86
|
Database: ${enableDb ? 'enabled' : 'disabled'}
|
|
92
|
-
Components: ${Object.keys(
|
|
87
|
+
Components: ${Object.keys(manifest.components ?? {}).length}`);
|
|
93
88
|
|
|
94
89
|
let extensionVersionId: string;
|
|
95
90
|
let signedUrl: string;
|
|
@@ -98,69 +93,28 @@ export const createExtensionVersion = async (
|
|
|
98
93
|
if (opts.verbose) {
|
|
99
94
|
console.log(`POST ${url}`);
|
|
100
95
|
}
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
... on CreateExtensionVersionSuccessResult {
|
|
113
|
-
extensionVersion {
|
|
114
|
-
id
|
|
115
|
-
}
|
|
116
|
-
signedUrl
|
|
117
|
-
}
|
|
118
|
-
... on Error {
|
|
119
|
-
message
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
`,
|
|
124
|
-
variables: {
|
|
125
|
-
input: {
|
|
126
|
-
extensionId,
|
|
127
|
-
extensionName: extConfig.name,
|
|
128
|
-
versionName,
|
|
129
|
-
enableServer,
|
|
130
|
-
enableDb,
|
|
131
|
-
},
|
|
96
|
+
const result = await createExtensionVersionRequest({
|
|
97
|
+
client: new GraphQLClient(url),
|
|
98
|
+
variables: {
|
|
99
|
+
input: {
|
|
100
|
+
extensionId,
|
|
101
|
+
extensionName: manifest.name,
|
|
102
|
+
versionName,
|
|
103
|
+
manifest: JSON.stringify(manifest),
|
|
104
|
+
enableServer,
|
|
105
|
+
enableDb,
|
|
106
|
+
config: config ? JSON.stringify(config) : undefined,
|
|
132
107
|
},
|
|
133
|
-
}
|
|
108
|
+
},
|
|
109
|
+
sessionAuthToken: apiToken,
|
|
134
110
|
});
|
|
135
|
-
if (
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const data = await createResult.json();
|
|
139
|
-
console.error(`${message}:`, parseErrorMessage(data));
|
|
140
|
-
process.exit(1);
|
|
141
|
-
} catch {
|
|
142
|
-
console.error(message);
|
|
143
|
-
process.exit(1);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
const data = await createResult.json();
|
|
147
|
-
const parseResult = createExtensionVersionResultSchema.safeParse(data);
|
|
148
|
-
if (!parseResult.success) {
|
|
149
|
-
console.error('Failed to create an extension version:', parseResult.error.message);
|
|
150
|
-
process.exit(1);
|
|
151
|
-
}
|
|
152
|
-
const result = parseResult.data;
|
|
153
|
-
if (result.errors) {
|
|
154
|
-
console.error('Failed to create an extension version:', parseErrorMessage(result));
|
|
155
|
-
process.exit(1);
|
|
156
|
-
}
|
|
157
|
-
if (result.data?.createExtensionVersion.__typename === 'CreateExtensionVersionSuccessResult') {
|
|
158
|
-
extensionVersionId = result.data.createExtensionVersion.extensionVersion.id;
|
|
159
|
-
signedUrl = result.data.createExtensionVersion.signedUrl;
|
|
111
|
+
if (result.createExtensionVersion.__typename === 'CreateExtensionVersionSuccessResult') {
|
|
112
|
+
extensionVersionId = result.createExtensionVersion.extensionVersion.id;
|
|
113
|
+
signedUrl = result.createExtensionVersion.signedUrl;
|
|
160
114
|
} else {
|
|
161
115
|
console.error(
|
|
162
|
-
`Failed to create an extension version (${result.
|
|
163
|
-
|
|
116
|
+
`Failed to create an extension version (${result.createExtensionVersion.__typename}):`,
|
|
117
|
+
result.createExtensionVersion.message,
|
|
164
118
|
);
|
|
165
119
|
process.exit(1);
|
|
166
120
|
}
|
|
@@ -197,14 +151,7 @@ export const createExtensionVersion = async (
|
|
|
197
151
|
|
|
198
152
|
archive.glob('**/*', {
|
|
199
153
|
cwd,
|
|
200
|
-
ignore:
|
|
201
|
-
'**/.git/**/*',
|
|
202
|
-
'.git/**/*',
|
|
203
|
-
'eslint.config.js',
|
|
204
|
-
'**/eslint.config.js',
|
|
205
|
-
'node_modules/**/*',
|
|
206
|
-
'**/node_modules/**/*',
|
|
207
|
-
],
|
|
154
|
+
ignore: ignoreGlobs,
|
|
208
155
|
});
|
|
209
156
|
|
|
210
157
|
if (opts.verbose) {
|
|
@@ -5,13 +5,13 @@ import type { Env } from '../../env.ts';
|
|
|
5
5
|
import type { WithGlobalOptions } from '../../global-options.js';
|
|
6
6
|
import { getExtensionDbConnectInfo, replaceEnvVar } from '../../util.ts';
|
|
7
7
|
|
|
8
|
-
type
|
|
8
|
+
type GetDbUrlOptions = {
|
|
9
9
|
extensionId?: string;
|
|
10
10
|
dbName?: string;
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
export const
|
|
14
|
-
opts: WithGlobalOptions<
|
|
13
|
+
export const getDbUrl = async (
|
|
14
|
+
opts: WithGlobalOptions<GetDbUrlOptions>,
|
|
15
15
|
env: Env,
|
|
16
16
|
): Promise<void> => {
|
|
17
17
|
const connInfo = getExtensionDbConnectInfo(opts, env);
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
getExtensionDbConnectInfo,
|
|
11
11
|
requireExtensionIdOptionOrEnvVar,
|
|
12
12
|
} from '../../util.ts';
|
|
13
|
-
import {
|
|
13
|
+
import { getDbUrl } from './get-db-url.ts';
|
|
14
14
|
|
|
15
15
|
const initExtDb = async ({
|
|
16
16
|
// A connection to the extension database by a superuser role.
|
|
@@ -149,7 +149,8 @@ export const initDb = async (
|
|
|
149
149
|
const coreDbUrl = requireCoreDbUrl(env);
|
|
150
150
|
const extensionId = requireExtensionIdOptionOrEnvVar(opts, env);
|
|
151
151
|
|
|
152
|
-
|
|
152
|
+
// This writes the DATABASE_URL environment variable to a .env.local (or .env.<env-mode>.local) file.
|
|
153
|
+
await getDbUrl(opts, env);
|
|
153
154
|
|
|
154
155
|
const db = await createPool(coreDbUrl, dbPoolOptions(opts));
|
|
155
156
|
|