@apps-in-toss/cli 0.0.0-dev.1740737494440
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 +1 -0
- package/bin.js +4 -0
- package/dist/index.cjs +395 -0
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +361 -0
- package/package.json +49 -0
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# @apps-in-toss/cli
|
package/bin.js
ADDED
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
initialize: () => initialize
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(src_exports);
|
|
36
|
+
var import_clipanion3 = require("clipanion");
|
|
37
|
+
|
|
38
|
+
// src/DeployCommand.ts
|
|
39
|
+
var import_assert = __toESM(require("assert"), 1);
|
|
40
|
+
var import_fs3 = __toESM(require("fs"), 1);
|
|
41
|
+
var import_path2 = __toESM(require("path"), 1);
|
|
42
|
+
var p = __toESM(require("@clack/prompts"), 1);
|
|
43
|
+
var import_clipanion = require("clipanion");
|
|
44
|
+
var import_debug2 = __toESM(require("debug"), 1);
|
|
45
|
+
var import_picocolors = __toESM(require("picocolors"), 1);
|
|
46
|
+
|
|
47
|
+
// src/utils/constants.ts
|
|
48
|
+
var APP_MANIFEST_NAME = "app.json";
|
|
49
|
+
var DEFAULT_API_BASE_URL = "https://apps-in-toss.toss.im/console";
|
|
50
|
+
|
|
51
|
+
// src/utils/getPackageRoot.ts
|
|
52
|
+
var import_fs = __toESM(require("fs"), 1);
|
|
53
|
+
var import_path = __toESM(require("path"), 1);
|
|
54
|
+
function getPackageRoot() {
|
|
55
|
+
let cwd = process.cwd();
|
|
56
|
+
const root = import_path.default.parse(cwd).root;
|
|
57
|
+
while (cwd !== root) {
|
|
58
|
+
if (import_fs.default.existsSync(import_path.default.join(cwd, "package.json"))) {
|
|
59
|
+
return cwd;
|
|
60
|
+
}
|
|
61
|
+
cwd = import_path.default.dirname(cwd);
|
|
62
|
+
}
|
|
63
|
+
return cwd;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/utils/readZipContent.ts
|
|
67
|
+
var import_yauzl = __toESM(require("yauzl"), 1);
|
|
68
|
+
function readZipContent(zipPath, fileName) {
|
|
69
|
+
return new Promise((resolve, reject) => {
|
|
70
|
+
import_yauzl.default.open(zipPath, { lazyEntries: true }, (error, zipFile) => {
|
|
71
|
+
if (error) {
|
|
72
|
+
reject(error);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
zipFile.on("entry", (entry) => {
|
|
76
|
+
if (entry.fileName === fileName) {
|
|
77
|
+
zipFile.openReadStream(entry, (error2, readStream) => {
|
|
78
|
+
if (error2) {
|
|
79
|
+
throw error2;
|
|
80
|
+
}
|
|
81
|
+
let fileData = "";
|
|
82
|
+
readStream.on("data", (chunk) => fileData += chunk.toString("utf8")).on("end", () => {
|
|
83
|
+
zipFile.close();
|
|
84
|
+
resolve(fileData);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
} else {
|
|
88
|
+
zipFile.readEntry();
|
|
89
|
+
}
|
|
90
|
+
}).on("end", () => {
|
|
91
|
+
zipFile.close();
|
|
92
|
+
reject(new Error(`'${fileName}' not found in zip file`));
|
|
93
|
+
}).on("error", (error2) => {
|
|
94
|
+
zipFile.close();
|
|
95
|
+
reject(error2);
|
|
96
|
+
});
|
|
97
|
+
zipFile.readEntry();
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// src/utils/upload.ts
|
|
103
|
+
var import_fs2 = __toESM(require("fs"), 1);
|
|
104
|
+
var import_debug = __toESM(require("debug"), 1);
|
|
105
|
+
var debug = (0, import_debug.default)("cli:deploy");
|
|
106
|
+
async function uploadArtifact(config) {
|
|
107
|
+
debug("uploadArtifact", config);
|
|
108
|
+
const baseUrl = config.baseUrl ?? DEFAULT_API_BASE_URL;
|
|
109
|
+
const response = await fetch(
|
|
110
|
+
`${baseUrl}/api-public/v3/appsintossconsole/bundles/${config.appName}/deployments/${config.deploymentId}/upload`,
|
|
111
|
+
{
|
|
112
|
+
method: "POST",
|
|
113
|
+
headers: {
|
|
114
|
+
"Content-Type": "application/octet-stream",
|
|
115
|
+
"X-Ait-Console-Api-Key": config.apiKey
|
|
116
|
+
},
|
|
117
|
+
body: import_fs2.default.createReadStream(config.artifactPath),
|
|
118
|
+
duplex: "half"
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
return handleResponse(response);
|
|
122
|
+
}
|
|
123
|
+
async function handleResponse(response) {
|
|
124
|
+
debug(`Response ${response.status} ${response.statusText}`);
|
|
125
|
+
if (!response.ok) {
|
|
126
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
127
|
+
}
|
|
128
|
+
const data = await response.clone().json();
|
|
129
|
+
debug("uploadArtifact response", data);
|
|
130
|
+
if (data.resultType !== "SUCCESS") {
|
|
131
|
+
const errorCode = data?.error?.errorCode ?? "-1";
|
|
132
|
+
const errorReason = data?.error.reason ?? "unknown";
|
|
133
|
+
throw new Error(`${errorReason} (Code: ${errorCode})`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// src/DeployCommand.ts
|
|
138
|
+
var debug2 = (0, import_debug2.default)("cli:deploy");
|
|
139
|
+
var DeployCommand = class extends import_clipanion.Command {
|
|
140
|
+
static paths = [["deploy"]];
|
|
141
|
+
apiKey = import_clipanion.Option.String("--api-key", {
|
|
142
|
+
required: false,
|
|
143
|
+
description: "\uC54C\uD30C \uBC30\uD3EC\uB97C \uC704\uD55C API \uD0A4"
|
|
144
|
+
});
|
|
145
|
+
baseUrl = import_clipanion.Option.String("--base-url", {
|
|
146
|
+
description: "API Base URL"
|
|
147
|
+
});
|
|
148
|
+
async execute() {
|
|
149
|
+
const baseUrl = this.baseUrl;
|
|
150
|
+
const apiKey = this.apiKey || await p.password({
|
|
151
|
+
message: "\uC571\uC778\uD1A0\uC2A4 \uBC30\uD3EC API \uD0A4\uB97C \uC785\uB825\uD574\uC8FC\uC138\uC694",
|
|
152
|
+
validate: (value) => {
|
|
153
|
+
if (value.length === 0) {
|
|
154
|
+
return "API \uD0A4\uB294 \uD544\uC218 \uC785\uB825 \uD56D\uBAA9\uC785\uB2C8\uB2E4.";
|
|
155
|
+
}
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
if (p.isCancel(apiKey)) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
try {
|
|
163
|
+
const packageRoot = getPackageRoot();
|
|
164
|
+
const artifactFile = import_fs3.default.readdirSync(packageRoot).find((file) => file.endsWith(".ait"));
|
|
165
|
+
if (!artifactFile) {
|
|
166
|
+
throw new Error("\uBC30\uD3EC\uD560 .ait \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
167
|
+
}
|
|
168
|
+
const resolvedArtifactPath = import_path2.default.resolve(packageRoot, artifactFile);
|
|
169
|
+
const { appName, deploymentId } = await readZipContent(resolvedArtifactPath, APP_MANIFEST_NAME).then((rawAppManifest) => {
|
|
170
|
+
const appManifest = JSON.parse(rawAppManifest);
|
|
171
|
+
const appName2 = appManifest.appName;
|
|
172
|
+
const deploymentId2 = appManifest.deploymentId;
|
|
173
|
+
(0, import_assert.default)(typeof appName2 === "string", "invalid appName");
|
|
174
|
+
return { appName: appName2, deploymentId: deploymentId2 };
|
|
175
|
+
}).catch((error) => {
|
|
176
|
+
debug2("invalid ait file", error);
|
|
177
|
+
throw new Error("\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 ait \uD30C\uC77C\uC785\uB2C8\uB2E4");
|
|
178
|
+
});
|
|
179
|
+
const colorAppName = import_picocolors.default.underline(import_picocolors.default.cyan(appName));
|
|
180
|
+
await p.tasks([
|
|
181
|
+
{
|
|
182
|
+
title: `${colorAppName} \uC571 \uBC30\uD3EC \uC911...`,
|
|
183
|
+
task: async () => {
|
|
184
|
+
await uploadArtifact({
|
|
185
|
+
artifactPath: resolvedArtifactPath,
|
|
186
|
+
appName,
|
|
187
|
+
deploymentId,
|
|
188
|
+
apiKey,
|
|
189
|
+
baseUrl
|
|
190
|
+
});
|
|
191
|
+
return `${colorAppName} \uBC30\uD3EC\uAC00 \uC644\uB8CC\uB418\uC5C8\uC5B4\uC694`;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
]);
|
|
195
|
+
if (deploymentId) {
|
|
196
|
+
p.note(import_picocolors.default.underline(import_picocolors.default.green(`intoss-private://${appName}?_deploymentId=${deploymentId}`)));
|
|
197
|
+
}
|
|
198
|
+
} catch (error) {
|
|
199
|
+
if (error instanceof Error) {
|
|
200
|
+
p.log.error(error.message);
|
|
201
|
+
} else {
|
|
202
|
+
console.error(error);
|
|
203
|
+
}
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// src/InitCommand.ts
|
|
210
|
+
var import_fs4 = __toESM(require("fs"), 1);
|
|
211
|
+
var import_path3 = __toESM(require("path"), 1);
|
|
212
|
+
var p2 = __toESM(require("@clack/prompts"), 1);
|
|
213
|
+
var import_clipanion2 = require("clipanion");
|
|
214
|
+
var import_es_toolkit = require("es-toolkit");
|
|
215
|
+
var import_execa = require("execa");
|
|
216
|
+
var import_yaml = __toESM(require("yaml"), 1);
|
|
217
|
+
|
|
218
|
+
// src/templates.ts
|
|
219
|
+
var WEB_FRAMEWORK_CONFIG_TEMPLATE = `import { defineConfig } from '@apps-in-toss/web-framework/config';
|
|
220
|
+
|
|
221
|
+
export default defineConfig({
|
|
222
|
+
appName: '%%appName%%',
|
|
223
|
+
web: {
|
|
224
|
+
port: %%webPort%%,
|
|
225
|
+
commands: {
|
|
226
|
+
dev: '%%webDevCommand%%',
|
|
227
|
+
build: '%%webBuildCommand%%',
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
permissions: []
|
|
231
|
+
});
|
|
232
|
+
`;
|
|
233
|
+
|
|
234
|
+
// src/utils/transformTemplate.ts
|
|
235
|
+
function transformTemplate(templateString, values) {
|
|
236
|
+
let result = templateString;
|
|
237
|
+
for (const key in values) {
|
|
238
|
+
const placeholder = `%%${key}%%`;
|
|
239
|
+
result = result.replace(new RegExp(placeholder, "g"), values[key]);
|
|
240
|
+
}
|
|
241
|
+
return result;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// src/InitCommand.ts
|
|
245
|
+
var import_meta = {};
|
|
246
|
+
async function getPnpRoot() {
|
|
247
|
+
try {
|
|
248
|
+
const pnpapi = (await import_meta.resolve("pnpapi")).replace("file://", "");
|
|
249
|
+
return import_path3.default.dirname(pnpapi);
|
|
250
|
+
} catch {
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
async function templateWebFramework({
|
|
255
|
+
appName,
|
|
256
|
+
cwd,
|
|
257
|
+
originalScripts
|
|
258
|
+
}) {
|
|
259
|
+
p2.log.step("bedrock.config.ts \uD30C\uC77C\uC744 \uC0DD\uC131\uD558\uB294 \uC911...");
|
|
260
|
+
const webPort = await p2.text({
|
|
261
|
+
message: "Enter web port",
|
|
262
|
+
placeholder: "5173",
|
|
263
|
+
defaultValue: "5173"
|
|
264
|
+
});
|
|
265
|
+
if (p2.isCancel(webPort)) {
|
|
266
|
+
p2.cancel("\uCD08\uAE30\uD654\uAC00 \uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4");
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
const config = transformTemplate(WEB_FRAMEWORK_CONFIG_TEMPLATE, {
|
|
270
|
+
appName,
|
|
271
|
+
webPort,
|
|
272
|
+
webDevCommand: originalScripts.dev === "ait dev" ? "" : originalScripts.dev,
|
|
273
|
+
webBuildCommand: originalScripts.build === "ait build" ? "" : originalScripts.build
|
|
274
|
+
});
|
|
275
|
+
await import_fs4.default.promises.writeFile(import_path3.default.join(cwd, "bedrock.config.ts"), config, {
|
|
276
|
+
encoding: "utf-8"
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
var InitCommand = class extends import_clipanion2.Command {
|
|
280
|
+
static paths = [[`init`]];
|
|
281
|
+
async execute() {
|
|
282
|
+
const template = await p2.select({
|
|
283
|
+
message: "\uD504\uB85C\uC81D\uD2B8\uB97C \uCD08\uAE30\uD654\uD560 \uD15C\uD50C\uB9BF\uC744 \uC120\uD0DD\uD574\uC8FC\uC138\uC694.",
|
|
284
|
+
options: [
|
|
285
|
+
{
|
|
286
|
+
value: "web-framework",
|
|
287
|
+
label: "\uC6F9 \uD504\uB808\uC784\uC6CC\uD06C",
|
|
288
|
+
hint: "\uC6F9 \uD504\uB85C\uC81D\uD2B8\uC5D0 \uC571\uC778\uD1A0\uC2A4 \uC6F9\uBDF0 \uAC1C\uBC1C\uD658\uACBD\uC744 \uC138\uD305\uD569\uB2C8\uB2E4."
|
|
289
|
+
}
|
|
290
|
+
]
|
|
291
|
+
});
|
|
292
|
+
if (p2.isCancel(template)) {
|
|
293
|
+
process.exit(0);
|
|
294
|
+
}
|
|
295
|
+
const cwd = getPackageRoot();
|
|
296
|
+
p2.intro("\u{1F680} \uC571 \uCD08\uAE30\uD654\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4");
|
|
297
|
+
const appName = await p2.text({
|
|
298
|
+
message: "Enter app name",
|
|
299
|
+
validate: (value) => {
|
|
300
|
+
if (!value) {
|
|
301
|
+
return "\uC571 \uC774\uB984\uC744 \uC785\uB825\uD574\uC8FC\uC138\uC694";
|
|
302
|
+
}
|
|
303
|
+
const kebabCaseValue = (0, import_es_toolkit.kebabCase)(value);
|
|
304
|
+
if (value !== kebabCaseValue) {
|
|
305
|
+
return `\uC571 \uC774\uB984\uC740 \uCF00\uBC25-\uCF00\uC774\uC2A4 \uD615\uC2DD\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4 (\uC608\uC2DC: ${kebabCaseValue})`;
|
|
306
|
+
}
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
if (p2.isCancel(appName)) {
|
|
311
|
+
p2.cancel("\uCD08\uAE30\uD654\uAC00 \uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4");
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
p2.log.step(`\uC571 \uC774\uB984\uC774 '${appName}'\uC73C\uB85C \uC124\uC815\uB418\uC5C8\uC2B5\uB2C8\uB2E4`);
|
|
315
|
+
p2.log.step("package.json \uC2A4\uD06C\uB9BD\uD2B8\uB97C \uC124\uC815\uD558\uB294 \uC911...");
|
|
316
|
+
const packageJson = await import_fs4.default.promises.readFile(import_path3.default.join(cwd, "package.json"), {
|
|
317
|
+
encoding: "utf-8"
|
|
318
|
+
});
|
|
319
|
+
const scripts = JSON.parse(packageJson);
|
|
320
|
+
const originalScripts = {
|
|
321
|
+
dev: scripts?.scripts?.dev || scripts?.scripts?.start,
|
|
322
|
+
build: scripts?.scripts?.build
|
|
323
|
+
};
|
|
324
|
+
scripts.scripts.dev = "bedrock dev";
|
|
325
|
+
scripts.scripts.build = "bedrock build";
|
|
326
|
+
scripts.scripts.deploy = "ait deploy";
|
|
327
|
+
await import_fs4.default.promises.writeFile(import_path3.default.join(cwd, "package.json"), JSON.stringify(scripts, null, 2), {
|
|
328
|
+
encoding: "utf-8"
|
|
329
|
+
});
|
|
330
|
+
p2.log.step(".gitignore \uD30C\uC77C\uC744 \uC5C5\uB370\uC774\uD2B8\uD558\uB294 \uC911...");
|
|
331
|
+
await import_fs4.default.promises.appendFile(import_path3.default.join(cwd, ".gitignore"), "\n.bedrock\n");
|
|
332
|
+
switch (template) {
|
|
333
|
+
case "web-framework": {
|
|
334
|
+
await templateWebFramework({
|
|
335
|
+
appName,
|
|
336
|
+
cwd,
|
|
337
|
+
originalScripts
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
const pnpRoot = await getPnpRoot();
|
|
342
|
+
if (pnpRoot) {
|
|
343
|
+
const yarnrcPath = import_path3.default.join(pnpRoot, ".yarnrc.yml");
|
|
344
|
+
let yarnrc = {};
|
|
345
|
+
try {
|
|
346
|
+
const yarnrcContent = await import_fs4.default.promises.readFile(yarnrcPath, { encoding: "utf-8" });
|
|
347
|
+
yarnrc = import_yaml.default.parse(yarnrcContent);
|
|
348
|
+
} catch {
|
|
349
|
+
p2.log.info(".yarnrc.yml \uD30C\uC77C\uC774 \uC5C6\uC5B4 \uC0C8\uB85C \uC0DD\uC131\uD569\uB2C8\uB2E4.");
|
|
350
|
+
}
|
|
351
|
+
p2.log.step(".yarnrc.yml \uD30C\uC77C\uC744 \uC5C5\uB370\uC774\uD2B8\uD558\uB294 \uC911...");
|
|
352
|
+
yarnrc = (0, import_es_toolkit.merge)(yarnrc, {
|
|
353
|
+
packageExtensions: {
|
|
354
|
+
"@react-native-community/cli-debugger-ui@*": {
|
|
355
|
+
dependencies: {
|
|
356
|
+
"@babel/runtime": "^7"
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
"react-native-video@*": {
|
|
360
|
+
peerDependencies: {
|
|
361
|
+
react: "*",
|
|
362
|
+
"react-native": "*"
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
"react-native-fast-image@*": {
|
|
366
|
+
dependencies: {
|
|
367
|
+
"@babel/runtime": "^7"
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
await import_fs4.default.promises.writeFile(yarnrcPath, import_yaml.default.stringify(yarnrc), { encoding: "utf-8" });
|
|
373
|
+
await (0, import_execa.execa)("yarn", ["install"], {
|
|
374
|
+
cwd,
|
|
375
|
+
stdio: "inherit"
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
p2.outro("\u2728 \uCD08\uAE30\uD654\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4!");
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
// src/index.ts
|
|
383
|
+
function initialize() {
|
|
384
|
+
const cli = new import_clipanion3.Cli({
|
|
385
|
+
binaryLabel: "ait",
|
|
386
|
+
binaryName: "ait"
|
|
387
|
+
});
|
|
388
|
+
cli.register(DeployCommand);
|
|
389
|
+
cli.register(InitCommand);
|
|
390
|
+
cli.runExit(process.argv.slice(2));
|
|
391
|
+
}
|
|
392
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
393
|
+
0 && (module.exports = {
|
|
394
|
+
initialize
|
|
395
|
+
});
|
package/dist/index.d.cts
ADDED
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
import { createRequire } from 'module'; const require = createRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Cli } from "clipanion";
|
|
5
|
+
|
|
6
|
+
// src/DeployCommand.ts
|
|
7
|
+
import assert from "assert";
|
|
8
|
+
import fs3 from "fs";
|
|
9
|
+
import path2 from "path";
|
|
10
|
+
import * as p from "@clack/prompts";
|
|
11
|
+
import { Command, Option } from "clipanion";
|
|
12
|
+
import Debug2 from "debug";
|
|
13
|
+
import picocolors from "picocolors";
|
|
14
|
+
|
|
15
|
+
// src/utils/constants.ts
|
|
16
|
+
var APP_MANIFEST_NAME = "app.json";
|
|
17
|
+
var DEFAULT_API_BASE_URL = "https://apps-in-toss.toss.im/console";
|
|
18
|
+
|
|
19
|
+
// src/utils/getPackageRoot.ts
|
|
20
|
+
import fs from "fs";
|
|
21
|
+
import path from "path";
|
|
22
|
+
function getPackageRoot() {
|
|
23
|
+
let cwd = process.cwd();
|
|
24
|
+
const root = path.parse(cwd).root;
|
|
25
|
+
while (cwd !== root) {
|
|
26
|
+
if (fs.existsSync(path.join(cwd, "package.json"))) {
|
|
27
|
+
return cwd;
|
|
28
|
+
}
|
|
29
|
+
cwd = path.dirname(cwd);
|
|
30
|
+
}
|
|
31
|
+
return cwd;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// src/utils/readZipContent.ts
|
|
35
|
+
import yauzl from "yauzl";
|
|
36
|
+
function readZipContent(zipPath, fileName) {
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
yauzl.open(zipPath, { lazyEntries: true }, (error, zipFile) => {
|
|
39
|
+
if (error) {
|
|
40
|
+
reject(error);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
zipFile.on("entry", (entry) => {
|
|
44
|
+
if (entry.fileName === fileName) {
|
|
45
|
+
zipFile.openReadStream(entry, (error2, readStream) => {
|
|
46
|
+
if (error2) {
|
|
47
|
+
throw error2;
|
|
48
|
+
}
|
|
49
|
+
let fileData = "";
|
|
50
|
+
readStream.on("data", (chunk) => fileData += chunk.toString("utf8")).on("end", () => {
|
|
51
|
+
zipFile.close();
|
|
52
|
+
resolve(fileData);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
} else {
|
|
56
|
+
zipFile.readEntry();
|
|
57
|
+
}
|
|
58
|
+
}).on("end", () => {
|
|
59
|
+
zipFile.close();
|
|
60
|
+
reject(new Error(`'${fileName}' not found in zip file`));
|
|
61
|
+
}).on("error", (error2) => {
|
|
62
|
+
zipFile.close();
|
|
63
|
+
reject(error2);
|
|
64
|
+
});
|
|
65
|
+
zipFile.readEntry();
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// src/utils/upload.ts
|
|
71
|
+
import fs2 from "fs";
|
|
72
|
+
import Debug from "debug";
|
|
73
|
+
var debug = Debug("cli:deploy");
|
|
74
|
+
async function uploadArtifact(config) {
|
|
75
|
+
debug("uploadArtifact", config);
|
|
76
|
+
const baseUrl = config.baseUrl ?? DEFAULT_API_BASE_URL;
|
|
77
|
+
const response = await fetch(
|
|
78
|
+
`${baseUrl}/api-public/v3/appsintossconsole/bundles/${config.appName}/deployments/${config.deploymentId}/upload`,
|
|
79
|
+
{
|
|
80
|
+
method: "POST",
|
|
81
|
+
headers: {
|
|
82
|
+
"Content-Type": "application/octet-stream",
|
|
83
|
+
"X-Ait-Console-Api-Key": config.apiKey
|
|
84
|
+
},
|
|
85
|
+
body: fs2.createReadStream(config.artifactPath),
|
|
86
|
+
duplex: "half"
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
return handleResponse(response);
|
|
90
|
+
}
|
|
91
|
+
async function handleResponse(response) {
|
|
92
|
+
debug(`Response ${response.status} ${response.statusText}`);
|
|
93
|
+
if (!response.ok) {
|
|
94
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
95
|
+
}
|
|
96
|
+
const data = await response.clone().json();
|
|
97
|
+
debug("uploadArtifact response", data);
|
|
98
|
+
if (data.resultType !== "SUCCESS") {
|
|
99
|
+
const errorCode = data?.error?.errorCode ?? "-1";
|
|
100
|
+
const errorReason = data?.error.reason ?? "unknown";
|
|
101
|
+
throw new Error(`${errorReason} (Code: ${errorCode})`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// src/DeployCommand.ts
|
|
106
|
+
var debug2 = Debug2("cli:deploy");
|
|
107
|
+
var DeployCommand = class extends Command {
|
|
108
|
+
static paths = [["deploy"]];
|
|
109
|
+
apiKey = Option.String("--api-key", {
|
|
110
|
+
required: false,
|
|
111
|
+
description: "\uC54C\uD30C \uBC30\uD3EC\uB97C \uC704\uD55C API \uD0A4"
|
|
112
|
+
});
|
|
113
|
+
baseUrl = Option.String("--base-url", {
|
|
114
|
+
description: "API Base URL"
|
|
115
|
+
});
|
|
116
|
+
async execute() {
|
|
117
|
+
const baseUrl = this.baseUrl;
|
|
118
|
+
const apiKey = this.apiKey || await p.password({
|
|
119
|
+
message: "\uC571\uC778\uD1A0\uC2A4 \uBC30\uD3EC API \uD0A4\uB97C \uC785\uB825\uD574\uC8FC\uC138\uC694",
|
|
120
|
+
validate: (value) => {
|
|
121
|
+
if (value.length === 0) {
|
|
122
|
+
return "API \uD0A4\uB294 \uD544\uC218 \uC785\uB825 \uD56D\uBAA9\uC785\uB2C8\uB2E4.";
|
|
123
|
+
}
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
if (p.isCancel(apiKey)) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
const packageRoot = getPackageRoot();
|
|
132
|
+
const artifactFile = fs3.readdirSync(packageRoot).find((file) => file.endsWith(".ait"));
|
|
133
|
+
if (!artifactFile) {
|
|
134
|
+
throw new Error("\uBC30\uD3EC\uD560 .ait \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
135
|
+
}
|
|
136
|
+
const resolvedArtifactPath = path2.resolve(packageRoot, artifactFile);
|
|
137
|
+
const { appName, deploymentId } = await readZipContent(resolvedArtifactPath, APP_MANIFEST_NAME).then((rawAppManifest) => {
|
|
138
|
+
const appManifest = JSON.parse(rawAppManifest);
|
|
139
|
+
const appName2 = appManifest.appName;
|
|
140
|
+
const deploymentId2 = appManifest.deploymentId;
|
|
141
|
+
assert(typeof appName2 === "string", "invalid appName");
|
|
142
|
+
return { appName: appName2, deploymentId: deploymentId2 };
|
|
143
|
+
}).catch((error) => {
|
|
144
|
+
debug2("invalid ait file", error);
|
|
145
|
+
throw new Error("\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 ait \uD30C\uC77C\uC785\uB2C8\uB2E4");
|
|
146
|
+
});
|
|
147
|
+
const colorAppName = picocolors.underline(picocolors.cyan(appName));
|
|
148
|
+
await p.tasks([
|
|
149
|
+
{
|
|
150
|
+
title: `${colorAppName} \uC571 \uBC30\uD3EC \uC911...`,
|
|
151
|
+
task: async () => {
|
|
152
|
+
await uploadArtifact({
|
|
153
|
+
artifactPath: resolvedArtifactPath,
|
|
154
|
+
appName,
|
|
155
|
+
deploymentId,
|
|
156
|
+
apiKey,
|
|
157
|
+
baseUrl
|
|
158
|
+
});
|
|
159
|
+
return `${colorAppName} \uBC30\uD3EC\uAC00 \uC644\uB8CC\uB418\uC5C8\uC5B4\uC694`;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
]);
|
|
163
|
+
if (deploymentId) {
|
|
164
|
+
p.note(picocolors.underline(picocolors.green(`intoss-private://${appName}?_deploymentId=${deploymentId}`)));
|
|
165
|
+
}
|
|
166
|
+
} catch (error) {
|
|
167
|
+
if (error instanceof Error) {
|
|
168
|
+
p.log.error(error.message);
|
|
169
|
+
} else {
|
|
170
|
+
console.error(error);
|
|
171
|
+
}
|
|
172
|
+
process.exit(1);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// src/InitCommand.ts
|
|
178
|
+
import fs4 from "fs";
|
|
179
|
+
import path3 from "path";
|
|
180
|
+
import * as p2 from "@clack/prompts";
|
|
181
|
+
import { Command as Command2 } from "clipanion";
|
|
182
|
+
import { kebabCase, merge } from "es-toolkit";
|
|
183
|
+
import { execa } from "execa";
|
|
184
|
+
import yaml from "yaml";
|
|
185
|
+
|
|
186
|
+
// src/templates.ts
|
|
187
|
+
var WEB_FRAMEWORK_CONFIG_TEMPLATE = `import { defineConfig } from '@apps-in-toss/web-framework/config';
|
|
188
|
+
|
|
189
|
+
export default defineConfig({
|
|
190
|
+
appName: '%%appName%%',
|
|
191
|
+
web: {
|
|
192
|
+
port: %%webPort%%,
|
|
193
|
+
commands: {
|
|
194
|
+
dev: '%%webDevCommand%%',
|
|
195
|
+
build: '%%webBuildCommand%%',
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
permissions: []
|
|
199
|
+
});
|
|
200
|
+
`;
|
|
201
|
+
|
|
202
|
+
// src/utils/transformTemplate.ts
|
|
203
|
+
function transformTemplate(templateString, values) {
|
|
204
|
+
let result = templateString;
|
|
205
|
+
for (const key in values) {
|
|
206
|
+
const placeholder = `%%${key}%%`;
|
|
207
|
+
result = result.replace(new RegExp(placeholder, "g"), values[key]);
|
|
208
|
+
}
|
|
209
|
+
return result;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// src/InitCommand.ts
|
|
213
|
+
async function getPnpRoot() {
|
|
214
|
+
try {
|
|
215
|
+
const pnpapi = (await import.meta.resolve("pnpapi")).replace("file://", "");
|
|
216
|
+
return path3.dirname(pnpapi);
|
|
217
|
+
} catch {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
async function templateWebFramework({
|
|
222
|
+
appName,
|
|
223
|
+
cwd,
|
|
224
|
+
originalScripts
|
|
225
|
+
}) {
|
|
226
|
+
p2.log.step("bedrock.config.ts \uD30C\uC77C\uC744 \uC0DD\uC131\uD558\uB294 \uC911...");
|
|
227
|
+
const webPort = await p2.text({
|
|
228
|
+
message: "Enter web port",
|
|
229
|
+
placeholder: "5173",
|
|
230
|
+
defaultValue: "5173"
|
|
231
|
+
});
|
|
232
|
+
if (p2.isCancel(webPort)) {
|
|
233
|
+
p2.cancel("\uCD08\uAE30\uD654\uAC00 \uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4");
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const config = transformTemplate(WEB_FRAMEWORK_CONFIG_TEMPLATE, {
|
|
237
|
+
appName,
|
|
238
|
+
webPort,
|
|
239
|
+
webDevCommand: originalScripts.dev === "ait dev" ? "" : originalScripts.dev,
|
|
240
|
+
webBuildCommand: originalScripts.build === "ait build" ? "" : originalScripts.build
|
|
241
|
+
});
|
|
242
|
+
await fs4.promises.writeFile(path3.join(cwd, "bedrock.config.ts"), config, {
|
|
243
|
+
encoding: "utf-8"
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
var InitCommand = class extends Command2 {
|
|
247
|
+
static paths = [[`init`]];
|
|
248
|
+
async execute() {
|
|
249
|
+
const template = await p2.select({
|
|
250
|
+
message: "\uD504\uB85C\uC81D\uD2B8\uB97C \uCD08\uAE30\uD654\uD560 \uD15C\uD50C\uB9BF\uC744 \uC120\uD0DD\uD574\uC8FC\uC138\uC694.",
|
|
251
|
+
options: [
|
|
252
|
+
{
|
|
253
|
+
value: "web-framework",
|
|
254
|
+
label: "\uC6F9 \uD504\uB808\uC784\uC6CC\uD06C",
|
|
255
|
+
hint: "\uC6F9 \uD504\uB85C\uC81D\uD2B8\uC5D0 \uC571\uC778\uD1A0\uC2A4 \uC6F9\uBDF0 \uAC1C\uBC1C\uD658\uACBD\uC744 \uC138\uD305\uD569\uB2C8\uB2E4."
|
|
256
|
+
}
|
|
257
|
+
]
|
|
258
|
+
});
|
|
259
|
+
if (p2.isCancel(template)) {
|
|
260
|
+
process.exit(0);
|
|
261
|
+
}
|
|
262
|
+
const cwd = getPackageRoot();
|
|
263
|
+
p2.intro("\u{1F680} \uC571 \uCD08\uAE30\uD654\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4");
|
|
264
|
+
const appName = await p2.text({
|
|
265
|
+
message: "Enter app name",
|
|
266
|
+
validate: (value) => {
|
|
267
|
+
if (!value) {
|
|
268
|
+
return "\uC571 \uC774\uB984\uC744 \uC785\uB825\uD574\uC8FC\uC138\uC694";
|
|
269
|
+
}
|
|
270
|
+
const kebabCaseValue = kebabCase(value);
|
|
271
|
+
if (value !== kebabCaseValue) {
|
|
272
|
+
return `\uC571 \uC774\uB984\uC740 \uCF00\uBC25-\uCF00\uC774\uC2A4 \uD615\uC2DD\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4 (\uC608\uC2DC: ${kebabCaseValue})`;
|
|
273
|
+
}
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
if (p2.isCancel(appName)) {
|
|
278
|
+
p2.cancel("\uCD08\uAE30\uD654\uAC00 \uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4");
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
p2.log.step(`\uC571 \uC774\uB984\uC774 '${appName}'\uC73C\uB85C \uC124\uC815\uB418\uC5C8\uC2B5\uB2C8\uB2E4`);
|
|
282
|
+
p2.log.step("package.json \uC2A4\uD06C\uB9BD\uD2B8\uB97C \uC124\uC815\uD558\uB294 \uC911...");
|
|
283
|
+
const packageJson = await fs4.promises.readFile(path3.join(cwd, "package.json"), {
|
|
284
|
+
encoding: "utf-8"
|
|
285
|
+
});
|
|
286
|
+
const scripts = JSON.parse(packageJson);
|
|
287
|
+
const originalScripts = {
|
|
288
|
+
dev: scripts?.scripts?.dev || scripts?.scripts?.start,
|
|
289
|
+
build: scripts?.scripts?.build
|
|
290
|
+
};
|
|
291
|
+
scripts.scripts.dev = "bedrock dev";
|
|
292
|
+
scripts.scripts.build = "bedrock build";
|
|
293
|
+
scripts.scripts.deploy = "ait deploy";
|
|
294
|
+
await fs4.promises.writeFile(path3.join(cwd, "package.json"), JSON.stringify(scripts, null, 2), {
|
|
295
|
+
encoding: "utf-8"
|
|
296
|
+
});
|
|
297
|
+
p2.log.step(".gitignore \uD30C\uC77C\uC744 \uC5C5\uB370\uC774\uD2B8\uD558\uB294 \uC911...");
|
|
298
|
+
await fs4.promises.appendFile(path3.join(cwd, ".gitignore"), "\n.bedrock\n");
|
|
299
|
+
switch (template) {
|
|
300
|
+
case "web-framework": {
|
|
301
|
+
await templateWebFramework({
|
|
302
|
+
appName,
|
|
303
|
+
cwd,
|
|
304
|
+
originalScripts
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
const pnpRoot = await getPnpRoot();
|
|
309
|
+
if (pnpRoot) {
|
|
310
|
+
const yarnrcPath = path3.join(pnpRoot, ".yarnrc.yml");
|
|
311
|
+
let yarnrc = {};
|
|
312
|
+
try {
|
|
313
|
+
const yarnrcContent = await fs4.promises.readFile(yarnrcPath, { encoding: "utf-8" });
|
|
314
|
+
yarnrc = yaml.parse(yarnrcContent);
|
|
315
|
+
} catch {
|
|
316
|
+
p2.log.info(".yarnrc.yml \uD30C\uC77C\uC774 \uC5C6\uC5B4 \uC0C8\uB85C \uC0DD\uC131\uD569\uB2C8\uB2E4.");
|
|
317
|
+
}
|
|
318
|
+
p2.log.step(".yarnrc.yml \uD30C\uC77C\uC744 \uC5C5\uB370\uC774\uD2B8\uD558\uB294 \uC911...");
|
|
319
|
+
yarnrc = merge(yarnrc, {
|
|
320
|
+
packageExtensions: {
|
|
321
|
+
"@react-native-community/cli-debugger-ui@*": {
|
|
322
|
+
dependencies: {
|
|
323
|
+
"@babel/runtime": "^7"
|
|
324
|
+
}
|
|
325
|
+
},
|
|
326
|
+
"react-native-video@*": {
|
|
327
|
+
peerDependencies: {
|
|
328
|
+
react: "*",
|
|
329
|
+
"react-native": "*"
|
|
330
|
+
}
|
|
331
|
+
},
|
|
332
|
+
"react-native-fast-image@*": {
|
|
333
|
+
dependencies: {
|
|
334
|
+
"@babel/runtime": "^7"
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
await fs4.promises.writeFile(yarnrcPath, yaml.stringify(yarnrc), { encoding: "utf-8" });
|
|
340
|
+
await execa("yarn", ["install"], {
|
|
341
|
+
cwd,
|
|
342
|
+
stdio: "inherit"
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
p2.outro("\u2728 \uCD08\uAE30\uD654\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4!");
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
// src/index.ts
|
|
350
|
+
function initialize() {
|
|
351
|
+
const cli = new Cli({
|
|
352
|
+
binaryLabel: "ait",
|
|
353
|
+
binaryName: "ait"
|
|
354
|
+
});
|
|
355
|
+
cli.register(DeployCommand);
|
|
356
|
+
cli.register(InitCommand);
|
|
357
|
+
cli.runExit(process.argv.slice(2));
|
|
358
|
+
}
|
|
359
|
+
export {
|
|
360
|
+
initialize
|
|
361
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@apps-in-toss/cli",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.0.0-dev.1740737494440",
|
|
5
|
+
"description": "CLI for Apps In Toss",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"prepack": "yarn build",
|
|
8
|
+
"typecheck": "tsc --noEmit",
|
|
9
|
+
"lint": "eslint .",
|
|
10
|
+
"build": "tsup"
|
|
11
|
+
},
|
|
12
|
+
"main": "./dist/index.cjs",
|
|
13
|
+
"module": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"require": "./dist/index.cjs",
|
|
19
|
+
"import": "./dist/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"bin.js"
|
|
25
|
+
],
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/debug": "^4",
|
|
28
|
+
"@types/node": "^22.10.2",
|
|
29
|
+
"@types/yauzl": "^2.10.3",
|
|
30
|
+
"eslint": "^9.7.0",
|
|
31
|
+
"tsup": "^8.3.5",
|
|
32
|
+
"typescript": "4.9.5",
|
|
33
|
+
"vitest": "^3.0.5"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@clack/prompts": "^0.10.0",
|
|
37
|
+
"clipanion": "^4.0.0-rc.4",
|
|
38
|
+
"debug": "^4.4.0",
|
|
39
|
+
"es-toolkit": "^1.32.0",
|
|
40
|
+
"execa": "^9.5.2",
|
|
41
|
+
"picocolors": "^1.1.1",
|
|
42
|
+
"yaml": "^2.7.0",
|
|
43
|
+
"yauzl": "^3.2.0"
|
|
44
|
+
},
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
},
|
|
48
|
+
"gitHead": "347b3082077a706fb9665295e27316e64573e93c"
|
|
49
|
+
}
|