directus-template-cli 0.6.0-beta.2 → 0.7.0-beta.10
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/README.md +0 -14
- package/bin/dev.js +6 -0
- package/bin/run.js +5 -0
- package/dist/commands/apply.d.ts +17 -17
- package/dist/commands/apply.js +166 -174
- package/dist/commands/base.d.ts +15 -0
- package/dist/commands/base.js +45 -0
- package/dist/commands/extract.d.ts +16 -9
- package/dist/commands/extract.js +81 -100
- package/dist/commands/init.d.ts +42 -0
- package/dist/commands/init.js +241 -0
- package/dist/flags/common.d.ts +8 -7
- package/dist/flags/common.js +13 -11
- package/dist/index.js +1 -5
- package/dist/lib/constants.d.ts +18 -0
- package/dist/lib/constants.js +25 -6
- package/dist/lib/extract/extract-access.js +11 -15
- package/dist/lib/extract/extract-assets.js +20 -25
- package/dist/lib/extract/extract-collections.js +12 -16
- package/dist/lib/extract/extract-content.d.ts +1 -1
- package/dist/lib/extract/extract-content.js +17 -26
- package/dist/lib/extract/extract-dashboards.js +22 -28
- package/dist/lib/extract/extract-extensions.js +12 -16
- package/dist/lib/extract/extract-fields.js +12 -16
- package/dist/lib/extract/extract-files.js +15 -19
- package/dist/lib/extract/extract-flows.js +22 -28
- package/dist/lib/extract/extract-folders.js +15 -19
- package/dist/lib/extract/extract-permissions.js +12 -16
- package/dist/lib/extract/extract-policies.js +12 -16
- package/dist/lib/extract/extract-presets.js +12 -16
- package/dist/lib/extract/extract-relations.js +14 -18
- package/dist/lib/extract/extract-roles.js +15 -19
- package/dist/lib/extract/extract-schema.js +17 -21
- package/dist/lib/extract/extract-settings.js +12 -16
- package/dist/lib/extract/extract-translations.js +12 -16
- package/dist/lib/extract/extract-users.js +15 -19
- package/dist/lib/extract/index.d.ts +1 -6
- package/dist/lib/extract/index.js +47 -58
- package/dist/lib/init/config.d.ts +3 -0
- package/dist/lib/init/config.js +12 -0
- package/dist/lib/init/index.d.ts +10 -0
- package/dist/lib/init/index.js +192 -0
- package/dist/lib/init/types.d.ts +30 -0
- package/dist/lib/init/types.js +1 -0
- package/dist/lib/load/apply-flags.js +17 -23
- package/dist/lib/load/index.d.ts +1 -12
- package/dist/lib/load/index.js +40 -44
- package/dist/lib/load/load-access.js +15 -20
- package/dist/lib/load/load-collections.d.ts +2 -0
- package/dist/lib/load/load-collections.js +29 -32
- package/dist/lib/load/load-dashboards.js +19 -25
- package/dist/lib/load/load-data.js +43 -49
- package/dist/lib/load/load-extensions.js +30 -38
- package/dist/lib/load/load-files.js +20 -24
- package/dist/lib/load/load-flows.js +23 -29
- package/dist/lib/load/load-folders.js +16 -20
- package/dist/lib/load/load-permissions.js +13 -17
- package/dist/lib/load/load-policies.js +14 -18
- package/dist/lib/load/load-presets.js +14 -18
- package/dist/lib/load/load-relations.d.ts +2 -0
- package/dist/lib/load/load-relations.js +16 -18
- package/dist/lib/load/load-roles.js +19 -23
- package/dist/lib/load/load-settings.js +18 -21
- package/dist/lib/load/load-translations.js +14 -18
- package/dist/lib/load/load-users.js +21 -25
- package/dist/lib/load/update-required-fields.js +13 -17
- package/dist/lib/sdk.d.ts +1 -2
- package/dist/lib/sdk.js +27 -27
- package/dist/lib/types/extension.js +1 -2
- package/dist/lib/types.d.ts +18 -0
- package/dist/lib/types.js +1 -0
- package/dist/lib/utils/animated-bunny.d.ts +2 -0
- package/dist/lib/utils/animated-bunny.js +62 -0
- package/dist/lib/utils/auth.d.ts +8 -6
- package/dist/lib/utils/auth.js +48 -39
- package/dist/lib/utils/catch-error.js +8 -11
- package/dist/lib/utils/check-template.js +4 -8
- package/dist/lib/utils/chunk-array.js +1 -5
- package/dist/lib/utils/ensure-dir.d.ts +2 -0
- package/dist/lib/utils/ensure-dir.js +11 -0
- package/dist/lib/utils/filter-fields.js +1 -4
- package/dist/lib/utils/get-role-ids.d.ts +1 -1
- package/dist/lib/utils/get-role-ids.js +7 -12
- package/dist/lib/utils/get-template.js +33 -36
- package/dist/lib/utils/logger.js +11 -13
- package/dist/lib/utils/open-url.js +5 -8
- package/dist/lib/utils/parse-github-url.d.ts +19 -0
- package/dist/lib/utils/parse-github-url.js +89 -0
- package/dist/lib/utils/path.js +6 -10
- package/dist/lib/utils/protected-domains.js +1 -4
- package/dist/lib/utils/read-file.js +8 -12
- package/dist/lib/utils/read-templates.js +9 -15
- package/dist/lib/utils/sanitize-flags.d.ts +3 -0
- package/dist/lib/utils/sanitize-flags.js +4 -0
- package/dist/lib/utils/system-fields.js +19 -22
- package/dist/lib/utils/template-config.d.ts +16 -0
- package/dist/lib/utils/template-config.js +34 -0
- package/dist/lib/utils/template-defaults.d.ts +1 -1
- package/dist/lib/utils/template-defaults.js +5 -14
- package/dist/lib/utils/transform-github-url.js +1 -5
- package/dist/lib/utils/validate-url.js +3 -6
- package/dist/lib/utils/wait.d.ts +7 -0
- package/dist/lib/utils/wait.js +9 -0
- package/dist/lib/utils/write-to-file.js +8 -11
- package/dist/services/docker.d.ts +23 -0
- package/dist/services/docker.js +187 -0
- package/dist/services/github.d.ts +18 -0
- package/dist/services/github.js +88 -0
- package/dist/services/posthog.d.ts +37 -0
- package/dist/services/posthog.js +104 -0
- package/oclif.manifest.json +102 -23
- package/package.json +46 -29
- package/bin/dev +0 -17
- package/bin/run +0 -5
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { spinner } from '@clack/prompts';
|
|
2
|
+
import { execa } from 'execa';
|
|
3
|
+
import net from 'node:net';
|
|
4
|
+
import { ux } from '@oclif/core';
|
|
5
|
+
import catchError from '../lib/utils/catch-error.js';
|
|
6
|
+
import { waitFor } from '../lib/utils/wait.js';
|
|
7
|
+
/**
|
|
8
|
+
* Check if a port is in use and what's using it
|
|
9
|
+
* @param port The port to check
|
|
10
|
+
* @returns Object indicating if port is in use and what's using it
|
|
11
|
+
*/
|
|
12
|
+
async function checkPort(port) {
|
|
13
|
+
return new Promise((resolve) => {
|
|
14
|
+
const server = net.createServer();
|
|
15
|
+
server.once('error', async (err) => {
|
|
16
|
+
if (err.code === 'EADDRINUSE') {
|
|
17
|
+
// Try to get information about what's using the port
|
|
18
|
+
try {
|
|
19
|
+
const { stdout } = await execa('lsof', ['-i', `:${port}`]);
|
|
20
|
+
const process = stdout.split('\n')[1]?.split(/\s+/)[0]; // Get process name
|
|
21
|
+
resolve({ inUse: true, process });
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
resolve({ inUse: true });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
resolve({ inUse: false });
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
server.once('listening', () => {
|
|
32
|
+
server.close();
|
|
33
|
+
resolve({ inUse: false });
|
|
34
|
+
});
|
|
35
|
+
server.listen(port);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Check if required ports are available and warn if they're in use
|
|
40
|
+
* @returns Promise<void>
|
|
41
|
+
*/
|
|
42
|
+
async function checkRequiredPorts() {
|
|
43
|
+
const portsToCheck = [
|
|
44
|
+
{ port: 8055, name: 'Directus API' },
|
|
45
|
+
{ port: 5432, name: 'PostgreSQL' },
|
|
46
|
+
];
|
|
47
|
+
let hasConflicts = false;
|
|
48
|
+
for (const { port, name } of portsToCheck) {
|
|
49
|
+
const status = await checkPort(port);
|
|
50
|
+
if (status.inUse) {
|
|
51
|
+
hasConflicts = true;
|
|
52
|
+
const process = status.process ? ` by ${status.process}` : '';
|
|
53
|
+
ux.warn(`Port ${port} (${name}) is already in use${process}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (hasConflicts) {
|
|
57
|
+
ux.warn('Please stop any conflicting services before continuing.');
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Check if Docker is installed and running
|
|
63
|
+
* @returns {Promise<DockerCheckResult>} Docker installation and running status
|
|
64
|
+
*/
|
|
65
|
+
async function checkDocker() {
|
|
66
|
+
try {
|
|
67
|
+
// Check if Docker is installed
|
|
68
|
+
const versionResult = await execa('docker', ['--version']);
|
|
69
|
+
const isInstalled = versionResult.exitCode === 0;
|
|
70
|
+
if (!isInstalled) {
|
|
71
|
+
return { installed: false, message: 'Docker is not installed. Please install Docker at https://docs.docker.com/get-started/get-docker/', running: false };
|
|
72
|
+
}
|
|
73
|
+
// Check if Docker daemon is running
|
|
74
|
+
const statusResult = await execa('docker', ['info']);
|
|
75
|
+
const isRunning = statusResult.exitCode === 0;
|
|
76
|
+
return {
|
|
77
|
+
installed: true,
|
|
78
|
+
message: 'Docker is installed and running.',
|
|
79
|
+
running: isRunning,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// If any command fails, Docker is either not installed or not running
|
|
84
|
+
return {
|
|
85
|
+
installed: false,
|
|
86
|
+
message: 'Docker is not running. Please start Docker and try again.',
|
|
87
|
+
running: false,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Start Docker containers using docker-compose
|
|
93
|
+
* @param {string} cwd - The current working directory
|
|
94
|
+
* @returns {Promise<void>} - Returns nothing
|
|
95
|
+
*/
|
|
96
|
+
async function startContainers(cwd) {
|
|
97
|
+
try {
|
|
98
|
+
// Check if required ports are available
|
|
99
|
+
await checkRequiredPorts();
|
|
100
|
+
const s = spinner();
|
|
101
|
+
s.start('Starting Docker containers');
|
|
102
|
+
return execa('docker-compose', ['up', '-d'], {
|
|
103
|
+
cwd,
|
|
104
|
+
}).then(() => {
|
|
105
|
+
s.stop('Docker containers running!');
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
catchError(error, {
|
|
110
|
+
context: { cwd, function: 'startContainers' },
|
|
111
|
+
fatal: true,
|
|
112
|
+
logToFile: true,
|
|
113
|
+
});
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Stop Docker containers
|
|
119
|
+
* @param {string} cwd - The current working directory
|
|
120
|
+
* @returns {Promise<void>} - Returns nothing
|
|
121
|
+
*/
|
|
122
|
+
async function stopContainers(cwd) {
|
|
123
|
+
try {
|
|
124
|
+
return execa('docker-compose', ['down'], {
|
|
125
|
+
cwd,
|
|
126
|
+
}).then(() => { });
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
catchError(error, {
|
|
130
|
+
context: { cwd, function: 'stopContainers' },
|
|
131
|
+
fatal: false,
|
|
132
|
+
logToFile: true,
|
|
133
|
+
});
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Wait for service health check to pass
|
|
139
|
+
* @param {DockerConfig} config - The Docker configuration
|
|
140
|
+
* @returns {Promise<boolean>} - Returns true if the service is healthy, false otherwise
|
|
141
|
+
*/
|
|
142
|
+
function createWaitForHealthy(config) {
|
|
143
|
+
async function waitForHealthy(healthCheckUrl) {
|
|
144
|
+
const s = spinner();
|
|
145
|
+
s.start('Waiting for Directus to be ready.');
|
|
146
|
+
try {
|
|
147
|
+
await waitFor(async () => {
|
|
148
|
+
try {
|
|
149
|
+
const response = await fetch(healthCheckUrl);
|
|
150
|
+
return response.ok;
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
}, {
|
|
156
|
+
errorMessage: 'Service failed to become healthy',
|
|
157
|
+
interval: config.interval,
|
|
158
|
+
maxAttempts: config.maxAttempts,
|
|
159
|
+
});
|
|
160
|
+
s.stop('Directus is ready!');
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
s.stop('');
|
|
165
|
+
catchError(error, {
|
|
166
|
+
context: { function: 'waitForHealthy', url: healthCheckUrl },
|
|
167
|
+
fatal: true,
|
|
168
|
+
logToFile: true,
|
|
169
|
+
});
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return waitForHealthy;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Create a Docker service instance
|
|
177
|
+
* @param {DockerConfig} config - The Docker configuration
|
|
178
|
+
* @returns {DockerService} - Returns a Docker service instance
|
|
179
|
+
*/
|
|
180
|
+
export function createDocker(config) {
|
|
181
|
+
return {
|
|
182
|
+
checkDocker,
|
|
183
|
+
startContainers,
|
|
184
|
+
stopContainers,
|
|
185
|
+
waitForHealthy: createWaitForHealthy(config),
|
|
186
|
+
};
|
|
187
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { parseGitHubUrl } from '../lib/utils/parse-github-url.js';
|
|
2
|
+
interface GitHubUrlParts {
|
|
3
|
+
owner: string;
|
|
4
|
+
path?: string;
|
|
5
|
+
ref?: string;
|
|
6
|
+
repo: string;
|
|
7
|
+
}
|
|
8
|
+
export interface GitHubService {
|
|
9
|
+
getTemplateDirectories(template: string, customUrl?: string): Promise<string[]>;
|
|
10
|
+
getTemplates(customUrl?: string): Promise<string[]>;
|
|
11
|
+
parseGitHubUrl(url: string): GitHubUrlParts;
|
|
12
|
+
}
|
|
13
|
+
export declare function createGitHub(token?: string): {
|
|
14
|
+
getTemplateDirectories: (template: string, customUrl?: string) => Promise<string[]>;
|
|
15
|
+
getTemplates: (customUrl?: string) => Promise<string[]>;
|
|
16
|
+
parseGitHubUrl: typeof parseGitHubUrl;
|
|
17
|
+
};
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Octokit } from '@octokit/rest';
|
|
2
|
+
import { DEFAULT_REPO } from '../lib/constants.js';
|
|
3
|
+
import { parseGitHubUrl } from '../lib/utils/parse-github-url.js';
|
|
4
|
+
export function createGitHub(token) {
|
|
5
|
+
const octokit = new Octokit({
|
|
6
|
+
auth: token,
|
|
7
|
+
});
|
|
8
|
+
/**
|
|
9
|
+
* Get the directories for a template.
|
|
10
|
+
* @param template - The template to get the directories for.
|
|
11
|
+
* @param customUrl - The custom URL to get the directories for.
|
|
12
|
+
* @returns The directories for the template.
|
|
13
|
+
*/
|
|
14
|
+
async function getTemplateDirectories(template, customUrl) {
|
|
15
|
+
// If template is a URL, parse it directly
|
|
16
|
+
if (template.startsWith('http')) {
|
|
17
|
+
const repo = parseGitHubUrl(template);
|
|
18
|
+
try {
|
|
19
|
+
const { data } = await octokit.rest.repos.getContent({
|
|
20
|
+
owner: repo.owner,
|
|
21
|
+
repo: repo.repo,
|
|
22
|
+
path: repo.path || '',
|
|
23
|
+
ref: repo.ref,
|
|
24
|
+
});
|
|
25
|
+
if (!Array.isArray(data))
|
|
26
|
+
return [];
|
|
27
|
+
// For direct URLs, we don't filter out the directus directory
|
|
28
|
+
// as the entire repo might be a directus template
|
|
29
|
+
return data
|
|
30
|
+
.filter(item => item.type === 'dir')
|
|
31
|
+
.map(item => item.name);
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
// If we can't get contents, return empty array
|
|
35
|
+
// This indicates no frontends are available
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Otherwise use default repo behavior
|
|
40
|
+
const repo = customUrl ? parseGitHubUrl(customUrl) : DEFAULT_REPO;
|
|
41
|
+
const templatePath = repo.path ? `${repo.path}/${template}` : template;
|
|
42
|
+
try {
|
|
43
|
+
const { data } = await octokit.rest.repos.getContent({
|
|
44
|
+
owner: repo.owner,
|
|
45
|
+
path: templatePath,
|
|
46
|
+
ref: repo.ref,
|
|
47
|
+
repo: repo.repo,
|
|
48
|
+
});
|
|
49
|
+
if (!Array.isArray(data))
|
|
50
|
+
return [];
|
|
51
|
+
return data
|
|
52
|
+
.filter(item => item.type === 'dir' && item.name !== 'directus')
|
|
53
|
+
.map(item => item.name);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
// If we can't get contents, return empty array
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Get the templates for a repository.
|
|
62
|
+
* @param customUrl - The custom URL to get the templates for.
|
|
63
|
+
* @returns The templates for the repository.
|
|
64
|
+
*/
|
|
65
|
+
async function getTemplates(customUrl) {
|
|
66
|
+
// If customUrl is provided and it's a full repository URL, return it as the only template
|
|
67
|
+
if (customUrl?.startsWith('http')) {
|
|
68
|
+
return [customUrl];
|
|
69
|
+
}
|
|
70
|
+
const repo = customUrl ? parseGitHubUrl(customUrl) : DEFAULT_REPO;
|
|
71
|
+
const { data } = await octokit.rest.repos.getContent({
|
|
72
|
+
owner: repo.owner,
|
|
73
|
+
path: repo.path || '',
|
|
74
|
+
ref: repo.ref,
|
|
75
|
+
repo: repo.repo,
|
|
76
|
+
});
|
|
77
|
+
if (!Array.isArray(data))
|
|
78
|
+
return [];
|
|
79
|
+
return data
|
|
80
|
+
.filter(item => item.type === 'dir')
|
|
81
|
+
.map(item => item.name);
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
getTemplateDirectories,
|
|
85
|
+
getTemplates,
|
|
86
|
+
parseGitHubUrl,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Config } from '@oclif/core';
|
|
2
|
+
import { PostHog } from 'posthog-node';
|
|
3
|
+
/**
|
|
4
|
+
* Initialize and get the PostHog client
|
|
5
|
+
* @param debug Whether to log debug information
|
|
6
|
+
* @returns The PostHog client
|
|
7
|
+
*/
|
|
8
|
+
export declare function getClient(debug?: boolean): PostHog;
|
|
9
|
+
/**
|
|
10
|
+
* Shutdown the PostHog client
|
|
11
|
+
* @param debug Whether to log debug information
|
|
12
|
+
* @returns void
|
|
13
|
+
*/
|
|
14
|
+
export declare function shutdown(debug?: boolean): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Track an event in PostHog
|
|
17
|
+
* @param options The tracking options
|
|
18
|
+
* @param options.lifecycle The lifecycle event to track ('start', 'complete', 'error')
|
|
19
|
+
* @param options.distinctId The distinct ID for the user
|
|
20
|
+
* @param options.command Optional command name (for command tracking)
|
|
21
|
+
* @param options.flags Optional command flags
|
|
22
|
+
* @param options.runId Optional run ID
|
|
23
|
+
* @param options.config Optional config object
|
|
24
|
+
* @param options.properties Optional additional properties to track
|
|
25
|
+
* @param options.debug Whether to log debug information
|
|
26
|
+
*/
|
|
27
|
+
export declare function track({ lifecycle, distinctId, command, flags, runId, message, config, properties, debug }: {
|
|
28
|
+
lifecycle: 'start' | 'complete' | 'error';
|
|
29
|
+
message?: string;
|
|
30
|
+
distinctId: string;
|
|
31
|
+
command?: string;
|
|
32
|
+
flags?: Record<string, unknown>;
|
|
33
|
+
runId?: string;
|
|
34
|
+
config?: Config;
|
|
35
|
+
properties?: Record<string, unknown>;
|
|
36
|
+
debug?: boolean;
|
|
37
|
+
}): void;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { ux } from '@oclif/core';
|
|
2
|
+
import { PostHog } from 'posthog-node';
|
|
3
|
+
import { POSTHOG_PUBLIC_KEY, POSTHOG_HOST } from '../lib/constants.js';
|
|
4
|
+
import { sanitizeFlags } from '../lib/utils/sanitize-flags.js';
|
|
5
|
+
// Create a singleton client using module scope
|
|
6
|
+
let client = null;
|
|
7
|
+
/**
|
|
8
|
+
* Initialize and get the PostHog client
|
|
9
|
+
* @param debug Whether to log debug information
|
|
10
|
+
* @returns The PostHog client
|
|
11
|
+
*/
|
|
12
|
+
export function getClient(debug = false) {
|
|
13
|
+
if (debug)
|
|
14
|
+
ux.stdout('Initializing PostHog client...');
|
|
15
|
+
if (!client) {
|
|
16
|
+
client = new PostHog(POSTHOG_PUBLIC_KEY, {
|
|
17
|
+
host: POSTHOG_HOST,
|
|
18
|
+
disableGeoip: false,
|
|
19
|
+
});
|
|
20
|
+
// Add error handling
|
|
21
|
+
client.on('error', err => {
|
|
22
|
+
ux.warn(`PostHog Error: ${err}`);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
if (debug)
|
|
26
|
+
ux.stdout('PostHog client initialized successfully');
|
|
27
|
+
return client;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Shutdown the PostHog client
|
|
31
|
+
* @param debug Whether to log debug information
|
|
32
|
+
* @returns void
|
|
33
|
+
*/
|
|
34
|
+
export async function shutdown(debug = false) {
|
|
35
|
+
if (debug)
|
|
36
|
+
ux.stdout('Shutting down PostHog client...');
|
|
37
|
+
if (!client)
|
|
38
|
+
return;
|
|
39
|
+
try {
|
|
40
|
+
await client.shutdown();
|
|
41
|
+
client = null;
|
|
42
|
+
if (debug)
|
|
43
|
+
ux.stdout('PostHog client shut down successfully');
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
ux.warn(`Error shutting down PostHog client: ${error}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Track an event in PostHog
|
|
51
|
+
* @param options The tracking options
|
|
52
|
+
* @param options.lifecycle The lifecycle event to track ('start', 'complete', 'error')
|
|
53
|
+
* @param options.distinctId The distinct ID for the user
|
|
54
|
+
* @param options.command Optional command name (for command tracking)
|
|
55
|
+
* @param options.flags Optional command flags
|
|
56
|
+
* @param options.runId Optional run ID
|
|
57
|
+
* @param options.config Optional config object
|
|
58
|
+
* @param options.properties Optional additional properties to track
|
|
59
|
+
* @param options.debug Whether to log debug information
|
|
60
|
+
*/
|
|
61
|
+
export function track({ lifecycle, distinctId, command, flags, runId, message, config, properties = {}, debug = false }) {
|
|
62
|
+
if (debug)
|
|
63
|
+
ux.stdout('Tracking event...');
|
|
64
|
+
const phClient = getClient(debug);
|
|
65
|
+
const eventProperties = command
|
|
66
|
+
? {
|
|
67
|
+
runId,
|
|
68
|
+
message,
|
|
69
|
+
...properties,
|
|
70
|
+
...getEnvironmentInfo(config),
|
|
71
|
+
// Always sanitize sensitive flags
|
|
72
|
+
...sanitizeFlags(flags),
|
|
73
|
+
}
|
|
74
|
+
: properties;
|
|
75
|
+
if (debug) {
|
|
76
|
+
ux.stdout('Capturing event...');
|
|
77
|
+
ux.stdout(JSON.stringify(eventProperties));
|
|
78
|
+
}
|
|
79
|
+
phClient.capture({
|
|
80
|
+
distinctId,
|
|
81
|
+
event: `directus_template_cli.${command}.${lifecycle}`,
|
|
82
|
+
properties: eventProperties
|
|
83
|
+
});
|
|
84
|
+
if (debug)
|
|
85
|
+
ux.stdout('Event tracked successfully');
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Get environment info
|
|
89
|
+
* @param config The config to get environment info from
|
|
90
|
+
* @returns The environment info
|
|
91
|
+
*/
|
|
92
|
+
function getEnvironmentInfo(config) {
|
|
93
|
+
return {
|
|
94
|
+
// PostHog properties
|
|
95
|
+
$os: process.platform,
|
|
96
|
+
$raw_user_agent: config?.userAgent || 'unknown',
|
|
97
|
+
// Custom properties
|
|
98
|
+
arch: process.arch || 'unknown',
|
|
99
|
+
nodeVersion: process.version,
|
|
100
|
+
platform: config?.platform || 'unknown',
|
|
101
|
+
shell: config?.shell || 'unknown',
|
|
102
|
+
version: config?.version || 'unknown',
|
|
103
|
+
};
|
|
104
|
+
}
|
package/oclif.manifest.json
CHANGED
|
@@ -169,21 +169,39 @@
|
|
|
169
169
|
"pluginType": "core",
|
|
170
170
|
"strict": true,
|
|
171
171
|
"enableJsonFlag": false,
|
|
172
|
-
"isESM":
|
|
172
|
+
"isESM": true,
|
|
173
173
|
"relativePath": [
|
|
174
174
|
"dist",
|
|
175
175
|
"commands",
|
|
176
176
|
"apply.js"
|
|
177
177
|
]
|
|
178
178
|
},
|
|
179
|
+
"base": {
|
|
180
|
+
"aliases": [],
|
|
181
|
+
"args": {},
|
|
182
|
+
"flags": {},
|
|
183
|
+
"hasDynamicHelp": false,
|
|
184
|
+
"hiddenAliases": [],
|
|
185
|
+
"id": "base",
|
|
186
|
+
"pluginAlias": "directus-template-cli",
|
|
187
|
+
"pluginName": "directus-template-cli",
|
|
188
|
+
"pluginType": "core",
|
|
189
|
+
"strict": true,
|
|
190
|
+
"enableJsonFlag": false,
|
|
191
|
+
"isESM": true,
|
|
192
|
+
"relativePath": [
|
|
193
|
+
"dist",
|
|
194
|
+
"commands",
|
|
195
|
+
"base.js"
|
|
196
|
+
]
|
|
197
|
+
},
|
|
179
198
|
"extract": {
|
|
180
199
|
"aliases": [],
|
|
181
200
|
"args": {},
|
|
182
201
|
"description": "Extract a template from a Directus instance.",
|
|
183
202
|
"examples": [
|
|
184
203
|
"$ directus-template-cli extract",
|
|
185
|
-
"$ directus-template-cli extract -p --templateName=\"My Template\" --templateLocation=\"./my-template\" --directusToken=\"admin-token-here\" --directusUrl=\"http://localhost:8055\""
|
|
186
|
-
"$ directus-template-cli extract -p --templateName=\"My Template\" --templateLocation=\"./my-template\" --directusToken=\"admin-token-here\" --directusUrl=\"http://localhost:8055\" --excludeCollections=collection1,collection2"
|
|
204
|
+
"$ directus-template-cli extract -p --templateName=\"My Template\" --templateLocation=\"./my-template\" --directusToken=\"admin-token-here\" --directusUrl=\"http://localhost:8055\""
|
|
187
205
|
],
|
|
188
206
|
"flags": {
|
|
189
207
|
"directusToken": {
|
|
@@ -206,16 +224,6 @@
|
|
|
206
224
|
"multiple": false,
|
|
207
225
|
"type": "option"
|
|
208
226
|
},
|
|
209
|
-
"excludeCollections": {
|
|
210
|
-
"char": "e",
|
|
211
|
-
"description": "Comma-separated list of collection names to exclude from extraction",
|
|
212
|
-
"name": "excludeCollections",
|
|
213
|
-
"required": false,
|
|
214
|
-
"delimiter": ",",
|
|
215
|
-
"hasDynamicHelp": false,
|
|
216
|
-
"multiple": true,
|
|
217
|
-
"type": "option"
|
|
218
|
-
},
|
|
219
227
|
"programmatic": {
|
|
220
228
|
"char": "p",
|
|
221
229
|
"description": "Run in programmatic mode (non-interactive) for use cases such as CI/CD pipelines.",
|
|
@@ -224,14 +232,6 @@
|
|
|
224
232
|
"allowNo": false,
|
|
225
233
|
"type": "boolean"
|
|
226
234
|
},
|
|
227
|
-
"skipFiles": {
|
|
228
|
-
"char": "f",
|
|
229
|
-
"description": "Skip extracting files and assets",
|
|
230
|
-
"name": "skipFiles",
|
|
231
|
-
"required": false,
|
|
232
|
-
"allowNo": false,
|
|
233
|
-
"type": "boolean"
|
|
234
|
-
},
|
|
235
235
|
"templateLocation": {
|
|
236
236
|
"dependsOn": [
|
|
237
237
|
"programmatic"
|
|
@@ -291,13 +291,92 @@
|
|
|
291
291
|
"pluginType": "core",
|
|
292
292
|
"strict": true,
|
|
293
293
|
"enableJsonFlag": false,
|
|
294
|
-
"isESM":
|
|
294
|
+
"isESM": true,
|
|
295
295
|
"relativePath": [
|
|
296
296
|
"dist",
|
|
297
297
|
"commands",
|
|
298
298
|
"extract.js"
|
|
299
299
|
]
|
|
300
|
+
},
|
|
301
|
+
"init": {
|
|
302
|
+
"aliases": [],
|
|
303
|
+
"args": {
|
|
304
|
+
"directory": {
|
|
305
|
+
"default": ".",
|
|
306
|
+
"description": "Directory to create the project in",
|
|
307
|
+
"name": "directory",
|
|
308
|
+
"required": false
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
"description": "Initialize a new Directus + Frontend monorepo using official or community starters.",
|
|
312
|
+
"examples": [
|
|
313
|
+
"$ directus-template-cli init",
|
|
314
|
+
"$ directus-template-cli init my-project",
|
|
315
|
+
"$ directus-template-cli init --frontend=nextjs --template=simple-cms",
|
|
316
|
+
"$ directus-template-cli init my-project --frontend=nextjs --template=simple-cms"
|
|
317
|
+
],
|
|
318
|
+
"flags": {
|
|
319
|
+
"frontend": {
|
|
320
|
+
"description": "Frontend framework to use (e.g., nextjs, nuxt, astro)",
|
|
321
|
+
"name": "frontend",
|
|
322
|
+
"hasDynamicHelp": false,
|
|
323
|
+
"multiple": false,
|
|
324
|
+
"type": "option"
|
|
325
|
+
},
|
|
326
|
+
"gitInit": {
|
|
327
|
+
"aliases": [
|
|
328
|
+
"git-init"
|
|
329
|
+
],
|
|
330
|
+
"description": "Initialize a new Git repository",
|
|
331
|
+
"name": "gitInit",
|
|
332
|
+
"allowNo": true,
|
|
333
|
+
"type": "boolean"
|
|
334
|
+
},
|
|
335
|
+
"installDeps": {
|
|
336
|
+
"aliases": [
|
|
337
|
+
"install-deps"
|
|
338
|
+
],
|
|
339
|
+
"description": "Install dependencies automatically",
|
|
340
|
+
"name": "installDeps",
|
|
341
|
+
"allowNo": true,
|
|
342
|
+
"type": "boolean"
|
|
343
|
+
},
|
|
344
|
+
"overrideDir": {
|
|
345
|
+
"description": "Override the default directory",
|
|
346
|
+
"name": "overrideDir",
|
|
347
|
+
"allowNo": false,
|
|
348
|
+
"type": "boolean"
|
|
349
|
+
},
|
|
350
|
+
"template": {
|
|
351
|
+
"description": "Template name (e.g., simple-cms) or GitHub URL (e.g., https://github.com/directus-labs/starters/tree/main/simple-cms)",
|
|
352
|
+
"name": "template",
|
|
353
|
+
"hasDynamicHelp": false,
|
|
354
|
+
"multiple": false,
|
|
355
|
+
"type": "option"
|
|
356
|
+
},
|
|
357
|
+
"disableTelemetry": {
|
|
358
|
+
"description": "Disable telemetry",
|
|
359
|
+
"env": "DISABLE_TELEMETRY",
|
|
360
|
+
"name": "disableTelemetry",
|
|
361
|
+
"allowNo": false,
|
|
362
|
+
"type": "boolean"
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
"hasDynamicHelp": false,
|
|
366
|
+
"hiddenAliases": [],
|
|
367
|
+
"id": "init",
|
|
368
|
+
"pluginAlias": "directus-template-cli",
|
|
369
|
+
"pluginName": "directus-template-cli",
|
|
370
|
+
"pluginType": "core",
|
|
371
|
+
"strict": true,
|
|
372
|
+
"enableJsonFlag": false,
|
|
373
|
+
"isESM": true,
|
|
374
|
+
"relativePath": [
|
|
375
|
+
"dist",
|
|
376
|
+
"commands",
|
|
377
|
+
"init.js"
|
|
378
|
+
]
|
|
300
379
|
}
|
|
301
380
|
},
|
|
302
|
-
"version": "0.
|
|
381
|
+
"version": "0.7.0-beta.10"
|
|
303
382
|
}
|