sayren 0.7.0 → 0.8.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 +168 -19
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -965,7 +965,7 @@ const cli_app_dev_store_name_required = ((inputs = {}, options = {}) => {
|
|
|
965
965
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
966
966
|
/** @typedef {{ dir: NonNullable<unknown> }} Cli_App_Dir_ExistsInputs */
|
|
967
967
|
const ko_cli_app_dir_exists = (i) => {
|
|
968
|
-
return `${i?.dir}에 이미
|
|
968
|
+
return `${i?.dir}에 이미 매니페스트(manifest.json)가 있습니다`;
|
|
969
969
|
};
|
|
970
970
|
/**
|
|
971
971
|
|
|
@@ -1037,7 +1037,7 @@ const cli_app_handle_mismatch = ((inputs, options = {}) => {
|
|
|
1037
1037
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
1038
1038
|
/** @typedef {{ events: NonNullable<unknown> }} Cli_App_Handler_MissingInputs */
|
|
1039
1039
|
const ko_cli_app_handler_missing = (i) => {
|
|
1040
|
-
return `매니페스트(events·schedules·http.public)에 있지만 코드에 함수가 없습니다: ${i?.events} (HANDLER_MISSING)`;
|
|
1040
|
+
return `매니페스트(events·schedules·http.public·flow.notifications·mcp.tools)에 있지만 코드에 함수가 없습니다: ${i?.events} (HANDLER_MISSING)`;
|
|
1041
1041
|
};
|
|
1042
1042
|
/**
|
|
1043
1043
|
|
|
@@ -1200,6 +1200,24 @@ const cli_app_manifest_invalid = ((inputs, options = {}) => {
|
|
|
1200
1200
|
return ko_cli_app_manifest_invalid(inputs);
|
|
1201
1201
|
});
|
|
1202
1202
|
|
|
1203
|
+
//#endregion
|
|
1204
|
+
//#region ../i18n/src/paraglide/messages/cli_app_manifest_legacy.js
|
|
1205
|
+
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
1206
|
+
/** @typedef {{}} Cli_App_Manifest_LegacyInputs */
|
|
1207
|
+
const ko_cli_app_manifest_legacy = () => {
|
|
1208
|
+
return `sayren.app.json은 옛 매니페스트 이름입니다. 파일 이름을 manifest.json으로 바꾸십시오`;
|
|
1209
|
+
};
|
|
1210
|
+
/**
|
|
1211
|
+
|
|
1212
|
+
* @param {Cli_App_Manifest_LegacyInputs} inputs
|
|
1213
|
+
* @param {{ locale?: "ko" }} options
|
|
1214
|
+
* @returns {LocalizedString}
|
|
1215
|
+
*/
|
|
1216
|
+
const cli_app_manifest_legacy = ((inputs = {}, options = {}) => {
|
|
1217
|
+
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
1218
|
+
return ko_cli_app_manifest_legacy(inputs);
|
|
1219
|
+
});
|
|
1220
|
+
|
|
1203
1221
|
//#endregion
|
|
1204
1222
|
//#region ../i18n/src/paraglide/messages/cli_app_manifest_missing.js
|
|
1205
1223
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
@@ -5257,6 +5275,8 @@ const ko_cli_usage = (i) => {
|
|
|
5257
5275
|
--data <json> app trigger: 이벤트 데이터
|
|
5258
5276
|
--order <orderId> app trigger: 주문 id를 데이터에 넣습니다
|
|
5259
5277
|
--schedule <이름> app trigger: 이벤트 대신 예약 작업을 실행합니다
|
|
5278
|
+
--flow <이름> app trigger: 이벤트 대신 흐름 알림을 보냅니다(--data는 알림 값)
|
|
5279
|
+
--tool <이름> app trigger: 이벤트 대신 에이전트 도구를 부릅니다(--data는 입력)
|
|
5260
5280
|
--lang <로케일> 메시지 언어(기본: SAYREN_LANG → 시스템 로케일 → ko)
|
|
5261
5281
|
|
|
5262
5282
|
종료 코드: 0 성공 · 1 실패 · 3 승인 대기(에이전트 토큰)`;
|
|
@@ -9180,7 +9200,7 @@ async function selectStore(auth, client, io, candidates, folderStore = null) {
|
|
|
9180
9200
|
|
|
9181
9201
|
//#endregion
|
|
9182
9202
|
//#region package.json
|
|
9183
|
-
var version = "0.
|
|
9203
|
+
var version = "0.8.1";
|
|
9184
9204
|
|
|
9185
9205
|
//#endregion
|
|
9186
9206
|
//#region src/client.ts
|
|
@@ -9222,14 +9242,16 @@ function detailsOf(error) {
|
|
|
9222
9242
|
//#endregion
|
|
9223
9243
|
//#region src/app-commands.ts
|
|
9224
9244
|
/**
|
|
9225
|
-
* `sayren app …`(이슈 #22, 매뉴얼 「앱 만들기」) — 앱 폴더(`
|
|
9245
|
+
* `sayren app …`(이슈 #22, 매뉴얼 「앱 만들기」) — 앱 폴더(`manifest.json`)에서 돈다. 서버는 코드를 빌드하지 않는다(A1):
|
|
9226
9246
|
* CLI가 esbuild로 서버 번들 한 파일을 만들어 올리고 api가 `DEPENDENCIES`·`VERIFY`·`BUNDLE`·`UPLOAD`를 돈다. 앱 화면(`ui/`)은
|
|
9227
9247
|
* 정적 파일 그대로 올린다.
|
|
9228
9248
|
*
|
|
9229
9249
|
* 인증은 둘이다. 앱 배포 키(`--key`·`SAYREN_APP_KEY`, developer.sayren.app에서 발행, `sak_…`)는 그 앱의 경로에만 쓰이고(CI 용도),
|
|
9230
9250
|
* 그 밖에는 `sayren login`의 계정 토큰이다. 앱 등록(`init`)·개발 상점은 계정 토큰만 된다.
|
|
9231
9251
|
*/
|
|
9232
|
-
const APP_MANIFEST_FILE = "
|
|
9252
|
+
const APP_MANIFEST_FILE = "manifest.json";
|
|
9253
|
+
/** 0.8.0까지의 매니페스트 이름 — `manifest.json`이 없을 때만 읽고 경고한다 */
|
|
9254
|
+
const LEGACY_APP_MANIFEST_FILE = "sayren.app.json";
|
|
9233
9255
|
const APP_STATE_FILE = `${STATE_DIR}/app.json`;
|
|
9234
9256
|
const APP_DEV_PORT = 4020;
|
|
9235
9257
|
const SERVER_ENTRY_CANDIDATES = [
|
|
@@ -9259,10 +9281,17 @@ function writeAppState(dir, state) {
|
|
|
9259
9281
|
mkdirSync(join(dir, STATE_DIR), { recursive: true });
|
|
9260
9282
|
writeFileSync(join(dir, APP_STATE_FILE), `${JSON.stringify(state, null, 2)}\n`, { mode: 384 });
|
|
9261
9283
|
}
|
|
9262
|
-
/**
|
|
9284
|
+
/** 앱 폴더의 매니페스트 파일 — `manifest.json`, 없으면 옛 이름 `sayren.app.json`. 둘 다 없으면 null */
|
|
9285
|
+
function manifestFileOf(dir) {
|
|
9286
|
+
if (existsSync(join(dir, APP_MANIFEST_FILE))) return APP_MANIFEST_FILE;
|
|
9287
|
+
if (existsSync(join(dir, LEGACY_APP_MANIFEST_FILE))) return LEGACY_APP_MANIFEST_FILE;
|
|
9288
|
+
return null;
|
|
9289
|
+
}
|
|
9290
|
+
/** 매니페스트 원문(JSON)과 검증 결과 — 문제가 있으면 CliError. 옛 이름으로 읽었으면 `warnings`에 이름 변경 안내가 든다 */
|
|
9263
9291
|
function loadManifest(dir) {
|
|
9264
|
-
const
|
|
9265
|
-
if (!
|
|
9292
|
+
const file = manifestFileOf(dir);
|
|
9293
|
+
if (!file) throw new CliError(cli_app_manifest_missing({ file: APP_MANIFEST_FILE }));
|
|
9294
|
+
const path = join(dir, file);
|
|
9266
9295
|
let raw;
|
|
9267
9296
|
try {
|
|
9268
9297
|
raw = JSON.parse(readFileSync(path, "utf8"));
|
|
@@ -9273,9 +9302,11 @@ function loadManifest(dir) {
|
|
|
9273
9302
|
if (!parsed.success) throw new CliError(cli_app_manifest_invalid({ problems: parsed.error.issues.map((issue) => `- ${issue.path.join(".") || "(root)"}: ${issue.message}`).join("\n") }));
|
|
9274
9303
|
const problems = appManifestProblems(parsed.data);
|
|
9275
9304
|
if (problems.length) throw new CliError(cli_app_manifest_invalid({ problems: problems.map((p) => `- ${p.path}: ${p.message} (${p.code})`).join("\n") }));
|
|
9305
|
+
const warnings = file === LEGACY_APP_MANIFEST_FILE ? [cli_app_manifest_legacy()] : [];
|
|
9276
9306
|
return {
|
|
9277
9307
|
raw,
|
|
9278
|
-
manifest: parsed.data
|
|
9308
|
+
manifest: parsed.data,
|
|
9309
|
+
warnings
|
|
9279
9310
|
};
|
|
9280
9311
|
}
|
|
9281
9312
|
function appDir(flags, io) {
|
|
@@ -9283,7 +9314,7 @@ function appDir(flags, io) {
|
|
|
9283
9314
|
}
|
|
9284
9315
|
function requireState(dir) {
|
|
9285
9316
|
const state = readAppState(dir);
|
|
9286
|
-
if (!state) throw new CliError(cli_app_not_registered({ file: APP_MANIFEST_FILE }));
|
|
9317
|
+
if (!state) throw new CliError(cli_app_not_registered({ file: manifestFileOf(dir) ?? APP_MANIFEST_FILE }));
|
|
9287
9318
|
return state;
|
|
9288
9319
|
}
|
|
9289
9320
|
/** 배포 키(`--key` → `SAYREN_APP_KEY`)가 있으면 그것, 없으면 계정 토큰(`resolveAuth`) */
|
|
@@ -9395,7 +9426,9 @@ async function loadBundle(dir, server) {
|
|
|
9395
9426
|
meta: {
|
|
9396
9427
|
events: [...meta.events],
|
|
9397
9428
|
http: [...meta.http],
|
|
9398
|
-
schedules: [...meta.schedules ?? []]
|
|
9429
|
+
schedules: [...meta.schedules ?? []],
|
|
9430
|
+
flows: [...meta.flows ?? []],
|
|
9431
|
+
tools: [...meta.tools ?? []]
|
|
9399
9432
|
}
|
|
9400
9433
|
};
|
|
9401
9434
|
}
|
|
@@ -9436,21 +9469,40 @@ function collectListing(dir, manifest) {
|
|
|
9436
9469
|
};
|
|
9437
9470
|
}
|
|
9438
9471
|
/** 로컬 검사 — 매니페스트, 번들, 이벤트 함수 존재, 비밀 값 형식, 크기. 서버 `VERIFY`·`BUNDLE`과 같은 규칙 */
|
|
9472
|
+
/**
|
|
9473
|
+
* 외부 런타임 앱(매뉴얼 「개발자 서버에서 실행」)이 올리는 서버 자리 — 코드는 개발자 서버에 있어 sayren 실행 환경에는 이것만 둔다(호출되지 않는다)
|
|
9474
|
+
*/
|
|
9475
|
+
const EXTERNAL_STUB_SERVER = "export default { fetch() { return new Response(\"external runtime\", { status: 404 }); } };\n";
|
|
9476
|
+
const EMPTY_META = {
|
|
9477
|
+
events: [],
|
|
9478
|
+
http: [],
|
|
9479
|
+
schedules: [],
|
|
9480
|
+
flows: [],
|
|
9481
|
+
tools: []
|
|
9482
|
+
};
|
|
9439
9483
|
async function verifyApp(dir) {
|
|
9440
|
-
const { raw, manifest } = loadManifest(dir);
|
|
9441
|
-
const
|
|
9484
|
+
const { raw, manifest, warnings } = loadManifest(dir);
|
|
9485
|
+
const external = manifest.runtime === "external";
|
|
9486
|
+
const server = external ? EXTERNAL_STUB_SERVER : await bundleServer(dir);
|
|
9442
9487
|
if (APP_SECRET_PATTERNS.find((pattern) => pattern.test(server))) throw new CliError(cli_app_secret_in_source());
|
|
9443
9488
|
const gzipBytes = gzipSync(server).byteLength;
|
|
9444
9489
|
if (gzipBytes > APP_SERVER_BUNDLE_MAX_GZIP_BYTES) throw new CliError(cli_app_bundle_too_large({ size: formatMb(gzipBytes) }));
|
|
9445
|
-
const { app, meta } =
|
|
9490
|
+
const { app, meta } = external ? {
|
|
9491
|
+
app: {
|
|
9492
|
+
fetch: async () => new Response("external runtime", { status: 404 }),
|
|
9493
|
+
__sayrenApp: EMPTY_META
|
|
9494
|
+
},
|
|
9495
|
+
meta: { ...EMPTY_META }
|
|
9496
|
+
} : await loadBundle(dir, server);
|
|
9446
9497
|
const httpKeys = new Set(meta.http.map((key) => key.trim().replace(/\s+/g, " ")));
|
|
9447
|
-
const missing = [
|
|
9498
|
+
const missing = external ? [] : [
|
|
9448
9499
|
...manifest.events.filter((event) => !meta.events.includes(event)),
|
|
9449
9500
|
...Object.keys(manifest.schedules).filter((name) => !meta.schedules.includes(name)),
|
|
9501
|
+
...Object.keys(manifest.flow?.notifications ?? {}).filter((name) => !meta.flows.includes(name)),
|
|
9502
|
+
...Object.keys(manifest.mcp?.tools ?? {}).filter((name) => !meta.tools.includes(name)),
|
|
9450
9503
|
...(manifest.http?.public ?? []).filter((key) => !httpKeys.has(key))
|
|
9451
9504
|
];
|
|
9452
9505
|
if (missing.length) throw new CliError(cli_app_handler_missing({ events: missing.join(", ") }));
|
|
9453
|
-
const warnings = [];
|
|
9454
9506
|
const listed = manifest.events;
|
|
9455
9507
|
const extra = meta.events.filter((event) => !listed.includes(event));
|
|
9456
9508
|
if (extra.length) warnings.push(cli_app_handler_unlisted({ events: extra.join(", ") }));
|
|
@@ -9560,7 +9612,7 @@ export default defineApp({
|
|
|
9560
9612
|
async function appInit(handle, flags, io) {
|
|
9561
9613
|
if (!handle || !HANDLE_RE.test(handle)) throw new CliError(cli_app_handle_invalid());
|
|
9562
9614
|
const dir = resolve(io.cwd, flags.dir ?? handle);
|
|
9563
|
-
if (
|
|
9615
|
+
if (manifestFileOf(dir)) throw new CliError(cli_app_dir_exists({ dir: relative(io.cwd, dir) || "." }));
|
|
9564
9616
|
const name = flags.name?.trim() || handle;
|
|
9565
9617
|
const auth = await developerAuth(flags, dir, io, { accountOnly: true });
|
|
9566
9618
|
const privateStoreId = flags.privateStore?.trim();
|
|
@@ -9825,6 +9877,16 @@ function devEnvelope(input) {
|
|
|
9825
9877
|
role: "OWNER"
|
|
9826
9878
|
} } : {},
|
|
9827
9879
|
...input.schedule ? { schedule: input.schedule } : {},
|
|
9880
|
+
...input.tool ? { tool: input.tool } : {},
|
|
9881
|
+
...input.flow ? { flow: {
|
|
9882
|
+
orderId: "ord_dev",
|
|
9883
|
+
orderItemIds: ["oi_dev"],
|
|
9884
|
+
flowId: "flow_dev",
|
|
9885
|
+
flowVersion: 1,
|
|
9886
|
+
state: "dev",
|
|
9887
|
+
params: {},
|
|
9888
|
+
...input.flow
|
|
9889
|
+
} } : {},
|
|
9828
9890
|
...input.event ? { event: {
|
|
9829
9891
|
id: `evt_dev_${devSeq}`,
|
|
9830
9892
|
type: input.event.type,
|
|
@@ -9876,7 +9938,8 @@ function readBody(req) {
|
|
|
9876
9938
|
async function appDev(flags, io) {
|
|
9877
9939
|
const dir = appDir(flags, io);
|
|
9878
9940
|
const state = requireState(dir);
|
|
9879
|
-
const { manifest } = loadManifest(dir);
|
|
9941
|
+
const { manifest, warnings } = loadManifest(dir);
|
|
9942
|
+
for (const warning of warnings) io.err(cli_app_warning({ message: warning }));
|
|
9880
9943
|
const { app } = await loadBundle(dir, await bundleServer(dir));
|
|
9881
9944
|
const port = Number(flags.port ?? io.env.SAYREN_APP_PORT ?? APP_DEV_PORT);
|
|
9882
9945
|
if (!Number.isInteger(port) || port < 1 || port > 65535) throw new CliError(cli_app_port_invalid({ value: String(flags.port) }));
|
|
@@ -9900,6 +9963,47 @@ async function appDev(flags, io) {
|
|
|
9900
9963
|
try {
|
|
9901
9964
|
if (req.method === "POST" && url.pathname === "/_trigger") {
|
|
9902
9965
|
const body = JSON.parse(await readBody(req) || "{}");
|
|
9966
|
+
if (body.tool) {
|
|
9967
|
+
const { settings: settings$1, secrets: secrets$1 } = local();
|
|
9968
|
+
const result$1 = await invokeLocal(app, devEnvelope({
|
|
9969
|
+
kind: "tool",
|
|
9970
|
+
tool: {
|
|
9971
|
+
name: body.tool,
|
|
9972
|
+
input: body.data ?? {}
|
|
9973
|
+
},
|
|
9974
|
+
publicOrigin,
|
|
9975
|
+
token: await ensureToken(),
|
|
9976
|
+
apiBaseUrl,
|
|
9977
|
+
appId: state.appId,
|
|
9978
|
+
settings: settings$1,
|
|
9979
|
+
secrets: secrets$1
|
|
9980
|
+
}));
|
|
9981
|
+
printResult(`[tool] ${body.tool}`, result$1, io);
|
|
9982
|
+
if (result$1.response?.body) io.out(` → ${result$1.response.body}`);
|
|
9983
|
+
res.writeHead(200, { "content-type": "application/json" });
|
|
9984
|
+
res.end(JSON.stringify(result$1));
|
|
9985
|
+
return;
|
|
9986
|
+
}
|
|
9987
|
+
if (body.flow) {
|
|
9988
|
+
const { settings: settings$1, secrets: secrets$1 } = local();
|
|
9989
|
+
const result$1 = await invokeLocal(app, devEnvelope({
|
|
9990
|
+
kind: "flow",
|
|
9991
|
+
flow: {
|
|
9992
|
+
...body.data ?? {},
|
|
9993
|
+
name: body.flow
|
|
9994
|
+
},
|
|
9995
|
+
publicOrigin,
|
|
9996
|
+
token: await ensureToken(),
|
|
9997
|
+
apiBaseUrl,
|
|
9998
|
+
appId: state.appId,
|
|
9999
|
+
settings: settings$1,
|
|
10000
|
+
secrets: secrets$1
|
|
10001
|
+
}));
|
|
10002
|
+
printResult(`[flow] ${body.flow}`, result$1, io);
|
|
10003
|
+
res.writeHead(200, { "content-type": "application/json" });
|
|
10004
|
+
res.end(JSON.stringify(result$1));
|
|
10005
|
+
return;
|
|
10006
|
+
}
|
|
9903
10007
|
if (body.schedule) {
|
|
9904
10008
|
const { settings: settings$1, secrets: secrets$1 } = local();
|
|
9905
10009
|
const result$1 = await invokeLocal(app, devEnvelope({
|
|
@@ -10019,6 +10123,47 @@ async function appDev(flags, io) {
|
|
|
10019
10123
|
}
|
|
10020
10124
|
async function appTrigger(type, flags, io) {
|
|
10021
10125
|
const port = Number(flags.port ?? io.env.SAYREN_APP_PORT ?? APP_DEV_PORT);
|
|
10126
|
+
if (flags.tool) {
|
|
10127
|
+
let toolInput = {};
|
|
10128
|
+
if (flags.data) try {
|
|
10129
|
+
toolInput = JSON.parse(flags.data);
|
|
10130
|
+
} catch {
|
|
10131
|
+
throw new CliError(cli_app_trigger_data_invalid());
|
|
10132
|
+
}
|
|
10133
|
+
const res$1 = await io.fetch(`http://127.0.0.1:${port}/_trigger`, {
|
|
10134
|
+
method: "POST",
|
|
10135
|
+
headers: { "content-type": "application/json" },
|
|
10136
|
+
body: JSON.stringify({
|
|
10137
|
+
tool: flags.tool,
|
|
10138
|
+
data: toolInput
|
|
10139
|
+
})
|
|
10140
|
+
});
|
|
10141
|
+
if (!res$1.ok) throw new CliError(cli_app_trigger_failed({ status: String(res$1.status) }));
|
|
10142
|
+
const result$1 = await res$1.json();
|
|
10143
|
+
printResult(`[tool] ${flags.tool}`, result$1, io);
|
|
10144
|
+
if (result$1.response?.body) io.out(` → ${result$1.response.body}`);
|
|
10145
|
+
return result$1.outcome === "OK" ? 0 : 1;
|
|
10146
|
+
}
|
|
10147
|
+
if (flags.flow) {
|
|
10148
|
+
let flowData = {};
|
|
10149
|
+
if (flags.data) try {
|
|
10150
|
+
flowData = JSON.parse(flags.data);
|
|
10151
|
+
} catch {
|
|
10152
|
+
throw new CliError(cli_app_trigger_data_invalid());
|
|
10153
|
+
}
|
|
10154
|
+
const res$1 = await io.fetch(`http://127.0.0.1:${port}/_trigger`, {
|
|
10155
|
+
method: "POST",
|
|
10156
|
+
headers: { "content-type": "application/json" },
|
|
10157
|
+
body: JSON.stringify({
|
|
10158
|
+
flow: flags.flow,
|
|
10159
|
+
data: flowData
|
|
10160
|
+
})
|
|
10161
|
+
});
|
|
10162
|
+
if (!res$1.ok) throw new CliError(cli_app_trigger_failed({ status: String(res$1.status) }));
|
|
10163
|
+
const result$1 = await res$1.json();
|
|
10164
|
+
printResult(`[flow] ${flags.flow}`, result$1, io);
|
|
10165
|
+
return result$1.outcome === "OK" ? 0 : 1;
|
|
10166
|
+
}
|
|
10022
10167
|
if (flags.schedule) {
|
|
10023
10168
|
const res$1 = await io.fetch(`http://127.0.0.1:${port}/_trigger`, {
|
|
10024
10169
|
method: "POST",
|
|
@@ -11954,7 +12099,9 @@ const VALUE_FLAGS = new Set([
|
|
|
11954
12099
|
"data",
|
|
11955
12100
|
"order",
|
|
11956
12101
|
"schedule",
|
|
11957
|
-
"private-store"
|
|
12102
|
+
"private-store",
|
|
12103
|
+
"flow",
|
|
12104
|
+
"tool"
|
|
11958
12105
|
]);
|
|
11959
12106
|
const BOOL_FLAGS = new Set([
|
|
11960
12107
|
"force",
|
|
@@ -12041,6 +12188,8 @@ async function main(argv, io) {
|
|
|
12041
12188
|
order: str(parsed.flags.order),
|
|
12042
12189
|
schedule: str(parsed.flags.schedule),
|
|
12043
12190
|
privateStore: str(parsed.flags["private-store"]),
|
|
12191
|
+
flow: str(parsed.flags.flow),
|
|
12192
|
+
tool: str(parsed.flags.tool),
|
|
12044
12193
|
yes: parsed.flags.yes === true
|
|
12045
12194
|
}, io);
|
|
12046
12195
|
case "init": return init({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sayren",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.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.13"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@biomejs/biome": "^2.5.14",
|