@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 ADDED
@@ -0,0 +1 @@
1
+ # @apps-in-toss/cli
package/bin.js ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { initialize } from './dist/index.js';
3
+
4
+ initialize();
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
+ });
@@ -0,0 +1,3 @@
1
+ declare function initialize(): void;
2
+
3
+ export { initialize };
@@ -0,0 +1,3 @@
1
+ declare function initialize(): void;
2
+
3
+ export { initialize };
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
+ }