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.
Files changed (114) hide show
  1. package/README.md +0 -14
  2. package/bin/dev.js +6 -0
  3. package/bin/run.js +5 -0
  4. package/dist/commands/apply.d.ts +17 -17
  5. package/dist/commands/apply.js +166 -174
  6. package/dist/commands/base.d.ts +15 -0
  7. package/dist/commands/base.js +45 -0
  8. package/dist/commands/extract.d.ts +16 -9
  9. package/dist/commands/extract.js +81 -100
  10. package/dist/commands/init.d.ts +42 -0
  11. package/dist/commands/init.js +241 -0
  12. package/dist/flags/common.d.ts +8 -7
  13. package/dist/flags/common.js +13 -11
  14. package/dist/index.js +1 -5
  15. package/dist/lib/constants.d.ts +18 -0
  16. package/dist/lib/constants.js +25 -6
  17. package/dist/lib/extract/extract-access.js +11 -15
  18. package/dist/lib/extract/extract-assets.js +20 -25
  19. package/dist/lib/extract/extract-collections.js +12 -16
  20. package/dist/lib/extract/extract-content.d.ts +1 -1
  21. package/dist/lib/extract/extract-content.js +17 -26
  22. package/dist/lib/extract/extract-dashboards.js +22 -28
  23. package/dist/lib/extract/extract-extensions.js +12 -16
  24. package/dist/lib/extract/extract-fields.js +12 -16
  25. package/dist/lib/extract/extract-files.js +15 -19
  26. package/dist/lib/extract/extract-flows.js +22 -28
  27. package/dist/lib/extract/extract-folders.js +15 -19
  28. package/dist/lib/extract/extract-permissions.js +12 -16
  29. package/dist/lib/extract/extract-policies.js +12 -16
  30. package/dist/lib/extract/extract-presets.js +12 -16
  31. package/dist/lib/extract/extract-relations.js +14 -18
  32. package/dist/lib/extract/extract-roles.js +15 -19
  33. package/dist/lib/extract/extract-schema.js +17 -21
  34. package/dist/lib/extract/extract-settings.js +12 -16
  35. package/dist/lib/extract/extract-translations.js +12 -16
  36. package/dist/lib/extract/extract-users.js +15 -19
  37. package/dist/lib/extract/index.d.ts +1 -6
  38. package/dist/lib/extract/index.js +47 -58
  39. package/dist/lib/init/config.d.ts +3 -0
  40. package/dist/lib/init/config.js +12 -0
  41. package/dist/lib/init/index.d.ts +10 -0
  42. package/dist/lib/init/index.js +192 -0
  43. package/dist/lib/init/types.d.ts +30 -0
  44. package/dist/lib/init/types.js +1 -0
  45. package/dist/lib/load/apply-flags.js +17 -23
  46. package/dist/lib/load/index.d.ts +1 -12
  47. package/dist/lib/load/index.js +40 -44
  48. package/dist/lib/load/load-access.js +15 -20
  49. package/dist/lib/load/load-collections.d.ts +2 -0
  50. package/dist/lib/load/load-collections.js +29 -32
  51. package/dist/lib/load/load-dashboards.js +19 -25
  52. package/dist/lib/load/load-data.js +43 -49
  53. package/dist/lib/load/load-extensions.js +30 -38
  54. package/dist/lib/load/load-files.js +20 -24
  55. package/dist/lib/load/load-flows.js +23 -29
  56. package/dist/lib/load/load-folders.js +16 -20
  57. package/dist/lib/load/load-permissions.js +13 -17
  58. package/dist/lib/load/load-policies.js +14 -18
  59. package/dist/lib/load/load-presets.js +14 -18
  60. package/dist/lib/load/load-relations.d.ts +2 -0
  61. package/dist/lib/load/load-relations.js +16 -18
  62. package/dist/lib/load/load-roles.js +19 -23
  63. package/dist/lib/load/load-settings.js +18 -21
  64. package/dist/lib/load/load-translations.js +14 -18
  65. package/dist/lib/load/load-users.js +21 -25
  66. package/dist/lib/load/update-required-fields.js +13 -17
  67. package/dist/lib/sdk.d.ts +1 -2
  68. package/dist/lib/sdk.js +27 -27
  69. package/dist/lib/types/extension.js +1 -2
  70. package/dist/lib/types.d.ts +18 -0
  71. package/dist/lib/types.js +1 -0
  72. package/dist/lib/utils/animated-bunny.d.ts +2 -0
  73. package/dist/lib/utils/animated-bunny.js +62 -0
  74. package/dist/lib/utils/auth.d.ts +8 -6
  75. package/dist/lib/utils/auth.js +48 -39
  76. package/dist/lib/utils/catch-error.js +8 -11
  77. package/dist/lib/utils/check-template.js +4 -8
  78. package/dist/lib/utils/chunk-array.js +1 -5
  79. package/dist/lib/utils/ensure-dir.d.ts +2 -0
  80. package/dist/lib/utils/ensure-dir.js +11 -0
  81. package/dist/lib/utils/filter-fields.js +1 -4
  82. package/dist/lib/utils/get-role-ids.d.ts +1 -1
  83. package/dist/lib/utils/get-role-ids.js +7 -12
  84. package/dist/lib/utils/get-template.js +33 -36
  85. package/dist/lib/utils/logger.js +11 -13
  86. package/dist/lib/utils/open-url.js +5 -8
  87. package/dist/lib/utils/parse-github-url.d.ts +19 -0
  88. package/dist/lib/utils/parse-github-url.js +89 -0
  89. package/dist/lib/utils/path.js +6 -10
  90. package/dist/lib/utils/protected-domains.js +1 -4
  91. package/dist/lib/utils/read-file.js +8 -12
  92. package/dist/lib/utils/read-templates.js +9 -15
  93. package/dist/lib/utils/sanitize-flags.d.ts +3 -0
  94. package/dist/lib/utils/sanitize-flags.js +4 -0
  95. package/dist/lib/utils/system-fields.js +19 -22
  96. package/dist/lib/utils/template-config.d.ts +16 -0
  97. package/dist/lib/utils/template-config.js +34 -0
  98. package/dist/lib/utils/template-defaults.d.ts +1 -1
  99. package/dist/lib/utils/template-defaults.js +5 -14
  100. package/dist/lib/utils/transform-github-url.js +1 -5
  101. package/dist/lib/utils/validate-url.js +3 -6
  102. package/dist/lib/utils/wait.d.ts +7 -0
  103. package/dist/lib/utils/wait.js +9 -0
  104. package/dist/lib/utils/write-to-file.js +8 -11
  105. package/dist/services/docker.d.ts +23 -0
  106. package/dist/services/docker.js +187 -0
  107. package/dist/services/github.d.ts +18 -0
  108. package/dist/services/github.js +88 -0
  109. package/dist/services/posthog.d.ts +37 -0
  110. package/dist/services/posthog.js +104 -0
  111. package/oclif.manifest.json +102 -23
  112. package/package.json +46 -29
  113. package/bin/dev +0 -17
  114. package/bin/run +0 -5
@@ -0,0 +1,192 @@
1
+ import { note, outro, spinner, log as clackLog } from '@clack/prompts';
2
+ import { ux } from '@oclif/core';
3
+ import { execa } from 'execa';
4
+ import { downloadTemplate } from 'giget';
5
+ import { glob } from 'glob';
6
+ import fs from 'node:fs';
7
+ import { detectPackageManager, installDependencies } from 'nypm';
8
+ import path from 'pathe';
9
+ import dotenv from 'dotenv';
10
+ import terminalLink from 'terminal-link';
11
+ import ApplyCommand from '../../commands/apply.js';
12
+ import { createDocker } from '../../services/docker.js';
13
+ import catchError from '../utils/catch-error.js';
14
+ import { createGigetString, parseGitHubUrl } from '../utils/parse-github-url.js';
15
+ import { readTemplateConfig } from '../utils/template-config.js';
16
+ import { DOCKER_CONFIG } from './config.js';
17
+ import { BSL_LICENSE_TEXT, pinkText } from '../constants.js';
18
+ export async function init({ dir, flags }) {
19
+ // Check target directory
20
+ const shouldForce = flags.overrideDir;
21
+ if (fs.existsSync(dir) && !shouldForce) {
22
+ throw new Error('Directory already exists. Use --override-dir to override.');
23
+ }
24
+ // If template is a URL, we need to handle it differently
25
+ const isDirectUrl = flags.template?.startsWith('http');
26
+ const directusDir = path.join(dir, 'directus');
27
+ let template;
28
+ let packageManager = null;
29
+ try {
30
+ // Download the template from GitHub
31
+ const parsedUrl = parseGitHubUrl(flags.template);
32
+ // If it's a direct URL, we download the entire repository
33
+ // Otherwise, we use the template from the starters repo
34
+ template = await downloadTemplate(createGigetString(parsedUrl), {
35
+ dir,
36
+ force: shouldForce,
37
+ });
38
+ // For direct URLs, we need to check if there's a directus directory
39
+ // If not, assume the entire repo is a directus template
40
+ if (isDirectUrl) {
41
+ if (!fs.existsSync(directusDir)) {
42
+ // Move all files to directus directory
43
+ fs.mkdirSync(directusDir, { recursive: true });
44
+ const files = fs.readdirSync(dir);
45
+ for (const file of files) {
46
+ if (file !== 'directus') {
47
+ fs.renameSync(path.join(dir, file), path.join(directusDir, file));
48
+ }
49
+ }
50
+ }
51
+ }
52
+ // Read template configuration
53
+ const templateInfo = readTemplateConfig(dir);
54
+ let frontendDir;
55
+ // Handle frontends based on template configuration
56
+ if (flags.frontend && templateInfo) {
57
+ // Find the selected frontend in the configuration
58
+ const selectedFrontend = templateInfo.frontendOptions.find(f => f.id === flags.frontend);
59
+ if (!selectedFrontend) {
60
+ throw new Error(`Frontend "${flags.frontend}" not found in template configuration`);
61
+ }
62
+ // Remove all frontend directories except the selected one
63
+ for (const frontend of templateInfo.frontendOptions) {
64
+ if (frontend.id !== flags.frontend) {
65
+ const pathToRemove = path.join(dir, frontend.path);
66
+ if (fs.existsSync(pathToRemove)) {
67
+ fs.rmSync(pathToRemove, { recursive: true });
68
+ }
69
+ }
70
+ }
71
+ // Move the selected frontend to the correct location if needed
72
+ frontendDir = path.join(dir, selectedFrontend.path);
73
+ if (frontendDir !== path.join(dir, flags.frontend)) {
74
+ fs.renameSync(frontendDir, path.join(dir, flags.frontend));
75
+ frontendDir = path.join(dir, flags.frontend);
76
+ }
77
+ }
78
+ const directusInfo = {
79
+ email: '',
80
+ password: '',
81
+ url: '',
82
+ };
83
+ // Find and copy all .env.example files
84
+ const envFiles = glob.sync(path.join(dir, '**', '.env.example'));
85
+ // Process all env files first
86
+ for (const file of envFiles) {
87
+ const envFile = file.replace('.env.example', '.env');
88
+ fs.copyFileSync(file, envFile);
89
+ }
90
+ // Then read Directus-specific info only from the Directus env file
91
+ const directusEnvFile = path.join(directusDir, '.env');
92
+ if (fs.existsSync(directusEnvFile)) {
93
+ const parsedEnv = dotenv.parse(fs.readFileSync(directusEnvFile, 'utf8'));
94
+ directusInfo.email = parsedEnv.ADMIN_EMAIL;
95
+ directusInfo.password = parsedEnv.ADMIN_PASSWORD;
96
+ directusInfo.url = parsedEnv.PUBLIC_URL;
97
+ }
98
+ // Start Directus and apply template only if directus directory exists
99
+ if (fs.existsSync(directusDir)) {
100
+ // Initialize Docker service
101
+ const dockerService = createDocker(DOCKER_CONFIG);
102
+ // Check if Docker is installed
103
+ const dockerStatus = await dockerService.checkDocker();
104
+ if (!dockerStatus.installed || !dockerStatus.running) {
105
+ throw new Error(dockerStatus.message);
106
+ }
107
+ await dockerService.startContainers(directusDir);
108
+ const healthCheckUrl = `${directusInfo.url || 'http://localhost:8055'}${DOCKER_CONFIG.healthCheckEndpoint}`;
109
+ // Wait for healthy before proceeding
110
+ const isHealthy = await dockerService.waitForHealthy(healthCheckUrl);
111
+ if (!isHealthy) {
112
+ throw new Error('Directus failed to become healthy');
113
+ }
114
+ const templatePath = path.join(directusDir, 'template');
115
+ ux.stdout(`Attempting to apply template from: ${templatePath}`);
116
+ await ApplyCommand.run([
117
+ '--directusUrl=http://localhost:8055',
118
+ '-p',
119
+ '--userEmail=admin@example.com',
120
+ '--userPassword=d1r3ctu5',
121
+ `--templateLocation=${templatePath}`,
122
+ ]);
123
+ }
124
+ // Install dependencies if requested
125
+ if (flags.installDeps) {
126
+ const s = spinner();
127
+ s.start('Installing dependencies');
128
+ try {
129
+ if (fs.existsSync(frontendDir)) {
130
+ packageManager = await detectPackageManager(frontendDir);
131
+ await installDependencies({
132
+ cwd: frontendDir,
133
+ packageManager,
134
+ silent: true,
135
+ });
136
+ }
137
+ }
138
+ catch (error) {
139
+ ux.warn('Failed to install dependencies');
140
+ throw error;
141
+ }
142
+ s.stop('Dependencies installed!');
143
+ }
144
+ // Initialize Git repo
145
+ if (flags.gitInit) {
146
+ const s = spinner();
147
+ s.start('Initializing git repository');
148
+ await initGit(dir);
149
+ s.stop('Git repository initialized!');
150
+ }
151
+ // Finishing up
152
+ const relativeDir = path.relative(process.cwd(), dir);
153
+ const directusUrl = directusInfo.url ?? 'http://localhost:8055';
154
+ const directusText = `- Directus is running on ${terminalLink(directusUrl, directusUrl)}. You can login with the email: ${pinkText(directusInfo.email)} and password: ${pinkText(directusInfo.password)}. \n`;
155
+ const frontendText = flags.frontend ? `- To start the frontend, run ${pinkText(`cd ${flags.frontend}`)} and then ${pinkText(`${packageManager?.name} run dev`)}. \n` : '';
156
+ const projectText = `- Navigate to your project directory using ${pinkText(`cd ${relativeDir}`)}. \n`;
157
+ const readmeText = '- Review the \`./README.md\` file for more information and next steps.';
158
+ const nextSteps = `${directusText}${projectText}${frontendText}${readmeText}`;
159
+ note(nextSteps, 'Next Steps');
160
+ clackLog.warn(BSL_LICENSE_TEXT);
161
+ outro(`Problems or questions? Hop into the community on Discord at ${pinkText(terminalLink('https://directus.chat', 'https://directus.chat'))}`);
162
+ }
163
+ catch (error) {
164
+ catchError(error, {
165
+ context: { dir, flags, function: 'init' },
166
+ fatal: true,
167
+ logToFile: true,
168
+ });
169
+ }
170
+ return {
171
+ directusDir,
172
+ frontendDir: flags.frontend ? path.join(dir, flags.frontend) : undefined,
173
+ template,
174
+ };
175
+ }
176
+ /**
177
+ * Initialize a git repository
178
+ * @param targetDir - The directory to initialize the git repository in
179
+ * @returns void
180
+ */
181
+ async function initGit(targetDir) {
182
+ try {
183
+ await execa('git', ['init'], { cwd: targetDir });
184
+ }
185
+ catch (error) {
186
+ catchError(error, {
187
+ context: { function: 'initGit', targetDir },
188
+ fatal: false,
189
+ logToFile: true,
190
+ });
191
+ }
192
+ }
@@ -0,0 +1,30 @@
1
+ export interface InitOptions {
2
+ frontend?: string;
3
+ initGit?: boolean;
4
+ installDeps?: boolean;
5
+ programmatic?: boolean;
6
+ targetDir: string;
7
+ template: string;
8
+ }
9
+ export interface TemplateInfo {
10
+ frontends: string[];
11
+ hasDirectus: boolean;
12
+ name: string;
13
+ }
14
+ export interface InitResult {
15
+ directusUrl?: string;
16
+ error?: Error;
17
+ success: boolean;
18
+ }
19
+ export interface DirectusConfig {
20
+ adminEmail: string;
21
+ adminPassword: string;
22
+ port: number;
23
+ url: string;
24
+ }
25
+ export interface DockerConfig {
26
+ composeFile: string;
27
+ healthCheckEndpoint: string;
28
+ interval: number;
29
+ maxAttempts: number;
30
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,10 +1,6 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validateInteractiveFlags = exports.validateProgrammaticFlags = exports.loadFlags = void 0;
4
- const tslib_1 = require("tslib");
5
- const core_1 = require("@oclif/core");
6
- const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
7
- exports.loadFlags = [
1
+ import { ux } from '@oclif/core';
2
+ import catchError from '../utils/catch-error.js';
3
+ export const loadFlags = [
8
4
  'content',
9
5
  'dashboards',
10
6
  'extensions',
@@ -15,53 +11,51 @@ exports.loadFlags = [
15
11
  'settings',
16
12
  'users',
17
13
  ];
18
- function validateProgrammaticFlags(flags) {
14
+ export function validateProgrammaticFlags(flags) {
19
15
  const { directusToken, directusUrl, templateLocation, userEmail, userPassword } = flags;
20
16
  if (!directusUrl)
21
- core_1.ux.error('Directus URL is required for programmatic mode.');
17
+ ux.error('Directus URL is required for programmatic mode.');
22
18
  if (!directusToken && (!userEmail || !userPassword))
23
- core_1.ux.error('Either Directus token or email and password are required for programmatic mode.');
19
+ ux.error('Either Directus token or email and password are required for programmatic mode.');
24
20
  if (!templateLocation)
25
- core_1.ux.error('Template location is required for programmatic mode.');
21
+ ux.error('Template location is required for programmatic mode.');
26
22
  return flags.partial ? handlePartialFlags(flags) : setAllFlagsTrue(flags);
27
23
  }
28
- exports.validateProgrammaticFlags = validateProgrammaticFlags;
29
- function validateInteractiveFlags(flags) {
24
+ export function validateInteractiveFlags(flags) {
30
25
  return flags.partial ? handlePartialFlags(flags) : setAllFlagsTrue(flags);
31
26
  }
32
- exports.validateInteractiveFlags = validateInteractiveFlags;
33
27
  function handlePartialFlags(flags) {
34
- const enabledFlags = exports.loadFlags.filter(flag => flags[flag] === true);
35
- const disabledFlags = exports.loadFlags.filter(flag => flags[flag] === false);
28
+ const enabledFlags = loadFlags.filter(flag => flags[flag] === true);
29
+ const disabledFlags = loadFlags.filter(flag => flags[flag] === false);
36
30
  if (enabledFlags.length > 0) {
37
- for (const flag of exports.loadFlags)
31
+ for (const flag of loadFlags)
38
32
  flags[flag] = enabledFlags.includes(flag);
39
33
  }
40
34
  else if (disabledFlags.length > 0) {
41
- for (const flag of exports.loadFlags)
35
+ for (const flag of loadFlags)
42
36
  flags[flag] = !disabledFlags.includes(flag);
43
37
  }
44
38
  else {
45
39
  setAllFlagsTrue(flags);
46
40
  }
47
41
  handleDependencies(flags);
48
- if (!exports.loadFlags.some(flag => flags[flag])) {
49
- (0, catch_error_1.default)(new Error('When using --partial, at least one component must be loaded.'), { fatal: true });
42
+ if (!loadFlags.some(flag => flags[flag])) {
43
+ catchError(new Error('When using --partial, at least one component must be loaded.'), { fatal: true });
50
44
  }
51
45
  return flags;
52
46
  }
53
47
  function handleDependencies(flags) {
54
48
  if (flags.content && (!flags.schema || !flags.files)) {
55
49
  flags.schema = flags.files = true;
56
- core_1.ux.warn('Content loading requires schema and files. Enabling schema and files flags.');
50
+ ux.warn('Content loading requires schema and files. Enabling schema and files flags.');
57
51
  }
58
52
  if (flags.users && !flags.permissions) {
59
53
  flags.permissions = true;
60
- core_1.ux.warn('User loading requires permissions. Enabling permissions flag.');
54
+ ux.warn('User loading requires permissions. Enabling permissions flag.');
61
55
  }
62
56
  }
63
57
  function setAllFlagsTrue(flags) {
64
- for (const flag of exports.loadFlags)
58
+ for (const flag of loadFlags)
65
59
  flags[flag] = true;
66
60
  return flags;
67
61
  }
@@ -1,13 +1,2 @@
1
- interface ApplyFlags {
2
- content: boolean;
3
- dashboards: boolean;
4
- extensions: boolean;
5
- files: boolean;
6
- flows: boolean;
7
- permissions: boolean;
8
- schema: boolean;
9
- settings: boolean;
10
- users: boolean;
11
- }
1
+ import type { ApplyFlags } from './apply-flags.js';
12
2
  export default function apply(dir: string, flags: ApplyFlags): Promise<{}>;
13
- export {};
@@ -1,68 +1,64 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
- const core_1 = require("@oclif/core");
5
- const check_template_1 = tslib_1.__importDefault(require("../utils/check-template"));
6
- const load_access_1 = tslib_1.__importDefault(require("./load-access"));
7
- const load_collections_1 = tslib_1.__importDefault(require("./load-collections"));
8
- const load_dashboards_1 = tslib_1.__importDefault(require("./load-dashboards"));
9
- const load_data_1 = tslib_1.__importDefault(require("./load-data"));
10
- const load_extensions_1 = tslib_1.__importDefault(require("./load-extensions"));
11
- const load_files_1 = tslib_1.__importDefault(require("./load-files"));
12
- const load_flows_1 = tslib_1.__importDefault(require("./load-flows"));
13
- const load_folders_1 = tslib_1.__importDefault(require("./load-folders"));
14
- const load_permissions_1 = tslib_1.__importDefault(require("./load-permissions"));
15
- const load_policies_1 = tslib_1.__importDefault(require("./load-policies"));
16
- const load_presets_1 = tslib_1.__importDefault(require("./load-presets"));
17
- const load_relations_1 = tslib_1.__importDefault(require("./load-relations"));
18
- const load_roles_1 = tslib_1.__importDefault(require("./load-roles"));
19
- const load_settings_1 = tslib_1.__importDefault(require("./load-settings"));
20
- const load_translations_1 = tslib_1.__importDefault(require("./load-translations"));
21
- const load_users_1 = tslib_1.__importDefault(require("./load-users"));
22
- const update_required_fields_1 = tslib_1.__importDefault(require("./update-required-fields"));
23
- async function apply(dir, flags) {
24
- const source = dir + '/src';
25
- const isTemplateOk = await (0, check_template_1.default)(source);
1
+ import { ux } from '@oclif/core';
2
+ import checkTemplate from '../utils/check-template.js';
3
+ import loadAccess from './load-access.js';
4
+ import loadCollections from './load-collections.js';
5
+ import loadDashboards from './load-dashboards.js';
6
+ import loadData from './load-data.js';
7
+ import loadExtensions from './load-extensions.js';
8
+ import loadFiles from './load-files.js';
9
+ import loadFlows from './load-flows.js';
10
+ import loadFolders from './load-folders.js';
11
+ import loadPermissions from './load-permissions.js';
12
+ import loadPolicies from './load-policies.js';
13
+ import loadPresets from './load-presets.js';
14
+ import loadRelations from './load-relations.js';
15
+ import loadRoles from './load-roles.js';
16
+ import loadSettings from './load-settings.js';
17
+ import loadTranslations from './load-translations.js';
18
+ import loadUsers from './load-users.js';
19
+ import updateRequiredFields from './update-required-fields.js';
20
+ export default async function apply(dir, flags) {
21
+ const source = `${dir}/src`;
22
+ const isTemplateOk = await checkTemplate(source);
26
23
  if (!isTemplateOk) {
27
- core_1.ux.error('The template is missing the collections, fields, or relations files. Older templates are not supported in v0.4 of directus-template-cli. Try using v0.3 to load older templates npx directus-template-cli@0.3 apply or extract the template using latest version before applying. Exiting...');
24
+ ux.error('The template is missing the collections, fields, or relations files. Older templates are not supported in v0.4 of directus-template-cli. Try using v0.3 to load older templates npx directus-template-cli@0.3 apply or extract the template using latest version before applying. Exiting...');
28
25
  }
29
26
  if (flags.schema) {
30
- await (0, load_collections_1.default)(source);
31
- await (0, load_relations_1.default)(source);
27
+ await loadCollections(source);
28
+ await loadRelations(source);
32
29
  }
33
30
  if (flags.permissions || flags.users) {
34
- await (0, load_roles_1.default)(source);
35
- await (0, load_policies_1.default)(source);
36
- await (0, load_permissions_1.default)(source);
31
+ await loadRoles(source);
32
+ await loadPolicies(source);
33
+ await loadPermissions(source);
37
34
  if (flags.users) {
38
- await (0, load_users_1.default)(source);
35
+ await loadUsers(source);
39
36
  }
40
- await (0, load_access_1.default)(source);
37
+ await loadAccess(source);
41
38
  }
42
39
  if (flags.files) {
43
- await (0, load_folders_1.default)(source);
44
- await (0, load_files_1.default)(source);
40
+ await loadFolders(source);
41
+ await loadFiles(source);
45
42
  }
46
43
  if (flags.content) {
47
- await (0, load_data_1.default)(source);
44
+ await loadData(source);
48
45
  }
49
46
  if (flags.schema) {
50
- await (0, update_required_fields_1.default)(source);
47
+ await updateRequiredFields(source);
51
48
  }
52
49
  if (flags.dashboards) {
53
- await (0, load_dashboards_1.default)(source);
50
+ await loadDashboards(source);
54
51
  }
55
52
  if (flags.flows) {
56
- await (0, load_flows_1.default)(source);
53
+ await loadFlows(source);
57
54
  }
58
55
  if (flags.settings) {
59
- await (0, load_settings_1.default)(source);
60
- await (0, load_translations_1.default)(source);
61
- await (0, load_presets_1.default)(source);
56
+ await loadSettings(source);
57
+ await loadTranslations(source);
58
+ await loadPresets(source);
62
59
  }
63
60
  if (flags.extensions) {
64
- await (0, load_extensions_1.default)(source);
61
+ await loadExtensions(source);
65
62
  }
66
63
  return {};
67
64
  }
68
- exports.default = apply;
@@ -1,25 +1,22 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
- const core_1 = require("@oclif/core");
5
- const constants_1 = require("../constants");
6
- const sdk_1 = require("../sdk");
7
- const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
8
- const get_role_ids_1 = tslib_1.__importDefault(require("../utils/get-role-ids"));
9
- const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
10
- async function loadAccess(dir) {
11
- const access = (0, read_file_1.default)('access', dir);
12
- core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${access.length} accesses`));
1
+ import { ux } from '@oclif/core';
2
+ import { DIRECTUS_PINK } from '../constants.js';
3
+ import { api } from '../sdk.js';
4
+ import catchError from '../utils/catch-error.js';
5
+ import getRoleIds from '../utils/get-role-ids.js';
6
+ import readFile from '../utils/read-file.js';
7
+ export default async function loadAccess(dir) {
8
+ const access = readFile('access', dir);
9
+ ux.action.start(ux.colorize(DIRECTUS_PINK, `Loading ${access.length} accesses`));
13
10
  if (access && access.length > 0) {
14
11
  // Fetch existing accesses
15
- const existingAccesses = await sdk_1.api.client.request(() => ({
12
+ const existingAccesses = await api.client.request(() => ({
16
13
  method: 'GET',
17
14
  params: {
18
15
  limit: -1,
19
16
  },
20
17
  path: '/access',
21
18
  }));
22
- const { legacyAdminRoleId, newAdminRoleId } = await (0, get_role_ids_1.default)(dir);
19
+ const { legacyAdminRoleId, newAdminRoleId } = await getRoleIds(dir);
23
20
  const existingAccessById = new Map(existingAccesses.map(acc => [acc.id, acc]));
24
21
  const existingAccessByCompositeKey = new Map(existingAccesses.map(acc => [getCompositeKey(acc), acc]));
25
22
  for await (const acc of access) {
@@ -39,7 +36,7 @@ async function loadAccess(dir) {
39
36
  if (acc.role === legacyAdminRoleId) {
40
37
  acc.role = newAdminRoleId;
41
38
  }
42
- await sdk_1.api.client.request(() => ({
39
+ await api.client.request(() => ({
43
40
  body: JSON.stringify(acc),
44
41
  method: 'POST',
45
42
  path: '/access',
@@ -49,7 +46,7 @@ async function loadAccess(dir) {
49
46
  existingAccessByCompositeKey.set(compositeKey, acc);
50
47
  }
51
48
  catch (error) {
52
- (0, catch_error_1.default)(error, {
49
+ catchError(error, {
53
50
  context: {
54
51
  access: acc,
55
52
  operation: 'createAccess',
@@ -58,11 +55,9 @@ async function loadAccess(dir) {
58
55
  }
59
56
  }
60
57
  }
61
- core_1.ux.action.stop();
58
+ ux.action.stop();
62
59
  }
63
- exports.default = loadAccess;
64
60
  // Helper function to generate a composite key for each access
65
61
  function getCompositeKey(acc) {
66
- var _a, _b;
67
- return `${(_a = acc.role) !== null && _a !== void 0 ? _a : 'null'}-${(_b = acc.user) !== null && _b !== void 0 ? _b : 'null'}-${acc.policy}`;
62
+ return `${acc.role ?? 'null'}-${acc.user ?? 'null'}-${acc.policy}`;
68
63
  }
@@ -1,4 +1,6 @@
1
1
  /**
2
2
  * Load collections into the Directus instance
3
+ * @param dir - The directory to read the collections and fields from
4
+ * @returns {Promise<void>} - Returns nothing
3
5
  */
4
6
  export default function loadCollections(dir: string): Promise<void>;
@@ -1,48 +1,45 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
- const sdk_1 = require("@directus/sdk");
5
- const core_1 = require("@oclif/core");
6
- const constants_1 = require("../constants");
7
- const sdk_2 = require("../sdk");
8
- const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
9
- const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
1
+ import { createCollection, createField, readCollections, readFields, updateCollection, } from '@directus/sdk';
2
+ import { ux } from '@oclif/core';
3
+ import { DIRECTUS_PINK } from '../constants.js';
4
+ import { api } from '../sdk.js';
5
+ import catchError from '../utils/catch-error.js';
6
+ import readFile from '../utils/read-file.js';
10
7
  /**
11
8
  * Load collections into the Directus instance
9
+ * @param dir - The directory to read the collections and fields from
10
+ * @returns {Promise<void>} - Returns nothing
12
11
  */
13
- async function loadCollections(dir) {
14
- const collectionsToAdd = (0, read_file_1.default)('collections', dir);
15
- const fieldsToAdd = (0, read_file_1.default)('fields', dir);
16
- core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${collectionsToAdd.length} collections and ${fieldsToAdd.length} fields`));
12
+ export default async function loadCollections(dir) {
13
+ const collectionsToAdd = readFile('collections', dir);
14
+ const fieldsToAdd = readFile('fields', dir);
15
+ ux.action.start(ux.colorize(DIRECTUS_PINK, `Loading ${collectionsToAdd.length} collections and ${fieldsToAdd.length} fields`));
17
16
  await processCollections(collectionsToAdd, fieldsToAdd);
18
17
  await updateCollections(collectionsToAdd);
19
18
  await addCustomFieldsOnSystemCollections(fieldsToAdd);
20
- core_1.ux.action.stop();
19
+ ux.action.stop();
21
20
  }
22
- exports.default = loadCollections;
23
21
  async function processCollections(collectionsToAdd, fieldsToAdd) {
24
- const existingCollections = await sdk_2.api.client.request((0, sdk_1.readCollections)());
25
- const existingFields = await sdk_2.api.client.request((0, sdk_1.readFields)());
22
+ const existingCollections = await api.client.request(readCollections());
23
+ const existingFields = await api.client.request(readFields());
26
24
  for await (const collection of collectionsToAdd) {
27
25
  try {
28
26
  const existingCollection = existingCollections.find((c) => c.collection === collection.collection);
29
27
  await (existingCollection ? addNewFieldsToExistingCollection(collection.collection, fieldsToAdd, existingFields) : addNewCollectionWithFields(collection, fieldsToAdd));
30
28
  }
31
29
  catch (error) {
32
- (0, catch_error_1.default)(error);
30
+ catchError(error);
33
31
  }
34
32
  }
35
33
  }
36
34
  const removeRequiredorIsNullable = (field) => {
37
- var _a, _b, _c;
38
- if (((_a = field.meta) === null || _a === void 0 ? void 0 : _a.required) === true) {
35
+ if (field.meta?.required === true) {
39
36
  field.meta.required = false;
40
37
  }
41
- if (((_b = field.schema) === null || _b === void 0 ? void 0 : _b.is_nullable) === false) {
38
+ if (field.schema?.is_nullable === false) {
42
39
  // eslint-disable-next-line camelcase
43
40
  field.schema.is_nullable = true;
44
41
  }
45
- if (((_c = field.schema) === null || _c === void 0 ? void 0 : _c.is_unique) === true) {
42
+ if (field.schema?.is_unique === true) {
46
43
  // eslint-disable-next-line camelcase
47
44
  field.schema.is_unique = false;
48
45
  }
@@ -57,7 +54,7 @@ async function addNewCollectionWithFields(collection, allFields) {
57
54
  meta: { ...collection.meta },
58
55
  };
59
56
  delete collectionWithoutGroup.meta.group;
60
- await sdk_2.api.client.request((0, sdk_1.createCollection)(collectionWithoutGroup));
57
+ await api.client.request(createCollection(collectionWithoutGroup));
61
58
  }
62
59
  async function addNewFieldsToExistingCollection(collectionName, fieldsToAdd, existingFields) {
63
60
  const collectionFieldsToAdd = fieldsToAdd.filter(field => field.collection === collectionName)
@@ -66,11 +63,11 @@ async function addNewFieldsToExistingCollection(collectionName, fieldsToAdd, exi
66
63
  for await (const field of collectionFieldsToAdd) {
67
64
  if (!existingCollectionFields.some((existingField) => existingField.field === field.field)) {
68
65
  try {
69
- // @ts-ignore
70
- await sdk_2.api.client.request((0, sdk_1.createField)(collectionName, field));
66
+ // @ts-ignore - ignore
67
+ await api.client.request(createField(collectionName, field));
71
68
  }
72
69
  catch (error) {
73
- (0, catch_error_1.default)(error);
70
+ catchError(error);
74
71
  }
75
72
  }
76
73
  }
@@ -84,27 +81,27 @@ async function updateCollections(collections) {
84
81
  group: collection.meta.group,
85
82
  },
86
83
  };
87
- await sdk_2.api.client.request((0, sdk_1.updateCollection)(collection.collection, pl));
84
+ await api.client.request(updateCollection(collection.collection, pl));
88
85
  }
89
86
  }
90
87
  catch (error) {
91
- (0, catch_error_1.default)(error);
88
+ catchError(error);
92
89
  }
93
90
  }
94
91
  }
95
92
  async function addCustomFieldsOnSystemCollections(fields) {
96
93
  const customFields = fields.filter((field) => field.collection.startsWith('directus_'));
97
- const existingFields = await sdk_2.api.client.request((0, sdk_1.readFields)());
94
+ const existingFields = await api.client.request(readFields());
98
95
  for await (const field of customFields) {
99
96
  try {
100
97
  const fieldExists = existingFields.some((existingField) => existingField.collection === field.collection && existingField.field === field.field);
101
98
  if (!fieldExists) {
102
- // @ts-expect-error string
103
- await sdk_2.api.client.request((0, sdk_1.createField)(field.collection, field));
99
+ // @ts-ignore
100
+ await api.client.request(createField(field.collection, field));
104
101
  }
105
102
  }
106
103
  catch (error) {
107
- (0, catch_error_1.default)(error);
104
+ catchError(error);
108
105
  }
109
106
  }
110
107
  }