sayren 0.5.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.mjs +146 -8
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { spawn, spawnSync } from "node:child_process";
|
|
3
3
|
import { stdin, stdout } from "node:process";
|
|
4
4
|
import { createInterface } from "node:readline/promises";
|
|
5
|
-
import { APP_DEPLOY_KEY_PATTERN, APP_SECRET_PATTERNS, APP_SERVER_BUNDLE_MAX_GZIP_BYTES, APP_UI_MAX_BYTES, APP_UI_MAX_FILES, ApiError, ApprovalPendingError, STOREFRONT_BUILD_TERMINAL_STATUSES, STOREFRONT_SOURCE_BLOB_BATCH_MAX, appManifestProblems, appManifestSchema, createStoreClient, normalizeStorefrontPath } from "@sayren/store-sdk";
|
|
5
|
+
import { APP_DEPLOY_KEY_PATTERN, APP_README_MAX_BYTES, APP_SECRET_PATTERNS, APP_SERVER_BUNDLE_MAX_GZIP_BYTES, APP_UI_MAX_BYTES, APP_UI_MAX_FILES, ApiError, ApprovalPendingError, STOREFRONT_BUILD_TERMINAL_STATUSES, STOREFRONT_SOURCE_BLOB_BATCH_MAX, appIconProblem, appManifestProblems, appManifestSchema, createStoreClient, normalizeStorefrontPath } from "@sayren/store-sdk";
|
|
6
6
|
import { chmodSync, closeSync, existsSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
7
7
|
import { createServer } from "node:http";
|
|
8
8
|
import { dirname, extname, join, relative, resolve, sep } from "node:path";
|
|
@@ -1067,6 +1067,42 @@ const cli_app_handler_unlisted = ((inputs, options = {}) => {
|
|
|
1067
1067
|
return ko_cli_app_handler_unlisted(inputs);
|
|
1068
1068
|
});
|
|
1069
1069
|
|
|
1070
|
+
//#endregion
|
|
1071
|
+
//#region ../i18n/src/paraglide/messages/cli_app_icon_invalid.js
|
|
1072
|
+
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
1073
|
+
/** @typedef {{ path: NonNullable<unknown>, problem: NonNullable<unknown> }} Cli_App_Icon_InvalidInputs */
|
|
1074
|
+
const ko_cli_app_icon_invalid = (i) => {
|
|
1075
|
+
return `아이콘을 쓸 수 없습니다(${i?.path}): ${i?.problem}`;
|
|
1076
|
+
};
|
|
1077
|
+
/**
|
|
1078
|
+
|
|
1079
|
+
* @param {Cli_App_Icon_InvalidInputs} inputs
|
|
1080
|
+
* @param {{ locale?: "ko" }} options
|
|
1081
|
+
* @returns {LocalizedString}
|
|
1082
|
+
*/
|
|
1083
|
+
const cli_app_icon_invalid = ((inputs, options = {}) => {
|
|
1084
|
+
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
1085
|
+
return ko_cli_app_icon_invalid(inputs);
|
|
1086
|
+
});
|
|
1087
|
+
|
|
1088
|
+
//#endregion
|
|
1089
|
+
//#region ../i18n/src/paraglide/messages/cli_app_icon_missing.js
|
|
1090
|
+
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
1091
|
+
/** @typedef {{ path: NonNullable<unknown> }} Cli_App_Icon_MissingInputs */
|
|
1092
|
+
const ko_cli_app_icon_missing = (i) => {
|
|
1093
|
+
return `매니페스트 icon의 파일이 없습니다: ${i?.path}`;
|
|
1094
|
+
};
|
|
1095
|
+
/**
|
|
1096
|
+
|
|
1097
|
+
* @param {Cli_App_Icon_MissingInputs} inputs
|
|
1098
|
+
* @param {{ locale?: "ko" }} options
|
|
1099
|
+
* @returns {LocalizedString}
|
|
1100
|
+
*/
|
|
1101
|
+
const cli_app_icon_missing = ((inputs, options = {}) => {
|
|
1102
|
+
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
1103
|
+
return ko_cli_app_icon_missing(inputs);
|
|
1104
|
+
});
|
|
1105
|
+
|
|
1070
1106
|
//#endregion
|
|
1071
1107
|
//#region ../i18n/src/paraglide/messages/cli_app_init_done.js
|
|
1072
1108
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
@@ -1108,6 +1144,24 @@ const cli_app_key_invalid = ((inputs = {}, options = {}) => {
|
|
|
1108
1144
|
return ko_cli_app_key_invalid(inputs);
|
|
1109
1145
|
});
|
|
1110
1146
|
|
|
1147
|
+
//#endregion
|
|
1148
|
+
//#region ../i18n/src/paraglide/messages/cli_app_listing_none.js
|
|
1149
|
+
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
1150
|
+
/** @typedef {{}} Cli_App_Listing_NoneInputs */
|
|
1151
|
+
const ko_cli_app_listing_none = () => {
|
|
1152
|
+
return `없음`;
|
|
1153
|
+
};
|
|
1154
|
+
/**
|
|
1155
|
+
|
|
1156
|
+
* @param {Cli_App_Listing_NoneInputs} inputs
|
|
1157
|
+
* @param {{ locale?: "ko" }} options
|
|
1158
|
+
* @returns {LocalizedString}
|
|
1159
|
+
*/
|
|
1160
|
+
const cli_app_listing_none = ((inputs = {}, options = {}) => {
|
|
1161
|
+
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
1162
|
+
return ko_cli_app_listing_none(inputs);
|
|
1163
|
+
});
|
|
1164
|
+
|
|
1111
1165
|
//#endregion
|
|
1112
1166
|
//#region ../i18n/src/paraglide/messages/cli_app_logs_empty.js
|
|
1113
1167
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
@@ -1199,6 +1253,42 @@ const cli_app_port_invalid = ((inputs, options = {}) => {
|
|
|
1199
1253
|
return ko_cli_app_port_invalid(inputs);
|
|
1200
1254
|
});
|
|
1201
1255
|
|
|
1256
|
+
//#endregion
|
|
1257
|
+
//#region ../i18n/src/paraglide/messages/cli_app_readme_missing.js
|
|
1258
|
+
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
1259
|
+
/** @typedef {{ path: NonNullable<unknown> }} Cli_App_Readme_MissingInputs */
|
|
1260
|
+
const ko_cli_app_readme_missing = (i) => {
|
|
1261
|
+
return `매니페스트 readme의 파일이 없습니다: ${i?.path}`;
|
|
1262
|
+
};
|
|
1263
|
+
/**
|
|
1264
|
+
|
|
1265
|
+
* @param {Cli_App_Readme_MissingInputs} inputs
|
|
1266
|
+
* @param {{ locale?: "ko" }} options
|
|
1267
|
+
* @returns {LocalizedString}
|
|
1268
|
+
*/
|
|
1269
|
+
const cli_app_readme_missing = ((inputs, options = {}) => {
|
|
1270
|
+
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
1271
|
+
return ko_cli_app_readme_missing(inputs);
|
|
1272
|
+
});
|
|
1273
|
+
|
|
1274
|
+
//#endregion
|
|
1275
|
+
//#region ../i18n/src/paraglide/messages/cli_app_readme_too_large.js
|
|
1276
|
+
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
1277
|
+
/** @typedef {{ limit: NonNullable<unknown>, path: NonNullable<unknown> }} Cli_App_Readme_Too_LargeInputs */
|
|
1278
|
+
const ko_cli_app_readme_too_large = (i) => {
|
|
1279
|
+
return `README가 ${i?.limit}KB를 넘습니다: ${i?.path}`;
|
|
1280
|
+
};
|
|
1281
|
+
/**
|
|
1282
|
+
|
|
1283
|
+
* @param {Cli_App_Readme_Too_LargeInputs} inputs
|
|
1284
|
+
* @param {{ locale?: "ko" }} options
|
|
1285
|
+
* @returns {LocalizedString}
|
|
1286
|
+
*/
|
|
1287
|
+
const cli_app_readme_too_large = ((inputs, options = {}) => {
|
|
1288
|
+
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
1289
|
+
return ko_cli_app_readme_too_large(inputs);
|
|
1290
|
+
});
|
|
1291
|
+
|
|
1202
1292
|
//#endregion
|
|
1203
1293
|
//#region ../i18n/src/paraglide/messages/cli_app_release_done.js
|
|
1204
1294
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
@@ -1512,9 +1602,9 @@ const cli_app_uploading = ((inputs, options = {}) => {
|
|
|
1512
1602
|
//#endregion
|
|
1513
1603
|
//#region ../i18n/src/paraglide/messages/cli_app_verify_ok.js
|
|
1514
1604
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
1515
|
-
/** @typedef {{ events: NonNullable<unknown>, http: NonNullable<unknown>, size: NonNullable<unknown>, ui: NonNullable<unknown> }} Cli_App_Verify_OkInputs */
|
|
1605
|
+
/** @typedef {{ events: NonNullable<unknown>, http: NonNullable<unknown>, size: NonNullable<unknown>, ui: NonNullable<unknown>, icon: NonNullable<unknown>, readme: NonNullable<unknown> }} Cli_App_Verify_OkInputs */
|
|
1516
1606
|
const ko_cli_app_verify_ok = (i) => {
|
|
1517
|
-
return `검사 통과 — 이벤트 ${i?.events} · HTTP ${i?.http} · 서버 번들 ${i?.size}(gzip) · 화면 파일 ${i?.ui}
|
|
1607
|
+
return `검사 통과 — 이벤트 ${i?.events} · HTTP ${i?.http} · 서버 번들 ${i?.size}(gzip) · 화면 파일 ${i?.ui}개 · 아이콘 ${i?.icon} · README ${i?.readme}`;
|
|
1518
1608
|
};
|
|
1519
1609
|
/**
|
|
1520
1610
|
|
|
@@ -9087,7 +9177,7 @@ async function selectStore(auth, client, io, candidates, folderStore = null) {
|
|
|
9087
9177
|
|
|
9088
9178
|
//#endregion
|
|
9089
9179
|
//#region package.json
|
|
9090
|
-
var version = "0.
|
|
9180
|
+
var version = "0.6.1";
|
|
9091
9181
|
|
|
9092
9182
|
//#endregion
|
|
9093
9183
|
//#region src/client.ts
|
|
@@ -9305,6 +9395,42 @@ async function loadBundle(dir, server) {
|
|
|
9305
9395
|
}
|
|
9306
9396
|
};
|
|
9307
9397
|
}
|
|
9398
|
+
function collectListing(dir, manifest) {
|
|
9399
|
+
let icon = null;
|
|
9400
|
+
if (manifest.icon) {
|
|
9401
|
+
const file = join(dir, manifest.icon);
|
|
9402
|
+
if (!existsSync(file)) throw new CliError(cli_app_icon_missing({ path: manifest.icon }));
|
|
9403
|
+
const bytes = readFileSync(file);
|
|
9404
|
+
const contentType = /\.svg$/i.test(manifest.icon) ? "image/svg+xml" : "image/png";
|
|
9405
|
+
const problem = appIconProblem(bytes, contentType);
|
|
9406
|
+
if (problem) throw new CliError(cli_app_icon_invalid({
|
|
9407
|
+
path: manifest.icon,
|
|
9408
|
+
problem
|
|
9409
|
+
}));
|
|
9410
|
+
icon = {
|
|
9411
|
+
path: manifest.icon,
|
|
9412
|
+
contentType,
|
|
9413
|
+
bytes
|
|
9414
|
+
};
|
|
9415
|
+
}
|
|
9416
|
+
const readmePath = manifest.readme ?? "README.md";
|
|
9417
|
+
let readme = null;
|
|
9418
|
+
if (existsSync(join(dir, readmePath))) {
|
|
9419
|
+
const text = readFileSync(join(dir, readmePath), "utf8");
|
|
9420
|
+
if (Buffer.byteLength(text, "utf8") > APP_README_MAX_BYTES) throw new CliError(cli_app_readme_too_large({
|
|
9421
|
+
path: readmePath,
|
|
9422
|
+
limit: String(APP_README_MAX_BYTES / 1024)
|
|
9423
|
+
}));
|
|
9424
|
+
readme = {
|
|
9425
|
+
path: readmePath,
|
|
9426
|
+
text
|
|
9427
|
+
};
|
|
9428
|
+
} else if (manifest.readme) throw new CliError(cli_app_readme_missing({ path: manifest.readme }));
|
|
9429
|
+
return {
|
|
9430
|
+
icon,
|
|
9431
|
+
readme
|
|
9432
|
+
};
|
|
9433
|
+
}
|
|
9308
9434
|
/** 로컬 검사 — 매니페스트, 번들, 이벤트 함수 존재, 비밀 값 형식, 크기. 서버 `VERIFY`·`BUNDLE`과 같은 규칙 */
|
|
9309
9435
|
async function verifyApp(dir) {
|
|
9310
9436
|
const { raw, manifest } = loadManifest(dir);
|
|
@@ -9321,6 +9447,7 @@ async function verifyApp(dir) {
|
|
|
9321
9447
|
if (extra.length) warnings.push(cli_app_handler_unlisted({ events: extra.join(", ") }));
|
|
9322
9448
|
const ui = manifest.ui?.adminPage ? collectUi(dir) : [];
|
|
9323
9449
|
if (manifest.ui?.adminPage && !ui.some((file) => file.path === "index.html")) throw new CliError(cli_app_ui_index_missing({ dir: UI_DIR }));
|
|
9450
|
+
const listing = collectListing(dir, manifest);
|
|
9324
9451
|
return {
|
|
9325
9452
|
manifest,
|
|
9326
9453
|
raw,
|
|
@@ -9331,6 +9458,7 @@ async function verifyApp(dir) {
|
|
|
9331
9458
|
},
|
|
9332
9459
|
app,
|
|
9333
9460
|
ui,
|
|
9461
|
+
listing,
|
|
9334
9462
|
warnings
|
|
9335
9463
|
};
|
|
9336
9464
|
}
|
|
@@ -9408,14 +9536,15 @@ function initFiles(handle, name) {
|
|
|
9408
9536
|
export default defineApp({
|
|
9409
9537
|
events: {
|
|
9410
9538
|
"ORDER.PAID": async (event, ctx) => {
|
|
9411
|
-
|
|
9412
|
-
const order = await ctx.api.orders.get(orderId);
|
|
9413
|
-
ctx.log.info("결제된 주문", order.orderNo, order.totalAmount);
|
|
9539
|
+
// event.data는 ORDER.PAID의 모양으로 좁혀진다 — 캐스팅하지 않는다
|
|
9540
|
+
const order = await ctx.api.orders.get(event.data.orderId);
|
|
9541
|
+
ctx.log.info("결제된 주문", order.orderNo, order.payment.totalAmount);
|
|
9414
9542
|
},
|
|
9415
9543
|
},
|
|
9416
9544
|
});
|
|
9417
9545
|
`,
|
|
9418
9546
|
".gitignore": "node_modules/\ndist/\n.env\n.sayren/\n",
|
|
9547
|
+
"README.md": `# ${name}\n\n이 앱이 하는 일을 한두 문장으로 씁니다.\n\n## 설정\n\n설치한 뒤 채울 설정을 설명합니다.\n`,
|
|
9419
9548
|
".env.example": `# 로컬 실행(sayren app dev)의 설정·비밀 값\n# ${SETTING_ENV_PREFIX}<설정 키>=값\n# ${SECRET_ENV_PREFIX}<비밀 값 이름>=값\n`
|
|
9420
9549
|
};
|
|
9421
9550
|
}
|
|
@@ -9454,7 +9583,9 @@ async function appVerify(flags, io) {
|
|
|
9454
9583
|
events: outcome.bundle.meta.events.join(", ") || "-",
|
|
9455
9584
|
http: outcome.bundle.meta.http.join(", ") || "-",
|
|
9456
9585
|
size: formatMb(outcome.bundle.gzipBytes),
|
|
9457
|
-
ui: String(outcome.ui.length)
|
|
9586
|
+
ui: String(outcome.ui.length),
|
|
9587
|
+
icon: outcome.listing.icon?.path ?? cli_app_listing_none(),
|
|
9588
|
+
readme: outcome.listing.readme?.path ?? cli_app_listing_none()
|
|
9458
9589
|
}));
|
|
9459
9590
|
return 0;
|
|
9460
9591
|
}
|
|
@@ -9486,6 +9617,13 @@ async function appDeploy(flags, io) {
|
|
|
9486
9617
|
path: file.path,
|
|
9487
9618
|
content: file.bytes.toString("base64")
|
|
9488
9619
|
})),
|
|
9620
|
+
listing: {
|
|
9621
|
+
icon: outcome.listing.icon ? {
|
|
9622
|
+
contentType: outcome.listing.icon.contentType,
|
|
9623
|
+
content: outcome.listing.icon.bytes.toString("base64")
|
|
9624
|
+
} : null,
|
|
9625
|
+
readme: outcome.listing.readme?.text ?? null
|
|
9626
|
+
},
|
|
9489
9627
|
...flags.message ? { message: flags.message } : {}
|
|
9490
9628
|
});
|
|
9491
9629
|
printBuild(version$1, io);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sayren",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "sayren CLI — 호스팅 스토어프론트(init·pull·deploy)와 서드파티 앱(app init·dev·deploy·release)",
|
|
6
6
|
"bin": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"esbuild": "^0.28.2",
|
|
17
|
-
"@sayren/store-sdk": "^0.30.
|
|
17
|
+
"@sayren/store-sdk": "^0.30.11"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@biomejs/biome": "^2.5.14",
|