@jungvonmatt/contentful-config 3.0.0
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/LICENSE +21 -0
- package/README.md +51 -0
- package/dist/contentful.d.ts +19 -0
- package/dist/contentful.js +62 -0
- package/dist/contentful.js.map +1 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.js +113 -0
- package/dist/index.js.map +1 -0
- package/package.json +45 -0
- package/src/contentful.ts +124 -0
- package/src/index.ts +138 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 Jung von Matt TECH (https://www.jvm.com/)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
[![NPM version][npm-image]][npm-url]
|
|
2
|
+
|
|
3
|
+
# JvM Contentful config loader
|
|
4
|
+
|
|
5
|
+
Tool for loading and managing Contentful configurations with support for environment variables and interactive prompts.
|
|
6
|
+
|
|
7
|
+
## Getting started
|
|
8
|
+
|
|
9
|
+
### Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @jungvonmatt/contentful-config
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
### Basic Example
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
import { loadContentfulConfig } from '@jungvonmatt/contentful-config';
|
|
21
|
+
|
|
22
|
+
// Load configuration from multiple sources:
|
|
23
|
+
// - contentful-cli configuration file (~/.contentfulrc.json)
|
|
24
|
+
// - environment variables (CONTENTFUL_SPACE_ID, etc.)
|
|
25
|
+
// - project configuration files (myapp.config.js, .myapprc, etc.)
|
|
26
|
+
const { config } = await loadContentfulConfig('myapp');
|
|
27
|
+
|
|
28
|
+
console.log(config.spaceId); // Contentful Space ID
|
|
29
|
+
console.log(config.environmentId); // Contentful Environment ID (defaults to 'master')
|
|
30
|
+
console.log(config.accessToken); // Content Delivery API Token
|
|
31
|
+
console.log(config.previewAccessToken); // Content Preview API Token
|
|
32
|
+
console.log(config.managementToken); // Content Management API Token
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### With Required Values
|
|
36
|
+
|
|
37
|
+
```js
|
|
38
|
+
import { loadContentfulConfig } from '@jungvonmatt/contentful-config';
|
|
39
|
+
|
|
40
|
+
// If required values are not found in configuration files or
|
|
41
|
+
// environment variables, an interactive prompt will be displayed
|
|
42
|
+
const { config } = await loadContentfulConfig('myapp', {
|
|
43
|
+
required: ['spaceId', 'accessToken']
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// The configuration now contains all required values,
|
|
47
|
+
// either from existing sources or user input
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
[npm-url]: https://www.npmjs.com/package/@jungvonmatt/contentful-config
|
|
51
|
+
[npm-image]: https://img.shields.io/npm/v/@jungvonmatt/contentful-config.svg
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { SetRequired } from 'type-fest';
|
|
2
|
+
import type { ClientOptions, Space } from 'contentful-management';
|
|
3
|
+
import contentful from 'contentful-management';
|
|
4
|
+
export type ContentfulOptions = {
|
|
5
|
+
accessToken: ClientOptions['accessToken'];
|
|
6
|
+
host?: ClientOptions['host'];
|
|
7
|
+
managementToken?: ClientOptions['accessToken'];
|
|
8
|
+
previewAccessToken?: ClientOptions['accessToken'];
|
|
9
|
+
environmentId?: string;
|
|
10
|
+
activeEnvironmentId?: string;
|
|
11
|
+
spaceId?: string;
|
|
12
|
+
activeSpaceId?: string;
|
|
13
|
+
};
|
|
14
|
+
export declare const getSpaces: (options: ContentfulOptions) => Promise<Space[]>;
|
|
15
|
+
export declare const getSpace: (options: SetRequired<ContentfulOptions, "spaceId">) => Promise<Space>;
|
|
16
|
+
export declare const getEnvironments: (options: SetRequired<ContentfulOptions, "spaceId">) => Promise<contentful.Environment[]>;
|
|
17
|
+
export declare const getEnvironment: (options: SetRequired<ContentfulOptions, "spaceId" | "environmentId">) => Promise<contentful.Environment>;
|
|
18
|
+
export declare const getApiKey: (options: SetRequired<ContentfulOptions, "spaceId">) => Promise<string>;
|
|
19
|
+
export declare const getPreviewApiKey: (options: SetRequired<ContentfulOptions, "spaceId">) => Promise<string>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import contentful from 'contentful-management';
|
|
2
|
+
let client;
|
|
3
|
+
const getClient = (options) => {
|
|
4
|
+
const { accessToken, managementToken, host } = options || {};
|
|
5
|
+
if (client) {
|
|
6
|
+
return client;
|
|
7
|
+
}
|
|
8
|
+
const params = {
|
|
9
|
+
accessToken: managementToken || accessToken,
|
|
10
|
+
};
|
|
11
|
+
if (host) {
|
|
12
|
+
params.host = host;
|
|
13
|
+
}
|
|
14
|
+
if (params.accessToken) {
|
|
15
|
+
client = contentful.createClient(params);
|
|
16
|
+
return client;
|
|
17
|
+
}
|
|
18
|
+
throw new Error('You need to login first. Run npx contentful login or pass the contentful management token');
|
|
19
|
+
};
|
|
20
|
+
export const getSpaces = async (options) => {
|
|
21
|
+
const client = getClient(options);
|
|
22
|
+
const { items: spaces } = await client.getSpaces();
|
|
23
|
+
return spaces;
|
|
24
|
+
};
|
|
25
|
+
export const getSpace = async (options) => {
|
|
26
|
+
const { spaceId } = options || {};
|
|
27
|
+
const client = getClient(options);
|
|
28
|
+
return client.getSpace(spaceId);
|
|
29
|
+
};
|
|
30
|
+
export const getEnvironments = async (options) => {
|
|
31
|
+
const space = await getSpace(options);
|
|
32
|
+
const { items: environments } = await space.getEnvironments();
|
|
33
|
+
return environments;
|
|
34
|
+
};
|
|
35
|
+
export const getEnvironment = async (options) => {
|
|
36
|
+
const { environmentId, spaceId } = options || {};
|
|
37
|
+
const space = await getSpace(options);
|
|
38
|
+
const { items: environments } = await space.getEnvironments();
|
|
39
|
+
const environmentIds = (environments || []).map((env) => env.sys.id);
|
|
40
|
+
if (environmentId && environmentIds.includes(environmentId)) {
|
|
41
|
+
return space.getEnvironment(environmentId);
|
|
42
|
+
}
|
|
43
|
+
if (environmentId && !environmentIds.includes(environmentId)) {
|
|
44
|
+
throw new Error(`Environment "${environmentId}" is not available in space ${spaceId}"`);
|
|
45
|
+
}
|
|
46
|
+
throw new Error('Missing required parameter: environmentId');
|
|
47
|
+
};
|
|
48
|
+
export const getApiKey = async (options) => {
|
|
49
|
+
const space = await getSpace(options);
|
|
50
|
+
const { items: apiKeys = [] } = (await space.getApiKeys()) || {};
|
|
51
|
+
const [apiKey] = apiKeys;
|
|
52
|
+
const { accessToken } = apiKey || {};
|
|
53
|
+
return accessToken;
|
|
54
|
+
};
|
|
55
|
+
export const getPreviewApiKey = async (options) => {
|
|
56
|
+
const space = await getSpace(options);
|
|
57
|
+
const { items: previewApiKeys = [] } = await space.getPreviewApiKeys();
|
|
58
|
+
const [previewApiKey] = previewApiKeys;
|
|
59
|
+
const { accessToken: previewAccessToken } = previewApiKey;
|
|
60
|
+
return previewAccessToken;
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=contentful.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contentful.js","sourceRoot":"","sources":["../src/contentful.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { LoadConfigOptions } from '@jungvonmatt/config-loader';
|
|
2
|
+
import { type ContentfulOptions } from './contentful.js';
|
|
3
|
+
export declare const getPromts: (data: Partial<ContentfulOptions>) => ({
|
|
4
|
+
type: string;
|
|
5
|
+
name: string;
|
|
6
|
+
message: string;
|
|
7
|
+
initial: string | (() => Promise<string>);
|
|
8
|
+
choices?: undefined;
|
|
9
|
+
skip?: undefined;
|
|
10
|
+
} | {
|
|
11
|
+
type: string;
|
|
12
|
+
name: string;
|
|
13
|
+
message: string;
|
|
14
|
+
choices: (answers: Partial<ContentfulOptions>) => Promise<{
|
|
15
|
+
name: string;
|
|
16
|
+
value: string;
|
|
17
|
+
}[]>;
|
|
18
|
+
initial: string;
|
|
19
|
+
skip?: undefined;
|
|
20
|
+
} | {
|
|
21
|
+
type: string;
|
|
22
|
+
name: string;
|
|
23
|
+
message: string;
|
|
24
|
+
choices: (answers: Partial<ContentfulOptions>) => Promise<string[]>;
|
|
25
|
+
initial: string;
|
|
26
|
+
skip?: undefined;
|
|
27
|
+
} | {
|
|
28
|
+
type: string;
|
|
29
|
+
name: string;
|
|
30
|
+
message: string;
|
|
31
|
+
skip(answers: Partial<ContentfulOptions>): boolean;
|
|
32
|
+
initial: (answers: Partial<ContentfulOptions>) => Promise<string>;
|
|
33
|
+
choices?: undefined;
|
|
34
|
+
})[];
|
|
35
|
+
type LoadContentfulConfigOptions<T extends Record<string, any> = ContentfulOptions> = Omit<LoadConfigOptions<T>, 'name'>;
|
|
36
|
+
export declare const loadContentfulConfig: <T extends Record<string, any> = ContentfulOptions>(name: string, options?: LoadContentfulConfigOptions<T>) => Promise<{
|
|
37
|
+
config: T;
|
|
38
|
+
isEmpty: boolean;
|
|
39
|
+
filepath: string | undefined;
|
|
40
|
+
missing: string[];
|
|
41
|
+
}>;
|
|
42
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { homedir } from 'node-homedir';
|
|
2
|
+
import { getApiKey, getEnvironments, getPreviewApiKey, getSpaces, } from './contentful.js';
|
|
3
|
+
export const getPromts = (data) => {
|
|
4
|
+
return [
|
|
5
|
+
{
|
|
6
|
+
type: 'input',
|
|
7
|
+
name: 'managementToken',
|
|
8
|
+
message: 'Management Token',
|
|
9
|
+
initial: data.managementToken,
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
type: 'select',
|
|
13
|
+
name: 'spaceId',
|
|
14
|
+
message: 'Space ID',
|
|
15
|
+
choices: async (answers) => {
|
|
16
|
+
const token = data.managementToken || answers.managementToken;
|
|
17
|
+
if (token) {
|
|
18
|
+
const spaces = await getSpaces({ accessToken: token });
|
|
19
|
+
return spaces.map((space) => ({
|
|
20
|
+
name: `${space.name} (${space.sys.id})`,
|
|
21
|
+
value: space.sys.id,
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
return [];
|
|
25
|
+
},
|
|
26
|
+
initial: data?.spaceId ?? data?.activeSpaceId,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
type: 'select',
|
|
30
|
+
name: 'environmentId',
|
|
31
|
+
message: 'Environment ID',
|
|
32
|
+
choices: async (answers) => {
|
|
33
|
+
const token = data.managementToken || answers.managementToken;
|
|
34
|
+
const spaceId = answers.spaceId || data.spaceId;
|
|
35
|
+
if (token && spaceId) {
|
|
36
|
+
const environments = await getEnvironments({ accessToken: token, spaceId });
|
|
37
|
+
return environments.map((environment) => environment.sys.id);
|
|
38
|
+
}
|
|
39
|
+
return [];
|
|
40
|
+
},
|
|
41
|
+
initial: data?.environmentId || data?.activeEnvironmentId,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
type: 'input',
|
|
45
|
+
name: 'accessToken',
|
|
46
|
+
message: 'Content Delivery API - access token',
|
|
47
|
+
skip(answers) {
|
|
48
|
+
return !answers.spaceId && !data.spaceId;
|
|
49
|
+
},
|
|
50
|
+
initial: async (answers) => {
|
|
51
|
+
if (data.accessToken) {
|
|
52
|
+
return typeof data.accessToken === 'function' ? data.accessToken() : data.accessToken;
|
|
53
|
+
}
|
|
54
|
+
const token = data.managementToken || answers.managementToken;
|
|
55
|
+
const spaceId = answers.spaceId || data.spaceId;
|
|
56
|
+
if (token && spaceId) {
|
|
57
|
+
return getApiKey({ accessToken: token, spaceId });
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
type: 'input',
|
|
63
|
+
name: 'previewAccessToken',
|
|
64
|
+
message: 'Content Preview API - access token',
|
|
65
|
+
skip(answers) {
|
|
66
|
+
return !answers.spaceId && !data.spaceId;
|
|
67
|
+
},
|
|
68
|
+
initial: async (answers) => {
|
|
69
|
+
if (data.previewAccessToken) {
|
|
70
|
+
return typeof data.previewAccessToken === 'function'
|
|
71
|
+
? data.previewAccessToken()
|
|
72
|
+
: data.previewAccessToken;
|
|
73
|
+
}
|
|
74
|
+
const token = data.managementToken || answers.managementToken;
|
|
75
|
+
const spaceId = answers.spaceId || data.spaceId;
|
|
76
|
+
if (token && spaceId) {
|
|
77
|
+
return getPreviewApiKey({ accessToken: token, spaceId });
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
];
|
|
82
|
+
};
|
|
83
|
+
export const loadContentfulConfig = async (name, options = {}) => {
|
|
84
|
+
const { loadConfig } = await import('@jungvonmatt/config-loader');
|
|
85
|
+
const contentfulCliOptions = await loadConfig({
|
|
86
|
+
name: 'contentful',
|
|
87
|
+
cwd: homedir(),
|
|
88
|
+
});
|
|
89
|
+
const result = await loadConfig({
|
|
90
|
+
...options,
|
|
91
|
+
name,
|
|
92
|
+
defaultConfig: {
|
|
93
|
+
environmentId: 'master',
|
|
94
|
+
host: 'api.contentful.com',
|
|
95
|
+
...contentfulCliOptions.config,
|
|
96
|
+
...options?.defaultConfig,
|
|
97
|
+
},
|
|
98
|
+
envMap: {
|
|
99
|
+
CONTENTFUL_SPACE_ID: 'spaceId',
|
|
100
|
+
CONTENTFUL_ENVIRONMENT_ID: 'environmentId',
|
|
101
|
+
CONTENTFUL_MANAGEMENT_TOKEN: 'managementToken',
|
|
102
|
+
CONTENTFUL_PREVIEW_TOKEN: 'previewAccessToken',
|
|
103
|
+
CONTENTFUL_PREVIEW_ACCESS_TOKEN: 'previewAccessToken',
|
|
104
|
+
CONTENTFUL_DELIVERY_TOKEN: 'accessToken',
|
|
105
|
+
CONTENTFUL_DELIVERY_ACCESS_TOKEN: 'accessToken',
|
|
106
|
+
CONTENTFUL_HOST: 'host',
|
|
107
|
+
...options?.envMap,
|
|
108
|
+
},
|
|
109
|
+
prompts: getPromts,
|
|
110
|
+
});
|
|
111
|
+
return { ...result, config: result.config };
|
|
112
|
+
};
|
|
113
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jungvonmatt/contentful-config",
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"main": "./dist/index.js",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": "./dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"contentful-typings": "./dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"src",
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
16
|
+
},
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=18"
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"clean": "rimraf ./dist",
|
|
22
|
+
"test": "jest",
|
|
23
|
+
"lint": "eslint --color src --fix --ext .ts",
|
|
24
|
+
"precompile": "npm run clean",
|
|
25
|
+
"compile": "tsc --build",
|
|
26
|
+
"watch": "tsc --build --watch"
|
|
27
|
+
},
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "git+https://github.com/jungvonmatt/contentful-ssg.git"
|
|
31
|
+
},
|
|
32
|
+
"author": "",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/jungvonmatt/contentful-ssg/issues"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://github.com/jungvonmatt/contentful-ssg#readme",
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@jungvonmatt/config-loader": "^0.1.0",
|
|
40
|
+
"contentful-management": "^11.12.1",
|
|
41
|
+
"node-homedir": "^2.0.0",
|
|
42
|
+
"type-fest": "^4.41.0"
|
|
43
|
+
},
|
|
44
|
+
"gitHead": "31f9f440b9e48364b7e11372ca0accf55c8ff368"
|
|
45
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { SetRequired } from 'type-fest';
|
|
2
|
+
import type { ApiKey, ClientAPI, ClientOptions, Space } from 'contentful-management';
|
|
3
|
+
import contentful from 'contentful-management';
|
|
4
|
+
|
|
5
|
+
let client: ClientAPI;
|
|
6
|
+
|
|
7
|
+
export type ContentfulOptions = {
|
|
8
|
+
accessToken: ClientOptions['accessToken'];
|
|
9
|
+
host?: ClientOptions['host'];
|
|
10
|
+
managementToken?: ClientOptions['accessToken'];
|
|
11
|
+
previewAccessToken?: ClientOptions['accessToken'];
|
|
12
|
+
environmentId?: string;
|
|
13
|
+
activeEnvironmentId?: string;
|
|
14
|
+
spaceId?: string;
|
|
15
|
+
activeSpaceId?: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Get contentful management client api
|
|
20
|
+
*/
|
|
21
|
+
const getClient = (options: ContentfulOptions) => {
|
|
22
|
+
const { accessToken, managementToken, host } = options || {};
|
|
23
|
+
|
|
24
|
+
if (client) {
|
|
25
|
+
return client;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const params: ClientOptions = {
|
|
29
|
+
accessToken: managementToken || accessToken,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
if (host) {
|
|
33
|
+
params.host = host;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (params.accessToken) {
|
|
37
|
+
client = contentful.createClient(params);
|
|
38
|
+
return client;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
throw new Error(
|
|
42
|
+
'You need to login first. Run npx contentful login or pass the contentful management token',
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Get Contentful spaces
|
|
48
|
+
*/
|
|
49
|
+
export const getSpaces = async (options: ContentfulOptions): Promise<Space[]> => {
|
|
50
|
+
const client = getClient(options);
|
|
51
|
+
|
|
52
|
+
const { items: spaces } = await client.getSpaces();
|
|
53
|
+
|
|
54
|
+
return spaces;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Get Contentful space
|
|
59
|
+
*/
|
|
60
|
+
export const getSpace = async (options: SetRequired<ContentfulOptions, 'spaceId'>) => {
|
|
61
|
+
const { spaceId } = options || {};
|
|
62
|
+
const client = getClient(options);
|
|
63
|
+
return client.getSpace(spaceId);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Get Contentful environments
|
|
68
|
+
*/
|
|
69
|
+
export const getEnvironments = async (options: SetRequired<ContentfulOptions, 'spaceId'>) => {
|
|
70
|
+
const space = await getSpace(options);
|
|
71
|
+
const { items: environments } = await space.getEnvironments();
|
|
72
|
+
|
|
73
|
+
return environments;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Get Contentful environment
|
|
78
|
+
*/
|
|
79
|
+
export const getEnvironment = async (
|
|
80
|
+
options: SetRequired<ContentfulOptions, 'spaceId' | 'environmentId'>,
|
|
81
|
+
) => {
|
|
82
|
+
const { environmentId, spaceId } = options || {};
|
|
83
|
+
const space = await getSpace(options);
|
|
84
|
+
|
|
85
|
+
const { items: environments } = await space.getEnvironments();
|
|
86
|
+
|
|
87
|
+
const environmentIds = (environments || []).map((env) => env.sys.id);
|
|
88
|
+
|
|
89
|
+
if (environmentId && environmentIds.includes(environmentId)) {
|
|
90
|
+
return space.getEnvironment(environmentId);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (environmentId && !environmentIds.includes(environmentId)) {
|
|
94
|
+
throw new Error(`Environment "${environmentId}" is not available in space ${spaceId}"`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
throw new Error('Missing required parameter: environmentId');
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Fetch api key from contentful
|
|
102
|
+
*/
|
|
103
|
+
export const getApiKey = async (options: SetRequired<ContentfulOptions, 'spaceId'>) => {
|
|
104
|
+
const space = await getSpace(options);
|
|
105
|
+
|
|
106
|
+
const { items: apiKeys = [] } = (await space.getApiKeys()) || {};
|
|
107
|
+
const [apiKey] = apiKeys;
|
|
108
|
+
const { accessToken } = apiKey || {};
|
|
109
|
+
|
|
110
|
+
return accessToken;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Fetch preview api key from contentful
|
|
115
|
+
*/
|
|
116
|
+
export const getPreviewApiKey = async (options: SetRequired<ContentfulOptions, 'spaceId'>) => {
|
|
117
|
+
const space = await getSpace(options);
|
|
118
|
+
|
|
119
|
+
const { items: previewApiKeys = [] } = await space.getPreviewApiKeys();
|
|
120
|
+
const [previewApiKey] = previewApiKeys;
|
|
121
|
+
const { accessToken: previewAccessToken } = previewApiKey as ApiKey;
|
|
122
|
+
|
|
123
|
+
return previewAccessToken;
|
|
124
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { homedir } from 'node-homedir';
|
|
2
|
+
import type { LoadConfigOptions } from '@jungvonmatt/config-loader';
|
|
3
|
+
import {
|
|
4
|
+
type ContentfulOptions,
|
|
5
|
+
getApiKey,
|
|
6
|
+
getEnvironments,
|
|
7
|
+
getPreviewApiKey,
|
|
8
|
+
getSpaces,
|
|
9
|
+
} from './contentful.js';
|
|
10
|
+
|
|
11
|
+
export const getPromts = (data: Partial<ContentfulOptions>) => {
|
|
12
|
+
return [
|
|
13
|
+
{
|
|
14
|
+
type: 'input',
|
|
15
|
+
name: 'managementToken',
|
|
16
|
+
message: 'Management Token',
|
|
17
|
+
initial: data.managementToken,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
type: 'select',
|
|
21
|
+
name: 'spaceId',
|
|
22
|
+
message: 'Space ID',
|
|
23
|
+
choices: async (answers: Partial<ContentfulOptions>) => {
|
|
24
|
+
const token = data.managementToken || answers.managementToken;
|
|
25
|
+
if (token) {
|
|
26
|
+
const spaces = await getSpaces({ accessToken: token });
|
|
27
|
+
return spaces.map((space) => ({
|
|
28
|
+
name: `${space.name} (${space.sys.id})`,
|
|
29
|
+
value: space.sys.id,
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return [];
|
|
34
|
+
},
|
|
35
|
+
initial: data?.spaceId ?? data?.activeSpaceId,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
type: 'select',
|
|
39
|
+
name: 'environmentId',
|
|
40
|
+
message: 'Environment ID',
|
|
41
|
+
choices: async (answers: Partial<ContentfulOptions>) => {
|
|
42
|
+
const token = data.managementToken || answers.managementToken;
|
|
43
|
+
const spaceId = answers.spaceId || data.spaceId;
|
|
44
|
+
if (token && spaceId) {
|
|
45
|
+
const environments = await getEnvironments({ accessToken: token, spaceId });
|
|
46
|
+
return environments.map((environment) => environment.sys.id);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return [];
|
|
50
|
+
},
|
|
51
|
+
initial: data?.environmentId || data?.activeEnvironmentId,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
type: 'input',
|
|
55
|
+
name: 'accessToken',
|
|
56
|
+
message: 'Content Delivery API - access token',
|
|
57
|
+
skip(answers: Partial<ContentfulOptions>) {
|
|
58
|
+
return !answers.spaceId && !data.spaceId;
|
|
59
|
+
},
|
|
60
|
+
initial: async (answers: Partial<ContentfulOptions>) => {
|
|
61
|
+
if (data.accessToken) {
|
|
62
|
+
return typeof data.accessToken === 'function' ? data.accessToken() : data.accessToken;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const token = data.managementToken || answers.managementToken;
|
|
66
|
+
const spaceId = answers.spaceId || data.spaceId;
|
|
67
|
+
if (token && spaceId) {
|
|
68
|
+
return getApiKey({ accessToken: token, spaceId });
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
type: 'input',
|
|
74
|
+
name: 'previewAccessToken',
|
|
75
|
+
message: 'Content Preview API - access token',
|
|
76
|
+
skip(answers: Partial<ContentfulOptions>) {
|
|
77
|
+
return !answers.spaceId && !data.spaceId;
|
|
78
|
+
},
|
|
79
|
+
initial: async (answers: Partial<ContentfulOptions>) => {
|
|
80
|
+
if (data.previewAccessToken) {
|
|
81
|
+
return typeof data.previewAccessToken === 'function'
|
|
82
|
+
? data.previewAccessToken()
|
|
83
|
+
: data.previewAccessToken;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const token = data.managementToken || answers.managementToken;
|
|
87
|
+
const spaceId = answers.spaceId || data.spaceId;
|
|
88
|
+
if (token && spaceId) {
|
|
89
|
+
return getPreviewApiKey({ accessToken: token, spaceId });
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
];
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
type LoadContentfulConfigOptions<T extends Record<string, any> = ContentfulOptions> = Omit<
|
|
97
|
+
LoadConfigOptions<T>,
|
|
98
|
+
'name'
|
|
99
|
+
>;
|
|
100
|
+
|
|
101
|
+
export const loadContentfulConfig = async <T extends Record<string, any> = ContentfulOptions>(
|
|
102
|
+
name: string,
|
|
103
|
+
options: LoadContentfulConfigOptions<T> = {},
|
|
104
|
+
) => {
|
|
105
|
+
const { loadConfig } = await import('@jungvonmatt/config-loader');
|
|
106
|
+
|
|
107
|
+
// Load global contentful config stored in a .contentfulrc.json file in the home directory
|
|
108
|
+
// https://www.contentful.com/developers/docs/tutorials/cli/config-management/
|
|
109
|
+
const contentfulCliOptions = await loadConfig<T>({
|
|
110
|
+
name: 'contentful',
|
|
111
|
+
cwd: homedir(),
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const result = await loadConfig<T>({
|
|
115
|
+
...options,
|
|
116
|
+
name,
|
|
117
|
+
defaultConfig: {
|
|
118
|
+
environmentId: 'master',
|
|
119
|
+
host: 'api.contentful.com',
|
|
120
|
+
...contentfulCliOptions.config,
|
|
121
|
+
...options?.defaultConfig,
|
|
122
|
+
},
|
|
123
|
+
envMap: {
|
|
124
|
+
CONTENTFUL_SPACE_ID: 'spaceId',
|
|
125
|
+
CONTENTFUL_ENVIRONMENT_ID: 'environmentId',
|
|
126
|
+
CONTENTFUL_MANAGEMENT_TOKEN: 'managementToken',
|
|
127
|
+
CONTENTFUL_PREVIEW_TOKEN: 'previewAccessToken',
|
|
128
|
+
CONTENTFUL_PREVIEW_ACCESS_TOKEN: 'previewAccessToken',
|
|
129
|
+
CONTENTFUL_DELIVERY_TOKEN: 'accessToken',
|
|
130
|
+
CONTENTFUL_DELIVERY_ACCESS_TOKEN: 'accessToken',
|
|
131
|
+
CONTENTFUL_HOST: 'host',
|
|
132
|
+
...options?.envMap,
|
|
133
|
+
} as const,
|
|
134
|
+
prompts: getPromts,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
return { ...result, config: result.config as T };
|
|
138
|
+
};
|