@xfilecom/xframe 0.1.29 → 0.1.32

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/bin/xframe.js CHANGED
@@ -316,6 +316,70 @@ async function collectDatabaseConfig(fromCli, skipDbPrompt, wantDbPullFlag) {
316
316
  }
317
317
  }
318
318
 
319
+ /** drizzle 루트 db:pull 과 Nest 런타임이 backend-core 로드 시 필요 (피어 미설치 시 모듈 누락) */
320
+ const NEST_MICROSERVICES_SPEC = '^10.0.0';
321
+ const REFLECT_METADATA_SPEC = '^0.2.0';
322
+
323
+ /**
324
+ * 옛 템플릿·캐시된 npx 패키지에도 대응: 루트 devDeps + apps/api deps 에 보강.
325
+ * 이미 있으면 변경 없음.
326
+ */
327
+ function ensureNestPeerDepsInPackageJsons(targetRoot) {
328
+ let touched = false;
329
+
330
+ const rootPkgPath = path.join(targetRoot, 'package.json');
331
+ if (fs.existsSync(rootPkgPath)) {
332
+ try {
333
+ const pkg = JSON.parse(fs.readFileSync(rootPkgPath, 'utf8'));
334
+ pkg.devDependencies = pkg.devDependencies || {};
335
+ let rootChanged = false;
336
+ if (!pkg.devDependencies['@nestjs/microservices']) {
337
+ pkg.devDependencies['@nestjs/microservices'] = NEST_MICROSERVICES_SPEC;
338
+ rootChanged = true;
339
+ }
340
+ if (!pkg.devDependencies['reflect-metadata']) {
341
+ pkg.devDependencies['reflect-metadata'] = REFLECT_METADATA_SPEC;
342
+ rootChanged = true;
343
+ }
344
+ if (rootChanged) {
345
+ fs.writeFileSync(rootPkgPath, `${JSON.stringify(pkg, null, 2)}\n`, 'utf8');
346
+ touched = true;
347
+ }
348
+ } catch {
349
+ /* ignore */
350
+ }
351
+ }
352
+
353
+ const apiPkgPath = path.join(targetRoot, 'apps', 'api', 'package.json');
354
+ if (fs.existsSync(apiPkgPath)) {
355
+ try {
356
+ const pkg = JSON.parse(fs.readFileSync(apiPkgPath, 'utf8'));
357
+ pkg.dependencies = pkg.dependencies || {};
358
+ let apiChanged = false;
359
+ if (!pkg.dependencies['@nestjs/microservices']) {
360
+ pkg.dependencies['@nestjs/microservices'] = NEST_MICROSERVICES_SPEC;
361
+ apiChanged = true;
362
+ }
363
+ if (!pkg.dependencies['reflect-metadata']) {
364
+ pkg.dependencies['reflect-metadata'] = REFLECT_METADATA_SPEC;
365
+ apiChanged = true;
366
+ }
367
+ if (apiChanged) {
368
+ fs.writeFileSync(apiPkgPath, `${JSON.stringify(pkg, null, 2)}\n`, 'utf8');
369
+ touched = true;
370
+ }
371
+ } catch {
372
+ /* ignore */
373
+ }
374
+ }
375
+
376
+ if (touched) {
377
+ console.log(
378
+ 'xframe: package.json 에 @nestjs/microservices · reflect-metadata 를 보강했습니다 (db:pull / API).',
379
+ );
380
+ }
381
+ }
382
+
319
383
  /** yarn 우선, 없거나 실패 시 npm (부모 셸 PATH 그대로 — shell:true 쓰면 sh라 yarn/nvm PATH가 빠지는 경우가 많음) */
320
384
  function installDependencies(cwd) {
321
385
  const publicNpm = 'https://registry.npmjs.org/';
@@ -544,6 +608,7 @@ async function main() {
544
608
  /** 템플릿은 모노레포 기준 front-core 소스를 가리키고, 생성 앱은 설치된 패키지로 바꿉니다. */
545
609
  patchWebTsconfigFrontCorePath(targetRoot);
546
610
  patchWebViteFrontCoreAlias(targetRoot);
611
+ ensureNestPeerDepsInPackageJsons(targetRoot);
547
612
 
548
613
  console.log(`Created ${packageName} at ${targetRoot}
549
614
 
@@ -577,7 +642,8 @@ Next:
577
642
  cd ${rel}
578
643
  yarn dev # 또는 npm run dev
579
644
  → API :3000/health · Client :3001 · Admin :3002
580
- (설치 생략: npx @xfilecom/xframe <dir> --no-install)`);
645
+ (설치 생략: npx @xfilecom/xframe <dir> --no-install)
646
+ 최신 스캐폴드: npx --yes @xfilecom/xframe@latest <dir>`);
581
647
  }
582
648
 
583
649
  main().catch((err) => {
package/defaults.json CHANGED
@@ -1,4 +1,4 @@
1
1
  {
2
- "backendCore": "^1.0.10",
3
- "frontCore": "^0.2.16"
2
+ "backendCore": "^1.0.12",
3
+ "frontCore": "^0.2.18"
4
4
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xfilecom/xframe",
3
- "version": "0.1.29",
3
+ "version": "0.1.32",
4
4
  "description": "Scaffold full-stack app: Nest + @xfilecom/backend-core, Vite/React + @xfilecom/front-core",
5
5
  "license": "UNLICENSED",
6
6
  "bin": {
@@ -1,9 +1,12 @@
1
1
  import { useCallback, useId, useRef, useState, type ReactNode } from 'react';
2
2
  import {
3
3
  Badge,
4
+ BottomSheet,
4
5
  Box,
5
6
  Button,
6
7
  Card,
8
+ ConfirmDialog,
9
+ Dialog,
7
10
  Input,
8
11
  InlineErrorList,
9
12
  LoadingOverlay,
@@ -32,6 +35,11 @@ export function FrontCoreShowcase() {
32
35
  const [toasts, setToasts] = useState<ToastEntry[]>([]);
33
36
  const [errors, setErrors] = useState<InlineErrorEntry[]>([]);
34
37
  const [loading, setLoading] = useState(false);
38
+ const [dialogOpen, setDialogOpen] = useState(false);
39
+ const [confirmOpen, setConfirmOpen] = useState(false);
40
+ const [confirmDestructiveOpen, setConfirmDestructiveOpen] = useState(false);
41
+ const [confirmLoadingDemo, setConfirmLoadingDemo] = useState(false);
42
+ const [sheetOpen, setSheetOpen] = useState(false);
35
43
 
36
44
  const pushToast = useCallback(
37
45
  (severity: ToastSeverity) => {
@@ -54,6 +62,59 @@ export function FrontCoreShowcase() {
54
62
  <ToastList toasts={toasts} onDismiss={(id) => setToasts((t) => t.filter((x) => x.id !== id))} />
55
63
  <LoadingOverlay active={loading} message="로딩 중…" />
56
64
 
65
+ <Dialog
66
+ open={dialogOpen}
67
+ onOpenChange={setDialogOpen}
68
+ title="Dialog"
69
+ description="title / description / children 조합. 배경 클릭·Escape 로 닫을 수 있습니다."
70
+ >
71
+ <Text variant="body">children 에 폼·리스트 등 자유롭게 넣을 수 있습니다.</Text>
72
+ <div className="xfc-dialog-footer">
73
+ <Button type="button" variant="muted" onClick={() => setDialogOpen(false)}>
74
+ 취소
75
+ </Button>
76
+ <Button type="button" variant="primary" onClick={() => setDialogOpen(false)}>
77
+ 확인
78
+ </Button>
79
+ </div>
80
+ </Dialog>
81
+
82
+ <ConfirmDialog
83
+ open={confirmOpen}
84
+ onOpenChange={setConfirmOpen}
85
+ title="ConfirmDialog"
86
+ message="일반 확인창입니다. 취소 시 onCancel 후 닫힙니다."
87
+ onConfirm={() => setConfirmOpen(false)}
88
+ />
89
+
90
+ <ConfirmDialog
91
+ open={confirmDestructiveOpen}
92
+ onOpenChange={setConfirmDestructiveOpen}
93
+ title="위험 작업"
94
+ message="destructive + 빨간 확인 버튼 예시입니다."
95
+ destructive
96
+ confirmLabel="삭제"
97
+ onConfirm={() => setConfirmDestructiveOpen(false)}
98
+ />
99
+
100
+ <ConfirmDialog
101
+ open={confirmLoadingDemo}
102
+ onOpenChange={setConfirmLoadingDemo}
103
+ title="로딩 중 확인"
104
+ message="confirmLoading 시 버튼이 잠깁니다."
105
+ confirmLoading
106
+ onConfirm={() => {}}
107
+ />
108
+
109
+ <BottomSheet open={sheetOpen} onOpenChange={setSheetOpen} title="BottomSheet" showHandle>
110
+ <Text variant="body">화면 하단에서 올라오는 패널입니다.</Text>
111
+ <Stack direction="row" gap="sm" align="center" style={{ marginTop: 'var(--xfc-space-md)', flexWrap: 'wrap' }}>
112
+ <Button type="button" variant="primary" onClick={() => setSheetOpen(false)}>
113
+ 닫기
114
+ </Button>
115
+ </Stack>
116
+ </BottomSheet>
117
+
57
118
  <Stack direction="column" gap="lg" align="stretch">
58
119
  <Card>
59
120
  <Stack direction="column" gap="md" align="stretch">
@@ -141,6 +202,33 @@ export function FrontCoreShowcase() {
141
202
  </Stack>
142
203
  </Card>
143
204
 
205
+ <Card>
206
+ <Stack direction="column" gap="md" align="stretch">
207
+ <SectionTitle>Dialog · ConfirmDialog · BottomSheet</SectionTitle>
208
+ <Text variant="small" style={{ color: 'var(--xfc-fg-muted)' }}>
209
+ document.body 포털 · z-index 10050 (토스트·로딩보다 위). base.css 의 .xfc-dialog-* /
210
+ .xfc-bottom-sheet-* 로 테마 조정.
211
+ </Text>
212
+ <Stack direction="row" gap="sm" align="center" style={{ flexWrap: 'wrap' }}>
213
+ <Button type="button" variant="secondary" onClick={() => setDialogOpen(true)}>
214
+ Dialog 열기
215
+ </Button>
216
+ <Button type="button" variant="secondary" onClick={() => setConfirmOpen(true)}>
217
+ Confirm
218
+ </Button>
219
+ <Button type="button" variant="secondary" onClick={() => setConfirmDestructiveOpen(true)}>
220
+ Confirm (destructive)
221
+ </Button>
222
+ <Button type="button" variant="secondary" onClick={() => setConfirmLoadingDemo(true)}>
223
+ Confirm (loading)
224
+ </Button>
225
+ <Button type="button" variant="secondary" onClick={() => setSheetOpen(true)}>
226
+ BottomSheet
227
+ </Button>
228
+ </Stack>
229
+ </Stack>
230
+ </Card>
231
+
144
232
  <Card>
145
233
  <Stack direction="column" gap="md" align="stretch">
146
234
  <SectionTitle>ToastList · InlineErrorList · LoadingOverlay</SectionTitle>