@notur/sdk 1.4.5 → 1.4.7
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 +136 -1
- package/bin/notur-create.js +586 -0
- package/bin/notur-doctor.js +123 -0
- package/bin/notur-pack.js +13 -7
- package/bin/notur-push.js +331 -0
- package/bin/notur-sync.js +199 -0
- package/bin/notur-validate.js +200 -0
- package/bin/notur.js +46 -0
- package/dist/events.d.ts +10 -0
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +7 -0
- package/dist/events.js.map +1 -1
- package/dist/hooks/useExtensionConfig.d.ts +23 -4
- package/dist/hooks/useExtensionConfig.d.ts.map +1 -1
- package/dist/hooks/useExtensionConfig.js +8 -1
- package/dist/hooks/useExtensionConfig.js.map +1 -1
- package/dist/hooks/useNavigate.d.ts +27 -6
- package/dist/hooks/useNavigate.d.ts.map +1 -1
- package/dist/hooks/useNavigate.js +11 -2
- package/dist/hooks/useNavigate.js.map +1 -1
- package/dist/hooks/useNoturEvent.d.ts +12 -0
- package/dist/hooks/useNoturEvent.d.ts.map +1 -1
- package/dist/hooks/useNoturEvent.js +12 -0
- package/dist/hooks/useNoturEvent.js.map +1 -1
- package/dist/hooks/usePermission.d.ts +10 -1
- package/dist/hooks/usePermission.d.ts.map +1 -1
- package/dist/hooks/usePermission.js +10 -1
- package/dist/hooks/usePermission.js.map +1 -1
- package/dist/hooks/useServerContext.d.ts +18 -3
- package/dist/hooks/useServerContext.d.ts.map +1 -1
- package/dist/hooks/useServerContext.js +8 -1
- package/dist/hooks/useServerContext.js.map +1 -1
- package/dist/hooks/useUserContext.d.ts +10 -2
- package/dist/hooks/useUserContext.d.ts.map +1 -1
- package/dist/hooks/useUserContext.js +2 -0
- package/dist/hooks/useUserContext.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +179 -20
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +6 -1
- package/dist/types.js.map +1 -1
- package/examples/red-button/.env.example +2 -0
- package/examples/red-button/README.md +30 -0
- package/examples/red-button/extension.yaml +9 -0
- package/examples/red-button/package.json +29 -0
- package/examples/red-button/resources/frontend/src/index.tsx +32 -0
- package/examples/red-button/tsconfig.json +13 -0
- package/examples/red-button/webpack.config.js +17 -0
- package/package.json +11 -3
package/bin/notur-pack.js
CHANGED
|
@@ -257,13 +257,19 @@ async function pack(sourceDir, outputPath, options = {}) {
|
|
|
257
257
|
];
|
|
258
258
|
|
|
259
259
|
if (options.dryRun) {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
260
|
+
try {
|
|
261
|
+
console.log('\nDry run mode (no archive written).');
|
|
262
|
+
console.log(`Would create: ${outputFullPath}`);
|
|
263
|
+
console.log(`Would include: ${archiveEntries.length} files`);
|
|
264
|
+
if (deterministicArgs.length > 0) {
|
|
265
|
+
console.log('Deterministic archive mode: enabled (GNU tar flags).');
|
|
266
|
+
} else {
|
|
267
|
+
console.log('Deterministic archive mode: not available (GNU tar not detected).');
|
|
268
|
+
}
|
|
269
|
+
} finally {
|
|
270
|
+
if (!checksumsExisted && fs.existsSync(checksumsPath)) {
|
|
271
|
+
fs.unlinkSync(checksumsPath);
|
|
272
|
+
}
|
|
267
273
|
}
|
|
268
274
|
return;
|
|
269
275
|
}
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const { spawnSync } = require('child_process');
|
|
7
|
+
|
|
8
|
+
function parseArgs() {
|
|
9
|
+
const args = process.argv.slice(2);
|
|
10
|
+
const options = {
|
|
11
|
+
path: '.',
|
|
12
|
+
archive: null,
|
|
13
|
+
host: null,
|
|
14
|
+
key: null,
|
|
15
|
+
envFile: null,
|
|
16
|
+
endpoint: '/api/notur/dev/push',
|
|
17
|
+
force: true,
|
|
18
|
+
noBuild: false,
|
|
19
|
+
keepArchive: false,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
for (let i = 0; i < args.length; i++) {
|
|
23
|
+
const arg = args[i];
|
|
24
|
+
if (arg === '--archive') {
|
|
25
|
+
options.archive = args[++i];
|
|
26
|
+
} else if (arg === '--host') {
|
|
27
|
+
options.host = args[++i];
|
|
28
|
+
} else if (arg === '--key') {
|
|
29
|
+
options.key = args[++i];
|
|
30
|
+
} else if (arg === '--env-file') {
|
|
31
|
+
options.envFile = args[++i];
|
|
32
|
+
} else if (arg === '--endpoint') {
|
|
33
|
+
options.endpoint = args[++i];
|
|
34
|
+
} else if (arg === '--no-force') {
|
|
35
|
+
options.force = false;
|
|
36
|
+
} else if (arg === '--no-build') {
|
|
37
|
+
options.noBuild = true;
|
|
38
|
+
} else if (arg === '--keep-archive') {
|
|
39
|
+
options.keepArchive = true;
|
|
40
|
+
} else if (arg === '--help' || arg === '-h') {
|
|
41
|
+
usage(0);
|
|
42
|
+
} else if (!arg.startsWith('-')) {
|
|
43
|
+
options.path = arg;
|
|
44
|
+
} else {
|
|
45
|
+
console.error(`Unknown argument: ${arg}`);
|
|
46
|
+
usage(1);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return options;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function usage(code) {
|
|
54
|
+
console.log(`Usage:
|
|
55
|
+
npx notur-push [path] --host https://panel.example.com --key notur_xxx
|
|
56
|
+
npx @notur/sdk push [path] --host https://panel.example.com --key notur_xxx
|
|
57
|
+
|
|
58
|
+
Options:
|
|
59
|
+
--archive <file> Upload an existing .notur archive instead of packing
|
|
60
|
+
--host <url> Remote Pterodactyl panel URL
|
|
61
|
+
--key <token> Notur remote push token
|
|
62
|
+
--env-file <file> Load values from a custom env file
|
|
63
|
+
--endpoint <path> Remote push endpoint (default: /api/notur/dev/push)
|
|
64
|
+
--no-build Skip npm/yarn/pnpm/bun build before packing
|
|
65
|
+
--no-force Do not overwrite an already installed extension
|
|
66
|
+
--keep-archive Keep the temporary archive generated for this push`);
|
|
67
|
+
process.exit(code);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function loadManifest(dir) {
|
|
71
|
+
const manifestPath = path.join(dir, 'extension.yaml');
|
|
72
|
+
if (!fs.existsSync(manifestPath)) {
|
|
73
|
+
return { id: path.basename(dir), version: 'dev' };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const raw = fs.readFileSync(manifestPath, 'utf8');
|
|
77
|
+
const id = raw.match(/^id:\s*["']?([^"'\n]+)["']?/m)?.[1]?.trim();
|
|
78
|
+
const version = raw.match(/^version:\s*["']?([^"'\n]+)["']?/m)?.[1]?.trim();
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
id: id || path.basename(dir),
|
|
82
|
+
version: version || 'dev',
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function detectPackageManager(dir) {
|
|
87
|
+
if (fs.existsSync(path.join(dir, 'bun.lockb')) || fs.existsSync(path.join(dir, 'bun.lock'))) return 'bun';
|
|
88
|
+
if (fs.existsSync(path.join(dir, 'pnpm-lock.yaml'))) return 'pnpm';
|
|
89
|
+
if (fs.existsSync(path.join(dir, 'yarn.lock'))) return 'yarn';
|
|
90
|
+
if (fs.existsSync(path.join(dir, 'package-lock.json')) || fs.existsSync(path.join(dir, 'package.json'))) return 'npm';
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function buildCommand(packageManager) {
|
|
95
|
+
switch (packageManager) {
|
|
96
|
+
case 'bun':
|
|
97
|
+
return ['bun', ['run', 'build']];
|
|
98
|
+
case 'pnpm':
|
|
99
|
+
return ['pnpm', ['run', 'build']];
|
|
100
|
+
case 'yarn':
|
|
101
|
+
return ['yarn', ['run', 'build']];
|
|
102
|
+
case 'npm':
|
|
103
|
+
return ['npm', ['run', 'build']];
|
|
104
|
+
default:
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function maybeBuild(dir, noBuild) {
|
|
110
|
+
if (noBuild || !fs.existsSync(path.join(dir, 'package.json'))) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const packageJson = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8'));
|
|
115
|
+
if (!packageJson.scripts || !packageJson.scripts.build) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const packageManager = detectPackageManager(dir);
|
|
120
|
+
const command = buildCommand(packageManager);
|
|
121
|
+
if (!command) {
|
|
122
|
+
console.warn('No supported package manager found; skipping build.');
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
console.log(`Running ${command[0]} ${command[1].join(' ')}...`);
|
|
127
|
+
const result = spawnSync(command[0], command[1], {
|
|
128
|
+
cwd: dir,
|
|
129
|
+
stdio: 'inherit',
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
if (result.status !== 0) {
|
|
133
|
+
console.error('Build failed; aborting push.');
|
|
134
|
+
process.exit(result.status ?? 1);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function packArchive(dir) {
|
|
139
|
+
const manifest = loadManifest(dir);
|
|
140
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'notur-push-'));
|
|
141
|
+
const archiveName = `${manifest.id.replace('/', '-')}-${manifest.version}.notur`;
|
|
142
|
+
const archivePath = path.join(tmpDir, archiveName);
|
|
143
|
+
const packScript = path.join(__dirname, 'notur-pack.js');
|
|
144
|
+
|
|
145
|
+
const result = spawnSync(process.execPath, [packScript, dir, '--output', archivePath], {
|
|
146
|
+
stdio: 'inherit',
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
if (result.status !== 0) {
|
|
150
|
+
console.error('Packaging failed; aborting push.');
|
|
151
|
+
process.exit(result.status ?? 1);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return { archivePath, tmpDir };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function resolveUrl(host, endpoint, force) {
|
|
158
|
+
const base = host.replace(/\/+$/, '');
|
|
159
|
+
const pathPart = endpoint.startsWith('/') ? endpoint : `/${endpoint}`;
|
|
160
|
+
const url = new URL(`${base}${pathPart}`);
|
|
161
|
+
if (!force) {
|
|
162
|
+
url.searchParams.set('force', '0');
|
|
163
|
+
}
|
|
164
|
+
return url;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async function pushArchive(options, archivePath) {
|
|
168
|
+
if (typeof fetch !== 'function' || typeof FormData !== 'function' || typeof Blob !== 'function') {
|
|
169
|
+
console.error('Error: notur-push requires Node.js 18+ for fetch/FormData support.');
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const url = resolveUrl(options.host, options.endpoint, options.force);
|
|
174
|
+
const data = fs.readFileSync(archivePath);
|
|
175
|
+
const form = new FormData();
|
|
176
|
+
form.append('extension', new Blob([data]), path.basename(archivePath));
|
|
177
|
+
|
|
178
|
+
const signaturePath = `${archivePath}.sig`;
|
|
179
|
+
if (fs.existsSync(signaturePath)) {
|
|
180
|
+
const signature = fs.readFileSync(signaturePath);
|
|
181
|
+
form.append('signature', new Blob([signature]), path.basename(signaturePath));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
console.log(`Uploading ${path.basename(archivePath)} to ${url.origin}...`);
|
|
185
|
+
|
|
186
|
+
const response = await fetch(url, {
|
|
187
|
+
method: 'POST',
|
|
188
|
+
headers: {
|
|
189
|
+
Authorization: `Bearer ${options.key}`,
|
|
190
|
+
Accept: 'application/json',
|
|
191
|
+
},
|
|
192
|
+
body: form,
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
const text = await response.text();
|
|
196
|
+
let payload = null;
|
|
197
|
+
try {
|
|
198
|
+
payload = text ? JSON.parse(text) : null;
|
|
199
|
+
} catch {
|
|
200
|
+
payload = null;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (!response.ok) {
|
|
204
|
+
console.error(`Remote push failed (${response.status}).`);
|
|
205
|
+
if (payload?.message) {
|
|
206
|
+
console.error(payload.message);
|
|
207
|
+
} else if (text) {
|
|
208
|
+
console.error(text);
|
|
209
|
+
}
|
|
210
|
+
process.exit(1);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (payload) {
|
|
214
|
+
console.log(`Pushed ${payload.id || 'extension'} v${payload.version || 'unknown'}.`);
|
|
215
|
+
if (payload.output) {
|
|
216
|
+
console.log(payload.output.trim());
|
|
217
|
+
}
|
|
218
|
+
} else {
|
|
219
|
+
console.log('Push completed.');
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function parseEnvValue(value) {
|
|
224
|
+
let parsed = value.trim();
|
|
225
|
+
if (
|
|
226
|
+
(parsed.startsWith('"') && parsed.endsWith('"')) ||
|
|
227
|
+
(parsed.startsWith("'") && parsed.endsWith("'"))
|
|
228
|
+
) {
|
|
229
|
+
parsed = parsed.slice(1, -1);
|
|
230
|
+
}
|
|
231
|
+
return parsed;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function loadEnvFile(filePath) {
|
|
235
|
+
if (!fs.existsSync(filePath)) {
|
|
236
|
+
return {};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const values = {};
|
|
240
|
+
const lines = fs.readFileSync(filePath, 'utf8').split(/\r?\n/);
|
|
241
|
+
|
|
242
|
+
for (const line of lines) {
|
|
243
|
+
const trimmed = line.trim();
|
|
244
|
+
if (!trimmed || trimmed.startsWith('#')) {
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const match = trimmed.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)=(.*)$/);
|
|
249
|
+
if (!match) {
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
values[match[1]] = parseEnvValue(match[2]);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return values;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function resolvePushConfig(options, extensionPath) {
|
|
260
|
+
const envFile = options.envFile
|
|
261
|
+
? path.resolve(options.envFile)
|
|
262
|
+
: path.join(extensionPath, '.env');
|
|
263
|
+
const fileEnv = loadEnvFile(envFile);
|
|
264
|
+
|
|
265
|
+
return {
|
|
266
|
+
...options,
|
|
267
|
+
host: options.host || process.env.NOTUR_HOST || fileEnv.NOTUR_HOST || null,
|
|
268
|
+
key:
|
|
269
|
+
options.key ||
|
|
270
|
+
process.env.NOTUR_API_KEY ||
|
|
271
|
+
process.env.NOTUR_PUSH_KEY ||
|
|
272
|
+
fileEnv.NOTUR_API_KEY ||
|
|
273
|
+
fileEnv.NOTUR_PUSH_KEY ||
|
|
274
|
+
null,
|
|
275
|
+
endpoint: options.endpoint || fileEnv.NOTUR_ENDPOINT || '/api/notur/dev/push',
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
async function main() {
|
|
280
|
+
let options = parseArgs();
|
|
281
|
+
const extensionPath = path.resolve(options.path);
|
|
282
|
+
|
|
283
|
+
if (!fs.existsSync(extensionPath) || !fs.statSync(extensionPath).isDirectory()) {
|
|
284
|
+
console.error(`Error: extension path does not exist: ${extensionPath}`);
|
|
285
|
+
process.exit(1);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
options = resolvePushConfig(options, extensionPath);
|
|
289
|
+
|
|
290
|
+
if (!options.host) {
|
|
291
|
+
console.error('Error: --host is required, or set NOTUR_HOST in the environment or local .env.');
|
|
292
|
+
process.exit(1);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (!options.key) {
|
|
296
|
+
console.error('Error: --key is required, or set NOTUR_PUSH_KEY / NOTUR_API_KEY in the environment or local .env.');
|
|
297
|
+
process.exit(1);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (!options.archive) {
|
|
301
|
+
maybeBuild(extensionPath, options.noBuild);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
let archivePath = options.archive ? path.resolve(options.archive) : null;
|
|
305
|
+
let tmpDir = null;
|
|
306
|
+
if (!archivePath) {
|
|
307
|
+
const packed = packArchive(extensionPath);
|
|
308
|
+
archivePath = packed.archivePath;
|
|
309
|
+
tmpDir = packed.tmpDir;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (!fs.existsSync(archivePath)) {
|
|
313
|
+
console.error(`Error: archive does not exist: ${archivePath}`);
|
|
314
|
+
process.exit(1);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
try {
|
|
318
|
+
await pushArchive(options, archivePath);
|
|
319
|
+
} finally {
|
|
320
|
+
if (tmpDir && !options.keepArchive) {
|
|
321
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
322
|
+
} else if (tmpDir) {
|
|
323
|
+
console.log(`Kept archive at ${archivePath}`);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
main().catch(error => {
|
|
329
|
+
console.error(error?.message || String(error));
|
|
330
|
+
process.exit(1);
|
|
331
|
+
});
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const yaml = require('yaml');
|
|
6
|
+
|
|
7
|
+
function parseArgs() {
|
|
8
|
+
const args = process.argv.slice(2);
|
|
9
|
+
const options = {
|
|
10
|
+
path: '.',
|
|
11
|
+
forceWebpack: false,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
for (let i = 0; i < args.length; i++) {
|
|
15
|
+
const arg = args[i];
|
|
16
|
+
if (arg === '--force-webpack') {
|
|
17
|
+
options.forceWebpack = true;
|
|
18
|
+
} else if (arg === '--help' || arg === '-h') {
|
|
19
|
+
usage(0);
|
|
20
|
+
} else if (!arg.startsWith('-')) {
|
|
21
|
+
options.path = arg;
|
|
22
|
+
} else {
|
|
23
|
+
console.error(`Unknown argument: ${arg}`);
|
|
24
|
+
usage(1);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return options;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function usage(code) {
|
|
32
|
+
console.log(`Usage:
|
|
33
|
+
npx notur-sync [path]
|
|
34
|
+
npx @notur/sdk sync [path]
|
|
35
|
+
|
|
36
|
+
Options:
|
|
37
|
+
--force-webpack Regenerate webpack.config.js from extension.yaml`);
|
|
38
|
+
process.exit(code);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function readManifest(extensionPath) {
|
|
42
|
+
const manifestPath = ['extension.yaml', 'extension.yml']
|
|
43
|
+
.map(file => path.join(extensionPath, file))
|
|
44
|
+
.find(file => fs.existsSync(file));
|
|
45
|
+
|
|
46
|
+
if (!manifestPath) {
|
|
47
|
+
console.error(`Error: extension.yaml not found in ${extensionPath}`);
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const manifest = yaml.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
52
|
+
if (!manifest?.id || !manifest?.version) {
|
|
53
|
+
console.error('Error: extension.yaml must contain id and version.');
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return manifest;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function packageName(id) {
|
|
61
|
+
return id.replace('/', '-');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function studly(value) {
|
|
65
|
+
return value
|
|
66
|
+
.split('-')
|
|
67
|
+
.filter(Boolean)
|
|
68
|
+
.map(part => part.charAt(0).toUpperCase() + part.slice(1))
|
|
69
|
+
.join('');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function libraryName(id) {
|
|
73
|
+
return id
|
|
74
|
+
.split(/[\/-]/)
|
|
75
|
+
.filter(Boolean)
|
|
76
|
+
.map(studly)
|
|
77
|
+
.join('');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function bundlePath(manifest) {
|
|
81
|
+
return manifest?.frontend?.bundle || 'resources/frontend/dist/extension.js';
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function syncPackageJson(extensionPath, manifest) {
|
|
85
|
+
const packagePath = path.join(extensionPath, 'package.json');
|
|
86
|
+
const current = fs.existsSync(packagePath)
|
|
87
|
+
? JSON.parse(fs.readFileSync(packagePath, 'utf8'))
|
|
88
|
+
: {};
|
|
89
|
+
|
|
90
|
+
const next = {
|
|
91
|
+
...current,
|
|
92
|
+
name: packageName(manifest.id),
|
|
93
|
+
version: manifest.version,
|
|
94
|
+
private: current.private ?? true,
|
|
95
|
+
scripts: {
|
|
96
|
+
...(current.scripts || {}),
|
|
97
|
+
build: current.scripts?.build || 'webpack-cli --mode production --config webpack.config.js',
|
|
98
|
+
dev: current.scripts?.dev || 'webpack-cli --mode development --watch --config webpack.config.js',
|
|
99
|
+
pack: current.scripts?.pack || 'notur-pack',
|
|
100
|
+
push: current.scripts?.push || 'notur-push',
|
|
101
|
+
sync: current.scripts?.sync || 'notur-sync',
|
|
102
|
+
validate: current.scripts?.validate || 'notur-validate',
|
|
103
|
+
doctor: current.scripts?.doctor || 'notur-doctor',
|
|
104
|
+
},
|
|
105
|
+
peerDependencies: {
|
|
106
|
+
react: '^16.14.0',
|
|
107
|
+
'react-dom': '^16.14.0',
|
|
108
|
+
...(current.peerDependencies || {}),
|
|
109
|
+
},
|
|
110
|
+
devDependencies: {
|
|
111
|
+
'@notur/sdk': '^1.4.7',
|
|
112
|
+
'@types/react': '^16.14.0',
|
|
113
|
+
'@types/react-dom': '^16.9.0',
|
|
114
|
+
react: '^16.14.0',
|
|
115
|
+
'react-dom': '^16.14.0',
|
|
116
|
+
'ts-loader': '^9.5.0',
|
|
117
|
+
typescript: '^5.3.0',
|
|
118
|
+
webpack: '^5.90.0',
|
|
119
|
+
'webpack-cli': '^6.0.0',
|
|
120
|
+
...(current.devDependencies || {}),
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
fs.writeFileSync(packagePath, JSON.stringify(next, null, 2) + '\n');
|
|
125
|
+
console.log(` synced ${path.relative(process.cwd(), packagePath)}`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function webpackTemplate(manifest) {
|
|
129
|
+
const bundle = bundlePath(manifest);
|
|
130
|
+
const filename = path.basename(bundle);
|
|
131
|
+
const outputDir = path.dirname(bundle);
|
|
132
|
+
|
|
133
|
+
return `const path = require('path');
|
|
134
|
+
const base = require('@notur/sdk/webpack.extension.config');
|
|
135
|
+
|
|
136
|
+
module.exports = {
|
|
137
|
+
...base,
|
|
138
|
+
entry: './resources/frontend/src/index.tsx',
|
|
139
|
+
output: {
|
|
140
|
+
...base.output,
|
|
141
|
+
filename: '${filename}',
|
|
142
|
+
path: path.resolve(__dirname, '${outputDir.replace(/\\/g, '/')}'),
|
|
143
|
+
library: {
|
|
144
|
+
...base.output.library,
|
|
145
|
+
name: '__NOTUR_EXT_${libraryName(manifest.id)}__',
|
|
146
|
+
type: 'umd',
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
`;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function syncWebpack(extensionPath, manifest, force) {
|
|
154
|
+
if (!manifest.frontend) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const webpackPath = path.join(extensionPath, 'webpack.config.js');
|
|
159
|
+
if (fs.existsSync(webpackPath) && !force) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
fs.writeFileSync(webpackPath, webpackTemplate(manifest));
|
|
164
|
+
console.log(` synced ${path.relative(process.cwd(), webpackPath)}`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function syncEnvExample(extensionPath) {
|
|
168
|
+
const envExamplePath = path.join(extensionPath, '.env.example');
|
|
169
|
+
if (fs.existsSync(envExamplePath)) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
fs.writeFileSync(envExamplePath, `NOTUR_HOST=https://panel.example.com
|
|
174
|
+
NOTUR_PUSH_KEY=notur_xxx
|
|
175
|
+
`);
|
|
176
|
+
console.log(` synced ${path.relative(process.cwd(), envExamplePath)}`);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function main() {
|
|
180
|
+
const options = parseArgs();
|
|
181
|
+
const extensionPath = path.resolve(options.path);
|
|
182
|
+
if (!fs.existsSync(extensionPath) || !fs.statSync(extensionPath).isDirectory()) {
|
|
183
|
+
console.error(`Error: extension path does not exist: ${extensionPath}`);
|
|
184
|
+
process.exit(1);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const manifest = readManifest(extensionPath);
|
|
188
|
+
console.log(`Syncing ${manifest.id} from extension.yaml`);
|
|
189
|
+
|
|
190
|
+
if (manifest.frontend) {
|
|
191
|
+
syncPackageJson(extensionPath, manifest);
|
|
192
|
+
syncWebpack(extensionPath, manifest, options.forceWebpack);
|
|
193
|
+
syncEnvExample(extensionPath);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
console.log('Done.');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
main();
|