magic-builder 1.2.0 → 1.3.1
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 +67 -1
- package/bin/magic-builder.js +1 -0
- package/package.json +5 -2
- package/src/commands/config.js +3 -1
- package/src/commands/doc.js +29 -6
- package/src/commands/extract-cookie.js +33 -2
- package/src/commands/page.js +108 -2
- package/src/commands/performance.js +367 -22
- package/src/commands/skill.js +8 -4
- package/src/commands/widget-publish.js +339 -0
- package/src/index.js +1 -0
- package/src/lib/config.js +28 -1
- package/src/lib/help.js +105 -9
- package/src/lib/multipart.js +3 -0
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { existsSync, readFileSync } = require('fs');
|
|
4
|
+
const { resolve } = require('path');
|
|
5
|
+
const { getWidgetPublishConfigPath } = require('../lib/config');
|
|
6
|
+
const { success, fail } = require('../lib/output');
|
|
7
|
+
|
|
8
|
+
const DEFAULT_ORIGIN = 'https://open.larkoffice.com';
|
|
9
|
+
|
|
10
|
+
async function run(args, opts) {
|
|
11
|
+
if (args.length) {
|
|
12
|
+
fail('Usage: magic-builder widget-publish --app-id <id> --block-type-id <id>', 'E_INVALID_ARGS');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const appId = String(opts.appId || '').trim();
|
|
16
|
+
const blockTypeId = String(opts.blockTypeId || '').trim();
|
|
17
|
+
if (!appId || !blockTypeId) {
|
|
18
|
+
fail('Missing --app-id or --block-type-id.', 'E_INVALID_ARGS');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const auth = loadPublishAuth(opts.config);
|
|
22
|
+
const client = createOpenPlatformClient(auth, opts.origin || DEFAULT_ORIGIN);
|
|
23
|
+
const detail = await client.post(`/developers/v2/block/detail/${appId}/${blockTypeId}`, {});
|
|
24
|
+
const block = extractBlock(detail);
|
|
25
|
+
const pkgId = extractDraftPkgId(detail, block);
|
|
26
|
+
if (!pkgId) throw commandError('Draft widget pkgId was not found in block detail.', 'E_INVALID_RESPONSE');
|
|
27
|
+
|
|
28
|
+
const updatePayload = { block: buildBlockUpdatePayload(block, pkgId, blockTypeId) };
|
|
29
|
+
if (!opts.dryRun) {
|
|
30
|
+
await client.post(`/developers/v2/block/detail/update/${appId}/${blockTypeId}`, updatePayload);
|
|
31
|
+
}
|
|
32
|
+
const versionChangeResponse = await client.post(`/developers/v1/app_version/change/${appId}`, {});
|
|
33
|
+
const versionChange = unwrapData(versionChangeResponse) || {};
|
|
34
|
+
const versionsResponse = await client.post(`/developers/v1/app_version/list/${appId}`, {});
|
|
35
|
+
const versions = extractVersionList(versionsResponse);
|
|
36
|
+
const appVersion = opts.version || getNextPatchVersion(versions);
|
|
37
|
+
const createPayload = buildCreateVersionPayload(
|
|
38
|
+
appVersion,
|
|
39
|
+
opts.changeLog,
|
|
40
|
+
getLatestVersion(versions),
|
|
41
|
+
versionChange
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
if (opts.dryRun) {
|
|
45
|
+
success({
|
|
46
|
+
dryRun: true,
|
|
47
|
+
appId,
|
|
48
|
+
blockTypeId,
|
|
49
|
+
pkgId,
|
|
50
|
+
appVersion,
|
|
51
|
+
updatePayload,
|
|
52
|
+
createPayload,
|
|
53
|
+
}, opts);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const createResponse = await client.post(`/developers/v1/app_version/create/${appId}`, createPayload);
|
|
58
|
+
const appVersionId = extractAppVersionId(createResponse);
|
|
59
|
+
if (!appVersionId) throw commandError('Created app version id was not found in response.', 'E_INVALID_RESPONSE');
|
|
60
|
+
|
|
61
|
+
const publishResponse = await client.post(`/developers/v1/publish/commit/${appId}/${appVersionId}`, {});
|
|
62
|
+
success({
|
|
63
|
+
appId,
|
|
64
|
+
blockTypeId,
|
|
65
|
+
pkgId,
|
|
66
|
+
appVersion,
|
|
67
|
+
appVersionId,
|
|
68
|
+
published: true,
|
|
69
|
+
response: publishResponse,
|
|
70
|
+
}, opts);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function loadPublishAuth(configFile) {
|
|
74
|
+
const path = resolve(String(configFile || getWidgetPublishConfigPath()));
|
|
75
|
+
if (!existsSync(path)) {
|
|
76
|
+
throw commandError(`Widget publish config not found: ${path}`, 'E_NO_CONFIG');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let config;
|
|
80
|
+
try {
|
|
81
|
+
config = JSON.parse(readFileSync(path, 'utf8'));
|
|
82
|
+
} catch (error) {
|
|
83
|
+
throw commandError(`Invalid widget publish config: ${error.message}`, 'E_INVALID_CONFIG');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const cookie = String(config.cookie || '').trim();
|
|
87
|
+
const csrfToken = String(config.csrfToken || config.csrf_token || '').trim();
|
|
88
|
+
if (!cookie || !csrfToken) {
|
|
89
|
+
throw commandError('Widget publish config must contain cookie and csrfToken.', 'E_INVALID_CONFIG');
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
cookie,
|
|
93
|
+
csrfToken,
|
|
94
|
+
timezoneOffset: Number.isFinite(Number(config.timezoneOffset)) ? Number(config.timezoneOffset) : -480,
|
|
95
|
+
locale: String(config.locale || 'zh-CN'),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function createOpenPlatformClient(auth, origin = DEFAULT_ORIGIN, fetchImpl = fetch) {
|
|
100
|
+
const baseUrl = String(origin || DEFAULT_ORIGIN).replace(/\/+$/, '');
|
|
101
|
+
return {
|
|
102
|
+
async post(path, body) {
|
|
103
|
+
const response = await fetchImpl(`${baseUrl}${path}`, {
|
|
104
|
+
method: 'POST',
|
|
105
|
+
headers: {
|
|
106
|
+
accept: '*/*',
|
|
107
|
+
'accept-language': `${auth.locale},zh;q=0.9`,
|
|
108
|
+
'cache-control': 'no-cache',
|
|
109
|
+
'content-type': 'application/json',
|
|
110
|
+
cookie: auth.cookie,
|
|
111
|
+
origin: baseUrl,
|
|
112
|
+
pragma: 'no-cache',
|
|
113
|
+
referer: getRequestReferer(baseUrl, path),
|
|
114
|
+
'x-csrf-token': auth.csrfToken,
|
|
115
|
+
'x-timezone-offset': String(auth.timezoneOffset),
|
|
116
|
+
},
|
|
117
|
+
body: JSON.stringify(body || {}),
|
|
118
|
+
});
|
|
119
|
+
const text = await response.text();
|
|
120
|
+
const data = parseJson(text);
|
|
121
|
+
if (!response.ok || isApiFailure(data)) {
|
|
122
|
+
const reason = data?.msg || data?.message || `HTTP ${response.status}`;
|
|
123
|
+
throw commandError(
|
|
124
|
+
`Open Platform request failed at ${path}: ${reason}`,
|
|
125
|
+
response.status === 401 || response.status === 403 ? 'E_AUTH_FAILED' : 'E_REQUEST_FAILED'
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
return data ?? text;
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function extractBlock(response) {
|
|
134
|
+
const data = unwrapData(response);
|
|
135
|
+
return data?.block || data?.detail?.block || data?.blockDetail?.block || data?.detail || data;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function extractDraftPkgId(response, block = {}) {
|
|
139
|
+
const candidates = [
|
|
140
|
+
response?.data?.blockVersions?.testVersion?.id,
|
|
141
|
+
response?.data?.blockVersions?.testVersion?.pkgId,
|
|
142
|
+
response?.data?.blockVersions?.draftVersion?.id,
|
|
143
|
+
response?.data?.blockVersions?.draftVersion?.pkgId,
|
|
144
|
+
block?.draftVersion?.pkgId,
|
|
145
|
+
block?.draftPkg?.pkgId,
|
|
146
|
+
block?.draftPackage?.pkgId,
|
|
147
|
+
block?.draft?.pkgId,
|
|
148
|
+
findDraftPkgId(response),
|
|
149
|
+
findValue(response, ['draftPkgId', 'draftPackageId']),
|
|
150
|
+
block?.pkgId,
|
|
151
|
+
];
|
|
152
|
+
return String(candidates.find(Boolean) || '').trim();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function buildBlockUpdatePayload(block = {}, pkgId, blockTypeId) {
|
|
156
|
+
return {
|
|
157
|
+
pkgId: String(pkgId),
|
|
158
|
+
icon: block.icon || '',
|
|
159
|
+
i18nTitle: block.i18nTitle || {},
|
|
160
|
+
i18nDesc: block.i18nDesc || {},
|
|
161
|
+
status: block.status !== false,
|
|
162
|
+
blockTypeId: block.blockTypeId || block.blockTypeID || blockTypeId,
|
|
163
|
+
pkgUpdateType: Number.isFinite(Number(block.pkgUpdateType)) ? Number(block.pkgUpdateType) : 0,
|
|
164
|
+
docXHost: block.docXHost || block.docxHost || {},
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function extractVersionList(response) {
|
|
169
|
+
const data = unwrapData(response);
|
|
170
|
+
if (Array.isArray(data)) return data;
|
|
171
|
+
for (const key of ['items', 'list', 'appVersions', 'versions']) {
|
|
172
|
+
if (Array.isArray(data?.[key])) return data[key];
|
|
173
|
+
}
|
|
174
|
+
return findArray(data, ['items', 'list', 'appVersions', 'versions']);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function getNextPatchVersion(versions) {
|
|
178
|
+
const parsed = versions
|
|
179
|
+
.map(item => String(item?.appVersion || item?.version || item?.versionName || item || ''))
|
|
180
|
+
.map(parseSemver)
|
|
181
|
+
.filter(Boolean)
|
|
182
|
+
.sort(compareSemver);
|
|
183
|
+
const latest = parsed.at(-1) || [1, 0, -1];
|
|
184
|
+
return `${latest[0]}.${latest[1]}.${latest[2] + 1}`;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function getLatestVersion(versions) {
|
|
188
|
+
return versions
|
|
189
|
+
.map(item => ({ item, version: parseSemver(item?.appVersion || item?.version || item?.versionName || item) }))
|
|
190
|
+
.filter(entry => entry.version)
|
|
191
|
+
.sort((a, b) => compareSemver(a.version, b.version))
|
|
192
|
+
.at(-1)?.item || {};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function buildCreateVersionPayload(
|
|
196
|
+
appVersion,
|
|
197
|
+
changeLog = '更新文档小组件版本',
|
|
198
|
+
latestVersion = {},
|
|
199
|
+
versionChange = {}
|
|
200
|
+
) {
|
|
201
|
+
const shareConfig = versionChange.changeAppShareConfig?.b2cShareSplitConfigSuggest;
|
|
202
|
+
return {
|
|
203
|
+
appVersion: String(appVersion),
|
|
204
|
+
mobileDefaultAbility: versionChange.mobileDefaultAbility || latestVersion.mobileDefaultAbility || 'bot',
|
|
205
|
+
pcDefaultAbility: versionChange.pcDefaultAbility || latestVersion.pcDefaultAbility || 'bot',
|
|
206
|
+
changeLog: String(changeLog || '更新文档小组件版本'),
|
|
207
|
+
visibleSuggest: latestVersion.visibleSuggest || { departments: [], members: [], groups: [], isAll: 1 },
|
|
208
|
+
applyReasonConfig: versionChange.applyReasonConfig || latestVersion.applyReasonConfig || {
|
|
209
|
+
apiPrivilegeNeedReason: true,
|
|
210
|
+
contactPrivilegeNeedReason: true,
|
|
211
|
+
dataPrivilegeReasonMap: {},
|
|
212
|
+
visibleScopeNeedReason: true,
|
|
213
|
+
apiPrivilegeReasonMap: {},
|
|
214
|
+
contactPrivilegeReason: '',
|
|
215
|
+
isDataPrivilegeExpandMap: { vc: false },
|
|
216
|
+
visibleScopeReason: '',
|
|
217
|
+
dataPrivilegeNeedReason: true,
|
|
218
|
+
isAutoAudit: false,
|
|
219
|
+
isContactExpand: false,
|
|
220
|
+
},
|
|
221
|
+
b2cShareSplitConfigSuggest: shareConfig || latestVersion.b2cShareSplitConfigSuggest || {
|
|
222
|
+
b2cGroupChatShareEnable: false,
|
|
223
|
+
b2cP2PChatShareEnable: false,
|
|
224
|
+
b2cP2PChatNeedAudit: false,
|
|
225
|
+
},
|
|
226
|
+
autoPublish: false,
|
|
227
|
+
blackVisibleSuggest: latestVersion.blackVisibleSuggest || { departments: [], members: [], groups: [], isAll: 0 },
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function extractAppVersionId(response) {
|
|
232
|
+
const data = unwrapData(response);
|
|
233
|
+
return String(
|
|
234
|
+
data?.appVersionId
|
|
235
|
+
|| data?.versionId
|
|
236
|
+
|| data?.appVersion?.id
|
|
237
|
+
|| data?.version?.id
|
|
238
|
+
|| data?.id
|
|
239
|
+
|| findValue(data, ['appVersionId', 'versionId'])
|
|
240
|
+
|| ''
|
|
241
|
+
).trim();
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function unwrapData(value) {
|
|
245
|
+
let current = value;
|
|
246
|
+
for (let i = 0; i < 3; i++) {
|
|
247
|
+
if (!current || typeof current !== 'object' || Array.isArray(current) || !('data' in current)) break;
|
|
248
|
+
current = current.data;
|
|
249
|
+
}
|
|
250
|
+
return current;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function findValue(value, names, predicate = () => true, path = '') {
|
|
254
|
+
if (!value || typeof value !== 'object') return '';
|
|
255
|
+
for (const [name, child] of Object.entries(value)) {
|
|
256
|
+
const childPath = path ? `${path}.${name}` : name;
|
|
257
|
+
if (names.includes(name) && child != null && predicate({ name, path: childPath })) return child;
|
|
258
|
+
const nested = findValue(child, names, predicate, childPath);
|
|
259
|
+
if (nested) return nested;
|
|
260
|
+
}
|
|
261
|
+
return '';
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function findDraftPkgId(value, path = '') {
|
|
265
|
+
if (!value || typeof value !== 'object') return '';
|
|
266
|
+
const marker = [
|
|
267
|
+
path,
|
|
268
|
+
value.status,
|
|
269
|
+
value.versionStatus,
|
|
270
|
+
value.pkgStatus,
|
|
271
|
+
value.type,
|
|
272
|
+
value.name,
|
|
273
|
+
].filter(Boolean).join(' ');
|
|
274
|
+
if (/draft|草稿/i.test(marker) && value.pkgId) return value.pkgId;
|
|
275
|
+
for (const [name, child] of Object.entries(value)) {
|
|
276
|
+
const found = findDraftPkgId(child, path ? `${path}.${name}` : name);
|
|
277
|
+
if (found) return found;
|
|
278
|
+
}
|
|
279
|
+
return '';
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function findArray(value, names) {
|
|
283
|
+
if (!value || typeof value !== 'object') return [];
|
|
284
|
+
for (const [name, child] of Object.entries(value)) {
|
|
285
|
+
if (names.includes(name) && Array.isArray(child)) return child;
|
|
286
|
+
const found = findArray(child, names);
|
|
287
|
+
if (found.length) return found;
|
|
288
|
+
}
|
|
289
|
+
return [];
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function getRequestReferer(baseUrl, path) {
|
|
293
|
+
const blockMatch = path.match(/\/block\/detail(?:\/update)?\/([^/]+)\/([^/]+)/);
|
|
294
|
+
if (blockMatch) return `${baseUrl}/app/${blockMatch[1]}/blocks/${blockMatch[2]}`;
|
|
295
|
+
const publishMatch = path.match(/\/publish\/commit\/([^/]+)\/([^/]+)/);
|
|
296
|
+
if (publishMatch) return `${baseUrl}/app/${publishMatch[1]}/version/${publishMatch[2]}`;
|
|
297
|
+
const appMatch = path.match(/\/app_version\/(?:list|create)\/([^/]+)/);
|
|
298
|
+
if (appMatch) return `${baseUrl}/app/${appMatch[1]}/version/create`;
|
|
299
|
+
return `${baseUrl}/`;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function parseSemver(value) {
|
|
303
|
+
const match = String(value || '').trim().match(/^(\d+)\.(\d+)\.(\d+)$/);
|
|
304
|
+
return match ? match.slice(1).map(Number) : null;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function compareSemver(a, b) {
|
|
308
|
+
return a[0] - b[0] || a[1] - b[1] || a[2] - b[2];
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function parseJson(text) {
|
|
312
|
+
try { return JSON.parse(text); } catch (_) { return null; }
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function isApiFailure(data) {
|
|
316
|
+
if (!data || typeof data !== 'object') return false;
|
|
317
|
+
if ('code' in data && ![0, '0', 200, '200'].includes(data.code)) return true;
|
|
318
|
+
return data.success === false;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function commandError(message, code) {
|
|
322
|
+
const error = new Error(message);
|
|
323
|
+
error.code = code;
|
|
324
|
+
return error;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
module.exports = {
|
|
328
|
+
run,
|
|
329
|
+
loadPublishAuth,
|
|
330
|
+
createOpenPlatformClient,
|
|
331
|
+
extractBlock,
|
|
332
|
+
extractDraftPkgId,
|
|
333
|
+
buildBlockUpdatePayload,
|
|
334
|
+
extractVersionList,
|
|
335
|
+
getNextPatchVersion,
|
|
336
|
+
getLatestVersion,
|
|
337
|
+
buildCreateVersionPayload,
|
|
338
|
+
extractAppVersionId,
|
|
339
|
+
};
|
package/src/index.js
CHANGED
|
@@ -15,6 +15,7 @@ module.exports = {
|
|
|
15
15
|
feedback: require('./commands/feedback'),
|
|
16
16
|
performance: require('./commands/performance'),
|
|
17
17
|
perf: require('./commands/performance'),
|
|
18
|
+
widgetPublish: require('./commands/widget-publish'),
|
|
18
19
|
extractCookie: require('./commands/extract-cookie'),
|
|
19
20
|
skill: require('./commands/skill'),
|
|
20
21
|
version: require('./commands/version'),
|
package/src/lib/config.js
CHANGED
|
@@ -8,6 +8,8 @@ const DEFAULT_BASE_URL = 'https://magic.solutionsuite.cn';
|
|
|
8
8
|
const CONFIG_DIR = path.join(os.homedir(), '.magic-builder');
|
|
9
9
|
const APPS_CONFIG_FILE = 'magic-apps.json';
|
|
10
10
|
const LEGACY_APPS_CONFIG_FILE = '.magic-apps.json';
|
|
11
|
+
const WIDGET_PUBLISH_CONFIG_FILE = 'widget-publish.json';
|
|
12
|
+
const PERFORMANCE_CONFIG_FILE = 'performance.json';
|
|
11
13
|
|
|
12
14
|
function normalizeMagicBaseUrl(value) {
|
|
13
15
|
const raw = String(value || DEFAULT_BASE_URL).trim().replace(/\/+$/, '');
|
|
@@ -23,6 +25,20 @@ function getAppsConfigPath() {
|
|
|
23
25
|
return path.join(CONFIG_DIR, APPS_CONFIG_FILE);
|
|
24
26
|
}
|
|
25
27
|
|
|
28
|
+
function getWidgetPublishConfigPath() {
|
|
29
|
+
return path.join(CONFIG_DIR, WIDGET_PUBLISH_CONFIG_FILE);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getPerformanceConfigPath() {
|
|
33
|
+
return path.join(CONFIG_DIR, PERFORMANCE_CONFIG_FILE);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function loadPerformanceConfig() {
|
|
37
|
+
const p = getPerformanceConfigPath();
|
|
38
|
+
if (!fs.existsSync(p)) return {};
|
|
39
|
+
try { return JSON.parse(fs.readFileSync(p, 'utf8')); } catch (_) { return {}; }
|
|
40
|
+
}
|
|
41
|
+
|
|
26
42
|
function loadAppsConfig() {
|
|
27
43
|
const p = fs.existsSync(getAppsConfigPath())
|
|
28
44
|
? getAppsConfigPath()
|
|
@@ -38,4 +54,15 @@ function saveAppsConfig(config) {
|
|
|
38
54
|
fs.writeFileSync(getAppsConfigPath(), JSON.stringify(config, null, 2));
|
|
39
55
|
}
|
|
40
56
|
|
|
41
|
-
module.exports = {
|
|
57
|
+
module.exports = {
|
|
58
|
+
DEFAULT_BASE_URL,
|
|
59
|
+
CONFIG_DIR,
|
|
60
|
+
normalizeMagicBaseUrl,
|
|
61
|
+
getBaseUrl,
|
|
62
|
+
getAppsConfigPath,
|
|
63
|
+
getWidgetPublishConfigPath,
|
|
64
|
+
getPerformanceConfigPath,
|
|
65
|
+
loadPerformanceConfig,
|
|
66
|
+
loadAppsConfig,
|
|
67
|
+
saveAppsConfig,
|
|
68
|
+
};
|
package/src/lib/help.js
CHANGED
|
@@ -15,13 +15,14 @@ SYNTAX:
|
|
|
15
15
|
|
|
16
16
|
COMMANDS:
|
|
17
17
|
auth Login and manage Magic developer tokens
|
|
18
|
-
page Publish
|
|
18
|
+
page Publish and manage Magic pages, collaborators, and access
|
|
19
19
|
faas Publish, list, and delete Magic FaaS functions
|
|
20
20
|
file Upload, list, and delete TOS files
|
|
21
21
|
link Generate Magic share links
|
|
22
22
|
doc Create or append Feishu Doc HTML Box apps
|
|
23
23
|
feedback Create Magic feedback records
|
|
24
|
-
performance
|
|
24
|
+
performance Write or formally submit a People performance review (alias: perf)
|
|
25
|
+
widget-publish Publish a document widget draft as a new app version
|
|
25
26
|
extract-cookie Extract Cookie data from a curl command
|
|
26
27
|
skill Check or update the Magic Builder skill package
|
|
27
28
|
version Show CLI version
|
|
@@ -38,6 +39,8 @@ EXAMPLES:
|
|
|
38
39
|
magic-builder page list --scope mine
|
|
39
40
|
magic-builder page export --id recxxx --out app.html
|
|
40
41
|
magic-builder page delete --id recxxx
|
|
42
|
+
magic-builder page collaborators add --id recxxx --open-ids ou_xxx,ou_yyy
|
|
43
|
+
magic-builder page access groups add --id recxxx --chat-ids oc_xxx
|
|
41
44
|
magic-builder faas publish handler.js --name report-api
|
|
42
45
|
magic-builder faas list
|
|
43
46
|
magic-builder faas delete --id recxxx
|
|
@@ -48,6 +51,7 @@ EXAMPLES:
|
|
|
48
51
|
magic-builder doc create --html app.html --title "Demo"
|
|
49
52
|
magic-builder feedback create --feedback "打不开页面"
|
|
50
53
|
magic-builder performance --cookie ./cookie.txt --markdown ./performance.md
|
|
54
|
+
magic-builder widget-publish --app-id cli_xxx --block-type-id blk_xxx
|
|
51
55
|
magic-builder extract-cookie --curl-file ./request.curl
|
|
52
56
|
magic-builder skill install
|
|
53
57
|
magic-builder skill check-update
|
|
@@ -83,11 +87,19 @@ COMMANDS:
|
|
|
83
87
|
auth set <token>
|
|
84
88
|
auth show
|
|
85
89
|
|
|
86
|
-
page publish <html> --title <title> [--id <id>] [--open-source]
|
|
90
|
+
page publish <html> --title <title> [--id <id>] [--custom-id <id>] [--open-source] [--comments]
|
|
87
91
|
page list [--title <keyword>] [--scope mine|public]
|
|
88
92
|
page export --id <id> --out <file|dir> [--scope mine|public]
|
|
89
93
|
page export --title <keyword> --out <dir> [--all] [--scope mine|public]
|
|
90
94
|
page delete --id <id>
|
|
95
|
+
page collaborators list --id <id>
|
|
96
|
+
page collaborators add|remove|set --id <id> --open-ids <ou_a,ou_b>
|
|
97
|
+
page collaborators set --id <id> --file <collaborators.json>
|
|
98
|
+
page access get|enable|disable --id <id>
|
|
99
|
+
page access require-login --id <id> --enabled true|false
|
|
100
|
+
page access users add|remove|set --id <id> --open-ids <ou_a,ou_b>
|
|
101
|
+
page access groups add|remove|set --id <id> --chat-ids <oc_a,oc_b>
|
|
102
|
+
page access set --id <id> --file <access.json>
|
|
91
103
|
|
|
92
104
|
faas publish <file.js> --name <name> [--id <id>]
|
|
93
105
|
faas publish --code <code> --name <name> [--id <id>]
|
|
@@ -101,16 +113,26 @@ COMMANDS:
|
|
|
101
113
|
link create --title <text>
|
|
102
114
|
link create --fid <id>
|
|
103
115
|
|
|
104
|
-
doc create --html <file> --title <title> [--summary <text>] [--as bot|user]
|
|
105
|
-
doc append --html <file> --doc-token <token> [--as bot|user]
|
|
116
|
+
doc create --html <file> --title <title> [--summary <text>] [--as bot|user] [--edition external|bytedance]
|
|
117
|
+
doc append --html <file> --doc-token <token> [--as bot|user] [--edition external|bytedance]
|
|
106
118
|
|
|
107
119
|
feedback create --feedback <text> [--title <title>] [--summary <text>]
|
|
108
120
|
feedback create --feedback-file <file> [--dry-run]
|
|
109
121
|
|
|
110
122
|
performance --review-url <url> --cookie <content|file> --markdown <content|file|url> [--dry-run]
|
|
123
|
+
perf self-review --review-url <url> [--good <text>|--good-file <file>]
|
|
124
|
+
[--improve <text>|--improve-file <file>] [--values-comment <text>|--values-comment-file <file>] [--dry-run]
|
|
125
|
+
perf submit --review-url <url> --cookie-file <file> --template-group-id <id> [--dry-run|--yes]
|
|
126
|
+
perf key-works --root-review-id <id> [--template-id <id>] --cookie-file <file>
|
|
127
|
+
perf review-users --review-id <id> --stage-id <id> --cookie-file <file>
|
|
128
|
+
perf review-users --review-url <url> --cookie-file <file>
|
|
129
|
+
perf invite-review --payload-file <file> --review-url <url> --cookie-file <file> [--dry-run]
|
|
111
130
|
perf --review-url <url> --cookie-file <file> --markdown-file <file> [--dry-run]
|
|
112
131
|
|
|
113
|
-
|
|
132
|
+
widget-publish --app-id <id> --block-type-id <id> [--version <x.y.z>] [--change-log <text>]
|
|
133
|
+
[--config <file>] [--dry-run]
|
|
134
|
+
|
|
135
|
+
extract-cookie --curl <content|file> [--out <file>|--out-dir <dir>] [--widget-publish]
|
|
114
136
|
|
|
115
137
|
skill install [--environment auto|local|cloud] [--skills-root <dir>]
|
|
116
138
|
skill check-update [--environment auto|local|cloud] [--skills-root <dir>]
|
|
@@ -155,11 +177,19 @@ SYNTAX:
|
|
|
155
177
|
page: `@HELP magic-builder/page
|
|
156
178
|
|
|
157
179
|
SYNTAX:
|
|
158
|
-
magic-builder page publish <html> --title <title> [--id <id>] [--open-source]
|
|
180
|
+
magic-builder page publish <html> --title <title> [--id <id>] [--custom-id <id>] [--open-source] [--comments]
|
|
159
181
|
magic-builder page list [--title <keyword>] [--scope mine|public]
|
|
160
182
|
magic-builder page export --id <id> --out <file|dir> [--scope mine|public]
|
|
161
183
|
magic-builder page export --title <keyword> --out <dir> [--all] [--scope mine|public]
|
|
162
184
|
magic-builder page delete --id <id>
|
|
185
|
+
magic-builder page collaborators list --id <id>
|
|
186
|
+
magic-builder page collaborators add|remove|set --id <id> --open-ids <ou_a,ou_b>
|
|
187
|
+
magic-builder page collaborators set --id <id> --file <collaborators.json>
|
|
188
|
+
magic-builder page access get|enable|disable --id <id>
|
|
189
|
+
magic-builder page access require-login --id <id> --enabled true|false
|
|
190
|
+
magic-builder page access users add|remove|set --id <id> --open-ids <ou_a,ou_b>
|
|
191
|
+
magic-builder page access groups add|remove|set --id <id> --chat-ids <oc_a,oc_b>
|
|
192
|
+
magic-builder page access set --id <id> --file <access.json>
|
|
163
193
|
`,
|
|
164
194
|
faas: `@HELP magic-builder/faas
|
|
165
195
|
|
|
@@ -185,8 +215,8 @@ SYNTAX:
|
|
|
185
215
|
doc: `@HELP magic-builder/doc
|
|
186
216
|
|
|
187
217
|
SYNTAX:
|
|
188
|
-
magic-builder doc create --html <file> --title <title> [--summary <text>] [--as bot|user]
|
|
189
|
-
magic-builder doc append --html <file> --doc-token <token> [--as bot|user]
|
|
218
|
+
magic-builder doc create --html <file> --title <title> [--summary <text>] [--as bot|user] [--edition external|bytedance]
|
|
219
|
+
magic-builder doc append --html <file> --doc-token <token> [--as bot|user] [--edition external|bytedance]
|
|
190
220
|
`,
|
|
191
221
|
feedback: `@HELP magic-builder/feedback
|
|
192
222
|
|
|
@@ -198,6 +228,14 @@ SYNTAX:
|
|
|
198
228
|
|
|
199
229
|
SYNTAX:
|
|
200
230
|
magic-builder performance --review-url <url> --cookie <content|file> --markdown <content|file|url>
|
|
231
|
+
magic-builder perf self-review --review-url <url> --good <text> --improve <text> --values-comment <text>
|
|
232
|
+
magic-builder perf self-review --review-url <url> --good-file <file> --improve-file <file> --values-comment-file <file>
|
|
233
|
+
magic-builder perf submit --review-url <url> --cookie-file <file> --template-group-id <id> --dry-run
|
|
234
|
+
magic-builder perf submit --review-url <url> --cookie-file <file> --template-group-id <id> --yes
|
|
235
|
+
magic-builder perf key-works --root-review-id <id> [--template-id <id>] --cookie-file <file>
|
|
236
|
+
magic-builder perf review-users --review-id <id> --stage-id <id> --cookie-file <file>
|
|
237
|
+
magic-builder perf review-users --review-url <url> --cookie-file <file>
|
|
238
|
+
magic-builder perf invite-review --payload-file <file> --review-url <url> --cookie-file <file> [--dry-run]
|
|
201
239
|
magic-builder perf --review-url <url> --cookie-file <file> --markdown-file <file>
|
|
202
240
|
|
|
203
241
|
COOKIE:
|
|
@@ -207,9 +245,41 @@ DRAFT:
|
|
|
207
245
|
--review-url resolves operator, tenant, form ids, and the current version
|
|
208
246
|
from /perf/api/user/settings and /perf/api/foundation/draft.
|
|
209
247
|
|
|
248
|
+
SELF REVIEW:
|
|
249
|
+
self-review updates only the explicitly passed text fields and preserves
|
|
250
|
+
the current performance and values ratings. It writes by default; use
|
|
251
|
+
--dry-run to inspect the generated payload without saving it.
|
|
252
|
+
|
|
253
|
+
KEY WORKS:
|
|
254
|
+
key-works reads the review-stage data for the specified template and root
|
|
255
|
+
review. The template id defaults to invite_review_template_id in
|
|
256
|
+
~/.magic-builder/performance.json and can be overridden with --template-id.
|
|
257
|
+
It is read-only and prints the complete API response as JSON.
|
|
258
|
+
|
|
259
|
+
REVIEW USERS:
|
|
260
|
+
review-users reads the invited review-user list for a review and stage. It
|
|
261
|
+
accepts either --review-url or explicit --review-id and --stage-id. Explicit
|
|
262
|
+
ids override values parsed from the URL. It does not modify review data and
|
|
263
|
+
prints the complete API response as JSON.
|
|
264
|
+
|
|
265
|
+
INVITE REVIEW:
|
|
266
|
+
invite-review writes a complete invite-review draft payload to People. Pass
|
|
267
|
+
the current payload as JSON or a JSON file. Use --dry-run to inspect it
|
|
268
|
+
without writing. The payload must contain key, data, and version, and its key
|
|
269
|
+
must identify an invite_review draft.
|
|
270
|
+
|
|
210
271
|
OPTIONS:
|
|
211
272
|
--dry-run Print the generated payload without sending it
|
|
212
273
|
--review-url <url> People performance review URL (recommended)
|
|
274
|
+
--good <text> Update the "did well" self-review text
|
|
275
|
+
--good-file <file> Read the "did well" text from a file
|
|
276
|
+
--improve <text> Update the "to improve" self-review text
|
|
277
|
+
--improve-file <file> Read the "to improve" text from a file
|
|
278
|
+
--values-comment <text> Update the values self-review comment
|
|
279
|
+
--values-comment-file <file> Read the values comment from a file
|
|
280
|
+
--template-group-id <id> Template group id (only needed when absent from the draft)
|
|
281
|
+
--submit-endpoint <url> Override the formal submission endpoint
|
|
282
|
+
--yes Confirm the irreversible formal submission
|
|
213
283
|
--draft-version <number> Override the version loaded from the current draft
|
|
214
284
|
--review-id <id> Override the performance review id
|
|
215
285
|
--form-id <id> Override the invitation/form id used by the draft key
|
|
@@ -219,17 +289,42 @@ OPTIONS:
|
|
|
219
289
|
--source-id <id> Override the form source id
|
|
220
290
|
--field-source-id <id> Override the writable field source id
|
|
221
291
|
--tenant-id <id> Override the People tenant id
|
|
292
|
+
--referer <url> Override the People request Referer
|
|
293
|
+
--stage-endpoint <url> Override the key-works query endpoint
|
|
294
|
+
--stage-id <id> Review stage id used by review-users
|
|
295
|
+
--review-users-endpoint <url> Override the review-users API origin
|
|
296
|
+
--payload <json> Complete invite-review draft payload
|
|
297
|
+
--payload-file <file> Read invite-review draft payload from a file
|
|
222
298
|
--endpoint <url> Override the draft API endpoint
|
|
223
299
|
`,
|
|
224
300
|
perf: `@HELP magic-builder/performance
|
|
225
301
|
|
|
226
302
|
Alias of "magic-builder performance".
|
|
303
|
+
`,
|
|
304
|
+
'widget-publish': `@HELP magic-builder/widget-publish
|
|
305
|
+
|
|
306
|
+
SYNTAX:
|
|
307
|
+
magic-builder widget-publish --app-id <id> --block-type-id <id>
|
|
308
|
+
[--version <x.y.z>] [--change-log <text>] [--config <file>] [--dry-run]
|
|
309
|
+
|
|
310
|
+
AUTH CONFIG:
|
|
311
|
+
Defaults to ~/.magic-builder/widget-publish.json:
|
|
312
|
+
{
|
|
313
|
+
"cookie": "open_locale=zh-CN; session=...",
|
|
314
|
+
"csrfToken": "...",
|
|
315
|
+
"timezoneOffset": -480
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
FLOW:
|
|
319
|
+
Load widget detail and latest uploaded pkgId, update the widget package, load the app's
|
|
320
|
+
version defaults, calculate the next version, create it, then submit publishing.
|
|
227
321
|
`,
|
|
228
322
|
'extract-cookie': `@HELP magic-builder/extract-cookie
|
|
229
323
|
|
|
230
324
|
SYNTAX:
|
|
231
325
|
magic-builder extract-cookie --curl <content|file> [--out <file>]
|
|
232
326
|
magic-builder extract-cookie --curl-file <file> [--out-dir <dir>]
|
|
327
|
+
magic-builder extract-cookie --curl-file <file> --widget-publish
|
|
233
328
|
cat request.curl | magic-builder extract-cookie [--out <file>]
|
|
234
329
|
|
|
235
330
|
OPTIONS:
|
|
@@ -237,6 +332,7 @@ OPTIONS:
|
|
|
237
332
|
--curl-file <file> Read curl command from a local file
|
|
238
333
|
--out <file> Output file (default: ./cookie.txt)
|
|
239
334
|
--out-dir <dir> Output directory; created when missing
|
|
335
|
+
--widget-publish Write Cookie and x-csrf-token to the widget publish config
|
|
240
336
|
`,
|
|
241
337
|
skill: `@HELP magic-builder/skill
|
|
242
338
|
|
package/src/lib/multipart.js
CHANGED
|
@@ -21,6 +21,7 @@ async function uploadSingle(filePath, opts = {}) {
|
|
|
21
21
|
|
|
22
22
|
const signRes = await request(`${baseUrl}/api/tos/sign`, {
|
|
23
23
|
method: 'POST',
|
|
24
|
+
token,
|
|
24
25
|
body: signBody,
|
|
25
26
|
});
|
|
26
27
|
|
|
@@ -48,6 +49,8 @@ async function uploadSingle(filePath, opts = {}) {
|
|
|
48
49
|
token,
|
|
49
50
|
body: {
|
|
50
51
|
action: 'record',
|
|
52
|
+
audit_id: signRes.data.audit_id,
|
|
53
|
+
audit_table_id: signRes.data.audit_table_id,
|
|
51
54
|
url,
|
|
52
55
|
key: signRes.data.key,
|
|
53
56
|
filename,
|