directus-template-cli 0.5.0-beta.2 → 0.5.0-beta.20
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 +176 -15
- package/dist/commands/apply.d.ts +41 -18
- package/dist/commands/apply.js +113 -122
- package/dist/commands/extract.d.ts +29 -1
- package/dist/commands/extract.js +76 -51
- package/dist/flags/common.d.ts +7 -0
- package/dist/flags/common.js +41 -0
- package/dist/lib/constants.d.ts +3 -0
- package/dist/lib/constants.js +6 -0
- package/dist/lib/extract/extract-access.js +5 -3
- package/dist/lib/extract/extract-assets.d.ts +0 -414
- package/dist/lib/extract/extract-assets.js +29 -25
- package/dist/lib/extract/extract-collections.js +5 -4
- package/dist/lib/extract/extract-content.d.ts +0 -2
- package/dist/lib/extract/extract-content.js +16 -15
- package/dist/lib/extract/extract-dashboards.js +8 -6
- package/dist/lib/extract/extract-extensions.js +5 -3
- package/dist/lib/extract/extract-fields.js +5 -4
- package/dist/lib/extract/extract-files.js +5 -3
- package/dist/lib/extract/extract-flows.js +8 -6
- package/dist/lib/extract/extract-folders.js +5 -3
- package/dist/lib/extract/extract-permissions.js +5 -3
- package/dist/lib/extract/extract-policies.js +5 -3
- package/dist/lib/extract/extract-presets.js +5 -3
- package/dist/lib/extract/extract-relations.js +5 -3
- package/dist/lib/extract/extract-roles.js +5 -3
- package/dist/lib/extract/extract-schema.js +6 -8
- package/dist/lib/extract/extract-settings.js +5 -3
- package/dist/lib/extract/extract-translations.js +6 -6
- package/dist/lib/extract/extract-users.js +6 -6
- package/dist/lib/load/apply-flags.d.ts +22 -0
- package/dist/lib/load/apply-flags.js +67 -0
- package/dist/lib/load/index.js +9 -5
- package/dist/lib/load/load-access.js +47 -41
- package/dist/lib/load/load-collections.js +61 -17
- package/dist/lib/load/load-dashboards.js +30 -30
- package/dist/lib/load/load-data.js +47 -11
- package/dist/lib/load/load-extensions.js +49 -43
- package/dist/lib/load/load-files.js +44 -51
- package/dist/lib/load/load-flows.d.ts +1 -1
- package/dist/lib/load/load-flows.js +44 -38
- package/dist/lib/load/load-folders.js +34 -35
- package/dist/lib/load/load-permissions.js +15 -17
- package/dist/lib/load/load-policies.js +23 -21
- package/dist/lib/load/load-presets.js +27 -26
- package/dist/lib/load/load-relations.js +19 -18
- package/dist/lib/load/load-roles.js +45 -45
- package/dist/lib/load/load-settings.js +39 -2
- package/dist/lib/load/load-translations.js +24 -24
- package/dist/lib/load/load-users.js +44 -34
- package/dist/lib/load/update-required-fields.d.ts +1 -0
- package/dist/lib/load/update-required-fields.js +24 -0
- package/dist/lib/sdk.d.ts +20 -2
- package/dist/lib/sdk.js +124 -9
- package/dist/lib/utils/auth.d.ts +26 -0
- package/dist/lib/utils/auth.js +48 -4
- package/dist/lib/utils/catch-error.d.ts +15 -2
- package/dist/lib/utils/catch-error.js +31 -25
- package/dist/lib/utils/get-template.d.ts +1 -0
- package/dist/lib/utils/get-template.js +42 -1
- package/dist/lib/utils/read-file.js +2 -1
- package/dist/lib/utils/read-templates.js +4 -2
- package/oclif.manifest.json +74 -28
- package/package.json +2 -2
- package/dist/lib/interfaces.d.ts +0 -8
- package/dist/lib/interfaces.js +0 -2
|
@@ -3,38 +3,38 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const sdk_1 = require("@directus/sdk");
|
|
5
5
|
const core_1 = require("@oclif/core");
|
|
6
|
+
const constants_1 = require("../constants");
|
|
6
7
|
const sdk_2 = require("../sdk");
|
|
7
8
|
const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
|
|
8
9
|
const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
9
10
|
async function loadTranslations(dir) {
|
|
10
|
-
core_1.ux.action.start('Loading translations');
|
|
11
11
|
const translations = (0, read_file_1.default)('translations', dir);
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
12
|
+
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${translations.length} translations`));
|
|
13
|
+
if (translations && translations.length > 0) {
|
|
14
|
+
// Fetch existing translations
|
|
15
|
+
const existingTranslations = await sdk_2.api.client.request((0, sdk_1.readTranslations)({
|
|
16
|
+
limit: -1,
|
|
17
|
+
}));
|
|
18
|
+
const existingTranslationKeys = new Set(existingTranslations.map(t => `${t.language}_${t.key}`));
|
|
19
|
+
const newTranslations = translations.filter(t => {
|
|
20
|
+
const key = `${t.language}_${t.key}`;
|
|
21
|
+
if (existingTranslationKeys.has(key)) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return true;
|
|
25
|
+
});
|
|
26
|
+
if (newTranslations.length > 0) {
|
|
27
|
+
try {
|
|
28
|
+
await sdk_2.api.client.request((0, sdk_1.createTranslations)(newTranslations));
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
(0, catch_error_1.default)(error);
|
|
32
|
+
}
|
|
22
33
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if (newTranslations.length > 0) {
|
|
26
|
-
try {
|
|
27
|
-
await sdk_2.api.client.request((0, sdk_1.createTranslations)(newTranslations));
|
|
28
|
-
core_1.ux.log(`Created ${newTranslations.length} new translations`);
|
|
34
|
+
else {
|
|
35
|
+
// ux.info('-- No new translations to create')
|
|
29
36
|
}
|
|
30
|
-
catch (error) {
|
|
31
|
-
(0, catch_error_1.default)(error);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
core_1.ux.log('No new translations to create');
|
|
36
37
|
}
|
|
37
38
|
core_1.ux.action.stop();
|
|
38
|
-
core_1.ux.log('Loaded translations');
|
|
39
39
|
}
|
|
40
40
|
exports.default = loadTranslations;
|
|
@@ -3,48 +3,58 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const sdk_1 = require("@directus/sdk");
|
|
5
5
|
const core_1 = require("@oclif/core");
|
|
6
|
+
const constants_1 = require("../constants");
|
|
6
7
|
const sdk_2 = require("../sdk");
|
|
7
8
|
const catch_error_1 = tslib_1.__importDefault(require("../utils/catch-error"));
|
|
8
9
|
const get_role_ids_1 = tslib_1.__importDefault(require("../utils/get-role-ids"));
|
|
9
10
|
const read_file_1 = tslib_1.__importDefault(require("../utils/read-file"));
|
|
10
11
|
async function loadUsers(dir) {
|
|
11
12
|
const users = (0, read_file_1.default)('users', dir);
|
|
12
|
-
core_1.ux.action.start(`Loading ${users.length} users`);
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
13
|
+
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Loading ${users.length} users`));
|
|
14
|
+
if (users && users.length > 0) {
|
|
15
|
+
const { legacyAdminRoleId, newAdminRoleId } = await (0, get_role_ids_1.default)(dir);
|
|
16
|
+
const existingUsers = await sdk_2.api.client.request((0, sdk_1.readUsers)({
|
|
17
|
+
limit: -1,
|
|
18
|
+
}));
|
|
19
|
+
const filteredUsers = users.map(user => {
|
|
20
|
+
// If the user is an admin, we need to change their role to the new admin role
|
|
21
|
+
const isAdmin = user.role === legacyAdminRoleId;
|
|
22
|
+
user.role = isAdmin ? newAdminRoleId : user.role;
|
|
23
|
+
// Delete the unneeded fields
|
|
24
|
+
delete user.last_page;
|
|
25
|
+
delete user.token;
|
|
26
|
+
delete user.policies;
|
|
27
|
+
// Delete passwords to prevent setting to *******
|
|
28
|
+
delete user.password;
|
|
29
|
+
return user;
|
|
30
|
+
});
|
|
31
|
+
for await (const user of filteredUsers) {
|
|
32
|
+
const existingUserWithSameId = existingUsers && Array.isArray(existingUsers)
|
|
33
|
+
? existingUsers.find(existing => existing.id === user.id)
|
|
34
|
+
: undefined;
|
|
35
|
+
const existingUserWithSameEmail = existingUsers && Array.isArray(existingUsers)
|
|
36
|
+
? existingUsers.find(existing => existing.email === user.email)
|
|
37
|
+
: undefined;
|
|
38
|
+
if (existingUserWithSameId) {
|
|
39
|
+
// Skip if there's an existing user with the same id
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (existingUserWithSameEmail) {
|
|
43
|
+
// Delete email if there's an existing user with the same email but different id
|
|
44
|
+
delete user.email;
|
|
45
|
+
}
|
|
46
|
+
if (user.email === null) {
|
|
47
|
+
// Delete email if it's null
|
|
48
|
+
delete user.email;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
await sdk_2.api.client.request((0, sdk_1.createUser)(user));
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
(0, catch_error_1.default)(error);
|
|
55
|
+
}
|
|
45
56
|
}
|
|
46
57
|
}
|
|
47
58
|
core_1.ux.action.stop();
|
|
48
|
-
core_1.ux.log('Loaded users');
|
|
49
59
|
}
|
|
50
60
|
exports.default = loadUsers;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function updateRequiredFields(dir: string): Promise<void>;
|
|
@@ -0,0 +1,24 @@
|
|
|
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"));
|
|
10
|
+
async function updateRequiredFields(dir) {
|
|
11
|
+
const fieldsToUpdate = (0, read_file_1.default)('fields', dir)
|
|
12
|
+
.filter(field => { var _a, _b; return field.meta.required === true || ((_a = field.schema) === null || _a === void 0 ? void 0 : _a.is_nullable) === false || ((_b = field.schema) === null || _b === void 0 ? void 0 : _b.is_unique) === true; });
|
|
13
|
+
core_1.ux.action.start(core_1.ux.colorize(constants_1.DIRECTUS_PINK, `Updating ${fieldsToUpdate.length} fields to required`));
|
|
14
|
+
for await (const field of fieldsToUpdate) {
|
|
15
|
+
try {
|
|
16
|
+
await sdk_2.api.client.request((0, sdk_1.updateField)(field.collection, field.field, { meta: { ...field.meta }, schema: { ...field.schema } }));
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
(0, catch_error_1.default)(error);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
core_1.ux.action.stop();
|
|
23
|
+
}
|
|
24
|
+
exports.default = updateRequiredFields;
|
package/dist/lib/sdk.d.ts
CHANGED
|
@@ -1,13 +1,31 @@
|
|
|
1
1
|
import type { AuthenticationClient, RestClient } from '@directus/sdk';
|
|
2
2
|
export interface Schema {
|
|
3
|
-
|
|
3
|
+
}
|
|
4
|
+
export declare class DirectusError extends Error {
|
|
5
|
+
errors: Array<{
|
|
6
|
+
extensions?: Record<string, unknown>;
|
|
7
|
+
message: string;
|
|
8
|
+
}>;
|
|
9
|
+
headers: Headers;
|
|
10
|
+
message: string;
|
|
11
|
+
response: Response;
|
|
12
|
+
status: number;
|
|
13
|
+
constructor(response: Response);
|
|
14
|
+
formatError(): string;
|
|
15
|
+
parseErrors(): Promise<void>;
|
|
4
16
|
}
|
|
5
17
|
declare class Api {
|
|
6
18
|
client: (RestClient<Schema> & AuthenticationClient<Schema>) | undefined;
|
|
19
|
+
private authData;
|
|
7
20
|
private limiter;
|
|
8
21
|
constructor();
|
|
22
|
+
getToken(): null | string;
|
|
9
23
|
initialize(url: string): void;
|
|
10
|
-
|
|
24
|
+
login(email: string, password: string): Promise<void>;
|
|
25
|
+
loginWithToken(token: string): Promise<void>;
|
|
26
|
+
logout(): Promise<void>;
|
|
27
|
+
refreshToken(): Promise<void>;
|
|
28
|
+
private enhancedFetch;
|
|
11
29
|
}
|
|
12
30
|
declare const api: Api;
|
|
13
31
|
export { api };
|
package/dist/lib/sdk.js
CHANGED
|
@@ -1,32 +1,147 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.api = void 0;
|
|
3
|
+
exports.api = exports.DirectusError = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const sdk_1 = require("@directus/sdk");
|
|
6
|
+
const core_1 = require("@oclif/core");
|
|
6
7
|
const bottleneck_1 = tslib_1.__importDefault(require("bottleneck"));
|
|
8
|
+
class DirectusError extends Error {
|
|
9
|
+
constructor(response) {
|
|
10
|
+
super(response.statusText);
|
|
11
|
+
this.name = 'DirectusError';
|
|
12
|
+
this.headers = response.headers;
|
|
13
|
+
this.status = response.status;
|
|
14
|
+
this.response = response;
|
|
15
|
+
this.errors = [];
|
|
16
|
+
this.message = response.statusText;
|
|
17
|
+
}
|
|
18
|
+
formatError() {
|
|
19
|
+
if (this.errors.length === 0) {
|
|
20
|
+
return `Directus Error: ${this.message} (Status: ${this.status})`;
|
|
21
|
+
}
|
|
22
|
+
const { extensions, message } = this.errors[0];
|
|
23
|
+
let formattedError = `Directus Error: ${message.trim()} (Status: ${this.status})`;
|
|
24
|
+
if (extensions) {
|
|
25
|
+
formattedError += ` ${JSON.stringify(extensions)}`;
|
|
26
|
+
}
|
|
27
|
+
return formattedError;
|
|
28
|
+
}
|
|
29
|
+
async parseErrors() {
|
|
30
|
+
try {
|
|
31
|
+
const data = await this.response.json();
|
|
32
|
+
if (data && Array.isArray(data.errors)) {
|
|
33
|
+
this.errors = data.errors;
|
|
34
|
+
this.message = this.formatError();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// If parsing fails, keep the errors array empty
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.DirectusError = DirectusError;
|
|
7
43
|
class Api {
|
|
8
44
|
constructor() {
|
|
45
|
+
this.authData = null;
|
|
9
46
|
this.limiter = new bottleneck_1.default({
|
|
10
|
-
maxConcurrent: 10,
|
|
11
|
-
minTime: 100, // 100ms between requests
|
|
12
|
-
|
|
13
|
-
|
|
47
|
+
maxConcurrent: 10,
|
|
48
|
+
minTime: 100, // Ensure at least 100ms between requests
|
|
49
|
+
reservoir: 50, // Reservoir to handle the default rate limiter of 50 requests per second
|
|
50
|
+
reservoirRefreshAmount: 50,
|
|
51
|
+
reservoirRefreshInterval: 1000, // Refill 50 requests every 1 second
|
|
52
|
+
retryCount: 3, // Retry a maximum of 3 times
|
|
53
|
+
});
|
|
54
|
+
this.limiter.on('failed', async (error, jobInfo) => {
|
|
55
|
+
var _a;
|
|
56
|
+
if (error instanceof DirectusError) {
|
|
57
|
+
const retryAfter = (_a = error.headers) === null || _a === void 0 ? void 0 : _a.get('Retry-After');
|
|
58
|
+
const statusCode = error.status;
|
|
59
|
+
if (statusCode === 429) {
|
|
60
|
+
const delay = retryAfter ? Number.parseInt(retryAfter, 10) * 1000 : 60000;
|
|
61
|
+
core_1.ux.log(`${core_1.ux.colorize('dim', '--')} Rate limited. Retrying after ${delay}ms`);
|
|
62
|
+
return delay;
|
|
63
|
+
}
|
|
64
|
+
if (statusCode === 503) {
|
|
65
|
+
const delay = retryAfter ? Number.parseInt(retryAfter, 10) * 1000 : 5000;
|
|
66
|
+
core_1.ux.log(`${core_1.ux.colorize('dim', '--')} Server under pressure. Retrying after ${delay}ms`);
|
|
67
|
+
return delay;
|
|
68
|
+
}
|
|
69
|
+
// If the status code is 400 or 401, we don't want to retry
|
|
70
|
+
if (statusCode === 400 || statusCode === 401) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// For other errors, use exponential backoff, but only if we haven't exceeded retryCount
|
|
75
|
+
if (jobInfo.retryCount < 3) {
|
|
76
|
+
const delay = Math.min(1000 * 2 ** jobInfo.retryCount, 30000);
|
|
77
|
+
core_1.ux.log(`${core_1.ux.colorize('dim', '--')} Request failed. Retrying after ${delay}ms`);
|
|
78
|
+
return delay;
|
|
79
|
+
}
|
|
80
|
+
core_1.ux.log(`${core_1.ux.colorize('dim', '--')} Max retries reached, not retrying further`);
|
|
81
|
+
});
|
|
82
|
+
this.limiter.on('retry', (error, jobInfo) => {
|
|
83
|
+
core_1.ux.log(`${core_1.ux.colorize('dim', '--')} Retrying job (attempt ${jobInfo.retryCount + 1})`);
|
|
84
|
+
});
|
|
85
|
+
this.limiter.on('depleted', empty => {
|
|
86
|
+
if (empty) {
|
|
87
|
+
core_1.ux.log(`${core_1.ux.colorize('dim', '--')} Rate limit quota depleted. Requests will be queued.`);
|
|
88
|
+
}
|
|
14
89
|
});
|
|
15
90
|
}
|
|
91
|
+
getToken() {
|
|
92
|
+
var _a, _b;
|
|
93
|
+
return (_b = (_a = this.authData) === null || _a === void 0 ? void 0 : _a.access_token) !== null && _b !== void 0 ? _b : null;
|
|
94
|
+
}
|
|
16
95
|
initialize(url) {
|
|
17
96
|
this.client = (0, sdk_1.createDirectus)(url, {
|
|
18
97
|
globals: {
|
|
19
|
-
fetch:
|
|
98
|
+
fetch: this.limiter.wrap(this.enhancedFetch),
|
|
20
99
|
},
|
|
21
100
|
})
|
|
22
101
|
.with((0, sdk_1.rest)())
|
|
23
|
-
.with((0, sdk_1.authentication)(
|
|
102
|
+
.with((0, sdk_1.authentication)('json', {
|
|
103
|
+
autoRefresh: true,
|
|
104
|
+
storage: {
|
|
105
|
+
get: () => this.authData,
|
|
106
|
+
set: data => {
|
|
107
|
+
this.authData = data;
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
}));
|
|
24
111
|
}
|
|
25
|
-
|
|
112
|
+
async login(email, password) {
|
|
26
113
|
if (!this.client) {
|
|
27
114
|
throw new Error('API client is not initialized. Call initialize() first.');
|
|
28
115
|
}
|
|
29
|
-
this.client.
|
|
116
|
+
await this.client.login(email, password);
|
|
117
|
+
}
|
|
118
|
+
async loginWithToken(token) {
|
|
119
|
+
if (!this.client) {
|
|
120
|
+
throw new Error('API client is not initialized. Call initialize() first.');
|
|
121
|
+
}
|
|
122
|
+
await this.client.setToken(token);
|
|
123
|
+
}
|
|
124
|
+
async logout() {
|
|
125
|
+
if (!this.client) {
|
|
126
|
+
throw new Error('API client is not initialized. Call initialize() first.');
|
|
127
|
+
}
|
|
128
|
+
await this.client.logout();
|
|
129
|
+
this.authData = null;
|
|
130
|
+
}
|
|
131
|
+
async refreshToken() {
|
|
132
|
+
if (!this.client) {
|
|
133
|
+
throw new Error('API client is not initialized. Call initialize() first.');
|
|
134
|
+
}
|
|
135
|
+
await this.client.refresh();
|
|
136
|
+
}
|
|
137
|
+
async enhancedFetch(...args) {
|
|
138
|
+
const response = await fetch(...args);
|
|
139
|
+
if (!response.ok) {
|
|
140
|
+
const error = new DirectusError(response);
|
|
141
|
+
await error.parseErrors();
|
|
142
|
+
throw error;
|
|
143
|
+
}
|
|
144
|
+
return response;
|
|
30
145
|
}
|
|
31
146
|
}
|
|
32
147
|
const api = new Api();
|
package/dist/lib/utils/auth.d.ts
CHANGED
|
@@ -1,2 +1,28 @@
|
|
|
1
|
+
interface AuthFlags {
|
|
2
|
+
directusToken?: string;
|
|
3
|
+
directusUrl: string;
|
|
4
|
+
userEmail?: string;
|
|
5
|
+
userPassword?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Get the Directus URL from the user
|
|
9
|
+
* @returns The Directus URL
|
|
10
|
+
*/
|
|
1
11
|
export declare function getDirectusUrl(): Promise<string>;
|
|
12
|
+
/**
|
|
13
|
+
* Get the Directus token from the user
|
|
14
|
+
* @param directusUrl - The Directus URL
|
|
15
|
+
* @returns The Directus token
|
|
16
|
+
*/
|
|
2
17
|
export declare function getDirectusToken(directusUrl: string): Promise<string>;
|
|
18
|
+
/**
|
|
19
|
+
* Initialize the Directus API with the provided flags
|
|
20
|
+
* @param flags - The validated ApplyFlags
|
|
21
|
+
*/
|
|
22
|
+
export declare function initializeDirectusApi(flags: AuthFlags): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Validate the authentication flags
|
|
25
|
+
* @param flags - The AuthFlags
|
|
26
|
+
*/
|
|
27
|
+
export declare function validateAuthFlags(flags: AuthFlags): void;
|
|
28
|
+
export {};
|
package/dist/lib/utils/auth.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getDirectusToken = exports.getDirectusUrl = void 0;
|
|
3
|
+
exports.validateAuthFlags = exports.initializeDirectusApi = exports.getDirectusToken = exports.getDirectusUrl = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const sdk_1 = require("@directus/sdk");
|
|
6
6
|
const core_1 = require("@oclif/core");
|
|
7
7
|
const sdk_2 = require("../sdk");
|
|
8
8
|
const catch_error_1 = tslib_1.__importDefault(require("./catch-error"));
|
|
9
9
|
const validate_url_1 = tslib_1.__importDefault(require("./validate-url"));
|
|
10
|
+
/**
|
|
11
|
+
* Get the Directus URL from the user
|
|
12
|
+
* @returns The Directus URL
|
|
13
|
+
*/
|
|
10
14
|
async function getDirectusUrl() {
|
|
11
15
|
const directusUrl = await core_1.ux.prompt('What is your Directus URL?', { default: 'http://localhost:8055' });
|
|
12
16
|
// Validate URL
|
|
@@ -18,13 +22,17 @@ async function getDirectusUrl() {
|
|
|
18
22
|
return directusUrl;
|
|
19
23
|
}
|
|
20
24
|
exports.getDirectusUrl = getDirectusUrl;
|
|
25
|
+
/**
|
|
26
|
+
* Get the Directus token from the user
|
|
27
|
+
* @param directusUrl - The Directus URL
|
|
28
|
+
* @returns The Directus token
|
|
29
|
+
*/
|
|
21
30
|
async function getDirectusToken(directusUrl) {
|
|
22
31
|
const directusToken = await core_1.ux.prompt('What is your Directus Admin Token?');
|
|
23
|
-
// Validate token
|
|
32
|
+
// Validate token by fetching the user
|
|
24
33
|
try {
|
|
25
|
-
sdk_2.api.
|
|
34
|
+
await sdk_2.api.loginWithToken(directusToken);
|
|
26
35
|
const response = await sdk_2.api.client.request((0, sdk_1.readMe)());
|
|
27
|
-
core_1.ux.log(`Logged in as ${response.first_name} ${response.last_name}`);
|
|
28
36
|
return directusToken;
|
|
29
37
|
}
|
|
30
38
|
catch (error) {
|
|
@@ -39,3 +47,39 @@ async function getDirectusToken(directusUrl) {
|
|
|
39
47
|
}
|
|
40
48
|
}
|
|
41
49
|
exports.getDirectusToken = getDirectusToken;
|
|
50
|
+
/**
|
|
51
|
+
* Initialize the Directus API with the provided flags
|
|
52
|
+
* @param flags - The validated ApplyFlags
|
|
53
|
+
*/
|
|
54
|
+
async function initializeDirectusApi(flags) {
|
|
55
|
+
sdk_2.api.initialize(flags.directusUrl);
|
|
56
|
+
try {
|
|
57
|
+
if (flags.directusToken) {
|
|
58
|
+
await sdk_2.api.loginWithToken(flags.directusToken);
|
|
59
|
+
}
|
|
60
|
+
else if (flags.userEmail && flags.userPassword) {
|
|
61
|
+
await sdk_2.api.login(flags.userEmail, flags.userPassword);
|
|
62
|
+
}
|
|
63
|
+
const response = await sdk_2.api.client.request((0, sdk_1.readMe)());
|
|
64
|
+
core_1.ux.log(`-- Logged in as ${response.first_name} ${response.last_name}`);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
(0, catch_error_1.default)('-- Unable to authenticate with the provided credentials. Please check your credentials.', {
|
|
68
|
+
fatal: true,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
exports.initializeDirectusApi = initializeDirectusApi;
|
|
73
|
+
/**
|
|
74
|
+
* Validate the authentication flags
|
|
75
|
+
* @param flags - The AuthFlags
|
|
76
|
+
*/
|
|
77
|
+
function validateAuthFlags(flags) {
|
|
78
|
+
if (!flags.directusUrl) {
|
|
79
|
+
core_1.ux.error('Directus URL is required.');
|
|
80
|
+
}
|
|
81
|
+
if (!flags.directusToken && (!flags.userEmail || !flags.userPassword)) {
|
|
82
|
+
core_1.ux.error('Either Directus token or email and password are required.');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
exports.validateAuthFlags = validateAuthFlags;
|
|
@@ -1,6 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Options for configuring the error handler behavior.
|
|
3
|
+
*/
|
|
4
|
+
interface ErrorHandlerOptions {
|
|
5
|
+
/** Additional context to be included in the error log. */
|
|
2
6
|
context?: Record<string, any>;
|
|
7
|
+
/** If true, the error will be treated as fatal and the process will exit. */
|
|
3
8
|
fatal?: boolean;
|
|
9
|
+
/** If true, the error will be logged to a file. */
|
|
10
|
+
logToFile?: boolean;
|
|
4
11
|
}
|
|
5
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Handles errors by formatting them and optionally logging to console and file.
|
|
14
|
+
* @param error - The error to be handled.
|
|
15
|
+
* @param options - Configuration options for error handling.
|
|
16
|
+
* @returns void
|
|
17
|
+
*/
|
|
18
|
+
export default function catchError(error: unknown, options?: ErrorHandlerOptions): void;
|
|
6
19
|
export {};
|
|
@@ -1,35 +1,41 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const core_1 = require("@oclif/core");
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
const sdk_1 = require("../sdk");
|
|
5
|
+
const logger_1 = require("../utils/logger");
|
|
6
|
+
/**
|
|
7
|
+
* Handles errors by formatting them and optionally logging to console and file.
|
|
8
|
+
* @param error - The error to be handled.
|
|
9
|
+
* @param options - Configuration options for error handling.
|
|
10
|
+
* @returns void
|
|
11
|
+
*/
|
|
12
|
+
function catchError(error, options = {}) {
|
|
13
|
+
const { context = {}, fatal = false, logToFile = true } = options;
|
|
14
|
+
let errorMessage;
|
|
15
|
+
if (error instanceof sdk_1.DirectusError) {
|
|
16
|
+
errorMessage = error.message;
|
|
17
|
+
}
|
|
18
|
+
else if (error instanceof Error) {
|
|
19
|
+
errorMessage = `Error: ${error.message}`;
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
errorMessage = `Unknown error: ${JSON.stringify(error)}`;
|
|
23
|
+
}
|
|
24
|
+
// Format the error message with context if provided
|
|
13
25
|
const formattedMessage = [
|
|
14
|
-
contextString && `Context: ${contextString}`,
|
|
15
26
|
errorMessage,
|
|
27
|
+
Object.keys(context).length > 0 && `Context: ${JSON.stringify(context)}`,
|
|
16
28
|
].filter(Boolean).join('\n');
|
|
17
|
-
|
|
29
|
+
// Log the error message to the console with the appropriate color
|
|
30
|
+
if (fatal) {
|
|
31
|
+
// ux.error exits the process with a non-zero code
|
|
32
|
+
core_1.ux.error(formattedMessage);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
core_1.ux.warn(formattedMessage);
|
|
36
|
+
}
|
|
18
37
|
if (logToFile) {
|
|
19
|
-
logger_1.logger.log('error', errorMessage,
|
|
38
|
+
logger_1.logger.log('error', errorMessage, context);
|
|
20
39
|
}
|
|
21
40
|
}
|
|
22
41
|
exports.default = catchError;
|
|
23
|
-
function isDirectusError(error) {
|
|
24
|
-
// @ts-ignore
|
|
25
|
-
return error && Array.isArray(error.errors) && error.errors.length > 0;
|
|
26
|
-
}
|
|
27
|
-
function formatDirectusError(error) {
|
|
28
|
-
var _a;
|
|
29
|
-
const status = ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) || 'Unknown';
|
|
30
|
-
const { extensions, message } = error.errors[0];
|
|
31
|
-
return `Directus Error: ${message.trim()}${extensions ? ` (${JSON.stringify(extensions)})` : ''} (Status: ${status})`;
|
|
32
|
-
}
|
|
33
|
-
function formatGenericError(error) {
|
|
34
|
-
return `Error: ${error.message}`;
|
|
35
|
-
}
|
|
@@ -4,5 +4,6 @@ interface Template {
|
|
|
4
4
|
}
|
|
5
5
|
export declare function getCommunityTemplates(): Promise<Template[]>;
|
|
6
6
|
export declare function getLocalTemplate(localTemplateDir: string): Promise<Template>;
|
|
7
|
+
export declare function getInteractiveLocalTemplate(localTemplateDir: string): Promise<Template[]>;
|
|
7
8
|
export declare function getGithubTemplate(ghTemplateUrl: string): Promise<Template>;
|
|
8
9
|
export {};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getGithubTemplate = exports.getLocalTemplate = exports.getCommunityTemplates = void 0;
|
|
3
|
+
exports.getGithubTemplate = exports.getInteractiveLocalTemplate = exports.getLocalTemplate = exports.getCommunityTemplates = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const giget_1 = require("giget");
|
|
6
|
+
const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
|
|
6
7
|
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
7
8
|
const path_1 = tslib_1.__importDefault(require("./path"));
|
|
8
9
|
const read_templates_1 = require("./read-templates");
|
|
@@ -33,6 +34,46 @@ async function getLocalTemplate(localTemplateDir) {
|
|
|
33
34
|
return (0, read_templates_1.readTemplate)(resolvedDir);
|
|
34
35
|
}
|
|
35
36
|
exports.getLocalTemplate = getLocalTemplate;
|
|
37
|
+
async function getInteractiveLocalTemplate(localTemplateDir) {
|
|
38
|
+
const resolvedDir = (0, path_1.default)(localTemplateDir);
|
|
39
|
+
if (!resolvedDir) {
|
|
40
|
+
throw new Error('Directory does not exist.');
|
|
41
|
+
}
|
|
42
|
+
const directTemplate = await (0, read_templates_1.readTemplate)(resolvedDir);
|
|
43
|
+
if (directTemplate) {
|
|
44
|
+
return [directTemplate];
|
|
45
|
+
}
|
|
46
|
+
const templates = await (0, read_templates_1.readAllTemplates)(resolvedDir);
|
|
47
|
+
if (templates.length === 0) {
|
|
48
|
+
// If no templates found, search nested directories
|
|
49
|
+
const nestedTemplates = await findNestedTemplates(resolvedDir, 2);
|
|
50
|
+
if (nestedTemplates.length === 0) {
|
|
51
|
+
throw new Error('No valid templates found in the specified directory or its subdirectories.');
|
|
52
|
+
}
|
|
53
|
+
return nestedTemplates;
|
|
54
|
+
}
|
|
55
|
+
return templates;
|
|
56
|
+
}
|
|
57
|
+
exports.getInteractiveLocalTemplate = getInteractiveLocalTemplate;
|
|
58
|
+
async function findNestedTemplates(dir, depth) {
|
|
59
|
+
if (depth === 0)
|
|
60
|
+
return [];
|
|
61
|
+
const templates = [];
|
|
62
|
+
const entries = await node_fs_1.default.promises.readdir(dir, { withFileTypes: true });
|
|
63
|
+
for (const entry of entries) {
|
|
64
|
+
if (entry.isDirectory()) {
|
|
65
|
+
const fullPath = node_path_1.default.join(dir, entry.name);
|
|
66
|
+
const dirTemplates = await (0, read_templates_1.readAllTemplates)(fullPath);
|
|
67
|
+
templates.push(...dirTemplates);
|
|
68
|
+
if (dirTemplates.length === 0 && depth > 1) {
|
|
69
|
+
// If no templates found and we can go deeper, search subdirectories
|
|
70
|
+
const nestedTemplates = await findNestedTemplates(fullPath, depth - 1);
|
|
71
|
+
templates.push(...nestedTemplates);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return templates;
|
|
76
|
+
}
|
|
36
77
|
async function getGithubTemplate(ghTemplateUrl) {
|
|
37
78
|
try {
|
|
38
79
|
const ghString = await (0, transform_github_url_1.transformGitHubUrl)(ghTemplateUrl);
|
|
@@ -3,10 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
|
|
5
5
|
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
6
|
+
const catch_error_1 = tslib_1.__importDefault(require("./catch-error"));
|
|
6
7
|
function readFile(file, dir) {
|
|
7
8
|
const filePath = node_path_1.default.join(dir, `${file}.json`); // Use path.join for proper path resolution
|
|
8
9
|
if (!node_fs_1.default.existsSync(filePath)) {
|
|
9
|
-
|
|
10
|
+
(0, catch_error_1.default)(`File not found: ${filePath}`);
|
|
10
11
|
}
|
|
11
12
|
const fileContents = node_fs_1.default.readFileSync(filePath, 'utf8');
|
|
12
13
|
const obj = JSON.parse(fileContents);
|