UNPKG

5.26 kBJavaScriptView Raw
1import { defaultValue, fs, semver, util } from './common';
2import { Manifest } from './manifest';
3const { stripSlashes } = util;
4const DEFAULT = {
5 FILE: 'ssr.yml',
6};
7const ERROR = {
8 noFile: (path) => `An "${DEFAULT.FILE}" configuration file does not exist at: ${path}`,
9};
10let Config = (() => {
11 class Config {
12 constructor(args) {
13 this.def = args.def;
14 }
15 get secret() {
16 return toValue(this.def.secret);
17 }
18 get builder() {
19 const builder = this.def.builder || {};
20 builder.bundles = builder.bundles || 'bundles';
21 builder.entries = builder.entries || '';
22 return builder;
23 }
24 get s3() {
25 const s3 = this.def.s3 || {};
26 const path = s3.path || {};
27 const endpoint = util.stripHttp(s3.endpoint || '');
28 const cdn = util.stripHttp(s3.cdn || '');
29 const accessKey = toValue(s3.accessKey);
30 const secret = toValue(s3.secret);
31 const bucket = s3.bucket || '';
32 const api = {
33 endpoint,
34 cdn,
35 accessKey,
36 secret,
37 bucket,
38 path: {
39 base: stripSlashes(path.base || ''),
40 manifest: stripSlashes(path.manifest || ''),
41 bundles: stripSlashes(path.bundles || ''),
42 },
43 get config() {
44 return { endpoint, accessKey, secret };
45 },
46 get fs() {
47 return fs.s3(api.config);
48 },
49 async versions(options = {}) {
50 const s3 = api.fs;
51 const prefix = `${api.path.base}/${api.path.bundles}`;
52 const list = s3.list({
53 bucket,
54 prefix,
55 });
56 const dirs = (await list.dirs).items.map(({ key }) => ({ key, version: fs.basename(key) }));
57 const versions = semver.sort(dirs.map((item) => item.version));
58 return options.sort === 'DESC' ? versions.reverse() : versions;
59 },
60 };
61 return api;
62 }
63 get baseUrl() {
64 const s3 = this.s3;
65 return `https://${s3.cdn || s3.endpoint}/${s3.path.base}`;
66 }
67 get manifest() {
68 const filePath = fs.resolve(this.def.manifest || 'manifest.yml');
69 const s3 = this.s3;
70 const manifestUrl = `https://${s3.endpoint}/${s3.bucket}/${s3.path.base}/${s3.path.manifest}`;
71 const baseUrl = this.baseUrl;
72 const config = this;
73 const api = {
74 local: {
75 path: filePath,
76 get exists() {
77 return fs.pathExists(filePath);
78 },
79 async load(args = {}) {
80 const { loadBundleManifest } = args;
81 return Manifest.fromFile({ path: filePath, baseUrl, loadBundleManifest });
82 },
83 async ensureLatest(args = {}) {
84 if (!(await api.local.exists)) {
85 await config.createFromTemplate();
86 }
87 const remote = await api.s3.pull({ force: true });
88 if (remote.ok) {
89 const minimal = defaultValue(args.minimal, true);
90 await remote.save(filePath, { minimal });
91 }
92 return api.local.load();
93 },
94 },
95 s3: {
96 url: manifestUrl,
97 async pull(args = {}) {
98 return Manifest.get(Object.assign(Object.assign({}, args), { manifestUrl, baseUrl }));
99 },
100 },
101 };
102 return api;
103 }
104 async createFromTemplate() {
105 const source = fs.join(__dirname, '../tmpl/manifest.yml');
106 const target = this.manifest.local.path;
107 await fs.ensureDir(fs.dirname(target));
108 await fs.copy(source, target);
109 return { source, target };
110 }
111 }
112 Config.create = async (options = {}) => {
113 const path = fs.resolve(options.path || DEFAULT.FILE);
114 if (!(await fs.pathExists(path))) {
115 throw new Error(ERROR.noFile(path));
116 }
117 else {
118 const def = await fs.file.loadAndParse(path);
119 return new Config({ def });
120 }
121 };
122 Config.createSync = (options = {}) => {
123 const path = fs.resolve(options.path || DEFAULT.FILE);
124 if (!fs.pathExistsSync(path)) {
125 throw new Error(`An "ssr.yml" configuration file does not exist at: ${path}`);
126 }
127 else {
128 const def = fs.file.loadAndParseSync(path);
129 return new Config({ def });
130 }
131 };
132 return Config;
133})();
134export { Config };
135const toValue = (value) => {
136 value = value || '';
137 value = process.env[value] ? process.env[value] : value;
138 return value || '';
139};