@wirechunk/cli 0.0.1 → 0.0.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wirechunk/cli",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
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 { z } from 'zod';
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 createExtensionVersionResultDataSchema = z.discriminatedUnion('__typename', [
20
- z.object({
21
- __typename: z.literal('CreateExtensionVersionSuccessResult'),
22
- extensionVersion: z.object({
23
- id: z.string(),
24
- }),
25
- signedUrl: z.string(),
26
- }),
27
- z.object({
28
- __typename: z.literal('AuthorizationError'),
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 (
@@ -84,6 +65,20 @@ export const createExtensionVersion = async (
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})
@@ -98,69 +93,27 @@ export const createExtensionVersion = async (
98
93
  if (opts.verbose) {
99
94
  console.log(`POST ${url}`);
100
95
  }
101
- const createResult = await fetch(url, {
102
- method: 'POST',
103
- headers: {
104
- 'Content-Type': 'application/json',
105
- Authorization: `Bearer ${apiToken}`,
106
- },
107
- body: JSON.stringify({
108
- query: `
109
- mutation ($input: CreateExtensionVersionInput!) {
110
- createExtensionVersion(input: $input) {
111
- __typename
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: extConfig.name,
102
+ versionName,
103
+ enableServer,
104
+ enableDb,
105
+ config: config ? JSON.stringify(config) : undefined,
132
106
  },
133
- }),
107
+ },
108
+ sessionAuthToken: apiToken,
134
109
  });
135
- if (!createResult.ok) {
136
- const message = `Failed to create an extension version (status ${createResult.status})`;
137
- try {
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;
110
+ if (result.createExtensionVersion.__typename === 'CreateExtensionVersionSuccessResult') {
111
+ extensionVersionId = result.createExtensionVersion.extensionVersion.id;
112
+ signedUrl = result.createExtensionVersion.signedUrl;
160
113
  } else {
161
114
  console.error(
162
- `Failed to create an extension version (${result.data?.createExtensionVersion.__typename ?? 'unknown error'}):`,
163
- parseErrorMessage(result.data?.createExtensionVersion),
115
+ `Failed to create an extension version (${result.createExtensionVersion.__typename}):`,
116
+ result.createExtensionVersion.message,
164
117
  );
165
118
  process.exit(1);
166
119
  }
@@ -197,14 +150,7 @@ export const createExtensionVersion = async (
197
150
 
198
151
  archive.glob('**/*', {
199
152
  cwd,
200
- ignore: [
201
- '**/.git/**/*',
202
- '.git/**/*',
203
- 'eslint.config.js',
204
- '**/eslint.config.js',
205
- 'node_modules/**/*',
206
- '**/node_modules/**/*',
207
- ],
153
+ ignore: ignoreGlobs,
208
154
  });
209
155
 
210
156
  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 DbConnectInfoOptions = {
8
+ type GetDbUrlOptions = {
9
9
  extensionId?: string;
10
10
  dbName?: string;
11
11
  };
12
12
 
13
- export const dbConnectInfo = async (
14
- opts: WithGlobalOptions<DbConnectInfoOptions>,
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 { dbConnectInfo } from './db-connect-info.ts';
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
- await dbConnectInfo(opts, env);
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