addashboard-cli 0.2.4
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 +48 -0
- package/dist/commands/ads.js +139 -0
- package/dist/commands/ads.js.map +1 -0
- package/dist/commands/auth.js +75 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/authDevice.js +110 -0
- package/dist/commands/authDevice.js.map +1 -0
- package/dist/commands/authGoogle.js +196 -0
- package/dist/commands/authGoogle.js.map +1 -0
- package/dist/commands/freee.js +249 -0
- package/dist/commands/freee.js.map +1 -0
- package/dist/commands/submission.js +299 -0
- package/dist/commands/submission.js.map +1 -0
- package/dist/index.js +290 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/apiClient.js +86 -0
- package/dist/lib/apiClient.js.map +1 -0
- package/dist/lib/credentialStore.js +76 -0
- package/dist/lib/credentialStore.js.map +1 -0
- package/package.json +54 -0
- package/skills/ad-ops/README.md +139 -0
- package/skills/ad-ops/SKILL.md +146 -0
- package/skills/ad-ops/config.json +5 -0
- package/skills/invoice-issue-freee/README.md +109 -0
- package/skills/invoice-issue-freee/SKILL.md +190 -0
- package/skills/invoice-issue-freee/config.json +31 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.buildApiClient = void 0;
|
|
7
|
+
exports.runFreeeLogin = runFreeeLogin;
|
|
8
|
+
exports.runFreeeTemplates = runFreeeTemplates;
|
|
9
|
+
exports.runFreeeIssue = runFreeeIssue;
|
|
10
|
+
/**
|
|
11
|
+
* webgram freee — freee 請求書発行コマンド群。
|
|
12
|
+
*
|
|
13
|
+
* - login: ローカル :8080 で認可コードを受け取り backend で token 交換
|
|
14
|
+
* - templates: 使用可能な帳票テンプレート一覧
|
|
15
|
+
* - issue: 請求書を発行し report_url(帳票詳細ページURL) を返す
|
|
16
|
+
* (submission.ts と同じく dry-run 既定 + --yes 安全弁)
|
|
17
|
+
*
|
|
18
|
+
* clientSecret は CLI に持たせない。token 交換は必ず backend で行う。
|
|
19
|
+
*/
|
|
20
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
21
|
+
const fs_1 = __importDefault(require("fs"));
|
|
22
|
+
const http_1 = __importDefault(require("http"));
|
|
23
|
+
const url_1 = require("url");
|
|
24
|
+
const child_process_1 = require("child_process");
|
|
25
|
+
const apiClient_1 = require("../lib/apiClient");
|
|
26
|
+
Object.defineProperty(exports, "buildApiClient", { enumerable: true, get: function () { return apiClient_1.buildApiClient; } });
|
|
27
|
+
const CALLBACK_PORT = 8080;
|
|
28
|
+
const CALLBACK_PATH = '/callback';
|
|
29
|
+
function sha256Hex(s) {
|
|
30
|
+
return crypto_1.default.createHash('sha256').update(s).digest('hex').slice(0, 16);
|
|
31
|
+
}
|
|
32
|
+
/** JWT (検証なし) から email を取り出す。失敗時は undefined。 */
|
|
33
|
+
function decodeJwtEmail(token) {
|
|
34
|
+
if (!token)
|
|
35
|
+
return undefined;
|
|
36
|
+
try {
|
|
37
|
+
const payload = token.split('.')[1];
|
|
38
|
+
if (!payload)
|
|
39
|
+
return undefined;
|
|
40
|
+
const v = JSON.parse(Buffer.from(payload, 'base64url').toString('utf8'));
|
|
41
|
+
return typeof v?.email === 'string' ? v.email : undefined;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** OS デフォルトブラウザで URL を開く(best-effort)。 */
|
|
48
|
+
function openBrowser(url) {
|
|
49
|
+
const platform = process.platform;
|
|
50
|
+
// win32 の `start` は cmd の組込みコマンドなので cmd 経由で起動する
|
|
51
|
+
const [cmd, cmdArgs] = platform === 'darwin'
|
|
52
|
+
? ['open', [url]]
|
|
53
|
+
: platform === 'win32'
|
|
54
|
+
? ['cmd', ['/c', 'start', '', url]]
|
|
55
|
+
: ['xdg-open', [url]];
|
|
56
|
+
try {
|
|
57
|
+
(0, child_process_1.spawn)(cmd, cmdArgs, { stdio: 'ignore', detached: true }).unref();
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// 開けなくてもURLは表示済みなので握りつぶす
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* ローカル :8080 で認可コールバックを1回受け取る。
|
|
65
|
+
* CSRF/認可コード注入対策として、開始時に生成した expectedState と
|
|
66
|
+
* コールバックの state を厳密照合し、不一致は拒否する(攻撃者は state を知らない)。
|
|
67
|
+
*
|
|
68
|
+
* bind は **ループバックのみ**(ネットワーク非公開)だが、redirect_uri が
|
|
69
|
+
* `localhost` のため OS が localhost を IPv6(::1) 優先解決する環境でも取りこぼさないよう
|
|
70
|
+
* 127.0.0.1 と ::1 の両方で listen する(どちらか先着のコールバックで解決)。
|
|
71
|
+
*/
|
|
72
|
+
function waitForAuthorizationCode(expectedState, timeoutMs = 180000) {
|
|
73
|
+
return new Promise((resolve, reject) => {
|
|
74
|
+
const servers = [];
|
|
75
|
+
let settled = false;
|
|
76
|
+
const closeAll = () => servers.forEach((s) => s.close());
|
|
77
|
+
const done = (fn) => {
|
|
78
|
+
if (settled)
|
|
79
|
+
return;
|
|
80
|
+
settled = true;
|
|
81
|
+
closeAll();
|
|
82
|
+
fn();
|
|
83
|
+
};
|
|
84
|
+
const handler = (req, res) => {
|
|
85
|
+
if (!req.url)
|
|
86
|
+
return;
|
|
87
|
+
const parsed = new url_1.URL(req.url, `http://127.0.0.1:${CALLBACK_PORT}`);
|
|
88
|
+
if (parsed.pathname !== CALLBACK_PATH) {
|
|
89
|
+
res.writeHead(404);
|
|
90
|
+
res.end();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const code = parsed.searchParams.get('code');
|
|
94
|
+
const state = parsed.searchParams.get('state');
|
|
95
|
+
const error = parsed.searchParams.get('error');
|
|
96
|
+
// state 検証(不一致 = 注入疑い)を最優先
|
|
97
|
+
const stateOk = state !== null && state === expectedState;
|
|
98
|
+
const success = !!code && stateOk;
|
|
99
|
+
res.writeHead(success ? 200 : 400, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
100
|
+
res.end(`<html><body style="font-family:sans-serif"><h3>${success
|
|
101
|
+
? 'freee 認可が完了しました。ターミナルに戻ってください。'
|
|
102
|
+
: `認可に失敗しました: ${error ?? (stateOk ? 'no_code' : 'state_mismatch')}`}</h3></body></html>`);
|
|
103
|
+
if (success)
|
|
104
|
+
done(() => resolve(code));
|
|
105
|
+
else if (!stateOk)
|
|
106
|
+
done(() => reject(new Error('state_mismatch: 認可レスポンスの state 不一致(注入の疑い)')));
|
|
107
|
+
else
|
|
108
|
+
done(() => reject(new Error(`authorization_failed: ${error ?? 'no_code'}`)));
|
|
109
|
+
};
|
|
110
|
+
for (const host of ['127.0.0.1', '::1']) {
|
|
111
|
+
const server = http_1.default.createServer(handler);
|
|
112
|
+
// 片方のアドレスが listen 不可(例: IPv6無効)でも、もう片方が生きていれば良い
|
|
113
|
+
server.on('error', (err) => {
|
|
114
|
+
if (err.code === 'EADDRINUSE')
|
|
115
|
+
done(() => reject(new Error(`ポート ${CALLBACK_PORT} が使用中です`)));
|
|
116
|
+
// それ以外(EADDRNOTAVAIL 等)は無視して他方の listen に委ねる
|
|
117
|
+
});
|
|
118
|
+
server.listen(CALLBACK_PORT, host);
|
|
119
|
+
servers.push(server);
|
|
120
|
+
}
|
|
121
|
+
setTimeout(() => done(() => reject(new Error('authorization_timeout'))), timeoutMs).unref();
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* webgram freee login: 認可URL取得 → ブラウザ認可 → code を backend で交換。
|
|
126
|
+
*/
|
|
127
|
+
async function runFreeeLogin(input) {
|
|
128
|
+
const log = input.logger ?? ((line) => console.error(line));
|
|
129
|
+
let client;
|
|
130
|
+
try {
|
|
131
|
+
client = (input.authedClientFactory ?? apiClient_1.buildAuthedApiClient)(input.store);
|
|
132
|
+
}
|
|
133
|
+
catch (e) {
|
|
134
|
+
return { ok: false, error: e.message };
|
|
135
|
+
}
|
|
136
|
+
// 1. clientId / authorizeUrl を backend から取得
|
|
137
|
+
let authorizeUrl;
|
|
138
|
+
try {
|
|
139
|
+
const cfg = await client.get('/api/freee/oauth/config');
|
|
140
|
+
authorizeUrl = cfg.data?.authorizeUrl;
|
|
141
|
+
if (!authorizeUrl)
|
|
142
|
+
return { ok: false, error: 'invalid_config_response' };
|
|
143
|
+
}
|
|
144
|
+
catch (e) {
|
|
145
|
+
return { ok: false, error: freeeErrMsg(e) };
|
|
146
|
+
}
|
|
147
|
+
// 2. 認可コード取得(ブラウザで開く + ローカル :8080 で受信)
|
|
148
|
+
// CSRF/認可コード注入対策として state を生成し、URL に付与 + コールバックで照合する
|
|
149
|
+
let code;
|
|
150
|
+
try {
|
|
151
|
+
if (input.codeProvider) {
|
|
152
|
+
code = await input.codeProvider();
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
const state = crypto_1.default.randomBytes(24).toString('base64url');
|
|
156
|
+
const urlWithState = `${authorizeUrl}${authorizeUrl.includes('?') ? '&' : '?'}state=${encodeURIComponent(state)}`;
|
|
157
|
+
log(`ブラウザで freee 認可画面を開きます。開かない場合は以下を手動で開いてください:\n${urlWithState}`);
|
|
158
|
+
openBrowser(urlWithState);
|
|
159
|
+
code = await waitForAuthorizationCode(state);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
catch (e) {
|
|
163
|
+
return { ok: false, error: e.message };
|
|
164
|
+
}
|
|
165
|
+
// 3. backend で token 交換
|
|
166
|
+
try {
|
|
167
|
+
const res = await client.post('/api/freee/oauth/exchange', { code });
|
|
168
|
+
return { ok: true, companyId: res.data?.companyId };
|
|
169
|
+
}
|
|
170
|
+
catch (e) {
|
|
171
|
+
return { ok: false, error: freeeErrMsg(e) };
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/** webgram freee templates: 帳票テンプレート一覧を取得。 */
|
|
175
|
+
async function runFreeeTemplates(input) {
|
|
176
|
+
let client;
|
|
177
|
+
try {
|
|
178
|
+
client = (input.clientFactory ?? apiClient_1.buildAuthedApiClient)(input.store);
|
|
179
|
+
}
|
|
180
|
+
catch (e) {
|
|
181
|
+
return { ok: false, error: e.message };
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
const res = await client.get('/api/freee/templates');
|
|
185
|
+
return { ok: true, data: res.data };
|
|
186
|
+
}
|
|
187
|
+
catch (e) {
|
|
188
|
+
return { ok: false, error: freeeErrMsg(e) };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* webgram freee issue: 請求書ボディ JSON を POST。
|
|
193
|
+
* 安全弁: dryRun=true 既定 → dry_run=1、dryRun=false && yes=false → exit 2。
|
|
194
|
+
*/
|
|
195
|
+
async function runFreeeIssue(input) {
|
|
196
|
+
const log = input.logger ?? ((line) => console.error(line));
|
|
197
|
+
if (!input.dryRun && !input.yes) {
|
|
198
|
+
return {
|
|
199
|
+
ok: false,
|
|
200
|
+
exitCode: 2,
|
|
201
|
+
error: '本実行するには --yes を明示してください (dry-run なしで freee に実発行する操作です)',
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
let body;
|
|
205
|
+
let raw;
|
|
206
|
+
try {
|
|
207
|
+
raw = fs_1.default.readFileSync(input.jsonFile, 'utf8');
|
|
208
|
+
body = JSON.parse(raw);
|
|
209
|
+
}
|
|
210
|
+
catch (e) {
|
|
211
|
+
return { ok: false, exitCode: 1, error: `json_read_error: ${e.message}` };
|
|
212
|
+
}
|
|
213
|
+
const creds = input.store.load();
|
|
214
|
+
const user = decodeJwtEmail(creds?.accessToken) ?? 'unknown';
|
|
215
|
+
log(`[cli/freee] user=${user} body_hash=${sha256Hex(raw)} dry_run=${input.dryRun}`);
|
|
216
|
+
let client;
|
|
217
|
+
try {
|
|
218
|
+
client = (input.clientFactory ?? apiClient_1.buildAuthedApiClient)(input.store);
|
|
219
|
+
}
|
|
220
|
+
catch (e) {
|
|
221
|
+
return { ok: false, exitCode: 1, error: e.message };
|
|
222
|
+
}
|
|
223
|
+
try {
|
|
224
|
+
const params = {};
|
|
225
|
+
if (input.dryRun)
|
|
226
|
+
params.dry_run = '1';
|
|
227
|
+
const res = await client.post('/api/freee/invoices', body, { params });
|
|
228
|
+
return { ok: true, exitCode: 0, data: res.data };
|
|
229
|
+
}
|
|
230
|
+
catch (e) {
|
|
231
|
+
const status = e?.response?.status;
|
|
232
|
+
if (status === 401)
|
|
233
|
+
return { ok: false, exitCode: 1, error: 'unauthorized' };
|
|
234
|
+
if (status === 403)
|
|
235
|
+
return { ok: false, exitCode: 1, error: 'forbidden: freee 発行権限がありません' };
|
|
236
|
+
return { ok: false, exitCode: 1, error: freeeErrMsg(e) };
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/** backend の error レスポンス({error:{message}} or {error})から文言を取り出す。 */
|
|
240
|
+
function freeeErrMsg(e) {
|
|
241
|
+
const data = e?.response?.data;
|
|
242
|
+
const err = data?.error;
|
|
243
|
+
if (typeof err === 'string')
|
|
244
|
+
return err;
|
|
245
|
+
if (err && typeof err === 'object' && 'message' in err)
|
|
246
|
+
return String(err.message);
|
|
247
|
+
return e.message ?? 'network_error';
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=freee.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"freee.js","sourceRoot":"","sources":["../../src/commands/freee.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SUBMIT_PLATFORMS = void 0;
|
|
7
|
+
exports.runSubmit = runSubmit;
|
|
8
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const apiClient_1 = require("../lib/apiClient");
|
|
12
|
+
exports.SUBMIT_PLATFORMS = ['meta', 'yda', 'google', 'smartnews', 'bytedance'];
|
|
13
|
+
/** v5 §5.3: platform → submit エンドポイント (T-02 yda, T-03 google, T-04 smartnews, T-05 bytedance) */
|
|
14
|
+
function resolveSubmitPath(platform) {
|
|
15
|
+
if (platform === 'meta')
|
|
16
|
+
return '/api/submission/meta';
|
|
17
|
+
if (platform === 'yda')
|
|
18
|
+
return '/api/submission/yda';
|
|
19
|
+
if (platform === 'google')
|
|
20
|
+
return '/api/submission/google';
|
|
21
|
+
if (platform === 'smartnews')
|
|
22
|
+
return '/api/submission/smartnews';
|
|
23
|
+
if (platform === 'bytedance')
|
|
24
|
+
return '/api/submission/bytedance';
|
|
25
|
+
throw new Error(`webgram submit は ${platform} に未対応です`);
|
|
26
|
+
}
|
|
27
|
+
function sha256Hex(s) {
|
|
28
|
+
return crypto_1.default.createHash('sha256').update(s).digest('hex').slice(0, 16);
|
|
29
|
+
}
|
|
30
|
+
/** JWT (検証なし) から email を取り出す。失敗時は undefined。 */
|
|
31
|
+
function decodeJwtEmail(token) {
|
|
32
|
+
if (!token)
|
|
33
|
+
return undefined;
|
|
34
|
+
try {
|
|
35
|
+
const payload = token.split('.')[1];
|
|
36
|
+
if (!payload)
|
|
37
|
+
return undefined;
|
|
38
|
+
const json = Buffer.from(payload, 'base64').toString('utf8');
|
|
39
|
+
const v = JSON.parse(json);
|
|
40
|
+
return typeof v?.email === 'string' ? v.email : undefined;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Meta 入稿ボディ内の ads[].videoPath (ローカルmp4) を先に
|
|
48
|
+
* POST /api/submission/meta/upload-video へ送って video_id を取得し、
|
|
49
|
+
* その ad の videoId に注入する(videoPath は削除)。
|
|
50
|
+
* videoPath 相対指定は JSON ファイルのあるディレクトリ基準で解決する。
|
|
51
|
+
* すでに videoId 指定済み、または videoPath 無しの ad は素通り。
|
|
52
|
+
*/
|
|
53
|
+
async function resolveMetaVideos(client, body, jsonFile, log) {
|
|
54
|
+
const baseDir = path_1.default.dirname(path_1.default.resolve(jsonFile));
|
|
55
|
+
for (const cp of body?.campaigns ?? []) {
|
|
56
|
+
for (const as of cp?.adSets ?? []) {
|
|
57
|
+
for (const ad of as?.ads ?? []) {
|
|
58
|
+
if (!ad?.videoPath || ad?.videoId)
|
|
59
|
+
continue;
|
|
60
|
+
const videoPath = path_1.default.isAbsolute(ad.videoPath)
|
|
61
|
+
? ad.videoPath
|
|
62
|
+
: path_1.default.join(baseDir, ad.videoPath);
|
|
63
|
+
const buf = fs_1.default.readFileSync(videoPath);
|
|
64
|
+
const fileName = path_1.default.basename(videoPath);
|
|
65
|
+
const form = new FormData();
|
|
66
|
+
form.append('accountId', String(body.accountId));
|
|
67
|
+
form.append('video', new Blob([buf]), fileName);
|
|
68
|
+
// upload-video は動画アップロード+処理完了待機でブロックするため、
|
|
69
|
+
// 既定 15s では足りない。3分に延長する。
|
|
70
|
+
const res = await client.post('/api/submission/meta/upload-video', form, { timeout: 180000 });
|
|
71
|
+
// backend は動画処理完了(ready)まで待って video_id を返す。ready 未達は 503 で
|
|
72
|
+
// throw されるが、防御的に video_id 欠落もエラー扱いにする(未処理動画で creative
|
|
73
|
+
// を作らせない = 1443226 回避の安全弁)。
|
|
74
|
+
if (!res.data?.video_id) {
|
|
75
|
+
throw new Error(`upload-video が video_id を返しませんでした (${fileName})`);
|
|
76
|
+
}
|
|
77
|
+
ad.videoId = res.data.video_id;
|
|
78
|
+
delete ad.videoPath;
|
|
79
|
+
log(`[cli/submit] uploaded video ${fileName} → ${ad.videoId}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* YDA 入稿ボディ内の adGroups[].ads[].videoPath (ローカルmp4) を先に
|
|
86
|
+
* POST /api/submission/yda/upload-video へ送って mediaId を取得し、
|
|
87
|
+
* その ad の videoMediaId / thumbnailMediaId に注入する(videoPath / thumbnailPath は削除)。
|
|
88
|
+
* すでに videoMediaId 指定済み、または videoPath 無しの ad は素通り。
|
|
89
|
+
* ad.thumbnailPath (ローカルjpg) があれば動画と一緒に multipart で送り、
|
|
90
|
+
* Yahoo は動画からサムネを自動生成しないため(本番実測)自前アップロードの mediaId を優先注入する。
|
|
91
|
+
*/
|
|
92
|
+
async function resolveYdaVideos(client, body, jsonFile, log) {
|
|
93
|
+
const baseDir = path_1.default.dirname(path_1.default.resolve(jsonFile));
|
|
94
|
+
for (const cp of body?.campaigns ?? []) {
|
|
95
|
+
for (const ag of cp?.adGroups ?? []) {
|
|
96
|
+
for (const ad of ag?.ads ?? []) {
|
|
97
|
+
if (!ad?.videoPath || ad?.videoMediaId)
|
|
98
|
+
continue;
|
|
99
|
+
const videoPath = path_1.default.isAbsolute(ad.videoPath)
|
|
100
|
+
? ad.videoPath
|
|
101
|
+
: path_1.default.join(baseDir, ad.videoPath);
|
|
102
|
+
const buf = fs_1.default.readFileSync(videoPath);
|
|
103
|
+
const fileName = path_1.default.basename(videoPath);
|
|
104
|
+
const form = new FormData();
|
|
105
|
+
form.append('accountId', String(body.accountId));
|
|
106
|
+
if (ad.videoTitle)
|
|
107
|
+
form.append('videoTitle', String(ad.videoTitle));
|
|
108
|
+
form.append('video', new Blob([buf]), fileName);
|
|
109
|
+
if (ad.thumbnailPath) {
|
|
110
|
+
const thumbnailPath = path_1.default.isAbsolute(ad.thumbnailPath)
|
|
111
|
+
? ad.thumbnailPath
|
|
112
|
+
: path_1.default.join(baseDir, ad.thumbnailPath);
|
|
113
|
+
const thumbBuf = fs_1.default.readFileSync(thumbnailPath);
|
|
114
|
+
form.append('thumbnail', new Blob([thumbBuf]), path_1.default.basename(thumbnailPath));
|
|
115
|
+
}
|
|
116
|
+
// upload-video は動画アップロード+処理完了待機でブロックするため 3分に延長
|
|
117
|
+
let res;
|
|
118
|
+
try {
|
|
119
|
+
res = await client.post('/api/submission/yda/upload-video', form, { timeout: 180000 });
|
|
120
|
+
}
|
|
121
|
+
catch (e) {
|
|
122
|
+
// backend のエラーボディ(Yahoo API エラー詳細)を表面化する
|
|
123
|
+
const detail = e?.response?.data ? JSON.stringify(e.response.data) : e?.message;
|
|
124
|
+
throw new Error(`upload-video 失敗 (${fileName}): ${detail}`);
|
|
125
|
+
}
|
|
126
|
+
if (!res.data?.media_id) {
|
|
127
|
+
throw new Error(`upload-video が media_id を返しませんでした (${fileName})`);
|
|
128
|
+
}
|
|
129
|
+
ad.videoMediaId = res.data.media_id;
|
|
130
|
+
if (res.data.thumbnail_media_id && !ad.thumbnailMediaId) {
|
|
131
|
+
ad.thumbnailMediaId = res.data.thumbnail_media_id;
|
|
132
|
+
}
|
|
133
|
+
delete ad.videoPath;
|
|
134
|
+
delete ad.thumbnailPath;
|
|
135
|
+
log(`[cli/submit] uploaded YDA video ${fileName} → mediaId=${ad.videoMediaId} thumbnailMediaId=${ad.thumbnailMediaId ?? 'none'}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Google ディスプレイ広告(RESPONSIVE_DISPLAY_AD)のローカル画像パスを先に
|
|
142
|
+
* POST /api/submission/google/upload-image へ送って IMAGE アセットの resource_name を取得し、
|
|
143
|
+
* ad の対応フィールド(marketingImages/squareMarketingImages/logoImages)に注入する。
|
|
144
|
+
*
|
|
145
|
+
* JSON では *ImagePaths (marketingImagePaths / squareMarketingImagePaths / logoImagePaths)
|
|
146
|
+
* にローカルパス配列を書く。アップロード後、対応する *Images フィールドへ resource_name を
|
|
147
|
+
* マージし *ImagePaths は削除する。既に resource_name を直接指定している場合はそれも保持する。
|
|
148
|
+
* 相対パスは JSON ファイルのあるディレクトリ基準で解決する。
|
|
149
|
+
*/
|
|
150
|
+
async function resolveGoogleImages(client, body, jsonFile, log) {
|
|
151
|
+
const baseDir = path_1.default.dirname(path_1.default.resolve(jsonFile));
|
|
152
|
+
const customerId = String(body?.customerId ?? '');
|
|
153
|
+
const uploadOne = async (relPath) => {
|
|
154
|
+
const abs = path_1.default.isAbsolute(relPath) ? relPath : path_1.default.join(baseDir, relPath);
|
|
155
|
+
const buf = fs_1.default.readFileSync(abs);
|
|
156
|
+
const fileName = path_1.default.basename(abs);
|
|
157
|
+
const form = new FormData();
|
|
158
|
+
form.append('customerId', customerId);
|
|
159
|
+
form.append('image', new Blob([buf]), fileName);
|
|
160
|
+
const res = await client.post('/api/submission/google/upload-image', form, { timeout: 120000 });
|
|
161
|
+
const rn = res.data?.asset_resource_name;
|
|
162
|
+
if (!rn)
|
|
163
|
+
throw new Error(`upload-image が asset_resource_name を返しませんでした (${fileName})`);
|
|
164
|
+
log(`[cli/submit] uploaded image ${fileName} → ${rn}`);
|
|
165
|
+
return rn;
|
|
166
|
+
};
|
|
167
|
+
const fields = [
|
|
168
|
+
['marketingImagePaths', 'marketingImages'],
|
|
169
|
+
['squareMarketingImagePaths', 'squareMarketingImages'],
|
|
170
|
+
['logoImagePaths', 'logoImages'],
|
|
171
|
+
];
|
|
172
|
+
for (const cp of body?.campaigns ?? []) {
|
|
173
|
+
for (const ag of cp?.adGroups ?? []) {
|
|
174
|
+
for (const ad of ag?.ads ?? []) {
|
|
175
|
+
if (ad?.type !== 'RESPONSIVE_DISPLAY_AD')
|
|
176
|
+
continue;
|
|
177
|
+
for (const [pathField, assetField] of fields) {
|
|
178
|
+
const paths = Array.isArray(ad?.[pathField]) ? ad[pathField] : [];
|
|
179
|
+
if (paths.length === 0)
|
|
180
|
+
continue;
|
|
181
|
+
const uploaded = [];
|
|
182
|
+
for (const p of paths)
|
|
183
|
+
uploaded.push(await uploadOne(p));
|
|
184
|
+
ad[assetField] = [...(Array.isArray(ad[assetField]) ? ad[assetField] : []), ...uploaded];
|
|
185
|
+
delete ad[pathField];
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* webgram submit の本体動作。
|
|
193
|
+
*
|
|
194
|
+
* 安全弁:
|
|
195
|
+
* 1. dryRun=true (default) → ?dry_run=1 付きで POST
|
|
196
|
+
* 2. dryRun=false AND yes=false → exit 2 で「--yes を明示してください」
|
|
197
|
+
* 3. yes=true → dry_run なしで POST (本実行)
|
|
198
|
+
*
|
|
199
|
+
* logger:
|
|
200
|
+
* `[cli/submit] platform=... user=... body_hash=... dry_run=...`
|
|
201
|
+
*/
|
|
202
|
+
async function runSubmit(input) {
|
|
203
|
+
const log = input.logger ?? ((line) => console.error(line));
|
|
204
|
+
// platform 検証
|
|
205
|
+
if (!exports.SUBMIT_PLATFORMS.includes(input.platform)) {
|
|
206
|
+
return { ok: false, exitCode: 1, error: `unsupported platform: ${input.platform}` };
|
|
207
|
+
}
|
|
208
|
+
// --yes 必須チェック (dry_run なしで yes も無し → 安全弁発動)
|
|
209
|
+
if (!input.dryRun && !input.yes) {
|
|
210
|
+
return {
|
|
211
|
+
ok: false,
|
|
212
|
+
exitCode: 2,
|
|
213
|
+
error: '本実行するには --yes を明示してください (dry-run なしで実 API を叩く操作です)',
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
// JSON 読込
|
|
217
|
+
let body;
|
|
218
|
+
let raw;
|
|
219
|
+
try {
|
|
220
|
+
raw = fs_1.default.readFileSync(input.jsonFile, 'utf8');
|
|
221
|
+
body = JSON.parse(raw);
|
|
222
|
+
}
|
|
223
|
+
catch (e) {
|
|
224
|
+
return { ok: false, exitCode: 1, error: `json_read_error: ${e.message}` };
|
|
225
|
+
}
|
|
226
|
+
let path;
|
|
227
|
+
try {
|
|
228
|
+
path = resolveSubmitPath(input.platform);
|
|
229
|
+
}
|
|
230
|
+
catch (e) {
|
|
231
|
+
return { ok: false, exitCode: 1, error: e.message };
|
|
232
|
+
}
|
|
233
|
+
// logger 行を吐く (本実行 / dry-run どちらでも記録)
|
|
234
|
+
const creds = input.store.load();
|
|
235
|
+
const user = decodeJwtEmail(creds?.accessToken) ?? 'unknown';
|
|
236
|
+
const bodyHash = sha256Hex(raw);
|
|
237
|
+
log(`[cli/submit] platform=${input.platform} user=${user} body_hash=${bodyHash} dry_run=${input.dryRun}`);
|
|
238
|
+
// 認証 client 構築
|
|
239
|
+
let client;
|
|
240
|
+
try {
|
|
241
|
+
client = (input.clientFactory ?? apiClient_1.buildAuthedApiClient)(input.store);
|
|
242
|
+
}
|
|
243
|
+
catch (e) {
|
|
244
|
+
return { ok: false, exitCode: 1, error: e.message };
|
|
245
|
+
}
|
|
246
|
+
// 本実行時のみ: Meta 動画 (ads[].videoPath) を先にアップロードして videoId へ解決
|
|
247
|
+
// dry-run では実 API を叩かないためアップロードもスキップ
|
|
248
|
+
if (input.platform === 'meta' && !input.dryRun) {
|
|
249
|
+
try {
|
|
250
|
+
await resolveMetaVideos(client, body, input.jsonFile, log);
|
|
251
|
+
}
|
|
252
|
+
catch (e) {
|
|
253
|
+
return { ok: false, exitCode: 1, error: `video_upload_error: ${e.message}` };
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
// 本実行時のみ: YDA 動画 (adGroups[].ads[].videoPath) を先にアップロードして mediaId へ解決
|
|
257
|
+
if (input.platform === 'yda' && !input.dryRun) {
|
|
258
|
+
try {
|
|
259
|
+
await resolveYdaVideos(client, body, input.jsonFile, log);
|
|
260
|
+
}
|
|
261
|
+
catch (e) {
|
|
262
|
+
return { ok: false, exitCode: 1, error: `video_upload_error: ${e.message}` };
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
// 本実行時のみ: Google ディスプレイ広告のローカル画像(*ImagePaths)を先に
|
|
266
|
+
// アップロードして asset resource_name へ解決。dry-run では実 API を叩かない
|
|
267
|
+
if (input.platform === 'google' && !input.dryRun) {
|
|
268
|
+
try {
|
|
269
|
+
await resolveGoogleImages(client, body, input.jsonFile, log);
|
|
270
|
+
}
|
|
271
|
+
catch (e) {
|
|
272
|
+
return { ok: false, exitCode: 1, error: `image_upload_error: ${e.message}` };
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
// POST 実行
|
|
276
|
+
try {
|
|
277
|
+
const params = {};
|
|
278
|
+
if (input.dryRun)
|
|
279
|
+
params.dry_run = '1';
|
|
280
|
+
const res = await client.post(path, body, { params });
|
|
281
|
+
return { ok: true, exitCode: 0, data: res.data };
|
|
282
|
+
}
|
|
283
|
+
catch (err) {
|
|
284
|
+
const status = err?.response?.status;
|
|
285
|
+
const data = err?.response?.data;
|
|
286
|
+
if (status === 400 && data?.error === 'size_limit_exceeded') {
|
|
287
|
+
return {
|
|
288
|
+
ok: false,
|
|
289
|
+
exitCode: 1,
|
|
290
|
+
error: `size_limit_exceeded: ${data.got} creatives > limit ${data.limit}`,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
if (status === 401)
|
|
294
|
+
return { ok: false, exitCode: 1, error: 'unauthorized' };
|
|
295
|
+
const msg = data?.error ?? err.message ?? 'network_error';
|
|
296
|
+
return { ok: false, exitCode: 1, error: msg };
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
//# sourceMappingURL=submission.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"submission.js","sourceRoot":"","sources":["../../src/commands/submission.ts"],"names":[],"mappings":";;;;;;AAsOA,8BAmGC;AAzUD,oDAA4B;AAC5B,4CAAoB;AACpB,gDAAwB;AAExB,gDAAwD;AAI3C,QAAA,gBAAgB,GAAe,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;AAyBhG,iGAAiG;AACjG,SAAS,iBAAiB,CAAC,QAAkB;IAC3C,IAAI,QAAQ,KAAK,MAAM;QAAE,OAAO,sBAAsB,CAAC;IACvD,IAAI,QAAQ,KAAK,KAAK;QAAE,OAAO,qBAAqB,CAAC;IACrD,IAAI,QAAQ,KAAK,QAAQ;QAAE,OAAO,wBAAwB,CAAC;IAC3D,IAAI,QAAQ,KAAK,WAAW;QAAE,OAAO,2BAA2B,CAAC;IACjE,IAAI,QAAQ,KAAK,WAAW;QAAE,OAAO,2BAA2B,CAAC;IACjE,MAAM,IAAI,KAAK,CAAC,oBAAoB,QAAQ,SAAS,CAAC,CAAC;AACzD,CAAC;AAED,SAAS,SAAS,CAAC,CAAS;IAC1B,OAAO,gBAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED,gDAAgD;AAChD,SAAS,cAAc,CAAC,KAAyB;IAC/C,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACpC,IAAI,CAAC,OAAO;YAAE,OAAO,SAAS,CAAC;QAC/B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC7D,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3B,OAAO,OAAO,CAAC,EAAE,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,iBAAiB,CAC9B,MAAqB,EACrB,IAAS,EACT,QAAgB,EAChB,GAA2B;IAE3B,MAAM,OAAO,GAAG,cAAI,CAAC,OAAO,CAAC,cAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IACrD,KAAK,MAAM,EAAE,IAAI,IAAI,EAAE,SAAS,IAAI,EAAE,EAAE,CAAC;QACvC,KAAK,MAAM,EAAE,IAAI,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,CAAC;YAClC,KAAK,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,EAAE,CAAC;gBAC/B,IAAI,CAAC,EAAE,EAAE,SAAS,IAAI,EAAE,EAAE,OAAO;oBAAE,SAAS;gBAC5C,MAAM,SAAS,GAAG,cAAI,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC;oBAC7C,CAAC,CAAC,EAAE,CAAC,SAAS;oBACd,CAAC,CAAC,cAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC;gBACrC,MAAM,GAAG,GAAG,YAAE,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;gBACvC,MAAM,QAAQ,GAAG,cAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;gBAC1C,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;gBAC5B,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;gBACjD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;gBAChD,0CAA0C;gBAC1C,yBAAyB;gBACzB,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,mCAAmC,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;gBAC9F,2DAA2D;gBAC3D,uDAAuD;gBACvD,4BAA4B;gBAC5B,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC;oBACxB,MAAM,IAAI,KAAK,CAAC,sCAAsC,QAAQ,GAAG,CAAC,CAAC;gBACrE,CAAC;gBACD,EAAE,CAAC,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;gBAC/B,OAAO,EAAE,CAAC,SAAS,CAAC;gBACpB,GAAG,CAAC,+BAA+B,QAAQ,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YACjE,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,KAAK,UAAU,gBAAgB,CAC7B,MAAqB,EACrB,IAAS,EACT,QAAgB,EAChB,GAA2B;IAE3B,MAAM,OAAO,GAAG,cAAI,CAAC,OAAO,CAAC,cAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IACrD,KAAK,MAAM,EAAE,IAAI,IAAI,EAAE,SAAS,IAAI,EAAE,EAAE,CAAC;QACvC,KAAK,MAAM,EAAE,IAAI,EAAE,EAAE,QAAQ,IAAI,EAAE,EAAE,CAAC;YACpC,KAAK,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,EAAE,CAAC;gBAC/B,IAAI,CAAC,EAAE,EAAE,SAAS,IAAI,EAAE,EAAE,YAAY;oBAAE,SAAS;gBACjD,MAAM,SAAS,GAAG,cAAI,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC;oBAC7C,CAAC,CAAC,EAAE,CAAC,SAAS;oBACd,CAAC,CAAC,cAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC;gBACrC,MAAM,GAAG,GAAG,YAAE,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;gBACvC,MAAM,QAAQ,GAAG,cAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;gBAC1C,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;gBAC5B,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;gBACjD,IAAI,EAAE,CAAC,UAAU;oBAAE,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;gBACpE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;gBAChD,IAAI,EAAE,CAAC,aAAa,EAAE,CAAC;oBACrB,MAAM,aAAa,GAAG,cAAI,CAAC,UAAU,CAAC,EAAE,CAAC,aAAa,CAAC;wBACrD,CAAC,CAAC,EAAE,CAAC,aAAa;wBAClB,CAAC,CAAC,cAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC;oBACzC,MAAM,QAAQ,GAAG,YAAE,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;oBAChD,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,cAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC;gBAC/E,CAAC;gBACD,+CAA+C;gBAC/C,IAAI,GAAG,CAAC;gBACR,IAAI,CAAC;oBACH,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,kCAAkC,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;gBACzF,CAAC;gBAAC,OAAO,CAAM,EAAE,CAAC;oBAChB,yCAAyC;oBACzC,MAAM,MAAM,GAAG,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC;oBAChF,MAAM,IAAI,KAAK,CAAC,oBAAoB,QAAQ,MAAM,MAAM,EAAE,CAAC,CAAC;gBAC9D,CAAC;gBACD,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC;oBACxB,MAAM,IAAI,KAAK,CAAC,sCAAsC,QAAQ,GAAG,CAAC,CAAC;gBACrE,CAAC;gBACD,EAAE,CAAC,YAAY,GAAG,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;gBACpC,IAAI,GAAG,CAAC,IAAI,CAAC,kBAAkB,IAAI,CAAC,EAAE,CAAC,gBAAgB,EAAE,CAAC;oBACxD,EAAE,CAAC,gBAAgB,GAAG,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC;gBACpD,CAAC;gBACD,OAAO,EAAE,CAAC,SAAS,CAAC;gBACpB,OAAO,EAAE,CAAC,aAAa,CAAC;gBACxB,GAAG,CAAC,mCAAmC,QAAQ,cAAc,EAAE,CAAC,YAAY,qBAAqB,EAAE,CAAC,gBAAgB,IAAI,MAAM,EAAE,CAAC,CAAC;YACpI,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,KAAK,UAAU,mBAAmB,CAChC,MAAqB,EACrB,IAAS,EACT,QAAgB,EAChB,GAA2B;IAE3B,MAAM,OAAO,GAAG,cAAI,CAAC,OAAO,CAAC,cAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IACrD,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,EAAE,UAAU,IAAI,EAAE,CAAC,CAAC;IAElD,MAAM,SAAS,GAAG,KAAK,EAAE,OAAe,EAAmB,EAAE;QAC3D,MAAM,GAAG,GAAG,cAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,cAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC7E,MAAM,GAAG,GAAG,YAAE,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,QAAQ,GAAG,cAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QAChD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,qCAAqC,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QAChG,MAAM,EAAE,GAAG,GAAG,CAAC,IAAI,EAAE,mBAAmB,CAAC;QACzC,IAAI,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,QAAQ,GAAG,CAAC,CAAC;QACvF,GAAG,CAAC,+BAA+B,QAAQ,MAAM,EAAE,EAAE,CAAC,CAAC;QACvD,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC;IAEF,MAAM,MAAM,GAA4B;QACtC,CAAC,qBAAqB,EAAE,iBAAiB,CAAC;QAC1C,CAAC,2BAA2B,EAAE,uBAAuB,CAAC;QACtD,CAAC,gBAAgB,EAAE,YAAY,CAAC;KACjC,CAAC;IAEF,KAAK,MAAM,EAAE,IAAI,IAAI,EAAE,SAAS,IAAI,EAAE,EAAE,CAAC;QACvC,KAAK,MAAM,EAAE,IAAI,EAAE,EAAE,QAAQ,IAAI,EAAE,EAAE,CAAC;YACpC,KAAK,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,EAAE,CAAC;gBAC/B,IAAI,EAAE,EAAE,IAAI,KAAK,uBAAuB;oBAAE,SAAS;gBACnD,KAAK,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,IAAI,MAAM,EAAE,CAAC;oBAC7C,MAAM,KAAK,GAAa,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC5E,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;wBAAE,SAAS;oBACjC,MAAM,QAAQ,GAAa,EAAE,CAAC;oBAC9B,KAAK,MAAM,CAAC,IAAI,KAAK;wBAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;oBACzD,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,QAAQ,CAAC,CAAC;oBACzF,OAAO,EAAE,CAAC,SAAS,CAAC,CAAC;gBACvB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACI,KAAK,UAAU,SAAS,CAAC,KAAkB;IAChD,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAEpE,cAAc;IACd,IAAI,CAAC,wBAAgB,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,yBAAyB,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC;IACtF,CAAC;IAED,6CAA6C;IAC7C,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;QAChC,OAAO;YACL,EAAE,EAAE,KAAK;YACT,QAAQ,EAAE,CAAC;YACX,KAAK,EAAE,oDAAoD;SAC5D,CAAC;IACJ,CAAC;IAED,UAAU;IACV,IAAI,IAAa,CAAC;IAClB,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,YAAE,CAAC,YAAY,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC9C,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,oBAAqB,CAAW,CAAC,OAAO,EAAE,EAAE,CAAC;IACvF,CAAC;IAED,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,iBAAiB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAG,CAAW,CAAC,OAAO,EAAE,CAAC;IACjE,CAAC;IAED,sCAAsC;IACtC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IACjC,MAAM,IAAI,GAAG,cAAc,CAAC,KAAK,EAAE,WAAW,CAAC,IAAI,SAAS,CAAC;IAC7D,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAChC,GAAG,CAAC,yBAAyB,KAAK,CAAC,QAAQ,SAAS,IAAI,cAAc,QAAQ,YAAY,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IAE1G,eAAe;IACf,IAAI,MAAqB,CAAC;IAC1B,IAAI,CAAC;QACH,MAAM,GAAG,CAAC,KAAK,CAAC,aAAa,IAAI,gCAAoB,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACtE,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAG,CAAW,CAAC,OAAO,EAAE,CAAC;IACjE,CAAC;IAED,4DAA4D;IAC5D,qCAAqC;IACrC,IAAI,KAAK,CAAC,QAAQ,KAAK,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QAC/C,IAAI,CAAC;YACH,MAAM,iBAAiB,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QAC7D,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,uBAAwB,CAAW,CAAC,OAAO,EAAE,EAAE,CAAC;QAC1F,CAAC;IACH,CAAC;IAED,sEAAsE;IACtE,IAAI,KAAK,CAAC,QAAQ,KAAK,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QAC9C,IAAI,CAAC;YACH,MAAM,gBAAgB,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QAC5D,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,uBAAwB,CAAW,CAAC,OAAO,EAAE,EAAE,CAAC;QAC1F,CAAC;IACH,CAAC;IAED,iDAAiD;IACjD,yDAAyD;IACzD,IAAI,KAAK,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QACjD,IAAI,CAAC;YACH,MAAM,mBAAmB,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QAC/D,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,uBAAwB,CAAW,CAAC,OAAO,EAAE,EAAE,CAAC;QAC1F,CAAC;IACH,CAAC;IAED,UAAU;IACV,IAAI,CAAC;QACH,MAAM,MAAM,GAA2B,EAAE,CAAC;QAC1C,IAAI,KAAK,CAAC,MAAM;YAAE,MAAM,CAAC,OAAO,GAAG,GAAG,CAAC;QACvC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;QACtD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;IACnD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAI,GAAmG,EAAE,QAAQ,EAAE,MAAM,CAAC;QACtI,MAAM,IAAI,GAAI,GAAkF,EAAE,QAAQ,EAAE,IAAI,CAAC;QAEjH,IAAI,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,KAAK,KAAK,qBAAqB,EAAE,CAAC;YAC5D,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,QAAQ,EAAE,CAAC;gBACX,KAAK,EAAE,wBAAwB,IAAI,CAAC,GAAG,sBAAsB,IAAI,CAAC,KAAK,EAAE;aAC1E,CAAC;QACJ,CAAC;QACD,IAAI,MAAM,KAAK,GAAG;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC;QAE7E,MAAM,GAAG,GAAG,IAAI,EAAE,KAAK,IAAK,GAAa,CAAC,OAAO,IAAI,eAAe,CAAC;QACrE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IAChD,CAAC;AACH,CAAC"}
|